files: respect executable for recursive directories
Apply explicit executable settings to recursive directory leaves so directory sources behave like documented file sources.
This commit is contained in:
parent
f4d01c1d87
commit
144f4e36d0
2 changed files with 126 additions and 20 deletions
|
|
@ -354,6 +354,63 @@ in
|
|||
# contain the recursion root, not the visited files.
|
||||
declare -A seenTargets
|
||||
|
||||
function setExecutableBit() {
|
||||
local target="$1"
|
||||
local executable="$2"
|
||||
|
||||
if [[ $executable == inherit ]]; then
|
||||
# Don't change file mode if it should match the source.
|
||||
:
|
||||
elif [[ $executable ]]; then
|
||||
chmod +x "$target"
|
||||
else
|
||||
chmod -x "$target"
|
||||
fi
|
||||
}
|
||||
|
||||
function insertFileEntry() {
|
||||
local source="$1"
|
||||
local target="$2"
|
||||
local executable="$3"
|
||||
local isExecutable
|
||||
|
||||
[[ -x $source ]] && isExecutable=1 || isExecutable=""
|
||||
|
||||
# Link the file into the home file directory if possible,
|
||||
# i.e., if the executable bit of the source is the same we
|
||||
# expect for the target. Otherwise, we copy the file and
|
||||
# set the executable bit to the expected value.
|
||||
if [[ $executable == inherit || $isExecutable == $executable ]]; then
|
||||
ln -s "$source" "$target"
|
||||
else
|
||||
cp "$source" "$target"
|
||||
setExecutableBit "$target" "$executable"
|
||||
fi
|
||||
}
|
||||
|
||||
function setLinkedFileExecutableBit() {
|
||||
local target="$1"
|
||||
local executable="$2"
|
||||
local isExecutable
|
||||
|
||||
if [[ -d $target || ! -e $target ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
[[ -x $target ]] && isExecutable=1 || isExecutable=""
|
||||
|
||||
if [[ $executable == inherit || $isExecutable == $executable ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
local tmp
|
||||
tmp="$(mktemp "$target.XXXXXX")"
|
||||
|
||||
cp "$target" "$tmp"
|
||||
setExecutableBit "$tmp" "$executable"
|
||||
mv -f "$tmp" "$target"
|
||||
}
|
||||
|
||||
function insertFile() {
|
||||
local source="$1"
|
||||
local relTarget="$2"
|
||||
|
|
@ -409,30 +466,19 @@ in
|
|||
else
|
||||
lndir -silent "$source" "$target"
|
||||
fi
|
||||
|
||||
if [[ $executable != inherit ]]; then
|
||||
local linkedFile
|
||||
|
||||
while IFS= read -r -d "" linkedFile; do
|
||||
setLinkedFileExecutableBit "$linkedFile" "$executable"
|
||||
done < <(find "$target" \( -type f -or -type l \) -print0)
|
||||
fi
|
||||
else
|
||||
ln -s "$source" "$target"
|
||||
fi
|
||||
else
|
||||
[[ -x $source ]] && isExecutable=1 || isExecutable=""
|
||||
|
||||
# Link the file into the home file directory if possible,
|
||||
# i.e., if the executable bit of the source is the same we
|
||||
# expect for the target. Otherwise, we copy the file and
|
||||
# set the executable bit to the expected value.
|
||||
if [[ $executable == inherit || $isExecutable == $executable ]]; then
|
||||
ln -s "$source" "$target"
|
||||
else
|
||||
cp "$source" "$target"
|
||||
|
||||
if [[ $executable == inherit ]]; then
|
||||
# Don't change file mode if it should match the source.
|
||||
:
|
||||
elif [[ $executable ]]; then
|
||||
chmod +x "$target"
|
||||
else
|
||||
chmod -x "$target"
|
||||
fi
|
||||
fi
|
||||
insertFileEntry "$source" "$target" "$executable"
|
||||
fi
|
||||
}
|
||||
''
|
||||
|
|
|
|||
|
|
@ -1,11 +1,71 @@
|
|||
{ pkgs, ... }:
|
||||
|
||||
let
|
||||
recursiveSource = pkgs.runCommand "recursive-executable-source" { } ''
|
||||
mkdir -p $out/nested
|
||||
|
||||
echo source > $out/source
|
||||
chmod 644 $out/source
|
||||
|
||||
echo nested > $out/nested/source
|
||||
chmod 755 $out/nested/source
|
||||
|
||||
ln -s /nonexistent/nowhere $out/dangling
|
||||
'';
|
||||
in
|
||||
{
|
||||
home.file."executable" = {
|
||||
text = "";
|
||||
executable = true;
|
||||
};
|
||||
|
||||
home.file."recursive-executable" = {
|
||||
source = recursiveSource;
|
||||
recursive = true;
|
||||
executable = true;
|
||||
};
|
||||
|
||||
home.file."recursive-non-executable" = {
|
||||
source = recursiveSource;
|
||||
recursive = true;
|
||||
executable = false;
|
||||
};
|
||||
|
||||
nmt.script = ''
|
||||
assertFileExists home-files/executable
|
||||
assertFileIsExecutable home-files/executable;
|
||||
|
||||
assertFileExists home-files/recursive-executable/source
|
||||
assertFileIsExecutable home-files/recursive-executable/source
|
||||
if [[ -L "$TESTED/home-files/recursive-executable/source" ]]; then
|
||||
fail "Expected recursive-executable/source to be copied so its executable bit can be changed."
|
||||
fi
|
||||
|
||||
assertFileExists home-files/recursive-executable/nested/source
|
||||
assertFileIsExecutable home-files/recursive-executable/nested/source
|
||||
assertLinkExists home-files/recursive-executable/nested/source
|
||||
|
||||
assertFileExists home-files/recursive-non-executable/source
|
||||
assertFileIsNotExecutable home-files/recursive-non-executable/source
|
||||
assertLinkExists home-files/recursive-non-executable/source
|
||||
|
||||
assertFileExists home-files/recursive-non-executable/nested/source
|
||||
assertFileIsNotExecutable home-files/recursive-non-executable/nested/source
|
||||
if [[ -L "$TESTED/home-files/recursive-non-executable/nested/source" ]]; then
|
||||
fail "Expected recursive-non-executable/nested/source to be copied so its executable bit can be changed."
|
||||
fi
|
||||
|
||||
# A dangling symlink among the recursively linked leaves has no
|
||||
# executable bit to fix. It must be left alone rather than crashing the
|
||||
# build when trying to cp/chmod through it.
|
||||
assertLinkExists home-files/recursive-executable/dangling
|
||||
if [[ -e "$TESTED/home-files/recursive-executable/dangling" ]]; then
|
||||
fail "Expected recursive-executable/dangling to remain a dangling symlink."
|
||||
fi
|
||||
|
||||
assertLinkExists home-files/recursive-non-executable/dangling
|
||||
if [[ -e "$TESTED/home-files/recursive-non-executable/dangling" ]]; then
|
||||
fail "Expected recursive-non-executable/dangling to remain a dangling symlink."
|
||||
fi
|
||||
'';
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue