Skip to content

Commit

Permalink
Merge build-docs-2380-2
Browse files Browse the repository at this point in the history
Authors: thijs, therve
Reviewer: jonathanj
Fixes: twisted#2380

Add a script to build documentation for the release.


git-svn-id: svn://svn.twistedmatrix.com/svn/Twisted/trunk@37746 bbbe8e31-12d6-0310-92fd-ac37d47ddeeb
  • Loading branch information
therve committed Mar 20, 2013
1 parent 244a3b8 commit 6307dfc
Show file tree
Hide file tree
Showing 4 changed files with 228 additions and 35 deletions.
20 changes: 20 additions & 0 deletions bin/admin/build-docs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/usr/bin/env python

# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.

# This script is not meant to be distributed to users of Twisted.
# It is only for use in making upstream Twisted releases.

import sys, os
extra = os.path.dirname(os.path.dirname(sys.argv[0]))
sys.path.insert(0, extra)
try:
import _preamble
except ImportError:
sys.exc_clear()
sys.path.remove(extra)

from twisted.python._release import BuildDocsScript

BuildDocsScript().main(sys.argv[1:])
69 changes: 67 additions & 2 deletions twisted/python/_release.py
Original file line number Diff line number Diff line change
Expand Up @@ -441,8 +441,7 @@ class APIBuilder(object):
"""
Generate API documentation from source files using
U{pydoctor<http://codespeak.net/~mwh/pydoctor/>}. This requires
pydoctor to be installed and usable (which means you won't be able to
use it with Python 2.3).
pydoctor to be installed and usable.
"""
def build(self, projectName, projectURL, sourceURL, packagePath,
outputPath):
Expand Down Expand Up @@ -1408,3 +1407,69 @@ def main(self, args):
sys.exit("Must specify two arguments: "
"Twisted checkout and destination path")
self.buildAPIDocs(FilePath(args[0]), FilePath(args[1]))



class BuildDocsScript(object):
"""
A thing for building the main documentation. See L{main}.
"""

def buildDocs(self, projectRoot, template):
"""
Build the main documentation of Twisted, with our project policy.
@param projectRoot: A L{FilePath} representing the root of the Twisted
checkout.
@type projectRoot: L{FilePath}
@param template: A L{FilePath} pointing to the template file that is
used for the look and feel of the howto documentation.
@type template: L{FilePath}
"""
version = Project(projectRoot.child("twisted")).getVersion()
versionString = version.base()
apiURL = "http://twistedmatrix.com/documents/%s/api/" % (
versionString,)

dirs = {}
docRoot = projectRoot.child("doc")

for p in docRoot.walk():
if p.basename() == 'man':
ManBuilder().build(p)

howtoRoot = docRoot.descendant(["core", "howto"])

for p in docRoot.walk():
if p.basename().endswith('.xhtml'):
if p.parent() not in dirs:
dirs[p.parent()] = True
DocBuilder().build(
versionString, howtoRoot, p.parent(),
template,
apiURL + "%s.html",
False)

BookBuilder().build(howtoRoot, dirs.keys(),
howtoRoot.child('book.tex'),
howtoRoot.child('book.pdf'))

for path in dirs:
for doc in path.globChildren("*.xhtml"):
doc.remove()


def main(self, args):
"""
Build the main documentation.
@type args: list of str
@param args: The command line arguments to process. This must contain
two strings: the path to the root of the Twisted checkout and the
path to the Twisted website template.
"""
if len(args) != 2:
sys.exit("Must specify two arguments: "
"Twisted checkout path and template path.")
self.buildDocs(FilePath(args[0]), FilePath(args[1]))
174 changes: 141 additions & 33 deletions twisted/python/test/test_release.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
NoDocumentsFound, filePathDelta, CommandFailed, BookBuilder,
DistributionBuilder, APIBuilder, BuildAPIDocsScript, buildAllTarballs,
runCommand, UncleanWorkingDirectory, NotWorkingDirectory,
ChangeVersionsScript, BuildTarballsScript, NewsBuilder)
ChangeVersionsScript, BuildTarballsScript, NewsBuilder, BuildDocsScript)

