2 # Copyright (C) 2012 Roman Zimbelmann <hut@lavabit.com>
3 # This software is distributed under the terms of the GNU GPL version 3.
5 boobies.py is a html preprocessor for pre-generated static websites.
7 It searches your html files for commands in the form of <!-- COMMAND [ARGS] -->
8 and evaluates them IN-PLACE. NESTING COMMANDS IS NOT SUPPORTED.
9 The following commands exist:
15 This will execute "ls -l" in the shell and insert the output into the block
18 You can write this in index.html:
21 <head><title>boobies</title></head>
24 and this in another file:
26 <!-- get head from index.html -->
30 and foo will be replaced by <head><title>boobies</title></head>.
34 <a href="about.html">about</a>
37 If you use this in a "get"-block, it will fix URLs with relative paths.
43 from subprocess
import Popen
, PIPE
, call
45 PATTERN_GET
= r
'(<!--\s*get\s+(\w+)\s+from\s+([^\s]+)\s*-->\n?)(.*?)(<!--\s*/get\s*-->)'
46 PATTERN_RUN
= r
'(<!--\s*run\s+(.*?)\s*-->(\n?))(.*?)(<!--\s*/run\s*-->)'
47 PATTERN_RELATIVE
= r
'(<!--\s*relative\s*-->\n?)(.*?)(<!--\s*/relative\s*-->)'
48 PATTERN_GETURL
= r
'href="([^"]+?\.[^"]+?)"'
49 PATTERN_GETKEYWORD
= r
'<!--\s*{0}\s*-->\n?(.*?)<!--\s*/{0}\s*-->'
52 if '-h' in sys
.argv
or '--help' in sys
.argv
or len(sys
.argv
) <= 1:
53 return sys
.stdout
.write("usage: boobies.py [--dry] [-h|--help] files...\n")
55 for filename
in [s
for s
in sys
.argv
[1:] if not s
.startswith('-')]:
56 tmpname
= filename
+ ".__new"
58 f
= open(filename
, 'r')
61 processed_content
= process(content
, filename
)
62 if processed_content
== content
:
63 print("unchanged: %s" % filename
)
66 tmp
= open(tmpname
, "w")
67 tmp
.write(processed_content
)
69 call(['diff', '-u', filename
, tmpname
])
71 if '--dry' in sys
.argv
:
74 print("writing: %s" % filename
)
75 os
.rename(tmpname
, filename
)
77 def process(content
, filename
):
79 PATH
= os
.path
.dirname(filename
)
80 content
= re
.sub(PATTERN_GET
, _command_get
, content
, 0, re
.S
)
81 content
= re
.sub(PATTERN_RUN
, _command_run
, content
, 0, re
.S
)
90 f
= open(filename
, 'r')
93 match
= re
.search(PATTERN_GETKEYWORD
.format(keyword
), content
, re
.DOTALL
)
95 sys
.stderr
.write("Could not find keyword {0} in {1}\n".format(keyword
, filename
))
98 result
= re
.sub(PATTERN_RELATIVE
, _command_relative
, match
.group(1), 0, re
.S
)
100 return m
.group(1) + result
+ m
.group(5)
103 def _command_relative(m
):
104 return m
.group(1) + re
.sub(PATTERN_GETURL
,
105 lambda match
: 'href="' + os
.path
.relpath(match
.group(1), PATH
) + '"',
106 m
.group(2)) + m
.group(3)
110 output
= Popen(m
.group(2), shell
=True, stdout
=PIPE
).communicate()[0]
111 if m
.group(3) != "\n":
112 output
= output
.strip()
113 return m
.group(1) + output
.decode('utf-8') + m
.group(5)
116 if __name__
== '__main__':