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