Compare commits

..
Author SHA1 Message Date
home-manager-ci[bot] 40e3b99d82 flake.lock: Update
Flake lock file updates:

• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/68d8aa3d661f0e6bd5862291b5bb263b2a6595c9?narHash=sha256-vPKLpjhIVWdDrfiUM8atW6YkIggCEKdSAlJPzzhkQlw%3D' (2026-04-05)
  → 'github:NixOS/nixpkgs/4c1018dae018162ec878d42fec712642d214fdfa?narHash=sha256-ar3rofg%2BawPB8QXDaFJhJ2jJhu%2BKqN/PRCXeyuXR76E%3D' (2026-04-09)
2026-04-12 05:47:34 +00:00
1251 changed files with 7965 additions and 28016 deletions
-4
View File
@@ -55,7 +55,3 @@ f2f1076c1f789595c2a2b18b76466fbd691025dd
11ad9d2e42ebf6d00db4d7bae252f1c6b7dd36a4
74b0e979375b0ed469e2394820aa50ba2114800b
de90ee24082bb8dd44145f5c733b807467856820
# Deadnix cleanup
71402c5df34df5ee7b6c10d738018f9f0c8bde2b
a93d80bcec089abf80894c25ee3934b7e196bbd9
+1 -15
View File
@@ -9,22 +9,8 @@ updates:
prefix: "ci:"
- package-ecosystem: "github-actions"
directory: "/"
target-branch: "release-26.05"
target-branch: "release-25.11"
schedule:
interval: "weekly"
commit-message:
prefix: "ci:"
- package-ecosystem: "nix"
directory: "/"
target-branch: "master"
schedule:
interval: "weekly"
commit-message:
prefix: "flake:"
- package-ecosystem: "nix"
directory: "/"
target-branch: "release-26.05"
schedule:
interval: "weekly"
commit-message:
prefix: "flake:"
+1 -4
View File
@@ -1,6 +1,3 @@
"release":
- base-branch:
- '^release-.*'
"ai":
- changed-files:
- any-glob-to-any-file:
@@ -10,7 +7,7 @@
- modules/programs/claude-code.nix
- modules/programs/codex.nix
- modules/programs/fabric-ai.nix
- modules/programs/antigravity-cli.nix
- modules/programs/gemini-cli.nix
- modules/programs/mcp.nix
- modules/programs/mistral-vibe.nix
- modules/programs/mods.nix
+1 -1
View File
@@ -15,7 +15,7 @@ jobs:
- uses: actions/checkout@v6
- uses: cachix/install-nix-action@v31
with:
nix_path: nixpkgs=channel:nixpkgs-unstable
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v17
with:
name: nix-community
+1 -1
View File
@@ -24,7 +24,7 @@ jobs:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
COUNT=$(gh api "repos/${{ github.repository }}/pulls/$PR_NUMBER/files" --paginate --jq '.[].filename' | grep -c '^modules/' || true)
COUNT=$(gh api "repos/${{ github.repository }}/pulls/$PR_NUMBER/files" --paginate --jq '.[].filename' | grep '^modules/' | wc -l || echo 0)
echo "Found $COUNT changed module files."
echo "count=$COUNT" >> "$GITHUB_OUTPUT"
+5 -5
View File
@@ -42,12 +42,12 @@ jobs:
GH_TOKEN: ${{ steps.app-token.outputs.token || secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
CHANGED_FILES=$(gh pr diff "$PR_NUMBER" --name-only | grep '^modules/' | grep -v '^modules/\(po\|.*\/news\)/' || true)
CHANGED_FILES=$(gh pr diff $PR_NUMBER --name-only | grep '^modules/' | grep -v '^modules/\(po\|.*\/news\)/' || true)
echo "Changed files:"
echo "$CHANGED_FILES"
echo "changed_files<<EOF" >> "$GITHUB_OUTPUT"
echo "$CHANGED_FILES" >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
echo "changed_files<<EOF" >> $GITHUB_OUTPUT
echo "$CHANGED_FILES" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: Extract Maintainers
id: extract-maintainers
env:
@@ -58,7 +58,7 @@ jobs:
MAINTAINERS=$(lib/python/extract-maintainers.py \
--changed-files "$CHANGED_FILES" \
--pr-author "$PR_AUTHOR")
echo "maintainers=$MAINTAINERS" >> "$GITHUB_OUTPUT"
echo "maintainers=$MAINTAINERS" >> $GITHUB_OUTPUT
echo "Found maintainers: $MAINTAINERS"
- name: Manage Reviewers
env:
+14 -36
View File
@@ -6,16 +6,13 @@ on:
concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.run_id }}
cancel-in-progress: true
permissions: {}
jobs:
changes:
runs-on: ubuntu-latest
timeout-minutes: 5
outputs:
docs: ${{ steps.changes.outputs.docs }}
format: ${{ steps.changes.outputs.format }}
hm: ${{ steps.changes.outputs.hm }}
parse: ${{ steps.changes.outputs.parse }}
tests: ${{ steps.changes.outputs.tests }}
steps:
- uses: actions/checkout@v6
@@ -42,12 +39,8 @@ jobs:
- 'flake.lock'
- 'flake.nix'
- 'home-manager/**'
parse:
- '**/*.nix'
- 'flake.lock'
tests:
needs: changes
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
@@ -60,23 +53,14 @@ jobs:
run: |
echo "rev=$(jq -r '.nodes.nixpkgs.locked.rev' flake.lock)" >> "$GITHUB_OUTPUT"
- uses: cachix/install-nix-action@v31
if: github.event_name == 'schedule' || needs.changes.outputs.docs == 'true' || needs.changes.outputs.tests == 'true' || needs.changes.outputs.hm == 'true' || needs.changes.outputs.parse == 'true' || needs.changes.outputs.format == 'true'
if: github.event_name == 'schedule' || needs.changes.outputs.docs == 'true' || needs.changes.outputs.tests == 'true' || needs.changes.outputs.hm == 'true' || needs.changes.outputs.format == 'true'
with:
nix_path: nixpkgs=https://github.com/NixOS/nixpkgs/archive/${{ steps.get-nixpkgs.outputs.rev }}.tar.gz
extra_nix_config: |
sandbox = true
- name: Build docs
if: github.event_name == 'schedule' || needs.changes.outputs.docs == 'true'
run: nix build --show-trace .#docs-jsonModuleMaintainers
- name: Parse Nix files with nix and Lix
if: >-
matrix.os == 'ubuntu-latest' &&
(github.event_name == 'schedule' || needs.changes.outputs.parse == 'true')
run: nix build --show-trace --keep-going .#ci-parse .#ci-parse-lix
- name: Format Check
if: >-
matrix.os == 'ubuntu-latest' &&
(github.event_name == 'schedule' || needs.changes.outputs.format == 'true')
if: github.event_name == 'schedule' || needs.changes.outputs.format == 'true'
run: nix fmt -- --ci
- name: Test init --switch with locked inputs
if: github.event_name == 'schedule' || needs.changes.outputs.hm == 'true'
@@ -92,37 +76,31 @@ jobs:
if: github.event_name == 'pull_request'
shell: bash
run: |
echo "### Test Job Summary" >> "$GITHUB_STEP_SUMMARY"
echo "" >> "$GITHUB_STEP_SUMMARY"
echo "A summary of tasks triggered by file changes in this PR:" >> "$GITHUB_STEP_SUMMARY"
echo "" >> "$GITHUB_STEP_SUMMARY"
echo "### Test Job Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "A summary of tasks triggered by file changes in this PR:" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [[ "${{ needs.changes.outputs.docs }}" == "true" ]]; then
echo "- ✅ **Docs Build:** Triggered" >> "$GITHUB_STEP_SUMMARY"
echo "- ✅ **Docs Build:** Triggered" >> $GITHUB_STEP_SUMMARY
else
echo "- ☑️ **Docs Build:** Skipped (no relevant files changed)" >> "$GITHUB_STEP_SUMMARY"
echo "- ☑️ **Docs Build:** Skipped (no relevant files changed)" >> $GITHUB_STEP_SUMMARY
fi
if [[ "${{ needs.changes.outputs.format }}" == "true" ]]; then
echo "- ✅ **Format Check:** Triggered" >> "$GITHUB_STEP_SUMMARY"
echo "- ✅ **Format Check:** Triggered" >> $GITHUB_STEP_SUMMARY
else
echo "- ☑️ **Format Check:** Skipped (no relevant files changed)" >> "$GITHUB_STEP_SUMMARY"
fi
if [[ "${{ needs.changes.outputs.parse }}" == "true" ]]; then
echo "- ✅ **Nix Parse (nix + Lix):** Triggered" >> "$GITHUB_STEP_SUMMARY"
else
echo "- ☑️ **Nix Parse (nix + Lix):** Skipped (no relevant files changed)" >> "$GITHUB_STEP_SUMMARY"
echo "- ☑️ **Format Check:** Skipped (no relevant files changed)" >> $GITHUB_STEP_SUMMARY
fi
if [[ "${{ needs.changes.outputs.hm }}" == "true" ]]; then
echo "- ✅ **Home Manager Tests:** Triggered" >> "$GITHUB_STEP_SUMMARY"
echo "- ✅ **Home Manager Tests:** Triggered" >> $GITHUB_STEP_SUMMARY
else
echo "- ☑️ **Home Manager Tests:** Skipped (no relevant files changed)" >> "$GITHUB_STEP_SUMMARY"
echo "- ☑️ **Home Manager Tests:** Skipped (no relevant files changed)" >> $GITHUB_STEP_SUMMARY
fi
if [[ "${{ needs.changes.outputs.tests }}" == "true" ]]; then
echo "- ✅ **General Tests:** Triggered" >> "$GITHUB_STEP_SUMMARY"
echo "- ✅ **General Tests:** Triggered" >> $GITHUB_STEP_SUMMARY
else
echo "- ☑️ **General Tests:** Skipped (no relevant files changed)" >> "$GITHUB_STEP_SUMMARY"
echo "- ☑️ **General Tests:** Skipped (no relevant files changed)" >> $GITHUB_STEP_SUMMARY
fi
+66
View File
@@ -0,0 +1,66 @@
name: Update flake inputs
on:
schedule:
# Update every Sunday and Wednesday
- cron: "51 3 * * 0,3"
workflow_dispatch:
jobs:
update:
runs-on: ubuntu-latest
if: github.event_name != 'schedule' || github.repository_owner == 'nix-community'
strategy:
fail-fast: false
matrix:
branch: [master, release-25.11]
steps:
- name: Create GitHub App token
uses: actions/create-github-app-token@v3
if: vars.CI_APP_ID
id: app-token
with:
app-id: ${{ vars.CI_APP_ID }}
private-key: ${{ secrets.CI_APP_PRIVATE_KEY }}
- name: Get GitHub App user info
if: vars.CI_APP_ID
id: user-info
env:
GH_TOKEN: ${{ steps.app-token.outputs.token}}
slug: ${{ steps.app-token.outputs.app-slug }}
run: |
name="$slug[bot]"
id=$(gh api "/users/$name" --jq .id)
{
echo "id=$id"
echo "name=$name"
echo "email=$id+$name@users.noreply.github.com"
} >> "$GITHUB_OUTPUT"
- name: Checkout repository
uses: actions/checkout@v6
with:
ref: ${{ matrix.branch }}
token: ${{ steps.app-token.outputs.token || secrets.GITHUB_TOKEN }}
- name: Install Nix
uses: cachix/install-nix-action@v31
- name: Update flake.lock
uses: DeterminateSystems/update-flake-lock@v28
with:
token: ${{ steps.app-token.outputs.token || secrets.GITHUB_TOKEN }}
git-committer-name: ${{ steps.user-info.outputs.name || 'github-actions[bot]' }}
git-committer-email: ${{ steps.user-info.outputs.email || '41898282+github-actions[bot]@users.noreply.github.com' }}
git-author-name: ${{ steps.user-info.outputs.name || 'github-actions[bot]' }}
git-author-email: ${{ steps.user-info.outputs.email || '41898282+github-actions[bot]@users.noreply.github.com' }}
pr-labels: dependencies
pr-title: "[${{ matrix.branch }}] flake.lock: Update"
pr-body: |
Automated update by the [update-flake-lock] GitHub Action.
```
{{ env.GIT_COMMIT_MESSAGE }}
```
This PR was most recently updated by workflow run [${{ github.run_id }}].
[update-flake-lock]: https://github.com/DeterminateSystems/update-flake-lock
[${{ github.run_id }}]: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
base: ${{ matrix.branch }}
branch: update/${{ matrix.branch }}
+9 -9
View File
@@ -184,7 +184,7 @@ jobs:
if [[ -n "$info" ]]; then
echo "PR info:"
echo "$info"
echo "$info" >> "$GITHUB_OUTPUT"
echo "$info" >> $GITHUB_OUTPUT
else
echo "No PR is currently open"
fi
@@ -266,21 +266,21 @@ jobs:
echo "✅ Successfully updated PR with new changes."
echo "$changes"
echo "🔗 PR URL: $pr_url"
echo "### ✅ PR Updated" >> "$GITHUB_STEP_SUMMARY"
echo "[$pr_url]($pr_url)" >> "$GITHUB_STEP_SUMMARY"
echo "### ✅ PR Updated" >> $GITHUB_STEP_SUMMARY
echo "[$pr_url]($pr_url)" >> $GITHUB_STEP_SUMMARY
elif [[ -n "$pr_url" ]]; then
echo "✅ Successfully created PR with maintainer updates."
echo "$changes"
echo "🔗 PR URL: $pr_url"
echo "### ✅ PR Created" >> "$GITHUB_STEP_SUMMARY"
echo "[$pr_url]($pr_url)" >> "$GITHUB_STEP_SUMMARY"
echo "### ✅ PR Created" >> $GITHUB_STEP_SUMMARY
echo "[$pr_url]($pr_url)" >> $GITHUB_STEP_SUMMARY
else
echo "❌ Failed to create or update pull request."
echo "### ❌ PR Operation Failed" >> "$GITHUB_STEP_SUMMARY"
echo "A pull request was intended but the URL was not captured. Please check the logs." >> "$GITHUB_STEP_SUMMARY"
echo "### ❌ PR Operation Failed" >> $GITHUB_STEP_SUMMARY
echo "A pull request was intended but the URL was not captured. Please check the logs." >> $GITHUB_STEP_SUMMARY
fi
else
echo "️ No changes detected - maintainers list is up to date."
echo "### ️ No Changes" >> "$GITHUB_STEP_SUMMARY"
echo "The maintainers list is up-to-date. No PR was created." >> "$GITHUB_STEP_SUMMARY"
echo "### ️ No Changes" >> $GITHUB_STEP_SUMMARY
echo "The maintainers list is up-to-date. No PR was created." >> $GITHUB_STEP_SUMMARY
fi
-1
View File
@@ -1 +0,0 @@
Noah Biewesch <dev@noahbiewesch.com> <90870942+trueNAHO@users.noreply.github.com>
-8
View File
@@ -1,8 +0,0 @@
# Contributing
Home Manager contribution guidelines live in the manual:
- [`docs/manual/contributing.md`](docs/manual/contributing.md)
- <https://nix-community.github.io/home-manager/#ch-contributing>
Read those docs before changing modules, tests, news entries, or release notes.
+2 -2
View File
@@ -125,7 +125,7 @@ Reference commits:
- Update the nixpkgs input to track the corresponding stable branch
- Example: For `release-25.11`, change from:
```nix
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
```
to:
```nix
@@ -135,7 +135,7 @@ Reference commits:
- Commit the flake.nix and flake.lock changes
**Note**: The release branch should track the stable NixOS release channel
(e.g., `nixos-25.11`), while master continues to track `nixpkgs-unstable`.
(e.g., `nixos-25.11`), while master continues to track `nixos-unstable`.
#### Step 3.5: On master - Update CI for the New Release Branch
+1 -1
View File
@@ -1,5 +1,5 @@
.PHONY: all all-tests test test-install format
NIXPKGS_REV := nixpkgs-unstable
NIXPKGS_REV := nixos-unstable
NIX_PATH := nixpkgs=https://github.com/NixOS/nixpkgs/archive/${NIXPKGS_REV}.tar.gz
all: all-tests test-install
+4 -5
View File
@@ -25,11 +25,10 @@ If you would like to contribute to Home Manager, then please have a look at
Releases
--------
Home Manager is developed against the `nixpkgs-unstable` branch, which often
causes it to contain tweaks for changes/packages not yet released in stable
[NixOS][].
Home Manager is developed against `nixos-unstable` branch, which often causes
it to contain tweaks for changes/packages not yet released in stable [NixOS][].
To avoid breaking users' configurations, Home Manager is released in branches
corresponding to NixOS releases (e.g. `release-26.05`). These branches get
corresponding to NixOS releases (e.g. `release-25.11`). These branches get
fixes, but usually not new modules. If you need a module to be backported, then
feel free to open an issue.
@@ -50,7 +49,7 @@ dconf store and cannot tell whether a configuration that is about to be
overwritten was from a previous Home Manager generation or from manual
configuration.
Home Manager targets `nixpkgs-unstable` and NixOS version 26.05 (the current
Home Manager targets [NixOS][] unstable and NixOS version 25.11 (the current
stable version), it may or may not work on other Linux distributions and NixOS
versions.
+41 -130
View File
@@ -21,13 +21,6 @@
name = "0xda157";
source = "nixpkgs";
};
"0xdsqr" = {
email = "me@dsqr.dev";
github = "0xdsqr";
githubId = 99584622;
name = "Dave Dennis";
source = "nixpkgs";
};
"3ulalia" = {
email = "3ulalia@proton.me";
github = "3ulalia";
@@ -119,21 +112,6 @@
name = "Denis Kaynar";
source = "home-manager";
};
ErinaYip = {
email = "erinayip@outlook.com";
github = "ErinaYip";
githubId = 227132255;
name = "erina";
source = "home-manager";
};
Eveeifyeve = {
email = "eveeg1971@gmail.com";
github = "Eveeifyeve";
githubId = 88671402;
matrix = "@eveeifyeve:matrix.org";
name = "Eveeifyeve";
source = "nixpkgs";
};
Fendse = {
email = "46252070+Fendse@users.noreply.github.com";
github = "Fendse";
@@ -412,6 +390,13 @@
name = "Sefa Eyeoglu";
source = "nixpkgs";
};
SebTM = {
email = "mail@sebastian-sellmeier.de";
github = "SebTM";
githubId = 17243347;
name = "Sebastian Sellmeier";
source = "nixpkgs";
};
ShamrockLee = {
email = "shamrocklee@posteo.net";
github = "ShamrockLee";
@@ -432,12 +417,6 @@
name = "Mel Bourgeois";
source = "nixpkgs";
};
SunOfLife1 = {
github = "SunOfLife1";
githubId = 30405063;
name = "SunOfLife1";
source = "home-manager";
};
Swarsel = {
email = "leon@swarsel.win";
github = "Swarsel";
@@ -473,6 +452,13 @@
name = "Vincent Breitmoser";
source = "nixpkgs";
};
Vortriz = {
email = "vorarishi22+nix@gmail.com";
github = "Vortriz";
githubId = 97402159;
name = "Rishi Vora";
source = "nixpkgs";
};
WGUNDERWOOD = {
email = "wg.underwood13@gmail.com";
github = "WGUNDERWOOD";
@@ -529,6 +515,14 @@
name = "David Chocholatý";
source = "nixpkgs";
};
adisbladis = {
email = "adisbladis@gmail.com";
github = "adisbladis";
githubId = 63286;
matrix = "@adis:blad.is";
name = "Adam Hose";
source = "nixpkgs";
};
afresquet = {
email = "alvarofresquet@gmail.com";
github = "afresquet";
@@ -685,13 +679,6 @@
name = "Filippo Berto";
source = "nixpkgs";
};
bittner = {
email = "peter@painless.software";
github = "bittner";
githubId = 665072;
name = "Peter Bittner";
source = "home-manager";
};
bjpbakker = {
email = "bart@thesoftwarecraft.com";
github = "bjpbakker";
@@ -1150,13 +1137,6 @@
name = "Fugi";
source = "nixpkgs";
};
garklein = {
email = "garklein97@gmail.com";
github = "garklein";
githubId = 63201615;
name = "Garklein";
source = "home-manager";
};
gauthsvenkat = {
email = "gauthsvenkat+home-manager@gmail.com";
github = "gauthsvenkat";
@@ -1258,18 +1238,6 @@
name = "Bhe Hongtyu";
source = "nixpkgs";
};
iamanaws = {
email = "iamanaws@httpd.dev";
github = "iamanaws";
githubId = 78835633;
keys = [
{
fingerprint = "CF10 DCBB 9318 BE1D 6040 4222 272C 61AB 190D ED28";
}
];
name = "Angel J";
source = "nixpkgs";
};
ilaumjd = {
email = "ilaumjd@gmail.com";
github = "ilaumjd";
@@ -1291,13 +1259,6 @@
name = "Ilya Savitsky";
source = "nixpkgs";
};
isaacST08 = {
email = "isaacst.nix@proton.me";
github = "isaacST08";
githubId = 106057977;
name = "Isaac Shiells Thomas";
source = "home-manager";
};
iynaix = {
email = "iynaix@gmail.com";
github = "iynaix";
@@ -1473,13 +1434,6 @@
name = "Nikolaos Karaolidis";
source = "nixpkgs";
};
kayskayskays = {
email = "115312476+kayskayskays@users.noreply.github.com";
github = "kayskayskays";
githubId = 115312476;
name = "Kays";
source = "home-manager";
};
khaneliman = {
email = "khaneliman12@gmail.com";
github = "khaneliman";
@@ -1502,13 +1456,6 @@
name = "Knut Magnus Aasrud";
source = "home-manager";
};
kpbaks = {
email = "kristoffer.pbs@gmail.com";
github = "kpbaks";
githubId = 57013304;
name = "Kristoffer Plagborg Bak Sørensen";
source = "nixpkgs";
};
kubukoz = {
email = "kubukoz@gmail.com";
github = "kubukoz";
@@ -1631,13 +1578,6 @@
name = "Manaiki Laut";
source = "nixpkgs";
};
marijanp = {
email = "marijan.petricevic94@gmail.com";
github = "marijanp";
githubId = 13599169;
name = "Marijan Petričević";
source = "nixpkgs";
};
mateusauler = {
email = "mateus@auler.dev";
github = "mateusauler";
@@ -1885,9 +1825,21 @@
email = "nukdokplex@nukdokplex.ru";
github = "nukdokplex";
githubId = 25458915;
keys = [
{
fingerprint = "7CE2 4C42 942D 58EA 99F6 F00A A47E 7374 3EF6 FCC4";
}
];
name = "Viktor Titov";
source = "nixpkgs";
};
nurelin = {
email = "nurelin@users.noreply.github.com";
github = "nurelin";
githubId = 5276274;
name = "nurelin";
source = "home-manager";
};
nyarly = {
email = "nyarly@gmail.com";
github = "nyarly";
@@ -1895,13 +1847,6 @@
name = "Judson Lester";
source = "nixpkgs";
};
ojsef39 = {
email = "me+github@jhofer.de";
github = "ojsef39";
githubId = 43563019;
name = "Josef Hofer";
source = "nixpkgs";
};
olmokramer = {
email = "olmokramer@users.noreply.github.com";
github = "olmokramer";
@@ -1992,6 +1937,13 @@
name = "Myles Wirth";
source = "nixpkgs";
};
pinage404 = {
email = "pinage404+nixpkgs@gmail.com";
github = "pinage404";
githubId = 6325757;
name = "pinage404";
source = "nixpkgs";
};
pjones = {
email = "pjones@devalot.com";
github = "pjones";
@@ -2165,13 +2117,6 @@
name = "Robert Helgesson";
source = "nixpkgs";
};
s0racat = {
email = "125882337+s0racat@users.noreply.github.com";
github = "s0racat";
githubId = 125882337;
name = "soracat";
source = "nixpkgs";
};
sableseyler = {
email = "sable@seyleri.us";
github = "sableseyler";
@@ -2184,20 +2129,6 @@
name = "Sable Seyler";
source = "nixpkgs";
};
sei40kr = {
email = "sei40kr@gmail.com";
github = "sei40kr";
githubId = 11665236;
name = "Seong Yong-ju";
source = "nixpkgs";
};
semi710 = {
email = "nik.singh710@gmail.com";
github = "semi710";
githubId = 60490474;
name = "Nikhil Singh";
source = "home-manager";
};
shikanime = {
email = "william.phetsinorath@shikanime.studio";
github = "shikanime";
@@ -2277,13 +2208,6 @@
name = "Sumner Evans";
source = "nixpkgs";
};
superflash41 = {
email = "saymon.nicho@pucp.edu.pe";
github = "superflash41";
githubId = 102434258;
name = "Saymon Nicho";
source = "home-manager";
};
surfaceflinger = {
email = "nat@nekopon.pl";
github = "surfaceflinger";
@@ -2458,13 +2382,6 @@
name = "Xavier Lambein";
source = "nixpkgs";
};
yaaaarn = {
email = "30006414+yaaaarn@users.noreply.github.com";
github = "yaaaarn";
githubId = 30006414;
name = "yarncat";
source = "nixpkgs";
};
yethal = {
github = "yethal";
githubId = 26117918;
@@ -2483,12 +2400,6 @@
name = "Jona Abdinghoff";
source = "nixpkgs";
};
zh4ngx = {
github = "zh4ngx";
githubId = 1329212;
name = "Andy Zhang";
source = "nixpkgs";
};
zorrobert = {
email = "118135271+zorrobert@users.noreply.github.com";
github = "zorrobert";
-45
View File
@@ -1,45 +0,0 @@
{
lib,
nix,
runCommand,
}:
let
home-manager =
with lib.fileset;
toSource {
root = ../.;
fileset = (fileFilter (file: file.hasExt "nix") ../.);
};
parseLog = "$TMPDIR/nix-parse.log";
in
runCommand "nix-parse-${nix.name}"
{
nativeBuildInputs = [
nix
];
}
''
export NIX_STORE_DIR=$TMPDIR/store
export NIX_STATE_DIR=$TMPDIR/state
nix-store --init
cd "${home-manager}"
# This will only show the first parse error, not all of them. That's fine, because
# the other CI jobs will report in more detail. This job is about checking parsing
# across different implementations / versions, not about providing the best DX.
# Returning all parse errors requires significantly more resources.
if ! find . -type f -iname '*.nix' | xargs -P $(nproc) nix-instantiate --parse 2> "${parseLog}" > /dev/null; then
cat "${parseLog}" >&2
echo "Parse failed in nix-instantiate." >&2
exit 1
fi
if grep "warning" "${parseLog}"; then
cat "${parseLog}" >&2
echo "Failing due to warnings in stderr" >&2
exit 1
fi
touch $out
''
+3 -9
View File
@@ -253,15 +253,9 @@ let
# Generate the HTML manual pages
home-manager-manual = pkgs.callPackage ./home-manager-manual.nix {
home-manager-options = {
home-manager = {
json = hmOptionsDocs.optionsJSON;
};
nixos = {
json = nixosOptionsDocs.optionsJSON;
};
nix-darwin = {
json = nixDarwinOptionsDocs.optionsJSON;
};
home-manager = hmOptionsDocs.optionsJSON;
nixos = nixosOptionsDocs.optionsJSON;
nix-darwin = nixDarwinOptionsDocs.optionsJSON;
};
inherit revision;
};
+4 -4
View File
@@ -2,16 +2,16 @@
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1779877693,
"narHash": "sha256-NOF9NAREhxr50bbBfVcVOq+ArCMSoe8dP79Pk2uyARk=",
"lastModified": 1773821835,
"narHash": "sha256-wvfdLLWJ2I9oEpDd9PfMA8osfIZicoQ5MT1jIwNs9Tk=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "4100e830e085863741bc69b156ec4ccd53ab5be0",
"rev": "c06b4ae3d6599a672a6210b7021d699c351eebda",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
+1 -1
View File
@@ -2,7 +2,7 @@
description = "Support developing Home Manager documentation";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
scss-reset = {
url = "github:andreymatin/scss-reset/1.4.2";
flake = false;
+38 -76
View File
@@ -1,99 +1,63 @@
{
stdenv,
lib,
callPackage,
mdbook,
python3,
documentation-highlighter,
revision,
home-manager-options,
nixos-render-docs,
}:
let
outputPath = "share/doc/home-manager";
mdbookOptions = callPackage ./mdbook/options.nix {
manpageUrls = ./manual/manpage-urls.json;
inherit revision;
optionDocs = {
home-manager = {
title = "Home Manager Configuration Options";
path = "home-manager";
prefix = "opt-";
json = "${home-manager-options.home-manager.json}";
};
nixos = {
title = "NixOS Configuration Options";
path = "nixos";
prefix = "nixos-opt-";
json = "${home-manager-options.nixos.json}";
};
nix-darwin = {
title = "nix-darwin Configuration Options";
path = "nix-darwin";
prefix = "nix-darwin-opt-";
json = "${home-manager-options.nix-darwin.json}";
};
};
};
in
stdenv.mkDerivation {
name = "home-manager-manual";
nativeBuildInputs = [
mdbook
python3
];
nativeBuildInputs = [ nixos-render-docs ];
src = ./.;
src = ./manual;
buildPhase = ''
runHook preBuild
mkdir -p out/{highlightjs,media}
mkdir -p source
python3 ${./mdbook/convert-markup.py} "$src/manual" source
python3 ${./mdbook/convert-markup.py} \
--base-depth 1 \
"$src/release-notes" \
source/release-notes
cp -t out/highlightjs \
${documentation-highlighter}/highlight.pack.js \
${documentation-highlighter}/LICENSE \
${documentation-highlighter}/mono-blue.css \
${documentation-highlighter}/loader.js
cp -r ${mdbookOptions}/options source/options
substituteInPlace ./options.md \
--subst-var-by \
OPTIONS_JSON \
${home-manager-options.home-manager}/share/doc/nixos/options.json
python3 ${./mdbook/substitute-summary.py} \
source/SUMMARY.md \
${mdbookOptions}/summary/home-manager.md \
${mdbookOptions}/summary/nixos.md \
${mdbookOptions}/summary/nix-darwin.md
substituteInPlace ./nixos-options.md \
--subst-var-by \
OPTIONS_JSON \
${home-manager-options.nixos}/share/doc/nixos/options.json
mdbook build source --dest-dir book
substituteInPlace ./nix-darwin-options.md \
--subst-var-by \
OPTIONS_JSON \
${home-manager-options.nix-darwin}/share/doc/nixos/options.json
mkdir -p out
cp -r book/* out/
cp ${./options.html} out/options.html
makeRedirect() {
local target=$1
local destination=$2
printf '%s\n' \
'<!doctype html>' \
'<html lang="en">' \
' <head>' \
' <meta charset="utf-8">' \
" <meta http-equiv=\"refresh\" content=\"0; url=$destination\">" \
" <link rel=\"canonical\" href=\"$destination\">" \
' <title>Redirecting...</title>' \
' </head>' \
' <body>' \
" <p>Redirecting to <a href=\"$destination\">$destination</a>.</p>" \
' </body>' \
'</html>' \
> "out/$target"
}
cp ${./static/style.css} out/style.css
cp ${./static/anchor-links.js} out/anchor-links.js
makeRedirect index.xhtml index.html
makeRedirect options.html options/home-manager/index.html
makeRedirect options.xhtml options/home-manager/index.html
makeRedirect nixos-options.xhtml options/nixos/index.html
makeRedirect nix-darwin-options.xhtml options/nix-darwin/index.html
makeRedirect release-notes.xhtml release-notes/release-notes.html
cp -r ${./release-notes} release-notes
runHook postBuild
nixos-render-docs manual html \
--manpage-urls ./manpage-urls.json \
--revision ${lib.trivial.revisionWithDefault revision} \
--stylesheet style.css \
--script highlightjs/highlight.pack.js \
--script highlightjs/loader.js \
--script anchor-links.js \
--toc-depth 1 \
--section-toc-depth 1 \
manual.md \
out/index.xhtml
'';
installPhase = ''
@@ -105,9 +69,7 @@ stdenv.mkDerivation {
echo "doc manual $dest index.html" >> $out/nix-support/hydra-build-products
'';
passthru = {
inherit home-manager-options mdbookOptions;
};
passthru = { inherit home-manager-options; };
meta = {
maintainers = [ lib.maintainers.considerate ];
+2 -7
View File
@@ -25,14 +25,9 @@ let
if [[ ! -v BROWSER || -z $BROWSER ]]; then
echo "$0: unable to start a web browser; please set \$BROWSER"
exit 1
else
exec "$BROWSER" "${html}/share/doc/${pathName}/index.xhtml"
fi
manualPath="${html}/share/doc/${pathName}/index.html"
if [[ ! -e $manualPath ]]; then
manualPath="${html}/share/doc/${pathName}/index.xhtml"
fi
exec "$BROWSER" "$manualPath"
'';
desktopItem = makeDesktopItem {
-64
View File
@@ -1,64 +0,0 @@
# Summary
- [Preface](preface.md)
- [Introduction to Home Manager](introduction.md)
- [Installing Home Manager](installation.md)
- [Standalone installation](installation/standalone.md)
- [NixOS module](installation/nixos.md)
- [nix-darwin module](installation/nix-darwin.md)
- [Using Home Manager](usage.md)
- [Configuration Example](usage/configuration.md)
- [Rollbacks](usage/rollbacks.md)
- [Keeping your ~ safe from harm](usage/dotfiles.md)
- [Graphical services](usage/graphical.md)
- [GPU on non-NixOS systems](usage/gpu-non-nixos.md)
- [Modular Services](usage/modular-services.md)
- [Updating](usage/updating.md)
- [Upgrading to a new Home Manager release](usage/upgrading.md)
- [Nix Flakes](nix-flakes.md)
- [Prerequisites](nix-flakes/prerequisites.md)
- [Standalone setup](nix-flakes/standalone.md)
- [NixOS module](nix-flakes/nixos.md)
- [nix-darwin module](nix-flakes/nix-darwin.md)
- [flake-parts module](nix-flakes/flake-parts.md)
- [Writing Home Manager Modules](writing-modules.md)
- [Option Types](writing-modules/types.md)
- [Contributing](contributing.md)
- [Getting started](contributing/getting-started.md)
- [Guidelines](contributing/guidelines.md)
- [Release Notes](contributing/release-notes.md)
- [News](contributing/news.md)
- [Tests](contributing/tests.md)
- [Home Manager Internals](internals.md)
- [Activation](internals/activation.md)
- [Third-Party Tools and Extensions](3rd-party.md)
- [Module Collections](3rd-party/collections.md)
- [Frequently Asked Questions (FAQ)](faq.md)
- [Why is there a collision error when switching generation?](faq/collision.md)
- [Why are the session variables not set?](faq/session-variables.md)
- [How to set up a configuration for multiple users/machines?](faq/multiple-users-machines.md)
- [Why do I get an error message about `ca.desrt.dconf` or `dconf.service`?](faq/ca-desrt-dconf.md)
- [How do I install packages from Nixpkgs unstable?](faq/unstable.md)
- [How do I change the package used by a module?](faq/change-package-module.md)
- [Options](options.md)
@HOME_MANAGER_OPTIONS@
@NIXOS_OPTIONS@
@NIX_DARWIN_OPTIONS@
- [Release Notes](release-notes/release-notes.md)
- [Release 26.11](release-notes/rl-2611.md)
- [Release 26.05](release-notes/rl-2605.md)
- [Release 25.11](release-notes/rl-2511.md)
- [Release 25.05](release-notes/rl-2505.md)
- [Release 24.11](release-notes/rl-2411.md)
- [Release 24.05](release-notes/rl-2405.md)
- [Release 23.11](release-notes/rl-2311.md)
- [Release 23.05](release-notes/rl-2305.md)
- [Release 22.11](release-notes/rl-2211.md)
- [Release 22.05](release-notes/rl-2205.md)
- [Release 21.11](release-notes/rl-2111.md)
- [Release 21.05](release-notes/rl-2105.md)
- [Release 20.09](release-notes/rl-2009.md)
- [Release 20.03](release-notes/rl-2003.md)
- [Release 19.09](release-notes/rl-1909.md)
- [Release 19.03](release-notes/rl-1903.md)
- [Release 18.09](release-notes/rl-1809.md)
-11
View File
@@ -1,11 +0,0 @@
[book]
title = "Home Manager Manual"
language = "en"
src = "."
[output.html]
git-repository-url = "https://github.com/nix-community/home-manager"
[output.html.fold]
enable = true
level = 0
-1
View File
@@ -22,7 +22,6 @@ configuration.
```{=include=} sections
contributing/getting-started.md
contributing/guidelines.md
contributing/release-notes.md
contributing/news.md
contributing/tests.md
```
+1 -40
View File
@@ -58,33 +58,6 @@ YAML, INI, TOML, or even a plain list of key/value pairs then consider
using a `settings` option as described in [Nix RFC
42](https://github.com/NixOS/rfcs/blob/master/rfcs/0042-config-option.md).
These guidelines describe the minimum option design requirements. Before
submitting a module, compare it against the upstream documentation or
source code and verify that the generated files, services, environment
variables, and command line arguments all match the upstream behavior
you intend to expose.
If a module installs a package, try to make the package option nullable,
for example
``` nix
package = lib.mkPackageOption pkgs "xdg-terminal-exec" { nullable = true; };
```
This lets users keep installation outside Home Manager, for example via
`apt` or because the program is built into macOS, while still using the
module for configuration. Keeping the package non-nullable is fine when
the enabled behavior structurally requires the executable or when
package-less support would make the module significantly more complex.
Avoid generating files for empty settings, null packages, or optional
features that are not configured.
If upstream does not use XDG paths by default but supports changing the
configuration location with an environment variable, for example
`FOO_HOME`, expose a `configDir` option and use it to respect
`home.preferXdgDirectories`.
## Add relevant tests {#sec-guidelines-add-tests}
If at all possible, make sure to add new tests and expand existing tests
@@ -108,7 +81,7 @@ Manager Git repository:
``` shell
$ nix-build -A docs.html
$ xdg-open ./result/share/doc/home-manager/index.html
$ xdg-open ./result/share/doc/home-manager/index.xhtml
```
When you have made changes to a module, it is a good idea to check that
@@ -186,13 +159,6 @@ formatted as described in [News](#sec-news).
When new modules are added a news entry should be included.
News entries and release notes serve different purposes. Release notes
should be updated separately when a change affects users migrating
between stable releases, such as state version default changes, required
migration steps, or broad behavior changes. See
[Release Notes](#sec-contributing-release-notes) and [News](#sec-news)
for more details.
## Use conditional modules and news {#sec-guidelines-conditional-modules}
Home Manager includes a number of modules that are only usable on some
@@ -228,11 +194,6 @@ that is, each commit should make sense in isolation. In particular, you
will be asked to amend any commit that introduces syntax errors or
similar problems even if they are fixed in a later commit.
Keep commits atomic and separated by concern. For example, a new
maintainer entry should be a separate first commit, and a shared module
should be committed separately from integrations in existing modules.
Pull requests should not include merge commits or fixup commits.
The commit messages should follow the [seven
rules](https://chris.beams.io/posts/git-commit/#seven-rules), except for
\"Capitalize the subject line\". We also ask you to include the affected
+3 -20
View File
@@ -6,17 +6,8 @@ associated news entry. In general, a news entry should only be added for
truly noteworthy news. For example, a bug fix or new option does
generally not need a news entry.
Release notes and news entries serve different purposes. A news entry is
shown during Home Manager activation and is useful for day-to-day
communication about noteworthy changes, such as a new module, a new
feature, or a specific deprecation. Release notes are read from the
website documentation and should summarize what users need to know before
or during a stable-release upgrade. See
[Release Notes](#sec-contributing-release-notes) for guidance on changes
that affect stable-release upgrades.
If you do have a change worthy of a news entry then please add one in
[`news`](https://github.com/nix-community/home-manager/blob/master/modules/misc/news)
[`news.nix`](https://github.com/nix-community/home-manager/blob/master/modules/misc/news.nix)
but you should follow some basic guidelines:
- Use the included news entry generator to create a news entry file:
@@ -37,8 +28,6 @@ but you should follow some basic guidelines:
- The entry condition should be as specific as possible. For example,
if you are changing or deprecating a specific option then you could
restrict the news to those users who actually use this option.
Prefer a targeted condition over skipping useful news only to avoid
notifying unaffected users.
- Wrap the news message so that it will fit in the typical terminal,
that is, at most 80 characters wide. Ideally a bit less.
@@ -64,10 +53,6 @@ but you should follow some basic guidelines:
A new module is available: 'services.foo'.
Since this news is specific to the module, its condition should use
the module enable option to avoid spamming non-users of the module,
for example `condition = config.services.foo.enable;`.
If the module is platform specific, e.g., a service module using
systemd, then a condition like
@@ -75,7 +60,5 @@ but you should follow some basic guidelines:
condition = hostPlatform.isLinux;
```
should be added, either by itself for platform-scoped news or in
combination with the module enable option. Use the `create-news-entry`
generator described above to scaffold this entry as part of your
contribution.
should be added. If you contribute a module then you don't need to
add this entry, the merger will create an entry for you.
-24
View File
@@ -1,24 +0,0 @@
# Release Notes {#sec-contributing-release-notes}
Home Manager release notes are published as part of the website documentation in
`docs/release-notes/rl-*.md`. They are intended for users migrating from one
stable release to another.
A change should be mentioned in the release notes when it affects migration
between stable releases. This includes changes that require user action or
awareness during an upgrade, such as:
- breaking changes;
- default changes guarded by `home.stateVersion`;
- required migration steps;
- broad behavior changes across platform or integration boundaries;
- compatibility changes that can affect existing configurations.
Do not use the presence or absence of a news entry to decide whether a change
belongs in the release notes. A change can require a news entry, a release note,
both, or neither.
When preparing a release, review the commits since the previous stable release
and update the upcoming release note file with the migration impact. Prefer
concise user-facing descriptions that name the affected option paths and explain
required action.
-13
View File
@@ -54,13 +54,6 @@ The `default.nix` file should list all test cases:
}
```
Prefer keeping related assertions in as few test files as practical.
Exercising several cases in one evaluation keeps the test suite cheaper
to evaluate and reduces maintenance burden. Split cases into separate
files when they need incompatible module configuration, platform
conditions, expected assertion failures, or otherwise cannot share one
evaluation.
### Common NMT Assertions {#sec-tests-assertions}
NMT provides several assertion functions:
@@ -169,12 +162,6 @@ For cross-platform modules that have packages which need to be stubbed on Darwin
add the package names to `tests/darwinScrublist.nix` to prevent build failures
during cross-platform test runs.
On Linux, packages are automatically scrubbed by the test infrastructure,
so tests should normally use the module's default package. Use
`test.stubs` or `config.lib.test.mkStubPackage` only when the automatic
scrubbing does not model the behavior that the test needs, such as a
package with additional files or a non-default executable layout.
## Using the tests command {#sec-tests-command}
Home Manager provides a convenient `tests` command for discovering and running tests:
+8 -59
View File
@@ -20,22 +20,10 @@ this package. This can typically be done in two ways.
{ pkgs, config, ... }:
let
pkgsUnstable = import <nixpkgs-unstable> {};
in
{
programs.beets.package = pkgsUnstable.beets;
# …
}
```
should work OK. With flakes, pass the unstable package set as
described in
[How do I install packages from Nixpkgs unstable?](#_how_do_i_install_packages_from_nixpkgs_unstable)
and then use the extra module argument:
``` nix
{ pkgsUnstable, ... }:
{
programs.beets.package = pkgsUnstable.beets;
@@ -44,7 +32,9 @@ this package. This can typically be done in two ways.
}
```
2. If no `package` option is available then you can typically change
should work OK.
3. If no `package` option is available then you can typically change
the relevant package using an
[overlay](https://nixos.org/nixpkgs/manual/#chap-overlays).
@@ -55,14 +45,16 @@ this package. This can typically be done in two ways.
{ pkgs, config, ... }:
let
pkgsUnstable = import <nixpkgs-unstable> {};
in
{
programs.skim.enable = true;
nixpkgs.overlays = [
(_final: _prev: {
(self: super: {
skim = pkgsUnstable.skim;
})
];
@@ -72,46 +64,3 @@ this package. This can typically be done in two ways.
```
should work OK.
The same Home Manager overlay works in a flake-based standalone
configuration if `pkgsUnstable` is passed to the Home Manager
module:
``` nix
{ pkgsUnstable, ... }:
{
programs.skim.enable = true;
nixpkgs.overlays = [
(_final: _prev: {
skim = pkgsUnstable.skim;
})
];
# …
}
```
This also works when Home Manager is used as a NixOS or nix-darwin
module without `home-manager.useGlobalPkgs = true`. If
`home-manager.useGlobalPkgs = true` is enabled, Home Manager uses
the system package set and the `nixpkgs.*` options inside Home
Manager are disabled. In that case, put the overlay in the system
configuration instead, for example:
``` nix
{ pkgsUnstable, ... }:
{
nixpkgs.overlays = [
(_final: _prev: {
skim = pkgsUnstable.skim;
})
];
}
```
In a flake-based NixOS or nix-darwin configuration, pass
`pkgsUnstable` to `nixosSystem` or `darwinSystem` with
`specialArgs`.
+7 -82
View File
@@ -3,20 +3,22 @@
If you are using a stable version of Nixpkgs but would like to install
some particular packages from Nixpkgs unstable -- or some other channel
-- then you can import the unstable Nixpkgs and refer to its packages
within your configuration.
With channels, something like
within your configuration. Something like
``` nix
{ pkgs, config, ... }:
let
pkgsUnstable = import <nixpkgs-unstable> {};
in
{
home.packages = [
pkgsUnstable.foo
];
# …
}
```
@@ -30,82 +32,5 @@ $ nix-channel --add https://nixos.org/channels/nixpkgs-unstable nixpkgs-unstable
$ nix-channel --update
```
With flakes, add another Nixpkgs input and pass its packages to your
Home Manager modules. For example, a standalone Home Manager flake can
define the following. Replace 25.11 with the release branch your
configuration follows.
``` nix
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11";
nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
home-manager.url = "github:nix-community/home-manager/release-25.11";
};
outputs =
{ nixpkgs, nixpkgs-unstable, home-manager, ... }:
let
# Replace this with the system of your Home Manager configuration.
system = "x86_64-linux";
pkgs = nixpkgs.legacyPackages.${system};
pkgsUnstable = nixpkgs-unstable.legacyPackages.${system};
in
{
homeConfigurations.jdoe = home-manager.lib.homeManagerConfiguration {
inherit pkgs;
extraSpecialArgs = { inherit pkgsUnstable; };
modules = [ ./home.nix ];
};
};
}
```
and then use the extra argument in `home.nix`:
``` nix
{ pkgsUnstable, ... }:
{
home.packages = [
pkgsUnstable.foo
];
}
```
When Home Manager is used as a NixOS or nix-darwin module, pass the
extra package set with `home-manager.extraSpecialArgs` in the system
configuration:
``` nix
outputs =
{ nixpkgs, nixpkgs-unstable, home-manager, ... }:
let
# Replace this with the system of your NixOS or nix-darwin configuration.
system = "x86_64-linux";
in
{
nixosConfigurations.hostname = nixpkgs.lib.nixosSystem {
inherit system;
modules = [
home-manager.nixosModules.home-manager
({ config, ... }: {
home-manager.extraSpecialArgs = {
pkgsUnstable = import nixpkgs-unstable {
inherit system;
config = config.nixpkgs.config;
overlays = config.nixpkgs.overlays;
};
# If you use a stock Nixpkgs configuration, you can use:
# pkgsUnstable = nixpkgs-unstable.legacyPackages.${system};
};
})
];
};
};
```
The nix-darwin setup is the same pattern with
`darwin.lib.darwinSystem` and
`home-manager.darwinModules.home-manager`.
Note, the package will not be affected by any package overrides,
overlays, etc.
+9 -9
View File
@@ -5,9 +5,9 @@ environments directly from the
[nix-darwin](https://github.com/nix-darwin/nix-darwin/) configuration file,
which often is more convenient than using the `home-manager` tool.
To make the nix-darwin module available for use you must `import` it
into your system configuration. This is most conveniently done by adding
a Home Manager channel. For example, if you are following Nixpkgs master
To make the NixOS module available for use you must `import` it into
your system configuration. This is most conveniently done by adding a
Home Manager channel. For example, if you are following Nixpkgs master
or an unstable channel, you can run
``` shell
@@ -15,10 +15,10 @@ $ nix-channel --add https://github.com/nix-community/home-manager/archive/master
$ nix-channel --update
```
and if you follow a Nixpkgs version 26.05 channel, you can run
and if you follow a Nixpkgs version 25.11 channel, you can run
``` shell
$ nix-channel --add https://github.com/nix-community/home-manager/archive/release-26.05.tar.gz home-manager
$ nix-channel --add https://github.com/nix-community/home-manager/archive/release-25.11.tar.gz home-manager
$ nix-channel --update
```
@@ -28,9 +28,9 @@ It is then possible to add
imports = [ <home-manager/nix-darwin> ];
```
to your nix-darwin `configuration.nix` file, which will introduce a
`home-manager.users` option whose type is an attribute set that maps
user names to Home Manager configurations.
to your nix-darwin `configuration.nix` file, which will introduce a new
NixOS option called `home-manager` whose type is an attribute set that
maps user names to Home Manager configurations.
For example, a nix-darwin configuration may include the lines
@@ -45,7 +45,7 @@ home-manager.users.eve = { pkgs, ... }: {
# The state version is required and should stay at the version you
# originally installed.
home.stateVersion = "26.05";
home.stateVersion = "25.11";
};
```
+6 -5
View File
@@ -17,10 +17,10 @@ $ sudo nix-channel --add https://github.com/nix-community/home-manager/archive/m
$ sudo nix-channel --update
```
and if you follow a Nixpkgs version 26.05 channel, you can run
and if you follow a Nixpkgs version 25.11 channel, you can run
``` shell
$ sudo nix-channel --add https://github.com/nix-community/home-manager/archive/release-26.05.tar.gz home-manager
$ sudo nix-channel --add https://github.com/nix-community/home-manager/archive/release-25.11.tar.gz home-manager
$ sudo nix-channel --update
```
@@ -39,7 +39,7 @@ Alternatively, home-manager installation can be done declaratively through confi
{ config, pkgs, lib, ... }:
let
home-manager = builtins.fetchTarball https://github.com/nix-community/home-manager/archive/release-26.05.tar.gz;
home-manager = builtins.fetchTarball https://github.com/nix-community/home-manager/archive/release-25.11.tar.gz;
in
{
imports =
@@ -54,7 +54,7 @@ in
# The state version is required and should stay at the version you
# originally installed.
home.stateVersion = "26.05";
home.stateVersion = "25.11";
};
}
```
@@ -74,7 +74,7 @@ home-manager.users.eve = { pkgs, ... }: {
# You should not change this value, even if you update Home Manager. If you do
# want to update the value, then make sure to first check the Home Manager
# release notes.
home.stateVersion = "26.05"; # Please read the comment before changing.
home.stateVersion = "25.11"; # Please read the comment before changing.
};
```
@@ -154,3 +154,4 @@ you create. This contains the system's NixOS configuration.
Once installed you can see [Using Home Manager](#ch-usage) for a more detailed
description of Home Manager and how to use it.
+2 -2
View File
@@ -19,10 +19,10 @@
$ nix-channel --update
```
and if you follow a Nixpkgs version 26.05 channel you can run
and if you follow a Nixpkgs version 25.11 channel you can run
``` shell
$ nix-channel --add https://github.com/nix-community/home-manager/archive/release-26.05.tar.gz home-manager
$ nix-channel --add https://github.com/nix-community/home-manager/archive/release-25.11.tar.gz home-manager
$ nix-channel --update
```
+1 -1
View File
@@ -1,6 +1,6 @@
# Home Manager Manual {#home-manager-manual}
## Version 26.11 (unstable)
## Version 26.05 (unstable)
```{=include=} preface
+6 -26
View File
@@ -20,32 +20,10 @@ flake in three ways:
`nixos-rebuild`. See [NixOS module](#sec-flakes-nixos-module) for a
description of this setup.
3. As a module within a [nix-darwin](https://github.com/nix-darwin/nix-darwin/)
system configuration. This allows the user profiles to be built
together with the system when running `darwin-rebuild`. See
[nix-darwin module](#sec-flakes-nix-darwin-module) for a
description of this setup.
Advanced users may want Home Manager's `nixpkgs` input to follow the
same Nixpkgs input as the rest of their flake. This avoids a second
Nixpkgs input and makes Home Manager use the same pinned Nixpkgs source
revision as the rest of the configuration:
``` nix
home-manager.inputs.nixpkgs.follows = "nixpkgs";
```
This removes the compatibility assumption between Home Manager and the
Nixpkgs revision in Home Manager's own lock file, so use it carefully,
especially when tracking unstable branches.
This does not by itself make Home Manager use the same `pkgs` value as
your NixOS or nix-darwin system. In NixOS and nix-darwin module setups,
`home-manager.useGlobalPkgs = true` controls that behavior by making
Home Manager modules receive the system `pkgs` value. When
`home-manager.useGlobalPkgs` is enabled, configure Nixpkgs overlays and
configuration at the system level instead of through Home Manager
`nixpkgs.*` options.
3. This allows the user profiles to be built together with the system
when running `darwin-rebuild`. See [nix-darwin
module](#sec-flakes-nix-darwin-module) for a description of this
setup.
```{=include=} sections
nix-flakes/prerequisites.md
@@ -54,3 +32,5 @@ nix-flakes/nixos.md
nix-flakes/nix-darwin.md
nix-flakes/flake-parts.md
```
+2 -1
View File
@@ -8,8 +8,9 @@ Manager's flake module, `flakeModules.home-manager`.
description = "flake-parts configuration";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
home-manager.url = "github:nix-community/home-manager";
home-manager.inputs.nixpkgs.follows = "nixpkgs";
flake-parts.url = "github:hercules-ci/flake-parts";
};
+6 -14
View File
@@ -8,10 +8,11 @@ to that of NixOS. The `flake.nix` would be:
description = "Darwin configuration";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
darwin.url = "github:nix-darwin/nix-darwin";
darwin.inputs.nixpkgs.follows = "nixpkgs";
home-manager.url = "github:nix-community/home-manager";
home-manager.inputs.nixpkgs.follows = "nixpkgs";
};
outputs = inputs@{ nixpkgs, home-manager, darwin, ... }: {
@@ -24,8 +25,10 @@ to that of NixOS. The `flake.nix` would be:
{
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.extraSpecialArgs = { inherit inputs; };
home-manager.users.jdoe = ./home.nix;
# Optionally, use home-manager.extraSpecialArgs to pass
# arguments to home.nix
}
];
};
@@ -34,19 +37,8 @@ to that of NixOS. The `flake.nix` would be:
}
```
Use `home-manager.extraSpecialArgs` to pass arguments from your flake to
`home.nix` and any imported Home Manager modules. For example, the
configuration above makes the complete `inputs` attrset available to modules,
so they can declare arguments such as `{ inputs, ... }:`.
The lower-level mechanism behind this is `_module.args`. Set
`_module.args.<name>` from inside a module only when you need to provide a
module argument from within the module graph itself. For values that originate
outside the module graph, such as flake inputs, prefer
`home-manager.extraSpecialArgs`.
and it is also rebuilt with the nix-darwin generations. The rebuild
command here may be `darwin-rebuild switch --flake ~/.config/darwin`.
command here may be `darwin-rebuild switch --flake <flake-uri>`.
You can use the above `flake.nix` as a template in `~/.config/darwin` by
+6 -17
View File
@@ -8,8 +8,9 @@ be as follows:
description = "NixOS configuration";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
home-manager.url = "github:nix-community/home-manager";
home-manager.inputs.nixpkgs.follows = "nixpkgs";
};
outputs = inputs@{ nixpkgs, home-manager, ... }: {
@@ -22,8 +23,10 @@ be as follows:
{
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.extraSpecialArgs = { inherit inputs; };
home-manager.users.jdoe = ./home.nix;
# Optionally, use home-manager.extraSpecialArgs to pass
# arguments to home.nix
}
];
};
@@ -32,24 +35,10 @@ be as follows:
}
```
Use `home-manager.extraSpecialArgs` to pass arguments from your flake to
`home.nix` and any imported Home Manager modules. For example, the
configuration above makes the complete `inputs` attrset available to modules,
so they can declare arguments such as `{ inputs, ... }:`.
The lower-level mechanism behind this is `_module.args`. Set
`_module.args.<name>` from inside a module only when you need to provide a
module argument from within the module graph itself. For values that originate
outside the module graph, such as flake inputs, prefer
`home-manager.extraSpecialArgs`.
The Home Manager configuration is then part of the NixOS configuration
and is automatically rebuilt with the system when using the appropriate
command for the system, such as
``` shell
$ nixos-rebuild switch --flake /etc/nixos
```
`nixos-rebuild switch --flake <flake-uri>`.
You can use the above `flake.nix` as a template in `/etc/nixos` by
+11 -39
View File
@@ -11,44 +11,15 @@ then to generate and activate a basic configuration run the command
$ nix run home-manager/master -- init --switch
```
For Nixpkgs or NixOS version 26.05 run
For Nixpkgs or NixOS version 25.11 run
``` shell
$ nix run home-manager/release-26.05 -- init --switch
$ nix run home-manager/release-25.11 -- init --switch
```
This will generate a `flake.nix` and a `home.nix` file in
`~/.config/home-manager`, creating the directory if it does not exist.
If you need to pass additional values from your flake to `home.nix` or any
imported Home Manager modules, use `extraSpecialArgs` in the call to
`home-manager.lib.homeManagerConfiguration`:
``` nix
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
home-manager.url = "github:nix-community/home-manager";
};
outputs = inputs@{ nixpkgs, home-manager, ... }: {
homeConfigurations.jdoe = home-manager.lib.homeManagerConfiguration {
pkgs = nixpkgs.legacyPackages.x86_64-linux;
extraSpecialArgs = { inherit inputs; };
modules = [ ./home.nix ];
};
};
}
```
Any attribute in `extraSpecialArgs` becomes a module argument, so `home.nix`
or imported modules can declare arguments such as `{ inputs, ... }:`.
The lower-level mechanism behind this is `_module.args`. Set
`_module.args.<name>` from inside a module only when you need to provide a
module argument from within the module graph itself. For values that originate
outside the module graph, such as flake inputs, prefer `extraSpecialArgs`.
If you omit the `--switch` option then the activation will not happen.
This is useful if you want to inspect and edit the configuration before
activating it.
@@ -59,7 +30,7 @@ $ # Edit files in ~/.config/home-manager
$ nix run home-manager/$branch -- init --switch
```
Where `$branch` is one of `master` or `release-26.05`.
Where `$branch` is one of `master` or `release-25.11`.
After the initial activation has completed successfully then building
and activating your flake-based configuration is as simple as
@@ -78,13 +49,14 @@ $ home-manager switch --flake ~/hmconf
```
::: {.note}
The flake inputs are not automatically updated by Home Manager. Update
the lock file with `nix flake update` before switching if you want to
use newer input revisions.
The flake inputs are not automatically updated by Home Manager. You need
to use the standard `nix flake update` command for that.
If you only want to update specific flake inputs, name them explicitly,
for example `nix flake update nixpkgs home-manager`.
If you only want to update a single flake input, then the command
`nix flake lock --update-input <input>` can be used.
These commands assume that your current directory is the flake. If not,
pass the flake path or URI with `--flake <flake-uri>`.
You can also pass flake-related options such as `--recreate-lock-file`
or `--update-input <input>` to `home-manager` when building or
switching, and these options will be forwarded to `nix build`. See the
[NixOS Wiki page](https://wiki.nixos.org/wiki/Flakes) for details.
:::
-1
View File
@@ -60,7 +60,6 @@ usage/rollbacks.md
usage/dotfiles.md
usage/graphical.md
usage/gpu-non-nixos.md
usage/modular-services.md
usage/updating.md
usage/upgrading.md
```
+2 -2
View File
@@ -20,7 +20,7 @@ A fresh install of Home Manager will generate a minimal
# You can update Home Manager without changing this value. See
# the Home Manager release notes for a list of state version
# changes in each release.
home.stateVersion = "26.05";
home.stateVersion = "25.11";
# Let Home Manager install and manage itself.
programs.home-manager.enable = true;
@@ -65,7 +65,7 @@ follows:
# You can update Home Manager without changing this value. See
# the Home Manager release notes for a list of state version
# changes in each release.
home.stateVersion = "26.05";
home.stateVersion = "25.11";
# Let Home Manager install and manage itself.
programs.home-manager.enable = true;
-133
View File
@@ -34,136 +34,3 @@ Activating checkLinkTargets
Existing file '/home/jdoe/.config/git/config' is in the way
Please move the above files and try again
```
This error is about a file that Home Manager wants to manage as a
symbolic link in your home directory. It is separate from package
profile collisions, which usually mention `installPackages` or a
`collision between .../bin/...` path. For package collisions, see
[Why is there a collision error when switching generation?](#_why_is_there_a_collision_error_when_switching_generation).
## Resolving file collisions {#sec-usage-dotfiles-collisions}
The safest resolution is to inspect the existing path, move any
settings you want Home Manager to manage into your configuration, and
remove or move the unmanaged file before switching again.
For a standalone Home Manager installation, you can ask Home Manager to
move unmanaged non-symlink paths out of the way during activation:
``` shell
home-manager switch -b backup
```
With the command above, a colliding `~/.config/git/config` is moved to
`~/.config/git/config.backup` before Home Manager links the managed
file. If the backup path already exists then activation still aborts, so
choose an extension whose backup path does not already exist.
Standalone activation can also run a custom command for each collision:
``` shell
home-manager switch -B trash-put
```
The command receives the colliding path as an argument and must move or
remove that path. If both `-B` and `-b` are set, the custom command takes
precedence; the command may still use the
`HOME_MANAGER_BACKUP_EXT` environment variable set by `-b`.
When Home Manager is used as a NixOS or nix-darwin module, configure the
corresponding module options instead of passing standalone command line
flags:
``` nix
{
home-manager.backupFileExtension = "backup";
}
```
or
``` nix
{
home-manager.backupCommand = "${pkgs.trash-cli}/bin/trash-put";
}
```
If both {option}`home-manager.backupCommand` and
{option}`home-manager.backupFileExtension` are set, the command takes
precedence. The extension is still exported to the command as
`HOME_MANAGER_BACKUP_EXT`, so the command can use it when implementing
its own backup naming. With
{option}`home-manager.backupFileExtension`, Home Manager refuses to
replace an existing backup path unless
{option}`home-manager.overwriteBackup` is enabled:
``` nix
{
home-manager.backupFileExtension = "backup";
home-manager.overwriteBackup = true;
}
```
::: {.warning}
{option}`home-manager.overwriteBackup` allows activation to clobber
existing backup files. Only enable it when those backup paths are
disposable.
:::
For individual files, many file options also support `force = true`:
``` nix
{
home.file.".config/example" = {
source = ./example;
force = true;
};
}
```
This skips the collision check for the affected target and lets Home
Manager replace the existing file or link. Use it sparingly; it can
silently delete local changes.
Backup commands and backup extensions are intended for unmanaged
non-symlink paths. If the colliding target is an unmanaged symbolic
link, move it manually or use `force = true` after checking that the
link target is safe to replace.
## Advanced file behavior {#sec-usage-dotfiles-advanced}
The notes below apply to {option}`home.file` and to options based on the
same file type, such as {option}`xdg.configFile`.
When a file source is a directory, {option}`home.file.<name>.recursive`
changes how the directory is linked. With the default `recursive =
false`, the target is one symbolic link to the source directory. With
`recursive = true`, Home Manager creates a matching directory tree and
links each leaf file into it.
Recursive directory linking has special overlap behavior. A direct
duplicate target, such as two managed files both targeting `foo`, is an
error. If a recursively linked directory provides `foo/bar` and another
managed file also targets `foo/bar`, Home Manager keeps the recursive
file by default and ignores the overlapping regular file.
The {option}`home.file.<name>.onChange` hook runs after the new files
are linked. For recursive file entries, the hook is always run, so it
should be written to be safe even when no leaf file actually changed.
Normally a path assigned to {option}`home.file.<name>.source` is copied
or linked through the Nix store. To make Home Manager create a link to a
live path outside the store, use
`config.lib.file.mkOutOfStoreSymlink`:
``` nix
{ config, ... }:
{
home.file.".config/example".source =
config.lib.file.mkOutOfStoreSymlink ./example;
}
```
This is useful when the target should follow changes to a mutable file
or directory outside the store.
+5 -6
View File
@@ -38,17 +38,16 @@ GPU drivers require an update, run
Because the `/run` directory is volatile and disappears on reboot, libraries
cannot be simply copied or linked there. The `non-nixos-gpu-setup` script
installs a
[`tmpfiles.d`](https://www.freedesktop.org/software/systemd/man/latest/tmpfiles.d.html)
config which ensures that the drivers are linked to `/run/opengl-driver` on
boot. Home Manager will always check and warn you when this setup needs to be
refreshed.
installs a Systemd service which ensures that the drivers are linked to
`/run/opengl-driver` on boot. Home Manager will always check and warn you when
this setup needs to be refreshed.
If you ever wish to uninstall these drivers, all you need to do is
```sh
sudo rm /run/opengl-driver
sudo rm /etc/tmpfiles.d/non-nixos-gpu.conf
sudo systemctl disable --now non-nixos-gpu.service
sudo rm /etc/systemd/system/non-nixos-gpu.service
```
-119
View File
@@ -1,119 +0,0 @@
# Modular Services {#sec-usage-modular-services}
Home Manager supports nixpkgs
[modular services](https://nixos.org/manual/nixos/unstable/#modular-services)
under [](#opt-home.services). This is the Home Manager analog to the
NixOS `system.services` namespace: each entry is an abstract service
sourced from `<nixpkgs/lib/services/lib.nix>` with the upstream portable
systemd module loaded into it, so service modules shipped with packages
(e.g. `pkgs.<name>.passthru.services.default`) drop in unchanged --
the same module evaluates on NixOS and on Home Manager.
A minimal example -- run mpd as a user service:
```nix
{ pkgs, ... }: {
home.services.mpd = {
process.argv = [ "${pkgs.mpd}/bin/mpd" "--no-daemon" ];
};
}
```
This produces `~/.config/systemd/user/mpd.service` with `ExecStart` set
to the mpd binary and `WantedBy=default.target`.
Each service exposes the upstream NixOS-style schema: [`process.argv`],
`systemd.lib`, `systemd.mainExecStart`, `systemd.service`,
`systemd.services`, `systemd.sockets`. Lifted units are translated from
NixOS-style attrs (`wantedBy`, `serviceConfig`, `unitConfig`,
`environment`, ...) into the section-based INI shape
(`{ Unit; Service; Install; }`) that Home Manager's
[](#opt-systemd.user.services) consumes. Only common keys are mapped
explicitly; uncommon options remain reachable via `unitConfig`,
`serviceConfig`, or `socketConfig`.
Sub-services (nested `services.<sub>` inside another service) and their
units are dashed under the parent service name. The empty unit key
`""` denotes the service's *primary* unit (lifted to a unit named
after the service itself); [`process.argv`] becomes the default
`ExecStart` for that unit, which defaults to `WantedBy=default.target`.
## Reusing upstream package modules {#sec-usage-modular-services-upstream}
Modular services exposed by packages under
`pkgs.<name>.passthru.services.default` can be imported directly.
For example, `pkgs.php`'s [`php-fpm`]:
```nix
{ pkgs, ... }: {
home.services."php-fpm" = {
imports = [ pkgs.php.passthru.services.default ];
configData."php-fpm.conf".source = builtins.elemAt config.home.services.php-fpm.process.argv 2;
php-fpm.settings.mypool = {
listen = "127.0.0.1:9000";
# FIXME: required by upstream modular service, but ignored when run as user
"user" = "";
"pm" = "dynamic";
"pm.max_children" = 75;
"pm.min_spare_servers" = 5;
"pm.max_spare_servers" = 20;
};
};
}
```
Some packages ship modules written for system services that include
directives the user-session manager cannot honour (`DynamicUser`,
`AmbientCapabilities`, ...). The unit is still generated with those
directives -- user systemd silently ignores what it cannot apply.
`WantedBy=multi-user.target` is automatically normalized to
`WantedBy=default.target`. Other directives can be overridden per
service:
```nix
home.services."tunnel" = {
imports = [ pkgs.ghostunnel.passthru.services.default ];
# ...
systemd.services."tunnel".serviceConfig.DynamicUser = lib.mkForce false;
};
```
## Configuration data {#sec-usage-modular-services-configdata}
Each service can declare configuration files via `configData.<name>`.
These are materialized at `$XDG_CONFIG_HOME/home-services/<service>/<name>`
(mirroring how NixOS lifts `configData` to `environment.etc`), with the
absolute path injected back into `configData.<name>.path` so the service
can refer to its files at a stable location:
```nix
{ config, ... }:
{
home.services.demo = {
process.argv = [ "/bin/myapp" "--config" config.home.services.demo.configData."app.toml".path ];
configData."app.toml".text = ''
port = 1234
'';
};
}
```
The store paths of all enabled `configData` entries are automatically
added to the primary unit's `X-Reload-Triggers`, so `home-manager switch`
restarts the service whenever any of its configuration files change. To
reload instead of restart, override `X-SwitchMethod`:
```nix
home.services.demo.systemd.services."".unitConfig.X-SwitchMethod = "reload";
```
## Scope notes {#sec-usage-modular-services-scope}
Home Manager mirrors the surface of nixpkgs' portable systemd module:
services and sockets only. Other unit kinds Home Manager supports
natively under [](#opt-systemd.user.services) (timers, paths, mounts, ...)
are intentionally not modeled on `home.services` until upstream grows them,
to keep both surfaces aligned.
[`process.argv`]: https://nixos.org/manual/nixos/unstable/#service-opt-process.argv
[`php-fpm`]: https://nixos.org/manual/nixos/stable/options#opt-_imports_=___pkgs.php.services.default___
+3 -75
View File
@@ -1,64 +1,8 @@
# Updating {#sec-updating}
Updating means moving to a newer revision of the Home Manager branch
that your configuration already follows. For example, a configuration
using `release-25.11` can update to a newer revision of `release-25.11`
without changing release branches.
If you want to move from one release branch to another, such as
`release-25.05` to `release-25.11`, or between a release branch and
`master`, see
[Upgrading to a new Home Manager release](#sec-upgrade-release).
## Flake-Based Configurations {#sec-updating-flakes}
Flake inputs are pinned in `flake.lock`, and Home Manager will keep using
the pinned revisions until you update that lock file.
To update all inputs in the flake:
``` shell
$ nix flake update
```
To update only specific inputs, name them explicitly:
``` shell
$ nix flake update home-manager nixpkgs
```
These commands assume that your current directory is the flake. If not,
pass the flake path or URI with `--flake <flake-uri>`.
After updating the lock file, rebuild with the command for your
installation method.
For a standalone Home Manager flake:
``` shell
$ home-manager switch --flake .
```
For Home Manager as a NixOS module:
``` shell
$ sudo nixos-rebuild switch --flake .
```
For Home Manager as a nix-darwin module:
``` shell
$ darwin-rebuild switch --flake .
```
## Channel-Based Configurations {#sec-updating-channels}
Channels are mutable references outside the Home Manager configuration
itself. Updating a channel moves it to a newer revision of the same
channel or branch.
For a standalone Home Manager channel installation, update the user's
channels and then switch:
If you have installed Home Manager using the Nix channel method then
updating Home Manager is done by first updating the channel. You can
then switch to the updated Home Manager environment.
``` shell
$ nix-channel --update
@@ -66,19 +10,3 @@ $ nix-channel --update
unpacking channels...
$ home-manager switch
```
For Home Manager as a NixOS module, update the root user's Home Manager
channel and rebuild the system:
``` shell
$ sudo nix-channel --update home-manager
$ sudo nixos-rebuild switch
```
For Home Manager as a nix-darwin module, update the Home Manager channel
used by your nix-darwin configuration and rebuild the system:
``` shell
$ nix-channel --update home-manager
$ darwin-rebuild switch
```
+58 -112
View File
@@ -2,47 +2,66 @@
## Overview {#sec-upgrade-release-overview}
When moving your configuration to a new Nixpkgs release branch, you
should also move Home Manager to the matching release branch. On NixOS
this usually means upgrading Home Manager together with NixOS. On
standalone and nix-darwin installations, match Home Manager to the
Nixpkgs branch used by your configuration. The examples below use 25.11;
replace this with the release branch you are upgrading to.
If your configuration follows `nixos-unstable` or `nixpkgs-unstable`,
use Home Manager's `master` branch.
When upgrading NixOS to a new major version (e.g., from 24.11 to
25.05), you also need to upgrade your Home Manager channel to maintain
compatibility. This guide covers the proper steps to upgrade Home
Manager channels for NixOS 25.05.
## Understanding Home Manager Versioning {#sec-upgrade-release-understanding-versioning}
Home Manager follows NixOS release cycles and provides corresponding branches:
- **release-\<version\>**: Stable branch for the matching NixOS or
Nixpkgs release, such as `release-25.11`.
- **release-##.##**: Stable branch for NixOS ##.## (current stable)
- **master**: Development branch (tracks nixpkgs-unstable)
- **master**: Development branch (tracks nixos-unstable)
:::{.note}
Use the Home Manager branch that matches the Nixpkgs branch used to
evaluate your Home Manager configuration. For stable NixOS
configurations, this is normally the same as your NixOS version.
Always use the Home Manager version that matches your NixOS version to
avoid compatibility issues.
:::
## Flake-Based Installation {#sec-upgrade-release-understanding-flake}
## Channel-Based Installation (Traditional) {#sec-upgrade-release-understanding-channel}
If you are using Home Manager with Nix flakes, update your `nixpkgs` and
`home-manager` inputs together:
1. First, verify your current Home Manager channel:
``` shell
$ nix-channel --list
```
You should see something like:
```
home-manager https://github.com/nix-community/home-manager/archive/release-24.11.tar.gz
```
1. Update the Home Manager channel to a NixOS 25.05 compatible version:
``` shell
$ nix-channel --add https://github.com/nix-community/home-manager/archive/release-25.05.tar.gz home-manager
$ nix-channel --update
```
1. Apply the changes:
``` shell
$ home-manager switch
```
## Flake-Based Installation (Modern) {#sec-upgrade-release-understanding-flake}
If you're using Home Manager with Nix flakes, update your `flake.nix`:
```nix
{
description = "Home Manager configuration";
inputs = {
# Match the Nixpkgs branch to the release you are using.
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11";
# Increment release branch for NixOS
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
home-manager = {
# Match the Home Manager branch to the Nixpkgs branch above.
url = "github:nix-community/home-manager/release-25.11";
# Follow corresponding `release` branch from Home Manager
url = "github:nix-community/home-manager/release-25.05";
inputs.nixpkgs.follows = "nixpkgs";
};
};
@@ -55,115 +74,44 @@ If you are using Home Manager with Nix flakes, update your `nixpkgs` and
}
```
For `nixos-unstable` or `nixpkgs-unstable`, use the `master` branch
instead:
```nix
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
home-manager = {
url = "github:nix-community/home-manager";
};
};
}
```
Then update the lock file and rebuild using the command for your
installation method.
For a standalone Home Manager flake:
Then update and rebuild. If you are using Home Manager standalone:
``` shell
$ nix flake update
$ home-manager switch --flake .
```
For Home Manager as a NixOS module:
And if you are using Home Manager as a NixOS module then you will need
to update your system configuration instead and run
``` shell
$ nix flake update
$ sudo nixos-rebuild switch --flake .
```
For Home Manager as a nix-darwin module:
``` shell
$ nix flake update
$ darwin-rebuild switch --flake .
```
These commands assume that your current directory is the flake. If not,
pass the flake path or URI with `--flake <flake-uri>`.
## Channel-Based Installation {#sec-upgrade-release-understanding-channel}
For a standalone channel-based installation, first verify your current
Home Manager channel:
``` shell
$ nix-channel --list
```
The entry identifies the Home Manager branch currently in use. For
example:
```
home-manager https://github.com/nix-community/home-manager/archive/release-25.11.tar.gz
```
Update the Home Manager channel to the branch matching your Nixpkgs
release, then switch:
``` shell
$ nix-channel --add https://github.com/nix-community/home-manager/archive/release-25.11.tar.gz home-manager
$ nix-channel --update
$ home-manager switch
```
When Home Manager is installed as a NixOS module with channels, update
the root user's Home Manager channel and rebuild the system:
``` shell
$ sudo nix-channel --add https://github.com/nix-community/home-manager/archive/release-25.11.tar.gz home-manager
$ sudo nix-channel --update
$ sudo nixos-rebuild switch
```
When Home Manager is installed as a nix-darwin module with channels,
update the Home Manager channel used by your nix-darwin configuration
and rebuild the system:
``` shell
$ nix-channel --add https://github.com/nix-community/home-manager/archive/release-25.11.tar.gz home-manager
$ nix-channel --update
$ darwin-rebuild switch
```
## State Version Management {#sec-upgrade-release-state-version}
:::{.warning}
Careful updating your `home.stateVersion` when upgrading Home Manager.
:::
The `stateVersion` should remain set to the Home Manager release you
first used for this home configuration.
The `stateVersion` is best to remain set to the NixOS version you
**first installed** Home Manager
```nix
{
# Example: if this home configuration was first created on 24.11.
home.stateVersion = "24.11";
home.stateVersion = "24.11"; # Example: if you first installed on 24.11
}
```
**Why?** The `stateVersion` ensures backward compatibility and
prevents breaking changes from affecting your existing configuration.
**Remember:** Channel or flake input version is not the same as state
version. Update Home Manager, keep `home.stateVersion` unchanged, and
only change it after reading the release notes and migrating any
affected configuration.
**Remember:** Channel version is not the same as State version. Update
the channel, keep the `stateVersion` unchanged. Advanced users can
view the changes between releases and see if any of the `stateVersion`
changes will affect them and increment, if they migrate their
configurations to follow the changed evaluation.
## Troubleshooting {#sec-upgrade-release-state-troubleshooting}
@@ -172,9 +120,8 @@ affected configuration.
Check the [Home Manager Release Notes](#ch-release-notes) for breaking changes.
1. **Version Mismatch Warning**: If you see warnings about version
mismatches, ensure your Home Manager branch matches the Nixpkgs
branch used by your configuration. For NixOS stable releases, this
usually means matching your NixOS version.
mismatches, ensure your Home Manager version matches your NixOS
version.
1. **Module Changes**: Modules are constantly being updated with new
features to keep up with changes in upstream packaging or to fix
@@ -182,8 +129,8 @@ Check the [Home Manager Release Notes](#ch-release-notes) for breaking changes.
there was something noted in the release notes or news entries.
1. **Channel Not Found**: If `nix-channel --list` shows no channels,
you might be using a different installation method, such as flakes,
or Home Manager may be imported through your system configuration.
you might be using a different installation method (like flakes or
NixOS module).
### Verification {#sec-upgrade-release-state-troubleshooting-verification}
@@ -193,8 +140,7 @@ After upgrading, verify the installation:
$ home-manager --version
```
This should show the Home Manager version or indicate that it is using
the expected release branch.
This should show version 25.05 or indicate it's using the release-25.05 branch.
## Additional Resources {#sec-upgrade-release-resources}
+1 -1
View File
@@ -4,7 +4,7 @@ Overall the basic option types are the same in Home Manager as NixOS. A
few Home Manager options, however, make use of custom types that are
worth describing in more detail. These are the option types `dagOf` and
`gvariant` that are used, for example, by
[programs.ssh.settings](#opt-programs.ssh.settings) and [dconf.settings](#opt-dconf.settings).
[programs.ssh.matchBlocks](#opt-programs.ssh.matchBlocks) and [dconf.settings](#opt-dconf.settings).
[]{#sec-option-types-dag}`hm.types.dagOf`
-231
View File
@@ -1,231 +0,0 @@
#!/usr/bin/env python3
from __future__ import annotations
import argparse
import html
import re
import shutil
import sys
from pathlib import Path
SIMPLE_ROLES = (
"command",
"component",
"description",
"file",
"index",
"system",
"type",
)
HEADING_ANCHOR = re.compile(r"^(#{1,6}\s+)(.*)\s+\{#([^}]+)\}\s*$")
INLINE_ANCHOR = re.compile(r"\[\]\{#([^}]+)\}")
OPTION_ROLE = re.compile(r"(?<![$`])\{option\}`([^`]*)`")
SIMPLE_ROLE = re.compile(r"(?<![$`])\{(" + "|".join(SIMPLE_ROLES) + r")\}`([^`]*)`")
OPTION_LINK = re.compile(
r"\[(?P<label>[^\]]*)\]\(#(?P<anchor>(?:opt|nixos-opt|nix-darwin-opt)-[^)]+)\)"
)
LEFTOVER_ROLE = re.compile(
r"(?<![$`])\{(" + "|".join(("option", *SIMPLE_ROLES)) + r")\}`[^`]*`"
)
FENCE = re.compile(r"^\s*(`{3,})(.*)$")
FENCE_CLOSE = re.compile(r"^\s*`{3,}\s*$")
ADMONITION_OPEN = re.compile(r"^\s*:::\s*\{\.(note|warning|example)\}\s*$")
ADMONITION_CLOSE = re.compile(r"^\s*:::\s*$")
DEEP_SPLIT_NAMESPACES = {"programs", "services"}
def option_target(anchor: str, current_file: Path, base_depth: int) -> str:
if anchor.startswith("nix-darwin-opt-"):
option = anchor.removeprefix("nix-darwin-opt-")
option = option.replace("<", "_").replace(">", "_")
anchor = f"nix-darwin-opt-{option}"
base = "options/nix-darwin"
elif anchor.startswith("nixos-opt-"):
option = anchor.removeprefix("nixos-opt-")
option = option.replace("<", "_").replace(">", "_")
anchor = f"nixos-opt-{option}"
base = "options/nixos"
else:
option = anchor.removeprefix("opt-")
option = option.replace("<", "_").replace(">", "_")
anchor = f"opt-{option}"
base = "options/home-manager"
page_parts = option_page_parts(option)
prefix = "../" * (base_depth + len(current_file.parent.parts))
return f"{prefix}{base}/{'/'.join(page_parts)}.md#{anchor}"
def option_page_parts(option_name: str) -> list[str]:
parts = option_name.split(".")
namespace = parts[0]
if namespace in DEEP_SPLIT_NAMESPACES and len(parts) > 1:
return parts[:2]
return [namespace]
def option_label(anchor: str) -> str:
if anchor.startswith("nix-darwin-opt-"):
return anchor.removeprefix("nix-darwin-opt-")
if anchor.startswith("nixos-opt-"):
return anchor.removeprefix("nixos-opt-")
return anchor.removeprefix("opt-")
def markdown_label(value: str) -> str:
return value.replace("<", "&lt;").replace(">", "&gt;")
def convert_inline(line: str, current_file: Path, base_depth: int) -> str:
line = line.replace("index.xhtml", "index.html")
line = INLINE_ANCHOR.sub(
lambda match: f'<a id="{html.escape(match.group(1), quote=True)}"></a>',
line,
)
line = OPTION_ROLE.sub(
lambda match: (
f"[{markdown_label(match.group(1))}]"
f"({option_target(f'opt-{match.group(1)}', current_file, base_depth)})"
),
line,
)
line = OPTION_LINK.sub(
lambda match: (
f"[{markdown_label(match.group('label') or option_label(match.group('anchor')))}]"
f"({option_target(match.group('anchor'), current_file, base_depth)})"
),
line,
)
return SIMPLE_ROLE.sub(lambda match: f"`{match.group(2)}`", line)
def convert_heading(line: str, current_file: Path, base_depth: int) -> str:
match = HEADING_ANCHOR.match(line)
if match is None:
return convert_inline(line, current_file, base_depth)
prefix, title, anchor = match.groups()
return (
f'<a id="{html.escape(anchor, quote=True)}"></a>\n'
f"{prefix}{convert_inline(title, current_file, base_depth)}"
)
def is_include_fence(line: str) -> tuple[bool, str]:
match = FENCE.match(line)
if match is None:
return False, ""
info = match.group(2).strip()
return info.startswith(("{=include=}", "include")), match.group(1)
def convert_markdown(
text: str,
source: Path,
current_file: Path,
base_depth: int,
) -> str:
output: list[str] = []
in_code_fence = False
code_fence = ""
in_include = False
include_fence = ""
in_admonition = False
for raw_line in text.splitlines(keepends=True):
line = raw_line[:-1] if raw_line.endswith("\n") else raw_line
newline = "\n" if raw_line.endswith("\n") else ""
if in_include:
if FENCE_CLOSE.match(line) and len(line.strip()) >= len(include_fence):
in_include = False
include_fence = ""
continue
if in_code_fence:
output.append(raw_line)
if FENCE_CLOSE.match(line) and len(line.strip()) >= len(code_fence):
in_code_fence = False
code_fence = ""
continue
include, fence = is_include_fence(line)
if include:
in_include = True
include_fence = fence
continue
fence_match = FENCE.match(line)
if fence_match is not None:
in_code_fence = True
code_fence = fence_match.group(1)
output.append(raw_line)
continue
if in_admonition:
if ADMONITION_CLOSE.match(line):
in_admonition = False
continue
converted = convert_inline(line, current_file, base_depth)
output.append(f"> {converted}{newline}" if converted else ">\n")
continue
admonition = ADMONITION_OPEN.match(line)
if admonition is not None:
in_admonition = True
output.append(f"> **{admonition.group(1).title()}**\n")
continue
output.append(convert_heading(line, current_file, base_depth) + newline)
if in_include:
raise ValueError(f"{source}: unterminated include block")
converted = "".join(output)
if LEFTOVER_ROLE.search(converted):
raise ValueError(f"{source}: unconverted NixOS-render-docs role remains")
if "```{=include=}" in converted:
raise ValueError(f"{source}: unconverted include block remains")
return converted
def convert_tree(source: Path, destination: Path, base_depth: int) -> None:
for path in source.rglob("*"):
if not path.is_file():
continue
target = destination / path.relative_to(source)
target.parent.mkdir(parents=True, exist_ok=True)
if path.suffix == ".md":
text = path.read_text(encoding="utf-8")
target.write_text(
convert_markdown(text, path, path.relative_to(source), base_depth),
encoding="utf-8",
)
else:
shutil.copy2(path, target)
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--base-depth", type=int, default=0)
parser.add_argument("source", type=Path)
parser.add_argument("destination", type=Path)
args = parser.parse_args()
if not args.source.is_dir():
print(f"missing source directory: {args.source}", file=sys.stderr)
return 1
args.destination.mkdir(parents=True, exist_ok=True)
convert_tree(args.source, args.destination, args.base_depth)
return 0
if __name__ == "__main__":
raise SystemExit(main())
-23
View File
@@ -1,23 +0,0 @@
{
pkgs,
optionDocs,
manpageUrls,
revision,
}:
pkgs.runCommand "home-manager-mdbook-options"
{
nativeBuildInputs = [
pkgs.buildPackages.nixos-render-docs
pkgs.buildPackages.python3
];
optionDocsJson = builtins.toJSON optionDocs;
passAsFile = [ "optionDocsJson" ];
}
''
python3 ${./render-options.py} \
"$optionDocsJsonPath" \
${manpageUrls} \
${revision} \
"$out"
''
-221
View File
@@ -1,221 +0,0 @@
#!/usr/bin/env python3
from __future__ import annotations
import json
import re
import subprocess
import sys
from pathlib import Path
OPTION_LINK = re.compile(
r"\[(?P<label>[^\]]*)\]\(#(?P<anchor>(?:opt|nixos-opt|nix-darwin-opt)-[^)]+)\)"
)
OPTION_HREF = re.compile(r'href="#(?P<anchor>(?:opt|nixos-opt|nix-darwin-opt)-[^"]+)"')
DEEP_SPLIT_NAMESPACES = {"programs", "services"}
def option_label(anchor: str) -> str:
if anchor.startswith("nix-darwin-opt-"):
return anchor.removeprefix("nix-darwin-opt-")
if anchor.startswith("nixos-opt-"):
return anchor.removeprefix("nixos-opt-")
return anchor.removeprefix("opt-")
def option_target(anchor: str, current_file: Path) -> str:
if anchor.startswith("nix-darwin-opt-"):
option = anchor.removeprefix("nix-darwin-opt-")
base = "options/nix-darwin"
elif anchor.startswith("nixos-opt-"):
option = anchor.removeprefix("nixos-opt-")
base = "options/nixos"
else:
option = anchor.removeprefix("opt-")
base = "options/home-manager"
page_parts = option_page_parts(option)
prefix = "../" * len(current_file.parent.parts)
return f"{prefix}{base}/{'/'.join(page_parts)}.md#{anchor}"
def rewrite_option_links(text: str, current_file: Path) -> str:
text = OPTION_LINK.sub(
lambda match: (
f"[{match.group('label') or option_label(match.group('anchor'))}]"
f"({option_target(match.group('anchor'), current_file)})"
),
text,
)
return OPTION_HREF.sub(
lambda match: f'href="{option_target(match.group("anchor"), current_file)}"',
text,
)
def namespace_for(option_name: str) -> str:
return option_name.split(".", 1)[0]
def option_page_parts(option_name: str) -> list[str]:
parts = option_name.split(".")
namespace = parts[0]
if namespace in DEEP_SPLIT_NAMESPACES and len(parts) > 1:
return parts[:2]
return [namespace]
def option_group_for(option_name: str) -> str:
return "/".join(option_page_parts(option_name))
def render_namespace(
options: dict[str, object],
destination: Path,
manpage_urls: Path,
revision: str,
anchor_prefix: str,
current_file: Path,
) -> None:
destination.parent.mkdir(parents=True, exist_ok=True)
source = destination.with_suffix(".json")
source.write_text(json.dumps(options, sort_keys=True), encoding="utf-8")
subprocess.run(
[
"nixos-render-docs",
"options",
"commonmark",
"--manpage-urls",
str(manpage_urls),
"--revision",
revision,
"--anchor-style",
"legacy",
"--anchor-prefix",
anchor_prefix,
str(source),
str(destination),
],
check=True,
)
source.unlink()
destination.write_text(
rewrite_option_links(destination.read_text(encoding="utf-8"), current_file),
encoding="utf-8",
)
def write_doc(
name: str,
doc: dict[str, str],
manpage_urls: Path,
revision: str,
output: Path,
) -> None:
options_json = Path(doc["json"]) / "share/doc/nixos/options.json"
options = json.loads(options_json.read_text(encoding="utf-8"))
grouped: dict[str, dict[str, object]] = {}
for option_name, option in options.items():
group = option_group_for(option_name)
grouped.setdefault(group, {})[option_name] = option
doc_dir = output / "options" / doc["path"]
doc_dir.mkdir(parents=True, exist_ok=True)
groups = sorted(grouped)
namespaces = sorted({group.split("/", 1)[0] for group in groups})
nested = {
namespace: sorted(
group for group in groups if group.startswith(f"{namespace}/")
)
for namespace in namespaces
}
index = [
f"# {doc['title']}\n",
"\n",
"Generated from Home Manager option definitions.\n",
"\n",
"## Namespaces\n",
"\n",
]
for namespace in namespaces:
if nested[namespace]:
index.append(f"- [{namespace}]({namespace}/index.md)\n")
else:
index.append(f"- [{namespace}]({namespace}.md)\n")
(doc_dir / "index.md").write_text("".join(index), encoding="utf-8")
summary_dir = output / "summary"
summary_dir.mkdir(parents=True, exist_ok=True)
summary = [f" - [{doc['title']}](options/{doc['path']}/index.md)\n"]
for namespace in namespaces:
if nested[namespace]:
namespace_index = doc_dir / namespace / "index.md"
namespace_index.parent.mkdir(parents=True, exist_ok=True)
namespace_index.write_text(
"".join(
[
f"# {namespace}\n",
"\n",
"## Modules\n",
"\n",
*(
f"- [{group.split('/', 1)[1]}]({group.split('/', 1)[1]}.md)\n"
for group in nested[namespace]
),
]
),
encoding="utf-8",
)
summary.append(
f" - [{namespace}](options/{doc['path']}/{namespace}/index.md)\n"
)
for group in nested[namespace]:
module_name = group.split("/", 1)[1]
summary.append(
f" - [{module_name}](options/{doc['path']}/{namespace}/{module_name}.md)\n"
)
else:
summary.append(
f" - [{namespace}](options/{doc['path']}/{namespace}.md)\n"
)
for group in groups:
page = doc_dir / f"{group}.md"
current_file = Path("options") / doc["path"] / f"{group}.md"
render_namespace(
grouped[group],
page,
manpage_urls,
revision,
doc["prefix"],
current_file,
)
(summary_dir / f"{name}.md").write_text("".join(summary), encoding="utf-8")
def main() -> int:
if len(sys.argv) != 5:
print(
"usage: render-options.py OPTION_DOCS MANPAGE_URLS REVISION OUT",
file=sys.stderr,
)
return 1
option_docs = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8"))
manpage_urls = Path(sys.argv[2])
revision = sys.argv[3]
output = Path(sys.argv[4])
for name, doc in option_docs.items():
write_doc(name, doc, manpage_urls, revision, output)
return 0
if __name__ == "__main__":
raise SystemExit(main())
-32
View File
@@ -1,32 +0,0 @@
#!/usr/bin/env python3
from __future__ import annotations
import sys
from pathlib import Path
def main() -> int:
if len(sys.argv) != 5:
print(
"usage: substitute-summary.py SUMMARY HM_SUMMARY NIXOS_SUMMARY DARWIN_SUMMARY",
file=sys.stderr,
)
return 1
summary = Path(sys.argv[1])
replacements = {
"@HOME_MANAGER_OPTIONS@": Path(sys.argv[2]).read_text(encoding="utf-8"),
"@NIXOS_OPTIONS@": Path(sys.argv[3]).read_text(encoding="utf-8"),
"@NIX_DARWIN_OPTIONS@": Path(sys.argv[4]).read_text(encoding="utf-8"),
}
text = summary.read_text(encoding="utf-8")
for needle, replacement in replacements.items():
text = text.replace(needle, replacement.rstrip())
summary.write_text(text, encoding="utf-8")
return 0
if __name__ == "__main__":
raise SystemExit(main())
+2 -3
View File
@@ -1,10 +1,9 @@
# Release Notes {#ch-release-notes}
This section lists the release notes for stable versions of Home Manager and the
current unstable version.
This section lists the release notes for stable versions of Home Manager
and the current unstable version.
```{=include=} chapters
rl-2611.md
rl-2605.md
rl-2511.md
rl-2505.md
+1 -1
View File
@@ -71,7 +71,7 @@ This release has the following notable changes:
no longer packages compton, and instead packages the (mostly)
compatible fork called picom.
- The list form of the `programs.ssh.matchBlocks` option has
- The list form of the [programs.ssh.matchBlocks](#opt-programs.ssh.matchBlocks) option has
been deprecated and configurations requiring match blocks in a
defined order should switch to using DAG entries instead. For
example, a configuration
+27 -161
View File
@@ -1,146 +1,40 @@
# Release 26.05 {#sec-release-26.05}
The 26.05 release branch became stable in May, 2026.
This is the current unstable branch and the information in this
section is therefore not final.
## Highlights {#sec-release-26.05-highlights}
This release has the following notable changes:
- Home Manager now supports RFC 42-style SSH configuration through
[](#opt-programs.ssh.settings). The legacy `programs.ssh.matchBlocks` format
is deprecated and migrated automatically.
- The new `home-manager.startAsUserService` option runs user activation on
demand at login instead of doing all setup during system boot, which helps on
systems where home directories are mounted later (for example, pam_mount).
- New options were added for `services.podman.useDefaultMachine` and podman
machine management on Darwin.
- The [](#opt-programs.rclone.enable) module now supports launchd-backed config,
mount, and serve agents on Darwin. The new
`programs.rclone.remotes.<name>.serve` option can manage `rclone serve`
sidecar services on both Linux and Darwin. On non-systemd platforms,
`programs.rclone.requiresUnit` is read-only and always `null` because there is
no systemd ordering unit to depend on.
- The Syncthing credentials flow now uses `services.syncthing.guiCredentials`
instead of the removed `services.syncthing.passwordFile` option.
- Firefox extensions are now managed per-profile through the
`programs.firefox.profiles.<name>.extensions.packages` and
`programs.firefox.profiles.<name>.extensions.settings` options. The top-level
`programs.firefox.extensions = [ ... ]` list was removed; migrate it to
`programs.firefox.profiles.<name>.extensions.packages`.
- Thunderbird now supports `accounts.email.accounts.<name>.ews`, the
`outlook.office365.com-ews` account flavor, declarative language packs, and
enterprise policies. Thunderbird accounts using the `outlook.office365.com`
flavor now default IMAP and SMTP authentication to OAuth2 when the account
does not set an authentication method explicitly.
- A new `systemd.user.packages` option provides a user-level equivalent of
`systemd.packages` for installing unit files from packages.
- WezTerm now supports declarative configuration via
[](#opt-programs.wezterm.settings). Settings are expressed as a Nix attribute
set and serialized to Lua using `lib.generators.toLua`. Raw Lua expressions
such as `wezterm.font` and `wezterm.action.*` can be embedded using
`lib.generators.mkLuaInline`. The existing
[](#opt-programs.wezterm.extraConfig) option remains fully supported and can
be combined with [](#opt-programs.wezterm.settings).
[](#opt-programs.wezterm.settings). Settings are expressed as a Nix
attribute set and serialized to Lua using `lib.generators.toLua`.
Raw Lua expressions such as `wezterm.font` and `wezterm.action.*`
can be embedded using `lib.generators.mkLuaInline`. The existing
[](#opt-programs.wezterm.extraConfig) option remains fully supported
and can be combined with [](#opt-programs.wezterm.settings).
- The [](#opt-programs.anki.uiScale) option now expects a value in the range
1.02.0, previously it erroneously expected values in the range `0.01.0`.
Anki sync options moved from `programs.anki.sync.*` to
`programs.anki.profiles."User 1".sync.*`, and
`programs.anki.sync.passwordFile` is migrated to
`programs.anki.profiles."User 1".sync.keyFile`.
- New [](#opt-home.services) namespace for nixpkgs
[modular services](https://nixos.org/manual/nixos/unstable/#modular-services).
Service modules shipped with packages (e.g.
`pkgs.<name>.passthru.services.default`) drop in unchanged and are lifted to
user systemd units. See [Modular Services](#sec-usage-modular-services) for
details.
- Dedicated modules were added for several VSCode forks (`programs.cursor`,
`programs.vscodium`, `programs.windsurf`, `programs.kiro`, and
`programs.antigravity`), built from a shared `mkVscodeModule` factory. Each
fork can now be configured independently and simultaneously. Users who
previously selected a fork by setting `programs.vscode.package` should migrate
to the matching module; the `programs.vscode.pname` option was removed.
- The AI coding-assistant modules ([](#opt-programs.claude-code.enable),
[](#opt-programs.codex.enable), and [](#opt-programs.opencode.enable)) now
share a unified `context` option for providing global instructions. The
previous per-module options (`claude-code.memory`,
`codex.custom-instructions`, and `opencode.rules`) are deprecated and migrated
automatically. MCP server configuration via `programs.mcp.servers` was also
extended to more assistant and editor modules through an
`enableMcpIntegration` option.
- The `programs.man` module was split so the man viewer can be selected through
the [](#opt-programs.man.man-db.enable) and
[](#opt-programs.man.mandoc.enable) submodules, which are mutually exclusive.
- The `programs.neovim.extraLuaConfig` option was renamed to
[](#opt-programs.neovim.initLua). Home Manager now writes generated Lua
initialization to {file}`$XDG_CONFIG_HOME/nvim/init.lua` by default. If you
manage that file outside Home Manager, set
[](#opt-programs.neovim.sideloadInitLua) to `true` to load the generated Lua
through the Neovim wrapper instead.
- A new `sshAuthSock` module manages the `SSH_AUTH_SOCK`
environment variable. It is implicitly configured by the
SSH-agent-providing modules (e.g. `services.ssh-agent`, `services.gpg-agent`).
The old `services.ssh-agent.enable{Bash,Zsh,Fish,Nushell}Integration` options
were removed; shell initialization is now provided through `sshAuthSock`.
- A new [](#opt-services.pipewire.enable) module provides client-side
configuration for PipeWire, WirePlumber, and the PulseAudio/JACK compatibility
layers. It does not install or manage the PipeWire daemon itself.
- The `services.swww` module was renamed to [](#opt-services.awww.enable)
following the upstream project rename. The `enable`, `package`, and
`extraArgs` options are migrated automatically from `services.swww.*` to
`services.awww.*`.
- Several modules dropped their freeform `extraConfig` escape hatches in favor
of RFC 42-style `settings`: `programs.aerospace.extraConfig` (and
`userSettings`) and `programs.aria2.extraConfig` were removed.
`programs.mise.settings` was renamed to `programs.mise.globalConfig.settings`.
The `programs.eww.configDir` and
`programs.eww.enable{Bash,Zsh,Fish}Integration` options were removed; use
[](#opt-programs.eww.yuckConfig) and [](#opt-programs.eww.scssConfig) for
declarative Eww config files. The `programs.niriswitcher` options were also
removed.
- Darwin integration received several behavior changes. Home Manager launchd
agents now wait for `/nix/store` before starting and use
`launchctl bootout --wait` when replacing agents. nix-darwin activations now
propagate dry-run mode into Home Manager user activations. On Darwin, Home
Manager also exports `TERMINFO_DIRS` so terminfo entries from Home
Manager-installed packages are visible to shells.
- The [](#opt-nix.assumeXdg) option was added for installations where Nix is
configured to use XDG base directories outside Home Manager. Home Manager also
detects `osConfig.nix.settings.use-xdg-base-directories` when deciding where
to place declarative channel entries.
- The [](#opt-programs.anki.uiScale) option now expects a value in the
range 1.02.0, previously it erroneously expected values in the
range `0.01.0`.
## State Version Changes {#sec-release-26.05-state-version-changes}
The state version in this release includes the changes below. These changes are
only active if the `home.stateVersion` option is set to \"26.05\" or later.
The state version in this release includes the changes below. These
changes are only active if the `home.stateVersion` option is set to
\"26.05\" or later.
- The [](#opt-gtk.gtk4.theme) option does not mirror [](#opt-gtk.theme) by
default anymore.
- The [](#opt-gtk.gtk4.theme) option does not mirror
[](#opt-gtk.theme) by default anymore.
- The [](#opt-programs.zsh.dotDir) option now defaults to the XDG configuration
directory (usually `~/.config/zsh`) when [](#opt-xdg.enable) is true.
- The [](#opt-programs.zsh.dotDir) option now defaults to the XDG
configuration directory (usually `~/.config/zsh`) when
[](#opt-xdg.enable) is true.
- The [](#opt-programs.yazi.shellWrapperName) option now defaults to `y` instead
of `yy`.
- The [](#opt-programs.yazi.shellWrapperName) option now defaults to
`y` instead of `yy`. For users with older `home.stateVersion` values,
the legacy default `yy` is retained.
- The [](#opt-xdg.userDirs.setSessionVariables) option now defaults to `false`
instead of `true`.
@@ -151,39 +45,11 @@ only active if the `home.stateVersion` option is set to \"26.05\" or later.
`DESKTOP`. Home Manager 26.05 introduced a warning when the `XDG_<name>_DIR`
form is used.
- The [](#opt-programs.man.package) option now defaults to `null` on Darwin
because the GNU `man` from nixpkgs ships `apropos`/`man -k` and
`whatis`/`man -f` binaries that don't work on Darwin. Nix-installed manual
pages still work with macOS's built-in `man` via
- The [](#opt-programs.man.package) option now defaults to `null` on
Darwin because the GNU `man` from nixpkgs ships `apropos`/`man -k`
and `whatis`/`man -f` binaries that don't work on Darwin. Nix-installed
manual pages still work with macOS's built-in `man` via
[](#opt-home.extraOutputsToInstall).
- The options [](#opt-programs.neovim.withPython3) and
[](#opt-programs.neovim.withRuby) now default to `false` following nixpkgs.
- Neovim plugin `config` fragments are assumed to be Lua by default through
`programs.neovim.plugins.<name>.type = "lua"`, instead of the previous `viml`
default.
- On Linux, `programs.firefox.configPath` now defaults to
`"${config.xdg.configHome}/mozilla/firefox"`, instead of the legacy
`".mozilla/firefox"`.
- The [](#opt-wayland.windowManager.hyprland.configType) option now defaults to
`"lua"`, instead of the legacy `"hyprlang"`. Set
`wayland.windowManager.hyprland.configType = "hyprlang"` to keep generating
{file}`$XDG_CONFIG_HOME/hypr/hyprland.conf`.
- The [](#opt-programs.docker-cli.configDir) option now defaults to
`"${config.xdg.configHome}/docker"` when [](#opt-xdg.enable) is true, instead
of `~/.docker`. Similarly, [](#opt-services.colima.profiles) now sets
`$DOCKER_HOST` for the default context.
- The [](#opt-services.home-manager.autoUpgrade.preSwitchCommands) option now
defaults to an empty list. Previously, when
[](#opt-services.home-manager.autoUpgrade.useFlake) was `true`, it defaulted
to `[ "nix flake update" ]`. Set `preSwitchCommands = [ "nix flake update" ]`
to keep updating flake inputs before each automatic switch.
- The [](#opt-programs.mergiraf.enableGitIntegration) and
[](#opt-programs.mergiraf.enableJujutsuIntegration) options now default to
`false`, so the integrations must be enabled explicitly.
[](#opt-programs.neovim.withRuby) now default to `false` following nixpkgs
-21
View File
@@ -1,21 +0,0 @@
# Release 26.11 {#sec-release-26.11}
This is the current unstable branch and the information in this
section is therefore not final.
## Highlights {#sec-release-26.11-highlights}
This release has the following notable changes:
- The [](#opt-programs.uv.enable) module can now install uv-managed Python
versions and tools through the new `programs.uv.python.versions`,
`programs.uv.python.default`, and `programs.uv.tool.packages` options. Unpinned
entries track the latest release on each activation while pinned ones stay put,
and `programs.uv.python.prune` / `programs.uv.tool.prune` make the managed set
fully declarative by removing versions and tools that are no longer listed.
## State Version Changes {#sec-release-26.11-state-version-changes}
The state version in this release includes the changes below. These
changes are only active if the `home.stateVersion` option is set to
"26.11" or later.
Generated
+4 -4
View File
@@ -2,16 +2,16 @@
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1781607440,
"narHash": "sha256-rxO+uc/KFbSJp+pgyXRuAX6QlG9hJdnt0BXpEQRXY+U=",
"lastModified": 1775710090,
"narHash": "sha256-ar3rofg+awPB8QXDaFJhJ2jJhu+KqN/PRCXeyuXR76E=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "3e41b24abd260e8f71dbe2f5737d24122f972158",
"rev": "4c1018dae018162ec878d42fec712642d214fdfa",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
+14 -47
View File
@@ -1,7 +1,7 @@
{
description = "Home Manager for Nix";
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
outputs =
{
@@ -45,47 +45,26 @@
}
// (
let
supportedSystems = [
"aarch64-darwin"
"aarch64-linux"
"i686-linux"
"x86_64-darwin"
"x86_64-linux"
];
forSystems = systems: f: nixpkgs.lib.genAttrs systems (system: f nixpkgs.legacyPackages.${system});
forAllPkgs = forSystems nixpkgs.lib.systems.flakeExposed;
forSupportedPkgs = forSystems supportedSystems;
forAllPkgs =
f:
nixpkgs.lib.genAttrs nixpkgs.lib.systems.flakeExposed (system: f nixpkgs.legacyPackages.${system});
forCI = nixpkgs.lib.genAttrs [
"aarch64-darwin"
"x86_64-linux"
];
testPkgsFor =
system:
import nixpkgs {
inherit system;
config.allowInsecurePredicate =
pkg:
builtins.elem (nixpkgs.lib.getName pkg) [
"librewolf"
"librewolf-unwrapped"
];
};
testChunks =
system:
let
pkgs = testPkgsFor system;
pkgs = nixpkgs.legacyPackages.${system};
inherit (pkgs) lib;
# Create chunked test packages for better CI parallelization
tests = import ./tests {
inherit pkgs;
enableBig = true;
# Disable big tests since this is only used for CI
enableBig = false;
};
allTests = lib.attrNames tests.build;
# Remove 'all' from the test list as it's a meta-package
@@ -134,7 +113,7 @@
buildTests =
system:
let
pkgs = testPkgsFor system;
pkgs = nixpkgs.legacyPackages.${system};
tests = import ./tests { inherit pkgs; };
renameTestPkg = n: nixpkgs.lib.nameValuePair "test-${n}";
in
@@ -143,7 +122,7 @@
buildTestsNoBig =
system:
let
pkgs = testPkgsFor system;
pkgs = nixpkgs.legacyPackages.${system};
tests = import ./tests {
inherit pkgs;
enableBig = false;
@@ -156,7 +135,7 @@
buildTestsNoBigIfd =
system:
let
pkgs = testPkgsFor system;
pkgs = nixpkgs.legacyPackages.${system};
tests = import ./tests {
inherit pkgs;
enableBig = false;
@@ -178,7 +157,7 @@
lib.mapAttrs' renameTestPkg tests;
in
{
formatter = forSupportedPkgs (pkgs: pkgs.callPackage ./home-manager/formatter.nix { });
formatter = forAllPkgs (pkgs: pkgs.callPackage ./home-manager/formatter.nix { });
# TODO: increase buildbot testing scope
buildbot = forCI (
@@ -209,24 +188,12 @@
{
default = hmPkg;
home-manager = hmPkg;
}
// nixpkgs.lib.optionalAttrs (nixpkgs.lib.elem pkgs.stdenv.hostPlatform.system supportedSystems) {
ci-parse = pkgs.callPackage ./ci/parse.nix { nix = pkgs.nixVersions.latest; };
ci-parse-lix = pkgs.callPackage ./ci/parse.nix {
nix = pkgs.lixPackageSets.latest.lix;
};
create-news-entry = pkgs.writeShellScriptBin "create-news-entry" ''
./modules/misc/news/create-news-entry.sh
'';
tests = pkgs.callPackage ./tests/package.nix {
flake = self;
inputOverrides = {
inherit nixpkgs;
};
};
tests = pkgs.callPackage ./tests/package.nix { flake = self; };
docs-html = docs.manual.html;
docs-htmlOpenTool = docs.manual.htmlOpenTool;
@@ -236,11 +203,11 @@
}
);
devShells = forSupportedPkgs (pkgs: {
devShells = forAllPkgs (pkgs: {
default = pkgs.callPackage ./home-manager/devShell.nix { };
});
legacyPackages = forSupportedPkgs (
legacyPackages = forAllPkgs (
pkgs:
let
inherit (pkgs.stdenv.hostPlatform) system;
-1
View File
@@ -18,7 +18,6 @@ pkgs.treefmt.withConfig {
deadnix
keep-sorted
nixf-diagnose
ruff
];
settings = pkgs.lib.importTOML ../treefmt.toml;
}
+4 -4
View File
@@ -313,7 +313,7 @@ function doInit() {
fi
local homeManagerUrl="github:nix-community/home-manager"
local nixpkgsUrl="github:nixos/nixpkgs/nixpkgs-unstable"
local nixpkgsUrl="github:nixos/nixpkgs/nixos-unstable"
while (( $# > 0 )); do
local opt="$1"
@@ -403,7 +403,7 @@ $xdgVars
# You should not change this value, even if you update Home Manager. If you do
# want to update the value, then make sure to first check the Home Manager
# release notes.
home.stateVersion = "26.05"; # Please read the comment before changing.
home.stateVersion = "25.11"; # Please read the comment before changing.
# The home.packages option allows you to install Nix packages into your
# environment.
@@ -1041,7 +1041,7 @@ function doUninstall() {
uninstall = true;
home.username = "$(escapeForNix "$USER")";
home.homeDirectory = "$(escapeForNix "$HOME")";
home.stateVersion = "26.05";
home.stateVersion = "25.11";
}
EOF
# shellcheck disable=2064
@@ -1279,7 +1279,7 @@ while [[ $# -gt 0 ]]; do
export VERBOSE=1
;;
--version)
echo 26.11-pre
echo 26.05-pre
exit 0
;;
*)
+6 -6
View File
@@ -8,8 +8,8 @@ msgstr ""
"Project-Id-Version: Home Manager\n"
"Report-Msgid-Bugs-To: https://github.com/nix-community/home-manager/issues\n"
"POT-Creation-Date: 2026-01-21 09:53+0100\n"
"PO-Revision-Date: 2026-04-30 04:09+0000\n"
"Last-Translator: Troy <radiohotline@disroot.org>\n"
"PO-Revision-Date: 2026-03-31 16:16+0000\n"
"Last-Translator: Anonymous <noreply@weblate.org>\n"
"Language-Team: Arabic <https://hosted.weblate.org/projects/home-manager/cli/"
"ar/>\n"
"Language: ar\n"
@@ -18,17 +18,17 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 "
"&& n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n"
"X-Generator: Weblate 5.17.1-dev\n"
"X-Generator: Weblate 5.17-dev\n"
#. translators: For example: "home-manager: missing argument for --cores"
#: home-manager/home-manager:16
msgid "%s: missing argument for %s"
msgstr "%s: معطيات مفقودة ل %s"
msgstr "%s: معطيات مفقوة ل %s"
#. translators: For example: "home-manager: --rollback can only be used after switch"
#: home-manager/home-manager:22
msgid "%s: %s can only be used after %s"
msgstr "%s%: s يمكن استخدامه فقط بعد %s"
msgstr "%s: %s يمكن استخدامه فقط بعد %s"
#: home-manager/home-manager:71
msgid "No configuration file found at %s"
@@ -212,7 +212,7 @@ msgstr "لا يمكن تشغيل البناء في مجلد قراءة فقط"
#: home-manager/home-manager:822
msgid "The configuration does not contain the specialisation \"%s\""
msgstr "لا يتضمن ملف الاعدادات التخصص \"%s\""
msgstr ""
#: home-manager/home-manager:876
msgid "No generation with ID %s"
-261
View File
@@ -1,261 +0,0 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR Home Manager contributors
# This file is distributed under the same license as the Home Manager package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: Home Manager\n"
"Report-Msgid-Bugs-To: https://github.com/nix-community/home-manager/issues\n"
"POT-Creation-Date: 2026-01-21 09:53+0100\n"
"PO-Revision-Date: 2026-05-31 21:01+0000\n"
"Last-Translator: Tofaa <tofig.adigozalov.180904@gmail.com>\n"
"Language-Team: Azerbaijani <https://hosted.weblate.org/projects/home-manager/"
"cli/az/>\n"
"Language: az\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 2026.6.dev0\n"
#. translators: For example: "home-manager: missing argument for --cores"
#: home-manager/home-manager:16
msgid "%s: missing argument for %s"
msgstr "%s: {s} üçün tələb olunan arqument verilməyib"
#. translators: For example: "home-manager: --rollback can only be used after switch"
#: home-manager/home-manager:22
msgid "%s: %s can only be used after %s"
msgstr "%s: %s ancaq %s'dən sonra işlənə bilər"
#: home-manager/home-manager:71
msgid "No configuration file found at %s"
msgstr "%s-də konfiqurasiya faylı tapılmadı"
#. translators: The first '%s' specifier will be replaced by either
#. 'home.nix' or 'flake.nix'.
#: home-manager/home-manager:88 home-manager/home-manager:92
#: home-manager/home-manager:191
msgid ""
"Keeping your Home Manager %s in %s is deprecated,\n"
"please move it to %s"
msgstr ""
"Home Manager %s faylının %s daxilində saxlanılması artıq dəstəklənmir.\n"
"Zəhmət olmasa onu %s ünvanına köçürün"
#: home-manager/home-manager:99
msgid "No configuration file found. Please create one at %s"
msgstr "Konfiqurasiya faylı tapılmadı. Zəhmət olmasa fayli %s'də yaradin"
#: home-manager/home-manager:114
msgid "Home Manager not found at %s."
msgstr "Home Manager %s'də tapılmadı."
#. translators: This message will be seen by very few users that likely are familiar with English. So feel free to leave this untranslated.
#: home-manager/home-manager:122
msgid ""
"The fallback Home Manager path %s has been deprecated and a file/directory "
"was found there."
msgstr ""
"Ehtiyat Home Manager yolu %s artıq köhnəlmişdir və həmin ünvanda fayl və ya "
"qovluq tapıldı."
#. translators: This message will be seen by very few users that likely are familiar with English. So feel free to leave this untranslated.
#: home-manager/home-manager:125
msgid ""
"To remove this warning, do one of the following.\n"
"\n"
"1. Explicitly tell Home Manager to use the path, for example by adding\n"
"\n"
" { programs.home-manager.path = \"%s\"; }\n"
"\n"
" to your configuration.\n"
"\n"
" If you import Home Manager directly, you can use the `path` parameter\n"
"\n"
" pkgs.callPackage /path/to/home-manager-package { path = \"%s\"; }\n"
"\n"
" when calling the Home Manager package.\n"
"\n"
"2. Remove the deprecated path.\n"
"\n"
" $ rm -r \"%s\""
msgstr ""
"Bu xəbərdarlığı aradan qaldırmaq üçün aşağıdakılardan birini edin.\n"
"\n"
"1. Home Manager-ə bu yolu istifadə etməsini açıq şəkildə bildirin. Məsələn, "
"konfiqurasiyanıza aşağıdakı sətri əlavə edin:\n"
"\n"
"{ programs.home-manager.path = \"%s\"; }\n"
"\n"
" Əgər Home Manager-i birbaşa import edirsinizsə, Home Manager paketini\n"
" çağırarkən `path` parametrindən istifadə edə bilərsiniz:\n"
"\n"
" pkgs.callPackage /path/to/home-manager-package { path = \"%s\"; }\n"
"\n"
"2. Köhnəlmiş yolu silin.\n"
"\n"
" $ rm -r \"%s\""
#: home-manager/home-manager:153
msgid "Sanity checking Nix"
msgstr "Nix yoxlanılır"
#: home-manager/home-manager:173
msgid "Could not find suitable profile directory, tried %s and %s"
msgstr "Uyğun profil qovluğu tapılmadı; %s və %s yolları yoxlanıldı"
#. translators: Here "flake" is a noun that refers to the Nix Flakes feature.
#: home-manager/home-manager:230
msgid "Can't inspect options of a flake configuration"
msgstr "Flake konfiqurasiyasının seçimlərinə baxış keçirmək mümkün deyil"
#: home-manager/home-manager:340 home-manager/home-manager:363
#: home-manager/home-manager:769 home-manager/home-manager:1289
msgid "%s: unknown option '%s'"
msgstr "%s: bilinməyən seçim '%s'"
#: home-manager/home-manager:345 home-manager/home-manager:1290
msgid "Run '%s --help' for usage help"
msgstr "İstifadə köməyi üçün '%s --help' işlədin"
#: home-manager/home-manager:371 home-manager/home-manager:476
msgid "The file %s already exists, leaving it unchanged..."
msgstr "%s faylı artıq mövcuddur, dəyişdirilmədən saxlanılır..."
#: home-manager/home-manager:373 home-manager/home-manager:478
msgid "Creating %s..."
msgstr "%s yaradılır..."
#: home-manager/home-manager:522
msgid "Creating initial Home Manager generation..."
msgstr "Ilkin Home Manager nəsili yaradılır..."
#. translators: The "%s" specifier will be replaced by a file path.
#: home-manager/home-manager:527
msgid ""
"All done! The home-manager tool should now be installed and you can edit\n"
"\n"
" %s\n"
"\n"
"to configure Home Manager. Run 'man home-configuration.nix' to\n"
"see all available options."
msgstr ""
"Hər şey tamamlandı! İndi home-manager aləti quraşdırılıb və Home Manager-i "
"konfiqurasiya etmək üçün %s faylını redaktə edə bilərsiniz.\n"
"\n"
"Mövcud bütün seçimləri görmək üçün 'man home-configuration.nix' əmrini icra "
"edin."
#. translators: The "%s" specifier will be replaced by a URL.
#: home-manager/home-manager:532
msgid ""
"Uh oh, the installation failed! Please create an issue at\n"
"\n"
" %s\n"
"\n"
"if the error seems to be the fault of Home Manager."
msgstr ""
"Quraşdırma uğursuz oldu! Əgər xəta Home Manager-in səbəbindən baş veribsə, "
"%s ünvanında issue yaradın."
#. translators: Here "flake" is a noun that refers to the Nix Flakes feature.
#: home-manager/home-manager:543
msgid "Can't instantiate a flake configuration"
msgstr "Flake konfiqurasiyasını yaratmaq mümkün deyil"
#: home-manager/home-manager:619
msgid ""
"There is %d unread and relevant news item.\n"
"Read it by running the command \"%s news\"."
msgid_plural ""
"There are %d unread and relevant news items.\n"
"Read them by running the command \"%s news\"."
msgstr[0] ""
"Oxunmamış və uyğun %d xəbər var.\n"
"\n"
"Onu oxumaq üçün \"%s news\" əmrini icra edin."
msgstr[1] ""
"Oxunmamış və uyğun %d xəbər var.\n"
"\n"
"Onları oxumaq üçün \"%s news\" əmrini icra edin."
#: home-manager/home-manager:633
msgid "Unknown \"news.display\" setting \"%s\"."
msgstr "Naməlum \"news.display\" ayarı: \"%s\"."
#: home-manager/home-manager:641
#, sh-format
msgid "Please set the $EDITOR or $VISUAL environment variable"
msgstr "Zəhmət olmasa $EDITOR və ya $VISUAL mühit dəyişənini təyin edin"
#: home-manager/home-manager:659
msgid "Cannot run build in read-only directory"
msgstr "Yalnız oxuma rejimində qovluqda build icra etmək mümkün deyil"
#: home-manager/home-manager:822
msgid "The configuration does not contain the specialisation \"%s\""
msgstr "Konfiqurasiya \"%s\" specialisation-ını ehtiva etmir"
#: home-manager/home-manager:876
msgid "No generation with ID %s"
msgstr "%s ID-li nəsil mövcud deyil"
#: home-manager/home-manager:878
msgid "Cannot remove the current generation %s"
msgstr "Cari nəsli (%s) silmək mümkün deyil"
#: home-manager/home-manager:880
msgid "Removing generation %s"
msgstr "%s nəsli silinir"
#: home-manager/home-manager:901
msgid "No generations to expire"
msgstr "Müddəti bitəcək heç bir nəsil yoxdur"
#: home-manager/home-manager:912
msgid "No home-manager packages seem to be installed."
msgstr "Heç bir home-manager paketi quraşdırılmış görünmür."
#: home-manager/home-manager:997
msgid "Unknown argument %s"
msgstr "Naməlum arqument: %s"
#: home-manager/home-manager:1022
msgid "This will remove Home Manager from your system."
msgstr "Bu, Home Manager-i sisteminizdən siləcək."
#: home-manager/home-manager:1025
msgid "This is a dry run, nothing will actually be uninstalled."
msgstr "Bu sınaq icrasıdır, heç nə faktiki olaraq silinməyəcək."
#: home-manager/home-manager:1029
msgid "Really uninstall Home Manager?"
msgstr "Home Manager-i həqiqətən silmək istəyirsiniz?"
#: home-manager/home-manager:1035
msgid "Switching to empty Home Manager configuration..."
msgstr "Boş Home Manager konfiqurasiyasına keçid edilir..."
#: home-manager/home-manager:1050
msgid "Yay!"
msgstr "Əla!"
#: home-manager/home-manager:1055
msgid "Home Manager is uninstalled but your home.nix is left untouched."
msgstr "Home Manager silindi, lakin home.nix faylınız dəyişdirilmədi."
#: home-manager/home-manager:1334
msgid "expire-generations expects one argument, got %d."
msgstr "expire-generations bir arqument gözləyir, lakin %d arqument verilib."
#: home-manager/home-manager:1359
msgid "Unknown command: %s"
msgstr "Naməlum əmr: %s"
#: home-manager/install.nix:21
msgid "This derivation is not buildable, please run it using nix-shell."
msgstr ""
"Bu derivasiya build edilə bilən deyil, zəhmət olmasa onu nix-shell ilə icra "
"edin."
+15 -15
View File
@@ -8,8 +8,8 @@ msgstr ""
"Project-Id-Version: Home Manager\n"
"Report-Msgid-Bugs-To: https://github.com/nix-community/home-manager/issues\n"
"POT-Creation-Date: 2026-01-21 09:53+0100\n"
"PO-Revision-Date: 2026-05-05 10:30+0000\n"
"Last-Translator: Ludovic Pagès <nanucq@proton.me>\n"
"PO-Revision-Date: 2026-03-31 16:16+0000\n"
"Last-Translator: TheBlackBeans <adrien.mathieu.net@gmail.com>\n"
"Language-Team: French <https://hosted.weblate.org/projects/home-manager/cli/"
"fr/>\n"
"Language: fr\n"
@@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
"X-Generator: Weblate 5.17.1\n"
"X-Generator: Weblate 5.17-dev\n"
#. translators: For example: "home-manager: missing argument for --cores"
#: home-manager/home-manager:16
@@ -52,7 +52,7 @@ msgstr ""
#: home-manager/home-manager:114
msgid "Home Manager not found at %s."
msgstr "Home Manager absent dans %s."
msgstr "Home Manager indisponible à %s."
#. translators: This message will be seen by very few users that likely are familiar with English. So feel free to leave this untranslated.
#: home-manager/home-manager:122
@@ -84,15 +84,15 @@ msgid ""
"\n"
" $ rm -r \"%s\""
msgstr ""
"Pour supprimer cet avertissement, exécutez l'une des actions suivantes :\n"
" \n"
"Pour supprimer cet avertissement, exécutez l'une des actions suivantes:\n"
"\n"
"1. Préciser explicitement à Home Manager d'utiliser le chemin d'accès, par "
"exemple en ajoutant ceci à votre configuration :\n"
"exemple en ajoutant ceci à votre configuration:\n"
"\n"
"\t{ programs.home-manager.path = \"%s\"; }\n"
"\n"
"Si vous importez Home Manager directement, vous pouvez utiliser le paramètre "
"`path` au lancement du package :\n"
"`path` au lancement du package:\n"
"\n"
"\tpkgs.callPackage /path/to/home-manager-package { path = \"%s\"; }\n"
"\n"
@@ -120,7 +120,7 @@ msgstr "%s : l'option '%s' est inconnue"
#: home-manager/home-manager:345 home-manager/home-manager:1290
msgid "Run '%s --help' for usage help"
msgstr "Exécuter '%s --help' pour de l'aide sur l'utilisation"
msgstr "Exécuter « %s --help » pour de l'aide sur l'utilisation"
#: home-manager/home-manager:371 home-manager/home-manager:476
msgid "The file %s already exists, leaving it unchanged..."
@@ -144,13 +144,13 @@ msgid ""
"to configure Home Manager. Run 'man home-configuration.nix' to\n"
"see all available options."
msgstr ""
"Terminé ! Home Manager devrait désormais être installé et vous pouvez "
"Tout est fait! Home Manager devrait désormais être installé et vous pouvez "
"éditer\n"
"\n"
" %s\n"
"\n"
"pour configurer Home Manager. Pour avoir une liste des options disponibles,\n"
"lancez 'man home-configuration.nix'."
"essayez 'man home-configuration.nix'."
#. translators: The "%s" specifier will be replaced by a URL.
#: home-manager/home-manager:532
@@ -161,8 +161,8 @@ msgid ""
"\n"
"if the error seems to be the fault of Home Manager."
msgstr ""
"Uh oh, l'installation a échoué! Veuillez signaler cette erreur à l'adresse "
"suivante\n"
"Uh oh, l'installation n'a pas réussi! Veuillez signaler cette erreur à "
"l'adresse suivante\n"
"\n"
" %s\n"
"\n"
@@ -198,11 +198,11 @@ msgstr "Veuillez remplir la variable d'environnement $EDITOR ou VISUAL"
#: home-manager/home-manager:659
msgid "Cannot run build in read-only directory"
msgstr "Impossible de lancer une compilation dans un dossier en lecture seule"
msgstr "Impossible de lancer une compilation dans un dossier en écriture seule"
#: home-manager/home-manager:822
msgid "The configuration does not contain the specialisation \"%s\""
msgstr "La configuration ne contient pas la spécialisation \"%s\""
msgstr ""
#: home-manager/home-manager:876
msgid "No generation with ID %s"
+4 -4
View File
@@ -8,8 +8,8 @@ msgstr ""
"Project-Id-Version: Home Manager\n"
"Report-Msgid-Bugs-To: https://github.com/nix-community/home-manager/issues\n"
"POT-Creation-Date: 2026-01-21 09:53+0100\n"
"PO-Revision-Date: 2026-06-12 10:01+0000\n"
"Last-Translator: Tommaso Soncin <soncintommaso@gmail.com>\n"
"PO-Revision-Date: 2026-03-31 16:16+0000\n"
"Last-Translator: Lorenzo Bevilacqua <lorenzobevilacqua02@gmail.com>\n"
"Language-Team: Italian <https://hosted.weblate.org/projects/home-manager/cli/"
"it/>\n"
"Language: it\n"
@@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 2026.7.dev0\n"
"X-Generator: Weblate 5.17-dev\n"
#. translators: For example: "home-manager: missing argument for --cores"
#: home-manager/home-manager:16
@@ -204,7 +204,7 @@ msgstr "Impossibile eseguire la build in una cartella in sola lettura"
#: home-manager/home-manager:822
msgid "The configuration does not contain the specialisation \"%s\""
msgstr "La configurazione non contiene la specializzazione \"%s\""
msgstr ""
#: home-manager/home-manager:876
msgid "No generation with ID %s"
+4 -4
View File
@@ -8,8 +8,8 @@ msgstr ""
"Project-Id-Version: Home Manager\n"
"Report-Msgid-Bugs-To: https://github.com/nix-community/home-manager/issues\n"
"POT-Creation-Date: 2026-01-21 09:53+0100\n"
"PO-Revision-Date: 2026-05-21 21:11+0000\n"
"Last-Translator: jay <jj8z@proton.me>\n"
"PO-Revision-Date: 2026-03-31 16:15+0000\n"
"Last-Translator: Erwin Mintiens <erwin.mintiens@protonmail.com>\n"
"Language-Team: Dutch <https://hosted.weblate.org/projects/home-manager/cli/"
"nl/>\n"
"Language: nl\n"
@@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 2026.6.dev0\n"
"X-Generator: Weblate 5.17-dev\n"
#. translators: For example: "home-manager: missing argument for --cores"
#: home-manager/home-manager:16
@@ -185,7 +185,7 @@ msgstr "Het is niet mogelijk om te bouwen in een read-only map"
#: home-manager/home-manager:822
msgid "The configuration does not contain the specialisation \"%s\""
msgstr "De configuratie bevat niet de specialisatie \"%s\""
msgstr ""
#: home-manager/home-manager:876
msgid "No generation with ID %s"
+13 -12
View File
@@ -8,8 +8,8 @@ msgstr ""
"Project-Id-Version: Home Manager\n"
"Report-Msgid-Bugs-To: https://github.com/nix-community/home-manager/issues\n"
"POT-Creation-Date: 2026-01-21 09:53+0100\n"
"PO-Revision-Date: 2026-04-26 13:09+0000\n"
"Last-Translator: Nikodem <35564466+x1pper@users.noreply.github.com>\n"
"PO-Revision-Date: 2026-03-31 16:15+0000\n"
"Last-Translator: Mateusz Kubica <mw.kubica@gmail.com>\n"
"Language-Team: Polish <https://hosted.weblate.org/projects/home-manager/cli/"
"pl/>\n"
"Language: pl\n"
@@ -18,7 +18,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
"|| n%100>=20) ? 1 : 2);\n"
"X-Generator: Weblate 5.17.1-dev\n"
"X-Generator: Weblate 5.17-dev\n"
#. translators: For example: "home-manager: missing argument for --cores"
#: home-manager/home-manager:16
@@ -83,24 +83,25 @@ msgid ""
"\n"
" $ rm -r \"%s\""
msgstr ""
"Zrób jedną z tych rzeczy aby pozbyć się tego ostrzeżenia:\n"
"Zrób jedną z tych rzeczy aby aby pozbyć się tego ostrzeżenia:\n"
"\n"
"1. Jednoznacznie skonfiguruj Home Manager żeby używał konkretnej ścieżki, "
"np. dodając\n"
"\n"
" { programs.home-manager.path = \"%s\"; }\n"
" { programs.home-manager.path = \"%s\"; }\n"
"\n"
" do twojej konfiguracji.\n"
" do twojej konfiguracji.\n"
"\n"
" Jeśli importujesz Home Manager bezpośrednio, możesz użyć parametru `path`\n"
" Jeśli importujesz Home Manager bezpośrednio, możesz użyć parametru "
"`path`\n"
"\n"
" pkgs.callPackage /ścieżka/do/pakiet-home-manager { path = \"%s\"; }\n"
" pkgs.callPackage /ścieżka/do/pakiet-home-manager { path = \"%s\"; }\n"
"\n"
" przy wywołaniu pakietu Home Manager.\n"
" przy wywołaniu pakietu Home Manager.\n"
"\n"
"2. Usuń przestarzałą ścieżkę:\n"
"2. Usuń przestarzałą ścieżkę.\n"
"\n"
" $ rm -r \"%s\""
" $ rm -r \"%s\""
#: home-manager/home-manager:153
msgid "Sanity checking Nix"
@@ -206,7 +207,7 @@ msgstr "Nie mogę uruchomić budowania w katalogu tylko-do-odczytu"
#: home-manager/home-manager:822
msgid "The configuration does not contain the specialisation \"%s\""
msgstr "Konfiguracja nie zawiera specjalizacji o nazwie \"%s\""
msgstr ""
#: home-manager/home-manager:876
msgid "No generation with ID %s"
+31 -58
View File
@@ -8,8 +8,8 @@ msgstr ""
"Project-Id-Version: Home Manager\n"
"Report-Msgid-Bugs-To: https://github.com/nix-community/home-manager/issues\n"
"POT-Creation-Date: 2026-01-21 09:53+0100\n"
"PO-Revision-Date: 2026-05-27 11:11+0000\n"
"Last-Translator: qb114514 <GNUqb114514@outlook.com>\n"
"PO-Revision-Date: 2026-03-31 16:14+0000\n"
"Last-Translator: Anonymous <noreply@weblate.org>\n"
"Language-Team: Toki Pona <https://hosted.weblate.org/projects/home-manager/"
"cli/tok/>\n"
"Language: tok\n"
@@ -17,21 +17,21 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Weblate 2026.6.dev0\n"
"X-Generator: Weblate 5.17-dev\n"
#. translators: For example: "home-manager: missing argument for --cores"
#: home-manager/home-manager:16
msgid "%s: missing argument for %s"
msgstr "%s: nimi %s li wile nimi poka"
msgstr ""
#. translators: For example: "home-manager: --rollback can only be used after switch"
#: home-manager/home-manager:22
msgid "%s: %s can only be used after %s"
msgstr "%s: %s li ken lon poka pini %s"
msgstr ""
#: home-manager/home-manager:71
msgid "No configuration file found at %s"
msgstr "lipu lawa li lon ala %s"
msgstr ""
#. translators: The first '%s' specifier will be replaced by either
#. 'home.nix' or 'flake.nix'.
@@ -41,16 +41,14 @@ msgid ""
"Keeping your Home Manager %s in %s is deprecated,\n"
"please move it to %s"
msgstr ""
"lipu %s pi ilo Home Manager li wile ala lon %s.\n"
"o tawa %s e ona"
#: home-manager/home-manager:99
msgid "No configuration file found. Please create one at %s"
msgstr "mi ken ala alasa e lipu lawa. o pali e lipu lawa lon %s"
msgstr ""
#: home-manager/home-manager:114
msgid "Home Manager not found at %s."
msgstr "ilo Home Manager li lon ala %s."
msgstr ""
#. translators: This message will be seen by very few users that likely are familiar with English. So feel free to leave this untranslated.
#: home-manager/home-manager:122
@@ -58,8 +56,6 @@ msgid ""
"The fallback Home Manager path %s has been deprecated and a file/directory "
"was found there."
msgstr ""
"tenpo pini la, ilo Home Manager li kepeken nasin %s. taso, tenpo ni la ilo "
"Home Manager li wile ale e nasin ni. lipu anu kulupu lipu li lon nasin ni."
#. translators: This message will be seen by very few users that likely are familiar with English. So feel free to leave this untranslated.
#: home-manager/home-manager:125
@@ -85,40 +81,37 @@ msgstr ""
#: home-manager/home-manager:153
msgid "Sanity checking Nix"
msgstr "mi alasa ilo Nix tan ni: ilo Nix li lon ala la ni li ike mute li nasa"
msgstr ""
#: home-manager/home-manager:173
msgid "Could not find suitable profile directory, tried %s and %s"
msgstr ""
"mi wile pana e kulupu lipu sina lon poki sona. taso mi ken ala alasa e ma "
"pona lon %s lon %s"
#. translators: Here "flake" is a noun that refers to the Nix Flakes feature.
#: home-manager/home-manager:230
msgid "Can't inspect options of a flake configuration"
msgstr "mi ken ala lukin e lipu lawa pi ilo Nix Flakes"
msgstr ""
#: home-manager/home-manager:340 home-manager/home-manager:363
#: home-manager/home-manager:769 home-manager/home-manager:1289
msgid "%s: unknown option '%s'"
msgstr "%s: mi ken ala sona e nimi '%s'"
msgstr ""
#: home-manager/home-manager:345 home-manager/home-manager:1290
msgid "Run '%s --help' for usage help"
msgstr "sina wile kama sona pali e ilo Home Manager la o toki e '%s --help'"
msgstr ""
#: home-manager/home-manager:371 home-manager/home-manager:476
msgid "The file %s already exists, leaving it unchanged..."
msgstr "lipu %s li lon. mi ante ala e ona."
msgstr ""
#: home-manager/home-manager:373 home-manager/home-manager:478
msgid "Creating %s..."
msgstr "mi pali e \"%s\"."
msgstr ""
#: home-manager/home-manager:522
msgid "Creating initial Home Manager generation..."
msgstr ""
"tenpo ni la mi pali e kulupu nanpa wan pi lipu lawa tan ilo Home Manager..."
#. translators: The "%s" specifier will be replaced by a file path.
#: home-manager/home-manager:527
@@ -130,12 +123,6 @@ msgid ""
"to configure Home Manager. Run 'man home-configuration.nix' to\n"
"see all available options."
msgstr ""
"pini a! ilo \"home-manager\" li lon. sina wile lawa e ilo Home Manager la "
"sina ken ante e lipu ni:\n"
"\n"
" lipu.%s\n"
"\n"
"sina wile kama sona e nasin lawa o toki e ni: 'man home-configuration.nix'."
#. translators: The "%s" specifier will be replaced by a URL.
#: home-manager/home-manager:532
@@ -146,17 +133,11 @@ msgid ""
"\n"
"if the error seems to be the fault of Home Manager."
msgstr ""
"ike li lon! mi ken ala pana e ilo Home Manager tawa sina. ken la sina pilin "
"e ni: ike ni li tan ilo Home Manager. ni la o pana e sona lon\n"
"\n"
" %s\n"
"\n"
"ni la sina pona e mi mute."
#. translators: Here "flake" is a noun that refers to the Nix Flakes feature.
#: home-manager/home-manager:543
msgid "Can't instantiate a flake configuration"
msgstr "mi ken ala pali e lipu lawa pi ilo Nix Flakes"
msgstr ""
#: home-manager/home-manager:619
msgid ""
@@ -166,88 +147,80 @@ msgid_plural ""
"There are %d unread and relevant news items.\n"
"Read them by running the command \"%s news\"."
msgstr[0] ""
"sona sin %d li lon.\n"
"sina wile lukin la o toki: \"%s news\"."
#: home-manager/home-manager:633
msgid "Unknown \"news.display\" setting \"%s\"."
msgstr ""
"sina pana e \"%s\" tawa nimi lawa \"news.display\". nimi lawa ni li ken ala "
"jo e nimi ni li ken jo e \"silent\" anu \"notify\" anu \"show\"."
#: home-manager/home-manager:641
#, sh-format
msgid "Please set the $EDITOR or $VISUAL environment variable"
msgstr "o pana e ilo tawa poki sona $EDITOR anu poki sona $VISUAL"
msgstr ""
#: home-manager/home-manager:659
msgid "Cannot run build in read-only directory"
msgstr "ma ni li ken ala ante. mi ken ala pali \"build\" lon ma ni"
msgstr ""
#: home-manager/home-manager:822
#, fuzzy
msgid "The configuration does not contain the specialisation \"%s\""
msgstr "lipu lawa jo ala lipu Specialisation \"%s\""
msgstr ""
#: home-manager/home-manager:876
msgid "No generation with ID %s"
msgstr "kulupu pi lipu lawa pi ilo Home Manager pi nimi %s li lon ala"
msgstr ""
#: home-manager/home-manager:878
msgid "Cannot remove the current generation %s"
msgstr ""
"mi ken ala weka e kulupu pi lipu lawa %s tan ni: tenpo ni la ona li lon tomo "
"sina"
#: home-manager/home-manager:880
msgid "Removing generation %s"
msgstr "mi weka e kulupu lawa pi nimi %s"
msgstr ""
#: home-manager/home-manager:901
msgid "No generations to expire"
msgstr "kulupu ale pi lipu lawa li majuna ala. mi wile ala weka e ona"
msgstr ""
#: home-manager/home-manager:912
msgid "No home-manager packages seem to be installed."
msgstr "ilo Home Manager li pana ala e ilo ante."
msgstr ""
#: home-manager/home-manager:997
msgid "Unknown argument %s"
msgstr "mi sona ala e nimi '%s'"
msgstr ""
#: home-manager/home-manager:1022
msgid "This will remove Home Manager from your system."
msgstr "ni li weka e ilo Home Manager."
msgstr ""
#: home-manager/home-manager:1025
msgid "This is a dry run, nothing will actually be uninstalled."
msgstr "tenpo ni la mi weka e ala li toki taso."
msgstr ""
#: home-manager/home-manager:1029
msgid "Really uninstall Home Manager?"
msgstr "sina wile ala wile weka e ilo Home Manager?"
msgstr ""
#: home-manager/home-manager:1035
msgid "Switching to empty Home Manager configuration..."
msgstr "tenpo ni la mi lon e lipu lawa pi ijo ala..."
msgstr ""
#: home-manager/home-manager:1050
msgid "Yay!"
msgstr "pona mute a!"
msgstr ""
#: home-manager/home-manager:1055
msgid "Home Manager is uninstalled but your home.nix is left untouched."
msgstr "ilo Home Manager li weka. taso, lipu home.nix li awen lon."
msgstr ""
#: home-manager/home-manager:1334
msgid "expire-generations expects one argument, got %d."
msgstr ""
"sina pana e nimi %d tawa ilo expire-generations. o pana e nimi wan taso."
#: home-manager/home-manager:1359
msgid "Unknown command: %s"
msgstr "mi sona ala pali %s"
msgstr ""
#: home-manager/install.nix:21
msgid "This derivation is not buildable, please run it using nix-shell."
msgstr "mi ken ala pali e ni. sina ken pali e ona kepeken ilo nix-shell."
msgstr ""
+5 -6
View File
@@ -8,8 +8,8 @@ msgstr ""
"Project-Id-Version: Home Manager\n"
"Report-Msgid-Bugs-To: https://github.com/nix-community/home-manager/issues\n"
"POT-Creation-Date: 2026-01-21 09:53+0100\n"
"PO-Revision-Date: 2026-05-27 11:11+0000\n"
"Last-Translator: qb114514 <GNUqb114514@outlook.com>\n"
"PO-Revision-Date: 2026-03-31 16:13+0000\n"
"Last-Translator: Zexin Yuan <yuan.zx@outlook.com>\n"
"Language-Team: Chinese (Simplified Han script) <https://hosted.weblate.org/"
"projects/home-manager/cli/zh_Hans/>\n"
"Language: zh_Hans\n"
@@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Weblate 2026.6.dev0\n"
"X-Generator: Weblate 5.17-dev\n"
#. translators: For example: "home-manager: missing argument for --cores"
#: home-manager/home-manager:16
@@ -27,7 +27,7 @@ msgstr "%s:缺少参数 %s"
#. translators: For example: "home-manager: --rollback can only be used after switch"
#: home-manager/home-manager:22
msgid "%s: %s can only be used after %s"
msgstr "%s: %s 只能在 %s 后使用"
msgstr ""
#: home-manager/home-manager:71
msgid "No configuration file found at %s"
@@ -193,9 +193,8 @@ msgid "Cannot run build in read-only directory"
msgstr "无法在只读目录中运行构建"
#: home-manager/home-manager:822
#, fuzzy
msgid "The configuration does not contain the specialisation \"%s\""
msgstr "配置不包含 specialisation “%s”"
msgstr ""
#: home-manager/home-manager:876
msgid "No generation with ID %s"
+34 -1
View File
@@ -2,5 +2,38 @@
{
inherit ((import ../modules/lib/stdlib-extended.nix lib)) hm;
homeManagerConfiguration = import ./eval-config.nix;
homeManagerConfiguration =
{
check ? true,
extraSpecialArgs ? { },
lib ? pkgs.lib,
modules ? [ ],
pkgs,
minimal ? false,
}:
import ../modules {
inherit
check
extraSpecialArgs
lib
pkgs
minimal
;
configuration = {
imports = modules ++ [
{
programs.home-manager.path = builtins.path {
path = ../.;
name = "source";
};
}
];
nixpkgs = {
config = lib.mkDefault pkgs.config;
inherit (pkgs) overlays;
};
};
};
}
-33
View File
@@ -1,33 +0,0 @@
{
check ? true,
extraSpecialArgs ? { },
lib ? pkgs.lib,
modules ? [ ],
pkgs,
minimal ? false,
}:
import ../modules {
inherit
check
extraSpecialArgs
lib
pkgs
minimal
;
configuration = {
imports = modules ++ [
{
programs.home-manager.path = builtins.path {
path = ../.;
name = "source";
};
}
];
nixpkgs = {
config = lib.mkDefault pkgs.config;
inherit (pkgs) overlays;
};
};
}
+17 -32
View File
@@ -17,67 +17,52 @@ def main():
print("🔍 Checking for duplicate maintainers between HM and nixpkgs...")
# Get home-manager maintainers
hm_result = subprocess.run(
["nix", "eval", "--file", "modules/lib/maintainers.nix", "--json"],
capture_output=True,
text=True,
check=True,
)
hm_result = subprocess.run(['nix', 'eval', '--file', 'modules/lib/maintainers.nix', '--json'],
capture_output=True, text=True, check=True)
hm_maintainers = json.loads(hm_result.stdout)
hm_github_users = set()
for name, data in hm_maintainers.items():
if "github" in data:
hm_github_users.add(data["github"])
if 'github' in data:
hm_github_users.add(data['github'])
# Read nixpkgs revision from flake.lock to ensure consistency between local and CI
flake_lock_path = Path("flake.lock")
with open(flake_lock_path, "r") as f:
flake_lock_path = Path('flake.lock')
with open(flake_lock_path, 'r') as f:
flake_lock = json.load(f)
nixpkgs_rev = flake_lock["nodes"]["nixpkgs"]["locked"]["rev"]
nixpkgs_rev = flake_lock['nodes']['nixpkgs']['locked']['rev']
print(f"📌 Using nixpkgs from flake.lock: {nixpkgs_rev[:7]}")
# Get nixpkgs maintainers from the locked revision
nixpkgs_result = subprocess.run(
[
"nix",
"eval",
f"github:NixOS/nixpkgs/{nixpkgs_rev}#lib.maintainers",
"--json",
],
capture_output=True,
text=True,
check=True,
['nix', 'eval', f'github:NixOS/nixpkgs/{nixpkgs_rev}#lib.maintainers', '--json'],
capture_output=True, text=True, check=True
)
nixpkgs_maintainers = json.loads(nixpkgs_result.stdout)
nixpkgs_github_users = set()
for name, data in nixpkgs_maintainers.items():
if isinstance(data, dict) and "github" in data:
nixpkgs_github_users.add(data["github"])
if isinstance(data, dict) and 'github' in data:
nixpkgs_github_users.add(data['github'])
# Find duplicates
duplicates = hm_github_users.intersection(nixpkgs_github_users)
if duplicates:
print(
f"❌ Found {len(duplicates)} duplicate maintainers between HM and nixpkgs:"
)
print(f'❌ Found {len(duplicates)} duplicate maintainers between HM and nixpkgs:')
for github_user in sorted(duplicates):
# Find the HM attribute name for this github user
hm_attr = None
for attr_name, data in hm_maintainers.items():
if data.get("github") == github_user:
if data.get('github') == github_user:
hm_attr = attr_name
break
print(f" - {github_user} (HM attribute: {hm_attr})")
print(f' - {github_user} (HM attribute: {hm_attr})')
print()
print(
"These maintainers should be removed from HM maintainers file to avoid duplication."
)
print("They can be referenced directly from nixpkgs instead.")
print('These maintainers should be removed from HM maintainers file to avoid duplication.')
print('They can be referenced directly from nixpkgs instead.')
sys.exit(1)
else:
print("✅ No duplicate maintainers found")
print('✅ No duplicate maintainers found')
if __name__ == "__main__":
+1 -4
View File
@@ -16,7 +16,6 @@ from pathlib import Path
class NixEvalError(Exception):
"""Custom exception for errors during Nix evaluation."""
pass
@@ -40,9 +39,7 @@ def run_nix_eval(nix_file: Path, *args: str) -> str:
)
return result.stdout.strip()
except FileNotFoundError:
logging.error(
"'nix-instantiate' command not found. Is Nix installed and in your PATH?"
)
logging.error("'nix-instantiate' command not found. Is Nix installed and in your PATH?")
raise NixEvalError("'nix-instantiate' not found")
except subprocess.CalledProcessError as e:
logging.error(f"Nix evaluation failed with exit code {e.returncode}")
+11 -18
View File
@@ -40,7 +40,6 @@ def get_project_root() -> Path:
# Assumes this script is at: <root>/flake/dev/generate-all-maintainers/
return Path(__file__).parent.parent.parent.parent.resolve()
class MetaMaintainerGenerator:
"""Generates maintainers list using meta.maintainers from Home Manager evaluation."""
@@ -55,12 +54,9 @@ class MetaMaintainerGenerator:
print("🔍 Extracting maintainers using meta.maintainers...")
try:
result = subprocess.run(
["nix", "eval", "--file", str(self.extractor_script), "--json"],
capture_output=True,
text=True,
timeout=60,
)
result = subprocess.run([
"nix", "eval", "--file", str(self.extractor_script), "--json"
], capture_output=True, text=True, timeout=60)
if result.returncode == 0:
data = json.loads(result.stdout)
@@ -91,7 +87,7 @@ class MetaMaintainerGenerator:
print(f"🏠 Home Manager maintainers: {len(hm_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(
inspect.cleandoc("""
# Home Manager all maintainers list.
@@ -118,12 +114,9 @@ class MetaMaintainerGenerator:
def validate_generated_file(self) -> bool:
"""Validate the generated Nix file syntax."""
try:
result = subprocess.run(
["nix-instantiate", "--eval", str(self.output_file), "--strict"],
capture_output=True,
text=True,
timeout=10,
)
result = subprocess.run([
'nix-instantiate', '--eval', str(self.output_file), '--strict'
], capture_output=True, text=True, timeout=10)
if result.returncode == 0:
print("✅ Generated file has valid Nix syntax")
@@ -155,16 +148,16 @@ def main():
description="Generate Home Manager all-maintainers.nix using meta.maintainers"
)
parser.add_argument(
"--root",
'--root',
type=Path,
default=None,
help="Path to Home Manager root (default: auto-detect)",
help='Path to Home Manager root (default: auto-detect)'
)
parser.add_argument(
"--output",
'--output',
type=Path,
default=None,
help="Output file path (default: <root>/all-maintainers.nix)",
help='Output file path (default: <root>/all-maintainers.nix)'
)
args = parser.parse_args()
+41 -108
View File
@@ -60,7 +60,6 @@ query($owner: String!, $repo: String!, $prNumber: Int!) {
class GHError(Exception):
"""Custom exception for errors related to 'gh' CLI commands."""
pass
@@ -95,28 +94,15 @@ def get_manual_reviewer_actions(
tuple: (manually_requested, manually_removed) sets of usernames
"""
try:
result = run_gh_command(
[
"api",
"graphql",
"-f",
f"query={MANUAL_REVIEW_REQUEST_QUERY}",
"-F",
f"owner={owner}",
"-F",
f"repo={repo}",
"-F",
f"prNumber={pr_number}",
]
)
result = run_gh_command([
"api", "graphql",
"-f", f"query={MANUAL_REVIEW_REQUEST_QUERY}",
"-F", f"owner={owner}",
"-F", f"repo={repo}",
"-F", f"prNumber={pr_number}",
])
data = json.loads(result.stdout)
nodes = (
data.get("data", {})
.get("repository", {})
.get("pullRequest", {})
.get("timelineItems", {})
.get("nodes", [])
)
nodes = data.get("data", {}).get("repository", {}).get("pullRequest", {}).get("timelineItems", {}).get("nodes", [])
manually_requested = set()
manually_removed = set()
@@ -157,15 +143,7 @@ def get_users_from_gh(args: list[str], error_message: str) -> set[str]:
def get_pending_reviewers(pr_number: int) -> set[str]:
"""Gets the set of currently pending reviewers for a PR."""
return get_users_from_gh(
[
"pr",
"view",
str(pr_number),
"--json",
"reviewRequests",
"--jq",
".reviewRequests[].login",
],
["pr", "view", str(pr_number), "--json", "reviewRequests", "--jq", ".reviewRequests[].login"],
"Error getting pending reviewers",
)
@@ -173,12 +151,7 @@ def get_pending_reviewers(pr_number: int) -> set[str]:
def get_past_reviewers(owner: str, repo: str, pr_number: int) -> set[str]:
"""Gets the set of users who have already reviewed the PR."""
return get_users_from_gh(
[
"api",
f"repos/{owner}/{repo}/pulls/{pr_number}/reviews",
"--jq",
".[].user.login",
],
["api", f"repos/{owner}/{repo}/pulls/{pr_number}/reviews", "--jq", ".[].user.login"],
"Error getting past reviewers",
)
@@ -189,14 +162,17 @@ def is_collaborator(owner: str, repo: str, username: str) -> bool:
Handles 404 as a non-collaborator, while other errors are raised.
"""
result = run_gh_command(
["api", f"repos/{owner}/{repo}/collaborators/{username}"], check=False
["api", f"repos/{owner}/{repo}/collaborators/{username}"],
check=False
)
if result.returncode == 0:
return True
if "HTTP 404" in result.stderr:
logging.error("'%s' is not a collaborator in this repository.", username)
logging.error(
"'%s' is not a collaborator in this repository.", username
)
return False
else:
logging.error(
@@ -219,32 +195,22 @@ def update_reviewers(
if reviewers_to_add:
logging.info("Requesting reviews from: %s", ", ".join(reviewers_to_add))
try:
run_gh_command(
[
"pr",
"edit",
str(pr_number),
"--add-reviewer",
",".join(reviewers_to_add),
]
)
run_gh_command([
"pr", "edit", str(pr_number),
"--add-reviewer", ",".join(reviewers_to_add)
])
except GHError as e:
logging.error("Failed to add reviewers: %s", e)
if reviewers_to_remove and owner and repo:
logging.info(
"Removing review requests from: %s", ", ".join(reviewers_to_remove)
)
logging.info("Removing review requests from: %s", ", ".join(reviewers_to_remove))
payload = json.dumps({"reviewers": list(reviewers_to_remove)})
try:
run_gh_command(
[
"api",
"--method",
"DELETE",
"api", "--method", "DELETE",
f"repos/{owner}/{repo}/pulls/{pr_number}/requested_reviewers",
"--input",
"-",
"--input", "-",
],
input_data=payload,
)
@@ -254,33 +220,15 @@ def update_reviewers(
def main() -> None:
"""Main function to handle command-line arguments and manage reviewers."""
parser = argparse.ArgumentParser(
description="Manage pull request reviewers for Home Manager."
)
parser = argparse.ArgumentParser(description="Manage pull request reviewers for Home Manager.")
parser.add_argument("--owner", required=True, help="Repository owner.")
parser.add_argument("--repo", required=True, help="Repository name.")
parser.add_argument(
"--pr-number", type=int, required=True, help="Pull request number."
)
parser.add_argument("--pr-number", type=int, required=True, help="Pull request number.")
parser.add_argument("--pr-author", required=True, help="PR author's username.")
parser.add_argument(
"--current-maintainers",
default="",
help="Space-separated list of maintainers for the changed files.",
)
parser.add_argument(
"--changed-files", default="", help="Newline-separated list of changed files."
)
parser.add_argument(
"--bot-user-name",
default="",
help="Bot user name to distinguish manual vs automated review requests.",
)
parser.add_argument(
"--dry-run",
action="store_true",
help="Show what would be done without making actual changes.",
)
parser.add_argument("--current-maintainers", default="", help="Space-separated list of maintainers for the changed files.")
parser.add_argument("--changed-files", default="", help="Newline-separated list of changed files.")
parser.add_argument("--bot-user-name", default="", help="Bot user name to distinguish manual vs automated review requests.")
parser.add_argument("--dry-run", action="store_true", help="Show what would be done without making actual changes.")
args = parser.parse_args()
no_changed_files = not args.changed_files.strip()
@@ -289,15 +237,13 @@ def main() -> None:
maintainers: set[str] = set(args.current_maintainers.split())
pending_reviewers = get_pending_reviewers(args.pr_number)
past_reviewers = get_past_reviewers(args.owner, args.repo, args.pr_number)
manually_requested, manually_removed = get_manual_reviewer_actions(
args.owner, args.repo, args.pr_number, args.bot_user_name
)
manually_requested, manually_removed = get_manual_reviewer_actions(args.owner, args.repo, args.pr_number, args.bot_user_name)
logging.info("File Maintainers: %s", " ".join(maintainers) or "None")
logging.info("Pending Reviewers: %s", " ".join(pending_reviewers) or "None")
logging.info("Past Reviewers: %s", " ".join(past_reviewers) or "None")
logging.info("Manually Requested: %s", " ".join(manually_requested) or "None")
logging.info("Manually Removed: %s", " ".join(manually_removed) or "None")
logging.info("File Maintainers: %s", ' '.join(maintainers) or "None")
logging.info("Pending Reviewers: %s", ' '.join(pending_reviewers) or "None")
logging.info("Past Reviewers: %s", ' '.join(past_reviewers) or "None")
logging.info("Manually Requested: %s", ' '.join(manually_requested) or "None")
logging.info("Manually Removed: %s", ' '.join(manually_removed) or "None")
# --- 2. Determine reviewers to remove ---
reviewers_to_remove: set[str] = set()
@@ -311,15 +257,13 @@ def main() -> None:
if reviewers_to_remove:
if args.dry_run:
logging.info(
"DRY RUN: Would remove reviewers: %s", ", ".join(reviewers_to_remove)
)
logging.info("DRY RUN: Would remove reviewers: %s", ", ".join(reviewers_to_remove))
else:
update_reviewers(
args.pr_number,
owner=args.owner,
repo=args.repo,
reviewers_to_remove=reviewers_to_remove,
reviewers_to_remove=reviewers_to_remove
)
else:
logging.info("No reviewers to remove.")
@@ -334,29 +278,20 @@ def main() -> None:
MAX_MAINTAINERS_THRESHOLD,
)
else:
users_to_exclude = (
{args.pr_author} | past_reviewers | pending_reviewers | manually_removed
)
users_to_exclude = {args.pr_author} | past_reviewers | pending_reviewers | manually_removed
potential_reviewers = maintainers - users_to_exclude
reviewers_to_add = {
user
for user in potential_reviewers
if is_collaborator(args.owner, args.repo, user)
user for user in potential_reviewers if is_collaborator(args.owner, args.repo, user)
}
non_collaborators = potential_reviewers - reviewers_to_add
if non_collaborators:
logging.warning(
"Ignoring non-collaborators: %s", ", ".join(non_collaborators)
)
logging.warning("Ignoring non-collaborators: %s", ", ".join(non_collaborators))
manually_removed_maintainers = reviewers_to_add & manually_removed
if manually_removed_maintainers:
logging.info(
"Not re-adding manually removed maintainers: %s",
", ".join(manually_removed_maintainers),
)
logging.info("Not re-adding manually removed maintainers: %s", ", ".join(manually_removed_maintainers))
reviewers_to_add -= manually_removed
if len(reviewers_to_add) > MAX_REVIEWERS:
@@ -369,9 +304,7 @@ def main() -> None:
if reviewers_to_add:
if args.dry_run:
logging.info(
"DRY RUN: Would add reviewers: %s", ", ".join(reviewers_to_add)
)
logging.info("DRY RUN: Would add reviewers: %s", ", ".join(reviewers_to_add))
else:
update_reviewers(args.pr_number, reviewers_to_add=reviewers_to_add)
else:
+12 -18
View File
@@ -14,38 +14,32 @@ import sys
def main():
print("🔍 Validating maintainer entries...")
result = subprocess.run(
["nix", "eval", "--file", "modules/lib/maintainers.nix", "--json"],
capture_output=True,
text=True,
check=True,
)
result = subprocess.run(['nix', 'eval', '--file', 'modules/lib/maintainers.nix', '--json'],
capture_output=True, text=True, check=True)
maintainers = json.loads(result.stdout)
errors = []
for name, data in maintainers.items():
if "github" not in data:
if 'github' not in data:
errors.append(f'{name}: Missing required field "github"')
if "githubId" not in data:
if 'githubId' not in data:
errors.append(f'{name}: Missing required field "githubId"')
if "githubId" in data:
github_id = data["githubId"]
if 'githubId' in data:
github_id = data['githubId']
if not isinstance(github_id, int):
errors.append(
f"{name}: githubId must be a number, not a string: {github_id} (type: {type(github_id).__name__})"
)
errors.append(f'{name}: githubId must be a number, not a string: {github_id} (type: {type(github_id).__name__})')
elif github_id <= 0:
errors.append(f"{name}: githubId must be positive: {github_id}")
errors.append(f'{name}: githubId must be positive: {github_id}')
if errors:
print("❌ Validation errors found:")
print('❌ Validation errors found:')
for error in errors:
print(f" - {error}")
print(f' - {error}')
sys.exit(1)
else:
print("✅ All maintainer entries are valid")
print(f"✅ Validated {len(maintainers)} maintainer entries")
print('✅ All maintainer entries are valid')
print(f'✅ Validated {len(maintainers)} maintainer entries')
if __name__ == "__main__":
+2 -6
View File
@@ -13,12 +13,8 @@ def main():
print("🔍 Validating maintainers.nix syntax...")
try:
subprocess.run(
["nix", "eval", "--file", "modules/lib/maintainers.nix", "--json"],
capture_output=True,
text=True,
check=True,
)
subprocess.run(['nix', 'eval', '--file', 'modules/lib/maintainers.nix', '--json'],
capture_output=True, text=True, check=True)
print("✅ Valid Nix syntax")
except subprocess.CalledProcessError:
print("❌ Invalid Nix syntax")
+4 -36
View File
@@ -9,7 +9,7 @@ let
;
cfg = config.accounts.email;
enabledAccounts = lib.filterAttrs (_n: v: v.enable) cfg.accounts;
enabledAccounts = lib.filterAttrs (n: v: v.enable) cfg.accounts;
gpgModule = types.submodule {
options = {
@@ -80,18 +80,6 @@ let
default = "none";
description = "Method to communicate the signature.";
};
htmlFormat = mkOption {
type = types.bool;
default = false;
description = ''
Whether Thunderbird should interpret {option}`text` as an HTML signature.
This maps to Thunderbird's `mail.identity.id_*.htmlSigFormat`
preference. The signature content itself is still written through
`mail.identity.id_*.htmlSigText`.
'';
};
};
};
@@ -109,9 +97,7 @@ let
type = types.bool;
default = false;
description = ''
Whether to use STARTTLS. This is discouraged and should be avoided if
possible. See <https://datatracker.ietf.org/doc/html/rfc8314> for
more.
Whether to use STARTTLS.
'';
};
@@ -414,7 +400,6 @@ let
"gmail.com"
"mailbox.org"
"migadu.com"
"outlook.office365.com-ews"
"outlook.office365.com"
"plain"
"posteo.de"
@@ -626,17 +611,6 @@ let
};
})
(mkIf (config.flavor == "outlook.office365.com-ews") {
userName = mkDefault config.address;
ews = {
host = "outlook.office365.com";
serviceDescriptionURL = "https://outlook.office365.com/EWS/Exchange.asmx";
authentication = "xoauth2";
tls.enable = true;
};
})
(mkIf (config.flavor == "fastmail.com") {
userName = mkDefault config.address;
@@ -659,14 +633,8 @@ let
(mkIf (config.flavor == "mailbox.org") {
userName = mkDefault config.address;
folders.inbox = mkDefault "INBOX";
imap = {
host = "imap.mailbox.org";
port = 993;
};
smtp = {
host = "smtp.mailbox.org";
port = 465;
};
imap.host = "imap.mailbox.org";
smtp.host = "smtp.mailbox.org";
})
(mkIf (config.flavor == "migadu.com") {
+7 -6
View File
@@ -16,10 +16,9 @@
# https://github.com/NixOS/nixpkgs/blob/nixpkgs-unstable/pkgs/development/libraries/glibc/nix-locale-archive.patch
{
config,
lib,
nixosConfig,
pkgs,
config,
...
}:
@@ -56,8 +55,9 @@ in
This option only applies to the Linux platform.
If Home Manager is installed as a NixOS submodule, this
option defaults to NixOS' {var}`i18n.glibcLocales`.
When Home Manager is configured with NixOS, the default value
will be set to {var}`i18n.glibcLocales` from the
system configuration.
'';
example = lib.literalExpression ''
pkgs.glibcLocales.override {
@@ -65,8 +65,9 @@ in
locales = [ "en_US.UTF-8/UTF-8" ];
}
'';
default = nixosConfig.i18n.glibcLocales or pkgs.glibcLocales;
defaultText = lib.literalExpression "nixosConfig.i18n.glibcLocales or pkgs.glibcLocales";
# NB. See nixos/default.nix for NixOS default.
default = pkgs.glibcLocales;
defaultText = lib.literalExpression "pkgs.glibcLocales";
};
};
+2 -2
View File
@@ -34,7 +34,7 @@ let
inherit
(
(import ./lib/file-type.nix {
(import lib/file-type.nix {
inherit homeDirectory lib pkgs;
})
)
@@ -100,7 +100,7 @@ in
(
let
dups = lib.attrNames (
lib.filterAttrs (_n: v: v > 1) (
lib.filterAttrs (n: v: v > 1) (
lib.foldAttrs (acc: v: acc + v) 0 (map (v: { ${v.target} = 1; }) cfg)
)
);
+7 -13
View File
@@ -266,15 +266,12 @@ in
default = { };
type =
with types;
lazyAttrsOf (
nullOr (oneOf [
str
path
int
float
bool
])
);
lazyAttrsOf (oneOf [
str
path
int
float
]);
example = {
EDITOR = "emacs";
GS_OPTIONS = "-sPAPERSIZE=a4";
@@ -310,9 +307,6 @@ in
BAR = "''${config.home.sessionVariables.FOO} World!";
};
```
Setting a value to `null` will skip setting the variable at all, which
may be useful when overriding.
'';
};
@@ -657,7 +651,7 @@ in
destination = "/etc/profile.d/hm-session-vars.sh";
text = ''
# Only source this once.
if [ -n "''${__HM_SESS_VARS_SOURCED-}" ]; then return; fi
if [ -n "$__HM_SESS_VARS_SOURCED" ]; then return; fi
export __HM_SESS_VARS_SOURCED=1
${config.lib.shell.exportAll cfg.sessionVariables}
+1
View File
@@ -46,6 +46,7 @@ let
in
{
meta.maintainers = with lib.maintainers; [
da157
kranzes
];
+40 -43
View File
@@ -10,16 +10,6 @@ let
fcitx5Package = cfg.fcitx5-with-addons.override { inherit (cfg) addons; };
iniFormat = pkgs.formats.ini { };
iniGlobalFormat = pkgs.formats.iniWithGlobalSection { };
normalizeFcitx5Value =
value:
if lib.isAttrs value then
lib.mapAttrs (_: normalizeFcitx5Value) value
else if builtins.isList value then
map normalizeFcitx5Value value
else if builtins.isBool value then
if value then "True" else "False"
else
value;
in
{
options = {
@@ -53,10 +43,12 @@ in
quickPhrase = lib.mkOption {
type = with lib.types; attrsOf str;
default = { };
example = {
smile = "";
angry = "()";
};
example = lib.literalExpression ''
{
smile = "";
angry = "()";
}
'';
description = "Quick phrases.";
};
@@ -81,16 +73,18 @@ in
description = ''
The global options in `config` file in ini format.
'';
example = {
Behavior = {
ActiveByDefault = false;
};
Hotkey = {
EnumerateWithTriggerKeys = true;
EnumerateSkipFirst = false;
ModifierOnlyKeyTimeout = 250;
};
};
example = lib.literalExpression ''
{
Behavior = {
ActiveByDefault = false;
};
Hotkey = {
EnumerateWithTriggerKeys = true;
EnumerateSkipFirst = false;
ModifierOnlyKeyTimeout = 250;
};
}
'';
};
inputMethod = lib.mkOption {
type = lib.types.submodule {
@@ -100,16 +94,18 @@ in
description = ''
The input method configure in `profile` file in ini format.
'';
example = {
GroupOrder."0" = "Default";
"Groups/0" = {
Name = "Default";
"Default Layout" = "us";
DefaultIM = "pinyin";
};
"Groups/0/Items/0".Name = "keyboard-us";
"Groups/0/Items/1".Name = "pinyin";
};
example = lib.literalExpression ''
{
GroupOrder."0" = "Default";
"Groups/0" = {
Name = "Default";
"Default Layout" = "us";
DefaultIM = "pinyin";
};
"Groups/0/Items/0".Name = "keyboard-us";
"Groups/0/Items/1".Name = "pinyin";
}
'';
};
addons = lib.mkOption {
type = with lib.types; (attrsOf iniGlobalFormat.type);
@@ -118,10 +114,12 @@ in
The addon configures in `conf` folder in ini format with global sections.
Each item is written to the corresponding file.
'';
example = {
classicui.globalSection.Theme = "example";
pinyin.globalSection.EmojiEnabled = "True";
};
example = lib.literalExpression ''
{
classicui.globalSection.Theme = "example";
pinyin.globalSection.EmojiEnabled = "True";
}
'';
};
};
@@ -233,12 +231,11 @@ in
lib.optionalAttrs (v != { }) {
${p} = f "fcitx5-${builtins.replaceStrings [ "/" ] [ "-" ] p}" v;
};
entries = lib.attrsets.mergeAttrsList [
(optionalFile "config" iniFormat.generate (normalizeFcitx5Value cfg.settings.globalOptions))
(optionalFile "profile" iniFormat.generate (normalizeFcitx5Value cfg.settings.inputMethod))
(optionalFile "config" iniFormat.generate cfg.settings.globalOptions)
(optionalFile "profile" iniFormat.generate cfg.settings.inputMethod)
(lib.concatMapAttrs (
name: value: optionalFile "conf/${name}.conf" iniGlobalFormat.generate (normalizeFcitx5Value value)
name: value: optionalFile "conf/${name}.conf" iniGlobalFormat.generate value
) cfg.settings.addons)
];
in
@@ -261,7 +258,7 @@ in
else if builtins.isString attrs.theme then
pkgs.writeText "fcitx5-theme.conf" attrs.theme
else
iniFormat.generate "fcitx5-${name}-theme" (normalizeFcitx5Value attrs.theme)
iniFormat.generate "fcitx5-${name}-theme" attrs.theme
))
]
) cfg.themes;
+19 -17
View File
@@ -14,25 +14,24 @@ let
dstDir = "${config.home.homeDirectory}/Library/LaunchAgents";
launchdConfig =
{ name, ... }:
{ config, name, ... }:
{
options = {
enable = lib.mkEnableOption name;
config = lib.mkOption {
type = lib.types.submodule (import ./launchd.nix);
default = { };
example = {
ProgramArguments = [
"/usr/bin/say"
"Good afternoon"
];
StartCalendarInterval = [
{
Hour = 12;
Minute = 0;
}
];
};
example = lib.literalExpression ''
{
ProgramArguments = [ "/usr/bin/say" "Good afternoon" ];
StartCalendarInterval = [
{
Hour = 12;
Minute = 0;
}
];
}
'';
description = ''
Define a launchd job. See {manpage}`launchd.plist(5)` for details.
'';
@@ -70,9 +69,9 @@ let
toAgent =
config: pkgs.writeText "${config.Label}.plist" (toPlist { escape = true; } (mutateConfig config));
agentPlists = lib.mapAttrs' (
_n: v: lib.nameValuePair "${v.config.Label}.plist" (toAgent v.config)
) (lib.filterAttrs (_n: v: v.enable) cfg.agents);
agentPlists = lib.mapAttrs' (n: v: lib.nameValuePair "${v.config.Label}.plist" (toAgent v.config)) (
lib.filterAttrs (n: v: v.enable) cfg.agents
);
agentsDrv = pkgs.runCommand "home-manager-agents" { } ''
mkdir -p "$out"
@@ -146,7 +145,7 @@ in
verboseEcho "Stopping agent '$domain/$agentName'..."
local bootout_output
bootout_output=$(run /bin/launchctl bootout --wait "$domain/$agentName" 2>&1) || {
bootout_output=$(run /bin/launchctl bootout "$domain/$agentName" 2>&1) || {
# Only show warning if it's not the common "No such process" error
if [[ "$bootout_output" != *"No such process"* ]]; then
warnEcho "Failed to stop agent '$domain/$agentName': $bootout_output"
@@ -154,6 +153,9 @@ in
verboseEcho "Agent '$domain/$agentName' was not running"
fi
}
# Give the system a moment to fully unload the agent
sleep 1
}
installAndBootstrapAgent() {
+1
View File
@@ -1,3 +1,4 @@
{ lib }:
{
# Converts a boolean to a yes/no string. This is used in lots of
# configuration formats.
+24 -40
View File
@@ -12,32 +12,20 @@
let
inherit (lib)
all
attrNames
attrValues
elem
filter
filterAttrs
head
hm
isAttrs
mapAttrs
length
tail
toposort
;
inherit (hm.dag)
empty
entriesBetween
entryAfter
entryBetween
isEntry
;
in
{
empty = { };
isEntry = e: e ? data && e ? after && e ? before;
isDag = dag: isAttrs dag && all isEntry (attrValues dag);
isDag = dag: builtins.isAttrs dag && all hm.dag.isEntry (builtins.attrValues dag);
# Takes an attribute set containing entries built by entryAnywhere,
# entryAfter, and entryBefore to a topologically sorted list of
@@ -96,19 +84,16 @@ in
# }
# true
topoSort =
let
before = a: b: elem a.name b.after;
in
dag:
let
names = attrNames dag;
dagBefore = name: filter (n: elem name dag.${n}.before) names;
dagBefore = dag: name: builtins.attrNames (filterAttrs (n: v: builtins.elem name v.before) dag);
normalizedDag = mapAttrs (n: v: {
name = n;
inherit (v) data;
after = v.after ++ dagBefore n;
after = v.after ++ dagBefore dag n;
}) dag;
sorted = toposort before (attrValues normalizedDag);
before = a: b: builtins.elem a.name b.after;
sorted = toposort before (builtins.attrValues normalizedDag);
in
if sorted ? result then
{
@@ -123,10 +108,10 @@ in
entryBetween = before: after: data: { inherit data before after; };
# Create a DAG entry with no particular dependency information.
entryAnywhere = entryBetween [ ] [ ];
entryAnywhere = hm.dag.entryBetween [ ] [ ];
entryAfter = entryBetween [ ];
entryBefore = before: entryBetween before [ ];
entryAfter = hm.dag.entryBetween [ ];
entryBefore = before: hm.dag.entryBetween before [ ];
# Given a list of entries, this function places them in order within the DAG.
# Each entry is labeled "${tag}-${entry index}" and other DAG entries can be
@@ -139,25 +124,24 @@ in
let
go =
i: before: after: entries:
let
name = "${tag}-${toString i}";
in
if entries == [ ] then
empty
hm.dag.empty
else if length entries == 1 then
{
"${name}" = hm.dag.entryBetween before after (head entries);
}
else
let
name = "${tag}-${toString i}";
in
if length entries == 1 then
{
"${name}" = entryBetween before after (head entries);
}
else
{
"${name}" = entryAfter after (head entries);
}
// go (i + 1) before [ name ] (tail entries);
{
"${name}" = hm.dag.entryAfter after (head entries);
}
// go (i + 1) before [ name ] (tail entries);
in
go 0;
entriesAnywhere = tag: entriesBetween tag [ ] [ ];
entriesAfter = tag: entriesBetween tag [ ];
entriesBefore = tag: before: entriesBetween tag before [ ];
entriesAnywhere = tag: hm.dag.entriesBetween tag [ ] [ ];
entriesAfter = tag: hm.dag.entriesBetween tag [ ];
entriesBefore = tag: before: hm.dag.entriesBetween tag before [ ];
}
+1 -3
View File
@@ -5,14 +5,12 @@ rec {
assertions = import ./assertions.nix { inherit lib; };
booleans = import ./booleans.nix;
booleans = import ./booleans.nix { inherit lib; };
darwin = import ./darwin.nix { inherit lib; };
deprecations = import ./deprecations.nix { inherit lib; };
generators = import ./generators.nix { inherit lib; };
git = import ./git.nix { inherit lib; };
gvariant = import ./gvariant.nix { inherit lib; };
maintainers = import ./maintainers.nix;
mcp = import ./mcp.nix { inherit lib; };
strings = import ./strings.nix { inherit lib; };
types = import ./types.nix { inherit gvariant lib; };
+1 -48
View File
@@ -1,47 +1,5 @@
{ lib }:
{
/*
Builds a standard warning for an option value shape that is deprecated.
Example:
mkDeprecatedOptionValueWarning {
option = [ "programs" "example" "settings" ];
old = "a list";
replacement = "`programs.example.settings.items`";
}
=> Using `programs.example.settings` as a list is deprecated and will be
removed in a future release. Please use `programs.example.settings.items`
instead.
*/
mkDeprecatedOptionValueWarning =
{
option,
old,
replacement,
details ? "",
}:
''
Using `${lib.showOption option}` as ${old} is deprecated and will be
removed in a future release. Please use ${replacement} instead.
''
+ lib.optionalString (details != "") ''
${details}
'';
# Builds a standard warning for an option value that has been renamed.
mkDeprecatedOptionValueRenameWarning =
{
option,
old,
replacement,
}:
''
The value ${old} for `${lib.showOption option}` is deprecated and will be
removed in a future release. Please use ${replacement} instead.
'';
/*
Returns a function that maps
[
@@ -235,7 +193,6 @@
optionUsesDefaultPriority = canDeferWarning && optionInfo.highestPrio >= warningPriority;
usingLegacyBranch = lib.versionOlder stateVersion since;
valuesEqual = legacy.value == current.value;
in
assert lib.assertMsg (!deferWarningToConfig || canDeferWarning) ''
`lib.hm.deprecations.mkStateVersionOptionDefault` requires both `config` and `options`
@@ -243,10 +200,7 @@
'';
{
default =
if usingLegacyBranch && !deferWarningToConfig && !valuesEqual then
lib.warn warning legacy.value
else
current.value;
if usingLegacyBranch && !deferWarningToConfig then lib.warn warning legacy.value else current.value;
defaultText = lib.literalExpression ''
if lib.versionAtLeast config.home.stateVersion "${since}" then ${currentText} else ${legacyText}
'';
@@ -255,7 +209,6 @@
shouldWarn =
deferWarningToConfig
&& usingLegacyBranch
&& !valuesEqual
&& (
if lib.isFunction shouldWarn then
shouldWarn { inherit optionInfo optionUsesDefaultPriority; }
+3 -5
View File
@@ -42,7 +42,7 @@ in
'';
};
target = mkOption {
type = types.nonEmptyStr;
type = types.str;
apply =
p:
let
@@ -106,13 +106,11 @@ in
type = types.bool;
default = false;
description = ''
When `recursive` is enabled, adds the `-ignorelinks` flag to lndir.
When `recursive` is enabled, adds `-ignorelinks` flag to lndir
It causes lndir to not treat symbolic links in the source directory specially.
The link created in the target directory will point back to the corresponding
symbolic link in the source directory. If that link points to a directory, the
resulting target will be a link to the source tree's symlink rather than a
recursively linked directory tree.
(symbolic link) file in the source directory. If the link is to a directory
'';
};
+5 -682
View File
@@ -1,684 +1,6 @@
{ lib }:
let
isDAGEntryWithOrdering' =
entry: lib.hm.dag.isEntry entry && (entry.after != [ ] || entry.before != [ ]);
hasDAGEntryWithOrdering' = attrs: lib.any isDAGEntryWithOrdering' (lib.attrValues attrs);
sortDAGEntries' =
{
cycleErrorMessage ? "Dependency cycle in DAG entries",
}:
attrs:
let
dag = lib.mapAttrs (
_: entry: if lib.hm.dag.isEntry entry then entry else lib.hm.dag.entryAnywhere entry
) attrs;
sortedDag = lib.hm.dag.topoSort dag;
entries = sortedDag.result or (abort "${cycleErrorMessage}: ${builtins.toJSON sortedDag}");
in
map (entry: {
inherit (entry) name;
value = entry.data;
}) entries;
# Freeform generators can use this to support DAG ordering while preserving
# entryAnywhere-shaped plain values beside ordered DAG entries.
toDAGOrderedAttrs' =
{
cycleErrorMessage ? "Dependency cycle in DAG entries",
}:
attrs:
if hasDAGEntryWithOrdering' attrs then
sortDAGEntries' { inherit cycleErrorMessage; } (
lib.mapAttrs (
_: entry: if isDAGEntryWithOrdering' entry then entry else lib.hm.dag.entryAnywhere entry
) attrs
)
else
lib.mapAttrsToList (name: value: { inherit name value; }) attrs;
toDAGOrderedText' =
{
renderAttrs,
renderList,
renderValue,
cycleErrorMessage ? "Dependency cycle in DAG entries",
}:
let
render =
value:
if lib.isDerivation value || builtins.isPath value then
renderValue value
else if builtins.isAttrs value then
renderAttrs (
map (entry: entry // { value = render entry.value; }) (
toDAGOrderedAttrs' { inherit cycleErrorMessage; } value
)
)
else if builtins.isList value then
renderList (map render value)
else
renderValue value;
in
render;
toDAGOrderedJsonText' =
{
cycleErrorMessage ? "Dependency cycle in DAG entries",
}:
toDAGOrderedText' {
inherit cycleErrorMessage;
renderValue = builtins.toJSON;
renderList = values: "[${lib.concatStringsSep "," values}]";
renderAttrs =
attrs:
let
renderAttr = entry: "${builtins.toJSON entry.name}:${entry.value}";
in
"{${lib.concatMapStringsSep "," renderAttr attrs}}";
};
toDAGOrderedKeyValue' =
{
mkKeyValue ? lib.generators.mkKeyValueDefault { } "=",
listsAsDuplicateKeys ? false,
listToValue ? null,
indent ? "",
cycleErrorMessage ? "Dependency cycle in DAG entries",
}:
assert listsAsDuplicateKeys -> listToValue == null;
attrs:
let
normalizeValue =
value: if listToValue != null && builtins.isList value then listToValue value else value;
mkLine = name: value: indent + mkKeyValue name value + "\n";
mkLines =
if listsAsDuplicateKeys then
name: value: map (mkLine name) (if builtins.isList value then value else [ value ])
else
name: value: [ (mkLine name (normalizeValue value)) ];
in
lib.concatStrings (
lib.concatMap (entry: mkLines entry.name entry.value) (
toDAGOrderedAttrs' { inherit cycleErrorMessage; } attrs
)
);
toDAGOrderedINI' =
{
mkSectionName ? (name: lib.escape [ "[" "]" ] name),
mkKeyValue ? lib.generators.mkKeyValueDefault { } "=",
listsAsDuplicateKeys ? false,
listToValue ? null,
cycleErrorMessage ? "Dependency cycle in INI sections",
}:
assert listsAsDuplicateKeys -> listToValue == null;
attrsOfAttrs:
let
mkSection =
section:
''
[${mkSectionName section.name}]
''
+ toDAGOrderedKeyValue' {
inherit
cycleErrorMessage
listToValue
listsAsDuplicateKeys
mkKeyValue
;
} section.value;
in
lib.concatStringsSep "\n" (
map mkSection (toDAGOrderedAttrs' { inherit cycleErrorMessage; } attrsOfAttrs)
);
mkDAGOrderedFormat' =
{
pkgs,
format,
generator,
nativeBuildInputs ? [ ],
buildCommand ? ''
cp "$valuePath" "$out"
'',
cycleErrorMessage ? null,
}:
format
// {
generate =
name: value:
pkgs.runCommandLocal name {
inherit nativeBuildInputs;
value = generator {
cycleErrorMessage =
if cycleErrorMessage == null then "Dependency cycle in ${name}" else cycleErrorMessage;
} value;
# Nix does not populate $valuePath when __structuredAttrs is true.
passAsFile = [ "value" ];
} buildCommand;
};
in
{
/**
Returns whether a value is a Home Manager DAG entry with ordering metadata.
# Inputs
`entry`
: 1\. Function argument
# Type
```
isDAGEntryWithOrdering :: Any -> Bool
```
*/
isDAGEntryWithOrdering = isDAGEntryWithOrdering';
/**
Returns whether an attribute set contains any Home Manager DAG entry with
ordering metadata.
# Inputs
`attrs`
: 1\. Function argument
# Type
```
hasDAGEntryWithOrdering :: AttrSet -> Bool
```
*/
hasDAGEntryWithOrdering = hasDAGEntryWithOrdering';
/**
Topologically sort an attribute set that contains Home Manager DAG entries.
Plain sibling values are treated as unordered DAG entries.
# Inputs
`options`
: Function options
`cycleErrorMessage` (string; optional)
: Message prefix to use when a dependency cycle is detected.
`attrs`
: Attribute set to sort
# Type
```
sortDAGEntries :: { cycleErrorMessage ? String } -> AttrSet -> [ { name :: String; value :: Any; } ]
```
# Examples
:::{.example}
## `lib.hm.generators.sortDAGEntries` usage example
```nix
lib.hm.generators.sortDAGEntries { } {
after = lib.hm.dag.entryAfter [ "before" ] "2";
before = "1";
}
=> [
{ name = "before"; value = "1"; }
{ name = "after"; value = "2"; }
]
```
:::
*/
sortDAGEntries = sortDAGEntries';
/**
Convert an attribute set to a list of name/value pairs, using topological
ordering when any value is a Home Manager DAG entry with non-empty ordering
metadata.
This is intended for freeform generators that should support optional DAG
ordering while preserving entryAnywhere-shaped plain values.
# Inputs
`options`
: Function options
`cycleErrorMessage` (string; optional)
: Message prefix to use when a dependency cycle is detected.
`attrs`
: Attribute set to convert
# Type
```
toDAGOrderedAttrs :: { cycleErrorMessage ? String } -> AttrSet -> [ { name :: String; value :: Any; } ]
```
*/
toDAGOrderedAttrs = toDAGOrderedAttrs';
/**
Render Nix values to text using caller-provided render functions while
preserving ordering from nested Home Manager DAG entries.
# Inputs
`options`
: Function options
`renderAttrs` (function)
: Render ordered attribute entries. Receives a list of
`{ name, value }` entries where `value` is already rendered text.
`renderList` (function)
: Render list values. Receives rendered element strings.
`renderValue` (function)
: Render scalar values, paths, and derivations.
`cycleErrorMessage` (string; optional)
: Message prefix to use when a dependency cycle is detected.
`value`
: Value to render
# Type
```
toDAGOrderedText :: { renderAttrs :: Function; renderList :: Function; renderValue :: Function; cycleErrorMessage ? String; } -> Any -> String
```
*/
toDAGOrderedText = toDAGOrderedText';
/**
Generate a key-value-style config file from an attribute set, preserving
ordering from Home Manager DAG entries.
# Inputs
`options`
: Function options
`mkKeyValue` (function; optional)
: Format a setting line from name and value.
`listsAsDuplicateKeys` (boolean; optional)
: Render list values as duplicate keys.
`listToValue` (function or null; optional)
: Convert list values to scalar values before rendering.
`indent` (string; optional)
: Initial indentation level.
`cycleErrorMessage` (string; optional)
: Message prefix to use when a dependency cycle is detected.
`attrs`
: Attribute set to render
# Type
```
toDAGOrderedKeyValue :: { mkKeyValue ? Function; listsAsDuplicateKeys ? Bool; listToValue ? NullOr Function; indent ? String; cycleErrorMessage ? String; } -> AttrSet -> String
```
*/
toDAGOrderedKeyValue = toDAGOrderedKeyValue';
/**
Generate an INI-style config file from an attribute set of sections while
preserving ordering from Home Manager DAG entries.
# Inputs
`options`
: Function options
`mkSectionName` (function; optional)
: Format a section name.
`mkKeyValue` (function; optional)
: Format a setting line from name and value.
`listsAsDuplicateKeys` (boolean; optional)
: Render list values as duplicate keys.
`listToValue` (function or null; optional)
: Convert list values to scalar values before rendering.
`cycleErrorMessage` (string; optional)
: Message prefix to use when a dependency cycle is detected.
`attrsOfAttrs`
: Attribute set of sections to render
# Type
```
toDAGOrderedINI :: { mkSectionName ? Function; mkKeyValue ? Function; listsAsDuplicateKeys ? Bool; listToValue ? NullOr Function; cycleErrorMessage ? String; } -> AttrSet -> String
```
*/
toDAGOrderedINI = toDAGOrderedINI';
/**
Wrap a `pkgs.formats` format so its `generate` function can render
Home Manager DAG entries in order.
# Inputs
`options`
: Function options
`pkgs` (attribute set)
: Package set used to create the generated derivation.
`format` (attribute set)
: Existing format value, for example `pkgs.formats.json { }`.
`generator` (function)
: Text renderer. Receives `{ cycleErrorMessage }` and returns a function
from value to rendered text.
`nativeBuildInputs` (list; optional)
: Build inputs needed by `buildCommand`.
`buildCommand` (string; optional)
: Builder script. Defaults to copying rendered text to `$out`.
`cycleErrorMessage` (string or null; optional)
: Message prefix to use when a dependency cycle is detected. When `null`,
the generated file name is used.
# Type
```
mkDAGOrderedFormat :: { pkgs :: AttrSet; format :: AttrSet; generator :: Function; nativeBuildInputs ? [Derivation]; buildCommand ? String; cycleErrorMessage ? NullOr String; } -> AttrSet
```
*/
mkDAGOrderedFormat = mkDAGOrderedFormat';
/**
Create a JSON format whose `generate` function renders nested ordered Home
Manager DAG entries in order.
# Inputs
`options`
: Function options
`pkgs` (attribute set)
: Package set used to create the generated derivation.
`jsonFormat` (attribute set; optional)
: Existing JSON format value. Defaults to `pkgs.formats.json { }`.
`cycleErrorMessage` (string or null; optional)
: Message prefix to use when a dependency cycle is detected. When `null`,
the generated file name is used.
# Type
```
mkDAGOrderedJsonFormat :: { pkgs :: AttrSet; jsonFormat ? AttrSet; cycleErrorMessage ? NullOr String; } -> AttrSet
```
*/
mkDAGOrderedJsonFormat =
{
pkgs,
jsonFormat ? pkgs.formats.json { },
cycleErrorMessage ? null,
}:
mkDAGOrderedFormat' {
inherit
pkgs
cycleErrorMessage
;
format = jsonFormat;
generator = { cycleErrorMessage }: toDAGOrderedJsonText' { inherit cycleErrorMessage; };
nativeBuildInputs = [ pkgs.buildPackages.jq ];
buildCommand = ''
jq . "$valuePath" > "$out"
'';
};
/**
Create a YAML format whose `generate` function renders nested ordered Home
Manager DAG entries in order.
# Inputs
`options`
: Function options
`pkgs` (attribute set)
: Package set used to create the generated derivation.
`yamlFormat` (attribute set; optional)
: Existing YAML format value. Defaults to `pkgs.formats.yaml { }`.
`cycleErrorMessage` (string or null; optional)
: Message prefix to use when a dependency cycle is detected. When `null`,
the generated file name is used.
# Type
```
mkDAGOrderedYamlFormat :: { pkgs :: AttrSet; yamlFormat ? AttrSet; cycleErrorMessage ? NullOr String; } -> AttrSet
```
*/
mkDAGOrderedYamlFormat =
{
pkgs,
yamlFormat ? pkgs.formats.yaml { },
cycleErrorMessage ? null,
}:
mkDAGOrderedFormat' {
inherit
pkgs
cycleErrorMessage
;
format = yamlFormat;
generator = { cycleErrorMessage }: toDAGOrderedJsonText' { inherit cycleErrorMessage; };
nativeBuildInputs = [ pkgs.buildPackages.remarshal ];
buildCommand = ''
json2yaml "$valuePath" "$out"
'';
};
/**
Create a TOML format whose `generate` function renders nested ordered Home
Manager DAG entries in order.
# Inputs
`options`
: Function options
`pkgs` (attribute set)
: Package set used to create the generated derivation.
`tomlFormat` (attribute set; optional)
: Existing TOML format value. Defaults to `pkgs.formats.toml { }`.
`cycleErrorMessage` (string or null; optional)
: Message prefix to use when a dependency cycle is detected. When `null`,
the generated file name is used.
# Type
```
mkDAGOrderedTomlFormat :: { pkgs :: AttrSet; tomlFormat ? AttrSet; cycleErrorMessage ? NullOr String; } -> AttrSet
```
*/
mkDAGOrderedTomlFormat =
{
pkgs,
tomlFormat ? pkgs.formats.toml { },
cycleErrorMessage ? null,
}:
mkDAGOrderedFormat' {
inherit
pkgs
cycleErrorMessage
;
format = tomlFormat;
generator = { cycleErrorMessage }: toDAGOrderedJsonText' { inherit cycleErrorMessage; };
nativeBuildInputs = [ pkgs.buildPackages.remarshal ];
buildCommand = ''
json2toml "$valuePath" "$out"
'';
};
/**
Create an INI format whose `generate` function renders ordered Home Manager
DAG entries in order.
# Inputs
`options`
: Function options
`pkgs` (attribute set)
: Package set used to create the generated derivation.
`iniFormat` (attribute set; optional)
: Existing INI format value. Defaults to `pkgs.formats.ini { ... }`.
`listsAsDuplicateKeys`, `listToValue`, `atomsCoercedToLists`
: Format options matching `pkgs.formats.ini`.
`mkSectionName`, `mkKeyValue`
: Format options for rendering section and setting lines.
`cycleErrorMessage` (string or null; optional)
: Message prefix to use when a dependency cycle is detected. When `null`,
the generated file name is used.
# Type
```
mkDAGOrderedIniFormat :: { pkgs :: AttrSet; iniFormat ? AttrSet; mkSectionName ? Function; mkKeyValue ? Function; listsAsDuplicateKeys ? Bool; listToValue ? NullOr Function; atomsCoercedToLists ? NullOr Bool; cycleErrorMessage ? NullOr String; } -> AttrSet
```
*/
mkDAGOrderedIniFormat =
{
pkgs,
mkSectionName ? (name: lib.escape [ "[" "]" ] name),
mkKeyValue ? lib.generators.mkKeyValueDefault { } "=",
listsAsDuplicateKeys ? false,
listToValue ? null,
atomsCoercedToLists ? null,
iniFormat ? pkgs.formats.ini {
inherit
atomsCoercedToLists
listsAsDuplicateKeys
listToValue
;
},
cycleErrorMessage ? null,
}:
assert listsAsDuplicateKeys -> listToValue == null;
mkDAGOrderedFormat' {
inherit
pkgs
cycleErrorMessage
;
format = iniFormat;
generator =
{ cycleErrorMessage }:
toDAGOrderedINI' {
inherit
cycleErrorMessage
listToValue
listsAsDuplicateKeys
mkKeyValue
mkSectionName
;
};
};
/**
Create a key-value format whose `generate` function renders ordered Home
Manager DAG entries in order.
# Inputs
`options`
: Function options
`pkgs` (attribute set)
: Package set used to create the generated derivation.
`keyValueFormat` (attribute set; optional)
: Existing key-value format value. Defaults to `pkgs.formats.keyValue`.
`listsAsDuplicateKeys`, `listToValue`
: Format options matching `pkgs.formats.keyValue`.
`mkKeyValue`
: Format option for rendering setting lines.
`cycleErrorMessage` (string or null; optional)
: Message prefix to use when a dependency cycle is detected. When `null`,
the generated file name is used.
# Type
```
mkDAGOrderedKeyValueFormat :: { pkgs :: AttrSet; keyValueFormat ? AttrSet; mkKeyValue ? Function; listsAsDuplicateKeys ? Bool; listToValue ? NullOr Function; cycleErrorMessage ? NullOr String; } -> AttrSet
```
*/
mkDAGOrderedKeyValueFormat =
{
pkgs,
mkKeyValue ? lib.generators.mkKeyValueDefault { } "=",
listsAsDuplicateKeys ? false,
listToValue ? null,
keyValueFormat ? pkgs.formats.keyValue {
inherit listsAsDuplicateKeys listToValue;
},
cycleErrorMessage ? null,
}:
assert listsAsDuplicateKeys -> listToValue == null;
mkDAGOrderedFormat' {
inherit
pkgs
cycleErrorMessage
;
format = keyValueFormat;
generator =
{ cycleErrorMessage }:
toDAGOrderedKeyValue' {
inherit
cycleErrorMessage
listToValue
listsAsDuplicateKeys
mkKeyValue
;
};
};
toHyprconf =
{
attrs,
@@ -688,11 +10,11 @@ in
let
inherit (lib)
all
any
concatMapStringsSep
concatStrings
concatStringsSep
filterAttrs
foldl
generators
hasPrefix
isAttrs
@@ -707,11 +29,12 @@ in
toHyprconf' =
indent: attrs:
let
isImportantField = n: _: any (prev: hasPrefix prev n) importantPrefixes;
isImportantField =
n: _: foldl (acc: prev: if hasPrefix prev n then true else acc) false importantPrefixes;
importantFields = filterAttrs isImportantField attrs;
withoutImportantFields = fields: removeAttrs fields (attrNames importantFields);
allSections = filterAttrs (_n: v: isAttrs v || isList v) attrs;
allSections = filterAttrs (n: v: isAttrs v || isList v) attrs;
sections = withoutImportantFields allSections;
mkSection =
@@ -734,7 +57,7 @@ in
inherit indent;
};
allFields = filterAttrs (_n: v: !(isAttrs v || isList v)) attrs;
allFields = filterAttrs (n: v: !(isAttrs v || isList v)) attrs;
fields = withoutImportantFields allFields;
in
mkFields importantFields
-11
View File
@@ -1,11 +0,0 @@
{ lib }:
{
diffPagerConfig = pagerCommand: {
pager = lib.genAttrs [
"diff"
"log"
"show"
] (_: pagerCommand);
};
}
+6 -71
View File
@@ -91,12 +91,6 @@
github = "b1kku";
githubId = 77858854;
};
bittner = {
name = "Peter Bittner";
email = "peter@painless.software";
github = "bittner";
githubId = 665072;
};
bjpbakker = {
email = "bart@thesoftwarecraft.com";
github = "bjpbakker";
@@ -121,12 +115,6 @@
github = "ckgxrg-salt";
githubId = 165614491;
};
csanthiago = {
name = "csanthiago";
email = "git@csanthiago.dev";
github = "csanthiago";
githubId = 8346803;
};
d-dervishi = {
email = "david.dervishi@epfl.ch";
github = "d-dervishi";
@@ -163,12 +151,6 @@
github = "dsoverlord";
githubId = 78819443;
};
dsqr = {
name = "Dave Dennis";
email = "me@dsqr.dev";
github = "0xdsqr";
githubId = 99584622;
};
dwagenk = {
email = "dwagenk@mailbox.org";
github = "dwagenk";
@@ -187,12 +169,6 @@
github = "epixtm";
githubId = 168025607;
};
ErinaYip = {
name = "erina";
email = "erinayip@outlook.com";
github = "ErinaYip";
githubId = 227132255;
};
exzombie = {
name = "Jure Varlec";
email = "jure@varlec.si";
@@ -229,12 +205,6 @@
github = "fpob";
githubId = 6289078;
};
garklein = {
name = "Garklein";
email = "garklein97@gmail.com";
github = "garklein";
githubId = 63201615;
};
gauthsvenkat = {
email = "gauthsvenkat+home-manager@gmail.com";
github = "gauthsvenkat";
@@ -258,12 +228,6 @@
}
];
};
isaacST08 = {
name = "Isaac Shiells Thomas";
email = "isaacst.nix@proton.me";
github = "isaacST08";
githubId = 106057977;
};
jack5079 = {
name = "Jack W.";
email = "nix@jack.cab";
@@ -320,12 +284,6 @@
github = "kalhauge";
githubId = 1182166;
};
kayskayskays = {
name = "Kays";
email = "115312476+kayskayskays@users.noreply.github.com";
github = "kayskayskays";
githubId = 115312476;
};
kmaasrud = {
name = "Knut Magnus Aasrud";
email = "km@aasrud.com";
@@ -464,6 +422,12 @@
github = "NitroSniper";
githubId = 44097331;
};
nurelin = {
name = "nurelin";
email = "nurelin@users.noreply.github.com";
github = "nurelin";
githubId = 5276274;
};
olmokramer = {
name = "Olmo Kramer";
email = "olmokramer@users.noreply.github.com";
@@ -547,41 +511,12 @@
github = "rszamszur";
githubId = 10353018;
};
semi710 = {
name = "Nikhil Singh";
email = "nik.singh710@gmail.com";
github = "semi710";
githubId = 60490474;
};
silmarp = {
name = "Silmar Pereira da Silva Junior";
email = "silmarjr2@gmail.com";
github = "silmarp";
githubId = 67292496;
};
soracat = {
name = "soracat";
email = "125882337+s0racat@users.noreply.github.com";
github = "s0racat";
githubId = 125882337;
};
SunOfLife1 = {
name = "SunOfLife1";
github = "SunOfLife1";
githubId = 30405063;
};
superflash41 = {
name = "Saymon Nicho";
email = "saymon.nicho@pucp.edu.pe";
github = "superflash41";
githubId = 102434258;
};
yarn = {
name = "yarncat";
email = "30006414+yaaaarn@users.noreply.github.com";
github = "yaaaarn";
githubId = 30006414;
};
zorrobert = {
name = "zorrobert";
email = "118135271+zorrobert@users.noreply.github.com";
-210
View File
@@ -1,210 +0,0 @@
{ lib }:
let
/*
Checks whether a value is a file reference submodule.
A file reference has the shape `{ file = "/path/to/file"; }` and is used
to indicate that an environment variable's value should be read from a file
at runtime (e.g. via sops-nix or systemd credentials).
Type: isFileRef :: Value -> Bool
*/
isFileRef = value: lib.isAttrs value && value ? file;
/*
Filters an `env` attrset to contain only literal (non-file-ref) values.
This is useful when a transform needs to produce two separate outputs:
one with the literal values and one with the file paths (for wrapping).
Type: literalEnv :: AttrSet -> AttrSet
Example:
literalEnv { API_KEY = "secret"; TOKEN.file = "/run/secrets/token"; }
=> { API_KEY = "secret"; }
*/
literalEnv = env: lib.filterAttrs (_: value: !isFileRef value) env;
/*
Extracts only the file paths from file-ref entries in an `env` attrset.
Returns a flat `attrsOf str` mapping variable names to their file paths.
Non-file-ref entries are excluded.
Type: fileRefEnv :: AttrSet -> AttrSet
Example:
fileRefEnv { API_KEY = "secret"; TOKEN.file = "/run/secrets/token"; }
=> { TOKEN = "/run/secrets/token"; }
*/
fileRefEnv = env: lib.mapAttrs (_: value: value.file) (lib.filterAttrs (_: isFileRef) env);
/*
Render an `env` attrset (literals + file refs) as a flat `attrsOf str`
by mapping file refs through `mkFileRef path` and leaving literals untouched.
Type: renderEnv :: (String -> String) -> AttrSet -> AttrSet
Example:
renderEnv (path: "{file:${path}}") {
API_KEY = "literal";
SESSION_TOKEN.file = "/run/secrets/token";
}
=> { API_KEY = "literal"; SESSION_TOKEN = "{file:/run/secrets/token}"; }
*/
renderEnv =
mkFileRef: env:
lib.mapAttrs (_: value: if isFileRef value then mkFileRef value.file else value) env;
/*
Wrap a local MCP server command in a shell script that reads file-backed
env values into the environment before executing the original process.
Compatible with file-based secret managers such as sops-nix or systemd
credentials. Reads file refs from `server.env`.
Type: mkEnvFilesWrapper :: { pkgs, name, server } -> Derivation
*/
mkEnvFilesWrapper =
{
pkgs,
name,
server,
}:
let
files = fileRefEnv (server.env or { });
in
pkgs.writeShellScript "mcp-${name}-wrapper" ''
${lib.concatStrings (
lib.mapAttrsToList (var: path: ''
if ${var}=$(cat ${lib.escapeShellArg path}); then
export ${var}
else
printf '[${name} wrapper ] Failed to read env var %s from %s\n' \
${lib.escapeShellArg var} \
${lib.escapeShellArg path} >&2
fi
'') files
)}
exec ${lib.escapeShellArgs ([ server.command ] ++ (server.args or [ ]))}
'';
/*
extraTransform factory: when the server has file refs in `env` and a
local `command`, replace `command` with a wrapper script that reads
those files at startup, reset `args` to `[ ]`, and drop the file refs
from `env` (leaving only literal entries).
When there is nothing to wrap, returns the server unchanged.
Type: wrapEnvFilesCommand :: { pkgs, name } -> AttrSet -> AttrSet
*/
wrapEnvFilesCommand =
{ pkgs, name }:
server:
let
files = fileRefEnv (server.env or { });
needsWrapping = files != { };
in
server
// lib.optionalAttrs needsWrapping {
command = mkEnvFilesWrapper { inherit pkgs name server; };
args = [ ];
env = literalEnv (server.env or { });
};
/*
Resolve the effective `enabled` state from a server config that may
have either an `enabled` or a `disabled` field (but not both).
Returns `null` if neither field is present, allowing callers to omit
the attribute from the output via the empty-value filter.
Type: resolveEnabled :: AttrSet -> Null | Bool
*/
resolveEnabled =
server:
let
hasEnabled = server ? enabled && server.enabled != null;
hasDisabled = server ? disabled && server.disabled != null;
in
if hasEnabled then
server.enabled
else if hasDisabled then
!server.disabled
else
null;
/*
extraTransform that adds `type = "stdio" | "http"` based on whether the
server has a `url`.
Type: addType :: AttrSet -> AttrSet
*/
addType =
server:
if server ? type then
server
else
server
// {
type = if server ? url && server.url != null then "http" else "stdio";
};
in
{
inherit
renderEnv
mkEnvFilesWrapper
wrapEnvFilesCommand
addType
;
/*
Normalise an MCP server attribute set for consumption by a client
program. Performs only universal steps:
1. Resolve `enabled` from optional `enabled`/`disabled` fields.
2. Apply each function in `extraTransforms` to the server attrs, in
order. Transforms run before `mkFileRef`, `exclude` and the
empty-value filter, so a transform can still read attrs that will
be excluded and operate on the raw env shape (with file refs).
3. Render any remaining file refs in `env` through `mkFileRef path`.
Callers that consume file refs themselves (e.g. via
`wrapEnvFilesCommand`) will have stripped them in an
extraTransform, so `mkFileRef` is a no-op for them.
4. Remove `disabled` and any keys listed in `exclude`.
5. Filter `null`, `[]`, and `{}` values.
Type: transformMcpServer ::
{ server, exclude?, extraTransforms?, mkFileRef? }
-> AttrSet
*/
transformMcpServer =
{
server,
exclude ? [ ],
extraTransforms ? [ ],
mkFileRef ? (path: "{file:${path}}"),
}:
let
enabled = resolveEnabled server;
normalised = server // {
inherit enabled;
url = if (server.url or null) != null then server.url else server.serverUrl or null;
};
transformed = lib.foldl' (acc: transform: transform acc) normalised extraTransforms;
withRenderedEnv =
transformed
// lib.optionalAttrs (transformed ? env) {
env = renderEnv mkFileRef transformed.env;
};
cleaned = removeAttrs withRenderedEnv (
[
"disabled"
"serverUrl"
]
++ exclude
);
in
lib.filterAttrs (_: value: value != null && value != [ ] && value != { }) cleaned;
}
+2 -9
View File
@@ -23,12 +23,7 @@ let
};
# Produces a Bourne shell like variable export statement.
export =
n: v:
let
value = if builtins.isBool v then lib.boolToString v else toString v;
in
''export ${n}="${value}"'';
export = n: v: ''export ${n}="${toString v}"'';
# Wrap a list of strings to a given line width.
# Packs as many items as possible per line without exceeding maxWidth.
@@ -74,9 +69,7 @@ in
# Given an attribute set containing shell variable names and their
# assignment, this function produces a string containing an export
# statement for each set entry.
exportAll =
vars:
lib.concatStringsSep "\n" (lib.mapAttrsToList export (lib.filterAttrs (_k: v: v != null) vars));
exportAll = vars: lib.concatStringsSep "\n" (lib.mapAttrsToList export vars);
# Formats a list of items for shell array content with intelligent width optimization.
# IMPORTANT: This formats the CONTENTS of an array (what goes inside parentheses),
+1 -8
View File
@@ -29,7 +29,7 @@ rec {
++ upperChars
++ stringToCharacters "0123456789";
empties = l: genList (_x: "") (length l);
empties = l: genList (x: "") (length l);
unsafeInName = stringToCharacters (replaceStrings safeChars (empties safeChars) path);
@@ -87,11 +87,4 @@ rec {
# Returns true for strings like `SCREAMING_SNAKE_CASE`, `SOME_CONSTANT`.
# Must be all uppercase letters/numbers, with words separated by single underscores.
isScreamingSnakeCase = str: builtins.match "^[A-Z0-9]+(_[A-Z0-9]+)*$" str != null;
# Check if the content is path-like (a path, a Nix store path string, or a derivation).
isPathLike =
content:
lib.isPath content
|| (builtins.isString content && lib.hasPrefix "${builtins.storeDir}/" content)
|| lib.isDerivation content;
}
+2 -4
View File
@@ -7,7 +7,7 @@ rec {
if builtins.isBool v then
if v then "true" else "false"
else if builtins.isString v then
''"${lib.escape [ "\\" "\"" "`" ] v}"''
''"${v}"''
else if builtins.isList v then
let
shell = import ./shell.nix { inherit lib; };
@@ -38,7 +38,5 @@ rec {
let
separator = if indent == "" then "\n" else "\n" + indent;
in
lib.concatStringsSep separator (
lib.mapAttrsToList export (lib.filterAttrs (_k: v: v != null) vars)
);
lib.concatStringsSep separator (lib.mapAttrsToList export vars);
}
+133 -228
View File
@@ -5,7 +5,6 @@
{
config,
lib,
nixosConfig,
pkgs,
...
}:
@@ -14,141 +13,38 @@ let
cfg = config.fonts.fontconfig;
xml = pkgs.formats.xml { };
inherit (config.home) profileDirectory;
globalConfig = config;
fontConfigFileType = lib.types.submodule (
let
noteContentOptionsExclusivity = ''
Note that {option}`source` will be derived from {option}`settings` and {option}`text` if they are
set; with override priorities being preserved. As a consequence, exactly
one of {option}`settings`, {option}`text`, and {option}`source` must be set with highest priority.
'';
in
{
config,
name,
options,
...
}:
{ name, ... }:
{
options = {
enable = lib.mkOption {
description = ''
Whether this file should be generated. This option allows specific
files to be disabled.
'';
type = lib.types.bool;
inherit
(lib.hm.deprecations.mkStateVersionOptionDefault {
inherit (globalConfig.home) stateVersion;
since = "26.11";
optionPath = [
"fonts"
"fontconfig"
"configFile"
name
"enable"
];
legacy.value = false;
current.value = true;
})
default
defaultText
;
};
label = lib.mkOption {
description = "Label to use for the name of the config file.";
default = name;
defaultText = lib.literalExpression "<name>";
type = lib.types.str;
};
priority = lib.mkOption {
description = ''
Determines the order in which configuration files are loaded.
Must be a value within the range of 0-99, where priority 0 is the
highest priority and 99 is the lowest.
'';
default = 90;
type = lib.types.ints.between 0 99;
};
target = lib.mkOption {
description = ''
Path to the target file relative to
{file}`''${config.xdg.configHome}/fontconfig/conf.d/`.
'';
default = "${toString config.priority}-hm-${config.label}.conf";
defaultText = ''"''${toString config.priority}-hm-''${config.label}.conf"'';
type = lib.types.nonEmptyStr;
};
settings = lib.mkOption {
inherit (xml) type;
default = { };
example = {
description = "Enable antialiasing";
match = {
"@target" = "font";
edit = {
"@mode" = "assign";
"@name" = "antialias";
bool = "true";
};
};
};
description = ''
Structured attrs of settings in the format of `pkgs.format.xml {}`. The
settings are implicitly wrapped inside the `<fontconfig>` tag, i.e. as
`{ fontconfig = <settings>; }`.
''
+ noteContentOptionsExclusivity;
};
enable = lib.mkEnableOption "Whether this font config file should be generated.";
text = lib.mkOption {
description = ''
Verbatim contents of the config file.
''
+ noteContentOptionsExclusivity;
type = lib.types.nullOr lib.types.lines;
default = null;
type = with lib.types; nullOr lines;
description = "Verbatim contents of the config file. If this option is null then the 'source' option must be set.";
};
source = lib.mkOption {
type = lib.types.nullOr lib.types.path;
default = null;
description = "Config file to source. Alternatively, use the 'text' option instead.";
};
label = lib.mkOption {
type = lib.types.str;
default = name;
defaultText = "<name>";
description = "Label to use for the name of the config file.";
};
priority = lib.mkOption {
type = lib.types.ints.between 0 99;
default = 90;
description = ''
Path to the source file.
''
+ noteContentOptionsExclusivity;
type =
let
thisOption = lib.showOption [
"fonts"
"fontconfig"
"configFile"
name
"source"
];
abortOnNull =
x:
if x != null then
x
else
abort ''
Setting '${thisOption}' to null is not
required anymore and disallowed. You can safely remove this definition.
'';
in
with lib.types;
coercedTo (nullOr path) abortOnNull path;
Determines the order in which configs are loaded.
Must be a value within the range of 0-99, where priority 0 is the highest priority and 99 is the lowest.
'';
};
};
config.source =
let
fileName = lib.hm.strings.storeFileName "hm-fontconfig-${config.label}.xml";
mkSettingsFile = settings: xml.generate fileName { fontconfig = settings; };
mkTextFile = pkgs.writeText fileName;
in
lib.mkMerge [
(lib.mkIf (config.settings != { }) (lib.mkDerivedConfig options.settings mkSettingsFile))
(lib.mkIf (config.text != null) (lib.mkDerivedConfig options.text mkTextFile))
];
}
);
@@ -174,25 +70,13 @@ in
fonts.fontconfig = {
enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Whether to enable fontconfig configuration. This will, for example,
allow fontconfig to discover fonts and configurations installed through
{var}`home.packages` and {command}`nix-env`.
If Home Manager is installed as a NixOS submodule and
{var}`home-manager.useUserPackages` is enabled, this option defaults to the
value of NixOS' {var}`fonts.fontconfig.enable`.
'';
# On NixOS, the per-user directory inside /etc/profiles is not known by
# fontconfig by default.
default =
nixosConfig != null
&& nixosConfig.home-manager.useUserPackages
&& nixosConfig.fonts.fontconfig.enable;
defaultText = lib.literalExpression ''
nixosConfig != null
&& nixosConfig.home-manager.useUserPackages
&& nixosConfig.fonts.fontconfig.enable;
Whether to enable fontconfig configuration. This will, for
example, allow fontconfig to discover fonts and
configurations installed through
{var}`home.packages` and
{command}`nix-env`.
'';
};
@@ -278,12 +162,13 @@ in
type = lib.types.attrsOf fontConfigFileType;
default = { };
description = ''
Config files that will be installed to {file}`~/.config/fontconfig/conf.d/`.
Extra font config files that will be added to `~/.config/fontconfig/conf.d/`.
Files are named like `fontconfig/conf.d/{priority}-{label}.conf`.
'';
example = {
tamzen-disable-antialiasing = {
tamzen = {
enable = true;
priority = 90;
label = "tamzen-disable-antialiasing";
text = ''
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
@@ -300,12 +185,13 @@ in
</match>
</fontconfig>
'';
};
priority = 90;
}; # => conf.d/90-tamzen-disable-antialiasing.conf
commit-mono-options = {
enable = true;
priority = 80;
source = "./resources/fontconfig/commit-mono.conf";
};
priority = 80;
}; # => conf.d/80-commit-mono-options.conf
};
};
@@ -349,93 +235,112 @@ in
fi
'';
fonts.fontconfig.configFile = {
fonts =
let
mkInclude = path: {
"@ignore_missing" = "yes";
"#text" = path;
};
in
{
fonts.fontconfig.configFile =
let
mkFontconfigConf = conf: ''
<?xml version='1.0'?>
<!-- Generated by Home Manager. -->
<!DOCTYPE fontconfig SYSTEM 'urn:fontconfig:fonts.dtd'>
<fontconfig>
${conf}
</fontconfig>
'';
in
{
fonts = {
enable = true;
priority = 10;
settings = {
description = "Add fonts in the Nix user profile";
include = map mkInclude [
"${config.home.path}/etc/fonts/conf.d"
"${config.home.path}/etc/fonts/fonts.conf"
];
dir = [
"${config.home.path}/lib/X11/fonts"
"${config.home.path}/share/fonts"
"${config.home.profileDirectory}/lib/X11/fonts"
"${config.home.profileDirectory}/share/fonts"
];
cachedir = "${config.home.path}/lib/fontconfig/cache";
};
source = null; # Set the source as null explicitly so that it cannot be overwritten by mistake by a user
text = mkFontconfigConf ''
<description>Add fonts in the Nix user profile</description>
<include ignore_missing="yes">${config.home.path}/etc/fonts/conf.d</include>
<include ignore_missing="yes">${config.home.path}/etc/fonts/fonts.conf</include>
<dir>${config.home.path}/lib/X11/fonts</dir>
<dir>${config.home.path}/share/fonts</dir>
<dir>${profileDirectory}/lib/X11/fonts</dir>
<dir>${profileDirectory}/share/fonts</dir>
<cachedir>${config.home.path}/lib/fontconfig/cache</cachedir>
'';
};
rendering =
let
toXmlValue =
value:
if lib.isBool value then
{ bool = lib.boolToString value; }
else if lib.isString value then
{ const = value; }
else
throw "expected bool or string but got ${lib.typeOf value}: ${toString value}";
assign =
name: value:
toXmlValue value
// {
"@mode" = "assign";
"@name" = name;
};
content =
lib.optional (cfg.antialiasing != null) (assign "antialias" cfg.antialiasing)
++ lib.optionals (cfg.hinting != null) [
(assign "hinting" true)
(assign "hintstyle" ("hint" + cfg.hinting))
]
++ lib.optional (cfg.subpixelRendering != null) (
assign "rgba" (lib.replaceStrings [ "ertical-" ] [ "" ] cfg.subpixelRendering)
rendering =
let
set =
name: value:
let
xmlValue =
if builtins.isBool value then
"<bool>${lib.boolToString value}</bool>"
else if builtins.isString value then
"<const>${value}</const>"
else
throw "expected bool or string but got ${builtins.typeOf value}: ${toString value}";
in
''
<match target="font">
<edit mode="assign" name="${name}">
${xmlValue}
</edit>
</match>
'';
content =
lib.optional (cfg.antialiasing != null) (set "antialias" cfg.antialiasing)
++ lib.optionals (cfg.hinting != null) [
(set "hinting" true)
(set "hintstyle" ("hint" + cfg.hinting))
]
++ lib.optional (cfg.subpixelRendering != null) (
set "rgba" (builtins.replaceStrings [ "ertical-" ] [ "" ] cfg.subpixelRendering)
);
in
{
enable = builtins.length content > 0;
priority = 10;
source = null;
text = mkFontconfigConf (
lib.concatStrings ([ "<description>Set the rendering mode</description>\n" ] ++ content)
);
in
{
enable = lib.length content > 0;
priority = 10;
settings = {
description = "Set the rendering mode";
match = {
"@target" = "font";
edit = content;
};
};
};
default-fonts =
let
filterNonEmpty = lib.filterAttrs (_: fonts: fonts != [ ]);
mkAlias = name: fonts: {
"@binding" = "same";
family = if name == "sansSerif" then "sans-serif" else name;
prefer.family = fonts;
default-fonts =
let
genDefault =
fonts: name:
lib.optionalString (fonts != [ ]) ''
<alias binding="same">
<family>${name}</family>
<prefer>
${lib.concatStringsSep "" (
map (font: ''
<family>${font}</family>
'') fonts
)}
</prefer>
</alias>
'';
in
{
enable = true;
priority = 52;
source = null;
text = mkFontconfigConf ''
<!-- Default fonts -->
${genDefault cfg.defaultFonts.sansSerif "sans-serif"}
${genDefault cfg.defaultFonts.serif "serif"}
${genDefault cfg.defaultFonts.monospace "monospace"}
${genDefault cfg.defaultFonts.emoji "emoji"}
'';
};
in
{
enable = true;
priority = 52;
settings = {
description = "Set default fonts";
alias = lib.mapAttrsToList mkAlias (filterNonEmpty cfg.defaultFonts);
};
};
};
};
xdg.configFile = lib.mapAttrs' (
_name: config:
lib.nameValuePair "fontconfig/conf.d/${config.target}" {
inherit (config) enable source;
name: config:
lib.nameValuePair "fontconfig/conf.d/${toString config.priority}-hm-${config.label}.conf" {
inherit (config) enable text;
source = lib.mkIf (config.source != null) config.source;
}
) cfg.configFile;
};
@@ -13,7 +13,7 @@ let
cfg3 = config.gtk.gtk3;
cfg4 = config.gtk.gtk4;
gtkLib = import ./lib.nix { inherit lib; };
gtkLib = import ./gtk/lib.nix { inherit lib; };
themeType = gtkLib.mkThemeType {
typeName = "theme";
@@ -41,9 +41,9 @@ in
];
imports = [
./gtk2.nix
./gtk3.nix
./gtk4.nix
./gtk/gtk2.nix
./gtk/gtk3.nix
./gtk/gtk4.nix
];
options.gtk = {
@@ -52,26 +52,26 @@ let
}
);
isNewsFile = n: v: v == "regular" && lib.hasSuffix ".nix" n && n != "default.nix";
isDirectory = _n: v: v == "directory";
isNixFile = n: v: v == "regular" && lib.hasSuffix ".nix" n;
isDirectory = n: v: v == "directory";
# Recursively collect all news .nix files from a directory
collectNewsFiles =
# Recursively collect all .nix files from a directory
collectNixFiles =
dir:
let
contents = builtins.readDir dir;
files = lib.filterAttrs isNewsFile contents;
files = lib.filterAttrs isNixFile contents;
fileList = map (file: dir + "/${file}") (builtins.attrNames files);
# Process subdirectories
subdirs = lib.filterAttrs isDirectory contents;
subdirFiles = lib.concatMap (subdir: collectNewsFiles (dir + "/${subdir}")) (
subdirFiles = lib.concatMap (subdir: collectNixFiles (dir + "/${subdir}")) (
builtins.attrNames subdirs
);
in
fileList ++ subdirFiles;
newsFiles = collectNewsFiles ./.;
newsFiles = collectNixFiles ./news;
newsEntries = map (
newsFile:
let
@@ -1,3 +1,9 @@
{
config,
lib,
pkgs,
...
}:
{
time = "2025-11-04T15:44:03+00:00";
condition = true;
@@ -1,12 +0,0 @@
{ config, ... }:
{
time = "2026-01-13T01:11:50+00:00";
condition = config.services.home-manager.autoUpgrade.enable;
message = ''
Multiple new options are available:
- services.home-manager.autoUpgrade.flags
- services.home-manager.autoUpgrade.preSwitchCommands
'';
}
@@ -1,15 +0,0 @@
{
time = "2026-03-02T15:33:49+00:00";
condition = true;
message = ''
New modules are available: 'programs.cursor', 'programs.vscodium',
'programs.windsurf', 'programs.kiro', and 'programs.antigravity'.
These provide dedicated configuration for VSCode-based editors,
allowing multiple editors to be configured simultaneously.
Users who previously set 'programs.vscode.package' to a non-vscode
package (e.g. pkgs.vscodium) should migrate to the corresponding
dedicated module instead.
'';
}

Some files were not shown because too many files have changed in this diff Show More