1
0
Fork 0
mirror of https://github.com/nix-community/home-manager synced 2024-12-24 02:39:48 +01:00

Merge branch 'pr-59'

This commit is contained in:
Robert Helgesson 2017-11-06 14:29:18 +01:00
commit a0afb6ec8e
No known key found for this signature in database
GPG key ID: C3DB11069E65DC86
7 changed files with 205 additions and 133 deletions

View file

@ -15,9 +15,7 @@ in
pkgs.stdenv.mkDerivation {
name = "home-manager";
phases = [ "installPhase" ];
installPhase = ''
buildCommand = ''
install -v -D -m755 ${./home-manager} $out/bin/home-manager
substituteInPlace $out/bin/home-manager \

View file

@ -6,8 +6,17 @@ with import ./lib/dag.nix { inherit lib; };
let
cfg = config.home.file;
homeDirectory = config.home.homeDirectory;
fileType = (import lib/file-type.nix {
inherit homeDirectory lib pkgs;
}).fileType;
# A symbolic link whose target path matches this pattern will be
# considered part of a Home Manager generation.
homeFilePattern = "${builtins.storeDir}/*-home-manager-files/*";
in
{
@ -15,50 +24,7 @@ in
home.file = mkOption {
description = "Attribute set of files to link into the user home.";
default = {};
type = types.loaOf (types.submodule (
{ name, config, ... }: {
options = {
target = mkOption {
type = types.str;
apply = removePrefix (homeDirectory + "/");
description = ''
Path to target file relative to <envar>HOME</envar>.
'';
};
text = mkOption {
default = null;
type = types.nullOr types.lines;
description = "Text of the file.";
};
source = mkOption {
type = types.path;
description = ''
Path of the source file. The file name must not start
with a period since Nix will not allow such names in
the Nix store.
</para><para>
This may refer to a directory.
'';
};
mode = mkOption {
type = types.str;
default = "444";
description = "The permissions to apply to the file.";
};
};
config = {
target = mkDefault name;
source = mkIf (config.text != null) (
let name' = "user-etc-" + baseNameOf name;
in mkDefault (pkgs.writeText name' config.text)
);
};
})
);
type = fileType "<envar>HOME</envar>" homeDirectory;
};
home-files = mkOption {
@ -83,11 +49,23 @@ in
})
];
warnings =
let
badFiles =
map (f: f.target)
(filter (f: f.mode != null)
(attrValues cfg));
badFilesStr = toString badFiles;
in
mkIf (badFiles != []) [
("The 'mode' field is deprecated for 'home.file', "
+ "use 'executable' instead: ${badFilesStr}")
];
# This verifies that the links we are about to create will not
# overwrite an existing file.
home.activation.checkLinkTargets = dagEntryBefore ["writeBoundary"] (
let
pattern = "-home-manager-files/";
check = pkgs.writeText "check" ''
. ${./lib-bash/color-echo.sh}
@ -97,7 +75,7 @@ in
relativePath="''${sourcePath#$newGenFiles/}"
targetPath="$HOME/$relativePath"
if [[ -e "$targetPath" \
&& ! "$(readlink "$targetPath")" =~ "${pattern}" ]] ; then
&& ! "$(readlink "$targetPath")" == ${homeFilePattern} ]] ; then
errorEcho "Existing file '$targetPath' is in the way"
collision=1
fi
@ -123,8 +101,6 @@ in
home.activation.linkGeneration = dagEntryAfter ["writeBoundary"] (
let
pattern = "-home-manager-files/";
link = pkgs.writeText "link" ''
newGenFiles="$1"
shift
@ -147,7 +123,7 @@ in
targetPath="$HOME/$relativePath"
if [[ -e "$newGenFiles/$relativePath" ]] ; then
$VERBOSE_ECHO "Checking $targetPath: exists"
elif [[ ! "$(readlink "$targetPath")" =~ "${pattern}" ]] ; then
elif [[ ! "$(readlink "$targetPath")" == ${homeFilePattern} ]] ; then
warnEcho "Path '$targetPath' not link into Home Manager generation. Skipping delete."
else
$VERBOSE_ECHO "Checking $targetPath: gone (deleting)"
@ -210,30 +186,57 @@ in
home-files = pkgs.stdenv.mkDerivation {
name = "home-manager-files";
phases = [ "installPhase" ];
# Symlink directories and files that have the right execute bit.
# Copy files that need their execute bit changed or use the
# deprecated 'mode' option.
buildCommand = ''
mkdir -p $out
installPhase =
"mkdir -p $out\n" +
concatStringsSep "\n" (
mapAttrsToList (n: v:
''
target="$(realpath -m "$out/${v.target}")"
function insertFile() {
local source="$1"
local relTarget="$2"
local executable="$3"
local mode="$4" # For backwards compatibility.
# Target file must be within $HOME.
if [[ ! "$target" =~ "$out" ]] ; then
echo "Error installing file '${v.target}' outside \$HOME" >&2
exit 1
fi
# Figure out the real absolute path to the target.
local target
target="$(realpath -m "$out/$relTarget")"
if [ -d "${v.source}" ]; then
mkdir -p "$(dirname "$out/${v.target}")"
ln -s "${v.source}" "$target"
# Target path must be within $HOME.
if [[ ! $target =~ $out ]] ; then
echo "Error installing file '$relTarget' outside \$HOME" >&2
exit 1
fi
mkdir -p "$(dirname "$target")"
if [[ -d $source ]]; then
ln -s "$source" "$target"
elif [[ $mode ]]; then
install -m "$mode" "$source" "$target"
else
[[ -x $source ]] && isExecutable=1 || isExecutable=""
if [[ $executable == symlink || $isExecutable == $executable ]]; then
ln -s "$source" "$target"
else
cp "$source" "$target"
if [[ $executable ]]; then
chmod +x "$target"
else
install -D -m${v.mode} "${v.source}" "$target"
chmod -x "$target"
fi
''
) cfg
);
fi
fi
}
'' + concatStrings (
mapAttrsToList (n: v: ''
insertFile "${v.source}" \
"${v.target}" \
"${if v.executable == null
then "symlink"
else builtins.toString v.executable}" \
"${builtins.toString v.mode}"
'') cfg
);
};
};
}

