Unverified Commit a344acdc authored by Robert Hensing's avatar Robert Hensing Committed by GitHub
Browse files

Merge pull request #224834 from tweag/pathType-and-co

Improvements to pathType, pathIsDirectory and pathIsRegularFile
parents 81a62011 378bf1a6
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -117,10 +117,11 @@ let
    inherit (self.meta) addMetaAttrs dontDistribute setName updateName
      appendToName mapDerivationAttrset setPrio lowPrio lowPrioSet hiPrio
      hiPrioSet getLicenseFromSpdxId getExe;
    inherit (self.sources) pathType pathIsDirectory cleanSourceFilter
    inherit (self.filesystem) pathType pathIsDirectory pathIsRegularFile;
    inherit (self.sources) cleanSourceFilter
      cleanSource sourceByRegex sourceFilesBySuffices
      commitIdFromGitRepo cleanSourceWith pathHasContext
      canCleanSource pathIsRegularFile pathIsGitRepo;
      canCleanSource pathIsGitRepo;
    inherit (self.modules) evalModules setDefaultModuleLocation
      unifyModuleSyntax applyModuleArgsIfFunction mergeModules
      mergeModules' mergeOptionDecls evalOptionValue mergeDefinitions
+81 −1
Original line number Diff line number Diff line
# Functions for copying sources to the Nix store.
# Functions for querying information about the filesystem
# without copying any files to the Nix store.
{ lib }:

# Tested in lib/tests/filesystem.sh
let
  inherit (builtins)
    readDir
    pathExists
    ;

  inherit (lib.strings)
    hasPrefix
    ;

  inherit (lib.filesystem)
    pathType
    ;
in

