mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Apply Tim Golden's patch from #1520, which resolves confusion between
file paths and relative URIs so that building on Windows is flawlessly possible.
This commit is contained in:
parent
4349b88f75
commit
cfa8045490
@ -27,13 +27,15 @@ from docutils.readers import doctree
|
|||||||
from docutils.frontend import OptionParser
|
from docutils.frontend import OptionParser
|
||||||
|
|
||||||
from .util import (get_matching_files, attrdict, status_iterator,
|
from .util import (get_matching_files, attrdict, status_iterator,
|
||||||
ensuredir, get_category, relative_uri)
|
ensuredir, get_category, relative_uri,
|
||||||
from .writer import HTMLWriter
|
webify_filepath, unwebify_filepath)
|
||||||
from .util.console import bold, purple, green
|
|
||||||
from .htmlhelp import build_hhx
|
from .htmlhelp import build_hhx
|
||||||
from .patchlevel import get_version_info, get_sys_version_info
|
from .patchlevel import get_version_info, get_sys_version_info
|
||||||
|
from .htmlwriter import HTMLWriter
|
||||||
|
#from .latexwriter import LaTeXWriter
|
||||||
from .environment import BuildEnvironment
|
from .environment import BuildEnvironment
|
||||||
from .highlighting import pygments, get_stylesheet
|
from .highlighting import pygments, get_stylesheet
|
||||||
|
from .util.console import bold, purple, green
|
||||||
|
|
||||||
# side effect: registers roles and directives
|
# side effect: registers roles and directives
|
||||||
from . import roles
|
from . import roles
|
||||||
@ -234,7 +236,7 @@ class Builder(object):
|
|||||||
# build all
|
# build all
|
||||||
filenames_set = set(self.env.all_files)
|
filenames_set = set(self.env.all_files)
|
||||||
|
|
||||||
self.prepare_writing(filenames)
|
self.prepare_writing(filenames_set)
|
||||||
|
|
||||||
# write target files
|
# write target files
|
||||||
with collect_env_warnings(self):
|
with collect_env_warnings(self):
|
||||||
@ -483,12 +485,12 @@ class StandaloneHTMLBuilder(Builder):
|
|||||||
self.srcdir, '*.rst', exclude=set(self.config.get('unused_files', ()))):
|
self.srcdir, '*.rst', exclude=set(self.config.get('unused_files', ()))):
|
||||||
try:
|
try:
|
||||||
targetmtime = path.getmtime(path.join(self.outdir,
|
targetmtime = path.getmtime(path.join(self.outdir,
|
||||||
filename[:-4] + '.html'))
|
unwebify_filepath(filename)[:-4] + '.html'))
|
||||||
except:
|
except:
|
||||||
targetmtime = 0
|
targetmtime = 0
|
||||||
if filename not in self.env.all_files:
|
if filename not in self.env.all_files:
|
||||||
yield filename
|
yield filename
|
||||||
elif path.getmtime(path.join(self.srcdir, filename)) > targetmtime:
|
elif path.getmtime(path.join(self.srcdir, unwebify_filepath(filename))) > targetmtime:
|
||||||
yield filename
|
yield filename
|
||||||
|
|
||||||
|
|
||||||
@ -513,7 +515,7 @@ class StandaloneHTMLBuilder(Builder):
|
|||||||
ctx = self.globalcontext.copy()
|
ctx = self.globalcontext.copy()
|
||||||
ctx.update(context)
|
ctx.update(context)
|
||||||
output = self.templates[templatename].render(ctx)
|
output = self.templates[templatename].render(ctx)
|
||||||
outfilename = path.join(self.outdir, filename[:-4] + '.html')
|
outfilename = path.join(self.outdir, unwebify_filepath(filename)[:-4] + '.html')
|
||||||
ensuredir(path.dirname(outfilename)) # normally different from self.outdir
|
ensuredir(path.dirname(outfilename)) # normally different from self.outdir
|
||||||
try:
|
try:
|
||||||
with codecs.open(outfilename, 'w', 'utf-8') as fp:
|
with codecs.open(outfilename, 'w', 'utf-8') as fp:
|
||||||
@ -522,7 +524,7 @@ class StandaloneHTMLBuilder(Builder):
|
|||||||
print >>self.warning_stream, "Error writing file %s: %s" % (outfilename, err)
|
print >>self.warning_stream, "Error writing file %s: %s" % (outfilename, err)
|
||||||
if self.copysource and context.get('sourcename'):
|
if self.copysource and context.get('sourcename'):
|
||||||
# copy the source file for the "show source" link
|
# copy the source file for the "show source" link
|
||||||
shutil.copyfile(path.join(self.srcdir, filename),
|
shutil.copyfile(path.join(self.srcdir, unwebify_filepath(filename)),
|
||||||
path.join(self.outdir, context['sourcename']))
|
path.join(self.outdir, context['sourcename']))
|
||||||
|
|
||||||
def handle_finish(self):
|
def handle_finish(self):
|
||||||
@ -547,10 +549,10 @@ class WebHTMLBuilder(StandaloneHTMLBuilder):
|
|||||||
self.srcdir, '*.rst', exclude=set(self.config.get('unused_files', ()))):
|
self.srcdir, '*.rst', exclude=set(self.config.get('unused_files', ()))):
|
||||||
try:
|
try:
|
||||||
targetmtime = path.getmtime(path.join(self.outdir,
|
targetmtime = path.getmtime(path.join(self.outdir,
|
||||||
filename[:-4] + '.fpickle'))
|
unwebify_filepath(filename)[:-4] + '.fpickle'))
|
||||||
except:
|
except:
|
||||||
targetmtime = 0
|
targetmtime = 0
|
||||||
if path.getmtime(path.join(self.srcdir, filename)) > targetmtime:
|
if path.getmtime(path.join(self.srcdir, unwebify_filepath(filename))) > targetmtime:
|
||||||
yield filename
|
yield filename
|
||||||
|
|
||||||
def get_target_uri(self, source_filename):
|
def get_target_uri(self, source_filename):
|
||||||
@ -577,7 +579,7 @@ class WebHTMLBuilder(StandaloneHTMLBuilder):
|
|||||||
self.indexer.feed(filename, category, title, doctree)
|
self.indexer.feed(filename, category, title, doctree)
|
||||||
|
|
||||||
def handle_file(self, filename, context, templatename='page'):
|
def handle_file(self, filename, context, templatename='page'):
|
||||||
outfilename = path.join(self.outdir, filename[:-4] + '.fpickle')
|
outfilename = path.join(self.outdir, unwebify_filepath(filename)[:-4] + '.fpickle')
|
||||||
ensuredir(path.dirname(outfilename))
|
ensuredir(path.dirname(outfilename))
|
||||||
context.pop('pathto', None) # can't be pickled
|
context.pop('pathto', None) # can't be pickled
|
||||||
with file(outfilename, 'wb') as fp:
|
with file(outfilename, 'wb') as fp:
|
||||||
@ -587,7 +589,7 @@ class WebHTMLBuilder(StandaloneHTMLBuilder):
|
|||||||
if context.get('sourcename'):
|
if context.get('sourcename'):
|
||||||
source_name = path.join(self.outdir, 'sources', context['sourcename'])
|
source_name = path.join(self.outdir, 'sources', context['sourcename'])
|
||||||
ensuredir(path.dirname(source_name))
|
ensuredir(path.dirname(source_name))
|
||||||
shutil.copyfile(path.join(self.srcdir, filename), source_name)
|
shutil.copyfile(path.join(self.srcdir, unwebify_filepath(filename)), source_name)
|
||||||
|
|
||||||
def handle_finish(self):
|
def handle_finish(self):
|
||||||
# dump the global context
|
# dump the global context
|
||||||
@ -632,8 +634,43 @@ class HTMLHelpBuilder(StandaloneHTMLBuilder):
|
|||||||
build_hhx(self, self.outdir, self.options.get('outname') or 'pydoc')
|
build_hhx(self, self.outdir, self.options.get('outname') or 'pydoc')
|
||||||
|
|
||||||
|
|
||||||
|
class LaTeXBuilder(Builder):
|
||||||
|
"""
|
||||||
|
Builds LaTeX output to create PDF.
|
||||||
|
"""
|
||||||
|
name = 'latex'
|
||||||
|
|
||||||
|
def init(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_outdated_files(self):
|
||||||
|
# always rebuild everything for now
|
||||||
|
return self.env.all_files
|
||||||
|
|
||||||
|
def get_target_uri(self, source_filename):
|
||||||
|
# XXX: returns nothing for now
|
||||||
|
return ''
|
||||||
|
|
||||||
|
def prepare_writing(self, filenames):
|
||||||
|
self.docwriter = LaTeXWriter(self.config, self.name)
|
||||||
|
self.docsettings = OptionParser(
|
||||||
|
defaults=self.env.settings,
|
||||||
|
components=(self.docwriter,)).get_default_values()
|
||||||
|
|
||||||
|
|
||||||
|
def write_file(self, filename, doctree):
|
||||||
|
destination = StringOutput(encoding='utf-8')
|
||||||
|
doctree.settings = self.docsettings
|
||||||
|
output = self.docwriter.write(doctree, destination)
|
||||||
|
print output
|
||||||
|
|
||||||
|
def finish(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
builders = {
|
builders = {
|
||||||
'html': StandaloneHTMLBuilder,
|
'html': StandaloneHTMLBuilder,
|
||||||
'web': WebHTMLBuilder,
|
'web': WebHTMLBuilder,
|
||||||
'htmlhelp': HTMLHelpBuilder,
|
'htmlhelp': HTMLHelpBuilder,
|
||||||
|
# 'latex': LaTeXBuilder,
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ from docutils.parsers.rst import directives, roles
|
|||||||
from docutils.parsers.rst.directives import admonitions
|
from docutils.parsers.rst.directives import admonitions
|
||||||
|
|
||||||
from . import addnodes
|
from . import addnodes
|
||||||
|
from .util import webify_filepath, unwebify_filepath
|
||||||
|
|
||||||
# ------ index markup --------------------------------------------------------------
|
# ------ index markup --------------------------------------------------------------
|
||||||
|
|
||||||
@ -554,7 +555,8 @@ def toctree_directive(name, arguments, options, content, lineno,
|
|||||||
subnode = addnodes.toctree()
|
subnode = addnodes.toctree()
|
||||||
includefiles = filter(None, content)
|
includefiles = filter(None, content)
|
||||||
# absolutize filenames
|
# absolutize filenames
|
||||||
includefiles = map(lambda x: path.normpath(path.join(dirname, x)), includefiles)
|
includefiles = [webify_filepath(path.normpath(path.join (dirname, x))) for x in includefiles]
|
||||||
|
#~ includefiles = map(lambda x: path.normpath(path.join(dirname, x)), includefiles)
|
||||||
subnode['includefiles'] = includefiles
|
subnode['includefiles'] = includefiles
|
||||||
subnode['maxdepth'] = options.get('maxdepth', -1)
|
subnode['maxdepth'] = options.get('maxdepth', -1)
|
||||||
return [subnode]
|
return [subnode]
|
||||||
@ -599,9 +601,9 @@ def literalinclude_directive(name, arguments, options, content, lineno,
|
|||||||
return [state.document.reporter.warning('File insertion disabled', line=lineno)]
|
return [state.document.reporter.warning('File insertion disabled', line=lineno)]
|
||||||
env = state.document.settings.env
|
env = state.document.settings.env
|
||||||
fn = arguments[0]
|
fn = arguments[0]
|
||||||
source_dir = path.dirname(path.abspath(state_machine.input_lines.source(
|
source_dir = webify_filepath(path.dirname(path.abspath(state_machine.input_lines.source(
|
||||||
lineno - state_machine.input_offset - 1)))
|
lineno - state_machine.input_offset - 1))))
|
||||||
fn = path.normpath(path.join(source_dir, fn))
|
fn = webify_filepath(path.normpath(path.join(source_dir, fn)))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(fn) as f:
|
with open(fn) as f:
|
||||||
|
@ -38,7 +38,7 @@ Body.enum.converters['loweralpha'] = \
|
|||||||
Body.enum.converters['upperroman'] = lambda x: None
|
Body.enum.converters['upperroman'] = lambda x: None
|
||||||
|
|
||||||
from . import addnodes
|
from . import addnodes
|
||||||
from .util import get_matching_files
|
from .util import get_matching_files, unwebify_filepath, WEB_SEP
|
||||||
from .refcounting import Refcounts
|
from .refcounting import Refcounts
|
||||||
|
|
||||||
default_settings = {
|
default_settings = {
|
||||||
@ -278,11 +278,11 @@ class BuildEnvironment:
|
|||||||
else:
|
else:
|
||||||
# if the doctree file is not there, rebuild
|
# if the doctree file is not there, rebuild
|
||||||
if not path.isfile(path.join(self.doctreedir,
|
if not path.isfile(path.join(self.doctreedir,
|
||||||
filename[:-3] + 'doctree')):
|
unwebify_filepath(filename)[:-3] + 'doctree')):
|
||||||
changed.append(filename)
|
changed.append(filename)
|
||||||
continue
|
continue
|
||||||
mtime, md5 = self.all_files[filename]
|
mtime, md5 = self.all_files[filename]
|
||||||
newmtime = path.getmtime(path.join(self.srcdir, filename))
|
newmtime = path.getmtime(path.join(self.srcdir, unwebify_filepath(filename)))
|
||||||
if newmtime == mtime:
|
if newmtime == mtime:
|
||||||
continue
|
continue
|
||||||
# check the MD5
|
# check the MD5
|
||||||
@ -297,6 +297,8 @@ class BuildEnvironment:
|
|||||||
"""
|
"""
|
||||||
(Re-)read all files new or changed since last update.
|
(Re-)read all files new or changed since last update.
|
||||||
Yields a summary and then filenames as it processes them.
|
Yields a summary and then filenames as it processes them.
|
||||||
|
Store all environment filenames as webified (ie using "/"
|
||||||
|
as a separator in place of os.path.sep).
|
||||||
"""
|
"""
|
||||||
added, changed, removed = self.get_outdated_files(config)
|
added, changed, removed = self.get_outdated_files(config)
|
||||||
msg = '%s added, %s changed, %s removed' % (len(added), len(changed),
|
msg = '%s added, %s changed, %s removed' % (len(added), len(changed),
|
||||||
@ -329,7 +331,7 @@ class BuildEnvironment:
|
|||||||
self.clear_file(filename)
|
self.clear_file(filename)
|
||||||
|
|
||||||
if src_path is None:
|
if src_path is None:
|
||||||
src_path = path.join(self.srcdir, filename)
|
src_path = path.join(self.srcdir, unwebify_filepath(filename))
|
||||||
|
|
||||||
self.filename = filename
|
self.filename = filename
|
||||||
doctree = publish_doctree(None, src_path, FileInput,
|
doctree = publish_doctree(None, src_path, FileInput,
|
||||||
@ -360,7 +362,7 @@ class BuildEnvironment:
|
|||||||
|
|
||||||
if save_parsed:
|
if save_parsed:
|
||||||
# save the parsed doctree
|
# save the parsed doctree
|
||||||
doctree_filename = path.join(self.doctreedir, filename[:-3] + 'doctree')
|
doctree_filename = path.join(self.doctreedir, unwebify_filepath(filename)[:-3] + 'doctree')
|
||||||
dirname = path.dirname(doctree_filename)
|
dirname = path.dirname(doctree_filename)
|
||||||
if not path.isdir(dirname):
|
if not path.isdir(dirname):
|
||||||
os.makedirs(dirname)
|
os.makedirs(dirname)
|
||||||
@ -516,7 +518,7 @@ class BuildEnvironment:
|
|||||||
|
|
||||||
def get_doctree(self, filename):
|
def get_doctree(self, filename):
|
||||||
"""Read the doctree for a file from the pickle and return it."""
|
"""Read the doctree for a file from the pickle and return it."""
|
||||||
doctree_filename = path.join(self.doctreedir, filename[:-3] + 'doctree')
|
doctree_filename = path.join(self.doctreedir, unwebify_filepath(filename)[:-3] + 'doctree')
|
||||||
with file(doctree_filename, 'rb') as f:
|
with file(doctree_filename, 'rb') as f:
|
||||||
doctree = pickle.load(f)
|
doctree = pickle.load(f)
|
||||||
doctree.reporter = Reporter(filename, 2, 4, stream=self.warning_stream)
|
doctree.reporter = Reporter(filename, 2, 4, stream=self.warning_stream)
|
||||||
@ -862,6 +864,6 @@ class BuildEnvironment:
|
|||||||
filename. This also resolves the special `index.rst` files. If the file
|
filename. This also resolves the special `index.rst` files. If the file
|
||||||
does not exist the return value will be `None`.
|
does not exist the return value will be `None`.
|
||||||
"""
|
"""
|
||||||
for rstname in filename + '.rst', filename + path.sep + 'index.rst':
|
for rstname in filename + '.rst', filename + WEB_SEP + 'index.rst':
|
||||||
if rstname in self.all_files:
|
if rstname in self.all_files:
|
||||||
return rstname
|
return rstname
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
sphinx.writer
|
sphinx.htmlwriter
|
||||||
~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
docutils writers handling Sphinx' custom nodes.
|
docutils writers handling Sphinx' custom nodes.
|
||||||
|
|
@ -15,17 +15,35 @@ import fnmatch
|
|||||||
from os import path
|
from os import path
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Define WEB_SEP as a manifest constant, not
|
||||||
|
# so much because we expect it to change in
|
||||||
|
# the future as to avoid the suspicion that
|
||||||
|
# a stray "/" in the code is a hangover from
|
||||||
|
# more *nix-oriented origins.
|
||||||
|
#
|
||||||
|
WEB_SEP = "/"
|
||||||
|
|
||||||
|
|
||||||
|
def webify_filepath(filepath):
|
||||||
|
return filepath.replace(os.path.sep, WEB_SEP)
|
||||||
|
|
||||||
|
|
||||||
|
def unwebify_filepath(webpath):
|
||||||
|
return webpath.replace(WEB_SEP, os.path.sep)
|
||||||
|
|
||||||
|
|
||||||
def relative_uri(base, to):
|
def relative_uri(base, to):
|
||||||
"""Return a relative URL from ``base`` to ``to``."""
|
"""Return a relative URL from ``base`` to ``to``."""
|
||||||
b2 = base.split('/')
|
b2 = base.split(WEB_SEP)
|
||||||
t2 = to.split('/')
|
t2 = to.split(WEB_SEP)
|
||||||
# remove common segments
|
# remove common segments
|
||||||
for x, y in zip(b2, t2):
|
for x, y in zip(b2, t2):
|
||||||
if x != y:
|
if x != y:
|
||||||
break
|
break
|
||||||
b2.pop(0)
|
b2.pop(0)
|
||||||
t2.pop(0)
|
t2.pop(0)
|
||||||
return '../' * (len(b2)-1) + '/'.join(t2)
|
return ('..' + WEB_SEP) * (len(b2)-1) + WEB_SEP.join(t2)
|
||||||
|
|
||||||
|
|
||||||
def ensuredir(path):
|
def ensuredir(path):
|
||||||
@ -60,12 +78,12 @@ def get_matching_files(dirname, pattern, exclude=()):
|
|||||||
qualified_name = path.join(root[dirlen:], sfile)
|
qualified_name = path.join(root[dirlen:], sfile)
|
||||||
if qualified_name in exclude:
|
if qualified_name in exclude:
|
||||||
continue
|
continue
|
||||||
yield qualified_name
|
yield webify_filepath(qualified_name)
|
||||||
|
|
||||||
|
|
||||||
def get_category(filename):
|
def get_category(filename):
|
||||||
"""Get the "category" part of a RST filename."""
|
"""Get the "category" part of a RST filename."""
|
||||||
parts = filename.split('/', 1)
|
parts = filename.split(WEB_SEP, 1)
|
||||||
if len(parts) < 2:
|
if len(parts) < 2:
|
||||||
return
|
return
|
||||||
return parts[0]
|
return parts[0]
|
||||||
|
Loading…
Reference in New Issue
Block a user