def has_package_conf(repository, package, directory="", keep=False): """Check if there is a Sphinx conf.py inside of a Rez package. Args: repository (str): The URL pointing to a git repository that contains `package` somewhere inside of it. package (str): The name of the Rez packge to find within `repository`. directory (str, optional): Part of checking for a conf.py file involves cloning the given `repository` to disk. If a root folder is given, the repository will be cloned as a child of this directory. If no folder is given, a temporary directory is chosen for the user. Default: "". keep (bool, optional): If False, delete temporary directories once they are no If longer needed. True, don't delete them. Default is False. Returns: bool: If a conf.py was found. """ repository = _get_repository(repository, directory=directory, keep=keep) for path in _iter_package_files(repository.working_dir): name = packages_.get_developer_package(os.path.dirname(path)).name if name == package: return bool(conf_manager.get_conf_file(os.path.dirname(path))) return False
def fix_intersphinx_mapping( # pylint: disable=too-many-arguments package, sphinx_files_must_exist, excluded_packages): """Replace or add the ``intersphinx_mapping`` attribute to a user's conf.py Sphinx file. Args: package (:class:`rez.developer_package.DeveloperPackage`): The Rez package to modify with a new, updated intersphinx mapping. sphinx_files_must_exist (bool, optional): If True and the "conf.py" files doesn't exist, raise an exception. If False and the file doesn't exist, don't error If and just keep moving. Default is False. excluded_packages (iter[str]): The names of Rez packages to ignore. Any intersphinx key/value pair that matches any of the names given to this parameter will be ignored. This parameter supports glob matching. Raises: :class:`.exceptions.SphinxFileMissing`: If `sphinx_files_must_exist` but the source package has no documentation. Returns: bool: If False, no fix was applied. If True, at least one file on-disk was changed. """ root = os.path.dirname(package.filepath) if sphinx_files_must_exist and _is_conf_file_missing(root): raise exceptions.SphinxFileMissing( "conf.py is missing. Either set sphinx_files_must_exist to False " "or create a conf.py to continue.") try: missing = get_missing_intersphinx_mappings( package, sphinx_files_must_exist=False) except exceptions.SphinxFileMissing: raise exceptions.SphinxFileMissing( 'Package "{package.name}" has no conf.py file. ' "Please create it and re-run this command.".format( package=package)) missing = { name: item for name, item in missing.items() if not any( fnmatch.fnmatch(name, pattern) for pattern in excluded_packages) } if not missing: return False conf_file = conf_manager.get_conf_file(root) links = get_existing_intersphinx_links(root) links.update(missing) sphinx_helper.replace_intersphinx_mapping(links, conf_file) return True
def run(cls, package, context): """Find a documentation for the Rez package. Args: package (:class:`rez.packages_.DeveloperPackage`): The Rez package that may or may not need documentation. context (:class:`.Context`): A data instance that knows whether `package` has a Python package. If there's no Python package, this checker is cancelled. Returns: list[:class:`.Description`]: If no issues are found, return an empty list. Otherwise, return one description of each found issue. """ if not _has_context_python_package(context): return [] root = finder.get_package_root(package) if conf_manager.get_conf_file(root): return [] # pragma: no cover summary = "No documentation found" full = [ summary, "Consider adding documentation to your Python package.", "Reference: https://www.sphinx-doc.org/en/master/usage/quickstart.html", ] code = base_checker.Code(short_name="E", long_name=cls.get_long_code()) location = message_description.Location(path=root, row=0, column=0, text="") return [ message_description.Description([summary], location, code=code, full=full), ]
def get_existing_intersphinx_links(directory): """Find the intersphinx information that's already written on-disk. Args: directory (str): The root directory of the Rez package. It's assumed that this directory has documentation written for it. Raises: EnvironmentError: If a conf.py was found but its ``intersphinx_mapping`` attribute is invalid. Returns: dict[str, tuple[str, NoneType]]: Each intersphinx label and the URL + target location. """ conf_file = conf_manager.get_conf_file(directory) if not conf_file: _LOGGER.debug( 'Directory "%s" has no Sphinx conf.py file was found. ' "Returning an empty dict.", directory, ) return dict() module = conf_manager.import_conf_file(conf_file) if hasattr(module, "intersphinx_mapping"): mapping = module.intersphinx_mapping or dict() if not isinstance(mapping, collections.MutableMapping): raise EnvironmentError( 'conf.py "{conf_file}" has an intersphinx_mapping but it is not a dict.' .format(conf_file=conf_file)) return mapping return dict()
def _is_conf_file_missing(directory): """bool: Check if a Sphinx conf.py can be found starting at `directory` Rez package.""" return not conf_manager.get_conf_file(directory)
def has_documentation(package): """Check if the given Rez package has documentation already. The logic for this function is bit involved. There are 2 "categories" of Rez packages - source Rez packages (packages that haven't been built/installed/released yet). - built/installed/released packages. Built Rez packages may not actually have documentation installed with the package. So if documentation is missing, you have to check the repository that the package came from to be totally sure. You can clone the repository and check it locally or check the repository remotely (doing it remotely is much faster but is also more complex). Source Rez packages however contain 100% of the package definition plus its documentation configuration files. So we only need to query for files on-disk to figure out if documentation is missing this function is given a source Rez package. Args: package (:class:`rez.packages_.Package`): The Rez package to check for existing documentation. Raises: :class:`exceptions.NoGitRepository`: If a repository URL was found but the remote repository could not be reached. Returns: str: A generic message saying that the package already has documentation. """ if not inspection.is_built_package(package): root = finder.get_package_root(package) if conf_manager.get_conf_file(root): return True repository = rez_git.get_repository_url(package) if not repository: raise exceptions.NoGitRepository( package, finder.get_package_root(package), "A built Rez package was found but it has no git repository.", ) keep = _is_keep_temporary_files_enabled() directory = _get_temporary_directory() remote_file = git_link.has_package_conf(repository, package.name, directory=directory, keep=keep) if remote_file: return True return False