Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Added generation of zipped HTML docs for offline viewing.

  • Loading branch information...
commit 10ad76315abb5a69116f9e93b80829e7335ee2d7 1 parent 2ccfd67
Jacob Kaplan-Moss authored August 16, 2011
2  .gitignore
... ...
@@ -1,4 +1,4 @@
1 1
 *.pyc
2 2
 *.db
3 3
 local_settings.py
4  
-
  4
+media/docs
88  django_website/docs/management/commands/update_docs.py
@@ -6,8 +6,11 @@
6 6
 
7 7
 import json
8 8
 import haystack
  9
+import optparse
9 10
 import subprocess
  11
+import zipfile
10 12
 import sphinx.cmdline
  13
+from contextlib import closing
11 14
 from django.conf import settings
12 15
 from django.core.management.base import NoArgsCommand
13 16
 from django.utils.html import strip_tags
@@ -15,16 +18,26 @@
15 18
 from ...models import DocumentRelease, Document
16 19
 
17 20
 class Command(NoArgsCommand):
  21
+    option_list = NoArgsCommand.option_list + (
  22
+        optparse.make_option(
  23
+            '--skip-indexing',
  24
+            action='store_false',
  25
+            dest='reindex',
  26
+            default=True,
  27
+            help='Skip reindexing (for testing, mostly).'
  28
+        ),
  29
+    )
  30
+
18 31
     def handle_noargs(self, **kwargs):
19 32
         try:
20 33
             verbosity = int(kwargs['verbosity'])
21 34
         except (KeyError, TypeError, ValueError):
22 35
             verbosity = 1
23  
-        
  36
+
24 37
         for release in DocumentRelease.objects.all():
25 38
             if verbosity >= 1:
26 39
                 print "Updating %s..." % release
27  
-            
  40
+
28 41
             destdir = Path(settings.DOCS_BUILD_ROOT).child(release.lang, release.version)
29 42
             if not destdir.exists():
30 43
                 destdir.mkdir(parents=True)
@@ -32,32 +45,54 @@ def handle_noargs(self, **kwargs):
32 45
             #
33 46
             # Update the release from SCM.
34 47
             #
35  
-            
  48
+
36 49
             # Make an SCM checkout/update into the destination directory.
37 50
             # Do this dynamically in case we add other SCM later.
38 51
             getattr(self, 'update_%s' % release.scm)(release.scm_url, destdir)
39  
-            
  52
+
40 53
             #
41  
-            # Use Sphinx to build the release docs into JSON documents.
  54
+            # Use Sphinx to build the release docs into JSON and HTML documents.
42 55
             #
  56
+            for builder in ('json', 'html'):
  57
+                # Make the directory for the built files - sphinx-build doesn't
  58
+                # do it for us, apparently.
  59
+                build_dir = destdir.child('_build', builder)
  60
+                if not build_dir.exists():
  61
+                    build_dir.mkdir(parents=True)
43 62
 
44  
-            # Make the directory for the JSON files - sphinx-build doesn't
45  
-            # do it for us, apparently.
46  
-            json_build_dir = destdir.child('_build', 'json')
47  
-            if not json_build_dir.exists():
48  
-                json_build_dir.mkdir(parents=True)
49  
-            
50  
-            # "Shell out" (not exactly, but basically) to sphinx-build.
51  
-            sphinx.cmdline.main(['sphinx-build',
52  
-                '-b', 'json',      # Use the JSON builder
53  
-                '-q',              # Be vewy qwiet
54  
-                destdir,           # Source file directory
55  
-                json_build_dir,    # Destination directory
56  
-            ])
  63
+                # "Shell out" (not exactly, but basically) to sphinx-build.
  64
+                if verbosity >= 2:
  65
+                    print "  building %s (into %s)" % (builder, build_dir)
  66
+                sphinx.cmdline.main(['sphinx-build',
  67
+                    '-b', builder,
  68
+                    '-q',              # Be vewy qwiet
  69
+                    destdir,           # Source file directory
  70
+                    build_dir,         # Destination directory
  71
+                ])
  72
+
  73
+            #
  74
+            # Create a zip file of the HTML build for offline reading.
  75
+            # This gets moved into MEDIA_ROOT for downloading.
  76
+            #
  77
+            html_build_dir = destdir.child('_build', 'html')
  78
+            zipfile_name = 'django-docs-%s-%s.zip' % (release.version, release.lang)
  79
+            zipfile_path = Path(settings.MEDIA_ROOT).child('docs', zipfile_name)
  80
+            if not zipfile_path.parent.exists():
  81
+                zipfile_path.parent.mkdir(parents=True)
  82
+            if verbosity >= 2:
  83
+                print "  build zip (into %s)" % zipfile_path
  84
