4 # gtk-doc - GTK DocBook documentation generator.
5 # Copyright (C) 1998 Damon Chaplin
6 # 2007 David Necas (Yeti)
7 # 2007-2016 Stefan Sauer
9 # This program is free software; you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation; either version 2 of the License, or
12 # (at your option) any later version.
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License
20 # along with this program; if not, write to the Free Software
21 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 The rebase tool rewrites URI references in installed HTML documentation.
28 from __future__
import print_function
38 # These two point to the last seen URI of given type for a package:
39 # OnlineMap: package => on-line URI
40 # LocalMap: package => local URI
41 # This maps all seen URIs of a package to fix broken links in the process:
42 # RevMap: URI => package
46 # Remember what mangling we did.
50 def log(options
, *msg
):
58 # We scan the directory containing GLib and any directories in GNOME2_PATH
59 # first, but these will be overriden by any later scans.
60 if "GNOME2_PATH" in os
.environ
:
61 for dir in os
.environ
["GNOME2_PATH"].split(':'):
62 dir = os
.path
.join(dir, "/share/gtk-doc/html")
63 if os
.path
.isdir(dir):
64 log(options
, "Prepending GNOME2_PATH directory:", dir)
65 other_dirs
= [dir] + other_dirs
67 dir = subprocess
.check_output([config
.pkg_config
, '--variable=prefix', 'glib-2.0'], universal_newlines
=True)
69 dir = os
.path
.join(dir, "/share/gtk-doc/html")
70 log(options
, "Prepending GLib directory", dir)
71 other_dirs
= [dir] + other_dirs
73 # Check all other dirs, but skip already scanned dirs ord subdirs of those
75 for dir in other_dirs
:
76 ScanDirectory(dir, options
)
79 RelativizeLocalMap(options
.html_dir
, options
)
81 RebaseReferences(options
.html_dir
, options
)
85 def ScanDirectory(dir, options
):
86 # This array holds any subdirectories found.
90 log(options
, "Scanning documentation directory " + dir)
92 if dir == options
.html_dir
:
93 log(options
, "Excluding self")
96 if not os
.path
.isdir(dir):
97 print('Cannot open dir "%s"' % dir)
101 for entry
in os
.listdir(dir):
102 if os
.path
.isdir(entry
):
103 subdirs
.push_back(entry
)
106 if entry
.endswith('.devhelp2'):
107 log(options
, "Reading index from " + entry
)
108 o
= ReadDevhelp(dir, entry
)
109 # Prefer this location over possibly stale index.sgml
114 if onlinedir
and entry
== "index.sgml":
115 log(options
, "Reading index from index.sgml")
116 onlinedir
= ReadIndex(dir, entry
)
118 elif entry
== "index.sgml.gz" and not os
.path
.exists(os
.path
.join(dir, 'index.sgml')):
119 # debian/ubuntu started to compress this as index.sgml.gz :/
120 print(''' Please fix https://bugs.launchpad.net/ubuntu/+source/gtk-doc/+bug/77138 . For now run:
123 elif entry
.endswith('.devhelp2.gz') and not os
.path
.exists(os
.path
.join(dir, entry
, 'devhelp2')):
124 # debian/ubuntu started to compress this as *devhelp2.gz :/
125 print('''Please fix https://bugs.launchpad.net/ubuntu/+source/gtk-doc/+bug/1466210 . For now run:
128 # we could consider supporting: gzip module
131 AddMap(dir, onlinedir
)
133 # Now recursively scan the subdirectories.
134 for subdir
in subdirs
:
135 ScanDirectory(os
.path
.join(dir, subdir
), options
)
138 def ReadDevhelp(dir, file):
141 for line
in open(os
.path
.join(dir, file)):
142 # online must come before chapter/functions
143 if '<chapters' in line
or '<functions' in line
:
145 match
= re
.search(r
' online="([^"]*)"/')
147 # Remove trailing non-directory component.
148 onlinedir
= re
.sub(r
'(.*/).*', r
'\1', match
.groups(1))
152 def ReadIndex(dir, file):
155 for line
in open(os
.path
.join(dir, file)):
156 # ONLINE must come before any ANCHORs
157 if '<ANCHOR' in line
:
159 match
= re
.match(r
'''^<ONLINE\s+href\s*=\s*"([^"]+)"\s*>''', line
)
161 # Remove trailing non-directory component.
162 onlinedir
= re
.sub(r
'''(.*/).*''', r
'\1', match
.groups(1))
166 def AddMap(dir, onlinerdir
, options
):
169 package
= os
.path
.split(dir)[1]
170 if options
.dest_dir
!= '' and dir.startswith(options
.dest_dir
):
171 dir = dir[len(options
.dest_dir
) - 1:]
174 log(options
, "On-line location of %s." % onlinedir
)
175 OnlineMap
[package
] = onlinedir
176 RevMap
[onlinedir
] = package
178 log(options
, "No On-line location for %s found" % package
)
180 log(options
, "Local location of $package: " + dir)
181 LocalMap
[package
] = dir
182 RevMap
[dir] = package
185 def RelativizeLocalMap(dirname
, options
):
189 dirname
= os
.path
.realpath(dirname
)
190 prefix
= os
.path
.split(dirname
)
191 for package
, dir in LocalMap
.items():
192 if dir.startswith(prefix
):
193 dir = os
.path
.join("..", dir[len(prefix
):])
194 LocalMap
[package
] = dir
195 log(options
, "Relativizing local location of $package to " + dir)
198 def RebaseReferences(dirname
, options
):
199 for ifile
in os
.listdir(dirname
):
200 if ifile
.endswith('.html'):
201 RebaseFile(os
.path
.join(dirname
, ifile
), options
)
204 def RebaseFile(filename
, options
):
205 log(options
, "Fixing file: " + filename
)
206 regex
= re
.compile(r
'''(<a(?:\s+\w+=(?:"[^"]*"|'[^']*'))*\s+href=")([^"]*)(")''',
209 def repl_func(match
):
210 return match
.group(1) + RebaseLink(match
.group(2), options
) + match
.group(3)
212 contents
= open(filename
).read()
213 processed
= re
.sub(regex
, repl_func
, contents
)
214 newfilename
= filename
+ '.new'
215 open(newfilename
, 'w').write(processed
)
217 os
.rename(newfilename
, filename
)
220 def RebaseLink(href
, options
):
221 match
= re
.match(r
'^(.*/)([^/]*)$', href
)
226 dir = origdir
= match
.group(1)
227 file = match
.group(2)
229 package
= RevMap
[dir]
231 match
= re
.match(r
'\.\./([^/]+)', href
)
232 if match
is not None:
233 package
= match
.groups(1)
234 elif options
.aggressive
:
235 match
= re
.search(r
'''([^/]+)/$''', href
)
236 package
= match
.groups(1)
239 if options
.online
and package
in OnlineMap
:
240 dir = OnlineMap
[package
]
241 elif package
in LocalMap
:
242 dir = LocalMap
[package
]
243 href
= os
.path
.join(dir, file)
245 log(options
, "Can't determine package for '%s'" % href
)
248 if origdir
in Mapped
:
249 Mapped
[origdir
][1] += 1
251 Mapped
[origdir
] = [dir, 1]
255 def PrintWhatWeHaveDone():
256 for origdir
in sorted(Mapped
.keys()):
257 info
= Mapped
[origdir
]
258 print(origdir
, "->", info
[0], "(%s)" % info
[1])