home-manager: rework news command

This new way of handling news should also work in Nix Flake setups.
This commit is contained in:
Robert Helgesson 2023-07-29 19:56:00 +02:00
parent 729ab77f9e
commit 3db43afcb4
No known key found for this signature in database
GPG key ID: 36BDAA14C2797E89
6 changed files with 158 additions and 130 deletions

View file

@ -0,0 +1,54 @@
# Used by the home-manager tool to present news to the user. The content of this
# file is considered internal and the exported fields may change without
# warning.
{ newsJsonFile, newsReadIdsFile ? null }:
let
inherit (builtins)
concatStringsSep filter hasAttr isString length optionalString readFile
replaceStrings sort split;
newsJson = builtins.fromJSON (builtins.readFile newsJsonFile);
# Sorted and relevant entries.
relevantEntries =
sort (a: b: a.time > b.time) (filter (e: e.condition) newsJson.entries);
newsReadIds = if newsReadIdsFile == null then
{ }
else
let ids = filter isString (split "\n" (readFile newsReadIdsFile));
in builtins.listToAttrs (map (id: {
name = id;
value = null;
}) ids);
newsIsRead = entry: hasAttr entry.id newsReadIds;
newsUnread = let pred = entry: entry.condition && !newsIsRead entry;
in filter pred relevantEntries;
prettyTime = t: replaceStrings [ "T" "+00:00" ] [ " " "" ] t;
layoutNews = entries:
let
mkTextEntry = entry:
let flag = if newsIsRead entry then "read" else "unread";
in ''
* ${prettyTime entry.time} [${flag}]
${replaceStrings [ "\n" ] [ "\n " ] entry.message}
'';
in concatStringsSep "\n\n" (map mkTextEntry entries);
in {
meta = {
numUnread = length newsUnread;
display = newsJson.display;
ids = concatStringsSep "\n" (map (e: e.id) newsJson.entries);
};
news = {
all = layoutNews relevantEntries;
unread = layoutNews newsUnread;
};
}

View file