View file

@ -265,7 +265,7 @@ in
pkgs.nix
];
sf = pkgs.writeText "activation-script" ''
activationScript = pkgs.writeScript "activation-script" ''
#!${pkgs.stdenv.shell}
set -eu
@ -283,10 +283,10 @@ in
pkgs.stdenv.mkDerivation {
name = "home-manager-generation";
phases = [ "installPhase" ];
buildCommand = ''
mkdir -p $out
installPhase = ''
install -D -m755 ${sf} $out/activate
cp ${activationScript} $out/activate
substituteInPlace $out/activate \
--subst-var-by GENERATION_DIR $out

105
modules/lib/file-type.nix Normal file
View file

@ -0,0 +1,105 @@
{ homeDirectory, lib, pkgs }:
with lib;
let
# Figures out a valid Nix store name for the given path.
storeFileName = path:
let
# All characters that are considered safe. Note "-" is not
# included to avoid "-" followed by digit being interpreted as a
# version.
safeChars =
[ "+" "." "_" "?" "=" ]
++ lowerChars
++ upperChars
++ stringToCharacters "0123456789";
empties = l: genList (x: "") (length l);
unsafeInName = stringToCharacters (
replaceStrings safeChars (empties safeChars) path
);
safeName = replaceStrings unsafeInName (empties unsafeInName) path;
in
"home_file_" + safeName;
in
{
# Constructs a type suitable for a `home.file` like option. The
# target path may be either absolute or relative, in which case it
# is relative the `basePath` argument (which itself must be an
# absolute path).
#
# Arguments:
# - basePathDesc docbook compatible description of the base path
# - basePath the file base path
fileType = basePathDesc: basePath: types.loaOf (types.submodule (
{ name, config, ... }: {
options = {
target = mkOption {
type = types.str;
apply = p:
let
absPath = if hasPrefix "/" p then p else "${basePath}/${p}";
in
removePrefix (homeDirectory + "/") absPath;
description = ''
Path to target file relative to ${basePathDesc}.
'';
};
text = mkOption {
default = null;
type = types.nullOr types.lines;
description = "Text of the file.";
};
source = mkOption {
type = types.path;
description = ''
Path of the source file. The file name must not start
with a period since Nix will not allow such names in
the Nix store.
</para><para>
This may refer to a directory.
'';
};
mode = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
The permissions to apply to the file.
</para><para>
DEPRECATED: use <varname>home.file.&lt;name?&gt;.executable</varname>
instead.
'';
};
executable = mkOption {
type = types.nullOr types.bool;
default = null;
description = ''
Set the execute bit. If <literal>null</literal>, defaults to the mode
of the <varname>source</varname> file or to <literal>false</literal>
for files created through the <varname>text</varname> option.
'';
};
};
config = {
target = mkDefault name;
source = mkIf (config.text != null) (
mkDefault (pkgs.writeTextFile {
inherit (config) executable text;
name = storeFileName name;
})
);
};
}
));
}

