oops, added wrong robots.txt
[objavi2.git] / objavi / book_utils.py
blob6f7f5be7d0ba8fda5692cfd73c297af33d952de4
1 # Part of Objavi2, which turns html manuals into books
3 # Copyright (C) 2009 Douglas Bagnall
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License along
16 # with this program; if not, write to the Free Software Foundation, Inc.,
17 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 """
19 General utility functions.
20 """
22 import os, sys
23 import shutil
24 import time, re
25 from subprocess import Popen, PIPE
27 #from objavi.fmbook import log
28 from objavi import config
30 #general, non-cgi functions
31 def init_log():
32 """Try to redirect stderr to the log file. If it doesn't work,
33 leave stderr as it is."""
34 if config.REDIRECT_LOG:
35 logfile = os.path.join(config.LOGDIR, 'objavi.log')
36 try:
37 size = os.stat(logfile).st_size
38 if size > config.LOG_ROTATE_SIZE:
39 oldlog = os.path.join(config.LOGDIR, time.strftime('objavi-%Y-%m-%d+%H-%M-%S.log'))
40 f = open(logfile, 'a')
41 print >> f, "CLOSING LOG at size %s, renaming to %s" % (size, oldlog)
42 f.close()
43 os.rename(logfile, oldlog)
44 except OSError, e:
45 log(e) # goes to original stderr
46 try:
47 f = open(logfile, 'a')
48 sys.stderr.flush()
49 os.dup2(f.fileno(), sys.stderr.fileno())
50 # reassign the object as well as dup()ing, in case it closes down out of scope.
51 sys.stderr = f
52 except (IOError, OSError), e:
53 log(e)
54 return
56 def log(*messages, **kwargs):
57 """Send the messages to the appropriate place (stderr, or syslog).
58 If a <debug> keyword is specified, the message is only printed if
59 its value is in the global DEBUG_MODES."""
60 if 'debug' not in kwargs or config.DEBUG_ALL or kwargs['debug'] in config.DEBUG_MODES:
61 for m in messages:
62 try:
63 print >> sys.stderr, m
64 except Exception:
65 print >> sys.stderr, repr(m)
66 sys.stderr.flush()
68 def log_types(*args, **kwargs):
69 """Log the type of the messages as well as their value (size constrained)."""
70 size = kwargs.get('size', 50)
71 for a in args:
72 try:
73 s = ("%s" % (a,))
74 except Exception:
75 try:
76 s = ("%r" % (a,))
77 except Exception:
78 s = '<UNPRINTABLE!>'
79 log("%s: %s" % (type(a), s[:size]))
81 def make_book_name(book, server, suffix='.pdf', timestamp=None):
82 lang = guess_lang(server, book)
83 book = ''.join(x for x in book if x.isalnum())
84 if timestamp is None:
85 timestamp = time.strftime('%Y.%m.%d-%H.%M.%S')
86 return '%s-%s-%s%s' % (book, lang,
87 timestamp,
88 suffix)
90 def guess_lang(server, book):
91 if server is None:
92 server = config.DEFAULT_SERVER
93 lang = config.SERVER_DEFAULTS[server].get('lang')
94 if lang is None and '_' in book:
95 lang = book[book.rindex('_') + 1:]
96 return lang
98 def guess_text_dir(server, book):
99 try:
100 dir = config.SERVER_DEFAULTS[server]['dir']
101 except KeyError:
102 dir = None
103 if dir not in ('LTR', 'RTL'):
104 log("server %s, book %s: no specified dir (%s)" %(server, book, dir))
105 if '_' in book:
106 lang = book[book.rindex('_') + 1:]
107 dir = config.LANGUAGE_DIR.get(lang, 'LTR')
108 elif '.' in server:
109 lang = server[:server.index('.')]
110 dir = config.LANGUAGE_DIR.get(lang, 'LTR')
111 else:
112 dir = 'LTR'
113 log("server %s, book %s: found dir %s" %(server, book, dir))
114 return str(dir)
116 def run(cmd):
117 try:
118 p = Popen(cmd, stdout=PIPE, stderr=PIPE)
119 out, err = p.communicate()
120 except Exception:
121 log("Failed on command: %r" % cmd)
122 raise
123 log("%s\n%s returned %s and produced\nstdout:%s\nstderr:%s" %
124 (' '.join(cmd), cmd[0], p.poll(), out, err))
125 return p.poll()
127 def shift_file(fn, dir, backup='~'):
128 """Shift a file and save backup (only works on same filesystem)"""
129 log("shifting file %r to %s" % (fn, dir))
130 base = os.path.basename(fn)
131 dest = os.path.join(dir, base)
132 if backup and os.path.exists(dest):
133 os.rename(dest, dest + backup)
134 shutil.move(fn, dest)
135 return dest
137 class ObjaviError(Exception):
138 pass
141 def decode_html_entities(text):
142 for encoding in ('ascii', 'utf-8', 'iso-8859-1'):
143 try:
144 text = text.decode(encoding)
145 break
146 except UnicodeDecodeError:
147 continue
148 def fixup(m):
149 entity = m.group(0)
150 try:
151 if entity[:3] == "&#x":
152 return unichr(int(entity[3:-1], 16))
153 elif entity[:2] == "&#":
154 return unichr(int(entity[2:-1]))
155 except ValueError:
156 log("ignoring bad entity %s" % entity)
157 return entity
158 return re.sub("&#?[0-9a-fA-F]+;", fixup, text).encode('utf-8')