@ -529,13 +529,16 @@ function doBuildFlake() {
"${PASSTHROUGH_OPTS[@]}"
}
# Presents news to the user. Takes as argument the path to a "news
# info" file as generated by `buildNews`.
# Presents news to the user as specified by the `news.display` option.
function presentNews() {
local infoFile="$1"
local newsNixFile="$WORK_DIR/news.nix"
buildNews "$newsNixFile"
# shellcheck source=/dev/null
. "$infoFile"
local newsDisplay
newsDisplay="$(nix-instantiate --eval --expr "(import ${newsNixFile}).meta.display" | xargs)"
local newsNumUnread
newsNumUnread="$(nix-instantiate --eval --expr "(import ${newsNixFile}).meta.numUnread" | xargs)"
# shellcheck disable=2154
if [[ $newsNumUnread -eq 0 ]]; then
@ -601,12 +604,9 @@ function doBuild() {
${NO_OUT_LINK+--no-out-link} \
--attr activationPackage \
|| return
local newsInfo
newsInfo=$(buildNews)
presentNews "$newsInfo"
fi
presentNews
}
function doSwitch() {
@ -632,12 +632,9 @@ function doSwitch() {
--out-link "$generation" \
--attr activationPackage \
&& "$generation/activate" || return
local newsInfo
newsInfo=$(buildNews)
presentNews "$newsInfo"
fi
presentNews
}
function doListGens() {
@ -718,62 +715,88 @@ function newsReadIdsFile() {
echo "$path"
}
# Builds news meta information to be sourced into this script.
# Builds the Home Manager news data file.
#
# Note, we suppress build output to remove unnecessary verbosity. We
# put the output in the work directory to avoid the risk of an
# unfortunately timed GC removing it.
function buildNews() {
setFlakeAttribute
local newsNixFile="$1"
local newsJsonFile="$WORK_DIR/news.json"
if [[ -v FLAKE_CONFIG_URI ]]; then
# translators: Here "flake" is a noun that refers to the Nix Flakes feature.
_iError "Sorry, this command is not yet supported in flake setup" >&2
exit 1
# TODO: Use check=false to make it more likely that the build succeeds.
doBuildFlake \
"$FLAKE_CONFIG_URI.config.news.json.output" \
--quiet \
--out-link "$newsJsonFile" \
|| return
else
doBuildAttr \
--out-link "$newsJsonFile" \
--arg check false \
--attr config.news.json.output \
> /dev/null \
|| return
fi
local output
output="$WORK_DIR/news-info.sh"
local extraArgs=()
doBuildAttr \
--out-link "$output" \
--no-build-output \
--quiet \
--arg check false \
--argstr newsReadIdsFile "$(newsReadIdsFile)" \
--attr newsInfo \
> /dev/null
for p in "${EXTRA_NIX_PATH[@]}"; do
extraArgs=("${extraArgs[@]}" "-I" "$p")
done
echo "$output"
local readIdsFile
readIdsFile=$(newsReadIdsFile)
nix-instantiate \
--no-build-output --strict \
--eval '<home-manager/home-manager/build-news.nix>' \
--arg newsJsonFile "$newsJsonFile" \
--arg newsReadIdsFile "$readIdsFile" \
"${extraArgs[@]}" \
> "$newsNixFile"
}
function doShowNews() {
setWorkDir
setFlakeAttribute
local infoFile
infoFile=$(buildNews) || return 1
local newsNixFile="$WORK_DIR/news.nix"
buildNews "$newsNixFile"
# shellcheck source=/dev/null
. "$infoFile"
local readIdsFile
readIdsFile=$(newsReadIdsFile)
# shellcheck disable=2154
local news
# shellcheck disable=2154,2046
case $1 in
--all)
${PAGER:-less} "$newsFileAll"
news="$(nix-instantiate --quiet --eval --expr "(import ${newsNixFile}).news.all")"
;;
--unread)
${PAGER:-less} "$newsFileUnread"
news="$(nix-instantiate --quiet --eval --expr "(import ${newsNixFile}).news.unread")"
;;
*)
_i 'Unknown argument %s' "$1"
return 1
esac
# shellcheck disable=2154
if [[ -s "$newsUnreadIdsFile" ]]; then
local newsReadIdsFile
newsReadIdsFile="$(newsReadIdsFile)"
cat "$newsUnreadIdsFile" >> "$newsReadIdsFile"
fi
# Prints the news without surrounding quotes.
echo -e "${news:1:-1}" | ${PAGER:-less}
local allIds
allIds="$(nix-instantiate --quiet --eval --expr "(import ${newsNixFile}).meta.ids")"
allIds="${allIds:1:-1}" # Trim surrounding quotes.
local readIdsFileNew="$WORK_DIR/news-read-ids.new"
{
cat "$readIdsFile"
echo -e "$allIds"
} | sort | uniq > "$readIdsFileNew"
mv -f "$readIdsFileNew" "$readIdsFile"
}
function doUninstall() {

View file

@ -15,60 +15,4 @@ let
check = check;
};
newsReadIds = if newsReadIdsFile == null then
{ }
else
let ids = splitString "\n" (fileContents newsReadIdsFile);
in builtins.listToAttrs (map (id: {
name = id;
value = null;
}) ids);
newsIsRead = entry: builtins.hasAttr entry.id newsReadIds;
newsFiltered = let pred = entry: entry.condition && !newsIsRead entry;
in filter pred env.newsEntries;
newsNumUnread = length newsFiltered;
newsFileUnread = pkgs.writeText "news-unread.txt" (concatMapStringsSep "\n\n"
(entry:
let
time =
replaceStrings [ "T" ] [ " " ] (removeSuffix "+00:00" entry.time);
in ''
* ${time}
${replaceStrings [ "\n" ] [ "\n " ] entry.message}
'') newsFiltered);
newsFileAll = pkgs.writeText "news-all.txt" (concatMapStringsSep "\n\n"
(entry:
let
flag = if newsIsRead entry then "read" else "unread";
time =
replaceStrings [ "T" ] [ " " ] (removeSuffix "+00:00" entry.time);
in ''
* ${time} [${flag}]
${replaceStrings [ "\n" ] [ "\n " ] entry.message}
'') env.newsEntries);
# File where each line corresponds to an unread news entry
# identifier. If non-empty then the file ends in "\n".
newsUnreadIdsFile = pkgs.writeText "news-unread-ids"
(let text = concatMapStringsSep "\n" (entry: entry.id) newsFiltered;
in text + optionalString (text != "") "\n");
newsInfo = pkgs.writeText "news-info.sh" ''
local newsNumUnread=${toString newsNumUnread}
local newsDisplay="${env.newsDisplay}"
local newsFileAll="${newsFileAll}"
local newsFileUnread="${newsFileUnread}"
local newsUnreadIdsFile="${newsUnreadIdsFile}"
'';
in {
inherit (env) activationPackage;
inherit newsInfo;
}
in { inherit (env) activationPackage config; }

