Completed
Push — 0.5.3 ( 36ca0e...04cb82 )
by Felipe A.
01:11
created

ArgParse._path()   A

Complexity

Conditions 3

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

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