pygments.rb 0.2.13 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. data/.gitignore +1 -0
  2. data/README.md +45 -19
  3. data/Rakefile +21 -11
  4. data/bench.rb +15 -48
  5. data/cache-lexers.rb +8 -0
  6. data/lexers +0 -0
  7. data/lib/pygments.rb +3 -6
  8. data/lib/pygments/mentos.py +343 -0
  9. data/lib/pygments/popen.rb +383 -0
  10. data/lib/pygments/version.rb +1 -1
  11. data/pygments.rb.gemspec +5 -4
  12. data/test/test_data.c +2581 -0
  13. data/test/test_data.py +514 -0
  14. data/test/test_data_generated +2582 -0
  15. data/test/test_pygments.rb +208 -84
  16. data/vendor/pygments-main/pygments/lexers/_mapping.py +1 -1
  17. data/vendor/pygments-main/pygments/lexers/shell.py +1 -1
  18. data/vendor/simplejson/.gitignore +10 -0
  19. data/vendor/simplejson/.travis.yml +5 -0
  20. data/vendor/simplejson/CHANGES.txt +291 -0
  21. data/vendor/simplejson/LICENSE.txt +19 -0
  22. data/vendor/simplejson/MANIFEST.in +5 -0
  23. data/vendor/simplejson/README.rst +19 -0
  24. data/vendor/simplejson/conf.py +179 -0
  25. data/vendor/simplejson/index.rst +628 -0
  26. data/vendor/simplejson/scripts/make_docs.py +18 -0
  27. data/vendor/simplejson/setup.py +104 -0
  28. data/vendor/simplejson/simplejson/__init__.py +510 -0
  29. data/vendor/simplejson/simplejson/_speedups.c +2745 -0
  30. data/vendor/simplejson/simplejson/decoder.py +425 -0
  31. data/vendor/simplejson/simplejson/encoder.py +567 -0
  32. data/vendor/simplejson/simplejson/ordered_dict.py +119 -0
  33. data/vendor/simplejson/simplejson/scanner.py +77 -0
  34. data/vendor/simplejson/simplejson/tests/__init__.py +67 -0
  35. data/vendor/simplejson/simplejson/tests/test_bigint_as_string.py +55 -0
  36. data/vendor/simplejson/simplejson/tests/test_check_circular.py +30 -0
  37. data/vendor/simplejson/simplejson/tests/test_decimal.py +66 -0
  38. data/vendor/simplejson/simplejson/tests/test_decode.py +83 -0
  39. data/vendor/simplejson/simplejson/tests/test_default.py +9 -0
  40. data/vendor/simplejson/simplejson/tests/test_dump.py +67 -0
  41. data/vendor/simplejson/simplejson/tests/test_encode_basestring_ascii.py +46 -0
  42. data/vendor/simplejson/simplejson/tests/test_encode_for_html.py +32 -0
  43. data/vendor/simplejson/simplejson/tests/test_errors.py +34 -0
  44. data/vendor/simplejson/simplejson/tests/test_fail.py +91 -0
  45. data/vendor/simplejson/simplejson/tests/test_float.py +19 -0
  46. data/vendor/simplejson/simplejson/tests/test_indent.py +86 -0
  47. data/vendor/simplejson/simplejson/tests/test_item_sort_key.py +20 -0
  48. data/vendor/simplejson/simplejson/tests/test_namedtuple.py +121 -0
  49. data/vendor/simplejson/simplejson/tests/test_pass1.py +76 -0
  50. data/vendor/simplejson/simplejson/tests/test_pass2.py +14 -0
  51. data/vendor/simplejson/simplejson/tests/test_pass3.py +20 -0
  52. data/vendor/simplejson/simplejson/tests/test_recursion.py +67 -0
  53. data/vendor/simplejson/simplejson/tests/test_scanstring.py +117 -0
  54. data/vendor/simplejson/simplejson/tests/test_separators.py +42 -0
  55. data/vendor/simplejson/simplejson/tests/test_speedups.py +20 -0
  56. data/vendor/simplejson/simplejson/tests/test_tuple.py +49 -0
  57. data/vendor/simplejson/simplejson/tests/test_unicode.py +109 -0
  58. data/vendor/simplejson/simplejson/tool.py +39 -0
  59. metadata +80 -22
  60. data/ext/extconf.rb +0 -14
  61. data/ext/pygments.c +0 -466
  62. data/lib/pygments/c.rb +0 -54
  63. data/lib/pygments/ffi.rb +0 -155
  64. data/vendor/.gitignore +0 -1