View file

@ -425,6 +425,23 @@ in
A new window manager module is available: 'xsession.windowManager.i3'.
'';
}
{
time = "2017-11-06T13:23:17+00:00";
condition = any (f: f.mode != null) (attrValues config.home.file);
message = ''
The
home.file.<name?>.mode
option is now deprecated. Please use
home.file.<name?>.executable
instead. The 'mode' option will be completely removed
December 6, 2017.
'';
}
];
};
}

View file

@ -6,55 +6,10 @@ let
cfg = config.xdg;
fileType = basePathDesc: basePath: (types.loaOf (types.submodule (
{ name, config, ... }: {
options = {
target = mkOption {
type = types.str;
apply = p: "${basePath}/${p}";
description = ''
Path to target file relative to <varname>${basePathDesc}</varname>.
'';
};
text = mkOption {
default = null;
type = types.nullOr types.lines;
description = "Text of the file.";
};
source = mkOption {
type = types.path;
description = ''
Path of the source file. The file name must not start
with a period since Nix will not allow such names in
the Nix store.
</para><para>
This may refer to a directory.
'';
};
executable = mkOption {
type = types.bool;
default = false;
description = "Whether the file should be executable.";
};
};
config = {
target = mkDefault name;
source = mkIf (config.text != null) (
let
file = pkgs.writeTextFile {
inherit (config) text executable;
name = "user-etc-" + baseNameOf name;
};
in
mkDefault file
);
};
}
)));
fileType = (import ../lib/file-type.nix {
inherit (config.home) homeDirectory;
inherit lib pkgs;
}).fileType;
defaultCacheHome = "${config.home.homeDirectory}/.cache";
defaultConfigHome = "${config.home.homeDirectory}/.config";
@ -81,7 +36,7 @@ in
};
configFile = mkOption {
type = fileType "xdg.configHome" cfg.configHome;
type = fileType "<varname>xdg.configHome</varname>" cfg.configHome;
default = {};
description = ''
Attribute set of files to link into the user's XDG
@ -126,13 +81,7 @@ in
})
{
home.file =
let
f = n: v: {
inherit (v) source target;
mode = if v.executable then "777" else "444";
};
in mapAttrsToList f cfg.configFile;
home.file = cfg.configFile;
}
];
}

View file

@ -105,7 +105,7 @@ in
'';
home.file.".xsession" = {
mode = "555";
executable = true;
text = ''
if [[ ! -v HM_XPROFILE_SOURCED ]]; then
. ~/.xprofile