X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=cmd%2Fweb-cmd.py;h=1c515e2d10d6ddfa0d488311adcd1f73315f11d8;hb=b27758e1ac79a11edf504ea94e21bd8160fa4974;hp=2ea8c73683137c5d4d29c6c18a1163750cf27ef6;hpb=6627d423d09194a15bed88e2199ac6e9a5d655ba;p=bup.git diff --git a/cmd/web-cmd.py b/cmd/web-cmd.py index 2ea8c73..1c515e2 100755 --- a/cmd/web-cmd.py +++ b/cmd/web-cmd.py @@ -1,47 +1,74 @@ #!/usr/bin/env python -import sys, stat, cgi, shutil, urllib, mimetypes, posixpath, time -import tornado.httpserver -import tornado.ioloop -import tornado.template -import tornado.web +import sys, stat, urllib, mimetypes, posixpath, time, webbrowser +import urllib from bup import options, git, vfs from bup.helpers import * +try: + import tornado.httpserver + import tornado.ioloop + import tornado.web +except ImportError: + log('error: cannot find the python "tornado" module; please install it\n') + sys.exit(1) handle_ctrl_c() -def _compute_breadcrumbs(path): +def _compute_breadcrumbs(path, show_hidden=False): """Returns a list of breadcrumb objects for a path.""" breadcrumbs = [] breadcrumbs.append(('[root]', '/')) path_parts = path.split('/')[1:-1] full_path = '/' for part in path_parts: - full_path += part + '/' - breadcrumbs.append((part, full_path)) + full_path += part + "/" + url_append = "" + if show_hidden: + url_append = '?hidden=1' + breadcrumbs.append((part, full_path+url_append)) return breadcrumbs -def _compute_dir_contents(n): +def _contains_hidden_files(n): + """Return True if n contains files starting with a '.', False otherwise.""" + for sub in n: + name = sub.name + if len(name)>1 and name.startswith('.'): + return True + + return False + + +def _compute_dir_contents(n, path, show_hidden=False): """Given a vfs node, returns an iterator for display info of all subs.""" - contents = [] + url_append = "" + if show_hidden: + url_append = "?hidden=1" + + if path != "/": + yield('..', '../' + url_append, '') for sub in n: - display = link = sub.name + display = sub.name + link = urllib.quote(sub.name) # link should be based on fully resolved type to avoid extra # HTTP redirect. - if stat.S_ISDIR(sub.try_lresolve('').mode): - link = sub.name + "/" + if stat.S_ISDIR(sub.try_resolve().mode): + link += "/" + + if not show_hidden and len(display)>1 and display.startswith('.'): + continue size = None if stat.S_ISDIR(sub.mode): - display = sub.name + '/' + display += '/' elif stat.S_ISLNK(sub.mode): - display = sub.name + '@' + display += '@' else: size = sub.size() + size = (opt.human_readable and format_filesize(size)) or size - yield (display, link, size) + yield (display, link + url_append, size) class BupRequestHandler(tornado.web.RequestHandler): @@ -50,7 +77,8 @@ class BupRequestHandler(tornado.web.RequestHandler): def head(self, path): return self._process_request(path) - + + @tornado.web.asynchronous def _process_request(self, path): path = urllib.unquote(path) print 'Handling request for %s' % path @@ -75,13 +103,18 @@ class BupRequestHandler(tornado.web.RequestHandler): print 'Redirecting from %s to %s' % (path, path + '/') return self.redirect(path + '/', permanent=True) + try: + show_hidden = int(self.request.arguments.get('hidden', [0])[-1]) + except ValueError, e: + show_hidden = False + self.render( 'list-directory.html', path=path, - breadcrumbs=_compute_breadcrumbs(path), - dir_contents=_compute_dir_contents(n), - # We need the standard url_escape so we don't escape / - url_escape=urllib.quote) + breadcrumbs=_compute_breadcrumbs(path, show_hidden), + files_hidden=_contains_hidden_files(n), + hidden_shown=show_hidden, + dir_contents=_compute_dir_contents(n, path, show_hidden)) def _get_file(self, path, n): """Process a request on a file. @@ -95,12 +128,25 @@ class BupRequestHandler(tornado.web.RequestHandler): self.set_header("Content-Type", ctype) size = n.size() self.set_header("Content-Length", str(size)) + assert(len(n.hash) == 20) + self.set_header("Etag", n.hash.encode('hex')) if self.request.method != 'HEAD': + self.flush() f = n.open() - for blob in chunkyreader(f): - self.write(blob) - f.close() + it = chunkyreader(f) + def write_more(me): + try: + blob = it.next() + except StopIteration: + f.close() + self.finish() + return + self.request.connection.stream.write(blob, + callback=lambda: me(me)) + write_more(write_more) + else: + self.finish() def _guess_type(self, path): """Guess the type of a file. @@ -141,8 +187,10 @@ class BupRequestHandler(tornado.web.RequestHandler): optspec = """ bup web [[hostname]:port] -- +human-readable display human readable file sizes (i.e. 3.9K, 4.7M) +browser open the site in the default browser """ -o = options.Options('bup web', optspec) +o = options.Options(optspec) (opt, flags, extra) = o.parse(sys.argv[1:]) if len(extra) > 1: @@ -160,6 +208,7 @@ top = vfs.RefList(None) settings = dict( debug = 1, template_path = resource_path('web'), + static_path = resource_path('web/static') ) # Disable buffering on stdout, for debug messages @@ -173,7 +222,15 @@ if __name__ == "__main__": http_server = tornado.httpserver.HTTPServer(application) http_server.listen(address[1], address=address[0]) - print "Serving HTTP on %s:%d..." % http_server._socket.getsockname() + try: + sock = http_server._socket # tornado < 2.0 + except AttributeError, e: + sock = http_server._sockets.values()[0] + + print "Serving HTTP on %s:%d..." % sock.getsockname() + loop = tornado.ioloop.IOLoop.instance() + if opt.browser: + browser_addr = 'http://' + address[0] + ':' + str(address[1]) + loop.add_callback(lambda : webbrowser.open(browser_addr)) loop.start() -