X-Git-Url: https://arthur.barton.de/gitweb/?a=blobdiff_plain;f=cmd%2Fweb-cmd.py;h=2ddc0b1a345737ee7998afecd1005a9a58a7948b;hb=96d4110838158be0f60484cfc84ac3a56772e09b;hp=4bcc5480dac13eecfed75bc5f6b4ff50c92f36c7;hpb=9fce16ff68357c6b41bed94c5be2ed985dccb9d7;p=bup.git diff --git a/cmd/web-cmd.py b/cmd/web-cmd.py index 4bcc548..2ddc0b1 100755 --- a/cmd/web-cmd.py +++ b/cmd/web-cmd.py @@ -1,23 +1,39 @@ -#!/usr/bin/env python -import sys, stat, urllib, mimetypes, posixpath, time -import tornado.httpserver -import tornado.ioloop -import tornado.web +#!/bin/sh +"""": # -*-python-*- +bup_python="$(dirname "$0")/bup-python" || exit $? +exec "$bup_python" "$0" ${1+"$@"} +""" +# end of bup preamble + +import mimetypes, os, posixpath, stat, sys, time, urllib, webbrowser + from bup import options, git, vfs -from bup.helpers import * +from bup.helpers import debug1, handle_ctrl_c, log, resource_path + +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 @@ -31,28 +47,36 @@ def _contains_hidden_files(n): return False -def _compute_dir_contents(n, show_hidden=False): +def _compute_dir_contents(n, path, show_hidden=False): """Given a vfs node, returns an iterator for display info of all subs.""" - for sub in n: - display = link = sub.name + url_append = "" + if show_hidden: + url_append = "?hidden=1" - if not show_hidden and len(display)>1 and display.startswith('.'): - continue + if path != "/": + yield('..', '../' + url_append, '') + for sub in n: + 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_resolve().mode): - link = sub.name + "/" + 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): @@ -61,7 +85,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 @@ -88,18 +113,16 @@ class BupRequestHandler(tornado.web.RequestHandler): try: show_hidden = int(self.request.arguments.get('hidden', [0])[-1]) - except ValueError, e: + except ValueError as e: show_hidden = False self.render( 'list-directory.html', path=path, - breadcrumbs=_compute_breadcrumbs(path), + breadcrumbs=_compute_breadcrumbs(path, show_hidden), files_hidden=_contains_hidden_files(n), hidden_shown=show_hidden, - dir_contents=_compute_dir_contents(n, show_hidden), - # We need the standard url_escape so we don't escape / - url_escape=urllib.quote) + dir_contents=_compute_dir_contents(n, path, show_hidden)) def _get_file(self, path, n): """Process a request on a file. @@ -113,12 +136,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. @@ -159,8 +195,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: @@ -188,11 +226,18 @@ application = tornado.web.Application([ (r"(/.*)", BupRequestHandler), ], **settings) -if __name__ == "__main__": - http_server = tornado.httpserver.HTTPServer(application) - http_server.listen(address[1], address=address[0]) +http_server = tornado.httpserver.HTTPServer(application) +http_server.listen(address[1], address=address[0]) + +try: + sock = http_server._socket # tornado < 2.0 +except AttributeError as e: + sock = http_server._sockets.values()[0] - print "Serving HTTP on %s:%d..." % http_server._socket.getsockname() - loop = tornado.ioloop.IOLoop.instance() - loop.start() +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()