84
|
1 #!/usr/bin/env python
|
|
2
|
|
3 """
|
|
4 serve directory with decoupage, e.g.
|
|
5
|
|
6 ``decoupage --port 8080 /home/jhammel/tmp``
|
|
7
|
|
8 If the directory is not specified, the current working directory is used
|
|
9 """
|
|
10
|
|
11 import optparse
|
|
12 import os
|
85
|
13 import socket
|
84
|
14 import sys
|
|
15
|
88
|
16 from .formatters import Datestamp, Sort, Up, DirectoryIndicator
|
84
|
17 from .web import Decoupage
|
|
18 from wsgiref import simple_server
|
|
19
|
|
20 here = os.path.dirname(os.path.realpath(__file__))
|
|
21
|
85
|
22 class DecoupageServer(Decoupage):
|
84
|
23 """serve locally with decoupage"""
|
85
|
24 # TODO: deprecate; move Decoupage to a few classes
|
|
25 # with more flexible formatters
|
|
26 def __init__(self, *args, **kwargs):
|
|
27 Decoupage.__init__(self, **kwargs)
|
|
28 # default formatters
|
|
29 # TODO: make configurable
|
88
|
30 self._formatters = [Sort(),
|
|
31 DirectoryIndicator('/'),
|
|
32 Up('..'),
|
|
33 Datestamp('modified: %m %d, %Y')]
|
85
|
34 def get_formatters(self, path):
|
|
35 return self._formatters
|
|
36
|
84
|
37
|
|
38 def main(args=sys.argv[1:]):
|
|
39
|
|
40 # parse command line options
|
|
41 usage = '%prog [options]'
|
|
42 parser = optparse.OptionParser(usage=usage, description=__doc__)
|
|
43 parser.add_option('-p', '--port', dest='port',
|
|
44 type='int', default=1977,
|
|
45 help="port to serve on [DEFAULT: %default]")
|
85
|
46 parser.add_option('-a', '--address', dest='address',
|
|
47 default='0.0.0.0',
|
|
48 help="address to serve on [DEFAULT: %default]")
|
84
|
49 parser.add_option('--no-reload', dest='auto_reload',
|
|
50 action='store_false', default=True,
|
|
51 help="do not dynamically refresh indices")
|
85
|
52 parser.add_option('--no-print-ip', dest='print_ip',
|
|
53 action='store_false', default=True,
|
|
54 help="do not print resolvable IP address")
|
84
|
55 options, args = parser.parse_args(args)
|
|
56 if not args:
|
|
57 directory = os.getcwd()
|
|
58 elif len(args) == 1:
|
|
59 directory = args[0]
|
|
60 if len(args) > 1:
|
|
61 # TODO:
|
|
62 # allow multiple directories with mount points
|
|
63 # e.g. `decoupage [options] directory [directory2=/foo] [...]`
|
|
64 # This may be done by creating a temporary directory with appropriate
|
|
65 # symbolic links (on OSes that allow them)
|
|
66
|
|
67 parser.print_help()
|
|
68 parser.exit(1)
|
85
|
69 if not os.path.isdir(directory):
|
|
70 raise OSError("'%s' is not a directory" % directory)
|
84
|
71
|
85
|
72 # create WSGI app
|
84
|
73 # TODO:
|
|
74 # - allow CLI specification of formatters
|
|
75 # - template specification
|
85
|
76 app = DecoupageServer(directory=directory,
|
|
77 auto_reload=options.auto_reload)
|
84
|
78
|
|
79
|
|
80 # create server
|
|
81 # TODO: allow choice amongst server classes
|
85
|
82 printable_address = '127.0.0.1' if options.address == '0.0.0.0' else options.address
|
|
83 server = simple_server.make_server(options.address, options.port, app)
|
84
|
84 print 'serving directory %s ( %s ) at \nhttp://%s:%d/' % (directory,
|
|
85 'file://' + directory, # XXX
|
85
|
86 printable_address,
|
84
|
87 options.port)
|
85
|
88 if options.print_ip:
|
|
89 # from http://stackoverflow.com/questions/166506/finding-local-ip-addresses-using-pythons-stdlib
|
|
90 hostname = "google.com"
|
|
91 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
92 s.connect((hostname,80))
|
|
93 hostname = s.getsockname()[0]
|
|
94 print "http://%s:%s/" % (hostname, options.port)
|
|
95 s.close()
|
84
|
96
|
85
|
97 # serve directory contents via decoupage
|
84
|
98 try:
|
|
99 server.serve_forever()
|
|
100 except KeyboardInterrupt:
|
|
101 pass
|
|
102
|
|
103 if __name__ == '__main__':
|
|
104 main()
|