1
0
mirror of https://github.com/nix-community/home-manager synced 2024-06-02 04:53:33 +02:00
home-manager/home-manager/home-manager
Robert Helgesson bf3a8c6383
home-manager: point <home-manager> to project root
Before this path would point to the modules path. Using the project
root instead makes it possible to set `<home-manager>` to point to a
downloadable archive of Home Manager. This should make it
significantly easier to install and keep Home Manager up to date.

To match this change we also deprecate the Home Manager option

    programs.home-manager.modulesPath

and instead ask users to use

    programs.home-manager.path
2017-10-24 01:14:22 +02:00

308 lines
7.9 KiB
Bash

#!@bash@/bin/bash
# This code explicitly requires GNU Core Utilities and we therefore
# need to ensure they are prioritized over any other similarly named
# tools on the system.
PATH=@coreutils@/bin:@less@/bin${PATH:+:}$PATH
set -euo pipefail
function errorEcho() {
echo $* >&2
}
# Attempts to set the HOME_MANAGER_CONFIG global variable.
#
# If no configuration file can be found then this function will print
# an error message and exit with an error code.
function setConfigFile() {
if [[ -v HOME_MANAGER_CONFIG ]] ; then
if [[ ! -e "$HOME_MANAGER_CONFIG" ]] ; then
errorEcho "No configuration file found at $HOME_MANAGER_CONFIG"
exit 1
fi
HOME_MANAGER_CONFIG="$(realpath "$HOME_MANAGER_CONFIG")"
return
fi
local confFile
for confFile in "$HOME/.config/nixpkgs/home.nix" \
"$HOME/.nixpkgs/home.nix" ; do
if [[ -e "$confFile" ]] ; then
HOME_MANAGER_CONFIG="$confFile"
return
fi
done
errorEcho "No configuration file found." \
"Please create one at ~/.config/nixpkgs/home.nix"
exit 1
}
function setHomeManagerNixPath() {
local path
for path in "@HOME_MANAGER_PATH@" \
"$HOME/.config/nixpkgs/home-manager" \
"$HOME/.nixpkgs/home-manager" ; do
if [[ -e "$path" || "$path" =~ ^https?:// ]] ; then
export NIX_PATH="$NIX_PATH${NIX_PATH:+:}home-manager=$path"
return
fi
done
}
function doBuildAttr() {
setConfigFile
setHomeManagerNixPath
local extraArgs="$*"
for p in "${EXTRA_NIX_PATH[@]}"; do
extraArgs="$extraArgs -I $p"
done
if [[ -v VERBOSE ]]; then
extraArgs="$extraArgs --show-trace"
fi
nix-build \
"<home-manager/home-manager/home-manager.nix>" \
$extraArgs \
--argstr confPath "$HOME_MANAGER_CONFIG" \
--argstr confAttr "$HOME_MANAGER_CONFIG_ATTRIBUTE"
}
# Presents news to the user. Takes as argument the path to a "news
# info" file as generated by `buildNews`.
function presentNews() {
local infoFile="$1"
# shellcheck source=/dev/null
. "$infoFile"
if [[ $newsNumUnread -eq 0 ]]; then
return
elif [[ "$newsDisplay" == "silent" ]]; then
return
elif [[ "$newsDisplay" == "notify" ]]; then
local msg
if [[ $newsNumUnread -eq 1 ]]; then
msg="There is an unread and relevant news item.\n"
msg+="Read it by running the command '$(basename "$0") news'."
else
msg="There are $newsNumUnread unread and relevant news items.\n"
msg+="Read them by running the command '$(basename "$0") news'."
fi
# Not actually an error but here stdout is reserved for
# nix-build output.
errorEcho
errorEcho -e "$msg"
errorEcho
if [[ -v DISPLAY ]] && type -P notify-send > /dev/null; then
notify-send "Home Manager" "$msg"
fi
elif [[ "$newsDisplay" == "show" ]]; then
doShowNews --unread
else
errorEcho "Unknown 'news.display' setting '$newsDisplay'."
fi
}
function doBuild() {
local newsInfo
newsInfo=$(buildNews)
local exitCode
doBuildAttr -A activationPackage \
&& exitCode=0 || exitCode=1
presentNews "$newsInfo"
return $exitCode
}
function doSwitch() {
local newsInfo
newsInfo=$(buildNews)
local generation
local exitCode=0
local wrkdir
# Build the generation and run the activate script. Note, we
# specify an output link si that it is treated as a GC root. This
# prevents an unfortunately timed GC from removing the generation
# before activation completes.
wrkdir="$(mktemp -d)"
generation=$(doBuildAttr -o "$wrkdir/result" -A activationPackage) \
&& $generation/activate || exitCode=1
# Because the previous command never fails, the script keeps
# running and $wrkdir is always removed.
rm -r "$wrkdir"
presentNews "$newsInfo"
return $exitCode
}
function doListGens() {
pushd "/nix/var/nix/profiles/per-user/$USER" > /dev/null
ls --color=yes -gG --sort time home-manager-*-link \
| cut -d' ' -f 4-
popd > /dev/null
}
function doListPackages() {
local outPath
outPath="$(nix-env -q --out-path | grep -o '/.*home-manager-path$')"
if [[ -n "$outPath" ]] ; then
nix-store -q --references "$outPath" | sed 's/[^-]*-//'
else
errorEcho "No home-manager packages seem to be installed."
fi
}
function newsReadIdsFile() {
local dataDir="${XDG_DATA_HOME:-$HOME/.local/share}/home-manager"
local path="$dataDir/news-read-ids"
# If the path doesn't exist then we should create it, otherwise
# Nix will error out when we attempt to use builtins.readFile.
if [[ ! -f "$path" ]]; then
mkdir -p "$dataDir"
touch "$path"
fi
echo "$path"
}
# Builds news meta information to be sourced into this script.
#
# Note, we suppress build output to remove unnecessary verbosity. We
# also use "no out link" to avoid the need for a build directory
# (although this exposes the risk of GC removing the result before we
# manage to source it).
function buildNews() {
doBuildAttr --quiet \
--attr newsInfo \
--no-out-link \
--arg check false \
--argstr newsReadIdsFile "$(newsReadIdsFile)"
}
function doShowNews() {
local infoFile
infoFile=$(buildNews) || return 1
# shellcheck source=/dev/null
. "$infoFile"
case $1 in
--all)
${PAGER:-less} "$newsFileAll"
;;
--unread)
${PAGER:-less} "$newsFileUnread"
;;
*)
errorEcho "Unknown argument $1"
return 1
esac
if [[ -s "$newsUnreadIdsFile" ]]; then
local newsReadIdsFile
newsReadIdsFile="$(newsReadIdsFile)"
cat "$newsUnreadIdsFile" >> "$newsReadIdsFile"
fi
}
function doHelp() {
echo "Usage: $0 [OPTION] COMMAND"
echo
echo "Options"
echo
echo " -f FILE The home configuration file."
echo " Default is '~/.config/nixpkgs/home.nix'."
echo " -A ATTRIBUTE Optional attribute that selects a configuration"
echo " expression in the configuration file."
echo " -I PATH Add a path to the Nix expression search path."
echo " -v Verbose output"
echo " -n Do a dry run, only prints what actions would be taken"
echo " -h Print this help"
echo
echo "Commands"
echo " help Print this help"
echo " build Build configuration into result directory"
echo " switch Build and activate configuration"
echo " generations List all home environment generations"
echo " packages List all packages installed in home-manager-path"
echo " news Show news entries in a pager"
}
EXTRA_NIX_PATH=()
HOME_MANAGER_CONFIG_ATTRIBUTE=""
while getopts f:I:A:vnh opt; do
case $opt in
f)
HOME_MANAGER_CONFIG="$OPTARG"
;;
I)
EXTRA_NIX_PATH+=("$OPTARG")
;;
A)
HOME_MANAGER_CONFIG_ATTRIBUTE="$OPTARG"
;;
v)
export VERBOSE=1
;;
n)
export DRY_RUN=1
;;
h)
doHelp
exit 0
;;
*)
errorEcho "Unknown option -$OPTARG"
doHelp >&2
exit 1
;;
esac
done
# Get rid of the options.
shift "$((OPTIND-1))"
cmd="$*"
case "$cmd" in
build)
doBuild
;;
switch)
doSwitch
;;
generations)
doListGens
;;
packages)
doListPackages
;;
news)
doShowNews --all
;;
help|--help)
doHelp
;;
*)
errorEcho "Unknown command: $cmd"
doHelp >&2
exit 1
;;
esac