1
0
Fork 0
mirror of https://github.com/nix-community/home-manager.git synced 2025-11-08 19:46:05 +01:00

ci: extract-maintainers-meta tweaks (#7434)

Simplify extraction and generation of file. We dont need the comments
and can leverage the appropriate lib.generator function.

Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
This commit is contained in:
Austin Horstman 2025-07-11 12:47:42 -05:00 committed by GitHub
parent 9d343f0880
commit b8b7e5ec35
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 71 additions and 64 deletions

View file

@ -13,6 +13,7 @@ let
moduleMaintainersJson = builtins.fromJSON (builtins.readFile docsLib.jsonModuleMaintainers); moduleMaintainersJson = builtins.fromJSON (builtins.readFile docsLib.jsonModuleMaintainers);
maintainers = moduleMaintainersJson; maintainers = moduleMaintainersJson;
# TODO: Find a better solution for extracting maintainers outside `modules`
additionalFiles = [ additionalFiles = [
../../docs/home-manager-manual.nix ../../docs/home-manager-manual.nix
]; ];
@ -58,22 +59,30 @@ let
allMaintainerObjects = extractMaintainerObjects maintainers ++ additionalMaintainerObjects; allMaintainerObjects = extractMaintainerObjects maintainers ++ additionalMaintainerObjects;
getMaintainerName = maintainer: maintainer.github or maintainer.name or null; allMaintainerNames = lib.filter (name: name != null) (
map (maintainer: maintainer.github or maintainer.name or null) allMaintainerObjects
allMaintainerNames = lib.filter (name: name != null) (map getMaintainerName allMaintainerObjects); );
maintainerDetails = lib.pipe allMaintainerObjects [
(lib.filter (obj: getMaintainerName obj != null))
(map (obj: {
name = getMaintainerName obj;
value = obj;
}))
lib.listToAttrs
];
hmMaintainers = import ../../modules/lib/maintainers.nix; hmMaintainers = import ../../modules/lib/maintainers.nix;
hmMaintainerNames = lib.attrNames hmMaintainers; hmMaintainerNames = lib.attrNames hmMaintainers;
maintainerDetails = lib.pipe allMaintainerObjects [
(lib.filter (obj: (obj.github or obj.name or null) != null))
(map (obj: {
name = obj.github or obj.name;
value = obj // {
source =
if categorizedMaintainers.home-manager ? ${obj.github} then
"home-manager"
else if categorizedMaintainers.nixpkgs ? ${obj.github} then
"nixpkgs"
else
throw "${obj.github} is neither a home-manager or nixpkgs maintainer";
};
}))
lib.listToAttrs
];
partitionedMaintainers = lib.partition (nameValue: lib.elem nameValue.name hmMaintainerNames) ( partitionedMaintainers = lib.partition (nameValue: lib.elem nameValue.name hmMaintainerNames) (
lib.attrsToList maintainerDetails lib.attrsToList maintainerDetails
); );
@ -83,35 +92,10 @@ let
nixpkgs = lib.listToAttrs partitionedMaintainers.wrong; nixpkgs = lib.listToAttrs partitionedMaintainers.wrong;
}; };
formatMaintainer = formattedMaintainers = lib.generators.toPretty {
name: info: source:
let
quotedName =
if lib.match "[0-9].*" name != null || lib.match "[^a-zA-Z0-9_-].*" name != null then
''"${name}"''
else
name;
filteredInfo = lib.filterAttrs (k: v: !lib.hasPrefix "_" k) info;
in
" ${quotedName} = ${
lib.generators.toPretty {
multiline = true; multiline = true;
indent = ""; indent = "";
} filteredInfo } maintainerDetails;
};";
formatAllMaintainers =
let
hmEntries = lib.mapAttrsToList (
name: info: formatMaintainer name info "home-manager"
) categorizedMaintainers.home-manager;
nixpkgsEntries = lib.mapAttrsToList (
name: info: formatMaintainer name info "nixpkgs"
) categorizedMaintainers.nixpkgs;
in
lib.concatStringsSep "\n" (hmEntries ++ nixpkgsEntries);
in in
{ {
@ -119,7 +103,7 @@ in
names = allMaintainerNames; names = allMaintainerNames;
details = maintainerDetails; details = maintainerDetails;
categorized = categorizedMaintainers; categorized = categorizedMaintainers;
formatted = formatAllMaintainers; formatted = formattedMaintainers;
stats = { stats = {
totalFiles = lib.length (lib.attrNames maintainers); totalFiles = lib.length (lib.attrNames maintainers);

View file

@ -9,13 +9,37 @@ reliable than parsing files with regex.
""" """
import argparse import argparse
import inspect
import json import json
import subprocess import subprocess
import sys import sys
from pathlib import Path from pathlib import Path
from typing import Dict
def get_project_root() -> Path:
"""
Find the project root directory.
Tries to find the git repository root. If that fails, falls back to
locating it relative to this script file.
"""
try:
# Ask git for the top-level directory of the current repository.
git_root_bytes = subprocess.check_output(
["git", "rev-parse", "--show-toplevel"], stderr=subprocess.DEVNULL
)
return Path(git_root_bytes.decode("utf-8").strip())
except (subprocess.CalledProcessError, FileNotFoundError):
# Fallback for when not in a git repo or git is not installed.
print(
"Warning: 'git rev-parse --show-toplevel' failed.",
"Falling back to script location to determine root.",
"This may not work correctly with flakes.",
file=sys.stderr,
)
# Assumes this script is at: <root>/flake/dev/generate-all-maintainers/
return Path(__file__).parent.parent.parent.parent.resolve()
class MetaMaintainerGenerator: class MetaMaintainerGenerator:
"""Generates maintainers list using meta.maintainers from Home Manager evaluation.""" """Generates maintainers list using meta.maintainers from Home Manager evaluation."""
@ -25,13 +49,13 @@ class MetaMaintainerGenerator:
self.output_file = hm_root / "all-maintainers.nix" self.output_file = hm_root / "all-maintainers.nix"
self.extractor_script = hm_root / "lib" / "nix" / "extract-maintainers-meta.nix" self.extractor_script = hm_root / "lib" / "nix" / "extract-maintainers-meta.nix"
def extract_maintainers_from_meta(self) -> Dict: def extract_maintainers_from_meta(self) -> dict:
"""Extract maintainer information using meta.maintainers.""" """Extract maintainer information using meta.maintainers."""
print("🔍 Extracting maintainers using meta.maintainers...") print("🔍 Extracting maintainers using meta.maintainers...")
try: try:
result = subprocess.run([ result = subprocess.run([
"nix", "eval", "--impure", "--file", str(self.extractor_script), "--json" "nix", "eval", "--file", str(self.extractor_script), "--json"
], capture_output=True, text=True, timeout=60) ], capture_output=True, text=True, timeout=60)
if result.returncode == 0: if result.returncode == 0:
@ -49,7 +73,7 @@ class MetaMaintainerGenerator:
print(f"❌ Error extracting maintainers: {e}") print(f"❌ Error extracting maintainers: {e}")
sys.exit(1) sys.exit(1)
def format_maintainer_entry(self, name: str, info: Dict, source: str) -> str: def format_maintainer_entry(self, name: str, info: dict, source: str) -> str:
"""Format a single maintainer entry with nix fmt compatible formatting.""" """Format a single maintainer entry with nix fmt compatible formatting."""
lines = [f" # {source}"] lines = [f" # {source}"]
lines.append(f" {name} = {{") lines.append(f" {name} = {{")
@ -116,7 +140,9 @@ class MetaMaintainerGenerator:
print(f"📦 Nixpkgs maintainers: {len(nixpkgs_maintainers)}") print(f"📦 Nixpkgs maintainers: {len(nixpkgs_maintainers)}")
with open(self.output_file, 'w') as f: with open(self.output_file, 'w') as f:
f.write('''# Home Manager all maintainers list. f.write(
inspect.cleandoc("""
# Home Manager all maintainers list.
# #
# This file lists all referenced maintainers in Home Manager. # This file lists all referenced maintainers in Home Manager.
# #
@ -125,17 +151,15 @@ class MetaMaintainerGenerator:
# #
# To regenerate: ./lib/python/generate-all-maintainers.py # To regenerate: ./lib/python/generate-all-maintainers.py
# #
{ """)
''') )
# Use the formatted maintainers from Nix evaluation # Use the formatted maintainers from Nix evaluation
print("✨ Adding formatted maintainers using lib.generators.toPretty...") print("✨ Adding formatted maintainers using lib.generators.toPretty...")
f.write("\n")
f.write(formatted_maintainers) f.write(formatted_maintainers)
f.write("\n") f.write("\n")
f.write('''}
''')
self.validate_generated_file() self.validate_generated_file()
self.print_statistics(maintainer_data) self.print_statistics(maintainer_data)
@ -143,7 +167,7 @@ class MetaMaintainerGenerator:
"""Validate the generated Nix file syntax.""" """Validate the generated Nix file syntax."""
try: try:
result = subprocess.run([ result = subprocess.run([
'nix', 'eval', '--file', str(self.output_file), '--json' 'nix-instantiate', '--eval', str(self.output_file), '--strict'
], capture_output=True, text=True, timeout=10) ], capture_output=True, text=True, timeout=10)
if result.returncode == 0: if result.returncode == 0:
@ -157,7 +181,7 @@ class MetaMaintainerGenerator:
print(f"Warning: Could not validate file: {e}") print(f"Warning: Could not validate file: {e}")
return False return False
def print_statistics(self, maintainer_data: Dict) -> None: def print_statistics(self, maintainer_data: dict) -> None:
"""Print generation statistics.""" """Print generation statistics."""
stats = maintainer_data["stats"] stats = maintainer_data["stats"]
@ -193,8 +217,7 @@ def main():
if args.root: if args.root:
hm_root = args.root hm_root = args.root
else: else:
script_dir = Path(__file__).parent hm_root = get_project_root()
hm_root = script_dir.parent.parent
if not (hm_root / "modules" / "lib" / "maintainers.nix").exists(): if not (hm_root / "modules" / "lib" / "maintainers.nix").exists():
print(f"Error: Could not find maintainers.nix in {hm_root}") print(f"Error: Could not find maintainers.nix in {hm_root}")