[project @ sridhar.ratna@gmail.com-20070903202953-xtz7j8qq4y8qdd0a]
[lightydir.git] / lightydir.py
blobf3390cbae077403b024b20aeb14d1225f4121a9f
1 # lightydir.py
3 __author__ = 'Sridhar Ratnakumar <srid@nearfar.org>'
5 import os, stat, time
6 import markdown
7 import web
8 web.webapi.internalerror = web.debugerror
11 class File(object):
13 def __init__(self, path):
14 if os.path.isdir(path) and not path.endswith(os.path.sep):
15 path += os.path.sep
16 self.path = path
18 def name(self):
19 rest, name = os.path.split(self.path)
20 if name == '':
21 rest, name = os.path.split(rest)
22 return name
24 def cgi_name(self):
25 if os.path.isdir(self.path):
26 return self.name() + "/"
27 else:
28 return self.name()
30 def parents(self):
31 """
32 >>> for p in File("/home/srid/foo/bar/").parents():
33 print p
34 /home/srid/foo/bar/
35 /home/srid/foo/
36 /home/srid/
37 /home/
39 >>>
40 """
41 path = self.path
42 yield path
43 if path.endswith("/"):
44 path = path[:-1]
45 while path:
46 path, rest = path.rsplit(os.path.sep, 1)
47 yield path + "/"
49 def is_hidden_file(self):
50 name = self.name()
51 return name.startswith('.') or name.endswith('~')
53 def last_modified(self):
54 t = os.stat(self.path)[stat.ST_MTIME]
55 return time.strftime("%d-%b-%Y %H:%M", time.localtime(t))
57 # from Trac source
58 @staticmethod
59 def pretty_size(size):
60 jump = 512
61 if size < jump:
62 return "1k"
64 units = ['k', 'M', 'GB', 'TB']
65 i = 0
66 while size >= jump and i < len(units):
67 i += 1
68 size /= 1024.0
70 return "%.1f%s" % (size, units[i - 1])
72 def size(self):
73 return File.pretty_size(os.stat(self.path)[stat.ST_SIZE])
77 class lightydir:
78 def GET(self):
79 web.header("Content-Type","%s; charset=utf-8" % 'text/html')
80 self.REQUEST_URI = path = os.environ.get('REQUEST_URI')
81 self.DOCUMENT_ROOT = os.environ.get('DOCUMENT_ROOT')
82 self.DIR_PATH = os.path.join(self.DOCUMENT_ROOT, self.REQUEST_URI[1:])
84 self.title = "Index of %s" % self.REQUEST_URI
85 self.body = ""
86 self.description = {}
88 self.readme()
90 body = self.body
91 filelist = os.listdir(self.DIR_PATH)
93 p, bzrbranch = self.bzrbranch()
94 if bzrbranch:
95 body += '<div id="bzr">'
96 body += ' <p>You can get the source code for this branch via: </p>'
97 body += ' <code>'
98 body += ' <a href="http://bazaar-vcs.org/">bzr</a> get %s' % bzrbranch
99 body += ' </code>'
100 body += '</div>'
102 trs = ['<tr><td><a href="..">..</a></td></tr>']
103 filelist.sort()
104 for file_name in filelist:
105 file = File(os.path.join(self.DIR_PATH, file_name))
106 if not file.is_hidden_file():
107 file_lm = file.last_modified()
108 file_size = os.path.isdir(file.path) and "-" or file.size()
109 trs.append(
110 '<tr><td><a href="%s">%s</a></td><td>%s</td><td class="s">%s</td><td>%s</td></tr>' % (
111 file.cgi_name(), file.cgi_name(), file_lm, file_size,
112 self.description.get(file_name, "")))
113 trs = "\n".join(trs)
114 title = self.title
115 print HTML % locals()
118 def readme(self):
119 SEP = "\nContents:\n"
120 readme_dir = os.path.join(self.DIR_PATH, "README.txt")
121 if os.path.exists(readme_dir):
122 file = open(readme_dir)
123 self.title = file.readline().strip() or self.title
124 self.body = rest = file.read()
125 desc = ""
126 if SEP in rest:
127 self.body, desc = rest.split(SEP, 1)
128 self.body = markdown.markdown(self.body)
129 self.description = {}
130 for line in desc.splitlines():
131 line = line.strip()
132 if line:
133 key, value = line.split(":", 1)
134 self.description[key.strip()] = value.strip()
137 def bzrbranch(self):
138 cnt = 0
139 for p in File(self.DIR_PATH).parents():
140 dot_bzr = os.path.join(p, ".bzr")
141 if os.path.exists(dot_bzr):
142 # infer the bzr URL (guess)
143 uri = os.environ['REQUEST_URI'].split('/')
144 uri = '/'.join(uri[:-cnt-1]) # whoa! hard to explain, sorry.
145 url = "http://%s%s" % (os.environ['SERVER_NAME'], uri)
146 return p, url
147 cnt += 1
148 return False, False # not a bzr branch
150 HTML = r"""
151 <html>
152 <head>
153 <title>%(title)s</title>
154 <style type="text/css">
155 body { color: #333333; background-color: white; font-size: 14px; margin-bottom: 20px;
156 font-family:"Lucida Grande","Bitstream Vera Sans","Verdana"; }
157 div.box { padding-left: 5em; }
158 a { color: #0033CC; }
159 a:hover { background-color: #0033CC; color: white; text-decoration: none; }
160 dl dt { font-weight: bold; }
161 li { padding-bottom: 2px; }
162 div#bzr { }
163 div#bzr code { padding-left: 20px; }
164 div#listdir { font-family: monospace;
165 background-color: #eeeeee;
166 border-bottom: 1px solid;
167 border-top: 1px solid;
168 margin-top: 12px;}
169 div#listdir table { font-size: 13px; margin: 12px; }
170 div#listdir th, td { text-align: left; padding-right: 14px; }
171 div#listdir th { padding-bottom: 3px; }
172 div#listdir td.s {text-align: right;}
173 </style>
174 </head>
176 <body>
177 <h1>%(title)s</h1>
179 %(body)s
181 <div id="listdir">
182 <table>
183 <thead>
184 <tr>
185 <th>Name</th>
186 <th>Last Modified</th>
187 <th>Size</th>
188 <th>Description</th>
189 </tr>
190 </thead>
191 <tbody>
192 %(trs)s
193 </tbody>
194 </table>
195 </div>
196 </body>
197 </html>
201 urls = (
202 "", "lightydir",