Commit 742ff4a6 by willmcgugan

Improved output for fsserve

parent 9076762b
......@@ -15,7 +15,7 @@ Serves the contents of PATH with one of a number of methods"""
optparse = super(FSServe, self).get_optparse()
optparse.add_option('-t', '--type', dest='type', type="string", default="http",
help="Server type to create (http, rpc, sftp)", metavar="TYPE")
optparse.add_option('-a', '--addr', dest='addr', type="string", default="",
optparse.add_option('-a', '--addr', dest='addr', type="string", default="localhost",
help="Server address", metavar="ADDR")
optparse.add_option('-p', '--port', dest='port', type="int",
help="Port number", metavar="")
......@@ -33,9 +33,8 @@ Serves the contents of PATH with one of a number of methods"""
if fs.isdir(path):
fs = fs.opendir(path)
path = '/'
if options.verbose:
print "Serving \"%s\" in %s" % (path, fs)
self.output("Opened %s\n" % fs, verbose=True)
port = options.port
......@@ -44,15 +43,17 @@ Serves the contents of PATH with one of a number of methods"""
if options.type == 'http':
from fs.expose.http import serve_fs
if port is None:
port = 80
serve_fs(fs, options.addr, port)
port = 80
self.output("Starting http server on %s:%i\n" % (options.addr, port), verbose=True)
serve_fs(fs, options.addr, port)
elif options.type == 'rpc':
from fs.expose.xmlrpc import RPCFSServer
if port is None:
port = 80
s = RPCFSServer(fs, (options.addr, port))
s.serve_forever()
self.output("Starting rpc server on %s:%i\n" % (options.addr, port), verbose=True)
s.serve_forever()
elif options.type == 'sftp':
from fs.expose.sftp import BaseSFTPServer
......@@ -60,6 +61,7 @@ Serves the contents of PATH with one of a number of methods"""
port = 22
server = BaseSFTPServer((options.addr, port), fs)
try:
self.output("Starting sftp server on %s:%i\n" % (options.addr, port), verbose=True)
server.serve_forever()
except Exception, e:
pass
......
......@@ -147,8 +147,7 @@ class Command(object):
def get_resources(self, fs_urls, dirs_only=False, files_only=False, single=False):
fs_paths = [self.open_fs(fs_url) for fs_url in fs_urls]
fs_paths = [self.open_fs(fs_url) for fs_url in fs_urls]
resources = []
for fs, path in fs_paths:
......@@ -187,10 +186,9 @@ class Command(object):
text = text.encode(self.encoding, 'replace')
return text
def output(self, msgs, verbose=False):
if verbose and not self.verbose:
if verbose and not self.options.verbose:
return
if isinstance(msgs, basestring):
msgs = (msgs,)
......@@ -281,6 +279,7 @@ class Command(object):
def run(self):
parser = self.get_optparse()
options, args = parser.parse_args()
self.options = options
if options.listopeners:
self.list_openers()
......
......@@ -9,6 +9,7 @@ import urllib
import posixpath
import time
import threading
import socket
def _datetime_to_epoch(d):
return mktime(d.timetuple())
......@@ -27,7 +28,10 @@ class FSHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
try:
f = self.send_head()
if f:
self.copyfile(f, self.wfile)
try:
self.copyfile(f, self.wfile)
except socket.error:
pass
finally:
if f is not None:
f.close()
......@@ -44,8 +48,6 @@ class FSHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
"""
path = self.translate_path(self.path)
#path = self.translate_path(self.path)
#print path
f = None
if self._fs.isdir(path):
if not self.path.endswith('/'):
......@@ -54,7 +56,7 @@ class FSHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
self.send_header("Location", self.path + "/")
self.end_headers()
return None
for index in "index.html", "index.htm":
for index in ("index.html", "index.htm"):
index = pathjoin(path, index)
if self._fs.exists(index):
path = index
......
"""
fs.opener: open file systems from a FS url
"""
__all__ = ['OpenerError',
'NoOpenerError',
'OpenerRegistry',
'opener']
import sys
from fs.osfs import OSFS
from fs.path import pathsplit, basename, join, iswildcard
......@@ -12,10 +22,6 @@ class OpenerError(Exception):
class NoOpenerError(OpenerError):
pass
class MissingParameterError(OpenerError):
pass
def _expand_syspath(path):
if path is None:
return path
......@@ -64,6 +70,7 @@ def _split_url_path(url):
class OpenerRegistry(object):
"""An opener stores a number of opener objects that are used to parse FS URLs"""
re_fs_url = re.compile(r'''
^
......@@ -95,18 +102,39 @@ class OpenerRegistry(object):
return match
def get_opener(self, name):
"""Retrieve an opener for the given protocol
:param name: name of the opener to open
:raises NoOpenerError: if no opener has been registered of that name
"""
if name not in self.registry:
raise NoOpenerError("No opener for %s" % name)
index = self.registry[name]
return self.openers[index]
def add(self, opener):
"""Adds an opener to the registry
:param opener: a class derived from fs.opener.Opener
"""
index = len(self.openers)
self.openers[index] = opener
for name in opener.names:
self.registry[name] = index
def parse(self, fs_url, default_fs_name=None, open_dir=True, writeable=False, create_dir=False):
def parse(self, fs_url, default_fs_name=None, writeable=False, create_dir=False):
"""Parses a FS url and returns an fs object a path within that FS object
(if indicated in the path). A tuple of (<FS instance>, <path>) is returned.
:param fs_url: an FS url
:param default_fs_name: the default FS to use if none is indicated (defaults is OSFS)
:param writeable: if True, a writeable FS will be returned
:oaram create_dir: if True, then the directory in the FS will be created
"""
orig_url = fs_url
match = self.split_segments(fs_url)
......@@ -154,7 +182,7 @@ class OpenerRegistry(object):
fs = fs.opendir(pathname)
fs_path = resourcename
return fs, fs_path
return fs, fs_path or ''
def open(self, fs_url, mode='rb'):
"""Opens a file from a given FS url
......@@ -173,15 +201,17 @@ class OpenerRegistry(object):
fs, path = self.parse(fs_url, writeable=writeable)
file_object = fs.open(path, mode)
# If we just return the file, the fs goes out of scope and closes,
# If we just return the file, then fs goes out of scope and closes,
# which may make the file unusable. To get around this, we store a
# reference in the file object to the FS, and patch the file's
# close method to also close the FS.
close = file_object.close
def replace_close():
fs.close()
return close()
file_object.close = replace_close
close_fs = fs
def replace_close():
ret = close()
close_fs.close()
return ret
file_object.close = replace_close
return file_object
......@@ -204,23 +234,35 @@ class OpenerRegistry(object):
it doesn't already exist
"""
fs, path = self.parse(fs_url, writable=writeable, create_dir=create_dir)
fs, path = self.parse(fs_url, writeable=writeable, create_dir=create_dir)
if path:
return fs.opendir(path)
return fs
class Opener(object):
"""The base class for openers
@classmethod
def get_param(cls, params, name, default=None):
try:
param = params.pop(0)
except IndexError:
if default is not None:
return default
raise MissingParameterError(error_msg)
return param
Opener follow a very simple protocol. To create an opener, derive a class
from `Opener` and define a classmethod called `get_fs`, which should have the following signature::
@classmethod
def get_fs(cls, registry, fs_name, fs_name_params, fs_path, writeable, create_dir):
The parameters of `get_fs` are as follows:
* `fs_name` the name of the opener, as extracted from the protocol part of the url,
* `fs_name_params` reserved for future use
* `fs_path` the path part of the url
* `writeable` if True, then `get_fs` must return an FS that can be written to
* `create_dir` if True then `get_fs` should attempt to silently create the directory references in path
In addition to `get_fs` an opener class should contain
two class attributes; names and desc. `names` is a list of protocols that
list opener will opener. `desc` is an English description of the individual opener syntax.
"""
pass
class OSFSOpener(Opener):
......@@ -299,7 +341,7 @@ rpc://www.example.org (opens an RPC server on www.example.org, default port 80)"
def get_fs(cls, registry, fs_name, fs_name_params, fs_path, writeable, create_dir):
from fs.rpcfs import RPCFS
username, password, fs_path = _parse_credentials(fs_path)
if not fs_path.startswith('http://'):
if '://' not in fs_path:
fs_path = 'http://' + fs_path
scheme, netloc, path, params, query, fragment = urlparse(fs_path)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment