summaryrefslogtreecommitdiff
path: root/sphinx/project.py
diff options
context:
space:
mode:
Diffstat (limited to 'sphinx/project.py')
-rw-r--r--sphinx/project.py97
1 files changed, 97 insertions, 0 deletions
diff --git a/sphinx/project.py b/sphinx/project.py
new file mode 100644
index 000000000..8b8aa5794
--- /dev/null
+++ b/sphinx/project.py
@@ -0,0 +1,97 @@
+"""
+ sphinx.project
+ ~~~~~~~~~~~~~~
+
+ Utility function and classes for Sphinx projects.
+
+ :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+import os
+from typing import TYPE_CHECKING
+
+from sphinx.locale import __
+from sphinx.util import get_matching_files
+from sphinx.util import logging
+from sphinx.util.matching import compile_matchers
+from sphinx.util.osutil import SEP, relpath
+
+if TYPE_CHECKING:
+ from typing import Dict, List, Set # NOQA
+
+logger = logging.getLogger(__name__)
+EXCLUDE_PATHS = ['**/_sources', '.#*', '**/.#*', '*.lproj/**']
+
+
+class Project(object):
+ """A project is source code set of Sphinx document."""
+
+ def __init__(self, srcdir, source_suffix):
+ # type: (str, Dict[str, str]) -> None
+ #: Source directory.
+ self.srcdir = srcdir
+
+ #: source_suffix. Same as :confval:`source_suffix`.
+ self.source_suffix = source_suffix
+
+ #: The name of documents belongs to this project.
+ self.docnames = set() # type: Set[str]
+
+ def restore(self, other):
+ # type: (Project) -> None
+ """Take over a result of last build."""
+ self.docnames = other.docnames
+
+ def discover(self, exclude_paths=[]):
+ # type: (List[str]) -> Set[str]
+ """Find all document files in the source directory and put them in
+ :attr:`docnames`.
+ """
+ self.docnames = set()
+ excludes = compile_matchers(exclude_paths + EXCLUDE_PATHS)
+ for filename in get_matching_files(self.srcdir, excludes): # type: ignore
+ docname = self.path2doc(filename)
+ if docname:
+ if os.access(os.path.join(self.srcdir, filename), os.R_OK):
+ self.docnames.add(docname)
+ else:
+ logger.warning(__("document not readable. Ignored."), location=docname)
+
+ return self.docnames
+
+ def path2doc(self, filename):
+ # type: (str) -> str
+ """Return the docname for the filename if the file is document.
+
+ *filename* should be absolute or relative to the source directory.
+ """
+ if filename.startswith(self.srcdir):
+ filename = relpath(filename, self.srcdir)
+ for suffix in self.source_suffix:
+ if filename.endswith(suffix):
+ return filename[:-len(suffix)]
+
+ # the file does not have docname
+ return None
+
+ def doc2path(self, docname, basedir=True):
+ # type: (str, bool) -> str
+ """Return the filename for the document name.
+
+ If *basedir* is True, return as an absolute path.
+ Else, return as a relative path to the source directory.
+ """
+ docname = docname.replace(SEP, os.path.sep)
+ basename = os.path.join(self.srcdir, docname)
+ for suffix in self.source_suffix:
+ if os.path.isfile(basename + suffix):
+ break
+ else:
+ # document does not exist
+ suffix = list(self.source_suffix)[0]
+
+ if basedir:
+ return basename + suffix
+ else:
+ return docname + suffix