if os.name != 'posix':
skip = "Release toolchain only supported on POSIX."
Expand Down Expand Up @@ -532,12 +532,12 @@ def test_replaceInFile(self):
the dict that is found in the file is replaced with the corresponding
value.
"""
in_ = 'foo\nhey hey $VER\nbar\n'
content = 'foo\nhey hey $VER\nbar\n'
outf = open('release.replace', 'w')
outf.write(in_)
outf.write(content)
outf.close()

expected = in_.replace('$VER', '2.0.0')
expected = content.replace('$VER', '2.0.0')
replaceInFile('release.replace', {'$VER': '2.0.0'})
self.assertEqual(open('release.replace').read(), expected)

Expand Down Expand Up @@ -768,6 +768,52 @@ def getArbitraryManHTMLOutput(self, version, prefix=""):
'prefix': prefix, 'version': version}).toxml("utf-8")


def setupTeXFiles(self, howtoDir):
"""
Create a main TeX file with 3 sections in C{howtoDir}.
@param howtoDir: The path in which to create the TeX files.
@return: The main TeX file C{FilePath}.
"""
sections = range(3)
self.setupTeXSections(sections, howtoDir)
return self.setupTeXBook(sections, howtoDir)


def setupTeXSections(self, sections, howtoDir):
"""
For every C{sections}, create a TeX file in C{howtoDir}.
@param sections: A list of sections to create.
@param howtoDir: The path in which to create the TeX files.
"""
for section in sections:
texPath = howtoDir.child("%s.tex" % (section,))
texPath.setContent(
self.getArbitraryOutput("1.2.3", section))


def setupTeXBook(self, sections, howtoDir):
"""
Setup the main C{book.tex} file referencing C{sections}.
@param sections: A list of sections to reference.
@param howtoDir: The path in which to create the TeX files.
@return: The main TeX file C{FilePath}.
"""
bookTeX = howtoDir.child("book.tex")
bookTeX.setContent(
r"\documentclass{book}" "\n"
r"\begin{document}" "\n" +
"\n".join([r"\input{%s.tex}" % (n,) for n in sections]) +
r"\end{document}" "\n")
return bookTeX



class DocBuilderTestCase(TestCase, BuilderTestsMixin):
"""
Expand Down Expand Up @@ -947,6 +993,91 @@ def test_getLinkrelToUncle(self):



class BuildDocsScriptTests(TestCase, BuilderTestsMixin,
StructureAssertingMixin):
"""
Tests for L{BuildDocsScript}.
"""

def setUp(self):
"""
Create a L{BuildDocsScript} in C{self.script}.
"""
BuilderTestsMixin.setUp(self)
self.script = BuildDocsScript()


def test_buildDocs(self):
"""
L{BuildDocsScript.buildDocs} generates Lore man pages, turn all Lore
pages to HTML, and build the PDF book.
"""
rootDir = FilePath(self.mktemp())
rootDir.createDirectory()
loreInput, loreOutput = self.getArbitraryLoreInputAndOutput(
"10.0.0",
apiBaseURL="http://twistedmatrix.com/documents/10.0.0/api/%s.html")
coreIndexInput, coreIndexOutput = self.getArbitraryLoreInputAndOutput(
"10.0.0", prefix="howto/",
apiBaseURL="http://twistedmatrix.com/documents/10.0.0/api/%s.html")

manInput = self.getArbitraryManInput()
manOutput = self.getArbitraryManHTMLOutput("10.0.0", "../howto/")

structure = {
"LICENSE": "copyright!",
"twisted": {"_version.py": genVersion("twisted", 10, 0, 0)},
"doc": {"core": {"index.xhtml": coreIndexInput,
"howto": {"template.tpl": self.template,
"index.xhtml": loreInput},
"man": {"twistd.1": manInput}}}}

outStructure = {
"LICENSE": "copyright!",
"twisted": {"_version.py": genVersion("twisted", 10, 0, 0)},
"doc": {"core": {"index.html": coreIndexOutput,
"howto": {"template.tpl": self.template,
"index.html": loreOutput},
"man": {"twistd.1": manInput,
"twistd-man.html": manOutput}}}}

self.createStructure(rootDir, structure)

howtoDir = rootDir.descendant(["doc", "core", "howto"])
self.setupTeXFiles(howtoDir)

templateFile = howtoDir.child("template.tpl")
self.script.buildDocs(rootDir, templateFile)

