Exemplo n.º 1
0
def is_file(*pathnames: str) -> bool:
    '''
    ``True`` only if all passed paths are existing non-directory files *after*
    following symbolic links.

    If any such path does *not* exist, this function silently ignores this path
    rather than raising an exception.

    Versus :func:`path.isfile`
    ----------
    This function intrinsically differs from the standard :func:`path.isfile`
    function. While the latter returns ``True`` only for non-special files and
    hence `False` for all non-directory special files (e.g., device nodes,
    sockets), this function returns `True` for *all* non-directory files
    regardless of whether these files are special or not.

    **Why?** Because this function complies with POSIX semantics, whereas
    :func:`path.isfile` does *not*. The specialness of non-directory files is
    usually irrelevant; in general, it only matters whether these files are
    directories or not. For example, the external command ``rm`` removes only
    non-directory files (regardless of specialness) while the external command
    ``rmdir`` removes only empty directories.

    Parameters
    ----------
    pathnames: tuple[str]
        Tuple of all paths to be tested.

    Returns
    ----------
    bool
        ``True`` only if all such paths are existing non-directory files
        *after* following symbolic links.
    '''

    # Avoid circular import dependencies.
    from betse.util.path import dirs, paths

    # Return true only if...
    return any(
        # This path both exists and is *NOT* a directory...
        paths.is_path(pathname) and not dirs.is_dir(pathname)
        # For each such path.
        for pathname in pathnames)
Exemplo n.º 2
0
def is_worktree(dirname: str) -> bool:
    '''
    ``True`` only if the directory with the passed pathname is a **Git working
    tree** (i.e., contains a ``.git`` subdirectory).

    Parameters
    ----------
    dirname : str
        Relative or absolute pathname of the directory to be tested.

    Returns
    ----------
    bool
        ``True`` only if this directory is a Git working tree.
    '''

    # Avoid circular import dependencies.
    from betse.util.path import dirs, pathnames

    # Absolute or relative pathname of this directory's ".git" subdirectory.
    git_subdirname = pathnames.join(dirname, '.git')

    # Return True only if this subdirectory exists.
    return dirs.is_dir(git_subdirname)
Exemplo n.º 3
0
    def _run_pyinstaller_commands(self):
        '''
        Run the PyInstaller command previously constructed by the
        :meth:`_init_pyinstaller_command` method for each entry point.
        '''

        # Defer heavyweight imports.
        from betse.util.path import dirs, paths, pathnames

        # True if the current distribution has at least one entry point.
        is_entry_point = False

        # Freeze each previously installed script wrapper.
        for script_basename, script_type, entry_point in\
            supcommand.iter_command_entry_points(self):
            # Note at least one entry point to be installed.
            is_entry_point = True

            #FIXME: We went to a great deal of trouble to implement this method.
            #Why don't we call it anymore, again?

            # Validate this wrapper's entry point.
            # freeze._check_entry_point(entry_point)

            # Relative path of the output frozen executable file or directory,
            # created by stripping the suffixing ".exe" filetype on Windows.
            frozen_pathname = pathnames.join(
                self.dist_dir,
                pathnames.get_pathname_sans_filetype(script_basename))

            # If cleaning *AND* this path exists, remove this path before
            # validating this path. Why? This path could be an existing file
            # and the current command freezing to a directory (or vice versa),
            # in which case subsequent validation would raise an exception.
            if self.clean and paths.is_path(frozen_pathname):

                #FIXME: Define a new paths.remove_path() function resembling
                #the existing buputils.remove_path() function.
                paths.remove_path(frozen_pathname)

            # Validate this path.
            self._check_frozen_path(frozen_pathname)

            # Set all environment variables used to communicate with the BETSE-
            # specific PyInstaller specification file run below.
            self._set_environment_variables(script_basename, script_type,
                                            entry_point)

            # Run this PyInstaller command for this entry point.
            self._run_pyinstaller_command(script_basename, script_type,
                                          entry_point)

            # Report these results to the user.
            frozen_pathtype = ('directory'
                               if dirs.is_dir(frozen_pathname) else 'file')
            print('Froze {} "{}".\n'.format(frozen_pathtype, frozen_pathname))

            #FIXME: Excise when beginning GUI work.
            break

        # If no entry points are registered for the current distribution, raise
        # an exception.
        if not is_entry_point:
            raise DistutilsExecError('No entry points found. {}'.format(
                freeze.EXCEPTION_ADVICE))
