mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge pull request #4436 from stephenfin/directory-validation
app: Centralize directory validation
This commit is contained in:
commit
3413590edd
@ -28,7 +28,8 @@ from docutils.parsers.rst import directives, roles
|
||||
import sphinx
|
||||
from sphinx import package_dir, locale
|
||||
from sphinx.config import Config
|
||||
from sphinx.errors import ConfigError, ExtensionError, VersionRequirementError
|
||||
from sphinx.errors import (
|
||||
ApplicationError, ConfigError, ExtensionError, VersionRequirementError)
|
||||
from sphinx.deprecation import RemovedInSphinx20Warning
|
||||
from sphinx.environment import BuildEnvironment
|
||||
from sphinx.events import EventManager
|
||||
@ -43,6 +44,7 @@ from sphinx.util.osutil import ENOENT, ensuredir
|
||||
from sphinx.util.console import bold # type: ignore
|
||||
from sphinx.util.docutils import is_html5_writer_available, directive_helper
|
||||
from sphinx.util.i18n import find_catalog_source_files
|
||||
from sphinx.util.osutil import abspath
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
@ -123,10 +125,24 @@ class Sphinx(object):
|
||||
self.enumerable_nodes = {} # type: Dict[nodes.Node, Tuple[unicode, Callable]] # NOQA
|
||||
self.html_themes = {} # type: Dict[unicode, unicode]
|
||||
|
||||
self.srcdir = srcdir
|
||||
# validate provided directories
|
||||
self.srcdir = abspath(srcdir)
|
||||
self.outdir = abspath(outdir)
|
||||
self.doctreedir = abspath(doctreedir)
|
||||
self.confdir = confdir
|
||||
self.outdir = outdir
|
||||
self.doctreedir = doctreedir
|
||||
if self.confdir: # confdir is optional
|
||||
self.confdir = abspath(self.confdir)
|
||||
if not path.isfile(path.join(self.confdir, 'conf.py')):
|
||||
raise ApplicationError("config directory doesn't contain a "
|
||||
"conf.py file (%s)" % confdir)
|
||||
|
||||
if not path.isdir(self.srcdir):
|
||||
raise ApplicationError('Cannot find source directory (%s)' %
|
||||
self.srcdir)
|
||||
|
||||
if self.srcdir == self.outdir:
|
||||
raise ApplicationError('Source directory and destination '
|
||||
'directory cannot be identical')
|
||||
|
||||
self.parallel = parallel
|
||||
|
||||
|
@ -11,9 +11,9 @@
|
||||
from __future__ import print_function
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
import traceback
|
||||
from os import path
|
||||
|
||||
from docutils.utils import SystemMessage
|
||||
from six import text_type, binary_type
|
||||
@ -24,7 +24,6 @@ from sphinx.application import Sphinx
|
||||
from sphinx.util import Tee, format_exception_cut_frames, save_traceback
|
||||
from sphinx.util.console import red, nocolor, color_terminal # type: ignore
|
||||
from sphinx.util.docutils import docutils_namespace, patch_docutils
|
||||
from sphinx.util.osutil import abspath, fs_encoding
|
||||
from sphinx.util.pycompat import terminal_safe
|
||||
|
||||
if False:
|
||||
@ -184,31 +183,19 @@ def main(argv=sys.argv[1:]): # type: ignore
|
||||
parser = get_parser()
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
# get paths (first and second positional argument)
|
||||
try:
|
||||
srcdir = abspath(args.sourcedir)
|
||||
confdir = abspath(args.confdir or srcdir)
|
||||
if args.noconfig:
|
||||
confdir = None
|
||||
if args.noconfig:
|
||||
args.confdir = None
|
||||
elif not args.confdir:
|
||||
args.confdir = args.sourcedir
|
||||
|
||||
if not path.isdir(srcdir):
|
||||
parser.error('cannot find source directory (%s)' % srcdir)
|
||||
if not args.noconfig and not path.isfile(path.join(confdir, 'conf.py')):
|
||||
parser.error("config directory doesn't contain a conf.py file "
|
||||
"(%s)" % confdir)
|
||||
|
||||
outdir = abspath(args.outputdir)
|
||||
if srcdir == outdir:
|
||||
parser.error('source directory and destination directory are same')
|
||||
except UnicodeError:
|
||||
parser.error('multibyte filename not supported on this filesystem '
|
||||
'encoding (%r)' % fs_encoding)
|
||||
if not args.doctreedir:
|
||||
args.doctreedir = os.path.join(args.sourcedir, '.doctrees')
|
||||
|
||||
# handle remaining filename arguments
|
||||
filenames = args.filenames
|
||||
missing_files = []
|
||||
for filename in filenames:
|
||||
if not path.isfile(filename):
|
||||
if not os.path.isfile(filename):
|
||||
missing_files.append(filename)
|
||||
if missing_files:
|
||||
parser.error('cannot find files %r' % missing_files)
|
||||
@ -226,8 +213,6 @@ def main(argv=sys.argv[1:]): # type: ignore
|
||||
if args.color == 'no' or (args.color == 'auto' and not color_terminal()):
|
||||
nocolor()
|
||||
|
||||
doctreedir = abspath(args.doctreedir or path.join(outdir, '.doctrees'))
|
||||
|
||||
status = sys.stdout
|
||||
warning = sys.stderr
|
||||
error = sys.stderr
|
||||
@ -281,9 +266,10 @@ def main(argv=sys.argv[1:]): # type: ignore
|
||||
app = None
|
||||
try:
|
||||
with patch_docutils(), docutils_namespace():
|
||||
app = Sphinx(srcdir, confdir, outdir, doctreedir, args.builder,
|
||||
confoverrides, status, warning, args.freshenv,
|
||||
args.warningiserror, args.tags, args.verbosity, args.jobs)
|
||||
app = Sphinx(args.sourcedir, args.confdir, args.outputdir,
|
||||
args.doctreedir, args.builder, confoverrides, status,
|
||||
warning, args.freshenv, args.warningiserror,
|
||||
args.tags, args.verbosity, args.jobs)
|
||||
app.build(args.force_all, filenames)
|
||||
return app.statuscode
|
||||
except (Exception, KeyboardInterrupt) as exc:
|
||||
|
@ -43,6 +43,11 @@ class SphinxWarning(SphinxError):
|
||||
category = 'Warning, treated as error'
|
||||
|
||||
|
||||
class ApplicationError(SphinxError):
|
||||
"""Application initialization error."""
|
||||
category = 'Application error'
|
||||
|
||||
|
||||
class ExtensionError(SphinxError):
|
||||
"""Extension error."""
|
||||
category = 'Extension error'
|
||||
|
@ -116,7 +116,7 @@ class BuildDoc(Command):
|
||||
for root, dirnames, filenames in os.walk(guess):
|
||||
if 'conf.py' in filenames:
|
||||
return root
|
||||
return None
|
||||
return os.curdir
|
||||
|
||||
# Overriding distutils' Command._ensure_stringlike which doesn't support
|
||||
# unicode, causing finalize_options to fail if invoked again. Workaround
|
||||
@ -134,30 +134,26 @@ class BuildDoc(Command):
|
||||
|
||||
def finalize_options(self):
|
||||
# type: () -> None
|
||||
self.ensure_string_list('builder')
|
||||
|
||||
if self.source_dir is None:
|
||||
self.source_dir = self._guess_source_dir()
|
||||
self.announce('Using source directory %s' % self.source_dir)
|
||||
|
||||
self.ensure_dirname('source_dir')
|
||||
if self.source_dir is None:
|
||||
self.source_dir = os.curdir
|
||||
self.source_dir = abspath(self.source_dir)
|
||||
|
||||
if self.config_dir is None:
|
||||
self.config_dir = self.source_dir
|
||||
self.config_dir = abspath(self.config_dir)
|
||||
|
||||
self.ensure_string_list('builder')
|
||||
if self.build_dir is None:
|
||||
build = self.get_finalized_command('build')
|
||||
self.build_dir = os.path.join(abspath(build.build_base), 'sphinx') # type: ignore
|
||||
self.mkpath(self.build_dir) # type: ignore
|
||||
self.build_dir = abspath(self.build_dir)
|
||||
|
||||
self.doctree_dir = os.path.join(self.build_dir, 'doctrees')
|
||||
self.mkpath(self.doctree_dir) # type: ignore
|
||||
|
||||
self.builder_target_dirs = [
|
||||
(builder, os.path.join(self.build_dir, builder))
|
||||
for builder in self.builder] # type: List[Tuple[str, unicode]]
|
||||
for _, builder_target_dir in self.builder_target_dirs:
|
||||
self.mkpath(builder_target_dir) # type: ignore
|
||||
|
||||
def run(self):
|
||||
# type: () -> None
|
||||
|
@ -137,12 +137,14 @@ def warning(app):
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def make_app(test_params):
|
||||
def make_app(test_params, monkeypatch):
|
||||
"""
|
||||
provides make_app function to initialize SphinxTestApp instance.
|
||||
if you want to initialize 'app' in your test function. please use this
|
||||
instead of using SphinxTestApp class directory.
|
||||
"""
|
||||
monkeypatch.setattr('sphinx.application.abspath', lambda x: x)
|
||||
|
||||
apps = []
|
||||
syspath = sys.path[:]
|
||||
|
||||
|
@ -219,7 +219,12 @@ def abspath(pathdir):
|
||||
# type: (unicode) -> unicode
|
||||
pathdir = path.abspath(pathdir)
|
||||
if isinstance(pathdir, bytes):
|
||||
pathdir = pathdir.decode(fs_encoding)
|
||||
try:
|
||||
pathdir = pathdir.decode(fs_encoding)
|
||||
except UnicodeDecodeError:
|
||||
raise UnicodeDecodeError('multibyte filename not supported on '
|
||||
'this filesystem encoding '
|
||||
'(%r)' % fs_encoding)
|
||||
return pathdir
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user