diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py index a8cb462c4..d5a66fef4 100644 --- a/sphinx/builders/html.py +++ b/sphinx/builders/html.py @@ -10,6 +10,7 @@ """ import os +import zlib import codecs import posixpath import cPickle as pickle @@ -711,15 +712,22 @@ class StandaloneHTMLBuilder(Builder): self.info('done') self.info(bold('dumping object inventory... '), nonl=True) - f = open(path.join(self.outdir, INVENTORY_FILENAME), 'w') + f = open(path.join(self.outdir, INVENTORY_FILENAME), 'wb') try: f.write('# Sphinx inventory version 2\n') f.write('# Project: %s\n' % self.config.project.encode('utf-8')) f.write('# Version: %s\n' % self.config.version) + f.write('# The remainder of this file is compressed using zlib.\n') + compressor = zlib.compressobj(9) for domainname, domain in self.env.domains.iteritems(): for name, type, docname, anchor, prio in domain.get_objects(): - f.write('%s %s:%s %s %s\n' % (name, domainname, type, prio, - self.get_target_uri(docname) + '#' + anchor)) + if anchor.endswith(name): + # this can shorten the inventory by as much as 25% + anchor = anchor[:-len(name)] + '$' + f.write(compressor.compress( + '%s %s:%s %s %s\n' % (name, domainname, type, prio, + self.get_target_uri(docname) + '#' + anchor))) + f.write(compressor.flush()) finally: f.close() self.info('done') diff --git a/sphinx/ext/intersphinx.py b/sphinx/ext/intersphinx.py index 7756ae707..f5d08ee44 100644 --- a/sphinx/ext/intersphinx.py +++ b/sphinx/ext/intersphinx.py @@ -25,6 +25,7 @@ """ import time +import zlib import urllib2 import posixpath from os import path @@ -62,12 +63,35 @@ def fetch_inventory_v1(f, uri, join): def fetch_inventory_v2(f, uri, join): invdata = {} - line = f.next() + line = f.readline() projname = line.rstrip()[11:].decode('utf-8') - line = f.next() + line = f.readline() version = line.rstrip()[11:] - for line in f: + line = f.readline() + if 'zlib' not in line: + raise ValueError + + def read_chunks(): + decompressor = zlib.decompressobj() + for chunk in iter(lambda: f.read(16 * 1024), ''): + yield decompressor.decompress(chunk) + yield decompressor.flush() + + def split_lines(iter): + buf = '' + for chunk in iter: + buf += chunk + lineend = buf.find('\n') + while lineend != -1: + yield buf[:lineend] + buf = buf[lineend+1:] + lineend = buf.find('\n') + assert not buf + + for line in split_lines(read_chunks()): name, type, prio, location = line.rstrip().split(None, 3) + if location.endswith('$'): + location = location[:-1] + name location = join(uri, location) invdata.setdefault(type, {})[name] = (projname, version, location) return invdata @@ -89,15 +113,18 @@ def fetch_inventory(app, uri, inv): '%s: %s' % (inv, err.__class__, err)) return try: - line = f.next().rstrip() - if line == '# Sphinx inventory version 1': - invdata = fetch_inventory_v1(f, uri, join) - elif line == '# Sphinx inventory version 2': - invdata = fetch_inventory_v2(f, uri, join) - else: + line = f.readline().rstrip() + try: + if line == '# Sphinx inventory version 1': + invdata = fetch_inventory_v1(f, uri, join) + elif line == '# Sphinx inventory version 2': + invdata = fetch_inventory_v2(f, uri, join) + else: + raise ValueError + f.close() + except ValueError: f.close() raise ValueError('unknown or unsupported inventory version') - f.close() except Exception, err: app.warn('intersphinx inventory %r not readable due to ' '%s: %s' % (inv, err.__class__.__name__, err))