data/test/test_data.py ADDED
@@ -0,0 +1,514 @@
1
+ # -*- coding: utf-8 -
2
+ #
3
+ # This file is part of gunicorn released under the MIT license.
4
+ # See the NOTICE for more information.
5
+
6
+ from __future__ import with_statement
7
+
8
+ import errno
9
+ import os
10
+ import select
11
+ import signal
12
+ import sys
13
+ import time
14
+ import traceback
15
+
16
+
17
+ from gunicorn.errors import HaltServer
18
+ from gunicorn.pidfile import Pidfile
19
+ from gunicorn.sock import create_socket
20
+ from gunicorn import util
21
+
22
+ from gunicorn import __version__, SERVER_SOFTWARE
23
+
24
+ class Arbiter(object):
25
+ """
26
+ Arbiter maintain the workers processes alive. It launches or
27
+ kills them if needed. It also manages application reloading
28
+ via SIGHUP/USR2.
29
+ """
30
+
31
+ # A flag indicating if a worker failed to
32
+ # to boot. If a worker process exist with
33
+ # this error code, the arbiter will terminate.
34
+ WORKER_BOOT_ERROR = 3
35
+
36
+ START_CTX = {}
37
+
38
+ LISTENER = None
39
+ WORKERS = {}
40
+ PIPE = []
41
+
42
+ # I love dynamic languages
43
+ SIG_QUEUE = []
44
+ SIGNALS = map(
45
+ lambda x: getattr(signal, "SIG%s" % x),
46
+ "HUP QUIT INT TERM TTIN TTOU USR1 USR2 WINCH".split()
47
+ )
48
+ SIG_NAMES = dict(
49
+ (getattr(signal, name), name[3:].lower()) for name in dir(signal)
50
+ if name[:3] == "SIG" and name[3] != "_"
51
+ )
52
+
53
+ def __init__(self, app):
54
+ os.environ["SERVER_SOFTWARE"] = SERVER_SOFTWARE
55
+
56
+ self.setup(app)
57
+
58
+ self.pidfile = None
59
+ self.worker_age = 0
60
+ self.reexec_pid = 0
61
+ self.master_name = "Master"
62
+
63
+ # get current path, try to use PWD env first
64
+ try:
65
+ a = os.stat(os.environ['PWD'])
66
+ b = os.stat(os.getcwd())
67
+ if a.ino == b.ino and a.dev == b.dev:
68
+ cwd = os.environ['PWD']
69
+ else:
70
+ cwd = os.getcwd()
71
+ except:
72
+ cwd = os.getcwd()
73
+
74
+ args = sys.argv[:]
75
+ args.insert(0, sys.executable)
76
+
77
+ # init start context
78
+ self.START_CTX = {
79
+ "args": args,
80
+ "cwd": cwd,
81
+ 0: sys.executable
82
+ }
83
+
84
+ def setup(self, app):
85
+ self.app = app
86
+ self.cfg = app.cfg
87
+ self.log = self.cfg.logger_class(app.cfg)
88
+
89
+ # reopen files
90
+ if 'GUNICORN_FD' in os.environ:
91
+ self.log.reopen_files()
92
+
93
+ self.address = self.cfg.address
94
+ self.num_workers = self.cfg.workers
95
+ self.debug = self.cfg.debug
96
+ self.timeout = self.cfg.timeout
97
+ self.proc_name = self.cfg.proc_name
98
+ self.worker_class = self.cfg.worker_class
99
+
100
+ if self.cfg.debug:
101
+ self.log.debug("Current configuration:")
102
+ for config, value in sorted(self.cfg.settings.iteritems()):
103
+ self.log.debug(" %s: %s", config, value.value)
104
+
105
+ if self.cfg.preload_app:
106
+ if not self.cfg.debug:
107
+ self.app.wsgi()
108
+ else:
109
+ self.log.warning("debug mode: app isn't preloaded.")
110
+
111
+ def start(self):
112
+ """\
113
+ Initialize the arbiter. Start listening and set pidfile if needed.
114
+ """
115
+ self.log.info("Starting gunicorn %s", __version__)
116
+ self.cfg.on_starting(self)
117
+ self.pid = os.getpid()
118
+ self.init_signals()
119
+ if not self.LISTENER:
120
+ self.LISTENER = create_socket(self.cfg, self.log)
121
+
122
+ if self.cfg.pidfile is not None:
123
+ self.pidfile = Pidfile(self.cfg.pidfile)
124
+ self.pidfile.create(self.pid)
125
+ self.log.debug("Arbiter booted")
126
+ self.log.info("Listening at: %s (%s)", self.LISTENER,
127
+ self.pid)
128
+ self.log.info("Using worker: %s",
129
+ self.cfg.settings['worker_class'].get())
130
+
131
+ self.cfg.when_ready(self)
132
+
133
+ def init_signals(self):
134
+ """\
135
+ Initialize master signal handling. Most of the signals
136
+ are queued. Child signals only wake up the master.
137
+ """
138
+ if self.PIPE:
139
+ map(os.close, self.PIPE)
140
+ self.PIPE = pair = os.pipe()
141
+ map(util.set_non_blocking, pair)
142
+ map(util.close_on_exec, pair)
143
+ self.log.close_on_exec()
144
+ map(lambda s: signal.signal(s, self.signal), self.SIGNALS)
145
+ signal.signal(signal.SIGCHLD, self.handle_chld)
146
+
147
+ def signal(self, sig, frame):
148
+ if len(self.SIG_QUEUE) < 5:
149
+ self.SIG_QUEUE.append(sig)
150
+ self.wakeup()
151
+
152
+ def run(self):
153
+ "Main master loop."
154
+ self.start()
155
+ util._setproctitle("master [%s]" % self.proc_name)
156
+
157
+ self.manage_workers()
158
+ while True:
159
+ try:
160
+ self.reap_workers()
161
+ sig = self.SIG_QUEUE.pop(0) if len(self.SIG_QUEUE) else None
162
+ if sig is None:
163
+ self.sleep()
164
+ self.murder_workers()
165
+ self.manage_workers()
166
+ continue
167
+
168
+ if sig not in self.SIG_NAMES:
169
+ self.log.info("Ignoring unknown signal: %s", sig)
170
+ continue
171
+
172
+ signame = self.SIG_NAMES.get(sig)
173
+ handler = getattr(self, "handle_%s" % signame, None)
174
+ if not handler:
175
+ self.log.error("Unhandled signal: %s", signame)
176
+ continue
177
+ self.log.info("Handling signal: %s", signame)
178
+ handler()
179
+ self.wakeup()
180
+ except StopIteration:
181
+ self.halt()
182
+ except KeyboardInterrupt:
183
+ self.halt()
184
+ except HaltServer, inst:
185
+ self.halt(reason=inst.reason, exit_status=inst.exit_status)
186
+ except SystemExit:
187
+ raise
188
+ except Exception:
189
+ self.log.info("Unhandled exception in main loop:\n%s",
190
+ traceback.format_exc())
191
+ self.stop(False)
192
+ if self.pidfile is not None:
193
+ self.pidfile.unlink()
194
+ sys.exit(-1)
195
+
196
+ def handle_chld(self, sig, frame):
197
+ "SIGCHLD handling"
198
+ self.wakeup()
199
+
200
+ def handle_hup(self):
201
+ """\
202
+ HUP handling.
203
+ - Reload configuration
204
+ - Start the new worker processes with a new configuration
205
+ - Gracefully shutdown the old worker processes
206
+ """
207
+ self.log.info("Hang up: %s", self.master_name)
208
+ self.reload()
209
+
210
+ def handle_quit(self):
211
+ "SIGQUIT handling"
212
+ raise StopIteration
213
+
214
+ def handle_int(self):
215
+ "SIGINT handling"
216
+ self.stop(False)
217
+ raise StopIteration
218
+
219
+ def handle_term(self):
220
+ "SIGTERM handling"
221
+ self.stop(False)
222
+ raise StopIteration
223
+
224
+ def handle_ttin(self):
225
+ """\
226
+ SIGTTIN handling.
227
+ Increases the number of workers by one.
228
+ """
229
+ self.num_workers += 1
230
+ self.manage_workers()
231
+
232
+ def handle_ttou(self):
233
+ """\
234
+ SIGTTOU handling.
235
+ Decreases the number of workers by one.
236
+ """
237
+ if self.num_workers <= 1:
238
+ return
239
+ self.num_workers -= 1
240
+ self.manage_workers()
241
+
242
+ def handle_usr1(self):
243
+ """\
244
+ SIGUSR1 handling.
245
+ Kill all workers by sending them a SIGUSR1
246
+ """
247
+ self.kill_workers(signal.SIGUSR1)
248
+ self.log.reopen_files()
249
+
250
+ def handle_usr2(self):
251
+ """\
252
+ SIGUSR2 handling.
253
+ Creates a new master/worker set as a slave of the current
254
+ master without affecting old workers. Use this to do live
255
+ deployment with the ability to backout a change.
256
+ """
257
+ self.reexec()
258
+
259
+ def handle_winch(self):
260
+ "SIGWINCH handling"
261
+ if os.getppid() == 1 or os.getpgrp() != os.getpid():
262
+ self.log.info("graceful stop of workers")
263
+ self.num_workers = 0
264
+ self.kill_workers(signal.SIGQUIT)
265
+ else:
266
+ self.log.info("SIGWINCH ignored. Not daemonized")
267
+
268
+ def wakeup(self):
269
+ """\
270
+ Wake up the arbiter by writing to the PIPE
271
+ """
272
+ try:
273
+ os.write(self.PIPE[1], '.')
274
+ except IOError, e:
275
+ if e.errno not in [errno.EAGAIN, errno.EINTR]:
276
+ raise
277
+
278
+ def halt(self, reason=None, exit_status=0):
279
+ """ halt arbiter """
280
+ self.stop()
281
+ self.log.info("Shutting down: %s", self.master_name)
282
+ if reason is not None:
283
+ self.log.info("Reason: %s", reason)
284
+ if self.pidfile is not None:
285
+ self.pidfile.unlink()
286
+ sys.exit(exit_status)
287
+
288
+ def sleep(self):
289
+ """\
290
+ Sleep until PIPE is readable or we timeout.
291
+ A readable PIPE means a signal occurred.
292
+ """
293
+ try:
294
+ ready = select.select([self.PIPE[0]], [], [], 1.0)
295
+ if not ready[0]:
296
+ return
297
+ while os.read(self.PIPE[0], 1):
298
+ pass
299
+ except select.error, e:
300
+ if e[0] not in [errno.EAGAIN, errno.EINTR]:
301
+ raise
302
+ except OSError, e:
303
+ if e.errno not in [errno.EAGAIN, errno.EINTR]:
304
+ raise
305
+ except KeyboardInterrupt:
306
+ sys.exit()
307
+
308
+
309
+ def stop(self, graceful=True):
310
+ """\
311
+ Stop workers
312
+
313
+ :attr graceful: boolean, If True (the default) workers will be
314
+ killed gracefully (ie. trying to wait for the current connection)
315
+ """
316
+ try:
317
+ self.LISTENER.close()
318
+ except Exception:
319
+ pass
320
+ self.LISTENER = None
321
+ sig = signal.SIGQUIT
322
+ if not graceful:
323
+ sig = signal.SIGTERM
324
+ limit = time.time() + self.cfg.graceful_timeout
325
+ while self.WORKERS and time.time() < limit:
326
+ self.kill_workers(sig)
327
+ time.sleep(0.1)
328
+ self.reap_workers()
329
+ self.kill_workers(signal.SIGKILL)
330
+
331
+ def reexec(self):
332
+ """\
333
+ Relaunch the master and workers.
334
+ """
335
+ if self.pidfile is not None:
336
+ self.pidfile.rename("%s.oldbin" % self.pidfile.fname)
337
+
338
+ self.reexec_pid = os.fork()
339
+ if self.reexec_pid != 0:
340
+ self.master_name = "Old Master"
341
+ return
342
+
343
+ os.environ['GUNICORN_FD'] = str(self.LISTENER.fileno())
344
+ os.chdir(self.START_CTX['cwd'])
345
+ self.cfg.pre_exec(self)
346
+ util.closerange(3, self.LISTENER.fileno())
347
+ util.closerange(self.LISTENER.fileno()+1, util.get_maxfd())
348
+ os.execvpe(self.START_CTX[0], self.START_CTX['args'], os.environ)
349
+
350
+ def reload(self):
351
+ old_address = self.cfg.address
352
+
353
+ # reload conf
354
+ self.app.reload()
355
+ self.setup(self.app)
356
+
357
+ # reopen log files
358
+ self.log.reopen_files()
359
+
360
+ # do we need to change listener ?
361
+ if old_address != self.cfg.address:
362
+ self.LISTENER.close()
363
+ self.LISTENER = create_socket(self.cfg, self.log)
364
+ self.log.info("Listening at: %s", self.LISTENER)
365
+
366
+ # do some actions on reload
367
+ self.cfg.on_reload(self)
368
+
369
+ # unlink pidfile
370
+ if self.pidfile is not None:
371
+ self.pidfile.unlink()
372
+
373
+ # create new pidfile
374
+ if self.cfg.pidfile is not None:
375
+ self.pidfile = Pidfile(self.cfg.pidfile)
376
+ self.pidfile.create(self.pid)
377
+
378
+ # set new proc_name
379
+ util._setproctitle("master [%s]" % self.proc_name)
380
+
381
+ # spawn new workers
382
+ for i in range(self.cfg.workers):
383
+ self.spawn_worker()
384
+
385
+ # manage workers
386
+ self.manage_workers()
387
+
388
+ def murder_workers(self):
389
+ """\
390
+ Kill unused/idle workers
391
+ """
392
+ for (pid, worker) in self.WORKERS.items():
393
+ try:
394
+ if time.time() - worker.tmp.last_update() <= self.timeout:
395
+ continue
396
+ except ValueError:
397
+ continue
398
+
399
+ self.log.critical("WORKER TIMEOUT (pid:%s)", pid)
400
+ self.kill_worker(pid, signal.SIGKILL)
401
+
402
+ def reap_workers(self):
403
+ """\
404
+ Reap workers to avoid zombie processes
405
+ """
406
+ try:
407
+ while True:
408
+ wpid, status = os.waitpid(-1, os.WNOHANG)
409
+ if not wpid:
410
+ break
411
+ if self.reexec_pid == wpid:
412
+ self.reexec_pid = 0
413
+ else:
414
+ # A worker said it cannot boot. We'll shutdown
415
+ # to avoid infinite start/stop cycles.
416
+ exitcode = status >> 8
417
+ if exitcode == self.WORKER_BOOT_ERROR:
418
+ reason = "Worker failed to boot."
419
+ raise HaltServer(reason, self.WORKER_BOOT_ERROR)
420
+ worker = self.WORKERS.pop(wpid, None)
421
+ if not worker:
422
+ continue
423
+ worker.tmp.close()
424
+ except OSError, e:
425
+ if e.errno == errno.ECHILD:
426
+ pass
427
+
428
+ def manage_workers(self):
429
+ """\
430
+ Maintain the number of workers by spawning or killing
431
+ as required.
432
+ """
433
+ if len(self.WORKERS.keys()) < self.num_workers:
434
+ self.spawn_workers()
435
+
436
+ workers = self.WORKERS.items()
437
+ workers.sort(key=lambda w: w[1].age)
438
+ while len(workers) > self.num_workers:
439
+ (pid, _) = workers.pop(0)
440
+ self.kill_worker(pid, signal.SIGQUIT)
441
+
442
+ def spawn_worker(self):
443
+ self.worker_age += 1
444
+ worker = self.worker_class(self.worker_age, self.pid, self.LISTENER,
445
+ self.app, self.timeout/2.0,
446
+ self.cfg, self.log)
447
+ self.cfg.pre_fork(self, worker)
448
+ pid = os.fork()
449
+ if pid != 0:
450
+ self.WORKERS[pid] = worker
451
+ return pid
452
+
453
+ # Process Child
454
+ worker_pid = os.getpid()
455
+ try:
456
+ util._setproctitle("worker [%s]" % self.proc_name)
457
+ self.log.info("Booting worker with pid: %s", worker_pid)
458
+ self.cfg.post_fork(self, worker)
459
+ worker.init_process()
460
+ sys.exit(0)
461
+ except SystemExit:
462
+ raise
463
+ except:
464
+ self.log.debug("Exception in worker process:\n%s",
465
+ traceback.format_exc())
466
+ if not worker.booted:
467
+ sys.exit(self.WORKER_BOOT_ERROR)
468
+ sys.exit(-1)
469
+ finally:
470
+ self.log.info("Worker exiting (pid: %s)", worker_pid)
471
+ try:
472
+ worker.tmp.close()
473
+ self.cfg.worker_exit(self, worker)
474
+ except:
475
+ pass
476
+
477
+ def spawn_workers(self):
478
+ """\
479
+ Spawn new workers as needed.
480
+
481
+ This is where a worker process leaves the main loop
482
+ of the master process.
483
+ """
484
+
485
+ for i in range(self.num_workers - len(self.WORKERS.keys())):
486
+ self.spawn_worker()
487
+
488
+ def kill_workers(self, sig):
489
+ """\
490
+ Kill all workers with the signal `sig`
491
+ :attr sig: `signal.SIG*` value
492
+ """
493
+ for pid in self.WORKERS.keys():
494
+ self.kill_worker(pid, sig)
495
+
496
+ def kill_worker(self, pid, sig):
497
+ """\
498
+ Kill a worker
499
+
500
+ :attr pid: int, worker pid
501
+ :attr sig: `signal.SIG*` value
502
+ """
503
+ try:
504
+ os.kill(pid, sig)
505
+ except OSError, e:
506
+ if e.errno == errno.ESRCH:
507
+ try:
508
+ worker = self.WORKERS.pop(pid)
509
+ worker.tmp.close()
510
+ self.cfg.worker_exit(self, worker)
511
+ return
512
+ except (KeyError, OSError):
513
+ return
514
+ raise