howtoDir.child("book.tex").remove()
howtoDir.child("book.pdf").remove()
self.assertStructure(rootDir, outStructure)

test_buildDocs.skip = latexSkip or loreSkip


def test_docsBuilderScriptMainRequiresThreeArguments(self):
"""
SystemExit is raised when the incorrect number of command line
arguments are passed to the main documentation building script.
"""
self.assertRaises(SystemExit, self.script.main, [])
self.assertRaises(SystemExit, self.script.main, ["foo"])
self.assertRaises(SystemExit, self.script.main, ["foo", "bar", "baz"])


def test_docsBuilderScriptMain(self):
"""
The main documentation building script invokes C{buildDocs} with the
arguments passed to it cast as L{FilePath}.
"""
calls = []
self.script.buildDocs = lambda a, b: calls.append((a, b))
self.script.main(["hello", "there"])
self.assertEqual(calls, [(FilePath("hello"), FilePath("there"))])



class APIBuilderTestCase(TestCase):
"""
Tests for L{APIBuilder}.
Expand Down Expand Up @@ -1323,35 +1454,12 @@ def test_buildPDFRejectsInvalidBookFilename(self):
None)


def _setupTeXFiles(self):
sections = range(3)
self._setupTeXSections(sections)
return self._setupTeXBook(sections)


def _setupTeXSections(self, sections):
for texSectionNumber in sections:
texPath = self.howtoDir.child("%d.tex" % (texSectionNumber,))
texPath.setContent(
self.getArbitraryOutput("1.2.3", texSectionNumber))


def _setupTeXBook(self, sections):
bookTeX = self.howtoDir.child("book.tex")
bookTeX.setContent(
r"\documentclass{book}" "\n"
r"\begin{document}" "\n" +
"\n".join([r"\input{%d.tex}" % (n,) for n in sections]) +
r"\end{document}" "\n")
return bookTeX


def test_buildPDF(self):
"""
L{BookBuilder.buildPDF} creates a PDF given an index tex file and a
directory containing .tex files.
"""
bookPath = self._setupTeXFiles()
bookPath = self.setupTeXFiles(self.howtoDir)
outputPath = FilePath(self.mktemp())

builder = BookBuilder()
Expand All @@ -1375,7 +1483,7 @@ def test_buildPDFLongPath(self):
self.howtoDir.makedirs()

# This will use the above long path.
bookPath = self._setupTeXFiles()
bookPath = self.setupTeXFiles(self.howtoDir)
outputPath = FilePath(self.mktemp())

builder = BookBuilder()
Expand All @@ -1400,7 +1508,7 @@ def run(self, command):
self.commands.append(command)
return BookBuilder.run(self, command)

bookPath = self._setupTeXFiles()
bookPath = self.setupTeXFiles(self.howtoDir)
outputPath = FilePath(self.mktemp())

builder = InspectableBookBuilder()
Expand Down Expand Up @@ -1435,7 +1543,7 @@ def test_noSideEffects(self):
the input book are the same before and after the call.
"""
startDir = os.getcwd()
bookTeX = self._setupTeXFiles()
bookTeX = self.setupTeXFiles(self.howtoDir)
startTeXSiblings = bookTeX.parent().children()
startHowtoChildren = self.howtoDir.children()

Expand Down Expand Up @@ -1478,7 +1586,7 @@ def test_build(self):
for sectionNumber in sections:
self.howtoDir.child("%d.xhtml" % (sectionNumber,)).setContent(
self.getArbitraryLoreInput(sectionNumber))
bookTeX = self._setupTeXBook(sections)
bookTeX = self.setupTeXBook(sections, self.howtoDir)
bookPDF = FilePath(self.mktemp())

builder = BookBuilder()
Expand All @@ -1495,7 +1603,7 @@ def test_buildRemovesTemporaryLaTeXFiles(self):
for sectionNumber in sections:
self.howtoDir.child("%d.xhtml" % (sectionNumber,)).setContent(
self.getArbitraryLoreInput(sectionNumber))
bookTeX = self._setupTeXBook(sections)
bookTeX = self.setupTeXBook(sections, self.howtoDir)
bookPDF = FilePath(self.mktemp())

builder = BookBuilder()
Expand Down
Empty file added twisted/topfiles/2380.misc
Empty file.

0 comments on commit 6307dfc

Please sign in to comment.