root/config.py

Revision 332:7e5c67a0041e, 14.2 kB (checked in by Stefan Schwarzer <sschwarzer@sschwarzer.net>, 1 year ago)
Separate ignore patterns in `WSB_IGNORE` with whitespace, not
semicolons. I hope this is the final decision. ;-)
Line 
1 # encoding: UTF-8
2 # Copyright (C) 2007, Stefan Schwarzer
3 #
4 # Permission is hereby granted, free of charge, to any person
5 # obtaining a copy of this software and associated documentation files
6 # (the "Software"), to deal in the Software without restriction,
7 # including without limitation the rights to use, copy, modify, merge,
8 # publish, distribute, sublicense, and/or sell copies of the Software,
9 # and to permit persons to whom the Software is furnished to do so,
10 # subject to the following conditions:
11 #
12 # The above copyright notice and this permission notice shall be
13 # included in all copies or substantial portions of the Software.
14 #
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 # SOFTWARE.
23
24 """
25 Configure the application.
26 """
27
28 import sys
29
30
31 MAN_PAGE = """\
32 NAME
33
34   Websourcebrowser - conveniently browse source code with a webbrowser
35
36 SYNOPSIS
37
38   wsbrowser [options]
39
40   The name of the executable is wsbrowser on Posix and wsbrowser.py on
41   Windows.
42
43 DESCRIPTION
44
45   Websourcebrowser starts an internal webserver and listens for HTTP
46   requests for directories and files in a project's source code
47   directory. The web interface allows to browse the source code with a
48   left frame containing the directory tree and a right frame a
49   selected file. The directory frame is always accessible.
50
51   If Pygments (http://pygments.org) is installed, files may be
52   displayed with syntax highlighting.
53
54   To stop Websourcebrowser, type Ctrl-C (on Posix) or Ctrl-Break (on
55   Windows).
56
57 WEB INTERFACE
58
59   After invoking Websourcebrowser, it outputs the URL you should put
60   in the address line of your webbrowser. After you've done this, you
61   get a display with two frames: The left displays the directory
62   specified by the --root option (or the default), the right shows a
63   placeholder. If you click a link in the left frame denoting a file,
64   it's shown in the right frame. If the file is a binary file for
65   which Websourcebrowser doesn't know to render it, a hexdump is shown
66   instead. At the moment, this happens even for popular formats as
67   PDF, and that will change.
68
69   The directory display on the left has several framed links which you
70   can imagine as buttons. "Reset view" resets the display, this is as
71   if you just entered the root URL which Websourcebrowser prints in
72   the terminal upon start. The button "Homepage" opens a new window
73   with the page identified with the command line option
74   --project-homepage. Below the two already described buttons you can
75   control the number of expanded directory levels. By definition, when
76   the level is 1, just a linear list of the directories and files in
77   the project root directory is shown. A level of 2 means that the
78   contained directories and files are also displayed. This is easier
79   to check out than to describe. Note that you won't see a difference
80   after a click if the project directory structure is not that deep.
81   By the way, clicking on a directory link will show a list of its
82   contents if they're not already displayed. If, for your taste, too
83   many levels are shown, you can reduce them with the buttons at the
84   top of the frame.
85
86 OPTIONS
87
88   -h, --help
89         Show this help text and exit.
90
91   -r ROOT, --root=ROOT
92         Set the document root directory (default: current directory).
93         For example, if --root=/my/greatproject is specified, the URL
94         path / will correspond to the directory /my/greatproject.
95         Directories or files "above" the root directory aren't
96         accessible (probably, see section BUGS).
97
98   -t PROJECT_TITLE, --project-title=PROJECT_TITLE
99         Set the project title to display as the title of the frameset
100         (default: capitalized base name of the root directory, so the
101         above root option sets a project title "Greatproject").
102
103   --project-homepage=PROJECT_HOMEPAGE
104         Make the specified URL accessible via the "Homepage" link in
105         the left frame (default: the Websourcebrowser homepage).
106
107   -d DIR_LEVELS, --dir-levels=DIR_LEVELS
108         Set the directory nesting level for the tree display in the
109         left frame (default: 1). The number 1 denotes a linear list, 2
110         additionally shows the direct subdirectories etc.
111
112         Using a large number will display the directory tree
113         completely expanded but may make the browsing rather slow for
114         a large directory tree. Thus it's recommended to keep the
115         default, 1.
116
117   --dir-indent=DIR_INDENT
118         Set the number of characters for indentation per directory
119         level (default: 4).
120
121   -i PATTERN, --ignore-pattern=PATTERN
122         Ignore directories and files matching this pattern (default:
123         nothing is ignored). To specify more than one pattern, repeat
124         this option.
125
126         Example: To ignore all Subversion bookkeeping files, use
127         --ignore-pattern="/*.svn" --ignore-pattern="/*.svn/*"
128
129   -l, --line-numbers
130         Prepend lines of text files with line numbers (default: no
131         line numbers).
132
133         This works only if Pygments is installed, otherwise this
134         option is ignored.
135
136   --http-host=HTTP_HOST
137         Use the specified host name or IP for the local interface to
138         listen on (default: localhost).
139
140         With the defaults for --http-host and --http-port, the address
141         line in the browser is http://localhost:8000/ .
142
143   --http-port=HTTP_PORT
144         Listen on this HTTP port (default: 8000).
145
146         With the defaults for --http-host and --http-port, the address
147         line in the browser is http://localhost:8000/ .
148
149   -c CLIENT, --allowed-client=CLIENT
150         Allow remote access from this host name or IP address
151         (default: allow only access from localhost). The localhost
152         address is always included. For multiple host names or IP
153         addresses use the option several times. For example:
154
155         wsbrowser -c my.host.com -c 199.243.19.27
156
157         As a special case, specifying ALL as the options value accepts
158         requests from all addresses and so effectively makes
159         Websourcebrowser a web server on the public internet, unless
160         prevented by a router or firewall.
161
162   --logging
163         Activate logging of HTTP accesses to standard output (default:
164         no logging).
165
166 ENVIRONMENT
167
168   WSB_IGNORE
169         Set wildcard patterns to ignore. If multiple patterns are
170         given, they must be separated with whitespace.
171
172         A typical example for WSB_IGNORE might be
173         *.pyc  *.pyo  */.svn  *.svn/*  */.hg  */.hg/*  *.swp
174
175         If both this environment variable and one or more
176         --ignore-pattern options are used, the patterns from the
177         command line are added to those from the environment variable.
178
179 BUGS
180
181   Probably there are some bugs as Websourcebrowser is still alpha
182   software. Currently, I don't recommend to use Websourcebrowser for
183   use on the public internet because it may contain significant
184   vulnerabilities. (I indeed paid attention to security though I would
185   welcome an experienced fellow to spot security problems.)
186
187   Since the software is still in the alpha stage, it may still change
188   significantly. This may include incompatible variations like
189   removing command line options or changing their semantics.
190
191 AUTHOR
192
193   The author of Websourcebrowser is
194   Stefan Schwarzer <sschwarzer@sschwarzer.net>.
195
196 SEE ALSO
197
198   The pydoc module in the Python distribution similarly acts as a
199   webserver if it's invoked as a program with the option -p and a port
200   number.
201 """
202
203 import optparse
204 import os
205 import socket
206 import sys
207
208 # Websourcebrowser modules
209 import coding
210 import tools
211
212 #
213 # constants used in several places
214 #
215 CSS_FILE_NAME = "websourcebrowser.css"
216 # window targets
217 DIR_WINDOW_TARGET = "websourcebrowser_dir"
218 SOURCE_WINDOW_TARGET = "websourcebrowser_source"
219 HELP_WINDOW_TARGET = "websourcebrowser_help"
220 # used to distinguish actual files from directories or files for
221 #  internal use, e. g. style sheets
222 SPECIAL_DIR = "_WEBSOURCEBROWSER_"
223 ALL_CLIENTS = "all_clients_allowed"
224
225 #
226 # defaults, can be changed via command line
227 #
228
229 # project root directory
230 root = os.getcwd()
231
232 # project title, included in HTML `title` and `h1` tags; if `None`,
233 #  use the basename of the root directory (see above), i. e. if the
234 #  root directory is "/some/project/path", the title becomes "Path"
235 project_title = None
236
237 # the project's homepage, as linked in the directory navigation pane
238 project_homepage = "http://websourcebrowser.sschwarzer.net"
239
240 # show that many recursive levels of directory items; 1 means to just
241 #  display the immediate directory contents but nothing below
242 # Note: the higher this number, the more sluggish the applications
243 #  become if you have deeply-nested directories with many items
244 dir_levels = 1
245
246 # amount of indentation per directory level in recursive listings;
247 #  usually a number of "&nbsp;" strings
248 dir_indent = 4
249
250 # list of glob patterns for files/directories to ignore; the patterns
251 #  account for the directory part, i. e. use ["*/.svn", "*/.svn/*"] to
252 #  ignore the Subversion metadata directory and all contained items
253 ignore_patterns = []
254
255 # if true, include line numbers in listings
256 line_numbers = False
257
258 # the local HTTP interface
259 http_host = 'localhost'
260
261 # the HTTP port to listen on
262 http_port = 8000
263
264 # clients which are allowed to access this server
265 allowed_clients = ['localhost']
266
267 # if true, log each GET request on stdout
268 logging = False
269
270
271 def set_from_args(args=None):
272     """
273     (Re)set the configuration values in the module from the provided
274     list of arguments `args`, compatible to what `sys.argv[1:]`
275     usually contains. The command line values are the default if
276     `args` is not set or `None`.
277
278     >>> import config
279     >>> config.set_from_args(["-t", u"Cool project", '--ignore-pattern=*/.svn',
280     ...                       '--ignore-pattern=*/.svn/*', '--http-port=8080',
281     ...                       '--line-numbers'])
282     >>> config.project_title
283     u'Cool project'
284     >>> config.ignore_patterns
285     ['*/.svn', '*/.svn/*']
286     >>> config.http_port   # the port value is an integer
287     8080
288     >>> config.dir_levels  # like the number of directory nesting levels
289     1
290     >>> config.line_numbers, config.logging
291     (True, False)
292     """
293     if args is None:
294         args = sys.argv[1:]
295     # set up command line parser
296     parser = optparse.OptionParser(add_help_option=False)
297     parser.add_option("-h", "--help", action='store_true')
298     parser.add_option("-r", "--root", help="document root [current directory]")
299     parser.add_option("-t", "--project-title",
300                       help="project title to use in HTML title "
301                            "[last part of root dir]")
302     parser.add_option("--project-homepage",
303                       help="homepage URL of the project [Websourcebrowser URL]")
304     parser.add_option("-d", "--dir-levels", type='int',
305                       help="display directory listings that many levels "
306                            "deep [1]")
307     parser.add_option("--dir-indent", type='int',
308                       help="number of spaces for each indentation "
309                            "level in a directory tree [%default]")
310     parser.add_option("-i", "--ignore-pattern", metavar="PATTERN",
311                       dest='ignore_patterns', action='append',
312                       help='ignore dirs/files matching this pattern '
313                            '(e. g. "*/.svn/*") [nothing ignored]')
314     parser.add_option("-l", "--line-numbers", action='store_true',
315                       help="prepend text lines with line numbers [no]")
316     parser.add_option("--http-host", help="local HTTP interface [localhost]")
317     parser.add_option("--http-port", type='int',
318                       help="HTTP port to listen on [%default]")
319     parser.add_option("-c", "--allowed-client", metavar="CLIENT",
320                       dest='allowed_clients', action='append',
321                       help="allow a remote client to connect [localhost]; "
322                            "use ALL to run as a public server")
323     parser.add_option("--logging", action='store_true',
324                       help="log HTTP accesses to stdout [no]")
325     parser.set_defaults(**globals())
326     (options, args) = parser.parse_args(args)
327     if options.help:
328         print MAN_PAGE
329         sys.exit()
330     # from here on, `args` is the list of only the positional arguments!
331     if args:
332         parser.error("program doesn't take arguments")
333     options.root = tools.normalize_path(os.path.expanduser(options.root))
334     if options.project_title is None:
335         options.project_title = os.path.basename(options.root).capitalize()
336     options.project_title = coding.decode(options.project_title)
337     # normalize allowed clients to IPs
338     allowed_clients = set()
339     dummy_port = 80
340     global invalid_clients
341     invalid_clients = []
342     for client in options.allowed_clients:
343         if client == "ALL":
344             allowed_clients = ALL_CLIENTS
345             break
346         try:
347             for addr_info in socket.getaddrinfo(client, dummy_port):
348                 allowed_clients.add(addr_info[4][0])
349         except socket.gaierror:
350             invalid_clients.append(client)
351     options.allowed_clients = allowed_clients
352     # copy changed configuration back to module namespace; do not use
353     #  `globals().update()` because that may copy too much
354     option_names = ['root', 'project_title', 'project_homepage', 'dir_levels',
355                     'dir_indent', 'ignore_patterns', 'line_numbers',
356                     'http_host', 'http_port', 'allowed_clients', 'logging']
357     for name in option_names:
358         globals()[name] = getattr(options, name)
359
360 def set_from_environment():
361     """
362     Inspect the environment to set some configuration parameters.
363
364     Currently, only the ignore patterns are considered, via the
365     environment variable `WSB_IGNORE`. Its value is a whitespace-
366     separated string of patterns, for example
367     "*.pyc  *.pyo  */.svn  *.svn/*  */.hg  */.hg/*  *.swp".
368     """
369     global ignore_patterns
370     environ = os.environ
371     patterns = environ.get('WSB_IGNORE', "")
372     for pattern in patterns.split():
373         ignore_patterns.append(pattern)
374
Note: See TracBrowser for help on using the browser.