# private utility functions for pydircolors
#
# Copyright 2019 Allen Wild <allenwild93@gmail.com>
# SPDX-License-Identifier: Apache-2.0

""" private/internal utility functions for pydircolors """

import os

__all__ = ['stat_at', 'readlink_at']

def stat_at(file, cwd=None, follow_symlinks=False):
    """Call `os.stat` on a file relative to a given directory.

    Args:
        file: Path to the file (relative to `cwd` if provided).
        cwd: Directory to resolve `file` against. May be a path string,
            an open directory file descriptor, or None.
        follow_symlinks: Whether to follow symlinks.

    Returns:
        An `os.stat_result` for the file.

    Raises:
        ValueError: If `cwd` is not str, int, or None.
        OSError: Propagated from `os.open` or `os.stat`.
    """
    if isinstance(cwd, str):
        dirfd = os.open(cwd, os.O_RDONLY)
        need_to_close = True
    elif cwd is None or isinstance(cwd, int):
        dirfd = cwd
        need_to_close = False
    else:
        raise ValueError('cwd must be str, int, or None')

    try:
        return os.stat(file, dir_fd=dirfd, follow_symlinks=follow_symlinks)
    finally:
        if need_to_close:
            os.close(dirfd)

def readlink_at(file, cwd=None):
    """Call `os.readlink` on a file relative to a given directory.

    Args:
        file: Path to the symlink (relative to `cwd` if provided).
        cwd: Directory to resolve `file` against. May be a path string,
            an open directory file descriptor, or None.

    Returns:
        The path to which the symlink points.

    Raises:
        ValueError: If `cwd` is not str, int, or None.
        OSError: Propagated from `os.open` or `os.readlink`.
    """
    if isinstance(cwd, str):
        dirfd = os.open(cwd, os.O_RDONLY)
        need_to_close = True
    elif cwd is None or isinstance(cwd, int):
        dirfd = cwd
        need_to_close = False
    else:
        raise ValueError('cwd must be str, int, or None')

    try:
        return os.readlink(file, dir_fd=dirfd)
    finally:
        if need_to_close:
            os.close(dirfd)