View file

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Home Manager\n"
"Report-Msgid-Bugs-To: https://github.com/nix-community/home-manager/issues\n"
"POT-Creation-Date: 2023-07-16 10:09+0200\n"
"POT-Creation-Date: 2023-07-30 09:08+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -78,11 +78,11 @@ msgid "Can't inspect options of a flake configuration"
msgstr ""
#: home-manager/home-manager:281 home-manager/home-manager:304
#: home-manager/home-manager:1000
#: home-manager/home-manager:1023
msgid "%s: unknown option '%s'"
msgstr ""
#: home-manager/home-manager:286 home-manager/home-manager:1001
#: home-manager/home-manager:286 home-manager/home-manager:1024
msgid "Run '%s --help' for usage help"
msgstr ""
@ -124,7 +124,7 @@ msgstr ""
msgid "Can't instantiate a flake configuration"
msgstr ""
#: home-manager/home-manager:549
#: home-manager/home-manager:552
msgid ""
"There is %d unread and relevant news item.\n"
"Read it by running the command \"%s news\"."
@ -134,77 +134,72 @@ msgid_plural ""
msgstr[0] ""
msgstr[1] ""
#: home-manager/home-manager:563
#: home-manager/home-manager:566
msgid "Unknown \"news.display\" setting \"%s\"."
msgstr ""
#: home-manager/home-manager:570
#: home-manager/home-manager:573
#, sh-format
msgid "Please set the $EDITOR environment variable"
msgstr ""
#: home-manager/home-manager:585
#: home-manager/home-manager:588
msgid "Cannot run build in read-only directory"
msgstr ""
#: home-manager/home-manager:669
#: home-manager/home-manager:666
msgid "No generation with ID %s"
msgstr ""
#: home-manager/home-manager:671
#: home-manager/home-manager:668
msgid "Cannot remove the current generation %s"
msgstr ""
#: home-manager/home-manager:673
#: home-manager/home-manager:670
msgid "Removing generation %s"
msgstr ""
#: home-manager/home-manager:692
#: home-manager/home-manager:689
msgid "No generations to expire"
msgstr ""
#: home-manager/home-manager:703
#: home-manager/home-manager:700
msgid "No home-manager packages seem to be installed."
msgstr ""
#. translators: Here "flake" is a noun that refers to the Nix Flakes feature.
#: home-manager/home-manager:730
msgid "Sorry, this command is not yet supported in flake setup"
msgstr ""
#: home-manager/home-manager:767
#: home-manager/home-manager:781
msgid "Unknown argument %s"
msgstr ""
#: home-manager/home-manager:783
#: home-manager/home-manager:805
msgid "This will remove Home Manager from your system."
msgstr ""
#: home-manager/home-manager:786
#: home-manager/home-manager:808
msgid "This is a dry run, nothing will actually be uninstalled."
msgstr ""
#: home-manager/home-manager:790
#: home-manager/home-manager:812
msgid "Really uninstall Home Manager?"
msgstr ""
#: home-manager/home-manager:796
#: home-manager/home-manager:818
msgid "Switching to empty Home Manager configuration..."
msgstr ""
#: home-manager/home-manager:823
#: home-manager/home-manager:846
msgid "Yay!"
msgstr ""
#: home-manager/home-manager:828
#: home-manager/home-manager:851
msgid "Home Manager is uninstalled but your home.nix is left untouched."
msgstr ""
#: home-manager/home-manager:1040
#: home-manager/home-manager:1063
msgid "expire-generations expects one argument, got %d."
msgstr ""
#: home-manager/home-manager:1062
#: home-manager/home-manager:1085
msgid "Unknown command: %s"
msgstr ""

View file

@ -85,10 +85,22 @@ in
default = [ ];
description = "News entries.";
};
json = {
output = mkOption {
internal = true;
type = types.package;
description = "The generated JSON file package.";
};
};
};
};
config = {
news.json.output = pkgs.writeText "hm-news.json" (builtins.toJSON {
inherit (cfg) display entries;
});
# Add news entries in chronological order (i.e., latest time
# should be at the bottom of the list). The time should be
# formatted as given in the output of

View file

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Home Manager Modules\n"
"Report-Msgid-Bugs-To: https://github.com/nix-community/home-manager/issues\n"
"POT-Creation-Date: 2023-07-16 10:09+0200\n"
"POT-Creation-Date: 2023-07-30 09:08+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -33,7 +33,7 @@ msgstr ""
msgid "No change so reusing latest profile generation %s"
msgstr ""
#: modules/home-environment.nix:634
#: modules/home-environment.nix:626
msgid ""
"Oops, Nix failed to install your new Home Manager profile!\n"
"\n"
@ -49,7 +49,7 @@ msgid ""
"Then try activating your Home Manager configuration again."
msgstr ""
#: modules/home-environment.nix:667
#: modules/home-environment.nix:659
msgid "Activating %s"
msgstr ""