80 self.htmlDir = htmlDir |
87 self.htmlDir = htmlDir |
81 self.outputDir = outputDir |
88 self.outputDir = outputDir |
82 self.namespace = namespace |
89 self.namespace = namespace |
83 self.virtualFolder = virtualFolder |
90 self.virtualFolder = virtualFolder |
84 self.filterName = filterName |
91 self.filterName = filterName |
85 self.filterAttributes = ( |
92 self.filterAttributes = filterAttributes and filterAttributes.split(":") or [] |
86 filterAttributes and filterAttributes.split(':') or [] |
|
87 ) |
|
88 self.relPath = os.path.relpath(self.htmlDir, self.outputDir) |
93 self.relPath = os.path.relpath(self.htmlDir, self.outputDir) |
89 self.title = title |
94 self.title = title |
90 self.createCollection = createCollection |
95 self.createCollection = createCollection |
91 |
96 |
92 self.packages = { |
97 self.packages = {"00index": {"subpackages": {}, "modules": {}}} |
93 "00index": { |
|
94 "subpackages": {}, |
|
95 "modules": {} |
|
96 } |
|
97 } |
|
98 self.remembered = False |
98 self.remembered = False |
99 self.keywords = [] |
99 self.keywords = [] |
100 |
100 |
101 def remember(self, file, moduleDocument, basename=""): |
101 def remember(self, file, moduleDocument, basename=""): |
102 """ |
102 """ |
103 Public method to remember a documentation file. |
103 Public method to remember a documentation file. |
104 |
104 |
105 @param file The filename to be remembered. (string) |
105 @param file The filename to be remembered. (string) |
106 @param moduleDocument The ModuleDocument object containing the |
106 @param moduleDocument The ModuleDocument object containing the |
107 information for the file. |
107 information for the file. |
108 @param basename The basename of the file hierarchy to be documented. |
108 @param basename The basename of the file hierarchy to be documented. |
109 The basename is stripped off the filename if it starts with |
109 The basename is stripped off the filename if it starts with |
110 the basename. |
110 the basename. |
111 """ |
111 """ |
112 self.remembered = True |
112 self.remembered = True |
113 if basename: |
113 if basename: |
114 file = file.replace(basename, "") |
114 file = file.replace(basename, "") |
115 |
115 |
116 if "__init__" in file: |
116 if "__init__" in file: |
117 dirName = os.path.dirname(file) |
117 dirName = os.path.dirname(file) |
118 udir = os.path.dirname(dirName) |
118 udir = os.path.dirname(dirName) |
119 if udir: |
119 if udir: |
120 upackage = udir.replace(os.sep, ".") |
120 upackage = udir.replace(os.sep, ".") |
124 elt = self.packages["00index"] |
124 elt = self.packages["00index"] |
125 else: |
125 else: |
126 elt = self.packages["00index"] |
126 elt = self.packages["00index"] |
127 package = dirName.replace(os.sep, ".") |
127 package = dirName.replace(os.sep, ".") |
128 elt["subpackages"][package] = moduleDocument.name() |
128 elt["subpackages"][package] = moduleDocument.name() |
129 |
129 |
130 self.packages[package] = { |
130 self.packages[package] = {"subpackages": {}, "modules": {}} |
131 "subpackages": {}, |
131 |
132 "modules": {} |
132 kwEntry = ( |
133 } |
133 "{0} (Package)".format(package.split(".")[-1]), |
134 |
134 joinext("index-{0}".format(package), ".html"), |
135 kwEntry = ("{0} (Package)".format(package.split('.')[-1]), |
135 ) |
136 joinext("index-{0}".format(package), ".html")) |
|
137 if kwEntry not in self.keywords: |
136 if kwEntry not in self.keywords: |
138 self.keywords.append(kwEntry) |
137 self.keywords.append(kwEntry) |
139 |
138 |
140 if moduleDocument.isEmpty(): |
139 if moduleDocument.isEmpty(): |
141 return |
140 return |
142 |
141 |
143 package = os.path.dirname(file).replace(os.sep, ".") |
142 package = os.path.dirname(file).replace(os.sep, ".") |
144 try: |
143 try: |
145 elt = self.packages[package] |
144 elt = self.packages[package] |
146 except KeyError: |
145 except KeyError: |
147 elt = self.packages["00index"] |
146 elt = self.packages["00index"] |
148 elt["modules"][moduleDocument.name()] = moduleDocument.name() |
147 elt["modules"][moduleDocument.name()] = moduleDocument.name() |
149 |
148 |
150 if "__init__" not in file: |
149 if "__init__" not in file: |
151 kwEntry = ( |
150 kwEntry = ( |
152 "{0} (Module)".format(moduleDocument.name().split('.')[-1]), |
151 "{0} (Module)".format(moduleDocument.name().split(".")[-1]), |
153 joinext(moduleDocument.name(), ".html")) |
152 joinext(moduleDocument.name(), ".html"), |
|
153 ) |
154 if kwEntry not in self.keywords: |
154 if kwEntry not in self.keywords: |
155 self.keywords.append(kwEntry) |
155 self.keywords.append(kwEntry) |
156 for kw in moduleDocument.getQtHelpKeywords(): |
156 for kw in moduleDocument.getQtHelpKeywords(): |
157 kwEntry = (kw[0], "{0}{1}".format( |
157 kwEntry = ( |
158 joinext(moduleDocument.name(), ".html"), kw[1])) |
158 kw[0], |
|
159 "{0}{1}".format(joinext(moduleDocument.name(), ".html"), kw[1]), |
|
160 ) |
159 if kwEntry not in self.keywords: |
161 if kwEntry not in self.keywords: |
160 self.keywords.append(kwEntry) |
162 self.keywords.append(kwEntry) |
161 |
163 |
162 def __generateSections(self, package, level): |
164 def __generateSections(self, package, level): |
163 """ |
165 """ |
164 Private method to generate the sections part. |
166 Private method to generate the sections part. |
165 |
167 |
166 @param package name of the package to process (string) |
168 @param package name of the package to process (string) |
167 @param level indentation level (integer) |
169 @param level indentation level (integer) |
168 @return sections part (string) |
170 @return sections part (string) |
169 """ |
171 """ |
170 indent = level * ' ' |
172 indent = level * " " |
171 indent1 = indent + ' ' |
173 indent1 = indent + " " |
172 s = indent + '<section title="{0}" ref="{1}">\n'.format( |
174 s = indent + '<section title="{0}" ref="{1}">\n'.format( |
173 package == "00index" and self.title or package, |
175 package == "00index" and self.title or package, |
174 package == "00index" and |
176 package == "00index" |
175 joinext("index", ".html") or |
177 and joinext("index", ".html") |
176 joinext("index-{0}".format(package), ".html")) |
178 or joinext("index-{0}".format(package), ".html"), |
|
179 ) |
177 for subpack in sorted(self.packages[package]["subpackages"]): |
180 for subpack in sorted(self.packages[package]["subpackages"]): |
178 s += self.__generateSections(subpack, level + 1) + '\n' |
181 s += self.__generateSections(subpack, level + 1) + "\n" |
179 for mod in sorted(self.packages[package]["modules"]): |
182 for mod in sorted(self.packages[package]["modules"]): |
180 s += indent1 + '<section title="{0}" ref="{1}" />\n'.format( |
183 s += indent1 + '<section title="{0}" ref="{1}" />\n'.format( |
181 mod, joinext(mod, ".html")) |
184 mod, joinext(mod, ".html") |
182 s += indent + '</section>' |
185 ) |
|
186 s += indent + "</section>" |
183 return s |
187 return s |
184 |
188 |
185 def __convertEol(self, txt, newline): |
189 def __convertEol(self, txt, newline): |
186 """ |
190 """ |
187 Private method to convert the newline characters. |
191 Private method to convert the newline characters. |
188 |
192 |
189 @param txt text to be converted (string) |
193 @param txt text to be converted (string) |
190 @param newline newline character to be used (string) |
194 @param newline newline character to be used (string) |
191 @return converted text (string) |
195 @return converted text (string) |
192 """ |
196 """ |
193 # step 1: normalize eol to '\n' |
197 # step 1: normalize eol to '\n' |
194 txt = txt.replace("\r\n", "\n").replace("\r", "\n") |
198 txt = txt.replace("\r\n", "\n").replace("\r", "\n") |
195 |
199 |
196 # step 2: convert to the target eol |
200 # step 2: convert to the target eol |
197 if newline is None: |
201 if newline is None: |
198 return txt.replace("\n", os.linesep) |
202 return txt.replace("\n", os.linesep) |
199 elif newline in ["\r", "\r\n"]: |
203 elif newline in ["\r", "\r\n"]: |
200 return txt.replace("\n", newline) |
204 return txt.replace("\n", newline) |
201 else: |
205 else: |
202 return txt |
206 return txt |
203 |
207 |
204 def generateFiles(self, basename="", newline=None): |
208 def generateFiles(self, basename="", newline=None): |
205 """ |
209 """ |
206 Public method to generate all index files. |
210 Public method to generate all index files. |
207 |
211 |
208 @param basename The basename of the file hierarchy to be documented. |
212 @param basename The basename of the file hierarchy to be documented. |
209 The basename is stripped off the filename if it starts with |
213 The basename is stripped off the filename if it starts with |
210 the basename. |
214 the basename. |
211 @param newline newline character to be used (string) |
215 @param newline newline character to be used (string) |
212 """ |
216 """ |
213 if not self.remembered: |
217 if not self.remembered: |
214 sys.stderr.write("No QtHelp to generate.\n") |
218 sys.stderr.write("No QtHelp to generate.\n") |
215 return |
219 return |
216 |
220 |
217 if basename: |
221 if basename: |
218 basename = basename.replace(os.sep, ".") |
222 basename = basename.replace(os.sep, ".") |
219 if not basename.endswith("."): |
223 if not basename.endswith("."): |
220 basename = "{0}.".format(basename) |
224 basename = "{0}.".format(basename) |
221 |
225 |
222 sections = self.__generateSections("00index", level=3) |
226 sections = self.__generateSections("00index", level=3) |
223 filesList = sorted(e for e in os.listdir(self.htmlDir) |
227 filesList = sorted(e for e in os.listdir(self.htmlDir) if e.endswith(".html")) |
224 if e.endswith('.html')) |
|
225 filesList.append("styles.css") |
228 filesList.append("styles.css") |
226 files = "\n".join( |
229 files = "\n".join([" <file>{0}</file>".format(f) for f in filesList]) |
227 [" <file>{0}</file>".format(f) for f in filesList]) |
|
228 filterAttribs = "\n".join( |
230 filterAttribs = "\n".join( |
229 [" <filterAttribute>{0}</filterAttribute>".format(a) |
231 [ |
230 for a in sorted(self.filterAttributes)]) |
232 " <filterAttribute>{0}</filterAttribute>".format(a) |
|
233 for a in sorted(self.filterAttributes) |
|
234 ] |
|
235 ) |
231 keywords = "\n".join( |
236 keywords = "\n".join( |
232 [' <keyword name="{0}" id="{1}" ref="{2}" />'.format( |
237 [ |
233 html_encode(kw[0]), html_encode(kw[0]), html_encode(kw[1])) |
238 ' <keyword name="{0}" id="{1}" ref="{2}" />'.format( |
234 for kw in sorted(self.keywords)]) |
239 html_encode(kw[0]), html_encode(kw[0]), html_encode(kw[1]) |
235 |
240 ) |
|
241 for kw in sorted(self.keywords) |
|
242 ] |
|
243 ) |
|
244 |
236 helpAttribs = { |
245 helpAttribs = { |
237 "namespace": self.namespace, |
246 "namespace": self.namespace, |
238 "folder": self.virtualFolder, |
247 "folder": self.virtualFolder, |
239 "filter_name": self.filterName, |
248 "filter_name": self.filterName, |
240 "filter_attributes": filterAttribs, |
249 "filter_attributes": filterAttribs, |
241 "sections": sections, |
250 "sections": sections, |
242 "keywords": keywords, |
251 "keywords": keywords, |
243 "files": files, |
252 "files": files, |
244 } |
253 } |
245 |
254 |
246 txt = self.__convertEol(HelpProject.format(**helpAttribs), newline) |
255 txt = self.__convertEol(HelpProject.format(**helpAttribs), newline) |
247 with open(os.path.join(self.outputDir, HelpProjectFile), "w", |
256 with open( |
248 encoding="utf-8", newline=newline) as f: |
257 os.path.join(self.outputDir, HelpProjectFile), |
|
258 "w", |
|
259 encoding="utf-8", |
|
260 newline=newline, |
|
261 ) as f: |
249 f.write(txt) |
262 f.write(txt) |
250 |
263 |
251 if ( |
264 if self.createCollection and not os.path.exists( |
252 self.createCollection and |
265 os.path.join(self.outputDir, HelpCollectionProjectFile) |
253 not os.path.exists(os.path.join( |
|
254 self.outputDir, HelpCollectionProjectFile)) |
|
255 ): |
266 ): |
256 collectionAttribs = { |
267 collectionAttribs = { |
257 "helpfile": HelpHelpFile, |
268 "helpfile": HelpHelpFile, |
258 } |
269 } |
259 |
270 |
260 txt = self.__convertEol( |
271 txt = self.__convertEol(HelpCollection.format(**collectionAttribs), newline) |
261 HelpCollection.format(**collectionAttribs), newline) |
272 with open( |
262 with open(os.path.join(self.outputDir, HelpCollectionProjectFile), |
273 os.path.join(self.outputDir, HelpCollectionProjectFile), |
263 "w", encoding="utf-8", newline=newline) as f: |
274 "w", |
|
275 encoding="utf-8", |
|
276 newline=newline, |
|
277 ) as f: |
264 f.write(txt) |
278 f.write(txt) |
265 |
279 |
266 sys.stdout.write("QtHelp files written.\n") |
280 sys.stdout.write("QtHelp files written.\n") |
267 sys.stdout.write("Generating QtHelp documentation...\n") |
281 sys.stdout.write("Generating QtHelp documentation...\n") |
268 sys.stdout.flush() |
282 sys.stdout.flush() |
269 sys.stderr.flush() |
283 sys.stderr.flush() |
270 |
284 |
271 cwd = os.getcwd() |
285 cwd = os.getcwd() |
272 # generate the compressed files |
286 # generate the compressed files |
273 qhelpgeneratorExe = os.path.join( |
287 qhelpgeneratorExe = os.path.join( |
274 getQtBinariesPath(libexec=True), |
288 getQtBinariesPath(libexec=True), generateQtToolName("qhelpgenerator") |
275 generateQtToolName("qhelpgenerator") |
|
276 ) |
289 ) |
277 if not os.path.exists(qhelpgeneratorExe): |
290 if not os.path.exists(qhelpgeneratorExe): |
278 qhelpgeneratorExe = os.path.join( |
291 qhelpgeneratorExe = os.path.join( |
279 getQtBinariesPath(libexec=False), |
292 getQtBinariesPath(libexec=False), generateQtToolName("qhelpgenerator") |
280 generateQtToolName("qhelpgenerator") |
293 ) |
281 ) |
294 shutil.copy(os.path.join(self.outputDir, HelpProjectFile), self.htmlDir) |
282 shutil.copy( |
|
283 os.path.join(self.outputDir, HelpProjectFile), self.htmlDir) |
|
284 os.chdir(self.htmlDir) |
295 os.chdir(self.htmlDir) |
285 subprocess.run([ # secok |
296 subprocess.run( |
286 qhelpgeneratorExe, |
297 [ # secok |
287 HelpProjectFile, "-o", os.path.join(self.outputDir, HelpHelpFile)]) |
298 qhelpgeneratorExe, |
|
299 HelpProjectFile, |
|
300 "-o", |
|
301 os.path.join(self.outputDir, HelpHelpFile), |
|
302 ] |
|
303 ) |
288 os.remove(HelpProjectFile) |
304 os.remove(HelpProjectFile) |
289 |
305 |
290 if self.createCollection: |
306 if self.createCollection: |
291 sys.stdout.write("Generating QtHelp collection...\n") |
307 sys.stdout.write("Generating QtHelp collection...\n") |
292 sys.stdout.flush() |
308 sys.stdout.flush() |
293 sys.stderr.flush() |
309 sys.stderr.flush() |
294 os.chdir(self.outputDir) |
310 os.chdir(self.outputDir) |
295 subprocess.run([ # secok |
311 subprocess.run( |
296 qhelpgeneratorExe, |
312 [ # secok |
297 HelpCollectionProjectFile, "-o", HelpCollectionFile]) |
313 qhelpgeneratorExe, |
298 |
314 HelpCollectionProjectFile, |
|
315 "-o", |
|
316 HelpCollectionFile, |
|
317 ] |
|
318 ) |
|
319 |
299 os.chdir(cwd) |
320 os.chdir(cwd) |