Exemplo n.º 4
0
def get_package_worktree_dirname_or_none(
        package: ModuleType) -> StrOrNoneTypes:
    '''
    **Absolute canonical dirname** (i.e., absolute dirname after resolving
    symbolic links) of the **Git-based working tree** (i.e., top-level
    directory containing the canonical ``.git`` subdirectory) governing the
    passed top-level Python package if found *or* ``None`` otherwise.

    Caveats
    ----------
    **This directory typically does not exist.** This directory is only
    required during development by developers and hence should *not* be assumed
    to exist.

    For safety and efficiency, this function does *not* recursively search the
    filesystem up from the directory yielding this package for a ``.git``
    subdirectory; rather, this function only directly searches that directory
    itself for such a subdirectory. For that reason, this function typically
    returns ``None`` for *all* modules except top-level packages installed in a
    developer manner (e.g., by running ``sudo python3 setup.py develop``).

    Parameters
    ----------
    package : ModuleType
        Top-level Python package to be queried.

    Returns
    ----------
    StrOrNoneTypes
        Either:

        * The absolute canonical dirname of that package's Git working tree if
          that package was installed in a developer manner: e.g., by

          * ``python3 setup.py develop``.
          * ``python3 setup.py symlink``.

        * ``None`` if that package was installed in a non-developer manner:
          e.g., by

          * ``pip3 install``.
          * ``python3 setup.py develop``.
    '''

    # Avoid circular import dependencies.
    from betse.util.path import dirs, pathnames
    from betse.util.py.module import pymodule

    # Absolute canonical dirname of the directory providing this package,
    # canonicalized into a directory rather than symbolic link to increase the
    # likelihood of obtaining the actual parent directory of this package
    package_dirname = pymodule.get_dirname_canonical(package)

    # Absolute dirname of the parent directory of this directory.
    worktree_dirname = pathnames.get_dirname(package_dirname)

    # Absolute dirname of the ".git" subdirectory of this parent directory.
    git_subdirname = pathnames.join(worktree_dirname, '.git')

    # Return this parent directory's absolute dirname if this subdirectory
    # exists *OR* "None" otherwise.
    return worktree_dirname if dirs.is_dir(git_subdirname) else None
Exemplo n.º 5
0
def copy(
    # Mandatory parameters.
    src_filename: str,
    trg_filename: str,

    # Optional parameters.
    is_overwritable: bool = False,
) -> None:
    '''
    Copy the passed source file to the passed target file or directory,
    raising an exception if that target file already exists unless the
    ``is_overwritable`` parameter is explicitly passed as ``True``.

    If the:

    * Source file is a symbolic link, this link (rather than its transitive
      target) will be copied and hence preserved.
    * Target file is a directory, the basename of the source file will be
      appended to this directory -- much like the standard ``cp`` POSIX
      command.

    For safety, the target file is:

    * Copied in a manner maximally preserving *all* existing metadata of the
      source file. This includes owner, group, permissions, times (e.g.,
      access, creation, modification), and extended attributes (if any).
    * *Not* overwritten by default. If this file already exists, an exception
      is raised unless the ``is_overwritable`` parameter is explicitly passed
      as ``True``. For brevity, consider calling the :func:`copy_overwritable`.

    Parameters
    ----------
    src_filename : str
        Absolute or relative path of the source file to be copied from.
    trg_filename : str
        Absolute or relative path of the target file to be copied to.
    is_overwritable : optional[bool]
        If this target file already exists and this boolean is ``True``, this
        file is silently overwritten; else, an exception is raised. Defaults to
        ``False``.

    Raises
    ----------
    BetseFileException
        If either the:

        * Source file does not exist.
        * Target file already exists *and* ``is_overwritable`` is ``False``.

    See Also
    ----------
    :func:`copy_overwritable`
        Higher-level function wrapping this lower-level function by
        unconditionally passing ``is_overwritable`` parameter as ``True``.
    '''

    # Avoid circular import dependencies.
    from betse.util.path import dirs, paths, pathnames

    # Log this copy.
    logs.log_debug('Copying file: %s -> %s', src_filename, trg_filename)

    # If this source file does *NOT* exist, raise an exception.
    die_unless_file(src_filename)

    # If this target file is a directory, append the basename of the passed
    # source file to this directory -- much like the "cp" POSIX command.
    if dirs.is_dir(trg_filename):
        trg_filename = pathnames.join(trg_filename,
                                      pathnames.get_basename(src_filename))

    # If this target file already exists but is *NOT* overwritable, raise an
    # exception.
    if not is_overwritable:
        paths.die_if_path(trg_filename)

    # Create the directory containing this target file *BEFORE* calling the
    # shutil.copy2() function, which assumes this directory to exist.
    dirs.make_parent_unless_dir(trg_filename)

    # Perform this copy in a manner preserving metadata and symbolic links.
    shutil.copy2(src_filename, trg_filename, follow_symlinks=False)