Completed
Push — 0.5.3 ( d5f94f...eba748 )
by Felipe A.
01:10
created

ExcludeAction   A

Complexity

Total Complexity 5

Size/Duplication

Total Lines 16
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 16
rs 10
c 0
b 0
f 0
wmc 5

2 Methods

Rating   Name   Duplication   Size   Complexity  
A __call__() 0 11 4
A __init__() 0 3 1
1
#!/usr/bin/env python
2
# -*- coding: utf-8 -*-
3
4
import sys
5
import os
6
import os.path
7
import argparse
8
import re
9
import flask
10
import warnings
11
import collections
12
13
import globre
14
15
from . import app, compat
16
from .compat import PY_LEGACY
17
18
19
class PluginAction(argparse.Action):
20
    def __call__(self, parser, namespace, value, option_string=None):
21
        warned = '%s_warning' % self.dest
22
        if ',' in value and not getattr(namespace, warned, False):
23
            setattr(namespace, warned, True)
24
            warnings.warn(
25
                'Comma-separated --plugin value is deprecated, '
26
                'use multiple --plugin instead.'
27
                )
28
        values = value.split(',')
29
        prev = getattr(namespace, self.dest, None)
30
        if isinstance(prev, list):
31
            values = prev + values
32
        setattr(namespace, self.dest, values)
33
        
34
35
class ExcludeAction(argparse.Action):
36
    def __init__(self, *args, **kwargs):
37
        self.sep = kwargs.pop('sep', os.sep)
38
        super(ExcludeAction, self).__init__(*args, **kwargs)
39
40
    def __call__(self, parser, namespace, value, option_string=None):
41
        rule = globre.compile(
42
            value, 
43
            sep=self.sep,
44
            flags=globre.EXACT if value.startswith(self.sep) else 0)
45
        prev = getattr(namespace, self.dest, None)
46
        if callable(prev):
47
            value = lambda path: rule.match(path) or prev(path)
48
        else:
49
            value = rule.match
50
        setattr(namespace, self.dest, value)
51
52
53
class ArgParse(argparse.ArgumentParser):
54
    default_directory = os.path.abspath(compat.getcwd())
55
    default_host = os.getenv('BROWSEPY_HOST', '127.0.0.1')
56
    default_port = os.getenv('BROWSEPY_PORT', '8080')
57
    plugin_action_class = PluginAction
58
    exclude_action_class = ExcludeAction
59
60
    description = 'extendable web file browser'
61
62
    def __init__(self, sep=os.sep):
63
        super(ArgParse, self).__init__(description=self.description)
64
65
        self.add_argument(
66
            'host', nargs='?',
67
            default=self.default_host,
68
            help='address to listen (default: %(default)s)')
69
        self.add_argument(
70
            'port', nargs='?', type=int,
71
            default=self.default_port,
72
            help='port to listen (default: %(default)s)')
73
        self.add_argument(
74
            '--directory', metavar='PATH', type=self._directory,
75
            default=self.default_directory,
76
            help='base serving directory (default: current path)')
77
        self.add_argument(
78
            '--initial', metavar='PATH', type=self._directory,
79
            help='initial directory (default: same as --directory)')
80
        self.add_argument(
81
            '--removable', metavar='PATH', type=self._directory,
82
            default=None,
83
            help='base directory for remove (default: none)')
84
        self.add_argument(
85
            '--upload', metavar='PATH', type=self._directory,
86
            default=None,
87
            help='base directory for upload (default: none)')
88
        self.add_argument(
89
            '--exclude', metavar='PATTERN',
90
            action=self.exclude_action_class,
91
            default=None,
92
            sep=sep,
93
            help='exclude paths by pattern (multiple allowed)')
94
        self.add_argument(
95
            '--plugin', metavar='MODULE',
96
            action=self.plugin_action_class,
97
            default=[],
98
            help='load plugin module (multiple allowed)')
99
        self.add_argument('--debug', action='store_true', help='debug mode')
100
101
    def _directory(self, arg):
102
        if not arg:
103
            return None
104
        if PY_LEGACY and hasattr(sys.stdin, 'encoding'):
105
            encoding = sys.stdin.encoding or sys.getdefaultencoding()
106
            arg = arg.decode(encoding)
107
        if os.path.isdir(arg):
108
            return os.path.abspath(arg)
109
        self.error('%s is not a valid directory' % arg)
110
111
112
def main(argv=sys.argv[1:], app=app, parser=ArgParse, run_fnc=flask.Flask.run):
113
    plugin_manager = app.extensions['plugin_manager']
114
    args = plugin_manager.load_arguments(argv, parser())
115
    os.environ['DEBUG'] = 'true' if args.debug else ''
116
    app.config.update(
117
        directory_base=args.directory,
118
        directory_start=args.initial or args.directory,
119
        directory_remove=args.removable,
120
        directory_upload=args.upload,
121
        plugin_modules=args.plugin,
122
        exclude_fnc=args.exclude
123
        )
124
    plugin_manager.reload()
125
    run_fnc(
126
        app,
127
        host=args.host,
128
        port=args.port,
129
        debug=args.debug,
130
        use_reloader=False,
131
        threaded=True
132
        )
133
134
135
if __name__ == '__main__':
136
    main()
137