+            with closing(zipfile.ZipFile(zipfile_path, 'w')) as zf:
  85
+                for f in html_build_dir.walk(filter=Path.isfile):
  86
+                    zf.write(f, html_build_dir.rel_path_to(f))
57 87
 
58 88
             #
59 89
             # Rebuild the imported document list and search index.
60 90
             #
  91
+            if not kwargs['reindex']:
  92
+                continue
  93
+
  94
+            if verbosity >= 2:
  95
+                print "  reindexing..."
61 96
 
62 97
             # Build a dict of {path_fragment: document_object}. We'll pop values
63 98
             # out of this dict as we go which'll make sure we know which
@@ -65,20 +100,21 @@ def handle_noargs(self, **kwargs):
65 100
             documents = dict((doc.path, doc) for doc in release.documents.all())
66 101
 
67 102
             # Walk the tree we've just built looking for ".fjson" documents
68  
-            # (just JSON, but Sphinx names them weirdly). Each one of those 
  103
+            # (just JSON, but Sphinx names them weirdly). Each one of those
69 104
             # documents gets a corresponding Document object created which
70  
-            # we'll then ask Sphinx to reindex. 
  105
+            # we'll then ask Sphinx to reindex.
71 106
             #
72 107
             # We have to be a bit careful to reverse-engineer the correct
73 108
             # relative path component, especially for "index" documents,
74  
-            # otherwise the search results will be incorrect. 
  109
+            # otherwise the search results will be incorrect.
  110
+            json_build_dir = destdir.child('_build', 'json')
75 111
             for built_doc in json_build_dir.walk():
76 112
                 if built_doc.isfile() and built_doc.ext == '.fjson':
77  
-                    
  113
+
78 114
                     # Convert the built_doc path which is now an absolute
79 115
                     # path (i.e. "/home/docs/en/1.2/_build/ref/models.json")
80 116
                     # into a path component (i.e. "ref/models").
81  
-                    path = json_build_dir.rel_path_to(built_doc) 
  117
+                    path = json_build_dir.rel_path_to(built_doc)
82 118
                     if path.stem == 'index':
83 119
                         path = path.parent
84 120
                     path = str(path.parent.child(path.stem))
@@ -89,7 +125,7 @@ def handle_noargs(self, **kwargs):
89 125
                     with open(built_doc) as fp:
90 126
                         json_doc = json.load(fp)
91 127
                         try:
92  
-                            ignored = json_doc['body'] # Just to make sure it exists.
  128
+                            json_doc['body']  # Just to make sure it exists.
93 129
                             title = strip_tags(json_doc['title'])
94 130
                         except KeyError, ex:
95 131
                             if verbosity >= 2:
@@ -98,8 +134,6 @@ def handle_noargs(self, **kwargs):
98 134
 
99 135
                     doc = documents.pop(path, Document(path=path, release=release))
100 136
                     doc.title = title
101  
-                    if verbosity >= 2:
102  
-                        print "Indexing:", doc
103 137
                     doc.save()
104 138
                     haystack.site.update_object(doc)
105 139
 
@@ -111,4 +145,4 @@ def handle_noargs(self, **kwargs):
111 145
                 doc.delete()
112 146
 
113 147
     def update_svn(self, url, destdir):
114  
-        subprocess.call(['svn', 'checkout', '-q', url, destdir])
  148
+        subprocess.call(['svn', 'checkout', '-q', url, destdir])
2  django_website/docs/templates/docs/doc.html
@@ -116,10 +116,12 @@ <h2 id="comments">Questions/Feedback</h2>
116 116
       <p>
117 117
       {% if version == "dev" %}
118 118
         Offline (development version):
  119
+        <a href="{{ MEDIA_URL }}docs/django-{{ version }}-{{ lang }}.pdf">HTML</a> | 
119 120
         <a href="http://media.readthedocs.org/pdf/django/latest/django.pdf">PDF</a> | 
120 121
         <a href="http://media.readthedocs.org/epub/django/latest/django.epub">ePub</a>
121 122
       {% else %}
122 123
         Offline (Django {{ version }}):
  124
+        <a href="{{ MEDIA_URL }}docs/django-{{ version }}-{{ lang }}.pdf">HTML</a> | 
123 125
         <a href="http://media.readthedocs.org/pdf/django/{{ version }}.X/django.pdf">PDF</a> | 
124 126
         <a href="http://media.readthedocs.org/epub/django/{{ version }}.X/django.epub">ePub</a>
125 127
       {% endif %}
2  django_website/docs/views.py
@@ -80,4 +80,4 @@ def extra_context(self):
80 80
             'version': default_release.version,
81 81
             'release': default_release,
82 82
         }
83  
-    
  83
+    

0 notes on commit 10ad763

Please sign in to comment.
Something went wrong with that request. Please try again.