{

  /*
    The type of a path. The path needs to exist and be accessible.
    The result is either "directory" for a directory, "regular" for a regular file, "symlink" for a symlink, or "unknown" for anything else.

    Type:
      pathType :: Path -> String

    Example:
      pathType /.
      => "directory"

      pathType /some/file.nix
      => "regular"
  */
  pathType =
    builtins.readFileType or
    # Nix <2.14 compatibility shim
    (path:
      if ! pathExists path
      # Fail irrecoverably to mimic the historic behavior of this function and
      # the new builtins.readFileType
      then abort "lib.filesystem.pathType: Path ${toString path} does not exist."
      # The filesystem root is the only path where `dirOf / == /` and
      # `baseNameOf /` is not valid. We can detect this and directly return
      # "directory", since we know the filesystem root can't be anything else.
      else if dirOf path == path
      then "directory"
      else (readDir (dirOf path)).${baseNameOf path}
    );

  /*
    Whether a path exists and is a directory.

    Type:
      pathIsDirectory :: Path -> Bool

    Example:
      pathIsDirectory /.
      => true

      pathIsDirectory /this/does/not/exist
      => false

      pathIsDirectory /some/file.nix
      => false
  */
  pathIsDirectory = path:
    pathExists path && pathType path == "directory";

  /*
    Whether a path exists and is a regular file, meaning not a symlink or any other special file type.

    Type:
      pathIsRegularFile :: Path -> Bool

    Example:
      pathIsRegularFile /.
      => false

      pathIsRegularFile /this/does/not/exist
      => false

      pathIsRegularFile /some/file.nix
      => true
  */
  pathIsRegularFile = path:
    pathExists path && pathType path == "regular";

  /*
    A map of all haskell packages defined in the given path,
    identified by having a cabal file with the same name as the
+18 −19
Original line number Diff line number Diff line
@@ -18,21 +18,11 @@ let
    pathExists
    readFile
    ;

  /*
    Returns the type of a path: regular (for file), symlink, or directory.
  */
  pathType = path: getAttr (baseNameOf path) (readDir (dirOf path));

  /*
    Returns true if the path exists and is a directory, false otherwise.
  */
  pathIsDirectory = path: if pathExists path then (pathType path) == "directory" else false;

  /*
    Returns true if the path exists and is a regular file, false otherwise.
  */
  pathIsRegularFile = path: if pathExists path then (pathType path) == "regular" else false;
  inherit (lib.filesystem)
    pathType
    pathIsDirectory
    pathIsRegularFile
    ;

  /*
    A basic filter for `cleanSourceWith` that removes
@@ -271,11 +261,20 @@ let
    };

in {
  inherit
    pathType
    pathIsDirectory
    pathIsRegularFile

  pathType = lib.warnIf (lib.isInOldestRelease 2305)
    "lib.sources.pathType has been moved to lib.filesystem.pathType."
    lib.filesystem.pathType;

  pathIsDirectory = lib.warnIf (lib.isInOldestRelease 2305)
    "lib.sources.pathIsDirectory has been moved to lib.filesystem.pathIsDirectory."
    lib.filesystem.pathIsDirectory;

  pathIsRegularFile = lib.warnIf (lib.isInOldestRelease 2305)
    "lib.sources.pathIsRegularFile has been moved to lib.filesystem.pathIsRegularFile."
    lib.filesystem.pathIsRegularFile;

  inherit
    pathIsGitRepo
    commitIdFromGitRepo

+92 −0
Original line number Diff line number Diff line
#!/usr/bin/env bash

# Tests lib/filesystem.nix
# Run:
# [nixpkgs]$ lib/tests/filesystem.sh
# or:
# [nixpkgs]$ nix-build lib/tests/release.nix

set -euo pipefail
shopt -s inherit_errexit

# Use
#     || die
die() {
  echo >&2 "test case failed: " "$@"
  exit 1
}

if test -n "${TEST_LIB:-}"; then
  NIX_PATH=nixpkgs="$(dirname "$TEST_LIB")"
else
  NIX_PATH=nixpkgs="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.."; pwd)"
fi
export NIX_PATH

work="$(mktemp -d)"
clean_up() {
  rm -rf "$work"
}
trap clean_up EXIT
cd "$work"

mkdir directory
touch regular
ln -s target symlink
mkfifo fifo

checkPathType() {
    local path=$1
    local expectedPathType=$2
    local actualPathType=$(nix-instantiate --eval --strict --json 2>&1 \
        -E '{ path }: let lib = import <nixpkgs/lib>; in lib.filesystem.pathType path' \
        --argstr path "$path")
    if [[ "$actualPathType" != "$expectedPathType" ]]; then
        die "lib.filesystem.pathType \"$path\" == $actualPathType, but $expectedPathType was expected"
    fi
}

checkPathType "/" '"directory"'
checkPathType "$PWD/directory" '"directory"'
checkPathType "$PWD/regular" '"regular"'
checkPathType "$PWD/symlink" '"symlink"'
checkPathType "$PWD/fifo" '"unknown"'
checkPathType "$PWD/non-existent" "error: evaluation aborted with the following error message: 'lib.filesystem.pathType: Path $PWD/non-existent does not exist.'"

checkPathIsDirectory() {
    local path=$1
    local expectedIsDirectory=$2
    local actualIsDirectory=$(nix-instantiate --eval --strict --json 2>&1 \
        -E '{ path }: let lib = import <nixpkgs/lib>; in lib.filesystem.pathIsDirectory path' \
        --argstr path "$path")
    if [[ "$actualIsDirectory" != "$expectedIsDirectory" ]]; then
        die "lib.filesystem.pathIsDirectory \"$path\" == $actualIsDirectory, but $expectedIsDirectory was expected"
    fi
}

checkPathIsDirectory "/" "true"
checkPathIsDirectory "$PWD/directory" "true"
checkPathIsDirectory "$PWD/regular" "false"
checkPathIsDirectory "$PWD/symlink" "false"
checkPathIsDirectory "$PWD/fifo" "false"
checkPathIsDirectory "$PWD/non-existent" "false"

checkPathIsRegularFile() {
    local path=$1
    local expectedIsRegularFile=$2
    local actualIsRegularFile=$(nix-instantiate --eval --strict --json 2>&1 \
        -E '{ path }: let lib = import <nixpkgs/lib>; in lib.filesystem.pathIsRegularFile path' \
        --argstr path "$path")
    if [[ "$actualIsRegularFile" != "$expectedIsRegularFile" ]]; then
        die "lib.filesystem.pathIsRegularFile \"$path\" == $actualIsRegularFile, but $expectedIsRegularFile was expected"
    fi
}

checkPathIsRegularFile "/" "false"
checkPathIsRegularFile "$PWD/directory" "false"
checkPathIsRegularFile "$PWD/regular" "true"
checkPathIsRegularFile "$PWD/symlink" "false"
checkPathIsRegularFile "$PWD/fifo" "false"
checkPathIsRegularFile "$PWD/non-existent" "false"

echo >&2 tests ok
+3 −0
Original line number Diff line number Diff line
@@ -44,6 +44,9 @@ pkgs.runCommand "nixpkgs-lib-tests" {
    echo "Running lib/tests/modules.sh"
    bash lib/tests/modules.sh

    echo "Running lib/tests/filesystem.sh"
    TEST_LIB=$PWD/lib bash lib/tests/filesystem.sh

    echo "Running lib/tests/sources.sh"
    TEST_LIB=$PWD/lib bash lib/tests/sources.sh