[PATCH 3 of 3 RFC] setup: install & build documentation using docutils

Martin Geisler mg at lazybytes.net
Sun Nov 22 15:23:45 CST 2009


Dan Villiom Podlaski Christiansen <danchr at gmail.com> writes:

Hi Dan,

Now that I've taked a better look at it, I think it looks quite good :-)

> @@ -212,6 +217,10 @@ class build_mo(build):
>              self.distribution.package_data_files = []
>          datafiles = self.distribution.package_data_files
>  
> +        if not hasattr(self.distribution, 'package_data_files'):
> +            self.distribution.package_data_files = []
> +        datafiles = self.distribution.package_data_files

I guess that is a duplicated hunk?

>          join = os.path.join
>          for po in os.listdir(podir):
>              if not po.endswith('.po'):
> @@ -229,6 +238,148 @@ class build_mo(build):
>  
>  build.sub_commands.append(('build_mo', None))
>  

> +    def finalize_options (self):
> +        # bit of a hack for turning "lib.<whatever>" into "data.<whatever>"
> +        undefined = self.build_dir is None
> +        self.set_undefined_options('build',
> +                                   ('build_lib', 'build_dir'),
> +                                   ('force', 'force'))
> +        if undefined:
> +            self.build_dir = self.build_dir.replace('lib', 'data')

Why is this hack necessary and what problem does it solve?

> +    def gendoc(self, output):
> +        from doc import gendoc
> +        from cStringIO import StringIO
> +
> +        s = StringIO()
> +        gendoc.show_doc(s)
> +        s = s.getvalue()
> +
> +        # only write to the file if the output has changed
> +        if not (os.path.exists(output) and file(output).read() == s):
> +            file(output, 'w').write(s)

Perhaps we could use self.make_file here like you do below?

> +        try:
> +            from docutils.writers import manpage
> +        except ImportError:
> +            # load & use the bundled rst2man
> +            from doc import rst2man as manpage

We should not import the manpage writer from Docutils, we have some
patches that are not yet applied upstream:

  http://sf.net/tracker/?func=detail&aid=2894087&group_id=38414&atid=422032

> +        # avoid cluttering the source directory by copying all documentation
> +        # files to the build directory
> +        self.mkpath(self.build_dir)
> +        self.copy_tree('doc', self.build_dir)

Where is self.build_dir normally? Perhaps we could start by duplicating
the Makefile functionality first. Then we can add support for extra
build directories afterwards.

> +        pattern = re.compile(r'^((.*)\.([0-9]))\.txt$')
> +
> +        stylesheet = 'style.css'
> +        datafiles.append((join('doc', self.distribution.get_name()),
> +                          [join(self.build_dir, stylesheet)]))
> +
> +        for srcfile in os.listdir(self.build_dir):

I would use the glob standard module here:

  for srcfile in glob.glob('*.[0-9].txt')

> +            srcfile = join(self.build_dir, srcfile)
> +            htmlfile = join(self.build_dir, match.group(1) + '.html')
> +            manfile = join(self.build_dir, match.group(1))

And then do srcfile[:-3] + 'html'

> +            # add resulting files to distrubution
> +            datafiles.append((join('doc', self.distribution.get_name()),
> +                              [htmlfile]))
> +            datafiles.append((join('man', 'man' + manfile.rsplit('.', 1)[1]),
> +                              [manfile]))

I think manfile.rsplit('.', 1)[1] is the same as srcfile[-5]?

> +            # reader & writer classes
> +            # NOTE: writers.get_writer_class('manpage') will be used eventually
> +            reader = readers.get_reader_class('standalone')(parser_name='rst')
> +            htmlwriter = writers.get_writer_class('html')()
> +            manwriter = manpage.Writer()
> +            components = (reader, reader.parser, htmlwriter, manwriter,)
> +
> +            # get & set docutils settings
> +            optparser = frontend.OptionParser(components)
> +            settings = optparser.parse_args(['--halt', 'warning',
> +                                             '--link-stylesheet',
> +                                             '--stylesheet-path', 'style.css'
> +                                             '--option-limit' '0'])
> +
> +            # read & parse ReST source
> +            reader.read(io.FileInput(source_path=srcfile, encoding='ascii'),
> +                        None, settings)
> +
> +            document = reader.document
> +            document.transformer.populate_from_components(components)
> +            document.transformer.apply_transforms()
> +
> +            # extract dependancies from docutils
> +            dependancies = [srcfile] + settings.record_dependencies.list
> +
> +            # generate the documentation files; using distutils to avoid
> +            # unnecessary processing
> +            self.make_file(infiles=[srcfile] + dependancies, outfile=htmlfile,

You already have srcfile in the dependancies list. Please remember to
correct the name as timeless pointed out :-)

> +                           func=htmlwriter.write,
> +                           args=(reader.document,
> +                                 io.FileOutput(destination_path=htmlfile,
> +                                               encoding='utf-8')),
> +                           exec_msg='generating %s' % htmlfile)
> +
> +            settings = optparser.parse_args(['--strip-elements-with-class',
> +                                             'htmlonly'], settings)

Is this code there in order to avoid parsing the documents twice? I
guess you could have used docutils.core.publish_programmatically or one
of the other publish_* function in that module?

-- 
Martin Geisler

VIFF (Virtual Ideal Functionality Framework) brings easy and efficient
SMPC (Secure Multiparty Computation) to Python. See: http://viff.dk/.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 197 bytes
Desc: not available
URL: <http://selenic.com/pipermail/mercurial-devel/attachments/20091122/6ba4af9b/attachment.pgp>


More information about the Mercurial-devel mailing list