From fb1234375c142c49d28ddbf1fdac5ee9a0f444bc Mon Sep 17 00:00:00 2001 From: "maruel@google.com" Date: Tue, 21 Oct 2008 23:00:58 +0000 Subject: Move the buildbot code to trunk/tools/buildbot so it is not included in a default source checkout. git-svn-id: svn://svn.chromium.org/chrome/trunk/src@3698 0039d316-1c4b-4281-b951-d872f2087c98 --- tools/buildbot/config/master.chromium/DEPS | 7 - tools/buildbot/config/master.chromium/Makefile | 21 - .../buildbot/config/master.chromium/Makefile.win32 | 21 - tools/buildbot/config/master.chromium/README | 8 - tools/buildbot/config/master.chromium/buildbot | 4 - tools/buildbot/config/master.chromium/buildbot.tac | 13 - tools/buildbot/config/master.chromium/master.cfg | 814 --- .../master.chromium/public_html/announce.html | 80 - .../master.chromium/public_html/buildbot.css | 183 - .../master.chromium/public_html/chromium-32.png | Bin 2750 -> 0 bytes .../config/master.chromium/public_html/favicon.ico | Bin 2478 -> 0 bytes .../config/master.chromium/public_html/index.html | 15 - .../public_html/status-summary.html | 0 .../buildbot/config/master.chromium/run_master.bat | 6 - tools/buildbot/config/master.tryserver/DEPS | 7 - tools/buildbot/config/master.tryserver/Makefile | 21 - .../config/master.tryserver/Makefile.win32 | 21 - tools/buildbot/config/master.tryserver/README | 8 - tools/buildbot/config/master.tryserver/buildbot | 4 - .../buildbot/config/master.tryserver/buildbot.tac | 11 - .../config/master.tryserver/mail_notifier.py | 127 - tools/buildbot/config/master.tryserver/master.cfg | 369 -- .../master.tryserver/public_html/announce.html | 4 - .../master.tryserver/public_html/buildbot.css | 183 - .../master.tryserver/public_html/chromium-32.png | Bin 2750 -> 0 bytes .../master.tryserver/public_html/favicon.ico | Bin 2478 -> 0 bytes .../config/master.tryserver/public_html/index.html | 9 - .../public_html/status-summary.html | 0 .../config/master.tryserver/run_master.bat | 6 - tools/buildbot/config/master.tryserver/try_job.py | 195 - .../master.tryserver/unittests/master_test.py | 69 - .../master.tryserver/unittests/try_job_test.py | 123 - tools/buildbot/config/slave/DEPS | 7 - tools/buildbot/config/slave/Makefile | 47 - tools/buildbot/config/slave/buildbot.tac | 45 - .../config/slave/cert/ssl_ui_test_root_ca.crt | 35 - tools/buildbot/config/slave/crontab.in | 18 - tools/buildbot/config/slave/info/admin | 1 - tools/buildbot/config/slave/info/host | 1 - tools/buildbot/config/slave/run_slave.bat | 5 - tools/buildbot/config/slave/run_slave.py | 98 - tools/buildbot/perf/dashboard/README.txt | 14 - tools/buildbot/perf/dashboard/changelog.html | 204 - tools/buildbot/perf/dashboard/details.html | 125 - tools/buildbot/perf/dashboard/js/common.js | 36 - tools/buildbot/perf/dashboard/js/plotter.js | 425 -- tools/buildbot/perf/dashboard/overview.html | 84 - tools/buildbot/perf/dashboard/report.html | 298 -- tools/buildbot/perf/dashboard/svn-log | 22 - tools/buildbot/perf/dashboard/ui/README.txt | 15 - tools/buildbot/perf/dashboard/ui/config.js | 16 - tools/buildbot/perf/dashboard/ui/details.html | 125 - .../perf/dashboard/ui/generic_plotter.html | 361 -- tools/buildbot/perf/dashboard/ui/js/common.js | 70 - tools/buildbot/perf/dashboard/ui/js/coordinates.js | 116 - tools/buildbot/perf/dashboard/ui/js/plotter.js | 316 -- .../perf/dashboard/ui/pagecycler_report.html | 260 - .../perf/dashboard/ui/playback_report.html | 341 -- .../perf/dashboard/ui/sunspider_report.html | 279 - tools/buildbot/perf/generate_perf.sh | 76 - tools/buildbot/perf/index.html | 9 - tools/buildbot/pylibs/buildbot/COPYING | 339 -- tools/buildbot/pylibs/buildbot/CREDITS | 74 - tools/buildbot/pylibs/buildbot/README.google | 9 - tools/buildbot/pylibs/buildbot/__init__.py | 2 - tools/buildbot/pylibs/buildbot/buildbot.png | Bin 783 -> 0 bytes tools/buildbot/pylibs/buildbot/buildset.py | 81 - tools/buildbot/pylibs/buildbot/buildslave.py | 350 -- tools/buildbot/pylibs/buildbot/changes/__init__.py | 0 tools/buildbot/pylibs/buildbot/changes/base.py | 10 - .../pylibs/buildbot/changes/bonsaipoller.py | 320 -- tools/buildbot/pylibs/buildbot/changes/changes.py | 277 - tools/buildbot/pylibs/buildbot/changes/dnotify.py | 100 - tools/buildbot/pylibs/buildbot/changes/freshcvs.py | 144 - .../buildbot/pylibs/buildbot/changes/hgbuildbot.py | 107 - tools/buildbot/pylibs/buildbot/changes/mail.py | 458 -- tools/buildbot/pylibs/buildbot/changes/maildir.py | 116 - tools/buildbot/pylibs/buildbot/changes/monotone.py | 305 -- tools/buildbot/pylibs/buildbot/changes/p4poller.py | 207 - tools/buildbot/pylibs/buildbot/changes/pb.py | 108 - .../buildbot/pylibs/buildbot/changes/svnpoller.py | 460 -- tools/buildbot/pylibs/buildbot/clients/__init__.py | 0 tools/buildbot/pylibs/buildbot/clients/base.py | 125 - tools/buildbot/pylibs/buildbot/clients/debug.glade | 684 --- tools/buildbot/pylibs/buildbot/clients/debug.py | 181 - tools/buildbot/pylibs/buildbot/clients/gtkPanes.py | 523 -- .../buildbot/pylibs/buildbot/clients/sendchange.py | 48 - tools/buildbot/pylibs/buildbot/dnotify.py | 102 - tools/buildbot/pylibs/buildbot/interfaces.py | 1070 ---- tools/buildbot/pylibs/buildbot/locks.py | 146 - tools/buildbot/pylibs/buildbot/manhole.py | 265 - tools/buildbot/pylibs/buildbot/master.py | 911 ---- tools/buildbot/pylibs/buildbot/pbutil.py | 147 - tools/buildbot/pylibs/buildbot/process/__init__.py | 0 tools/buildbot/pylibs/buildbot/process/base.py | 596 --- tools/buildbot/pylibs/buildbot/process/builder.py | 745 --- .../buildbot/pylibs/buildbot/process/buildstep.py | 1098 ---- tools/buildbot/pylibs/buildbot/process/factory.py | 180 - .../pylibs/buildbot/process/process_twisted.py | 118 - .../buildbot/pylibs/buildbot/process/properties.py | 157 - .../pylibs/buildbot/process/step_twisted2.py | 161 - tools/buildbot/pylibs/buildbot/scheduler.py | 748 --- tools/buildbot/pylibs/buildbot/scripts/__init__.py | 0 .../pylibs/buildbot/scripts/checkconfig.py | 52 - .../buildbot/pylibs/buildbot/scripts/logwatcher.py | 97 - tools/buildbot/pylibs/buildbot/scripts/reconfig.py | 69 - tools/buildbot/pylibs/buildbot/scripts/runner.py | 962 ---- tools/buildbot/pylibs/buildbot/scripts/sample.cfg | 175 - tools/buildbot/pylibs/buildbot/scripts/startup.py | 128 - .../buildbot/pylibs/buildbot/scripts/tryclient.py | 658 --- tools/buildbot/pylibs/buildbot/slave/__init__.py | 0 tools/buildbot/pylibs/buildbot/slave/bot.py | 504 -- tools/buildbot/pylibs/buildbot/slave/bot_orig.py | 503 -- tools/buildbot/pylibs/buildbot/slave/commands.py | 2508 --------- tools/buildbot/pylibs/buildbot/slave/interfaces.py | 56 - tools/buildbot/pylibs/buildbot/slave/registry.py | 17 - tools/buildbot/pylibs/buildbot/sourcestamp.py | 95 - tools/buildbot/pylibs/buildbot/status/__init__.py | 0 tools/buildbot/pylibs/buildbot/status/base.py | 60 - tools/buildbot/pylibs/buildbot/status/builder.py | 2074 -------- tools/buildbot/pylibs/buildbot/status/client.py | 568 -- tools/buildbot/pylibs/buildbot/status/html.py | 6 - tools/buildbot/pylibs/buildbot/status/mail.py | 361 -- tools/buildbot/pylibs/buildbot/status/progress.py | 308 -- tools/buildbot/pylibs/buildbot/status/tests.py | 73 - tools/buildbot/pylibs/buildbot/status/tinderbox.py | 223 - .../pylibs/buildbot/status/web/__init__.py | 0 tools/buildbot/pylibs/buildbot/status/web/about.py | 33 - tools/buildbot/pylibs/buildbot/status/web/base.py | 395 -- .../buildbot/pylibs/buildbot/status/web/baseweb.py | 576 -- tools/buildbot/pylibs/buildbot/status/web/build.py | 289 -- .../buildbot/pylibs/buildbot/status/web/builder.py | 358 -- .../buildbot/pylibs/buildbot/status/web/changes.py | 41 - .../pylibs/buildbot/status/web/classic.css | 78 - tools/buildbot/pylibs/buildbot/status/web/grid.py | 263 - .../buildbot/pylibs/buildbot/status/web/index.html | 32 - tools/buildbot/pylibs/buildbot/status/web/logs.py | 168 - .../buildbot/pylibs/buildbot/status/web/robots.txt | 9 - .../buildbot/pylibs/buildbot/status/web/slaves.py | 71 - tools/buildbot/pylibs/buildbot/status/web/step.py | 85 - tools/buildbot/pylibs/buildbot/status/web/tests.py | 64 - .../pylibs/buildbot/status/web/waterfall.py | 981 ---- .../buildbot/pylibs/buildbot/status/web/xmlrpc.py | 193 - tools/buildbot/pylibs/buildbot/status/words.py | 861 --- tools/buildbot/pylibs/buildbot/steps/__init__.py | 0 tools/buildbot/pylibs/buildbot/steps/dummy.py | 103 - tools/buildbot/pylibs/buildbot/steps/maxq.py | 46 - tools/buildbot/pylibs/buildbot/steps/python.py | 112 - .../pylibs/buildbot/steps/python_twisted.py | 820 --- tools/buildbot/pylibs/buildbot/steps/shell.py | 444 -- tools/buildbot/pylibs/buildbot/steps/source.py | 1074 ---- tools/buildbot/pylibs/buildbot/steps/transfer.py | 295 -- tools/buildbot/pylibs/buildbot/steps/trigger.py | 127 - tools/buildbot/pylibs/buildbot/test/__init__.py | 0 tools/buildbot/pylibs/buildbot/test/emit.py | 11 - tools/buildbot/pylibs/buildbot/test/emitlogs.py | 42 - .../buildbot/pylibs/buildbot/test/mail/freshcvs.1 | 68 - .../buildbot/pylibs/buildbot/test/mail/freshcvs.2 | 101 - .../buildbot/pylibs/buildbot/test/mail/freshcvs.3 | 97 - .../buildbot/pylibs/buildbot/test/mail/freshcvs.4 | 45 - .../buildbot/pylibs/buildbot/test/mail/freshcvs.5 | 54 - .../buildbot/pylibs/buildbot/test/mail/freshcvs.6 | 70 - .../buildbot/pylibs/buildbot/test/mail/freshcvs.7 | 68 - .../buildbot/pylibs/buildbot/test/mail/freshcvs.8 | 61 - .../buildbot/pylibs/buildbot/test/mail/freshcvs.9 | 18 - .../pylibs/buildbot/test/mail/svn-commit.1 | 67 - .../pylibs/buildbot/test/mail/svn-commit.2 | 1218 ----- .../buildbot/pylibs/buildbot/test/mail/syncmail.1 | 152 - .../buildbot/pylibs/buildbot/test/mail/syncmail.2 | 56 - .../buildbot/pylibs/buildbot/test/mail/syncmail.3 | 39 - .../buildbot/pylibs/buildbot/test/mail/syncmail.4 | 290 -- .../buildbot/pylibs/buildbot/test/mail/syncmail.5 | 70 - tools/buildbot/pylibs/buildbot/test/runutils.py | 514 -- tools/buildbot/pylibs/buildbot/test/sleep.py | 8 - tools/buildbot/pylibs/buildbot/test/subdir/emit.py | 11 - .../pylibs/buildbot/test/test__versions.py | 16 - .../pylibs/buildbot/test/test_bonsaipoller.py | 244 - .../buildbot/pylibs/buildbot/test/test_buildreq.py | 181 - .../pylibs/buildbot/test/test_buildstep.py | 134 - .../buildbot/pylibs/buildbot/test/test_changes.py | 228 - tools/buildbot/pylibs/buildbot/test/test_config.py | 1276 ----- .../buildbot/pylibs/buildbot/test/test_control.py | 104 - .../pylibs/buildbot/test/test_dependencies.py | 166 - tools/buildbot/pylibs/buildbot/test/test_locks.py | 425 -- .../buildbot/pylibs/buildbot/test/test_maildir.py | 92 - .../pylibs/buildbot/test/test_mailparse.py | 293 -- .../buildbot/pylibs/buildbot/test/test_p4poller.py | 213 - .../pylibs/buildbot/test/test_properties.py | 273 - tools/buildbot/pylibs/buildbot/test/test_run.py | 845 --- tools/buildbot/pylibs/buildbot/test/test_runner.py | 392 -- .../pylibs/buildbot/test/test_scheduler.py | 313 -- tools/buildbot/pylibs/buildbot/test/test_shell.py | 138 - .../pylibs/buildbot/test/test_slavecommand.py | 289 -- tools/buildbot/pylibs/buildbot/test/test_slaves.py | 623 --- tools/buildbot/pylibs/buildbot/test/test_status.py | 1230 ----- tools/buildbot/pylibs/buildbot/test/test_steps.py | 678 --- .../pylibs/buildbot/test/test_svnpoller.py | 476 -- .../buildbot/pylibs/buildbot/test/test_transfer.py | 368 -- .../buildbot/pylibs/buildbot/test/test_twisted.py | 219 - tools/buildbot/pylibs/buildbot/test/test_util.py | 26 - tools/buildbot/pylibs/buildbot/test/test_vc.py | 2796 ---------- tools/buildbot/pylibs/buildbot/test/test_web.py | 535 -- .../buildbot/pylibs/buildbot/test/test_webparts.py | 141 - tools/buildbot/pylibs/buildbot/util.py | 70 - tools/buildbot/pylibs/pytz/EGG-INFO/PKG-INFO | 52 - tools/buildbot/pylibs/pytz/EGG-INFO/SOURCES.txt | 581 --- .../pylibs/pytz/EGG-INFO/dependency_links.txt | 1 - tools/buildbot/pylibs/pytz/EGG-INFO/top_level.txt | 1 - tools/buildbot/pylibs/pytz/EGG-INFO/zip-safe | 1 - tools/buildbot/pylibs/pytz/README.google | 4 - tools/buildbot/pylibs/pytz/__init__.py | 1400 ----- tools/buildbot/pylibs/pytz/reference.py | 127 - tools/buildbot/pylibs/pytz/tzfile.py | 113 - tools/buildbot/pylibs/pytz/tzinfo.py | 382 -- tools/buildbot/pylibs/pytz/zoneinfo/Africa/Abidjan | Bin 156 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Africa/Accra | Bin 378 -> 0 bytes .../pylibs/pytz/zoneinfo/Africa/Addis_Ababa | Bin 180 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Africa/Algiers | Bin 734 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Africa/Asmara | Bin 201 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Africa/Asmera | Bin 201 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Africa/Bamako | Bin 208 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Africa/Bangui | Bin 157 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Africa/Banjul | Bin 232 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Africa/Bissau | Bin 194 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Africa/Blantyre | Bin 157 -> 0 bytes .../pylibs/pytz/zoneinfo/Africa/Brazzaville | Bin 157 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Africa/Bujumbura | Bin 140 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Africa/Cairo | Bin 9307 -> 0 bytes .../pylibs/pytz/zoneinfo/Africa/Casablanca | Bin 458 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Africa/Ceuta | Bin 2049 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Africa/Conakry | Bin 208 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Africa/Dakar | Bin 194 -> 0 bytes .../pylibs/pytz/zoneinfo/Africa/Dar_es_Salaam | Bin 213 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Africa/Djibouti | Bin 157 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Africa/Douala | Bin 157 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Africa/El_Aaiun | Bin 194 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Africa/Freetown | Bin 665 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Africa/Gaborone | Bin 194 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Africa/Harare | Bin 157 -> 0 bytes .../pylibs/pytz/zoneinfo/Africa/Johannesburg | Bin 245 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Africa/Kampala | Bin 253 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Africa/Khartoum | Bin 669 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Africa/Kigali | Bin 157 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Africa/Kinshasa | Bin 140 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Africa/Lagos | Bin 157 -> 0 bytes .../pylibs/pytz/zoneinfo/Africa/Libreville | Bin 157 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Africa/Lome | Bin 139 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Africa/Luanda | Bin 178 -> 0 bytes .../pylibs/pytz/zoneinfo/Africa/Lubumbashi | Bin 140 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Africa/Lusaka | Bin 157 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Africa/Malabo | Bin 195 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Africa/Maputo | Bin 157 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Africa/Maseru | Bin 204 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Africa/Mbabane | Bin 160 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Africa/Mogadishu | Bin 194 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Africa/Monrovia | Bin 215 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Africa/Nairobi | Bin 253 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Africa/Ndjamena | Bin 211 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Africa/Niamey | Bin 225 -> 0 bytes .../pylibs/pytz/zoneinfo/Africa/Nouakchott | Bin 208 -> 0 bytes .../pylibs/pytz/zoneinfo/Africa/Ouagadougou | Bin 156 -> 0 bytes .../pylibs/pytz/zoneinfo/Africa/Porto-Novo | Bin 195 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Africa/Sao_Tome | Bin 173 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Africa/Timbuktu | Bin 208 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Africa/Tripoli | Bin 599 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Africa/Tunis | Bin 1517 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Africa/Windhoek | Bin 1556 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/America/Adak | Bin 2353 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Anchorage | Bin 2358 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Anguilla | Bin 156 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Antigua | Bin 194 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Araguaina | Bin 854 -> 0 bytes .../pytz/zoneinfo/America/Argentina/Buenos_Aires | Bin 1882 -> 0 bytes .../pytz/zoneinfo/America/Argentina/Catamarca | Bin 1936 -> 0 bytes .../pytz/zoneinfo/America/Argentina/ComodRivadavia | Bin 1936 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Argentina/Cordoba | Bin 1908 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Argentina/Jujuy | Bin 1936 -> 0 bytes .../pytz/zoneinfo/America/Argentina/La_Rioja | Bin 1950 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Argentina/Mendoza | Bin 1964 -> 0 bytes .../pytz/zoneinfo/America/Argentina/Rio_Gallegos | Bin 1936 -> 0 bytes .../pytz/zoneinfo/America/Argentina/San_Juan | Bin 1950 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Argentina/Tucuman | Bin 1936 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Argentina/Ushuaia | Bin 1936 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/America/Aruba | Bin 194 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Asuncion | Bin 2020 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Atikokan | Bin 319 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/America/Atka | Bin 2353 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/America/Bahia | Bin 994 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Barbados | Bin 330 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/America/Belem | Bin 574 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/America/Belize | Bin 962 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Blanc-Sablon | Bin 281 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Boa_Vista | Bin 630 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/America/Bogota | Bin 231 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/America/Boise | Bin 2377 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Buenos_Aires | Bin 1882 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Cambridge_Bay | Bin 2052 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Campo_Grande | Bin 1983 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/America/Cancun | Bin 1450 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Caracas | Bin 224 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Catamarca | Bin 1936 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Cayenne | Bin 186 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/America/Cayman | Bin 177 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Chicago | Bin 3543 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Chihuahua | Bin 1492 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Coral_Harbour | Bin 319 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Cordoba | Bin 1908 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Costa_Rica | Bin 315 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/America/Cuiaba | Bin 1955 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Curacao | Bin 194 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Danmarkshavn | Bin 700 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/America/Dawson | Bin 2067 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Dawson_Creek | Bin 1033 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/America/Denver | Bin 2427 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Detroit | Bin 2202 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Dominica | Bin 156 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Edmonton | Bin 2388 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Eirunepe | Bin 602 -> 0 bytes .../pylibs/pytz/zoneinfo/America/El_Salvador | Bin 236 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Ensenada | Bin 2342 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Fort_Wayne | Bin 1649 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Fortaleza | Bin 714 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Glace_Bay | Bin 2192 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Godthab | Bin 8296 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Goose_Bay | Bin 3187 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Grand_Turk | Bin 1871 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Grenada | Bin 156 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Guadeloupe | Bin 156 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Guatemala | Bin 292 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Guayaquil | Bin 177 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/America/Guyana | Bin 256 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Halifax | Bin 3424 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/America/Havana | Bin 2411 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Hermosillo | Bin 424 -> 0 bytes .../pytz/zoneinfo/America/Indiana/Indianapolis | Bin 1649 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Indiana/Knox | Bin 2395 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Indiana/Marengo | Bin 1705 -> 0 bytes .../pytz/zoneinfo/America/Indiana/Petersburg | Bin 1887 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Indiana/Tell_City | Bin 1677 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Indiana/Vevay | Bin 1397 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Indiana/Vincennes | Bin 1677 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Indiana/Winamac | Bin 1761 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Indianapolis | Bin 1649 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/America/Inuvik | Bin 1914 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Iqaluit | Bin 2000 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Jamaica | Bin 481 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/America/Jujuy | Bin 1936 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/America/Juneau | Bin 2324 -> 0 bytes .../pytz/zoneinfo/America/Kentucky/Louisville | Bin 2755 -> 0 bytes .../pytz/zoneinfo/America/Kentucky/Monticello | Bin 2335 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Knox_IN | Bin 2395 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/America/La_Paz | Bin 217 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/America/Lima | Bin 395 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Los_Angeles | Bin 2819 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Louisville | Bin 2755 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/America/Maceio | Bin 742 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Managua | Bin 421 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/America/Manaus | Bin 602 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Marigot | Bin 156 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Martinique | Bin 231 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Mazatlan | Bin 1534 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Mendoza | Bin 1964 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Menominee | Bin 2241 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/America/Merida | Bin 1426 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Mexico_City | Bin 1604 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Miquelon | Bin 1670 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Moncton | Bin 3137 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Monterrey | Bin 1402 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Montevideo | Bin 2118 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Montreal | Bin 3477 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Montserrat | Bin 156 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/America/Nassau | Bin 2270 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/New_York | Bin 3519 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Nipigon | Bin 2105 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/America/Nome | Bin 2350 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Noronha | Bin 714 -> 0 bytes .../pytz/zoneinfo/America/North_Dakota/Center | Bin 2363 -> 0 bytes .../pytz/zoneinfo/America/North_Dakota/New_Salem | Bin 2363 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/America/Panama | Bin 177 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Pangnirtung | Bin 2062 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Paramaribo | Bin 294 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Phoenix | Bin 327 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Port-au-Prince | Bin 711 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Port_of_Spain | Bin 156 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Porto_Acre | Bin 574 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Porto_Velho | Bin 574 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Puerto_Rico | Bin 229 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Rainy_River | Bin 2105 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Rankin_Inlet | Bin 1900 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/America/Recife | Bin 714 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/America/Regina | Bin 980 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Resolute | Bin 1014 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Rio_Branco | Bin 574 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Rosario | Bin 1908 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Santiago | Bin 9011 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Santo_Domingo | Bin 463 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Sao_Paulo | Bin 1983 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Scoresbysund | Bin 1911 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Shiprock | Bin 2427 -> 0 bytes .../pylibs/pytz/zoneinfo/America/St_Barthelemy | Bin 156 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/St_Johns | Bin 3632 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/St_Kitts | Bin 156 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/St_Lucia | Bin 177 -> 0 bytes .../pylibs/pytz/zoneinfo/America/St_Thomas | Bin 156 -> 0 bytes .../pylibs/pytz/zoneinfo/America/St_Vincent | Bin 177 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Swift_Current | Bin 560 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Tegucigalpa | Bin 264 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/America/Thule | Bin 1514 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Thunder_Bay | Bin 2185 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Tijuana | Bin 2342 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Toronto | Bin 3477 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Tortola | Bin 156 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Vancouver | Bin 2875 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/America/Virgin | Bin 156 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Whitehorse | Bin 2067 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Winnipeg | Bin 2865 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/America/Yakutat | Bin 2288 -> 0 bytes .../pylibs/pytz/zoneinfo/America/Yellowknife | Bin 1966 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Antarctica/Casey | Bin 157 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Antarctica/Davis | Bin 188 -> 0 bytes .../pylibs/pytz/zoneinfo/Antarctica/DumontDUrville | Bin 213 -> 0 bytes .../pylibs/pytz/zoneinfo/Antarctica/Mawson | Bin 160 -> 0 bytes .../pylibs/pytz/zoneinfo/Antarctica/McMurdo | Bin 2001 -> 0 bytes .../pylibs/pytz/zoneinfo/Antarctica/Palmer | Bin 8546 -> 0 bytes .../pylibs/pytz/zoneinfo/Antarctica/Rothera | Bin 159 -> 0 bytes .../pylibs/pytz/zoneinfo/Antarctica/South_Pole | Bin 2001 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Antarctica/Syowa | Bin 160 -> 0 bytes .../pylibs/pytz/zoneinfo/Antarctica/Vostok | Bin 160 -> 0 bytes .../pylibs/pytz/zoneinfo/Arctic/Longyearbyen | Bin 2225 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Aden | Bin 157 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Almaty | Bin 922 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Amman | Bin 1890 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Anadyr | Bin 1931 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Aqtau | Bin 1112 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Aqtobe | Bin 1038 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Ashgabat | Bin 657 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Ashkhabad | Bin 657 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Baghdad | Bin 1818 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Bahrain | Bin 195 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Baku | Bin 1942 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Bangkok | Bin 178 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Beirut | Bin 2149 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Bishkek | Bin 1047 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Brunei | Bin 187 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Calcutta | Bin 265 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Asia/Choibalsan | Bin 860 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Chongqing | Bin 389 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Chungking | Bin 389 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Colombo | Bin 347 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Dacca | Bin 310 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Damascus | Bin 2306 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Dhaka | Bin 310 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Dili | Bin 277 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Dubai | Bin 157 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Dushanbe | Bin 597 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Gaza | Bin 2279 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Harbin | Bin 447 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Hong_Kong | Bin 1135 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Hovd | Bin 834 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Irkutsk | Bin 1935 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Istanbul | Bin 2721 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Jakarta | Bin 344 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Jayapura | Bin 209 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Jerusalem | Bin 2197 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Kabul | Bin 173 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Kamchatka | Bin 1915 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Karachi | Bin 333 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Kashgar | Bin 419 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Katmandu | Bin 198 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Asia/Krasnoyarsk | Bin 1914 -> 0 bytes .../pylibs/pytz/zoneinfo/Asia/Kuala_Lumpur | Bin 372 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Kuching | Bin 505 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Kuwait | Bin 157 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Macao | Bin 781 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Macau | Bin 781 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Magadan | Bin 1915 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Makassar | Bin 247 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Manila | Bin 319 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Muscat | Bin 157 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Nicosia | Bin 2002 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Asia/Novosibirsk | Bin 1944 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Omsk | Bin 1914 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Oral | Bin 1086 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Asia/Phnom_Penh | Bin 239 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Pontianak | Bin 359 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Pyongyang | Bin 242 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Qatar | Bin 195 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Qyzylorda | Bin 1068 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Rangoon | Bin 259 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Riyadh | Bin 157 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Riyadh87 | Bin 8669 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Riyadh88 | Bin 8523 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Riyadh89 | Bin 8523 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Saigon | Bin 239 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Sakhalin | Bin 1961 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Samarkand | Bin 677 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Seoul | Bin 380 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Shanghai | Bin 405 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Singapore | Bin 402 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Taipei | Bin 724 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Tashkent | Bin 667 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Tbilisi | Bin 1100 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Tehran | Bin 1622 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Tel_Aviv | Bin 2197 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Thimbu | Bin 195 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Thimphu | Bin 195 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Tokyo | Bin 331 -> 0 bytes .../pylibs/pytz/zoneinfo/Asia/Ujung_Pandang | Bin 247 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Asia/Ulaanbaatar | Bin 834 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Asia/Ulan_Bator | Bin 834 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Urumqi | Bin 389 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Vientiane | Bin 239 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Asia/Vladivostok | Bin 1929 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Yakutsk | Bin 1914 -> 0 bytes .../pylibs/pytz/zoneinfo/Asia/Yekaterinburg | Bin 2000 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Asia/Yerevan | Bin 2012 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Atlantic/Azores | Bin 3462 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Atlantic/Bermuda | Bin 1990 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Atlantic/Canary | Bin 1899 -> 0 bytes .../pylibs/pytz/zoneinfo/Atlantic/Cape_Verde | Bin 240 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Atlantic/Faeroe | Bin 1815 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Faroe | Bin 1815 -> 0 bytes .../pylibs/pytz/zoneinfo/Atlantic/Jan_Mayen | Bin 2225 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Atlantic/Madeira | Bin 3452 -> 0 bytes .../pylibs/pytz/zoneinfo/Atlantic/Reykjavik | Bin 1141 -> 0 bytes .../pylibs/pytz/zoneinfo/Atlantic/South_Georgia | Bin 139 -> 0 bytes .../pylibs/pytz/zoneinfo/Atlantic/St_Helena | Bin 177 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Atlantic/Stanley | Bin 1961 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Australia/ACT | Bin 2183 -> 0 bytes .../pylibs/pytz/zoneinfo/Australia/Adelaide | Bin 2202 -> 0 bytes .../pylibs/pytz/zoneinfo/Australia/Brisbane | Bin 413 -> 0 bytes .../pylibs/pytz/zoneinfo/Australia/Broken_Hill | Bin 2237 -> 0 bytes .../pylibs/pytz/zoneinfo/Australia/Canberra | Bin 2183 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Australia/Currie | Bin 2183 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Australia/Darwin | Bin 288 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Australia/Eucla | Bin 446 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Australia/Hobart | Bin 2295 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Australia/LHI | Bin 1821 -> 0 bytes .../pylibs/pytz/zoneinfo/Australia/Lindeman | Bin 483 -> 0 bytes .../pylibs/pytz/zoneinfo/Australia/Lord_Howe | Bin 1821 -> 0 bytes .../pylibs/pytz/zoneinfo/Australia/Melbourne | Bin 2183 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Australia/NSW | Bin 2183 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Australia/North | Bin 288 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Australia/Perth | Bin 440 -> 0 bytes .../pylibs/pytz/zoneinfo/Australia/Queensland | Bin 413 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Australia/South | Bin 2202 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Australia/Sydney | Bin 2183 -> 0 bytes .../pylibs/pytz/zoneinfo/Australia/Tasmania | Bin 2295 -> 0 bytes .../pylibs/pytz/zoneinfo/Australia/Victoria | Bin 2183 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Australia/West | Bin 440 -> 0 bytes .../pylibs/pytz/zoneinfo/Australia/Yancowinna | Bin 2237 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Brazil/Acre | Bin 574 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Brazil/DeNoronha | Bin 714 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Brazil/East | Bin 1983 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Brazil/West | Bin 602 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/CET | Bin 2074 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/CST6CDT | Bin 2294 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Canada/Atlantic | Bin 3424 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Canada/Central | Bin 2865 -> 0 bytes .../pylibs/pytz/zoneinfo/Canada/East-Saskatchewan | Bin 980 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Canada/Eastern | Bin 3477 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Canada/Mountain | Bin 2388 -> 0 bytes .../pylibs/pytz/zoneinfo/Canada/Newfoundland | Bin 3632 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Canada/Pacific | Bin 2875 -> 0 bytes .../pylibs/pytz/zoneinfo/Canada/Saskatchewan | Bin 980 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Canada/Yukon | Bin 2067 -> 0 bytes .../pylibs/pytz/zoneinfo/Chile/Continental | Bin 9011 -> 0 bytes .../pylibs/pytz/zoneinfo/Chile/EasterIsland | Bin 8773 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Cuba | Bin 2411 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/EET | Bin 1876 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/EST | Bin 118 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/EST5EDT | Bin 2294 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Egypt | Bin 9307 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Eire | Bin 3533 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT | Bin 118 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+0 | Bin 118 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+1 | Bin 126 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+10 | Bin 130 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+11 | Bin 130 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+12 | Bin 130 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+2 | Bin 126 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+3 | Bin 126 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+4 | Bin 126 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+5 | Bin 126 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+6 | Bin 126 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+7 | Bin 126 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+8 | Bin 126 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+9 | Bin 126 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-0 | Bin 118 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-1 | Bin 127 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-10 | Bin 131 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-11 | Bin 131 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-12 | Bin 131 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-13 | Bin 131 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-14 | Bin 131 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-2 | Bin 127 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-3 | Bin 127 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-4 | Bin 127 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-5 | Bin 127 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-6 | Bin 127 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-7 | Bin 127 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-8 | Bin 127 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-9 | Bin 127 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT0 | Bin 118 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Etc/Greenwich | Bin 118 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Etc/UCT | Bin 118 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Etc/UTC | Bin 118 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Etc/Universal | Bin 118 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Etc/Zulu | Bin 118 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Europe/Amsterdam | Bin 2917 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Europe/Andorra | Bin 1725 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Europe/Athens | Bin 2245 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Europe/Belfast | Bin 3661 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Europe/Belgrade | Bin 1917 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Europe/Berlin | Bin 2295 -> 0 bytes .../pylibs/pytz/zoneinfo/Europe/Bratislava | Bin 2246 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Europe/Brussels | Bin 2944 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Europe/Bucharest | Bin 2195 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Europe/Budapest | Bin 2393 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Europe/Chisinau | Bin 2407 -> 0 bytes .../pylibs/pytz/zoneinfo/Europe/Copenhagen | Bin 2134 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Europe/Dublin | Bin 3533 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Europe/Gibraltar | Bin 3035 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Europe/Guernsey | Bin 3661 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Europe/Helsinki | Bin 1883 -> 0 bytes .../pylibs/pytz/zoneinfo/Europe/Isle_of_Man | Bin 3661 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Europe/Istanbul | Bin 2721 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Europe/Jersey | Bin 3661 -> 0 bytes .../pylibs/pytz/zoneinfo/Europe/Kaliningrad | Bin 2233 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Europe/Kiev | Bin 2057 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Europe/Lisbon | Bin 3439 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Europe/Ljubljana | Bin 1917 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Europe/London | Bin 3661 -> 0 bytes .../pylibs/pytz/zoneinfo/Europe/Luxembourg | Bin 2960 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Europe/Madrid | Bin 2593 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Europe/Malta | Bin 2603 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Europe/Mariehamn | Bin 1883 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Europe/Minsk | Bin 2067 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Europe/Monaco | Bin 2927 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Europe/Moscow | Bin 2194 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Europe/Nicosia | Bin 2002 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Europe/Oslo | Bin 2225 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Europe/Paris | Bin 2945 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Europe/Podgorica | Bin 1917 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Europe/Prague | Bin 2246 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Europe/Riga | Bin 2209 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Europe/Rome | Bin 2652 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Europe/Samara | Bin 2046 -> 0 bytes .../pylibs/pytz/zoneinfo/Europe/San_Marino | Bin 2652 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Europe/Sarajevo | Bin 1917 -> 0 bytes .../pylibs/pytz/zoneinfo/Europe/Simferopol | Bin 2113 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Europe/Skopje | Bin 1917 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Europe/Sofia | Bin 2074 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Europe/Stockholm | Bin 1892 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Europe/Tallinn | Bin 2175 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Europe/Tirane | Bin 2084 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Europe/Tiraspol | Bin 2407 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Europe/Uzhgorod | Bin 2077 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Europe/Vaduz | Bin 1799 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Europe/Vatican | Bin 2652 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Europe/Vienna | Bin 2211 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Europe/Vilnius | Bin 2173 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Europe/Volgograd | Bin 1982 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Europe/Warsaw | Bin 2679 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Europe/Zagreb | Bin 1917 -> 0 bytes .../pylibs/pytz/zoneinfo/Europe/Zaporozhye | Bin 2085 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Europe/Zurich | Bin 1920 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Factory | Bin 255 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/GB | Bin 3661 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/GB-Eire | Bin 3661 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/GMT | Bin 118 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/GMT+0 | Bin 118 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/GMT-0 | Bin 118 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/GMT0 | Bin 118 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Greenwich | Bin 118 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/HST | Bin 119 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Hongkong | Bin 1135 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Iceland | Bin 1141 -> 0 bytes .../pylibs/pytz/zoneinfo/Indian/Antananarivo | Bin 227 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Indian/Chagos | Bin 187 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Indian/Christmas | Bin 140 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Indian/Cocos | Bin 143 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Indian/Comoro | Bin 157 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Indian/Kerguelen | Bin 157 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Indian/Mahe | Bin 157 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Indian/Maldives | Bin 178 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Indian/Mauritius | Bin 157 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Indian/Mayotte | Bin 157 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Indian/Reunion | Bin 157 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Iran | Bin 1622 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Israel | Bin 2197 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Jamaica | Bin 481 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Japan | Bin 331 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Kwajalein | Bin 211 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Libya | Bin 599 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/MET | Bin 2074 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/MST | Bin 118 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/MST7MDT | Bin 2294 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Mexico/BajaNorte | Bin 2342 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Mexico/BajaSur | Bin 1534 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Mexico/General | Bin 1604 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Mideast/Riyadh87 | Bin 8669 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Mideast/Riyadh88 | Bin 8523 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Mideast/Riyadh89 | Bin 8523 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/NZ | Bin 2434 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/NZ-CHAT | Bin 2018 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Navajo | Bin 2427 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/PRC | Bin 405 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/PST8PDT | Bin 2294 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Apia | Bin 214 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Pacific/Auckland | Bin 2434 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Pacific/Chatham | Bin 2018 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Easter | Bin 8773 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Efate | Bin 464 -> 0 bytes .../pylibs/pytz/zoneinfo/Pacific/Enderbury | Bin 204 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Pacific/Fakaofo | Bin 140 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Fiji | Bin 240 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Pacific/Funafuti | Bin 141 -> 0 bytes .../pylibs/pytz/zoneinfo/Pacific/Galapagos | Bin 197 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Pacific/Gambier | Bin 159 -> 0 bytes .../pylibs/pytz/zoneinfo/Pacific/Guadalcanal | Bin 158 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Guam | Bin 199 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Pacific/Honolulu | Bin 312 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Pacific/Johnston | Bin 119 -> 0 bytes .../pylibs/pytz/zoneinfo/Pacific/Kiritimati | Bin 204 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Kosrae | Bin 188 -> 0 bytes .../pylibs/pytz/zoneinfo/Pacific/Kwajalein | Bin 211 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Majuro | Bin 171 -> 0 bytes .../pylibs/pytz/zoneinfo/Pacific/Marquesas | Bin 162 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Midway | Bin 268 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Nauru | Bin 240 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Niue | Bin 200 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Pacific/Norfolk | Bin 182 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Noumea | Bin 300 -> 0 bytes .../pylibs/pytz/zoneinfo/Pacific/Pago_Pago | Bin 290 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Palau | Bin 140 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/Pacific/Pitcairn | Bin 177 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Ponape | Bin 144 -> 0 bytes .../pylibs/pytz/zoneinfo/Pacific/Port_Moresby | Bin 163 -> 0 bytes .../pylibs/pytz/zoneinfo/Pacific/Rarotonga | Bin 548 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Saipan | Bin 229 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Samoa | Bin 290 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Tahiti | Bin 160 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Tarawa | Bin 144 -> 0 bytes .../pylibs/pytz/zoneinfo/Pacific/Tongatapu | Bin 313 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Truk | Bin 144 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Wake | Bin 144 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Wallis | Bin 141 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Yap | Bin 144 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Poland | Bin 2679 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Portugal | Bin 3439 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/ROC | Bin 724 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/ROK | Bin 380 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Singapore | Bin 402 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Turkey | Bin 2721 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/UCT | Bin 118 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/US/Alaska | Bin 2358 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/US/Aleutian | Bin 2353 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/US/Arizona | Bin 327 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/US/Central | Bin 3543 -> 0 bytes .../buildbot/pylibs/pytz/zoneinfo/US/East-Indiana | Bin 1649 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/US/Eastern | Bin 3519 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/US/Hawaii | Bin 312 -> 0 bytes .../pylibs/pytz/zoneinfo/US/Indiana-Starke | Bin 2395 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/US/Michigan | Bin 2202 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/US/Mountain | Bin 2427 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/US/Pacific | Bin 2819 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/US/Pacific-New | Bin 2819 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/US/Samoa | Bin 290 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/UTC | Bin 118 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Universal | Bin 118 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/W-SU | Bin 2194 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/WET | Bin 1873 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/Zulu | Bin 118 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/iso3166.tab | 269 - tools/buildbot/pylibs/pytz/zoneinfo/localtime | Bin 255 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/posixrules | Bin 3519 -> 0 bytes tools/buildbot/pylibs/pytz/zoneinfo/zone.tab | 422 -- tools/buildbot/pylibs/simplejson/README.google | 11 - tools/buildbot/pylibs/simplejson/__init__.py | 287 - tools/buildbot/pylibs/simplejson/_speedups.c | 215 - tools/buildbot/pylibs/simplejson/decoder.py | 273 - tools/buildbot/pylibs/simplejson/encoder.py | 371 -- tools/buildbot/pylibs/simplejson/jsonfilter.py | 40 - tools/buildbot/pylibs/simplejson/scanner.py | 63 - tools/buildbot/pylibs/twisted/LICENSE | 51 - tools/buildbot/pylibs/twisted/README.google | 11 - tools/buildbot/pylibs/twisted/__init__.py | 24 - tools/buildbot/pylibs/twisted/_version.py | 3 - .../pylibs/twisted/application/__init__.py | 7 - tools/buildbot/pylibs/twisted/application/app.py | 653 --- .../pylibs/twisted/application/internet.py | 270 - .../pylibs/twisted/application/reactors.py | 83 - .../buildbot/pylibs/twisted/application/service.py | 376 -- .../pylibs/twisted/application/strports.py | 175 - tools/buildbot/pylibs/twisted/conch/__init__.py | 18 - tools/buildbot/pylibs/twisted/conch/_version.py | 3 - tools/buildbot/pylibs/twisted/conch/avatar.py | 37 - tools/buildbot/pylibs/twisted/conch/checkers.py | 176 - .../pylibs/twisted/conch/client/__init__.py | 9 - .../buildbot/pylibs/twisted/conch/client/agent.py | 56 - .../pylibs/twisted/conch/client/connect.py | 22 - .../pylibs/twisted/conch/client/default.py | 209 - .../buildbot/pylibs/twisted/conch/client/direct.py | 124 - .../pylibs/twisted/conch/client/options.py | 104 - tools/buildbot/pylibs/twisted/conch/client/unix.py | 396 -- tools/buildbot/pylibs/twisted/conch/error.py | 33 - .../pylibs/twisted/conch/insults/__init__.py | 4 - .../pylibs/twisted/conch/insults/client.py | 138 - .../pylibs/twisted/conch/insults/colors.py | 29 - .../pylibs/twisted/conch/insults/helper.py | 450 -- .../pylibs/twisted/conch/insults/insults.py | 1067 ---- .../buildbot/pylibs/twisted/conch/insults/text.py | 186 - .../pylibs/twisted/conch/insults/window.py | 864 --- tools/buildbot/pylibs/twisted/conch/interfaces.py | 354 -- tools/buildbot/pylibs/twisted/conch/ls.py | 55 - tools/buildbot/pylibs/twisted/conch/manhole.py | 336 -- tools/buildbot/pylibs/twisted/conch/manhole_ssh.py | 146 - tools/buildbot/pylibs/twisted/conch/manhole_tap.py | 128 - tools/buildbot/pylibs/twisted/conch/mixin.py | 49 - .../twisted/conch/openssh_compat/__init__.py | 11 - .../pylibs/twisted/conch/openssh_compat/factory.py | 43 - .../pylibs/twisted/conch/openssh_compat/primes.py | 26 - tools/buildbot/pylibs/twisted/conch/recvline.py | 328 -- .../pylibs/twisted/conch/scripts/__init__.py | 1 - .../buildbot/pylibs/twisted/conch/scripts/cftp.py | 799 --- .../pylibs/twisted/conch/scripts/ckeygen.py | 180 - .../buildbot/pylibs/twisted/conch/scripts/conch.py | 525 -- .../pylibs/twisted/conch/scripts/tkconch.py | 572 -- .../buildbot/pylibs/twisted/conch/ssh/__init__.py | 10 - tools/buildbot/pylibs/twisted/conch/ssh/agent.py | 145 - tools/buildbot/pylibs/twisted/conch/ssh/asn1.py | 65 - tools/buildbot/pylibs/twisted/conch/ssh/channel.py | 281 - tools/buildbot/pylibs/twisted/conch/ssh/common.py | 130 - .../pylibs/twisted/conch/ssh/connection.py | 613 --- tools/buildbot/pylibs/twisted/conch/ssh/factory.py | 129 - .../pylibs/twisted/conch/ssh/filetransfer.py | 896 ---- .../pylibs/twisted/conch/ssh/forwarding.py | 181 - tools/buildbot/pylibs/twisted/conch/ssh/keys.py | 829 --- tools/buildbot/pylibs/twisted/conch/ssh/service.py | 48 - tools/buildbot/pylibs/twisted/conch/ssh/session.py | 255 - tools/buildbot/pylibs/twisted/conch/ssh/sexpy.py | 42 - .../buildbot/pylibs/twisted/conch/ssh/transport.py | 1408 ----- .../buildbot/pylibs/twisted/conch/ssh/userauth.py | 438 -- tools/buildbot/pylibs/twisted/conch/stdio.py | 95 - tools/buildbot/pylibs/twisted/conch/tap.py | 47 - tools/buildbot/pylibs/twisted/conch/telnet.py | 996 ---- .../buildbot/pylibs/twisted/conch/test/__init__.py | 1 - .../buildbot/pylibs/twisted/conch/test/keydata.py | 174 - .../pylibs/twisted/conch/test/test_cftp.py | 705 --- .../pylibs/twisted/conch/test/test_channel.py | 279 - .../pylibs/twisted/conch/test/test_conch.py | 594 --- .../pylibs/twisted/conch/test/test_connection.py | 615 --- .../pylibs/twisted/conch/test/test_filetransfer.py | 513 -- .../pylibs/twisted/conch/test/test_helper.py | 560 -- .../pylibs/twisted/conch/test/test_insults.py | 382 -- .../pylibs/twisted/conch/test/test_keys.py | 846 --- .../pylibs/twisted/conch/test/test_manhole.py | 345 -- .../pylibs/twisted/conch/test/test_mixin.py | 47 - .../pylibs/twisted/conch/test/test_recvline.py | 648 --- .../buildbot/pylibs/twisted/conch/test/test_ssh.py | 844 --- .../pylibs/twisted/conch/test/test_telnet.py | 672 --- .../pylibs/twisted/conch/test/test_text.py | 101 - .../pylibs/twisted/conch/test/test_transport.py | 1930 ------- .../pylibs/twisted/conch/test/test_userauth.py | 176 - .../pylibs/twisted/conch/test/test_window.py | 49 - tools/buildbot/pylibs/twisted/conch/topfiles/NEWS | 127 - .../buildbot/pylibs/twisted/conch/topfiles/README | 3 - .../pylibs/twisted/conch/topfiles/setup.py | 46 - tools/buildbot/pylibs/twisted/conch/ttymodes.py | 121 - tools/buildbot/pylibs/twisted/conch/ui/__init__.py | 11 - tools/buildbot/pylibs/twisted/conch/ui/ansi.py | 240 - tools/buildbot/pylibs/twisted/conch/ui/tkvt100.py | 197 - tools/buildbot/pylibs/twisted/conch/unix.py | 457 -- tools/buildbot/pylibs/twisted/copyright.py | 41 - tools/buildbot/pylibs/twisted/cred/__init__.py | 13 - tools/buildbot/pylibs/twisted/cred/checkers.py | 266 - tools/buildbot/pylibs/twisted/cred/credentials.py | 198 - tools/buildbot/pylibs/twisted/cred/error.py | 41 - tools/buildbot/pylibs/twisted/cred/pamauth.py | 79 - tools/buildbot/pylibs/twisted/cred/portal.py | 120 - tools/buildbot/pylibs/twisted/cred/strcred.py | 270 - tools/buildbot/pylibs/twisted/cred/util.py | 40 - .../buildbot/pylibs/twisted/enterprise/__init__.py | 9 - tools/buildbot/pylibs/twisted/enterprise/adbapi.py | 440 -- .../pylibs/twisted/enterprise/reflector.py | 167 - tools/buildbot/pylibs/twisted/enterprise/row.py | 127 - .../pylibs/twisted/enterprise/sqlreflector.py | 327 -- tools/buildbot/pylibs/twisted/enterprise/util.py | 200 - tools/buildbot/pylibs/twisted/flow/__init__.py | 18 - tools/buildbot/pylibs/twisted/flow/_version.py | 3 - tools/buildbot/pylibs/twisted/flow/base.py | 213 - tools/buildbot/pylibs/twisted/flow/controller.py | 101 - tools/buildbot/pylibs/twisted/flow/flow.py | 102 - tools/buildbot/pylibs/twisted/flow/pipe.py | 112 - tools/buildbot/pylibs/twisted/flow/protocol.py | 151 - tools/buildbot/pylibs/twisted/flow/stage.py | 239 - .../buildbot/pylibs/twisted/flow/test/__init__.py | 1 - .../buildbot/pylibs/twisted/flow/test/test_flow.py | 491 -- tools/buildbot/pylibs/twisted/flow/threads.py | 210 - tools/buildbot/pylibs/twisted/flow/topfiles/README | 6 - .../buildbot/pylibs/twisted/flow/topfiles/setup.py | 26 - tools/buildbot/pylibs/twisted/flow/web.py | 50 - tools/buildbot/pylibs/twisted/flow/wrap.py | 217 - tools/buildbot/pylibs/twisted/im.py | 6 - tools/buildbot/pylibs/twisted/internet/__init__.py | 10 - .../pylibs/twisted/internet/_dumbwin32proc.py | 337 -- .../pylibs/twisted/internet/_dumbwin32proc_orig.py | 338 -- .../pylibs/twisted/internet/_javaserialport.py | 78 - .../pylibs/twisted/internet/_pollingfile.py | 270 - .../pylibs/twisted/internet/_posixserialport.py | 60 - .../pylibs/twisted/internet/_posixstdio.py | 171 - .../buildbot/pylibs/twisted/internet/_sslverify.py | 948 ---- .../pylibs/twisted/internet/_threadedselect.py | 362 -- .../pylibs/twisted/internet/_win32serialport.py | 112 - .../pylibs/twisted/internet/_win32stdio.py | 116 - tools/buildbot/pylibs/twisted/internet/abstract.py | 368 -- tools/buildbot/pylibs/twisted/internet/address.py | 113 - tools/buildbot/pylibs/twisted/internet/base.py | 1069 ---- .../buildbot/pylibs/twisted/internet/cfreactor.py | 342 -- .../pylibs/twisted/internet/cfsupport/cfdate.pxi | 2 - .../pylibs/twisted/internet/cfsupport/cfdecl.pxi | 227 - .../twisted/internet/cfsupport/cfrunloop.pxi | 104 - .../pylibs/twisted/internet/cfsupport/cfsocket.pxi | 111 - .../pylibs/twisted/internet/cfsupport/cfsupport.c | 2136 -------- .../twisted/internet/cfsupport/cfsupport.pyx | 6 - .../pylibs/twisted/internet/cfsupport/python.pxi | 5 - .../pylibs/twisted/internet/cfsupport/setup.py | 50 - tools/buildbot/pylibs/twisted/internet/default.py | 21 - tools/buildbot/pylibs/twisted/internet/defer.py | 1107 ---- .../pylibs/twisted/internet/epollreactor.py | 256 - tools/buildbot/pylibs/twisted/internet/error.py | 305 -- tools/buildbot/pylibs/twisted/internet/fdesc.py | 93 - .../pylibs/twisted/internet/glib2reactor.py | 49 - .../pylibs/twisted/internet/gtk2reactor.py | 295 -- .../buildbot/pylibs/twisted/internet/gtkreactor.py | 233 - .../buildbot/pylibs/twisted/internet/interfaces.py | 1417 ----- .../twisted/internet/iocpreactor/__init__.py | 2 - .../twisted/internet/iocpreactor/abstract.py | 456 -- .../pylibs/twisted/internet/iocpreactor/build.bat | 4 - .../pylibs/twisted/internet/iocpreactor/const.py | 26 - .../twisted/internet/iocpreactor/interfaces.py | 33 - .../internet/iocpreactor/iocpsupport/acceptex.pxi | 38 - .../internet/iocpreactor/iocpsupport/connectex.pxi | 34 - .../internet/iocpreactor/iocpsupport/iocpsupport.c | 2003 ------- .../iocpreactor/iocpsupport/iocpsupport.pyx | 250 - .../iocpreactor/iocpsupport/winsock_pointers.c | 62 - .../iocpreactor/iocpsupport/winsock_pointers.h | 51 - .../internet/iocpreactor/iocpsupport/wsarecv.pxi | 61 - .../internet/iocpreactor/iocpsupport/wsasend.pxi | 27 - .../pylibs/twisted/internet/iocpreactor/notes.txt | 24 - .../pylibs/twisted/internet/iocpreactor/reactor.py | 211 - .../pylibs/twisted/internet/iocpreactor/setup.py | 23 - .../pylibs/twisted/internet/iocpreactor/tcp.py | 497 -- .../pylibs/twisted/internet/iocpreactor/udp.py | 389 -- .../buildbot/pylibs/twisted/internet/kqreactor.py | 232 - tools/buildbot/pylibs/twisted/internet/main.py | 28 - .../pylibs/twisted/internet/pollreactor.py | 217 - .../buildbot/pylibs/twisted/internet/posixbase.py | 406 -- tools/buildbot/pylibs/twisted/internet/process.py | 922 ---- tools/buildbot/pylibs/twisted/internet/protocol.py | 674 --- .../pylibs/twisted/internet/pyuisupport.py | 37 - .../buildbot/pylibs/twisted/internet/qtreactor.py | 15 - tools/buildbot/pylibs/twisted/internet/reactor.py | 12 - .../pylibs/twisted/internet/selectreactor.py | 204 - .../buildbot/pylibs/twisted/internet/serialport.py | 65 - tools/buildbot/pylibs/twisted/internet/ssl.py | 205 - tools/buildbot/pylibs/twisted/internet/stdio.py | 31 - tools/buildbot/pylibs/twisted/internet/task.py | 420 -- tools/buildbot/pylibs/twisted/internet/tcp.py | 894 ---- .../pylibs/twisted/internet/test/__init__.py | 6 - .../twisted/internet/test/test_gtk2reactor.py | 43 - .../pylibs/twisted/internet/test/test_iocp.py | 105 - tools/buildbot/pylibs/twisted/internet/threads.py | 88 - .../buildbot/pylibs/twisted/internet/tksupport.py | 68 - tools/buildbot/pylibs/twisted/internet/udp.py | 385 -- tools/buildbot/pylibs/twisted/internet/unix.py | 297 -- tools/buildbot/pylibs/twisted/internet/utils.py | 172 - .../pylibs/twisted/internet/win32eventreactor.py | 244 - .../buildbot/pylibs/twisted/internet/wxreactor.py | 181 - .../buildbot/pylibs/twisted/internet/wxsupport.py | 61 - tools/buildbot/pylibs/twisted/lore/__init__.py | 21 - tools/buildbot/pylibs/twisted/lore/_version.py | 3 - tools/buildbot/pylibs/twisted/lore/default.py | 53 - tools/buildbot/pylibs/twisted/lore/docbook.py | 66 - tools/buildbot/pylibs/twisted/lore/htmlbook.py | 47 - tools/buildbot/pylibs/twisted/lore/indexer.py | 50 - tools/buildbot/pylibs/twisted/lore/latex.py | 455 -- tools/buildbot/pylibs/twisted/lore/lint.py | 214 - tools/buildbot/pylibs/twisted/lore/lmath.py | 76 - tools/buildbot/pylibs/twisted/lore/man2lore.py | 291 -- tools/buildbot/pylibs/twisted/lore/nevowlore.py | 108 - tools/buildbot/pylibs/twisted/lore/numberer.py | 33 - tools/buildbot/pylibs/twisted/lore/process.py | 120 - .../pylibs/twisted/lore/scripts/__init__.py | 1 - tools/buildbot/pylibs/twisted/lore/scripts/lore.py | 158 - tools/buildbot/pylibs/twisted/lore/slides.py | 352 -- tools/buildbot/pylibs/twisted/lore/template.mgp | 24 - .../buildbot/pylibs/twisted/lore/test/__init__.py | 1 - .../pylibs/twisted/lore/test/good_internal.xhtml | 23 - .../pylibs/twisted/lore/test/good_simple.xhtml | 2 - .../twisted/lore/test/lore_index_file_out.html | 2 - .../lore/test/lore_index_file_out_multiple.html | 5 - .../lore_index_file_unnumbered_multiple_out.html | 4 - .../lore/test/lore_index_file_unnumbered_out.html | 2 - .../pylibs/twisted/lore/test/lore_index_test.xhtml | 21 - .../twisted/lore/test/lore_index_test2.xhtml | 22 - .../twisted/lore/test/lore_index_test3.xhtml | 22 - .../twisted/lore/test/lore_index_test_out.html | 2 - .../twisted/lore/test/lore_index_test_out2.html | 2 - .../twisted/lore/test/lore_numbering_test.xhtml | 30 - .../twisted/lore/test/lore_numbering_test_out.html | 2 - .../lore/test/lore_numbering_test_out2.html | 2 - .../buildbot/pylibs/twisted/lore/test/simple.html | 9 - .../buildbot/pylibs/twisted/lore/test/simple.xhtml | 2 - .../pylibs/twisted/lore/test/simple1.xhtml | 2 - .../pylibs/twisted/lore/test/simple2.xhtml | 2 - .../buildbot/pylibs/twisted/lore/test/simple3.html | 9 - .../pylibs/twisted/lore/test/simple3.xhtml | 2 - .../buildbot/pylibs/twisted/lore/test/simple4.html | 9 - .../pylibs/twisted/lore/test/simple4.xhtml | 2 - .../pylibs/twisted/lore/test/simple4foo.xhtml | 2 - .../buildbot/pylibs/twisted/lore/test/template.tpl | 22 - .../buildbot/pylibs/twisted/lore/test/test_lore.py | 352 -- .../pylibs/twisted/lore/test/test_man2lore.py | 162 - tools/buildbot/pylibs/twisted/lore/texi.py | 109 - tools/buildbot/pylibs/twisted/lore/topfiles/NEWS | 60 - tools/buildbot/pylibs/twisted/lore/topfiles/README | 3 - .../buildbot/pylibs/twisted/lore/topfiles/setup.py | 27 - tools/buildbot/pylibs/twisted/lore/tree.py | 901 ---- tools/buildbot/pylibs/twisted/mail/__init__.py | 15 - tools/buildbot/pylibs/twisted/mail/_version.py | 3 - tools/buildbot/pylibs/twisted/mail/alias.py | 435 -- tools/buildbot/pylibs/twisted/mail/bounce.py | 61 - tools/buildbot/pylibs/twisted/mail/imap4.py | 5490 -------------------- tools/buildbot/pylibs/twisted/mail/mail.py | 333 -- tools/buildbot/pylibs/twisted/mail/maildir.py | 459 -- tools/buildbot/pylibs/twisted/mail/pb.py | 115 - tools/buildbot/pylibs/twisted/mail/pop3.py | 1072 ---- tools/buildbot/pylibs/twisted/mail/pop3client.py | 704 --- tools/buildbot/pylibs/twisted/mail/protocols.py | 225 - tools/buildbot/pylibs/twisted/mail/relay.py | 114 - tools/buildbot/pylibs/twisted/mail/relaymanager.py | 631 --- .../pylibs/twisted/mail/scripts/__init__.py | 1 - .../pylibs/twisted/mail/scripts/mailmail.py | 363 -- tools/buildbot/pylibs/twisted/mail/smtp.py | 2016 ------- tools/buildbot/pylibs/twisted/mail/tap.py | 185 - .../buildbot/pylibs/twisted/mail/test/__init__.py | 1 - .../pylibs/twisted/mail/test/pop3testserver.py | 311 -- .../pylibs/twisted/mail/test/rfc822.message | 86 - .../pylibs/twisted/mail/test/test_bounce.py | 32 - .../buildbot/pylibs/twisted/mail/test/test_imap.py | 3040 ----------- .../buildbot/pylibs/twisted/mail/test/test_mail.py | 1863 ------- .../pylibs/twisted/mail/test/test_options.py | 38 - .../buildbot/pylibs/twisted/mail/test/test_pop3.py | 1071 ---- .../pylibs/twisted/mail/test/test_pop3client.py | 573 -- .../buildbot/pylibs/twisted/mail/test/test_smtp.py | 982 ---- tools/buildbot/pylibs/twisted/mail/topfiles/NEWS | 113 - tools/buildbot/pylibs/twisted/mail/topfiles/README | 5 - .../buildbot/pylibs/twisted/mail/topfiles/setup.py | 48 - tools/buildbot/pylibs/twisted/manhole/__init__.py | 8 - .../buildbot/pylibs/twisted/manhole/_inspectro.py | 369 -- tools/buildbot/pylibs/twisted/manhole/explorer.py | 655 --- .../pylibs/twisted/manhole/gladereactor.glade | 342 -- .../pylibs/twisted/manhole/gladereactor.py | 219 - .../pylibs/twisted/manhole/inspectro.glade | 510 -- .../buildbot/pylibs/twisted/manhole/logview.glade | 39 - tools/buildbot/pylibs/twisted/manhole/service.py | 399 -- tools/buildbot/pylibs/twisted/manhole/telnet.py | 117 - .../buildbot/pylibs/twisted/manhole/ui/__init__.py | 7 - .../pylibs/twisted/manhole/ui/gtk2manhole.glade | 268 - .../pylibs/twisted/manhole/ui/gtk2manhole.py | 377 -- .../pylibs/twisted/manhole/ui/gtkmanhole.py | 184 - tools/buildbot/pylibs/twisted/manhole/ui/gtkrc | 62 - .../pylibs/twisted/manhole/ui/pywidgets.py | 250 - .../pylibs/twisted/manhole/ui/spelunk_gnome.py | 665 --- tools/buildbot/pylibs/twisted/names/__init__.py | 7 - tools/buildbot/pylibs/twisted/names/_version.py | 3 - tools/buildbot/pylibs/twisted/names/authority.py | 322 -- tools/buildbot/pylibs/twisted/names/cache.py | 96 - tools/buildbot/pylibs/twisted/names/client.py | 814 --- tools/buildbot/pylibs/twisted/names/common.py | 224 - tools/buildbot/pylibs/twisted/names/dns.py | 1621 ------ tools/buildbot/pylibs/twisted/names/error.py | 88 - tools/buildbot/pylibs/twisted/names/hosts.py | 61 - tools/buildbot/pylibs/twisted/names/resolve.py | 59 - tools/buildbot/pylibs/twisted/names/root.py | 208 - tools/buildbot/pylibs/twisted/names/secondary.py | 102 - tools/buildbot/pylibs/twisted/names/server.py | 188 - tools/buildbot/pylibs/twisted/names/srvconnect.py | 185 - tools/buildbot/pylibs/twisted/names/tap.py | 119 - .../buildbot/pylibs/twisted/names/test/__init__.py | 1 - .../pylibs/twisted/names/test/test_cache.py | 14 - .../pylibs/twisted/names/test/test_client.py | 307 -- .../buildbot/pylibs/twisted/names/test/test_dns.py | 340 -- .../pylibs/twisted/names/test/test_names.py | 712 --- .../pylibs/twisted/names/test/test_rootresolve.py | 13 - .../pylibs/twisted/names/test/test_srvconnect.py | 140 - tools/buildbot/pylibs/twisted/names/topfiles/NEWS | 75 - .../buildbot/pylibs/twisted/names/topfiles/README | 3 - .../pylibs/twisted/names/topfiles/setup.py | 48 - tools/buildbot/pylibs/twisted/news/__init__.py | 11 - tools/buildbot/pylibs/twisted/news/_version.py | 3 - tools/buildbot/pylibs/twisted/news/database.py | 995 ---- tools/buildbot/pylibs/twisted/news/news.py | 90 - tools/buildbot/pylibs/twisted/news/nntp.py | 1069 ---- tools/buildbot/pylibs/twisted/news/tap.py | 132 - .../buildbot/pylibs/twisted/news/test/__init__.py | 1 - .../buildbot/pylibs/twisted/news/test/test_news.py | 107 - .../buildbot/pylibs/twisted/news/test/test_nntp.py | 124 - tools/buildbot/pylibs/twisted/news/topfiles/NEWS | 31 - tools/buildbot/pylibs/twisted/news/topfiles/README | 4 - .../buildbot/pylibs/twisted/news/topfiles/setup.py | 27 - tools/buildbot/pylibs/twisted/pair/__init__.py | 20 - tools/buildbot/pylibs/twisted/pair/_version.py | 3 - tools/buildbot/pylibs/twisted/pair/ethernet.py | 56 - tools/buildbot/pylibs/twisted/pair/ip.py | 72 - tools/buildbot/pylibs/twisted/pair/raw.py | 35 - tools/buildbot/pylibs/twisted/pair/rawudp.py | 55 - .../buildbot/pylibs/twisted/pair/test/__init__.py | 1 - .../pylibs/twisted/pair/test/test_ethernet.py | 226 - tools/buildbot/pylibs/twisted/pair/test/test_ip.py | 417 -- .../pylibs/twisted/pair/test/test_rawudp.py | 327 -- tools/buildbot/pylibs/twisted/pair/topfiles/README | 4 - .../buildbot/pylibs/twisted/pair/topfiles/setup.py | 26 - tools/buildbot/pylibs/twisted/pair/tuntap.py | 170 - .../buildbot/pylibs/twisted/persisted/__init__.py | 10 - tools/buildbot/pylibs/twisted/persisted/aot.py | 560 -- .../buildbot/pylibs/twisted/persisted/crefutil.py | 167 - tools/buildbot/pylibs/twisted/persisted/dirdbm.py | 358 -- .../pylibs/twisted/persisted/journal/__init__.py | 10 - .../pylibs/twisted/persisted/journal/base.py | 226 - .../pylibs/twisted/persisted/journal/picklelog.py | 48 - .../pylibs/twisted/persisted/journal/rowjournal.py | 99 - .../buildbot/pylibs/twisted/persisted/marmalade.py | 416 -- tools/buildbot/pylibs/twisted/persisted/sob.py | 233 - tools/buildbot/pylibs/twisted/persisted/styles.py | 256 - tools/buildbot/pylibs/twisted/plugin.py | 246 - tools/buildbot/pylibs/twisted/plugins/__init__.py | 17 - .../pylibs/twisted/plugins/cred_anonymous.py | 40 - tools/buildbot/pylibs/twisted/plugins/cred_file.py | 60 - .../buildbot/pylibs/twisted/plugins/cred_memory.py | 68 - tools/buildbot/pylibs/twisted/plugins/cred_unix.py | 138 - .../pylibs/twisted/plugins/twisted_conch.py | 18 - .../buildbot/pylibs/twisted/plugins/twisted_ftp.py | 10 - .../pylibs/twisted/plugins/twisted_inet.py | 10 - .../pylibs/twisted/plugins/twisted_lore.py | 38 - .../pylibs/twisted/plugins/twisted_mail.py | 10 - .../pylibs/twisted/plugins/twisted_manhole.py | 10 - .../pylibs/twisted/plugins/twisted_names.py | 10 - .../pylibs/twisted/plugins/twisted_news.py | 10 - .../pylibs/twisted/plugins/twisted_portforward.py | 10 - .../pylibs/twisted/plugins/twisted_qtstub.py | 45 - .../pylibs/twisted/plugins/twisted_reactors.py | 38 - .../pylibs/twisted/plugins/twisted_socks.py | 10 - .../pylibs/twisted/plugins/twisted_telnet.py | 10 - .../pylibs/twisted/plugins/twisted_trial.py | 53 - .../buildbot/pylibs/twisted/plugins/twisted_web.py | 11 - .../pylibs/twisted/plugins/twisted_words.py | 42 - .../buildbot/pylibs/twisted/protocols/__init__.py | 10 - .../buildbot/pylibs/twisted/protocols/_c_urlarg.c | 146 - tools/buildbot/pylibs/twisted/protocols/amp.py | 2223 -------- tools/buildbot/pylibs/twisted/protocols/basic.py | 486 -- tools/buildbot/pylibs/twisted/protocols/dict.py | 362 -- tools/buildbot/pylibs/twisted/protocols/dns.py | 6 - .../buildbot/pylibs/twisted/protocols/ethernet.py | 7 - tools/buildbot/pylibs/twisted/protocols/finger.py | 43 - tools/buildbot/pylibs/twisted/protocols/ftp.py | 2625 ---------- .../pylibs/twisted/protocols/gps/__init__.py | 1 - .../buildbot/pylibs/twisted/protocols/gps/nmea.py | 208 - .../pylibs/twisted/protocols/gps/rockwell.py | 268 - tools/buildbot/pylibs/twisted/protocols/htb.py | 269 - tools/buildbot/pylibs/twisted/protocols/http.py | 7 - tools/buildbot/pylibs/twisted/protocols/ident.py | 227 - tools/buildbot/pylibs/twisted/protocols/imap4.py | 7 - tools/buildbot/pylibs/twisted/protocols/ip.py | 7 - tools/buildbot/pylibs/twisted/protocols/irc.py | 7 - tools/buildbot/pylibs/twisted/protocols/jabber.py | 7 - .../buildbot/pylibs/twisted/protocols/loopback.py | 335 -- .../buildbot/pylibs/twisted/protocols/memcache.py | 657 --- .../pylibs/twisted/protocols/mice/__init__.py | 1 - .../pylibs/twisted/protocols/mice/mouseman.py | 127 - tools/buildbot/pylibs/twisted/protocols/msn.py | 7 - tools/buildbot/pylibs/twisted/protocols/nntp.py | 7 - tools/buildbot/pylibs/twisted/protocols/oscar.py | 7 - tools/buildbot/pylibs/twisted/protocols/pcp.py | 209 - .../buildbot/pylibs/twisted/protocols/policies.py | 631 --- tools/buildbot/pylibs/twisted/protocols/pop3.py | 6 - .../pylibs/twisted/protocols/portforward.py | 76 - tools/buildbot/pylibs/twisted/protocols/postfix.py | 132 - tools/buildbot/pylibs/twisted/protocols/raw.py | 7 - tools/buildbot/pylibs/twisted/protocols/rawudp.py | 7 - .../buildbot/pylibs/twisted/protocols/shoutcast.py | 120 - tools/buildbot/pylibs/twisted/protocols/sip.py | 1190 ----- tools/buildbot/pylibs/twisted/protocols/smtp.py | 6 - tools/buildbot/pylibs/twisted/protocols/socks.py | 173 - .../buildbot/pylibs/twisted/protocols/stateful.py | 52 - tools/buildbot/pylibs/twisted/protocols/sux.py | 7 - tools/buildbot/pylibs/twisted/protocols/telnet.py | 325 -- tools/buildbot/pylibs/twisted/protocols/toc.py | 7 - tools/buildbot/pylibs/twisted/protocols/wire.py | 90 - .../buildbot/pylibs/twisted/protocols/xmlstream.py | 5 - tools/buildbot/pylibs/twisted/python/__init__.py | 13 - tools/buildbot/pylibs/twisted/python/_epoll.c | 925 ---- tools/buildbot/pylibs/twisted/python/_epoll.pyx | 181 - tools/buildbot/pylibs/twisted/python/_release.py | 803 --- .../pylibs/twisted/python/_twisted_zsh_stub | 89 - tools/buildbot/pylibs/twisted/python/compat.py | 168 - tools/buildbot/pylibs/twisted/python/components.py | 445 -- tools/buildbot/pylibs/twisted/python/context.py | 90 - tools/buildbot/pylibs/twisted/python/deprecate.py | 134 - tools/buildbot/pylibs/twisted/python/dispatch.py | 42 - tools/buildbot/pylibs/twisted/python/dist.py | 361 -- tools/buildbot/pylibs/twisted/python/dxprofile.py | 56 - tools/buildbot/pylibs/twisted/python/failure.py | 550 -- tools/buildbot/pylibs/twisted/python/filepath.py | 675 --- tools/buildbot/pylibs/twisted/python/finalize.py | 46 - tools/buildbot/pylibs/twisted/python/formmethod.py | 363 -- tools/buildbot/pylibs/twisted/python/hook.py | 177 - tools/buildbot/pylibs/twisted/python/htmlizer.py | 87 - tools/buildbot/pylibs/twisted/python/lockfile.py | 143 - tools/buildbot/pylibs/twisted/python/log.py | 584 --- tools/buildbot/pylibs/twisted/python/logfile.py | 309 -- tools/buildbot/pylibs/twisted/python/modules.py | 759 --- tools/buildbot/pylibs/twisted/python/monkey.py | 73 - tools/buildbot/pylibs/twisted/python/otp.py | 481 -- tools/buildbot/pylibs/twisted/python/plugin.py | 332 -- tools/buildbot/pylibs/twisted/python/procutils.py | 45 - tools/buildbot/pylibs/twisted/python/randbytes.py | 177 - tools/buildbot/pylibs/twisted/python/rebuild.py | 264 - tools/buildbot/pylibs/twisted/python/reflect.py | 745 --- tools/buildbot/pylibs/twisted/python/release.py | 57 - tools/buildbot/pylibs/twisted/python/roots.py | 257 - tools/buildbot/pylibs/twisted/python/runtime.py | 82 - tools/buildbot/pylibs/twisted/python/shortcut.py | 76 - tools/buildbot/pylibs/twisted/python/syslog.py | 40 - .../pylibs/twisted/python/test/__init__.py | 3 - .../pylibs/twisted/python/test/test_components.py | 741 --- .../pylibs/twisted/python/test/test_deprecate.py | 173 - .../pylibs/twisted/python/test/test_dist.py | 173 - .../pylibs/twisted/python/test/test_release.py | 1516 ------ .../pylibs/twisted/python/test/test_util.py | 597 --- .../pylibs/twisted/python/test/test_versions.py | 269 - .../pylibs/twisted/python/test/test_zipstream.py | 396 -- tools/buildbot/pylibs/twisted/python/text.py | 227 - tools/buildbot/pylibs/twisted/python/threadable.py | 120 - tools/buildbot/pylibs/twisted/python/threadpool.py | 242 - .../buildbot/pylibs/twisted/python/timeoutqueue.py | 49 - tools/buildbot/pylibs/twisted/python/urlpath.py | 122 - tools/buildbot/pylibs/twisted/python/usage.py | 631 --- tools/buildbot/pylibs/twisted/python/util.py | 915 ---- tools/buildbot/pylibs/twisted/python/versions.py | 235 - tools/buildbot/pylibs/twisted/python/win32.py | 160 - tools/buildbot/pylibs/twisted/python/zippath.py | 215 - tools/buildbot/pylibs/twisted/python/zipstream.py | 377 -- tools/buildbot/pylibs/twisted/python/zsh/README | 8 - tools/buildbot/pylibs/twisted/python/zsh/_cftp | 48 - tools/buildbot/pylibs/twisted/python/zsh/_ckeygen | 25 - tools/buildbot/pylibs/twisted/python/zsh/_conch | 58 - tools/buildbot/pylibs/twisted/python/zsh/_lore | 28 - tools/buildbot/pylibs/twisted/python/zsh/_manhole | 19 - tools/buildbot/pylibs/twisted/python/zsh/_mktap | 304 -- .../buildbot/pylibs/twisted/python/zsh/_pyhtmlizer | 8 - tools/buildbot/pylibs/twisted/python/zsh/_tap2deb | 23 - tools/buildbot/pylibs/twisted/python/zsh/_tap2rpm | 23 - .../buildbot/pylibs/twisted/python/zsh/_tapconvert | 17 - tools/buildbot/pylibs/twisted/python/zsh/_tkconch | 38 - tools/buildbot/pylibs/twisted/python/zsh/_tkmktap | 0 tools/buildbot/pylibs/twisted/python/zsh/_trial | 40 - tools/buildbot/pylibs/twisted/python/zsh/_twistd | 328 -- .../buildbot/pylibs/twisted/python/zsh/_websetroot | 0 tools/buildbot/pylibs/twisted/python/zshcomp.py | 780 --- tools/buildbot/pylibs/twisted/runner/__init__.py | 15 - tools/buildbot/pylibs/twisted/runner/_version.py | 3 - tools/buildbot/pylibs/twisted/runner/inetd.py | 70 - tools/buildbot/pylibs/twisted/runner/inetdconf.py | 194 - tools/buildbot/pylibs/twisted/runner/inetdtap.py | 160 - tools/buildbot/pylibs/twisted/runner/portmap.c | 57 - tools/buildbot/pylibs/twisted/runner/procmon.py | 235 - tools/buildbot/pylibs/twisted/runner/procutils.py | 5 - tools/buildbot/pylibs/twisted/runner/topfiles/NEWS | 20 - .../buildbot/pylibs/twisted/runner/topfiles/README | 2 - .../pylibs/twisted/runner/topfiles/setup.py | 33 - tools/buildbot/pylibs/twisted/scripts/__init__.py | 12 - .../pylibs/twisted/scripts/_twistd_unix.py | 313 -- tools/buildbot/pylibs/twisted/scripts/_twistw.py | 88 - tools/buildbot/pylibs/twisted/scripts/htmlizer.py | 66 - tools/buildbot/pylibs/twisted/scripts/manhole.py | 185 - tools/buildbot/pylibs/twisted/scripts/mktap.py | 190 - tools/buildbot/pylibs/twisted/scripts/tap2deb.py | 279 - tools/buildbot/pylibs/twisted/scripts/tap2rpm.py | 273 - .../buildbot/pylibs/twisted/scripts/tapconvert.py | 53 - .../pylibs/twisted/scripts/test/__init__.py | 6 - .../pylibs/twisted/scripts/test/test_mktap.py | 107 - tools/buildbot/pylibs/twisted/scripts/tkunzip.py | 286 - tools/buildbot/pylibs/twisted/scripts/trial.py | 368 -- tools/buildbot/pylibs/twisted/scripts/twistd.py | 30 - tools/buildbot/pylibs/twisted/spread/__init__.py | 12 - tools/buildbot/pylibs/twisted/spread/banana.py | 351 -- tools/buildbot/pylibs/twisted/spread/flavors.py | 603 --- tools/buildbot/pylibs/twisted/spread/interfaces.py | 28 - tools/buildbot/pylibs/twisted/spread/jelly.py | 1136 ---- tools/buildbot/pylibs/twisted/spread/pb.py | 1349 ----- tools/buildbot/pylibs/twisted/spread/publish.py | 142 - tools/buildbot/pylibs/twisted/spread/refpath.py | 99 - .../buildbot/pylibs/twisted/spread/ui/__init__.py | 12 - .../buildbot/pylibs/twisted/spread/ui/gtk2util.py | 215 - tools/buildbot/pylibs/twisted/spread/ui/gtkutil.py | 204 - .../buildbot/pylibs/twisted/spread/ui/login2.glade | 461 -- tools/buildbot/pylibs/twisted/spread/ui/tktree.py | 204 - tools/buildbot/pylibs/twisted/spread/ui/tkutil.py | 397 -- tools/buildbot/pylibs/twisted/spread/util.py | 215 - tools/buildbot/pylibs/twisted/tap/__init__.py | 10 - tools/buildbot/pylibs/twisted/tap/ftp.py | 51 - tools/buildbot/pylibs/twisted/tap/manhole.py | 51 - tools/buildbot/pylibs/twisted/tap/portforward.py | 24 - tools/buildbot/pylibs/twisted/tap/socks.py | 34 - tools/buildbot/pylibs/twisted/tap/telnet.py | 29 - tools/buildbot/pylibs/twisted/test/__init__.py | 10 - tools/buildbot/pylibs/twisted/test/app_qtstub.py | 53 - .../pylibs/twisted/test/crash_test_dummy.py | 34 - .../pylibs/twisted/test/generator_failure_tests.py | 169 - tools/buildbot/pylibs/twisted/test/iosim.py | 275 - .../pylibs/twisted/test/mock_win32process.py | 48 - tools/buildbot/pylibs/twisted/test/myrebuilder1.py | 15 - tools/buildbot/pylibs/twisted/test/myrebuilder2.py | 16 - tools/buildbot/pylibs/twisted/test/plugin_basic.py | 57 - .../buildbot/pylibs/twisted/test/plugin_extra1.py | 23 - .../buildbot/pylibs/twisted/test/plugin_extra2.py | 35 - .../pylibs/twisted/test/process_cmdline.py | 5 - .../buildbot/pylibs/twisted/test/process_echoer.py | 10 - tools/buildbot/pylibs/twisted/test/process_fds.py | 40 - .../buildbot/pylibs/twisted/test/process_linger.py | 17 - .../buildbot/pylibs/twisted/test/process_reader.py | 12 - .../buildbot/pylibs/twisted/test/process_signal.py | 8 - .../pylibs/twisted/test/process_stdinreader.py | 23 - .../buildbot/pylibs/twisted/test/process_tester.py | 37 - tools/buildbot/pylibs/twisted/test/process_tty.py | 6 - .../pylibs/twisted/test/process_twisted.py | 43 - .../buildbot/pylibs/twisted/test/proto_helpers.py | 93 - tools/buildbot/pylibs/twisted/test/raiser.c | 316 -- tools/buildbot/pylibs/twisted/test/raiser.pyx | 21 - .../pylibs/twisted/test/reflect_helper_IE.py | 4 - .../pylibs/twisted/test/reflect_helper_VE.py | 4 - .../pylibs/twisted/test/reflect_helper_ZDE.py | 4 - tools/buildbot/pylibs/twisted/test/server.pem | 36 - tools/buildbot/pylibs/twisted/test/ssl_helpers.py | 26 - .../pylibs/twisted/test/stdio_test_consumer.py | 39 - .../pylibs/twisted/test/stdio_test_hostpeer.py | 32 - .../pylibs/twisted/test/stdio_test_lastwrite.py | 45 - .../pylibs/twisted/test/stdio_test_loseconn.py | 29 - .../pylibs/twisted/test/stdio_test_producer.py | 55 - .../pylibs/twisted/test/stdio_test_write.py | 32 - .../pylibs/twisted/test/stdio_test_writeseq.py | 30 - .../buildbot/pylibs/twisted/test/test_abstract.py | 83 - tools/buildbot/pylibs/twisted/test/test_adbapi.py | 575 -- tools/buildbot/pylibs/twisted/test/test_amp.py | 2115 -------- .../pylibs/twisted/test/test_application.py | 899 ---- .../pylibs/twisted/test/test_assertions.py | 22 - tools/buildbot/pylibs/twisted/test/test_banana.py | 264 - tools/buildbot/pylibs/twisted/test/test_compat.py | 192 - tools/buildbot/pylibs/twisted/test/test_context.py | 15 - .../pylibs/twisted/test/test_cooperator.py | 189 - tools/buildbot/pylibs/twisted/test/test_defer.py | 899 ---- tools/buildbot/pylibs/twisted/test/test_defgen.py | 283 - tools/buildbot/pylibs/twisted/test/test_dict.py | 22 - tools/buildbot/pylibs/twisted/test/test_dirdbm.py | 174 - tools/buildbot/pylibs/twisted/test/test_doc.py | 92 - .../pylibs/twisted/test/test_enterprise.py | 41 - tools/buildbot/pylibs/twisted/test/test_epoll.py | 159 - tools/buildbot/pylibs/twisted/test/test_error.py | 170 - .../buildbot/pylibs/twisted/test/test_explorer.py | 236 - .../pylibs/twisted/test/test_extensions.py | 18 - .../buildbot/pylibs/twisted/test/test_factories.py | 122 - tools/buildbot/pylibs/twisted/test/test_failure.py | 318 -- tools/buildbot/pylibs/twisted/test/test_fdesc.py | 176 - tools/buildbot/pylibs/twisted/test/test_finger.py | 35 - .../pylibs/twisted/test/test_formmethod.py | 77 - tools/buildbot/pylibs/twisted/test/test_ftp.py | 2253 -------- tools/buildbot/pylibs/twisted/test/test_hook.py | 150 - tools/buildbot/pylibs/twisted/test/test_htb.py | 96 - tools/buildbot/pylibs/twisted/test/test_ident.py | 194 - tools/buildbot/pylibs/twisted/test/test_import.py | 92 - .../buildbot/pylibs/twisted/test/test_internet.py | 1653 ------ tools/buildbot/pylibs/twisted/test/test_iutils.py | 151 - tools/buildbot/pylibs/twisted/test/test_jelly.py | 589 --- tools/buildbot/pylibs/twisted/test/test_journal.py | 169 - .../buildbot/pylibs/twisted/test/test_lockfile.py | 49 - tools/buildbot/pylibs/twisted/test/test_log.py | 434 -- tools/buildbot/pylibs/twisted/test/test_logfile.py | 288 - .../buildbot/pylibs/twisted/test/test_loopback.py | 328 -- tools/buildbot/pylibs/twisted/test/test_manhole.py | 75 - .../buildbot/pylibs/twisted/test/test_memcache.py | 510 -- tools/buildbot/pylibs/twisted/test/test_modules.py | 371 -- tools/buildbot/pylibs/twisted/test/test_monkey.py | 161 - tools/buildbot/pylibs/twisted/test/test_newcred.py | 444 -- tools/buildbot/pylibs/twisted/test/test_nmea.py | 115 - tools/buildbot/pylibs/twisted/test/test_paths.py | 648 --- tools/buildbot/pylibs/twisted/test/test_pb.py | 1618 ------ .../buildbot/pylibs/twisted/test/test_pbfailure.py | 407 -- tools/buildbot/pylibs/twisted/test/test_pcp.py | 368 -- .../buildbot/pylibs/twisted/test/test_persisted.py | 474 -- tools/buildbot/pylibs/twisted/test/test_plugin.py | 694 --- .../buildbot/pylibs/twisted/test/test_policies.py | 682 --- tools/buildbot/pylibs/twisted/test/test_postfix.py | 104 - tools/buildbot/pylibs/twisted/test/test_process.py | 2237 -------- .../buildbot/pylibs/twisted/test/test_protocols.py | 725 --- .../buildbot/pylibs/twisted/test/test_randbytes.py | 178 - tools/buildbot/pylibs/twisted/test/test_rebuild.py | 217 - tools/buildbot/pylibs/twisted/test/test_reflect.py | 491 -- .../buildbot/pylibs/twisted/test/test_reflector.py | 396 -- tools/buildbot/pylibs/twisted/test/test_roots.py | 63 - .../buildbot/pylibs/twisted/test/test_shortcut.py | 20 - tools/buildbot/pylibs/twisted/test/test_sip.py | 740 --- tools/buildbot/pylibs/twisted/test/test_sob.py | 188 - tools/buildbot/pylibs/twisted/test/test_socks.py | 280 - .../pylibs/twisted/test/test_split_compat.py | 35 - tools/buildbot/pylibs/twisted/test/test_ssl.py | 431 -- .../buildbot/pylibs/twisted/test/test_sslverify.py | 534 -- .../buildbot/pylibs/twisted/test/test_stateful.py | 74 - tools/buildbot/pylibs/twisted/test/test_stdio.py | 265 - tools/buildbot/pylibs/twisted/test/test_strcred.py | 623 --- .../buildbot/pylibs/twisted/test/test_strerror.py | 145 - .../buildbot/pylibs/twisted/test/test_strports.py | 58 - tools/buildbot/pylibs/twisted/test/test_task.py | 479 -- tools/buildbot/pylibs/twisted/test/test_tcp.py | 1776 ------- .../pylibs/twisted/test/test_tcp_internals.py | 240 - tools/buildbot/pylibs/twisted/test/test_text.py | 156 - .../pylibs/twisted/test/test_threadable.py | 104 - .../pylibs/twisted/test/test_threadpool.py | 307 -- tools/buildbot/pylibs/twisted/test/test_threads.py | 356 -- .../pylibs/twisted/test/test_timeoutqueue.py | 73 - tools/buildbot/pylibs/twisted/test/test_tpfile.py | 52 - tools/buildbot/pylibs/twisted/test/test_twistd.py | 724 --- tools/buildbot/pylibs/twisted/test/test_udp.py | 801 --- tools/buildbot/pylibs/twisted/test/test_unix.py | 418 -- tools/buildbot/pylibs/twisted/test/test_usage.py | 372 -- tools/buildbot/pylibs/twisted/test/test_zshcomp.py | 210 - tools/buildbot/pylibs/twisted/test/testutils.py | 55 - .../pylibs/twisted/test/threading_latency.py | 54 - tools/buildbot/pylibs/twisted/test/time_helpers.py | 65 - tools/buildbot/pylibs/twisted/topfiles/CREDITS | 60 - .../buildbot/pylibs/twisted/topfiles/ChangeLog.Old | 3888 -------------- tools/buildbot/pylibs/twisted/topfiles/NEWS | 610 --- tools/buildbot/pylibs/twisted/topfiles/README | 14 - tools/buildbot/pylibs/twisted/topfiles/setup.py | 97 - tools/buildbot/pylibs/twisted/trial/__init__.py | 52 - tools/buildbot/pylibs/twisted/trial/itrial.py | 250 - tools/buildbot/pylibs/twisted/trial/reporter.py | 983 ---- tools/buildbot/pylibs/twisted/trial/runner.py | 833 --- .../buildbot/pylibs/twisted/trial/test/__init__.py | 1 - .../buildbot/pylibs/twisted/trial/test/detests.py | 195 - .../pylibs/twisted/trial/test/erroneous.py | 152 - .../pylibs/twisted/trial/test/mockcustomsuite.py | 21 - .../pylibs/twisted/trial/test/mockcustomsuite2.py | 21 - .../pylibs/twisted/trial/test/mockcustomsuite3.py | 28 - .../pylibs/twisted/trial/test/mockdoctest.py | 104 - .../pylibs/twisted/trial/test/moduleself.py | 7 - .../pylibs/twisted/trial/test/moduletest.py | 11 - tools/buildbot/pylibs/twisted/trial/test/notpython | 2 - tools/buildbot/pylibs/twisted/trial/test/novars.py | 6 - .../buildbot/pylibs/twisted/trial/test/packages.py | 134 - tools/buildbot/pylibs/twisted/trial/test/sample.py | 40 - .../pylibs/twisted/trial/test/scripttest.py | 11 - .../pylibs/twisted/trial/test/suppression.py | 56 - .../pylibs/twisted/trial/test/test_assertions.py | 696 --- .../pylibs/twisted/trial/test/test_class.py | 202 - .../pylibs/twisted/trial/test/test_deferred.py | 220 - .../pylibs/twisted/trial/test/test_doctest.py | 66 - .../pylibs/twisted/trial/test/test_keyboard.py | 113 - .../pylibs/twisted/trial/test/test_loader.py | 475 -- .../buildbot/pylibs/twisted/trial/test/test_log.py | 197 - .../pylibs/twisted/trial/test/test_output.py | 154 - .../pylibs/twisted/trial/test/test_pyunitcompat.py | 222 - .../pylibs/twisted/trial/test/test_reporter.py | 1031 ---- .../pylibs/twisted/trial/test/test_runner.py | 676 --- .../pylibs/twisted/trial/test/test_script.py | 390 -- .../pylibs/twisted/trial/test/test_test_visitor.py | 82 - .../pylibs/twisted/trial/test/test_tests.py | 1124 ---- .../pylibs/twisted/trial/test/test_util.py | 533 -- tools/buildbot/pylibs/twisted/trial/test/weird.py | 20 - tools/buildbot/pylibs/twisted/trial/unittest.py | 1454 ------ tools/buildbot/pylibs/twisted/trial/util.py | 367 -- tools/buildbot/pylibs/twisted/web/__init__.py | 14 - tools/buildbot/pylibs/twisted/web/_version.py | 3 - tools/buildbot/pylibs/twisted/web/client.py | 434 -- tools/buildbot/pylibs/twisted/web/demo.py | 29 - tools/buildbot/pylibs/twisted/web/distrib.py | 303 -- tools/buildbot/pylibs/twisted/web/domhelpers.py | 260 - tools/buildbot/pylibs/twisted/web/error.py | 61 - tools/buildbot/pylibs/twisted/web/google.py | 75 - tools/buildbot/pylibs/twisted/web/guard.py | 217 - tools/buildbot/pylibs/twisted/web/html.py | 49 - tools/buildbot/pylibs/twisted/web/http.py | 1244 ----- tools/buildbot/pylibs/twisted/web/microdom.py | 873 ---- tools/buildbot/pylibs/twisted/web/monitor.py | 85 - tools/buildbot/pylibs/twisted/web/proxy.py | 283 - tools/buildbot/pylibs/twisted/web/resource.py | 204 - tools/buildbot/pylibs/twisted/web/rewrite.py | 52 - tools/buildbot/pylibs/twisted/web/script.py | 163 - tools/buildbot/pylibs/twisted/web/server.py | 571 -- tools/buildbot/pylibs/twisted/web/soap.py | 154 - tools/buildbot/pylibs/twisted/web/static.py | 466 -- tools/buildbot/pylibs/twisted/web/sux.py | 657 --- tools/buildbot/pylibs/twisted/web/tap.py | 201 - tools/buildbot/pylibs/twisted/web/test/__init__.py | 1 - tools/buildbot/pylibs/twisted/web/test/test_cgi.py | 121 - .../pylibs/twisted/web/test/test_distrib.py | 64 - .../pylibs/twisted/web/test/test_domhelpers.py | 234 - .../buildbot/pylibs/twisted/web/test/test_http.py | 548 -- tools/buildbot/pylibs/twisted/web/test/test_mvc.py | 122 - .../buildbot/pylibs/twisted/web/test/test_proxy.py | 407 -- .../buildbot/pylibs/twisted/web/test/test_soap.py | 114 - .../pylibs/twisted/web/test/test_static.py | 64 - tools/buildbot/pylibs/twisted/web/test/test_tap.py | 33 - tools/buildbot/pylibs/twisted/web/test/test_web.py | 611 --- .../pylibs/twisted/web/test/test_webclient.py | 475 -- .../buildbot/pylibs/twisted/web/test/test_woven.py | 570 -- tools/buildbot/pylibs/twisted/web/test/test_xml.py | 760 --- .../pylibs/twisted/web/test/test_xmlrpc.py | 452 -- tools/buildbot/pylibs/twisted/web/topfiles/NEWS | 107 - tools/buildbot/pylibs/twisted/web/topfiles/README | 1 - .../buildbot/pylibs/twisted/web/topfiles/setup.py | 28 - tools/buildbot/pylibs/twisted/web/trp.py | 15 - tools/buildbot/pylibs/twisted/web/twcgi.py | 256 - tools/buildbot/pylibs/twisted/web/util.py | 390 -- tools/buildbot/pylibs/twisted/web/vhost.py | 141 - tools/buildbot/pylibs/twisted/web/widgets.py | 1050 ---- .../pylibs/twisted/web/woven/FlashConduit.fla | Bin 20992 -> 0 bytes .../pylibs/twisted/web/woven/FlashConduit.swf | Bin 882 -> 0 bytes .../pylibs/twisted/web/woven/FlashConduitGlue.html | 25 - .../twisted/web/woven/WebConduit2_mozilla.js | 82 - .../pylibs/twisted/web/woven/WebConduit2_msie.js | 105 - .../pylibs/twisted/web/woven/WebConduitGlue.html | 11 - .../buildbot/pylibs/twisted/web/woven/__init__.py | 3 - .../pylibs/twisted/web/woven/controller.py | 436 -- tools/buildbot/pylibs/twisted/web/woven/dirlist.py | 114 - .../pylibs/twisted/web/woven/flashconduit.py | 35 - tools/buildbot/pylibs/twisted/web/woven/form.py | 575 -- tools/buildbot/pylibs/twisted/web/woven/guard.py | 383 -- tools/buildbot/pylibs/twisted/web/woven/input.py | 347 -- .../pylibs/twisted/web/woven/interfaces.py | 198 - tools/buildbot/pylibs/twisted/web/woven/model.py | 487 -- tools/buildbot/pylibs/twisted/web/woven/page.py | 105 - .../pylibs/twisted/web/woven/simpleguard.py | 82 - .../buildbot/pylibs/twisted/web/woven/tapestry.py | 170 - .../buildbot/pylibs/twisted/web/woven/template.py | 374 -- tools/buildbot/pylibs/twisted/web/woven/utils.py | 198 - tools/buildbot/pylibs/twisted/web/woven/view.py | 687 --- tools/buildbot/pylibs/twisted/web/woven/widgets.py | 1036 ---- tools/buildbot/pylibs/twisted/web/xmlrpc.py | 414 -- tools/buildbot/pylibs/twisted/words/__init__.py | 10 - tools/buildbot/pylibs/twisted/words/_version.py | 3 - tools/buildbot/pylibs/twisted/words/ewords.py | 34 - tools/buildbot/pylibs/twisted/words/im/__init__.py | 8 - .../pylibs/twisted/words/im/baseaccount.py | 62 - tools/buildbot/pylibs/twisted/words/im/basechat.py | 316 -- .../pylibs/twisted/words/im/basesupport.py | 270 - .../buildbot/pylibs/twisted/words/im/gtkaccount.py | 224 - tools/buildbot/pylibs/twisted/words/im/gtkchat.py | 413 -- .../buildbot/pylibs/twisted/words/im/gtkcommon.py | 190 - .../twisted/words/im/instancemessenger.glade | 3165 ----------- .../buildbot/pylibs/twisted/words/im/interfaces.py | 324 -- .../buildbot/pylibs/twisted/words/im/ircsupport.py | 268 - .../buildbot/pylibs/twisted/words/im/jyaccount.py | 243 - tools/buildbot/pylibs/twisted/words/im/jychat.py | 286 - tools/buildbot/pylibs/twisted/words/im/locals.py | 26 - .../buildbot/pylibs/twisted/words/im/pbsupport.py | 260 - tools/buildbot/pylibs/twisted/words/im/proxyui.py | 24 - tools/buildbot/pylibs/twisted/words/im/tap.py | 15 - .../buildbot/pylibs/twisted/words/im/tocsupport.py | 220 - tools/buildbot/pylibs/twisted/words/iwords.py | 266 - .../pylibs/twisted/words/protocols/__init__.py | 1 - .../buildbot/pylibs/twisted/words/protocols/irc.py | 2329 --------- .../twisted/words/protocols/jabber/__init__.py | 8 - .../twisted/words/protocols/jabber/client.py | 369 -- .../twisted/words/protocols/jabber/component.py | 229 - .../pylibs/twisted/words/protocols/jabber/error.py | 336 -- .../twisted/words/protocols/jabber/ijabber.py | 199 - .../pylibs/twisted/words/protocols/jabber/jid.py | 249 - .../twisted/words/protocols/jabber/jstrports.py | 31 - .../pylibs/twisted/words/protocols/jabber/sasl.py | 225 - .../words/protocols/jabber/sasl_mechanisms.py | 224 - .../twisted/words/protocols/jabber/xmlstream.py | 1078 ---- .../words/protocols/jabber/xmpp_stringprep.py | 248 - .../buildbot/pylibs/twisted/words/protocols/msn.py | 2457 --------- .../pylibs/twisted/words/protocols/oscar.py | 1238 ----- .../buildbot/pylibs/twisted/words/protocols/toc.py | 1615 ------ .../pylibs/twisted/words/scripts/__init__.py | 1 - tools/buildbot/pylibs/twisted/words/scripts/im.py | 22 - tools/buildbot/pylibs/twisted/words/service.py | 1195 ----- tools/buildbot/pylibs/twisted/words/tap.py | 72 - .../buildbot/pylibs/twisted/words/test/__init__.py | 1 - .../pylibs/twisted/words/test/test_basesupport.py | 97 - .../pylibs/twisted/words/test/test_domish.py | 369 -- .../buildbot/pylibs/twisted/words/test/test_irc.py | 451 -- .../pylibs/twisted/words/test/test_jabberclient.py | 272 - .../twisted/words/test/test_jabbercomponent.py | 137 - .../pylibs/twisted/words/test/test_jabbererror.py | 308 -- .../pylibs/twisted/words/test/test_jabberjid.py | 225 - .../pylibs/twisted/words/test/test_jabbersasl.py | 171 - .../words/test/test_jabbersaslmechanisms.py | 75 - .../twisted/words/test/test_jabberxmlstream.py | 1174 ----- .../words/test/test_jabberxmppstringprep.py | 84 - .../buildbot/pylibs/twisted/words/test/test_msn.py | 379 -- .../pylibs/twisted/words/test/test_service.py | 936 ---- .../buildbot/pylibs/twisted/words/test/test_tap.py | 78 - .../buildbot/pylibs/twisted/words/test/test_toc.py | 343 -- .../pylibs/twisted/words/test/test_xishutil.py | 307 -- .../pylibs/twisted/words/test/test_xmlstream.py | 110 - .../pylibs/twisted/words/test/test_xpath.py | 260 - tools/buildbot/pylibs/twisted/words/toctap.py | 20 - tools/buildbot/pylibs/twisted/words/topfiles/NEWS | 135 - .../buildbot/pylibs/twisted/words/topfiles/README | 4 - .../pylibs/twisted/words/topfiles/setup.py | 51 - .../buildbot/pylibs/twisted/words/xish/__init__.py | 10 - tools/buildbot/pylibs/twisted/words/xish/domish.py | 831 --- .../buildbot/pylibs/twisted/words/xish/utility.py | 335 -- .../pylibs/twisted/words/xish/xmlstream.py | 211 - tools/buildbot/pylibs/twisted/words/xish/xpath.py | 333 -- .../pylibs/twisted/words/xish/xpathparser.g | 375 -- .../pylibs/twisted/words/xish/xpathparser.py | 508 -- tools/buildbot/pylibs/zope/PUBLICATION.cfg | 9 - tools/buildbot/pylibs/zope/README.google | 7 - tools/buildbot/pylibs/zope/README.txt | 18 - tools/buildbot/pylibs/zope/__init__.py | 22 - .../pylibs/zope/exceptions/DEPENDENCIES.cfg | 2 - tools/buildbot/pylibs/zope/exceptions/__init__.py | 34 - .../pylibs/zope/exceptions/exceptionformatter.py | 240 - .../buildbot/pylibs/zope/exceptions/interfaces.py | 114 - tools/buildbot/pylibs/zope/exceptions/log.py | 35 - .../pylibs/zope/exceptions/tests/__init__.py | 2 - .../exceptions/tests/test_exceptionformatter.py | 168 - .../pylibs/zope/interface/DEPENDENCIES.cfg | 1 - .../buildbot/pylibs/zope/interface/PUBLICATION.cfg | 8 - tools/buildbot/pylibs/zope/interface/README.ru.txt | 689 --- tools/buildbot/pylibs/zope/interface/README.txt | 807 --- tools/buildbot/pylibs/zope/interface/SETUP.cfg | 5 - tools/buildbot/pylibs/zope/interface/__init__.py | 80 - tools/buildbot/pylibs/zope/interface/_flatten.py | 37 - .../interface/_zope_interface_coptimizations.pyd | Bin 17408 -> 0 bytes tools/buildbot/pylibs/zope/interface/adapter.py | 644 --- tools/buildbot/pylibs/zope/interface/adapter.txt | 546 -- tools/buildbot/pylibs/zope/interface/advice.py | 192 - .../pylibs/zope/interface/common/__init__.py | 2 - .../pylibs/zope/interface/common/idatetime.py | 577 -- .../pylibs/zope/interface/common/interfaces.py | 98 - .../pylibs/zope/interface/common/mapping.py | 127 - .../pylibs/zope/interface/common/sequence.py | 152 - .../pylibs/zope/interface/common/tests/__init__.py | 2 - .../zope/interface/common/tests/basemapping.py | 115 - .../zope/interface/common/tests/test_idatetime.py | 49 - .../buildbot/pylibs/zope/interface/declarations.py | 1386 ----- tools/buildbot/pylibs/zope/interface/document.py | 107 - tools/buildbot/pylibs/zope/interface/exceptions.py | 69 - tools/buildbot/pylibs/zope/interface/human.ru.txt | 154 - tools/buildbot/pylibs/zope/interface/human.txt | 152 - tools/buildbot/pylibs/zope/interface/interface.py | 821 --- tools/buildbot/pylibs/zope/interface/interfaces.py | 730 --- tools/buildbot/pylibs/zope/interface/ro.py | 63 - .../pylibs/zope/interface/tests/__init__.py | 2 - .../buildbot/pylibs/zope/interface/tests/dummy.py | 25 - .../pylibs/zope/interface/tests/foodforthought.txt | 61 - tools/buildbot/pylibs/zope/interface/tests/ifoo.py | 28 - tools/buildbot/pylibs/zope/interface/tests/m1.py | 23 - tools/buildbot/pylibs/zope/interface/tests/m2.py | 17 - tools/buildbot/pylibs/zope/interface/tests/odd.py | 129 - .../pylibs/zope/interface/tests/test_adapter.py | 335 -- .../pylibs/zope/interface/tests/test_advice.py | 178 - .../zope/interface/tests/test_declarations.py | 416 -- .../pylibs/zope/interface/tests/test_document.py | 71 - .../pylibs/zope/interface/tests/test_element.py | 43 - .../pylibs/zope/interface/tests/test_interface.py | 352 -- .../zope/interface/tests/test_odd_declarations.py | 204 - .../pylibs/zope/interface/tests/test_sorting.py | 49 - .../pylibs/zope/interface/tests/test_verify.py | 196 - .../pylibs/zope/interface/tests/unitfixtures.py | 142 - tools/buildbot/pylibs/zope/interface/verify.py | 111 - .../buildbot/pylibs/zope/testing/DEPENDENCIES.cfg | 1 - tools/buildbot/pylibs/zope/testing/__init__.py | 17 - tools/buildbot/pylibs/zope/testing/cleanup.py | 65 - tools/buildbot/pylibs/zope/testing/doctest.py | 2745 ---------- tools/buildbot/pylibs/zope/testing/doctestunit.py | 33 - tools/buildbot/pylibs/zope/testing/formparser.py | 234 - tools/buildbot/pylibs/zope/testing/formparser.txt | 143 - .../buildbot/pylibs/zope/testing/loggingsupport.py | 124 - tools/buildbot/pylibs/zope/testing/loghandler.py | 77 - tools/buildbot/pylibs/zope/testing/module.py | 47 - .../buildbot/pylibs/zope/testing/renormalizing.py | 221 - tools/buildbot/pylibs/zope/testing/testrunner.py | 1921 ------- tools/buildbot/pylibs/zope/testing/testrunner.txt | 89 - tools/buildbot/pylibs/zope/testing/tests.py | 32 - tools/buildbot/scripts/common/chromium_commands.py | 386 -- tools/buildbot/scripts/common/chromium_config.py | 200 - tools/buildbot/scripts/common/chromium_utils.py | 437 -- tools/buildbot/scripts/common/twistd | 21 - tools/buildbot/scripts/master/bot_data.py | 193 - tools/buildbot/scripts/master/chromium_changes.py | 74 - tools/buildbot/scripts/master/chromium_factory.py | 19 - tools/buildbot/scripts/master/chromium_process.py | 148 - tools/buildbot/scripts/master/chromium_status.py | 686 --- tools/buildbot/scripts/master/chromium_step.py | 159 - tools/buildbot/scripts/master/copytree.py | 185 - tools/buildbot/scripts/master/factory_commands.py | 1001 ---- tools/buildbot/scripts/master/irc_contact.py | 804 --- tools/buildbot/scripts/master/json_file.py | 204 - .../buildbot/scripts/master/log_parser/__init__.py | 0 .../scripts/master/log_parser/archive_command.py | 36 - .../scripts/master/log_parser/cl_command.py | 276 - .../scripts/master/log_parser/gtest_command.py | 110 - .../scripts/master/log_parser/process_log.py | 871 ---- .../scripts/master/log_parser/retcode_command.py | 44 - .../master/log_parser/webkit_test_command.py | 112 - tools/buildbot/scripts/master/master_utils.py | 534 -- tools/buildbot/scripts/master/topics.html | 28 - .../master/unittests/chromium_changes_test.py | 51 - .../master/unittests/chromium_status_test.py | 157 - .../master/unittests/chromium_utils_test.py | 33 - .../scripts/master/unittests/data/benchpress_log | 28 - .../unittests/data/commit_charge-summary.dat | 1 - .../master/unittests/data/dest_startup_test_log | 19 - .../master/unittests/data/error-log-compile-stdio | 118 - .../unittests/data/error-log-compile-stdio-devenv | 83 - .../data/error-log-compile-stdio-devenv-converted | 83 - .../unittests/data/graphing_processor-graphs.dat | 1 - .../master/unittests/data/graphing_processor.log | 33 - .../master/unittests/data/ok-log-compile-stdio | 33 - .../scripts/master/unittests/data/page_cycler_log | 34 - .../unittests/data/page_cycler_log_duplicates | 83 - .../master/unittests/data/page_cycler_log_io | 56 - .../master/unittests/data/page_cycler_log_io_intl1 | 51 - .../scripts/master/unittests/data/playback_log | 50 - .../master/unittests/data/processes-summary.dat | 1 - .../scripts/master/unittests/data/startup_test_log | 28 - .../master/unittests/data/tab_switching_test_log | 9 - .../unittests/data/vm_final_browser-summary.dat | 1 - .../unittests/data/vm_final_total-summary.dat | 1 - .../unittests/data/ws_final_browser-summary.dat | 1 - .../unittests/data/ws_final_total-summary.dat | 1 - .../master/unittests/devenv_log_to_ib_log_test.py | 19 - .../master/unittests/gtest_command_unittest.py | 89 - .../master/unittests/ib_output_parser_test.py | 86 - .../scripts/master/unittests/master_utils_test.py | 38 - .../scripts/master/unittests/process_log_test.py | 564 -- .../buildbot/scripts/master/unittests/runtests.py | 72 - tools/buildbot/scripts/master/whuffie.html | 141 - tools/buildbot/scripts/slave/archive_build.py | 455 -- .../buildbot/scripts/slave/archive_crash_dumps.py | 76 - .../scripts/slave/archive_layout_test_results.py | 95 - tools/buildbot/scripts/slave/check_slave.py | 299 -- tools/buildbot/scripts/slave/compile.py | 182 - .../scripts/slave/differential_installer.py | 166 - tools/buildbot/scripts/slave/extract_build.py | 38 - tools/buildbot/scripts/slave/kill_processes.py | 67 - tools/buildbot/scripts/slave/known-crashes.txt | 1 - .../buildbot/scripts/slave/layout_test_wrapper.py | 116 - .../scripts/slave/node_leak_test_wrapper.py | 76 - tools/buildbot/scripts/slave/playback_tests.py | 96 - tools/buildbot/scripts/slave/run_crash_handler.py | 62 - tools/buildbot/scripts/slave/runtest.py | 164 - tools/buildbot/scripts/slave/slave_utils.py | 94 - 1761 files changed, 311426 deletions(-) delete mode 100644 tools/buildbot/config/master.chromium/DEPS delete mode 100644 tools/buildbot/config/master.chromium/Makefile delete mode 100644 tools/buildbot/config/master.chromium/Makefile.win32 delete mode 100644 tools/buildbot/config/master.chromium/README delete mode 100644 tools/buildbot/config/master.chromium/buildbot delete mode 100644 tools/buildbot/config/master.chromium/buildbot.tac delete mode 100644 tools/buildbot/config/master.chromium/master.cfg delete mode 100644 tools/buildbot/config/master.chromium/public_html/announce.html delete mode 100644 tools/buildbot/config/master.chromium/public_html/buildbot.css delete mode 100644 tools/buildbot/config/master.chromium/public_html/chromium-32.png delete mode 100644 tools/buildbot/config/master.chromium/public_html/favicon.ico delete mode 100644 tools/buildbot/config/master.chromium/public_html/index.html delete mode 100644 tools/buildbot/config/master.chromium/public_html/status-summary.html delete mode 100644 tools/buildbot/config/master.chromium/run_master.bat delete mode 100644 tools/buildbot/config/master.tryserver/DEPS delete mode 100644 tools/buildbot/config/master.tryserver/Makefile delete mode 100644 tools/buildbot/config/master.tryserver/Makefile.win32 delete mode 100644 tools/buildbot/config/master.tryserver/README delete mode 100644 tools/buildbot/config/master.tryserver/buildbot delete mode 100644 tools/buildbot/config/master.tryserver/buildbot.tac delete mode 100644 tools/buildbot/config/master.tryserver/mail_notifier.py delete mode 100644 tools/buildbot/config/master.tryserver/master.cfg delete mode 100644 tools/buildbot/config/master.tryserver/public_html/announce.html delete mode 100644 tools/buildbot/config/master.tryserver/public_html/buildbot.css delete mode 100644 tools/buildbot/config/master.tryserver/public_html/chromium-32.png delete mode 100644 tools/buildbot/config/master.tryserver/public_html/favicon.ico delete mode 100644 tools/buildbot/config/master.tryserver/public_html/index.html delete mode 100644 tools/buildbot/config/master.tryserver/public_html/status-summary.html delete mode 100644 tools/buildbot/config/master.tryserver/run_master.bat delete mode 100644 tools/buildbot/config/master.tryserver/try_job.py delete mode 100644 tools/buildbot/config/master.tryserver/unittests/master_test.py delete mode 100644 tools/buildbot/config/master.tryserver/unittests/try_job_test.py delete mode 100644 tools/buildbot/config/slave/DEPS delete mode 100644 tools/buildbot/config/slave/Makefile delete mode 100644 tools/buildbot/config/slave/buildbot.tac delete mode 100644 tools/buildbot/config/slave/cert/ssl_ui_test_root_ca.crt delete mode 100644 tools/buildbot/config/slave/crontab.in delete mode 100644 tools/buildbot/config/slave/info/admin delete mode 100644 tools/buildbot/config/slave/info/host delete mode 100644 tools/buildbot/config/slave/run_slave.bat delete mode 100644 tools/buildbot/config/slave/run_slave.py delete mode 100644 tools/buildbot/perf/dashboard/README.txt delete mode 100644 tools/buildbot/perf/dashboard/changelog.html delete mode 100644 tools/buildbot/perf/dashboard/details.html delete mode 100644 tools/buildbot/perf/dashboard/js/common.js delete mode 100644 tools/buildbot/perf/dashboard/js/plotter.js delete mode 100644 tools/buildbot/perf/dashboard/overview.html delete mode 100644 tools/buildbot/perf/dashboard/report.html delete mode 100644 tools/buildbot/perf/dashboard/svn-log delete mode 100644 tools/buildbot/perf/dashboard/ui/README.txt delete mode 100644 tools/buildbot/perf/dashboard/ui/config.js delete mode 100644 tools/buildbot/perf/dashboard/ui/details.html delete mode 100644 tools/buildbot/perf/dashboard/ui/generic_plotter.html delete mode 100644 tools/buildbot/perf/dashboard/ui/js/common.js delete mode 100644 tools/buildbot/perf/dashboard/ui/js/coordinates.js delete mode 100644 tools/buildbot/perf/dashboard/ui/js/plotter.js delete mode 100644 tools/buildbot/perf/dashboard/ui/pagecycler_report.html delete mode 100644 tools/buildbot/perf/dashboard/ui/playback_report.html delete mode 100644 tools/buildbot/perf/dashboard/ui/sunspider_report.html delete mode 100755 tools/buildbot/perf/generate_perf.sh delete mode 100644 tools/buildbot/perf/index.html delete mode 100644 tools/buildbot/pylibs/buildbot/COPYING delete mode 100644 tools/buildbot/pylibs/buildbot/CREDITS delete mode 100644 tools/buildbot/pylibs/buildbot/README.google delete mode 100644 tools/buildbot/pylibs/buildbot/__init__.py delete mode 100644 tools/buildbot/pylibs/buildbot/buildbot.png delete mode 100644 tools/buildbot/pylibs/buildbot/buildset.py delete mode 100644 tools/buildbot/pylibs/buildbot/buildslave.py delete mode 100644 tools/buildbot/pylibs/buildbot/changes/__init__.py delete mode 100644 tools/buildbot/pylibs/buildbot/changes/base.py delete mode 100644 tools/buildbot/pylibs/buildbot/changes/bonsaipoller.py delete mode 100644 tools/buildbot/pylibs/buildbot/changes/changes.py delete mode 100644 tools/buildbot/pylibs/buildbot/changes/dnotify.py delete mode 100644 tools/buildbot/pylibs/buildbot/changes/freshcvs.py delete mode 100644 tools/buildbot/pylibs/buildbot/changes/hgbuildbot.py delete mode 100644 tools/buildbot/pylibs/buildbot/changes/mail.py delete mode 100644 tools/buildbot/pylibs/buildbot/changes/maildir.py delete mode 100644 tools/buildbot/pylibs/buildbot/changes/monotone.py delete mode 100644 tools/buildbot/pylibs/buildbot/changes/p4poller.py delete mode 100644 tools/buildbot/pylibs/buildbot/changes/pb.py delete mode 100644 tools/buildbot/pylibs/buildbot/changes/svnpoller.py delete mode 100644 tools/buildbot/pylibs/buildbot/clients/__init__.py delete mode 100644 tools/buildbot/pylibs/buildbot/clients/base.py delete mode 100644 tools/buildbot/pylibs/buildbot/clients/debug.glade delete mode 100644 tools/buildbot/pylibs/buildbot/clients/debug.py delete mode 100644 tools/buildbot/pylibs/buildbot/clients/gtkPanes.py delete mode 100644 tools/buildbot/pylibs/buildbot/clients/sendchange.py delete mode 100644 tools/buildbot/pylibs/buildbot/dnotify.py delete mode 100644 tools/buildbot/pylibs/buildbot/interfaces.py delete mode 100644 tools/buildbot/pylibs/buildbot/locks.py delete mode 100644 tools/buildbot/pylibs/buildbot/manhole.py delete mode 100644 tools/buildbot/pylibs/buildbot/master.py delete mode 100644 tools/buildbot/pylibs/buildbot/pbutil.py delete mode 100644 tools/buildbot/pylibs/buildbot/process/__init__.py delete mode 100644 tools/buildbot/pylibs/buildbot/process/base.py delete mode 100644 tools/buildbot/pylibs/buildbot/process/builder.py delete mode 100644 tools/buildbot/pylibs/buildbot/process/buildstep.py delete mode 100644 tools/buildbot/pylibs/buildbot/process/factory.py delete mode 100644 tools/buildbot/pylibs/buildbot/process/process_twisted.py delete mode 100644 tools/buildbot/pylibs/buildbot/process/properties.py delete mode 100644 tools/buildbot/pylibs/buildbot/process/step_twisted2.py delete mode 100644 tools/buildbot/pylibs/buildbot/scheduler.py delete mode 100644 tools/buildbot/pylibs/buildbot/scripts/__init__.py delete mode 100644 tools/buildbot/pylibs/buildbot/scripts/checkconfig.py delete mode 100644 tools/buildbot/pylibs/buildbot/scripts/logwatcher.py delete mode 100644 tools/buildbot/pylibs/buildbot/scripts/reconfig.py delete mode 100644 tools/buildbot/pylibs/buildbot/scripts/runner.py delete mode 100644 tools/buildbot/pylibs/buildbot/scripts/sample.cfg delete mode 100644 tools/buildbot/pylibs/buildbot/scripts/startup.py delete mode 100644 tools/buildbot/pylibs/buildbot/scripts/tryclient.py delete mode 100644 tools/buildbot/pylibs/buildbot/slave/__init__.py delete mode 100644 tools/buildbot/pylibs/buildbot/slave/bot.py delete mode 100644 tools/buildbot/pylibs/buildbot/slave/bot_orig.py delete mode 100644 tools/buildbot/pylibs/buildbot/slave/commands.py delete mode 100644 tools/buildbot/pylibs/buildbot/slave/interfaces.py delete mode 100644 tools/buildbot/pylibs/buildbot/slave/registry.py delete mode 100644 tools/buildbot/pylibs/buildbot/sourcestamp.py delete mode 100644 tools/buildbot/pylibs/buildbot/status/__init__.py delete mode 100644 tools/buildbot/pylibs/buildbot/status/base.py delete mode 100644 tools/buildbot/pylibs/buildbot/status/builder.py delete mode 100644 tools/buildbot/pylibs/buildbot/status/client.py delete mode 100644 tools/buildbot/pylibs/buildbot/status/html.py delete mode 100644 tools/buildbot/pylibs/buildbot/status/mail.py delete mode 100644 tools/buildbot/pylibs/buildbot/status/progress.py delete mode 100644 tools/buildbot/pylibs/buildbot/status/tests.py delete mode 100644 tools/buildbot/pylibs/buildbot/status/tinderbox.py delete mode 100644 tools/buildbot/pylibs/buildbot/status/web/__init__.py delete mode 100644 tools/buildbot/pylibs/buildbot/status/web/about.py delete mode 100644 tools/buildbot/pylibs/buildbot/status/web/base.py delete mode 100644 tools/buildbot/pylibs/buildbot/status/web/baseweb.py delete mode 100644 tools/buildbot/pylibs/buildbot/status/web/build.py delete mode 100644 tools/buildbot/pylibs/buildbot/status/web/builder.py delete mode 100644 tools/buildbot/pylibs/buildbot/status/web/changes.py delete mode 100644 tools/buildbot/pylibs/buildbot/status/web/classic.css delete mode 100644 tools/buildbot/pylibs/buildbot/status/web/grid.py delete mode 100644 tools/buildbot/pylibs/buildbot/status/web/index.html delete mode 100644 tools/buildbot/pylibs/buildbot/status/web/logs.py delete mode 100644 tools/buildbot/pylibs/buildbot/status/web/robots.txt delete mode 100644 tools/buildbot/pylibs/buildbot/status/web/slaves.py delete mode 100644 tools/buildbot/pylibs/buildbot/status/web/step.py delete mode 100644 tools/buildbot/pylibs/buildbot/status/web/tests.py delete mode 100644 tools/buildbot/pylibs/buildbot/status/web/waterfall.py delete mode 100644 tools/buildbot/pylibs/buildbot/status/web/xmlrpc.py delete mode 100644 tools/buildbot/pylibs/buildbot/status/words.py delete mode 100644 tools/buildbot/pylibs/buildbot/steps/__init__.py delete mode 100644 tools/buildbot/pylibs/buildbot/steps/dummy.py delete mode 100644 tools/buildbot/pylibs/buildbot/steps/maxq.py delete mode 100644 tools/buildbot/pylibs/buildbot/steps/python.py delete mode 100644 tools/buildbot/pylibs/buildbot/steps/python_twisted.py delete mode 100644 tools/buildbot/pylibs/buildbot/steps/shell.py delete mode 100644 tools/buildbot/pylibs/buildbot/steps/source.py delete mode 100644 tools/buildbot/pylibs/buildbot/steps/transfer.py delete mode 100644 tools/buildbot/pylibs/buildbot/steps/trigger.py delete mode 100644 tools/buildbot/pylibs/buildbot/test/__init__.py delete mode 100644 tools/buildbot/pylibs/buildbot/test/emit.py delete mode 100644 tools/buildbot/pylibs/buildbot/test/emitlogs.py delete mode 100644 tools/buildbot/pylibs/buildbot/test/mail/freshcvs.1 delete mode 100644 tools/buildbot/pylibs/buildbot/test/mail/freshcvs.2 delete mode 100644 tools/buildbot/pylibs/buildbot/test/mail/freshcvs.3 delete mode 100644 tools/buildbot/pylibs/buildbot/test/mail/freshcvs.4 delete mode 100644 tools/buildbot/pylibs/buildbot/test/mail/freshcvs.5 delete mode 100644 tools/buildbot/pylibs/buildbot/test/mail/freshcvs.6 delete mode 100644 tools/buildbot/pylibs/buildbot/test/mail/freshcvs.7 delete mode 100644 tools/buildbot/pylibs/buildbot/test/mail/freshcvs.8 delete mode 100644 tools/buildbot/pylibs/buildbot/test/mail/freshcvs.9 delete mode 100644 tools/buildbot/pylibs/buildbot/test/mail/svn-commit.1 delete mode 100644 tools/buildbot/pylibs/buildbot/test/mail/svn-commit.2 delete mode 100644 tools/buildbot/pylibs/buildbot/test/mail/syncmail.1 delete mode 100644 tools/buildbot/pylibs/buildbot/test/mail/syncmail.2 delete mode 100644 tools/buildbot/pylibs/buildbot/test/mail/syncmail.3 delete mode 100644 tools/buildbot/pylibs/buildbot/test/mail/syncmail.4 delete mode 100644 tools/buildbot/pylibs/buildbot/test/mail/syncmail.5 delete mode 100644 tools/buildbot/pylibs/buildbot/test/runutils.py delete mode 100644 tools/buildbot/pylibs/buildbot/test/sleep.py delete mode 100644 tools/buildbot/pylibs/buildbot/test/subdir/emit.py delete mode 100644 tools/buildbot/pylibs/buildbot/test/test__versions.py delete mode 100644 tools/buildbot/pylibs/buildbot/test/test_bonsaipoller.py delete mode 100644 tools/buildbot/pylibs/buildbot/test/test_buildreq.py delete mode 100644 tools/buildbot/pylibs/buildbot/test/test_buildstep.py delete mode 100644 tools/buildbot/pylibs/buildbot/test/test_changes.py delete mode 100644 tools/buildbot/pylibs/buildbot/test/test_config.py delete mode 100644 tools/buildbot/pylibs/buildbot/test/test_control.py delete mode 100644 tools/buildbot/pylibs/buildbot/test/test_dependencies.py delete mode 100644 tools/buildbot/pylibs/buildbot/test/test_locks.py delete mode 100644 tools/buildbot/pylibs/buildbot/test/test_maildir.py delete mode 100644 tools/buildbot/pylibs/buildbot/test/test_mailparse.py delete mode 100644 tools/buildbot/pylibs/buildbot/test/test_p4poller.py delete mode 100644 tools/buildbot/pylibs/buildbot/test/test_properties.py delete mode 100644 tools/buildbot/pylibs/buildbot/test/test_run.py delete mode 100644 tools/buildbot/pylibs/buildbot/test/test_runner.py delete mode 100644 tools/buildbot/pylibs/buildbot/test/test_scheduler.py delete mode 100644 tools/buildbot/pylibs/buildbot/test/test_shell.py delete mode 100644 tools/buildbot/pylibs/buildbot/test/test_slavecommand.py delete mode 100644 tools/buildbot/pylibs/buildbot/test/test_slaves.py delete mode 100644 tools/buildbot/pylibs/buildbot/test/test_status.py delete mode 100644 tools/buildbot/pylibs/buildbot/test/test_steps.py delete mode 100644 tools/buildbot/pylibs/buildbot/test/test_svnpoller.py delete mode 100644 tools/buildbot/pylibs/buildbot/test/test_transfer.py delete mode 100644 tools/buildbot/pylibs/buildbot/test/test_twisted.py delete mode 100644 tools/buildbot/pylibs/buildbot/test/test_util.py delete mode 100644 tools/buildbot/pylibs/buildbot/test/test_vc.py delete mode 100644 tools/buildbot/pylibs/buildbot/test/test_web.py delete mode 100644 tools/buildbot/pylibs/buildbot/test/test_webparts.py delete mode 100644 tools/buildbot/pylibs/buildbot/util.py delete mode 100644 tools/buildbot/pylibs/pytz/EGG-INFO/PKG-INFO delete mode 100644 tools/buildbot/pylibs/pytz/EGG-INFO/SOURCES.txt delete mode 100644 tools/buildbot/pylibs/pytz/EGG-INFO/dependency_links.txt delete mode 100644 tools/buildbot/pylibs/pytz/EGG-INFO/top_level.txt delete mode 100644 tools/buildbot/pylibs/pytz/EGG-INFO/zip-safe delete mode 100644 tools/buildbot/pylibs/pytz/README.google delete mode 100644 tools/buildbot/pylibs/pytz/__init__.py delete mode 100644 tools/buildbot/pylibs/pytz/reference.py delete mode 100644 tools/buildbot/pylibs/pytz/tzfile.py delete mode 100644 tools/buildbot/pylibs/pytz/tzinfo.py delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Abidjan delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Accra delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Addis_Ababa delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Algiers delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Asmara delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Asmera delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Bamako delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Bangui delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Banjul delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Bissau delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Blantyre delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Brazzaville delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Bujumbura delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Cairo delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Casablanca delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Ceuta delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Conakry delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Dakar delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Dar_es_Salaam delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Djibouti delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Douala delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/El_Aaiun delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Freetown delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Gaborone delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Harare delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Johannesburg delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Kampala delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Khartoum delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Kigali delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Kinshasa delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Lagos delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Libreville delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Lome delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Luanda delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Lubumbashi delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Lusaka delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Malabo delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Maputo delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Maseru delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Mbabane delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Mogadishu delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Monrovia delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Nairobi delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Ndjamena delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Niamey delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Nouakchott delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Ouagadougou delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Porto-Novo delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Sao_Tome delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Timbuktu delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Tripoli delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Tunis delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Africa/Windhoek delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Adak delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Anchorage delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Anguilla delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Antigua delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Araguaina delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/Buenos_Aires delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/Catamarca delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/ComodRivadavia delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/Cordoba delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/Jujuy delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/La_Rioja delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/Mendoza delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/Rio_Gallegos delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/San_Juan delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/Tucuman delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/Ushuaia delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Aruba delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Asuncion delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Atikokan delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Atka delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Bahia delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Barbados delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Belem delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Belize delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Blanc-Sablon delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Boa_Vista delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Bogota delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Boise delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Buenos_Aires delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Cambridge_Bay delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Campo_Grande delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Cancun delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Caracas delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Catamarca delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Cayenne delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Cayman delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Chicago delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Chihuahua delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Coral_Harbour delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Cordoba delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Costa_Rica delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Cuiaba delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Curacao delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Danmarkshavn delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Dawson delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Dawson_Creek delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Denver delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Detroit delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Dominica delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Edmonton delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Eirunepe delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/El_Salvador delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Ensenada delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Fort_Wayne delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Fortaleza delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Glace_Bay delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Godthab delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Goose_Bay delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Grand_Turk delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Grenada delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Guadeloupe delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Guatemala delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Guayaquil delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Guyana delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Halifax delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Havana delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Hermosillo delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Indiana/Indianapolis delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Indiana/Knox delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Indiana/Marengo delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Indiana/Petersburg delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Indiana/Tell_City delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Indiana/Vevay delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Indiana/Vincennes delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Indiana/Winamac delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Indianapolis delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Inuvik delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Iqaluit delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Jamaica delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Jujuy delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Juneau delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Kentucky/Louisville delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Kentucky/Monticello delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Knox_IN delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/La_Paz delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Lima delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Los_Angeles delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Louisville delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Maceio delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Managua delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Manaus delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Marigot delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Martinique delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Mazatlan delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Mendoza delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Menominee delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Merida delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Mexico_City delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Miquelon delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Moncton delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Monterrey delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Montevideo delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Montreal delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Montserrat delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Nassau delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/New_York delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Nipigon delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Nome delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Noronha delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/North_Dakota/Center delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/North_Dakota/New_Salem delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Panama delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Pangnirtung delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Paramaribo delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Phoenix delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Port-au-Prince delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Port_of_Spain delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Porto_Acre delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Porto_Velho delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Puerto_Rico delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Rainy_River delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Rankin_Inlet delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Recife delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Regina delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Resolute delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Rio_Branco delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Rosario delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Santiago delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Santo_Domingo delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Sao_Paulo delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Scoresbysund delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Shiprock delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/St_Barthelemy delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/St_Johns delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/St_Kitts delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/St_Lucia delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/St_Thomas delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/St_Vincent delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Swift_Current delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Tegucigalpa delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Thule delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Thunder_Bay delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Tijuana delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Toronto delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Tortola delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Vancouver delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Virgin delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Whitehorse delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Winnipeg delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Yakutat delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/America/Yellowknife delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/Casey delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/Davis delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/DumontDUrville delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/Mawson delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/McMurdo delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/Palmer delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/Rothera delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/South_Pole delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/Syowa delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/Vostok delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Arctic/Longyearbyen delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Aden delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Almaty delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Amman delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Anadyr delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Aqtau delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Aqtobe delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Ashgabat delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Ashkhabad delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Baghdad delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Bahrain delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Baku delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Bangkok delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Beirut delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Bishkek delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Brunei delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Calcutta delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Choibalsan delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Chongqing delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Chungking delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Colombo delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Dacca delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Damascus delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Dhaka delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Dili delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Dubai delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Dushanbe delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Gaza delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Harbin delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Hong_Kong delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Hovd delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Irkutsk delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Istanbul delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Jakarta delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Jayapura delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Jerusalem delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Kabul delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Kamchatka delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Karachi delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Kashgar delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Katmandu delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Krasnoyarsk delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Kuala_Lumpur delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Kuching delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Kuwait delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Macao delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Macau delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Magadan delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Makassar delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Manila delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Muscat delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Nicosia delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Novosibirsk delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Omsk delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Oral delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Phnom_Penh delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Pontianak delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Pyongyang delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Qatar delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Qyzylorda delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Rangoon delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Riyadh delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Riyadh87 delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Riyadh88 delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Riyadh89 delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Saigon delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Sakhalin delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Samarkand delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Seoul delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Shanghai delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Singapore delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Taipei delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Tashkent delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Tbilisi delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Tehran delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Tel_Aviv delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Thimbu delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Thimphu delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Tokyo delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Ujung_Pandang delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Ulaanbaatar delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Ulan_Bator delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Urumqi delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Vientiane delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Vladivostok delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Yakutsk delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Yekaterinburg delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Asia/Yerevan delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Azores delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Bermuda delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Canary delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Cape_Verde delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Faeroe delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Faroe delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Jan_Mayen delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Madeira delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Reykjavik delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/South_Georgia delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/St_Helena delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Stanley delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Australia/ACT delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Australia/Adelaide delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Australia/Brisbane delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Australia/Broken_Hill delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Australia/Canberra delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Australia/Currie delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Australia/Darwin delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Australia/Eucla delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Australia/Hobart delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Australia/LHI delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Australia/Lindeman delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Australia/Lord_Howe delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Australia/Melbourne delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Australia/NSW delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Australia/North delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Australia/Perth delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Australia/Queensland delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Australia/South delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Australia/Sydney delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Australia/Tasmania delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Australia/Victoria delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Australia/West delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Australia/Yancowinna delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Brazil/Acre delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Brazil/DeNoronha delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Brazil/East delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Brazil/West delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/CET delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/CST6CDT delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Canada/Atlantic delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Canada/Central delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Canada/East-Saskatchewan delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Canada/Eastern delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Canada/Mountain delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Canada/Newfoundland delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Canada/Pacific delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Canada/Saskatchewan delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Canada/Yukon delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Chile/Continental delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Chile/EasterIsland delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Cuba delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/EET delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/EST delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/EST5EDT delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Egypt delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Eire delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+0 delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+1 delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+10 delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+11 delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+12 delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+2 delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+3 delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+4 delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+5 delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+6 delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+7 delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+8 delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+9 delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-0 delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-1 delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-10 delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-11 delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-12 delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-13 delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-14 delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-2 delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-3 delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-4 delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-5 delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-6 delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-7 delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-8 delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-9 delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT0 delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Etc/Greenwich delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Etc/UCT delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Etc/UTC delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Etc/Universal delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Etc/Zulu delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Amsterdam delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Andorra delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Athens delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Belfast delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Belgrade delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Berlin delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Bratislava delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Brussels delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Bucharest delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Budapest delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Chisinau delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Copenhagen delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Dublin delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Gibraltar delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Guernsey delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Helsinki delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Isle_of_Man delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Istanbul delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Jersey delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Kaliningrad delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Kiev delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Lisbon delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Ljubljana delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/London delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Luxembourg delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Madrid delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Malta delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Mariehamn delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Minsk delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Monaco delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Moscow delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Nicosia delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Oslo delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Paris delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Podgorica delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Prague delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Riga delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Rome delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Samara delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/San_Marino delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Sarajevo delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Simferopol delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Skopje delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Sofia delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Stockholm delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Tallinn delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Tirane delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Tiraspol delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Uzhgorod delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Vaduz delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Vatican delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Vienna delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Vilnius delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Volgograd delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Warsaw delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Zagreb delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Zaporozhye delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Europe/Zurich delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Factory delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/GB delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/GB-Eire delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/GMT delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/GMT+0 delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/GMT-0 delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/GMT0 delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Greenwich delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/HST delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Hongkong delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Iceland delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Indian/Antananarivo delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Indian/Chagos delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Indian/Christmas delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Indian/Cocos delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Indian/Comoro delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Indian/Kerguelen delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Indian/Mahe delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Indian/Maldives delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Indian/Mauritius delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Indian/Mayotte delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Indian/Reunion delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Iran delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Israel delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Jamaica delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Japan delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Kwajalein delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Libya delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/MET delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/MST delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/MST7MDT delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Mexico/BajaNorte delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Mexico/BajaSur delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Mexico/General delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Mideast/Riyadh87 delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Mideast/Riyadh88 delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Mideast/Riyadh89 delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/NZ delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/NZ-CHAT delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Navajo delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/PRC delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/PST8PDT delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Apia delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Auckland delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Chatham delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Easter delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Efate delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Enderbury delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Fakaofo delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Fiji delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Funafuti delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Galapagos delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Gambier delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Guadalcanal delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Guam delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Honolulu delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Johnston delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Kiritimati delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Kosrae delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Kwajalein delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Majuro delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Marquesas delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Midway delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Nauru delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Niue delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Norfolk delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Noumea delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Pago_Pago delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Palau delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Pitcairn delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Ponape delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Port_Moresby delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Rarotonga delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Saipan delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Samoa delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Tahiti delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Tarawa delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Tongatapu delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Truk delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Wake delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Wallis delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Yap delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Poland delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Portugal delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/ROC delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/ROK delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Singapore delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Turkey delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/UCT delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/US/Alaska delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/US/Aleutian delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/US/Arizona delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/US/Central delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/US/East-Indiana delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/US/Eastern delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/US/Hawaii delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/US/Indiana-Starke delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/US/Michigan delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/US/Mountain delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/US/Pacific delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/US/Pacific-New delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/US/Samoa delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/UTC delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Universal delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/W-SU delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/WET delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/Zulu delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/iso3166.tab delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/localtime delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/posixrules delete mode 100644 tools/buildbot/pylibs/pytz/zoneinfo/zone.tab delete mode 100644 tools/buildbot/pylibs/simplejson/README.google delete mode 100644 tools/buildbot/pylibs/simplejson/__init__.py delete mode 100644 tools/buildbot/pylibs/simplejson/_speedups.c delete mode 100644 tools/buildbot/pylibs/simplejson/decoder.py delete mode 100644 tools/buildbot/pylibs/simplejson/encoder.py delete mode 100644 tools/buildbot/pylibs/simplejson/jsonfilter.py delete mode 100644 tools/buildbot/pylibs/simplejson/scanner.py delete mode 100644 tools/buildbot/pylibs/twisted/LICENSE delete mode 100644 tools/buildbot/pylibs/twisted/README.google delete mode 100644 tools/buildbot/pylibs/twisted/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/_version.py delete mode 100644 tools/buildbot/pylibs/twisted/application/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/application/app.py delete mode 100644 tools/buildbot/pylibs/twisted/application/internet.py delete mode 100644 tools/buildbot/pylibs/twisted/application/reactors.py delete mode 100644 tools/buildbot/pylibs/twisted/application/service.py delete mode 100644 tools/buildbot/pylibs/twisted/application/strports.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/_version.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/avatar.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/checkers.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/client/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/client/agent.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/client/connect.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/client/default.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/client/direct.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/client/options.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/client/unix.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/error.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/insults/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/insults/client.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/insults/colors.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/insults/helper.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/insults/insults.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/insults/text.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/insults/window.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/interfaces.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/ls.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/manhole.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/manhole_ssh.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/manhole_tap.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/mixin.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/openssh_compat/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/openssh_compat/factory.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/openssh_compat/primes.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/recvline.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/scripts/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/scripts/cftp.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/scripts/ckeygen.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/scripts/conch.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/scripts/tkconch.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/ssh/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/ssh/agent.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/ssh/asn1.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/ssh/channel.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/ssh/common.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/ssh/connection.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/ssh/factory.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/ssh/filetransfer.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/ssh/forwarding.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/ssh/keys.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/ssh/service.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/ssh/session.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/ssh/sexpy.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/ssh/transport.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/ssh/userauth.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/stdio.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/tap.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/telnet.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/test/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/test/keydata.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/test/test_cftp.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/test/test_channel.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/test/test_conch.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/test/test_connection.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/test/test_filetransfer.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/test/test_helper.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/test/test_insults.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/test/test_keys.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/test/test_manhole.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/test/test_mixin.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/test/test_recvline.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/test/test_ssh.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/test/test_telnet.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/test/test_text.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/test/test_transport.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/test/test_userauth.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/test/test_window.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/topfiles/NEWS delete mode 100644 tools/buildbot/pylibs/twisted/conch/topfiles/README delete mode 100644 tools/buildbot/pylibs/twisted/conch/topfiles/setup.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/ttymodes.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/ui/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/ui/ansi.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/ui/tkvt100.py delete mode 100644 tools/buildbot/pylibs/twisted/conch/unix.py delete mode 100644 tools/buildbot/pylibs/twisted/copyright.py delete mode 100644 tools/buildbot/pylibs/twisted/cred/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/cred/checkers.py delete mode 100644 tools/buildbot/pylibs/twisted/cred/credentials.py delete mode 100644 tools/buildbot/pylibs/twisted/cred/error.py delete mode 100644 tools/buildbot/pylibs/twisted/cred/pamauth.py delete mode 100644 tools/buildbot/pylibs/twisted/cred/portal.py delete mode 100644 tools/buildbot/pylibs/twisted/cred/strcred.py delete mode 100644 tools/buildbot/pylibs/twisted/cred/util.py delete mode 100644 tools/buildbot/pylibs/twisted/enterprise/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/enterprise/adbapi.py delete mode 100644 tools/buildbot/pylibs/twisted/enterprise/reflector.py delete mode 100644 tools/buildbot/pylibs/twisted/enterprise/row.py delete mode 100644 tools/buildbot/pylibs/twisted/enterprise/sqlreflector.py delete mode 100644 tools/buildbot/pylibs/twisted/enterprise/util.py delete mode 100644 tools/buildbot/pylibs/twisted/flow/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/flow/_version.py delete mode 100644 tools/buildbot/pylibs/twisted/flow/base.py delete mode 100644 tools/buildbot/pylibs/twisted/flow/controller.py delete mode 100644 tools/buildbot/pylibs/twisted/flow/flow.py delete mode 100644 tools/buildbot/pylibs/twisted/flow/pipe.py delete mode 100644 tools/buildbot/pylibs/twisted/flow/protocol.py delete mode 100644 tools/buildbot/pylibs/twisted/flow/stage.py delete mode 100644 tools/buildbot/pylibs/twisted/flow/test/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/flow/test/test_flow.py delete mode 100644 tools/buildbot/pylibs/twisted/flow/threads.py delete mode 100644 tools/buildbot/pylibs/twisted/flow/topfiles/README delete mode 100644 tools/buildbot/pylibs/twisted/flow/topfiles/setup.py delete mode 100644 tools/buildbot/pylibs/twisted/flow/web.py delete mode 100644 tools/buildbot/pylibs/twisted/flow/wrap.py delete mode 100644 tools/buildbot/pylibs/twisted/im.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/_dumbwin32proc.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/_dumbwin32proc_orig.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/_javaserialport.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/_pollingfile.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/_posixserialport.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/_posixstdio.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/_sslverify.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/_threadedselect.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/_win32serialport.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/_win32stdio.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/abstract.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/address.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/base.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/cfreactor.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/cfsupport/cfdate.pxi delete mode 100644 tools/buildbot/pylibs/twisted/internet/cfsupport/cfdecl.pxi delete mode 100644 tools/buildbot/pylibs/twisted/internet/cfsupport/cfrunloop.pxi delete mode 100644 tools/buildbot/pylibs/twisted/internet/cfsupport/cfsocket.pxi delete mode 100644 tools/buildbot/pylibs/twisted/internet/cfsupport/cfsupport.c delete mode 100644 tools/buildbot/pylibs/twisted/internet/cfsupport/cfsupport.pyx delete mode 100644 tools/buildbot/pylibs/twisted/internet/cfsupport/python.pxi delete mode 100644 tools/buildbot/pylibs/twisted/internet/cfsupport/setup.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/default.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/defer.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/epollreactor.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/error.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/fdesc.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/glib2reactor.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/gtk2reactor.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/gtkreactor.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/interfaces.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/iocpreactor/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/iocpreactor/abstract.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/iocpreactor/build.bat delete mode 100644 tools/buildbot/pylibs/twisted/internet/iocpreactor/const.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/iocpreactor/interfaces.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/iocpreactor/iocpsupport/acceptex.pxi delete mode 100644 tools/buildbot/pylibs/twisted/internet/iocpreactor/iocpsupport/connectex.pxi delete mode 100644 tools/buildbot/pylibs/twisted/internet/iocpreactor/iocpsupport/iocpsupport.c delete mode 100644 tools/buildbot/pylibs/twisted/internet/iocpreactor/iocpsupport/iocpsupport.pyx delete mode 100644 tools/buildbot/pylibs/twisted/internet/iocpreactor/iocpsupport/winsock_pointers.c delete mode 100644 tools/buildbot/pylibs/twisted/internet/iocpreactor/iocpsupport/winsock_pointers.h delete mode 100644 tools/buildbot/pylibs/twisted/internet/iocpreactor/iocpsupport/wsarecv.pxi delete mode 100644 tools/buildbot/pylibs/twisted/internet/iocpreactor/iocpsupport/wsasend.pxi delete mode 100644 tools/buildbot/pylibs/twisted/internet/iocpreactor/notes.txt delete mode 100644 tools/buildbot/pylibs/twisted/internet/iocpreactor/reactor.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/iocpreactor/setup.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/iocpreactor/tcp.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/iocpreactor/udp.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/kqreactor.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/main.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/pollreactor.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/posixbase.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/process.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/protocol.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/pyuisupport.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/qtreactor.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/reactor.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/selectreactor.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/serialport.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/ssl.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/stdio.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/task.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/tcp.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/test/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/test/test_gtk2reactor.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/test/test_iocp.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/threads.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/tksupport.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/udp.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/unix.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/utils.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/win32eventreactor.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/wxreactor.py delete mode 100644 tools/buildbot/pylibs/twisted/internet/wxsupport.py delete mode 100644 tools/buildbot/pylibs/twisted/lore/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/lore/_version.py delete mode 100644 tools/buildbot/pylibs/twisted/lore/default.py delete mode 100644 tools/buildbot/pylibs/twisted/lore/docbook.py delete mode 100644 tools/buildbot/pylibs/twisted/lore/htmlbook.py delete mode 100644 tools/buildbot/pylibs/twisted/lore/indexer.py delete mode 100644 tools/buildbot/pylibs/twisted/lore/latex.py delete mode 100644 tools/buildbot/pylibs/twisted/lore/lint.py delete mode 100644 tools/buildbot/pylibs/twisted/lore/lmath.py delete mode 100644 tools/buildbot/pylibs/twisted/lore/man2lore.py delete mode 100644 tools/buildbot/pylibs/twisted/lore/nevowlore.py delete mode 100644 tools/buildbot/pylibs/twisted/lore/numberer.py delete mode 100644 tools/buildbot/pylibs/twisted/lore/process.py delete mode 100644 tools/buildbot/pylibs/twisted/lore/scripts/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/lore/scripts/lore.py delete mode 100644 tools/buildbot/pylibs/twisted/lore/slides.py delete mode 100644 tools/buildbot/pylibs/twisted/lore/template.mgp delete mode 100644 tools/buildbot/pylibs/twisted/lore/test/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/lore/test/good_internal.xhtml delete mode 100644 tools/buildbot/pylibs/twisted/lore/test/good_simple.xhtml delete mode 100644 tools/buildbot/pylibs/twisted/lore/test/lore_index_file_out.html delete mode 100644 tools/buildbot/pylibs/twisted/lore/test/lore_index_file_out_multiple.html delete mode 100644 tools/buildbot/pylibs/twisted/lore/test/lore_index_file_unnumbered_multiple_out.html delete mode 100644 tools/buildbot/pylibs/twisted/lore/test/lore_index_file_unnumbered_out.html delete mode 100644 tools/buildbot/pylibs/twisted/lore/test/lore_index_test.xhtml delete mode 100644 tools/buildbot/pylibs/twisted/lore/test/lore_index_test2.xhtml delete mode 100644 tools/buildbot/pylibs/twisted/lore/test/lore_index_test3.xhtml delete mode 100644 tools/buildbot/pylibs/twisted/lore/test/lore_index_test_out.html delete mode 100644 tools/buildbot/pylibs/twisted/lore/test/lore_index_test_out2.html delete mode 100644 tools/buildbot/pylibs/twisted/lore/test/lore_numbering_test.xhtml delete mode 100644 tools/buildbot/pylibs/twisted/lore/test/lore_numbering_test_out.html delete mode 100644 tools/buildbot/pylibs/twisted/lore/test/lore_numbering_test_out2.html delete mode 100644 tools/buildbot/pylibs/twisted/lore/test/simple.html delete mode 100644 tools/buildbot/pylibs/twisted/lore/test/simple.xhtml delete mode 100644 tools/buildbot/pylibs/twisted/lore/test/simple1.xhtml delete mode 100644 tools/buildbot/pylibs/twisted/lore/test/simple2.xhtml delete mode 100644 tools/buildbot/pylibs/twisted/lore/test/simple3.html delete mode 100644 tools/buildbot/pylibs/twisted/lore/test/simple3.xhtml delete mode 100644 tools/buildbot/pylibs/twisted/lore/test/simple4.html delete mode 100644 tools/buildbot/pylibs/twisted/lore/test/simple4.xhtml delete mode 100644 tools/buildbot/pylibs/twisted/lore/test/simple4foo.xhtml delete mode 100644 tools/buildbot/pylibs/twisted/lore/test/template.tpl delete mode 100644 tools/buildbot/pylibs/twisted/lore/test/test_lore.py delete mode 100644 tools/buildbot/pylibs/twisted/lore/test/test_man2lore.py delete mode 100644 tools/buildbot/pylibs/twisted/lore/texi.py delete mode 100644 tools/buildbot/pylibs/twisted/lore/topfiles/NEWS delete mode 100644 tools/buildbot/pylibs/twisted/lore/topfiles/README delete mode 100644 tools/buildbot/pylibs/twisted/lore/topfiles/setup.py delete mode 100644 tools/buildbot/pylibs/twisted/lore/tree.py delete mode 100644 tools/buildbot/pylibs/twisted/mail/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/mail/_version.py delete mode 100644 tools/buildbot/pylibs/twisted/mail/alias.py delete mode 100644 tools/buildbot/pylibs/twisted/mail/bounce.py delete mode 100644 tools/buildbot/pylibs/twisted/mail/imap4.py delete mode 100644 tools/buildbot/pylibs/twisted/mail/mail.py delete mode 100644 tools/buildbot/pylibs/twisted/mail/maildir.py delete mode 100644 tools/buildbot/pylibs/twisted/mail/pb.py delete mode 100644 tools/buildbot/pylibs/twisted/mail/pop3.py delete mode 100644 tools/buildbot/pylibs/twisted/mail/pop3client.py delete mode 100644 tools/buildbot/pylibs/twisted/mail/protocols.py delete mode 100644 tools/buildbot/pylibs/twisted/mail/relay.py delete mode 100644 tools/buildbot/pylibs/twisted/mail/relaymanager.py delete mode 100644 tools/buildbot/pylibs/twisted/mail/scripts/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/mail/scripts/mailmail.py delete mode 100644 tools/buildbot/pylibs/twisted/mail/smtp.py delete mode 100644 tools/buildbot/pylibs/twisted/mail/tap.py delete mode 100644 tools/buildbot/pylibs/twisted/mail/test/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/mail/test/pop3testserver.py delete mode 100644 tools/buildbot/pylibs/twisted/mail/test/rfc822.message delete mode 100644 tools/buildbot/pylibs/twisted/mail/test/test_bounce.py delete mode 100644 tools/buildbot/pylibs/twisted/mail/test/test_imap.py delete mode 100644 tools/buildbot/pylibs/twisted/mail/test/test_mail.py delete mode 100644 tools/buildbot/pylibs/twisted/mail/test/test_options.py delete mode 100644 tools/buildbot/pylibs/twisted/mail/test/test_pop3.py delete mode 100644 tools/buildbot/pylibs/twisted/mail/test/test_pop3client.py delete mode 100644 tools/buildbot/pylibs/twisted/mail/test/test_smtp.py delete mode 100644 tools/buildbot/pylibs/twisted/mail/topfiles/NEWS delete mode 100644 tools/buildbot/pylibs/twisted/mail/topfiles/README delete mode 100644 tools/buildbot/pylibs/twisted/mail/topfiles/setup.py delete mode 100644 tools/buildbot/pylibs/twisted/manhole/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/manhole/_inspectro.py delete mode 100644 tools/buildbot/pylibs/twisted/manhole/explorer.py delete mode 100644 tools/buildbot/pylibs/twisted/manhole/gladereactor.glade delete mode 100644 tools/buildbot/pylibs/twisted/manhole/gladereactor.py delete mode 100644 tools/buildbot/pylibs/twisted/manhole/inspectro.glade delete mode 100644 tools/buildbot/pylibs/twisted/manhole/logview.glade delete mode 100644 tools/buildbot/pylibs/twisted/manhole/service.py delete mode 100644 tools/buildbot/pylibs/twisted/manhole/telnet.py delete mode 100644 tools/buildbot/pylibs/twisted/manhole/ui/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/manhole/ui/gtk2manhole.glade delete mode 100644 tools/buildbot/pylibs/twisted/manhole/ui/gtk2manhole.py delete mode 100644 tools/buildbot/pylibs/twisted/manhole/ui/gtkmanhole.py delete mode 100644 tools/buildbot/pylibs/twisted/manhole/ui/gtkrc delete mode 100644 tools/buildbot/pylibs/twisted/manhole/ui/pywidgets.py delete mode 100644 tools/buildbot/pylibs/twisted/manhole/ui/spelunk_gnome.py delete mode 100644 tools/buildbot/pylibs/twisted/names/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/names/_version.py delete mode 100644 tools/buildbot/pylibs/twisted/names/authority.py delete mode 100644 tools/buildbot/pylibs/twisted/names/cache.py delete mode 100644 tools/buildbot/pylibs/twisted/names/client.py delete mode 100644 tools/buildbot/pylibs/twisted/names/common.py delete mode 100644 tools/buildbot/pylibs/twisted/names/dns.py delete mode 100644 tools/buildbot/pylibs/twisted/names/error.py delete mode 100644 tools/buildbot/pylibs/twisted/names/hosts.py delete mode 100644 tools/buildbot/pylibs/twisted/names/resolve.py delete mode 100644 tools/buildbot/pylibs/twisted/names/root.py delete mode 100644 tools/buildbot/pylibs/twisted/names/secondary.py delete mode 100644 tools/buildbot/pylibs/twisted/names/server.py delete mode 100644 tools/buildbot/pylibs/twisted/names/srvconnect.py delete mode 100644 tools/buildbot/pylibs/twisted/names/tap.py delete mode 100644 tools/buildbot/pylibs/twisted/names/test/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/names/test/test_cache.py delete mode 100644 tools/buildbot/pylibs/twisted/names/test/test_client.py delete mode 100644 tools/buildbot/pylibs/twisted/names/test/test_dns.py delete mode 100644 tools/buildbot/pylibs/twisted/names/test/test_names.py delete mode 100644 tools/buildbot/pylibs/twisted/names/test/test_rootresolve.py delete mode 100644 tools/buildbot/pylibs/twisted/names/test/test_srvconnect.py delete mode 100644 tools/buildbot/pylibs/twisted/names/topfiles/NEWS delete mode 100644 tools/buildbot/pylibs/twisted/names/topfiles/README delete mode 100644 tools/buildbot/pylibs/twisted/names/topfiles/setup.py delete mode 100644 tools/buildbot/pylibs/twisted/news/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/news/_version.py delete mode 100644 tools/buildbot/pylibs/twisted/news/database.py delete mode 100644 tools/buildbot/pylibs/twisted/news/news.py delete mode 100644 tools/buildbot/pylibs/twisted/news/nntp.py delete mode 100644 tools/buildbot/pylibs/twisted/news/tap.py delete mode 100644 tools/buildbot/pylibs/twisted/news/test/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/news/test/test_news.py delete mode 100644 tools/buildbot/pylibs/twisted/news/test/test_nntp.py delete mode 100644 tools/buildbot/pylibs/twisted/news/topfiles/NEWS delete mode 100644 tools/buildbot/pylibs/twisted/news/topfiles/README delete mode 100644 tools/buildbot/pylibs/twisted/news/topfiles/setup.py delete mode 100644 tools/buildbot/pylibs/twisted/pair/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/pair/_version.py delete mode 100644 tools/buildbot/pylibs/twisted/pair/ethernet.py delete mode 100644 tools/buildbot/pylibs/twisted/pair/ip.py delete mode 100644 tools/buildbot/pylibs/twisted/pair/raw.py delete mode 100644 tools/buildbot/pylibs/twisted/pair/rawudp.py delete mode 100644 tools/buildbot/pylibs/twisted/pair/test/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/pair/test/test_ethernet.py delete mode 100644 tools/buildbot/pylibs/twisted/pair/test/test_ip.py delete mode 100644 tools/buildbot/pylibs/twisted/pair/test/test_rawudp.py delete mode 100644 tools/buildbot/pylibs/twisted/pair/topfiles/README delete mode 100644 tools/buildbot/pylibs/twisted/pair/topfiles/setup.py delete mode 100644 tools/buildbot/pylibs/twisted/pair/tuntap.py delete mode 100644 tools/buildbot/pylibs/twisted/persisted/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/persisted/aot.py delete mode 100644 tools/buildbot/pylibs/twisted/persisted/crefutil.py delete mode 100644 tools/buildbot/pylibs/twisted/persisted/dirdbm.py delete mode 100644 tools/buildbot/pylibs/twisted/persisted/journal/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/persisted/journal/base.py delete mode 100644 tools/buildbot/pylibs/twisted/persisted/journal/picklelog.py delete mode 100644 tools/buildbot/pylibs/twisted/persisted/journal/rowjournal.py delete mode 100644 tools/buildbot/pylibs/twisted/persisted/marmalade.py delete mode 100644 tools/buildbot/pylibs/twisted/persisted/sob.py delete mode 100644 tools/buildbot/pylibs/twisted/persisted/styles.py delete mode 100644 tools/buildbot/pylibs/twisted/plugin.py delete mode 100644 tools/buildbot/pylibs/twisted/plugins/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/plugins/cred_anonymous.py delete mode 100644 tools/buildbot/pylibs/twisted/plugins/cred_file.py delete mode 100644 tools/buildbot/pylibs/twisted/plugins/cred_memory.py delete mode 100644 tools/buildbot/pylibs/twisted/plugins/cred_unix.py delete mode 100644 tools/buildbot/pylibs/twisted/plugins/twisted_conch.py delete mode 100644 tools/buildbot/pylibs/twisted/plugins/twisted_ftp.py delete mode 100644 tools/buildbot/pylibs/twisted/plugins/twisted_inet.py delete mode 100644 tools/buildbot/pylibs/twisted/plugins/twisted_lore.py delete mode 100644 tools/buildbot/pylibs/twisted/plugins/twisted_mail.py delete mode 100644 tools/buildbot/pylibs/twisted/plugins/twisted_manhole.py delete mode 100644 tools/buildbot/pylibs/twisted/plugins/twisted_names.py delete mode 100644 tools/buildbot/pylibs/twisted/plugins/twisted_news.py delete mode 100644 tools/buildbot/pylibs/twisted/plugins/twisted_portforward.py delete mode 100644 tools/buildbot/pylibs/twisted/plugins/twisted_qtstub.py delete mode 100644 tools/buildbot/pylibs/twisted/plugins/twisted_reactors.py delete mode 100644 tools/buildbot/pylibs/twisted/plugins/twisted_socks.py delete mode 100644 tools/buildbot/pylibs/twisted/plugins/twisted_telnet.py delete mode 100644 tools/buildbot/pylibs/twisted/plugins/twisted_trial.py delete mode 100644 tools/buildbot/pylibs/twisted/plugins/twisted_web.py delete mode 100644 tools/buildbot/pylibs/twisted/plugins/twisted_words.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/_c_urlarg.c delete mode 100644 tools/buildbot/pylibs/twisted/protocols/amp.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/basic.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/dict.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/dns.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/ethernet.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/finger.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/ftp.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/gps/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/gps/nmea.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/gps/rockwell.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/htb.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/http.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/ident.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/imap4.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/ip.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/irc.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/jabber.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/loopback.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/memcache.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/mice/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/mice/mouseman.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/msn.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/nntp.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/oscar.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/pcp.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/policies.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/pop3.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/portforward.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/postfix.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/raw.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/rawudp.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/shoutcast.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/sip.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/smtp.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/socks.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/stateful.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/sux.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/telnet.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/toc.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/wire.py delete mode 100644 tools/buildbot/pylibs/twisted/protocols/xmlstream.py delete mode 100644 tools/buildbot/pylibs/twisted/python/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/python/_epoll.c delete mode 100644 tools/buildbot/pylibs/twisted/python/_epoll.pyx delete mode 100644 tools/buildbot/pylibs/twisted/python/_release.py delete mode 100644 tools/buildbot/pylibs/twisted/python/_twisted_zsh_stub delete mode 100644 tools/buildbot/pylibs/twisted/python/compat.py delete mode 100644 tools/buildbot/pylibs/twisted/python/components.py delete mode 100644 tools/buildbot/pylibs/twisted/python/context.py delete mode 100644 tools/buildbot/pylibs/twisted/python/deprecate.py delete mode 100644 tools/buildbot/pylibs/twisted/python/dispatch.py delete mode 100644 tools/buildbot/pylibs/twisted/python/dist.py delete mode 100644 tools/buildbot/pylibs/twisted/python/dxprofile.py delete mode 100644 tools/buildbot/pylibs/twisted/python/failure.py delete mode 100644 tools/buildbot/pylibs/twisted/python/filepath.py delete mode 100644 tools/buildbot/pylibs/twisted/python/finalize.py delete mode 100644 tools/buildbot/pylibs/twisted/python/formmethod.py delete mode 100644 tools/buildbot/pylibs/twisted/python/hook.py delete mode 100644 tools/buildbot/pylibs/twisted/python/htmlizer.py delete mode 100644 tools/buildbot/pylibs/twisted/python/lockfile.py delete mode 100644 tools/buildbot/pylibs/twisted/python/log.py delete mode 100644 tools/buildbot/pylibs/twisted/python/logfile.py delete mode 100644 tools/buildbot/pylibs/twisted/python/modules.py delete mode 100644 tools/buildbot/pylibs/twisted/python/monkey.py delete mode 100644 tools/buildbot/pylibs/twisted/python/otp.py delete mode 100644 tools/buildbot/pylibs/twisted/python/plugin.py delete mode 100644 tools/buildbot/pylibs/twisted/python/procutils.py delete mode 100644 tools/buildbot/pylibs/twisted/python/randbytes.py delete mode 100644 tools/buildbot/pylibs/twisted/python/rebuild.py delete mode 100644 tools/buildbot/pylibs/twisted/python/reflect.py delete mode 100644 tools/buildbot/pylibs/twisted/python/release.py delete mode 100644 tools/buildbot/pylibs/twisted/python/roots.py delete mode 100644 tools/buildbot/pylibs/twisted/python/runtime.py delete mode 100644 tools/buildbot/pylibs/twisted/python/shortcut.py delete mode 100644 tools/buildbot/pylibs/twisted/python/syslog.py delete mode 100644 tools/buildbot/pylibs/twisted/python/test/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/python/test/test_components.py delete mode 100644 tools/buildbot/pylibs/twisted/python/test/test_deprecate.py delete mode 100644 tools/buildbot/pylibs/twisted/python/test/test_dist.py delete mode 100644 tools/buildbot/pylibs/twisted/python/test/test_release.py delete mode 100644 tools/buildbot/pylibs/twisted/python/test/test_util.py delete mode 100644 tools/buildbot/pylibs/twisted/python/test/test_versions.py delete mode 100644 tools/buildbot/pylibs/twisted/python/test/test_zipstream.py delete mode 100644 tools/buildbot/pylibs/twisted/python/text.py delete mode 100644 tools/buildbot/pylibs/twisted/python/threadable.py delete mode 100644 tools/buildbot/pylibs/twisted/python/threadpool.py delete mode 100644 tools/buildbot/pylibs/twisted/python/timeoutqueue.py delete mode 100644 tools/buildbot/pylibs/twisted/python/urlpath.py delete mode 100644 tools/buildbot/pylibs/twisted/python/usage.py delete mode 100644 tools/buildbot/pylibs/twisted/python/util.py delete mode 100644 tools/buildbot/pylibs/twisted/python/versions.py delete mode 100644 tools/buildbot/pylibs/twisted/python/win32.py delete mode 100644 tools/buildbot/pylibs/twisted/python/zippath.py delete mode 100644 tools/buildbot/pylibs/twisted/python/zipstream.py delete mode 100644 tools/buildbot/pylibs/twisted/python/zsh/README delete mode 100644 tools/buildbot/pylibs/twisted/python/zsh/_cftp delete mode 100644 tools/buildbot/pylibs/twisted/python/zsh/_ckeygen delete mode 100644 tools/buildbot/pylibs/twisted/python/zsh/_conch delete mode 100644 tools/buildbot/pylibs/twisted/python/zsh/_lore delete mode 100644 tools/buildbot/pylibs/twisted/python/zsh/_manhole delete mode 100644 tools/buildbot/pylibs/twisted/python/zsh/_mktap delete mode 100644 tools/buildbot/pylibs/twisted/python/zsh/_pyhtmlizer delete mode 100644 tools/buildbot/pylibs/twisted/python/zsh/_tap2deb delete mode 100644 tools/buildbot/pylibs/twisted/python/zsh/_tap2rpm delete mode 100644 tools/buildbot/pylibs/twisted/python/zsh/_tapconvert delete mode 100644 tools/buildbot/pylibs/twisted/python/zsh/_tkconch delete mode 100644 tools/buildbot/pylibs/twisted/python/zsh/_tkmktap delete mode 100644 tools/buildbot/pylibs/twisted/python/zsh/_trial delete mode 100644 tools/buildbot/pylibs/twisted/python/zsh/_twistd delete mode 100644 tools/buildbot/pylibs/twisted/python/zsh/_websetroot delete mode 100644 tools/buildbot/pylibs/twisted/python/zshcomp.py delete mode 100644 tools/buildbot/pylibs/twisted/runner/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/runner/_version.py delete mode 100644 tools/buildbot/pylibs/twisted/runner/inetd.py delete mode 100644 tools/buildbot/pylibs/twisted/runner/inetdconf.py delete mode 100644 tools/buildbot/pylibs/twisted/runner/inetdtap.py delete mode 100644 tools/buildbot/pylibs/twisted/runner/portmap.c delete mode 100644 tools/buildbot/pylibs/twisted/runner/procmon.py delete mode 100644 tools/buildbot/pylibs/twisted/runner/procutils.py delete mode 100644 tools/buildbot/pylibs/twisted/runner/topfiles/NEWS delete mode 100644 tools/buildbot/pylibs/twisted/runner/topfiles/README delete mode 100644 tools/buildbot/pylibs/twisted/runner/topfiles/setup.py delete mode 100644 tools/buildbot/pylibs/twisted/scripts/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/scripts/_twistd_unix.py delete mode 100644 tools/buildbot/pylibs/twisted/scripts/_twistw.py delete mode 100644 tools/buildbot/pylibs/twisted/scripts/htmlizer.py delete mode 100644 tools/buildbot/pylibs/twisted/scripts/manhole.py delete mode 100644 tools/buildbot/pylibs/twisted/scripts/mktap.py delete mode 100644 tools/buildbot/pylibs/twisted/scripts/tap2deb.py delete mode 100644 tools/buildbot/pylibs/twisted/scripts/tap2rpm.py delete mode 100644 tools/buildbot/pylibs/twisted/scripts/tapconvert.py delete mode 100644 tools/buildbot/pylibs/twisted/scripts/test/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/scripts/test/test_mktap.py delete mode 100644 tools/buildbot/pylibs/twisted/scripts/tkunzip.py delete mode 100644 tools/buildbot/pylibs/twisted/scripts/trial.py delete mode 100644 tools/buildbot/pylibs/twisted/scripts/twistd.py delete mode 100644 tools/buildbot/pylibs/twisted/spread/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/spread/banana.py delete mode 100644 tools/buildbot/pylibs/twisted/spread/flavors.py delete mode 100644 tools/buildbot/pylibs/twisted/spread/interfaces.py delete mode 100644 tools/buildbot/pylibs/twisted/spread/jelly.py delete mode 100644 tools/buildbot/pylibs/twisted/spread/pb.py delete mode 100644 tools/buildbot/pylibs/twisted/spread/publish.py delete mode 100644 tools/buildbot/pylibs/twisted/spread/refpath.py delete mode 100644 tools/buildbot/pylibs/twisted/spread/ui/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/spread/ui/gtk2util.py delete mode 100644 tools/buildbot/pylibs/twisted/spread/ui/gtkutil.py delete mode 100644 tools/buildbot/pylibs/twisted/spread/ui/login2.glade delete mode 100644 tools/buildbot/pylibs/twisted/spread/ui/tktree.py delete mode 100644 tools/buildbot/pylibs/twisted/spread/ui/tkutil.py delete mode 100644 tools/buildbot/pylibs/twisted/spread/util.py delete mode 100644 tools/buildbot/pylibs/twisted/tap/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/tap/ftp.py delete mode 100644 tools/buildbot/pylibs/twisted/tap/manhole.py delete mode 100644 tools/buildbot/pylibs/twisted/tap/portforward.py delete mode 100644 tools/buildbot/pylibs/twisted/tap/socks.py delete mode 100644 tools/buildbot/pylibs/twisted/tap/telnet.py delete mode 100644 tools/buildbot/pylibs/twisted/test/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/test/app_qtstub.py delete mode 100644 tools/buildbot/pylibs/twisted/test/crash_test_dummy.py delete mode 100644 tools/buildbot/pylibs/twisted/test/generator_failure_tests.py delete mode 100644 tools/buildbot/pylibs/twisted/test/iosim.py delete mode 100644 tools/buildbot/pylibs/twisted/test/mock_win32process.py delete mode 100644 tools/buildbot/pylibs/twisted/test/myrebuilder1.py delete mode 100644 tools/buildbot/pylibs/twisted/test/myrebuilder2.py delete mode 100644 tools/buildbot/pylibs/twisted/test/plugin_basic.py delete mode 100644 tools/buildbot/pylibs/twisted/test/plugin_extra1.py delete mode 100644 tools/buildbot/pylibs/twisted/test/plugin_extra2.py delete mode 100644 tools/buildbot/pylibs/twisted/test/process_cmdline.py delete mode 100644 tools/buildbot/pylibs/twisted/test/process_echoer.py delete mode 100644 tools/buildbot/pylibs/twisted/test/process_fds.py delete mode 100644 tools/buildbot/pylibs/twisted/test/process_linger.py delete mode 100644 tools/buildbot/pylibs/twisted/test/process_reader.py delete mode 100644 tools/buildbot/pylibs/twisted/test/process_signal.py delete mode 100644 tools/buildbot/pylibs/twisted/test/process_stdinreader.py delete mode 100644 tools/buildbot/pylibs/twisted/test/process_tester.py delete mode 100644 tools/buildbot/pylibs/twisted/test/process_tty.py delete mode 100644 tools/buildbot/pylibs/twisted/test/process_twisted.py delete mode 100644 tools/buildbot/pylibs/twisted/test/proto_helpers.py delete mode 100644 tools/buildbot/pylibs/twisted/test/raiser.c delete mode 100644 tools/buildbot/pylibs/twisted/test/raiser.pyx delete mode 100644 tools/buildbot/pylibs/twisted/test/reflect_helper_IE.py delete mode 100644 tools/buildbot/pylibs/twisted/test/reflect_helper_VE.py delete mode 100644 tools/buildbot/pylibs/twisted/test/reflect_helper_ZDE.py delete mode 100644 tools/buildbot/pylibs/twisted/test/server.pem delete mode 100644 tools/buildbot/pylibs/twisted/test/ssl_helpers.py delete mode 100644 tools/buildbot/pylibs/twisted/test/stdio_test_consumer.py delete mode 100644 tools/buildbot/pylibs/twisted/test/stdio_test_hostpeer.py delete mode 100644 tools/buildbot/pylibs/twisted/test/stdio_test_lastwrite.py delete mode 100644 tools/buildbot/pylibs/twisted/test/stdio_test_loseconn.py delete mode 100644 tools/buildbot/pylibs/twisted/test/stdio_test_producer.py delete mode 100644 tools/buildbot/pylibs/twisted/test/stdio_test_write.py delete mode 100644 tools/buildbot/pylibs/twisted/test/stdio_test_writeseq.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_abstract.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_adbapi.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_amp.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_application.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_assertions.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_banana.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_compat.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_context.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_cooperator.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_defer.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_defgen.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_dict.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_dirdbm.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_doc.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_enterprise.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_epoll.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_error.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_explorer.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_extensions.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_factories.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_failure.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_fdesc.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_finger.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_formmethod.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_ftp.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_hook.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_htb.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_ident.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_import.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_internet.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_iutils.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_jelly.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_journal.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_lockfile.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_log.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_logfile.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_loopback.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_manhole.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_memcache.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_modules.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_monkey.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_newcred.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_nmea.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_paths.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_pb.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_pbfailure.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_pcp.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_persisted.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_plugin.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_policies.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_postfix.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_process.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_protocols.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_randbytes.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_rebuild.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_reflect.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_reflector.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_roots.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_shortcut.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_sip.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_sob.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_socks.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_split_compat.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_ssl.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_sslverify.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_stateful.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_stdio.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_strcred.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_strerror.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_strports.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_task.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_tcp.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_tcp_internals.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_text.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_threadable.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_threadpool.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_threads.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_timeoutqueue.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_tpfile.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_twistd.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_udp.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_unix.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_usage.py delete mode 100644 tools/buildbot/pylibs/twisted/test/test_zshcomp.py delete mode 100644 tools/buildbot/pylibs/twisted/test/testutils.py delete mode 100644 tools/buildbot/pylibs/twisted/test/threading_latency.py delete mode 100644 tools/buildbot/pylibs/twisted/test/time_helpers.py delete mode 100644 tools/buildbot/pylibs/twisted/topfiles/CREDITS delete mode 100644 tools/buildbot/pylibs/twisted/topfiles/ChangeLog.Old delete mode 100644 tools/buildbot/pylibs/twisted/topfiles/NEWS delete mode 100644 tools/buildbot/pylibs/twisted/topfiles/README delete mode 100644 tools/buildbot/pylibs/twisted/topfiles/setup.py delete mode 100644 tools/buildbot/pylibs/twisted/trial/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/trial/itrial.py delete mode 100644 tools/buildbot/pylibs/twisted/trial/reporter.py delete mode 100644 tools/buildbot/pylibs/twisted/trial/runner.py delete mode 100644 tools/buildbot/pylibs/twisted/trial/test/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/trial/test/detests.py delete mode 100644 tools/buildbot/pylibs/twisted/trial/test/erroneous.py delete mode 100644 tools/buildbot/pylibs/twisted/trial/test/mockcustomsuite.py delete mode 100644 tools/buildbot/pylibs/twisted/trial/test/mockcustomsuite2.py delete mode 100644 tools/buildbot/pylibs/twisted/trial/test/mockcustomsuite3.py delete mode 100644 tools/buildbot/pylibs/twisted/trial/test/mockdoctest.py delete mode 100644 tools/buildbot/pylibs/twisted/trial/test/moduleself.py delete mode 100644 tools/buildbot/pylibs/twisted/trial/test/moduletest.py delete mode 100644 tools/buildbot/pylibs/twisted/trial/test/notpython delete mode 100644 tools/buildbot/pylibs/twisted/trial/test/novars.py delete mode 100644 tools/buildbot/pylibs/twisted/trial/test/packages.py delete mode 100644 tools/buildbot/pylibs/twisted/trial/test/sample.py delete mode 100644 tools/buildbot/pylibs/twisted/trial/test/scripttest.py delete mode 100644 tools/buildbot/pylibs/twisted/trial/test/suppression.py delete mode 100644 tools/buildbot/pylibs/twisted/trial/test/test_assertions.py delete mode 100644 tools/buildbot/pylibs/twisted/trial/test/test_class.py delete mode 100644 tools/buildbot/pylibs/twisted/trial/test/test_deferred.py delete mode 100644 tools/buildbot/pylibs/twisted/trial/test/test_doctest.py delete mode 100644 tools/buildbot/pylibs/twisted/trial/test/test_keyboard.py delete mode 100644 tools/buildbot/pylibs/twisted/trial/test/test_loader.py delete mode 100644 tools/buildbot/pylibs/twisted/trial/test/test_log.py delete mode 100644 tools/buildbot/pylibs/twisted/trial/test/test_output.py delete mode 100644 tools/buildbot/pylibs/twisted/trial/test/test_pyunitcompat.py delete mode 100644 tools/buildbot/pylibs/twisted/trial/test/test_reporter.py delete mode 100644 tools/buildbot/pylibs/twisted/trial/test/test_runner.py delete mode 100644 tools/buildbot/pylibs/twisted/trial/test/test_script.py delete mode 100644 tools/buildbot/pylibs/twisted/trial/test/test_test_visitor.py delete mode 100644 tools/buildbot/pylibs/twisted/trial/test/test_tests.py delete mode 100644 tools/buildbot/pylibs/twisted/trial/test/test_util.py delete mode 100644 tools/buildbot/pylibs/twisted/trial/test/weird.py delete mode 100644 tools/buildbot/pylibs/twisted/trial/unittest.py delete mode 100644 tools/buildbot/pylibs/twisted/trial/util.py delete mode 100644 tools/buildbot/pylibs/twisted/web/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/web/_version.py delete mode 100644 tools/buildbot/pylibs/twisted/web/client.py delete mode 100644 tools/buildbot/pylibs/twisted/web/demo.py delete mode 100644 tools/buildbot/pylibs/twisted/web/distrib.py delete mode 100644 tools/buildbot/pylibs/twisted/web/domhelpers.py delete mode 100644 tools/buildbot/pylibs/twisted/web/error.py delete mode 100644 tools/buildbot/pylibs/twisted/web/google.py delete mode 100644 tools/buildbot/pylibs/twisted/web/guard.py delete mode 100644 tools/buildbot/pylibs/twisted/web/html.py delete mode 100644 tools/buildbot/pylibs/twisted/web/http.py delete mode 100644 tools/buildbot/pylibs/twisted/web/microdom.py delete mode 100644 tools/buildbot/pylibs/twisted/web/monitor.py delete mode 100644 tools/buildbot/pylibs/twisted/web/proxy.py delete mode 100644 tools/buildbot/pylibs/twisted/web/resource.py delete mode 100644 tools/buildbot/pylibs/twisted/web/rewrite.py delete mode 100644 tools/buildbot/pylibs/twisted/web/script.py delete mode 100644 tools/buildbot/pylibs/twisted/web/server.py delete mode 100644 tools/buildbot/pylibs/twisted/web/soap.py delete mode 100644 tools/buildbot/pylibs/twisted/web/static.py delete mode 100644 tools/buildbot/pylibs/twisted/web/sux.py delete mode 100644 tools/buildbot/pylibs/twisted/web/tap.py delete mode 100644 tools/buildbot/pylibs/twisted/web/test/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/web/test/test_cgi.py delete mode 100644 tools/buildbot/pylibs/twisted/web/test/test_distrib.py delete mode 100644 tools/buildbot/pylibs/twisted/web/test/test_domhelpers.py delete mode 100644 tools/buildbot/pylibs/twisted/web/test/test_http.py delete mode 100644 tools/buildbot/pylibs/twisted/web/test/test_mvc.py delete mode 100644 tools/buildbot/pylibs/twisted/web/test/test_proxy.py delete mode 100644 tools/buildbot/pylibs/twisted/web/test/test_soap.py delete mode 100644 tools/buildbot/pylibs/twisted/web/test/test_static.py delete mode 100644 tools/buildbot/pylibs/twisted/web/test/test_tap.py delete mode 100644 tools/buildbot/pylibs/twisted/web/test/test_web.py delete mode 100644 tools/buildbot/pylibs/twisted/web/test/test_webclient.py delete mode 100644 tools/buildbot/pylibs/twisted/web/test/test_woven.py delete mode 100644 tools/buildbot/pylibs/twisted/web/test/test_xml.py delete mode 100644 tools/buildbot/pylibs/twisted/web/test/test_xmlrpc.py delete mode 100644 tools/buildbot/pylibs/twisted/web/topfiles/NEWS delete mode 100644 tools/buildbot/pylibs/twisted/web/topfiles/README delete mode 100644 tools/buildbot/pylibs/twisted/web/topfiles/setup.py delete mode 100644 tools/buildbot/pylibs/twisted/web/trp.py delete mode 100644 tools/buildbot/pylibs/twisted/web/twcgi.py delete mode 100644 tools/buildbot/pylibs/twisted/web/util.py delete mode 100644 tools/buildbot/pylibs/twisted/web/vhost.py delete mode 100644 tools/buildbot/pylibs/twisted/web/widgets.py delete mode 100644 tools/buildbot/pylibs/twisted/web/woven/FlashConduit.fla delete mode 100644 tools/buildbot/pylibs/twisted/web/woven/FlashConduit.swf delete mode 100644 tools/buildbot/pylibs/twisted/web/woven/FlashConduitGlue.html delete mode 100644 tools/buildbot/pylibs/twisted/web/woven/WebConduit2_mozilla.js delete mode 100644 tools/buildbot/pylibs/twisted/web/woven/WebConduit2_msie.js delete mode 100644 tools/buildbot/pylibs/twisted/web/woven/WebConduitGlue.html delete mode 100644 tools/buildbot/pylibs/twisted/web/woven/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/web/woven/controller.py delete mode 100644 tools/buildbot/pylibs/twisted/web/woven/dirlist.py delete mode 100644 tools/buildbot/pylibs/twisted/web/woven/flashconduit.py delete mode 100644 tools/buildbot/pylibs/twisted/web/woven/form.py delete mode 100644 tools/buildbot/pylibs/twisted/web/woven/guard.py delete mode 100644 tools/buildbot/pylibs/twisted/web/woven/input.py delete mode 100644 tools/buildbot/pylibs/twisted/web/woven/interfaces.py delete mode 100644 tools/buildbot/pylibs/twisted/web/woven/model.py delete mode 100644 tools/buildbot/pylibs/twisted/web/woven/page.py delete mode 100644 tools/buildbot/pylibs/twisted/web/woven/simpleguard.py delete mode 100644 tools/buildbot/pylibs/twisted/web/woven/tapestry.py delete mode 100644 tools/buildbot/pylibs/twisted/web/woven/template.py delete mode 100644 tools/buildbot/pylibs/twisted/web/woven/utils.py delete mode 100644 tools/buildbot/pylibs/twisted/web/woven/view.py delete mode 100644 tools/buildbot/pylibs/twisted/web/woven/widgets.py delete mode 100644 tools/buildbot/pylibs/twisted/web/xmlrpc.py delete mode 100644 tools/buildbot/pylibs/twisted/words/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/words/_version.py delete mode 100644 tools/buildbot/pylibs/twisted/words/ewords.py delete mode 100644 tools/buildbot/pylibs/twisted/words/im/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/words/im/baseaccount.py delete mode 100644 tools/buildbot/pylibs/twisted/words/im/basechat.py delete mode 100644 tools/buildbot/pylibs/twisted/words/im/basesupport.py delete mode 100644 tools/buildbot/pylibs/twisted/words/im/gtkaccount.py delete mode 100644 tools/buildbot/pylibs/twisted/words/im/gtkchat.py delete mode 100644 tools/buildbot/pylibs/twisted/words/im/gtkcommon.py delete mode 100644 tools/buildbot/pylibs/twisted/words/im/instancemessenger.glade delete mode 100644 tools/buildbot/pylibs/twisted/words/im/interfaces.py delete mode 100644 tools/buildbot/pylibs/twisted/words/im/ircsupport.py delete mode 100644 tools/buildbot/pylibs/twisted/words/im/jyaccount.py delete mode 100644 tools/buildbot/pylibs/twisted/words/im/jychat.py delete mode 100644 tools/buildbot/pylibs/twisted/words/im/locals.py delete mode 100644 tools/buildbot/pylibs/twisted/words/im/pbsupport.py delete mode 100644 tools/buildbot/pylibs/twisted/words/im/proxyui.py delete mode 100644 tools/buildbot/pylibs/twisted/words/im/tap.py delete mode 100644 tools/buildbot/pylibs/twisted/words/im/tocsupport.py delete mode 100644 tools/buildbot/pylibs/twisted/words/iwords.py delete mode 100644 tools/buildbot/pylibs/twisted/words/protocols/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/words/protocols/irc.py delete mode 100644 tools/buildbot/pylibs/twisted/words/protocols/jabber/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/words/protocols/jabber/client.py delete mode 100644 tools/buildbot/pylibs/twisted/words/protocols/jabber/component.py delete mode 100644 tools/buildbot/pylibs/twisted/words/protocols/jabber/error.py delete mode 100644 tools/buildbot/pylibs/twisted/words/protocols/jabber/ijabber.py delete mode 100644 tools/buildbot/pylibs/twisted/words/protocols/jabber/jid.py delete mode 100644 tools/buildbot/pylibs/twisted/words/protocols/jabber/jstrports.py delete mode 100644 tools/buildbot/pylibs/twisted/words/protocols/jabber/sasl.py delete mode 100644 tools/buildbot/pylibs/twisted/words/protocols/jabber/sasl_mechanisms.py delete mode 100644 tools/buildbot/pylibs/twisted/words/protocols/jabber/xmlstream.py delete mode 100644 tools/buildbot/pylibs/twisted/words/protocols/jabber/xmpp_stringprep.py delete mode 100644 tools/buildbot/pylibs/twisted/words/protocols/msn.py delete mode 100644 tools/buildbot/pylibs/twisted/words/protocols/oscar.py delete mode 100644 tools/buildbot/pylibs/twisted/words/protocols/toc.py delete mode 100644 tools/buildbot/pylibs/twisted/words/scripts/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/words/scripts/im.py delete mode 100644 tools/buildbot/pylibs/twisted/words/service.py delete mode 100644 tools/buildbot/pylibs/twisted/words/tap.py delete mode 100644 tools/buildbot/pylibs/twisted/words/test/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/words/test/test_basesupport.py delete mode 100644 tools/buildbot/pylibs/twisted/words/test/test_domish.py delete mode 100644 tools/buildbot/pylibs/twisted/words/test/test_irc.py delete mode 100644 tools/buildbot/pylibs/twisted/words/test/test_jabberclient.py delete mode 100644 tools/buildbot/pylibs/twisted/words/test/test_jabbercomponent.py delete mode 100644 tools/buildbot/pylibs/twisted/words/test/test_jabbererror.py delete mode 100644 tools/buildbot/pylibs/twisted/words/test/test_jabberjid.py delete mode 100644 tools/buildbot/pylibs/twisted/words/test/test_jabbersasl.py delete mode 100644 tools/buildbot/pylibs/twisted/words/test/test_jabbersaslmechanisms.py delete mode 100644 tools/buildbot/pylibs/twisted/words/test/test_jabberxmlstream.py delete mode 100644 tools/buildbot/pylibs/twisted/words/test/test_jabberxmppstringprep.py delete mode 100644 tools/buildbot/pylibs/twisted/words/test/test_msn.py delete mode 100644 tools/buildbot/pylibs/twisted/words/test/test_service.py delete mode 100644 tools/buildbot/pylibs/twisted/words/test/test_tap.py delete mode 100644 tools/buildbot/pylibs/twisted/words/test/test_toc.py delete mode 100644 tools/buildbot/pylibs/twisted/words/test/test_xishutil.py delete mode 100644 tools/buildbot/pylibs/twisted/words/test/test_xmlstream.py delete mode 100644 tools/buildbot/pylibs/twisted/words/test/test_xpath.py delete mode 100644 tools/buildbot/pylibs/twisted/words/toctap.py delete mode 100644 tools/buildbot/pylibs/twisted/words/topfiles/NEWS delete mode 100644 tools/buildbot/pylibs/twisted/words/topfiles/README delete mode 100644 tools/buildbot/pylibs/twisted/words/topfiles/setup.py delete mode 100644 tools/buildbot/pylibs/twisted/words/xish/__init__.py delete mode 100644 tools/buildbot/pylibs/twisted/words/xish/domish.py delete mode 100644 tools/buildbot/pylibs/twisted/words/xish/utility.py delete mode 100644 tools/buildbot/pylibs/twisted/words/xish/xmlstream.py delete mode 100644 tools/buildbot/pylibs/twisted/words/xish/xpath.py delete mode 100644 tools/buildbot/pylibs/twisted/words/xish/xpathparser.g delete mode 100644 tools/buildbot/pylibs/twisted/words/xish/xpathparser.py delete mode 100644 tools/buildbot/pylibs/zope/PUBLICATION.cfg delete mode 100644 tools/buildbot/pylibs/zope/README.google delete mode 100644 tools/buildbot/pylibs/zope/README.txt delete mode 100644 tools/buildbot/pylibs/zope/__init__.py delete mode 100644 tools/buildbot/pylibs/zope/exceptions/DEPENDENCIES.cfg delete mode 100644 tools/buildbot/pylibs/zope/exceptions/__init__.py delete mode 100644 tools/buildbot/pylibs/zope/exceptions/exceptionformatter.py delete mode 100644 tools/buildbot/pylibs/zope/exceptions/interfaces.py delete mode 100644 tools/buildbot/pylibs/zope/exceptions/log.py delete mode 100644 tools/buildbot/pylibs/zope/exceptions/tests/__init__.py delete mode 100644 tools/buildbot/pylibs/zope/exceptions/tests/test_exceptionformatter.py delete mode 100644 tools/buildbot/pylibs/zope/interface/DEPENDENCIES.cfg delete mode 100644 tools/buildbot/pylibs/zope/interface/PUBLICATION.cfg delete mode 100644 tools/buildbot/pylibs/zope/interface/README.ru.txt delete mode 100644 tools/buildbot/pylibs/zope/interface/README.txt delete mode 100644 tools/buildbot/pylibs/zope/interface/SETUP.cfg delete mode 100644 tools/buildbot/pylibs/zope/interface/__init__.py delete mode 100644 tools/buildbot/pylibs/zope/interface/_flatten.py delete mode 100644 tools/buildbot/pylibs/zope/interface/_zope_interface_coptimizations.pyd delete mode 100644 tools/buildbot/pylibs/zope/interface/adapter.py delete mode 100644 tools/buildbot/pylibs/zope/interface/adapter.txt delete mode 100644 tools/buildbot/pylibs/zope/interface/advice.py delete mode 100644 tools/buildbot/pylibs/zope/interface/common/__init__.py delete mode 100644 tools/buildbot/pylibs/zope/interface/common/idatetime.py delete mode 100644 tools/buildbot/pylibs/zope/interface/common/interfaces.py delete mode 100644 tools/buildbot/pylibs/zope/interface/common/mapping.py delete mode 100644 tools/buildbot/pylibs/zope/interface/common/sequence.py delete mode 100644 tools/buildbot/pylibs/zope/interface/common/tests/__init__.py delete mode 100644 tools/buildbot/pylibs/zope/interface/common/tests/basemapping.py delete mode 100644 tools/buildbot/pylibs/zope/interface/common/tests/test_idatetime.py delete mode 100644 tools/buildbot/pylibs/zope/interface/declarations.py delete mode 100644 tools/buildbot/pylibs/zope/interface/document.py delete mode 100644 tools/buildbot/pylibs/zope/interface/exceptions.py delete mode 100644 tools/buildbot/pylibs/zope/interface/human.ru.txt delete mode 100644 tools/buildbot/pylibs/zope/interface/human.txt delete mode 100644 tools/buildbot/pylibs/zope/interface/interface.py delete mode 100644 tools/buildbot/pylibs/zope/interface/interfaces.py delete mode 100644 tools/buildbot/pylibs/zope/interface/ro.py delete mode 100644 tools/buildbot/pylibs/zope/interface/tests/__init__.py delete mode 100644 tools/buildbot/pylibs/zope/interface/tests/dummy.py delete mode 100644 tools/buildbot/pylibs/zope/interface/tests/foodforthought.txt delete mode 100644 tools/buildbot/pylibs/zope/interface/tests/ifoo.py delete mode 100644 tools/buildbot/pylibs/zope/interface/tests/m1.py delete mode 100644 tools/buildbot/pylibs/zope/interface/tests/m2.py delete mode 100644 tools/buildbot/pylibs/zope/interface/tests/odd.py delete mode 100644 tools/buildbot/pylibs/zope/interface/tests/test_adapter.py delete mode 100644 tools/buildbot/pylibs/zope/interface/tests/test_advice.py delete mode 100644 tools/buildbot/pylibs/zope/interface/tests/test_declarations.py delete mode 100644 tools/buildbot/pylibs/zope/interface/tests/test_document.py delete mode 100644 tools/buildbot/pylibs/zope/interface/tests/test_element.py delete mode 100644 tools/buildbot/pylibs/zope/interface/tests/test_interface.py delete mode 100644 tools/buildbot/pylibs/zope/interface/tests/test_odd_declarations.py delete mode 100644 tools/buildbot/pylibs/zope/interface/tests/test_sorting.py delete mode 100644 tools/buildbot/pylibs/zope/interface/tests/test_verify.py delete mode 100644 tools/buildbot/pylibs/zope/interface/tests/unitfixtures.py delete mode 100644 tools/buildbot/pylibs/zope/interface/verify.py delete mode 100644 tools/buildbot/pylibs/zope/testing/DEPENDENCIES.cfg delete mode 100644 tools/buildbot/pylibs/zope/testing/__init__.py delete mode 100644 tools/buildbot/pylibs/zope/testing/cleanup.py delete mode 100644 tools/buildbot/pylibs/zope/testing/doctest.py delete mode 100644 tools/buildbot/pylibs/zope/testing/doctestunit.py delete mode 100644 tools/buildbot/pylibs/zope/testing/formparser.py delete mode 100644 tools/buildbot/pylibs/zope/testing/formparser.txt delete mode 100644 tools/buildbot/pylibs/zope/testing/loggingsupport.py delete mode 100644 tools/buildbot/pylibs/zope/testing/loghandler.py delete mode 100644 tools/buildbot/pylibs/zope/testing/module.py delete mode 100644 tools/buildbot/pylibs/zope/testing/renormalizing.py delete mode 100644 tools/buildbot/pylibs/zope/testing/testrunner.py delete mode 100644 tools/buildbot/pylibs/zope/testing/testrunner.txt delete mode 100644 tools/buildbot/pylibs/zope/testing/tests.py delete mode 100644 tools/buildbot/scripts/common/chromium_commands.py delete mode 100644 tools/buildbot/scripts/common/chromium_config.py delete mode 100644 tools/buildbot/scripts/common/chromium_utils.py delete mode 100644 tools/buildbot/scripts/common/twistd delete mode 100644 tools/buildbot/scripts/master/bot_data.py delete mode 100644 tools/buildbot/scripts/master/chromium_changes.py delete mode 100644 tools/buildbot/scripts/master/chromium_factory.py delete mode 100644 tools/buildbot/scripts/master/chromium_process.py delete mode 100644 tools/buildbot/scripts/master/chromium_status.py delete mode 100644 tools/buildbot/scripts/master/chromium_step.py delete mode 100644 tools/buildbot/scripts/master/copytree.py delete mode 100644 tools/buildbot/scripts/master/factory_commands.py delete mode 100644 tools/buildbot/scripts/master/irc_contact.py delete mode 100644 tools/buildbot/scripts/master/json_file.py delete mode 100644 tools/buildbot/scripts/master/log_parser/__init__.py delete mode 100644 tools/buildbot/scripts/master/log_parser/archive_command.py delete mode 100644 tools/buildbot/scripts/master/log_parser/cl_command.py delete mode 100644 tools/buildbot/scripts/master/log_parser/gtest_command.py delete mode 100644 tools/buildbot/scripts/master/log_parser/process_log.py delete mode 100644 tools/buildbot/scripts/master/log_parser/retcode_command.py delete mode 100644 tools/buildbot/scripts/master/log_parser/webkit_test_command.py delete mode 100644 tools/buildbot/scripts/master/master_utils.py delete mode 100644 tools/buildbot/scripts/master/topics.html delete mode 100644 tools/buildbot/scripts/master/unittests/chromium_changes_test.py delete mode 100644 tools/buildbot/scripts/master/unittests/chromium_status_test.py delete mode 100644 tools/buildbot/scripts/master/unittests/chromium_utils_test.py delete mode 100644 tools/buildbot/scripts/master/unittests/data/benchpress_log delete mode 100644 tools/buildbot/scripts/master/unittests/data/commit_charge-summary.dat delete mode 100644 tools/buildbot/scripts/master/unittests/data/dest_startup_test_log delete mode 100644 tools/buildbot/scripts/master/unittests/data/error-log-compile-stdio delete mode 100644 tools/buildbot/scripts/master/unittests/data/error-log-compile-stdio-devenv delete mode 100644 tools/buildbot/scripts/master/unittests/data/error-log-compile-stdio-devenv-converted delete mode 100644 tools/buildbot/scripts/master/unittests/data/graphing_processor-graphs.dat delete mode 100644 tools/buildbot/scripts/master/unittests/data/graphing_processor.log delete mode 100644 tools/buildbot/scripts/master/unittests/data/ok-log-compile-stdio delete mode 100644 tools/buildbot/scripts/master/unittests/data/page_cycler_log delete mode 100644 tools/buildbot/scripts/master/unittests/data/page_cycler_log_duplicates delete mode 100644 tools/buildbot/scripts/master/unittests/data/page_cycler_log_io delete mode 100644 tools/buildbot/scripts/master/unittests/data/page_cycler_log_io_intl1 delete mode 100644 tools/buildbot/scripts/master/unittests/data/playback_log delete mode 100644 tools/buildbot/scripts/master/unittests/data/processes-summary.dat delete mode 100644 tools/buildbot/scripts/master/unittests/data/startup_test_log delete mode 100644 tools/buildbot/scripts/master/unittests/data/tab_switching_test_log delete mode 100644 tools/buildbot/scripts/master/unittests/data/vm_final_browser-summary.dat delete mode 100644 tools/buildbot/scripts/master/unittests/data/vm_final_total-summary.dat delete mode 100644 tools/buildbot/scripts/master/unittests/data/ws_final_browser-summary.dat delete mode 100644 tools/buildbot/scripts/master/unittests/data/ws_final_total-summary.dat delete mode 100644 tools/buildbot/scripts/master/unittests/devenv_log_to_ib_log_test.py delete mode 100644 tools/buildbot/scripts/master/unittests/gtest_command_unittest.py delete mode 100644 tools/buildbot/scripts/master/unittests/ib_output_parser_test.py delete mode 100644 tools/buildbot/scripts/master/unittests/master_utils_test.py delete mode 100644 tools/buildbot/scripts/master/unittests/process_log_test.py delete mode 100644 tools/buildbot/scripts/master/unittests/runtests.py delete mode 100644 tools/buildbot/scripts/master/whuffie.html delete mode 100644 tools/buildbot/scripts/slave/archive_build.py delete mode 100644 tools/buildbot/scripts/slave/archive_crash_dumps.py delete mode 100644 tools/buildbot/scripts/slave/archive_layout_test_results.py delete mode 100644 tools/buildbot/scripts/slave/check_slave.py delete mode 100644 tools/buildbot/scripts/slave/compile.py delete mode 100644 tools/buildbot/scripts/slave/differential_installer.py delete mode 100644 tools/buildbot/scripts/slave/extract_build.py delete mode 100644 tools/buildbot/scripts/slave/kill_processes.py delete mode 100644 tools/buildbot/scripts/slave/known-crashes.txt delete mode 100644 tools/buildbot/scripts/slave/layout_test_wrapper.py delete mode 100644 tools/buildbot/scripts/slave/node_leak_test_wrapper.py delete mode 100644 tools/buildbot/scripts/slave/playback_tests.py delete mode 100644 tools/buildbot/scripts/slave/run_crash_handler.py delete mode 100644 tools/buildbot/scripts/slave/runtest.py delete mode 100644 tools/buildbot/scripts/slave/slave_utils.py (limited to 'tools') diff --git a/tools/buildbot/config/master.chromium/DEPS b/tools/buildbot/config/master.chromium/DEPS deleted file mode 100644 index 0c36e10..0000000 --- a/tools/buildbot/config/master.chromium/DEPS +++ /dev/null @@ -1,7 +0,0 @@ -deps = { - "pylibs": - "/trunk/tools/buildbot/pylibs", - - "scripts": - "/trunk/tools/buildbot/scripts", -} diff --git a/tools/buildbot/config/master.chromium/Makefile b/tools/buildbot/config/master.chromium/Makefile deleted file mode 100644 index ff62a42..0000000 --- a/tools/buildbot/config/master.chromium/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -# -*- makefile -*- - -# This is a simple makefile which lives in a buildmaster/buildslave -# directory (next to the buildbot.tac file). It allows you to start/stop the -# master or slave by doing 'make start' or 'make stop'. - -# The 'reconfig' target will tell a buildmaster to reload its config file. - -# Note that a relative PYTHONPATH entry is relative to the current directory. - -start: - PYTHONPATH=../scripts/master:../scripts/common:../scripts/private:../pylibs python ../scripts/common/twistd --no_save -y buildbot.tac - -stop: - kill `cat twistd.pid` - -reconfig: - kill -HUP `cat twistd.pid` - -log: - tail -f twistd.log diff --git a/tools/buildbot/config/master.chromium/Makefile.win32 b/tools/buildbot/config/master.chromium/Makefile.win32 deleted file mode 100644 index b26b0ff..0000000 --- a/tools/buildbot/config/master.chromium/Makefile.win32 +++ /dev/null @@ -1,21 +0,0 @@ -# -*- makefile -*- - -# This is a simple makefile which lives in a buildmaster/buildslave -# directory (next to the buildbot.tac file). It allows you to start/stop the -# master or slave by doing 'make start' or 'make stop'. - -# The 'reconfig' target will tell a buildmaster to reload its config file. - -# Note that a relative PYTHONPATH entry is relative to the current directory. - -start: - PYTHONPATH="../scripts/master;../scripts/common;../scripts/private;../pylibs" ../depot_tools/release/python_24/python ../scripts/common/twistd --no_save -y buildbot.tac - -stop: - kill `cat twistd.pid` - -reconfig: - kill -HUP `cat twistd.pid` - -log: - tail -f twistd.log diff --git a/tools/buildbot/config/master.chromium/README b/tools/buildbot/config/master.chromium/README deleted file mode 100644 index 5043d78..0000000 --- a/tools/buildbot/config/master.chromium/README +++ /dev/null @@ -1,8 +0,0 @@ -This directory contains the configuration for the buildbot master. - -Files: - Makefile commands for controlling buildbot - master.cfg contains the build configuration - buildbot.tac generated file that initializes buildbot - buildbot.css css file used for the waterfall display - twistd shell script used to run buildbot diff --git a/tools/buildbot/config/master.chromium/buildbot b/tools/buildbot/config/master.chromium/buildbot deleted file mode 100644 index cf3628d..0000000 --- a/tools/buildbot/config/master.chromium/buildbot +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/python - -from buildbot.scripts import runner -runner.run() diff --git a/tools/buildbot/config/master.chromium/buildbot.tac b/tools/buildbot/config/master.chromium/buildbot.tac deleted file mode 100644 index b19a063..0000000 --- a/tools/buildbot/config/master.chromium/buildbot.tac +++ /dev/null @@ -1,13 +0,0 @@ -import os - -from twisted.application import service -from buildbot.master import BuildMaster - -import chromium_config as config - -basedir = os.path.dirname(os.path.abspath(__file__)) -configfile = r'master.cfg' - -application = service.Application('buildmaster') -BuildMaster(basedir, configfile).setServiceParent(application) - diff --git a/tools/buildbot/config/master.chromium/master.cfg b/tools/buildbot/config/master.chromium/master.cfg deleted file mode 100644 index ea8811f..0000000 --- a/tools/buildbot/config/master.chromium/master.cfg +++ /dev/null @@ -1,814 +0,0 @@ -# -*- python -*- -# ex: set syntax=python: - -# Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# This is the buildmaster config file for the 'chromium' bot. It must -# be installed as 'master.cfg' in your buildmaster's base directory -# (although the filename can be changed with the --basedir option to -# 'mktap buildbot master'). - -# It has one job: define a dictionary named BuildmasterConfig. This -# dictionary has a variety of keys to control different aspects of the -# buildmaster. They are documented in docs/config.xhtml . - -# This file follows this naming convention: -# Factories: f_chromium_[dbg/rel]_[type] -# Builders: b_chromium_[dbg/rel]_[os]_[type] -# BuildDir: chromium-[dbg/rel]-[os]-[type] -# -# os = xp/vista/linux/mac -# type = perf/tests/full/jsc/webkit_latest/purify - -from buildbot import locks -from buildbot.steps import shell - -import os - -# These modules come from scripts/master, which must be in the PYTHONPATH. -import master_utils -import chromium_step -import chromium_config as config -# These modules come from scripts/common, which must be in the PYTHONPATH. -import chromium_utils - - -# The default behavior of this master.cfg file is to run our production -# buildbot (of course). Setting the following variable to False will -# suppress initialization of production defaults. -PRODUCTION_BUILDBOT_MASTER = True - -if PRODUCTION_BUILDBOT_MASTER: - # Production defaults - MASTER_HOST = config.Master.master_host - TRUNK_URL = config.Master.trunk_url - BRANCH_URL = config.Master.branch_url - TRUNK_INTERNAL_URL = config.Master.trunk_internal_url - PROJECT_URL = config.Master.project_url - SVN_BINARY = config.Master.svn_binary_path - WEB_STATUS = True - MAIL_NOTIFIER = False - IRC_STATUS_BOT = True - PB_LISTENER = True -else: - MASTER_HOST = config.Master.master_host_experimental - TRUNK_URL = config.Master.trunk_url - BRANCH_URL = config.Master.branch_url - TRUNK_INTERNAL_URL = config.Master.trunk_internal_url - SVN_BINARY = config.Master.svn_binary_path_experimental - WEB_STATUS = True - MAIL_NOTIFIER = False - IRC_STATUS_BOT = False - PB_LISTENER = False - -MASTER_PORT = config.Master.master_port - -# This is the dictionary that the buildmaster pays attention to. We also use -# a shorter alias to save typing. -c = BuildmasterConfig = {} - -# 'slavePortnum' defines the TCP port to listen on. This must match the value -# configured into the buildslaves (with their --master option) -c['slavePortnum'] = config.Master.slave_port - - -####### BUILDSLAVES - -# the 'bots' list defines the set of allowable buildslaves. Each element is a -# tuple of bot-name and bot-password. These correspond to values given to the -# buildslave's mktap invocation. -bot_password = config.Master.GetBotPassword() -print bot_password -if PRODUCTION_BUILDBOT_MASTER: - c['bots'] = [('hae162', bot_password), - ('hae163', bot_password), - ('hae164', bot_password), - ('hae165', bot_password), - ('hae166', bot_password), - ('hae167', bot_password), - ('hae168', bot_password), - ('hae169', bot_password), - ('hae170', bot_password), - ('hae171', bot_password), - ('hae172', bot_password), - ('hae173', bot_password), - ('hae174', bot_password), - ('hae175', bot_password), - ('hae176', bot_password), - ('hae177', bot_password), - ('hae178', bot_password), - ('hae179', bot_password), - ('hae180', bot_password), - ('hae181', bot_password), - ('hae182', bot_password), - ('hae183', bot_password), - ('hae184', bot_password), - ('hae185', bot_password), - ('hae186', bot_password), - ('hae187', bot_password), - ('hae188', bot_password), - ('internal-1', bot_password), - ('internal-2', bot_password), - ('internal-3', bot_password), - ('internal-4', bot_password), - ('internal-5', bot_password), - ('internal-6', bot_password), - ('internal-7', bot_password), - ('chromebuild-linux', bot_password)] -else: - c['bots'] = [('chromium-experimental', bot_password)] - - -####### CHANGESOURCES - -# the 'sources' list tells the buildmaster how it should find out about -# source code changes. Any class which implements IChangeSource can be added -# to this list: there are several in buildbot/changes/*.py to choose from. -def ChromeTreeFileSplitter(path): - """split_file for the 'src' project in the trunk.""" - - # List of projects we are interested in. The project names must exactly - # match paths in the Subversion repository, relative to the 'path' URL - # argument. master_utils.SplitPath() will use them as branch names to - # kick off the Schedulers for different projects. - projects = ['src'] - return master_utils.SplitPath(projects, path) - -def MergeFileSplitter(path): - """split_file for webkit merge branch changes.""" - projects = ['chrome_webkit_merge_branch'] - return master_utils.SplitPath(projects, path) - - -import chromium_changes -# Polls TRUNK_URL for changes -trunk_poller = chromium_changes.SVNPoller(svnurl = TRUNK_URL, - split_file=ChromeTreeFileSplitter, - pollinterval=10, - svnbin=SVN_BINARY) - -# Polls BRANCH_URL for changes and recognizes 'chrome_webkit_merge_branch' -# changes. -merge_poller = chromium_changes.SVNPoller(svnurl = BRANCH_URL, - split_file=MergeFileSplitter, - pollinterval=30, - svnbin=SVN_BINARY) - -c['sources'] = [trunk_poller, merge_poller] - - -####### SCHEDULERS - -## configure the Schedulers - -from buildbot.scheduler import Dependent -from buildbot.scheduler import Nightly -from buildbot.scheduler import Scheduler - -# Main scheduler for all changes in trunk. -s_chromium = Scheduler(name='chromium', - branch='src', - treeStableTimer=60, - builderNames=['Chromium XP', - 'Chromium XP (jsc)', - 'XP Tests (purify)', - 'Webkit (purify)', - 'Modules XP', - 'Modules XP (dbg)', - 'Modules XP (purify)', - 'Modules Vista', - 'Modules Vista (dbg)', - 'Modules Linux (dbg)', - 'Modules Mac', - 'Modules Mac (dbg)']) - -# Scheduler to trigger slaves that depend on the release build. -s_chromium_rel_builder = Scheduler(name='chromium_rel_builder', - branch='src', - treeStableTimer=60, - builderNames=['Chromium Builder']) - -s_chromium_rel_dependent = Dependent('chromium_rel_dependent', - s_chromium_rel_builder, - ['XP Tests', - 'Vista Tests', - 'XP Perf', - 'Vista Perf', - ]) - - -# Scheduler to trigger slaves that depend on the debug build. -s_chromium_dbg_builder = Scheduler(name='chromium_dbg_builder', - branch='src', - treeStableTimer=60, - builderNames=['Chromium Builder (dbg)']) - -s_chromium_dbg_dependent = Dependent('chromium_dbg_dependent', - s_chromium_dbg_builder, - ['XP Tests (dbg)', - 'Vista Tests (dbg)', - 'Interactive Tests (dbg)', - 'XP Perf (dbg)', - 'Vista Perf (dbg)' - ]) - - -# Scheduler to trigger slaves that depend on the webkit release build. -s_webkit_rel_builder = Scheduler(name='webkit_rel_builder', - branch='src', - treeStableTimer=60, - builderNames=['Webkit Builder']) - -s_webkit_rel_builder_dependent = Dependent('webkit_release_dependent', - s_webkit_rel_builder, - ['Webkit']) - -# Scheduler to trigger slaves that depend on the webkit debug build. -s_webkit_dbg_builder = Scheduler(name='webkit_dbg_builder', - branch='src', - treeStableTimer=60, - builderNames=['Webkit Builder (dbg)']) - -s_webkit_dbg_builder_dependent = Dependent('webkit_dbg_dependent', - s_webkit_dbg_builder, - ['Webkit (dbg)']) - -# Sechduler to trigger slaves that depend on the webkit release build with the -# latest version of v8. -s_webkit_rel_builder_v8 = Scheduler(name='webkit_rel_builder_v8', - branch='src', - treeStableTimer=60, - builderNames=['Webkit Builder (V8-Latest)']) - -s_webkit_rel_builder_dependent_v8 = Dependent('webkit_rel_dependent_v8', - s_webkit_rel_builder_v8, - ['Webkit (V8-Latest)']) - -# Special weekly scheduler for purify_layout. Starts every friday at 11pm. -s_webkit_rel_purify_layout = Nightly(name='webkit_rel_purify_layout', - dayOfWeek=4, - hour=23, - builderNames=['Webkit (purify layout)']) - -# Webkit Merge scheduler -s_webkit_rel_merge = Scheduler(name='webkit_rel_merge', - branch='chrome_webkit_merge_branch', - treeStableTimer=60, - builderNames=['Webkit (merge)', - 'Chromium XP (merge)']) - -# Experimental Scheduler -s_chromium_experimental = Scheduler(name='experimental', - branch='src', - treeStableTimer=60, - builderNames=['Chromium Experimental']) - -if PRODUCTION_BUILDBOT_MASTER: - c['schedulers'] = [s_chromium, - s_chromium_rel_builder, - s_chromium_rel_dependent, - s_chromium_dbg_builder, - s_chromium_dbg_dependent, - s_webkit_rel_builder, - s_webkit_rel_builder_dependent, - s_webkit_dbg_builder, - s_webkit_dbg_builder_dependent, - s_webkit_rel_builder_v8, - s_webkit_rel_builder_dependent_v8, - s_webkit_rel_merge, - s_webkit_rel_purify_layout] -else: - c['schedulers'] = [s_chromium_experimental] - -####### BUILDERS - -# the 'builders' list defines the Builders. Each one is configured with a -# dictionary, using the following keys: -# name (required): the name used to describe this bilder -# slavename (required): which slave to use, must appear in c['bots'] -# builddir (required): which subdirectory to run the builder in -# factory (required): a BuildFactory to define how the build is run -# periodicBuildTime (optional): if set, force a build every N seconds - -# buildbot/process/factory.py provides several BuildFactory classes you can -# start with, which implement build processes for common targets (GNU -# autoconf projects, CPAN perl modules, etc). The factory.BuildFactory is the -# base class, and is configured with a series of BuildSteps. When the build -# is run, the appropriate buildslave is told to execute each Step in turn. - -# the first BuildStep is typically responsible for obtaining a copy of the -# sources. There are source-obtaining Steps in buildbot/process/step.py for -# CVS, SVN, and others. - -builders = [] - -# ---------------------------------------------------------------------------- -# FACTORIES - -m = master_utils.MasterFactory('src/chrome', - TRUNK_URL + '/src', - TRUNK_INTERNAL_URL + '/src-internal') - -m_webkit = master_utils.MasterFactory('src/webkit', - TRUNK_URL + '/src', - TRUNK_INTERNAL_URL + '/src-internal') - -m_linux = master_utils.MasterFactory('src/chrome', - TRUNK_URL + '/src', - TRUNK_INTERNAL_URL + '/src-internal', - target_platform='linux2') - -m_mac = master_utils.MasterFactory('src/chrome', - TRUNK_URL + '/src', - TRUNK_INTERNAL_URL + '/src-internal', - target_platform='darwin') - -# The identifier of the factory is the build configuration. If two factories -# are using the same build configuration, they should have the same identifier. - -# BuilderTesters using a custom build configuration. -f_chromium_rel_full = m.NewBuildFactory(identifier='chromium-rel-xp', - archive_build=True, - run_crash_handler=True, - check_deps=True, - tests=['selenium', 'unit', 'ui', 'test_shell', - 'page_cycler', 'page_cycler_http', 'startup', - 'tab_switching', 'memory']) - -f_chromium_rel_jsc = m.NewBuildFactory(identifier='chromium-rel-jsc', - solution='chrome_kjs.sln', - # We don't archive because the machine is not in bighouse - # yet and can't access the drive. - #archive_build=True, - with_pageheap=True, - show_perf_results=True, - perf_id='chromium-rel-jsc', - run_crash_handler=True, - tests=['selenium', 'unit', 'ui', 'test_shell', - 'page_cycler', 'startup', 'tab_switching']) - -f_chromium_rel_merge = m.NewBuildFactory(identifier='chromium-rel-merge', - svnurl=config.Master.merge_branch_url, - run_crash_handler=True, - tests=['selenium', 'unit', 'ui', 'test_shell', - 'page_cycler', 'startup', 'tab_switching']) - - -f_chromium_rel_purify = m.NewBuildFactory(identifier='chromium-rel-purify', - mode='purify', - run_crash_handler=True, - tests=['purify_chrome']) - -f_chromium_rel_builder = m.NewBuildFactory(identifier='chromium-rel', - slave_type='Builder', - check_deps=True, - tests=[]) - -f_chromium_dbg_builder = m.NewBuildFactory(identifier='chromium-dbg', - target='Debug', - slave_type='Builder', - check_deps=True, - tests=[]) - -f_chromium_rel_tests = m.NewBuildFactory(identifier='chromium-rel', - slave_type='Tester', - run_crash_handler=True, - tests=['unit', 'ui']) - -f_chromium_dbg_tests = m.NewBuildFactory(identifier='chromium-dbg', - target='Debug', - slave_type='Tester', - run_crash_handler=True, - tests=['unit', 'ui']) - -f_chromium_dbg_interactive_tests = m.NewBuildFactory(identifier='chromium-dbg', - target='Debug', - # this machine should just get a build from - # the builder, but it's too slow since the - # machine in not in bighouse - # slave_type='Tester', - run_crash_handler=True, - tests=['interactive_ui']) - -f_chromium_dbg_perf = m.NewBuildFactory(identifier='chromium-dbg', - target='Debug', - slave_type='Tester', - run_crash_handler=True, - tests=['plugin', 'page_cycler', - 'startup', 'tab_switching']) - -f_chromium_dbg_perf_vista = m.NewBuildFactory(identifier='chromium-dbg', - target='Debug', - slave_type='Tester', - run_crash_handler=True, - tests=['page_cycler', 'startup', - 'tab_switching']) - -f_chromium_rel_perf_xp_dual = m.NewBuildFactory(identifier='chromium-rel', - slave_type='Tester', - show_perf_results=True, - perf_id='chromium-rel-xp-dual', - run_crash_handler=True, - tests=['page_cycler', 'startup', - 'tab_switching', 'memory']) - -f_chromium_rel_perf_vista_dual = m.NewBuildFactory(identifier='chromium-rel', - #slave_type='Tester', - show_perf_results=True, - perf_id='chromium-rel-vista-dual', - run_crash_handler=True, - tests=['page_cycler', 'startup', - 'tab_switching', 'memory']) - -f_webkit_rel_builder = m_webkit.NewBuildFactory('webkit-rel', - slave_type='Builder', - tests=[]) - -f_webkit_dbg_builder = m_webkit.NewBuildFactory('webkit-dbg', - target='Debug', - slave_type='Builder', - tests=[]) - -f_webkit_rel = m_webkit.NewBuildFactory('webkit-rel', - slave_type='Tester', - tests=['test_shell', 'webkit']) - -f_webkit_dbg = m_webkit.NewBuildFactory('webkit-dbg', - target='Debug', - slave_type='Tester', - tests=['test_shell', 'webkit']) - -f_webkit_rel_builder_v8 = m_webkit.NewBuildFactory( - 'webkit-rel-v8', - slave_type='Builder', - tests=[], - gclient_custom_deps=[m_webkit.CUSTOM_DEPS_V8_LATEST]) - -f_webkit_rel_v8 = m_webkit.NewBuildFactory( - 'webkit-rel-v8', - slave_type='Tester', - tests=['test_shell', 'webkit'], - gclient_custom_deps=[m_webkit.CUSTOM_DEPS_V8_LATEST]) - -f_webkit_rel_purify = m_webkit.NewBuildFactory('webkit-rel-purify', - mode='purify', - tests=['purify_webkit']) - -f_webkit_rel_purify_layout = m_webkit.NewBuildFactory('webkit-rel-purify', - mode='purify', - tests=['purify_layout']) - -f_webkit_rel_merge = m_webkit.NewBuildFactory('webkit-rel-merge', - svnurl=config.Master.merge_branch_url, - tests=['test_shell', 'webkit']) - -f_sub_rel = m.NewSubmoduleFactory(identifier='sub-rel') -f_sub_dbg = m.NewSubmoduleFactory(identifier='sub-deb', target='Debug') -f_sub_rel_purify = m.NewSubmoduleFactory(identifier='sub-rel-purify', - mode='purify') - -f_sub_dbg_linux = m_linux.NewBuildFactory(identifier='sub-dbg-linux', - target='Hammer', - tests=['base', 'net', 'googleurl', - 'unit'], - build_dir='src/chrome', - run_crash_handler=False, - options=['--build-tool=scons', - '--', 'Hammer']) - -f_sub_rel_mac = m_mac.NewBuildFactory(identifier='sub-rel-mac', - target='Release', - tests=['base', 'net', 'googleurl', - 'unit'], - build_dir='src/build', - run_crash_handler=False, - options=['--build-tool=xcode', '--', - '-project', 'all.xcodeproj']) - -f_sub_dbg_mac = m_mac.NewBuildFactory(identifier='sub-dbg-mac', - target='Debug', - tests=['base', 'net', 'googleurl', - 'unit'], - build_dir='src/build', - run_crash_handler=False, - options=['--build-tool=xcode', '--', - '-project', 'all.xcodeproj']) - -f_chromium_experimental = m.NewBuildFactory(identifier='chromium-experimental', - tests=[]) - -internal_4_lock = locks.SlaveLock('internal4') -internal_5_lock = locks.SlaveLock('internal5') - -b_chromium_rel_xp_full = {'name': 'Chromium XP', - 'slavename': 'hae178', - 'builddir': 'chromium-rel-xp', - 'factory': f_chromium_rel_full, -} - -b_chromium_dbg_builder = {'name': 'Chromium Builder (dbg)', - 'slavename': 'hae176', - 'builddir': 'chromium-dbg-builder', - 'factory': f_chromium_dbg_builder, -} - -b_chromium_rel_builder = {'name': 'Chromium Builder', - 'slavename': 'hae177', - 'builddir': 'chromium-rel-builder', - 'factory': f_chromium_rel_builder, -} - -b_chromium_rel_xp_tests = {'name': 'XP Tests', - 'slavename': 'hae175', - 'builddir': 'chromium-rel-xp-tests', - 'factory': f_chromium_rel_tests, -} - -b_chromium_dbg_xp_tests = {'name': 'XP Tests (dbg)', - 'slavename': 'hae174', - 'builddir': 'chromium-dbg-xp-tests', - 'factory': f_chromium_dbg_tests, -} - -b_chromium_dbg_xp_interactive_tests = {'name': 'Interactive Tests (dbg)', - 'slavename': 'internal-1', - 'builddir': 'chromium-dbg-xp-interactive', - 'factory': f_chromium_dbg_interactive_tests, -} - -b_chromium_rel_vista_tests = {'name': 'Vista Tests', - 'slavename': 'hae173', - 'builddir': 'chromium-rel-vista-tests', - 'factory': f_chromium_rel_tests, -} - -b_chromium_dbg_vista_tests = {'name': 'Vista Tests (dbg)', - 'slavename': 'hae172', - 'builddir': 'chromium-dbg-vista-tests', - 'factory': f_chromium_dbg_tests, -} - -b_chromium_dbg_xp_perf = {'name': 'XP Perf (dbg)', - 'slavename': 'hae168', - 'builddir': 'chromium-dbg-xp-perf', - 'factory': f_chromium_dbg_perf, -} - -b_chromium_dbg_vista_perf = {'name': 'Vista Perf (dbg)', - 'slavename': 'hae167', - 'builddir': 'chromium-dbg-vista-perf', - 'factory': f_chromium_dbg_perf_vista, -} - -b_chromium_rel_xp_perf_dual = {'name': 'XP Perf', - 'slavename': 'internal-6', - 'builddir': 'chromium-rel-xp-perf-dual', - 'factory': f_chromium_rel_perf_xp_dual, -} - -b_chromium_rel_vista_perf_dual = {'name': 'Vista Perf', - 'slavename': 'internal-7', - 'builddir': 'chromium-rel-vista-perf-dual', - 'factory': f_chromium_rel_perf_vista_dual, -} - -b_chromium_rel_xp_purify = {'name': 'XP Tests (purify)', - 'slavename': 'internal-3', - 'builddir': 'pc', - 'factory': f_chromium_rel_purify, -} - -b_chromium_rel_xp_jsc = {'name': 'Chromium XP (jsc)', - 'slavename': 'internal-2', - 'builddir': 'chromium-rel-xp-jsc', - 'factory': f_chromium_rel_jsc, -} - -b_chromium_rel_xp_merge = {'name': 'Chromium XP (merge)', - 'slavename': 'internal-5', - 'builddir': 'chromium-rel-xp-merge', - 'factory': f_chromium_rel_merge, - 'locks': [internal_5_lock], -} - -b_webkit_rel_builder = {'name': 'Webkit Builder', - 'slavename': 'hae184', - 'builddir': 'webkit-rel-builder', - 'factory': f_webkit_rel_builder, -} - -b_webkit_dbg_builder = {'name': 'Webkit Builder (dbg)', - 'slavename': 'hae183', - 'builddir': 'webkit-dbg-builder', - 'factory': f_webkit_dbg_builder, -} - -b_webkit_rel_builder_v8 = {'name': 'Webkit Builder (V8-Latest)', - 'slavename': 'hae182', - 'builddir': 'webkit-rel-builder-v8', - 'factory': f_webkit_rel_builder_v8, -} - -b_webkit_rel = {'name': 'Webkit', - 'slavename': 'hae181', - 'builddir': 'webkit-rel', - 'factory': f_webkit_rel, -} - -b_webkit_dbg = {'name': 'Webkit (dbg)', - 'slavename': 'hae180', - 'builddir': 'webkit-dbg', - 'factory': f_webkit_dbg, -} - -b_webkit_rel_v8 = {'name': 'Webkit (V8-Latest)', - 'slavename': 'hae179', - 'builddir': 'webkit-rel-v8', - 'factory': f_webkit_rel_v8, -} - -b_webkit_rel_purify = {'name': 'Webkit (purify)', - 'slavename': 'internal-4', - 'builddir': 'pw', - 'factory': f_webkit_rel_purify, - 'locks': [internal_4_lock], -} - -b_webkit_rel_purify_layout = {'name': 'Webkit (purify layout)', - 'slavename': 'internal-4', - 'builddir': 'pl', - 'factory': f_webkit_rel_purify_layout, - 'locks': [internal_4_lock], -} - -b_webkit_rel_merge = {'name': 'Webkit (merge)', - 'slavename': 'internal-5', - 'builddir': 'webkit-rel-merge', - 'factory': f_webkit_rel_merge, - 'locks': [internal_5_lock], -} - -b_sub_dbg_xp = {'name': 'Modules XP (dbg)', - 'slavename': 'hae187', - 'builddir': 'sub-dbg-xp', - 'factory': f_sub_dbg, -} - -b_sub_rel_xp = {'name': 'Modules XP', - 'slavename': 'hae188', - 'builddir': 'sub-rel-xp', - 'factory': f_sub_rel, -} - -b_sub_rel_xp_purify = {'name': 'Modules XP (purify)', - 'slavename': 'internal-4', - 'builddir': 'ps', - 'factory': f_sub_rel_purify, - 'locks': [internal_4_lock], -} - -b_sub_dbg_vista = {'name': 'Modules Vista (dbg)', - 'slavename': 'hae185', - 'builddir': 'sub-dbg-vista', - 'factory': f_sub_dbg, -} - -b_sub_rel_vista = {'name': 'Modules Vista', - 'slavename': 'hae186', - 'builddir': 'sub-rel-vista', - 'factory': f_sub_rel, -} - -b_chromium_experimental = {'name': 'Chromium Experimental', - 'slavename': 'chromium-experimental', - 'builddir': 'chromium-experimental', - 'factory': f_chromium_experimental, -} - -b_sub_dbg_linux = {'name': 'Modules Linux (dbg)', - 'slavename': 'chromebuild-linux', - 'builddir': 'sub-dbg-linux', - 'factory': f_sub_dbg_linux, -} - -b_sub_rel_mac = {'name': 'Modules Mac', - 'slavename': 'hae163', - 'builddir': 'sub-rel-mac', - 'factory': f_sub_rel_mac, -} - -b_sub_dbg_mac = {'name': 'Modules Mac (dbg)', - 'slavename': 'hae165', - 'builddir': 'sub-dbg-mac', - 'factory': f_sub_dbg_mac, -} - -if PRODUCTION_BUILDBOT_MASTER: - c['builders'] = [b_chromium_rel_xp_full, - b_chromium_rel_builder, - b_chromium_dbg_builder, - b_chromium_rel_xp_tests, - b_chromium_dbg_xp_tests, - b_chromium_rel_xp_purify, - b_chromium_rel_vista_tests, - b_chromium_dbg_vista_tests, - b_chromium_dbg_xp_interactive_tests, - b_chromium_rel_xp_perf_dual, - b_chromium_dbg_xp_perf, - b_chromium_rel_vista_perf_dual, - b_chromium_dbg_vista_perf, - b_chromium_rel_xp_jsc, - b_chromium_rel_xp_merge, - b_webkit_rel_builder, - b_webkit_rel_builder_v8, - b_webkit_dbg_builder, - b_webkit_rel, - b_webkit_rel_v8, - b_webkit_dbg, - b_webkit_rel_purify, - b_webkit_rel_purify_layout, - b_webkit_rel_merge, - b_sub_rel_xp, - b_sub_dbg_xp, - b_sub_rel_xp_purify, - b_sub_rel_vista, - b_sub_dbg_vista, - b_sub_dbg_linux, - b_sub_rel_mac, - b_sub_dbg_mac] -else: - c['builders'] = [b_chromium_experimental] - - -####### STATUS TARGETS - -# 'status' is a list of Status Targets. The results of each build will be -# pushed to these targets. buildbot/status/*.py has a variety to choose from, -# including web pages, email senders, and IRC bots. - -c['status'] = [] - -if WEB_STATUS: - #from buildbot.status.html import WebStatus - from chromium_status import WebStatus - c['status'].append(WebStatus(MASTER_PORT, allowForce=True)) - c['status'].append(WebStatus(8014, allowForce=False)) - -if MAIL_NOTIFIER: - from buildbot.status import mail - c['status'].append(mail.MailNotifier( - fromaddr=config.Master.notifications_from, mode='problem')) - -if IRC_STATUS_BOT: - from buildbot.status import words - # Patch our topic-observing bot in on top of the IRC factory. - from chromium_status import IrcStatusChatterBot - words.IrcStatusFactory.protocol = IrcStatusChatterBot - c['status'].append(words.IRC(host=config.Master.irc_host, - nick=config.Master.irc_nickname, - channels=config.Master.irc_channels)) - -if PB_LISTENER: - from buildbot.status import client - c['status'].append(client.PBListener(9988)) - - -####### DEBUGGING OPTIONS - -# if you set 'debugPassword', then you can connect to the buildmaster with -# the diagnostic tool in contrib/debugclient.py . From this tool, you can -# manually force builds and inject changes, which may be useful for testing -# your buildmaster without actually commiting changes to your repository (or -# before you have a functioning 'sources' set up). The debug tool uses the -# same port number as the slaves do: 'slavePortnum'. - -#c['debugPassword'] = 'debugpassword' - -# if you set 'manhole', you can ssh into the buildmaster and get an -# interactive python shell, which may be useful for debugging buildbot -# internals. It is probably only useful for buildbot developers. You can also -# use an authorized_keys file, or plain telnet. -#from buildbot import manhole -#c['manhole'] = manhole.PasswordManhole('tcp:9999:interface=127.0.0.1', -# 'admin', 'password') - - -####### PROJECT IDENTITY - -# the 'projectName' string will be used to describe the project that this -# buildbot is working on. For example, it is used as the title of the -# waterfall HTML page. The 'projectURL' string will be used to provide a link -# from buildbot HTML pages to your project's home page. - -c['projectName'] = config.Master.project_name -c['projectURL'] = config.Master.project_url - -# the 'buildbotURL' string should point to the location where the buildbot's -# internal web server (usually the html.Waterfall page) is visible. This -# typically uses the port number set in the Waterfall 'status' entry, but -# with an externally-visible host name which the buildbot cannot figure out -# without some help. - -c['buildbotURL'] = config.Master.buildbot_url diff --git a/tools/buildbot/config/master.chromium/public_html/announce.html b/tools/buildbot/config/master.chromium/public_html/announce.html deleted file mode 100644 index ab48173..0000000 --- a/tools/buildbot/config/master.chromium/public_html/announce.html +++ /dev/null @@ -1,80 +0,0 @@ -
- - - - - - - - -
- - - - - - - - - - - - - - - - - -
- Builds: - - continuous | - symbols | - perf | - status -
- Development: - - source | - reviews | - bugs -
- Chromium: - - www | - blog | - dev | - support -
- Sheriffs: - - nsylvain, tc -
-
- - - - -
-
-
-
diff --git a/tools/buildbot/config/master.chromium/public_html/buildbot.css b/tools/buildbot/config/master.chromium/public_html/buildbot.css deleted file mode 100644 index e119869..0000000 --- a/tools/buildbot/config/master.chromium/public_html/buildbot.css +++ /dev/null @@ -1,183 +0,0 @@ -body { - margin-bottom:50px; -} - -body, td { - font-family: Verdana, Cursor; - font-size: 10px; - font-weight: bold; -} - -a:link,a:visited,a:active { - color: #444; -} -a:hover { - color: #000000; -} - -table { - border-spacing: 1px 1px; -} - -table td { - padding: 3px 0px 3px 0px; - text-align: center; -} - -.Project { - width: 100px; -} - -.LastBuild, .Activity { - padding: 0 0 0 4px; -} - -.LastBuild, .Activity, .Builder, .BuildStep { - width: 155px; - max-width: 155px; -} - -div.BuildResultInfo { - color: #444; -} - -div.Announcement { - margin-bottom: 1em; -} - -div.Announcement > a:hover { - color: black; -} - -div.Announcement > div.Notice { - background-color: #afdaff; - padding: 0.5em; - font-size: 16px; - text-align: center; -} - -div.Announcement > div.Open { - border: 3px solid #8fdf5f; - padding: 0.5em; - font-size: 16px; - text-align: center; -} - -div.Announcement > div.Closed { - border: 5px solid #e98080; - padding: 0.5em; - font-size: 24px; - font-weight: bold; - text-align: center; -} - -td.Time { - color: #000; - border-bottom: 1px solid #aaa; - background-color: #eee; -} - -td.Activity, td.Change, td.Builder { - color: #333333; - background-color: #CCCCCC; -} - -td.Change { - border-radius: 5px; - -webkit-border-radius: 5px; -} -td.Event { - color: #777; - background-color: #ddd; - border-radius: 5px; - -webkit-border-radius: 5px; -} - -td.Activity { - border-top-left-radius: 10px; - -webkit-border-top-left-radius: 10px; - min-height: 20px; - padding: 2px 0 2px 0; -} - -td.idle, td.waiting, td.offline, td.building { - border-top-left-radius: 0px; - -webkit-border-top-left-radius: 0px; -} - -.LastBuild { - border-top-left-radius: 5px; - -webkit-border-top-left-radius: 5px; - border-top-right-radius: 5px; - -webkit-border-top-right-radius: 5px; -} - -/* LastBuild, BuildStep states */ -.success { - color: #FFFFFF; - background-color: #8fdf5f; -} - -.failure { - color: #FFFFFF; - background-color: #e98080; -} - -.warnings { - color: #FFFFFF; - background-color: #ffc343; -} - -.exception, td.offline { - color: #FFFFFF; - background-color: #e0b0ff; -} - -.start,.running, td.building { - color: #666666; - background-color: #fffc6c; -} - -.start { - border-bottom-left-radius: 10px; - -webkit-border-bottom-left-radius: 10px; - border-bottom-right-radius: 10px; - -webkit-border-bottom-right-radius: 10px; -} - -.closed { - background-color: #ff0000; -} - -.closed .large { - font-size: 1.5em; - font-weight: bolder; -} - -td.Project a:hover, td.start a:hover { - color: #000; -} - -.mini-box { - text-align:center; - height:20px; - padding:0 2px; - line-height:0; - white-space:nowrap; -} - -.mini-box a { - border-radius:0; - -webkit-border-radius:0; - display:block; - width:100%; - height:20px; - line-height:20px; - margin-top:-30px; -} - -.mini-closed { - -box-sizing:border-box; - -webkit-box-sizing:border-box; - border:4px solid red; -} diff --git a/tools/buildbot/config/master.chromium/public_html/chromium-32.png b/tools/buildbot/config/master.chromium/public_html/chromium-32.png deleted file mode 100644 index e804e3f..0000000 Binary files a/tools/buildbot/config/master.chromium/public_html/chromium-32.png and /dev/null differ diff --git a/tools/buildbot/config/master.chromium/public_html/favicon.ico b/tools/buildbot/config/master.chromium/public_html/favicon.ico deleted file mode 100644 index 30ad166..0000000 Binary files a/tools/buildbot/config/master.chromium/public_html/favicon.ico and /dev/null differ diff --git a/tools/buildbot/config/master.chromium/public_html/index.html b/tools/buildbot/config/master.chromium/public_html/index.html deleted file mode 100644 index d585770..0000000 --- a/tools/buildbot/config/master.chromium/public_html/index.html +++ /dev/null @@ -1,15 +0,0 @@ - - - -BuildBot Index page - - - - - - diff --git a/tools/buildbot/config/master.chromium/public_html/status-summary.html b/tools/buildbot/config/master.chromium/public_html/status-summary.html deleted file mode 100644 index e69de29..0000000 diff --git a/tools/buildbot/config/master.chromium/run_master.bat b/tools/buildbot/config/master.chromium/run_master.bat deleted file mode 100644 index 1e4eb20..0000000 --- a/tools/buildbot/config/master.chromium/run_master.bat +++ /dev/null @@ -1,6 +0,0 @@ -@echo off -setlocal -title Master -set PYTHONPATH=.;..\scripts\master;..\scripts\common;..\scripts\private;..\pylibs -set PATH=%~dp0..\depot_tools\release\python_24\;%PATH% -python ..\scripts\common\twistd --no_save -y buildbot.tac \ No newline at end of file diff --git a/tools/buildbot/config/master.tryserver/DEPS b/tools/buildbot/config/master.tryserver/DEPS deleted file mode 100644 index 0c36e10..0000000 --- a/tools/buildbot/config/master.tryserver/DEPS +++ /dev/null @@ -1,7 +0,0 @@ -deps = { - "pylibs": - "/trunk/tools/buildbot/pylibs", - - "scripts": - "/trunk/tools/buildbot/scripts", -} diff --git a/tools/buildbot/config/master.tryserver/Makefile b/tools/buildbot/config/master.tryserver/Makefile deleted file mode 100644 index ff62a42..0000000 --- a/tools/buildbot/config/master.tryserver/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -# -*- makefile -*- - -# This is a simple makefile which lives in a buildmaster/buildslave -# directory (next to the buildbot.tac file). It allows you to start/stop the -# master or slave by doing 'make start' or 'make stop'. - -# The 'reconfig' target will tell a buildmaster to reload its config file. - -# Note that a relative PYTHONPATH entry is relative to the current directory. - -start: - PYTHONPATH=../scripts/master:../scripts/common:../scripts/private:../pylibs python ../scripts/common/twistd --no_save -y buildbot.tac - -stop: - kill `cat twistd.pid` - -reconfig: - kill -HUP `cat twistd.pid` - -log: - tail -f twistd.log diff --git a/tools/buildbot/config/master.tryserver/Makefile.win32 b/tools/buildbot/config/master.tryserver/Makefile.win32 deleted file mode 100644 index 00d6783..0000000 --- a/tools/buildbot/config/master.tryserver/Makefile.win32 +++ /dev/null @@ -1,21 +0,0 @@ -# -*- makefile -*- - -# This is a simple makefile which lives in a buildmaster/buildslave -# directory (next to the buildbot.tac file). It allows you to start/stop the -# master or slave by doing 'make start' or 'make stop'. - -# The 'reconfig' target will tell a buildmaster to reload its config file. - -# Note that a relative PYTHONPATH entry is relative to the current directory. - -start: - PYTHONPATH="../scripts/master;../scripts/common;../scripts/private;../pylibs" ../depot_tools/latest/python_24/python ../scripts/common/twistd --no_save -y buildbot.tac - -stop: - kill `cat twistd.pid` - -reconfig: - kill -HUP `cat twistd.pid` - -log: - tail -f twistd.log diff --git a/tools/buildbot/config/master.tryserver/README b/tools/buildbot/config/master.tryserver/README deleted file mode 100644 index 26f261c..0000000 --- a/tools/buildbot/config/master.tryserver/README +++ /dev/null @@ -1,8 +0,0 @@ -This directory contains the configuration for the buildbot master. - -Files: - Makefile commands for controlling buildbot - master.cfg contains the tryserver configuration - buildbot.tac generated file that initializes buildbot - buildbot.css css file used for the waterfall display - twistd shell script used to run buildbot diff --git a/tools/buildbot/config/master.tryserver/buildbot b/tools/buildbot/config/master.tryserver/buildbot deleted file mode 100644 index cf3628d..0000000 --- a/tools/buildbot/config/master.tryserver/buildbot +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/python - -from buildbot.scripts import runner -runner.run() diff --git a/tools/buildbot/config/master.tryserver/buildbot.tac b/tools/buildbot/config/master.tryserver/buildbot.tac deleted file mode 100644 index ac7497c..0000000 --- a/tools/buildbot/config/master.tryserver/buildbot.tac +++ /dev/null @@ -1,11 +0,0 @@ -import os - -from twisted.application import service -from buildbot.master import BuildMaster - -basedir = os.path.dirname(os.path.abspath(__file__)) -configfile = r'master.cfg' - -application = service.Application('buildmaster') -BuildMaster(basedir, configfile).setServiceParent(application) - diff --git a/tools/buildbot/config/master.tryserver/mail_notifier.py b/tools/buildbot/config/master.tryserver/mail_notifier.py deleted file mode 100644 index acf159e..0000000 --- a/tools/buildbot/config/master.tryserver/mail_notifier.py +++ /dev/null @@ -1,127 +0,0 @@ -#!/usr/bin/python -# Copyright (c) 2008 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""A class to mail the try bot results. -""" - -from buildbot.status import mail -from buildbot.status.builder import FAILURE, SUCCESS, WARNINGS -from email.Message import Message -from email.Utils import formatdate -import urllib -from twisted.internet import defer - - -class MailNotifier(mail.MailNotifier): - def buildMessage(self, name, build, results): - """Send an email about the result. Don't attach the patch as - MailNotifier.buildMessage do.""" - - projectName = self.status.getProjectName() - ss = build.getSourceStamp() - build_url = self.status.getURLForThing(build) - waterfall_url = self.status.getBuildbotURL() - # build.getSlavename() - - patch_url_text = "" - if ss and ss.patch: - patch_url_text = "Patch: %s/steps/gclient/logs/patch\n\n" % build_url - failure_bot = "" - failure_tree = "" - if results != SUCCESS: - failure_bot = "(In case the bot is broken)\n" - failure_tree = "(in case the tree is broken)\n" - - if ss is None: - source = "unavailable" - else: - source = "" - if ss.branch: - source += "[branch %s] " % ss.branch - if ss.revision: - source += ss.revision - else: - source += "HEAD" # TODO(maruel): Tell the exact rev? That'd require feedback from the bot :/ - if ss.patch is not None: - source += " (plus patch)" - - t = build.getText() - if t: - t = ": " + " ".join(t) - else: - t = "" - - if results == SUCCESS: - status_text = "You are awesome! Try succeeded!" - res = "success" - elif results == WARNINGS: - status_text = "Try Had Warnings%s" % t - res = "warnings" - else: - status_text = "TRY FAILED%s" % t - res = "failure" - - text = """Slave: %s - -Run details: %s - -%sSlave history: %swaterfall?builder=%s -%s -Build Reason: %s - -Build Source Stamp: %s - ---=> %s <=-- - -Try server waterfall: %s -Buildbot waterfall: http://build.chromium.org/ -%s -Sincerely, - - - The monkey which sends all these emails manually - - -Reminders: - - Patching is done inside the update step. - - So if the update step failed, that may be that the patch step failed. - The patch can fail because of svn property change or binary file change. - - The patch will fail if the tree has conflicting changes since your last upload. - - On Windows, the execution order is compile debug, test debug, compile release. - - On Mac/linux, the execution order is compile debug, test debug. - -Automated text version 0.2""" % (name, - build_url, - patch_url_text, - urllib.quote(waterfall_url, '/:'), - urllib.quote(name), - failure_bot, - build.getReason(), - source, - status_text, - urllib.quote(waterfall_url, '/:'), - failure_tree) - - m = Message() - m.set_payload(text) - - m['Date'] = formatdate(localtime=True) - m['Subject'] = self.subject % { - 'result': res, - 'projectName': projectName, - 'builder': name, - 'reason': build.getReason(), - } - m['From'] = self.fromaddr - # now, who is this message going to? - dl = [] - recipients = self.extraRecipients[:] - if self.sendToInterestedUsers and self.lookup: - for u in build.getInterestedUsers(): - d = defer.maybeDeferred(self.lookup.getAddress, u) - d.addCallback(recipients.append) - dl.append(d) - d = defer.DeferredList(dl) - d.addCallback(self._gotRecipients, recipients, m) - return d diff --git a/tools/buildbot/config/master.tryserver/master.cfg b/tools/buildbot/config/master.tryserver/master.cfg deleted file mode 100644 index 2c56e51..0000000 --- a/tools/buildbot/config/master.tryserver/master.cfg +++ /dev/null @@ -1,369 +0,0 @@ -# -*- python -*- -# ex: set syntax=python: - -# Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# This is the buildmaster config file for the 'chromium' bot. It must -# be installed as 'master.cfg' in your buildmaster's base directory -# (although the filename can be changed with the --basedir option to -# 'mktap buildbot master'). - -# It has one job: define a dictionary named BuildmasterConfig. This -# dictionary has a variety of keys to control different aspects of the -# buildmaster. They are documented in docs/config.xhtml . - -from buildbot import locks -from buildbot.buildslave import BuildSlave -from buildbot.changes.pb import PBChangeSource -from buildbot.steps import shell -import os - -# These modules come from scripts/master, which must be in the PYTHONPATH. -import chromium_config as config -import chromium_step -import chromium_utils -import factory_commands -import master_utils -from try_job import TryJob - - - -# The default behavior of this master.cfg file is to run our production -# buildbot (of course). Setting the following variable to False will -# suppress initialization of production defaults. -PRODUCTION_BUILDBOT_MASTER = True - -if PRODUCTION_BUILDBOT_MASTER: - # Production defaults - MASTER_HOST = 'maruel-ub.i' - TRUNK_URL = config.Master.trunk_url - TRUNK_INTERNAL_URL = config.Master.trunk_internal_url - PROJECT_URL = config.Master.project_url - SVN_BINARY = config.Master.svn_binary_path - WEB_STATUS = True - MAIL_NOTIFIER = True - IRC_STATUS_BOT = False - PB_LISTENER = True -else: - MASTER_HOST = config.Master.master_host_experimental - TRUNK_URL = config.Master.trunk_url - TRUNK_INTERNAL_URL = config.Master.trunk_internal_url - SVN_BINARY = config.Master.svn_binary_path_experimental - WEB_STATUS = True - MAIL_NOTIFIER = False - IRC_STATUS_BOT = False - PB_LISTENER = False - -MASTER_PORT = config.Master.master_port - - -# This is the dictionary that the buildmaster pays attention to. We also use -# a shorter alias to save typing. -c = BuildmasterConfig = {} - -# 'slavePortnum' defines the TCP port to listen on. This must match the value -# configured into the buildslaves (with their --master option) -c['slavePortnum'] = config.Master.slave_port - - -####### BUILDSLAVES - -# the 'bots' list defines the set of allowable buildslaves. Each element is a -# tuple of bot-name and bot-password. These correspond to values given to the -# buildslave's mktap invocation. -c['slaves'] = [] -c['builders'] = [] - - -####### CHANGESOURCES - -c['change_source'] = [ PBChangeSource() ] - - -####### BUILDERS - -# FACTORIES - -m_win = master_utils.MasterFactory('src/chrome', - TRUNK_URL + '/src', - TRUNK_INTERNAL_URL + '/src-internal', - target_platform='win32') - -m_win_webkit = master_utils.MasterFactory('src/webkit', - TRUNK_URL + '/src', - TRUNK_INTERNAL_URL + '/src-internal', - target_platform='win32') - -m_linux = master_utils.MasterFactory('src/chrome', - TRUNK_URL + '/src', - TRUNK_INTERNAL_URL + '/src-internal', - target_platform='linux2') - -m_mac = master_utils.MasterFactory('src/chrome', - TRUNK_URL + '/src', - TRUNK_INTERNAL_URL + '/src-internal', - target_platform='darwin') - -def CreateBot(os, prefix='try ', postfix=None, slave_name=None, slave_dir=None, - password=config.Master.GetBotPassword(), bot_name=None, - index=None, builder_identifier=None, target=None, webkit=False, - tests=['unit', 'ui', 'net', 'base'], - options=None, mode=None, solution=None, svnurl=None, - perf_id=None, register_slave=True, timeout=1200, locks=None): - if os not in ('win32', 'win64', 'linux', 'mac'): - raise Exception(os + ' is not an known os type') - if not bot_name: - bot_name = prefix + os - if postfix: - bot_name += ' ' + postfix - if target in ('Hammer', 'Debug'): - bot_name += ' dbg' - if target == 'Release': - bot_name += ' rel' - if index: - bot_name += ' ' + str(index) - if not slave_name: - slave_name = bot_name.replace(' ', '-') - if not builder_identifier: - builder_identifier = slave_name - if not slave_dir: - slave_dir = bot_name.replace(' ', '-') - multi_config = isinstance(target, (list, tuple)) - if multi_config: - first_target = target[0] - else: - first_target = target - - run_crash_handler=False - build_dir = None - if os in ('win32', 'win64'): - if webkit: - factory = m_win_webkit - else: - factory = m_win - run_crash_handler = True - elif os == 'linux': - factory = m_linux - if not options: - options=['--build-tool=scons', '--', 'Hammer'] - elif os == 'mac': - factory = m_mac - build_dir = 'src/build' - if not options: - options=['--build-tool=xcode', '--', '-project', 'all.xcodeproj'] - builder_factory = factory.NewBuildFactory( - identifier=builder_identifier, slave_type='Trybot', target=first_target, - run_crash_handler=run_crash_handler, tests=tests, options=options, - mode=mode, solution=solution, svnurl=svnurl, perf_id=perf_id, - compile_timeout=timeout, build_dir=build_dir) - if multi_config: - # Do a release compilation to trap release-only compilation failure. - factory_cmd_obj = factory_commands.FactoryCommands( - builder_factory, builder_identifier, target[1], factory._build_dir, - factory._target_platform) - factory_cmd_obj.AddCompileStep(factory._solution, timeout=timeout) - # TODO(maruel): if mode == 'official': archive the build somewhere. Probably - # always archive the build? - # TODO(maruel): Add a revert step here to accelerate the next build? - # TODO(maruel): Preemptively recompile clean to accelerate next build? - builder = { - 'name': bot_name, - 'slavename': slave_name, - 'builddir': slave_dir, - 'factory': builder_factory, - } - if locks: - builder['locks'] = [locks] - c['builders'].append(builder) - if register_slave: - c['slaves'].append(BuildSlave(builder['slavename'], password)) - - -# Try queues. -pools = [[], [], []] -number_win32 = 13 -number_linux_dbg = 2 -number_mac_dbg = 2 -win32_locks = [None] -win_multi_locks = [None] - - -# Linux bots -for index in range(1, number_linux_dbg + 1): - CreateBot(index=index, os='linux', target='Hammer', - tests=['base', 'net', 'googleurl', 'unit']) - pools[1].append('try linux dbg %d' % index) - - -# Mac bots -for index in range(1, number_mac_dbg + 1): - CreateBot(index=index, os='mac', target='Debug', - tests=['base', 'net', 'googleurl']) - pools[2].append('try mac dbg %d' % index) - - -# Windows bots -for index in range(1, number_win32 + 1): - win32_locks.append(locks.SlaveLock('try-win32-%d' % index)) - CreateBot(index=index, target=['Debug', 'Release'], os='win32', - locks=win32_locks[index]) - pools[0].append('try win32 %d' % index) - -CreateBot(index=1, target='Release', os='win32', - tests=['page_cycler', 'startup', 'tab_switching', 'memory'], - postfix='perf', slave_name='try-win32-4', - register_slave=False, locks=win32_locks[4]) - -CreateBot(index=1, target='Release', os='win32', - tests=['page_cycler', 'startup', 'tab_switching', 'memory'], - svnurl=config.Master.merge_branch_url, - postfix='merge perf', slave_name='try-win32-5', - register_slave=False, locks=win32_locks[5]) - -CreateBot(index=1, target='Release', os='win32', tests=['unit', 'ui'], - svnurl=config.Master.merge_branch_url, - postfix='merge', slave_name='try-win32-6', - register_slave=False, locks=win32_locks[6]) - -CreateBot(index=1, target='Debug', os='win32', tests=['unit', 'ui'], - svnurl=config.Master.merge_branch_url, - postfix='merge', slave_name='try-win32-7', - register_slave=False, locks=win32_locks[7]) - -CreateBot(index=1, target='Debug', os='win32', tests=['test_shell', 'webkit'], - postfix='webkit', webkit=True, slave_name='try-win32-8', - register_slave=False, locks=win32_locks[8]) - -CreateBot(index=1, target='Release', os='win32', tests=['test_shell', 'webkit'], - postfix='webkit', webkit=True, slave_name='try-win32-9', - register_slave=False, locks=win32_locks[9]) - -# Mixed bag bots. They are all manually triggered. -c['slaves'].append(BuildSlave('try-win-multi-1', - config.Master.GetBotPassword())) -c['slaves'].append(BuildSlave('try-win-multi-2', - config.Master.GetBotPassword())) - -for index in (1,2): - win_multi_locks.append(locks.SlaveLock('try-win-multi-%d' % index)) - CreateBot(index=index, target='Hammer', os='win32', tests=['unit'], - postfix='scons', options=['--build-tool=scons'], - slave_name=('try-win-multi-%d' % index), register_slave=False, - locks=win_multi_locks[index]) - - CreateBot(index=index, target='Release', os='win32', - postfix='official', mode='official', timeout=3600, - slave_name=('try-win-multi-%d' % index), register_slave=False, - locks=win_multi_locks[index]) - - CreateBot(index=index, target='Debug', os='win32', - postfix='jsc', solution='chrome_kjs.sln', - slave_name=('try-win-multi-%d' % index), register_slave=False, - tests=['selenium', 'unit', 'ui', 'test_shell', 'page_cycler'], - locks=win_multi_locks[index]) - - CreateBot(index=index, target='Release', os='win32', - postfix='perf official', mode='official', perf_id='try-official', - slave_name=('try-win-multi-%d' % index), register_slave=False, - timeout=3600, - tests=['selenium', 'unit', 'ui', 'test_shell', - 'page_cycler', 'startup', 'tab_switching'], - locks=win_multi_locks[index]) - - -####### SCHEDULERS - -# Configure the Schedulers; -# Main Tryscheduler for the try queue. groups is defined in the loop above. -c['schedulers'] = [] - -c['schedulers'].append(TryJob(name='try_job', - jobdir='tryserver', - pools=pools)) - -# c['schedulers'].append(TryJob(name='try_job', - # jobdir='tryserver.webkit_merge', - # pools=[['try win32 webkit merge rel 1'], - # ['try win32 webkit merge dbg 1'], - # ['try mac webkit merge dbg 1'], - # ['try linux webkit merge dbg 1']])) - - -####### STATUS TARGETS - -# 'status' is a list of Status Targets. The results of each build will be -# pushed to these targets. buildbot/status/*.py has a variety to choose from, -# including web pages, email senders, and IRC bots. - -c['status'] = [] - -if WEB_STATUS: - #from buildbot.status.html import WebStatus - from chromium_status import WebStatus - c['status'].append(WebStatus(MASTER_PORT, allowForce=True)) - -# TODO(maruel): Send to the email burried in the buildsetID. -if MAIL_NOTIFIER: - from mail_notifier import MailNotifier - c['status'].append(MailNotifier( - fromaddr='try_server_noreply@%s' % MASTER_HOST, - subject="try %(result)s for %(reason)s on %(builder)s", - mode='all', - relayhost='smtp', - lookup="google.com", - extraRecipients=['maruel@google.com'])) - -# TODO(maruel): Alert the nick burried in the buildsetID. -if IRC_STATUS_BOT: - from buildbot.status import words - # Patch our topic-observing bot in on top of the IRC factory. - from chromium_status import IrcStatusChatterBot - words.IrcStatusFactory.protocol = IrcStatusChatterBot - c['status'].append(words.IRC(host=config.Master.irc_host, - nick='trybot', - channels=config.Master.irc_channels)) - -if PB_LISTENER: - from buildbot.status import client - c['status'].append(client.PBListener(9988)) - - -####### DEBUGGING OPTIONS - -# if you set 'debugPassword', then you can connect to the buildmaster with -# the diagnostic tool in contrib/debugclient.py . From this tool, you can -# manually force builds and inject changes, which may be useful for testing -# your buildmaster without actually commiting changes to your repository (or -# before you have a functioning 'sources' set up). The debug tool uses the -# same port number as the slaves do: 'slavePortnum'. - -#c['debugPassword'] = 'debugpassword' - -# if you set 'manhole', you can ssh into the buildmaster and get an -# interactive python shell, which may be useful for debugging buildbot -# internals. It is probably only useful for buildbot developers. You can also -# use an authorized_keys file, or plain telnet. -#from buildbot import manhole -#c['manhole'] = manhole.PasswordManhole('tcp:9999:interface=127.0.0.1', -# 'admin', 'password') - - -####### PROJECT IDENTITY - -# the 'projectName' string will be used to describe the project that this -# buildbot is working on. For example, it is used as the title of the -# waterfall HTML page. The 'projectURL' string will be used to provide a link -# from buildbot HTML pages to your project's home page. - -c['projectName'] = 'Chrome try server' -c['projectURL'] = 'http://go/ChromeTryServer' - -# the 'buildbotURL' string should point to the location where the buildbot's -# internal web server (usually the html.Waterfall page) is visible. This -# typically uses the port number set in the Waterfall 'status' entry, but -# with an externally-visible host name which the buildbot cannot figure out -# without some help. - -c['buildbotURL'] = 'http://%s:%s/' % (MASTER_HOST, MASTER_PORT) diff --git a/tools/buildbot/config/master.tryserver/public_html/announce.html b/tools/buildbot/config/master.tryserver/public_html/announce.html deleted file mode 100644 index 59b93fe..0000000 --- a/tools/buildbot/config/master.tryserver/public_html/announce.html +++ /dev/null @@ -1,4 +0,0 @@ -
    -
  1. Try bot result is not authorative.
  2. -
  3. If your patch contains svn cp/svn mv, svn property change or binary files, the patch will fail.
  4. -
diff --git a/tools/buildbot/config/master.tryserver/public_html/buildbot.css b/tools/buildbot/config/master.tryserver/public_html/buildbot.css deleted file mode 100644 index ad7cb26..0000000 --- a/tools/buildbot/config/master.tryserver/public_html/buildbot.css +++ /dev/null @@ -1,183 +0,0 @@ -body { - margin-bottom:50px; -} - -body, td { - font-family: Verdana, Cursor; - font-size: 10px; - font-weight: bold; -} - -a:link,a:visited,a:active { - color: #444; -} -a:hover { - color: #FFFFFF; -} - -table { - border-spacing: 1px 1px; -} - -table td { - padding: 3px 0px 3px 0px; - text-align: center; -} - -.Project { - width: 100px; -} - -.LastBuild, .Activity { - padding: 0 0 0 4px; -} - -.LastBuild, .Activity, .Builder, .BuildStep { - width: 155px; - max-width: 155px; -} - -div.BuildResultInfo { - color: #444; -} - -div.Announcement { - margin-bottom: 1em; -} - -div.Announcement > a:hover { - color: black; -} - -div.Announcement > div.Notice { - background-color: #afdaff; - padding: 0.5em; - font-size: 16px; - text-align: center; -} - -div.Announcement > div.Open { - border: 3px solid #8fdf5f; - padding: 0.5em; - font-size: 16px; - text-align: center; -} - -div.Announcement > div.Closed { - border: 5px solid #e98080; - padding: 0.5em; - font-size: 24px; - font-weight: bold; - text-align: center; -} - -td.Time { - color: #000; - border-bottom: 1px solid #aaa; - background-color: #eee; -} - -td.Activity, td.Change, td.Builder { - color: #333333; - background-color: #CCCCCC; -} - -td.Change { - border-radius: 5px; - -webkit-border-radius: 5px; -} -td.Event { - color: #777; - background-color: #ddd; - border-radius: 5px; - -webkit-border-radius: 5px; -} - -td.Activity { - border-top-left-radius: 10px; - -webkit-border-top-left-radius: 10px; - min-height: 20px; - padding: 8px 0 8px 0; -} - -td.idle, td.waiting, td.offline, td.building { - border-top-left-radius: 0px; - -webkit-border-top-left-radius: 0px; -} - -.LastBuild { - border-top-left-radius: 5px; - -webkit-border-top-left-radius: 5px; - border-top-right-radius: 5px; - -webkit-border-top-right-radius: 5px; -} - -/* LastBuild, BuildStep states */ -.success { - color: #FFFFFF; - background-color: #8fdf5f; -} - -.failure { - color: #FFFFFF; - background-color: #e98080; -} - -.warnings { - color: #FFFFFF; - background-color: #ffc343; -} - -.exception, td.offline { - color: #FFFFFF; - background-color: #e0b0ff; -} - -.start,.running, td.building { - color: #666666; - background-color: #fffc6c; -} - -.start { - border-bottom-left-radius: 10px; - -webkit-border-bottom-left-radius: 10px; - border-bottom-right-radius: 10px; - -webkit-border-bottom-right-radius: 10px; -} - -.closed { - background-color: #ff0000; -} - -.closed .large { - font-size: 1.5em; - font-weight: bolder; -} - -td.Project a:hover, td.start a:hover { - color: #000; -} - -.mini-box { - text-align:center; - height:20px; - padding:0 2px; - line-height:0; - white-space:nowrap; -} - -.mini-box a { - border-radius:0; - -webkit-border-radius:0; - display:block; - width:100%; - height:20px; - line-height:20px; - margin-top:-30px; -} - -.mini-closed { - -box-sizing:border-box; - -webkit-box-sizing:border-box; - border:4px solid red; -} \ No newline at end of file diff --git a/tools/buildbot/config/master.tryserver/public_html/chromium-32.png b/tools/buildbot/config/master.tryserver/public_html/chromium-32.png deleted file mode 100644 index e804e3f..0000000 Binary files a/tools/buildbot/config/master.tryserver/public_html/chromium-32.png and /dev/null differ diff --git a/tools/buildbot/config/master.tryserver/public_html/favicon.ico b/tools/buildbot/config/master.tryserver/public_html/favicon.ico deleted file mode 100644 index 30ad166..0000000 Binary files a/tools/buildbot/config/master.tryserver/public_html/favicon.ico and /dev/null differ diff --git a/tools/buildbot/config/master.tryserver/public_html/index.html b/tools/buildbot/config/master.tryserver/public_html/index.html deleted file mode 100644 index 4225558..0000000 --- a/tools/buildbot/config/master.tryserver/public_html/index.html +++ /dev/null @@ -1,9 +0,0 @@ - - - -TryServer Index page - - - - - diff --git a/tools/buildbot/config/master.tryserver/public_html/status-summary.html b/tools/buildbot/config/master.tryserver/public_html/status-summary.html deleted file mode 100644 index e69de29..0000000 diff --git a/tools/buildbot/config/master.tryserver/run_master.bat b/tools/buildbot/config/master.tryserver/run_master.bat deleted file mode 100644 index 1e4eb20..0000000 --- a/tools/buildbot/config/master.tryserver/run_master.bat +++ /dev/null @@ -1,6 +0,0 @@ -@echo off -setlocal -title Master -set PYTHONPATH=.;..\scripts\master;..\scripts\common;..\scripts\private;..\pylibs -set PATH=%~dp0..\depot_tools\release\python_24\;%PATH% -python ..\scripts\common\twistd --no_save -y buildbot.tac \ No newline at end of file diff --git a/tools/buildbot/config/master.tryserver/try_job.py b/tools/buildbot/config/master.tryserver/try_job.py deleted file mode 100644 index ec327db..0000000 --- a/tools/buildbot/config/master.tryserver/try_job.py +++ /dev/null @@ -1,195 +0,0 @@ -#!/usr/bin/python -# Copyright (c) 2008 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""A class overload to extract a patch file and execute it on the try servers. -""" - -import os -import random - -from buildbot import buildset -from buildbot.changes.maildir import MaildirService, NoSuchMaildir -from buildbot.scheduler import BadJobfile, TryBase, Try_Jobdir -from buildbot.sourcestamp import SourceStamp -from twisted.application import service, internet -from twisted.python import log, runtime - - -class TryJob(Try_Jobdir): - """Simple Try_Jobdir overload that executes the patch files in the pending - directory. - - groups is the groups of default builders used for round robin. The other - builders can still be used.""" - def __init__(self, name, pools, jobdir): - """Skip over Try_Jobdir.__init__ to change watcher.""" - builderNames = [] - self.pools = pools - # Flatten and remove duplicates. - for pool in pools: - for builder in pool: - if not builder in builderNames: - builderNames.append(builder) - TryBase.__init__(self, name, builderNames) - self.jobdir = jobdir - self.watcher = PoolingMaildirService() - self.watcher.setServiceParent(self) - - def parseJob(self, f): - """Remove the NetstringReceiver bits. Only read a patch file and apply it. - For now, hard code most of the variables. - Add idle builder selection in each pools.""" - - # The dev's email address must be hidden in that variable somehow. - file_name = f.name - builderNames = [] - if not file_name or len(file_name) < 2: - buildsetID = 'Unnamed patchset' - else: - # Strip the path. - file_name = os.path.basename(file_name) - buildsetID = file_name - # username.change_name.[bot1,bot2,bot3].diff - items = buildsetID.split('.') - if len(items) == 4: - builderNames = items[2].split(",") - print 'Choose %s for job %s' % (",".join(builderNames), file_name) - - # The user hasn't requested a specific bot. We'll choose one. - if not builderNames: - # First, collect the list of idle and disconnected bots. - idle_bots = [] - disconnected_bots = [] - # self.listBuilderNames() is the merged list of 'groups'. - for name in self.listBuilderNames(): - # parent is of type buildbot.master.BuildMaster. - # botmaster is of type buildbot.master.BotMaster. - # builders is a dictionary of - # string : buildbot.process.builder.Builder. - if not name in self.parent.botmaster.builders: - # The bot is non-existent. - disconnected_bots.append(name) - else: - # slave is of type buildbot.process.builder.Builder - slave = self.parent.botmaster.builders[name] - # Get the status of the builder. - # slave.slaves is a list of buildbot.process.builder.SlaveBuilder and - # not a buildbot.buildslave.BuildSlave as written in the doc(nor - # buildbot.slave.bot.BuildSlave) - # slave.slaves[0].slave is of type buildbot.buildslave.BuildSlave - # TODO(maruel): Support shared slave. - if len(slave.slaves) == 1 and slave.slaves[0].slave: - if slave.slaves[0].isAvailable(): - idle_bots.append(name) - else: - disconnected_bots.append(name) - - # Now for each pool, we select one bot that is idle. - for pool in self.pools: - prospects = [] - found_idler = False - for builder in pool: - if builder in idle_bots: - # Found one bot, go for next pool. - builderNames.append(builder) - found_idler = True - break - if not builder in disconnected_bots: - prospects.append(builder) - if found_idler: - continue - # All bots are either busy or disconnected.. - if prospects: - builderNames.append(random.choice(prospects)) - - if not builderNames: - # If no builder are available, throw a BadJobfile exception since we - # can't select a group. - raise BadJobfile - - print 'Choose %s for job %s' % (",".join(builderNames), file_name) - - # Always use the trunk. - branch = None - # Always use the latest revision, HEAD. - baserev = None - # The diff is the file's content. - diff = f.read() - # -pN argument to patch. - patchlevel = 0 - - patch = (patchlevel, diff) - ss = SourceStamp(branch, baserev, patch) - return builderNames, ss, buildsetID - - def messageReceived(self, filename): - """Same as Try_Jobdir.messageReceived except 'reason' which is modified and - the builderNames restriction lifted.""" - md = os.path.join(self.parent.basedir, self.jobdir) - if runtime.platformType == "posix": - # open the file before moving it, because I'm afraid that once - # it's in cur/, someone might delete it at any moment - path = os.path.join(md, "new", filename) - f = open(path, "r") - os.rename(os.path.join(md, "new", filename), - os.path.join(md, "cur", filename)) - else: - # do this backwards under windows, because you can't move a file - # that somebody is holding open. This was causing a Permission - # Denied error on bear's win32-twisted1.3 buildslave. - os.rename(os.path.join(md, "new", filename), - os.path.join(md, "cur", filename)) - path = os.path.join(md, "cur", filename) - f = open(path, "r") - - try: - builderNames, ss, bsid = self.parseJob(f) - except BadJobfile: - log.msg("%s reports a bad jobfile in %s" % (self, filename)) - log.err() - return - reason = "'%s' try job" % bsid - bs = buildset.BuildSet(builderNames, ss, reason=reason, bsid=bsid) - self.parent.submitBuildSet(bs) - - -class PoolingMaildirService(MaildirService): - def startService(self): - """Remove the dnotify support since it doesn't work for nfs directories.""" - self.files = {} - service.MultiService.startService(self) - self.newdir = os.path.join(self.basedir, "new") - if not os.path.isdir(self.basedir) or not os.path.isdir(self.newdir): - raise NoSuchMaildir("invalid maildir '%s'" % self.basedir) - # Make it poll faster. - self.pollinterval = 5 - t = internet.TimerService(self.pollinterval, self.poll) - t.setServiceParent(self) - self.poll() - - def poll(self): - """Make the polling a bit more resistent by waiting two cycles before - grabbing the file.""" - assert self.basedir - newfiles = [] - for f in os.listdir(self.newdir): - newfiles.append(f) - # fine-grained timestamp in the filename - for n in newfiles: - try: - stats = os.stat(os.path.join(self.newdir, f)) - except OSError: - print 'Failed to grab stats for %s' % os.path.join(self.newdir, f) - continue - props = (stats.st_size, stats.st_mtime) - if n in self.files and self.files[n] == props: - self.messageReceived(n) - del self.files[n] - else: - # Update de properties - if n in self.files: - print 'Last seen ' + n + ' as ' + str(props) - print n + ' is now ' + str(props) - self.files[n] = props diff --git a/tools/buildbot/config/master.tryserver/unittests/master_test.py b/tools/buildbot/config/master.tryserver/unittests/master_test.py deleted file mode 100644 index 68b0a4d..0000000 --- a/tools/buildbot/config/master.tryserver/unittests/master_test.py +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/python -# Copyright (c) 2008 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import os -import sys -import unittest - -MASTER_SCRIPT = os.path.abspath('../master.cfg') -directory = os.path.dirname(__file__) -while not os.path.exists(os.path.join(directory, 'scripts')): - directory = os.path.join(directory, '..') - -sys.path.append(os.path.join(os.path.dirname(__file__), '..')) -sys.path.append(os.path.join(directory, 'scripts', 'common')) -sys.path.append(os.path.join(directory, 'scripts', 'master')) -sys.path.append(os.path.join(directory, 'pylibs')) - - -def ReadFile(filename): - """Returns the contents of a file.""" - file = open(filename, 'r') - result = file.read() - file.close() - return result - - -def WriteFile(filename, contents): - """Overwrites the file with the given contents.""" - file = open(filename, 'w') - file.write(contents) - file.close() - - -def ExecuteMasterScript(): - """Execute the master script and returns its dictionary.""" - script_locals = {} - exec(ReadFile(MASTER_SCRIPT), script_locals) - return script_locals - - -class MasterScriptTest(unittest.TestCase): - def setUp(self): - self.bot_password = os.path.join(directory, 'scripts', 'common', - '.bot_password') - self.existed = os.path.exists(self.bot_password) - if not self.existed: - WriteFile(self.bot_password, 'bleh') - - def tearDown(self): - if not self.existed: - os.remove(self.bot_password) - - def testParse(self): - script_locals = ExecuteMasterScript() - self.assertNotEqual(script_locals['BuildmasterConfig']['slavePortnum'], 0) - self.assertTrue(len(script_locals['BuildmasterConfig']['slaves']) > 0) - self.assertTrue(len(script_locals['BuildmasterConfig']['builders']) > 0) - self.assertTrue(len(script_locals['BuildmasterConfig']['change_source']) - > 0) - self.assertTrue(len(script_locals['BuildmasterConfig']['schedulers']) > 0) - self.assertTrue(len(script_locals['BuildmasterConfig']['status']) > 0) - self.assertTrue(len(script_locals['BuildmasterConfig']['buildbotURL']) > 0) - - -if __name__ == '__main__': - unittest.main() - \ No newline at end of file diff --git a/tools/buildbot/config/master.tryserver/unittests/try_job_test.py b/tools/buildbot/config/master.tryserver/unittests/try_job_test.py deleted file mode 100644 index 00cf56e..0000000 --- a/tools/buildbot/config/master.tryserver/unittests/try_job_test.py +++ /dev/null @@ -1,123 +0,0 @@ -#!/usr/bin/python -# Copyright (c) 2008 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import os -import sys -import unittest - -directory = os.path.dirname(__file__) -while not os.path.exists(os.path.join(directory, 'scripts')): - directory = os.path.join(directory, '..') -sys.path.append(os.path.join(os.path.dirname(__file__), '..')) -sys.path.append(os.path.join(directory, 'scripts', 'common')) -sys.path.append(os.path.join(directory, 'pylibs')) - -import try_job -from buildbot.scheduler import BadJobfile - -class FileMock: - name = 'user-test.diff' - def read(self): - return 'Dummy file content' - - -class SlaveMock: - def __init__(self, is_available=True, empty=False): - self.is_available = is_available - if not empty: - self.slave = True - else: - self.slave = None - - def isAvailable(self): - return self.is_available - -class SlavesMock: - def __init__(self, empty=False, avail=True): - if not empty: - self.slaves = [SlaveMock(avail)] - else: - self.slaves = [] - - -class BotMasterMock: - def __init__(self, avail, busy, dead): - if dead: - self.builders = { - 'a' : SlavesMock(empty=True), - 'd' : SlavesMock(empty=True), - 'f' : SlavesMock(empty=True), - } - else: - self.builders = { - 'a' : SlavesMock(avail=True), - 'b' : SlavesMock(avail=avail and not busy), - 'c' : SlavesMock(avail=avail and not busy), - 'd' : SlavesMock(avail=False), - 'e' : SlavesMock(avail=True and not busy), - 'f' : SlavesMock(empty=True), - 'g' : SlavesMock(avail=False), - } - - -class ParentMock: - def __init__(self, avail, busy, dead): - self.botmaster = BotMasterMock(avail, busy, dead) - - -class TryJobTest(unittest.TestCase): - def setUp(self): - """Setup the pools. - 'f' should never be selected since it's empty.""" - self.pools = [['a', 'b', 'c'], ['d', 'e'], ['f']] - - def testParseJobGroup1(self): - tryjob = try_job.TryJob(name='test1', - jobdir='test2', - pools=self.pools) - tryjob.parent = ParentMock(False, False, False) - (builderNames, ss, buildsetID) = tryjob.parseJob(FileMock()) - # avail: a, e. - # not avail: b, c, d, g. - # empty = f. - self.assertEquals(builderNames, ['a', 'e']) - self.assertEquals(buildsetID, 'user-test.diff') - - def testParseJobGroup2(self): - tryjob = try_job.TryJob(name='test1', - jobdir='test2', - pools=self.pools) - tryjob.parent = ParentMock(True, False, False) - (builderNames, ss, buildsetID) = tryjob.parseJob(FileMock()) - # avail: a, b, c, e. - # not avail: d, g. - # empty = f. - self.assertEquals(builderNames, ['a', 'e']) - self.assertEquals(buildsetID, 'user-test.diff') - - def testParseJobGroupBusy(self): - tryjob = try_job.TryJob(name='test1', - jobdir='test2', - pools=self.pools) - tryjob.parent = ParentMock(False, True, False) - (builderNames, ss, buildsetID) = tryjob.parseJob(FileMock()) - # avail: a. - # not avail: b, c, d, e, g. - # empty = f. - self.assertEquals(builderNames[0], 'a') - self.assertTrue(builderNames[1] in ('d', 'e')) - - def testParseJobGroupDead(self): - tryjob = try_job.TryJob(name='test1', - jobdir='test2', - pools=self.pools) - tryjob.parent = ParentMock(False, False, True) - # no bots are available. None can be selected. - self.assertRaises(BadJobfile, tryjob.parseJob, FileMock()) - - -if __name__ == '__main__': - unittest.main() - \ No newline at end of file diff --git a/tools/buildbot/config/slave/DEPS b/tools/buildbot/config/slave/DEPS deleted file mode 100644 index 5948d5e..0000000 --- a/tools/buildbot/config/slave/DEPS +++ /dev/null @@ -1,7 +0,0 @@ -deps = { - "scripts": - "/trunk/tools/buildbot/scripts", - - "pylibs": - "/trunk/tools/buildbot/pylibs", -} diff --git a/tools/buildbot/config/slave/Makefile b/tools/buildbot/config/slave/Makefile deleted file mode 100644 index bae3091..0000000 --- a/tools/buildbot/config/slave/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# -*- makefile -*- - -# This is a simple makefile which lives in a buildmaster/buildslave -# directory (next to the buildbot.tac file). It allows you to start/stop the -# master or slave by doing 'make start' or 'make stop'. - -# The 'reconfig' target will tell a buildmaster to reload its config file. - -# On the Mac, the buildbot is started via the launchd mechanism as a -# LaunchAgent to give the slave a proper Mac UI environment for tests. In -# order for this to work, the plist must be present and loaded by launchd, and -# the user must be logged in to the UI. The plist is loaded by launchd at user -# login (and the job may have been initially started at that time too). Our -# Mac build slaves are all set up this way, and have auto-login enabled, so -# "make start" should just work and do the right thing. -# -# When using launchd to start the job, it also needs to be used to stop the -# job. Otherwise, launchd might try to restart the job when stopped manually -# by SIGTERM. Using SIGHUP for reconfig is safe with launchd. -# -# Because it's possible to have more than one slave on a machine (for testing), -# this tests to make sure that the slave is in the known slave location, -# /b/slave, which is what the LaunchAgent operates on. -USE_LAUNCHD := \ - $(shell [ -f ~/Library/LaunchAgents/org.chromium.buildbot.slave.plist ] && \ - [ "$$(pwd -P)" = "/b/slave" ] && \ - echo 1) - -start: -ifneq ($(USE_LAUNCHD),1) - python2.4 run_slave.py --no_save -y buildbot.tac -else - launchctl start org.chromium.buildbot.slave -endif - -stop: -ifneq ($(USE_LAUNCHD),1) - kill `cat twistd.pid` -else - launchctl stop org.chromium.buildbot.slave -endif - -reconfig: - kill -HUP `cat twistd.pid` - -log: - tail -f twistd.log diff --git a/tools/buildbot/config/slave/buildbot.tac b/tools/buildbot/config/slave/buildbot.tac deleted file mode 100644 index 1b4d62e..0000000 --- a/tools/buildbot/config/slave/buildbot.tac +++ /dev/null @@ -1,45 +0,0 @@ -# Chrome Buildbot slave configuration - -import os -import sys - -from twisted.application import service -from buildbot.slave.bot import BuildSlave - -import chromium_config as config - -slavename = None -password = config.Master.GetBotPassword() -host = None -port = None -basedir = None -keepalive = 600 -usepty = 1 -umask = None - - -if slavename is None: - msg = '*** No slavename configured in %s.\n' % repr(__file__) - sys.stderr.write(msg) - sys.exit(1) - -if password is None: - msg = '*** No password configured in %s.\n' % repr(__file__) - sys.stderr.write(msg) - sys.exit(1) - -if host is None: - host = "%s.%s" % (config.Master.master_host, config.Master.master_domain) - -if port is None: - port = config.Master.slave_port - -if basedir is None: - dir, _file = os.path.split(__file__) - basedir = os.path.abspath(dir) - - -application = service.Application('buildslave') -s = BuildSlave(host, port, slavename, password, basedir, keepalive, usepty, - umask=umask) -s.setServiceParent(application) diff --git a/tools/buildbot/config/slave/cert/ssl_ui_test_root_ca.crt b/tools/buildbot/config/slave/cert/ssl_ui_test_root_ca.crt deleted file mode 100644 index 873b4f7..0000000 --- a/tools/buildbot/config/slave/cert/ssl_ui_test_root_ca.crt +++ /dev/null @@ -1,35 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIGCTCCA/GgAwIBAgIJANRRk9Q/3tlOMA0GCSqGSIb3DQEBBQUAMGAxEDAOBgNV -BAMTB1Rlc3QgQ0ExCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYw -FAYDVQQHEw1Nb3VudGFpbiBWaWV3MRIwEAYDVQQKEwlDZXJ0IFRlc3QwHhcNMDgw -NzI4MjIzMjAxWhcNMTMwNzI3MjIzMjAxWjBgMRAwDgYDVQQDEwdUZXN0IENBMQsw -CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRh -aW4gVmlldzESMBAGA1UEChMJQ2VydCBUZXN0MIICIjANBgkqhkiG9w0BAQEFAAOC -Ag8AMIICCgKCAgEAuyR/rlxmPi+L48rXdlACgz+Cq06jf8Ns0H/eaofQCB7odsKu -CXzyngqGetohqAmW8XNzGKAlHzjJcnySzhxG8V3V22aILTI7lfSxrNpLKGaJ69MO -lg6zFty/zkZ94oRX6Q1t2yRrWBN4isXMOxwRg7cGzuN8ejG0/vbgIVQulF6cqDge -5BXtXhD4GnKEbvLh5TRxK8x3VBNlVIlRx1gKVz0q8MFgyFRcMS3PEiaFarSWwq8M -I7QaeifUnXwA5BquXdwf6+8CWdanPv2wG9LylWHK/YbnBz4g/9ppYCAz2V++em+K -/CADHRNIyuEXw6LWmwmYzMd05J+46dbEEua0tRiK3yVl5Q60Bo4NZcUZA3KZ7A9l -JS13/tzFKLqCn+SLzQnZfDAp8ys/Eu9arxYq70dAPUv0eJDSuXNQx2HQBxF3phQ+ -9AvKH5Vu4UgD3lSCqXiLwtOjeCxXZJ3830jIkFOupSZI7H3f3NmMxDba5OzLXXb+ -GfLgR9ulI1Qk+UmISL6/Tsu5453jn6opv/kapD9g7Jc6AFTak1SlHWZU4JH7c1x6 -THSB9FLcjbHt5heK8qcFMU5U6OiJmKW2WKn5k2Rwv0hteLhfN1lchqZkwobzu74z -QG/Z2Q/ClU89X95U5qF1ZxuriP668SxETzPR8D9uBU/5VzkrC3c8SbcTFUECAwEA -AaOBxTCBwjAdBgNVHQ4EFgQUXc5/mePUGUExT8bPsSX1Wq/jlzEwgZIGA1UdIwSB -ijCBh4AUXc5/mePUGUExT8bPsSX1Wq/jlzGhZKRiMGAxEDAOBgNVBAMTB1Rlc3Qg -Q0ExCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1N -b3VudGFpbiBWaWV3MRIwEAYDVQQKEwlDZXJ0IFRlc3SCCQDUUZPUP97ZTjAMBgNV -HRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4ICAQA2FoW/5tyDSkEfEQFVfLcfNvmt -s2XK7SbPZtoIYx0lnqXZ8fUxCg0chmkiCypng6msvhEwGs3z7qZWd04bY8RAZYbQ -9bhjvB0LH4lVfsK4pCAKYQDAHC271XZPd3RmdHaekH70T0w2avFxG9M91CaVRaLh -SheeCVm6aJcFnaBfSd78vDz8Ly+Jtod737JZrkmP7Oko78SrB/CfiMcf6jIdekxP -9bwi75Y0+rfaK9x/Pyjz4U23ooZLX2f/21c3JSTwR19qGZOHvQircP7scQzgtlJl -zGxQKEZwYHAPxNHbPoScLOP2LXqWUnheC5LQcsm3BtRKM5AniEqW8HqKAxrGOPNO -cj8E3hVf6lZaAeFH5CTN/rudb869k/ibJkaeo6pjeytssMr+PvpstWmWqhfEJTZn -om7w+xMsYKe1cZv6c2WIVFuvl/g8CLYuu6SXjtDqj7HVbhC1+IupXl5N4pBXIXCf -Q33D4JsmM51ySMk5SxAl6HaxiB9hU3dqJqWjiKBJztLnZUDWUpCb3g09yygXeTmY -fNGaY+mZX3HBohrAy0kj06OgT12ovmWsmQRIvpTBybTbX37vt11xOLN/WNnifkH9 -HcEOc/WW68x2dJbnF4sBfV/0edA8ectGdyqzn1gvYjdMDPSSbAZ4B/EIijfHqILb -R3901wi9fJwhBxFIuQ== ------END CERTIFICATE----- diff --git a/tools/buildbot/config/slave/crontab.in b/tools/buildbot/config/slave/crontab.in deleted file mode 100644 index 4c8d16e..0000000 --- a/tools/buildbot/config/slave/crontab.in +++ /dev/null @@ -1,18 +0,0 @@ -# Chromium crontab input file for restarting build slaves on reboot. -# Feed this to crontab as follows: -# -# $ crontab -u $USER crontab.in -# -# Note that it's a good idea to specify the -u option when using -# a role account, because crontab can get confused by su. -# -# Crontab will run the command with a hermetic environment with -# $SHELL, $LOGNAME (also $USER if necessary) and $HOME set from -# /etc/passwd, and $PATH set to "/usr/bin:/bin", so there's no -# need to set environment variables. -# -# $MAILTO is used explicitly by cron for failure notification. - -MAILTO=chrome-build-alerts@google.com - -@reboot cd $HOME/b/slave && make start diff --git a/tools/buildbot/config/slave/info/admin b/tools/buildbot/config/slave/info/admin deleted file mode 100644 index b68aa03..0000000 --- a/tools/buildbot/config/slave/info/admin +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tools/buildbot/config/slave/info/host b/tools/buildbot/config/slave/info/host deleted file mode 100644 index bae3333..0000000 --- a/tools/buildbot/config/slave/info/host +++ /dev/null @@ -1 +0,0 @@ -.. diff --git a/tools/buildbot/config/slave/run_slave.bat b/tools/buildbot/config/slave/run_slave.bat deleted file mode 100644 index 5408e79..0000000 --- a/tools/buildbot/config/slave/run_slave.bat +++ /dev/null @@ -1,5 +0,0 @@ -@echo off -setlocal -title Build slave -set PATH=%~dp0..\depot_tools\release\python_24\;%PATH% -python.exe %~dp0\run_slave.py --no_save -y buildbot.tac diff --git a/tools/buildbot/config/slave/run_slave.py b/tools/buildbot/config/slave/run_slave.py deleted file mode 100644 index fbd2d57..0000000 --- a/tools/buildbot/config/slave/run_slave.py +++ /dev/null @@ -1,98 +0,0 @@ -#!/usr/bin/python -# Copyright (c) 2008 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -""" Initialize the environment variables and start the buildbot slave. -""" - -import os -import shutil -import sys - -def remove_all_vars_except(dict, vars): - """Remove all variable keys from the specified dict except those in vars""" - for key in set(dict.keys()) - set(vars): - dict.pop(key) - -if '__main__' == __name__: - # change the current directory to the directory of the script. - os.chdir(sys.path[0]) - - # Set the python path. - parent_dir = os.path.abspath(os.path.pardir) - - sys.path.insert(0, os.path.join(parent_dir, 'scripts', 'common')) - sys.path.insert(0, os.path.join(parent_dir, 'scripts', 'private')) - sys.path.insert(0, os.path.join(parent_dir, 'scripts', 'slave')) - sys.path.insert(0, os.path.join(parent_dir, 'pylibs')) - sys.path.insert(0, os.path.join(parent_dir, 'symsrc')) - - # Copy these paths into the PYTHONPATH env variable. If you add - # more path to sys.path, you need to change this line to reflect the - # change. - os.environ['PYTHONPATH'] = os.pathsep.join(sys.path[:4]) - os.environ['CHROME_HEADLESS'] = '1' - - # Platform-specific initialization. - - if sys.platform == 'win32': - # list of all variables that we want to keep - env_var = [ - 'APPDATA', - 'CHROME_HEADLESS', - 'CHROMIUM_BUILD', - 'COMSPEC', - 'OS', - 'PATH', - 'PATHEXT', - 'PROGRAMFILES', - 'PYTHONPATH', - 'SYSTEMDRIVE', - 'SYSTEMROOT', - 'TEMP', - 'TMP', - 'USERNAME', - 'USERPROFILE', - 'WINDIR', - ] - - remove_all_vars_except(os.environ, env_var) - - # extend the env variables with the chrome-specific settings. - depot_tools = os.path.join(parent_dir, 'depot_tools') - python_24 = os.path.join(depot_tools, 'release', 'python_24') - system32 = os.path.join(os.environ['SYSTEMROOT'], 'system32') - wbem = os.path.join(system32, 'WBEM') - - slave_path = [depot_tools, python_24, system32, wbem] - os.environ['PATH'] = os.pathsep.join(slave_path) - os.environ['LOGNAME'] = os.environ['USERNAME'] - - elif sys.platform in ('darwin', 'posix', 'linux2'): - # list of all variables that we want to keep - env_var = [ - 'CHROME_HEADLESS', - 'DISPLAY', - 'HOME', - 'HOSTNAME', - 'LOGNAME', - 'PATH', - 'PWD', - 'PYTHONPATH', - 'SHELL', - 'USER', - 'USERNAME' - ] - - remove_all_vars_except(os.environ, env_var) - - depot_tools = os.path.join(parent_dir, 'depot_tools') - - slave_path = [depot_tools, '/usr/bin', '/bin', - '/usr/sbin', '/sbin', '/usr/local/bin'] - os.environ['PATH'] = os.pathsep.join(slave_path) - - # Run the slave. - import twisted.scripts.twistd as twistd - twistd.run() diff --git a/tools/buildbot/perf/dashboard/README.txt b/tools/buildbot/perf/dashboard/README.txt deleted file mode 100644 index 36c8ede..0000000 --- a/tools/buildbot/perf/dashboard/README.txt +++ /dev/null @@ -1,14 +0,0 @@ -OVERVIEW - - This directory contains code for building a dashboard for tracking perf test - results over a sequence of chrome builds. - - -CONTENTS - - ui/ - - contains the HTML and JS used to construct the UI of the performance - dashboard. - - log_scraper has been deprecated over log parsers running on buildbot. - diff --git a/tools/buildbot/perf/dashboard/changelog.html b/tools/buildbot/perf/dashboard/changelog.html deleted file mode 100644 index 0288f50..0000000 --- a/tools/buildbot/perf/dashboard/changelog.html +++ /dev/null @@ -1,204 +0,0 @@ - - - - - - -
- SVN path: - SVN revision range: - text - html - -
- - - - - diff --git a/tools/buildbot/perf/dashboard/details.html b/tools/buildbot/perf/dashboard/details.html deleted file mode 100644 index d991d22..0000000 --- a/tools/buildbot/perf/dashboard/details.html +++ /dev/null @@ -1,125 +0,0 @@ - - - - - - - - - - - - - -
PageMeanStdDevRuns...
- - diff --git a/tools/buildbot/perf/dashboard/js/common.js b/tools/buildbot/perf/dashboard/js/common.js deleted file mode 100644 index 8a02a50..0000000 --- a/tools/buildbot/perf/dashboard/js/common.js +++ /dev/null @@ -1,36 +0,0 @@ -function Fetch(url, callback) { - var r = new XMLHttpRequest(); - r.open("GET", url); - r.setRequestHeader("pragma", "no-cache"); - r.setRequestHeader("cache-control", "no-cache"); - r.send(null); - - r.onload = function() { - callback(r.responseText); - } -} - -// returns an Object with properties given by the parameters specified in the -// URL's query string. -function ParseParams() { - var result = new Object(); - var s = window.location.search.substring(1).split('&'); - for (i = 0; i < s.length; ++i) { - var v = s[i].split('='); - result[v[0]] = v[1]; - } - return result; -} - -// create the URL constructed from the current pathname and the given params. -function MakeURL(params) { - var url = window.location.pathname; - var sep = '?'; - for (p in params) { - if (!p) - continue; - url = url + sep + p + '=' + params[p]; - sep = '&'; - } - return url; -} diff --git a/tools/buildbot/perf/dashboard/js/plotter.js b/tools/buildbot/perf/dashboard/js/plotter.js deleted file mode 100644 index 57a333f..0000000 --- a/tools/buildbot/perf/dashboard/js/plotter.js +++ /dev/null @@ -1,425 +0,0 @@ -// plotting select reports against time - -// vertical marker for columns -function Marker(color) { - var m = document.createElement("DIV"); - m.setAttribute("class", "plot-cursor"); - m.style.backgroundColor = color; - m.style.opacity = "0.3"; - m.style.position = "absolute"; - m.style.left = "-2px"; - m.style.top = "-2px"; - m.style.width = "0px"; - m.style.height = "0px"; - return m; -} - -/** - * Create a horizontal marker at the indicated mouse location. - * @constructor - * - * @param canvasRect {Object} The canvas bounds (in client coords). - * @param mousePoint {MousePoint} The mouse click location that spawned the - * marker. - */ -function HorizontalMarker(canvasRect, mousePoint) { - // Add a horizontal line to the graph. - var m = document.createElement("DIV"); - m.setAttribute("class", "plot-baseline"); - m.style.backgroundColor = HorizontalMarker.COLOR; - m.style.opacity = "0.3"; - m.style.position = "absolute"; - m.style.left = canvasRect.x; - var h = HorizontalMarker.HEIGHT; - m.style.top = (mousePoint.clientPoint.y - h/2).toFixed(0) + "px"; - m.style.width = canvasRect.width + "px"; - m.style.height = h + "px"; - this.markerDiv_ = m; - - this.value = mousePoint.plotterPoint.y; -} - -HorizontalMarker.HEIGHT = 5; -HorizontalMarker.COLOR = "rgb(0,100,100)"; - -// Remove the horizontal line from the graph. -HorizontalMarker.prototype.remove_ = function() { - this.markerDiv_.parentNode.removeChild(this.markerDiv_); -} - -function Plotter(xVals, yVals, yDevs, resultNode, zoomed) { - this.xVals_ = xVals; - this.yVals_ = yVals; - this.yDevs_ = yDevs; - this.resultNode_ = resultNode; - this.zoomed_ = zoomed; - this.extraData_ = []; - this.units = "msec"; -} - -Plotter.prototype.getArrayMinMax_ = function(ary) { - var aryMin = ary[0]; - var aryMax = ary[0]; - for (i = 1; i < ary.length; ++i) { - if (ary[i] < aryMin) { - aryMin = ary[i]; - } else if (ary[i] > aryMax) { - aryMax = ary[i]; - } - } - return [aryMin, aryMax]; -} - -Plotter.prototype.calcGlobalExtents_ = function() { - var e = {}; - - var i; - - // yVals[i] + yDevs[i] - var ymax = []; - for (i = 0; i < this.yVals_.length; ++i) { - ymax.push(this.yVals_[i] + this.yDevs_[i]); - } - var rmax = this.getArrayMinMax_(ymax); - e.max = rmax[1]; - - // yVals[i] - yDevs[i] - var ymin = []; - for (i = 0; i < this.yVals_.length; ++i) { - ymin.push(this.yVals_[i] - this.yDevs_[i]); - } - var rmin = this.getArrayMinMax_(ymin); - e.min = rmin[0]; - - // check extra data for extents that exceed - for (i in this.extraData_) { - var r = this.getArrayMinMax_(this.extraData_[i].yvals); - if (r[0] < e.min) - e.min = r[0]; - if (r[1] > e.max) - e.max = r[1]; - } - - return e; -} - -Plotter.prototype.addAlternateData = function(yvals, color) { - // add an extra trace to the plot; does not affect graph extents - this.extraData_.push({"yvals": yvals, "color": color}); -} - -Plotter.prototype.plot = function() { - var e = {}; - - height = window.innerHeight - 16; - width = window.innerWidth - 16; - - e.heightMax = Math.min(400, height - 80); - e.widthMax = width; - - var canvas = document.createElement("CANVAS"); - canvas.setAttribute("class", "plot"); - canvas.setAttribute("width", e.widthMax); - canvas.setAttribute("height", e.heightMax); - - // Display coordinates on the left, deltas from baseline on the right. - var hoverStatsDiv = document.createElement("DIV"); - hoverStatsDiv.innerHTML = - "" + - "" + - "" + - "
move mouse over graphShift-click to place baseline
"; - - var tr = hoverStatsDiv.firstChild.firstChild.firstChild; - this.coordinates_td_ = tr.childNodes[0]; - this.baseline_deltas_td_ = tr.childNodes[1]; - - // horizontal ruler - var ruler = document.createElement("DIV"); - ruler.setAttribute("class", "plot-ruler"); - ruler.style.borderBottom = "1px dotted black"; - ruler.style.position = "absolute"; - ruler.style.left = "-2px"; - ruler.style.top = "-2px"; - ruler.style.width = "0px"; - ruler.style.height = "0px"; - this.ruler_div_ = ruler; - - // marker for the result-point that the mouse is currently over - this.cursor_div_ = new Marker("rgb(100,80,240)"); - - // marker for the result-point for which details are shown - this.marker_div_ = new Marker("rgb(100,100,100)"); - - // find global extents - - e.xMin = -0.5; - e.xMax = this.xVals_.length - 0.5; - - var yExt = this.calcGlobalExtents_(); - var yd = (yExt.max - yExt.min) / 10.0; - //e.yMin = this.zoomed_ ? (yExt.min - yd) : 0; - //e.yMax = yExt.max + yd; - e.yMin = yExt.min - yd; - e.yMax = yExt.max + yd; - this.extents_ = e; - - var ctx = canvas.getContext("2d"); - - var ss = { - "yvals": "rgb(60,0,240)", - "ydevs": "rgba(100,100,100,0.6)" - }; - this.plot1_(ctx, this.yVals_, this.yDevs_, e, ss); - - for (var i = 0; i < this.extraData_.length; ++i) { - ss = { - "yvals": this.extraData_[i].color - }; - this.plot1_(ctx, this.extraData_[i].yvals, null, e, ss); - } - - //this.resultNode_.appendChild(legend); - this.resultNode_.appendChild(canvas); - this.resultNode_.appendChild(hoverStatsDiv); - this.resultNode_.appendChild(ruler); - this.resultNode_.appendChild(this.cursor_div_); - this.resultNode_.appendChild(this.marker_div_); - - // hook up event listener - var self = this; - canvas.parentNode.addEventListener( - "mousemove", function(evt) { self.onMouseMove_(evt); }, false); - this.cursor_div_.addEventListener( - "click", function(evt) { self.onMouseClick_(evt); }, false); - - this.canvas_ = canvas; -} - -Plotter.prototype.getIndex_ = function(x, e) { - // map x coord to xVals_ element - - var index; - if (x < 0) { - index = 0; - } else if (x > this.xVals_.length - 1) { - index = this.xVals_.length - 1; - } else { - index = x.toFixed(0); - } - return index; -} - -function MousePoint(clientPoint, canvasPoint, plotterPoint) { - this.clientPoint = clientPoint; - this.canvasPoint = canvasPoint; - this.plotterPoint = plotterPoint; -} - -Plotter.prototype.getCanvasRect_ = function() { - return { - "x": this.canvas_.offsetLeft, - "y": this.canvas_.offsetTop, - "width": this.canvas_.offsetWidth, - "height": this.canvas_.offsetHeight - }; -} - -/** - * Map the mouse position into various coordinate spaces. - * - * @param evt {MouseEvent} Either a mouse click or mouse move event. - * - * @return {MousePoint} |x| such that: - * |x.clientPoint| is the mouse point in the client window coordinate space. - * |x.canvasPoint| is the mouse point in the canvas's coordinate space. - * |x.plotterPoint| is the mouse point in the plotter's coordinate space. - */ -Plotter.prototype.translateMouseEvent_ = function(evt) { - var canvasRect = this.getCanvasRect_(); - - var cx = evt.clientX - canvasRect.x; - var cy = evt.clientY - canvasRect.y; - - var e = this.extents_; - - var x = cx / e.widthMax * (e.xMax - e.xMin) + e.xMin; - var y = (e.heightMax - cy) / e.heightMax * (e.yMax - e.yMin + 1) + e.yMin; - - return new MousePoint( - {x: evt.clientX, y: evt.clientY}, // clientPoint - {x: cx, y:cy}, // canvasPoint - {x: x, y: y}); // plotterPoint -} - -Plotter.prototype.onMouseMove_ = function(evt) { - var canvasRect = this.getCanvasRect_(); - - var mousePoint = this.translateMouseEvent_(evt); - var x = mousePoint.plotterPoint.x; - var y = mousePoint.plotterPoint.y; - - var index = this.getIndex_(x); - this.current_index_ = index; - - this.coordinates_td_.innerHTML = - "CL #" + this.xVals_[index] + ": " + - this.yVals_[index].toFixed(2) + " \u00B1 " + - this.yDevs_[index].toFixed(2) + " " + this.units + ": " + - y.toFixed(2) + " " + this.units; - - // If there is a horizontal marker, display deltas relative to it. - if (this.horizontalMarker_) { - var baseline = this.horizontalMarker_.value; - var delta = y - baseline - var fraction = delta / baseline; // allow division by 0 - - var deltaStr = (delta >= 0 ? "+" : "") + delta.toFixed(0) + " " + this.units; - var percentStr = (fraction >= 0 ? "+" : "") + - (fraction * 100).toFixed(3) + "%"; - - this.baseline_deltas_td_.innerHTML = deltaStr + ": " + percentStr; - } - - // update ruler - var r = this.ruler_div_; - r.style.left = canvasRect.x + "px"; - r.style.top = canvasRect.y + "px"; - r.style.width = canvasRect.width + "px"; - var h = evt.clientY - canvasRect.y; - if (h > canvasRect.height) - h = canvasRect.height; - r.style.height = h + "px"; - - // update cursor - var c = this.cursor_div_; - c.style.top = canvasRect.y + "px"; - c.style.height = canvasRect.height + "px"; - var w = canvasRect.width / this.xVals_.length; - var x = (canvasRect.x + w * index).toFixed(0); - c.style.left = x + "px"; - c.style.width = w + "px"; - - if ("onmouseover" in this) - this.onmouseover(this.xVals_[index], this.yVals_[index], this.yDevs_[index], e); -} - -/** - * Left-click in the plotter selects the column (changelist). - * Shift-left-click in the plotter lays down a horizontal marker. - * This horizontal marker is used as the baseline for ruler metrics. - * - * @param evt {DOMEvent} The click event in the plotter. - */ -Plotter.prototype.onMouseClick_ = function(evt) { - - if (evt.shiftKey) { - if (this.horizontalMarker_) { - this.horizontalMarker_.remove_(); - } - - this.horizontalMarker_ = new HorizontalMarker( - this.getCanvasRect_(), this.translateMouseEvent_(evt)); - - // Insert before cursor node, otherwise it catches clicks. - this.cursor_div_.parentNode.insertBefore( - this.horizontalMarker_.markerDiv_, this.cursor_div_); - } else { - var index = this.current_index_; - - var m = this.marker_div_; - var c = this.cursor_div_; - m.style.top = c.style.top; - m.style.left = c.style.left; - m.style.width = c.style.width; - m.style.height = c.style.height; - - if ("onclick" in this) { - var this_x = this.xVals_[index]; - var prev_x = index > 0 ? (this.xVals_[index-1] + 1) : this_x; - this.onclick(prev_x, this_x, this.yVals_[index], this.yDevs_[index], - this.extents_); - } - } -} - -Plotter.prototype.plot1_ = -function(ctx, yVals, yDevs, extents, strokeStyles) { - var e = extents; - - function mapY(y) { - var r = e.heightMax - e.heightMax * (y - e.yMin) / (e.yMax - e.yMin); - //document.getElementById('log').appendChild(document.createTextNode(r + '\n')); - return r; - } - - ctx.strokeStyle = strokeStyles.yvals; - ctx.lineWidth = 2; - ctx.beginPath(); - - // draw main line - var initial = true; - for (i = 0; i < yVals.length; ++i) { - if (yVals[i] == 0.0) - continue; - var x = e.widthMax * (i - e.xMin) / (e.xMax - e.xMin); - var y = mapY(yVals[i]); - if (initial) { - initial = false; - } else { - ctx.lineTo(x, y); - } - ctx.moveTo(x, y); - } - - ctx.closePath(); - ctx.stroke(); - - // deviation bars - if (yDevs) { - ctx.strokeStyle = strokeStyles.ydevs; - ctx.lineWidth = 1.0; - ctx.beginPath(); - - for (i = 0; i < yVals.length; ++i) { - var x = e.widthMax * (i - e.xMin) / (e.xMax - e.xMin); - var y = mapY(yVals[i]); - - var y2 = mapY(yVals[i] + yDevs[i]); - ctx.moveTo(x, y); - ctx.lineTo(x, y2); - - var m = 2; - ctx.moveTo(x, y2); - ctx.lineTo(x - m, y2); - ctx.moveTo(x, y2); - ctx.lineTo(x + m, y2); - - var y2 = mapY(yVals[i] - yDevs[i]); - ctx.moveTo(x, y); - ctx.lineTo(x, y2); - - ctx.moveTo(x, y2); - ctx.lineTo(x - m, y2); - ctx.moveTo(x, y2); - ctx.lineTo(x + m, y2); - - // draw a marker - var d = 3; - ctx.moveTo(x, y); - ctx.lineTo(x + d, y + d); - ctx.moveTo(x, y); - ctx.lineTo(x - d, y + d); - ctx.moveTo(x, y); - ctx.lineTo(x - d, y - d); - ctx.moveTo(x, y); - ctx.lineTo(x + d, y - d); - - ctx.moveTo(x, y); - } - - ctx.closePath(); - ctx.stroke(); - } -} diff --git a/tools/buildbot/perf/dashboard/overview.html b/tools/buildbot/perf/dashboard/overview.html deleted file mode 100644 index 2c312cde..0000000 --- a/tools/buildbot/perf/dashboard/overview.html +++ /dev/null @@ -1,84 +0,0 @@ - - - Chrome Perf Overview - - - - -
-

- Currently showing - -

-
- [ page-load-time | - vm-peak-browser | - vm-peak-renderer | - ws-peak-browser | - ws-peak-renderer | - io-op-browser | - io-byte-browser ] -

Chromium XP Dual Core

- - - - - - - - - - - -
-

Chromium Vista Dual Core

- - - - - - - - - - - -
-

Chromium XP JSC

- - - - - - - - - - - -
- - -
- - - diff --git a/tools/buildbot/perf/dashboard/report.html b/tools/buildbot/perf/dashboard/report.html deleted file mode 100644 index 5949e00..0000000 --- a/tools/buildbot/perf/dashboard/report.html +++ /dev/null @@ -1,298 +0,0 @@ - - - - - - - - - -

-

- - - -
-
-Builds generated by a Chromium build slave - are run through the - -and the results of that test are charted here. -
-

-

-

- -
-

- -
-
-
- - -
-
-
CL
-
Pages
-
-
-

-
-
-
-
diff --git a/tools/buildbot/perf/dashboard/svn-log b/tools/buildbot/perf/dashboard/svn-log
deleted file mode 100644
index 9a15495..0000000
--- a/tools/buildbot/perf/dashboard/svn-log
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/usr/bin/python2.4
-
-import os
-import subprocess
-import sys
-
-print 'content-type: text/xml'
-print ''
-
-try:
-	options = {}
-	query_string = os.environ['QUERY_STRING'].split('&')
-	for q in query_string:
-	  opt = q.split('=')
-	  options[opt[0]] = opt[1]
-
-	c = ['svn', 'log', '--xml', '-v', '-r', options['range'], options['url']]
-	sys.stdout.flush()
-	subprocess.call(c)
-except Exception, e:
-	print e
-
diff --git a/tools/buildbot/perf/dashboard/ui/README.txt b/tools/buildbot/perf/dashboard/ui/README.txt
deleted file mode 100644
index afe617f..0000000
--- a/tools/buildbot/perf/dashboard/ui/README.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-USAGE
-
-  Copy these files into the directory where the log_scraper scripts write their
-  output.  Presumably this should be a directory reachable via the web. There
-  are different types of reports, use the one you need. You may need to rename
-  the report name to "report.html".
-
-  Point your browser at report.html and behold.
-  
-
-BROWSER COMPAT
-
-  This application uses the  tag to render the graph of the performance
-  data, so you will need a capable browser to view it.  Firefox 1.5 and above
-  should work.  Safari with WebKit tip-of-tree also appears to mostly work.
diff --git a/tools/buildbot/perf/dashboard/ui/config.js b/tools/buildbot/perf/dashboard/ui/config.js
deleted file mode 100644
index 27c54a0..0000000
--- a/tools/buildbot/perf/dashboard/ui/config.js
+++ /dev/null
@@ -1,16 +0,0 @@
-var Config = {
-  // test title:
-  'title': "page-cycler test",
-
-  // link to the source code for the test:
-  'source': "http://chrome-svn/viewvc/chrome-internal/trunk/data/page_cycler/moz/start.html?revision=HEAD",
-
-  // link to svn repository viewer:
-  'changeLinkPrefix': "http://src.chromium.org/viewvc/chrome?view=rev&revision=",
-
-  // builder name:
-  'builder': "chrome Release - Full",
-
-  // builder link:
-  'builderLink': "http://build.chromium.org/buildbot/waterfall/waterfall?builder=chrome%20Release%20-%20Full"
-};
diff --git a/tools/buildbot/perf/dashboard/ui/details.html b/tools/buildbot/perf/dashboard/ui/details.html
deleted file mode 100644
index d991d22..0000000
--- a/tools/buildbot/perf/dashboard/ui/details.html
+++ /dev/null
@@ -1,125 +0,0 @@
-
-
-
-
-
-
-
-
-  
-    
-  
-  
-  
-
PageMeanStdDevRuns...
- - diff --git a/tools/buildbot/perf/dashboard/ui/generic_plotter.html b/tools/buildbot/perf/dashboard/ui/generic_plotter.html deleted file mode 100644 index 1f685e4..0000000 --- a/tools/buildbot/perf/dashboard/ui/generic_plotter.html +++ /dev/null @@ -1,361 +0,0 @@ - - - - - - - - - - - - - - - - - -
- - - -
- -
-Builds generated by the buildbot -are run through the - -and the results of that test are charted here. -
- -
-The vertical axis is measured values, and the horizontal -axis is the revision number for the build being tested. -
-

-
- -
-
-
-
- - -
-
-
CL
-
Pages
-
-
-

-
-
-
diff --git a/tools/buildbot/perf/dashboard/ui/js/common.js b/tools/buildbot/perf/dashboard/ui/js/common.js
deleted file mode 100644
index b43603e..0000000
--- a/tools/buildbot/perf/dashboard/ui/js/common.js
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
-  Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
-  Use of this source code is governed by a BSD-style license that can be
-  found in the LICENSE file.
-*/
-
-/*
-  Common methods for performance-plotting JS.
-*/
-
-function Fetch(url, callback) {
-  var r = new XMLHttpRequest();
-  r.open("GET", url);
-  r.setRequestHeader("pragma", "no-cache");
-  r.setRequestHeader("cache-control", "no-cache");
-  r.send(null);
-
-  r.onload = function() {
-    callback(r.responseText);
-  }
-}
-
-// Returns an Object with properties given by the parameters specified in the
-// URL's query string.
-function ParseParams() {
-  var result = new Object();
-  var s = window.location.search.substring(1).split('&');
-  for (i = 0; i < s.length; ++i) {
-    var v = s[i].split('=');
-    result[v[0]] = unescape(v[1]);
-  }
-  return result;
-}
-
-// Creates the URL constructed from the current pathname and the given params.
-function MakeURL(params) {
-  var url = window.location.pathname;
-  var sep = '?';
-  for (p in params) {
-    if (!p)
-      continue;
-    url = url + sep + p + '=' + params[p];
-    sep = '&';
-  }
-  return url;
-}
-
-// Returns a string describing an object, recursively.  On the initial call,
-// |name| is optionally the name of the object and |indent| is not needed.
-function DebugDump(obj, opt_name, opt_indent) {
-  var name = opt_name || '';
-  var indent = opt_indent || '';
-  if (typeof obj == "object") {
-    var child = null;
-    var output = indent + name + "\n";
-
-    for (var item in obj) {
-      try {
-        child = obj[item];
-      } catch (e) {
-        child = "";
-      }
-      output += DebugDump(child, item, indent + "  ");
-    }
-
-    return output;
-  } else {
-    return indent + name + ": " + obj + "\n";
-  }
-}
diff --git a/tools/buildbot/perf/dashboard/ui/js/coordinates.js b/tools/buildbot/perf/dashboard/ui/js/coordinates.js
deleted file mode 100644
index 665d1a1..0000000
--- a/tools/buildbot/perf/dashboard/ui/js/coordinates.js
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
-  Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
-  Use of this source code is governed by a BSD-style license that can be
-  found in the LICENSE file.
-*/
-
-/**
- * 'Understands' plot data positioning.
- *  @constructor
- *
- * @param {Array} plotData data that will be displayed
- */
-function Coordinates(plotData) {
-  this.plotData = plotData;
-  
-  height = window.innerHeight - 16;
-  width = window.innerWidth - 16;
-
-  this.widthMax = width;
-  this.heightMax = Math.min(400, height - 85);
-
-  this.xMinValue = -0.5;
-  this.xMaxValue = (this.plotData[0].length - 1)+ 0.5;
-  this.processYValues_();
-}
-
-Coordinates.prototype.processYValues_ = function () {
-  var merged = [];
-  for (var i = 0; i < this.plotData.length; i++)
-    for (var j = 0; j < this.plotData[i].length; j++)
-      merged.push(this.plotData[i][j][0]);
-    
-  var max = Math.max.apply( Math, merged );
-  var min = Math.min.apply( Math, merged );
-  var yd = (max - min) / 10.0;
-  if (yd == 0)
-    yd = max / 10;
-  this.yMinValue = min - yd;
-  this.yMaxValue = max + yd;
-};
-
-/**
- * Difference between horizontal max min values.
- */
-Coordinates.prototype.xValueRange = function() {
-  return this.xMaxValue - this.xMinValue;
-};
-
-/**
- * Difference between vertical max min values.
- */
-Coordinates.prototype.yValueRange = function() {
-  return this.yMaxValue - this.yMinValue
-};
-
-/**
- * Converts horizontal data value to pixel value on canvas.
- * @param {number} value horizontal data value
- */
-Coordinates.prototype.xPoints = function(value) {
-  return this.widthMax * ((value - this.xMinValue) / this.xValueRange());
-};
-
-/**
- * Converts vertical data value to pixel value on canvas.
- * @param {number} value vertical data value
- */
-Coordinates.prototype.yPoints = function(value) {
-  /* Converts value to canvas Y position in pixels. */
-  return this.heightMax  - this.heightMax * (value - this.yMinValue) / 
-    this.yValueRange();
-};
-
-/**
- * Converts X point on canvas to value it represents.
- * @param {number} position horizontal point on canvas.
- */
-Coordinates.prototype.xValue = function(position) {
-  /* Converts canvas X pixels to value. */
-  return position / this.widthMax * (this.xValueRange()) + this.xMinValue;
-};
-
-/**
- * Converts Y point on canvas to value it represents.
- * @param {number} position vertical point on canvas.
- */
-Coordinates.prototype.yValue = function(position) {
-  /* Converts canvas Y pixels to value. 
-  position is point value is from top.
-  */
-  var position = this.heightMax - position;
-  var ratio = parseFloat(this.heightMax / position);
-  return  this.yMinValue + this.yValueRange() / ratio;
-};
-
-/**
- * Converts canvas X pixel to data index.
- * @param {number} xPosition horizontal point on canvas
- */
-Coordinates.prototype.dataSampleIndex = function(xPosition) {
-  var xValue = this.xValue(xPosition);
-  var index;
-  if (xValue < 0) {
-    index = 0;
-  } else if (xValue > this.plotData[0].length - 1) {
-    index = this.plotData[0].length - 1;
-  } else {
-    index = xValue.toFixed(0);
-  }
-  return index;
-};
-
-Coordinates.prototype.log = function(val) {
-  document.getElementById('log').appendChild(
-    document.createTextNode(val + '\n'));
-};
diff --git a/tools/buildbot/perf/dashboard/ui/js/plotter.js b/tools/buildbot/perf/dashboard/ui/js/plotter.js
deleted file mode 100644
index 0064379..0000000
--- a/tools/buildbot/perf/dashboard/ui/js/plotter.js
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
-  Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
-  Use of this source code is governed by a BSD-style license that can be
-  found in the LICENSE file.
-*/
-
-// Collection of classes used to plot data in a .  Create a Plotter()
-// to generate a plot.
-
-// vertical marker for columns
-function Marker(color) {
-  var m = document.createElement("DIV");
-  m.setAttribute("class", "plot-cursor");
-  m.style.backgroundColor = color;
-  m.style.opacity = "0.3";
-  m.style.position = "absolute";
-  m.style.left = "-2px";
-  m.style.top = "-2px";
-  m.style.width = "0px";
-  m.style.height = "0px";
-  return m;
-}
-
-/**
- * HorizontalMarker class
- * Create a horizontal marker at the indicated mouse location.
- * @constructor
- *
- * @param canvasRect {Object} The canvas bounds (in client coords).
- * @param clientY {Number} The vertical mouse click location that spawned
- *    the marker, in the client coordinate space.
- * @param yValue {Number} The plotted value corresponding to the clientY
- *     click location.
- */
-function HorizontalMarker(canvasRect, clientY, yValue) {
-  // Add a horizontal line to the graph.
-  var m = document.createElement("DIV");
-  m.setAttribute("class", "plot-baseline");
-  m.style.backgroundColor = HorizontalMarker.COLOR;
-  m.style.opacity = "0.3";
-  m.style.position = "absolute";
-  m.style.left = canvasRect.offsetLeft;
-  var h = HorizontalMarker.HEIGHT;
-  m.style.top = (clientY - h/2).toFixed(0) + "px";
-  m.style.width = canvasRect.width + "px";
-  m.style.height = h + "px";
-  this.markerDiv_ = m;
-
-  this.value = yValue;
-}
-
-HorizontalMarker.HEIGHT = 5;
-HorizontalMarker.COLOR = "rgb(0,100,100)";
-
-// Remove the horizontal line from the graph.
-HorizontalMarker.prototype.remove_ = function() {
-  this.markerDiv_.parentNode.removeChild(this.markerDiv_);
-}
-
-/**
- * Plotter class
- * @constructor
- *
- * Draws a chart using CANVAS element. Takes array of lines to draw with
- * deviations values for each data sample.
- *
- * @param {Array} clNumbers list of clNumbers for each data sample.
- * @param {Array} plotData list of arrays that represent individual lines.
- *                         The line itself is an Array of value and stdd.
- * @param {Array} dataDescription list of data description for each line
- *                         in plotData.
- * @units {string} units name of measurement used to describe plotted data.
- *
- * Example of the plotData:
- *  [
- *    [line 1 data],
- *    [line 2 data]
- *  ].
- *  Line data looks like  [[point one], [point two]].
- *  And individual points are [value, deviation value]
- */
-function Plotter(clNumbers, plotData, dataDescription, units, resultNode) {
-  this.clNumbers_ = clNumbers;
-  this.plotData_ = plotData;
-  this.dataDescription_ = dataDescription;
-  this.resultNode_ = resultNode;
-  this.units_ = units;
-  this.coordinates = new Coordinates(plotData);
-}
-
-/**
- * Does the actual plotting.
- */
-Plotter.prototype.plot = function() {
-  var canvas = this.canvas();
-  this.coordinates_div_ = this.coordinates_();
-  this.ruler_div_ = this.ruler();
-  // marker for the result-point that the mouse is currently over
-  this.cursor_div_ = new Marker("rgb(100,80,240)");
-  // marker for the result-point for which details are shown
-  this.marker_div_ = new Marker("rgb(100,100,100)");
-  var ctx = canvas.getContext("2d");
-  for (var i = 0; i < this.plotData_.length; i++)
-    this.plotLine_(ctx, this.nextColor(i), this.plotData_[i]);
-
-  this.resultNode_.appendChild(canvas);
-  this.resultNode_.appendChild(this.coordinates_div_);
-
-  this.resultNode_.appendChild(this.ruler_div_);
-  this.resultNode_.appendChild(this.cursor_div_);
-  this.resultNode_.appendChild(this.marker_div_);
-  this.attachEventListeners(canvas);
-  this.canvasRectangle = {
-    "offsetLeft": canvas.offsetLeft,
-    "offsetTop":  canvas.offsetTop,
-    "width":      canvas.offsetWidth,
-    "height":     canvas.offsetHeight
-  };
-};
-
-Plotter.prototype.drawDeviationBar_ = function(context, strokeStyles, x, y,
-                                                deviationValue) {
-  context.strokeStyle = strokeStyles;
-  context.lineWidth = 1.0;
-  context.beginPath();
-  context.moveTo(x, (y + deviationValue));
-  context.lineTo(x, (y - deviationValue));
-  context.moveTo(x, (y - deviationValue));
-  context.closePath();
-  context.stroke();
-};
-
-Plotter.prototype.plotLine_ = function(ctx, strokeStyles, data) {
-  ctx.strokeStyle = strokeStyles;
-  ctx.lineWidth = 2.0;
-  ctx.beginPath();
-  var initial = true;
-  var deviationData = [];
-  for (var i = 0; i < data.length; i++) {
-    var x = this.coordinates.xPoints(i);
-    var value = data[i][0];
-    var stdd = data[i][1];
-    var y = this.coordinates.yPoints(value);
-    // Re-set 'initial' if we're at a gap in the data.
-    if (value == 0)
-      initial = true;
-    else if (initial)
-      initial = false;
-    else
-      ctx.lineTo(x, y);
-
-    ctx.moveTo(x, y);
-    var err = 0;
-    if (value != 0 && stdd != 0)
-      err = y / parseFloat(value / stdd);
-    deviationData.push([x, y, err])
-  }
-  ctx.closePath();
-  ctx.stroke();
-
-  for (var i = 0; i < deviationData.length; i++) {
-    this.drawDeviationBar_(ctx, strokeStyles, deviationData[i][0],
-                            deviationData[i][1], deviationData[i][2]);
-  }
-};
-
-Plotter.prototype.attachEventListeners = function(canvas) {
-  var self = this;
-  canvas.parentNode.addEventListener(
-    "mousemove", function(evt) { self.onMouseMove_(evt); }, false);
-  this.cursor_div_.addEventListener(
-    "click", function(evt) { self.onMouseClick_(evt); }, false);
-};
-
-Plotter.prototype.updateRuler_ = function(evt) {
-  var r = this.ruler_div_;
-  r.style.left = this.canvasRectangle.offsetLeft + "px";
-
-  r.style.top = this.canvasRectangle.offsetTop + "px";
-  r.style.width = this.canvasRectangle.width + "px";
-  var h = evt.clientY - this.canvasRectangle.offsetTop;
-  if (h > this.canvasRectangle.height)
-    h = this.canvasRectangle.height;
-  r.style.height = h + "px";
-};
-
-Plotter.prototype.updateCursor_ = function() {
-  var c = this.cursor_div_;
-  c.style.top = this.canvasRectangle.offsetTop + "px";
-  c.style.height = this.canvasRectangle.height + "px";
-  var w = this.canvasRectangle.width / this.clNumbers_.length;
-  var x = (this.canvasRectangle.offsetLeft +
-            w * this.current_index_).toFixed(0);
-  c.style.left = x + "px";
-  c.style.width = w + "px";
-};
-
-
-Plotter.prototype.onMouseMove_ = function(evt) {
-  var canvas = evt.currentTarget.firstChild;
-  var positionX = evt.clientX - this.canvasRectangle.offsetLeft;
-  var positionY = evt.clientY - this.canvasRectangle.offsetTop;
-
-  this.current_index_ = this.coordinates.dataSampleIndex(positionX);
-  var yValue = this.coordinates.yValue(positionY);
-
-  this.coordinates_td_.innerHTML =
-      "CL #" + this.clNumbers_[this.current_index_] + ": " +
-      this.plotData_[0][this.current_index_][0].toFixed(2) + " " +
-      this.units_ + " +/- " +
-      this.plotData_[0][this.current_index_][1].toFixed(2) + " " +
-      yValue.toFixed(2) + " " + this.units_;
-
-  // If there is a horizontal marker, also display deltas relative to it.
-  if (this.horizontal_marker_) {
-    var baseline = this.horizontal_marker_.value;
-    var delta = yValue - baseline
-    var fraction = delta / baseline; // allow division by 0
-
-    var deltaStr = (delta >= 0 ? "+" : "") + delta.toFixed(0) + " " +
-        this.units_;
-    var percentStr = (fraction >= 0 ? "+" : "") +
-        (fraction * 100).toFixed(3) + "%";
-
-    this.baseline_deltas_td_.innerHTML = deltaStr + ": " + percentStr;
-  }
-
-  this.updateRuler_(evt);
-  this.updateCursor_();
-};
-
-Plotter.prototype.onMouseClick_ = function(evt) {
-  // Shift-click controls the horizontal reference line.
-  if (evt.shiftKey) {
-    if (this.horizontal_marker_) {
-      this.horizontal_marker_.remove_();
-    }
-
-    var canvasY = evt.clientY - this.canvasRectangle.offsetTop;
-    this.horizontal_marker_ = new HorizontalMarker(this.canvasRectangle,
-        evt.clientY, this.coordinates.yValue(canvasY));
-
-    // Insert before cursor node, otherwise it catches clicks.
-    this.cursor_div_.parentNode.insertBefore(
-        this.horizontal_marker_.markerDiv_, this.cursor_div_);
-  } else {
-    var index = this.current_index_;
-    var m = this.marker_div_;
-    var c = this.cursor_div_;
-    m.style.top = c.style.top;
-    m.style.left = c.style.left;
-    m.style.width = c.style.width;
-    m.style.height = c.style.height;
-    if ("onclick" in this)
-      this.onclick(this.clNumbers_[index]);
-  }
-};
-
-Plotter.prototype.canvas = function() {
-  var canvas = document.createElement("CANVAS");
-  canvas.setAttribute("id", "_canvas");
-  canvas.setAttribute("class", "plot");
-  canvas.setAttribute("width", this.coordinates.widthMax);
-  canvas.setAttribute("height", this.coordinates.heightMax);
-  return canvas;
-};
-
-Plotter.prototype.ruler = function() {
-  ruler = document.createElement("DIV");
-  ruler.setAttribute("class", "plot-ruler");
-  ruler.style.borderBottom = "1px dotted black";
-  ruler.style.position = "absolute";
-  ruler.style.left = "-2px";
-  ruler.style.top = "-2px";
-  ruler.style.width = "0px";
-  ruler.style.height = "0px";
-  return ruler;
-};
-
-Plotter.prototype.coordinates_ = function() {
-  var coordinatesDiv = document.createElement("DIV");
-  var table_html =
-     "" +
-     "" +
-     "" +
-     "" +
-     "
Legend: "; - for (var i = 0; i < this.dataDescription_.length; i++) { - if (i > 0) - table_html += ", "; - table_html += "" + this.dataDescription_[i] + ""; - } - table_html += "
move mouse over graphShift-click to place baseline
"; - coordinatesDiv.innerHTML = table_html; - - var tr = coordinatesDiv.firstChild.firstChild.childNodes[1]; - this.coordinates_td_ = tr.childNodes[0]; - this.baseline_deltas_td_ = tr.childNodes[1]; - - return coordinatesDiv; -}; - -Plotter.prototype.nextColor = function(i) { - var increment = (i * 50); - var red = (60 + increment) % 255; - var green = increment % 255; - var blue = (240 + increment) % 255; - return "rgb(" + red +"," + green + "," + blue + ")"; -}; - -Plotter.prototype.log = function(val) { - document.getElementById('log').appendChild( - document.createTextNode(val + '\n')); -}; diff --git a/tools/buildbot/perf/dashboard/ui/pagecycler_report.html b/tools/buildbot/perf/dashboard/ui/pagecycler_report.html deleted file mode 100644 index 13a79d8..0000000 --- a/tools/buildbot/perf/dashboard/ui/pagecycler_report.html +++ /dev/null @@ -1,260 +0,0 @@ - - - - - - - - - - -

-

- - - -
-
-Builds generated by the BUILD TYPE build -slave are run through the - -and the results of that test are charted here. -
-

-

-

- -
-

- -
-
-
- - -
-
-
CL
-
Pages
-
-
-

-
-
-
-
diff --git a/tools/buildbot/perf/dashboard/ui/playback_report.html b/tools/buildbot/perf/dashboard/ui/playback_report.html
deleted file mode 100644
index 42471ed..0000000
--- a/tools/buildbot/perf/dashboard/ui/playback_report.html
+++ /dev/null
@@ -1,341 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-

-

- - - -
-
-Builds generated by the - -build slave are run through the - -and the results of that test are charted here. -
-

-

-

-The vertical axis is the count or time and the horizontal axis is the -change-list for the build being tested.

-This color is for the latest build, and -this color is for the reference build. -
-

- -
-
-
- - -
-
-
CL
-
-
-

-
-
diff --git a/tools/buildbot/perf/dashboard/ui/sunspider_report.html b/tools/buildbot/perf/dashboard/ui/sunspider_report.html
deleted file mode 100644
index 748789d..0000000
--- a/tools/buildbot/perf/dashboard/ui/sunspider_report.html
+++ /dev/null
@@ -1,279 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-

-

- - - -
-
-Builds generated by the BUILD TYPE build -slave are run through the - -and the results of that test are charted here. -
-

-

-

-The vertical axis is the time in milliseconds for the build to complete the -test, and the horizontal axis is the change-list for the build being -tested -
-

-
- -
-
-
-
- - -
-
-
CL
-
-
-

-
-
diff --git a/tools/buildbot/perf/generate_perf.sh b/tools/buildbot/perf/generate_perf.sh
deleted file mode 100755
index ae77788..0000000
--- a/tools/buildbot/perf/generate_perf.sh
+++ /dev/null
@@ -1,76 +0,0 @@
-#!/bin/sh
-# Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# Initializes all the perf directories.
-# TODO(nsylvain): Convert to python.
-
-# Create or reinitialize a standard perf test directory.
-function InitDir()
-{
-  # Create the directory if it does not exist.
-  mkdir -p $1
-
-  # remove the current files, if any.
-  rm -f $1/details.html
-  rm -f $1/report.html
-  rm -f $1/js
-}
-
-# Util function to create config.js file.
-# The first parameter is the test directory.
-# The second parameter is the test title.
-function WriteConfig()
-{
-  echo "var Config = {" > $1/config.js
-  echo "  title: '$2'," >>  $1/config.js
-  echo "  changeLinkPrefix: 'http://src.chromium.org/viewvc/chrome?view=rev&revision='" >> $1/config.js
-  echo "};" >> $1/config.js
-}
-
-# Initialize the dashboard for a ui perf test.
-# The first parameter is the test directory.
-# The second parameter is the name of the test.
-function InitUIDashboard()
-{
-  # Create or reinitialize the directory.
-  InitDir $1
-
-  # Create the new file
-  ln -s ../../dashboard/ui/details.html $1/
-  ln -s ../../dashboard/ui/generic_plotter.html $1/report.html
-  ln -s ../../dashboard/ui/js $1/
-
-  # Create the config.js file.
-  WriteConfig $1 "$2"
-}
-
-# Initialize all the perf directories for a tester.
-# The first parameter is the root directory for the tester.
-function InitTester()
-{
-  mkdir -p $1
-
-  # Add any new perf tests here
-  InitUIDashboard $1/moz "Page Cycler Moz"
-  InitUIDashboard $1/intl1 "Page Cycler Intl1"
-  InitUIDashboard $1/intl2 "Page Cycler Intl2"
-  InitUIDashboard $1/dhtml "Page Cycler DHTML"
-  InitUIDashboard $1/moz-http "Page Cycler Moz - HTTP"
-  InitUIDashboard $1/new-tab-ui-cold "New Tab Cold"
-  InitUIDashboard $1/new-tab-ui-warm "New Tab Warm"
-  InitUIDashboard $1/startup "Startup"
-  InitUIDashboard $1/tab-switching "Tab Switching"
-  InitUIDashboard $1/bloat-http "Bloat - HTTP"
-
-  InitUIDashboard $1/memory "Memory"
-  
-  chmod -R 755 $1
-}
-
-# Add any new perf testers here.
-InitTester xp-release-dual-core
-InitTester xp-release-jsc
-InitTester vista-release-dual-core
-
diff --git a/tools/buildbot/perf/index.html b/tools/buildbot/perf/index.html
deleted file mode 100644
index 0837426..0000000
--- a/tools/buildbot/perf/index.html
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-BuildBot perf page
-
-
-
-
-
diff --git a/tools/buildbot/pylibs/buildbot/COPYING b/tools/buildbot/pylibs/buildbot/COPYING
deleted file mode 100644
index d511905..0000000
--- a/tools/buildbot/pylibs/buildbot/COPYING
+++ /dev/null
@@ -1,339 +0,0 @@
-		    GNU GENERAL PUBLIC LICENSE
-		       Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-			    Preamble
-
-  The licenses for most software are designed to take away your
-freedom to share and change it.  By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users.  This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it.  (Some other Free Software Foundation software is covered by
-the GNU Lesser General Public License instead.)  You can apply it to
-your programs, too.
-
-  When we speak of free software, we are referring to freedom, not
-price.  Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
-  To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
-  For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have.  You must make sure that they, too, receive or can get the
-source code.  And you must show them these terms so they know their
-rights.
-
-  We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
-  Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software.  If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
-  Finally, any free program is threatened constantly by software
-patents.  We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary.  To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
-  The precise terms and conditions for copying, distribution and
-modification follow.
-
-		    GNU GENERAL PUBLIC LICENSE
-   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
-  0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License.  The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language.  (Hereinafter, translation is included without limitation in
-the term "modification".)  Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope.  The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
-  1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
-  2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
-    a) You must cause the modified files to carry prominent notices
-    stating that you changed the files and the date of any change.
-
-    b) You must cause any work that you distribute or publish, that in
-    whole or in part contains or is derived from the Program or any
-    part thereof, to be licensed as a whole at no charge to all third
-    parties under the terms of this License.
-
-    c) If the modified program normally reads commands interactively
-    when run, you must cause it, when started running for such
-    interactive use in the most ordinary way, to print or display an
-    announcement including an appropriate copyright notice and a
-    notice that there is no warranty (or else, saying that you provide
-    a warranty) and that users may redistribute the program under
-    these conditions, and telling the user how to view a copy of this
-    License.  (Exception: if the Program itself is interactive but
-    does not normally print such an announcement, your work based on
-    the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole.  If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works.  But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
-  3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
-    a) Accompany it with the complete corresponding machine-readable
-    source code, which must be distributed under the terms of Sections
-    1 and 2 above on a medium customarily used for software interchange; or,
-
-    b) Accompany it with a written offer, valid for at least three
-    years, to give any third party, for a charge no more than your
-    cost of physically performing source distribution, a complete
-    machine-readable copy of the corresponding source code, to be
-    distributed under the terms of Sections 1 and 2 above on a medium
-    customarily used for software interchange; or,
-
-    c) Accompany it with the information you received as to the offer
-    to distribute corresponding source code.  (This alternative is
-    allowed only for noncommercial distribution and only if you
-    received the program in object code or executable form with such
-    an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it.  For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable.  However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
-  4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License.  Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
-  5. You are not required to accept this License, since you have not
-signed it.  However, nothing else grants you permission to modify or
-distribute the Program or its derivative works.  These actions are
-prohibited by law if you do not accept this License.  Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
-  6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions.  You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
-  7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License.  If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all.  For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices.  Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
-  8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded.  In such case, this License incorporates
-the limitation as if written in the body of this License.
-
-  9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time.  Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number.  If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation.  If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
-  10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission.  For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this.  Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
-			    NO WARRANTY
-
-  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
-  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
-		     END OF TERMS AND CONDITIONS
-
-	    How to Apply These Terms to Your New Programs
-
-  If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
-  To do so, attach the following notices to the program.  It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-    
-    Copyright (C)   
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License along
-    with this program; if not, write to the Free Software Foundation, Inc.,
-    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
-    Gnomovision version 69, Copyright (C) year name of author
-    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
-    This is free software, and you are welcome to redistribute it
-    under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License.  Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary.  Here is a sample; alter the names:
-
-  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
-  `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
-  , 1 April 1989
-  Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs.  If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library.  If this is what you want to do, use the GNU Lesser General
-Public License instead of this License.
diff --git a/tools/buildbot/pylibs/buildbot/CREDITS b/tools/buildbot/pylibs/buildbot/CREDITS
deleted file mode 100644
index 4fa91de..0000000
--- a/tools/buildbot/pylibs/buildbot/CREDITS
+++ /dev/null
@@ -1,74 +0,0 @@
-This is a list of everybody who has contributed to Buildbot in some way, in
-no particular order. Thanks everybody!
-
-Aaron Hsieh
-Albert Hofkamp
-Alexander Lorenz
-Alexander Staubo
-AllMyData.com
-Andrew Bennetts
-Anthony Baxter
-Baptiste Lepilleur
-Bear
-Ben Hearsum
-Benoit Sigoure
-Brad Hards
-Brandon Philips
-Brett Neely
-Charles Lepple
-Christian Unger
-Clement Stenac
-Dan Locks
-Dave Liebreich
-Dave Peticolas
-Dobes Vandermeer
-Dustin Mitchell
-Elliot Murphy
-Fabrice Crestois
-Gary Granger
-Gerald Combs
-Greg Ward
-Grig Gheorghiu
-Haavard Skinnemoen
-JP Calderone
-James Knight
-Jerome Davann
-John Backstrand
-John O'Duinn
-John Pye
-John Saxton
-Jose Dapena Paz
-Kevin Turner
-Kirill Lapshin
-Marius Gedminas
-Mark Dillavou
-Mark Hammond
-Mark Pauley
-Mark Rowe
-Mateusz Loskot
-Nathaniel Smith
-Neal Norwitz
-Nick Mathewson
-Nick Trout
-Niklaus Giger
-Olivier Bonnet
-Olly Betts
-Paul Warren
-Paul Winkler
-Phil Thompson
-Philipp Frauenfelder
-Rene Rivera
-Riccardo Magliocchetti
-Rob Helmer
-Roch Gadsdon
-Roy Rapoport
-Scott Lamb
-Stephen Davis
-Steven Walter
-Ted Mielczarek
-Thomas Vander Stichele
-Tobi Vollebregt
-Wade Brainerd
-Yoz Grahame
-Zandr Milewski
-chops
diff --git a/tools/buildbot/pylibs/buildbot/README.google b/tools/buildbot/pylibs/buildbot/README.google
deleted file mode 100644
index a4d0d8b..0000000
--- a/tools/buildbot/pylibs/buildbot/README.google
+++ /dev/null
@@ -1,9 +0,0 @@
-URL: http://buildbot.net/trac
-Version: 0.7.8
-License: GNU General Public License (GPL) Version 2
-
-Local modifications:
-
-slave/bot.py:
-  Edited to import google_commands.  Original version saved as bot_orig.py.
-
diff --git a/tools/buildbot/pylibs/buildbot/__init__.py b/tools/buildbot/pylibs/buildbot/__init__.py
deleted file mode 100644
index bf4a25f..0000000
--- a/tools/buildbot/pylibs/buildbot/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-
-version = "0.7.8"
diff --git a/tools/buildbot/pylibs/buildbot/buildbot.png b/tools/buildbot/pylibs/buildbot/buildbot.png
deleted file mode 100644
index 387ba15..0000000
Binary files a/tools/buildbot/pylibs/buildbot/buildbot.png and /dev/null differ
diff --git a/tools/buildbot/pylibs/buildbot/buildset.py b/tools/buildbot/pylibs/buildbot/buildset.py
deleted file mode 100644
index fe59f74..0000000
--- a/tools/buildbot/pylibs/buildbot/buildset.py
+++ /dev/null
@@ -1,81 +0,0 @@
-from buildbot.process import base
-from buildbot.status import builder
-from buildbot.process.properties import Properties
-
-
-class BuildSet:
-    """I represent a set of potential Builds, all of the same source tree,
-    across a specified list of Builders. I can represent a build of a
-    specific version of the source tree (named by source.branch and
-    source.revision), or a build of a certain set of Changes
-    (source.changes=list)."""
-
-    def __init__(self, builderNames, source, reason=None, bsid=None,
-                 properties=None):
-        """
-        @param source: a L{buildbot.sourcestamp.SourceStamp}
-        """
-        self.builderNames = builderNames
-        self.source = source
-        self.reason = reason
-
-        self.properties = Properties()
-        if properties: self.properties.updateFromProperties(properties)
-
-        self.stillHopeful = True
-        self.status = bss = builder.BuildSetStatus(source, reason,
-                                                   builderNames, bsid)
-
-    def waitUntilSuccess(self):
-        return self.status.waitUntilSuccess()
-    def waitUntilFinished(self):
-        return self.status.waitUntilFinished()
-
-    def start(self, builders):
-        """This is called by the BuildMaster to actually create and submit
-        the BuildRequests."""
-        self.requests = []
-        reqs = []
-
-        # create the requests
-        for b in builders:
-            req = base.BuildRequest(self.reason, self.source, b.name, 
-                                    properties=self.properties)
-            reqs.append((b, req))
-            self.requests.append(req)
-            d = req.waitUntilFinished()
-            d.addCallback(self.requestFinished, req)
-
-        # tell our status about them
-        req_statuses = [req.status for req in self.requests]
-        self.status.setBuildRequestStatuses(req_statuses)
-
-        # now submit them
-        for b,req in reqs:
-            b.submitBuildRequest(req)
-
-    def requestFinished(self, buildstatus, req):
-        # TODO: this is where individual build status results are aggregated
-        # into a BuildSet-wide status. Consider making a rule that says one
-        # WARNINGS results in the overall status being WARNINGS too. The
-        # current rule is that any FAILURE means FAILURE, otherwise you get
-        # SUCCESS.
-        self.requests.remove(req)
-        results = buildstatus.getResults()
-        if results == builder.FAILURE:
-            self.status.setResults(results)
-            if self.stillHopeful:
-                # oh, cruel reality cuts deep. no joy for you. This is the
-                # first failure. This flunks the overall BuildSet, so we can
-                # notify success watchers that they aren't going to be happy.
-                self.stillHopeful = False
-                self.status.giveUpHope()
-                self.status.notifySuccessWatchers()
-        if not self.requests:
-            # that was the last build, so we can notify finished watchers. If
-            # we haven't failed by now, we can claim success.
-            if self.stillHopeful:
-                self.status.setResults(builder.SUCCESS)
-                self.status.notifySuccessWatchers()
-            self.status.notifyFinishedWatchers()
-
diff --git a/tools/buildbot/pylibs/buildbot/buildslave.py b/tools/buildbot/pylibs/buildbot/buildslave.py
deleted file mode 100644
index 3e7397b..0000000
--- a/tools/buildbot/pylibs/buildbot/buildslave.py
+++ /dev/null
@@ -1,350 +0,0 @@
-
-import time
-from email.Message import Message
-from email.Utils import formatdate
-from zope.interface import implements
-from twisted.python import log
-from twisted.internet import defer, reactor
-from twisted.application import service
-
-from buildbot.pbutil import NewCredPerspective
-from buildbot.status.builder import SlaveStatus
-from buildbot.status.mail import MailNotifier
-from buildbot.interfaces import IBuildSlave
-from buildbot.process.properties import Properties
-
-class BuildSlave(NewCredPerspective, service.MultiService):
-    """This is the master-side representative for a remote buildbot slave.
-    There is exactly one for each slave described in the config file (the
-    c['slaves'] list). When buildbots connect in (.attach), they get a
-    reference to this instance. The BotMaster object is stashed as the
-    .botmaster attribute. The BotMaster is also our '.parent' Service.
-
-    I represent a build slave -- a remote machine capable of
-    running builds.  I am instantiated by the configuration file, and can be
-    subclassed to add extra functionality."""
-
-    implements(IBuildSlave)
-
-    def __init__(self, name, password, max_builds=None,
-                 notify_on_missing=[], missing_timeout=3600,
-                 properties={}):
-        """
-        @param name: botname this machine will supply when it connects
-        @param password: password this machine will supply when
-                         it connects
-        @param max_builds: maximum number of simultaneous builds that will
-                           be run concurrently on this buildslave (the
-                           default is None for no limit)
-        @param properties: properties that will be applied to builds run on 
-                           this slave
-        @type properties: dictionary
-        """
-        service.MultiService.__init__(self)
-        self.slavename = name
-        self.password = password
-        self.botmaster = None # no buildmaster yet
-        self.slave_status = SlaveStatus(name)
-        self.slave = None # a RemoteReference to the Bot, when connected
-        self.slave_commands = None
-        self.slavebuilders = []
-        self.max_builds = max_builds
-
-        self.properties = Properties()
-        self.properties.update(properties, "BuildSlave")
-        self.properties.setProperty("slavename", name, "BuildSlave")
-
-        self.lastMessageReceived = 0
-        if isinstance(notify_on_missing, str):
-            notify_on_missing = [notify_on_missing]
-        self.notify_on_missing = notify_on_missing
-        for i in notify_on_missing:
-            assert isinstance(i, str)
-        self.missing_timeout = missing_timeout
-        self.missing_timer = None
-
-    def update(self, new):
-        """
-        Given a new BuildSlave, configure this one identically.  Because
-        BuildSlave objects are remotely referenced, we can't replace them
-        without disconnecting the slave, yet there's no reason to do that.
-        """
-        # the reconfiguration logic should guarantee this:
-        assert self.slavename == new.slavename
-        assert self.password == new.password
-        assert self.__class__ == new.__class__
-        self.max_builds = new.max_builds
-
-    def __repr__(self):
-        if self.botmaster:
-            builders = self.botmaster.getBuildersForSlave(self.slavename)
-            return "" % \
-               (self.slavename, ','.join(map(lambda b: b.name, builders)))
-        else:
-            return "" % self.slavename
-
-    def setBotmaster(self, botmaster):
-        assert not self.botmaster, "BuildSlave already has a botmaster"
-        self.botmaster = botmaster
-
-    def updateSlave(self):
-        """Called to add or remove builders after the slave has connected.
-
-        @return: a Deferred that indicates when an attached slave has
-        accepted the new builders and/or released the old ones."""
-        if self.slave:
-            return self.sendBuilderList()
-        return defer.succeed(None)
-
-    def updateSlaveStatus(self, buildStarted=None, buildFinished=None):
-        if buildStarted:
-            self.slave_status.buildStarted(buildStarted)
-        if buildFinished:
-            self.slave_status.buildFinished(buildFinished)
-
-    def attached(self, bot):
-        """This is called when the slave connects.
-
-        @return: a Deferred that fires with a suitable pb.IPerspective to
-                 give to the slave (i.e. 'self')"""
-
-        if self.missing_timer:
-            self.missing_timer.cancel()
-            self.missing_timer = None
-
-        if self.slave:
-            # uh-oh, we've got a duplicate slave. The most likely
-            # explanation is that the slave is behind a slow link, thinks we
-            # went away, and has attempted to reconnect, so we've got two
-            # "connections" from the same slave, but the previous one is
-            # stale. Give the new one precedence.
-            log.msg("duplicate slave %s replacing old one" % self.slavename)
-
-            # just in case we've got two identically-configured slaves,
-            # report the IP addresses of both so someone can resolve the
-            # squabble
-            tport = self.slave.broker.transport
-            log.msg("old slave was connected from", tport.getPeer())
-            log.msg("new slave is from", bot.broker.transport.getPeer())
-            d = self.disconnect()
-        else:
-            d = defer.succeed(None)
-        # now we go through a sequence of calls, gathering information, then
-        # tell the Botmaster that it can finally give this slave to all the
-        # Builders that care about it.
-
-        # we accumulate slave information in this 'state' dictionary, then
-        # set it atomically if we make it far enough through the process
-        state = {}
-
-        def _log_attachment_on_slave(res):
-            d1 = bot.callRemote("print", "attached")
-            d1.addErrback(lambda why: None)
-            return d1
-        d.addCallback(_log_attachment_on_slave)
-
-        def _get_info(res):
-            d1 = bot.callRemote("getSlaveInfo")
-            def _got_info(info):
-                log.msg("Got slaveinfo from '%s'" % self.slavename)
-                # TODO: info{} might have other keys
-                state["admin"] = info.get("admin")
-                state["host"] = info.get("host")
-            def _info_unavailable(why):
-                # maybe an old slave, doesn't implement remote_getSlaveInfo
-                log.msg("BuildSlave.info_unavailable")
-                log.err(why)
-            d1.addCallbacks(_got_info, _info_unavailable)
-            return d1
-        d.addCallback(_get_info)
-
-        def _get_commands(res):
-            d1 = bot.callRemote("getCommands")
-            def _got_commands(commands):
-                state["slave_commands"] = commands
-            def _commands_unavailable(why):
-                # probably an old slave
-                log.msg("BuildSlave._commands_unavailable")
-                if why.check(AttributeError):
-                    return
-                log.err(why)
-            d1.addCallbacks(_got_commands, _commands_unavailable)
-            return d1
-        d.addCallback(_get_commands)
-
-        def _accept_slave(res):
-            self.slave_status.setAdmin(state.get("admin"))
-            self.slave_status.setHost(state.get("host"))
-            self.slave_status.setConnected(True)
-            self.slave_commands = state.get("slave_commands")
-            self.slave = bot
-            log.msg("bot attached")
-            self.messageReceivedFromSlave()
-            return self.updateSlave()
-        d.addCallback(_accept_slave)
-
-        # Finally, the slave gets a reference to this BuildSlave. They
-        # receive this later, after we've started using them.
-        d.addCallback(lambda res: self)
-        return d
-
-    def messageReceivedFromSlave(self):
-        now = time.time()
-        self.lastMessageReceived = now
-        self.slave_status.setLastMessageReceived(now)
-
-    def detached(self, mind):
-        self.slave = None
-        self.slave_status.setConnected(False)
-        self.botmaster.slaveLost(self)
-        log.msg("BuildSlave.detached(%s)" % self.slavename)
-        if self.notify_on_missing and self.parent:
-            self.missing_timer = reactor.callLater(self.missing_timeout,
-                                                   self._missing_timer_fired)
-
-    def _missing_timer_fired(self):
-        self.missing_timer = None
-        # notify people, but only if we're still in the config
-        if not self.parent:
-            return
-
-        # first, see if we have a MailNotifier we can use. This gives us a
-        # fromaddr and a relayhost.
-        buildmaster = self.botmaster.parent
-        status = buildmaster.getStatus()
-        for st in buildmaster.statusTargets:
-            if isinstance(st, MailNotifier):
-                break
-        else:
-            # if not, they get a default MailNotifier, which always uses SMTP
-            # to localhost and uses a dummy fromaddr of "buildbot".
-            log.msg("buildslave-missing msg using default MailNotifier")
-            st = MailNotifier("buildbot")
-        # now construct the mail
-        text = "The Buildbot working for '%s'\n" % status.getProjectName()
-        text += ("has noticed that the buildslave named %s went away\n" %
-                 self.slavename)
-        text += "\n"
-        text += ("It last disconnected at %s (buildmaster-local time)\n" %
-                 time.ctime(time.time() - self.missing_timeout)) # close enough
-        text += "\n"
-        text += "The admin on record (as reported by BUILDSLAVE:info/admin)\n"
-        text += "was '%s'.\n" % self.slave_status.getAdmin()
-        text += "\n"
-        text += "Sincerely,\n"
-        text += " The Buildbot\n"
-        text += " %s\n" % status.getProjectURL()
-
-        m = Message()
-        m.set_payload(text)
-        m['Date'] = formatdate(localtime=True)
-        m['Subject'] = "Buildbot: buildslave %s was lost" % self.slavename
-        m['From'] = st.fromaddr
-        recipients = self.notify_on_missing
-        m['To'] = ", ".join(recipients)
-        d = st.sendMessage(m, recipients)
-        # return the Deferred for testing purposes
-        return d
-
-    def disconnect(self):
-        """Forcibly disconnect the slave.
-
-        This severs the TCP connection and returns a Deferred that will fire
-        (with None) when the connection is probably gone.
-
-        If the slave is still alive, they will probably try to reconnect
-        again in a moment.
-
-        This is called in two circumstances. The first is when a slave is
-        removed from the config file. In this case, when they try to
-        reconnect, they will be rejected as an unknown slave. The second is
-        when we wind up with two connections for the same slave, in which
-        case we disconnect the older connection.
-        """
-
-        if not self.slave:
-            return defer.succeed(None)
-        log.msg("disconnecting old slave %s now" % self.slavename)
-
-        # all kinds of teardown will happen as a result of
-        # loseConnection(), but it happens after a reactor iteration or
-        # two. Hook the actual disconnect so we can know when it is safe
-        # to connect the new slave. We have to wait one additional
-        # iteration (with callLater(0)) to make sure the *other*
-        # notifyOnDisconnect handlers have had a chance to run.
-        d = defer.Deferred()
-
-        # notifyOnDisconnect runs the callback with one argument, the
-        # RemoteReference being disconnected.
-        def _disconnected(rref):
-            reactor.callLater(0, d.callback, None)
-        self.slave.notifyOnDisconnect(_disconnected)
-        tport = self.slave.broker.transport
-        # this is the polite way to request that a socket be closed
-        tport.loseConnection()
-        try:
-            # but really we don't want to wait for the transmit queue to
-            # drain. The remote end is unlikely to ACK the data, so we'd
-            # probably have to wait for a (20-minute) TCP timeout.
-            #tport._closeSocket()
-            # however, doing _closeSocket (whether before or after
-            # loseConnection) somehow prevents the notifyOnDisconnect
-            # handlers from being run. Bummer.
-            tport.offset = 0
-            tport.dataBuffer = ""
-            pass
-        except:
-            # however, these hacks are pretty internal, so don't blow up if
-            # they fail or are unavailable
-            log.msg("failed to accelerate the shutdown process")
-            pass
-        log.msg("waiting for slave to finish disconnecting")
-
-        # When this Deferred fires, we'll be ready to accept the new slave
-        return d
-
-    def sendBuilderList(self):
-        our_builders = self.botmaster.getBuildersForSlave(self.slavename)
-        blist = [(b.name, b.builddir) for b in our_builders]
-        d = self.slave.callRemote("setBuilderList", blist)
-        def _sent(slist):
-            dl = []
-            for name, remote in slist.items():
-                # use get() since we might have changed our mind since then
-                b = self.botmaster.builders.get(name)
-                if b:
-                    d1 = b.attached(self, remote, self.slave_commands)
-                    dl.append(d1)
-            return defer.DeferredList(dl)
-        def _set_failed(why):
-            log.msg("BuildSlave.sendBuilderList (%s) failed" % self)
-            log.err(why)
-            # TODO: hang up on them?, without setBuilderList we can't use
-            # them
-        d.addCallbacks(_sent, _set_failed)
-        return d
-
-    def perspective_keepalive(self):
-        pass
-
-    def addSlaveBuilder(self, sb):
-        log.msg("%s adding %s" % (self, sb))
-        self.slavebuilders.append(sb)
-
-    def removeSlaveBuilder(self, sb):
-        log.msg("%s removing %s" % (self, sb))
-        if sb in self.slavebuilders:
-            self.slavebuilders.remove(sb)
-
-    def canStartBuild(self):
-        """
-        I am called when a build is requested to see if this buildslave
-        can start a build.  This function can be used to limit overall
-        concurrency on the buildslave.
-        """
-        if self.max_builds:
-            active_builders = [sb for sb in self.slavebuilders if sb.isBusy()]
-            if len(active_builders) >= self.max_builds:
-                return False
-        return True
-
diff --git a/tools/buildbot/pylibs/buildbot/changes/__init__.py b/tools/buildbot/pylibs/buildbot/changes/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/tools/buildbot/pylibs/buildbot/changes/base.py b/tools/buildbot/pylibs/buildbot/changes/base.py
deleted file mode 100644
index 72c45bf..0000000
--- a/tools/buildbot/pylibs/buildbot/changes/base.py
+++ /dev/null
@@ -1,10 +0,0 @@
-
-from zope.interface import implements
-from twisted.application import service
-
-from buildbot.interfaces import IChangeSource
-from buildbot import util
-
-class ChangeSource(service.Service, util.ComparableMixin):
-    implements(IChangeSource)
-
diff --git a/tools/buildbot/pylibs/buildbot/changes/bonsaipoller.py b/tools/buildbot/pylibs/buildbot/changes/bonsaipoller.py
deleted file mode 100644
index 2e319bb..0000000
--- a/tools/buildbot/pylibs/buildbot/changes/bonsaipoller.py
+++ /dev/null
@@ -1,320 +0,0 @@
-import time
-from xml.dom import minidom
-
-from twisted.python import log, failure
-from twisted.internet import reactor
-from twisted.internet.task import LoopingCall
-from twisted.web.client import getPage
-
-from buildbot.changes import base, changes
-
-class InvalidResultError(Exception):
-    def __init__(self, value="InvalidResultError"):
-        self.value = value
-    def __str__(self):
-        return repr(self.value)
-
-class EmptyResult(Exception):
-    pass
-
-class NoMoreCiNodes(Exception):
-    pass
-
-class NoMoreFileNodes(Exception):
-    pass
-
-class BonsaiResult:
-    """I hold a list of CiNodes"""
-    def __init__(self, nodes=[]):
-        self.nodes = nodes
-
-    def __cmp__(self, other):
-        if len(self.nodes) != len(other.nodes):
-            return False
-        for i in range(len(self.nodes)):
-            if self.nodes[i].log != other.nodes[i].log \
-              or self.nodes[i].who != other.nodes[i].who \
-              or self.nodes[i].date != other.nodes[i].date \
-              or len(self.nodes[i].files) != len(other.nodes[i].files):
-                return -1
-
-	        for j in range(len(self.nodes[i].files)):
-	            if self.nodes[i].files[j].revision \
-	              != other.nodes[i].files[j].revision \
-	              or self.nodes[i].files[j].filename \
-	              != other.nodes[i].files[j].filename:
-	                return -1
-
-        return 0
-
-class CiNode:
-    """I hold information baout one  node, including a list of files"""
-    def __init__(self, log="", who="", date=0, files=[]):
-        self.log = log
-        self.who = who
-        self.date = date
-        self.files = files
-
-class FileNode:
-    """I hold information about one  node"""
-    def __init__(self, revision="", filename=""):
-        self.revision = revision
-        self.filename = filename
-
-class BonsaiParser:
-    """I parse the XML result from a bonsai cvsquery."""
-
-    def __init__(self, data):
-        try:
-        # this is a fix for non-ascii characters
-        # because bonsai does not give us an encoding to work with
-        # it impossible to be 100% sure what to decode it as but latin1 covers
-        # the broadest base
-            data = data.decode("latin1")
-            data = data.encode("ascii", "replace")
-            self.dom = minidom.parseString(data)
-            log.msg(data)
-        except:
-            raise InvalidResultError("Malformed XML in result")
-
-        self.ciNodes = self.dom.getElementsByTagName("ci")
-        self.currentCiNode = None # filled in by _nextCiNode()
-        self.fileNodes = None # filled in by _nextCiNode()
-        self.currentFileNode = None # filled in by _nextFileNode()
-        self.bonsaiResult = self._parseData()
-
-    def getData(self):
-        return self.bonsaiResult
-
-    def _parseData(self):
-        """Returns data from a Bonsai cvsquery in a BonsaiResult object"""
-        nodes = []
-        try:
-            while self._nextCiNode():
-                files = []
-                try:
-                    while self._nextFileNode():
-                        files.append(FileNode(self._getRevision(),
-                                              self._getFilename()))
-                except NoMoreFileNodes:
-                    pass
-                except InvalidResultError:
-                    raise
-                cinode = CiNode(self._getLog(), self._getWho(),
-                                self._getDate(), files)
-                # hack around bonsai xml output bug for empty check-in comments
-                if not cinode.log and nodes and \
-                        not nodes[-1].log and \
-                        cinode.who == nodes[-1].who and \
-                        cinode.date == nodes[-1].date:
-                    nodes[-1].files += cinode.files
-                else:
-                    nodes.append(cinode)
-
-        except NoMoreCiNodes:
-            pass
-        except InvalidResultError, EmptyResult:
-            raise
-
-        return BonsaiResult(nodes)
-
-
-    def _nextCiNode(self):
-        """Iterates to the next  node and fills self.fileNodes with
-           child  nodes"""
-        try:
-            self.currentCiNode = self.ciNodes.pop(0)
-            if len(self.currentCiNode.getElementsByTagName("files")) > 1:
-                raise InvalidResultError("Multiple  for one ")
-
-            self.fileNodes = self.currentCiNode.getElementsByTagName("f")
-        except IndexError:
-            # if there was zero  nodes in the result
-            if not self.currentCiNode:
-                raise EmptyResult
-            else:
-                raise NoMoreCiNodes
-
-        return True
-
-    def _nextFileNode(self):
-        """Iterates to the next  node"""
-        try:
-            self.currentFileNode = self.fileNodes.pop(0)
-        except IndexError:
-            raise NoMoreFileNodes
-
-        return True
-
-    def _getLog(self):
-        """Returns the log of the current  node"""
-        logs = self.currentCiNode.getElementsByTagName("log")
-        if len(logs) < 1:
-            raise InvalidResultError("No log present")
-        elif len(logs) > 1:
-            raise InvalidResultError("Multiple logs present")
-
-        # catch empty check-in comments
-        if logs[0].firstChild:
-            return logs[0].firstChild.data
-        return ''
-
-    def _getWho(self):
-        """Returns the e-mail address of the commiter"""
-        # convert unicode string to regular string
-        return str(self.currentCiNode.getAttribute("who"))
-
-    def _getDate(self):
-        """Returns the date (unix time) of the commit"""
-        # convert unicode number to regular one
-        try:
-            commitDate = int(self.currentCiNode.getAttribute("date"))
-        except ValueError:
-            raise InvalidResultError
-
-        return commitDate
-
-    def _getFilename(self):
-        """Returns the filename of the current  node"""
-        try:
-            filename = self.currentFileNode.firstChild.data
-        except AttributeError:
-            raise InvalidResultError("Missing filename")
-
-        return filename
-
-    def _getRevision(self):
-        return self.currentFileNode.getAttribute("rev")
-
-
-class BonsaiPoller(base.ChangeSource):
-    """This source will poll a bonsai server for changes and submit
-    them to the change master."""
-
-    compare_attrs = ["bonsaiURL", "pollInterval", "tree",
-                     "module", "branch", "cvsroot"]
-
-    parent = None # filled in when we're added
-    loop = None
-    volatile = ['loop']
-    working = False
-
-    def __init__(self, bonsaiURL, module, branch, tree="default",
-                 cvsroot="/cvsroot", pollInterval=30):
-        """
-        @type   bonsaiURL:      string
-        @param  bonsaiURL:      The base URL of the Bonsai server
-                                (ie. http://bonsai.mozilla.org)
-        @type   module:         string
-        @param  module:         The module to look for changes in. Commonly
-                                this is 'all'
-        @type   branch:         string
-        @param  branch:         The branch to look for changes in. This must
-                                match the
-                                'branch' option for the Scheduler.
-        @type   tree:           string
-        @param  tree:           The tree to look for changes in. Commonly this
-                                is 'all'
-        @type   cvsroot:        string
-        @param  cvsroot:        The cvsroot of the repository. Usually this is
-                                '/cvsroot'
-        @type   pollInterval:   int
-        @param  pollInterval:   The time (in seconds) between queries for
-                                changes
-        """
-
-        self.bonsaiURL = bonsaiURL
-        self.module = module
-        self.branch = branch
-        self.tree = tree
-        self.cvsroot = cvsroot
-        self.pollInterval = pollInterval
-        self.lastChange = time.time()
-        self.lastPoll = time.time()
-
-    def startService(self):
-        self.loop = LoopingCall(self.poll)
-        base.ChangeSource.startService(self)
-
-        reactor.callLater(0, self.loop.start, self.pollInterval)
-
-    def stopService(self):
-        self.loop.stop()
-        return base.ChangeSource.stopService(self)
-
-    def describe(self):
-        str = ""
-        str += "Getting changes from the Bonsai service running at %s " \
-                % self.bonsaiURL
-        str += "
Using tree: %s, branch: %s, and module: %s" % (self.tree, \ - self.branch, self.module) - return str - - def poll(self): - if self.working: - log.msg("Not polling Bonsai because last poll is still working") - else: - self.working = True - d = self._get_changes() - d.addCallback(self._process_changes) - d.addCallbacks(self._finished_ok, self._finished_failure) - return - - def _finished_ok(self, res): - assert self.working - self.working = False - - # check for failure -- this is probably never hit but the twisted docs - # are not clear enough to be sure. it is being kept "just in case" - if isinstance(res, failure.Failure): - log.msg("Bonsai poll failed: %s" % res) - return res - - def _finished_failure(self, res): - log.msg("Bonsai poll failed: %s" % res) - assert self.working - self.working = False - return None # eat the failure - - def _make_url(self): - args = ["treeid=%s" % self.tree, "module=%s" % self.module, - "branch=%s" % self.branch, "branchtype=match", - "sortby=Date", "date=explicit", - "mindate=%d" % self.lastChange, - "maxdate=%d" % int(time.time()), - "cvsroot=%s" % self.cvsroot, "xml=1"] - # build the bonsai URL - url = self.bonsaiURL - url += "/cvsquery.cgi?" - url += "&".join(args) - - return url - - def _get_changes(self): - url = self._make_url() - log.msg("Polling Bonsai tree at %s" % url) - - self.lastPoll = time.time() - # get the page, in XML format - return getPage(url, timeout=self.pollInterval) - - def _process_changes(self, query): - try: - bp = BonsaiParser(query) - result = bp.getData() - except InvalidResultError, e: - log.msg("Could not process Bonsai query: " + e.value) - return - except EmptyResult: - return - - for cinode in result.nodes: - files = [file.filename + ' (revision '+file.revision+')' - for file in cinode.files] - c = changes.Change(who = cinode.who, - files = files, - comments = cinode.log, - when = cinode.date, - branch = self.branch) - self.parent.addChange(c) - self.lastChange = self.lastPoll diff --git a/tools/buildbot/pylibs/buildbot/changes/changes.py b/tools/buildbot/pylibs/buildbot/changes/changes.py deleted file mode 100644 index 7a52e89..0000000 --- a/tools/buildbot/pylibs/buildbot/changes/changes.py +++ /dev/null @@ -1,277 +0,0 @@ - -import sys, os, time -from cPickle import dump - -from zope.interface import implements -from twisted.python import log -from twisted.internet import defer -from twisted.application import service -from twisted.web import html - -from buildbot import interfaces, util - -html_tmpl = """ -

Changed by: %(who)s
-Changed at: %(at)s
-%(branch)s -%(revision)s -
- -Changed files: -%(files)s - -Comments: -%(comments)s -

-""" - -class Change: - """I represent a single change to the source tree. This may involve - several files, but they are all changed by the same person, and there is - a change comment for the group as a whole. - - If the version control system supports sequential repository- (or - branch-) wide change numbers (like SVN, P4, and Arch), then revision= - should be set to that number. The highest such number will be used at - checkout time to get the correct set of files. - - If it does not (like CVS), when= should be set to the timestamp (seconds - since epoch, as returned by time.time()) when the change was made. when= - will be filled in for you (to the current time) if you omit it, which is - suitable for ChangeSources which have no way of getting more accurate - timestamps. - - Changes should be submitted to ChangeMaster.addChange() in - chronologically increasing order. Out-of-order changes will probably - cause the html.Waterfall display to be corrupted.""" - - implements(interfaces.IStatusEvent) - - number = None - - links = [] - branch = None - revision = None # used to create a source-stamp - - def __init__(self, who, files, comments, isdir=0, links=[], - revision=None, when=None, branch=None): - self.who = who - self.files = files - self.comments = comments - self.isdir = isdir - self.links = links - self.revision = revision - if when is None: - when = util.now() - self.when = when - self.branch = branch - - def asText(self): - data = "" - data += self.getFileContents() - data += "At: %s\n" % self.getTime() - data += "Changed By: %s\n" % self.who - data += "Comments: %s\n\n" % self.comments - return data - - def asHTML(self): - links = [] - for file in self.files: - link = filter(lambda s: s.find(file) != -1, self.links) - if len(link) == 1: - # could get confused - links.append('%s' % (link[0], file)) - else: - links.append('%s' % file) - revision = "" - if self.revision: - revision = "Revision: %s
\n" % self.revision - branch = "" - if self.branch: - branch = "Branch: %s
\n" % self.branch - - kwargs = { 'who' : html.escape(self.who), - 'at' : self.getTime(), - 'files' : html.UL(links) + '\n', - 'revision': revision, - 'branch' : branch, - 'comments': html.PRE(self.comments) } - return html_tmpl % kwargs - - def get_HTML_box(self, url): - """Return the contents of a TD cell for the waterfall display. - - @param url: the URL that points to an HTML page that will render - using our asHTML method. The Change is free to use this or ignore it - as it pleases. - - @return: the HTML that will be put inside the table cell. Typically - this is just a single href named after the author of the change and - pointing at the passed-in 'url'. - """ - who = self.getShortAuthor() - return '%s' % (url, - html.escape(self.comments), - html.escape(who)) - - def getShortAuthor(self): - return self.who - - def getTime(self): - if not self.when: - return "?" - return time.strftime("%a %d %b %Y %H:%M:%S", - time.localtime(self.when)) - - def getTimes(self): - return (self.when, None) - - def getText(self): - return [html.escape(self.who)] - def getColor(self): - return "white" - def getLogs(self): - return {} - - def getFileContents(self): - data = "" - if len(self.files) == 1: - if self.isdir: - data += "Directory: %s\n" % self.files[0] - else: - data += "File: %s\n" % self.files[0] - else: - data += "Files:\n" - for f in self.files: - data += " %s\n" % f - return data - -class ChangeMaster(service.MultiService): - - """This is the master-side service which receives file change - notifications from CVS. It keeps a log of these changes, enough to - provide for the HTML waterfall display, and to tell - temporarily-disconnected bots what they missed while they were - offline. - - Change notifications come from two different kinds of sources. The first - is a PB service (servicename='changemaster', perspectivename='change'), - which provides a remote method called 'addChange', which should be - called with a dict that has keys 'filename' and 'comments'. - - The second is a list of objects derived from the ChangeSource class. - These are added with .addSource(), which also sets the .changemaster - attribute in the source to point at the ChangeMaster. When the - application begins, these will be started with .start() . At shutdown - time, they will be terminated with .stop() . They must be persistable. - They are expected to call self.changemaster.addChange() with Change - objects. - - There are several different variants of the second type of source: - - - L{buildbot.changes.mail.MaildirSource} watches a maildir for CVS - commit mail. It uses DNotify if available, or polls every 10 - seconds if not. It parses incoming mail to determine what files - were changed. - - - L{buildbot.changes.freshcvs.FreshCVSSource} makes a PB - connection to the CVSToys 'freshcvs' daemon and relays any - changes it announces. - - """ - - implements(interfaces.IEventSource) - - debug = False - # todo: use Maildir class to watch for changes arriving by mail - - def __init__(self): - service.MultiService.__init__(self) - self.changes = [] - # self.basedir must be filled in by the parent - self.nextNumber = 1 - - def addSource(self, source): - assert interfaces.IChangeSource.providedBy(source) - assert service.IService.providedBy(source) - if self.debug: - print "ChangeMaster.addSource", source - source.setServiceParent(self) - - def removeSource(self, source): - assert source in self - if self.debug: - print "ChangeMaster.removeSource", source, source.parent - d = defer.maybeDeferred(source.disownServiceParent) - return d - - def addChange(self, change): - """Deliver a file change event. The event should be a Change object. - This method will timestamp the object as it is received.""" - log.msg("adding change, who %s, %d files, rev=%s, branch=%s, " - "comments %s" % (change.who, len(change.files), - change.revision, change.branch, - change.comments)) - change.number = self.nextNumber - self.nextNumber += 1 - self.changes.append(change) - self.parent.addChange(change) - # TODO: call pruneChanges after a while - - def pruneChanges(self): - self.changes = self.changes[-100:] # or something - - def eventGenerator(self, branches=[]): - for i in range(len(self.changes)-1, -1, -1): - c = self.changes[i] - if not branches or c.branch in branches: - yield c - - def getChangeNumbered(self, num): - if not self.changes: - return None - first = self.changes[0].number - if first + len(self.changes)-1 != self.changes[-1].number: - log.msg(self, - "lost a change somewhere: [0] is %d, [%d] is %d" % \ - (self.changes[0].number, - len(self.changes) - 1, - self.changes[-1].number)) - for c in self.changes: - log.msg("c[%d]: " % c.number, c) - return None - offset = num - first - log.msg(self, "offset", offset) - return self.changes[offset] - - def __getstate__(self): - d = service.MultiService.__getstate__(self) - del d['parent'] - del d['services'] # lose all children - del d['namedServices'] - return d - - def __setstate__(self, d): - self.__dict__ = d - # self.basedir must be set by the parent - self.services = [] # they'll be repopulated by readConfig - self.namedServices = {} - - - def saveYourself(self): - filename = os.path.join(self.basedir, "changes.pck") - tmpfilename = filename + ".tmp" - try: - dump(self, open(tmpfilename, "wb")) - if sys.platform == 'win32': - # windows cannot rename a file on top of an existing one - if os.path.exists(filename): - os.unlink(filename) - os.rename(tmpfilename, filename) - except Exception, e: - log.msg("unable to save changes") - log.err() - - def stopService(self): - self.saveYourself() - return service.MultiService.stopService(self) diff --git a/tools/buildbot/pylibs/buildbot/changes/dnotify.py b/tools/buildbot/pylibs/buildbot/changes/dnotify.py deleted file mode 100644 index 0674248..0000000 --- a/tools/buildbot/pylibs/buildbot/changes/dnotify.py +++ /dev/null @@ -1,100 +0,0 @@ - -import fcntl, signal, os - -class DNotify_Handler: - def __init__(self): - self.watchers = {} - self.installed = 0 - def install(self): - if self.installed: - return - signal.signal(signal.SIGIO, self.fire) - self.installed = 1 - def uninstall(self): - if not self.installed: - return - signal.signal(signal.SIGIO, signal.SIG_DFL) - self.installed = 0 - def add(self, watcher): - self.watchers[watcher.fd] = watcher - self.install() - def remove(self, watcher): - if self.watchers.has_key(watcher.fd): - del(self.watchers[watcher.fd]) - if not self.watchers: - self.uninstall() - def fire(self, signum, frame): - # this is the signal handler - # without siginfo_t, we must fire them all - for watcher in self.watchers.values(): - watcher.callback() - -class DNotify: - DN_ACCESS = fcntl.DN_ACCESS # a file in the directory was read - DN_MODIFY = fcntl.DN_MODIFY # a file was modified (write,truncate) - DN_CREATE = fcntl.DN_CREATE # a file was created - DN_DELETE = fcntl.DN_DELETE # a file was unlinked - DN_RENAME = fcntl.DN_RENAME # a file was renamed - DN_ATTRIB = fcntl.DN_ATTRIB # a file had attributes changed (chmod,chown) - - handler = [None] - - def __init__(self, dirname, callback=None, - flags=[DN_MODIFY,DN_CREATE,DN_DELETE,DN_RENAME]): - - """This object watches a directory for changes. The .callback - attribute should be set to a function to be run every time something - happens to it. Be aware that it will be called more times than you - expect.""" - - if callback: - self.callback = callback - else: - self.callback = self.fire - self.dirname = dirname - self.flags = reduce(lambda x, y: x | y, flags) | fcntl.DN_MULTISHOT - self.fd = os.open(dirname, os.O_RDONLY) - # ideally we would move the notification to something like SIGRTMIN, - # (to free up SIGIO) and use sigaction to have the signal handler - # receive a structure with the fd number. But python doesn't offer - # either. - if not self.handler[0]: - self.handler[0] = DNotify_Handler() - self.handler[0].add(self) - fcntl.fcntl(self.fd, fcntl.F_NOTIFY, self.flags) - def remove(self): - self.handler[0].remove(self) - os.close(self.fd) - def fire(self): - print self.dirname, "changed!" - -def test_dnotify1(): - d = DNotify(".") - while 1: - signal.pause() - -def test_dnotify2(): - # create ./foo/, create/delete files in ./ and ./foo/ while this is - # running. Notice how both notifiers are fired when anything changes; - # this is an unfortunate side-effect of the lack of extended sigaction - # support in Python. - count = [0] - d1 = DNotify(".") - def fire1(count=count, d1=d1): - print "./ changed!", count[0] - count[0] += 1 - if count[0] > 5: - d1.remove() - del(d1) - # change the callback, since we can't define it until after we have the - # dnotify object. Hmm, unless we give the dnotify to the callback. - d1.callback = fire1 - def fire2(): print "foo/ changed!" - d2 = DNotify("foo", fire2) - while 1: - signal.pause() - - -if __name__ == '__main__': - test_dnotify2() - diff --git a/tools/buildbot/pylibs/buildbot/changes/freshcvs.py b/tools/buildbot/pylibs/buildbot/changes/freshcvs.py deleted file mode 100644 index 53a2ac4..0000000 --- a/tools/buildbot/pylibs/buildbot/changes/freshcvs.py +++ /dev/null @@ -1,144 +0,0 @@ - -import os.path - -from zope.interface import implements -from twisted.cred import credentials -from twisted.spread import pb -from twisted.application.internet import TCPClient -from twisted.python import log - -import cvstoys.common # to make sure VersionedPatch gets registered - -from buildbot.interfaces import IChangeSource -from buildbot.pbutil import ReconnectingPBClientFactory -from buildbot.changes.changes import Change -from buildbot import util - -class FreshCVSListener(pb.Referenceable): - def remote_notify(self, root, files, message, user): - try: - self.source.notify(root, files, message, user) - except Exception, e: - print "notify failed" - log.err() - - def remote_goodbye(self, message): - pass - -class FreshCVSConnectionFactory(ReconnectingPBClientFactory): - - def gotPerspective(self, perspective): - log.msg("connected to FreshCVS daemon") - ReconnectingPBClientFactory.gotPerspective(self, perspective) - self.source.connected = True - # TODO: freshcvs-1.0.10 doesn't handle setFilter correctly, it will - # be fixed in the upcoming 1.0.11 . I haven't been able to test it - # to make sure the failure mode is survivable, so I'll just leave - # this out for now. - return - if self.source.prefix is not None: - pathfilter = "^%s" % self.source.prefix - d = perspective.callRemote("setFilter", - None, pathfilter, None) - # ignore failures, setFilter didn't work in 1.0.10 and this is - # just an optimization anyway - d.addErrback(lambda f: None) - - def clientConnectionLost(self, connector, reason): - ReconnectingPBClientFactory.clientConnectionLost(self, connector, - reason) - self.source.connected = False - -class FreshCVSSourceNewcred(TCPClient, util.ComparableMixin): - """This source will connect to a FreshCVS server associated with one or - more CVS repositories. Each time a change is committed to a repository, - the server will send us a message describing the change. This message is - used to build a Change object, which is then submitted to the - ChangeMaster. - - This class handles freshcvs daemons which use newcred. CVSToys-1.0.9 - does not, later versions might. - """ - - implements(IChangeSource) - compare_attrs = ["host", "port", "username", "password", "prefix"] - - changemaster = None # filled in when we're added - connected = False - - def __init__(self, host, port, user, passwd, prefix=None): - self.host = host - self.port = port - self.username = user - self.password = passwd - if prefix is not None and not prefix.endswith("/"): - log.msg("WARNING: prefix '%s' should probably end with a slash" \ - % prefix) - self.prefix = prefix - self.listener = l = FreshCVSListener() - l.source = self - self.factory = f = FreshCVSConnectionFactory() - f.source = self - self.creds = credentials.UsernamePassword(user, passwd) - f.startLogin(self.creds, client=l) - TCPClient.__init__(self, host, port, f) - - def __repr__(self): - return "" % \ - ((self.host, self.port), self.prefix) - - def describe(self): - online = "" - if not self.connected: - online = " [OFFLINE]" - return "freshcvs %s:%s%s" % (self.host, self.port, online) - - def notify(self, root, files, message, user): - pathnames = [] - isdir = 0 - for f in files: - if not isinstance(f, (cvstoys.common.VersionedPatch, - cvstoys.common.Directory)): - continue - pathname, filename = f.pathname, f.filename - #r1, r2 = getattr(f, 'r1', None), getattr(f, 'r2', None) - if isinstance(f, cvstoys.common.Directory): - isdir = 1 - path = os.path.join(pathname, filename) - log.msg("FreshCVS notify '%s'" % path) - if self.prefix: - if path.startswith(self.prefix): - path = path[len(self.prefix):] - else: - continue - pathnames.append(path) - if pathnames: - # now() is close enough: FreshCVS *is* realtime, after all - when=util.now() - c = Change(user, pathnames, message, isdir, when=when) - self.parent.addChange(c) - -class FreshCVSSourceOldcred(FreshCVSSourceNewcred): - """This is for older freshcvs daemons (from CVSToys-1.0.9 and earlier). - """ - - def __init__(self, host, port, user, passwd, - serviceName="cvstoys.notify", prefix=None): - self.host = host - self.port = port - self.prefix = prefix - self.listener = l = FreshCVSListener() - l.source = self - self.factory = f = FreshCVSConnectionFactory() - f.source = self - f.startGettingPerspective(user, passwd, serviceName, client=l) - TCPClient.__init__(self, host, port, f) - - def __repr__(self): - return "" % \ - ((self.host, self.port), self.prefix) - -# this is suitable for CVSToys-1.0.10 and later. If you run CVSToys-1.0.9 or -# earlier, use FreshCVSSourceOldcred instead. -FreshCVSSource = FreshCVSSourceNewcred - diff --git a/tools/buildbot/pylibs/buildbot/changes/hgbuildbot.py b/tools/buildbot/pylibs/buildbot/changes/hgbuildbot.py deleted file mode 100644 index ecfb763..0000000 --- a/tools/buildbot/pylibs/buildbot/changes/hgbuildbot.py +++ /dev/null @@ -1,107 +0,0 @@ -# hgbuildbot.py - mercurial hooks for buildbot -# -# Copyright 2007 Frederic Leroy -# -# This software may be used and distributed according to the terms -# of the GNU General Public License, incorporated herein by reference. - -# hook extension to send change notifications to buildbot when a changeset is -# brought into the repository from elsewhere. -# -# default mode is to use mercurial branch -# -# to use, configure hgbuildbot in .hg/hgrc like this: -# -# [hooks] -# changegroup = python:buildbot.changes.hgbuildbot.hook -# -# [hgbuildbot] -# # config items go in here -# -# config items: -# -# REQUIRED: -# master = host:port # host to send buildbot changes -# -# OPTIONAL: -# branchtype = inrepo|dirname # dirname: branch = name of directory -# # containing the repository -# # -# # inrepo: branch = mercurial branch -# -# branch = branchname # if set, branch is always branchname - -import os - -from mercurial.i18n import gettext as _ -from mercurial.node import bin, hex - -# mercurial's on-demand-importing hacks interfere with the: -#from zope.interface import Interface -# that Twisted needs to do, so disable it. -try: - from mercurial import demandimport - demandimport.disable() -except ImportError: - pass - -from buildbot.clients import sendchange -from twisted.internet import defer, reactor - - -def hook(ui, repo, hooktype, node=None, source=None, **kwargs): - # read config parameters - master = ui.config('hgbuildbot', 'master') - if master: - branchtype = ui.config('hgbuildbot', 'branchtype') - branch = ui.config('hgbuildbot', 'branch') - else: - ui.write("* You must add a [hgbuildbot] section to .hg/hgrc in " - "order to use buildbot hook\n") - return - - if branch is None: - if branchtype is not None: - if branchtype == 'dirname': - branch = os.path.basename(os.getcwd()) - if branchtype == 'inrepo': - branch=repo.workingctx().branch() - - if hooktype == 'changegroup': - s = sendchange.Sender(master, None) - d = defer.Deferred() - reactor.callLater(0, d.callback, None) - # process changesets - def _send(res, c): - ui.status("rev %s sent\n" % c['revision']) - return s.send(c['branch'], c['revision'], c['comments'], - c['files'], c['username']) - - node=bin(node) - start = repo.changelog.rev(node) - end = repo.changelog.count() - for rev in xrange(start, end): - # send changeset - n = repo.changelog.node(rev) - changeset=repo.changelog.extract(repo.changelog.revision(n)) - change = { - 'master': master, - # note: this is more likely to be a full email address, which - # would make the left-hand "Changes" column kind of wide. The - # buildmaster should probably be improved to display an - # abbreviation of the username. - 'username': changeset[1], - 'revision': hex(n), - 'comments': changeset[4], - 'files': changeset[3], - 'branch': branch - } - d.addCallback(_send, change) - - d.addCallbacks(s.printSuccess, s.printFailure) - d.addBoth(s.stop) - s.run() - else: - ui.status(_('hgbuildbot: hook %s not supported\n') % hooktype) - return - diff --git a/tools/buildbot/pylibs/buildbot/changes/mail.py b/tools/buildbot/pylibs/buildbot/changes/mail.py deleted file mode 100644 index 7d86d47..0000000 --- a/tools/buildbot/pylibs/buildbot/changes/mail.py +++ /dev/null @@ -1,458 +0,0 @@ -# -*- test-case-name: buildbot.test.test_mailparse -*- - -""" -Parse various kinds of 'CVS notify' email. -""" -import os, re -from email import message_from_file -from email.Utils import parseaddr -from email.Iterators import body_line_iterator - -from zope.interface import implements -from twisted.python import log -from buildbot import util -from buildbot.interfaces import IChangeSource -from buildbot.changes import changes -from buildbot.changes.maildir import MaildirService - -class MaildirSource(MaildirService, util.ComparableMixin): - """This source will watch a maildir that is subscribed to a FreshCVS - change-announcement mailing list. - """ - implements(IChangeSource) - - compare_attrs = ["basedir", "pollinterval"] - name = None - - def __init__(self, maildir, prefix=None): - MaildirService.__init__(self, maildir) - self.prefix = prefix - if prefix and not prefix.endswith("/"): - log.msg("%s: you probably want your prefix=('%s') to end with " - "a slash") - - def describe(self): - return "%s mailing list in maildir %s" % (self.name, self.basedir) - - def messageReceived(self, filename): - path = os.path.join(self.basedir, "new", filename) - change = self.parse_file(open(path, "r"), self.prefix) - if change: - self.parent.addChange(change) - os.rename(os.path.join(self.basedir, "new", filename), - os.path.join(self.basedir, "cur", filename)) - - def parse_file(self, fd, prefix=None): - m = message_from_file(fd) - return self.parse(m, prefix) - -class FCMaildirSource(MaildirSource): - name = "FreshCVS" - - def parse(self, m, prefix=None): - """Parse mail sent by FreshCVS""" - - # FreshCVS sets From: to "user CVS ", but the <> part may be - # modified by the MTA (to include a local domain) - name, addr = parseaddr(m["from"]) - if not name: - return None # no From means this message isn't from FreshCVS - cvs = name.find(" CVS") - if cvs == -1: - return None # this message isn't from FreshCVS - who = name[:cvs] - - # we take the time of receipt as the time of checkin. Not correct, - # but it avoids the out-of-order-changes issue. See the comment in - # parseSyncmail about using the 'Date:' header - when = util.now() - - files = [] - comments = "" - isdir = 0 - lines = list(body_line_iterator(m)) - while lines: - line = lines.pop(0) - if line == "Modified files:\n": - break - while lines: - line = lines.pop(0) - if line == "\n": - break - line = line.rstrip("\n") - linebits = line.split(None, 1) - file = linebits[0] - if prefix: - # insist that the file start with the prefix: FreshCVS sends - # changes we don't care about too - if file.startswith(prefix): - file = file[len(prefix):] - else: - continue - if len(linebits) == 1: - isdir = 1 - elif linebits[1] == "0 0": - isdir = 1 - files.append(file) - while lines: - line = lines.pop(0) - if line == "Log message:\n": - break - # message is terminated by "ViewCVS links:" or "Index:..." (patch) - while lines: - line = lines.pop(0) - if line == "ViewCVS links:\n": - break - if line.find("Index: ") == 0: - break - comments += line - comments = comments.rstrip() + "\n" - - if not files: - return None - - change = changes.Change(who, files, comments, isdir, when=when) - - return change - -class SyncmailMaildirSource(MaildirSource): - name = "Syncmail" - - def parse(self, m, prefix=None): - """Parse messages sent by the 'syncmail' program, as suggested by the - sourceforge.net CVS Admin documentation. Syncmail is maintained at - syncmail.sf.net . - """ - # pretty much the same as freshcvs mail, not surprising since CVS is - # the one creating most of the text - - # The mail is sent from the person doing the checkin. Assume that the - # local username is enough to identify them (this assumes a one-server - # cvs-over-rsh environment rather than the server-dirs-shared-over-NFS - # model) - name, addr = parseaddr(m["from"]) - if not addr: - return None # no From means this message isn't from FreshCVS - at = addr.find("@") - if at == -1: - who = addr # might still be useful - else: - who = addr[:at] - - # we take the time of receipt as the time of checkin. Not correct (it - # depends upon the email latency), but it avoids the - # out-of-order-changes issue. Also syncmail doesn't give us anything - # better to work with, unless you count pulling the v1-vs-v2 - # timestamp out of the diffs, which would be ugly. TODO: Pulling the - # 'Date:' header from the mail is a possibility, and - # email.Utils.parsedate_tz may be useful. It should be configurable, - # however, because there are a lot of broken clocks out there. - when = util.now() - - subject = m["subject"] - # syncmail puts the repository-relative directory in the subject: - # mprefix + "%(dir)s %(file)s,%(oldversion)s,%(newversion)s", where - # 'mprefix' is something that could be added by a mailing list - # manager. - # this is the only reasonable way to determine the directory name - space = subject.find(" ") - if space != -1: - directory = subject[:space] - else: - directory = subject - - files = [] - comments = "" - isdir = 0 - branch = None - - lines = list(body_line_iterator(m)) - while lines: - line = lines.pop(0) - - if (line == "Modified Files:\n" or - line == "Added Files:\n" or - line == "Removed Files:\n"): - break - - while lines: - line = lines.pop(0) - if line == "\n": - break - if line == "Log Message:\n": - lines.insert(0, line) - break - line = line.lstrip() - line = line.rstrip() - # note: syncmail will send one email per directory involved in a - # commit, with multiple files if they were in the same directory. - # Unlike freshCVS, it makes no attempt to collect all related - # commits into a single message. - - # note: syncmail will report a Tag underneath the ... Files: line - # e.g.: Tag: BRANCH-DEVEL - - if line.startswith('Tag:'): - branch = line.split(' ')[-1].rstrip() - continue - - thesefiles = line.split(" ") - for f in thesefiles: - f = directory + "/" + f - if prefix: - # insist that the file start with the prefix: we may get - # changes we don't care about too - if f.startswith(prefix): - f = f[len(prefix):] - else: - continue - break - # TODO: figure out how new directories are described, set - # .isdir - files.append(f) - - if not files: - return None - - while lines: - line = lines.pop(0) - if line == "Log Message:\n": - break - # message is terminated by "Index:..." (patch) or "--- NEW FILE.." - # or "--- filename DELETED ---". Sigh. - while lines: - line = lines.pop(0) - if line.find("Index: ") == 0: - break - if re.search(r"^--- NEW FILE", line): - break - if re.search(r" DELETED ---$", line): - break - comments += line - comments = comments.rstrip() + "\n" - - change = changes.Change(who, files, comments, isdir, when=when, - branch=branch) - - return change - -# Bonsai mail parser by Stephen Davis. -# -# This handles changes for CVS repositories that are watched by Bonsai -# (http://www.mozilla.org/bonsai.html) - -# A Bonsai-formatted email message looks like: -# -# C|1071099907|stephend|/cvs|Sources/Scripts/buildbot|bonsai.py|1.2|||18|7 -# A|1071099907|stephend|/cvs|Sources/Scripts/buildbot|master.cfg|1.1|||18|7 -# R|1071099907|stephend|/cvs|Sources/Scripts/buildbot|BuildMaster.py||| -# LOGCOMMENT -# Updated bonsai parser and switched master config to buildbot-0.4.1 style. -# -# :ENDLOGCOMMENT -# -# In the first example line, stephend is the user, /cvs the repository, -# buildbot the directory, bonsai.py the file, 1.2 the revision, no sticky -# and branch, 18 lines added and 7 removed. All of these fields might not be -# present (during "removes" for example). -# -# There may be multiple "control" lines or even none (imports, directory -# additions) but there is one email per directory. We only care about actual -# changes since it is presumed directory additions don't actually affect the -# build. At least one file should need to change (the makefile, say) to -# actually make a new directory part of the build process. That's my story -# and I'm sticking to it. - -class BonsaiMaildirSource(MaildirSource): - name = "Bonsai" - - def parse(self, m, prefix=None): - """Parse mail sent by the Bonsai cvs loginfo script.""" - - # we don't care who the email came from b/c the cvs user is in the - # msg text - - who = "unknown" - timestamp = None - files = [] - lines = list(body_line_iterator(m)) - - # read the control lines (what/who/where/file/etc.) - while lines: - line = lines.pop(0) - if line == "LOGCOMMENT\n": - break; - line = line.rstrip("\n") - - # we'd like to do the following but it won't work if the number of - # items doesn't match so... - # what, timestamp, user, repo, module, file = line.split( '|' ) - items = line.split('|') - if len(items) < 6: - # not a valid line, assume this isn't a bonsai message - return None - - try: - # just grab the bottom-most timestamp, they're probably all the - # same. TODO: I'm assuming this is relative to the epoch, but - # this needs testing. - timestamp = int(items[1]) - except ValueError: - pass - - user = items[2] - if user: - who = user - - module = items[4] - file = items[5] - if module and file: - path = "%s/%s" % (module, file) - files.append(path) - sticky = items[7] - branch = items[8] - - # if no files changed, return nothing - if not files: - return None - - # read the comments - comments = "" - while lines: - line = lines.pop(0) - if line == ":ENDLOGCOMMENT\n": - break - comments += line - comments = comments.rstrip() + "\n" - - # return buildbot Change object - return changes.Change(who, files, comments, when=timestamp, - branch=branch) - -# svn "commit-email.pl" handler. The format is very similar to freshcvs mail; -# here's a sample: - -# From: username [at] apache.org [slightly obfuscated to avoid spam here] -# To: commits [at] spamassassin.apache.org -# Subject: svn commit: r105955 - in spamassassin/trunk: . lib/Mail -# ... -# -# Author: username -# Date: Sat Nov 20 00:17:49 2004 [note: TZ = local tz on server!] -# New Revision: 105955 -# -# Modified: [also Removed: and Added:] -# [filename] -# ... -# Log: -# [log message] -# ... -# -# -# Modified: spamassassin/trunk/lib/Mail/SpamAssassin.pm -# [unified diff] -# -# [end of mail] - -class SVNCommitEmailMaildirSource(MaildirSource): - name = "SVN commit-email.pl" - - def parse(self, m, prefix=None): - """Parse messages sent by the svn 'commit-email.pl' trigger. - """ - - # The mail is sent from the person doing the checkin. Assume that the - # local username is enough to identify them (this assumes a one-server - # cvs-over-rsh environment rather than the server-dirs-shared-over-NFS - # model) - name, addr = parseaddr(m["from"]) - if not addr: - return None # no From means this message isn't from FreshCVS - at = addr.find("@") - if at == -1: - who = addr # might still be useful - else: - who = addr[:at] - - # we take the time of receipt as the time of checkin. Not correct (it - # depends upon the email latency), but it avoids the - # out-of-order-changes issue. Also syncmail doesn't give us anything - # better to work with, unless you count pulling the v1-vs-v2 - # timestamp out of the diffs, which would be ugly. TODO: Pulling the - # 'Date:' header from the mail is a possibility, and - # email.Utils.parsedate_tz may be useful. It should be configurable, - # however, because there are a lot of broken clocks out there. - when = util.now() - - files = [] - comments = "" - isdir = 0 - lines = list(body_line_iterator(m)) - rev = None - while lines: - line = lines.pop(0) - - # "Author: jmason" - match = re.search(r"^Author: (\S+)", line) - if match: - who = match.group(1) - - # "New Revision: 105955" - match = re.search(r"^New Revision: (\d+)", line) - if match: - rev = match.group(1) - - # possible TODO: use "Date: ..." data here instead of time of - # commit message receipt, above. however, this timestamp is - # specified *without* a timezone, in the server's local TZ, so to - # be accurate buildbot would need a config setting to specify the - # source server's expected TZ setting! messy. - - # this stanza ends with the "Log:" - if (line == "Log:\n"): - break - - # commit message is terminated by the file-listing section - while lines: - line = lines.pop(0) - if (line == "Modified:\n" or - line == "Added:\n" or - line == "Removed:\n"): - break - comments += line - comments = comments.rstrip() + "\n" - - while lines: - line = lines.pop(0) - if line == "\n": - break - if line.find("Modified:\n") == 0: - continue # ignore this line - if line.find("Added:\n") == 0: - continue # ignore this line - if line.find("Removed:\n") == 0: - continue # ignore this line - line = line.strip() - - thesefiles = line.split(" ") - for f in thesefiles: - if prefix: - # insist that the file start with the prefix: we may get - # changes we don't care about too - if f.startswith(prefix): - f = f[len(prefix):] - else: - log.msg("ignored file from svn commit: prefix '%s' " - "does not match filename '%s'" % (prefix, f)) - continue - - # TODO: figure out how new directories are described, set - # .isdir - files.append(f) - - if not files: - log.msg("no matching files found, ignoring commit") - return None - - return changes.Change(who, files, comments, when=when, revision=rev) - diff --git a/tools/buildbot/pylibs/buildbot/changes/maildir.py b/tools/buildbot/pylibs/buildbot/changes/maildir.py deleted file mode 100644 index 2e4a706..0000000 --- a/tools/buildbot/pylibs/buildbot/changes/maildir.py +++ /dev/null @@ -1,116 +0,0 @@ - -# This is a class which watches a maildir for new messages. It uses the -# linux dirwatcher API (if available) to look for new files. The -# .messageReceived method is invoked with the filename of the new message, -# relative to the top of the maildir (so it will look like "new/blahblah"). - -import os -from twisted.python import log -from twisted.application import service, internet -from twisted.internet import reactor -dnotify = None -try: - import dnotify -except: - # I'm not actually sure this log message gets recorded - log.msg("unable to import dnotify, so Maildir will use polling instead") - -class NoSuchMaildir(Exception): - pass - -class MaildirService(service.MultiService): - """I watch a maildir for new messages. I should be placed as the service - child of some MultiService instance. When running, I use the linux - dirwatcher API (if available) or poll for new files in the 'new' - subdirectory of my maildir path. When I discover a new message, I invoke - my .messageReceived() method with the short filename of the new message, - so the full name of the new file can be obtained with - os.path.join(maildir, 'new', filename). messageReceived() should be - overridden by a subclass to do something useful. I will not move or - delete the file on my own: the subclass's messageReceived() should - probably do that. - """ - pollinterval = 10 # only used if we don't have DNotify - - def __init__(self, basedir=None): - """Create the Maildir watcher. BASEDIR is the maildir directory (the - one which contains new/ and tmp/) - """ - service.MultiService.__init__(self) - self.basedir = basedir - self.files = [] - self.dnotify = None - - def setBasedir(self, basedir): - # some users of MaildirService (scheduler.Try_Jobdir, in particular) - # don't know their basedir until setServiceParent, since it is - # relative to the buildmaster's basedir. So let them set it late. We - # don't actually need it until our own startService. - self.basedir = basedir - - def startService(self): - service.MultiService.startService(self) - self.newdir = os.path.join(self.basedir, "new") - if not os.path.isdir(self.basedir) or not os.path.isdir(self.newdir): - raise NoSuchMaildir("invalid maildir '%s'" % self.basedir) - try: - if dnotify: - # we must hold an fd open on the directory, so we can get - # notified when it changes. - self.dnotify = dnotify.DNotify(self.newdir, - self.dnotify_callback, - [dnotify.DNotify.DN_CREATE]) - except (IOError, OverflowError): - # IOError is probably linux<2.4.19, which doesn't support - # dnotify. OverflowError will occur on some 64-bit machines - # because of a python bug - log.msg("DNotify failed, falling back to polling") - if not self.dnotify: - t = internet.TimerService(self.pollinterval, self.poll) - t.setServiceParent(self) - self.poll() - - def dnotify_callback(self): - log.msg("dnotify noticed something, now polling") - - # give it a moment. I found that qmail had problems when the message - # was removed from the maildir instantly. It shouldn't, that's what - # maildirs are made for. I wasn't able to eyeball any reason for the - # problem, and safecat didn't behave the same way, but qmail reports - # "Temporary_error_on_maildir_delivery" (qmail-local.c:165, - # maildir_child() process exited with rc not in 0,2,3,4). Not sure - # why, and I'd have to hack qmail to investigate further, so it's - # easier to just wait a second before yanking the message out of new/ - - reactor.callLater(0.1, self.poll) - - - def stopService(self): - if self.dnotify: - self.dnotify.remove() - self.dnotify = None - return service.MultiService.stopService(self) - - def poll(self): - assert self.basedir - # see what's new - for f in self.files: - if not os.path.isfile(os.path.join(self.newdir, f)): - self.files.remove(f) - newfiles = [] - for f in os.listdir(self.newdir): - if not f in self.files: - newfiles.append(f) - self.files.extend(newfiles) - # TODO: sort by ctime, then filename, since safecat uses a rather - # fine-grained timestamp in the filename - for n in newfiles: - # TODO: consider catching exceptions in messageReceived - self.messageReceived(n) - - def messageReceived(self, filename): - """Called when a new file is noticed. Will call - self.parent.messageReceived() with a path relative to maildir/new. - Should probably be overridden in subclasses.""" - self.parent.messageReceived(filename) - diff --git a/tools/buildbot/pylibs/buildbot/changes/monotone.py b/tools/buildbot/pylibs/buildbot/changes/monotone.py deleted file mode 100644 index 302c1c5..0000000 --- a/tools/buildbot/pylibs/buildbot/changes/monotone.py +++ /dev/null @@ -1,305 +0,0 @@ - -import tempfile -import os -from cStringIO import StringIO - -from twisted.python import log -from twisted.application import service -from twisted.internet import defer, protocol, error, reactor -from twisted.internet.task import LoopingCall - -from buildbot import util -from buildbot.interfaces import IChangeSource -from buildbot.changes.changes import Change - -class _MTProtocol(protocol.ProcessProtocol): - - def __init__(self, deferred, cmdline): - self.cmdline = cmdline - self.deferred = deferred - self.s = StringIO() - - def errReceived(self, text): - log.msg("stderr: %s" % text) - - def outReceived(self, text): - log.msg("stdout: %s" % text) - self.s.write(text) - - def processEnded(self, reason): - log.msg("Command %r exited with value %s" % (self.cmdline, reason)) - if isinstance(reason.value, error.ProcessDone): - self.deferred.callback(self.s.getvalue()) - else: - self.deferred.errback(reason) - -class Monotone: - """All methods of this class return a Deferred.""" - - def __init__(self, bin, db): - self.bin = bin - self.db = db - - def _run_monotone(self, args): - d = defer.Deferred() - cmdline = (self.bin, "--db=" + self.db) + tuple(args) - p = _MTProtocol(d, cmdline) - log.msg("Running command: %r" % (cmdline,)) - log.msg("wd: %s" % os.getcwd()) - reactor.spawnProcess(p, self.bin, cmdline) - return d - - def _process_revision_list(self, output): - if output: - return output.strip().split("\n") - else: - return [] - - def get_interface_version(self): - d = self._run_monotone(["automate", "interface_version"]) - d.addCallback(self._process_interface_version) - return d - - def _process_interface_version(self, output): - return tuple(map(int, output.strip().split("."))) - - def db_init(self): - return self._run_monotone(["db", "init"]) - - def db_migrate(self): - return self._run_monotone(["db", "migrate"]) - - def pull(self, server, pattern): - return self._run_monotone(["pull", server, pattern]) - - def get_revision(self, rid): - return self._run_monotone(["cat", "revision", rid]) - - def get_heads(self, branch, rcfile=""): - cmd = ["automate", "heads", branch] - if rcfile: - cmd += ["--rcfile=" + rcfile] - d = self._run_monotone(cmd) - d.addCallback(self._process_revision_list) - return d - - def erase_ancestors(self, revs): - d = self._run_monotone(["automate", "erase_ancestors"] + revs) - d.addCallback(self._process_revision_list) - return d - - def ancestry_difference(self, new_rev, old_revs): - d = self._run_monotone(["automate", "ancestry_difference", new_rev] - + old_revs) - d.addCallback(self._process_revision_list) - return d - - def descendents(self, rev): - d = self._run_monotone(["automate", "descendents", rev]) - d.addCallback(self._process_revision_list) - return d - - def log(self, rev, depth=None): - if depth is not None: - depth_arg = ["--last=%i" % (depth,)] - else: - depth_arg = [] - return self._run_monotone(["log", "-r", rev] + depth_arg) - - -class MonotoneSource(service.Service, util.ComparableMixin): - """This source will poll a monotone server for changes and submit them to - the change master. - - @param server_addr: monotone server specification (host:portno) - - @param branch: monotone branch to watch - - @param trusted_keys: list of keys whose code you trust - - @param db_path: path to monotone database to pull into - - @param pollinterval: interval in seconds between polls, defaults to 10 minutes - @param monotone_exec: path to monotone executable, defaults to "monotone" - """ - - __implements__ = IChangeSource, service.Service.__implements__ - compare_attrs = ["server_addr", "trusted_keys", "db_path", - "pollinterval", "branch", "monotone_exec"] - - parent = None # filled in when we're added - done_revisions = [] - last_revision = None - loop = None - d = None - tmpfile = None - monotone = None - volatile = ["loop", "d", "tmpfile", "monotone"] - - def __init__(self, server_addr, branch, trusted_keys, db_path, - pollinterval=60 * 10, monotone_exec="monotone"): - self.server_addr = server_addr - self.branch = branch - self.trusted_keys = trusted_keys - self.db_path = db_path - self.pollinterval = pollinterval - self.monotone_exec = monotone_exec - self.monotone = Monotone(self.monotone_exec, self.db_path) - - def startService(self): - self.loop = LoopingCall(self.start_poll) - self.loop.start(self.pollinterval) - service.Service.startService(self) - - def stopService(self): - self.loop.stop() - return service.Service.stopService(self) - - def describe(self): - return "monotone_source %s %s" % (self.server_addr, - self.branch) - - def start_poll(self): - if self.d is not None: - log.msg("last poll still in progress, skipping next poll") - return - log.msg("starting poll") - self.d = self._maybe_init_db() - self.d.addCallback(self._do_netsync) - self.d.addCallback(self._get_changes) - self.d.addErrback(self._handle_error) - - def _handle_error(self, failure): - log.err(failure) - self.d = None - - def _maybe_init_db(self): - if not os.path.exists(self.db_path): - log.msg("init'ing db") - return self.monotone.db_init() - else: - log.msg("db already exists, migrating") - return self.monotone.db_migrate() - - def _do_netsync(self, output): - return self.monotone.pull(self.server_addr, self.branch) - - def _get_changes(self, output): - d = self._get_new_head() - d.addCallback(self._process_new_head) - return d - - def _get_new_head(self): - # This function returns a deferred that resolves to a good pick of new - # head (or None if there is no good new head.) - - # First need to get all new heads... - rcfile = """function get_revision_cert_trust(signers, id, name, val) - local trusted_signers = { %s } - local ts_table = {} - for k, v in pairs(trusted_signers) do ts_table[v] = 1 end - for k, v in pairs(signers) do - if ts_table[v] then - return true - end - end - return false - end - """ - trusted_list = ", ".join(['"' + key + '"' for key in self.trusted_keys]) - # mktemp is unsafe, but mkstemp is not 2.2 compatible. - tmpfile_name = tempfile.mktemp() - f = open(tmpfile_name, "w") - f.write(rcfile % trusted_list) - f.close() - d = self.monotone.get_heads(self.branch, tmpfile_name) - d.addCallback(self._find_new_head, tmpfile_name) - return d - - def _find_new_head(self, new_heads, tmpfile_name): - os.unlink(tmpfile_name) - # Now get the old head's descendents... - if self.last_revision is not None: - d = self.monotone.descendents(self.last_revision) - else: - d = defer.succeed(new_heads) - d.addCallback(self._pick_new_head, new_heads) - return d - - def _pick_new_head(self, old_head_descendents, new_heads): - for r in new_heads: - if r in old_head_descendents: - return r - return None - - def _process_new_head(self, new_head): - if new_head is None: - log.msg("No new head") - self.d = None - return None - # Okay, we have a new head; we need to get all the revisions since - # then and create change objects for them. - # Step 1: simplify set of processed revisions. - d = self._simplify_revisions() - # Step 2: get the list of new revisions - d.addCallback(self._get_new_revisions, new_head) - # Step 3: add a change for each - d.addCallback(self._add_changes_for_revisions) - # Step 4: all done - d.addCallback(self._finish_changes, new_head) - return d - - def _simplify_revisions(self): - d = self.monotone.erase_ancestors(self.done_revisions) - d.addCallback(self._reset_done_revisions) - return d - - def _reset_done_revisions(self, new_done_revisions): - self.done_revisions = new_done_revisions - return None - - def _get_new_revisions(self, blah, new_head): - if self.done_revisions: - return self.monotone.ancestry_difference(new_head, - self.done_revisions) - else: - # Don't force feed the builder with every change since the - # beginning of time when it's first started up. - return defer.succeed([new_head]) - - def _add_changes_for_revisions(self, revs): - d = defer.succeed(None) - for rid in revs: - d.addCallback(self._add_change_for_revision, rid) - return d - - def _add_change_for_revision(self, blah, rid): - d = self.monotone.log(rid, 1) - d.addCallback(self._add_change_from_log, rid) - return d - - def _add_change_from_log(self, log, rid): - d = self.monotone.get_revision(rid) - d.addCallback(self._add_change_from_log_and_revision, log, rid) - return d - - def _add_change_from_log_and_revision(self, revision, log, rid): - # Stupid way to pull out everything inside quotes (which currently - # uniquely identifies filenames inside a changeset). - pieces = revision.split('"') - files = [] - for i in range(len(pieces)): - if (i % 2) == 1: - files.append(pieces[i]) - # Also pull out author key and date - author = "unknown author" - pieces = log.split('\n') - for p in pieces: - if p.startswith("Author:"): - author = p.split()[1] - self.parent.addChange(Change(author, files, log, revision=rid)) - - def _finish_changes(self, blah, new_head): - self.done_revisions.append(new_head) - self.last_revision = new_head - self.d = None diff --git a/tools/buildbot/pylibs/buildbot/changes/p4poller.py b/tools/buildbot/pylibs/buildbot/changes/p4poller.py deleted file mode 100644 index a313343..0000000 --- a/tools/buildbot/pylibs/buildbot/changes/p4poller.py +++ /dev/null @@ -1,207 +0,0 @@ -# -*- test-case-name: buildbot.test.test_p4poller -*- - -# Many thanks to Dave Peticolas for contributing this module - -import re -import time - -from twisted.python import log, failure -from twisted.internet import defer, reactor -from twisted.internet.utils import getProcessOutput -from twisted.internet.task import LoopingCall - -from buildbot import util -from buildbot.changes import base, changes - -def get_simple_split(branchfile): - """Splits the branchfile argument and assuming branch is - the first path component in branchfile, will return - branch and file else None.""" - - index = branchfile.find('/') - if index == -1: return None, None - branch, file = branchfile.split('/', 1) - return branch, file - -class P4Source(base.ChangeSource, util.ComparableMixin): - """This source will poll a perforce repository for changes and submit - them to the change master.""" - - compare_attrs = ["p4port", "p4user", "p4passwd", "p4base", - "p4bin", "pollinterval"] - - changes_line_re = re.compile( - r"Change (?P\d+) on \S+ by \S+@\S+ '.+'$") - describe_header_re = re.compile( - r"Change \d+ by (?P\S+)@\S+ on (?P.+)$") - file_re = re.compile(r"^\.\.\. (?P[^#]+)#\d+ \w+$") - datefmt = '%Y/%m/%d %H:%M:%S' - - parent = None # filled in when we're added - last_change = None - loop = None - working = False - - def __init__(self, p4port=None, p4user=None, p4passwd=None, - p4base='//', p4bin='p4', - split_file=lambda branchfile: (None, branchfile), - pollinterval=60 * 10, histmax=None): - """ - @type p4port: string - @param p4port: p4 port definition (host:portno) - @type p4user: string - @param p4user: p4 user - @type p4passwd: string - @param p4passwd: p4 passwd - @type p4base: string - @param p4base: p4 file specification to limit a poll to - without the trailing '...' (i.e., //) - @type p4bin: string - @param p4bin: path to p4 binary, defaults to just 'p4' - @type split_file: func - $param split_file: splits a filename into branch and filename. - @type pollinterval: int - @param pollinterval: interval in seconds between polls - @type histmax: int - @param histmax: (obsolete) maximum number of changes to look back through. - ignored; accepted for backwards compatibility. - """ - - self.p4port = p4port - self.p4user = p4user - self.p4passwd = p4passwd - self.p4base = p4base - self.p4bin = p4bin - self.split_file = split_file - self.pollinterval = pollinterval - self.loop = LoopingCall(self.checkp4) - - def startService(self): - base.ChangeSource.startService(self) - - # Don't start the loop just yet because the reactor isn't running. - # Give it a chance to go and install our SIGCHLD handler before - # spawning processes. - reactor.callLater(0, self.loop.start, self.pollinterval) - - def stopService(self): - self.loop.stop() - return base.ChangeSource.stopService(self) - - def describe(self): - return "p4source %s %s" % (self.p4port, self.p4base) - - def checkp4(self): - # Our return value is only used for unit testing. - if self.working: - log.msg("Skipping checkp4 because last one has not finished") - return defer.succeed(None) - else: - self.working = True - d = self._get_changes() - d.addCallback(self._process_changes) - d.addBoth(self._finished) - return d - - def _finished(self, res): - assert self.working - self.working = False - - # Again, the return value is only for unit testing. - # If there's a failure, log it so it isn't lost. - if isinstance(res, failure.Failure): - log.msg('P4 poll failed: %s' % res) - return None - return res - - def _get_changes(self): - args = [] - if self.p4port: - args.extend(['-p', self.p4port]) - if self.p4user: - args.extend(['-u', self.p4user]) - if self.p4passwd: - args.extend(['-P', self.p4passwd]) - args.extend(['changes']) - if self.last_change is not None: - args.extend(['%s...@%d,now' % (self.p4base, self.last_change+1)]) - else: - args.extend(['-m', '1', '%s...' % (self.p4base,)]) - env = {} - return getProcessOutput(self.p4bin, args, env) - - def _process_changes(self, result): - last_change = self.last_change - changelists = [] - for line in result.split('\n'): - line = line.strip() - if not line: continue - m = self.changes_line_re.match(line) - assert m, "Unexpected 'p4 changes' output: %r" % result - num = int(m.group('num')) - if last_change is None: - log.msg('P4Poller: starting at change %d' % num) - self.last_change = num - return [] - changelists.append(num) - changelists.reverse() # oldest first - - # Retrieve each sequentially. - d = defer.succeed(None) - for c in changelists: - d.addCallback(self._get_describe, c) - d.addCallback(self._process_describe, c) - return d - - def _get_describe(self, dummy, num): - args = [] - if self.p4port: - args.extend(['-p', self.p4port]) - if self.p4user: - args.extend(['-u', self.p4user]) - if self.p4passwd: - args.extend(['-P', self.p4passwd]) - args.extend(['describe', '-s', str(num)]) - env = {} - d = getProcessOutput(self.p4bin, args, env) - return d - - def _process_describe(self, result, num): - lines = result.split('\n') - # SF#1555985: Wade Brainerd reports a stray ^M at the end of the date - # field. The rstrip() is intended to remove that. - lines[0] = lines[0].rstrip() - m = self.describe_header_re.match(lines[0]) - assert m, "Unexpected 'p4 describe -s' result: %r" % result - who = m.group('who') - when = time.mktime(time.strptime(m.group('when'), self.datefmt)) - comments = '' - while not lines[0].startswith('Affected files'): - comments += lines.pop(0) + '\n' - lines.pop(0) # affected files - - branch_files = {} # dict for branch mapped to file(s) - while lines: - line = lines.pop(0).strip() - if not line: continue - m = self.file_re.match(line) - assert m, "Invalid file line: %r" % line - path = m.group('path') - if path.startswith(self.p4base): - branch, file = self.split_file(path[len(self.p4base):]) - if (branch == None and file == None): continue - if branch_files.has_key(branch): - branch_files[branch].append(file) - else: - branch_files[branch] = [file] - - for branch in branch_files: - c = changes.Change(who=who, - files=branch_files[branch], - comments=comments, - revision=num, - when=when, - branch=branch) - self.parent.addChange(c) - - self.last_change = num diff --git a/tools/buildbot/pylibs/buildbot/changes/pb.py b/tools/buildbot/pylibs/buildbot/changes/pb.py deleted file mode 100644 index 2035e4c..0000000 --- a/tools/buildbot/pylibs/buildbot/changes/pb.py +++ /dev/null @@ -1,108 +0,0 @@ -# -*- test-case-name: buildbot.test.test_changes -*- - -from twisted.python import log - -from buildbot.pbutil import NewCredPerspective -from buildbot.changes import base, changes - -class ChangePerspective(NewCredPerspective): - - def __init__(self, changemaster, prefix): - self.changemaster = changemaster - self.prefix = prefix - - def attached(self, mind): - return self - def detached(self, mind): - pass - - def perspective_addChange(self, changedict): - log.msg("perspective_addChange called") - pathnames = [] - prefixpaths = None - for path in changedict['files']: - if self.prefix: - if not path.startswith(self.prefix): - # this file does not start with the prefix, so ignore it - continue - path = path[len(self.prefix):] - pathnames.append(path) - - if pathnames: - change = changes.Change(changedict['who'], - pathnames, - changedict['comments'], - branch=changedict.get('branch'), - revision=changedict.get('revision'), - ) - self.changemaster.addChange(change) - -class PBChangeSource(base.ChangeSource): - compare_attrs = ["user", "passwd", "port", "prefix"] - - def __init__(self, user="change", passwd="changepw", port=None, - prefix=None, sep=None): - """I listen on a TCP port for Changes from 'buildbot sendchange'. - - I am a ChangeSource which will accept Changes from a remote source. I - share a TCP listening port with the buildslaves. - - Both the 'buildbot sendchange' command and the - contrib/svn_buildbot.py tool know how to send changes to me. - - @type prefix: string (or None) - @param prefix: if set, I will ignore any filenames that do not start - with this string. Moreover I will remove this string - from all filenames before creating the Change object - and delivering it to the Schedulers. This is useful - for changes coming from version control systems that - represent branches as parent directories within the - repository (like SVN and Perforce). Use a prefix of - 'trunk/' or 'project/branches/foobranch/' to only - follow one branch and to get correct tree-relative - filenames. - - @param sep: DEPRECATED (with an axe). sep= was removed in - buildbot-0.7.4 . Instead of using it, you should use - prefix= with a trailing directory separator. This - docstring (and the better-than-nothing error message - which occurs when you use it) will be removed in 0.7.5 . - """ - - # sep= was removed in 0.7.4 . This more-helpful-than-nothing error - # message will be removed in 0.7.5 . - assert sep is None, "prefix= is now a complete string, do not use sep=" - # TODO: current limitations - assert user == "change" - assert passwd == "changepw" - assert port == None - self.user = user - self.passwd = passwd - self.port = port - self.prefix = prefix - - def describe(self): - # TODO: when the dispatcher is fixed, report the specific port - #d = "PB listener on port %d" % self.port - d = "PBChangeSource listener on all-purpose slaveport" - if self.prefix is not None: - d += " (prefix '%s')" % self.prefix - return d - - def startService(self): - base.ChangeSource.startService(self) - # our parent is the ChangeMaster object - # find the master's Dispatch object and register our username - # TODO: the passwd should be registered here too - master = self.parent.parent - master.dispatcher.register(self.user, self) - - def stopService(self): - base.ChangeSource.stopService(self) - # unregister our username - master = self.parent.parent - master.dispatcher.unregister(self.user) - - def getPerspective(self): - return ChangePerspective(self.parent, self.prefix) - diff --git a/tools/buildbot/pylibs/buildbot/changes/svnpoller.py b/tools/buildbot/pylibs/buildbot/changes/svnpoller.py deleted file mode 100644 index 6f6a688..0000000 --- a/tools/buildbot/pylibs/buildbot/changes/svnpoller.py +++ /dev/null @@ -1,460 +0,0 @@ -# -*- test-case-name: buildbot.test.test_svnpoller -*- - -# Based on the work of Dave Peticolas for the P4poll -# Changed to svn (using xml.dom.minidom) by Niklaus Giger -# Hacked beyond recognition by Brian Warner - -from twisted.python import log -from twisted.internet import defer, reactor, utils -from twisted.internet.task import LoopingCall - -from buildbot import util -from buildbot.changes import base -from buildbot.changes.changes import Change - -import xml.dom.minidom - -def _assert(condition, msg): - if condition: - return True - raise AssertionError(msg) - -def dbgMsg(myString): - log.msg(myString) - return 1 - -# these split_file_* functions are available for use as values to the -# split_file= argument. -def split_file_alwaystrunk(path): - return (None, path) - -def split_file_branches(path): - # turn trunk/subdir/file.c into (None, "subdir/file.c") - # and branches/1.5.x/subdir/file.c into ("branches/1.5.x", "subdir/file.c") - pieces = path.split('/') - if pieces[0] == 'trunk': - return (None, '/'.join(pieces[1:])) - elif pieces[0] == 'branches': - return ('/'.join(pieces[0:2]), '/'.join(pieces[2:])) - else: - return None - - -class SVNPoller(base.ChangeSource, util.ComparableMixin): - """This source will poll a Subversion repository for changes and submit - them to the change master.""" - - compare_attrs = ["svnurl", "split_file_function", - "svnuser", "svnpasswd", - "pollinterval", "histmax", - "svnbin"] - - parent = None # filled in when we're added - last_change = None - loop = None - working = False - - def __init__(self, svnurl, split_file=None, - svnuser=None, svnpasswd=None, - pollinterval=10*60, histmax=100, - svnbin='svn'): - """ - @type svnurl: string - @param svnurl: the SVN URL that describes the repository and - subdirectory to watch. If this ChangeSource should - only pay attention to a single branch, this should - point at the repository for that branch, like - svn://svn.twistedmatrix.com/svn/Twisted/trunk . If it - should follow multiple branches, point it at the - repository directory that contains all the branches - like svn://svn.twistedmatrix.com/svn/Twisted and also - provide a branch-determining function. - - Each file in the repository has a SVN URL in the form - (SVNURL)/(BRANCH)/(FILEPATH), where (BRANCH) could be - empty or not, depending upon your branch-determining - function. Only files that start with (SVNURL)/(BRANCH) - will be monitored. The Change objects that are sent to - the Schedulers will see (FILEPATH) for each modified - file. - - @type split_file: callable or None - @param split_file: a function that is called with a string of the - form (BRANCH)/(FILEPATH) and should return a tuple - (BRANCH, FILEPATH). This function should match - your repository's branch-naming policy. Each - changed file has a fully-qualified URL that can be - split into a prefix (which equals the value of the - 'svnurl' argument) and a suffix; it is this suffix - which is passed to the split_file function. - - If the function returns None, the file is ignored. - Use this to indicate that the file is not a part - of this project. - - For example, if your repository puts the trunk in - trunk/... and branches are in places like - branches/1.5/..., your split_file function could - look like the following (this function is - available as svnpoller.split_file_branches):: - - pieces = path.split('/') - if pieces[0] == 'trunk': - return (None, '/'.join(pieces[1:])) - elif pieces[0] == 'branches': - return ('/'.join(pieces[0:2]), - '/'.join(pieces[2:])) - else: - return None - - If instead your repository layout puts the trunk - for ProjectA in trunk/ProjectA/... and the 1.5 - branch in branches/1.5/ProjectA/..., your - split_file function could look like:: - - pieces = path.split('/') - if pieces[0] == 'trunk': - branch = None - pieces.pop(0) # remove 'trunk' - elif pieces[0] == 'branches': - pieces.pop(0) # remove 'branches' - # grab branch name - branch = 'branches/' + pieces.pop(0) - else: - return None # something weird - projectname = pieces.pop(0) - if projectname != 'ProjectA': - return None # wrong project - return (branch, '/'.join(pieces)) - - The default of split_file= is None, which - indicates that no splitting should be done. This - is equivalent to the following function:: - - return (None, path) - - If you wish, you can override the split_file - method with the same sort of function instead of - passing in a split_file= argument. - - - @type svnuser: string - @param svnuser: If set, the --username option will be added to - the 'svn log' command. You may need this to get - access to a private repository. - @type svnpasswd: string - @param svnpasswd: If set, the --password option will be added. - - @type pollinterval: int - @param pollinterval: interval in seconds between polls. The default - is 600 seconds (10 minutes). Smaller values - decrease the latency between the time a change - is recorded and the time the buildbot notices - it, but it also increases the system load. - - @type histmax: int - @param histmax: maximum number of changes to look back through. - The default is 100. Smaller values decrease - system load, but if more than histmax changes - are recorded between polls, the extra ones will - be silently lost. - - @type svnbin: string - @param svnbin: path to svn binary, defaults to just 'svn'. Use - this if your subversion command lives in an - unusual location. - """ - - if svnurl.endswith("/"): - svnurl = svnurl[:-1] # strip the trailing slash - self.svnurl = svnurl - self.split_file_function = split_file or split_file_alwaystrunk - self.svnuser = svnuser - self.svnpasswd = svnpasswd - - self.svnbin = svnbin - self.pollinterval = pollinterval - self.histmax = histmax - self._prefix = None - self.overrun_counter = 0 - self.loop = LoopingCall(self.checksvn) - - def split_file(self, path): - # use getattr() to avoid turning this function into a bound method, - # which would require it to have an extra 'self' argument - f = getattr(self, "split_file_function") - return f(path) - - def startService(self): - log.msg("SVNPoller(%s) starting" % self.svnurl) - base.ChangeSource.startService(self) - # Don't start the loop just yet because the reactor isn't running. - # Give it a chance to go and install our SIGCHLD handler before - # spawning processes. - reactor.callLater(0, self.loop.start, self.pollinterval) - - def stopService(self): - log.msg("SVNPoller(%s) shutting down" % self.svnurl) - self.loop.stop() - return base.ChangeSource.stopService(self) - - def describe(self): - return "SVNPoller watching %s" % self.svnurl - - def checksvn(self): - # Our return value is only used for unit testing. - - # we need to figure out the repository root, so we can figure out - # repository-relative pathnames later. Each SVNURL is in the form - # (ROOT)/(PROJECT)/(BRANCH)/(FILEPATH), where (ROOT) is something - # like svn://svn.twistedmatrix.com/svn/Twisted (i.e. there is a - # physical repository at /svn/Twisted on that host), (PROJECT) is - # something like Projects/Twisted (i.e. within the repository's - # internal namespace, everything under Projects/Twisted/ has - # something to do with Twisted, but these directory names do not - # actually appear on the repository host), (BRANCH) is something like - # "trunk" or "branches/2.0.x", and (FILEPATH) is a tree-relative - # filename like "twisted/internet/defer.py". - - # our self.svnurl attribute contains (ROOT)/(PROJECT) combined - # together in a way that we can't separate without svn's help. If the - # user is not using the split_file= argument, then self.svnurl might - # be (ROOT)/(PROJECT)/(BRANCH) . In any case, the filenames we will - # get back from 'svn log' will be of the form - # (PROJECT)/(BRANCH)/(FILEPATH), but we want to be able to remove - # that (PROJECT) prefix from them. To do this without requiring the - # user to tell us how svnurl is split into ROOT and PROJECT, we do an - # 'svn info --xml' command at startup. This command will include a - # element that tells us ROOT. We then strip this prefix from - # self.svnurl to determine PROJECT, and then later we strip the - # PROJECT prefix from the filenames reported by 'svn log --xml' to - # get a (BRANCH)/(FILEPATH) that can be passed to split_file() to - # turn into separate BRANCH and FILEPATH values. - - # whew. - - if self.working: - log.msg("SVNPoller(%s) overrun: timer fired but the previous " - "poll had not yet finished." % self.svnurl) - self.overrun_counter += 1 - return defer.succeed(None) - self.working = True - - log.msg("SVNPoller polling") - if not self._prefix: - # this sets self._prefix when it finishes. It fires with - # self._prefix as well, because that makes the unit tests easier - # to write. - d = self.get_root() - d.addCallback(self.determine_prefix) - else: - d = defer.succeed(self._prefix) - - d.addCallback(self.get_logs) - d.addCallback(self.parse_logs) - d.addCallback(self.get_new_logentries) - d.addCallback(self.create_changes) - d.addCallback(self.submit_changes) - d.addCallbacks(self.finished_ok, self.finished_failure) - return d - - def getProcessOutput(self, args): - # this exists so we can override it during the unit tests - d = utils.getProcessOutput(self.svnbin, args, {}) - return d - - def get_root(self): - args = ["info", "--xml", "--non-interactive", self.svnurl] - if self.svnuser: - args.extend(["--username=%s" % self.svnuser]) - if self.svnpasswd: - args.extend(["--password=%s" % self.svnpasswd]) - d = self.getProcessOutput(args) - return d - - def determine_prefix(self, output): - try: - doc = xml.dom.minidom.parseString(output) - except xml.parsers.expat.ExpatError: - dbgMsg("_process_changes: ExpatError in %s" % output) - log.msg("SVNPoller._determine_prefix_2: ExpatError in '%s'" - % output) - raise - rootnodes = doc.getElementsByTagName("root") - if not rootnodes: - # this happens if the URL we gave was already the root. In this - # case, our prefix is empty. - self._prefix = "" - return self._prefix - rootnode = rootnodes[0] - root = "".join([c.data for c in rootnode.childNodes]) - # root will be a unicode string - _assert(self.svnurl.startswith(root), - "svnurl='%s' doesn't start with ='%s'" % - (self.svnurl, root)) - self._prefix = self.svnurl[len(root):] - if self._prefix.startswith("/"): - self._prefix = self._prefix[1:] - log.msg("SVNPoller: svnurl=%s, root=%s, so prefix=%s" % - (self.svnurl, root, self._prefix)) - return self._prefix - - def get_logs(self, ignored_prefix=None): - args = [] - args.extend(["log", "--xml", "--verbose", "--non-interactive"]) - if self.svnuser: - args.extend(["--username=%s" % self.svnuser]) - if self.svnpasswd: - args.extend(["--password=%s" % self.svnpasswd]) - args.extend(["--limit=%d" % (self.histmax), self.svnurl]) - d = self.getProcessOutput(args) - return d - - def parse_logs(self, output): - # parse the XML output, return a list of nodes - try: - doc = xml.dom.minidom.parseString(output) - except xml.parsers.expat.ExpatError: - dbgMsg("_process_changes: ExpatError in %s" % output) - log.msg("SVNPoller._parse_changes: ExpatError in '%s'" % output) - raise - logentries = doc.getElementsByTagName("logentry") - return logentries - - - def _filter_new_logentries(self, logentries, last_change): - # given a list of logentries, return a tuple of (new_last_change, - # new_logentries), where new_logentries contains only the ones after - # last_change - if not logentries: - # no entries, so last_change must stay at None - return (None, []) - - mostRecent = int(logentries[0].getAttribute("revision")) - - if last_change is None: - # if this is the first time we've been run, ignore any changes - # that occurred before now. This prevents a build at every - # startup. - log.msg('svnPoller: starting at change %s' % mostRecent) - return (mostRecent, []) - - if last_change == mostRecent: - # an unmodified repository will hit this case - log.msg('svnPoller: _process_changes last %s mostRecent %s' % ( - last_change, mostRecent)) - return (mostRecent, []) - - new_logentries = [] - for el in logentries: - if last_change == int(el.getAttribute("revision")): - break - new_logentries.append(el) - new_logentries.reverse() # return oldest first - return (mostRecent, new_logentries) - - def get_new_logentries(self, logentries): - last_change = self.last_change - (new_last_change, - new_logentries) = self._filter_new_logentries(logentries, - self.last_change) - self.last_change = new_last_change - log.msg('svnPoller: _process_changes %s .. %s' % - (last_change, new_last_change)) - return new_logentries - - - def _get_text(self, element, tag_name): - child_nodes = element.getElementsByTagName(tag_name)[0].childNodes - text = "".join([t.data for t in child_nodes]) - return text - - def _transform_path(self, path): - _assert(path.startswith(self._prefix), - "filepath '%s' should start with prefix '%s'" % - (path, self._prefix)) - relative_path = path[len(self._prefix):] - if relative_path.startswith("/"): - relative_path = relative_path[1:] - where = self.split_file(relative_path) - # 'where' is either None or (branch, final_path) - return where - - def create_changes(self, new_logentries): - changes = [] - - for el in new_logentries: - branch_files = [] # get oldest change first - revision = str(el.getAttribute("revision")) - dbgMsg("Adding change revision %s" % (revision,)) - # TODO: the rest of buildbot may not be ready for unicode 'who' - # values - author = self._get_text(el, "author") - comments = self._get_text(el, "msg") - # there is a "date" field, but it provides localtime in the - # repository's timezone, whereas we care about buildmaster's - # localtime (since this will get used to position the boxes on - # the Waterfall display, etc). So ignore the date field and use - # our local clock instead. - #when = self._get_text(el, "date") - #when = time.mktime(time.strptime("%.19s" % when, - # "%Y-%m-%dT%H:%M:%S")) - branches = {} - pathlist = el.getElementsByTagName("paths")[0] - for p in pathlist.getElementsByTagName("path"): - action = p.getAttribute("action") - path = "".join([t.data for t in p.childNodes]) - # the rest of buildbot is certaily not yet ready to handle - # unicode filenames, because they get put in RemoteCommands - # which get sent via PB to the buildslave, and PB doesn't - # handle unicode. - path = path.encode("ascii") - if path.startswith("/"): - path = path[1:] - where = self._transform_path(path) - - # if 'where' is None, the file was outside any project that - # we care about and we should ignore it - if where: - branch, filename = where - if not branch in branches: - branches[branch] = { 'files': []} - branches[branch]['files'].append(filename) - - if not branches[branch].has_key('action'): - branches[branch]['action'] = action - - for branch in branches.keys(): - action = branches[branch]['action'] - files = branches[branch]['files'] - number_of_files_changed = len(files) - - if action == u'D' and number_of_files_changed == 1 and files[0] == '': - log.msg("Ignoring deletion of branch '%s'" % branch) - else: - c = Change(who=author, - files=files, - comments=comments, - revision=revision, - branch=branch) - changes.append(c) - - return changes - - def submit_changes(self, changes): - for c in changes: - self.parent.addChange(c) - - def finished_ok(self, res): - log.msg("SVNPoller finished polling") - dbgMsg('_finished : %s' % res) - assert self.working - self.working = False - return res - - def finished_failure(self, f): - log.msg("SVNPoller failed") - dbgMsg('_finished : %s' % f) - assert self.working - self.working = False - return None # eat the failure diff --git a/tools/buildbot/pylibs/buildbot/clients/__init__.py b/tools/buildbot/pylibs/buildbot/clients/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tools/buildbot/pylibs/buildbot/clients/base.py b/tools/buildbot/pylibs/buildbot/clients/base.py deleted file mode 100644 index 6d9e46c..0000000 --- a/tools/buildbot/pylibs/buildbot/clients/base.py +++ /dev/null @@ -1,125 +0,0 @@ - -import sys, re - -from twisted.spread import pb -from twisted.cred import credentials, error -from twisted.internet import reactor - -class StatusClient(pb.Referenceable): - """To use this, call my .connected method with a RemoteReference to the - buildmaster's StatusClientPerspective object. - """ - - def __init__(self, events): - self.builders = {} - self.events = events - - def connected(self, remote): - print "connected" - self.remote = remote - remote.callRemote("subscribe", self.events, 5, self) - - def remote_builderAdded(self, buildername, builder): - print "builderAdded", buildername - - def remote_builderRemoved(self, buildername): - print "builderRemoved", buildername - - def remote_builderChangedState(self, buildername, state, eta): - print "builderChangedState", buildername, state, eta - - def remote_buildStarted(self, buildername, build): - print "buildStarted", buildername - - def remote_buildFinished(self, buildername, build, results): - print "buildFinished", results - - def remote_buildETAUpdate(self, buildername, build, eta): - print "ETA", buildername, eta - - def remote_stepStarted(self, buildername, build, stepname, step): - print "stepStarted", buildername, stepname - - def remote_stepFinished(self, buildername, build, stepname, step, results): - print "stepFinished", buildername, stepname, results - - def remote_stepETAUpdate(self, buildername, build, stepname, step, - eta, expectations): - print "stepETA", buildername, stepname, eta - - def remote_logStarted(self, buildername, build, stepname, step, - logname, log): - print "logStarted", buildername, stepname - - def remote_logFinished(self, buildername, build, stepname, step, - logname, log): - print "logFinished", buildername, stepname - - def remote_logChunk(self, buildername, build, stepname, step, logname, log, - channel, text): - ChunkTypes = ["STDOUT", "STDERR", "HEADER"] - print "logChunk[%s]: %s" % (ChunkTypes[channel], text) - -class TextClient: - def __init__(self, master, events="steps"): - """ - @type events: string, one of builders, builds, steps, logs, full - @param events: specify what level of detail should be reported. - - 'builders': only announce new/removed Builders - - 'builds': also announce builderChangedState, buildStarted, and - buildFinished - - 'steps': also announce buildETAUpdate, stepStarted, stepFinished - - 'logs': also announce stepETAUpdate, logStarted, logFinished - - 'full': also announce log contents - """ - self.master = master - self.listener = StatusClient(events) - - def run(self): - """Start the TextClient.""" - self.startConnecting() - reactor.run() - - def startConnecting(self): - try: - host, port = re.search(r'(.+):(\d+)', self.master).groups() - port = int(port) - except: - print "unparseable master location '%s'" % self.master - print " expecting something more like localhost:8007" - raise - cf = pb.PBClientFactory() - creds = credentials.UsernamePassword("statusClient", "clientpw") - d = cf.login(creds) - reactor.connectTCP(host, port, cf) - d.addCallbacks(self.connected, self.not_connected) - return d - def connected(self, ref): - ref.notifyOnDisconnect(self.disconnected) - self.listener.connected(ref) - def not_connected(self, why): - if why.check(error.UnauthorizedLogin): - print """ -Unable to login.. are you sure we are connecting to a -buildbot.status.client.PBListener port and not to the slaveport? -""" - reactor.stop() - return why - def disconnected(self, ref): - print "lost connection" - # we can get here in one of two ways: the buildmaster has - # disconnected us (probably because it shut itself down), or because - # we've been SIGINT'ed. In the latter case, our reactor is already - # shut down, but we have no easy way of detecting that. So protect - # our attempt to shut down the reactor. - try: - reactor.stop() - except RuntimeError: - pass - -if __name__ == '__main__': - master = "localhost:8007" - if len(sys.argv) > 1: - master = sys.argv[1] - c = TextClient() - c.run() diff --git a/tools/buildbot/pylibs/buildbot/clients/debug.glade b/tools/buildbot/pylibs/buildbot/clients/debug.glade deleted file mode 100644 index 40468bb..0000000 --- a/tools/buildbot/pylibs/buildbot/clients/debug.glade +++ /dev/null @@ -1,684 +0,0 @@ - - - - - - - - True - Buildbot Debug Tool - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - True - False - True - False - False - GDK_WINDOW_TYPE_HINT_NORMAL - GDK_GRAVITY_NORTH_WEST - True - False - - - - True - False - 0 - - - - True - False - 0 - - - - True - True - Connect - True - GTK_RELIEF_NORMAL - True - - - - 0 - False - False - - - - - - True - Disconnected - False - False - GTK_JUSTIFY_CENTER - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - True - True - - - - - 0 - False - False - - - - - - True - False - 0 - - - - True - True - Reload .cfg - True - GTK_RELIEF_NORMAL - True - - - - 0 - False - False - - - - - - True - False - True - Rebuild .py - True - GTK_RELIEF_NORMAL - True - - - - 0 - False - False - - - - - - True - True - poke IRC - True - GTK_RELIEF_NORMAL - True - - - - 0 - False - False - - - - - 0 - True - True - - - - - - True - False - 0 - - - - True - True - Branch: - True - GTK_RELIEF_NORMAL - True - False - False - True - - - - 0 - False - False - - - - - - True - True - True - True - 0 - - True - * - False - - - 0 - True - True - - - - - 0 - True - True - - - - - - True - False - 0 - - - - True - True - Revision: - True - GTK_RELIEF_NORMAL - True - False - False - True - - - - 0 - False - False - - - - - - True - True - True - True - 0 - - True - * - False - - - 0 - True - True - - - - - 0 - True - True - - - - - - 4 - True - 0 - 0.5 - GTK_SHADOW_ETCHED_IN - - - - True - 0.5 - 0.5 - 1 - 1 - 0 - 0 - 0 - 0 - - - - True - False - 0 - - - - True - False - 0 - - - - True - True - commit - True - GTK_RELIEF_NORMAL - True - - - - 0 - False - False - - - - - - True - True - True - True - 0 - twisted/internet/app.py - True - * - False - - - 0 - True - True - - - - - 0 - True - True - - - - - - True - False - 0 - - - - True - Who: - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - True - True - True - True - 0 - bob - True - * - False - - - 0 - True - True - - - - - 0 - True - True - - - - - - - - - - True - Commit - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 2 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - label_item - - - - - 0 - True - True - - - - - - 4 - True - 0 - 0.5 - GTK_SHADOW_ETCHED_IN - - - - True - False - 0 - - - - True - False - 3 - - - - True - Builder: - False - False - GTK_JUSTIFY_CENTER - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - True - True - True - True - 0 - one - True - * - False - - - 0 - True - True - - - - - 0 - True - True - - - - - - True - False - 0 - - - - True - True - Request -Build - True - GTK_RELIEF_NORMAL - True - - - - 0 - False - False - - - - - - True - True - Ping -Builder - True - GTK_RELIEF_NORMAL - True - - - - 0 - False - False - - - - - - - - - 0 - True - True - - - - - - True - False - 0 - - - - True - Currently: - False - False - GTK_JUSTIFY_CENTER - False - False - 0.5 - 0.5 - 7 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - True - True - offline - True - GTK_RELIEF_NORMAL - True - - - - 0 - False - False - - - - - - True - True - idle - True - GTK_RELIEF_NORMAL - True - - - - 0 - False - False - - - - - - True - True - waiting - True - GTK_RELIEF_NORMAL - True - - - - 0 - False - False - - - - - - True - True - building - True - GTK_RELIEF_NORMAL - True - - - - 0 - False - False - - - - - 0 - True - True - - - - - - - - True - Builder - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 2 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - label_item - - - - - 0 - True - True - - - - - - - diff --git a/tools/buildbot/pylibs/buildbot/clients/debug.py b/tools/buildbot/pylibs/buildbot/clients/debug.py deleted file mode 100644 index 5413765..0000000 --- a/tools/buildbot/pylibs/buildbot/clients/debug.py +++ /dev/null @@ -1,181 +0,0 @@ - -from twisted.internet import gtk2reactor -gtk2reactor.install() -from twisted.internet import reactor -from twisted.python import util -from twisted.spread import pb -from twisted.cred import credentials -import gtk.glade -import sys, re - -class DebugWidget: - def __init__(self, master="localhost:8007", passwd="debugpw"): - self.connected = 0 - try: - host, port = re.search(r'(.+):(\d+)', master).groups() - except: - print "unparseable master location '%s'" % master - print " expecting something more like localhost:8007" - raise - self.host = host - self.port = int(port) - self.passwd = passwd - self.remote = None - xml = self.xml = gtk.glade.XML(util.sibpath(__file__, "debug.glade")) - g = xml.get_widget - self.buildname = g('buildname') - self.filename = g('filename') - self.connectbutton = g('connectbutton') - self.connectlabel = g('connectlabel') - g('window1').connect('destroy', lambda win: gtk.main_quit()) - # put the master info in the window's titlebar - g('window1').set_title("Buildbot Debug Tool: %s" % master) - c = xml.signal_connect - c('do_connect', self.do_connect) - c('do_reload', self.do_reload) - c('do_rebuild', self.do_rebuild) - c('do_poke_irc', self.do_poke_irc) - c('do_build', self.do_build) - c('do_ping', self.do_ping) - c('do_commit', self.do_commit) - c('on_usebranch_toggled', self.usebranch_toggled) - self.usebranch_toggled(g('usebranch')) - c('on_userevision_toggled', self.userevision_toggled) - self.userevision_toggled(g('userevision')) - c('do_current_offline', self.do_current, "offline") - c('do_current_idle', self.do_current, "idle") - c('do_current_waiting', self.do_current, "waiting") - c('do_current_building', self.do_current, "building") - - def do_connect(self, widget): - if self.connected: - self.connectlabel.set_text("Disconnecting...") - if self.remote: - self.remote.broker.transport.loseConnection() - else: - self.connectlabel.set_text("Connecting...") - f = pb.PBClientFactory() - creds = credentials.UsernamePassword("debug", self.passwd) - d = f.login(creds) - reactor.connectTCP(self.host, int(self.port), f) - d.addCallbacks(self.connect_complete, self.connect_failed) - def connect_complete(self, ref): - self.connectbutton.set_label("Disconnect") - self.connectlabel.set_text("Connected") - self.connected = 1 - self.remote = ref - self.remote.callRemote("print", "hello cleveland") - self.remote.notifyOnDisconnect(self.disconnected) - def connect_failed(self, why): - self.connectlabel.set_text("Failed") - print why - def disconnected(self, ref): - self.connectbutton.set_label("Connect") - self.connectlabel.set_text("Disconnected") - self.connected = 0 - self.remote = None - - def do_reload(self, widget): - if not self.remote: - return - d = self.remote.callRemote("reload") - d.addErrback(self.err) - def do_rebuild(self, widget): - print "Not yet implemented" - return - def do_poke_irc(self, widget): - if not self.remote: - return - d = self.remote.callRemote("pokeIRC") - d.addErrback(self.err) - - def do_build(self, widget): - if not self.remote: - return - name = self.buildname.get_text() - branch = None - if self.xml.get_widget("usebranch").get_active(): - branch = self.xml.get_widget('branch').get_text() - if branch == '': - branch = None - revision = None - if self.xml.get_widget("userevision").get_active(): - revision = self.xml.get_widget('revision').get_text() - if revision == '': - revision = None - reason = "debugclient 'Request Build' button pushed" - properties = {} - d = self.remote.callRemote("requestBuild", - name, reason, branch, revision, properties) - d.addErrback(self.err) - - def do_ping(self, widget): - if not self.remote: - return - name = self.buildname.get_text() - d = self.remote.callRemote("pingBuilder", name) - d.addErrback(self.err) - - def usebranch_toggled(self, widget): - rev = self.xml.get_widget('branch') - if widget.get_active(): - rev.set_sensitive(True) - else: - rev.set_sensitive(False) - - def userevision_toggled(self, widget): - rev = self.xml.get_widget('revision') - if widget.get_active(): - rev.set_sensitive(True) - else: - rev.set_sensitive(False) - - def do_commit(self, widget): - if not self.remote: - return - filename = self.filename.get_text() - who = self.xml.get_widget("who").get_text() - - branch = None - if self.xml.get_widget("usebranch").get_active(): - branch = self.xml.get_widget('branch').get_text() - if branch == '': - branch = None - - revision = None - if self.xml.get_widget("userevision").get_active(): - revision = self.xml.get_widget('revision').get_text() - try: - revision = int(revision) - except ValueError: - pass - if revision == '': - revision = None - - kwargs = { 'revision': revision, 'who': who } - if branch: - kwargs['branch'] = branch - d = self.remote.callRemote("fakeChange", filename, **kwargs) - d.addErrback(self.err) - - def do_current(self, widget, state): - if not self.remote: - return - name = self.buildname.get_text() - d = self.remote.callRemote("setCurrentState", name, state) - d.addErrback(self.err) - def err(self, failure): - print "received error:", failure - - def run(self): - reactor.run() - -if __name__ == '__main__': - master = "localhost:8007" - if len(sys.argv) > 1: - master = sys.argv[1] - passwd = "debugpw" - if len(sys.argv) > 2: - passwd = sys.argv[2] - d = DebugWidget(master, passwd) - d.run() diff --git a/tools/buildbot/pylibs/buildbot/clients/gtkPanes.py b/tools/buildbot/pylibs/buildbot/clients/gtkPanes.py deleted file mode 100644 index f41e395..0000000 --- a/tools/buildbot/pylibs/buildbot/clients/gtkPanes.py +++ /dev/null @@ -1,523 +0,0 @@ - -from twisted.internet import gtk2reactor -gtk2reactor.install() - -import sys, time - -import pygtk -pygtk.require("2.0") -import gobject, gtk -assert(gtk.Window) # in gtk1 it's gtk.GtkWindow - -from twisted.spread import pb - -#from buildbot.clients.base import Builder, Client -from buildbot.clients.base import TextClient -from buildbot.util import now - -''' -class Pane: - def __init__(self): - pass - -class OneRow(Pane): - """This is a one-row status bar. It has one square per Builder, and that - square is either red, yellow, or green. """ - - def __init__(self): - Pane.__init__(self) - self.widget = gtk.VBox(gtk.FALSE, 2) - self.nameBox = gtk.HBox(gtk.TRUE) - self.statusBox = gtk.HBox(gtk.TRUE) - self.widget.add(self.nameBox) - self.widget.add(self.statusBox) - self.widget.show_all() - self.builders = [] - - def getWidget(self): - return self.widget - def addBuilder(self, builder): - print "OneRow.addBuilder" - # todo: ordering. Should follow the order in which they were added - # to the original BotMaster - self.builders.append(builder) - # add the name to the left column, and a label (with background) to - # the right - name = gtk.Label(builder.name) - status = gtk.Label('??') - status.set_size_request(64,64) - box = gtk.EventBox() - box.add(status) - name.show() - box.show_all() - self.nameBox.add(name) - self.statusBox.add(box) - builder.haveSomeWidgets([name, status, box]) - -class R2Builder(Builder): - def start(self): - self.nameSquare.set_text(self.name) - self.statusSquare.set_text("???") - self.subscribe() - def haveSomeWidgets(self, widgets): - self.nameSquare, self.statusSquare, self.statusBox = widgets - - def remote_newLastBuildStatus(self, event): - color = None - if event: - text = "\n".join(event.text) - color = event.color - else: - text = "none" - self.statusSquare.set_text(text) - if color: - print "color", color - self.statusBox.modify_bg(gtk.STATE_NORMAL, - gtk.gdk.color_parse(color)) - - def remote_currentlyOffline(self): - self.statusSquare.set_text("offline") - def remote_currentlyIdle(self): - self.statusSquare.set_text("idle") - def remote_currentlyWaiting(self, seconds): - self.statusSquare.set_text("waiting") - def remote_currentlyInterlocked(self): - self.statusSquare.set_text("interlocked") - def remote_currentlyBuilding(self, eta): - self.statusSquare.set_text("building") - - -class CompactRow(Pane): - def __init__(self): - Pane.__init__(self) - self.widget = gtk.VBox(gtk.FALSE, 3) - self.nameBox = gtk.HBox(gtk.TRUE, 2) - self.lastBuildBox = gtk.HBox(gtk.TRUE, 2) - self.statusBox = gtk.HBox(gtk.TRUE, 2) - self.widget.add(self.nameBox) - self.widget.add(self.lastBuildBox) - self.widget.add(self.statusBox) - self.widget.show_all() - self.builders = [] - - def getWidget(self): - return self.widget - - def addBuilder(self, builder): - self.builders.append(builder) - - name = gtk.Label(builder.name) - name.show() - self.nameBox.add(name) - - last = gtk.Label('??') - last.set_size_request(64,64) - lastbox = gtk.EventBox() - lastbox.add(last) - lastbox.show_all() - self.lastBuildBox.add(lastbox) - - status = gtk.Label('??') - status.set_size_request(64,64) - statusbox = gtk.EventBox() - statusbox.add(status) - statusbox.show_all() - self.statusBox.add(statusbox) - - builder.haveSomeWidgets([name, last, lastbox, status, statusbox]) - - def removeBuilder(self, name, builder): - self.nameBox.remove(builder.nameSquare) - self.lastBuildBox.remove(builder.lastBuildBox) - self.statusBox.remove(builder.statusBox) - self.builders.remove(builder) - -class CompactBuilder(Builder): - def setup(self): - self.timer = None - self.text = [] - self.eta = None - def start(self): - self.nameSquare.set_text(self.name) - self.statusSquare.set_text("???") - self.subscribe() - def haveSomeWidgets(self, widgets): - (self.nameSquare, - self.lastBuildSquare, self.lastBuildBox, - self.statusSquare, self.statusBox) = widgets - - def remote_currentlyOffline(self): - self.eta = None - self.stopTimer() - self.statusSquare.set_text("offline") - self.statusBox.modify_bg(gtk.STATE_NORMAL, - gtk.gdk.color_parse("red")) - def remote_currentlyIdle(self): - self.eta = None - self.stopTimer() - self.statusSquare.set_text("idle") - def remote_currentlyWaiting(self, seconds): - self.nextBuild = now() + seconds - self.startTimer(self.updateWaiting) - def remote_currentlyInterlocked(self): - self.stopTimer() - self.statusSquare.set_text("interlocked") - def startTimer(self, func): - # the func must clear self.timer and return gtk.FALSE when the event - # has arrived - self.stopTimer() - self.timer = gtk.timeout_add(1000, func) - func() - def stopTimer(self): - if self.timer: - gtk.timeout_remove(self.timer) - self.timer = None - def updateWaiting(self): - when = self.nextBuild - if now() < when: - next = time.strftime("%H:%M:%S", time.localtime(when)) - secs = "[%d seconds]" % (when - now()) - self.statusSquare.set_text("waiting\n%s\n%s" % (next, secs)) - return gtk.TRUE # restart timer - else: - # done - self.statusSquare.set_text("waiting\n[RSN]") - self.timer = None - return gtk.FALSE - - def remote_currentlyBuilding(self, eta): - self.stopTimer() - self.statusSquare.set_text("building") - if eta: - d = eta.callRemote("subscribe", self, 5) - - def remote_newLastBuildStatus(self, event): - color = None - if event: - text = "\n".join(event.text) - color = event.color - else: - text = "none" - if not color: color = "gray" - self.lastBuildSquare.set_text(text) - self.lastBuildBox.modify_bg(gtk.STATE_NORMAL, - gtk.gdk.color_parse(color)) - - def remote_newEvent(self, event): - assert(event.__class__ == GtkUpdatingEvent) - self.current = event - event.builder = self - self.text = event.text - if not self.text: self.text = ["idle"] - self.eta = None - self.stopTimer() - self.updateText() - color = event.color - if not color: color = "gray" - self.statusBox.modify_bg(gtk.STATE_NORMAL, - gtk.gdk.color_parse(color)) - - def updateCurrent(self): - text = self.current.text - if text: - self.text = text - self.updateText() - color = self.current.color - if color: - self.statusBox.modify_bg(gtk.STATE_NORMAL, - gtk.gdk.color_parse(color)) - def updateText(self): - etatext = [] - if self.eta: - etatext = [time.strftime("%H:%M:%S", time.localtime(self.eta))] - if now() > self.eta: - etatext += ["RSN"] - else: - seconds = self.eta - now() - etatext += ["[%d secs]" % seconds] - text = "\n".join(self.text + etatext) - self.statusSquare.set_text(text) - def updateTextTimer(self): - self.updateText() - return gtk.TRUE # restart timer - - def remote_progress(self, seconds): - if seconds == None: - self.eta = None - else: - self.eta = now() + seconds - self.startTimer(self.updateTextTimer) - self.updateText() - def remote_finished(self, eta): - self.eta = None - self.stopTimer() - self.updateText() - eta.callRemote("unsubscribe", self) -''' - -class Box: - def __init__(self, text="?"): - self.text = text - self.box = gtk.EventBox() - self.label = gtk.Label(text) - self.box.add(self.label) - self.box.set_size_request(64,64) - self.timer = None - - def getBox(self): - return self.box - - def setText(self, text): - self.text = text - self.label.set_text(text) - - def setColor(self, color): - if not color: - return - self.box.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(color)) - - def setETA(self, eta): - if eta: - self.when = now() + eta - self.startTimer() - else: - self.stopTimer() - - def startTimer(self): - self.stopTimer() - self.timer = gobject.timeout_add(1000, self.update) - self.update() - - def stopTimer(self): - if self.timer: - gobject.source_remove(self.timer) - self.timer = None - self.label.set_text(self.text) - - def update(self): - if now() < self.when: - next = time.strftime("%H:%M:%S", time.localtime(self.when)) - secs = "[%d secs]" % (self.when - now()) - self.label.set_text("%s\n%s\n%s" % (self.text, next, secs)) - return True # restart timer - else: - # done - self.label.set_text("%s\n[soon]\n[overdue]" % (self.text,)) - self.timer = None - return False - - - -class ThreeRowBuilder: - def __init__(self, name, ref): - self.name = name - - self.last = Box() - self.current = Box() - self.step = Box("idle") - self.step.setColor("white") - - self.ref = ref - - def getBoxes(self): - return self.last.getBox(), self.current.getBox(), self.step.getBox() - - def getLastBuild(self): - d = self.ref.callRemote("getLastFinishedBuild") - d.addCallback(self.gotLastBuild) - def gotLastBuild(self, build): - if build: - build.callRemote("getText").addCallback(self.gotLastText) - build.callRemote("getColor").addCallback(self.gotLastColor) - - def gotLastText(self, text): - self.last.setText("\n".join(text)) - def gotLastColor(self, color): - self.last.setColor(color) - - def getState(self): - self.ref.callRemote("getState").addCallback(self.gotState) - def gotState(self, res): - state, ETA, builds = res - # state is one of: offline, idle, waiting, interlocked, building - # TODO: ETA is going away, you have to look inside the builds to get - # that value - currentmap = {"offline": "red", - "idle": "white", - "waiting": "yellow", - "interlocked": "yellow", - "building": "yellow",} - text = state - self.current.setColor(currentmap[state]) - if ETA is not None: - text += "\nETA=%s secs" % ETA - self.current.setText(state) - - def buildStarted(self, build): - print "[%s] buildStarted" % (self.name,) - self.current.setColor("yellow") - - def buildFinished(self, build, results): - print "[%s] buildFinished: %s" % (self.name, results) - self.gotLastBuild(build) - self.current.setColor("white") - self.current.stopTimer() - - def buildETAUpdate(self, eta): - print "[%s] buildETAUpdate: %s" % (self.name, eta) - self.current.setETA(eta) - - - def stepStarted(self, stepname, step): - print "[%s] stepStarted: %s" % (self.name, stepname) - self.step.setText(stepname) - self.step.setColor("yellow") - def stepFinished(self, stepname, step, results): - print "[%s] stepFinished: %s %s" % (self.name, stepname, results) - self.step.setText("idle") - self.step.setColor("white") - self.step.stopTimer() - def stepETAUpdate(self, stepname, eta): - print "[%s] stepETAUpdate: %s %s" % (self.name, stepname, eta) - self.step.setETA(eta) - - -class ThreeRowClient(pb.Referenceable): - def __init__(self, window): - self.window = window - self.buildernames = [] - self.builders = {} - - def connected(self, ref): - print "connected" - self.ref = ref - self.pane = gtk.VBox(False, 2) - self.table = gtk.Table(1+3, 1) - self.pane.add(self.table) - self.window.vb.add(self.pane) - self.pane.show_all() - ref.callRemote("subscribe", "logs", 5, self) - - def removeTable(self): - for child in self.table.get_children(): - self.table.remove(child) - self.pane.remove(self.table) - - def makeTable(self): - columns = len(self.builders) - self.table = gtk.Table(2, columns) - self.pane.add(self.table) - for i in range(len(self.buildernames)): - name = self.buildernames[i] - b = self.builders[name] - last,current,step = b.getBoxes() - self.table.attach(gtk.Label(name), i, i+1, 0, 1) - self.table.attach(last, i, i+1, 1, 2, - xpadding=1, ypadding=1) - self.table.attach(current, i, i+1, 2, 3, - xpadding=1, ypadding=1) - self.table.attach(step, i, i+1, 3, 4, - xpadding=1, ypadding=1) - self.table.show_all() - - def rebuildTable(self): - self.removeTable() - self.makeTable() - - def remote_builderAdded(self, buildername, builder): - print "builderAdded", buildername - assert buildername not in self.buildernames - self.buildernames.append(buildername) - - b = ThreeRowBuilder(buildername, builder) - self.builders[buildername] = b - self.rebuildTable() - b.getLastBuild() - b.getState() - - def remote_builderRemoved(self, buildername): - del self.builders[buildername] - self.buildernames.remove(buildername) - self.rebuildTable() - - def remote_builderChangedState(self, name, state, eta): - self.builders[name].gotState((state, eta, None)) - def remote_buildStarted(self, name, build): - self.builders[name].buildStarted(build) - def remote_buildFinished(self, name, build, results): - self.builders[name].buildFinished(build, results) - - def remote_buildETAUpdate(self, name, build, eta): - self.builders[name].buildETAUpdate(eta) - def remote_stepStarted(self, name, build, stepname, step): - self.builders[name].stepStarted(stepname, step) - def remote_stepFinished(self, name, build, stepname, step, results): - self.builders[name].stepFinished(stepname, step, results) - - def remote_stepETAUpdate(self, name, build, stepname, step, - eta, expectations): - # expectations is a list of (metricname, current_value, - # expected_value) tuples, so that we could show individual progress - # meters for each metric - self.builders[name].stepETAUpdate(stepname, eta) - - def remote_logStarted(self, buildername, build, stepname, step, - logname, log): - pass - - def remote_logFinished(self, buildername, build, stepname, step, - logname, log): - pass - - -class GtkClient(TextClient): - ClientClass = ThreeRowClient - - def __init__(self, master): - self.master = master - - w = gtk.Window() - self.w = w - #w.set_size_request(64,64) - w.connect('destroy', lambda win: gtk.main_quit()) - self.vb = gtk.VBox(False, 2) - self.status = gtk.Label("unconnected") - self.vb.add(self.status) - self.listener = self.ClientClass(self) - w.add(self.vb) - w.show_all() - - def connected(self, ref): - self.status.set_text("connected") - TextClient.connected(self, ref) - -""" - def addBuilder(self, name, builder): - Client.addBuilder(self, name, builder) - self.pane.addBuilder(builder) - def removeBuilder(self, name): - self.pane.removeBuilder(name, self.builders[name]) - Client.removeBuilder(self, name) - - def startConnecting(self, master): - self.master = master - Client.startConnecting(self, master) - self.status.set_text("connecting to %s.." % master) - def connected(self, remote): - Client.connected(self, remote) - self.status.set_text(self.master) - remote.notifyOnDisconnect(self.disconnected) - def disconnected(self, remote): - self.status.set_text("disconnected, will retry") -""" - -def main(): - master = "localhost:8007" - if len(sys.argv) > 1: - master = sys.argv[1] - c = GtkClient(master) - c.run() - -if __name__ == '__main__': - main() - diff --git a/tools/buildbot/pylibs/buildbot/clients/sendchange.py b/tools/buildbot/pylibs/buildbot/clients/sendchange.py deleted file mode 100644 index 6a01f4e..0000000 --- a/tools/buildbot/pylibs/buildbot/clients/sendchange.py +++ /dev/null @@ -1,48 +0,0 @@ - -from twisted.spread import pb -from twisted.cred import credentials -from twisted.internet import reactor - -class Sender: - def __init__(self, master, user=None): - self.user = user - self.host, self.port = master.split(":") - self.port = int(self.port) - self.num_changes = 0 - - def send(self, branch, revision, comments, files, user=None): - if user is None: - user = self.user - change = {'who': user, 'files': files, 'comments': comments, - 'branch': branch, 'revision': revision} - self.num_changes += 1 - - f = pb.PBClientFactory() - d = f.login(credentials.UsernamePassword("change", "changepw")) - reactor.connectTCP(self.host, self.port, f) - d.addCallback(self.addChange, change) - return d - - def addChange(self, remote, change): - d = remote.callRemote('addChange', change) - d.addCallback(lambda res: remote.broker.transport.loseConnection()) - return d - - def printSuccess(self, res): - if self.num_changes > 1: - print "%d changes sent successfully" % self.num_changes - elif self.num_changes == 1: - print "change sent successfully" - else: - print "no changes to send" - - def printFailure(self, why): - print "change(s) NOT sent, something went wrong:" - print why - - def stop(self, res): - reactor.stop() - return res - - def run(self): - reactor.run() diff --git a/tools/buildbot/pylibs/buildbot/dnotify.py b/tools/buildbot/pylibs/buildbot/dnotify.py deleted file mode 100644 index d23d600..0000000 --- a/tools/buildbot/pylibs/buildbot/dnotify.py +++ /dev/null @@ -1,102 +0,0 @@ - -# spiv wants this - -import fcntl, signal - -class DNotify_Handler: - def __init__(self): - self.watchers = {} - self.installed = 0 - def install(self): - if self.installed: - return - signal.signal(signal.SIGIO, self.fire) - self.installed = 1 - def uninstall(self): - if not self.installed: - return - signal.signal(signal.SIGIO, signal.SIG_DFL) - self.installed = 0 - def add(self, watcher): - self.watchers[watcher.fd.fileno()] = watcher - self.install() - def remove(self, watcher): - if self.watchers.has_key(watcher.fd.fileno()): - del(self.watchers[watcher.fd.fileno()]) - if not self.watchers: - self.uninstall() - def fire(self, signum, frame): - # this is the signal handler - # without siginfo_t, we must fire them all - for watcher in self.watchers.values(): - watcher.callback() - -class DNotify: - DN_ACCESS = fcntl.DN_ACCESS # a file in the directory was read - DN_MODIFY = fcntl.DN_MODIFY # a file was modified (write,truncate) - DN_CREATE = fcntl.DN_CREATE # a file was created - DN_DELETE = fcntl.DN_DELETE # a file was unlinked - DN_RENAME = fcntl.DN_RENAME # a file was renamed - DN_ATTRIB = fcntl.DN_ATTRIB # a file had attributes changed (chmod,chown) - - handler = [None] - - def __init__(self, dirname, callback=None, - flags=[DN_MODIFY,DN_CREATE,DN_DELETE,DN_RENAME]): - - """This object watches a directory for changes. The .callback - attribute should be set to a function to be run every time something - happens to it. Be aware that it will be called more times than you - expect.""" - - if callback: - self.callback = callback - else: - self.callback = self.fire - self.dirname = dirname - self.flags = reduce(lambda x, y: x | y, flags) | fcntl.DN_MULTISHOT - self.fd = open(dirname, "r") - # ideally we would move the notification to something like SIGRTMIN, - # (to free up SIGIO) and use sigaction to have the signal handler - # receive a structure with the fd number. But python doesn't offer - # either. - if not self.handler[0]: - self.handler[0] = DNotify_Handler() - self.handler[0].add(self) - fcntl.fcntl(self.fd, fcntl.F_NOTIFY, self.flags) - def remove(self): - self.handler[0].remove(self) - self.fd.close() - def fire(self): - print self.dirname, "changed!" - -def test_dnotify1(): - d = DNotify(".") - while 1: - signal.pause() - -def test_dnotify2(): - # create ./foo/, create/delete files in ./ and ./foo/ while this is - # running. Notice how both notifiers are fired when anything changes; - # this is an unfortunate side-effect of the lack of extended sigaction - # support in Python. - count = [0] - d1 = DNotify(".") - def fire1(count=count, d1=d1): - print "./ changed!", count[0] - count[0] += 1 - if count[0] > 5: - d1.remove() - del(d1) - # change the callback, since we can't define it until after we have the - # dnotify object. Hmm, unless we give the dnotify to the callback. - d1.callback = fire1 - def fire2(): print "foo/ changed!" - d2 = DNotify("foo", fire2) - while 1: - signal.pause() - - -if __name__ == '__main__': - test_dnotify2() - diff --git a/tools/buildbot/pylibs/buildbot/interfaces.py b/tools/buildbot/pylibs/buildbot/interfaces.py deleted file mode 100644 index 4b68fcf..0000000 --- a/tools/buildbot/pylibs/buildbot/interfaces.py +++ /dev/null @@ -1,1070 +0,0 @@ - -"""Interface documentation. - -Define the interfaces that are implemented by various buildbot classes. -""" - -from zope.interface import Interface - -# exceptions that can be raised while trying to start a build -class NoSlaveError(Exception): - pass -class BuilderInUseError(Exception): - pass -class BuildSlaveTooOldError(Exception): - pass - -class IChangeSource(Interface): - """Object which feeds Change objects to the changemaster. When files or - directories are changed and the version control system provides some - kind of notification, this object should turn it into a Change object - and pass it through:: - - self.changemaster.addChange(change) - """ - - def start(): - """Called when the buildmaster starts. Can be used to establish - connections to VC daemons or begin polling.""" - - def stop(): - """Called when the buildmaster shuts down. Connections should be - terminated, polling timers should be canceled.""" - - def describe(): - """Should return a string which briefly describes this source. This - string will be displayed in an HTML status page.""" - -class IScheduler(Interface): - """I watch for Changes in the source tree and decide when to trigger - Builds. I create BuildSet objects and submit them to the BuildMaster. I - am a service, and the BuildMaster is always my parent. - - @ivar properties: properties to be applied to all builds started by this - scheduler - @type properties: L - """ - - def addChange(change): - """A Change has just been dispatched by one of the ChangeSources. - Each Scheduler will receive this Change. I may decide to start a - build as a result, or I might choose to ignore it.""" - - def listBuilderNames(): - """Return a list of strings indicating the Builders that this - Scheduler might feed.""" - - def getPendingBuildTimes(): - """Return a list of timestamps for any builds that are waiting in the - tree-stable-timer queue. This is only relevant for Change-based - schedulers, all others can just return an empty list.""" - # TODO: it might be nice to make this into getPendingBuildSets, which - # would let someone subscribe to the buildset being finished. - # However, the Scheduler doesn't actually create the buildset until - # it gets submitted, so doing this would require some major rework. - -class IUpstreamScheduler(Interface): - """This marks an IScheduler as being eligible for use as the 'upstream=' - argument to a buildbot.scheduler.Dependent instance.""" - - def subscribeToSuccessfulBuilds(target): - """Request that the target callbable be invoked after every - successful buildset. The target will be called with a single - argument: the SourceStamp used by the successful builds.""" - - def listBuilderNames(): - """Return a list of strings indicating the Builders that this - Scheduler might feed.""" - -class ISourceStamp(Interface): - """ - @cvar branch: branch from which source was drawn - @type branch: string or None - - @cvar revision: revision of the source, or None to use CHANGES - @type revision: varies depending on VC - - @cvar patch: patch applied to the source, or None if no patch - @type patch: None or tuple (level diff) - - @cvar changes: the source step should check out hte latest revision - in the given changes - @type changes: tuple of L{buildbot.changes.changes.Change} instances, - all of which are on the same branch - """ - - def canBeMergedWith(self, other): - """ - Can this SourceStamp be merged with OTHER? - """ - - def mergeWith(self, others): - """Generate a SourceStamp for the merger of me and all the other - BuildRequests. This is called by a Build when it starts, to figure - out what its sourceStamp should be.""" - - def getAbsoluteSourceStamp(self, got_revision): - """Get a new SourceStamp object reflecting the actual revision found - by a Source step.""" - - def getText(self): - """Returns a list of strings to describe the stamp. These are - intended to be displayed in a narrow column. If more space is - available, the caller should join them together with spaces before - presenting them to the user.""" - -class IEmailSender(Interface): - """I know how to send email, and can be used by other parts of the - Buildbot to contact developers.""" - pass - -class IEmailLookup(Interface): - def getAddress(user): - """Turn a User-name string into a valid email address. Either return - a string (with an @ in it), None (to indicate that the user cannot - be reached by email), or a Deferred which will fire with the same.""" - -class IStatus(Interface): - """I am an object, obtainable from the buildmaster, which can provide - status information.""" - - def getProjectName(): - """Return the name of the project that this Buildbot is working - for.""" - def getProjectURL(): - """Return the URL of this Buildbot's project.""" - def getBuildbotURL(): - """Return the URL of the top-most Buildbot status page, or None if - this Buildbot does not provide a web status page.""" - def getURLForThing(thing): - """Return the URL of a page which provides information on 'thing', - which should be an object that implements one of the status - interfaces defined in L{buildbot.interfaces}. Returns None if no - suitable page is available (or if no Waterfall is running).""" - - def getChangeSources(): - """Return a list of IChangeSource objects.""" - - def getChange(number): - """Return an IChange object.""" - - def getSchedulers(): - """Return a list of ISchedulerStatus objects for all - currently-registered Schedulers.""" - - def getBuilderNames(categories=None): - """Return a list of the names of all current Builders.""" - def getBuilder(name): - """Return the IBuilderStatus object for a given named Builder. Raises - KeyError if there is no Builder by that name.""" - - def getSlaveNames(): - """Return a list of buildslave names, suitable for passing to - getSlave().""" - def getSlave(name): - """Return the ISlaveStatus object for a given named buildslave.""" - - def getBuildSets(): - """Return a list of active (non-finished) IBuildSetStatus objects.""" - - def generateFinishedBuilds(builders=[], branches=[], - num_builds=None, finished_before=None, - max_search=200): - """Return a generator that will produce IBuildStatus objects each - time you invoke its .next() method, starting with the most recent - finished build and working backwards. - - @param builders: this is a list of Builder names, and the generator - will only produce builds that ran on the given - Builders. If the list is empty, produce builds from - all Builders. - - @param branches: this is a list of branch names, and the generator - will only produce builds that used the given - branches. If the list is empty, produce builds from - all branches. - - @param num_builds: the generator will stop after providing this many - builds. The default of None means to produce as - many builds as possible. - - @type finished_before: int: a timestamp, seconds since the epoch - @param finished_before: if provided, do not produce any builds that - finished after the given timestamp. - - @type max_search: int - @param max_search: this method may have to examine a lot of builds - to find some that match the search parameters, - especially if there aren't any matching builds. - This argument imposes a hard limit on the number - of builds that will be examined within any given - Builder. - """ - - def subscribe(receiver): - """Register an IStatusReceiver to receive new status events. The - receiver will immediately be sent a set of 'builderAdded' messages - for all current builders. It will receive further 'builderAdded' and - 'builderRemoved' messages as the config file is reloaded and builders - come and go. It will also receive 'buildsetSubmitted' messages for - all outstanding BuildSets (and each new BuildSet that gets - submitted). No additional messages will be sent unless the receiver - asks for them by calling .subscribe on the IBuilderStatus objects - which accompany the addedBuilder message.""" - - def unsubscribe(receiver): - """Unregister an IStatusReceiver. No further status messgaes will be - delivered.""" - -class IBuildSetStatus(Interface): - """I represent a set of Builds, each run on a separate Builder but all - using the same source tree.""" - - def getSourceStamp(): - """Return a SourceStamp object which can be used to re-create - the source tree that this build used. - - This method will return None if the source information is no longer - available.""" - pass - def getReason(): - pass - def getID(): - """Return the BuildSet's ID string, if any. The 'try' feature uses a - random string as a BuildSetID to relate submitted jobs with the - resulting BuildSet.""" - def getResponsibleUsers(): - pass # not implemented - def getInterestedUsers(): - pass # not implemented - def getBuilderNames(): - """Return a list of the names of all Builders on which this set will - do builds.""" - def getBuildRequests(): - """Return a list of IBuildRequestStatus objects that represent my - component Builds. This list might correspond to the Builders named by - getBuilderNames(), but if builder categories are used, or 'Builder - Aliases' are implemented, then they may not.""" - def isFinished(): - pass - def waitUntilSuccess(): - """Return a Deferred that fires (with this IBuildSetStatus object) - when the outcome of the BuildSet is known, i.e., upon the first - failure, or after all builds complete successfully.""" - def waitUntilFinished(): - """Return a Deferred that fires (with this IBuildSetStatus object) - when all builds have finished.""" - def getResults(): - pass - -class IBuildRequestStatus(Interface): - """I represent a request to build a particular set of source code on a - particular Builder. These requests may be merged by the time they are - finally turned into a Build.""" - - def getSourceStamp(): - """Return a SourceStamp object which can be used to re-create - the source tree that this build used. This method will - return an absolute SourceStamp if possible, and its results - may change as the build progresses. Specifically, a "HEAD" - build may later be more accurately specified by an absolute - SourceStamp with the specific revision information. - - This method will return None if the source information is no longer - available.""" - pass - def getBuilderName(): - pass - def getBuilds(): - """Return a list of IBuildStatus objects for each Build that has been - started in an attempt to satify this BuildRequest.""" - - def subscribe(observer): - """Register a callable that will be invoked (with a single - IBuildStatus object) for each Build that is created to satisfy this - request. There may be multiple Builds created in an attempt to handle - the request: they may be interrupted by the user or abandoned due to - a lost slave. The last Build (the one which actually gets to run to - completion) is said to 'satisfy' the BuildRequest. The observer will - be called once for each of these Builds, both old and new.""" - def unsubscribe(observer): - """Unregister the callable that was registered with subscribe().""" - - -class ISlaveStatus(Interface): - def getName(): - """Return the name of the build slave.""" - - def getAdmin(): - """Return a string with the slave admin's contact data.""" - - def getHost(): - """Return a string with the slave host info.""" - - def isConnected(): - """Return True if the slave is currently online, False if not.""" - - def lastMessageReceived(): - """Return a timestamp (seconds since epoch) indicating when the most - recent message was received from the buildslave.""" - -class ISchedulerStatus(Interface): - def getName(): - """Return the name of this Scheduler (a string).""" - - def getPendingBuildsets(): - """Return an IBuildSet for all BuildSets that are pending. These - BuildSets are waiting for their tree-stable-timers to expire.""" - # TODO: this is not implemented anywhere - - -class IBuilderStatus(Interface): - def getName(): - """Return the name of this Builder (a string).""" - - def getState(): - # TODO: this isn't nearly as meaningful as it used to be - """Return a tuple (state, builds) for this Builder. 'state' is the - so-called 'big-status', indicating overall status (as opposed to - which step is currently running). It is a string, one of 'offline', - 'idle', or 'building'. 'builds' is a list of IBuildStatus objects - (possibly empty) representing the currently active builds.""" - - def getSlaves(): - """Return a list of ISlaveStatus objects for the buildslaves that are - used by this builder.""" - - def getPendingBuilds(): - """Return an IBuildRequestStatus object for all upcoming builds - (those which are ready to go but which are waiting for a buildslave - to be available.""" - - def getCurrentBuilds(): - """Return a list containing an IBuildStatus object for each build - currently in progress.""" - # again, we could probably provide an object for 'waiting' and - # 'interlocked' too, but things like the Change list might still be - # subject to change - - def getLastFinishedBuild(): - """Return the IBuildStatus object representing the last finished - build, which may be None if the builder has not yet finished any - builds.""" - - def getBuild(number): - """Return an IBuildStatus object for a historical build. Each build - is numbered (starting at 0 when the Builder is first added), - getBuild(n) will retrieve the Nth such build. getBuild(-n) will - retrieve a recent build, with -1 being the most recent build - started. If the Builder is idle, this will be the same as - getLastFinishedBuild(). If the Builder is active, it will be an - unfinished build. This method will return None if the build is no - longer available. Older builds are likely to have less information - stored: Logs are the first to go, then Steps.""" - - def getEvent(number): - """Return an IStatusEvent object for a recent Event. Builders - connecting and disconnecting are events, as are ping attempts. - getEvent(-1) will return the most recent event. Events are numbered, - but it probably doesn't make sense to ever do getEvent(+n).""" - - def generateFinishedBuilds(branches=[], - num_builds=None, - max_buildnum=None, finished_before=None, - max_search=200, - ): - """Return a generator that will produce IBuildStatus objects each - time you invoke its .next() method, starting with the most recent - finished build, then the previous build, and so on back to the oldest - build available. - - @param branches: this is a list of branch names, and the generator - will only produce builds that involve the given - branches. If the list is empty, the generator will - produce all builds regardless of what branch they - used. - - @param num_builds: if provided, the generator will stop after - providing this many builds. The default of None - means to produce as many builds as possible. - - @param max_buildnum: if provided, the generator will start by - providing the build with this number, or the - highest-numbered preceding build (i.e. the - generator will not produce any build numbered - *higher* than max_buildnum). The default of None - means to start with the most recent finished - build. -1 means the same as None. -2 means to - start with the next-most-recent completed build, - etc. - - @type finished_before: int: a timestamp, seconds since the epoch - @param finished_before: if provided, do not produce any builds that - finished after the given timestamp. - - @type max_search: int - @param max_search: this method may have to examine a lot of builds - to find some that match the search parameters, - especially if there aren't any matching builds. - This argument imposes a hard limit on the number - of builds that will be examined. - """ - - def subscribe(receiver): - """Register an IStatusReceiver to receive new status events. The - receiver will be given builderChangedState, buildStarted, and - buildFinished messages.""" - - def unsubscribe(receiver): - """Unregister an IStatusReceiver. No further status messgaes will be - delivered.""" - -class IEventSource(Interface): - def eventGenerator(branches=[]): - """This function creates a generator which will yield all of this - object's status events, starting with the most recent and progressing - backwards in time. These events provide the IStatusEvent interface. - At the moment they are all instances of buildbot.status.builder.Event - or buildbot.status.builder.BuildStepStatus . - - @param branches: a list of branch names. The generator should only - return events that are associated with these branches. If the list is - empty, events for all branches should be returned (i.e. an empty list - means 'accept all' rather than 'accept none'). - """ - -class IBuildStatus(Interface): - """I represent the status of a single Build/BuildRequest. It could be - in-progress or finished.""" - - def getBuilder(): - """ - Return the BuilderStatus that owns this build. - - @rtype: implementor of L{IBuilderStatus} - """ - - def isFinished(): - """Return a boolean. True means the build has finished, False means - it is still running.""" - - def waitUntilFinished(): - """Return a Deferred that will fire when the build finishes. If the - build has already finished, this deferred will fire right away. The - callback is given this IBuildStatus instance as an argument.""" - - def getProperty(propname): - """Return the value of the build property with the given name. Raises - KeyError if there is no such property on this build.""" - - def getReason(): - """Return a string that indicates why the build was run. 'changes', - 'forced', and 'periodic' are the most likely values. 'try' will be - added in the future.""" - - def getSourceStamp(): - """Return a SourceStamp object which can be used to re-create - the source tree that this build used. - - This method will return None if the source information is no longer - available.""" - # TODO: it should be possible to expire the patch but still remember - # that the build was r123+something. - - def getChanges(): - """Return a list of Change objects which represent which source - changes went into the build.""" - - def getResponsibleUsers(): - """Return a list of Users who are to blame for the changes that went - into this build. If anything breaks (at least anything that wasn't - already broken), blame them. Specifically, this is the set of users - who were responsible for the Changes that went into this build. Each - User is a string, corresponding to their name as known by the VC - repository.""" - - def getInterestedUsers(): - """Return a list of Users who will want to know about the results of - this build. This is a superset of getResponsibleUsers(): it adds - people who are interested in this build but who did not actually - make the Changes that went into it (build sheriffs, code-domain - owners).""" - - def getNumber(): - """Within each builder, each Build has a number. Return it.""" - - def getPreviousBuild(): - """Convenience method. Returns None if the previous build is - unavailable.""" - - def getSteps(): - """Return a list of IBuildStepStatus objects. For invariant builds - (those which always use the same set of Steps), this should always - return the complete list, however some of the steps may not have - started yet (step.getTimes()[0] will be None). For variant builds, - this may not be complete (asking again later may give you more of - them).""" - - def getTimes(): - """Returns a tuple of (start, end). 'start' and 'end' are the times - (seconds since the epoch) when the Build started and finished. If - the build is still running, 'end' will be None.""" - - # while the build is running, the following methods make sense. - # Afterwards they return None - - def getETA(): - """Returns the number of seconds from now in which the build is - expected to finish, or None if we can't make a guess. This guess will - be refined over time.""" - - def getCurrentStep(): - """Return an IBuildStepStatus object representing the currently - active step.""" - - # Once you know the build has finished, the following methods are legal. - # Before ths build has finished, they all return None. - - def getSlavename(): - """Return the name of the buildslave which handled this build.""" - - def getText(): - """Returns a list of strings to describe the build. These are - intended to be displayed in a narrow column. If more space is - available, the caller should join them together with spaces before - presenting them to the user.""" - - def getColor(): - """Returns a single string with the color that should be used to - display the build. 'green', 'orange', or 'red' are the most likely - ones.""" - - def getResults(): - """Return a constant describing the results of the build: one of the - constants in buildbot.status.builder: SUCCESS, WARNINGS, or - FAILURE.""" - - def getLogs(): - """Return a list of logs that describe the build as a whole. Some - steps will contribute their logs, while others are are less important - and will only be accessible through the IBuildStepStatus objects. - Each log is an object which implements the IStatusLog interface.""" - - def getTestResults(): - """Return a dictionary that maps test-name tuples to ITestResult - objects. This may return an empty or partially-filled dictionary - until the build has completed.""" - - # subscription interface - - def subscribe(receiver, updateInterval=None): - """Register an IStatusReceiver to receive new status events. The - receiver will be given stepStarted and stepFinished messages. If - 'updateInterval' is non-None, buildETAUpdate messages will be sent - every 'updateInterval' seconds.""" - - def unsubscribe(receiver): - """Unregister an IStatusReceiver. No further status messgaes will be - delivered.""" - -class ITestResult(Interface): - """I describe the results of a single unit test.""" - - def getName(): - """Returns a tuple of strings which make up the test name. Tests may - be arranged in a hierarchy, so looking for common prefixes may be - useful.""" - - def getResults(): - """Returns a constant describing the results of the test: SUCCESS, - WARNINGS, FAILURE.""" - - def getText(): - """Returns a list of short strings which describe the results of the - test in slightly more detail. Suggested components include - 'failure', 'error', 'passed', 'timeout'.""" - - def getLogs(): - # in flux, it may be possible to provide more structured information - # like python Failure instances - """Returns a dictionary of test logs. The keys are strings like - 'stdout', 'log', 'exceptions'. The values are strings.""" - - -class IBuildStepStatus(Interface): - """I hold status for a single BuildStep.""" - - def getName(): - """Returns a short string with the name of this step. This string - may have spaces in it.""" - - def getBuild(): - """Returns the IBuildStatus object which contains this step.""" - - def getTimes(): - """Returns a tuple of (start, end). 'start' and 'end' are the times - (seconds since the epoch) when the Step started and finished. If the - step has not yet started, 'start' will be None. If the step is still - running, 'end' will be None.""" - - def getExpectations(): - """Returns a list of tuples (name, current, target). Each tuple - describes a single axis along which the step's progress can be - measured. 'name' is a string which describes the axis itself, like - 'filesCompiled' or 'tests run' or 'bytes of output'. 'current' is a - number with the progress made so far, while 'target' is the value - that we expect (based upon past experience) to get to when the build - is finished. - - 'current' will change over time until the step is finished. It is - 'None' until the step starts. When the build is finished, 'current' - may or may not equal 'target' (which is merely the expectation based - upon previous builds).""" - - def getURLs(): - """Returns a dictionary of URLs. Each key is a link name (a short - string, like 'results' or 'coverage'), and each value is a URL. These - links will be displayed along with the LogFiles. - """ - - def getLogs(): - """Returns a list of IStatusLog objects. If the step has not yet - finished, this list may be incomplete (asking again later may give - you more of them).""" - - - def isFinished(): - """Return a boolean. True means the step has finished, False means it - is still running.""" - - def waitUntilFinished(): - """Return a Deferred that will fire when the step finishes. If the - step has already finished, this deferred will fire right away. The - callback is given this IBuildStepStatus instance as an argument.""" - - # while the step is running, the following methods make sense. - # Afterwards they return None - - def getETA(): - """Returns the number of seconds from now in which the step is - expected to finish, or None if we can't make a guess. This guess will - be refined over time.""" - - # Once you know the step has finished, the following methods are legal. - # Before ths step has finished, they all return None. - - def getText(): - """Returns a list of strings which describe the step. These are - intended to be displayed in a narrow column. If more space is - available, the caller should join them together with spaces before - presenting them to the user.""" - - def getColor(): - """Returns a single string with the color that should be used to - display this step. 'green', 'orange', 'red' and 'yellow' are the - most likely ones.""" - - def getResults(): - """Return a tuple describing the results of the step: (result, - strings). 'result' is one of the constants in - buildbot.status.builder: SUCCESS, WARNINGS, FAILURE, or SKIPPED. - 'strings' is an optional list of strings that the step wants to - append to the overall build's results. These strings are usually - more terse than the ones returned by getText(): in particular, - successful Steps do not usually contribute any text to the overall - build.""" - - # subscription interface - - def subscribe(receiver, updateInterval=10): - """Register an IStatusReceiver to receive new status events. The - receiver will be given logStarted and logFinished messages. It will - also be given a ETAUpdate message every 'updateInterval' seconds.""" - - def unsubscribe(receiver): - """Unregister an IStatusReceiver. No further status messgaes will be - delivered.""" - -class IStatusEvent(Interface): - """I represent a Builder Event, something non-Build related that can - happen to a Builder.""" - - def getTimes(): - """Returns a tuple of (start, end) like IBuildStepStatus, but end==0 - indicates that this is a 'point event', which has no duration. - SlaveConnect/Disconnect are point events. Ping is not: it starts - when requested and ends when the response (positive or negative) is - returned""" - - def getText(): - """Returns a list of strings which describe the event. These are - intended to be displayed in a narrow column. If more space is - available, the caller should join them together with spaces before - presenting them to the user.""" - - def getColor(): - """Returns a single string with the color that should be used to - display this event. 'red' and 'yellow' are the most likely ones.""" - - -LOG_CHANNEL_STDOUT = 0 -LOG_CHANNEL_STDERR = 1 -LOG_CHANNEL_HEADER = 2 - -class IStatusLog(Interface): - """I represent a single Log, which is a growing list of text items that - contains some kind of output for a single BuildStep. I might be finished, - in which case this list has stopped growing. - - Each Log has a name, usually something boring like 'log' or 'output'. - These names are not guaranteed to be unique, however they are usually - chosen to be useful within the scope of a single step (i.e. the Compile - step might produce both 'log' and 'warnings'). The name may also have - spaces. If you want something more globally meaningful, at least within a - given Build, try:: - - '%s.%s' % (log.getStep.getName(), log.getName()) - - The Log can be presented as plain text, or it can be accessed as a list - of items, each of which has a channel indicator (header, stdout, stderr) - and a text chunk. An HTML display might represent the interleaved - channels with different styles, while a straight download-the-text - interface would just want to retrieve a big string. - - The 'header' channel is used by ShellCommands to prepend a note about - which command is about to be run ('running command FOO in directory - DIR'), and append another note giving the exit code of the process. - - Logs can be streaming: if the Log has not yet finished, you can - subscribe to receive new chunks as they are added. - - A ShellCommand will have a Log associated with it that gathers stdout - and stderr. Logs may also be created by parsing command output or - through other synthetic means (grepping for all the warnings in a - compile log, or listing all the test cases that are going to be run). - Such synthetic Logs are usually finished as soon as they are created.""" - - - def getName(): - """Returns a short string with the name of this log, probably 'log'. - """ - - def getStep(): - """Returns the IBuildStepStatus which owns this log.""" - # TODO: can there be non-Step logs? - - def isFinished(): - """Return a boolean. True means the log has finished and is closed, - False means it is still open and new chunks may be added to it.""" - - def waitUntilFinished(): - """Return a Deferred that will fire when the log is closed. If the - log has already finished, this deferred will fire right away. The - callback is given this IStatusLog instance as an argument.""" - - def subscribe(receiver, catchup): - """Register an IStatusReceiver to receive chunks (with logChunk) as - data is added to the Log. If you use this, you will also want to use - waitUntilFinished to find out when the listener can be retired. - Subscribing to a closed Log is a no-op. - - If 'catchup' is True, the receiver will immediately be sent a series - of logChunk messages to bring it up to date with the partially-filled - log. This allows a status client to join a Log already in progress - without missing any data. If the Log has already finished, it is too - late to catch up: just do getText() instead. - - If the Log is very large, the receiver will be called many times with - a lot of data. There is no way to throttle this data. If the receiver - is planning on sending the data on to somewhere else, over a narrow - connection, you can get a throttleable subscription by using - C{subscribeConsumer} instead.""" - - def unsubscribe(receiver): - """Remove a receiver previously registered with subscribe(). Attempts - to remove a receiver which was not previously registered is a no-op. - """ - - def subscribeConsumer(consumer): - """Register an L{IStatusLogConsumer} to receive all chunks of the - logfile, including all the old entries and any that will arrive in - the future. The consumer will first have their C{registerProducer} - method invoked with a reference to an object that can be told - C{pauseProducing}, C{resumeProducing}, and C{stopProducing}. Then the - consumer's C{writeChunk} method will be called repeatedly with each - (channel, text) tuple in the log, starting with the very first. The - consumer will be notified with C{finish} when the log has been - exhausted (which can only happen when the log is finished). Note that - a small amount of data could be written via C{writeChunk} even after - C{pauseProducing} has been called. - - To unsubscribe the consumer, use C{producer.stopProducing}.""" - - # once the log has finished, the following methods make sense. They can - # be called earlier, but they will only return the contents of the log up - # to the point at which they were called. You will lose items that are - # added later. Use C{subscribe} or C{subscribeConsumer} to avoid missing - # anything. - - def hasContents(): - """Returns True if the LogFile still has contents available. Returns - False for logs that have been pruned. Clients should test this before - offering to show the contents of any log.""" - - def getText(): - """Return one big string with the contents of the Log. This merges - all non-header chunks together.""" - - def readlines(channel=LOG_CHANNEL_STDOUT): - """Read lines from one channel of the logfile. This returns an - iterator that will provide single lines of text (including the - trailing newline). - """ - - def getTextWithHeaders(): - """Return one big string with the contents of the Log. This merges - all chunks (including headers) together.""" - - def getChunks(): - """Generate a list of (channel, text) tuples. 'channel' is a number, - 0 for stdout, 1 for stderr, 2 for header. (note that stderr is merged - into stdout if PTYs are in use).""" - -class IStatusLogConsumer(Interface): - """I am an object which can be passed to IStatusLog.subscribeConsumer(). - I represent a target for writing the contents of an IStatusLog. This - differs from a regular IStatusReceiver in that it can pause the producer. - This makes it more suitable for use in streaming data over network - sockets, such as an HTTP request. Note that the consumer can only pause - the producer until it has caught up with all the old data. After that - point, C{pauseProducing} is ignored and all new output from the log is - sent directoy to the consumer.""" - - def registerProducer(producer, streaming): - """A producer is being hooked up to this consumer. The consumer only - has to handle a single producer. It should send .pauseProducing and - .resumeProducing messages to the producer when it wants to stop or - resume the flow of data. 'streaming' will be set to True because the - producer is always a PushProducer. - """ - - def unregisterProducer(): - """The previously-registered producer has been removed. No further - pauseProducing or resumeProducing calls should be made. The consumer - should delete its reference to the Producer so it can be released.""" - - def writeChunk(chunk): - """A chunk (i.e. a tuple of (channel, text)) is being written to the - consumer.""" - - def finish(): - """The log has finished sending chunks to the consumer.""" - -class IStatusReceiver(Interface): - """I am an object which can receive build status updates. I may be - subscribed to an IStatus, an IBuilderStatus, or an IBuildStatus.""" - - def buildsetSubmitted(buildset): - """A new BuildSet has been submitted to the buildmaster. - - @type buildset: implementor of L{IBuildSetStatus} - """ - - def builderAdded(builderName, builder): - """ - A new Builder has just been added. This method may return an - IStatusReceiver (probably 'self') which will be subscribed to receive - builderChangedState and buildStarted/Finished events. - - @type builderName: string - @type builder: L{buildbot.status.builder.BuilderStatus} - @rtype: implementor of L{IStatusReceiver} - """ - - def builderChangedState(builderName, state): - """Builder 'builderName' has changed state. The possible values for - 'state' are 'offline', 'idle', and 'building'.""" - - def buildStarted(builderName, build): - """Builder 'builderName' has just started a build. The build is an - object which implements IBuildStatus, and can be queried for more - information. - - This method may return an IStatusReceiver (it could even return - 'self'). If it does so, stepStarted and stepFinished methods will be - invoked on the object for the steps of this one build. This is a - convenient way to subscribe to all build steps without missing any. - This receiver will automatically be unsubscribed when the build - finishes. - - It can also return a tuple of (IStatusReceiver, interval), in which - case buildETAUpdate messages are sent ever 'interval' seconds, in - addition to the stepStarted and stepFinished messages.""" - - def buildETAUpdate(build, ETA): - """This is a periodic update on the progress this Build has made - towards completion.""" - - def stepStarted(build, step): - """A step has just started. 'step' is the IBuildStepStatus which - represents the step: it can be queried for more information. - - This method may return an IStatusReceiver (it could even return - 'self'). If it does so, logStarted and logFinished methods will be - invoked on the object for logs created by this one step. This - receiver will be automatically unsubscribed when the step finishes. - - Alternatively, the method may return a tuple of an IStatusReceiver - and an integer named 'updateInterval'. In addition to - logStarted/logFinished messages, it will also receive stepETAUpdate - messages about every updateInterval seconds.""" - - def stepETAUpdate(build, step, ETA, expectations): - """This is a periodic update on the progress this Step has made - towards completion. It gets an ETA (in seconds from the present) of - when the step ought to be complete, and a list of expectation tuples - (as returned by IBuildStepStatus.getExpectations) with more detailed - information.""" - - def logStarted(build, step, log): - """A new Log has been started, probably because a step has just - started running a shell command. 'log' is the IStatusLog object - which can be queried for more information. - - This method may return an IStatusReceiver (such as 'self'), in which - case the target's logChunk method will be invoked as text is added to - the logfile. This receiver will automatically be unsubsribed when the - log finishes.""" - - def logChunk(build, step, log, channel, text): - """Some text has been added to this log. 'channel' is one of - LOG_CHANNEL_STDOUT, LOG_CHANNEL_STDERR, or LOG_CHANNEL_HEADER, as - defined in IStatusLog.getChunks.""" - - def logFinished(build, step, log): - """A Log has been closed.""" - - def stepFinished(build, step, results): - """A step has just finished. 'results' is the result tuple described - in IBuildStepStatus.getResults.""" - - def buildFinished(builderName, build, results): - """ - A build has just finished. 'results' is the result tuple described - in L{IBuildStatus.getResults}. - - @type builderName: string - @type build: L{buildbot.status.builder.BuildStatus} - @type results: tuple - """ - - def builderRemoved(builderName): - """The Builder has been removed.""" - -class IControl(Interface): - def addChange(change): - """Add a change to all builders. Each Builder will decide for - themselves whether the change is interesting or not, and may initiate - a build as a result.""" - - def submitBuildSet(buildset): - """Submit a BuildSet object, which will eventually be run on all of - the builders listed therein.""" - - def getBuilder(name): - """Retrieve the IBuilderControl object for the given Builder.""" - -class IBuilderControl(Interface): - def requestBuild(request): - """Queue a L{buildbot.process.base.BuildRequest} object for later - building.""" - - def requestBuildSoon(request): - """Submit a BuildRequest like requestBuild, but raise a - L{buildbot.interfaces.NoSlaveError} if no slaves are currently - available, so it cannot be used to queue a BuildRequest in the hopes - that a slave will eventually connect. This method is appropriate for - use by things like the web-page 'Force Build' button.""" - - def resubmitBuild(buildStatus, reason=""): - """Rebuild something we've already built before. This submits a - BuildRequest to our Builder using the same SourceStamp as the earlier - build. This has no effect (but may eventually raise an exception) if - this Build has not yet finished.""" - - def getPendingBuilds(): - """Return a list of L{IBuildRequestControl} objects for this Builder. - Each one corresponds to a pending build that has not yet started (due - to a scarcity of build slaves). These upcoming builds can be canceled - through the control object.""" - - def getBuild(number): - """Attempt to return an IBuildControl object for the given build. - Returns None if no such object is available. This will only work for - the build that is currently in progress: once the build finishes, - there is nothing to control anymore.""" - - def ping(timeout=30): - """Attempt to contact the slave and see if it is still alive. This - returns a Deferred which fires with either True (the slave is still - alive) or False (the slave did not respond). As a side effect, adds - an event to this builder's column in the waterfall display - containing the results of the ping.""" - # TODO: this ought to live in ISlaveControl, maybe with disconnect() - # or something. However the event that is emitted is most useful in - # the Builder column, so it kinda fits here too. - -class IBuildRequestControl(Interface): - def subscribe(observer): - """Register a callable that will be invoked (with a single - IBuildControl object) for each Build that is created to satisfy this - request. There may be multiple Builds created in an attempt to handle - the request: they may be interrupted by the user or abandoned due to - a lost slave. The last Build (the one which actually gets to run to - completion) is said to 'satisfy' the BuildRequest. The observer will - be called once for each of these Builds, both old and new.""" - def unsubscribe(observer): - """Unregister the callable that was registered with subscribe().""" - def cancel(): - """Remove the build from the pending queue. Has no effect if the - build has already been started.""" - -class IBuildControl(Interface): - def getStatus(): - """Return an IBuildStatus object for the Build that I control.""" - def stopBuild(reason=""): - """Halt the build. This has no effect if the build has already - finished.""" - -class ILogFile(Interface): - """This is the internal interface to a LogFile, used by the BuildStep to - write data into the log. - """ - def addStdout(data): - pass - def addStderr(data): - pass - def addHeader(data): - pass - def finish(): - """The process that is feeding the log file has finished, and no - further data will be added. This closes the logfile.""" - -class ILogObserver(Interface): - """Objects which provide this interface can be used in a BuildStep to - watch the output of a LogFile and parse it incrementally. - """ - - # internal methods - def setStep(step): - pass - def setLog(log): - pass - - # methods called by the LogFile - def logChunk(build, step, log, channel, text): - pass - -class IBuildSlave(Interface): - # this is a marker interface for the BuildSlave class - pass diff --git a/tools/buildbot/pylibs/buildbot/locks.py b/tools/buildbot/pylibs/buildbot/locks.py deleted file mode 100644 index 7e97a31..0000000 --- a/tools/buildbot/pylibs/buildbot/locks.py +++ /dev/null @@ -1,146 +0,0 @@ -# -*- test-case-name: buildbot.test.test_locks -*- - -from twisted.python import log -from twisted.internet import reactor, defer -from buildbot import util - -if False: # for debugging - debuglog = log.msg -else: - debuglog = lambda m: None - -class BaseLock: - description = "" - - def __init__(self, name, maxCount=1): - self.name = name - self.waiting = [] - self.owners = [] - self.maxCount=maxCount - - def __repr__(self): - return self.description - - def isAvailable(self): - debuglog("%s isAvailable: self.owners=%r" % (self, self.owners)) - return len(self.owners) < self.maxCount - - def claim(self, owner): - debuglog("%s claim(%s)" % (self, owner)) - assert owner is not None - assert len(self.owners) < self.maxCount, "ask for isAvailable() first" - self.owners.append(owner) - debuglog(" %s is claimed" % (self,)) - - def release(self, owner): - debuglog("%s release(%s)" % (self, owner)) - assert owner in self.owners - self.owners.remove(owner) - # who can we wake up? - if self.waiting: - d = self.waiting.pop(0) - reactor.callLater(0, d.callback, self) - - def waitUntilMaybeAvailable(self, owner): - """Fire when the lock *might* be available. The caller will need to - check with isAvailable() when the deferred fires. This loose form is - used to avoid deadlocks. If we were interested in a stronger form, - this would be named 'waitUntilAvailable', and the deferred would fire - after the lock had been claimed. - """ - debuglog("%s waitUntilAvailable(%s)" % (self, owner)) - if self.isAvailable(): - return defer.succeed(self) - d = defer.Deferred() - self.waiting.append(d) - return d - - -class RealMasterLock(BaseLock): - def __init__(self, lockid): - BaseLock.__init__(self, lockid.name, lockid.maxCount) - self.description = "" % (self.name, self.maxCount) - - def getLock(self, slave): - return self - -class RealSlaveLock: - def __init__(self, lockid): - self.name = lockid.name - self.maxCount = lockid.maxCount - self.maxCountForSlave = lockid.maxCountForSlave - self.description = "" % (self.name, - self.maxCount, - self.maxCountForSlave) - self.locks = {} - - def __repr__(self): - return self.description - - def getLock(self, slavebuilder): - slavename = slavebuilder.slave.slavename - if not self.locks.has_key(slavename): - maxCount = self.maxCountForSlave.get(slavename, - self.maxCount) - lock = self.locks[slavename] = BaseLock(self.name, maxCount) - desc = "" % (self.name, maxCount, - slavename, id(lock)) - lock.description = desc - self.locks[slavename] = lock - return self.locks[slavename] - - -# master.cfg should only reference the following MasterLock and SlaveLock -# classes. They are identifiers that will be turned into real Locks later, -# via the BotMaster.getLockByID method. - -class MasterLock(util.ComparableMixin): - """I am a semaphore that limits the number of simultaneous actions. - - Builds and BuildSteps can declare that they wish to claim me as they run. - Only a limited number of such builds or steps will be able to run - simultaneously. By default this number is one, but my maxCount parameter - can be raised to allow two or three or more operations to happen at the - same time. - - Use this to protect a resource that is shared among all builders and all - slaves, for example to limit the load on a common SVN repository. - """ - - compare_attrs = ['name', 'maxCount'] - lockClass = RealMasterLock - def __init__(self, name, maxCount=1): - self.name = name - self.maxCount = maxCount - -class SlaveLock(util.ComparableMixin): - """I am a semaphore that limits simultaneous actions on each buildslave. - - Builds and BuildSteps can declare that they wish to claim me as they run. - Only a limited number of such builds or steps will be able to run - simultaneously on any given buildslave. By default this number is one, - but my maxCount parameter can be raised to allow two or three or more - operations to happen on a single buildslave at the same time. - - Use this to protect a resource that is shared among all the builds taking - place on each slave, for example to limit CPU or memory load on an - underpowered machine. - - Each buildslave will get an independent copy of this semaphore. By - default each copy will use the same owner count (set with maxCount), but - you can provide maxCountForSlave with a dictionary that maps slavename to - owner count, to allow some slaves more parallelism than others. - - """ - - compare_attrs = ['name', 'maxCount', '_maxCountForSlaveList'] - lockClass = RealSlaveLock - def __init__(self, name, maxCount=1, maxCountForSlave={}): - self.name = name - self.maxCount = maxCount - self.maxCountForSlave = maxCountForSlave - # for comparison purposes, turn this dictionary into a stably-sorted - # list of tuples - self._maxCountForSlaveList = self.maxCountForSlave.items() - self._maxCountForSlaveList.sort() - self._maxCountForSlaveList = tuple(self._maxCountForSlaveList) diff --git a/tools/buildbot/pylibs/buildbot/manhole.py b/tools/buildbot/pylibs/buildbot/manhole.py deleted file mode 100644 index e5479b3..0000000 --- a/tools/buildbot/pylibs/buildbot/manhole.py +++ /dev/null @@ -1,265 +0,0 @@ - -import os.path -import binascii, base64 -from twisted.python import log -from twisted.application import service, strports -from twisted.cred import checkers, portal -from twisted.conch import manhole, telnet, manhole_ssh, checkers as conchc -from twisted.conch.insults import insults -from twisted.internet import protocol - -from buildbot.util import ComparableMixin -from zope.interface import implements # requires Twisted-2.0 or later - -# makeTelnetProtocol and _TelnetRealm are for the TelnetManhole - -class makeTelnetProtocol: - # this curries the 'portal' argument into a later call to - # TelnetTransport() - def __init__(self, portal): - self.portal = portal - - def __call__(self): - auth = telnet.AuthenticatingTelnetProtocol - return telnet.TelnetTransport(auth, self.portal) - -class _TelnetRealm: - implements(portal.IRealm) - - def __init__(self, namespace_maker): - self.namespace_maker = namespace_maker - - def requestAvatar(self, avatarId, *interfaces): - if telnet.ITelnetProtocol in interfaces: - namespace = self.namespace_maker() - p = telnet.TelnetBootstrapProtocol(insults.ServerProtocol, - manhole.ColoredManhole, - namespace) - return (telnet.ITelnetProtocol, p, lambda: None) - raise NotImplementedError() - - -class chainedProtocolFactory: - # this curries the 'namespace' argument into a later call to - # chainedProtocolFactory() - def __init__(self, namespace): - self.namespace = namespace - - def __call__(self): - return insults.ServerProtocol(manhole.ColoredManhole, self.namespace) - -class AuthorizedKeysChecker(conchc.SSHPublicKeyDatabase): - """Accept connections using SSH keys from a given file. - - SSHPublicKeyDatabase takes the username that the prospective client has - requested and attempts to get a ~/.ssh/authorized_keys file for that - username. This requires root access, so it isn't as useful as you'd - like. - - Instead, this subclass looks for keys in a single file, given as an - argument. This file is typically kept in the buildmaster's basedir. The - file should have 'ssh-dss ....' lines in it, just like authorized_keys. - """ - - def __init__(self, authorized_keys_file): - self.authorized_keys_file = os.path.expanduser(authorized_keys_file) - - def checkKey(self, credentials): - f = open(self.authorized_keys_file) - for l in f.readlines(): - l2 = l.split() - if len(l2) < 2: - continue - try: - if base64.decodestring(l2[1]) == credentials.blob: - return 1 - except binascii.Error: - continue - return 0 - - -class _BaseManhole(service.MultiService): - """This provides remote access to a python interpreter (a read/exec/print - loop) embedded in the buildmaster via an internal SSH server. This allows - detailed inspection of the buildmaster state. It is of most use to - buildbot developers. Connect to this by running an ssh client. - """ - - def __init__(self, port, checker, using_ssh=True): - """ - @type port: string or int - @param port: what port should the Manhole listen on? This is a - strports specification string, like 'tcp:12345' or - 'tcp:12345:interface=127.0.0.1'. Bare integers are treated as a - simple tcp port. - - @type checker: an object providing the - L{twisted.cred.checkers.ICredentialsChecker} interface - @param checker: if provided, this checker is used to authenticate the - client instead of using the username/password scheme. You must either - provide a username/password or a Checker. Some useful values are:: - import twisted.cred.checkers as credc - import twisted.conch.checkers as conchc - c = credc.AllowAnonymousAccess # completely open - c = credc.FilePasswordDB(passwd_filename) # file of name:passwd - c = conchc.UNIXPasswordDatabase # getpwnam() (probably /etc/passwd) - - @type using_ssh: bool - @param using_ssh: If True, accept SSH connections. If False, accept - regular unencrypted telnet connections. - """ - - # unfortunately, these don't work unless we're running as root - #c = credc.PluggableAuthenticationModulesChecker: PAM - #c = conchc.SSHPublicKeyDatabase() # ~/.ssh/authorized_keys - # and I can't get UNIXPasswordDatabase to work - - service.MultiService.__init__(self) - if type(port) is int: - port = "tcp:%d" % port - self.port = port # for comparison later - self.checker = checker # to maybe compare later - - def makeNamespace(): - # close over 'self' so we can get access to .parent later - master = self.parent - namespace = { - 'master': master, - 'status': master.getStatus(), - } - return namespace - - def makeProtocol(): - namespace = makeNamespace() - p = insults.ServerProtocol(manhole.ColoredManhole, namespace) - return p - - self.using_ssh = using_ssh - if using_ssh: - r = manhole_ssh.TerminalRealm() - r.chainedProtocolFactory = makeProtocol - p = portal.Portal(r, [self.checker]) - f = manhole_ssh.ConchFactory(p) - else: - r = _TelnetRealm(makeNamespace) - p = portal.Portal(r, [self.checker]) - f = protocol.ServerFactory() - f.protocol = makeTelnetProtocol(p) - s = strports.service(self.port, f) - s.setServiceParent(self) - - - def startService(self): - service.MultiService.startService(self) - if self.using_ssh: - via = "via SSH" - else: - via = "via telnet" - log.msg("Manhole listening %s on port %s" % (via, self.port)) - - -class TelnetManhole(_BaseManhole, ComparableMixin): - """This Manhole accepts unencrypted (telnet) connections, and requires a - username and password authorize access. You are encouraged to use the - encrypted ssh-based manhole classes instead.""" - - compare_attrs = ["port", "username", "password"] - - def __init__(self, port, username, password): - """ - @type port: string or int - @param port: what port should the Manhole listen on? This is a - strports specification string, like 'tcp:12345' or - 'tcp:12345:interface=127.0.0.1'. Bare integers are treated as a - simple tcp port. - - @param username: - @param password: username= and password= form a pair of strings to - use when authenticating the remote user. - """ - - self.username = username - self.password = password - - c = checkers.InMemoryUsernamePasswordDatabaseDontUse() - c.addUser(username, password) - - _BaseManhole.__init__(self, port, c, using_ssh=False) - -class PasswordManhole(_BaseManhole, ComparableMixin): - """This Manhole accepts encrypted (ssh) connections, and requires a - username and password to authorize access. - """ - - compare_attrs = ["port", "username", "password"] - - def __init__(self, port, username, password): - """ - @type port: string or int - @param port: what port should the Manhole listen on? This is a - strports specification string, like 'tcp:12345' or - 'tcp:12345:interface=127.0.0.1'. Bare integers are treated as a - simple tcp port. - - @param username: - @param password: username= and password= form a pair of strings to - use when authenticating the remote user. - """ - - self.username = username - self.password = password - - c = checkers.InMemoryUsernamePasswordDatabaseDontUse() - c.addUser(username, password) - - _BaseManhole.__init__(self, port, c) - -class AuthorizedKeysManhole(_BaseManhole, ComparableMixin): - """This Manhole accepts ssh connections, and requires that the - prospective client have an ssh private key that matches one of the public - keys in our authorized_keys file. It is created with the name of a file - that contains the public keys that we will accept.""" - - compare_attrs = ["port", "keyfile"] - - def __init__(self, port, keyfile): - """ - @type port: string or int - @param port: what port should the Manhole listen on? This is a - strports specification string, like 'tcp:12345' or - 'tcp:12345:interface=127.0.0.1'. Bare integers are treated as a - simple tcp port. - - @param keyfile: the name of a file (relative to the buildmaster's - basedir) that contains SSH public keys of authorized - users, one per line. This is the exact same format - as used by sshd in ~/.ssh/authorized_keys . - """ - - # TODO: expanduser this, and make it relative to the buildmaster's - # basedir - self.keyfile = keyfile - c = AuthorizedKeysChecker(keyfile) - _BaseManhole.__init__(self, port, c) - -class ArbitraryCheckerManhole(_BaseManhole, ComparableMixin): - """This Manhole accepts ssh connections, but uses an arbitrary - user-supplied 'checker' object to perform authentication.""" - - compare_attrs = ["port", "checker"] - - def __init__(self, port, checker): - """ - @type port: string or int - @param port: what port should the Manhole listen on? This is a - strports specification string, like 'tcp:12345' or - 'tcp:12345:interface=127.0.0.1'. Bare integers are treated as a - simple tcp port. - - @param checker: an instance of a twisted.cred 'checker' which will - perform authentication - """ - - _BaseManhole.__init__(self, port, checker) - - diff --git a/tools/buildbot/pylibs/buildbot/master.py b/tools/buildbot/pylibs/buildbot/master.py deleted file mode 100644 index cd6391b..0000000 --- a/tools/buildbot/pylibs/buildbot/master.py +++ /dev/null @@ -1,911 +0,0 @@ -# -*- test-case-name: buildbot.test.test_run -*- - -import os -signal = None -try: - import signal -except ImportError: - pass -from cPickle import load -import warnings - -from zope.interface import implements -from twisted.python import log, components -from twisted.internet import defer, reactor -from twisted.spread import pb -from twisted.cred import portal, checkers -from twisted.application import service, strports -from twisted.persisted import styles - -# sibling imports -from buildbot.util import now -from buildbot.pbutil import NewCredPerspective -from buildbot.process.builder import Builder, IDLE -from buildbot.process.base import BuildRequest -from buildbot.status.builder import Status -from buildbot.changes.changes import Change, ChangeMaster -from buildbot.sourcestamp import SourceStamp -from buildbot.buildslave import BuildSlave -from buildbot import interfaces -from buildbot.process.properties import Properties - -######################################## - -class BotMaster(service.MultiService): - - """This is the master-side service which manages remote buildbot slaves. - It provides them with BuildSlaves, and distributes file change - notification messages to them. - """ - - debug = 0 - - def __init__(self): - service.MultiService.__init__(self) - self.builders = {} - self.builderNames = [] - # builders maps Builder names to instances of bb.p.builder.Builder, - # which is the master-side object that defines and controls a build. - # They are added by calling botmaster.addBuilder() from the startup - # code. - - # self.slaves contains a ready BuildSlave instance for each - # potential buildslave, i.e. all the ones listed in the config file. - # If the slave is connected, self.slaves[slavename].slave will - # contain a RemoteReference to their Bot instance. If it is not - # connected, that attribute will hold None. - self.slaves = {} # maps slavename to BuildSlave - self.statusClientService = None - self.watchers = {} - - # self.locks holds the real Lock instances - self.locks = {} - - # these four are convenience functions for testing - - def waitUntilBuilderAttached(self, name): - b = self.builders[name] - #if b.slaves: - # return defer.succeed(None) - d = defer.Deferred() - b.watchers['attach'].append(d) - return d - - def waitUntilBuilderDetached(self, name): - b = self.builders.get(name) - if not b or not b.slaves: - return defer.succeed(None) - d = defer.Deferred() - b.watchers['detach'].append(d) - return d - - def waitUntilBuilderFullyDetached(self, name): - b = self.builders.get(name) - # TODO: this looks too deeply inside the Builder object - if not b or not b.slaves: - return defer.succeed(None) - d = defer.Deferred() - b.watchers['detach_all'].append(d) - return d - - def waitUntilBuilderIdle(self, name): - b = self.builders[name] - # TODO: this looks way too deeply inside the Builder object - for sb in b.slaves: - if sb.state != IDLE: - d = defer.Deferred() - b.watchers['idle'].append(d) - return d - return defer.succeed(None) - - def loadConfig_Slaves(self, new_slaves): - old_slaves = [c for c in list(self) - if interfaces.IBuildSlave.providedBy(c)] - - # identify added/removed slaves. For each slave we construct a tuple - # of (name, password, class), and we consider the slave to be already - # present if the tuples match. (we include the class to make sure - # that BuildSlave(name,pw) is different than - # SubclassOfBuildSlave(name,pw) ). If the password or class has - # changed, we will remove the old version of the slave and replace it - # with a new one. If anything else has changed, we just update the - # old BuildSlave instance in place. If the name has changed, of - # course, it looks exactly the same as deleting one slave and adding - # an unrelated one. - old_t = {} - for s in old_slaves: - old_t[(s.slavename, s.password, s.__class__)] = s - new_t = {} - for s in new_slaves: - new_t[(s.slavename, s.password, s.__class__)] = s - removed = [old_t[t] - for t in old_t - if t not in new_t] - added = [new_t[t] - for t in new_t - if t not in old_t] - remaining_t = [t - for t in new_t - if t in old_t] - # removeSlave will hang up on the old bot - dl = [] - for s in removed: - dl.append(self.removeSlave(s)) - d = defer.DeferredList(dl, fireOnOneErrback=True) - def _add(res): - for s in added: - self.addSlave(s) - for t in remaining_t: - old_t[t].update(new_t[t]) - d.addCallback(_add) - return d - - def addSlave(self, s): - s.setServiceParent(self) - s.setBotmaster(self) - self.slaves[s.slavename] = s - - def removeSlave(self, s): - # TODO: technically, disownServiceParent could return a Deferred - s.disownServiceParent() - d = self.slaves[s.slavename].disconnect() - del self.slaves[s.slavename] - return d - - def slaveLost(self, bot): - for name, b in self.builders.items(): - if bot.slavename in b.slavenames: - b.detached(bot) - - def getBuildersForSlave(self, slavename): - return [b - for b in self.builders.values() - if slavename in b.slavenames] - - def getBuildernames(self): - return self.builderNames - - def getBuilders(self): - allBuilders = [self.builders[name] for name in self.builderNames] - return allBuilders - - def setBuilders(self, builders): - self.builders = {} - self.builderNames = [] - for b in builders: - for slavename in b.slavenames: - # this is actually validated earlier - assert slavename in self.slaves - self.builders[b.name] = b - self.builderNames.append(b.name) - b.setBotmaster(self) - d = self._updateAllSlaves() - return d - - def _updateAllSlaves(self): - """Notify all buildslaves about changes in their Builders.""" - dl = [s.updateSlave() for s in self.slaves.values()] - return defer.DeferredList(dl) - - def maybeStartAllBuilds(self): - for b in self.builders.values(): - b.maybeStartBuild() - - def getPerspective(self, slavename): - return self.slaves[slavename] - - def shutdownSlaves(self): - # TODO: make this into a bot method rather than a builder method - for b in self.slaves.values(): - b.shutdownSlave() - - def stopService(self): - for b in self.builders.values(): - b.builder_status.addPointEvent(["master", "shutdown"]) - b.builder_status.saveYourself() - return service.Service.stopService(self) - - def getLockByID(self, lockid): - """Convert a Lock identifier into an actual Lock instance. - @param lockid: a locks.MasterLock or locks.SlaveLock instance - @return: a locks.RealMasterLock or locks.RealSlaveLock instance - """ - if not lockid in self.locks: - self.locks[lockid] = lockid.lockClass(lockid) - # if the master.cfg file has changed maxCount= on the lock, the next - # time a build is started, they'll get a new RealLock instance. Note - # that this requires that MasterLock and SlaveLock (marker) instances - # be hashable and that they should compare properly. - return self.locks[lockid] - -######################################## - - - -class DebugPerspective(NewCredPerspective): - def attached(self, mind): - return self - def detached(self, mind): - pass - - def perspective_requestBuild(self, buildername, reason, branch, revision, properties={}): - c = interfaces.IControl(self.master) - bc = c.getBuilder(buildername) - ss = SourceStamp(branch, revision) - bpr = Properties() - bpr.update(properties, "remote requestBuild") - br = BuildRequest(reason, ss, builderName=buildername, properties=bpr) - bc.requestBuild(br) - - def perspective_pingBuilder(self, buildername): - c = interfaces.IControl(self.master) - bc = c.getBuilder(buildername) - bc.ping() - - def perspective_fakeChange(self, file, revision=None, who="fakeUser", - branch=None): - change = Change(who, [file], "some fake comments\n", - branch=branch, revision=revision) - c = interfaces.IControl(self.master) - c.addChange(change) - - def perspective_setCurrentState(self, buildername, state): - builder = self.botmaster.builders.get(buildername) - if not builder: return - if state == "offline": - builder.statusbag.currentlyOffline() - if state == "idle": - builder.statusbag.currentlyIdle() - if state == "waiting": - builder.statusbag.currentlyWaiting(now()+10) - if state == "building": - builder.statusbag.currentlyBuilding(None) - def perspective_reload(self): - print "doing reload of the config file" - self.master.loadTheConfigFile() - def perspective_pokeIRC(self): - print "saying something on IRC" - from buildbot.status import words - for s in self.master: - if isinstance(s, words.IRC): - bot = s.f - for channel in bot.channels: - print " channel", channel - bot.p.msg(channel, "Ow, quit it") - - def perspective_print(self, msg): - print "debug", msg - -class Dispatcher(styles.Versioned): - implements(portal.IRealm) - persistenceVersion = 2 - - def __init__(self): - self.names = {} - - def upgradeToVersion1(self): - self.master = self.botmaster.parent - def upgradeToVersion2(self): - self.names = {} - - def register(self, name, afactory): - self.names[name] = afactory - def unregister(self, name): - del self.names[name] - - def requestAvatar(self, avatarID, mind, interface): - assert interface == pb.IPerspective - afactory = self.names.get(avatarID) - if afactory: - p = afactory.getPerspective() - elif avatarID == "debug": - p = DebugPerspective() - p.master = self.master - p.botmaster = self.botmaster - elif avatarID == "statusClient": - p = self.statusClientService.getPerspective() - else: - # it must be one of the buildslaves: no other names will make it - # past the checker - p = self.botmaster.getPerspective(avatarID) - - if not p: - raise ValueError("no perspective for '%s'" % avatarID) - - d = defer.maybeDeferred(p.attached, mind) - d.addCallback(self._avatarAttached, mind) - return d - - def _avatarAttached(self, p, mind): - return (pb.IPerspective, p, lambda p=p,mind=mind: p.detached(mind)) - -######################################## - -# service hierarchy: -# BuildMaster -# BotMaster -# ChangeMaster -# all IChangeSource objects -# StatusClientService -# TCPClient(self.ircFactory) -# TCPServer(self.slaveFactory) -> dispatcher.requestAvatar -# TCPServer(self.site) -# UNIXServer(ResourcePublisher(self.site)) - - -class BuildMaster(service.MultiService, styles.Versioned): - debug = 0 - persistenceVersion = 3 - manhole = None - debugPassword = None - projectName = "(unspecified)" - projectURL = None - buildbotURL = None - change_svc = None - properties = Properties() - - def __init__(self, basedir, configFileName="master.cfg"): - service.MultiService.__init__(self) - self.setName("buildmaster") - self.basedir = basedir - self.configFileName = configFileName - - # the dispatcher is the realm in which all inbound connections are - # looked up: slave builders, change notifications, status clients, and - # the debug port - dispatcher = Dispatcher() - dispatcher.master = self - self.dispatcher = dispatcher - self.checker = checkers.InMemoryUsernamePasswordDatabaseDontUse() - # the checker starts with no user/passwd pairs: they are added later - p = portal.Portal(dispatcher) - p.registerChecker(self.checker) - self.slaveFactory = pb.PBServerFactory(p) - self.slaveFactory.unsafeTracebacks = True # let them see exceptions - - self.slavePortnum = None - self.slavePort = None - - self.botmaster = BotMaster() - self.botmaster.setName("botmaster") - self.botmaster.setServiceParent(self) - dispatcher.botmaster = self.botmaster - - self.status = Status(self.botmaster, self.basedir) - - self.statusTargets = [] - - # this ChangeMaster is a dummy, only used by tests. In the real - # buildmaster, where the BuildMaster instance is activated - # (startService is called) by twistd, this attribute is overwritten. - self.useChanges(ChangeMaster()) - - self.readConfig = False - - def upgradeToVersion1(self): - self.dispatcher = self.slaveFactory.root.portal.realm - - def upgradeToVersion2(self): # post-0.4.3 - self.webServer = self.webTCPPort - del self.webTCPPort - self.webDistribServer = self.webUNIXPort - del self.webUNIXPort - self.configFileName = "master.cfg" - - def upgradeToVersion3(self): - # post 0.6.3, solely to deal with the 0.6.3 breakage. Starting with - # 0.6.5 I intend to do away with .tap files altogether - self.services = [] - self.namedServices = {} - del self.change_svc - - def startService(self): - service.MultiService.startService(self) - self.loadChanges() # must be done before loading the config file - if not self.readConfig: - # TODO: consider catching exceptions during this call to - # loadTheConfigFile and bailing (reactor.stop) if it fails, - # since without a config file we can't do anything except reload - # the config file, and it would be nice for the user to discover - # this quickly. - self.loadTheConfigFile() - if signal and hasattr(signal, "SIGHUP"): - signal.signal(signal.SIGHUP, self._handleSIGHUP) - for b in self.botmaster.builders.values(): - b.builder_status.addPointEvent(["master", "started"]) - b.builder_status.saveYourself() - - def useChanges(self, changes): - if self.change_svc: - # TODO: can return a Deferred - self.change_svc.disownServiceParent() - self.change_svc = changes - self.change_svc.basedir = self.basedir - self.change_svc.setName("changemaster") - self.dispatcher.changemaster = self.change_svc - self.change_svc.setServiceParent(self) - - def loadChanges(self): - filename = os.path.join(self.basedir, "changes.pck") - try: - changes = load(open(filename, "rb")) - styles.doUpgrade() - except IOError: - log.msg("changes.pck missing, using new one") - changes = ChangeMaster() - except EOFError: - log.msg("corrupted changes.pck, using new one") - changes = ChangeMaster() - self.useChanges(changes) - - def _handleSIGHUP(self, *args): - reactor.callLater(0, self.loadTheConfigFile) - - def getStatus(self): - """ - @rtype: L{buildbot.status.builder.Status} - """ - return self.status - - def loadTheConfigFile(self, configFile=None): - if not configFile: - configFile = os.path.join(self.basedir, self.configFileName) - - log.msg("loading configuration from %s" % configFile) - configFile = os.path.expanduser(configFile) - - try: - f = open(configFile, "r") - except IOError, e: - log.msg("unable to open config file '%s'" % configFile) - log.msg("leaving old configuration in place") - log.err(e) - return - - try: - self.loadConfig(f) - except: - log.msg("error during loadConfig") - log.err() - log.msg("The new config file is unusable, so I'll ignore it.") - log.msg("I will keep using the previous config file instead.") - f.close() - - def loadConfig(self, f): - """Internal function to load a specific configuration file. Any - errors in the file will be signalled by raising an exception. - - @return: a Deferred that will fire (with None) when the configuration - changes have been completed. This may involve a round-trip to each - buildslave that was involved.""" - - localDict = {'basedir': os.path.expanduser(self.basedir)} - try: - exec f in localDict - except: - log.msg("error while parsing config file") - raise - - try: - config = localDict['BuildmasterConfig'] - except KeyError: - log.err("missing config dictionary") - log.err("config file must define BuildmasterConfig") - raise - - known_keys = ("bots", "slaves", - "sources", "change_source", - "schedulers", "builders", - "slavePortnum", "debugPassword", "manhole", - "status", "projectName", "projectURL", "buildbotURL", - "properties" - ) - for k in config.keys(): - if k not in known_keys: - log.msg("unknown key '%s' defined in config dictionary" % k) - - try: - # required - schedulers = config['schedulers'] - builders = config['builders'] - for k in builders: - if k['name'].startswith("_"): - errmsg = ("builder names must not start with an " - "underscore: " + k['name']) - log.err(errmsg) - raise ValueError(errmsg) - - slavePortnum = config['slavePortnum'] - #slaves = config['slaves'] - #change_source = config['change_source'] - - # optional - debugPassword = config.get('debugPassword') - manhole = config.get('manhole') - status = config.get('status', []) - projectName = config.get('projectName') - projectURL = config.get('projectURL') - buildbotURL = config.get('buildbotURL') - properties = config.get('properties', {}) - - except KeyError, e: - log.msg("config dictionary is missing a required parameter") - log.msg("leaving old configuration in place") - raise - - #if "bots" in config: - # raise KeyError("c['bots'] is no longer accepted") - - slaves = config.get('slaves', []) - if "bots" in config: - m = ("c['bots'] is deprecated as of 0.7.6 and will be " - "removed by 0.8.0 . Please use c['slaves'] instead.") - log.msg(m) - warnings.warn(m, DeprecationWarning) - for name, passwd in config['bots']: - slaves.append(BuildSlave(name, passwd)) - - if "bots" not in config and "slaves" not in config: - log.msg("config dictionary must have either 'bots' or 'slaves'") - log.msg("leaving old configuration in place") - raise KeyError("must have either 'bots' or 'slaves'") - - #if "sources" in config: - # raise KeyError("c['sources'] is no longer accepted") - - change_source = config.get('change_source', []) - if isinstance(change_source, (list, tuple)): - change_sources = change_source - else: - change_sources = [change_source] - if "sources" in config: - m = ("c['sources'] is deprecated as of 0.7.6 and will be " - "removed by 0.8.0 . Please use c['change_source'] instead.") - log.msg(m) - warnings.warn(m, DeprecationWarning) - for s in config['sources']: - change_sources.append(s) - - # do some validation first - for s in slaves: - assert isinstance(s, BuildSlave) - if s.slavename in ("debug", "change", "status"): - raise KeyError, "reserved name '%s' used for a bot" % s.slavename - if config.has_key('interlocks'): - raise KeyError("c['interlocks'] is no longer accepted") - - assert isinstance(change_sources, (list, tuple)) - for s in change_sources: - assert interfaces.IChangeSource(s, None) - # this assertion catches c['schedulers'] = Scheduler(), since - # Schedulers are service.MultiServices and thus iterable. - errmsg = "c['schedulers'] must be a list of Scheduler instances" - assert isinstance(schedulers, (list, tuple)), errmsg - for s in schedulers: - assert interfaces.IScheduler(s, None), errmsg - assert isinstance(status, (list, tuple)) - for s in status: - assert interfaces.IStatusReceiver(s, None) - - slavenames = [s.slavename for s in slaves] - buildernames = [] - dirnames = [] - for b in builders: - if type(b) is tuple: - raise ValueError("builder %s must be defined with a dict, " - "not a tuple" % b[0]) - if b.has_key('slavename') and b['slavename'] not in slavenames: - raise ValueError("builder %s uses undefined slave %s" \ - % (b['name'], b['slavename'])) - for n in b.get('slavenames', []): - if n not in slavenames: - raise ValueError("builder %s uses undefined slave %s" \ - % (b['name'], n)) - if b['name'] in buildernames: - raise ValueError("duplicate builder name %s" - % b['name']) - buildernames.append(b['name']) - if b['builddir'] in dirnames: - raise ValueError("builder %s reuses builddir %s" - % (b['name'], b['builddir'])) - dirnames.append(b['builddir']) - - unscheduled_buildernames = buildernames[:] - schedulernames = [] - for s in schedulers: - for b in s.listBuilderNames(): - assert b in buildernames, \ - "%s uses unknown builder %s" % (s, b) - if b in unscheduled_buildernames: - unscheduled_buildernames.remove(b) - - if s.name in schedulernames: - # TODO: schedulers share a namespace with other Service - # children of the BuildMaster node, like status plugins, the - # Manhole, the ChangeMaster, and the BotMaster (although most - # of these don't have names) - msg = ("Schedulers must have unique names, but " - "'%s' was a duplicate" % (s.name,)) - raise ValueError(msg) - schedulernames.append(s.name) - - if unscheduled_buildernames: - log.msg("Warning: some Builders have no Schedulers to drive them:" - " %s" % (unscheduled_buildernames,)) - - # assert that all locks used by the Builds and their Steps are - # uniquely named. - locks = {} - for b in builders: - for l in b.get('locks', []): - if locks.has_key(l.name): - if locks[l.name] is not l: - raise ValueError("Two different locks (%s and %s) " - "share the name %s" - % (l, locks[l.name], l.name)) - else: - locks[l.name] = l - # TODO: this will break with any BuildFactory that doesn't use a - # .steps list, but I think the verification step is more - # important. - for s in b['factory'].steps: - for l in s[1].get('locks', []): - if locks.has_key(l.name): - if locks[l.name] is not l: - raise ValueError("Two different locks (%s and %s)" - " share the name %s" - % (l, locks[l.name], l.name)) - else: - locks[l.name] = l - - if not isinstance(properties, dict): - raise ValueError("c['properties'] must be a dictionary") - - # slavePortnum supposed to be a strports specification - if type(slavePortnum) is int: - slavePortnum = "tcp:%d" % slavePortnum - - # now we're committed to implementing the new configuration, so do - # it atomically - # TODO: actually, this is spread across a couple of Deferreds, so it - # really isn't atomic. - - d = defer.succeed(None) - - self.projectName = projectName - self.projectURL = projectURL - self.buildbotURL = buildbotURL - - self.properties = Properties() - self.properties.update(properties, self.configFileName) - - # self.slaves: Disconnect any that were attached and removed from the - # list. Update self.checker with the new list of passwords, including - # debug/change/status. - d.addCallback(lambda res: self.loadConfig_Slaves(slaves)) - - # self.debugPassword - if debugPassword: - self.checker.addUser("debug", debugPassword) - self.debugPassword = debugPassword - - # self.manhole - if manhole != self.manhole: - # changing - if self.manhole: - # disownServiceParent may return a Deferred - d.addCallback(lambda res: self.manhole.disownServiceParent()) - def _remove(res): - self.manhole = None - return res - d.addCallback(_remove) - if manhole: - def _add(res): - self.manhole = manhole - manhole.setServiceParent(self) - d.addCallback(_add) - - # add/remove self.botmaster.builders to match builders. The - # botmaster will handle startup/shutdown issues. - d.addCallback(lambda res: self.loadConfig_Builders(builders)) - - d.addCallback(lambda res: self.loadConfig_status(status)) - - # Schedulers are added after Builders in case they start right away - d.addCallback(lambda res: self.loadConfig_Schedulers(schedulers)) - # and Sources go after Schedulers for the same reason - d.addCallback(lambda res: self.loadConfig_Sources(change_sources)) - - # self.slavePort - if self.slavePortnum != slavePortnum: - if self.slavePort: - def closeSlavePort(res): - d1 = self.slavePort.disownServiceParent() - self.slavePort = None - return d1 - d.addCallback(closeSlavePort) - if slavePortnum is not None: - def openSlavePort(res): - self.slavePort = strports.service(slavePortnum, - self.slaveFactory) - self.slavePort.setServiceParent(self) - d.addCallback(openSlavePort) - log.msg("BuildMaster listening on port %s" % slavePortnum) - self.slavePortnum = slavePortnum - - log.msg("configuration update started") - def _done(res): - self.readConfig = True - log.msg("configuration update complete") - d.addCallback(_done) - d.addCallback(lambda res: self.botmaster.maybeStartAllBuilds()) - return d - - def loadConfig_Slaves(self, new_slaves): - # set up the Checker with the names and passwords of all valid bots - self.checker.users = {} # violates abstraction, oh well - for s in new_slaves: - self.checker.addUser(s.slavename, s.password) - self.checker.addUser("change", "changepw") - # let the BotMaster take care of the rest - return self.botmaster.loadConfig_Slaves(new_slaves) - - def loadConfig_Sources(self, sources): - if not sources: - log.msg("warning: no ChangeSources specified in c['change_source']") - # shut down any that were removed, start any that were added - deleted_sources = [s for s in self.change_svc if s not in sources] - added_sources = [s for s in sources if s not in self.change_svc] - dl = [self.change_svc.removeSource(s) for s in deleted_sources] - def addNewOnes(res): - [self.change_svc.addSource(s) for s in added_sources] - d = defer.DeferredList(dl, fireOnOneErrback=1, consumeErrors=0) - d.addCallback(addNewOnes) - return d - - def allSchedulers(self): - return [child for child in self - if interfaces.IScheduler.providedBy(child)] - - - def loadConfig_Schedulers(self, newschedulers): - oldschedulers = self.allSchedulers() - removed = [s for s in oldschedulers if s not in newschedulers] - added = [s for s in newschedulers if s not in oldschedulers] - dl = [defer.maybeDeferred(s.disownServiceParent) for s in removed] - def addNewOnes(res): - for s in added: - s.setServiceParent(self) - d = defer.DeferredList(dl, fireOnOneErrback=1) - d.addCallback(addNewOnes) - return d - - def loadConfig_Builders(self, newBuilderData): - somethingChanged = False - newList = {} - newBuilderNames = [] - allBuilders = self.botmaster.builders.copy() - for data in newBuilderData: - name = data['name'] - newList[name] = data - newBuilderNames.append(name) - - # identify all that were removed - for oldname in self.botmaster.getBuildernames(): - if oldname not in newList: - log.msg("removing old builder %s" % oldname) - del allBuilders[oldname] - somethingChanged = True - # announce the change - self.status.builderRemoved(oldname) - - # everything in newList is either unchanged, changed, or new - for name, data in newList.items(): - old = self.botmaster.builders.get(name) - basedir = data['builddir'] # used on both master and slave - #name, slave, builddir, factory = data - if not old: # new - # category added after 0.6.2 - category = data.get('category', None) - log.msg("adding new builder %s for category %s" % - (name, category)) - statusbag = self.status.builderAdded(name, basedir, category) - builder = Builder(data, statusbag) - allBuilders[name] = builder - somethingChanged = True - elif old.compareToSetup(data): - # changed: try to minimize the disruption and only modify the - # pieces that really changed - diffs = old.compareToSetup(data) - log.msg("updating builder %s: %s" % (name, "\n".join(diffs))) - - statusbag = old.builder_status - statusbag.saveYourself() # seems like a good idea - # TODO: if the basedir was changed, we probably need to make - # a new statusbag - new_builder = Builder(data, statusbag) - new_builder.consumeTheSoulOfYourPredecessor(old) - # that migrates any retained slavebuilders too - - # point out that the builder was updated. On the Waterfall, - # this will appear just after any currently-running builds. - statusbag.addPointEvent(["config", "updated"]) - - allBuilders[name] = new_builder - somethingChanged = True - else: - # unchanged: leave it alone - log.msg("builder %s is unchanged" % name) - pass - - if somethingChanged: - sortedAllBuilders = [allBuilders[name] for name in newBuilderNames] - d = self.botmaster.setBuilders(sortedAllBuilders) - return d - return None - - def loadConfig_status(self, status): - dl = [] - - # remove old ones - for s in self.statusTargets[:]: - if not s in status: - log.msg("removing IStatusReceiver", s) - d = defer.maybeDeferred(s.disownServiceParent) - dl.append(d) - self.statusTargets.remove(s) - # after those are finished going away, add new ones - def addNewOnes(res): - for s in status: - if not s in self.statusTargets: - log.msg("adding IStatusReceiver", s) - s.setServiceParent(self) - self.statusTargets.append(s) - d = defer.DeferredList(dl, fireOnOneErrback=1) - d.addCallback(addNewOnes) - return d - - - def addChange(self, change): - for s in self.allSchedulers(): - s.addChange(change) - - def submitBuildSet(self, bs): - # determine the set of Builders to use - builders = [] - for name in bs.builderNames: - b = self.botmaster.builders.get(name) - if b: - if b not in builders: - builders.append(b) - continue - # TODO: add aliases like 'all' - raise KeyError("no such builder named '%s'" % name) - - # now tell the BuildSet to create BuildRequests for all those - # Builders and submit them - bs.start(builders) - self.status.buildsetSubmitted(bs.status) - - -class Control: - implements(interfaces.IControl) - - def __init__(self, master): - self.master = master - - def addChange(self, change): - self.master.change_svc.addChange(change) - - def submitBuildSet(self, bs): - self.master.submitBuildSet(bs) - - def getBuilder(self, name): - b = self.master.botmaster.builders[name] - return interfaces.IBuilderControl(b) - -components.registerAdapter(Control, BuildMaster, interfaces.IControl) - -# so anybody who can get a handle on the BuildMaster can cause a build with: -# IControl(master).getBuilder("full-2.3").requestBuild(buildrequest) - diff --git a/tools/buildbot/pylibs/buildbot/pbutil.py b/tools/buildbot/pylibs/buildbot/pbutil.py deleted file mode 100644 index bc85a01..0000000 --- a/tools/buildbot/pylibs/buildbot/pbutil.py +++ /dev/null @@ -1,147 +0,0 @@ - -"""Base classes handy for use with PB clients. -""" - -from twisted.spread import pb - -from twisted.spread.pb import PBClientFactory -from twisted.internet import protocol -from twisted.python import log - -class NewCredPerspective(pb.Avatar): - def attached(self, mind): - return self - def detached(self, mind): - pass - -class ReconnectingPBClientFactory(PBClientFactory, - protocol.ReconnectingClientFactory): - """Reconnecting client factory for PB brokers. - - Like PBClientFactory, but if the connection fails or is lost, the factory - will attempt to reconnect. - - Instead of using f.getRootObject (which gives a Deferred that can only - be fired once), override the gotRootObject method. - - Instead of using the newcred f.login (which is also one-shot), call - f.startLogin() with the credentials and client, and override the - gotPerspective method. - - Instead of using the oldcred f.getPerspective (also one-shot), call - f.startGettingPerspective() with the same arguments, and override - gotPerspective. - - gotRootObject and gotPerspective will be called each time the object is - received (once per successful connection attempt). You will probably want - to use obj.notifyOnDisconnect to find out when the connection is lost. - - If an authorization error occurs, failedToGetPerspective() will be - invoked. - - To use me, subclass, then hand an instance to a connector (like - TCPClient). - """ - - def __init__(self): - PBClientFactory.__init__(self) - self._doingLogin = False - self._doingGetPerspective = False - - def clientConnectionFailed(self, connector, reason): - PBClientFactory.clientConnectionFailed(self, connector, reason) - # Twisted-1.3 erroneously abandons the connection on non-UserErrors. - # To avoid this bug, don't upcall, and implement the correct version - # of the method here. - if self.continueTrying: - self.connector = connector - self.retry() - - def clientConnectionLost(self, connector, reason): - PBClientFactory.clientConnectionLost(self, connector, reason, - reconnecting=True) - RCF = protocol.ReconnectingClientFactory - RCF.clientConnectionLost(self, connector, reason) - - def clientConnectionMade(self, broker): - self.resetDelay() - PBClientFactory.clientConnectionMade(self, broker) - if self._doingLogin: - self.doLogin(self._root) - if self._doingGetPerspective: - self.doGetPerspective(self._root) - self.gotRootObject(self._root) - - def __getstate__(self): - # this should get folded into ReconnectingClientFactory - d = self.__dict__.copy() - d['connector'] = None - d['_callID'] = None - return d - - # oldcred methods - - def getPerspective(self, *args): - raise RuntimeError, "getPerspective is one-shot: use startGettingPerspective instead" - - def startGettingPerspective(self, username, password, serviceName, - perspectiveName=None, client=None): - self._doingGetPerspective = True - if perspectiveName == None: - perspectiveName = username - self._oldcredArgs = (username, password, serviceName, - perspectiveName, client) - - def doGetPerspective(self, root): - # oldcred getPerspective() - (username, password, - serviceName, perspectiveName, client) = self._oldcredArgs - d = self._cbAuthIdentity(root, username, password) - d.addCallback(self._cbGetPerspective, - serviceName, perspectiveName, client) - d.addCallbacks(self.gotPerspective, self.failedToGetPerspective) - - - # newcred methods - - def login(self, *args): - raise RuntimeError, "login is one-shot: use startLogin instead" - - def startLogin(self, credentials, client=None): - self._credentials = credentials - self._client = client - self._doingLogin = True - - def doLogin(self, root): - # newcred login() - d = self._cbSendUsername(root, self._credentials.username, - self._credentials.password, self._client) - d.addCallbacks(self.gotPerspective, self.failedToGetPerspective) - - - # methods to override - - def gotPerspective(self, perspective): - """The remote avatar or perspective (obtained each time this factory - connects) is now available.""" - pass - - def gotRootObject(self, root): - """The remote root object (obtained each time this factory connects) - is now available. This method will be called each time the connection - is established and the object reference is retrieved.""" - pass - - def failedToGetPerspective(self, why): - """The login process failed, most likely because of an authorization - failure (bad password), but it is also possible that we lost the new - connection before we managed to send our credentials. - """ - log.msg("ReconnectingPBClientFactory.failedToGetPerspective") - if why.check(pb.PBConnectionLost): - log.msg("we lost the brand-new connection") - # retrying might help here, let clientConnectionLost decide - return - # probably authorization - self.stopTrying() # logging in harder won't help - log.err(why) diff --git a/tools/buildbot/pylibs/buildbot/process/__init__.py b/tools/buildbot/pylibs/buildbot/process/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tools/buildbot/pylibs/buildbot/process/base.py b/tools/buildbot/pylibs/buildbot/process/base.py deleted file mode 100644 index 801a3a1..0000000 --- a/tools/buildbot/pylibs/buildbot/process/base.py +++ /dev/null @@ -1,596 +0,0 @@ -# -*- test-case-name: buildbot.test.test_step -*- - -import types - -from zope.interface import implements -from twisted.python import log -from twisted.python.failure import Failure -from twisted.internet import reactor, defer, error - -from buildbot import interfaces -from buildbot.status.builder import SUCCESS, WARNINGS, FAILURE, EXCEPTION -from buildbot.status.builder import Results, BuildRequestStatus -from buildbot.status.progress import BuildProgress -from buildbot.process.properties import Properties - -class BuildRequest: - """I represent a request to a specific Builder to run a single build. - - I have a SourceStamp which specifies what sources I will build. This may - specify a specific revision of the source tree (so source.branch, - source.revision, and source.patch are used). The .patch attribute is - either None or a tuple of (patchlevel, diff), consisting of a number to - use in 'patch -pN', and a unified-format context diff. - - Alternatively, the SourceStamp may specify a set of Changes to be built, - contained in source.changes. In this case, I may be mergeable with other - BuildRequests on the same branch. - - I may be part of a BuildSet, in which case I will report status results - to it. - - I am paired with a BuildRequestStatus object, to which I feed status - information. - - @type source: a L{buildbot.sourcestamp.SourceStamp} instance. - @ivar source: the source code that this BuildRequest use - - @type reason: string - @ivar reason: the reason this Build is being requested. Schedulers - provide this, but for forced builds the user requesting the - build will provide a string. - - @type properties: Properties object - @ivar properties: properties that should be applied to this build - - @ivar status: the IBuildStatus object which tracks our status - - @ivar submittedAt: a timestamp (seconds since epoch) when this request - was submitted to the Builder. This is used by the CVS - step to compute a checkout timestamp. - """ - - source = None - builder = None - startCount = 0 # how many times we have tried to start this build - - implements(interfaces.IBuildRequestControl) - - def __init__(self, reason, source, builderName=None, properties=None): - # TODO: remove the =None on builderName, it is there so I don't have - # to change a lot of tests that create BuildRequest objects - assert interfaces.ISourceStamp(source, None) - self.reason = reason - self.source = source - - self.properties = Properties() - if properties: - self.properties.updateFromProperties(properties) - - self.start_watchers = [] - self.finish_watchers = [] - self.status = BuildRequestStatus(source, builderName) - - def canBeMergedWith(self, other): - return self.source.canBeMergedWith(other.source) - - def mergeWith(self, others): - return self.source.mergeWith([o.source for o in others]) - - def mergeReasons(self, others): - """Return a reason for the merged build request.""" - reasons = [] - for req in [self] + others: - if req.reason and req.reason not in reasons: - reasons.append(req.reason) - return ", ".join(reasons) - - def waitUntilFinished(self): - """Get a Deferred that will fire (with a - L{buildbot.interfaces.IBuildStatus} instance when the build - finishes.""" - d = defer.Deferred() - self.finish_watchers.append(d) - return d - - # these are called by the Builder - - def requestSubmitted(self, builder): - # the request has been placed on the queue - self.builder = builder - - def buildStarted(self, build, buildstatus): - """This is called by the Builder when a Build has been started in the - hopes of satifying this BuildRequest. It may be called multiple - times, since interrupted builds and lost buildslaves may force - multiple Builds to be run until the fate of the BuildRequest is known - for certain.""" - for o in self.start_watchers[:]: - # these observers get the IBuildControl - o(build) - # while these get the IBuildStatus - self.status.buildStarted(buildstatus) - - def finished(self, buildstatus): - """This is called by the Builder when the BuildRequest has been - retired. This happens when its Build has either succeeded (yay!) or - failed (boo!). TODO: If it is halted due to an exception (oops!), or - some other retryable error, C{finished} will not be called yet.""" - - for w in self.finish_watchers: - w.callback(buildstatus) - self.finish_watchers = [] - - # IBuildRequestControl - - def subscribe(self, observer): - self.start_watchers.append(observer) - def unsubscribe(self, observer): - self.start_watchers.remove(observer) - - def cancel(self): - """Cancel this request. This can only be successful if the Build has - not yet been started. - - @return: a boolean indicating if the cancel was successful.""" - if self.builder: - return self.builder.cancelBuildRequest(self) - return False - - -class Build: - """I represent a single build by a single slave. Specialized Builders can - use subclasses of Build to hold status information unique to those build - processes. - - I control B{how} the build proceeds. The actual build is broken up into a - series of steps, saved in the .buildSteps[] array as a list of - L{buildbot.process.step.BuildStep} objects. Each step is a single remote - command, possibly a shell command. - - During the build, I put status information into my C{BuildStatus} - gatherer. - - After the build, I go away. - - I can be used by a factory by setting buildClass on - L{buildbot.process.factory.BuildFactory} - - @ivar requests: the list of L{BuildRequest}s that triggered me - @ivar build_status: the L{buildbot.status.builder.BuildStatus} that - collects our status - """ - - implements(interfaces.IBuildControl) - - workdir = "build" - build_status = None - reason = "changes" - finished = False - results = None - - def __init__(self, requests): - self.requests = requests - for req in self.requests: - req.startCount += 1 - self.locks = [] - # build a source stamp - self.source = requests[0].mergeWith(requests[1:]) - self.reason = requests[0].mergeReasons(requests[1:]) - - self.progress = None - self.currentStep = None - self.slaveEnvironment = {} - - def setBuilder(self, builder): - """ - Set the given builder as our builder. - - @type builder: L{buildbot.process.builder.Builder} - """ - self.builder = builder - - def setLocks(self, locks): - self.locks = locks - - def getSourceStamp(self): - return self.source - - def setProperty(self, propname, value, source): - """Set a property on this build. This may only be called after the - build has started, so that it has a BuildStatus object where the - properties can live.""" - self.build_status.setProperty(propname, value, source) - - def getProperties(self): - return self.build_status.getProperties() - - def getProperty(self, propname): - return self.build_status.getProperty(propname) - - def allChanges(self): - return self.source.changes - - def allFiles(self): - # return a list of all source files that were changed - files = [] - havedirs = 0 - for c in self.allChanges(): - for f in c.files: - files.append(f) - if c.isdir: - havedirs = 1 - return files - - def __repr__(self): - return "" % (self.builder.name,) - - def __getstate__(self): - d = self.__dict__.copy() - if d.has_key('remote'): - del d['remote'] - return d - - def blamelist(self): - blamelist = [] - for c in self.allChanges(): - if c.who not in blamelist: - blamelist.append(c.who) - blamelist.sort() - return blamelist - - def changesText(self): - changetext = "" - for c in self.allChanges(): - changetext += "-" * 60 + "\n\n" + c.asText() + "\n" - # consider sorting these by number - return changetext - - def setStepFactories(self, step_factories): - """Set a list of 'step factories', which are tuples of (class, - kwargs), where 'class' is generally a subclass of step.BuildStep . - These are used to create the Steps themselves when the Build starts - (as opposed to when it is first created). By creating the steps - later, their __init__ method will have access to things like - build.allFiles() .""" - self.stepFactories = list(step_factories) - - - - useProgress = True - - def getSlaveCommandVersion(self, command, oldversion=None): - return self.slavebuilder.getSlaveCommandVersion(command, oldversion) - def getSlaveName(self): - return self.slavebuilder.slave.slavename - - def setupProperties(self): - props = self.getProperties() - - # start with global properties from the configuration - buildmaster = self.builder.botmaster.parent - props.updateFromProperties(buildmaster.properties) - - # get any properties from requests (this is the path through - # which schedulers will send us properties) - for rq in self.requests: - props.updateFromProperties(rq.properties) - - # now set some properties of our own, corresponding to the - # build itself - props.setProperty("buildername", self.builder.name, "Build") - props.setProperty("buildnumber", self.build_status.number, "Build") - props.setProperty("branch", self.source.branch, "Build") - props.setProperty("revision", self.source.revision, "Build") - - def setupSlaveBuilder(self, slavebuilder): - self.slavebuilder = slavebuilder - - # navigate our way back to the L{buildbot.buildslave.BuildSlave} - # object that came from the config, and get its properties - buildslave_properties = slavebuilder.slave.properties - self.getProperties().updateFromProperties(buildslave_properties) - - self.slavename = slavebuilder.slave.slavename - self.build_status.setSlavename(self.slavename) - - def startBuild(self, build_status, expectations, slavebuilder): - """This method sets up the build, then starts it by invoking the - first Step. It returns a Deferred which will fire when the build - finishes. This Deferred is guaranteed to never errback.""" - - # we are taking responsibility for watching the connection to the - # remote. This responsibility was held by the Builder until our - # startBuild was called, and will not return to them until we fire - # the Deferred returned by this method. - - log.msg("%s.startBuild" % self) - self.build_status = build_status - # now that we have a build_status, we can set properties - self.setupProperties() - self.setupSlaveBuilder(slavebuilder) - slavebuilder.slave.updateSlaveStatus(buildStarted=build_status) - - # convert all locks into their real forms - self.locks = [self.builder.botmaster.getLockByID(l) - for l in self.locks] - # then narrow SlaveLocks down to the right slave - self.locks = [l.getLock(self.slavebuilder) for l in self.locks] - self.remote = slavebuilder.remote - self.remote.notifyOnDisconnect(self.lostRemote) - d = self.deferred = defer.Deferred() - def _release_slave(res, slave, bs): - self.slavebuilder.buildFinished() - slave.updateSlaveStatus(buildFinished=bs) - return res - d.addCallback(_release_slave, self.slavebuilder.slave, build_status) - - try: - self.setupBuild(expectations) # create .steps - except: - # the build hasn't started yet, so log the exception as a point - # event instead of flunking the build. TODO: associate this - # failure with the build instead. this involves doing - # self.build_status.buildStarted() from within the exception - # handler - log.msg("Build.setupBuild failed") - log.err(Failure()) - self.builder.builder_status.addPointEvent(["setupBuild", - "exception"], - color="purple") - self.finished = True - self.results = FAILURE - self.deferred = None - d.callback(self) - return d - - self.acquireLocks().addCallback(self._startBuild_2) - return d - - def acquireLocks(self, res=None): - log.msg("acquireLocks(step %s, locks %s)" % (self, self.locks)) - if not self.locks: - return defer.succeed(None) - for lock in self.locks: - if not lock.isAvailable(): - log.msg("Build %s waiting for lock %s" % (self, lock)) - d = lock.waitUntilMaybeAvailable(self) - d.addCallback(self.acquireLocks) - return d - # all locks are available, claim them all - for lock in self.locks: - lock.claim(self) - return defer.succeed(None) - - def _startBuild_2(self, res): - self.build_status.buildStarted(self) - self.startNextStep() - - def setupBuild(self, expectations): - # create the actual BuildSteps. If there are any name collisions, we - # add a count to the loser until it is unique. - self.steps = [] - self.stepStatuses = {} - stepnames = [] - sps = [] - - for factory, args in self.stepFactories: - args = args.copy() - try: - step = factory(**args) - except: - log.msg("error while creating step, factory=%s, args=%s" - % (factory, args)) - raise - step.setBuild(self) - step.setBuildSlave(self.slavebuilder.slave) - step.setDefaultWorkdir(self.workdir) - name = step.name - count = 1 - while name in stepnames and count < 100: - count += 1 - name = step.name + "_%d" % count - if name in stepnames: - raise RuntimeError("duplicate step '%s'" % step.name) - step.name = name - stepnames.append(name) - self.steps.append(step) - - # tell the BuildStatus about the step. This will create a - # BuildStepStatus and bind it to the Step. - step_status = self.build_status.addStepWithName(name) - step.setStepStatus(step_status) - - sp = None - if self.useProgress: - # XXX: maybe bail if step.progressMetrics is empty? or skip - # progress for that one step (i.e. "it is fast"), or have a - # separate "variable" flag that makes us bail on progress - # tracking - sp = step.setupProgress() - if sp: - sps.append(sp) - - # Create a buildbot.status.progress.BuildProgress object. This is - # called once at startup to figure out how to build the long-term - # Expectations object, and again at the start of each build to get a - # fresh BuildProgress object to track progress for that individual - # build. TODO: revisit at-startup call - - if self.useProgress: - self.progress = BuildProgress(sps) - if self.progress and expectations: - self.progress.setExpectationsFrom(expectations) - - # we are now ready to set up our BuildStatus. - self.build_status.setSourceStamp(self.source) - self.build_status.setReason(self.reason) - self.build_status.setBlamelist(self.blamelist()) - self.build_status.setProgress(self.progress) - - self.results = [] # list of FAILURE, SUCCESS, WARNINGS, SKIPPED - self.result = SUCCESS # overall result, may downgrade after each step - self.text = [] # list of text string lists (text2) - - def getNextStep(self): - """This method is called to obtain the next BuildStep for this build. - When it returns None (or raises a StopIteration exception), the build - is complete.""" - if not self.steps: - return None - return self.steps.pop(0) - - def startNextStep(self): - try: - s = self.getNextStep() - except StopIteration: - s = None - if not s: - return self.allStepsDone() - self.currentStep = s - d = defer.maybeDeferred(s.startStep, self.remote) - d.addCallback(self._stepDone, s) - d.addErrback(self.buildException) - - def _stepDone(self, results, step): - self.currentStep = None - if self.finished: - return # build was interrupted, don't keep building - terminate = self.stepDone(results, step) # interpret/merge results - if terminate: - return self.allStepsDone() - self.startNextStep() - - def stepDone(self, result, step): - """This method is called when the BuildStep completes. It is passed a - status object from the BuildStep and is responsible for merging the - Step's results into those of the overall Build.""" - - terminate = False - text = None - if type(result) == types.TupleType: - result, text = result - assert type(result) == type(SUCCESS) - log.msg(" step '%s' complete: %s" % (step.name, Results[result])) - self.results.append(result) - if text: - self.text.extend(text) - if not self.remote: - terminate = True - if result == FAILURE: - if step.warnOnFailure: - if self.result != FAILURE: - self.result = WARNINGS - if step.flunkOnFailure: - self.result = FAILURE - if step.haltOnFailure: - self.result = FAILURE - terminate = True - elif result == WARNINGS: - if step.warnOnWarnings: - if self.result != FAILURE: - self.result = WARNINGS - if step.flunkOnWarnings: - self.result = FAILURE - elif result == EXCEPTION: - self.result = EXCEPTION - terminate = True - return terminate - - def lostRemote(self, remote=None): - # the slave went away. There are several possible reasons for this, - # and they aren't necessarily fatal. For now, kill the build, but - # TODO: see if we can resume the build when it reconnects. - log.msg("%s.lostRemote" % self) - self.remote = None - if self.currentStep: - # this should cause the step to finish. - log.msg(" stopping currentStep", self.currentStep) - self.currentStep.interrupt(Failure(error.ConnectionLost())) - - def stopBuild(self, reason=""): - # the idea here is to let the user cancel a build because, e.g., - # they realized they committed a bug and they don't want to waste - # the time building something that they know will fail. Another - # reason might be to abandon a stuck build. We want to mark the - # build as failed quickly rather than waiting for the slave's - # timeout to kill it on its own. - - log.msg(" %s: stopping build: %s" % (self, reason)) - if self.finished: - return - # TODO: include 'reason' in this point event - self.builder.builder_status.addPointEvent(['interrupt']) - self.currentStep.interrupt(reason) - if 0: - # TODO: maybe let its deferred do buildFinished - if self.currentStep and self.currentStep.progress: - # XXX: really .fail or something - self.currentStep.progress.finish() - text = ["stopped", reason] - self.buildFinished(text, "red", FAILURE) - - def allStepsDone(self): - if self.result == FAILURE: - color = "red" - text = ["failed"] - elif self.result == WARNINGS: - color = "orange" - text = ["warnings"] - elif self.result == EXCEPTION: - color = "purple" - text = ["exception"] - else: - color = "green" - text = ["build", "successful"] - text.extend(self.text) - return self.buildFinished(text, color, self.result) - - def buildException(self, why): - log.msg("%s.buildException" % self) - log.err(why) - self.buildFinished(["build", "exception"], "purple", FAILURE) - - def buildFinished(self, text, color, results): - """This method must be called when the last Step has completed. It - marks the Build as complete and returns the Builder to the 'idle' - state. - - It takes three arguments which describe the overall build status: - text, color, results. 'results' is one of SUCCESS, WARNINGS, or - FAILURE. - - If 'results' is SUCCESS or WARNINGS, we will permit any dependant - builds to start. If it is 'FAILURE', those builds will be - abandoned.""" - - self.finished = True - if self.remote: - self.remote.dontNotifyOnDisconnect(self.lostRemote) - self.results = results - - log.msg(" %s: build finished" % self) - self.build_status.setText(text) - self.build_status.setColor(color) - self.build_status.setResults(results) - self.build_status.buildFinished() - if self.progress: - # XXX: also test a 'timing consistent' flag? - log.msg(" setting expectations for next time") - self.builder.setExpectations(self.progress) - reactor.callLater(0, self.releaseLocks) - self.deferred.callback(self) - self.deferred = None - - def releaseLocks(self): - log.msg("releaseLocks(%s): %s" % (self, self.locks)) - for lock in self.locks: - lock.release(self) - - # IBuildControl - - def getStatus(self): - return self.build_status - - # stopBuild is defined earlier - diff --git a/tools/buildbot/pylibs/buildbot/process/builder.py b/tools/buildbot/pylibs/buildbot/process/builder.py deleted file mode 100644 index e0beb7c..0000000 --- a/tools/buildbot/pylibs/buildbot/process/builder.py +++ /dev/null @@ -1,745 +0,0 @@ - -import random, weakref -from zope.interface import implements -from twisted.python import log, components -from twisted.spread import pb -from twisted.internet import reactor, defer - -from buildbot import interfaces -from buildbot.status.progress import Expectations -from buildbot.util import now -from buildbot.process import base - -(ATTACHING, # slave attached, still checking hostinfo/etc - IDLE, # idle, available for use - PINGING, # build about to start, making sure it is still alive - BUILDING, # build is running - ) = range(4) - -class SlaveBuilder(pb.Referenceable): - """I am the master-side representative for one of the - L{buildbot.slave.bot.SlaveBuilder} objects that lives in a remote - buildbot. When a remote builder connects, I query it for command versions - and then make it available to any Builds that are ready to run. """ - - def __init__(self): - self.ping_watchers = [] - self.state = ATTACHING - self.remote = None - self.slave = None - self.builder_name = None - - def __repr__(self): - r = " string, or None - @param commands: provides the slave's version of each RemoteCommand - """ - self.slave = slave - self.remote = remote - self.remoteCommands = commands # maps command name to version - self.slave.addSlaveBuilder(self) - log.msg("Buildslave %s attached to %s" % (slave.slavename, - self.builder_name)) - d = self.remote.callRemote("setMaster", self) - d.addErrback(self._attachFailure, "Builder.setMaster") - d.addCallback(self._attached2) - return d - - def _attached2(self, res): - d = self.remote.callRemote("print", "attached") - d.addErrback(self._attachFailure, "Builder.print 'attached'") - d.addCallback(self._attached3) - return d - - def _attached3(self, res): - # now we say they're really attached - self.state = IDLE - return self - - def _attachFailure(self, why, where): - assert isinstance(where, str) - log.msg(where) - log.err(why) - return why - - def detached(self): - log.msg("Buildslave %s detached from %s" % (self.slave.slavename, - self.builder_name)) - if self.slave: - self.slave.removeSlaveBuilder(self) - self.slave = None - self.remote = None - self.remoteCommands = None - - def buildStarted(self): - self.state = BUILDING - - def buildFinished(self): - self.state = IDLE - reactor.callLater(0, self.builder.botmaster.maybeStartAllBuilds) - - def ping(self, timeout, status=None): - """Ping the slave to make sure it is still there. Returns a Deferred - that fires with True if it is. - - @param status: if you point this at a BuilderStatus, a 'pinging' - event will be pushed. - """ - - self.state = PINGING - newping = not self.ping_watchers - d = defer.Deferred() - self.ping_watchers.append(d) - if newping: - if status: - event = status.addEvent(["pinging"], "yellow") - d2 = defer.Deferred() - d2.addCallback(self._pong_status, event) - self.ping_watchers.insert(0, d2) - # I think it will make the tests run smoother if the status - # is updated before the ping completes - Ping().ping(self.remote, timeout).addCallback(self._pong) - - return d - - def _pong(self, res): - watchers, self.ping_watchers = self.ping_watchers, [] - for d in watchers: - d.callback(res) - - def _pong_status(self, res, event): - if res: - event.text = ["ping", "success"] - event.color = "green" - else: - event.text = ["ping", "failed"] - event.color = "red" - event.finish() - -class Ping: - running = False - timer = None - - def ping(self, remote, timeout): - assert not self.running - self.running = True - log.msg("sending ping") - self.d = defer.Deferred() - # TODO: add a distinct 'ping' command on the slave.. using 'print' - # for this purpose is kind of silly. - remote.callRemote("print", "ping").addCallbacks(self._pong, - self._ping_failed, - errbackArgs=(remote,)) - - # We use either our own timeout or the (long) TCP timeout to detect - # silently-missing slaves. This might happen because of a NAT - # timeout or a routing loop. If the slave just shuts down (and we - # somehow missed the FIN), we should get a "connection refused" - # message. - self.timer = reactor.callLater(timeout, self._ping_timeout, remote) - return self.d - - def _ping_timeout(self, remote): - log.msg("ping timeout") - # force the BuildSlave to disconnect, since this indicates that - # the bot is unreachable. - del self.timer - remote.broker.transport.loseConnection() - # the forcibly-lost connection will now cause the ping to fail - - def _stopTimer(self): - if not self.running: - return - self.running = False - - if self.timer: - self.timer.cancel() - del self.timer - - def _pong(self, res): - log.msg("ping finished: success") - self._stopTimer() - self.d.callback(True) - - def _ping_failed(self, res, remote): - log.msg("ping finished: failure") - self._stopTimer() - # the slave has some sort of internal error, disconnect them. If we - # don't, we'll requeue a build and ping them again right away, - # creating a nasty loop. - remote.broker.transport.loseConnection() - # TODO: except, if they actually did manage to get this far, they'll - # probably reconnect right away, and we'll do this game again. Maybe - # it would be better to leave them in the PINGING state. - self.d.callback(False) - - -class Builder(pb.Referenceable): - """I manage all Builds of a given type. - - Each Builder is created by an entry in the config file (the c['builders'] - list), with a number of parameters. - - One of these parameters is the L{buildbot.process.factory.BuildFactory} - object that is associated with this Builder. The factory is responsible - for creating new L{Build} objects. Each - Build object defines when and how the build is performed, so a new - Factory or Builder should be defined to control this behavior. - - The Builder holds on to a number of L{base.BuildRequest} objects in a - list named C{.buildable}. Incoming BuildRequest objects will be added to - this list, or (if possible) merged into an existing request. When a slave - becomes available, I will use my C{BuildFactory} to turn the request into - a new C{Build} object. The C{BuildRequest} is forgotten, the C{Build} - goes into C{.building} while it runs. Once the build finishes, I will - discard it. - - I maintain a list of available SlaveBuilders, one for each connected - slave that the C{slavenames} parameter says we can use. Some of these - will be idle, some of them will be busy running builds for me. If there - are multiple slaves, I can run multiple builds at once. - - I also manage forced builds, progress expectation (ETA) management, and - some status delivery chores. - - I am persisted in C{BASEDIR/BUILDERNAME/builder}, so I can remember how - long a build usually takes to run (in my C{expectations} attribute). This - pickle also includes the L{buildbot.status.builder.BuilderStatus} object, - which remembers the set of historic builds. - - @type buildable: list of L{buildbot.process.base.BuildRequest} - @ivar buildable: BuildRequests that are ready to build, but which are - waiting for a buildslave to be available. - - @type building: list of L{buildbot.process.base.Build} - @ivar building: Builds that are actively running - - @type slaves: list of L{buildbot.buildslave.BuildSlave} objects - @ivar slaves: the slaves currently available for building - """ - - expectations = None # this is created the first time we get a good build - START_BUILD_TIMEOUT = 10 - CHOOSE_SLAVES_RANDOMLY = True # disabled for determinism during tests - - def __init__(self, setup, builder_status): - """ - @type setup: dict - @param setup: builder setup data, as stored in - BuildmasterConfig['builders']. Contains name, - slavename(s), builddir, factory, locks. - @type builder_status: L{buildbot.status.builder.BuilderStatus} - """ - self.name = setup['name'] - self.slavenames = [] - if setup.has_key('slavename'): - self.slavenames.append(setup['slavename']) - if setup.has_key('slavenames'): - self.slavenames.extend(setup['slavenames']) - self.builddir = setup['builddir'] - self.buildFactory = setup['factory'] - self.locks = setup.get("locks", []) - if setup.has_key('periodicBuildTime'): - raise ValueError("periodicBuildTime can no longer be defined as" - " part of the Builder: use scheduler.Periodic" - " instead") - - # build/wannabuild slots: Build objects move along this sequence - self.buildable = [] - self.building = [] - # old_building holds active builds that were stolen from a predecessor - self.old_building = weakref.WeakKeyDictionary() - - # buildslaves which have connected but which are not yet available. - # These are always in the ATTACHING state. - self.attaching_slaves = [] - - # buildslaves at our disposal. Each SlaveBuilder instance has a - # .state that is IDLE, PINGING, or BUILDING. "PINGING" is used when a - # Build is about to start, to make sure that they're still alive. - self.slaves = [] - - self.builder_status = builder_status - self.builder_status.setSlavenames(self.slavenames) - - # for testing, to help synchronize tests - self.watchers = {'attach': [], 'detach': [], 'detach_all': [], - 'idle': []} - - def setBotmaster(self, botmaster): - self.botmaster = botmaster - - def compareToSetup(self, setup): - diffs = [] - setup_slavenames = [] - if setup.has_key('slavename'): - setup_slavenames.append(setup['slavename']) - setup_slavenames.extend(setup.get('slavenames', [])) - if setup_slavenames != self.slavenames: - diffs.append('slavenames changed from %s to %s' \ - % (self.slavenames, setup_slavenames)) - if setup['builddir'] != self.builddir: - diffs.append('builddir changed from %s to %s' \ - % (self.builddir, setup['builddir'])) - if setup['factory'] != self.buildFactory: # compare objects - diffs.append('factory changed') - oldlocks = [(lock.__class__, lock.name) - for lock in setup.get('locks',[])] - newlocks = [(lock.__class__, lock.name) - for lock in self.locks] - if oldlocks != newlocks: - diffs.append('locks changed from %s to %s' % (oldlocks, newlocks)) - return diffs - - def __repr__(self): - return "" % (self.name, id(self)) - - - def submitBuildRequest(self, req): - req.submittedAt = now() - self.buildable.append(req) - req.requestSubmitted(self) - self.builder_status.addBuildRequest(req.status) - self.maybeStartBuild() - - def cancelBuildRequest(self, req): - if req in self.buildable: - self.buildable.remove(req) - self.builder_status.removeBuildRequest(req.status) - return True - return False - - def __getstate__(self): - d = self.__dict__.copy() - # TODO: note that d['buildable'] can contain Deferreds - del d['building'] # TODO: move these back to .buildable? - del d['slaves'] - return d - - def __setstate__(self, d): - self.__dict__ = d - self.building = [] - self.slaves = [] - - def consumeTheSoulOfYourPredecessor(self, old): - """Suck the brain out of an old Builder. - - This takes all the runtime state from an existing Builder and moves - it into ourselves. This is used when a Builder is changed in the - master.cfg file: the new Builder has a different factory, but we want - all the builds that were queued for the old one to get processed by - the new one. Any builds which are already running will keep running. - The new Builder will get as many of the old SlaveBuilder objects as - it wants.""" - - log.msg("consumeTheSoulOfYourPredecessor: %s feeding upon %s" % - (self, old)) - # we claim all the pending builds, removing them from the old - # Builder's queue. This insures that the old Builder will not start - # any new work. - log.msg(" stealing %s buildrequests" % len(old.buildable)) - self.buildable.extend(old.buildable) - old.buildable = [] - - # old.building (i.e. builds which are still running) is not migrated - # directly: it keeps track of builds which were in progress in the - # old Builder. When those builds finish, the old Builder will be - # notified, not us. However, since the old SlaveBuilder will point to - # us, it is our maybeStartBuild() that will be triggered. - if old.building: - self.builder_status.setBigState("building") - # however, we do grab a weakref to the active builds, so that our - # BuilderControl can see them and stop them. We use a weakref because - # we aren't the one to get notified, so there isn't a convenient - # place to remove it from self.building . - for b in old.building: - self.old_building[b] = None - for b in old.old_building: - self.old_building[b] = None - - # Our set of slavenames may be different. Steal any of the old - # buildslaves that we want to keep using. - for sb in old.slaves[:]: - if sb.slave.slavename in self.slavenames: - log.msg(" stealing buildslave %s" % sb) - self.slaves.append(sb) - old.slaves.remove(sb) - sb.setBuilder(self) - - # old.attaching_slaves: - # these SlaveBuilders are waiting on a sequence of calls: - # remote.setMaster and remote.print . When these two complete, - # old._attached will be fired, which will add a 'connect' event to - # the builder_status and try to start a build. However, we've pulled - # everything out of the old builder's queue, so it will have no work - # to do. The outstanding remote.setMaster/print call will be holding - # the last reference to the old builder, so it will disappear just - # after that response comes back. - # - # The BotMaster will ask the slave to re-set their list of Builders - # shortly after this function returns, which will cause our - # attached() method to be fired with a bunch of references to remote - # SlaveBuilders, some of which we already have (by stealing them - # from the old Builder), some of which will be new. The new ones - # will be re-attached. - - # Therefore, we don't need to do anything about old.attaching_slaves - - return # all done - - def getBuild(self, number): - for b in self.building: - if b.build_status.number == number: - return b - for b in self.old_building.keys(): - if b.build_status.number == number: - return b - return None - - def fireTestEvent(self, name, fire_with=None): - if fire_with is None: - fire_with = self - watchers = self.watchers[name] - self.watchers[name] = [] - for w in watchers: - reactor.callLater(0, w.callback, fire_with) - - def attached(self, slave, remote, commands): - """This is invoked by the BuildSlave when the self.slavename bot - registers their builder. - - @type slave: L{buildbot.buildslave.BuildSlave} - @param slave: the BuildSlave that represents the buildslave as a whole - @type remote: L{twisted.spread.pb.RemoteReference} - @param remote: a reference to the L{buildbot.slave.bot.SlaveBuilder} - @type commands: dict: string -> string, or None - @param commands: provides the slave's version of each RemoteCommand - - @rtype: L{twisted.internet.defer.Deferred} - @return: a Deferred that fires (with 'self') when the slave-side - builder is fully attached and ready to accept commands. - """ - for s in self.attaching_slaves + self.slaves: - if s.slave == slave: - # already attached to them. This is fairly common, since - # attached() gets called each time we receive the builder - # list from the slave, and we ask for it each time we add or - # remove a builder. So if the slave is hosting builders - # A,B,C, and the config file changes A, we'll remove A and - # re-add it, triggering two builder-list requests, getting - # two redundant calls to attached() for B, and another two - # for C. - # - # Therefore, when we see that we're already attached, we can - # just ignore it. TODO: build a diagram of the state - # transitions here, I'm concerned about sb.attached() failing - # and leaving sb.state stuck at 'ATTACHING', and about - # the detached() message arriving while there's some - # transition pending such that the response to the transition - # re-vivifies sb - return defer.succeed(self) - - sb = SlaveBuilder() - sb.setBuilder(self) - self.attaching_slaves.append(sb) - d = sb.attached(slave, remote, commands) - d.addCallback(self._attached) - d.addErrback(self._not_attached, slave) - return d - - def _attached(self, sb): - # TODO: make this .addSlaveEvent(slave.slavename, ['connect']) ? - self.builder_status.addPointEvent(['connect', sb.slave.slavename]) - self.attaching_slaves.remove(sb) - self.slaves.append(sb) - reactor.callLater(0, self.maybeStartBuild) - - self.fireTestEvent('attach') - return self - - def _not_attached(self, why, slave): - # already log.err'ed by SlaveBuilder._attachFailure - # TODO: make this .addSlaveEvent? - # TODO: remove from self.slaves (except that detached() should get - # run first, right?) - self.builder_status.addPointEvent(['failed', 'connect', - slave.slave.slavename]) - # TODO: add an HTMLLogFile of the exception - self.fireTestEvent('attach', why) - - def detached(self, slave): - """This is called when the connection to the bot is lost.""" - log.msg("%s.detached" % self, slave.slavename) - for sb in self.attaching_slaves + self.slaves: - if sb.slave == slave: - break - else: - log.msg("WEIRD: Builder.detached(%s) (%s)" - " not in attaching_slaves(%s)" - " or slaves(%s)" % (slave, slave.slavename, - self.attaching_slaves, - self.slaves)) - return - if sb.state == BUILDING: - # the Build's .lostRemote method (invoked by a notifyOnDisconnect - # handler) will cause the Build to be stopped, probably right - # after the notifyOnDisconnect that invoked us finishes running. - - # TODO: should failover to a new Build - #self.retryBuild(sb.build) - pass - - if sb in self.attaching_slaves: - self.attaching_slaves.remove(sb) - if sb in self.slaves: - self.slaves.remove(sb) - - # TODO: make this .addSlaveEvent? - self.builder_status.addPointEvent(['disconnect', slave.slavename]) - sb.detached() # inform the SlaveBuilder that their slave went away - self.updateBigStatus() - self.fireTestEvent('detach') - if not self.slaves: - self.fireTestEvent('detach_all') - - def updateBigStatus(self): - if not self.slaves: - self.builder_status.setBigState("offline") - elif self.building: - self.builder_status.setBigState("building") - else: - self.builder_status.setBigState("idle") - self.fireTestEvent('idle') - - def maybeStartBuild(self): - log.msg("maybeStartBuild %s: %s %s" % - (self, self.buildable, self.slaves)) - if not self.buildable: - self.updateBigStatus() - return # nothing to do - - # pick an idle slave - available_slaves = [sb for sb in self.slaves if sb.isAvailable()] - if not available_slaves: - log.msg("%s: want to start build, but we don't have a remote" - % self) - self.updateBigStatus() - return - if self.CHOOSE_SLAVES_RANDOMLY: - sb = random.choice(available_slaves) - else: - sb = available_slaves[0] - - # there is something to build, and there is a slave on which to build - # it. Grab the oldest request, see if we can merge it with anything - # else. - req = self.buildable.pop(0) - self.builder_status.removeBuildRequest(req.status) - mergers = [] - for br in self.buildable[:]: - if req.canBeMergedWith(br): - self.buildable.remove(br) - self.builder_status.removeBuildRequest(br.status) - mergers.append(br) - requests = [req] + mergers - - # Create a new build from our build factory and set ourself as the - # builder. - build = self.buildFactory.newBuild(requests) - build.setBuilder(self) - build.setLocks(self.locks) - - # start it - self.startBuild(build, sb) - - def startBuild(self, build, sb): - """Start a build on the given slave. - @param build: the L{base.Build} to start - @param sb: the L{SlaveBuilder} which will host this build - - @return: a Deferred which fires with a - L{buildbot.interfaces.IBuildControl} that can be used to stop the - Build, or to access a L{buildbot.interfaces.IBuildStatus} which will - watch the Build as it runs. """ - - self.building.append(build) - self.updateBigStatus() - - log.msg("starting build %s.. pinging the slave %s" % (build, sb)) - # ping the slave to make sure they're still there. If they're fallen - # off the map (due to a NAT timeout or something), this will fail in - # a couple of minutes, depending upon the TCP timeout. TODO: consider - # making this time out faster, or at least characterize the likely - # duration. - d = sb.ping(self.START_BUILD_TIMEOUT) - d.addCallback(self._startBuild_1, build, sb) - return d - - def _startBuild_1(self, res, build, sb): - if not res: - return self._startBuildFailed("slave ping failed", build, sb) - # The buildslave is ready to go. sb.buildStarted() sets its state to - # BUILDING (so we won't try to use it for any other builds). This - # gets set back to IDLE by the Build itself when it finishes. - sb.buildStarted() - d = sb.remote.callRemote("startBuild") - d.addCallbacks(self._startBuild_2, self._startBuildFailed, - callbackArgs=(build,sb), errbackArgs=(build,sb)) - return d - - def _startBuild_2(self, res, build, sb): - # create the BuildStatus object that goes with the Build - bs = self.builder_status.newBuild() - - # start the build. This will first set up the steps, then tell the - # BuildStatus that it has started, which will announce it to the - # world (through our BuilderStatus object, which is its parent). - # Finally it will start the actual build process. - d = build.startBuild(bs, self.expectations, sb) - d.addCallback(self.buildFinished, sb) - d.addErrback(log.err) # this shouldn't happen. if it does, the slave - # will be wedged - for req in build.requests: - req.buildStarted(build, bs) - return build # this is the IBuildControl - - def _startBuildFailed(self, why, build, sb): - # put the build back on the buildable list - log.msg("I tried to tell the slave that the build %s started, but " - "remote_startBuild failed: %s" % (build, why)) - # release the slave. This will queue a call to maybeStartBuild, which - # will fire after other notifyOnDisconnect handlers have marked the - # slave as disconnected (so we don't try to use it again). - sb.buildFinished() - - log.msg("re-queueing the BuildRequest") - self.building.remove(build) - for req in build.requests: - self.buildable.insert(0, req) # the interrupted build gets first - # priority - self.builder_status.addBuildRequest(req.status) - - - def buildFinished(self, build, sb): - """This is called when the Build has finished (either success or - failure). Any exceptions during the build are reported with - results=FAILURE, not with an errback.""" - - # by the time we get here, the Build has already released the slave - # (which queues a call to maybeStartBuild) - - self.building.remove(build) - for req in build.requests: - req.finished(build.build_status) - - def setExpectations(self, progress): - """Mark the build as successful and update expectations for the next - build. Only call this when the build did not fail in any way that - would invalidate the time expectations generated by it. (if the - compile failed and thus terminated early, we can't use the last - build to predict how long the next one will take). - """ - if self.expectations: - self.expectations.update(progress) - else: - # the first time we get a good build, create our Expectations - # based upon its results - self.expectations = Expectations(progress) - log.msg("new expectations: %s seconds" % \ - self.expectations.expectedBuildTime()) - - def shutdownSlave(self): - if self.remote: - self.remote.callRemote("shutdown") - - -class BuilderControl(components.Adapter): - implements(interfaces.IBuilderControl) - - def requestBuild(self, req): - """Submit a BuildRequest to this Builder.""" - self.original.submitBuildRequest(req) - - def requestBuildSoon(self, req): - """Submit a BuildRequest like requestBuild, but raise a - L{buildbot.interfaces.NoSlaveError} if no slaves are currently - available, so it cannot be used to queue a BuildRequest in the hopes - that a slave will eventually connect. This method is appropriate for - use by things like the web-page 'Force Build' button.""" - if not self.original.slaves: - raise interfaces.NoSlaveError - self.requestBuild(req) - - def resubmitBuild(self, bs, reason=""): - if not bs.isFinished(): - return - - ss = bs.getSourceStamp(absolute=True) - req = base.BuildRequest(reason, ss, self.original.name) - self.requestBuild(req) - - def getPendingBuilds(self): - # return IBuildRequestControl objects - raise NotImplementedError - - def getBuild(self, number): - return self.original.getBuild(number) - - def ping(self, timeout=30): - if not self.original.slaves: - self.original.builder_status.addPointEvent(["ping", "no slave"], - "red") - return defer.succeed(False) # interfaces.NoSlaveError - dl = [] - for s in self.original.slaves: - dl.append(s.ping(timeout, self.original.builder_status)) - d = defer.DeferredList(dl) - d.addCallback(self._gatherPingResults) - return d - - def _gatherPingResults(self, res): - for ignored,success in res: - if not success: - return False - return True - -components.registerAdapter(BuilderControl, Builder, interfaces.IBuilderControl) diff --git a/tools/buildbot/pylibs/buildbot/process/buildstep.py b/tools/buildbot/pylibs/buildbot/process/buildstep.py deleted file mode 100644 index fe2eea4..0000000 --- a/tools/buildbot/pylibs/buildbot/process/buildstep.py +++ /dev/null @@ -1,1098 +0,0 @@ -# -*- test-case-name: buildbot.test.test_steps -*- - -from zope.interface import implements -from twisted.internet import reactor, defer, error -from twisted.protocols import basic -from twisted.spread import pb -from twisted.python import log -from twisted.python.failure import Failure -from twisted.web.util import formatFailure - -from buildbot import interfaces -from buildbot.status import progress -from buildbot.status.builder import SUCCESS, WARNINGS, FAILURE, SKIPPED, \ - EXCEPTION - -""" -BuildStep and RemoteCommand classes for master-side representation of the -build process -""" - -class RemoteCommand(pb.Referenceable): - """ - I represent a single command to be run on the slave. I handle the details - of reliably gathering status updates from the slave (acknowledging each), - and (eventually, in a future release) recovering from interrupted builds. - This is the master-side object that is known to the slave-side - L{buildbot.slave.bot.SlaveBuilder}, to which status updates are sent. - - My command should be started by calling .run(), which returns a - Deferred that will fire when the command has finished, or will - errback if an exception is raised. - - Typically __init__ or run() will set up self.remote_command to be a - string which corresponds to one of the SlaveCommands registered in - the buildslave, and self.args to a dictionary of arguments that will - be passed to the SlaveCommand instance. - - start, remoteUpdate, and remoteComplete are available to be overridden - - @type commandCounter: list of one int - @cvar commandCounter: provides a unique value for each - RemoteCommand executed across all slaves - @type active: boolean - @ivar active: whether the command is currently running - """ - commandCounter = [0] # we use a list as a poor man's singleton - active = False - - def __init__(self, remote_command, args): - """ - @type remote_command: string - @param remote_command: remote command to start. This will be - passed to - L{buildbot.slave.bot.SlaveBuilder.remote_startCommand} - and needs to have been registered - slave-side by - L{buildbot.slave.registry.registerSlaveCommand} - @type args: dict - @param args: arguments to send to the remote command - """ - - self.remote_command = remote_command - self.args = args - - def __getstate__(self): - dict = self.__dict__.copy() - # Remove the remote ref: if necessary (only for resumed builds), it - # will be reattached at resume time - if dict.has_key("remote"): - del dict["remote"] - return dict - - def run(self, step, remote): - self.active = True - self.step = step - self.remote = remote - c = self.commandCounter[0] - self.commandCounter[0] += 1 - #self.commandID = "%d %d" % (c, random.randint(0, 1000000)) - self.commandID = "%d" % c - log.msg("%s: RemoteCommand.run [%s]" % (self, self.commandID)) - self.deferred = defer.Deferred() - - d = defer.maybeDeferred(self.start) - - # _finished is called with an error for unknown commands, errors - # that occur while the command is starting (including OSErrors in - # exec()), StaleBroker (when the connection was lost before we - # started), and pb.PBConnectionLost (when the slave isn't responding - # over this connection, perhaps it had a power failure, or NAT - # weirdness). If this happens, self.deferred is fired right away. - d.addErrback(self._finished) - - # Connections which are lost while the command is running are caught - # when our parent Step calls our .lostRemote() method. - return self.deferred - - def start(self): - """ - Tell the slave to start executing the remote command. - - @rtype: L{twisted.internet.defer.Deferred} - @returns: a deferred that will fire when the remote command is - done (with None as the result) - """ - # This method only initiates the remote command. - # We will receive remote_update messages as the command runs. - # We will get a single remote_complete when it finishes. - # We should fire self.deferred when the command is done. - d = self.remote.callRemote("startCommand", self, self.commandID, - self.remote_command, self.args) - return d - - def interrupt(self, why): - # TODO: consider separating this into interrupt() and stop(), where - # stop() unconditionally calls _finished, but interrupt() merely - # asks politely for the command to stop soon. - - log.msg("RemoteCommand.interrupt", self, why) - if not self.active: - log.msg(" but this RemoteCommand is already inactive") - return - if not self.remote: - log.msg(" but our .remote went away") - return - if isinstance(why, Failure) and why.check(error.ConnectionLost): - log.msg("RemoteCommand.disconnect: lost slave") - self.remote = None - self._finished(why) - return - - # tell the remote command to halt. Returns a Deferred that will fire - # when the interrupt command has been delivered. - - d = defer.maybeDeferred(self.remote.callRemote, "interruptCommand", - self.commandID, str(why)) - # the slave may not have remote_interruptCommand - d.addErrback(self._interruptFailed) - return d - - def _interruptFailed(self, why): - log.msg("RemoteCommand._interruptFailed", self) - # TODO: forcibly stop the Command now, since we can't stop it - # cleanly - return None - - def remote_update(self, updates): - """ - I am called by the slave's L{buildbot.slave.bot.SlaveBuilder} so - I can receive updates from the running remote command. - - @type updates: list of [object, int] - @param updates: list of updates from the remote command - """ - self.buildslave.messageReceivedFromSlave() - max_updatenum = 0 - for (update, num) in updates: - #log.msg("update[%d]:" % num) - try: - if self.active: # ignore late updates - self.remoteUpdate(update) - except: - # log failure, terminate build, let slave retire the update - self._finished(Failure()) - # TODO: what if multiple updates arrive? should - # skip the rest but ack them all - if num > max_updatenum: - max_updatenum = num - return max_updatenum - - def remoteUpdate(self, update): - raise NotImplementedError("You must implement this in a subclass") - - def remote_complete(self, failure=None): - """ - Called by the slave's L{buildbot.slave.bot.SlaveBuilder} to - notify me the remote command has finished. - - @type failure: L{twisted.python.failure.Failure} or None - - @rtype: None - """ - self.buildslave.messageReceivedFromSlave() - # call the real remoteComplete a moment later, but first return an - # acknowledgement so the slave can retire the completion message. - if self.active: - reactor.callLater(0, self._finished, failure) - return None - - def _finished(self, failure=None): - self.active = False - # call .remoteComplete. If it raises an exception, or returns the - # Failure that we gave it, our self.deferred will be errbacked. If - # it does not (either it ate the Failure or there the step finished - # normally and it didn't raise a new exception), self.deferred will - # be callbacked. - d = defer.maybeDeferred(self.remoteComplete, failure) - # arrange for the callback to get this RemoteCommand instance - # instead of just None - d.addCallback(lambda r: self) - # this fires the original deferred we returned from .run(), - # with self as the result, or a failure - d.addBoth(self.deferred.callback) - - def remoteComplete(self, maybeFailure): - """Subclasses can override this. - - This is called when the RemoteCommand has finished. 'maybeFailure' - will be None if the command completed normally, or a Failure - instance in one of the following situations: - - - the slave was lost before the command was started - - the slave didn't respond to the startCommand message - - the slave raised an exception while starting the command - (bad command name, bad args, OSError from missing executable) - - the slave raised an exception while finishing the command - (they send back a remote_complete message with a Failure payload) - - and also (for now): - - slave disconnected while the command was running - - This method should do cleanup, like closing log files. It should - normally return the 'failure' argument, so that any exceptions will - be propagated to the Step. If it wants to consume them, return None - instead.""" - - return maybeFailure - -class LoggedRemoteCommand(RemoteCommand): - """ - - I am a L{RemoteCommand} which gathers output from the remote command into - one or more local log files. My C{self.logs} dictionary contains - references to these L{buildbot.status.builder.LogFile} instances. Any - stdout/stderr/header updates from the slave will be put into - C{self.logs['stdio']}, if it exists. If the remote command uses other log - files, they will go into other entries in C{self.logs}. - - If you want to use stdout or stderr, you should create a LogFile named - 'stdio' and pass it to my useLog() message. Otherwise stdout/stderr will - be ignored, which is probably not what you want. - - Unless you tell me otherwise, when my command completes I will close all - the LogFiles that I know about. - - @ivar logs: maps logname to a LogFile instance - @ivar _closeWhenFinished: maps logname to a boolean. If true, this - LogFile will be closed when the RemoteCommand - finishes. LogFiles which are shared between - multiple RemoteCommands should use False here. - - """ - - rc = None - debug = False - - def __init__(self, *args, **kwargs): - self.logs = {} - self._closeWhenFinished = {} - RemoteCommand.__init__(self, *args, **kwargs) - - def __repr__(self): - return "" % (self.remote_command, id(self)) - - def useLog(self, loog, closeWhenFinished=False, logfileName=None): - """Start routing messages from a remote logfile to a local LogFile - - I take a local ILogFile instance in 'loog', and arrange to route - remote log messages for the logfile named 'logfileName' into it. By - default this logfileName comes from the ILogFile itself (using the - name by which the ILogFile will be displayed), but the 'logfileName' - argument can be used to override this. For example, if - logfileName='stdio', this logfile will collect text from the stdout - and stderr of the command. - - @param loog: an instance which implements ILogFile - @param closeWhenFinished: a boolean, set to False if the logfile - will be shared between multiple - RemoteCommands. If True, the logfile will - be closed when this ShellCommand is done - with it. - @param logfileName: a string, which indicates which remote log file - should be routed into this ILogFile. This should - match one of the keys of the logfiles= argument - to ShellCommand. - - """ - - assert interfaces.ILogFile.providedBy(loog) - if not logfileName: - logfileName = loog.getName() - assert logfileName not in self.logs - self.logs[logfileName] = loog - self._closeWhenFinished[logfileName] = closeWhenFinished - - def start(self): - log.msg("LoggedRemoteCommand.start") - if 'stdio' not in self.logs: - log.msg("LoggedRemoteCommand (%s) is running a command, but " - "it isn't being logged to anything. This seems unusual." - % self) - self.updates = {} - return RemoteCommand.start(self) - - def addStdout(self, data): - if 'stdio' in self.logs: - self.logs['stdio'].addStdout(data) - def addStderr(self, data): - if 'stdio' in self.logs: - self.logs['stdio'].addStderr(data) - def addHeader(self, data): - if 'stdio' in self.logs: - self.logs['stdio'].addHeader(data) - - def addToLog(self, logname, data): - if logname in self.logs: - self.logs[logname].addStdout(data) - else: - log.msg("%s.addToLog: no such log %s" % (self, logname)) - - def remoteUpdate(self, update): - if self.debug: - for k,v in update.items(): - log.msg("Update[%s]: %s" % (k,v)) - if update.has_key('stdout'): - # 'stdout': data - self.addStdout(update['stdout']) - if update.has_key('stderr'): - # 'stderr': data - self.addStderr(update['stderr']) - if update.has_key('header'): - # 'header': data - self.addHeader(update['header']) - if update.has_key('log'): - # 'log': (logname, data) - logname, data = update['log'] - self.addToLog(logname, data) - if update.has_key('rc'): - rc = self.rc = update['rc'] - log.msg("%s rc=%s" % (self, rc)) - self.addHeader("program finished with exit code %d\n" % rc) - - for k in update: - if k not in ('stdout', 'stderr', 'header', 'rc'): - if k not in self.updates: - self.updates[k] = [] - self.updates[k].append(update[k]) - - def remoteComplete(self, maybeFailure): - for name,loog in self.logs.items(): - if self._closeWhenFinished[name]: - if maybeFailure: - loog.addHeader("\nremoteFailed: %s" % maybeFailure) - else: - log.msg("closing log %s" % loog) - loog.finish() - return maybeFailure - - -class LogObserver: - implements(interfaces.ILogObserver) - - def setStep(self, step): - self.step = step - - def setLog(self, loog): - assert interfaces.IStatusLog.providedBy(loog) - loog.subscribe(self, True) - - def logChunk(self, build, step, log, channel, text): - if channel == interfaces.LOG_CHANNEL_STDOUT: - self.outReceived(text) - elif channel == interfaces.LOG_CHANNEL_STDERR: - self.errReceived(text) - - # TODO: add a logEnded method? er, stepFinished? - - def outReceived(self, data): - """This will be called with chunks of stdout data. Override this in - your observer.""" - pass - - def errReceived(self, data): - """This will be called with chunks of stderr data. Override this in - your observer.""" - pass - - -class LogLineObserver(LogObserver): - def __init__(self): - self.stdoutParser = basic.LineOnlyReceiver() - self.stdoutParser.delimiter = "\n" - self.stdoutParser.lineReceived = self.outLineReceived - self.stdoutParser.transport = self # for the .disconnecting attribute - self.disconnecting = False - - self.stderrParser = basic.LineOnlyReceiver() - self.stderrParser.delimiter = "\n" - self.stderrParser.lineReceived = self.errLineReceived - self.stderrParser.transport = self - - def setMaxLineLength(self, max_length): - """ - Set the maximum line length: lines longer than max_length are - dropped. Default is 16384 bytes. Use sys.maxint for effective - infinity. - """ - self.stdoutParser.MAX_LENGTH = max_length - self.stderrParser.MAX_LENGTH = max_length - - def outReceived(self, data): - self.stdoutParser.dataReceived(data) - - def errReceived(self, data): - self.stderrParser.dataReceived(data) - - def outLineReceived(self, line): - """This will be called with complete stdout lines (not including the - delimiter). Override this in your observer.""" - pass - - def errLineReceived(self, line): - """This will be called with complete lines of stderr (not including - the delimiter). Override this in your observer.""" - pass - - -class RemoteShellCommand(LoggedRemoteCommand): - """This class helps you run a shell command on the build slave. It will - accumulate all the command's output into a Log named 'stdio'. When the - command is finished, it will fire a Deferred. You can then check the - results of the command and parse the output however you like.""" - - def __init__(self, workdir, command, env=None, - want_stdout=1, want_stderr=1, - timeout=20*60, logfiles={}, **kwargs): - """ - @type workdir: string - @param workdir: directory where the command ought to run, - relative to the Builder's home directory. Defaults to - '.': the same as the Builder's homedir. This should - probably be '.' for the initial 'cvs checkout' - command (which creates a workdir), and the Build-wide - workdir for all subsequent commands (including - compiles and 'cvs update'). - - @type command: list of strings (or string) - @param command: the shell command to run, like 'make all' or - 'cvs update'. This should be a list or tuple - which can be used directly as the argv array. - For backwards compatibility, if this is a - string, the text will be given to '/bin/sh -c - %s'. - - @type env: dict of string->string - @param env: environment variables to add or change for the - slave. Each command gets a separate - environment; all inherit the slave's initial - one. TODO: make it possible to delete some or - all of the slave's environment. - - @type want_stdout: bool - @param want_stdout: defaults to True. Set to False if stdout should - be thrown away. Do this to avoid storing or - sending large amounts of useless data. - - @type want_stderr: bool - @param want_stderr: False if stderr should be thrown away - - @type timeout: int - @param timeout: tell the remote that if the command fails to - produce any output for this number of seconds, - the command is hung and should be killed. Use - None to disable the timeout. - """ - - self.command = command # stash .command, set it later - if env is not None: - # avoid mutating the original master.cfg dictionary. Each - # ShellCommand gets its own copy, any start() methods won't be - # able to modify the original. - env = env.copy() - args = {'workdir': workdir, - 'env': env, - 'want_stdout': want_stdout, - 'want_stderr': want_stderr, - 'logfiles': logfiles, - 'timeout': timeout, - } - LoggedRemoteCommand.__init__(self, "shell", args) - - def start(self): - self.args['command'] = self.command - if self.remote_command == "shell": - # non-ShellCommand slavecommands are responsible for doing this - # fixup themselves - if self.step.slaveVersion("shell", "old") == "old": - self.args['dir'] = self.args['workdir'] - what = "command '%s' in dir '%s'" % (self.args['command'], - self.args['workdir']) - log.msg(what) - return LoggedRemoteCommand.start(self) - - def __repr__(self): - return "" % self.command - -class BuildStep: - """ - I represent a single step of the build process. This step may involve - zero or more commands to be run in the build slave, as well as arbitrary - processing on the master side. Regardless of how many slave commands are - run, the BuildStep will result in a single status value. - - The step is started by calling startStep(), which returns a Deferred that - fires when the step finishes. See C{startStep} for a description of the - results provided by that Deferred. - - __init__ and start are good methods to override. Don't forget to upcall - BuildStep.__init__ or bad things will happen. - - To launch a RemoteCommand, pass it to .runCommand and wait on the - Deferred it returns. - - Each BuildStep generates status as it runs. This status data is fed to - the L{buildbot.status.builder.BuildStepStatus} listener that sits in - C{self.step_status}. It can also feed progress data (like how much text - is output by a shell command) to the - L{buildbot.status.progress.StepProgress} object that lives in - C{self.progress}, by calling C{self.setProgress(metric, value)} as it - runs. - - @type build: L{buildbot.process.base.Build} - @ivar build: the parent Build which is executing this step - - @type progress: L{buildbot.status.progress.StepProgress} - @ivar progress: tracks ETA for the step - - @type step_status: L{buildbot.status.builder.BuildStepStatus} - @ivar step_status: collects output status - """ - - # these parameters are used by the parent Build object to decide how to - # interpret our results. haltOnFailure will affect the build process - # immediately, the others will be taken into consideration when - # determining the overall build status. - # - haltOnFailure = False - flunkOnWarnings = False - flunkOnFailure = False - warnOnWarnings = False - warnOnFailure = False - - # 'parms' holds a list of all the parameters we care about, to allow - # users to instantiate a subclass of BuildStep with a mixture of - # arguments, some of which are for us, some of which are for the subclass - # (or a delegate of the subclass, like how ShellCommand delivers many - # arguments to the RemoteShellCommand that it creates). Such delegating - # subclasses will use this list to figure out which arguments are meant - # for us and which should be given to someone else. - parms = ['name', 'locks', - 'haltOnFailure', - 'flunkOnWarnings', - 'flunkOnFailure', - 'warnOnWarnings', - 'warnOnFailure', - 'progressMetrics', - ] - - name = "generic" - locks = [] - progressMetrics = () # 'time' is implicit - useProgress = True # set to False if step is really unpredictable - build = None - step_status = None - progress = None - - def __init__(self, **kwargs): - self.factory = (self.__class__, dict(kwargs)) - for p in self.__class__.parms: - if kwargs.has_key(p): - setattr(self, p, kwargs[p]) - del kwargs[p] - if kwargs: - why = "%s.__init__ got unexpected keyword argument(s) %s" \ - % (self, kwargs.keys()) - raise TypeError(why) - self._pendingLogObservers = [] - - def setBuild(self, build): - # subclasses which wish to base their behavior upon qualities of the - # Build (e.g. use the list of changed files to run unit tests only on - # code which has been modified) should do so here. The Build is not - # available during __init__, but setBuild() will be called just - # afterwards. - self.build = build - - def setBuildSlave(self, buildslave): - self.buildslave = buildslave - - def setDefaultWorkdir(self, workdir): - # the Build calls this just after __init__ and setDefaultWorkdir. - # ShellCommand and variants use a slave-side workdir, but some other - # steps do not. Subclasses which use a workdir should use the value - # set by this method unless they were constructed with something more - # specific. - pass - - def addFactoryArguments(self, **kwargs): - self.factory[1].update(kwargs) - - def getStepFactory(self): - return self.factory - - def setStepStatus(self, step_status): - self.step_status = step_status - - def setupProgress(self): - if self.useProgress: - sp = progress.StepProgress(self.name, self.progressMetrics) - self.progress = sp - self.step_status.setProgress(sp) - return sp - return None - - def setProgress(self, metric, value): - """BuildSteps can call self.setProgress() to announce progress along - some metric.""" - if self.progress: - self.progress.setProgress(metric, value) - - def getProperty(self, propname): - return self.build.getProperty(propname) - - def setProperty(self, propname, value, source="Step"): - self.build.setProperty(propname, value, source) - - def startStep(self, remote): - """Begin the step. This returns a Deferred that will fire when the - step finishes. - - This deferred fires with a tuple of (result, [extra text]), although - older steps used to return just the 'result' value, so the receiving - L{base.Build} needs to be prepared to handle that too. C{result} is - one of the SUCCESS/WARNINGS/FAILURE/SKIPPED constants from - L{buildbot.status.builder}, and the extra text is a list of short - strings which should be appended to the Build's text results. This - text allows a test-case step which fails to append B{17 tests} to the - Build's status, in addition to marking the build as failing. - - The deferred will errback if the step encounters an exception, - including an exception on the slave side (or if the slave goes away - altogether). Failures in shell commands (rc!=0) will B{not} cause an - errback, in general the BuildStep will evaluate the results and - decide whether to treat it as a WARNING or FAILURE. - - @type remote: L{twisted.spread.pb.RemoteReference} - @param remote: a reference to the slave's - L{buildbot.slave.bot.SlaveBuilder} instance where any - RemoteCommands may be run - """ - - self.remote = remote - self.deferred = defer.Deferred() - # convert all locks into their real form - self.locks = [self.build.builder.botmaster.getLockByID(l) - for l in self.locks] - # then narrow SlaveLocks down to the slave that this build is being - # run on - self.locks = [l.getLock(self.build.slavebuilder) for l in self.locks] - for l in self.locks: - if l in self.build.locks: - log.msg("Hey, lock %s is claimed by both a Step (%s) and the" - " parent Build (%s)" % (l, self, self.build)) - raise RuntimeError("lock claimed by both Step and Build") - d = self.acquireLocks() - d.addCallback(self._startStep_2) - return self.deferred - - def acquireLocks(self, res=None): - log.msg("acquireLocks(step %s, locks %s)" % (self, self.locks)) - if not self.locks: - return defer.succeed(None) - for lock in self.locks: - if not lock.isAvailable(): - log.msg("step %s waiting for lock %s" % (self, lock)) - d = lock.waitUntilMaybeAvailable(self) - d.addCallback(self.acquireLocks) - return d - # all locks are available, claim them all - for lock in self.locks: - lock.claim(self) - return defer.succeed(None) - - def _startStep_2(self, res): - if self.progress: - self.progress.start() - self.step_status.stepStarted() - try: - skip = self.start() - if skip == SKIPPED: - reactor.callLater(0, self.releaseLocks) - reactor.callLater(0, self.deferred.callback, SKIPPED) - except: - log.msg("BuildStep.startStep exception in .start") - self.failed(Failure()) - - def start(self): - """Begin the step. Override this method and add code to do local - processing, fire off remote commands, etc. - - To spawn a command in the buildslave, create a RemoteCommand instance - and run it with self.runCommand:: - - c = RemoteCommandFoo(args) - d = self.runCommand(c) - d.addCallback(self.fooDone).addErrback(self.failed) - - As the step runs, it should send status information to the - BuildStepStatus:: - - self.step_status.setColor('red') - self.step_status.setText(['compile', 'failed']) - self.step_status.setText2(['4', 'warnings']) - - To have some code parse stdio (or other log stream) in realtime, add - a LogObserver subclass. This observer can use self.step.setProgress() - to provide better progress notification to the step.:: - - self.addLogObserver('stdio', MyLogObserver()) - - To add a LogFile, use self.addLog. Make sure it gets closed when it - finishes. When giving a Logfile to a RemoteShellCommand, just ask it - to close the log when the command completes:: - - log = self.addLog('output') - cmd = RemoteShellCommand(args) - cmd.useLog(log, closeWhenFinished=True) - - You can also create complete Logfiles with generated text in a single - step:: - - self.addCompleteLog('warnings', text) - - When the step is done, it should call self.finished(result). 'result' - will be provided to the L{buildbot.process.base.Build}, and should be - one of the constants defined above: SUCCESS, WARNINGS, FAILURE, or - SKIPPED. - - If the step encounters an exception, it should call self.failed(why). - 'why' should be a Failure object. This automatically fails the whole - build with an exception. It is a good idea to add self.failed as an - errback to any Deferreds you might obtain. - - If the step decides it does not need to be run, start() can return - the constant SKIPPED. This fires the callback immediately: it is not - necessary to call .finished yourself. This can also indicate to the - status-reporting mechanism that this step should not be displayed.""" - - raise NotImplementedError("your subclass must implement this method") - - def interrupt(self, reason): - """Halt the command, either because the user has decided to cancel - the build ('reason' is a string), or because the slave has - disconnected ('reason' is a ConnectionLost Failure). Any further - local processing should be skipped, and the Step completed with an - error status. The results text should say something useful like - ['step', 'interrupted'] or ['remote', 'lost']""" - pass - - def releaseLocks(self): - log.msg("releaseLocks(%s): %s" % (self, self.locks)) - for lock in self.locks: - lock.release(self) - - def finished(self, results): - if self.progress: - self.progress.finish() - self.step_status.stepFinished(results) - self.releaseLocks() - self.deferred.callback(results) - - def failed(self, why): - # if isinstance(why, pb.CopiedFailure): # a remote exception might - # only have short traceback, so formatFailure is not as useful as - # you'd like (no .frames, so no traceback is displayed) - log.msg("BuildStep.failed, traceback follows") - log.err(why) - try: - if self.progress: - self.progress.finish() - self.addHTMLLog("err.html", formatFailure(why)) - self.addCompleteLog("err.text", why.getTraceback()) - # could use why.getDetailedTraceback() for more information - self.step_status.setColor("purple") - self.step_status.setText([self.name, "exception"]) - self.step_status.setText2([self.name]) - self.step_status.stepFinished(EXCEPTION) - except: - log.msg("exception during failure processing") - log.err() - # the progress stuff may still be whacked (the StepStatus may - # think that it is still running), but the build overall will now - # finish - try: - self.releaseLocks() - except: - log.msg("exception while releasing locks") - log.err() - - log.msg("BuildStep.failed now firing callback") - self.deferred.callback(EXCEPTION) - - # utility methods that BuildSteps may find useful - - def slaveVersion(self, command, oldversion=None): - """Return the version number of the given slave command. For the - commands defined in buildbot.slave.commands, this is the value of - 'cvs_ver' at the top of that file. Non-existent commands will return - a value of None. Buildslaves running buildbot-0.5.0 or earlier did - not respond to the version query: commands on those slaves will - return a value of OLDVERSION, so you can distinguish between old - buildslaves and missing commands. - - If you know that <=0.5.0 buildslaves have the command you want (CVS - and SVN existed back then, but none of the other VC systems), then it - makes sense to call this with oldversion='old'. If the command you - want is newer than that, just leave oldversion= unspecified, and the - command will return None for a buildslave that does not implement the - command. - """ - return self.build.getSlaveCommandVersion(command, oldversion) - - def slaveVersionIsOlderThan(self, command, minversion): - sv = self.build.getSlaveCommandVersion(command, None) - if sv is None: - return True - # the version we get back is a string form of the CVS version number - # of the slave's buildbot/slave/commands.py, something like 1.39 . - # This might change in the future (I might move away from CVS), but - # if so I'll keep updating that string with suitably-comparable - # values. - if sv.split(".") < minversion.split("."): - return True - return False - - def getSlaveName(self): - return self.build.getSlaveName() - - def addLog(self, name): - loog = self.step_status.addLog(name) - self._connectPendingLogObservers() - return loog - - def getLog(self, name): - for l in self.step_status.getLogs(): - if l.getName() == name: - return l - raise KeyError("no log named '%s'" % (name,)) - - def addCompleteLog(self, name, text): - log.msg("addCompleteLog(%s)" % name) - loog = self.step_status.addLog(name) - size = loog.chunkSize - for start in range(0, len(text), size): - loog.addStdout(text[start:start+size]) - loog.finish() - self._connectPendingLogObservers() - - def addHTMLLog(self, name, html): - log.msg("addHTMLLog(%s)" % name) - self.step_status.addHTMLLog(name, html) - self._connectPendingLogObservers() - - def addLogObserver(self, logname, observer): - assert interfaces.ILogObserver.providedBy(observer) - observer.setStep(self) - self._pendingLogObservers.append((logname, observer)) - self._connectPendingLogObservers() - - def _connectPendingLogObservers(self): - if not self._pendingLogObservers: - return - if not self.step_status: - return - current_logs = {} - for loog in self.step_status.getLogs(): - current_logs[loog.getName()] = loog - for logname, observer in self._pendingLogObservers[:]: - if logname in current_logs: - observer.setLog(current_logs[logname]) - self._pendingLogObservers.remove((logname, observer)) - - def addURL(self, name, url): - """Add a BuildStep URL to this step. - - An HREF to this URL will be added to any HTML representations of this - step. This allows a step to provide links to external web pages, - perhaps to provide detailed HTML code coverage results or other forms - of build status. - """ - self.step_status.addURL(name, url) - - def runCommand(self, c): - c.buildslave = self.buildslave - d = c.run(self, self.remote) - return d - - -class OutputProgressObserver(LogObserver): - length = 0 - - def __init__(self, name): - self.name = name - - def logChunk(self, build, step, log, channel, text): - self.length += len(text) - self.step.setProgress(self.name, self.length) - -class LoggingBuildStep(BuildStep): - """This is an abstract base class, suitable for inheritance by all - BuildSteps that invoke RemoteCommands which emit stdout/stderr messages. - """ - - progressMetrics = ('output',) - logfiles = {} - - parms = BuildStep.parms + ['logfiles'] - - def __init__(self, logfiles={}, *args, **kwargs): - BuildStep.__init__(self, *args, **kwargs) - self.addFactoryArguments(logfiles=logfiles) - # merge a class-level 'logfiles' attribute with one passed in as an - # argument - self.logfiles = self.logfiles.copy() - self.logfiles.update(logfiles) - self.addLogObserver('stdio', OutputProgressObserver("output")) - - def describe(self, done=False): - raise NotImplementedError("implement this in a subclass") - - def startCommand(self, cmd, errorMessages=[]): - """ - @param cmd: a suitable RemoteCommand which will be launched, with - all output being put into our self.stdio_log LogFile - """ - log.msg("ShellCommand.startCommand(cmd=%s)", (cmd,)) - self.cmd = cmd # so we can interrupt it - self.step_status.setColor("yellow") - self.step_status.setText(self.describe(False)) - - # stdio is the first log - self.stdio_log = stdio_log = self.addLog("stdio") - cmd.useLog(stdio_log, True) - for em in errorMessages: - stdio_log.addHeader(em) - # TODO: consider setting up self.stdio_log earlier, and have the - # code that passes in errorMessages instead call - # self.stdio_log.addHeader() directly. - - # there might be other logs - self.setupLogfiles(cmd, self.logfiles) - - d = self.runCommand(cmd) # might raise ConnectionLost - d.addCallback(lambda res: self.commandComplete(cmd)) - d.addCallback(lambda res: self.createSummary(cmd.logs['stdio'])) - d.addCallback(lambda res: self.evaluateCommand(cmd)) # returns results - def _gotResults(results): - self.setStatus(cmd, results) - return results - d.addCallback(_gotResults) # returns results - d.addCallbacks(self.finished, self.checkDisconnect) - d.addErrback(self.failed) - - def setupLogfiles(self, cmd, logfiles): - """Set up any additional logfiles= logs. - """ - for logname,remotefilename in logfiles.items(): - # tell the BuildStepStatus to add a LogFile - newlog = self.addLog(logname) - # and tell the LoggedRemoteCommand to feed it - cmd.useLog(newlog, True) - - def interrupt(self, reason): - # TODO: consider adding an INTERRUPTED or STOPPED status to use - # instead of FAILURE, might make the text a bit more clear. - # 'reason' can be a Failure, or text - self.addCompleteLog('interrupt', str(reason)) - d = self.cmd.interrupt(reason) - return d - - def checkDisconnect(self, f): - f.trap(error.ConnectionLost) - self.step_status.setColor("red") - self.step_status.setText(self.describe(True) + - ["failed", "slave", "lost"]) - self.step_status.setText2(["failed", "slave", "lost"]) - return self.finished(FAILURE) - - # to refine the status output, override one or more of the following - # methods. Change as little as possible: start with the first ones on - # this list and only proceed further if you have to - # - # createSummary: add additional Logfiles with summarized results - # evaluateCommand: decides whether the step was successful or not - # - # getText: create the final per-step text strings - # describeText2: create the strings added to the overall build status - # - # getText2: only adds describeText2() when the step affects build status - # - # setStatus: handles all status updating - - # commandComplete is available for general-purpose post-completion work. - # It is a good place to do one-time parsing of logfiles, counting - # warnings and errors. It should probably stash such counts in places - # like self.warnings so they can be picked up later by your getText - # method. - - # TODO: most of this stuff should really be on BuildStep rather than - # ShellCommand. That involves putting the status-setup stuff in - # .finished, which would make it hard to turn off. - - def commandComplete(self, cmd): - """This is a general-purpose hook method for subclasses. It will be - called after the remote command has finished, but before any of the - other hook functions are called.""" - pass - - def createSummary(self, log): - """To create summary logs, do something like this: - warnings = grep('^Warning:', log.getText()) - self.addCompleteLog('warnings', warnings) - """ - pass - - def evaluateCommand(self, cmd): - """Decide whether the command was SUCCESS, WARNINGS, or FAILURE. - Override this to, say, declare WARNINGS if there is any stderr - activity, or to say that rc!=0 is not actually an error.""" - - if cmd.rc != 0: - return FAILURE - # if cmd.log.getStderr(): return WARNINGS - return SUCCESS - - def getText(self, cmd, results): - if results == SUCCESS: - return self.describe(True) - elif results == WARNINGS: - return self.describe(True) + ["warnings"] - else: - return self.describe(True) + ["failed"] - - def getText2(self, cmd, results): - """We have decided to add a short note about ourselves to the overall - build description, probably because something went wrong. Return a - short list of short strings. If your subclass counts test failures or - warnings of some sort, this is a good place to announce the count.""" - # return ["%d warnings" % warningcount] - # return ["%d tests" % len(failedTests)] - return [self.name] - - def maybeGetText2(self, cmd, results): - if results == SUCCESS: - # successful steps do not add anything to the build's text - pass - elif results == WARNINGS: - if (self.flunkOnWarnings or self.warnOnWarnings): - # we're affecting the overall build, so tell them why - return self.getText2(cmd, results) - else: - if (self.haltOnFailure or self.flunkOnFailure - or self.warnOnFailure): - # we're affecting the overall build, so tell them why - return self.getText2(cmd, results) - return [] - - def getColor(self, cmd, results): - assert results in (SUCCESS, WARNINGS, FAILURE) - if results == SUCCESS: - return "green" - elif results == WARNINGS: - return "orange" - else: - return "red" - - def setStatus(self, cmd, results): - # this is good enough for most steps, but it can be overridden to - # get more control over the displayed text - self.step_status.setColor(self.getColor(cmd, results)) - self.step_status.setText(self.getText(cmd, results)) - self.step_status.setText2(self.maybeGetText2(cmd, results)) - -# (WithProeprties used to be available in this module) -from buildbot.process.properties import WithProperties -_hush_pyflakes = [WithProperties] -del _hush_pyflakes - diff --git a/tools/buildbot/pylibs/buildbot/process/factory.py b/tools/buildbot/pylibs/buildbot/process/factory.py deleted file mode 100644 index fb2eddc..0000000 --- a/tools/buildbot/pylibs/buildbot/process/factory.py +++ /dev/null @@ -1,180 +0,0 @@ -# -*- test-case-name: buildbot.test.test_step -*- - -from buildbot import util -from buildbot.process.base import Build -from buildbot.process.buildstep import BuildStep -from buildbot.steps.source import CVS, SVN -from buildbot.steps.shell import Configure, Compile, Test, PerlModuleTest - -# deprecated, use BuildFactory.addStep -def s(steptype, **kwargs): - # convenience function for master.cfg files, to create step - # specification tuples - return (steptype, kwargs) - -class BuildFactory(util.ComparableMixin): - """ - @cvar buildClass: class to use when creating builds - @type buildClass: L{buildbot.process.base.Build} - """ - buildClass = Build - useProgress = 1 - compare_attrs = ['buildClass', 'steps', 'useProgress'] - - def __init__(self, steps=None): - if steps is None: - steps = [] - self.steps = [self._makeStepFactory(s) for s in steps] - - def _makeStepFactory(self, step_or_factory): - if isinstance(step_or_factory, BuildStep): - return step_or_factory.getStepFactory() - return step_or_factory - - def newBuild(self, request): - """Create a new Build instance. - @param request: a L{base.BuildRequest} describing what is to be built - """ - b = self.buildClass(request) - b.useProgress = self.useProgress - b.setStepFactories(self.steps) - return b - - def addStep(self, step_or_factory, **kwargs): - if isinstance(step_or_factory, BuildStep): - s = step_or_factory.getStepFactory() - else: - s = (step_or_factory, dict(kwargs)) - self.steps.append(s) - - -# BuildFactory subclasses for common build tools - -class GNUAutoconf(BuildFactory): - def __init__(self, source, configure="./configure", - configureEnv={}, - configureFlags=[], - compile=["make", "all"], - test=["make", "check"]): - BuildFactory.__init__(self, [source]) - if configure is not None: - # we either need to wind up with a string (which will be - # space-split), or with a list of strings (which will not). The - # list of strings is the preferred form. - if type(configure) is str: - if configureFlags: - assert not " " in configure # please use list instead - command = [configure] + configureFlags - else: - command = configure - else: - assert isinstance(configure, (list, tuple)) - command = configure + configureFlags - self.addStep(Configure, command=command, env=configureEnv) - if compile is not None: - self.addStep(Compile, command=compile) - if test is not None: - self.addStep(Test, command=test) - -class CPAN(BuildFactory): - def __init__(self, source, perl="perl"): - BuildFactory.__init__(self, [source]) - self.addStep(Configure, command=[perl, "Makefile.PL"]) - self.addStep(Compile, command=["make"]) - self.addStep(PerlModuleTest, command=["make", "test"]) - -class Distutils(BuildFactory): - def __init__(self, source, python="python", test=None): - BuildFactory.__init__(self, [source]) - self.addStep(Compile, command=[python, "./setup.py", "build"]) - if test is not None: - self.addStep(Test, command=test) - -class Trial(BuildFactory): - """Build a python module that uses distutils and trial. Set 'tests' to - the module in which the tests can be found, or set useTestCaseNames=True - to always have trial figure out which tests to run (based upon which - files have been changed). - - See docs/factories.xhtml for usage samples. Not all of the Trial - BuildStep options are available here, only the most commonly used ones. - To get complete access, you will need to create a custom - BuildFactory.""" - - trial = "trial" - randomly = False - recurse = False - - def __init__(self, source, - buildpython=["python"], trialpython=[], trial=None, - testpath=".", randomly=None, recurse=None, - tests=None, useTestCaseNames=False, env=None): - BuildFactory.__init__(self, [source]) - assert tests or useTestCaseNames, "must use one or the other" - if trial is not None: - self.trial = trial - if randomly is not None: - self.randomly = randomly - if recurse is not None: - self.recurse = recurse - - from buildbot.steps.python_twisted import Trial - buildcommand = buildpython + ["./setup.py", "build"] - self.addStep(Compile, command=buildcommand, env=env) - self.addStep(Trial, - python=trialpython, trial=self.trial, - testpath=testpath, - tests=tests, testChanges=useTestCaseNames, - randomly=self.randomly, - recurse=self.recurse, - env=env, - ) - - -# compatibility classes, will go away. Note that these only offer -# compatibility at the constructor level: if you have subclassed these -# factories, your subclasses are unlikely to still work correctly. - -ConfigurableBuildFactory = BuildFactory - -class BasicBuildFactory(GNUAutoconf): - # really a "GNU Autoconf-created tarball -in-CVS tree" builder - - def __init__(self, cvsroot, cvsmodule, - configure=None, configureEnv={}, - compile="make all", - test="make check", cvsCopy=False): - mode = "clobber" - if cvsCopy: - mode = "copy" - source = s(CVS, cvsroot=cvsroot, cvsmodule=cvsmodule, mode=mode) - GNUAutoconf.__init__(self, source, - configure=configure, configureEnv=configureEnv, - compile=compile, - test=test) - -class QuickBuildFactory(BasicBuildFactory): - useProgress = False - - def __init__(self, cvsroot, cvsmodule, - configure=None, configureEnv={}, - compile="make all", - test="make check", cvsCopy=False): - mode = "update" - source = s(CVS, cvsroot=cvsroot, cvsmodule=cvsmodule, mode=mode) - GNUAutoconf.__init__(self, source, - configure=configure, configureEnv=configureEnv, - compile=compile, - test=test) - -class BasicSVN(GNUAutoconf): - - def __init__(self, svnurl, - configure=None, configureEnv={}, - compile="make all", - test="make check"): - source = s(SVN, svnurl=svnurl, mode="update") - GNUAutoconf.__init__(self, source, - configure=configure, configureEnv=configureEnv, - compile=compile, - test=test) diff --git a/tools/buildbot/pylibs/buildbot/process/process_twisted.py b/tools/buildbot/pylibs/buildbot/process/process_twisted.py deleted file mode 100644 index 36d6fc5..0000000 --- a/tools/buildbot/pylibs/buildbot/process/process_twisted.py +++ /dev/null @@ -1,118 +0,0 @@ - -# Build classes specific to the Twisted codebase - -from buildbot.process.base import Build -from buildbot.process.factory import BuildFactory -from buildbot.steps import shell -from buildbot.steps.python_twisted import HLint, ProcessDocs, BuildDebs, \ - Trial, RemovePYCs - -class TwistedBuild(Build): - workdir = "Twisted" # twisted's bin/trial expects to live in here - def isFileImportant(self, filename): - if filename.startswith("doc/fun/"): - return 0 - if filename.startswith("sandbox/"): - return 0 - return 1 - -class TwistedTrial(Trial): - tests = "twisted" - # the Trial in Twisted >=2.1.0 has --recurse on by default, and -to - # turned into --reporter=bwverbose . - recurse = False - trialMode = ["--reporter=bwverbose"] - testpath = None - trial = "./bin/trial" - -class TwistedBaseFactory(BuildFactory): - buildClass = TwistedBuild - # bin/trial expects its parent directory to be named "Twisted": it uses - # this to add the local tree to PYTHONPATH during tests - workdir = "Twisted" - - def __init__(self, source): - BuildFactory.__init__(self, [source]) - -class QuickTwistedBuildFactory(TwistedBaseFactory): - treeStableTimer = 30 - useProgress = 0 - - def __init__(self, source, python="python"): - TwistedBaseFactory.__init__(self, source) - if type(python) is str: - python = [python] - self.addStep(HLint, python=python[0]) - self.addStep(RemovePYCs) - for p in python: - cmd = [p, "setup.py", "build_ext", "-i"] - self.addStep(shell.Compile, command=cmd, flunkOnFailure=True) - self.addStep(TwistedTrial, python=p, testChanges=True) - -class FullTwistedBuildFactory(TwistedBaseFactory): - treeStableTimer = 5*60 - - def __init__(self, source, python="python", - processDocs=False, runTestsRandomly=False, - compileOpts=[], compileOpts2=[]): - TwistedBaseFactory.__init__(self, source) - if processDocs: - self.addStep(ProcessDocs) - - if type(python) == str: - python = [python] - assert isinstance(compileOpts, list) - assert isinstance(compileOpts2, list) - cmd = (python + compileOpts + ["setup.py", "build_ext"] - + compileOpts2 + ["-i"]) - - self.addStep(shell.Compile, command=cmd, flunkOnFailure=True) - self.addStep(RemovePYCs) - self.addStep(TwistedTrial, python=python, randomly=runTestsRandomly) - -class TwistedDebsBuildFactory(TwistedBaseFactory): - treeStableTimer = 10*60 - - def __init__(self, source, python="python"): - TwistedBaseFactory.__init__(self, source) - self.addStep(ProcessDocs, haltOnFailure=True) - self.addStep(BuildDebs, warnOnWarnings=True) - -class TwistedReactorsBuildFactory(TwistedBaseFactory): - treeStableTimer = 5*60 - - def __init__(self, source, - python="python", compileOpts=[], compileOpts2=[], - reactors=None): - TwistedBaseFactory.__init__(self, source) - - if type(python) == str: - python = [python] - assert isinstance(compileOpts, list) - assert isinstance(compileOpts2, list) - cmd = (python + compileOpts + ["setup.py", "build_ext"] - + compileOpts2 + ["-i"]) - - self.addStep(shell.Compile, command=cmd, warnOnFailure=True) - - if reactors == None: - reactors = [ - 'gtk2', - 'gtk', - #'kqueue', - 'poll', - 'c', - 'qt', - #'win32', - ] - for reactor in reactors: - flunkOnFailure = 1 - warnOnFailure = 0 - #if reactor in ['c', 'qt', 'win32']: - # # these are buggy, so tolerate failures for now - # flunkOnFailure = 0 - # warnOnFailure = 1 - self.addStep(RemovePYCs) # TODO: why? - self.addStep(TwistedTrial, name=reactor, python=python, - reactor=reactor, flunkOnFailure=flunkOnFailure, - warnOnFailure=warnOnFailure) diff --git a/tools/buildbot/pylibs/buildbot/process/properties.py b/tools/buildbot/pylibs/buildbot/process/properties.py deleted file mode 100644 index 60e8646..0000000 --- a/tools/buildbot/pylibs/buildbot/process/properties.py +++ /dev/null @@ -1,157 +0,0 @@ -import re -import weakref -from buildbot import util - -class Properties(util.ComparableMixin): - """ - I represent a set of properties that can be interpolated into various - strings in buildsteps. - - @ivar properties: dictionary mapping property values to tuples - (value, source), where source is a string identifing the source - of the property. - - Objects of this class can be read like a dictionary -- in this case, - only the property value is returned. - - As a special case, a property value of None is returned as an empty - string when used as a mapping. - """ - - compare_attrs = ('properties') - - def __init__(self, **kwargs): - """ - @param kwargs: initial property values (for testing) - """ - self.properties = {} - self.pmap = PropertyMap(self) - if kwargs: self.update(kwargs, "TEST") - - def __getstate__(self): - d = self.__dict__.copy() - del d['pmap'] - return d - - def __setstate__(self, d): - self.__dict__ = d - self.pmap = PropertyMap(self) - - def __getitem__(self, name): - """Just get the value for this property.""" - rv = self.properties[name][0] - return rv - - def has_key(self, name): - return self.properties.has_key(name) - - def getProperty(self, name, default=None): - """Get the value for the given property.""" - return self.properties.get(name, (default,))[0] - - def getPropertySource(self, name): - return self.properties[name][1] - - def asList(self): - """Return the properties as a sorted list of (name, value, source)""" - l = [ (k, v[0], v[1]) for k,v in self.properties.items() ] - l.sort() - return l - - def __repr__(self): - return repr(dict([ (k,v[0]) for k,v in self.properties.iteritems() ])) - - def setProperty(self, name, value, source): - self.properties[name] = (value, source) - - def update(self, dict, source): - """Update this object from a dictionary, with an explicit source specified.""" - for k, v in dict.items(): - self.properties[k] = (v, source) - - def updateFromProperties(self, other): - """Update this object based on another object; the other object's """ - self.properties.update(other.properties) - - def render(self, value): - """ - Return a variant of value that has any WithProperties objects - substituted. This recurses into Python's compound data types. - """ - # we use isinstance to detect Python's standard data types, and call - # this function recursively for the values in those types - if isinstance(value, (str, unicode)): - return value - elif isinstance(value, WithProperties): - return value.render(self.pmap) - elif isinstance(value, list): - return [ self.render(e) for e in value ] - elif isinstance(value, tuple): - return tuple([ self.render(e) for e in value ]) - elif isinstance(value, dict): - return dict([ (self.render(k), self.render(v)) for k,v in value.iteritems() ]) - else: - return value - -class PropertyMap: - """ - Privately-used mapping object to implement WithProperties' substitutions, - including the rendering of None as ''. - """ - colon_minus_re = re.compile(r"(.*):-(.*)") - colon_plus_re = re.compile(r"(.*):\+(.*)") - def __init__(self, properties): - # use weakref here to avoid a reference loop - self.properties = weakref.ref(properties) - - def __getitem__(self, key): - properties = self.properties() - assert properties is not None - - # %(prop:-repl)s - # if prop exists, use it; otherwise, use repl - mo = self.colon_minus_re.match(key) - if mo: - prop, repl = mo.group(1,2) - if properties.has_key(prop): - rv = properties[prop] - else: - rv = repl - else: - # %(prop:+repl)s - # if prop exists, use repl; otherwise, an empty string - mo = self.colon_plus_re.match(key) - if mo: - prop, repl = mo.group(1,2) - if properties.has_key(prop): - rv = repl - else: - rv = '' - else: - rv = properties[key] - - # translate 'None' to an empty string - if rv is None: rv = '' - return rv - -class WithProperties(util.ComparableMixin): - """ - This is a marker class, used fairly widely to indicate that we - want to interpolate build properties. - """ - - compare_attrs = ('fmtstring', 'args') - - def __init__(self, fmtstring, *args): - self.fmtstring = fmtstring - self.args = args - - def render(self, pmap): - if self.args: - strings = [] - for name in self.args: - strings.append(pmap[name]) - s = self.fmtstring % tuple(strings) - else: - s = self.fmtstring % pmap - return s diff --git a/tools/buildbot/pylibs/buildbot/process/step_twisted2.py b/tools/buildbot/pylibs/buildbot/process/step_twisted2.py deleted file mode 100644 index 450215c..0000000 --- a/tools/buildbot/pylibs/buildbot/process/step_twisted2.py +++ /dev/null @@ -1,161 +0,0 @@ - -from buildbot.status import tests -from buildbot.process.step import SUCCESS, FAILURE, BuildStep -from buildbot.process.step_twisted import RunUnitTests - -from zope.interface import implements -from twisted.python import log, failure -from twisted.spread import jelly -from twisted.pb.tokens import BananaError -from twisted.web.html import PRE -from twisted.web.error import NoResource - -class Null: pass -ResultTypes = Null() -ResultTypeNames = ["SKIP", - "EXPECTED_FAILURE", "FAILURE", "ERROR", - "UNEXPECTED_SUCCESS", "SUCCESS"] -try: - from twisted.trial import reporter # introduced in Twisted-1.0.5 - # extract the individual result types - for name in ResultTypeNames: - setattr(ResultTypes, name, getattr(reporter, name)) -except ImportError: - from twisted.trial import unittest # Twisted-1.0.4 has them here - for name in ResultTypeNames: - setattr(ResultTypes, name, getattr(unittest, name)) - -log._keepErrors = 0 -from twisted.trial import remote # for trial/jelly parsing - -import StringIO - -class OneJellyTest(tests.OneTest): - def html(self, request): - tpl = "\n\n%s\n\n\n" - pptpl = "\n\n
%s
\n\n\n" - t = request.postpath[0] # one of 'short', 'long' #, or 'html' - if isinstance(self.results, failure.Failure): - # it would be nice to remove unittest functions from the - # traceback like unittest.format_exception() does. - if t == 'short': - s = StringIO.StringIO() - self.results.printTraceback(s) - return pptpl % PRE(s.getvalue()) - elif t == 'long': - s = StringIO.StringIO() - self.results.printDetailedTraceback(s) - return pptpl % PRE(s.getvalue()) - #elif t == 'html': - # return tpl % formatFailure(self.results) - # ACK! source lines aren't stored in the Failure, rather, - # formatFailure pulls them (by filename) from the local - # disk. Feh. Even printTraceback() won't work. Double feh. - return NoResource("No such mode '%s'" % t) - if self.results == None: - return tpl % "No results to show: test probably passed." - # maybe results are plain text? - return pptpl % PRE(self.results) - -class TwistedJellyTestResults(tests.TestResults): - oneTestClass = OneJellyTest - def describeOneTest(self, testname): - return "%s: %s\n" % (testname, self.tests[testname][0]) - -class RunUnitTestsJelly(RunUnitTests): - """I run the unit tests with the --jelly option, which generates - machine-parseable results as the tests are run. - """ - trialMode = "--jelly" - implements(remote.IRemoteReporter) - - ourtypes = { ResultTypes.SKIP: tests.SKIP, - ResultTypes.EXPECTED_FAILURE: tests.EXPECTED_FAILURE, - ResultTypes.FAILURE: tests.FAILURE, - ResultTypes.ERROR: tests.ERROR, - ResultTypes.UNEXPECTED_SUCCESS: tests.UNEXPECTED_SUCCESS, - ResultTypes.SUCCESS: tests.SUCCESS, - } - - def __getstate__(self): - #d = RunUnitTests.__getstate__(self) - d = self.__dict__.copy() - # Banana subclasses are Ephemeral - if d.has_key("decoder"): - del d['decoder'] - return d - def start(self): - self.decoder = remote.DecodeReport(self) - # don't accept anything unpleasant from the (untrusted) build slave - # The jellied stream may have Failures, but everything inside should - # be a string - security = jelly.SecurityOptions() - security.allowBasicTypes() - security.allowInstancesOf(failure.Failure) - self.decoder.taster = security - self.results = TwistedJellyTestResults() - RunUnitTests.start(self) - - def logProgress(self, progress): - # XXX: track number of tests - BuildStep.logProgress(self, progress) - - def addStdout(self, data): - if not self.decoder: - return - try: - self.decoder.dataReceived(data) - except BananaError: - self.decoder = None - log.msg("trial --jelly output unparseable, traceback follows") - log.deferr() - - def remote_start(self, expectedTests, times=None): - print "remote_start", expectedTests - def remote_reportImportError(self, name, aFailure, times=None): - pass - def remote_reportStart(self, testClass, method, times=None): - print "reportStart", testClass, method - - def remote_reportResults(self, testClass, method, resultType, results, - times=None): - print "reportResults", testClass, method, resultType - which = testClass + "." + method - self.results.addTest(which, - self.ourtypes.get(resultType, tests.UNKNOWN), - results) - - def finished(self, rc): - # give self.results to our Build object - self.build.testsFinished(self.results) - total = self.results.countTests() - count = self.results.countFailures() - result = SUCCESS - if total == None: - result = (FAILURE, ['tests%s' % self.rtext(' (%s)')]) - if count: - result = (FAILURE, ["%d tes%s%s" % (count, - (count == 1 and 't' or 'ts'), - self.rtext(' (%s)'))]) - return self.stepComplete(result) - def finishStatus(self, result): - total = self.results.countTests() - count = self.results.countFailures() - color = "green" - text = [] - if count == 0: - text.extend(["%d %s" % \ - (total, - total == 1 and "test" or "tests"), - "passed"]) - else: - text.append("tests") - text.append("%d %s" % \ - (count, - count == 1 and "failure" or "failures")) - color = "red" - self.updateCurrentActivity(color=color, text=text) - self.addFileToCurrentActivity("tests", self.results) - #self.finishStatusSummary() - self.finishCurrentActivity() - diff --git a/tools/buildbot/pylibs/buildbot/scheduler.py b/tools/buildbot/pylibs/buildbot/scheduler.py deleted file mode 100644 index b556512..0000000 --- a/tools/buildbot/pylibs/buildbot/scheduler.py +++ /dev/null @@ -1,748 +0,0 @@ -# -*- test-case-name: buildbot.test.test_dependencies -*- - -import time, os.path - -from zope.interface import implements -from twisted.internet import reactor -from twisted.application import service, internet, strports -from twisted.python import log, runtime -from twisted.protocols import basic -from twisted.cred import portal, checkers -from twisted.spread import pb - -from buildbot import interfaces, buildset, util, pbutil -from buildbot.status import builder -from buildbot.sourcestamp import SourceStamp -from buildbot.changes.maildir import MaildirService -from buildbot.process.properties import Properties - - -class BaseScheduler(service.MultiService, util.ComparableMixin): - """ - A Schduler creates BuildSets and submits them to the BuildMaster. - - @ivar name: name of the scheduler - - @ivar properties: additional properties specified in this - scheduler's configuration - @type properties: Properties object - """ - implements(interfaces.IScheduler) - - def __init__(self, name, properties={}): - """ - @param name: name for this scheduler - - @param properties: properties to be propagated from this scheduler - @type properties: dict - """ - service.MultiService.__init__(self) - self.name = name - self.properties = Properties() - self.properties.update(properties, "Scheduler") - self.properties.setProperty("scheduler", name, "Scheduler") - - def __repr__(self): - # TODO: why can't id() return a positive number? %d is ugly. - return "" % (self.name, id(self)) - - def submitBuildSet(self, bs): - self.parent.submitBuildSet(bs) - - def addChange(self, change): - pass - -class BaseUpstreamScheduler(BaseScheduler): - implements(interfaces.IUpstreamScheduler) - - def __init__(self, name, properties={}): - BaseScheduler.__init__(self, name, properties) - self.successWatchers = [] - - def subscribeToSuccessfulBuilds(self, watcher): - self.successWatchers.append(watcher) - def unsubscribeToSuccessfulBuilds(self, watcher): - self.successWatchers.remove(watcher) - - def submitBuildSet(self, bs): - d = bs.waitUntilFinished() - d.addCallback(self.buildSetFinished) - BaseScheduler.submitBuildSet(self, bs) - - def buildSetFinished(self, bss): - if not self.running: - return - if bss.getResults() == builder.SUCCESS: - ss = bss.getSourceStamp() - for w in self.successWatchers: - w(ss) - - -class Scheduler(BaseUpstreamScheduler): - """The default Scheduler class will run a build after some period of time - called the C{treeStableTimer}, on a given set of Builders. It only pays - attention to a single branch. You you can provide a C{fileIsImportant} - function which will evaluate each Change to decide whether or not it - should trigger a new build. - """ - - fileIsImportant = None - compare_attrs = ('name', 'treeStableTimer', 'builderNames', 'branch', - 'fileIsImportant', 'properties') - - def __init__(self, name, branch, treeStableTimer, builderNames, - fileIsImportant=None, properties={}): - """ - @param name: the name of this Scheduler - @param branch: The branch name that the Scheduler should pay - attention to. Any Change that is not on this branch - will be ignored. It can be set to None to only pay - attention to the default branch. - @param treeStableTimer: the duration, in seconds, for which the tree - must remain unchanged before a build will be - triggered. This is intended to avoid builds - of partially-committed fixes. - @param builderNames: a list of Builder names. When this Scheduler - decides to start a set of builds, they will be - run on the Builders named by this list. - - @param fileIsImportant: A callable which takes one argument (a Change - instance) and returns True if the change is - worth building, and False if it is not. - Unimportant Changes are accumulated until the - build is triggered by an important change. - The default value of None means that all - Changes are important. - - @param properties: properties to apply to all builds started from this - scheduler - """ - - BaseUpstreamScheduler.__init__(self, name, properties) - self.treeStableTimer = treeStableTimer - errmsg = ("The builderNames= argument to Scheduler must be a list " - "of Builder description names (i.e. the 'name' key of the " - "Builder specification dictionary)") - assert isinstance(builderNames, (list, tuple)), errmsg - for b in builderNames: - assert isinstance(b, str), errmsg - self.builderNames = builderNames - self.branch = branch - if fileIsImportant: - assert callable(fileIsImportant) - self.fileIsImportant = fileIsImportant - - self.importantChanges = [] - self.unimportantChanges = [] - self.nextBuildTime = None - self.timer = None - - def listBuilderNames(self): - return self.builderNames - - def getPendingBuildTimes(self): - if self.nextBuildTime is not None: - return [self.nextBuildTime] - return [] - - def addChange(self, change): - if change.branch != self.branch: - log.msg("%s ignoring off-branch %s" % (self, change)) - return - if not self.fileIsImportant: - self.addImportantChange(change) - elif self.fileIsImportant(change): - self.addImportantChange(change) - else: - self.addUnimportantChange(change) - - def addImportantChange(self, change): - log.msg("%s: change is important, adding %s" % (self, change)) - self.importantChanges.append(change) - self.nextBuildTime = max(self.nextBuildTime, - change.when + self.treeStableTimer) - self.setTimer(self.nextBuildTime) - - def addUnimportantChange(self, change): - log.msg("%s: change is not important, adding %s" % (self, change)) - self.unimportantChanges.append(change) - - def setTimer(self, when): - log.msg("%s: setting timer to %s" % - (self, time.strftime("%H:%M:%S", time.localtime(when)))) - now = util.now() - if when < now: - when = now + 1 - if self.timer: - self.timer.cancel() - self.timer = reactor.callLater(when - now, self.fireTimer) - - def stopTimer(self): - if self.timer: - self.timer.cancel() - self.timer = None - - def fireTimer(self): - # clear out our state - self.timer = None - self.nextBuildTime = None - changes = self.importantChanges + self.unimportantChanges - self.importantChanges = [] - self.unimportantChanges = [] - - # create a BuildSet, submit it to the BuildMaster - bs = buildset.BuildSet(self.builderNames, - SourceStamp(changes=changes), - properties=self.properties) - self.submitBuildSet(bs) - - def stopService(self): - self.stopTimer() - return service.MultiService.stopService(self) - - -class AnyBranchScheduler(BaseUpstreamScheduler): - """This Scheduler will handle changes on a variety of branches. It will - accumulate Changes for each branch separately. It works by creating a - separate Scheduler for each new branch it sees.""" - - schedulerFactory = Scheduler - fileIsImportant = None - - compare_attrs = ('name', 'branches', 'treeStableTimer', 'builderNames', - 'fileIsImportant', 'properties') - - def __init__(self, name, branches, treeStableTimer, builderNames, - fileIsImportant=None, properties={}): - """ - @param name: the name of this Scheduler - @param branches: The branch names that the Scheduler should pay - attention to. Any Change that is not on one of these - branches will be ignored. It can be set to None to - accept changes from any branch. Don't use [] (an - empty list), because that means we don't pay - attention to *any* branches, so we'll never build - anything. - @param treeStableTimer: the duration, in seconds, for which the tree - must remain unchanged before a build will be - triggered. This is intended to avoid builds - of partially-committed fixes. - @param builderNames: a list of Builder names. When this Scheduler - decides to start a set of builds, they will be - run on the Builders named by this list. - - @param fileIsImportant: A callable which takes one argument (a Change - instance) and returns True if the change is - worth building, and False if it is not. - Unimportant Changes are accumulated until the - build is triggered by an important change. - The default value of None means that all - Changes are important. - - @param properties: properties to apply to all builds started from this - scheduler - """ - - BaseUpstreamScheduler.__init__(self, name, properties) - self.treeStableTimer = treeStableTimer - for b in builderNames: - assert isinstance(b, str) - self.builderNames = builderNames - self.branches = branches - if self.branches == []: - log.msg("AnyBranchScheduler %s: branches=[], so we will ignore " - "all branches, and never trigger any builds. Please set " - "branches=None to mean 'all branches'" % self) - # consider raising an exception here, to make this warning more - # prominent, but I can vaguely imagine situations where you might - # want to comment out branches temporarily and wouldn't - # appreciate it being treated as an error. - if fileIsImportant: - assert callable(fileIsImportant) - self.fileIsImportant = fileIsImportant - self.schedulers = {} # one per branch - - def __repr__(self): - return "" % self.name - - def listBuilderNames(self): - return self.builderNames - - def getPendingBuildTimes(self): - bts = [] - for s in self.schedulers.values(): - if s.nextBuildTime is not None: - bts.append(s.nextBuildTime) - return bts - - def addChange(self, change): - branch = change.branch - if self.branches is not None and branch not in self.branches: - log.msg("%s ignoring off-branch %s" % (self, change)) - return - s = self.schedulers.get(branch) - if not s: - if branch: - name = self.name + "." + branch - else: - name = self.name + "." - s = self.schedulerFactory(name, branch, - self.treeStableTimer, - self.builderNames, - self.fileIsImportant) - s.successWatchers = self.successWatchers - s.setServiceParent(self) - # TODO: does this result in schedulers that stack up forever? - # When I make the persistify-pass, think about this some more. - self.schedulers[branch] = s - s.addChange(change) - - -class Dependent(BaseUpstreamScheduler): - """This scheduler runs some set of 'downstream' builds when the - 'upstream' scheduler has completed successfully.""" - - compare_attrs = ('name', 'upstream', 'builders', 'properties') - - def __init__(self, name, upstream, builderNames, properties={}): - assert interfaces.IUpstreamScheduler.providedBy(upstream) - BaseUpstreamScheduler.__init__(self, name, properties) - self.upstream = upstream - self.builderNames = builderNames - - def listBuilderNames(self): - return self.builderNames - - def getPendingBuildTimes(self): - # report the upstream's value - return self.upstream.getPendingBuildTimes() - - def startService(self): - service.MultiService.startService(self) - self.upstream.subscribeToSuccessfulBuilds(self.upstreamBuilt) - - def stopService(self): - d = service.MultiService.stopService(self) - self.upstream.unsubscribeToSuccessfulBuilds(self.upstreamBuilt) - return d - - def upstreamBuilt(self, ss): - bs = buildset.BuildSet(self.builderNames, ss, - properties=self.properties) - self.submitBuildSet(bs) - - - -class Periodic(BaseUpstreamScheduler): - """Instead of watching for Changes, this Scheduler can just start a build - at fixed intervals. The C{periodicBuildTimer} parameter sets the number - of seconds to wait between such periodic builds. The first build will be - run immediately.""" - - # TODO: consider having this watch another (changed-based) scheduler and - # merely enforce a minimum time between builds. - - compare_attrs = ('name', 'builderNames', 'periodicBuildTimer', 'branch', 'properties') - - def __init__(self, name, builderNames, periodicBuildTimer, - branch=None, properties={}): - BaseUpstreamScheduler.__init__(self, name, properties) - self.builderNames = builderNames - self.periodicBuildTimer = periodicBuildTimer - self.branch = branch - self.reason = ("The Periodic scheduler named '%s' triggered this build" - % name) - self.timer = internet.TimerService(self.periodicBuildTimer, - self.doPeriodicBuild) - self.timer.setServiceParent(self) - - def listBuilderNames(self): - return self.builderNames - - def getPendingBuildTimes(self): - # TODO: figure out when self.timer is going to fire next and report - # that - return [] - - def doPeriodicBuild(self): - bs = buildset.BuildSet(self.builderNames, - SourceStamp(branch=self.branch), - self.reason, - properties=self.properties) - self.submitBuildSet(bs) - - - -class Nightly(BaseUpstreamScheduler): - """Imitate 'cron' scheduling. This can be used to schedule a nightly - build, or one which runs are certain times of the day, week, or month. - - Pass some subset of minute, hour, dayOfMonth, month, and dayOfWeek; each - may be a single number or a list of valid values. The builds will be - triggered whenever the current time matches these values. Wildcards are - represented by a '*' string. All fields default to a wildcard except - 'minute', so with no fields this defaults to a build every hour, on the - hour. - - For example, the following master.cfg clause will cause a build to be - started every night at 3:00am:: - - s = Nightly('nightly', ['builder1', 'builder2'], hour=3, minute=0) - c['schedules'].append(s) - - This scheduler will perform a build each monday morning at 6:23am and - again at 8:23am:: - - s = Nightly('BeforeWork', ['builder1'], - dayOfWeek=0, hour=[6,8], minute=23) - - The following runs a build every two hours:: - - s = Nightly('every2hours', ['builder1'], hour=range(0, 24, 2)) - - And this one will run only on December 24th:: - - s = Nightly('SleighPreflightCheck', ['flying_circuits', 'radar'], - month=12, dayOfMonth=24, hour=12, minute=0) - - For dayOfWeek and dayOfMonth, builds are triggered if the date matches - either of them. All time values are compared against the tuple returned - by time.localtime(), so month and dayOfMonth numbers start at 1, not - zero. dayOfWeek=0 is Monday, dayOfWeek=6 is Sunday. - """ - - compare_attrs = ('name', 'builderNames', - 'minute', 'hour', 'dayOfMonth', 'month', - 'dayOfWeek', 'branch', 'properties') - - def __init__(self, name, builderNames, minute=0, hour='*', - dayOfMonth='*', month='*', dayOfWeek='*', - branch=None, properties={}): - # Setting minute=0 really makes this an 'Hourly' scheduler. This - # seemed like a better default than minute='*', which would result in - # a build every 60 seconds. - BaseUpstreamScheduler.__init__(self, name, properties) - self.builderNames = builderNames - self.minute = minute - self.hour = hour - self.dayOfMonth = dayOfMonth - self.month = month - self.dayOfWeek = dayOfWeek - self.branch = branch - self.delayedRun = None - self.nextRunTime = None - self.reason = ("The Nightly scheduler named '%s' triggered this build" - % name) - - def addTime(self, timetuple, secs): - return time.localtime(time.mktime(timetuple)+secs) - def findFirstValueAtLeast(self, values, value, default=None): - for v in values: - if v >= value: return v - return default - - def setTimer(self): - self.nextRunTime = self.calculateNextRunTime() - self.delayedRun = reactor.callLater(self.nextRunTime - time.time(), - self.doPeriodicBuild) - - def startService(self): - BaseUpstreamScheduler.startService(self) - self.setTimer() - - def stopService(self): - BaseUpstreamScheduler.stopService(self) - self.delayedRun.cancel() - - def isRunTime(self, timetuple): - def check(ourvalue, value): - if ourvalue == '*': return True - if isinstance(ourvalue, int): return value == ourvalue - return (value in ourvalue) - - if not check(self.minute, timetuple[4]): - #print 'bad minute', timetuple[4], self.minute - return False - - if not check(self.hour, timetuple[3]): - #print 'bad hour', timetuple[3], self.hour - return False - - if not check(self.month, timetuple[1]): - #print 'bad month', timetuple[1], self.month - return False - - if self.dayOfMonth != '*' and self.dayOfWeek != '*': - # They specified both day(s) of month AND day(s) of week. - # This means that we only have to match one of the two. If - # neither one matches, this time is not the right time. - if not (check(self.dayOfMonth, timetuple[2]) or - check(self.dayOfWeek, timetuple[6])): - #print 'bad day' - return False - else: - if not check(self.dayOfMonth, timetuple[2]): - #print 'bad day of month' - return False - - if not check(self.dayOfWeek, timetuple[6]): - #print 'bad day of week' - return False - - return True - - def calculateNextRunTime(self): - return self.calculateNextRunTimeFrom(time.time()) - - def calculateNextRunTimeFrom(self, now): - dateTime = time.localtime(now) - - # Remove seconds by advancing to at least the next minue - dateTime = self.addTime(dateTime, 60-dateTime[5]) - - # Now we just keep adding minutes until we find something that matches - - # It not an efficient algorithm, but it'll *work* for now - yearLimit = dateTime[0]+2 - while not self.isRunTime(dateTime): - dateTime = self.addTime(dateTime, 60) - #print 'Trying', time.asctime(dateTime) - assert dateTime[0] < yearLimit, 'Something is wrong with this code' - return time.mktime(dateTime) - - def listBuilderNames(self): - return self.builderNames - - def getPendingBuildTimes(self): - # TODO: figure out when self.timer is going to fire next and report - # that - if self.nextRunTime is None: return [] - return [self.nextRunTime] - - def doPeriodicBuild(self): - # Schedule the next run - self.setTimer() - - # And trigger a build - bs = buildset.BuildSet(self.builderNames, - SourceStamp(branch=self.branch), - self.reason, - properties=self.properties) - self.submitBuildSet(bs) - - def addChange(self, change): - pass - - - -class TryBase(BaseScheduler): - def __init__(self, name, builderNames, properties={}): - BaseScheduler.__init__(self, name, properties) - self.builderNames = builderNames - - def listBuilderNames(self): - return self.builderNames - - def getPendingBuildTimes(self): - # we can't predict what the developers are going to do in the future - return [] - - def addChange(self, change): - # Try schedulers ignore Changes - pass - - -class BadJobfile(Exception): - pass - -class JobFileScanner(basic.NetstringReceiver): - def __init__(self): - self.strings = [] - self.transport = self # so transport.loseConnection works - self.error = False - - def stringReceived(self, s): - self.strings.append(s) - - def loseConnection(self): - self.error = True - -class Try_Jobdir(TryBase): - compare_attrs = ( 'name', 'builderNames', 'jobdir', 'properties' ) - - def __init__(self, name, builderNames, jobdir, properties={}): - TryBase.__init__(self, name, builderNames, properties) - self.jobdir = jobdir - self.watcher = MaildirService() - self.watcher.setServiceParent(self) - - def setServiceParent(self, parent): - self.watcher.setBasedir(os.path.join(parent.basedir, self.jobdir)) - TryBase.setServiceParent(self, parent) - - def parseJob(self, f): - # jobfiles are serialized build requests. Each is a list of - # serialized netstrings, in the following order: - # "1", the version number of this format - # buildsetID, arbitrary string, used to find the buildSet later - # branch name, "" for default-branch - # base revision, "" for HEAD - # patchlevel, usually "1" - # patch - # builderNames... - p = JobFileScanner() - p.dataReceived(f.read()) - if p.error: - raise BadJobfile("unable to parse netstrings") - s = p.strings - ver = s.pop(0) - if ver != "1": - raise BadJobfile("unknown version '%s'" % ver) - buildsetID, branch, baserev, patchlevel, diff = s[:5] - builderNames = s[5:] - if branch == "": - branch = None - if baserev == "": - baserev = None - patchlevel = int(patchlevel) - patch = (patchlevel, diff) - ss = SourceStamp(branch, baserev, patch) - return builderNames, ss, buildsetID - - def messageReceived(self, filename): - md = os.path.join(self.parent.basedir, self.jobdir) - if runtime.platformType == "posix": - # open the file before moving it, because I'm afraid that once - # it's in cur/, someone might delete it at any moment - path = os.path.join(md, "new", filename) - f = open(path, "r") - os.rename(os.path.join(md, "new", filename), - os.path.join(md, "cur", filename)) - else: - # do this backwards under windows, because you can't move a file - # that somebody is holding open. This was causing a Permission - # Denied error on bear's win32-twisted1.3 buildslave. - os.rename(os.path.join(md, "new", filename), - os.path.join(md, "cur", filename)) - path = os.path.join(md, "cur", filename) - f = open(path, "r") - - try: - builderNames, ss, bsid = self.parseJob(f) - except BadJobfile: - log.msg("%s reports a bad jobfile in %s" % (self, filename)) - log.err() - return - # compare builderNames against self.builderNames - # TODO: think about this some more.. why bother restricting it? - # perhaps self.builderNames should be used as the default list - # instead of being used as a restriction? - for b in builderNames: - if not b in self.builderNames: - log.msg("%s got jobfile %s with builder %s" % (self, - filename, b)) - log.msg(" but that wasn't in our list: %s" - % (self.builderNames,)) - return - - reason = "'try' job" - bs = buildset.BuildSet(builderNames, ss, reason=reason, - bsid=bsid, properties=self.properties) - self.submitBuildSet(bs) - -class Try_Userpass(TryBase): - compare_attrs = ( 'name', 'builderNames', 'port', 'userpass', 'properties' ) - implements(portal.IRealm) - - def __init__(self, name, builderNames, port, userpass, properties={}): - TryBase.__init__(self, name, builderNames, properties) - if type(port) is int: - port = "tcp:%d" % port - self.port = port - self.userpass = userpass - c = checkers.InMemoryUsernamePasswordDatabaseDontUse() - for user,passwd in self.userpass: - c.addUser(user, passwd) - - p = portal.Portal(self) - p.registerChecker(c) - f = pb.PBServerFactory(p) - s = strports.service(port, f) - s.setServiceParent(self) - - def getPort(self): - # utility method for tests: figure out which TCP port we just opened. - return self.services[0]._port.getHost().port - - def requestAvatar(self, avatarID, mind, interface): - log.msg("%s got connection from user %s" % (self, avatarID)) - assert interface == pb.IPerspective - p = Try_Userpass_Perspective(self, avatarID) - return (pb.IPerspective, p, lambda: None) - -class Try_Userpass_Perspective(pbutil.NewCredPerspective): - def __init__(self, parent, username): - self.parent = parent - self.username = username - - def perspective_try(self, branch, revision, patch, builderNames, properties={}): - log.msg("user %s requesting build on builders %s" % (self.username, - builderNames)) - for b in builderNames: - if not b in self.parent.builderNames: - log.msg("%s got job with builder %s" % (self, b)) - log.msg(" but that wasn't in our list: %s" - % (self.parent.builderNames,)) - return - ss = SourceStamp(branch, revision, patch) - reason = "'try' job from user %s" % self.username - - # roll the specified props in with our inherited props - combined_props = Properties() - combined_props.updateFromProperties(self.parent.properties) - combined_props.update(properties, "try build") - - bs = buildset.BuildSet(builderNames, - ss, - reason=reason, - properties=combined_props) - - self.parent.submitBuildSet(bs) - - # return a remotely-usable BuildSetStatus object - from buildbot.status.client import makeRemote - return makeRemote(bs.status) - -class Triggerable(BaseUpstreamScheduler): - """This scheduler doesn't do anything until it is triggered by a Trigger - step in a factory. In general, that step will not complete until all of - the builds that I fire have finished. - """ - - compare_attrs = ('name', 'builderNames', 'properties') - - def __init__(self, name, builderNames, properties={}): - BaseUpstreamScheduler.__init__(self, name, properties) - self.builderNames = builderNames - - def listBuilderNames(self): - return self.builderNames - - def getPendingBuildTimes(self): - return [] - - def trigger(self, ss, set_props=None): - """Trigger this scheduler. Returns a deferred that will fire when the - buildset is finished. - """ - - # properties for this buildset are composed of our own properties, - # potentially overridden by anything from the triggering build - props = Properties() - props.updateFromProperties(self.properties) - if set_props: props.updateFromProperties(set_props) - - bs = buildset.BuildSet(self.builderNames, ss, properties=props) - d = bs.waitUntilFinished() - self.submitBuildSet(bs) - return d diff --git a/tools/buildbot/pylibs/buildbot/scripts/__init__.py b/tools/buildbot/pylibs/buildbot/scripts/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tools/buildbot/pylibs/buildbot/scripts/checkconfig.py b/tools/buildbot/pylibs/buildbot/scripts/checkconfig.py deleted file mode 100644 index 37bdf23..0000000 --- a/tools/buildbot/pylibs/buildbot/scripts/checkconfig.py +++ /dev/null @@ -1,52 +0,0 @@ -import sys -import os -from shutil import copy, rmtree -from tempfile import mkdtemp -from os.path import isfile -import traceback - -from buildbot import master - -class ConfigLoader(master.BuildMaster): - def __init__(self, configFileName="master.cfg"): - master.BuildMaster.__init__(self, ".", configFileName) - dir = os.getcwd() - # Use a temporary directory since loadConfig() creates a bunch of - # directories and compiles .py files - tempdir = mkdtemp() - try: - copy(configFileName, tempdir) - for entry in os.listdir("."): - # Any code in a subdirectory will _not_ be copied! This is a bug - if isfile(entry): - copy(entry, tempdir) - except: - raise - - try: - os.chdir(tempdir) - # Add the temp directory to the library path so local modules work - sys.path.append(tempdir) - configFile = open(configFileName, "r") - self.loadConfig(configFile) - except: - os.chdir(dir) - rmtree(tempdir) - raise - os.chdir(dir) - rmtree(tempdir) - -if __name__ == '__main__': - try: - if len(sys.argv) > 1: - c = ConfigLoader(sys.argv[1]) - else: - c = ConfigLoader() - except IOError: - print >> sys.stderr, "Could not open config file" - sys.exit(2) - except: - print >> sys.stderr, "Error in config file:" - t, v, tb = sys.exc_info() - print >> sys.stderr, traceback.print_exception(t, v, tb) - sys.exit(1) diff --git a/tools/buildbot/pylibs/buildbot/scripts/logwatcher.py b/tools/buildbot/pylibs/buildbot/scripts/logwatcher.py deleted file mode 100644 index c40e46d..0000000 --- a/tools/buildbot/pylibs/buildbot/scripts/logwatcher.py +++ /dev/null @@ -1,97 +0,0 @@ - -import os -from twisted.python.failure import Failure -from twisted.internet import defer, reactor, protocol, error -from twisted.protocols.basic import LineOnlyReceiver - -class FakeTransport: - disconnecting = False - -class BuildmasterTimeoutError(Exception): - pass -class BuildslaveTimeoutError(Exception): - pass -class ReconfigError(Exception): - pass -class BuildSlaveDetectedError(Exception): - pass - -class TailProcess(protocol.ProcessProtocol): - def outReceived(self, data): - self.lw.dataReceived(data) - def errReceived(self, data): - print "ERR: '%s'" % (data,) - - -class LogWatcher(LineOnlyReceiver): - POLL_INTERVAL = 0.1 - TIMEOUT_DELAY = 10.0 - delimiter = os.linesep - - def __init__(self, logfile): - self.logfile = logfile - self.in_reconfig = False - self.transport = FakeTransport() - self.pp = TailProcess() - self.pp.lw = self - self.processtype = "buildmaster" - self.timer = None - - def start(self): - # return a Deferred that fires when the reconfig process has - # finished. It errbacks with TimeoutError if the finish line has not - # been seen within 10 seconds, and with ReconfigError if the error - # line was seen. If the logfile could not be opened, it errbacks with - # an IOError. - self.p = reactor.spawnProcess(self.pp, "/usr/bin/tail", - ("tail", "-F", "-n", "0", self.logfile), - env=os.environ, - ) - self.running = True - d = defer.maybeDeferred(self._start) - return d - - def _start(self): - self.d = defer.Deferred() - self.timer = reactor.callLater(self.TIMEOUT_DELAY, self.timeout) - return self.d - - def timeout(self): - self.timer = None - if self.processtype == "buildmaster": - e = BuildmasterTimeoutError() - else: - e = BuildslaveTimeoutError() - self.finished(Failure(e)) - - def finished(self, results): - try: - self.p.signalProcess("KILL") - except error.ProcessExitedAlready: - pass - if self.timer: - self.timer.cancel() - self.timer = None - self.running = False - self.in_reconfig = False - self.d.callback(results) - - def lineReceived(self, line): - if not self.running: - return - if "Log opened." in line: - self.in_reconfig = True - if "loading configuration from" in line: - self.in_reconfig = True - if "Creating BuildSlave" in line: - self.processtype = "buildslave" - - if self.in_reconfig: - print line - - if "message from master: attached" in line: - return self.finished("buildslave") - if "I will keep using the previous config file" in line: - return self.finished(Failure(ReconfigError())) - if "configuration update complete" in line: - return self.finished("buildmaster") diff --git a/tools/buildbot/pylibs/buildbot/scripts/reconfig.py b/tools/buildbot/pylibs/buildbot/scripts/reconfig.py deleted file mode 100644 index 104214b..0000000 --- a/tools/buildbot/pylibs/buildbot/scripts/reconfig.py +++ /dev/null @@ -1,69 +0,0 @@ - -import os, signal, platform -from twisted.internet import reactor - -from buildbot.scripts.logwatcher import LogWatcher, BuildmasterTimeoutError, \ - ReconfigError - -class Reconfigurator: - def run(self, config): - # Returns "Microsoft" for Vista and "Windows" for other versions - if platform.system() in ("Windows", "Microsoft"): - print "Reconfig (through SIGHUP) is not supported on Windows." - print "The 'buildbot debugclient' tool can trigger a reconfig" - print "remotely, but requires Gtk+ libraries to run." - return - - basedir = config['basedir'] - quiet = config['quiet'] - os.chdir(basedir) - f = open("twistd.pid", "rt") - self.pid = int(f.read().strip()) - if quiet: - os.kill(self.pid, signal.SIGHUP) - return - - # keep reading twistd.log. Display all messages between "loading - # configuration from ..." and "configuration update complete" or - # "I will keep using the previous config file instead.", or until - # 10 seconds have elapsed. - - self.sent_signal = False - lw = LogWatcher("twistd.log") - d = lw.start() - d.addCallbacks(self.success, self.failure) - reactor.callLater(0.2, self.sighup) - reactor.run() - - def sighup(self): - if self.sent_signal: - return - print "sending SIGHUP to process %d" % self.pid - self.sent_signal = True - os.kill(self.pid, signal.SIGHUP) - - def success(self, res): - print """ -Reconfiguration appears to have completed successfully. -""" - reactor.stop() - - def failure(self, why): - if why.check(BuildmasterTimeoutError): - print "Never saw reconfiguration finish." - elif why.check(ReconfigError): - print """ -Reconfiguration failed. Please inspect the master.cfg file for errors, -correct them, then try 'buildbot reconfig' again. -""" - elif why.check(IOError): - # we were probably unable to open the file in the first place - self.sighup() - else: - print "Error while following twistd.log: %s" % why - reactor.stop() - -def reconfig(config): - r = Reconfigurator() - r.run(config) - diff --git a/tools/buildbot/pylibs/buildbot/scripts/runner.py b/tools/buildbot/pylibs/buildbot/scripts/runner.py deleted file mode 100644 index 38611f6..0000000 --- a/tools/buildbot/pylibs/buildbot/scripts/runner.py +++ /dev/null @@ -1,962 +0,0 @@ -# -*- test-case-name: buildbot.test.test_runner -*- - -# N.B.: don't import anything that might pull in a reactor yet. Some of our -# subcommands want to load modules that need the gtk reactor. -import os, sys, stat, re, time -import traceback -from twisted.python import usage, util, runtime - -# this is mostly just a front-end for mktap, twistd, and kill(1), but in the -# future it will also provide an interface to some developer tools that talk -# directly to a remote buildmaster (like 'try' and a status client) - -# the create/start/stop commands should all be run as the same user, -# preferably a separate 'buildbot' account. - -class MakerBase(usage.Options): - optFlags = [ - ['help', 'h', "Display this message"], - ["quiet", "q", "Do not emit the commands being run"], - ] - - #["basedir", "d", None, "Base directory for the buildmaster"], - opt_h = usage.Options.opt_help - - def parseArgs(self, *args): - if len(args) > 0: - self['basedir'] = args[0] - else: - self['basedir'] = None - if len(args) > 1: - raise usage.UsageError("I wasn't expecting so many arguments") - - def postOptions(self): - if self['basedir'] is None: - raise usage.UsageError(" parameter is required") - self['basedir'] = os.path.abspath(self['basedir']) - -makefile_sample = """# -*- makefile -*- - -# This is a simple makefile which lives in a buildmaster/buildslave -# directory (next to the buildbot.tac file). It allows you to start/stop the -# master or slave by doing 'make start' or 'make stop'. - -# The 'reconfig' target will tell a buildmaster to reload its config file. - -start: - twistd --no_save -y buildbot.tac - -stop: - kill `cat twistd.pid` - -reconfig: - kill -HUP `cat twistd.pid` - -log: - tail -f twistd.log -""" - -class Maker: - def __init__(self, config): - self.config = config - self.basedir = config['basedir'] - self.force = config.get('force', False) - self.quiet = config['quiet'] - - def mkdir(self): - if os.path.exists(self.basedir): - if not self.quiet: - print "updating existing installation" - return - if not self.quiet: print "mkdir", self.basedir - os.mkdir(self.basedir) - - def mkinfo(self): - path = os.path.join(self.basedir, "info") - if not os.path.exists(path): - if not self.quiet: print "mkdir", path - os.mkdir(path) - created = False - admin = os.path.join(path, "admin") - if not os.path.exists(admin): - if not self.quiet: - print "Creating info/admin, you need to edit it appropriately" - f = open(admin, "wt") - f.write("Your Name Here \n") - f.close() - created = True - host = os.path.join(path, "host") - if not os.path.exists(host): - if not self.quiet: - print "Creating info/host, you need to edit it appropriately" - f = open(host, "wt") - f.write("Please put a description of this build host here\n") - f.close() - created = True - if created and not self.quiet: - print "Please edit the files in %s appropriately." % path - - def chdir(self): - if not self.quiet: print "chdir", self.basedir - os.chdir(self.basedir) - - def makeTAC(self, contents, secret=False): - tacfile = "buildbot.tac" - if os.path.exists(tacfile): - oldcontents = open(tacfile, "rt").read() - if oldcontents == contents: - if not self.quiet: - print "buildbot.tac already exists and is correct" - return - if not self.quiet: - print "not touching existing buildbot.tac" - print "creating buildbot.tac.new instead" - tacfile = "buildbot.tac.new" - f = open(tacfile, "wt") - f.write(contents) - f.close() - if secret: - os.chmod(tacfile, 0600) - - def makefile(self): - target = "Makefile.sample" - if os.path.exists(target): - oldcontents = open(target, "rt").read() - if oldcontents == makefile_sample: - if not self.quiet: - print "Makefile.sample already exists and is correct" - return - if not self.quiet: - print "replacing Makefile.sample" - else: - if not self.quiet: - print "creating Makefile.sample" - f = open(target, "wt") - f.write(makefile_sample) - f.close() - - def sampleconfig(self, source): - target = "master.cfg.sample" - config_sample = open(source, "rt").read() - if os.path.exists(target): - oldcontents = open(target, "rt").read() - if oldcontents == config_sample: - if not self.quiet: - print "master.cfg.sample already exists and is up-to-date" - return - if not self.quiet: - print "replacing master.cfg.sample" - else: - if not self.quiet: - print "creating master.cfg.sample" - f = open(target, "wt") - f.write(config_sample) - f.close() - os.chmod(target, 0600) - - def public_html(self, index_html, buildbot_css, robots_txt): - webdir = os.path.join(self.basedir, "public_html") - if os.path.exists(webdir): - if not self.quiet: - print "public_html/ already exists: not replacing" - return - else: - os.mkdir(webdir) - if not self.quiet: - print "populating public_html/" - target = os.path.join(webdir, "index.html") - f = open(target, "wt") - f.write(open(index_html, "rt").read()) - f.close() - - target = os.path.join(webdir, "buildbot.css") - f = open(target, "wt") - f.write(open(buildbot_css, "rt").read()) - f.close() - - target = os.path.join(webdir, "robots.txt") - f = open(target, "wt") - f.write(open(robots_txt, "rt").read()) - f.close() - - def populate_if_missing(self, target, source, overwrite=False): - new_contents = open(source, "rt").read() - if os.path.exists(target): - old_contents = open(target, "rt").read() - if old_contents != new_contents: - if overwrite: - if not self.quiet: - print "%s has old/modified contents" % target - print " overwriting it with new contents" - open(target, "wt").write(new_contents) - else: - if not self.quiet: - print "%s has old/modified contents" % target - print " writing new contents to %s.new" % target - open(target + ".new", "wt").write(new_contents) - # otherwise, it's up to date - else: - if not self.quiet: - print "populating %s" % target - open(target, "wt").write(new_contents) - - def upgrade_public_html(self, index_html, buildbot_css, robots_txt): - webdir = os.path.join(self.basedir, "public_html") - if not os.path.exists(webdir): - if not self.quiet: - print "populating public_html/" - os.mkdir(webdir) - self.populate_if_missing(os.path.join(webdir, "index.html"), - index_html) - self.populate_if_missing(os.path.join(webdir, "buildbot.css"), - buildbot_css) - self.populate_if_missing(os.path.join(webdir, "robots.txt"), - robots_txt) - - def check_master_cfg(self): - from buildbot.master import BuildMaster - from twisted.python import log, failure - - master_cfg = os.path.join(self.basedir, "master.cfg") - if not os.path.exists(master_cfg): - if not self.quiet: - print "No master.cfg found" - return 1 - - # side-effects of loading the config file: - - # for each Builder defined in c['builders'], if the status directory - # didn't already exist, it will be created, and the - # $BUILDERNAME/builder pickle might be created (with a single - # "builder created" event). - - # we put basedir in front of sys.path, because that's how the - # buildmaster itself will run, and it is quite common to have the - # buildmaster import helper classes from other .py files in its - # basedir. - - if sys.path[0] != self.basedir: - sys.path.insert(0, self.basedir) - - m = BuildMaster(self.basedir) - # we need to route log.msg to stdout, so any problems can be seen - # there. But if everything goes well, I'd rather not clutter stdout - # with log messages. So instead we add a logObserver which gathers - # messages and only displays them if something goes wrong. - messages = [] - log.addObserver(messages.append) - try: - # this will raise an exception if there's something wrong with - # the config file. Note that this BuildMaster instance is never - # started, so it won't actually do anything with the - # configuration. - m.loadConfig(open(master_cfg, "r")) - except: - f = failure.Failure() - if not self.quiet: - print - for m in messages: - print "".join(m['message']) - print f - print - print "An error was detected in the master.cfg file." - print "Please correct the problem and run 'buildbot upgrade-master' again." - print - return 1 - return 0 - -class UpgradeMasterOptions(MakerBase): - optFlags = [ - ["replace", "r", "Replace any modified files without confirmation."], - ] - - def getSynopsis(self): - return "Usage: buildbot upgrade-master [options] " - - longdesc = """ - This command takes an existing buildmaster working directory and - adds/modifies the files there to work with the current version of - buildbot. When this command is finished, the buildmaster directory should - look much like a brand-new one created by the 'create-master' command. - - Use this after you've upgraded your buildbot installation and before you - restart the buildmaster to use the new version. - - If you have modified the files in your working directory, this command - will leave them untouched, but will put the new recommended contents in a - .new file (for example, if index.html has been modified, this command - will create index.html.new). You can then look at the new version and - decide how to merge its contents into your modified file. - """ - -def upgradeMaster(config): - basedir = config['basedir'] - m = Maker(config) - # TODO: check Makefile - # TODO: check TAC file - # check web files: index.html, classic.css, robots.txt - webdir = os.path.join(basedir, "public_html") - m.upgrade_public_html(util.sibpath(__file__, "../status/web/index.html"), - util.sibpath(__file__, "../status/web/classic.css"), - util.sibpath(__file__, "../status/web/robots.txt"), - ) - m.populate_if_missing(os.path.join(basedir, "master.cfg.sample"), - util.sibpath(__file__, "sample.cfg"), - overwrite=True) - rc = m.check_master_cfg() - if rc: - return rc - if not config['quiet']: - print "upgrade complete" - - -class MasterOptions(MakerBase): - optFlags = [ - ["force", "f", - "Re-use an existing directory (will not overwrite master.cfg file)"], - ] - optParameters = [ - ["config", "c", "master.cfg", "name of the buildmaster config file"], - ] - def getSynopsis(self): - return "Usage: buildbot create-master [options] " - - longdesc = """ - This command creates a buildmaster working directory and buildbot.tac - file. The master will live in and create various files there. - - At runtime, the master will read a configuration file (named - 'master.cfg' by default) in its basedir. This file should contain python - code which eventually defines a dictionary named 'BuildmasterConfig'. - The elements of this dictionary are used to configure the Buildmaster. - See doc/config.xhtml for details about what can be controlled through - this interface.""" - -masterTAC = """ -from twisted.application import service -from buildbot.master import BuildMaster - -basedir = r'%(basedir)s' -configfile = r'%(config)s' - -application = service.Application('buildmaster') -BuildMaster(basedir, configfile).setServiceParent(application) - -""" - -def createMaster(config): - m = Maker(config) - m.mkdir() - m.chdir() - contents = masterTAC % config - m.makeTAC(contents) - m.sampleconfig(util.sibpath(__file__, "sample.cfg")) - m.public_html(util.sibpath(__file__, "../status/web/index.html"), - util.sibpath(__file__, "../status/web/classic.css"), - util.sibpath(__file__, "../status/web/robots.txt"), - ) - m.makefile() - - if not m.quiet: print "buildmaster configured in %s" % m.basedir - -class SlaveOptions(MakerBase): - optFlags = [ - ["force", "f", "Re-use an existing directory"], - ] - optParameters = [ -# ["name", "n", None, "Name for this build slave"], -# ["passwd", "p", None, "Password for this build slave"], -# ["basedir", "d", ".", "Base directory to use"], -# ["master", "m", "localhost:8007", -# "Location of the buildmaster (host:port)"], - - ["keepalive", "k", 600, - "Interval at which keepalives should be sent (in seconds)"], - ["usepty", None, 1, - "(1 or 0) child processes should be run in a pty"], - ["umask", None, "None", - "controls permissions of generated files. Use --umask=022 to be world-readable"], - ] - - longdesc = """ - This command creates a buildslave working directory and buildbot.tac - file. The bot will use the and arguments to authenticate - itself when connecting to the master. All commands are run in a - build-specific subdirectory of . is a string of the - form 'hostname:port', and specifies where the buildmaster can be reached. - - , , and will be provided by the buildmaster - administrator for your bot. You must choose yourself. - """ - - def getSynopsis(self): - return "Usage: buildbot create-slave [options] " - - def parseArgs(self, *args): - if len(args) < 4: - raise usage.UsageError("command needs more arguments") - basedir, master, name, passwd = args - self['basedir'] = basedir - self['master'] = master - self['name'] = name - self['passwd'] = passwd - - def postOptions(self): - MakerBase.postOptions(self) - self['usepty'] = int(self['usepty']) - self['keepalive'] = int(self['keepalive']) - if self['master'].find(":") == -1: - raise usage.UsageError("--master must be in the form host:portnum") - -slaveTAC = """ -from twisted.application import service -from buildbot.slave.bot import BuildSlave - -basedir = r'%(basedir)s' -buildmaster_host = '%(host)s' -port = %(port)d -slavename = '%(name)s' -passwd = '%(passwd)s' -keepalive = %(keepalive)d -usepty = %(usepty)d -umask = %(umask)s - -application = service.Application('buildslave') -s = BuildSlave(buildmaster_host, port, slavename, passwd, basedir, - keepalive, usepty, umask=umask) -s.setServiceParent(application) - -""" - -def createSlave(config): - m = Maker(config) - m.mkdir() - m.chdir() - try: - master = config['master'] - host, port = re.search(r'(.+):(\d+)', master).groups() - config['host'] = host - config['port'] = int(port) - except: - print "unparseable master location '%s'" % master - print " expecting something more like localhost:8007" - raise - contents = slaveTAC % config - - m.makeTAC(contents, secret=True) - - m.makefile() - m.mkinfo() - - if not m.quiet: print "buildslave configured in %s" % m.basedir - - - -def stop(config, signame="TERM", wait=False): - import signal - basedir = config['basedir'] - quiet = config['quiet'] - os.chdir(basedir) - f = open("twistd.pid", "rt") - pid = int(f.read().strip()) - signum = getattr(signal, "SIG"+signame) - timer = 0 - os.kill(pid, signum) - if not wait: - if not quiet: - print "sent SIG%s to process" % signame - return - time.sleep(0.1) - while timer < 10: - # poll once per second until twistd.pid goes away, up to 10 seconds - try: - os.kill(pid, 0) - except OSError: - if not quiet: - print "buildbot process %d is dead" % pid - return - timer += 1 - time.sleep(1) - if not quiet: - print "never saw process go away" - -def restart(config): - quiet = config['quiet'] - from buildbot.scripts.startup import start - stop(config, wait=True) - if not quiet: - print "now restarting buildbot process.." - start(config) - - -def loadOptions(filename="options", here=None, home=None): - """Find the .buildbot/FILENAME file. Crawl from the current directory up - towards the root, and also look in ~/.buildbot . The first directory - that's owned by the user and has the file we're looking for wins. Windows - skips the owned-by-user test. - - @rtype: dict - @return: a dictionary of names defined in the options file. If no options - file was found, return an empty dict. - """ - - if here is None: - here = os.getcwd() - here = os.path.abspath(here) - - if home is None: - if runtime.platformType == 'win32': - home = os.path.join(os.environ['APPDATA'], "buildbot") - else: - home = os.path.expanduser("~/.buildbot") - - searchpath = [] - toomany = 20 - while True: - searchpath.append(os.path.join(here, ".buildbot")) - next = os.path.dirname(here) - if next == here: - break # we've hit the root - here = next - toomany -= 1 # just in case - if toomany == 0: - raise ValueError("Hey, I seem to have wandered up into the " - "infinite glories of the heavens. Oops.") - searchpath.append(home) - - localDict = {} - - for d in searchpath: - if os.path.isdir(d): - if runtime.platformType != 'win32': - if os.stat(d)[stat.ST_UID] != os.getuid(): - print "skipping %s because you don't own it" % d - continue # security, skip other people's directories - optfile = os.path.join(d, filename) - if os.path.exists(optfile): - try: - f = open(optfile, "r") - options = f.read() - exec options in localDict - except: - print "error while reading %s" % optfile - raise - break - - for k in localDict.keys(): - if k.startswith("__"): - del localDict[k] - return localDict - -class StartOptions(MakerBase): - optFlags = [ - ['quiet', 'q', "Don't display startup log messages"], - ] - def getSynopsis(self): - return "Usage: buildbot start " - -class StopOptions(MakerBase): - def getSynopsis(self): - return "Usage: buildbot stop " - -class ReconfigOptions(MakerBase): - optFlags = [ - ['quiet', 'q', "Don't display log messages about reconfiguration"], - ] - def getSynopsis(self): - return "Usage: buildbot reconfig " - - - -class RestartOptions(MakerBase): - optFlags = [ - ['quiet', 'q', "Don't display startup log messages"], - ] - def getSynopsis(self): - return "Usage: buildbot restart " - -class DebugClientOptions(usage.Options): - optFlags = [ - ['help', 'h', "Display this message"], - ] - optParameters = [ - ["master", "m", None, - "Location of the buildmaster's slaveport (host:port)"], - ["passwd", "p", None, "Debug password to use"], - ] - - def parseArgs(self, *args): - if len(args) > 0: - self['master'] = args[0] - if len(args) > 1: - self['passwd'] = args[1] - if len(args) > 2: - raise usage.UsageError("I wasn't expecting so many arguments") - -def debugclient(config): - from buildbot.clients import debug - opts = loadOptions() - - master = config.get('master') - if not master: - master = opts.get('master') - if master is None: - raise usage.UsageError("master must be specified: on the command " - "line or in ~/.buildbot/options") - - passwd = config.get('passwd') - if not passwd: - passwd = opts.get('debugPassword') - if passwd is None: - raise usage.UsageError("passwd must be specified: on the command " - "line or in ~/.buildbot/options") - - d = debug.DebugWidget(master, passwd) - d.run() - -class StatusClientOptions(usage.Options): - optFlags = [ - ['help', 'h', "Display this message"], - ] - optParameters = [ - ["master", "m", None, - "Location of the buildmaster's status port (host:port)"], - ] - - def parseArgs(self, *args): - if len(args) > 0: - self['master'] = args[0] - if len(args) > 1: - raise usage.UsageError("I wasn't expecting so many arguments") - -def statuslog(config): - from buildbot.clients import base - opts = loadOptions() - master = config.get('master') - if not master: - master = opts.get('masterstatus') - if master is None: - raise usage.UsageError("master must be specified: on the command " - "line or in ~/.buildbot/options") - c = base.TextClient(master) - c.run() - -def statusgui(config): - from buildbot.clients import gtkPanes - opts = loadOptions() - master = config.get('master') - if not master: - master = opts.get('masterstatus') - if master is None: - raise usage.UsageError("master must be specified: on the command " - "line or in ~/.buildbot/options") - c = gtkPanes.GtkClient(master) - c.run() - -class SendChangeOptions(usage.Options): - optParameters = [ - ("master", "m", None, - "Location of the buildmaster's PBListener (host:port)"), - ("username", "u", None, "Username performing the commit"), - ("branch", "b", None, "Branch specifier"), - ("revision", "r", None, "Revision specifier (string)"), - ("revision_number", "n", None, "Revision specifier (integer)"), - ("revision_file", None, None, "Filename containing revision spec"), - ("comments", "m", None, "log message"), - ("logfile", "F", None, - "Read the log messages from this file (- for stdin)"), - ] - def getSynopsis(self): - return "Usage: buildbot sendchange [options] filenames.." - def parseArgs(self, *args): - self['files'] = args - - -def sendchange(config, runReactor=False): - """Send a single change to the buildmaster's PBChangeSource. The - connection will be drpoped as soon as the Change has been sent.""" - from buildbot.clients.sendchange import Sender - - opts = loadOptions() - user = config.get('username', opts.get('username')) - master = config.get('master', opts.get('master')) - branch = config.get('branch', opts.get('branch')) - revision = config.get('revision') - # SVN and P4 use numeric revisions - if config.get("revision_number"): - revision = int(config['revision_number']) - if config.get("revision_file"): - revision = open(config["revision_file"],"r").read() - - comments = config.get('comments') - if not comments and config.get('logfile'): - if config['logfile'] == "-": - f = sys.stdin - else: - f = open(config['logfile'], "rt") - comments = f.read() - if comments is None: - comments = "" - - files = config.get('files', []) - - assert user, "you must provide a username" - assert master, "you must provide the master location" - - s = Sender(master, user) - d = s.send(branch, revision, comments, files) - if runReactor: - d.addCallbacks(s.printSuccess, s.printFailure) - d.addBoth(s.stop) - s.run() - return d - - -class ForceOptions(usage.Options): - optParameters = [ - ["builder", None, None, "which Builder to start"], - ["branch", None, None, "which branch to build"], - ["revision", None, None, "which revision to build"], - ["reason", None, None, "the reason for starting the build"], - ] - - def parseArgs(self, *args): - args = list(args) - if len(args) > 0: - if self['builder'] is not None: - raise usage.UsageError("--builder provided in two ways") - self['builder'] = args.pop(0) - if len(args) > 0: - if self['reason'] is not None: - raise usage.UsageError("--reason provided in two ways") - self['reason'] = " ".join(args) - - -class TryOptions(usage.Options): - optParameters = [ - ["connect", "c", None, - "how to reach the buildmaster, either 'ssh' or 'pb'"], - # for ssh, use --tryhost, --username, and --trydir - ["tryhost", None, None, - "the hostname (used by ssh) for the buildmaster"], - ["trydir", None, None, - "the directory (on the tryhost) where tryjobs are deposited"], - ["username", "u", None, "Username performing the trial build"], - # for PB, use --master, --username, and --passwd - ["master", "m", None, - "Location of the buildmaster's PBListener (host:port)"], - ["passwd", None, None, "password for PB authentication"], - - ["diff", None, None, - "Filename of a patch to use instead of scanning a local tree. Use '-' for stdin."], - ["patchlevel", "p", 0, - "Number of slashes to remove from patch pathnames, like the -p option to 'patch'"], - - ["baserev", None, None, - "Base revision to use instead of scanning a local tree."], - - ["vc", None, None, - "The VC system in use, one of: cvs,svn,tla,baz,darcs"], - ["branch", None, None, - "The branch in use, for VC systems that can't figure it out" - " themselves"], - - ["builder", "b", None, - "Run the trial build on this Builder. Can be used multiple times."], - ["properties", None, None, - "A set of properties made available in the build environment, format:prop=value,propb=valueb..."], - ] - - optFlags = [ - ["wait", None, "wait until the builds have finished"], - ] - - def __init__(self): - super(TryOptions, self).__init__() - self['builders'] = [] - self['properties'] = {} - - def opt_builder(self, option): - self['builders'].append(option) - - def opt_properties(self, option): - # We need to split the value of this option into a dictionary of properties - properties = {} - propertylist = option.split(",") - for i in range(0,len(propertylist)): - print propertylist[i] - splitproperty = propertylist[i].split("=") - properties[splitproperty[0]] = splitproperty[1] - self['properties'] = properties - - def opt_patchlevel(self, option): - self['patchlevel'] = int(option) - - def getSynopsis(self): - return "Usage: buildbot try [options]" - -def doTry(config): - from buildbot.scripts import tryclient - t = tryclient.Try(config) - t.run() - -class TryServerOptions(usage.Options): - optParameters = [ - ["jobdir", None, None, "the jobdir (maildir) for submitting jobs"], - ] - -def doTryServer(config): - import md5 - jobdir = os.path.expanduser(config["jobdir"]) - job = sys.stdin.read() - # now do a 'safecat'-style write to jobdir/tmp, then move atomically to - # jobdir/new . Rather than come up with a unique name randomly, I'm just - # going to MD5 the contents and prepend a timestamp. - timestring = "%d" % time.time() - jobhash = md5.new(job).hexdigest() - fn = "%s-%s" % (timestring, jobhash) - tmpfile = os.path.join(jobdir, "tmp", fn) - newfile = os.path.join(jobdir, "new", fn) - f = open(tmpfile, "w") - f.write(job) - f.close() - os.rename(tmpfile, newfile) - - -class CheckConfigOptions(usage.Options): - optFlags = [ - ['quiet', 'q', "Don't display error messages or tracebacks"], - ] - - def getSynopsis(self): - return "Usage :buildbot checkconfig [configFile]\n" + \ - " If not specified, 'master.cfg' will be used as 'configFile'" - - def parseArgs(self, *args): - if len(args) >= 1: - self['configFile'] = args[0] - else: - self['configFile'] = 'master.cfg' - - -def doCheckConfig(config): - quiet = config.get('quiet') - configFile = config.get('configFile') - try: - from buildbot.scripts.checkconfig import ConfigLoader - ConfigLoader(configFile) - except: - if not quiet: - # Print out the traceback in a nice format - t, v, tb = sys.exc_info() - traceback.print_exception(t, v, tb) - sys.exit(1) - - if not quiet: - print "Config file is good!" - - -class Options(usage.Options): - synopsis = "Usage: buildbot [command options]" - - subCommands = [ - # the following are all admin commands - ['create-master', None, MasterOptions, - "Create and populate a directory for a new buildmaster"], - ['upgrade-master', None, UpgradeMasterOptions, - "Upgrade an existing buildmaster directory for the current version"], - ['create-slave', None, SlaveOptions, - "Create and populate a directory for a new buildslave"], - ['start', None, StartOptions, "Start a buildmaster or buildslave"], - ['stop', None, StopOptions, "Stop a buildmaster or buildslave"], - ['restart', None, RestartOptions, - "Restart a buildmaster or buildslave"], - - ['reconfig', None, ReconfigOptions, - "SIGHUP a buildmaster to make it re-read the config file"], - ['sighup', None, ReconfigOptions, - "SIGHUP a buildmaster to make it re-read the config file"], - - ['sendchange', None, SendChangeOptions, - "Send a change to the buildmaster"], - - ['debugclient', None, DebugClientOptions, - "Launch a small debug panel GUI"], - - ['statuslog', None, StatusClientOptions, - "Emit current builder status to stdout"], - ['statusgui', None, StatusClientOptions, - "Display a small window showing current builder status"], - - #['force', None, ForceOptions, "Run a build"], - ['try', None, TryOptions, "Run a build with your local changes"], - - ['tryserver', None, TryServerOptions, - "buildmaster-side 'try' support function, not for users"], - - ['checkconfig', None, CheckConfigOptions, - "test the validity of a master.cfg config file"], - - # TODO: 'watch' - ] - - def opt_version(self): - import buildbot - print "Buildbot version: %s" % buildbot.version - usage.Options.opt_version(self) - - def opt_verbose(self): - from twisted.python import log - log.startLogging(sys.stderr) - - def postOptions(self): - if not hasattr(self, 'subOptions'): - raise usage.UsageError("must specify a command") - - -def run(): - config = Options() - try: - config.parseOptions() - except usage.error, e: - print "%s: %s" % (sys.argv[0], e) - print - c = getattr(config, 'subOptions', config) - print str(c) - sys.exit(1) - - command = config.subCommand - so = config.subOptions - - if command == "create-master": - createMaster(so) - elif command == "upgrade-master": - upgradeMaster(so) - elif command == "create-slave": - createSlave(so) - elif command == "start": - from buildbot.scripts.startup import start - start(so) - elif command == "stop": - stop(so, wait=True) - elif command == "restart": - restart(so) - elif command == "reconfig" or command == "sighup": - from buildbot.scripts.reconfig import Reconfigurator - Reconfigurator().run(so) - elif command == "sendchange": - sendchange(so, True) - elif command == "debugclient": - debugclient(so) - elif command == "statuslog": - statuslog(so) - elif command == "statusgui": - statusgui(so) - elif command == "try": - doTry(so) - elif command == "tryserver": - doTryServer(so) - elif command == "checkconfig": - doCheckConfig(so) - - diff --git a/tools/buildbot/pylibs/buildbot/scripts/sample.cfg b/tools/buildbot/pylibs/buildbot/scripts/sample.cfg deleted file mode 100644 index 5962bb7..0000000 --- a/tools/buildbot/pylibs/buildbot/scripts/sample.cfg +++ /dev/null @@ -1,175 +0,0 @@ -# -*- python -*- -# ex: set syntax=python: - -# This is a sample buildmaster config file. It must be installed as -# 'master.cfg' in your buildmaster's base directory (although the filename -# can be changed with the --basedir option to 'mktap buildbot master'). - -# It has one job: define a dictionary named BuildmasterConfig. This -# dictionary has a variety of keys to control different aspects of the -# buildmaster. They are documented in docs/config.xhtml . - - -# This is the dictionary that the buildmaster pays attention to. We also use -# a shorter alias to save typing. -c = BuildmasterConfig = {} - -####### BUILDSLAVES - -# the 'slaves' list defines the set of allowable buildslaves. Each element is -# a tuple of bot-name and bot-password. These correspond to values given to -# the buildslave's mktap invocation. -from buildbot.buildslave import BuildSlave -c['slaves'] = [BuildSlave("bot1name", "bot1passwd")] - -# to limit to two concurrent builds on a slave, use -# c['slaves'] = [BuildSlave("bot1name", "bot1passwd", max_builds=2)] - - -# 'slavePortnum' defines the TCP port to listen on. This must match the value -# configured into the buildslaves (with their --master option) - -c['slavePortnum'] = 9989 - -####### CHANGESOURCES - -# the 'change_source' setting tells the buildmaster how it should find out -# about source code changes. Any class which implements IChangeSource can be -# put here: there are several in buildbot/changes/*.py to choose from. - -from buildbot.changes.pb import PBChangeSource -c['change_source'] = PBChangeSource() - -# For example, if you had CVSToys installed on your repository, and your -# CVSROOT/freshcfg file had an entry like this: -#pb = ConfigurationSet([ -# (None, None, None, PBService(userpass=('foo', 'bar'), port=4519)), -# ]) - -# then you could use the following buildmaster Change Source to subscribe to -# the FreshCVS daemon and be notified on every commit: -# -#from buildbot.changes.freshcvs import FreshCVSSource -#fc_source = FreshCVSSource("cvs.example.com", 4519, "foo", "bar") -#c['change_source'] = fc_source - -# or, use a PBChangeSource, and then have your repository's commit script run -# 'buildbot sendchange', or use contrib/svn_buildbot.py, or -# contrib/arch_buildbot.py : -# -#from buildbot.changes.pb import PBChangeSource -#c['change_source'] = PBChangeSource() - - -####### SCHEDULERS - -## configure the Schedulers - -from buildbot.scheduler import Scheduler -c['schedulers'] = [] -c['schedulers'].append(Scheduler(name="all", branch=None, - treeStableTimer=2*60, - builderNames=["buildbot-full"])) - - -####### BUILDERS - -# the 'builders' list defines the Builders. Each one is configured with a -# dictionary, using the following keys: -# name (required): the name used to describe this bilder -# slavename (required): which slave to use, must appear in c['bots'] -# builddir (required): which subdirectory to run the builder in -# factory (required): a BuildFactory to define how the build is run -# periodicBuildTime (optional): if set, force a build every N seconds - -# buildbot/process/factory.py provides several BuildFactory classes you can -# start with, which implement build processes for common targets (GNU -# autoconf projects, CPAN perl modules, etc). The factory.BuildFactory is the -# base class, and is configured with a series of BuildSteps. When the build -# is run, the appropriate buildslave is told to execute each Step in turn. - -# the first BuildStep is typically responsible for obtaining a copy of the -# sources. There are source-obtaining Steps in buildbot/steps/source.py for -# CVS, SVN, and others. - -cvsroot = ":pserver:anonymous@cvs.sourceforge.net:/cvsroot/buildbot" -cvsmodule = "buildbot" - -from buildbot.process import factory -from buildbot.steps.source import CVS -from buildbot.steps.shell import Compile -from buildbot.steps.python_twisted import Trial -f1 = factory.BuildFactory() -f1.addStep(CVS(cvsroot=cvsroot, cvsmodule=cvsmodule, login="", mode="copy")) -f1.addStep(Compile(command=["python", "./setup.py", "build"])) -f1.addStep(Trial(testpath=".")) - -b1 = {'name': "buildbot-full", - 'slavename': "bot1name", - 'builddir': "full", - 'factory': f1, - } -c['builders'] = [b1] - - -####### STATUS TARGETS - -# 'status' is a list of Status Targets. The results of each build will be -# pushed to these targets. buildbot/status/*.py has a variety to choose from, -# including web pages, email senders, and IRC bots. - -c['status'] = [] - -from buildbot.status import html -c['status'].append(html.WebStatus(http_port=8010)) - -# from buildbot.status import mail -# c['status'].append(mail.MailNotifier(fromaddr="buildbot@localhost", -# extraRecipients=["builds@example.com"], -# sendToInterestedUsers=False)) -# -# from buildbot.status import words -# c['status'].append(words.IRC(host="irc.example.com", nick="bb", -# channels=["#example"])) -# -# from buildbot.status import client -# c['status'].append(client.PBListener(9988)) - - -####### DEBUGGING OPTIONS - -# if you set 'debugPassword', then you can connect to the buildmaster with -# the diagnostic tool in contrib/debugclient.py . From this tool, you can -# manually force builds and inject changes, which may be useful for testing -# your buildmaster without actually commiting changes to your repository (or -# before you have a functioning 'sources' set up). The debug tool uses the -# same port number as the slaves do: 'slavePortnum'. - -#c['debugPassword'] = "debugpassword" - -# if you set 'manhole', you can ssh into the buildmaster and get an -# interactive python shell, which may be useful for debugging buildbot -# internals. It is probably only useful for buildbot developers. You can also -# use an authorized_keys file, or plain telnet. -#from buildbot import manhole -#c['manhole'] = manhole.PasswordManhole("tcp:9999:interface=127.0.0.1", -# "admin", "password") - - -####### PROJECT IDENTITY - -# the 'projectName' string will be used to describe the project that this -# buildbot is working on. For example, it is used as the title of the -# waterfall HTML page. The 'projectURL' string will be used to provide a link -# from buildbot HTML pages to your project's home page. - -c['projectName'] = "Buildbot" -c['projectURL'] = "http://buildbot.sourceforge.net/" - -# the 'buildbotURL' string should point to the location where the buildbot's -# internal web server (usually the html.Waterfall page) is visible. This -# typically uses the port number set in the Waterfall 'status' entry, but -# with an externally-visible host name which the buildbot cannot figure out -# without some help. - -c['buildbotURL'] = "http://localhost:8010/" diff --git a/tools/buildbot/pylibs/buildbot/scripts/startup.py b/tools/buildbot/pylibs/buildbot/scripts/startup.py deleted file mode 100644 index 9472af2..0000000 --- a/tools/buildbot/pylibs/buildbot/scripts/startup.py +++ /dev/null @@ -1,128 +0,0 @@ - -import os, sys, time - -class Follower: - def follow(self): - from twisted.internet import reactor - from buildbot.scripts.reconfig import LogWatcher - self.rc = 0 - print "Following twistd.log until startup finished.." - lw = LogWatcher("twistd.log") - d = lw.start() - d.addCallbacks(self._success, self._failure) - reactor.run() - return self.rc - - def _success(self, processtype): - from twisted.internet import reactor - print "The %s appears to have (re)started correctly." % processtype - self.rc = 0 - reactor.stop() - - def _failure(self, why): - from twisted.internet import reactor - from buildbot.scripts.logwatcher import BuildmasterTimeoutError, \ - ReconfigError, BuildslaveTimeoutError, BuildSlaveDetectedError - if why.check(BuildmasterTimeoutError): - print """ -The buildmaster took more than 10 seconds to start, so we were unable to -confirm that it started correctly. Please 'tail twistd.log' and look for a -line that says 'configuration update complete' to verify correct startup. -""" - elif why.check(BuildslaveTimeoutError): - print """ -The buildslave took more than 10 seconds to start and/or connect to the -buildmaster, so we were unable to confirm that it started and connected -correctly. Please 'tail twistd.log' and look for a line that says 'message -from master: attached' to verify correct startup. If you see a bunch of -messages like 'will retry in 6 seconds', your buildslave might not have the -correct hostname or portnumber for the buildmaster, or the buildmaster might -not be running. If you see messages like - 'Failure: twisted.cred.error.UnauthorizedLogin' -then your buildslave might be using the wrong botname or password. Please -correct these problems and then restart the buildslave. -""" - elif why.check(ReconfigError): - print """ -The buildmaster appears to have encountered an error in the master.cfg config -file during startup. It is probably running with an empty configuration right -now. Please inspect and fix master.cfg, then restart the buildmaster. -""" - elif why.check(BuildSlaveDetectedError): - print """ -Buildslave is starting up, not following logfile. -""" - else: - print """ -Unable to confirm that the buildmaster started correctly. You may need to -stop it, fix the config file, and restart. -""" - print why - self.rc = 1 - reactor.stop() - - -def start(config): - os.chdir(config['basedir']) - if (not os.path.exists("buildbot.tac") and - not os.path.exists("Makefile.buildbot")): - print "This doesn't look like a buildbot base directory:" - print "No buildbot.tac or Makefile.buildbot file." - print "Giving up!" - sys.exit(1) - if config['quiet']: - return launch(config) - - # we probably can't do this os.fork under windows - from twisted.python.runtime import platformType - if platformType == "win32": - return launch(config) - - # fork a child to launch the daemon, while the parent process tails the - # logfile - if os.fork(): - # this is the parent - rc = Follower().follow() - sys.exit(rc) - # this is the child: give the logfile-watching parent a chance to start - # watching it before we start the daemon - time.sleep(0.2) - launch(config) - -def launch(config): - sys.path.insert(0, os.path.abspath(os.getcwd())) - if os.path.exists("/usr/bin/make") and os.path.exists("Makefile.buildbot"): - # Preferring the Makefile lets slave admins do useful things like set - # up environment variables for the buildslave. - cmd = "make -f Makefile.buildbot start" - if not config['quiet']: - print cmd - os.system(cmd) - else: - # see if we can launch the application without actually having to - # spawn twistd, since spawning processes correctly is a real hassle - # on windows. - from twisted.python.runtime import platformType - argv = ["twistd", - "--no_save", - "--logfile=twistd.log", # windows doesn't use the same default - "--python=buildbot.tac"] - if platformType == "win32": - argv.append("--reactor=win32") - sys.argv = argv - - # this is copied from bin/twistd. twisted-2.0.0 through 2.4.0 use - # _twistw.run . Twisted-2.5.0 and later use twistd.run, even for - # windows. - from twisted import __version__ - major, minor, ignored = __version__.split(".", 2) - major = int(major) - minor = int(minor) - if (platformType == "win32" and (major == 2 and minor < 5)): - from twisted.scripts import _twistw - run = _twistw.run - else: - from twisted.scripts import twistd - run = twistd.run - run() - diff --git a/tools/buildbot/pylibs/buildbot/scripts/tryclient.py b/tools/buildbot/pylibs/buildbot/scripts/tryclient.py deleted file mode 100644 index 1cb97124..0000000 --- a/tools/buildbot/pylibs/buildbot/scripts/tryclient.py +++ /dev/null @@ -1,658 +0,0 @@ -# -*- test-case-name: buildbot.test.test_scheduler,buildbot.test.test_vc -*- - -import sys, os, re, time, random -from twisted.internet import utils, protocol, defer, reactor, task -from twisted.spread import pb -from twisted.cred import credentials -from twisted.python import log -from twisted.python.procutils import which - -from buildbot.sourcestamp import SourceStamp -from buildbot.scripts import runner -from buildbot.util import now -from buildbot.status import builder - -class SourceStampExtractor: - - def __init__(self, treetop, branch): - self.treetop = treetop - self.branch = branch - self.exe = which(self.vcexe)[0] - - def dovc(self, cmd): - """This accepts the arguments of a command, without the actual - command itself.""" - env = os.environ.copy() - env['LC_ALL'] = "C" - d = utils.getProcessOutputAndValue(self.exe, cmd, env=env, - path=self.treetop) - d.addCallback(self._didvc, cmd) - return d - def _didvc(self, res, cmd): - (stdout, stderr, code) = res - # 'bzr diff' sets rc=1 if there were any differences. tla, baz, and - # cvs do something similar, so don't bother requring rc=0. - return stdout - - def get(self): - """Return a Deferred that fires with a SourceStamp instance.""" - d = self.getBaseRevision() - d.addCallback(self.getPatch) - d.addCallback(self.done) - return d - def readPatch(self, res, patchlevel): - self.patch = (patchlevel, res) - def done(self, res): - # TODO: figure out the branch too - ss = SourceStamp(self.branch, self.baserev, self.patch) - return ss - -class CVSExtractor(SourceStampExtractor): - patchlevel = 0 - vcexe = "cvs" - def getBaseRevision(self): - # this depends upon our local clock and the repository's clock being - # reasonably synchronized with each other. We express everything in - # UTC because the '%z' format specifier for strftime doesn't always - # work. - self.baserev = time.strftime("%Y-%m-%d %H:%M:%S +0000", - time.gmtime(now())) - return defer.succeed(None) - - def getPatch(self, res): - # the -q tells CVS to not announce each directory as it works - if self.branch is not None: - # 'cvs diff' won't take both -r and -D at the same time (it - # ignores the -r). As best I can tell, there is no way to make - # cvs give you a diff relative to a timestamp on the non-trunk - # branch. A bare 'cvs diff' will tell you about the changes - # relative to your checked-out versions, but I know of no way to - # find out what those checked-out versions are. - raise RuntimeError("Sorry, CVS 'try' builds don't work with " - "branches") - args = ['-q', 'diff', '-u', '-D', self.baserev] - d = self.dovc(args) - d.addCallback(self.readPatch, self.patchlevel) - return d - -class SVNExtractor(SourceStampExtractor): - patchlevel = 0 - vcexe = "svn" - - def getBaseRevision(self): - d = self.dovc(["status", "-u"]) - d.addCallback(self.parseStatus) - return d - def parseStatus(self, res): - # svn shows the base revision for each file that has been modified or - # which needs an update. You can update each file to a different - # version, so each file is displayed with its individual base - # revision. It also shows the repository-wide latest revision number - # on the last line ("Status against revision: \d+"). - - # for our purposes, we use the latest revision number as the "base" - # revision, and get a diff against that. This means we will get - # reverse-diffs for local files that need updating, but the resulting - # tree will still be correct. The only weirdness is that the baserev - # that we emit may be different than the version of the tree that we - # first checked out. - - # to do this differently would probably involve scanning the revision - # numbers to find the max (or perhaps the min) revision, and then - # using that as a base. - - for line in res.split("\n"): - m = re.search(r'^Status against revision:\s+(\d+)', line) - if m: - self.baserev = int(m.group(1)) - return - raise IndexError("Could not find 'Status against revision' in " - "SVN output: %s" % res) - def getPatch(self, res): - d = self.dovc(["diff", "-r%d" % self.baserev]) - d.addCallback(self.readPatch, self.patchlevel) - return d - -class BazExtractor(SourceStampExtractor): - patchlevel = 1 - vcexe = "baz" - def getBaseRevision(self): - d = self.dovc(["tree-id"]) - d.addCallback(self.parseStatus) - return d - def parseStatus(self, res): - tid = res.strip() - slash = tid.index("/") - dd = tid.rindex("--") - self.branch = tid[slash+1:dd] - self.baserev = tid[dd+2:] - def getPatch(self, res): - d = self.dovc(["diff"]) - d.addCallback(self.readPatch, self.patchlevel) - return d - -class TlaExtractor(SourceStampExtractor): - patchlevel = 1 - vcexe = "tla" - def getBaseRevision(self): - # 'tla logs --full' gives us ARCHIVE/BRANCH--REVISION - # 'tla logs' gives us REVISION - d = self.dovc(["logs", "--full", "--reverse"]) - d.addCallback(self.parseStatus) - return d - def parseStatus(self, res): - tid = res.split("\n")[0].strip() - slash = tid.index("/") - dd = tid.rindex("--") - self.branch = tid[slash+1:dd] - self.baserev = tid[dd+2:] - - def getPatch(self, res): - d = self.dovc(["changes", "--diffs"]) - d.addCallback(self.readPatch, self.patchlevel) - return d - -class BzrExtractor(SourceStampExtractor): - patchlevel = 0 - vcexe = "bzr" - def getBaseRevision(self): - d = self.dovc(["version-info"]) - d.addCallback(self.get_revision_number) - return d - def get_revision_number(self, out): - for line in out.split("\n"): - colon = line.find(":") - if colon != -1: - key, value = line[:colon], line[colon+2:] - if key == "revno": - self.baserev = int(value) - return - raise ValueError("unable to find revno: in bzr output: '%s'" % out) - - def getPatch(self, res): - d = self.dovc(["diff"]) - d.addCallback(self.readPatch, self.patchlevel) - return d - -class MercurialExtractor(SourceStampExtractor): - patchlevel = 1 - vcexe = "hg" - def getBaseRevision(self): - d = self.dovc(["identify"]) - d.addCallback(self.parseStatus) - return d - def parseStatus(self, output): - m = re.search(r'^(\w+)', output) - self.baserev = m.group(0) - def getPatch(self, res): - d = self.dovc(["diff"]) - d.addCallback(self.readPatch, self.patchlevel) - return d - -class DarcsExtractor(SourceStampExtractor): - patchlevel = 1 - vcexe = "darcs" - def getBaseRevision(self): - d = self.dovc(["changes", "--context"]) - d.addCallback(self.parseStatus) - return d - def parseStatus(self, res): - self.baserev = res # the whole context file - def getPatch(self, res): - d = self.dovc(["diff", "-u"]) - d.addCallback(self.readPatch, self.patchlevel) - return d - -class GitExtractor(SourceStampExtractor): - patchlevel = 1 - vcexe = "git" - - def getBaseRevision(self): - d = self.dovc(["branch", "--no-color", "-v", "--no-abbrev"]) - d.addCallback(self.parseStatus) - return d - - def parseStatus(self, res): - # The current branch is marked by '*' at the start of the - # line, followed by the branch name and the SHA1. - # - # Branch names may contain pretty much anything but whitespace. - m = re.search(r'^\* (\S+)\s+([0-9a-f]{40})', res, re.MULTILINE) - if m: - self.branch = m.group(1) - self.baserev = m.group(2) - return - raise IndexError("Could not find current GIT branch: %s" % res) - - def getPatch(self, res): - d = self.dovc(["diff", self.baserev]) - d.addCallback(self.readPatch, self.patchlevel) - return d - -def getSourceStamp(vctype, treetop, branch=None): - if vctype == "cvs": - e = CVSExtractor(treetop, branch) - elif vctype == "svn": - e = SVNExtractor(treetop, branch) - elif vctype == "baz": - e = BazExtractor(treetop, branch) - elif vctype == "bzr": - e = BzrExtractor(treetop, branch) - elif vctype == "tla": - e = TlaExtractor(treetop, branch) - elif vctype == "hg": - e = MercurialExtractor(treetop, branch) - elif vctype == "darcs": - e = DarcsExtractor(treetop, branch) - elif vctype == "git": - e = GitExtractor(treetop, branch) - else: - raise KeyError("unknown vctype '%s'" % vctype) - return e.get() - - -def ns(s): - return "%d:%s," % (len(s), s) - -def createJobfile(bsid, branch, baserev, patchlevel, diff, builderNames): - job = "" - job += ns("1") - job += ns(bsid) - job += ns(branch) - job += ns(str(baserev)) - job += ns("%d" % patchlevel) - job += ns(diff) - for bn in builderNames: - job += ns(bn) - return job - -def getTopdir(topfile, start=None): - """walk upwards from the current directory until we find this topfile""" - if not start: - start = os.getcwd() - here = start - toomany = 20 - while toomany > 0: - if os.path.exists(os.path.join(here, topfile)): - return here - next = os.path.dirname(here) - if next == here: - break # we've hit the root - here = next - toomany -= 1 - raise ValueError("Unable to find topfile '%s' anywhere from %s upwards" - % (topfile, start)) - -class RemoteTryPP(protocol.ProcessProtocol): - def __init__(self, job): - self.job = job - self.d = defer.Deferred() - def connectionMade(self): - self.transport.write(self.job) - self.transport.closeStdin() - def outReceived(self, data): - sys.stdout.write(data) - def errReceived(self, data): - sys.stderr.write(data) - def processEnded(self, status_object): - sig = status_object.value.signal - rc = status_object.value.exitCode - if sig != None or rc != 0: - self.d.errback(RuntimeError("remote 'buildbot tryserver' failed" - ": sig=%s, rc=%s" % (sig, rc))) - return - self.d.callback((sig, rc)) - -class BuildSetStatusGrabber: - retryCount = 5 # how many times to we try to grab the BuildSetStatus? - retryDelay = 3 # seconds to wait between attempts - - def __init__(self, status, bsid): - self.status = status - self.bsid = bsid - - def grab(self): - # return a Deferred that either fires with the BuildSetStatus - # reference or errbacks because we were unable to grab it - self.d = defer.Deferred() - # wait a second before querying to give the master's maildir watcher - # a chance to see the job - reactor.callLater(1, self.go) - return self.d - - def go(self, dummy=None): - if self.retryCount == 0: - raise RuntimeError("couldn't find matching buildset") - self.retryCount -= 1 - d = self.status.callRemote("getBuildSets") - d.addCallback(self._gotSets) - - def _gotSets(self, buildsets): - for bs,bsid in buildsets: - if bsid == self.bsid: - # got it - self.d.callback(bs) - return - d = defer.Deferred() - d.addCallback(self.go) - reactor.callLater(self.retryDelay, d.callback, None) - - -class Try(pb.Referenceable): - buildsetStatus = None - quiet = False - - def __init__(self, config): - self.config = config - self.opts = runner.loadOptions() - self.connect = self.getopt('connect', 'try_connect') - assert self.connect, "you must specify a connect style: ssh or pb" - self.builderNames = self.getopt('builders', 'try_builders') - assert self.builderNames, "no builders! use --builder or " \ - "try_builders=[names..] in .buildbot/options" - - def getopt(self, config_name, options_name, default=None): - value = self.config.get(config_name) - if value is None or value == []: - value = self.opts.get(options_name) - if value is None or value == []: - value = default - return value - - def createJob(self): - # returns a Deferred which fires when the job parameters have been - # created - opts = self.opts - # generate a random (unique) string. It would make sense to add a - # hostname and process ID here, but a) I suspect that would cause - # windows portability problems, and b) really this is good enough - self.bsid = "%d-%s" % (time.time(), random.randint(0, 1000000)) - - # common options - branch = self.getopt("branch", "try_branch") - - difffile = self.config.get("diff") - if difffile: - baserev = self.config.get("baserev") - if difffile == "-": - diff = sys.stdin.read() - else: - diff = open(difffile,"r").read() - patch = (self.config['patchlevel'], diff) - ss = SourceStamp(branch, baserev, patch) - d = defer.succeed(ss) - else: - vc = self.getopt("vc", "try_vc") - if vc in ("cvs", "svn"): - # we need to find the tree-top - topdir = self.getopt("try_topdir", "try_topdir") - if topdir: - treedir = os.path.expanduser(topdir) - else: - topfile = self.getopt("try-topfile", "try_topfile") - treedir = getTopdir(topfile) - else: - treedir = os.getcwd() - d = getSourceStamp(vc, treedir, branch) - d.addCallback(self._createJob_1) - return d - - def _createJob_1(self, ss): - self.sourcestamp = ss - if self.connect == "ssh": - patchlevel, diff = ss.patch - revspec = ss.revision - if revspec is None: - revspec = "" - self.jobfile = createJobfile(self.bsid, - ss.branch or "", revspec, - patchlevel, diff, - self.builderNames) - - def deliverJob(self): - # returns a Deferred that fires when the job has been delivered - opts = self.opts - - if self.connect == "ssh": - tryhost = self.getopt("tryhost", "try_host") - tryuser = self.getopt("username", "try_username") - trydir = self.getopt("trydir", "try_dir") - - argv = ["ssh", "-l", tryuser, tryhost, - "buildbot", "tryserver", "--jobdir", trydir] - # now run this command and feed the contents of 'job' into stdin - - pp = RemoteTryPP(self.jobfile) - p = reactor.spawnProcess(pp, argv[0], argv, os.environ) - d = pp.d - return d - if self.connect == "pb": - user = self.getopt("username", "try_username") - passwd = self.getopt("passwd", "try_password") - master = self.getopt("master", "try_master") - tryhost, tryport = master.split(":") - tryport = int(tryport) - f = pb.PBClientFactory() - d = f.login(credentials.UsernamePassword(user, passwd)) - reactor.connectTCP(tryhost, tryport, f) - d.addCallback(self._deliverJob_pb) - return d - raise RuntimeError("unknown connecttype '%s', should be 'ssh' or 'pb'" - % self.connect) - - def _deliverJob_pb(self, remote): - ss = self.sourcestamp - - d = remote.callRemote("try", - ss.branch, - ss.revision, - ss.patch, - self.builderNames, - self.config.get('properties', {})) - d.addCallback(self._deliverJob_pb2) - return d - def _deliverJob_pb2(self, status): - self.buildsetStatus = status - return status - - def getStatus(self): - # returns a Deferred that fires when the builds have finished, and - # may emit status messages while we wait - wait = bool(self.getopt("wait", "try_wait", False)) - if not wait: - # TODO: emit the URL where they can follow the builds. This - # requires contacting the Status server over PB and doing - # getURLForThing() on the BuildSetStatus. To get URLs for - # individual builds would require we wait for the builds to - # start. - print "not waiting for builds to finish" - return - d = self.running = defer.Deferred() - if self.buildsetStatus: - self._getStatus_1() - # contact the status port - # we're probably using the ssh style - master = self.getopt("master", "masterstatus") - host, port = master.split(":") - port = int(port) - self.announce("contacting the status port at %s:%d" % (host, port)) - f = pb.PBClientFactory() - creds = credentials.UsernamePassword("statusClient", "clientpw") - d = f.login(creds) - reactor.connectTCP(host, port, f) - d.addCallback(self._getStatus_ssh_1) - return self.running - - def _getStatus_ssh_1(self, remote): - # find a remotereference to the corresponding BuildSetStatus object - self.announce("waiting for job to be accepted") - g = BuildSetStatusGrabber(remote, self.bsid) - d = g.grab() - d.addCallback(self._getStatus_1) - return d - - def _getStatus_1(self, res=None): - if res: - self.buildsetStatus = res - # gather the set of BuildRequests - d = self.buildsetStatus.callRemote("getBuildRequests") - d.addCallback(self._getStatus_2) - - def _getStatus_2(self, brs): - self.builderNames = [] - self.buildRequests = {} - - # self.builds holds the current BuildStatus object for each one - self.builds = {} - - # self.outstanding holds the list of builderNames which haven't - # finished yet - self.outstanding = [] - - # self.results holds the list of build results. It holds a tuple of - # (result, text) - self.results = {} - - # self.currentStep holds the name of the Step that each build is - # currently running - self.currentStep = {} - - # self.ETA holds the expected finishing time (absolute time since - # epoch) - self.ETA = {} - - for n,br in brs: - self.builderNames.append(n) - self.buildRequests[n] = br - self.builds[n] = None - self.outstanding.append(n) - self.results[n] = [None,None] - self.currentStep[n] = None - self.ETA[n] = None - # get new Builds for this buildrequest. We follow each one until - # it finishes or is interrupted. - br.callRemote("subscribe", self) - - # now that those queries are in transit, we can start the - # display-status-every-30-seconds loop - self.printloop = task.LoopingCall(self.printStatus) - self.printloop.start(3, now=False) - - - # these methods are invoked by the status objects we've subscribed to - - def remote_newbuild(self, bs, builderName): - if self.builds[builderName]: - self.builds[builderName].callRemote("unsubscribe", self) - self.builds[builderName] = bs - bs.callRemote("subscribe", self, 20) - d = bs.callRemote("waitUntilFinished") - d.addCallback(self._build_finished, builderName) - - def remote_stepStarted(self, buildername, build, stepname, step): - self.currentStep[buildername] = stepname - - def remote_stepFinished(self, buildername, build, stepname, step, results): - pass - - def remote_buildETAUpdate(self, buildername, build, eta): - self.ETA[buildername] = now() + eta - - def _build_finished(self, bs, builderName): - # we need to collect status from the newly-finished build. We don't - # remove the build from self.outstanding until we've collected - # everything we want. - self.builds[builderName] = None - self.ETA[builderName] = None - self.currentStep[builderName] = "finished" - d = bs.callRemote("getResults") - d.addCallback(self._build_finished_2, bs, builderName) - return d - def _build_finished_2(self, results, bs, builderName): - self.results[builderName][0] = results - d = bs.callRemote("getText") - d.addCallback(self._build_finished_3, builderName) - return d - def _build_finished_3(self, text, builderName): - self.results[builderName][1] = text - - self.outstanding.remove(builderName) - if not self.outstanding: - # all done - return self.statusDone() - - def printStatus(self): - names = self.buildRequests.keys() - names.sort() - for n in names: - if n not in self.outstanding: - # the build is finished, and we have results - code,text = self.results[n] - t = builder.Results[code] - if text: - t += " (%s)" % " ".join(text) - elif self.builds[n]: - t = self.currentStep[n] or "building" - if self.ETA[n]: - t += " [ETA %ds]" % (self.ETA[n] - now()) - else: - t = "no build" - self.announce("%s: %s" % (n, t)) - self.announce("") - - def statusDone(self): - self.printloop.stop() - print "All Builds Complete" - # TODO: include a URL for all failing builds - names = self.buildRequests.keys() - names.sort() - happy = True - for n in names: - code,text = self.results[n] - t = "%s: %s" % (n, builder.Results[code]) - if text: - t += " (%s)" % " ".join(text) - print t - if self.results[n] != builder.SUCCESS: - happy = False - - if happy: - self.exitcode = 0 - else: - self.exitcode = 1 - self.running.callback(self.exitcode) - - def announce(self, message): - if not self.quiet: - print message - - def run(self): - # we can't do spawnProcess until we're inside reactor.run(), so get - # funky - print "using '%s' connect method" % self.connect - self.exitcode = 0 - d = defer.Deferred() - d.addCallback(lambda res: self.createJob()) - d.addCallback(lambda res: self.announce("job created")) - d.addCallback(lambda res: self.deliverJob()) - d.addCallback(lambda res: self.announce("job has been delivered")) - d.addCallback(lambda res: self.getStatus()) - d.addErrback(log.err) - d.addCallback(self.cleanup) - d.addCallback(lambda res: reactor.stop()) - - reactor.callLater(0, d.callback, None) - reactor.run() - sys.exit(self.exitcode) - - def logErr(self, why): - log.err(why) - print "error during 'try' processing" - print why - - def cleanup(self, res=None): - if self.buildsetStatus: - self.buildsetStatus.broker.transport.loseConnection() - - - diff --git a/tools/buildbot/pylibs/buildbot/slave/__init__.py b/tools/buildbot/pylibs/buildbot/slave/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tools/buildbot/pylibs/buildbot/slave/bot.py b/tools/buildbot/pylibs/buildbot/slave/bot.py deleted file mode 100644 index 444d211..0000000 --- a/tools/buildbot/pylibs/buildbot/slave/bot.py +++ /dev/null @@ -1,504 +0,0 @@ -import os.path - -import chromium_commands - -from twisted.spread import pb -from twisted.python import log -from twisted.internet import reactor, defer -from twisted.application import service, internet -from twisted.cred import credentials - -from buildbot.util import now -from buildbot.pbutil import ReconnectingPBClientFactory -from buildbot.slave import registry -# make sure the standard commands get registered. This import is performed -# for its side-effects. -from buildbot.slave import commands -# and make pyflakes think we aren't being stupid -commands = commands - -class NoCommandRunning(pb.Error): - pass -class WrongCommandRunning(pb.Error): - pass -class UnknownCommand(pb.Error): - pass - -class Master: - def __init__(self, host, port, username, password): - self.host = host - self.port = port - self.username = username - self.password = password - -class SlaveBuild: - - """This is an object that can hold state from one step to another in the - same build. All SlaveCommands have access to it. - """ - def __init__(self, builder): - self.builder = builder - -class SlaveBuilder(pb.Referenceable, service.Service): - - """This is the local representation of a single Builder: it handles a - single kind of build (like an all-warnings build). It has a name and a - home directory. The rest of its behavior is determined by the master. - """ - - stopCommandOnShutdown = True - - # remote is a ref to the Builder object on the master side, and is set - # when they attach. We use it to detect when the connection to the master - # is severed. - remote = None - - # .build points to a SlaveBuild object, a new one for each build - build = None - - # .command points to a SlaveCommand instance, and is set while the step - # is running. We use it to implement the stopBuild method. - command = None - - # .remoteStep is a ref to the master-side BuildStep object, and is set - # when the step is started - remoteStep = None - - def __init__(self, name, not_really): - #service.Service.__init__(self) # Service has no __init__ method - self.setName(name) - self.not_really = not_really - - def __repr__(self): - return "" % (self.name, id(self)) - - def setServiceParent(self, parent): - service.Service.setServiceParent(self, parent) - self.bot = self.parent - # note that self.parent will go away when the buildmaster's config - # file changes and this Builder is removed (possibly because it has - # been changed, so the Builder will be re-added again in a moment). - # This may occur during a build, while a step is running. - - def setBuilddir(self, builddir): - assert self.parent - self.builddir = builddir - self.basedir = os.path.join(self.bot.basedir, self.builddir) - if not os.path.isdir(self.basedir): - os.mkdir(self.basedir) - - def stopService(self): - service.Service.stopService(self) - if self.stopCommandOnShutdown: - self.stopCommand() - - def activity(self): - bot = self.parent - if bot: - buildslave = bot.parent - if buildslave: - bf = buildslave.bf - bf.activity() - - def remote_setMaster(self, remote): - self.remote = remote - self.remote.notifyOnDisconnect(self.lostRemote) - def remote_print(self, message): - log.msg("SlaveBuilder.remote_print(%s): message from master: %s" % - (self.name, message)) - if message == "ping": - return self.remote_ping() - - def remote_ping(self): - log.msg("SlaveBuilder.remote_ping(%s)" % self) - if self.bot and self.bot.parent: - debugOpts = self.bot.parent.debugOpts - if debugOpts.get("stallPings"): - log.msg(" debug_stallPings") - timeout, timers = debugOpts["stallPings"] - d = defer.Deferred() - t = reactor.callLater(timeout, d.callback, None) - timers.append(t) - return d - if debugOpts.get("failPingOnce"): - log.msg(" debug_failPingOnce") - class FailPingError(pb.Error): pass - del debugOpts['failPingOnce'] - raise FailPingError("debug_failPingOnce means we should fail") - - def lostRemote(self, remote): - log.msg("lost remote") - self.remote = None - - def lostRemoteStep(self, remotestep): - log.msg("lost remote step") - self.remoteStep = None - if self.stopCommandOnShutdown: - self.stopCommand() - - # the following are Commands that can be invoked by the master-side - # Builder - def remote_startBuild(self): - """This is invoked before the first step of any new build is run. It - creates a new SlaveBuild object, which holds slave-side state from - one step to the next.""" - self.build = SlaveBuild(self) - log.msg("%s.startBuild" % self) - - def remote_startCommand(self, stepref, stepId, command, args): - """ - This gets invoked by L{buildbot.process.step.RemoteCommand.start}, as - part of various master-side BuildSteps, to start various commands - that actually do the build. I return nothing. Eventually I will call - .commandComplete() to notify the master-side RemoteCommand that I'm - done. - """ - - self.activity() - - if self.command: - log.msg("leftover command, dropping it") - self.stopCommand() - - try: - factory, version = registry.commandRegistry[command] - except KeyError: - raise UnknownCommand, "unrecognized SlaveCommand '%s'" % command - self.command = factory(self, stepId, args) - - log.msg(" startCommand:%s [id %s]" % (command,stepId)) - self.remoteStep = stepref - self.remoteStep.notifyOnDisconnect(self.lostRemoteStep) - d = self.command.doStart() - d.addCallback(lambda res: None) - d.addBoth(self.commandComplete) - return None - - def remote_interruptCommand(self, stepId, why): - """Halt the current step.""" - log.msg("asked to interrupt current command: %s" % why) - self.activity() - if not self.command: - # TODO: just log it, a race could result in their interrupting a - # command that wasn't actually running - log.msg(" .. but none was running") - return - self.command.doInterrupt() - - - def stopCommand(self): - """Make any currently-running command die, with no further status - output. This is used when the buildslave is shutting down or the - connection to the master has been lost. Interrupt the command, - silence it, and then forget about it.""" - if not self.command: - return - log.msg("stopCommand: halting current command %s" % self.command) - self.command.doInterrupt() # shut up! and die! - self.command = None # forget you! - - # sendUpdate is invoked by the Commands we spawn - def sendUpdate(self, data): - """This sends the status update to the master-side - L{buildbot.process.step.RemoteCommand} object, giving it a sequence - number in the process. It adds the update to a queue, and asks the - master to acknowledge the update so it can be removed from that - queue.""" - - if not self.running: - # .running comes from service.Service, and says whether the - # service is running or not. If we aren't running, don't send any - # status messages. - return - # the update[1]=0 comes from the leftover 'updateNum', which the - # master still expects to receive. Provide it to avoid significant - # interoperability issues between new slaves and old masters. - if self.remoteStep: - update = [data, 0] - updates = [update] - d = self.remoteStep.callRemote("update", updates) - d.addCallback(self.ackUpdate) - d.addErrback(self._ackFailed, "SlaveBuilder.sendUpdate") - - def ackUpdate(self, acknum): - self.activity() # update the "last activity" timer - - def ackComplete(self, dummy): - self.activity() # update the "last activity" timer - - def _ackFailed(self, why, where): - log.msg("SlaveBuilder._ackFailed:", where) - #log.err(why) # we don't really care - - - # this is fired by the Deferred attached to each Command - def commandComplete(self, failure): - if failure: - log.msg("SlaveBuilder.commandFailed", self.command) - log.err(failure) - # failure, if present, is a failure.Failure. To send it across - # the wire, we must turn it into a pb.CopyableFailure. - failure = pb.CopyableFailure(failure) - failure.unsafeTracebacks = True - else: - # failure is None - log.msg("SlaveBuilder.commandComplete", self.command) - self.command = None - if not self.running: - log.msg(" but we weren't running, quitting silently") - return - if self.remoteStep: - self.remoteStep.dontNotifyOnDisconnect(self.lostRemoteStep) - d = self.remoteStep.callRemote("complete", failure) - d.addCallback(self.ackComplete) - d.addErrback(self._ackFailed, "sendComplete") - self.remoteStep = None - - - def remote_shutdown(self): - print "slave shutting down on command from master" - reactor.stop() - - -class Bot(pb.Referenceable, service.MultiService): - """I represent the slave-side bot.""" - usePTY = None - name = "bot" - - def __init__(self, basedir, usePTY, not_really=0): - service.MultiService.__init__(self) - self.basedir = basedir - self.usePTY = usePTY - self.not_really = not_really - self.builders = {} - - def startService(self): - assert os.path.isdir(self.basedir) - service.MultiService.startService(self) - - def remote_getDirs(self): - return filter(lambda d: os.path.isdir(d), os.listdir(self.basedir)) - - def remote_getCommands(self): - commands = {} - for name, (factory, version) in registry.commandRegistry.items(): - commands[name] = version - return commands - - def remote_setBuilderList(self, wanted): - retval = {} - wanted_dirs = ["info"] - for (name, builddir) in wanted: - wanted_dirs.append(builddir) - b = self.builders.get(name, None) - if b: - if b.builddir != builddir: - log.msg("changing builddir for builder %s from %s to %s" \ - % (name, b.builddir, builddir)) - b.setBuilddir(builddir) - else: - b = SlaveBuilder(name, self.not_really) - b.usePTY = self.usePTY - b.setServiceParent(self) - b.setBuilddir(builddir) - self.builders[name] = b - retval[name] = b - for name in self.builders.keys(): - if not name in map(lambda a: a[0], wanted): - log.msg("removing old builder %s" % name) - self.builders[name].disownServiceParent() - del(self.builders[name]) - - for d in os.listdir(self.basedir): - if os.path.isdir(d): - if d not in wanted_dirs: - log.msg("I have a leftover directory '%s' that is not " - "being used by the buildmaster: you can delete " - "it now" % d) - return retval - - def remote_print(self, message): - log.msg("message from master:", message) - - def remote_getSlaveInfo(self): - """This command retrieves data from the files in SLAVEDIR/info/* and - sends the contents to the buildmaster. These are used to describe - the slave and its configuration, and should be created and - maintained by the slave administrator. They will be retrieved each - time the master-slave connection is established. - """ - - files = {} - basedir = os.path.join(self.basedir, "info") - if not os.path.isdir(basedir): - return files - for f in os.listdir(basedir): - filename = os.path.join(basedir, f) - if os.path.isfile(filename): - files[f] = open(filename, "r").read() - return files - -class BotFactory(ReconnectingPBClientFactory): - # 'keepaliveInterval' serves two purposes. The first is to keep the - # connection alive: it guarantees that there will be at least some - # traffic once every 'keepaliveInterval' seconds, which may help keep an - # interposed NAT gateway from dropping the address mapping because it - # thinks the connection has been abandoned. The second is to put an upper - # limit on how long the buildmaster might have gone away before we notice - # it. For this second purpose, we insist upon seeing *some* evidence of - # the buildmaster at least once every 'keepaliveInterval' seconds. - keepaliveInterval = None # None = do not use keepalives - - # 'keepaliveTimeout' seconds before the interval expires, we will send a - # keepalive request, both to add some traffic to the connection, and to - # prompt a response from the master in case all our builders are idle. We - # don't insist upon receiving a timely response from this message: a slow - # link might put the request at the wrong end of a large build message. - keepaliveTimeout = 30 # how long we will go without a response - - keepaliveTimer = None - activityTimer = None - lastActivity = 0 - unsafeTracebacks = 1 - perspective = None - - def __init__(self, keepaliveInterval, keepaliveTimeout): - ReconnectingPBClientFactory.__init__(self) - self.keepaliveInterval = keepaliveInterval - self.keepaliveTimeout = keepaliveTimeout - - def startedConnecting(self, connector): - ReconnectingPBClientFactory.startedConnecting(self, connector) - self.connector = connector - - def gotPerspective(self, perspective): - ReconnectingPBClientFactory.gotPerspective(self, perspective) - self.perspective = perspective - try: - perspective.broker.transport.setTcpKeepAlive(1) - except: - log.msg("unable to set SO_KEEPALIVE") - if not self.keepaliveInterval: - self.keepaliveInterval = 10*60 - self.activity() - if self.keepaliveInterval: - log.msg("sending application-level keepalives every %d seconds" \ - % self.keepaliveInterval) - self.startTimers() - - def clientConnectionFailed(self, connector, reason): - self.connector = None - ReconnectingPBClientFactory.clientConnectionFailed(self, - connector, reason) - - def clientConnectionLost(self, connector, reason): - self.connector = None - self.stopTimers() - self.perspective = None - ReconnectingPBClientFactory.clientConnectionLost(self, - connector, reason) - - def startTimers(self): - assert self.keepaliveInterval - assert not self.keepaliveTimer - assert not self.activityTimer - # Insist that doKeepalive fires before checkActivity. Really, it - # needs to happen at least one RTT beforehand. - assert self.keepaliveInterval > self.keepaliveTimeout - - # arrange to send a keepalive a little while before our deadline - when = self.keepaliveInterval - self.keepaliveTimeout - self.keepaliveTimer = reactor.callLater(when, self.doKeepalive) - # and check for activity too - self.activityTimer = reactor.callLater(self.keepaliveInterval, - self.checkActivity) - - def stopTimers(self): - if self.keepaliveTimer: - self.keepaliveTimer.cancel() - self.keepaliveTimer = None - if self.activityTimer: - self.activityTimer.cancel() - self.activityTimer = None - - def activity(self, res=None): - self.lastActivity = now() - - def doKeepalive(self): - # send the keepalive request. If it fails outright, the connection - # was already dropped, so just log and ignore. - self.keepaliveTimer = None - log.msg("sending app-level keepalive") - d = self.perspective.callRemote("keepalive") - d.addCallback(self.activity) - d.addErrback(self.keepaliveLost) - - def keepaliveLost(self, f): - log.msg("BotFactory.keepaliveLost") - - def checkActivity(self): - self.activityTimer = None - if self.lastActivity + self.keepaliveInterval < now(): - log.msg("BotFactory.checkActivity: nothing from master for " - "%d secs" % (now() - self.lastActivity)) - self.perspective.broker.transport.loseConnection() - return - self.startTimers() - - def stopFactory(self): - ReconnectingPBClientFactory.stopFactory(self) - self.stopTimers() - - -class BuildSlave(service.MultiService): - botClass = Bot - - # debugOpts is a dictionary used during unit tests. - - # debugOpts['stallPings'] can be set to a tuple of (timeout, []). Any - # calls to remote_print will stall for 'timeout' seconds before - # returning. The DelayedCalls used to implement this are stashed in the - # list so they can be cancelled later. - - # debugOpts['failPingOnce'] can be set to True to make the slaveping fail - # exactly once. - - def __init__(self, buildmaster_host, port, name, passwd, basedir, - keepalive, usePTY, keepaliveTimeout=30, umask=None, - debugOpts={}): - log.msg("Creating BuildSlave") - service.MultiService.__init__(self) - self.debugOpts = debugOpts.copy() - bot = self.botClass(basedir, usePTY) - bot.setServiceParent(self) - self.bot = bot - if keepalive == 0: - keepalive = None - self.umask = umask - bf = self.bf = BotFactory(keepalive, keepaliveTimeout) - bf.startLogin(credentials.UsernamePassword(name, passwd), client=bot) - self.connection = c = internet.TCPClient(buildmaster_host, port, bf) - c.setServiceParent(self) - - def waitUntilDisconnected(self): - # utility method for testing. Returns a Deferred that will fire when - # we lose the connection to the master. - if not self.bf.perspective: - return defer.succeed(None) - d = defer.Deferred() - self.bf.perspective.notifyOnDisconnect(lambda res: d.callback(None)) - return d - - def startService(self): - if self.umask is not None: - os.umask(self.umask) - service.MultiService.startService(self) - - def stopService(self): - self.bf.continueTrying = 0 - self.bf.stopTrying() - service.MultiService.stopService(self) - # now kill the TCP connection - # twisted >2.0.1 does this for us, and leaves _connection=None - if self.connection._connection: - self.connection._connection.disconnect() diff --git a/tools/buildbot/pylibs/buildbot/slave/bot_orig.py b/tools/buildbot/pylibs/buildbot/slave/bot_orig.py deleted file mode 100644 index 8a3519f..0000000 --- a/tools/buildbot/pylibs/buildbot/slave/bot_orig.py +++ /dev/null @@ -1,503 +0,0 @@ - -import os.path - -from twisted.spread import pb -from twisted.python import log -from twisted.internet import reactor, defer -from twisted.application import service, internet -from twisted.cred import credentials - -from buildbot.util import now -from buildbot.pbutil import ReconnectingPBClientFactory -from buildbot.slave import registry -# make sure the standard commands get registered. This import is performed -# for its side-effects. -from buildbot.slave import commands -# and make pyflakes think we aren't being stupid -commands = commands - -class NoCommandRunning(pb.Error): - pass -class WrongCommandRunning(pb.Error): - pass -class UnknownCommand(pb.Error): - pass - -class Master: - def __init__(self, host, port, username, password): - self.host = host - self.port = port - self.username = username - self.password = password - -class SlaveBuild: - - """This is an object that can hold state from one step to another in the - same build. All SlaveCommands have access to it. - """ - def __init__(self, builder): - self.builder = builder - -class SlaveBuilder(pb.Referenceable, service.Service): - - """This is the local representation of a single Builder: it handles a - single kind of build (like an all-warnings build). It has a name and a - home directory. The rest of its behavior is determined by the master. - """ - - stopCommandOnShutdown = True - - # remote is a ref to the Builder object on the master side, and is set - # when they attach. We use it to detect when the connection to the master - # is severed. - remote = None - - # .build points to a SlaveBuild object, a new one for each build - build = None - - # .command points to a SlaveCommand instance, and is set while the step - # is running. We use it to implement the stopBuild method. - command = None - - # .remoteStep is a ref to the master-side BuildStep object, and is set - # when the step is started - remoteStep = None - - def __init__(self, name, not_really): - #service.Service.__init__(self) # Service has no __init__ method - self.setName(name) - self.not_really = not_really - - def __repr__(self): - return "" % (self.name, id(self)) - - def setServiceParent(self, parent): - service.Service.setServiceParent(self, parent) - self.bot = self.parent - # note that self.parent will go away when the buildmaster's config - # file changes and this Builder is removed (possibly because it has - # been changed, so the Builder will be re-added again in a moment). - # This may occur during a build, while a step is running. - - def setBuilddir(self, builddir): - assert self.parent - self.builddir = builddir - self.basedir = os.path.join(self.bot.basedir, self.builddir) - if not os.path.isdir(self.basedir): - os.mkdir(self.basedir) - - def stopService(self): - service.Service.stopService(self) - if self.stopCommandOnShutdown: - self.stopCommand() - - def activity(self): - bot = self.parent - if bot: - buildslave = bot.parent - if buildslave: - bf = buildslave.bf - bf.activity() - - def remote_setMaster(self, remote): - self.remote = remote - self.remote.notifyOnDisconnect(self.lostRemote) - def remote_print(self, message): - log.msg("SlaveBuilder.remote_print(%s): message from master: %s" % - (self.name, message)) - if message == "ping": - return self.remote_ping() - - def remote_ping(self): - log.msg("SlaveBuilder.remote_ping(%s)" % self) - if self.bot and self.bot.parent: - debugOpts = self.bot.parent.debugOpts - if debugOpts.get("stallPings"): - log.msg(" debug_stallPings") - timeout, timers = debugOpts["stallPings"] - d = defer.Deferred() - t = reactor.callLater(timeout, d.callback, None) - timers.append(t) - return d - if debugOpts.get("failPingOnce"): - log.msg(" debug_failPingOnce") - class FailPingError(pb.Error): pass - del debugOpts['failPingOnce'] - raise FailPingError("debug_failPingOnce means we should fail") - - def lostRemote(self, remote): - log.msg("lost remote") - self.remote = None - - def lostRemoteStep(self, remotestep): - log.msg("lost remote step") - self.remoteStep = None - if self.stopCommandOnShutdown: - self.stopCommand() - - # the following are Commands that can be invoked by the master-side - # Builder - def remote_startBuild(self): - """This is invoked before the first step of any new build is run. It - creates a new SlaveBuild object, which holds slave-side state from - one step to the next.""" - self.build = SlaveBuild(self) - log.msg("%s.startBuild" % self) - - def remote_startCommand(self, stepref, stepId, command, args): - """ - This gets invoked by L{buildbot.process.step.RemoteCommand.start}, as - part of various master-side BuildSteps, to start various commands - that actually do the build. I return nothing. Eventually I will call - .commandComplete() to notify the master-side RemoteCommand that I'm - done. - """ - - self.activity() - - if self.command: - log.msg("leftover command, dropping it") - self.stopCommand() - - try: - factory, version = registry.commandRegistry[command] - except KeyError: - raise UnknownCommand, "unrecognized SlaveCommand '%s'" % command - self.command = factory(self, stepId, args) - - log.msg(" startCommand:%s [id %s]" % (command,stepId)) - self.remoteStep = stepref - self.remoteStep.notifyOnDisconnect(self.lostRemoteStep) - d = self.command.doStart() - d.addCallback(lambda res: None) - d.addBoth(self.commandComplete) - return None - - def remote_interruptCommand(self, stepId, why): - """Halt the current step.""" - log.msg("asked to interrupt current command: %s" % why) - self.activity() - if not self.command: - # TODO: just log it, a race could result in their interrupting a - # command that wasn't actually running - log.msg(" .. but none was running") - return - self.command.doInterrupt() - - - def stopCommand(self): - """Make any currently-running command die, with no further status - output. This is used when the buildslave is shutting down or the - connection to the master has been lost. Interrupt the command, - silence it, and then forget about it.""" - if not self.command: - return - log.msg("stopCommand: halting current command %s" % self.command) - self.command.doInterrupt() # shut up! and die! - self.command = None # forget you! - - # sendUpdate is invoked by the Commands we spawn - def sendUpdate(self, data): - """This sends the status update to the master-side - L{buildbot.process.step.RemoteCommand} object, giving it a sequence - number in the process. It adds the update to a queue, and asks the - master to acknowledge the update so it can be removed from that - queue.""" - - if not self.running: - # .running comes from service.Service, and says whether the - # service is running or not. If we aren't running, don't send any - # status messages. - return - # the update[1]=0 comes from the leftover 'updateNum', which the - # master still expects to receive. Provide it to avoid significant - # interoperability issues between new slaves and old masters. - if self.remoteStep: - update = [data, 0] - updates = [update] - d = self.remoteStep.callRemote("update", updates) - d.addCallback(self.ackUpdate) - d.addErrback(self._ackFailed, "SlaveBuilder.sendUpdate") - - def ackUpdate(self, acknum): - self.activity() # update the "last activity" timer - - def ackComplete(self, dummy): - self.activity() # update the "last activity" timer - - def _ackFailed(self, why, where): - log.msg("SlaveBuilder._ackFailed:", where) - #log.err(why) # we don't really care - - - # this is fired by the Deferred attached to each Command - def commandComplete(self, failure): - if failure: - log.msg("SlaveBuilder.commandFailed", self.command) - log.err(failure) - # failure, if present, is a failure.Failure. To send it across - # the wire, we must turn it into a pb.CopyableFailure. - failure = pb.CopyableFailure(failure) - failure.unsafeTracebacks = True - else: - # failure is None - log.msg("SlaveBuilder.commandComplete", self.command) - self.command = None - if not self.running: - log.msg(" but we weren't running, quitting silently") - return - if self.remoteStep: - self.remoteStep.dontNotifyOnDisconnect(self.lostRemoteStep) - d = self.remoteStep.callRemote("complete", failure) - d.addCallback(self.ackComplete) - d.addErrback(self._ackFailed, "sendComplete") - self.remoteStep = None - - - def remote_shutdown(self): - print "slave shutting down on command from master" - reactor.stop() - - -class Bot(pb.Referenceable, service.MultiService): - """I represent the slave-side bot.""" - usePTY = None - name = "bot" - - def __init__(self, basedir, usePTY, not_really=0): - service.MultiService.__init__(self) - self.basedir = basedir - self.usePTY = usePTY - self.not_really = not_really - self.builders = {} - - def startService(self): - assert os.path.isdir(self.basedir) - service.MultiService.startService(self) - - def remote_getDirs(self): - return filter(lambda d: os.path.isdir(d), os.listdir(self.basedir)) - - def remote_getCommands(self): - commands = {} - for name, (factory, version) in registry.commandRegistry.items(): - commands[name] = version - return commands - - def remote_setBuilderList(self, wanted): - retval = {} - wanted_dirs = ["info"] - for (name, builddir) in wanted: - wanted_dirs.append(builddir) - b = self.builders.get(name, None) - if b: - if b.builddir != builddir: - log.msg("changing builddir for builder %s from %s to %s" \ - % (name, b.builddir, builddir)) - b.setBuilddir(builddir) - else: - b = SlaveBuilder(name, self.not_really) - b.usePTY = self.usePTY - b.setServiceParent(self) - b.setBuilddir(builddir) - self.builders[name] = b - retval[name] = b - for name in self.builders.keys(): - if not name in map(lambda a: a[0], wanted): - log.msg("removing old builder %s" % name) - self.builders[name].disownServiceParent() - del(self.builders[name]) - - for d in os.listdir(self.basedir): - if os.path.isdir(d): - if d not in wanted_dirs: - log.msg("I have a leftover directory '%s' that is not " - "being used by the buildmaster: you can delete " - "it now" % d) - return retval - - def remote_print(self, message): - log.msg("message from master:", message) - - def remote_getSlaveInfo(self): - """This command retrieves data from the files in SLAVEDIR/info/* and - sends the contents to the buildmaster. These are used to describe - the slave and its configuration, and should be created and - maintained by the slave administrator. They will be retrieved each - time the master-slave connection is established. - """ - - files = {} - basedir = os.path.join(self.basedir, "info") - if not os.path.isdir(basedir): - return files - for f in os.listdir(basedir): - filename = os.path.join(basedir, f) - if os.path.isfile(filename): - files[f] = open(filename, "r").read() - return files - -class BotFactory(ReconnectingPBClientFactory): - # 'keepaliveInterval' serves two purposes. The first is to keep the - # connection alive: it guarantees that there will be at least some - # traffic once every 'keepaliveInterval' seconds, which may help keep an - # interposed NAT gateway from dropping the address mapping because it - # thinks the connection has been abandoned. The second is to put an upper - # limit on how long the buildmaster might have gone away before we notice - # it. For this second purpose, we insist upon seeing *some* evidence of - # the buildmaster at least once every 'keepaliveInterval' seconds. - keepaliveInterval = None # None = do not use keepalives - - # 'keepaliveTimeout' seconds before the interval expires, we will send a - # keepalive request, both to add some traffic to the connection, and to - # prompt a response from the master in case all our builders are idle. We - # don't insist upon receiving a timely response from this message: a slow - # link might put the request at the wrong end of a large build message. - keepaliveTimeout = 30 # how long we will go without a response - - keepaliveTimer = None - activityTimer = None - lastActivity = 0 - unsafeTracebacks = 1 - perspective = None - - def __init__(self, keepaliveInterval, keepaliveTimeout): - ReconnectingPBClientFactory.__init__(self) - self.keepaliveInterval = keepaliveInterval - self.keepaliveTimeout = keepaliveTimeout - - def startedConnecting(self, connector): - ReconnectingPBClientFactory.startedConnecting(self, connector) - self.connector = connector - - def gotPerspective(self, perspective): - ReconnectingPBClientFactory.gotPerspective(self, perspective) - self.perspective = perspective - try: - perspective.broker.transport.setTcpKeepAlive(1) - except: - log.msg("unable to set SO_KEEPALIVE") - if not self.keepaliveInterval: - self.keepaliveInterval = 10*60 - self.activity() - if self.keepaliveInterval: - log.msg("sending application-level keepalives every %d seconds" \ - % self.keepaliveInterval) - self.startTimers() - - def clientConnectionFailed(self, connector, reason): - self.connector = None - ReconnectingPBClientFactory.clientConnectionFailed(self, - connector, reason) - - def clientConnectionLost(self, connector, reason): - self.connector = None - self.stopTimers() - self.perspective = None - ReconnectingPBClientFactory.clientConnectionLost(self, - connector, reason) - - def startTimers(self): - assert self.keepaliveInterval - assert not self.keepaliveTimer - assert not self.activityTimer - # Insist that doKeepalive fires before checkActivity. Really, it - # needs to happen at least one RTT beforehand. - assert self.keepaliveInterval > self.keepaliveTimeout - - # arrange to send a keepalive a little while before our deadline - when = self.keepaliveInterval - self.keepaliveTimeout - self.keepaliveTimer = reactor.callLater(when, self.doKeepalive) - # and check for activity too - self.activityTimer = reactor.callLater(self.keepaliveInterval, - self.checkActivity) - - def stopTimers(self): - if self.keepaliveTimer: - self.keepaliveTimer.cancel() - self.keepaliveTimer = None - if self.activityTimer: - self.activityTimer.cancel() - self.activityTimer = None - - def activity(self, res=None): - self.lastActivity = now() - - def doKeepalive(self): - # send the keepalive request. If it fails outright, the connection - # was already dropped, so just log and ignore. - self.keepaliveTimer = None - log.msg("sending app-level keepalive") - d = self.perspective.callRemote("keepalive") - d.addCallback(self.activity) - d.addErrback(self.keepaliveLost) - - def keepaliveLost(self, f): - log.msg("BotFactory.keepaliveLost") - - def checkActivity(self): - self.activityTimer = None - if self.lastActivity + self.keepaliveInterval < now(): - log.msg("BotFactory.checkActivity: nothing from master for " - "%d secs" % (now() - self.lastActivity)) - self.perspective.broker.transport.loseConnection() - return - self.startTimers() - - def stopFactory(self): - ReconnectingPBClientFactory.stopFactory(self) - self.stopTimers() - - -class BuildSlave(service.MultiService): - botClass = Bot - - # debugOpts is a dictionary used during unit tests. - - # debugOpts['stallPings'] can be set to a tuple of (timeout, []). Any - # calls to remote_print will stall for 'timeout' seconds before - # returning. The DelayedCalls used to implement this are stashed in the - # list so they can be cancelled later. - - # debugOpts['failPingOnce'] can be set to True to make the slaveping fail - # exactly once. - - def __init__(self, buildmaster_host, port, name, passwd, basedir, - keepalive, usePTY, keepaliveTimeout=30, umask=None, - debugOpts={}): - log.msg("Creating BuildSlave") - service.MultiService.__init__(self) - self.debugOpts = debugOpts.copy() - bot = self.botClass(basedir, usePTY) - bot.setServiceParent(self) - self.bot = bot - if keepalive == 0: - keepalive = None - self.umask = umask - bf = self.bf = BotFactory(keepalive, keepaliveTimeout) - bf.startLogin(credentials.UsernamePassword(name, passwd), client=bot) - self.connection = c = internet.TCPClient(buildmaster_host, port, bf) - c.setServiceParent(self) - - def waitUntilDisconnected(self): - # utility method for testing. Returns a Deferred that will fire when - # we lose the connection to the master. - if not self.bf.perspective: - return defer.succeed(None) - d = defer.Deferred() - self.bf.perspective.notifyOnDisconnect(lambda res: d.callback(None)) - return d - - def startService(self): - if self.umask is not None: - os.umask(self.umask) - service.MultiService.startService(self) - - def stopService(self): - self.bf.continueTrying = 0 - self.bf.stopTrying() - service.MultiService.stopService(self) - # now kill the TCP connection - # twisted >2.0.1 does this for us, and leaves _connection=None - if self.connection._connection: - self.connection._connection.disconnect() diff --git a/tools/buildbot/pylibs/buildbot/slave/commands.py b/tools/buildbot/pylibs/buildbot/slave/commands.py deleted file mode 100644 index 87c7928..0000000 --- a/tools/buildbot/pylibs/buildbot/slave/commands.py +++ /dev/null @@ -1,2508 +0,0 @@ -# -*- test-case-name: buildbot.test.test_slavecommand -*- - -import os, re, signal, shutil, types, time -from stat import ST_CTIME, ST_MTIME, ST_SIZE - -from zope.interface import implements -from twisted.internet.protocol import ProcessProtocol -from twisted.internet import reactor, defer, task -from twisted.python import log, failure, runtime -from twisted.python.procutils import which - -from buildbot.slave.interfaces import ISlaveCommand -from buildbot.slave.registry import registerSlaveCommand - -# this used to be a CVS $-style "Revision" auto-updated keyword, but since I -# moved to Darcs as the primary repository, this is updated manually each -# time this file is changed. The last cvs_ver that was here was 1.51 . -command_version = "2.5" - -# version history: -# >=1.17: commands are interruptable -# >=1.28: Arch understands 'revision', added Bazaar -# >=1.33: Source classes understand 'retry' -# >=1.39: Source classes correctly handle changes in branch (except Git) -# Darcs accepts 'revision' (now all do but Git) (well, and P4Sync) -# Arch/Baz should accept 'build-config' -# >=1.51: (release 0.7.3) -# >= 2.1: SlaveShellCommand now accepts 'initial_stdin', 'keep_stdin_open', -# and 'logfiles'. It now sends 'log' messages in addition to -# stdout/stdin/header/rc. It acquired writeStdin/closeStdin methods, -# but these are not remotely callable yet. -# (not externally visible: ShellCommandPP has writeStdin/closeStdin. -# ShellCommand accepts new arguments (logfiles=, initialStdin=, -# keepStdinOpen=) and no longer accepts stdin=) -# (release 0.7.4) -# >= 2.2: added monotone, uploadFile, and downloadFile (release 0.7.5) -# >= 2.3: added bzr (release 0.7.6) -# >= 2.4: Git understands 'revision' and branches -# >= 2.5: workaround added for remote 'hg clone --rev REV' when hg<0.9.2 - -class CommandInterrupted(Exception): - pass -class TimeoutError(Exception): - pass - -class AbandonChain(Exception): - """A series of chained steps can raise this exception to indicate that - one of the intermediate ShellCommands has failed, such that there is no - point in running the remainder. 'rc' should be the non-zero exit code of - the failing ShellCommand.""" - - def __repr__(self): - return "" % self.args[0] - -def getCommand(name): - possibles = which(name) - if not possibles: - raise RuntimeError("Couldn't find executable for '%s'" % name) - return possibles[0] - -def rmdirRecursive(dir): - """This is a replacement for shutil.rmtree that works better under - windows. Thanks to Bear at the OSAF for the code.""" - if not os.path.exists(dir): - return - - if os.path.islink(dir): - os.remove(dir) - return - - # Verify the directory is read/write/execute for the current user - os.chmod(dir, 0700) - - for name in os.listdir(dir): - full_name = os.path.join(dir, name) - # on Windows, if we don't have write permission we can't remove - # the file/directory either, so turn that on - if os.name == 'nt': - if not os.access(full_name, os.W_OK): - # I think this is now redundant, but I don't have an NT - # machine to test on, so I'm going to leave it in place - # -warner - os.chmod(full_name, 0600) - - if os.path.isdir(full_name): - rmdirRecursive(full_name) - else: - os.chmod(full_name, 0700) - os.remove(full_name) - os.rmdir(dir) - -class ShellCommandPP(ProcessProtocol): - debug = False - - def __init__(self, command): - self.command = command - self.pending_stdin = "" - self.stdin_finished = False - - def writeStdin(self, data): - assert not self.stdin_finished - if self.connected: - self.transport.write(data) - else: - self.pending_stdin += data - - def closeStdin(self): - if self.connected: - if self.debug: log.msg(" closing stdin") - self.transport.closeStdin() - self.stdin_finished = True - - def connectionMade(self): - if self.debug: - log.msg("ShellCommandPP.connectionMade") - if not self.command.process: - if self.debug: - log.msg(" assigning self.command.process: %s" % - (self.transport,)) - self.command.process = self.transport - - # TODO: maybe we shouldn't close stdin when using a PTY. I can't test - # this yet, recent debian glibc has a bug which causes thread-using - # test cases to SIGHUP trial, and the workaround is to either run - # the whole test with /bin/sh -c " ".join(argv) (way gross) or to - # not use a PTY. Once the bug is fixed, I'll be able to test what - # happens when you close stdin on a pty. My concern is that it will - # SIGHUP the child (since we are, in a sense, hanging up on them). - # But it may well be that keeping stdout open prevents the SIGHUP - # from being sent. - #if not self.command.usePTY: - - if self.pending_stdin: - if self.debug: log.msg(" writing to stdin") - self.transport.write(self.pending_stdin) - if self.stdin_finished: - if self.debug: log.msg(" closing stdin") - self.transport.closeStdin() - - def outReceived(self, data): - if self.debug: - log.msg("ShellCommandPP.outReceived") - self.command.addStdout(data) - - def errReceived(self, data): - if self.debug: - log.msg("ShellCommandPP.errReceived") - self.command.addStderr(data) - - def processEnded(self, status_object): - if self.debug: - log.msg("ShellCommandPP.processEnded", status_object) - # status_object is a Failure wrapped around an - # error.ProcessTerminated or and error.ProcessDone. - # requires twisted >= 1.0.4 to overcome a bug in process.py - sig = status_object.value.signal - rc = status_object.value.exitCode - self.command.finished(sig, rc) - -class LogFileWatcher: - POLL_INTERVAL = 2 - - def __init__(self, command, name, logfile): - self.command = command - self.name = name - self.logfile = logfile - log.msg("LogFileWatcher created to watch %s" % logfile) - # we are created before the ShellCommand starts. If the logfile we're - # supposed to be watching already exists, record its size and - # ctime/mtime so we can tell when it starts to change. - self.old_logfile_stats = self.statFile() - self.started = False - - # every 2 seconds we check on the file again - self.poller = task.LoopingCall(self.poll) - - def start(self): - self.poller.start(self.POLL_INTERVAL).addErrback(self._cleanupPoll) - - def _cleanupPoll(self, err): - log.err(err, msg="Polling error") - self.poller = None - - def stop(self): - self.poll() - if self.poller is not None: - self.poller.stop() - if self.started: - self.f.close() - - def statFile(self): - if os.path.exists(self.logfile): - s = os.stat(self.logfile) - return (s[ST_CTIME], s[ST_MTIME], s[ST_SIZE]) - return None - - def poll(self): - if not self.started: - s = self.statFile() - if s == self.old_logfile_stats: - return # not started yet - if not s: - # the file was there, but now it's deleted. Forget about the - # initial state, clearly the process has deleted the logfile - # in preparation for creating a new one. - self.old_logfile_stats = None - return # no file to work with - self.f = open(self.logfile, "rb") - self.started = True - self.f.seek(self.f.tell(), 0) - while True: - data = self.f.read(10000) - if not data: - return - self.command.addLogfile(self.name, data) - - -class ShellCommand: - # This is a helper class, used by SlaveCommands to run programs in a - # child shell. - - notreally = False - BACKUP_TIMEOUT = 5 - KILL = "KILL" - CHUNK_LIMIT = 128*1024 - - def __init__(self, builder, command, - workdir, environ=None, - sendStdout=True, sendStderr=True, sendRC=True, - timeout=None, initialStdin=None, keepStdinOpen=False, - keepStdout=False, keepStderr=False, - logfiles={}): - """ - - @param keepStdout: if True, we keep a copy of all the stdout text - that we've seen. This copy is available in - self.stdout, which can be read after the command - has finished. - @param keepStderr: same, for stderr - - """ - - self.builder = builder - self.command = command - self.sendStdout = sendStdout - self.sendStderr = sendStderr - self.sendRC = sendRC - self.logfiles = logfiles - self.workdir = workdir - self.environ = os.environ.copy() - if environ: - if environ.has_key('PYTHONPATH'): - ppath = environ['PYTHONPATH'] - # Need to do os.pathsep translation. We could either do that - # by replacing all incoming ':'s with os.pathsep, or by - # accepting lists. I like lists better. - if not isinstance(ppath, str): - # If it's not a string, treat it as a sequence to be - # turned in to a string. - ppath = os.pathsep.join(ppath) - - if self.environ.has_key('PYTHONPATH'): - # special case, prepend the builder's items to the - # existing ones. This will break if you send over empty - # strings, so don't do that. - ppath = ppath + os.pathsep + self.environ['PYTHONPATH'] - - environ['PYTHONPATH'] = ppath - - self.environ.update(environ) - self.initialStdin = initialStdin - self.keepStdinOpen = keepStdinOpen - self.timeout = timeout - self.timer = None - self.keepStdout = keepStdout - self.keepStderr = keepStderr - - # usePTY=True is a convenience for cleaning up all children and - # grandchildren of a hung command. Fall back to usePTY=False on - # systems where ptys cause problems. - - self.usePTY = self.builder.usePTY - if runtime.platformType != "posix": - self.usePTY = False # PTYs are posix-only - if initialStdin is not None: - # for .closeStdin to matter, we must use a pipe, not a PTY - self.usePTY = False - - self.logFileWatchers = [] - for name,filename in self.logfiles.items(): - w = LogFileWatcher(self, name, - os.path.join(self.workdir, filename)) - self.logFileWatchers.append(w) - - def __repr__(self): - return "" % self.command - - def sendStatus(self, status): - self.builder.sendUpdate(status) - - def start(self): - # return a Deferred which fires (with the exit code) when the command - # completes - if self.keepStdout: - self.stdout = "" - if self.keepStderr: - self.stderr = "" - self.deferred = defer.Deferred() - try: - self._startCommand() - except: - log.msg("error in ShellCommand._startCommand") - log.err() - # pretend it was a shell error - self.deferred.errback(AbandonChain(-1)) - return self.deferred - - def _startCommand(self): - # ensure workdir exists - if not os.path.isdir(self.workdir): - os.makedirs(self.workdir) - log.msg("ShellCommand._startCommand") - if self.notreally: - self.sendStatus({'header': "command '%s' in dir %s" % \ - (self.command, self.workdir)}) - self.sendStatus({'header': "(not really)\n"}) - self.finished(None, 0) - return - - self.pp = ShellCommandPP(self) - - if type(self.command) in types.StringTypes: - if runtime.platformType == 'win32': - argv = [os.environ['COMSPEC'], '/c', self.command] - else: - # for posix, use /bin/sh. for other non-posix, well, doesn't - # hurt to try - argv = ['/bin/sh', '-c', self.command] - else: - if runtime.platformType == 'win32': - argv = [os.environ['COMSPEC'], '/c'] + list(self.command) - else: - argv = self.command - - # self.stdin is handled in ShellCommandPP.connectionMade - - # first header line is the command in plain text, argv joined with - # spaces. You should be able to cut-and-paste this into a shell to - # obtain the same results. If there are spaces in the arguments, too - # bad. - msg = " ".join(argv) - log.msg(" " + msg) - self.sendStatus({'header': msg+"\n"}) - - # then comes the secondary information - msg = " in dir %s" % (self.workdir,) - if self.timeout: - msg += " (timeout %d secs)" % (self.timeout,) - log.msg(" " + msg) - self.sendStatus({'header': msg+"\n"}) - - msg = " watching logfiles %s" % (self.logfiles,) - log.msg(" " + msg) - self.sendStatus({'header': msg+"\n"}) - - # then the argv array for resolving unambiguity - msg = " argv: %s" % (argv,) - log.msg(" " + msg) - self.sendStatus({'header': msg+"\n"}) - - # then the environment, since it sometimes causes problems - msg = " environment:\n" - env_names = self.environ.keys() - env_names.sort() - for name in env_names: - msg += " %s=%s\n" % (name, self.environ[name]) - log.msg(" environment: %s" % (self.environ,)) - self.sendStatus({'header': msg}) - - if self.initialStdin: - msg = " writing %d bytes to stdin" % len(self.initialStdin) - log.msg(" " + msg) - self.sendStatus({'header': msg+"\n"}) - - if self.keepStdinOpen: - msg = " leaving stdin open" - else: - msg = " closing stdin" - log.msg(" " + msg) - self.sendStatus({'header': msg+"\n"}) - - msg = " using PTY: %s" % bool(self.usePTY) - log.msg(" " + msg) - self.sendStatus({'header': msg+"\n"}) - - # this will be buffered until connectionMade is called - if self.initialStdin: - self.pp.writeStdin(self.initialStdin) - if not self.keepStdinOpen: - self.pp.closeStdin() - - # win32eventreactor's spawnProcess (under twisted <= 2.0.1) returns - # None, as opposed to all the posixbase-derived reactors (which - # return the new Process object). This is a nuisance. We can make up - # for it by having the ProcessProtocol give us their .transport - # attribute after they get one. I'd prefer to get it from - # spawnProcess because I'm concerned about returning from this method - # without having a valid self.process to work with. (if kill() were - # called right after we return, but somehow before connectionMade - # were called, then kill() would blow up). - self.process = None - p = reactor.spawnProcess(self.pp, argv[0], argv, - self.environ, - self.workdir, - usePTY=self.usePTY) - # connectionMade might have been called during spawnProcess - if not self.process: - self.process = p - - # connectionMade also closes stdin as long as we're not using a PTY. - # This is intended to kill off inappropriately interactive commands - # better than the (long) hung-command timeout. ProcessPTY should be - # enhanced to allow the same childFDs argument that Process takes, - # which would let us connect stdin to /dev/null . - - if self.timeout: - self.timer = reactor.callLater(self.timeout, self.doTimeout) - - for w in self.logFileWatchers: - w.start() - - - def _chunkForSend(self, data): - # limit the chunks that we send over PB to 128k, since it has a - # hardwired string-size limit of 640k. - LIMIT = self.CHUNK_LIMIT - for i in range(0, len(data), LIMIT): - yield data[i:i+LIMIT] - - def addStdout(self, data): - if self.sendStdout: - for chunk in self._chunkForSend(data): - self.sendStatus({'stdout': chunk}) - if self.keepStdout: - self.stdout += data - if self.timer: - self.timer.reset(self.timeout) - - def addStderr(self, data): - if self.sendStderr: - for chunk in self._chunkForSend(data): - self.sendStatus({'stderr': chunk}) - if self.keepStderr: - self.stderr += data - if self.timer: - self.timer.reset(self.timeout) - - def addLogfile(self, name, data): - for chunk in self._chunkForSend(data): - self.sendStatus({'log': (name, chunk)}) - if self.timer: - self.timer.reset(self.timeout) - - def finished(self, sig, rc): - log.msg("command finished with signal %s, exit code %s" % (sig,rc)) - for w in self.logFileWatchers: - # this will send the final updates - w.stop() - if sig is not None: - rc = -1 - if self.sendRC: - if sig is not None: - self.sendStatus( - {'header': "process killed by signal %d\n" % sig}) - self.sendStatus({'rc': rc}) - if self.timer: - self.timer.cancel() - self.timer = None - d = self.deferred - self.deferred = None - if d: - d.callback(rc) - else: - log.msg("Hey, command %s finished twice" % self) - - def failed(self, why): - log.msg("ShellCommand.failed: command failed: %s" % (why,)) - if self.timer: - self.timer.cancel() - self.timer = None - d = self.deferred - self.deferred = None - if d: - d.errback(why) - else: - log.msg("Hey, command %s finished twice" % self) - - def doTimeout(self): - self.timer = None - msg = "command timed out: %d seconds without output" % self.timeout - self.kill(msg) - - def kill(self, msg): - # This may be called by the timeout, or when the user has decided to - # abort this build. - if self.timer: - self.timer.cancel() - self.timer = None - if hasattr(self.process, "pid"): - msg += ", killing pid %d" % self.process.pid - log.msg(msg) - self.sendStatus({'header': "\n" + msg + "\n"}) - - hit = 0 - if runtime.platformType == "posix": - try: - # really want to kill off all child processes too. Process - # Groups are ideal for this, but that requires - # spawnProcess(usePTY=1). Try both ways in case process was - # not started that way. - - # the test suite sets self.KILL=None to tell us we should - # only pretend to kill the child. This lets us test the - # backup timer. - - sig = None - if self.KILL is not None: - sig = getattr(signal, "SIG"+ self.KILL, None) - - if self.KILL == None: - log.msg("self.KILL==None, only pretending to kill child") - elif sig is None: - log.msg("signal module is missing SIG%s" % self.KILL) - elif not hasattr(os, "kill"): - log.msg("os module is missing the 'kill' function") - else: - log.msg("trying os.kill(-pid, %d)" % (sig,)) - # TODO: maybe use os.killpg instead of a negative pid? - os.kill(-self.process.pid, sig) - log.msg(" signal %s sent successfully" % sig) - hit = 1 - except OSError: - # probably no-such-process, maybe because there is no process - # group - pass - if not hit: - try: - if self.KILL is None: - log.msg("self.KILL==None, only pretending to kill child") - else: - log.msg("trying process.signalProcess('KILL')") - self.process.signalProcess(self.KILL) - log.msg(" signal %s sent successfully" % (self.KILL,)) - hit = 1 - except OSError: - # could be no-such-process, because they finished very recently - pass - if not hit: - log.msg("signalProcess/os.kill failed both times") - - if runtime.platformType == "posix": - # we only do this under posix because the win32eventreactor - # blocks here until the process has terminated, while closing - # stderr. This is weird. - self.pp.transport.loseConnection() - - # finished ought to be called momentarily. Just in case it doesn't, - # set a timer which will abandon the command. - self.timer = reactor.callLater(self.BACKUP_TIMEOUT, - self.doBackupTimeout) - - def doBackupTimeout(self): - log.msg("we tried to kill the process, and it wouldn't die.." - " finish anyway") - self.timer = None - self.sendStatus({'header': "SIGKILL failed to kill process\n"}) - if self.sendRC: - self.sendStatus({'header': "using fake rc=-1\n"}) - self.sendStatus({'rc': -1}) - self.failed(TimeoutError("SIGKILL failed to kill process")) - - - def writeStdin(self, data): - self.pp.writeStdin(data) - - def closeStdin(self): - self.pp.closeStdin() - - -class Command: - implements(ISlaveCommand) - - """This class defines one command that can be invoked by the build master. - The command is executed on the slave side, and always sends back a - completion message when it finishes. It may also send intermediate status - as it runs (by calling builder.sendStatus). Some commands can be - interrupted (either by the build master or a local timeout), in which - case the step is expected to complete normally with a status message that - indicates an error occurred. - - These commands are used by BuildSteps on the master side. Each kind of - BuildStep uses a single Command. The slave must implement all the - Commands required by the set of BuildSteps used for any given build: - this is checked at startup time. - - All Commands are constructed with the same signature: - c = CommandClass(builder, args) - where 'builder' is the parent SlaveBuilder object, and 'args' is a - dict that is interpreted per-command. - - The setup(args) method is available for setup, and is run from __init__. - - The Command is started with start(). This method must be implemented in a - subclass, and it should return a Deferred. When your step is done, you - should fire the Deferred (the results are not used). If the command is - interrupted, it should fire the Deferred anyway. - - While the command runs. it may send status messages back to the - buildmaster by calling self.sendStatus(statusdict). The statusdict is - interpreted by the master-side BuildStep however it likes. - - A separate completion message is sent when the deferred fires, which - indicates that the Command has finished, but does not carry any status - data. If the Command needs to return an exit code of some sort, that - should be sent as a regular status message before the deferred is fired . - Once builder.commandComplete has been run, no more status messages may be - sent. - - If interrupt() is called, the Command should attempt to shut down as - quickly as possible. Child processes should be killed, new ones should - not be started. The Command should send some kind of error status update, - then complete as usual by firing the Deferred. - - .interrupted should be set by interrupt(), and can be tested to avoid - sending multiple error status messages. - - If .running is False, the bot is shutting down (or has otherwise lost the - connection to the master), and should not send any status messages. This - is checked in Command.sendStatus . - - """ - - # builder methods: - # sendStatus(dict) (zero or more) - # commandComplete() or commandInterrupted() (one, at end) - - debug = False - interrupted = False - running = False # set by Builder, cleared on shutdown or when the - # Deferred fires - - def __init__(self, builder, stepId, args): - self.builder = builder - self.stepId = stepId # just for logging - self.args = args - self.setup(args) - - def setup(self, args): - """Override this in a subclass to extract items from the args dict.""" - pass - - def doStart(self): - self.running = True - d = defer.maybeDeferred(self.start) - d.addBoth(self.commandComplete) - return d - - def start(self): - """Start the command. This method should return a Deferred that will - fire when the command has completed. The Deferred's argument will be - ignored. - - This method should be overridden by subclasses.""" - raise NotImplementedError, "You must implement this in a subclass" - - def sendStatus(self, status): - """Send a status update to the master.""" - if self.debug: - log.msg("sendStatus", status) - if not self.running: - log.msg("would sendStatus but not .running") - return - self.builder.sendUpdate(status) - - def doInterrupt(self): - self.running = False - self.interrupt() - - def interrupt(self): - """Override this in a subclass to allow commands to be interrupted. - May be called multiple times, test and set self.interrupted=True if - this matters.""" - pass - - def commandComplete(self, res): - self.running = False - return res - - # utility methods, mostly used by SlaveShellCommand and the like - - def _abandonOnFailure(self, rc): - if type(rc) is not int: - log.msg("weird, _abandonOnFailure was given rc=%s (%s)" % \ - (rc, type(rc))) - assert isinstance(rc, int) - if rc != 0: - raise AbandonChain(rc) - return rc - - def _sendRC(self, res): - self.sendStatus({'rc': 0}) - - def _checkAbandoned(self, why): - log.msg("_checkAbandoned", why) - why.trap(AbandonChain) - log.msg(" abandoning chain", why.value) - self.sendStatus({'rc': why.value.args[0]}) - return None - - - -class SlaveFileUploadCommand(Command): - """ - Upload a file from slave to build master - Arguments: - - - ['workdir']: base directory to use - - ['slavesrc']: name of the slave-side file to read from - - ['writer']: RemoteReference to a transfer._FileWriter object - - ['maxsize']: max size (in bytes) of file to write - - ['blocksize']: max size for each data block - """ - debug = False - - def setup(self, args): - self.workdir = args['workdir'] - self.filename = args['slavesrc'] - self.writer = args['writer'] - self.remaining = args['maxsize'] - self.blocksize = args['blocksize'] - self.stderr = None - self.rc = 0 - - def start(self): - if self.debug: - log.msg('SlaveFileUploadCommand started') - - # Open file - self.path = os.path.join(self.builder.basedir, - self.workdir, - os.path.expanduser(self.filename)) - try: - self.fp = open(self.path, 'rb') - if self.debug: - log.msg('Opened %r for upload' % self.path) - except: - # TODO: this needs cleanup - self.fp = None - self.stderr = 'Cannot open file %r for upload' % self.path - self.rc = 1 - if self.debug: - log.msg('Cannot open file %r for upload' % self.path) - - self.sendStatus({'header': "sending %s" % self.path}) - - d = defer.Deferred() - reactor.callLater(0, self._loop, d) - def _close(res): - # close the file, but pass through any errors from _loop - d1 = self.writer.callRemote("close") - d1.addErrback(log.err) - d1.addCallback(lambda ignored: res) - return d1 - d.addBoth(_close) - d.addBoth(self.finished) - return d - - def _loop(self, fire_when_done): - d = defer.maybeDeferred(self._writeBlock) - def _done(finished): - if finished: - fire_when_done.callback(None) - else: - self._loop(fire_when_done) - def _err(why): - fire_when_done.errback(why) - d.addCallbacks(_done, _err) - return None - - def _writeBlock(self): - """Write a block of data to the remote writer""" - - if self.interrupted or self.fp is None: - if self.debug: - log.msg('SlaveFileUploadCommand._writeBlock(): end') - return True - - length = self.blocksize - if self.remaining is not None and length > self.remaining: - length = self.remaining - - if length <= 0: - if self.stderr is None: - self.stderr = 'Maximum filesize reached, truncating file %r' \ - % self.path - self.rc = 1 - data = '' - else: - data = self.fp.read(length) - - if self.debug: - log.msg('SlaveFileUploadCommand._writeBlock(): '+ - 'allowed=%d readlen=%d' % (length, len(data))) - if len(data) == 0: - log.msg("EOF: callRemote(close)") - return True - - if self.remaining is not None: - self.remaining = self.remaining - len(data) - assert self.remaining >= 0 - d = self.writer.callRemote('write', data) - d.addCallback(lambda res: False) - return d - - def interrupt(self): - if self.debug: - log.msg('interrupted') - if self.interrupted: - return - if self.stderr is None: - self.stderr = 'Upload of %r interrupted' % self.path - self.rc = 1 - self.interrupted = True - # the next _writeBlock call will notice the .interrupted flag - - def finished(self, res): - if self.debug: - log.msg('finished: stderr=%r, rc=%r' % (self.stderr, self.rc)) - if self.stderr is None: - self.sendStatus({'rc': self.rc}) - else: - self.sendStatus({'stderr': self.stderr, 'rc': self.rc}) - return res - -registerSlaveCommand("uploadFile", SlaveFileUploadCommand, command_version) - - -class SlaveFileDownloadCommand(Command): - """ - Download a file from master to slave - Arguments: - - - ['workdir']: base directory to use - - ['slavedest']: name of the slave-side file to be created - - ['reader']: RemoteReference to a transfer._FileReader object - - ['maxsize']: max size (in bytes) of file to write - - ['blocksize']: max size for each data block - - ['mode']: access mode for the new file - """ - debug = False - - def setup(self, args): - self.workdir = args['workdir'] - self.filename = args['slavedest'] - self.reader = args['reader'] - self.bytes_remaining = args['maxsize'] - self.blocksize = args['blocksize'] - self.mode = args['mode'] - self.stderr = None - self.rc = 0 - - def start(self): - if self.debug: - log.msg('SlaveFileDownloadCommand starting') - - # Open file - self.path = os.path.join(self.builder.basedir, - self.workdir, - os.path.expanduser(self.filename)) - try: - self.fp = open(self.path, 'wb') - if self.debug: - log.msg('Opened %r for download' % self.path) - if self.mode is not None: - # note: there is a brief window during which the new file - # will have the buildslave's default (umask) mode before we - # set the new one. Don't use this mode= feature to keep files - # private: use the buildslave's umask for that instead. (it - # is possible to call os.umask() before and after the open() - # call, but cleaning up from exceptions properly is more of a - # nuisance that way). - os.chmod(self.path, self.mode) - except IOError: - # TODO: this still needs cleanup - self.fp = None - self.stderr = 'Cannot open file %r for download' % self.path - self.rc = 1 - if self.debug: - log.msg('Cannot open file %r for download' % self.path) - - d = defer.Deferred() - reactor.callLater(0, self._loop, d) - def _close(res): - # close the file, but pass through any errors from _loop - d1 = self.reader.callRemote('close') - d1.addErrback(log.err) - d1.addCallback(lambda ignored: res) - return d1 - d.addBoth(_close) - d.addBoth(self.finished) - return d - - def _loop(self, fire_when_done): - d = defer.maybeDeferred(self._readBlock) - def _done(finished): - if finished: - fire_when_done.callback(None) - else: - self._loop(fire_when_done) - def _err(why): - fire_when_done.errback(why) - d.addCallbacks(_done, _err) - return None - - def _readBlock(self): - """Read a block of data from the remote reader.""" - - if self.interrupted or self.fp is None: - if self.debug: - log.msg('SlaveFileDownloadCommand._readBlock(): end') - return True - - length = self.blocksize - if self.bytes_remaining is not None and length > self.bytes_remaining: - length = self.bytes_remaining - - if length <= 0: - if self.stderr is None: - self.stderr = 'Maximum filesize reached, truncating file %r' \ - % self.path - self.rc = 1 - return True - else: - d = self.reader.callRemote('read', length) - d.addCallback(self._writeData) - return d - - def _writeData(self, data): - if self.debug: - log.msg('SlaveFileDownloadCommand._readBlock(): readlen=%d' % - len(data)) - if len(data) == 0: - return True - - if self.bytes_remaining is not None: - self.bytes_remaining = self.bytes_remaining - len(data) - assert self.bytes_remaining >= 0 - self.fp.write(data) - return False - - def interrupt(self): - if self.debug: - log.msg('interrupted') - if self.interrupted: - return - if self.stderr is None: - self.stderr = 'Download of %r interrupted' % self.path - self.rc = 1 - self.interrupted = True - # now we wait for the next read request to return. _readBlock will - # abandon the file when it sees self.interrupted set. - - def finished(self, res): - if self.fp is not None: - self.fp.close() - - if self.debug: - log.msg('finished: stderr=%r, rc=%r' % (self.stderr, self.rc)) - if self.stderr is None: - self.sendStatus({'rc': self.rc}) - else: - self.sendStatus({'stderr': self.stderr, 'rc': self.rc}) - return res - -registerSlaveCommand("downloadFile", SlaveFileDownloadCommand, command_version) - - - -class SlaveShellCommand(Command): - """This is a Command which runs a shell command. The args dict contains - the following keys: - - - ['command'] (required): a shell command to run. If this is a string, - it will be run with /bin/sh (['/bin/sh', - '-c', command]). If it is a list - (preferred), it will be used directly. - - ['workdir'] (required): subdirectory in which the command will be - run, relative to the builder dir - - ['env']: a dict of environment variables to augment/replace - os.environ . PYTHONPATH is treated specially, and - should be a list of path components to be prepended to - any existing PYTHONPATH environment variable. - - ['initial_stdin']: a string which will be written to the command's - stdin as soon as it starts - - ['keep_stdin_open']: unless True, the command's stdin will be - closed as soon as initial_stdin has been - written. Set this to True if you plan to write - to stdin after the command has been started. - - ['want_stdout']: 0 if stdout should be thrown away - - ['want_stderr']: 0 if stderr should be thrown away - - ['not_really']: 1 to skip execution and return rc=0 - - ['timeout']: seconds of silence to tolerate before killing command - - ['logfiles']: dict mapping LogFile name to the workdir-relative - filename of a local log file. This local file will be - watched just like 'tail -f', and all changes will be - written to 'log' status updates. - - ShellCommand creates the following status messages: - - {'stdout': data} : when stdout data is available - - {'stderr': data} : when stderr data is available - - {'header': data} : when headers (command start/stop) are available - - {'log': (logfile_name, data)} : when log files have new contents - - {'rc': rc} : when the process has terminated - """ - - def start(self): - args = self.args - # args['workdir'] is relative to Builder directory, and is required. - assert args['workdir'] is not None - workdir = os.path.join(self.builder.basedir, args['workdir']) - - c = ShellCommand(self.builder, args['command'], - workdir, environ=args.get('env'), - timeout=args.get('timeout', None), - sendStdout=args.get('want_stdout', True), - sendStderr=args.get('want_stderr', True), - sendRC=True, - initialStdin=args.get('initial_stdin'), - keepStdinOpen=args.get('keep_stdin_open'), - logfiles=args.get('logfiles', {}), - ) - self.command = c - d = self.command.start() - return d - - def interrupt(self): - self.interrupted = True - self.command.kill("command interrupted") - - def writeStdin(self, data): - self.command.writeStdin(data) - - def closeStdin(self): - self.command.closeStdin() - -registerSlaveCommand("shell", SlaveShellCommand, command_version) - - -class DummyCommand(Command): - """ - I am a dummy no-op command that by default takes 5 seconds to complete. - See L{buildbot.steps.dummy.RemoteDummy} - """ - - def start(self): - self.d = defer.Deferred() - log.msg(" starting dummy command [%s]" % self.stepId) - self.timer = reactor.callLater(1, self.doStatus) - return self.d - - def interrupt(self): - if self.interrupted: - return - self.timer.cancel() - self.timer = None - self.interrupted = True - self.finished() - - def doStatus(self): - log.msg(" sending intermediate status") - self.sendStatus({'stdout': 'data'}) - timeout = self.args.get('timeout', 5) + 1 - self.timer = reactor.callLater(timeout - 1, self.finished) - - def finished(self): - log.msg(" dummy command finished [%s]" % self.stepId) - if self.interrupted: - self.sendStatus({'rc': 1}) - else: - self.sendStatus({'rc': 0}) - self.d.callback(0) - -registerSlaveCommand("dummy", DummyCommand, command_version) - - -# this maps handle names to a callable. When the WaitCommand starts, this -# callable is invoked with no arguments. It should return a Deferred. When -# that Deferred fires, our WaitCommand will finish. -waitCommandRegistry = {} - -class WaitCommand(Command): - """ - I am a dummy command used by the buildbot unit test suite. I want for the - unit test to tell us to finish. See L{buildbot.steps.dummy.Wait} - """ - - def start(self): - self.d = defer.Deferred() - log.msg(" starting wait command [%s]" % self.stepId) - handle = self.args['handle'] - cb = waitCommandRegistry[handle] - del waitCommandRegistry[handle] - def _called(): - log.msg(" wait-%s starting" % (handle,)) - d = cb() - def _done(res): - log.msg(" wait-%s finishing: %s" % (handle, res)) - return res - d.addBoth(_done) - d.addCallbacks(self.finished, self.failed) - reactor.callLater(0, _called) - return self.d - - def interrupt(self): - log.msg(" wait command interrupted") - if self.interrupted: - return - self.interrupted = True - self.finished("interrupted") - - def finished(self, res): - log.msg(" wait command finished [%s]" % self.stepId) - if self.interrupted: - self.sendStatus({'rc': 2}) - else: - self.sendStatus({'rc': 0}) - self.d.callback(0) - def failed(self, why): - log.msg(" wait command failed [%s]" % self.stepId) - self.sendStatus({'rc': 1}) - self.d.callback(0) - -registerSlaveCommand("dummy.wait", WaitCommand, command_version) - - -class SourceBase(Command): - """Abstract base class for Version Control System operations (checkout - and update). This class extracts the following arguments from the - dictionary received from the master: - - - ['workdir']: (required) the subdirectory where the buildable sources - should be placed - - - ['mode']: one of update/copy/clobber/export, defaults to 'update' - - - ['revision']: If not None, this is an int or string which indicates - which sources (along a time-like axis) should be used. - It is the thing you provide as the CVS -r or -D - argument. - - - ['patch']: If not None, this is a tuple of (striplevel, patch) - which contains a patch that should be applied after the - checkout has occurred. Once applied, the tree is no - longer eligible for use with mode='update', and it only - makes sense to use this in conjunction with a - ['revision'] argument. striplevel is an int, and patch - is a string in standard unified diff format. The patch - will be applied with 'patch -p%d = 0: - self.retry = (delay, repeats-1) - msg = ("update failed, trying %d more times after %d seconds" - % (repeats, delay)) - self.sendStatus({'header': msg + "\n"}) - log.msg(msg) - d = defer.Deferred() - d.addCallback(lambda res: self.doVCFull()) - d.addBoth(self.maybeDoVCRetry) - reactor.callLater(delay, d.callback, None) - return d - return res - - def doClobber(self, dummy, dirname): - # TODO: remove the old tree in the background -## workdir = os.path.join(self.builder.basedir, self.workdir) -## deaddir = self.workdir + ".deleting" -## if os.path.isdir(workdir): -## try: -## os.rename(workdir, deaddir) -## # might fail if deaddir already exists: previous deletion -## # hasn't finished yet -## # start the deletion in the background -## # TODO: there was a solaris/NetApp/NFS problem where a -## # process that was still running out of the directory we're -## # trying to delete could prevent the rm-rf from working. I -## # think it stalled the rm, but maybe it just died with -## # permission issues. Try to detect this. -## os.commands("rm -rf %s &" % deaddir) -## except: -## # fall back to sequential delete-then-checkout -## pass - d = os.path.join(self.builder.basedir, dirname) - if runtime.platformType != "posix": - # if we're running on w32, use rmtree instead. It will block, - # but hopefully it won't take too long. - rmdirRecursive(d) - return defer.succeed(0) - command = ["rm", "-rf", d] - c = ShellCommand(self.builder, command, self.builder.basedir, - sendRC=0, timeout=self.timeout) - self.command = c - # sendRC=0 means the rm command will send stdout/stderr to the - # master, but not the rc=0 when it finishes. That job is left to - # _sendRC - d = c.start() - d.addCallback(self._abandonOnFailure) - return d - - def doCopy(self, res): - # now copy tree to workdir - fromdir = os.path.join(self.builder.basedir, self.srcdir) - todir = os.path.join(self.builder.basedir, self.workdir) - if runtime.platformType != "posix": - shutil.copytree(fromdir, todir) - return defer.succeed(0) - command = ['cp', '-R', '-P', '-p', fromdir, todir] - c = ShellCommand(self.builder, command, self.builder.basedir, - sendRC=False, timeout=self.timeout) - self.command = c - d = c.start() - d.addCallback(self._abandonOnFailure) - return d - - def doPatch(self, res): - patchlevel, diff = self.patch - command = [getCommand("patch"), '-p%d' % patchlevel] - dir = os.path.join(self.builder.basedir, self.workdir) - # mark the directory so we don't try to update it later - open(os.path.join(dir, ".buildbot-patched"), "w").write("patched\n") - # now apply the patch - c = ShellCommand(self.builder, command, dir, - sendRC=False, timeout=self.timeout, - initialStdin=diff) - self.command = c - d = c.start() - d.addCallback(self._abandonOnFailure) - return d - - -class CVS(SourceBase): - """CVS-specific VC operation. In addition to the arguments handled by - SourceBase, this command reads the following keys: - - ['cvsroot'] (required): the CVSROOT repository string - ['cvsmodule'] (required): the module to be retrieved - ['branch']: a '-r' tag or branch name to use for the checkout/update - ['login']: a string for use as a password to 'cvs login' - ['global_options']: a list of strings to use before the CVS verb - """ - - header = "cvs operation" - - def setup(self, args): - SourceBase.setup(self, args) - self.vcexe = getCommand("cvs") - self.cvsroot = args['cvsroot'] - self.cvsmodule = args['cvsmodule'] - self.global_options = args.get('global_options', []) - self.branch = args.get('branch') - self.login = args.get('login') - self.sourcedata = "%s\n%s\n%s\n" % (self.cvsroot, self.cvsmodule, - self.branch) - - def sourcedirIsUpdateable(self): - if os.path.exists(os.path.join(self.builder.basedir, - self.srcdir, ".buildbot-patched")): - return False - return os.path.isdir(os.path.join(self.builder.basedir, - self.srcdir, "CVS")) - - def start(self): - if self.login is not None: - # need to do a 'cvs login' command first - d = self.builder.basedir - command = ([self.vcexe, '-d', self.cvsroot] + self.global_options - + ['login']) - c = ShellCommand(self.builder, command, d, - sendRC=False, timeout=self.timeout, - initialStdin=self.login+"\n") - self.command = c - d = c.start() - d.addCallback(self._abandonOnFailure) - d.addCallback(self._didLogin) - return d - else: - return self._didLogin(None) - - def _didLogin(self, res): - # now we really start - return SourceBase.start(self) - - def doVCUpdate(self): - d = os.path.join(self.builder.basedir, self.srcdir) - command = [self.vcexe, '-z3'] + self.global_options + ['update', '-dP'] - if self.branch: - command += ['-r', self.branch] - if self.revision: - command += ['-D', self.revision] - c = ShellCommand(self.builder, command, d, - sendRC=False, timeout=self.timeout) - self.command = c - return c.start() - - def doVCFull(self): - d = self.builder.basedir - if self.mode == "export": - verb = "export" - else: - verb = "checkout" - command = ([self.vcexe, '-d', self.cvsroot, '-z3'] + - self.global_options + - [verb, '-d', self.srcdir]) - if self.branch: - command += ['-r', self.branch] - if self.revision: - command += ['-D', self.revision] - command += [self.cvsmodule] - c = ShellCommand(self.builder, command, d, - sendRC=False, timeout=self.timeout) - self.command = c - return c.start() - - def parseGotRevision(self): - # CVS does not have any kind of revision stamp to speak of. We return - # the current timestamp as a best-effort guess, but this depends upon - # the local system having a clock that is - # reasonably-well-synchronized with the repository. - return time.strftime("%Y-%m-%d %H:%M:%S +0000", time.gmtime()) - -registerSlaveCommand("cvs", CVS, command_version) - -class SVN(SourceBase): - """Subversion-specific VC operation. In addition to the arguments - handled by SourceBase, this command reads the following keys: - - ['svnurl'] (required): the SVN repository string - """ - - header = "svn operation" - - def setup(self, args): - SourceBase.setup(self, args) - self.vcexe = getCommand("svn") - self.svnurl = args['svnurl'] - self.sourcedata = "%s\n" % self.svnurl - - def sourcedirIsUpdateable(self): - if os.path.exists(os.path.join(self.builder.basedir, - self.srcdir, ".buildbot-patched")): - return False - return os.path.isdir(os.path.join(self.builder.basedir, - self.srcdir, ".svn")) - - def doVCUpdate(self): - revision = self.args['revision'] or 'HEAD' - # update: possible for mode in ('copy', 'update') - d = os.path.join(self.builder.basedir, self.srcdir) - command = [self.vcexe, 'update', '--revision', str(revision), - '--non-interactive', '--no-auth-cache'] - c = ShellCommand(self.builder, command, d, - sendRC=False, timeout=self.timeout, - keepStdout=True) - self.command = c - return c.start() - - def doVCFull(self): - revision = self.args['revision'] or 'HEAD' - d = self.builder.basedir - if self.mode == "export": - command = [self.vcexe, 'export', '--revision', str(revision), - '--non-interactive', '--no-auth-cache', - self.svnurl, self.srcdir] - else: - # mode=='clobber', or copy/update on a broken workspace - command = [self.vcexe, 'checkout', '--revision', str(revision), - '--non-interactive', '--no-auth-cache', - self.svnurl, self.srcdir] - c = ShellCommand(self.builder, command, d, - sendRC=False, timeout=self.timeout, - keepStdout=True) - self.command = c - return c.start() - - def getSvnVersionCommand(self): - """ - Get the (shell) command used to determine SVN revision number - of checked-out code - - return: list of strings, passable as the command argument to ShellCommand - """ - # svn checkout operations finish with 'Checked out revision 16657.' - # svn update operations finish the line 'At revision 16654.' - # But we don't use those. Instead, run 'svnversion'. - svnversion_command = getCommand("svnversion") - # older versions of 'svnversion' (1.1.4) require the WC_PATH - # argument, newer ones (1.3.1) do not. - return [svnversion_command, "."] - - def parseGotRevision(self): - c = ShellCommand(self.builder, - self.getSvnVersionCommand(), - os.path.join(self.builder.basedir, self.srcdir), - environ=self.env, - sendStdout=False, sendStderr=False, sendRC=False, - keepStdout=True) - c.usePTY = False - d = c.start() - def _parse(res): - r_raw = c.stdout.strip() - # Extract revision from the version "number" string - r = r_raw.rstrip('MS') - r = r.split(':')[-1] - got_version = None - try: - got_version = int(r) - except ValueError: - msg =("SVN.parseGotRevision unable to parse output " - "of svnversion: '%s'" % r_raw) - log.msg(msg) - self.sendStatus({'header': msg + "\n"}) - return got_version - d.addCallback(_parse) - return d - - -registerSlaveCommand("svn", SVN, command_version) - -class Darcs(SourceBase): - """Darcs-specific VC operation. In addition to the arguments - handled by SourceBase, this command reads the following keys: - - ['repourl'] (required): the Darcs repository string - """ - - header = "darcs operation" - - def setup(self, args): - SourceBase.setup(self, args) - self.vcexe = getCommand("darcs") - self.repourl = args['repourl'] - self.sourcedata = "%s\n" % self.repourl - self.revision = self.args.get('revision') - - def sourcedirIsUpdateable(self): - if os.path.exists(os.path.join(self.builder.basedir, - self.srcdir, ".buildbot-patched")): - return False - if self.revision: - # checking out a specific revision requires a full 'darcs get' - return False - return os.path.isdir(os.path.join(self.builder.basedir, - self.srcdir, "_darcs")) - - def doVCUpdate(self): - assert not self.revision - # update: possible for mode in ('copy', 'update') - d = os.path.join(self.builder.basedir, self.srcdir) - command = [self.vcexe, 'pull', '--all', '--verbose'] - c = ShellCommand(self.builder, command, d, - sendRC=False, timeout=self.timeout) - self.command = c - return c.start() - - def doVCFull(self): - # checkout or export - d = self.builder.basedir - command = [self.vcexe, 'get', '--verbose', '--partial', - '--repo-name', self.srcdir] - if self.revision: - # write the context to a file - n = os.path.join(self.builder.basedir, ".darcs-context") - f = open(n, "wb") - f.write(self.revision) - f.close() - # tell Darcs to use that context - command.append('--context') - command.append(n) - command.append(self.repourl) - - c = ShellCommand(self.builder, command, d, - sendRC=False, timeout=self.timeout) - self.command = c - d = c.start() - if self.revision: - d.addCallback(self.removeContextFile, n) - return d - - def removeContextFile(self, res, n): - os.unlink(n) - return res - - def parseGotRevision(self): - # we use 'darcs context' to find out what we wound up with - command = [self.vcexe, "changes", "--context"] - c = ShellCommand(self.builder, command, - os.path.join(self.builder.basedir, self.srcdir), - environ=self.env, - sendStdout=False, sendStderr=False, sendRC=False, - keepStdout=True) - c.usePTY = False - d = c.start() - d.addCallback(lambda res: c.stdout) - return d - -registerSlaveCommand("darcs", Darcs, command_version) - -class Monotone(SourceBase): - """Monotone-specific VC operation. In addition to the arguments handled - by SourceBase, this command reads the following keys: - - ['server_addr'] (required): the address of the server to pull from - ['branch'] (required): the branch the revision is on - ['db_path'] (required): the local database path to use - ['revision'] (required): the revision to check out - ['monotone']: (required): path to monotone executable - """ - - header = "monotone operation" - - def setup(self, args): - SourceBase.setup(self, args) - self.server_addr = args["server_addr"] - self.branch = args["branch"] - self.db_path = args["db_path"] - self.revision = args["revision"] - self.monotone = args["monotone"] - self._made_fulls = False - self._pull_timeout = args["timeout"] - - def _makefulls(self): - if not self._made_fulls: - basedir = self.builder.basedir - self.full_db_path = os.path.join(basedir, self.db_path) - self.full_srcdir = os.path.join(basedir, self.srcdir) - self._made_fulls = True - - def sourcedirIsUpdateable(self): - self._makefulls() - if os.path.exists(os.path.join(self.full_srcdir, - ".buildbot_patched")): - return False - return (os.path.isfile(self.full_db_path) - and os.path.isdir(os.path.join(self.full_srcdir, "MT"))) - - def doVCUpdate(self): - return self._withFreshDb(self._doUpdate) - - def _doUpdate(self): - # update: possible for mode in ('copy', 'update') - command = [self.monotone, "update", - "-r", self.revision, - "-b", self.branch] - c = ShellCommand(self.builder, command, self.full_srcdir, - sendRC=False, timeout=self.timeout) - self.command = c - return c.start() - - def doVCFull(self): - return self._withFreshDb(self._doFull) - - def _doFull(self): - command = [self.monotone, "--db=" + self.full_db_path, - "checkout", - "-r", self.revision, - "-b", self.branch, - self.full_srcdir] - c = ShellCommand(self.builder, command, self.builder.basedir, - sendRC=False, timeout=self.timeout) - self.command = c - return c.start() - - def _withFreshDb(self, callback): - self._makefulls() - # first ensure the db exists and is usable - if os.path.isfile(self.full_db_path): - # already exists, so run 'db migrate' in case monotone has been - # upgraded under us - command = [self.monotone, "db", "migrate", - "--db=" + self.full_db_path] - else: - # We'll be doing an initial pull, so up the timeout to 3 hours to - # make sure it will have time to complete. - self._pull_timeout = max(self._pull_timeout, 3 * 60 * 60) - self.sendStatus({"header": "creating database %s\n" - % (self.full_db_path,)}) - command = [self.monotone, "db", "init", - "--db=" + self.full_db_path] - c = ShellCommand(self.builder, command, self.builder.basedir, - sendRC=False, timeout=self.timeout) - self.command = c - d = c.start() - d.addCallback(self._abandonOnFailure) - d.addCallback(self._didDbInit) - d.addCallback(self._didPull, callback) - return d - - def _didDbInit(self, res): - command = [self.monotone, "--db=" + self.full_db_path, - "pull", "--ticker=dot", self.server_addr, self.branch] - c = ShellCommand(self.builder, command, self.builder.basedir, - sendRC=False, timeout=self._pull_timeout) - self.sendStatus({"header": "pulling %s from %s\n" - % (self.branch, self.server_addr)}) - self.command = c - return c.start() - - def _didPull(self, res, callback): - return callback() - -registerSlaveCommand("monotone", Monotone, command_version) - - -class Git(SourceBase): - """Git specific VC operation. In addition to the arguments - handled by SourceBase, this command reads the following keys: - - ['repourl'] (required): the upstream GIT repository string - ['branch'] (optional): which version (i.e. branch or tag) to - retrieve. Default: "master". - """ - - header = "git operation" - - def setup(self, args): - SourceBase.setup(self, args) - self.repourl = args['repourl'] - self.branch = args.get('branch') - if not self.branch: - self.branch = "master" - self.sourcedata = "%s %s\n" % (self.repourl, self.branch) - - def _fullSrcdir(self): - return os.path.join(self.builder.basedir, self.srcdir) - - def _commitSpec(self): - if self.revision: - return self.revision - return self.branch - - def sourcedirIsUpdateable(self): - if os.path.exists(os.path.join(self._fullSrcdir(), - ".buildbot-patched")): - return False - return os.path.isdir(os.path.join(self._fullSrcdir(), ".git")) - - def _didFetch(self, res): - if self.revision: - head = self.revision - else: - head = 'FETCH_HEAD' - - command = ['git-reset', '--hard', head] - c = ShellCommand(self.builder, command, self._fullSrcdir(), - sendRC=False, timeout=self.timeout) - self.command = c - return c.start() - - def doVCUpdate(self): - command = ['git-fetch', self.repourl, self.branch] - self.sendStatus({"header": "fetching branch %s from %s\n" - % (self.branch, self.repourl)}) - c = ShellCommand(self.builder, command, self._fullSrcdir(), - sendRC=False, timeout=self.timeout) - self.command = c - d = c.start() - d.addCallback(self._abandonOnFailure) - d.addCallback(self._didFetch) - return d - - def _didInit(self, res): - return self.doVCUpdate() - - def doVCFull(self): - os.mkdir(self._fullSrcdir()) - c = ShellCommand(self.builder, ['git-init'], self._fullSrcdir(), - sendRC=False, timeout=self.timeout) - self.command = c - d = c.start() - d.addCallback(self._abandonOnFailure) - d.addCallback(self._didInit) - return d - - def parseGotRevision(self): - command = ['git-rev-parse', 'HEAD'] - c = ShellCommand(self.builder, command, self._fullSrcdir(), - sendRC=False, keepStdout=True) - c.usePTY = False - d = c.start() - def _parse(res): - hash = c.stdout.strip() - if len(hash) != 40: - return None - return hash - d.addCallback(_parse) - return d - -registerSlaveCommand("git", Git, command_version) - -class Arch(SourceBase): - """Arch-specific (tla-specific) VC operation. In addition to the - arguments handled by SourceBase, this command reads the following keys: - - ['url'] (required): the repository string - ['version'] (required): which version (i.e. branch) to retrieve - ['revision'] (optional): the 'patch-NN' argument to check out - ['archive']: the archive name to use. If None, use the archive's default - ['build-config']: if present, give to 'tla build-config' after checkout - """ - - header = "arch operation" - buildconfig = None - - def setup(self, args): - SourceBase.setup(self, args) - self.vcexe = getCommand("tla") - self.archive = args.get('archive') - self.url = args['url'] - self.version = args['version'] - self.revision = args.get('revision') - self.buildconfig = args.get('build-config') - self.sourcedata = "%s\n%s\n%s\n" % (self.url, self.version, - self.buildconfig) - - def sourcedirIsUpdateable(self): - if self.revision: - # Arch cannot roll a directory backwards, so if they ask for a - # specific revision, clobber the directory. Technically this - # could be limited to the cases where the requested revision is - # later than our current one, but it's too hard to extract the - # current revision from the tree. - return False - if os.path.exists(os.path.join(self.builder.basedir, - self.srcdir, ".buildbot-patched")): - return False - return os.path.isdir(os.path.join(self.builder.basedir, - self.srcdir, "{arch}")) - - def doVCUpdate(self): - # update: possible for mode in ('copy', 'update') - d = os.path.join(self.builder.basedir, self.srcdir) - command = [self.vcexe, 'replay'] - if self.revision: - command.append(self.revision) - c = ShellCommand(self.builder, command, d, - sendRC=False, timeout=self.timeout) - self.command = c - return c.start() - - def doVCFull(self): - # to do a checkout, we must first "register" the archive by giving - # the URL to tla, which will go to the repository at that URL and - # figure out the archive name. tla will tell you the archive name - # when it is done, and all further actions must refer to this name. - - command = [self.vcexe, 'register-archive', '--force', self.url] - c = ShellCommand(self.builder, command, self.builder.basedir, - sendRC=False, keepStdout=True, - timeout=self.timeout) - self.command = c - d = c.start() - d.addCallback(self._abandonOnFailure) - d.addCallback(self._didRegister, c) - return d - - def _didRegister(self, res, c): - # find out what tla thinks the archive name is. If the user told us - # to use something specific, make sure it matches. - r = re.search(r'Registering archive: (\S+)\s*$', c.stdout) - if r: - msg = "tla reports archive name is '%s'" % r.group(1) - log.msg(msg) - self.builder.sendUpdate({'header': msg+"\n"}) - if self.archive and r.group(1) != self.archive: - msg = (" mismatch, we wanted an archive named '%s'" - % self.archive) - log.msg(msg) - self.builder.sendUpdate({'header': msg+"\n"}) - raise AbandonChain(-1) - self.archive = r.group(1) - assert self.archive, "need archive name to continue" - return self._doGet() - - def _doGet(self): - ver = self.version - if self.revision: - ver += "--%s" % self.revision - command = [self.vcexe, 'get', '--archive', self.archive, - '--no-pristine', - ver, self.srcdir] - c = ShellCommand(self.builder, command, self.builder.basedir, - sendRC=False, timeout=self.timeout) - self.command = c - d = c.start() - d.addCallback(self._abandonOnFailure) - if self.buildconfig: - d.addCallback(self._didGet) - return d - - def _didGet(self, res): - d = os.path.join(self.builder.basedir, self.srcdir) - command = [self.vcexe, 'build-config', self.buildconfig] - c = ShellCommand(self.builder, command, d, - sendRC=False, timeout=self.timeout) - self.command = c - d = c.start() - d.addCallback(self._abandonOnFailure) - return d - - def parseGotRevision(self): - # using code from tryclient.TlaExtractor - # 'tla logs --full' gives us ARCHIVE/BRANCH--REVISION - # 'tla logs' gives us REVISION - command = [self.vcexe, "logs", "--full", "--reverse"] - c = ShellCommand(self.builder, command, - os.path.join(self.builder.basedir, self.srcdir), - environ=self.env, - sendStdout=False, sendStderr=False, sendRC=False, - keepStdout=True) - c.usePTY = False - d = c.start() - def _parse(res): - tid = c.stdout.split("\n")[0].strip() - slash = tid.index("/") - dd = tid.rindex("--") - #branch = tid[slash+1:dd] - baserev = tid[dd+2:] - return baserev - d.addCallback(_parse) - return d - -registerSlaveCommand("arch", Arch, command_version) - -class Bazaar(Arch): - """Bazaar (/usr/bin/baz) is an alternative client for Arch repositories. - It is mostly option-compatible, but archive registration is different - enough to warrant a separate Command. - - ['archive'] (required): the name of the archive being used - """ - - def setup(self, args): - Arch.setup(self, args) - self.vcexe = getCommand("baz") - # baz doesn't emit the repository name after registration (and - # grepping through the output of 'baz archives' is too hard), so we - # require that the buildmaster configuration to provide both the - # archive name and the URL. - self.archive = args['archive'] # required for Baz - self.sourcedata = "%s\n%s\n%s\n" % (self.url, self.version, - self.buildconfig) - - # in _didRegister, the regexp won't match, so we'll stick with the name - # in self.archive - - def _doGet(self): - # baz prefers ARCHIVE/VERSION. This will work even if - # my-default-archive is not set. - ver = self.archive + "/" + self.version - if self.revision: - ver += "--%s" % self.revision - command = [self.vcexe, 'get', '--no-pristine', - ver, self.srcdir] - c = ShellCommand(self.builder, command, self.builder.basedir, - sendRC=False, timeout=self.timeout) - self.command = c - d = c.start() - d.addCallback(self._abandonOnFailure) - if self.buildconfig: - d.addCallback(self._didGet) - return d - - def parseGotRevision(self): - # using code from tryclient.BazExtractor - command = [self.vcexe, "tree-id"] - c = ShellCommand(self.builder, command, - os.path.join(self.builder.basedir, self.srcdir), - environ=self.env, - sendStdout=False, sendStderr=False, sendRC=False, - keepStdout=True) - c.usePTY = False - d = c.start() - def _parse(res): - tid = c.stdout.strip() - slash = tid.index("/") - dd = tid.rindex("--") - #branch = tid[slash+1:dd] - baserev = tid[dd+2:] - return baserev - d.addCallback(_parse) - return d - -registerSlaveCommand("bazaar", Bazaar, command_version) - - -class Bzr(SourceBase): - """bzr-specific VC operation. In addition to the arguments - handled by SourceBase, this command reads the following keys: - - ['repourl'] (required): the Bzr repository string - """ - - header = "bzr operation" - - def setup(self, args): - SourceBase.setup(self, args) - self.vcexe = getCommand("bzr") - self.repourl = args['repourl'] - self.sourcedata = "%s\n" % self.repourl - self.revision = self.args.get('revision') - - def sourcedirIsUpdateable(self): - if os.path.exists(os.path.join(self.builder.basedir, - self.srcdir, ".buildbot-patched")): - return False - if self.revision: - # checking out a specific revision requires a full 'bzr checkout' - return False - return os.path.isdir(os.path.join(self.builder.basedir, - self.srcdir, ".bzr")) - - def doVCUpdate(self): - assert not self.revision - # update: possible for mode in ('copy', 'update') - srcdir = os.path.join(self.builder.basedir, self.srcdir) - command = [self.vcexe, 'update'] - c = ShellCommand(self.builder, command, srcdir, - sendRC=False, timeout=self.timeout) - self.command = c - return c.start() - - def doVCFull(self): - # checkout or export - d = self.builder.basedir - if self.mode == "export": - # exporting in bzr requires a separate directory - return self.doVCExport() - # originally I added --lightweight here, but then 'bzr revno' is - # wrong. The revno reported in 'bzr version-info' is correct, - # however. Maybe this is a bzr bug? - # - # In addition, you cannot perform a 'bzr update' on a repo pulled - # from an HTTP repository that used 'bzr checkout --lightweight'. You - # get a "ERROR: Cannot lock: transport is read only" when you try. - # - # So I won't bother using --lightweight for now. - - command = [self.vcexe, 'checkout'] - if self.revision: - command.append('--revision') - command.append(str(self.revision)) - command.append(self.repourl) - command.append(self.srcdir) - - c = ShellCommand(self.builder, command, d, - sendRC=False, timeout=self.timeout) - self.command = c - d = c.start() - return d - - def doVCExport(self): - tmpdir = os.path.join(self.builder.basedir, "export-temp") - srcdir = os.path.join(self.builder.basedir, self.srcdir) - command = [self.vcexe, 'checkout', '--lightweight'] - if self.revision: - command.append('--revision') - command.append(str(self.revision)) - command.append(self.repourl) - command.append(tmpdir) - c = ShellCommand(self.builder, command, self.builder.basedir, - sendRC=False, timeout=self.timeout) - self.command = c - d = c.start() - def _export(res): - command = [self.vcexe, 'export', srcdir] - c = ShellCommand(self.builder, command, tmpdir, - sendRC=False, timeout=self.timeout) - self.command = c - return c.start() - d.addCallback(_export) - return d - - def get_revision_number(self, out): - # it feels like 'bzr revno' sometimes gives different results than - # the 'revno:' line from 'bzr version-info', and the one from - # version-info is more likely to be correct. - for line in out.split("\n"): - colon = line.find(":") - if colon != -1: - key, value = line[:colon], line[colon+2:] - if key == "revno": - return int(value) - raise ValueError("unable to find revno: in bzr output: '%s'" % out) - - def parseGotRevision(self): - command = [self.vcexe, "version-info"] - c = ShellCommand(self.builder, command, - os.path.join(self.builder.basedir, self.srcdir), - environ=self.env, - sendStdout=False, sendStderr=False, sendRC=False, - keepStdout=True) - c.usePTY = False - d = c.start() - def _parse(res): - try: - return self.get_revision_number(c.stdout) - except ValueError: - msg =("Bzr.parseGotRevision unable to parse output " - "of bzr version-info: '%s'" % c.stdout.strip()) - log.msg(msg) - self.sendStatus({'header': msg + "\n"}) - return None - d.addCallback(_parse) - return d - -registerSlaveCommand("bzr", Bzr, command_version) - -class Mercurial(SourceBase): - """Mercurial specific VC operation. In addition to the arguments - handled by SourceBase, this command reads the following keys: - - ['repourl'] (required): the Cogito repository string - """ - - header = "mercurial operation" - - def setup(self, args): - SourceBase.setup(self, args) - self.vcexe = getCommand("hg") - self.repourl = args['repourl'] - self.sourcedata = "%s\n" % self.repourl - self.stdout = "" - self.stderr = "" - - def sourcedirIsUpdateable(self): - if os.path.exists(os.path.join(self.builder.basedir, - self.srcdir, ".buildbot-patched")): - return False - # like Darcs, to check out a specific (old) revision, we have to do a - # full checkout. TODO: I think 'hg pull' plus 'hg update' might work - if self.revision: - return False - return os.path.isdir(os.path.join(self.builder.basedir, - self.srcdir, ".hg")) - - def doVCUpdate(self): - d = os.path.join(self.builder.basedir, self.srcdir) - command = [self.vcexe, 'pull', '--update', '--verbose'] - if self.args['revision']: - command.extend(['--rev', self.args['revision']]) - c = ShellCommand(self.builder, command, d, - sendRC=False, timeout=self.timeout, - keepStdout=True) - self.command = c - d = c.start() - d.addCallback(self._handleEmptyUpdate) - return d - - def _handleEmptyUpdate(self, res): - if type(res) is int and res == 1: - if self.command.stdout.find("no changes found") != -1: - # 'hg pull', when it doesn't have anything to do, exits with - # rc=1, and there appears to be no way to shut this off. It - # emits a distinctive message to stdout, though. So catch - # this and pretend that it completed successfully. - return 0 - return res - - def doVCFull(self): - newdir = os.path.join(self.builder.basedir, self.srcdir) - command = [self.vcexe, 'clone'] - if self.args['revision']: - command.extend(['--rev', self.args['revision']]) - command.extend([self.repourl, newdir]) - c = ShellCommand(self.builder, command, self.builder.basedir, - sendRC=False, keepStdout=True, keepStderr=True, - timeout=self.timeout) - self.command = c - d = c.start() - d.addCallback(self._maybeFallback, c) - return d - - def _maybeFallback(self, res, c): - # to do 'hg clone -r REV' (i.e. to check out a specific revision) - # from a remote (HTTP) repository, both the client and the server - # need to be hg-0.9.2 or newer. If this caused a checkout failure, we - # fall back to doing a checkout of HEAD (spelled 'tip' in hg - # parlance) and then 'hg update' *backwards* to the desired revision. - if res == 0: - return res - - errmsgs = [ - # hg-0.6 didn't even have the 'clone' command - # hg-0.7 - "hg clone: option --rev not recognized", - # hg-0.8, 0.8.1, 0.9 - "abort: clone -r not supported yet for remote repositories.", - # hg-0.9.1 - ("abort: clone by revision not supported yet for " - "remote repositories"), - # hg-0.9.2 and later say this when the other end is too old - ("abort: src repository does not support revision lookup " - "and so doesn't support clone by revision"), - ] - - fallback_is_useful = False - for errmsg in errmsgs: - # the error message might be in stdout if we're using PTYs, which - # merge stdout and stderr. - if errmsg in c.stdout or errmsg in c.stderr: - fallback_is_useful = True - break - if not fallback_is_useful: - return res # must be some other error - - # ok, do the fallback - newdir = os.path.join(self.builder.basedir, self.srcdir) - command = [self.vcexe, 'clone'] - command.extend([self.repourl, newdir]) - c = ShellCommand(self.builder, command, self.builder.basedir, - sendRC=False, timeout=self.timeout) - self.command = c - d = c.start() - d.addCallback(self._abandonOnFailure) - d.addCallback(self._updateToDesiredRevision) - return d - - def _updateToDesiredRevision(self, res): - assert self.args['revision'] - newdir = os.path.join(self.builder.basedir, self.srcdir) - # hg-0.9.1 and earlier (which need this fallback) also want to see - # 'hg update REV' instead of 'hg update --rev REV'. Note that this is - # the only place we use 'hg update', since what most VC tools mean - # by, say, 'cvs update' is expressed as 'hg pull --update' instead. - command = [self.vcexe, 'update', self.args['revision']] - c = ShellCommand(self.builder, command, newdir, - sendRC=False, timeout=self.timeout) - return c.start() - - def parseGotRevision(self): - # we use 'hg identify' to find out what we wound up with - command = [self.vcexe, "identify"] - c = ShellCommand(self.builder, command, - os.path.join(self.builder.basedir, self.srcdir), - environ=self.env, - sendStdout=False, sendStderr=False, sendRC=False, - keepStdout=True) - d = c.start() - def _parse(res): - m = re.search(r'^(\w+)', c.stdout) - return m.group(1) - d.addCallback(_parse) - return d - -registerSlaveCommand("hg", Mercurial, command_version) - - -class P4(SourceBase): - """A P4 source-updater. - - ['p4port'] (required): host:port for server to access - ['p4user'] (optional): user to use for access - ['p4passwd'] (optional): passwd to try for the user - ['p4client'] (optional): client spec to use - ['p4extra_views'] (optional): additional client views to use - """ - - header = "p4" - - def setup(self, args): - SourceBase.setup(self, args) - self.p4port = args['p4port'] - self.p4client = args['p4client'] - self.p4user = args['p4user'] - self.p4passwd = args['p4passwd'] - self.p4base = args['p4base'] - self.p4extra_views = args['p4extra_views'] - self.p4mode = args['mode'] - self.p4branch = args['branch'] - - self.sourcedata = str([ - # Perforce server. - self.p4port, - - # Client spec. - self.p4client, - - # Depot side of view spec. - self.p4base, - self.p4branch, - self.p4extra_views, - - # Local side of view spec (srcdir is made from these). - self.builder.basedir, - self.mode, - self.workdir - ]) - - - def sourcedirIsUpdateable(self): - if os.path.exists(os.path.join(self.builder.basedir, - self.srcdir, ".buildbot-patched")): - return False - # We assume our client spec is still around. - # We just say we aren't updateable if the dir doesn't exist so we - # don't get ENOENT checking the sourcedata. - return os.path.isdir(os.path.join(self.builder.basedir, - self.srcdir)) - - def doVCUpdate(self): - return self._doP4Sync(force=False) - - def _doP4Sync(self, force): - command = ['p4'] - - if self.p4port: - command.extend(['-p', self.p4port]) - if self.p4user: - command.extend(['-u', self.p4user]) - if self.p4passwd: - command.extend(['-P', self.p4passwd]) - if self.p4client: - command.extend(['-c', self.p4client]) - command.extend(['sync']) - if force: - command.extend(['-f']) - if self.revision: - command.extend(['@' + str(self.revision)]) - env = {} - c = ShellCommand(self.builder, command, self.builder.basedir, - environ=env, sendRC=False, timeout=self.timeout, - keepStdout=True) - self.command = c - d = c.start() - d.addCallback(self._abandonOnFailure) - return d - - - def doVCFull(self): - env = {} - command = ['p4'] - client_spec = '' - client_spec += "Client: %s\n\n" % self.p4client - client_spec += "Owner: %s\n\n" % self.p4user - client_spec += "Description:\n\tCreated by %s\n\n" % self.p4user - client_spec += "Root:\t%s\n\n" % self.builder.basedir - client_spec += "Options:\tallwrite rmdir\n\n" - client_spec += "LineEnd:\tlocal\n\n" - - # Setup a view - client_spec += "View:\n\t%s" % (self.p4base) - if self.p4branch: - client_spec += "%s/" % (self.p4branch) - client_spec += "... //%s/%s/...\n" % (self.p4client, self.srcdir) - if self.p4extra_views: - for k, v in self.p4extra_views: - client_spec += "\t%s/... //%s/%s%s/...\n" % (k, self.p4client, - self.srcdir, v) - if self.p4port: - command.extend(['-p', self.p4port]) - if self.p4user: - command.extend(['-u', self.p4user]) - if self.p4passwd: - command.extend(['-P', self.p4passwd]) - command.extend(['client', '-i']) - log.msg(client_spec) - c = ShellCommand(self.builder, command, self.builder.basedir, - environ=env, sendRC=False, timeout=self.timeout, - initialStdin=client_spec) - self.command = c - d = c.start() - d.addCallback(self._abandonOnFailure) - d.addCallback(lambda _: self._doP4Sync(force=True)) - return d - -registerSlaveCommand("p4", P4, command_version) - - -class P4Sync(SourceBase): - """A partial P4 source-updater. Requires manual setup of a per-slave P4 - environment. The only thing which comes from the master is P4PORT. - 'mode' is required to be 'copy'. - - ['p4port'] (required): host:port for server to access - ['p4user'] (optional): user to use for access - ['p4passwd'] (optional): passwd to try for the user - ['p4client'] (optional): client spec to use - """ - - header = "p4 sync" - - def setup(self, args): - SourceBase.setup(self, args) - self.vcexe = getCommand("p4") - self.p4port = args['p4port'] - self.p4user = args['p4user'] - self.p4passwd = args['p4passwd'] - self.p4client = args['p4client'] - - def sourcedirIsUpdateable(self): - return True - - def _doVC(self, force): - d = os.path.join(self.builder.basedir, self.srcdir) - command = [self.vcexe] - if self.p4port: - command.extend(['-p', self.p4port]) - if self.p4user: - command.extend(['-u', self.p4user]) - if self.p4passwd: - command.extend(['-P', self.p4passwd]) - if self.p4client: - command.extend(['-c', self.p4client]) - command.extend(['sync']) - if force: - command.extend(['-f']) - if self.revision: - command.extend(['@' + self.revision]) - env = {} - c = ShellCommand(self.builder, command, d, environ=env, - sendRC=False, timeout=self.timeout) - self.command = c - return c.start() - - def doVCUpdate(self): - return self._doVC(force=False) - - def doVCFull(self): - return self._doVC(force=True) - -registerSlaveCommand("p4sync", P4Sync, command_version) diff --git a/tools/buildbot/pylibs/buildbot/slave/interfaces.py b/tools/buildbot/pylibs/buildbot/slave/interfaces.py deleted file mode 100644 index fb143a7..0000000 --- a/tools/buildbot/pylibs/buildbot/slave/interfaces.py +++ /dev/null @@ -1,56 +0,0 @@ - -from zope.interface import Interface - -class ISlaveCommand(Interface): - """This interface is implemented by all of the buildslave's Command - subclasses. It specifies how the buildslave can start, interrupt, and - query the various Commands running on behalf of the buildmaster.""" - - def __init__(builder, stepId, args): - """Create the Command. 'builder' is a reference to the parent - buildbot.bot.SlaveBuilder instance, which will be used to send status - updates (by calling builder.sendStatus). 'stepId' is a random string - which helps correlate slave logs with the master. 'args' is a dict of - arguments that comes from the master-side BuildStep, with contents - that are specific to the individual Command subclass. - - This method is not intended to be subclassed.""" - - def setup(args): - """This method is provided for subclasses to override, to extract - parameters from the 'args' dictionary. The default implemention does - nothing. It will be called from __init__""" - - def start(): - """Begin the command, and return a Deferred. - - While the command runs, it should send status updates to the - master-side BuildStep by calling self.sendStatus(status). The - 'status' argument is typically a dict with keys like 'stdout', - 'stderr', and 'rc'. - - When the step completes, it should fire the Deferred (the results are - not used). If an exception occurs during execution, it may also - errback the deferred, however any reasonable errors should be trapped - and indicated with a non-zero 'rc' status rather than raising an - exception. Exceptions should indicate problems within the buildbot - itself, not problems in the project being tested. - - """ - - def interrupt(): - """This is called to tell the Command that the build is being stopped - and therefore the command should be terminated as quickly as - possible. The command may continue to send status updates, up to and - including an 'rc' end-of-command update (which should indicate an - error condition). The Command's deferred should still be fired when - the command has finally completed. - - If the build is being stopped because the slave it shutting down or - because the connection to the buildmaster has been lost, the status - updates will simply be discarded. The Command does not need to be - aware of this. - - Child shell processes should be killed. Simple ShellCommand classes - can just insert a header line indicating that the process will be - killed, then os.kill() the child.""" diff --git a/tools/buildbot/pylibs/buildbot/slave/registry.py b/tools/buildbot/pylibs/buildbot/slave/registry.py deleted file mode 100644 index 772aad3..0000000 --- a/tools/buildbot/pylibs/buildbot/slave/registry.py +++ /dev/null @@ -1,17 +0,0 @@ - -commandRegistry = {} - -def registerSlaveCommand(name, factory, version): - """ - Register a slave command with the registry, making it available in slaves. - - @type name: string - @param name: name under which the slave command will be registered; used - for L{buildbot.slave.bot.SlaveBuilder.remote_startCommand} - - @type factory: L{buildbot.slave.commands.Command} - @type version: string - @param version: version string of the factory code - """ - assert not commandRegistry.has_key(name) - commandRegistry[name] = (factory, version) diff --git a/tools/buildbot/pylibs/buildbot/sourcestamp.py b/tools/buildbot/pylibs/buildbot/sourcestamp.py deleted file mode 100644 index e2162ca..0000000 --- a/tools/buildbot/pylibs/buildbot/sourcestamp.py +++ /dev/null @@ -1,95 +0,0 @@ - -from zope.interface import implements -from buildbot import util, interfaces - -class SourceStamp(util.ComparableMixin): - """This is a tuple of (branch, revision, patchspec, changes). - - C{branch} is always valid, although it may be None to let the Source - step use its default branch. There are three possibilities for the - remaining elements: - - (revision=REV, patchspec=None, changes=None): build REV. If REV is - None, build the HEAD revision from the given branch. - - (revision=REV, patchspec=(LEVEL, DIFF), changes=None): checkout REV, - then apply a patch to the source, with C{patch -pPATCHLEVEL = self.chunkSize: - self.merge() - - for w in self.watchers: - w.logChunk(self.step.build, self.step, self, channel, text) - self.length += len(text) - - def addStdout(self, text): - self.addEntry(STDOUT, text) - def addStderr(self, text): - self.addEntry(STDERR, text) - def addHeader(self, text): - self.addEntry(HEADER, text) - - def finish(self): - self.merge() - if self.openfile: - # we don't do an explicit close, because there might be readers - # shareing the filehandle. As soon as they stop reading, the - # filehandle will be released and automatically closed. We will - # do a sync, however, to make sure the log gets saved in case of - # a crash. - os.fsync(self.openfile.fileno()) - del self.openfile - self.finished = True - watchers = self.finishedWatchers - self.finishedWatchers = [] - for w in watchers: - w.callback(self) - self.watchers = [] - - # persistence stuff - def __getstate__(self): - d = self.__dict__.copy() - del d['step'] # filled in upon unpickling - del d['watchers'] - del d['finishedWatchers'] - d['entries'] = [] # let 0.6.4 tolerate the saved log. TODO: really? - if d.has_key('finished'): - del d['finished'] - if d.has_key('openfile'): - del d['openfile'] - return d - - def __setstate__(self, d): - self.__dict__ = d - self.watchers = [] # probably not necessary - self.finishedWatchers = [] # same - # self.step must be filled in by our parent - self.finished = True - - def upgrade(self, logfilename): - """Save our .entries to a new-style offline log file (if necessary), - and modify our in-memory representation to use it. The original - pickled LogFile (inside the pickled Build) won't be modified.""" - self.filename = logfilename - if not os.path.exists(self.getFilename()): - self.openfile = open(self.getFilename(), "w") - self.finished = False - for channel,text in self.entries: - self.addEntry(channel, text) - self.finish() # releases self.openfile, which will be closed - del self.entries - -class HTMLLogFile: - implements(interfaces.IStatusLog) - - filename = None - - def __init__(self, parent, name, logfilename, html): - self.step = parent - self.name = name - self.filename = logfilename - self.html = html - - def getName(self): - return self.name # set in BuildStepStatus.addLog - def getStep(self): - return self.step - - def isFinished(self): - return True - def waitUntilFinished(self): - return defer.succeed(self) - - def hasContents(self): - return True - def getText(self): - return self.html # looks kinda like text - def getTextWithHeaders(self): - return self.html - def getChunks(self): - return [(STDERR, self.html)] - - def subscribe(self, receiver, catchup): - pass - def unsubscribe(self, receiver): - pass - - def finish(self): - pass - - def __getstate__(self): - d = self.__dict__.copy() - del d['step'] - return d - - def upgrade(self, logfilename): - pass - - -class Event: - implements(interfaces.IStatusEvent) - - started = None - finished = None - text = [] - color = None - - # IStatusEvent methods - def getTimes(self): - return (self.started, self.finished) - def getText(self): - return self.text - def getColor(self): - return self.color - def getLogs(self): - return [] - - def finish(self): - self.finished = util.now() - -class TestResult: - implements(interfaces.ITestResult) - - def __init__(self, name, results, text, logs): - assert isinstance(name, tuple) - self.name = name - self.results = results - self.text = text - self.logs = logs - - def getName(self): - return self.name - - def getResults(self): - return self.results - - def getText(self): - return self.text - - def getLogs(self): - return self.logs - - -class BuildSetStatus: - implements(interfaces.IBuildSetStatus) - - def __init__(self, source, reason, builderNames, bsid=None): - self.source = source - self.reason = reason - self.builderNames = builderNames - self.id = bsid - self.successWatchers = [] - self.finishedWatchers = [] - self.stillHopeful = True - self.finished = False - - def setBuildRequestStatuses(self, buildRequestStatuses): - self.buildRequests = buildRequestStatuses - def setResults(self, results): - # the build set succeeds only if all its component builds succeed - self.results = results - def giveUpHope(self): - self.stillHopeful = False - - - def notifySuccessWatchers(self): - for d in self.successWatchers: - d.callback(self) - self.successWatchers = [] - - def notifyFinishedWatchers(self): - self.finished = True - for d in self.finishedWatchers: - d.callback(self) - self.finishedWatchers = [] - - # methods for our clients - - def getSourceStamp(self): - return self.source - def getReason(self): - return self.reason - def getResults(self): - return self.results - def getID(self): - return self.id - - def getBuilderNames(self): - return self.builderNames - def getBuildRequests(self): - return self.buildRequests - def isFinished(self): - return self.finished - - def waitUntilSuccess(self): - if self.finished or not self.stillHopeful: - # the deferreds have already fired - return defer.succeed(self) - d = defer.Deferred() - self.successWatchers.append(d) - return d - - def waitUntilFinished(self): - if self.finished: - return defer.succeed(self) - d = defer.Deferred() - self.finishedWatchers.append(d) - return d - -class BuildRequestStatus: - implements(interfaces.IBuildRequestStatus) - - def __init__(self, source, builderName): - self.source = source - self.builderName = builderName - self.builds = [] # list of BuildStatus objects - self.observers = [] - - def buildStarted(self, build): - self.builds.append(build) - for o in self.observers[:]: - o(build) - - # methods called by our clients - def getSourceStamp(self): - return self.source - def getBuilderName(self): - return self.builderName - def getBuilds(self): - return self.builds - - def subscribe(self, observer): - self.observers.append(observer) - for b in self.builds: - observer(b) - def unsubscribe(self, observer): - self.observers.remove(observer) - - -class BuildStepStatus(styles.Versioned): - """ - I represent a collection of output status for a - L{buildbot.process.step.BuildStep}. - - Statistics contain any information gleaned from a step that is - not in the form of a logfile. As an example, steps that run - tests might gather statistics about the number of passed, failed, - or skipped tests. - - @type color: string - @cvar color: color that this step feels best represents its - current mood. yellow,green,red,orange are the - most likely choices, although purple indicates - an exception - @type progress: L{buildbot.status.progress.StepProgress} - @cvar progress: tracks ETA for the step - @type text: list of strings - @cvar text: list of short texts that describe the command and its status - @type text2: list of strings - @cvar text2: list of short texts added to the overall build description - @type logs: dict of string -> L{buildbot.status.builder.LogFile} - @ivar logs: logs of steps - @type statistics: dict - @ivar statistics: results from running this step - """ - # note that these are created when the Build is set up, before each - # corresponding BuildStep has started. - implements(interfaces.IBuildStepStatus, interfaces.IStatusEvent) - persistenceVersion = 2 - - started = None - finished = None - progress = None - text = [] - color = None - results = (None, []) - text2 = [] - watchers = [] - updates = {} - finishedWatchers = [] - statistics = {} - - def __init__(self, parent): - assert interfaces.IBuildStatus(parent) - self.build = parent - self.logs = [] - self.urls = {} - self.watchers = [] - self.updates = {} - self.finishedWatchers = [] - self.statistics = {} - - def getName(self): - """Returns a short string with the name of this step. This string - may have spaces in it.""" - return self.name - - def getBuild(self): - return self.build - - def getTimes(self): - return (self.started, self.finished) - - def getExpectations(self): - """Returns a list of tuples (name, current, target).""" - if not self.progress: - return [] - ret = [] - metrics = self.progress.progress.keys() - metrics.sort() - for m in metrics: - t = (m, self.progress.progress[m], self.progress.expectations[m]) - ret.append(t) - return ret - - def getLogs(self): - return self.logs - - def getURLs(self): - return self.urls.copy() - - def isFinished(self): - return (self.finished is not None) - - def waitUntilFinished(self): - if self.finished: - d = defer.succeed(self) - else: - d = defer.Deferred() - self.finishedWatchers.append(d) - return d - - # while the step is running, the following methods make sense. - # Afterwards they return None - - def getETA(self): - if self.started is None: - return None # not started yet - if self.finished is not None: - return None # already finished - if not self.progress: - return None # no way to predict - return self.progress.remaining() - - # Once you know the step has finished, the following methods are legal. - # Before this step has finished, they all return None. - - def getText(self): - """Returns a list of strings which describe the step. These are - intended to be displayed in a narrow column. If more space is - available, the caller should join them together with spaces before - presenting them to the user.""" - return self.text - - def getColor(self): - """Returns a single string with the color that should be used to - display this step. 'green', 'orange', 'red', 'yellow' and 'purple' - are the most likely ones.""" - return self.color - - def getResults(self): - """Return a tuple describing the results of the step. - 'result' is one of the constants in L{buildbot.status.builder}: - SUCCESS, WARNINGS, FAILURE, or SKIPPED. - 'strings' is an optional list of strings that the step wants to - append to the overall build's results. These strings are usually - more terse than the ones returned by getText(): in particular, - successful Steps do not usually contribute any text to the - overall build. - - @rtype: tuple of int, list of strings - @returns: (result, strings) - """ - return (self.results, self.text2) - - def hasStatistic(self, name): - """Return true if this step has a value for the given statistic. - """ - return self.statistics.has_key(name) - - def getStatistic(self, name, default=None): - """Return the given statistic, if present - """ - return self.statistics.get(name, default) - - # subscription interface - - def subscribe(self, receiver, updateInterval=10): - # will get logStarted, logFinished, stepETAUpdate - assert receiver not in self.watchers - self.watchers.append(receiver) - self.sendETAUpdate(receiver, updateInterval) - - def sendETAUpdate(self, receiver, updateInterval): - self.updates[receiver] = None - # they might unsubscribe during stepETAUpdate - receiver.stepETAUpdate(self.build, self, - self.getETA(), self.getExpectations()) - if receiver in self.watchers: - self.updates[receiver] = reactor.callLater(updateInterval, - self.sendETAUpdate, - receiver, - updateInterval) - - def unsubscribe(self, receiver): - if receiver in self.watchers: - self.watchers.remove(receiver) - if receiver in self.updates: - if self.updates[receiver] is not None: - self.updates[receiver].cancel() - del self.updates[receiver] - - - # methods to be invoked by the BuildStep - - def setName(self, stepname): - self.name = stepname - - def setProgress(self, stepprogress): - self.progress = stepprogress - - def stepStarted(self): - self.started = util.now() - if self.build: - self.build.stepStarted(self) - - def addLog(self, name): - assert self.started # addLog before stepStarted won't notify watchers - logfilename = self.build.generateLogfileName(self.name, name) - log = LogFile(self, name, logfilename) - self.logs.append(log) - for w in self.watchers: - receiver = w.logStarted(self.build, self, log) - if receiver: - log.subscribe(receiver, True) - d = log.waitUntilFinished() - d.addCallback(lambda log: log.unsubscribe(receiver)) - d = log.waitUntilFinished() - d.addCallback(self.logFinished) - return log - - def addHTMLLog(self, name, html): - assert self.started # addLog before stepStarted won't notify watchers - logfilename = self.build.generateLogfileName(self.name, name) - log = HTMLLogFile(self, name, logfilename, html) - self.logs.append(log) - for w in self.watchers: - receiver = w.logStarted(self.build, self, log) - # TODO: think about this: there isn't much point in letting - # them subscribe - #if receiver: - # log.subscribe(receiver, True) - w.logFinished(self.build, self, log) - - def logFinished(self, log): - for w in self.watchers: - w.logFinished(self.build, self, log) - - def addURL(self, name, url): - self.urls[name] = url - - def setColor(self, color): - self.color = color - def setText(self, text): - self.text = text - def setText2(self, text): - self.text2 = text - - def setStatistic(self, name, value): - """Set the given statistic. Usually called by subclasses. - """ - self.statistics[name] = value - - def stepFinished(self, results): - self.finished = util.now() - self.results = results - for loog in self.logs: - if not loog.isFinished(): - loog.finish() - - for r in self.updates.keys(): - if self.updates[r] is not None: - self.updates[r].cancel() - del self.updates[r] - - watchers = self.finishedWatchers - self.finishedWatchers = [] - for w in watchers: - w.callback(self) - - # persistence - - def __getstate__(self): - d = styles.Versioned.__getstate__(self) - del d['build'] # filled in when loading - if d.has_key('progress'): - del d['progress'] - del d['watchers'] - del d['finishedWatchers'] - del d['updates'] - return d - - def __setstate__(self, d): - styles.Versioned.__setstate__(self, d) - # self.build must be filled in by our parent - for loog in self.logs: - loog.step = self - - def upgradeToVersion1(self): - if not hasattr(self, "urls"): - self.urls = {} - - def upgradeToVersion2(self): - if not hasattr(self, "statistics"): - self.statistics = {} - - -class BuildStatus(styles.Versioned): - implements(interfaces.IBuildStatus, interfaces.IStatusEvent) - persistenceVersion = 3 - - source = None - reason = None - changes = [] - blamelist = [] - progress = None - started = None - finished = None - currentStep = None - text = [] - color = None - results = None - slavename = "???" - - # these lists/dicts are defined here so that unserialized instances have - # (empty) values. They are set in __init__ to new objects to make sure - # each instance gets its own copy. - watchers = [] - updates = {} - finishedWatchers = [] - testResults = {} - - def __init__(self, parent, number): - """ - @type parent: L{BuilderStatus} - @type number: int - """ - assert interfaces.IBuilderStatus(parent) - self.builder = parent - self.number = number - self.watchers = [] - self.updates = {} - self.finishedWatchers = [] - self.steps = [] - self.testResults = {} - self.properties = Properties() - - # IBuildStatus - - def getBuilder(self): - """ - @rtype: L{BuilderStatus} - """ - return self.builder - - def getProperty(self, propname): - return self.properties[propname] - - def getProperties(self): - return self.properties - - def getNumber(self): - return self.number - - def getPreviousBuild(self): - if self.number == 0: - return None - return self.builder.getBuild(self.number-1) - - def getSourceStamp(self, absolute=False): - if not absolute or not self.properties.has_key('got_revision'): - return self.source - return self.source.getAbsoluteSourceStamp(self.properties['got_revision']) - - def getReason(self): - return self.reason - - def getChanges(self): - return self.changes - - def getResponsibleUsers(self): - return self.blamelist - - def getInterestedUsers(self): - # TODO: the Builder should add others: sheriffs, domain-owners - return self.blamelist - - def getSteps(self): - """Return a list of IBuildStepStatus objects. For invariant builds - (those which always use the same set of Steps), this should be the - complete list, however some of the steps may not have started yet - (step.getTimes()[0] will be None). For variant builds, this may not - be complete (asking again later may give you more of them).""" - return self.steps - - def getTimes(self): - return (self.started, self.finished) - - _sentinel = [] # used as a sentinel to indicate unspecified initial_value - def getSummaryStatistic(self, name, summary_fn, initial_value=_sentinel): - """Summarize the named statistic over all steps in which it - exists, using combination_fn and initial_value to combine multiple - results into a single result. This translates to a call to Python's - X{reduce}:: - return reduce(summary_fn, step_stats_list, initial_value) - """ - step_stats_list = [ - st.getStatistic(name) - for st in self.steps - if st.hasStatistic(name) ] - if initial_value is self._sentinel: - return reduce(summary_fn, step_stats_list) - else: - return reduce(summary_fn, step_stats_list, initial_value) - - def isFinished(self): - return (self.finished is not None) - - def waitUntilFinished(self): - if self.finished: - d = defer.succeed(self) - else: - d = defer.Deferred() - self.finishedWatchers.append(d) - return d - - # while the build is running, the following methods make sense. - # Afterwards they return None - - def getETA(self): - if self.finished is not None: - return None - if not self.progress: - return None - eta = self.progress.eta() - if eta is None: - return None - return eta - util.now() - - def getCurrentStep(self): - return self.currentStep - - # Once you know the build has finished, the following methods are legal. - # Before ths build has finished, they all return None. - - def getText(self): - text = [] - text.extend(self.text) - for s in self.steps: - text.extend(s.text2) - return text - - def getColor(self): - return self.color - - def getResults(self): - return self.results - - def getSlavename(self): - return self.slavename - - def getTestResults(self): - return self.testResults - - def getLogs(self): - # TODO: steps should contribute significant logs instead of this - # hack, which returns every log from every step. The logs should get - # names like "compile" and "test" instead of "compile.output" - logs = [] - for s in self.steps: - for log in s.getLogs(): - logs.append(log) - return logs - - # subscription interface - - def subscribe(self, receiver, updateInterval=None): - # will receive stepStarted and stepFinished messages - # and maybe buildETAUpdate - self.watchers.append(receiver) - if updateInterval is not None: - self.sendETAUpdate(receiver, updateInterval) - - def sendETAUpdate(self, receiver, updateInterval): - self.updates[receiver] = None - ETA = self.getETA() - if ETA is not None: - receiver.buildETAUpdate(self, self.getETA()) - # they might have unsubscribed during buildETAUpdate - if receiver in self.watchers: - self.updates[receiver] = reactor.callLater(updateInterval, - self.sendETAUpdate, - receiver, - updateInterval) - - def unsubscribe(self, receiver): - if receiver in self.watchers: - self.watchers.remove(receiver) - if receiver in self.updates: - if self.updates[receiver] is not None: - self.updates[receiver].cancel() - del self.updates[receiver] - - # methods for the base.Build to invoke - - def addStepWithName(self, name): - """The Build is setting up, and has added a new BuildStep to its - list. Create a BuildStepStatus object to which it can send status - updates.""" - - s = BuildStepStatus(self) - s.setName(name) - self.steps.append(s) - return s - - def setProperty(self, propname, value, source): - self.properties.setProperty(propname, value, source) - - def addTestResult(self, result): - self.testResults[result.getName()] = result - - def setSourceStamp(self, sourceStamp): - self.source = sourceStamp - self.changes = self.source.changes - - def setReason(self, reason): - self.reason = reason - def setBlamelist(self, blamelist): - self.blamelist = blamelist - def setProgress(self, progress): - self.progress = progress - - def buildStarted(self, build): - """The Build has been set up and is about to be started. It can now - be safely queried, so it is time to announce the new build.""" - - self.started = util.now() - # now that we're ready to report status, let the BuilderStatus tell - # the world about us - self.builder.buildStarted(self) - - def setSlavename(self, slavename): - self.slavename = slavename - - def setText(self, text): - assert isinstance(text, (list, tuple)) - self.text = text - def setColor(self, color): - self.color = color - def setResults(self, results): - self.results = results - - def buildFinished(self): - self.currentStep = None - self.finished = util.now() - - for r in self.updates.keys(): - if self.updates[r] is not None: - self.updates[r].cancel() - del self.updates[r] - - watchers = self.finishedWatchers - self.finishedWatchers = [] - for w in watchers: - w.callback(self) - - # methods called by our BuildStepStatus children - - def stepStarted(self, step): - self.currentStep = step - name = self.getBuilder().getName() - for w in self.watchers: - receiver = w.stepStarted(self, step) - if receiver: - if type(receiver) == type(()): - step.subscribe(receiver[0], receiver[1]) - else: - step.subscribe(receiver) - d = step.waitUntilFinished() - d.addCallback(lambda step: step.unsubscribe(receiver)) - - step.waitUntilFinished().addCallback(self._stepFinished) - - def _stepFinished(self, step): - results = step.getResults() - for w in self.watchers: - w.stepFinished(self, step, results) - - # methods called by our BuilderStatus parent - - def pruneLogs(self): - # this build is somewhat old: remove the build logs to save space - # TODO: delete logs visible through IBuildStatus.getLogs - for s in self.steps: - s.pruneLogs() - - def pruneSteps(self): - # this build is very old: remove the build steps too - self.steps = [] - - # persistence stuff - - def generateLogfileName(self, stepname, logname): - """Return a filename (relative to the Builder's base directory) where - the logfile's contents can be stored uniquely. - - The base filename is made by combining our build number, the Step's - name, and the log's name, then removing unsuitable characters. The - filename is then made unique by appending _0, _1, etc, until it does - not collide with any other logfile. - - These files are kept in the Builder's basedir (rather than a - per-Build subdirectory) because that makes cleanup easier: cron and - find will help get rid of the old logs, but the empty directories are - more of a hassle to remove.""" - - starting_filename = "%d-log-%s-%s" % (self.number, stepname, logname) - starting_filename = re.sub(r'[^\w\.\-]', '_', starting_filename) - # now make it unique - unique_counter = 0 - filename = starting_filename - while filename in [l.filename - for step in self.steps - for l in step.getLogs() - if l.filename]: - filename = "%s_%d" % (starting_filename, unique_counter) - unique_counter += 1 - return filename - - def __getstate__(self): - d = styles.Versioned.__getstate__(self) - # for now, a serialized Build is always "finished". We will never - # save unfinished builds. - if not self.finished: - d['finished'] = True - # TODO: push an "interrupted" step so it is clear that the build - # was interrupted. The builder will have a 'shutdown' event, but - # someone looking at just this build will be confused as to why - # the last log is truncated. - del d['builder'] # filled in by our parent when loading - del d['watchers'] - del d['updates'] - del d['finishedWatchers'] - return d - - def __setstate__(self, d): - styles.Versioned.__setstate__(self, d) - # self.builder must be filled in by our parent when loading - for step in self.steps: - step.build = self - self.watchers = [] - self.updates = {} - self.finishedWatchers = [] - - def upgradeToVersion1(self): - if hasattr(self, "sourceStamp"): - # the old .sourceStamp attribute wasn't actually very useful - maxChangeNumber, patch = self.sourceStamp - changes = getattr(self, 'changes', []) - source = sourcestamp.SourceStamp(branch=None, - revision=None, - patch=patch, - changes=changes) - self.source = source - self.changes = source.changes - del self.sourceStamp - - def upgradeToVersion2(self): - self.properties = {} - - def upgradeToVersion3(self): - # in version 3, self.properties became a Properties object - propdict = self.properties - self.properties = Properties() - self.properties.update(propdict, "Upgrade from previous version") - - def upgradeLogfiles(self): - # upgrade any LogFiles that need it. This must occur after we've been - # attached to our Builder, and after we know about all LogFiles of - # all Steps (to get the filenames right). - assert self.builder - for s in self.steps: - for l in s.getLogs(): - if l.filename: - pass # new-style, log contents are on disk - else: - logfilename = self.generateLogfileName(s.name, l.name) - # let the logfile update its .filename pointer, - # transferring its contents onto disk if necessary - l.upgrade(logfilename) - - def saveYourself(self): - filename = os.path.join(self.builder.basedir, "%d" % self.number) - if os.path.isdir(filename): - # leftover from 0.5.0, which stored builds in directories - shutil.rmtree(filename, ignore_errors=True) - tmpfilename = filename + ".tmp" - try: - dump(self, open(tmpfilename, "wb"), -1) - if sys.platform == 'win32': - # windows cannot rename a file on top of an existing one, so - # fall back to delete-first. There are ways this can fail and - # lose the builder's history, so we avoid using it in the - # general (non-windows) case - if os.path.exists(filename): - os.unlink(filename) - os.rename(tmpfilename, filename) - except: - log.msg("unable to save build %s-#%d" % (self.builder.name, - self.number)) - log.err() - - - -class BuilderStatus(styles.Versioned): - """I handle status information for a single process.base.Builder object. - That object sends status changes to me (frequently as Events), and I - provide them on demand to the various status recipients, like the HTML - waterfall display and the live status clients. It also sends build - summaries to me, which I log and provide to status clients who aren't - interested in seeing details of the individual build steps. - - I am responsible for maintaining the list of historic Events and Builds, - pruning old ones, and loading them from / saving them to disk. - - I live in the buildbot.process.base.Builder object, in the - .builder_status attribute. - - @type category: string - @ivar category: user-defined category this builder belongs to; can be - used to filter on in status clients - """ - - implements(interfaces.IBuilderStatus, interfaces.IEventSource) - persistenceVersion = 1 - - # these limit the amount of memory we consume, as well as the size of the - # main Builder pickle. The Build and LogFile pickles on disk must be - # handled separately. - buildCacheSize = 30 - buildHorizon = 100 # forget builds beyond this - stepHorizon = 50 # forget steps in builds beyond this - - category = None - currentBigState = "offline" # or idle/waiting/interlocked/building - basedir = None # filled in by our parent - - def __init__(self, buildername, category=None): - self.name = buildername - self.category = category - - self.slavenames = [] - self.events = [] - # these three hold Events, and are used to retrieve the current - # state of the boxes. - self.lastBuildStatus = None - #self.currentBig = None - #self.currentSmall = None - self.currentBuilds = [] - self.pendingBuilds = [] - self.nextBuild = None - self.watchers = [] - self.buildCache = [] # TODO: age builds out of the cache - - # persistence - - def __getstate__(self): - # when saving, don't record transient stuff like what builds are - # currently running, because they won't be there when we start back - # up. Nor do we save self.watchers, nor anything that gets set by our - # parent like .basedir and .status - d = styles.Versioned.__getstate__(self) - d['watchers'] = [] - del d['buildCache'] - for b in self.currentBuilds: - b.saveYourself() - # TODO: push a 'hey, build was interrupted' event - del d['currentBuilds'] - del d['pendingBuilds'] - del d['currentBigState'] - del d['basedir'] - del d['status'] - del d['nextBuildNumber'] - return d - - def __setstate__(self, d): - # when loading, re-initialize the transient stuff. Remember that - # upgradeToVersion1 and such will be called after this finishes. - styles.Versioned.__setstate__(self, d) - self.buildCache = [] - self.currentBuilds = [] - self.pendingBuilds = [] - self.watchers = [] - self.slavenames = [] - # self.basedir must be filled in by our parent - # self.status must be filled in by our parent - - def upgradeToVersion1(self): - if hasattr(self, 'slavename'): - self.slavenames = [self.slavename] - del self.slavename - if hasattr(self, 'nextBuildNumber'): - del self.nextBuildNumber # determineNextBuildNumber chooses this - - def determineNextBuildNumber(self): - """Scan our directory of saved BuildStatus instances to determine - what our self.nextBuildNumber should be. Set it one larger than the - highest-numbered build we discover. This is called by the top-level - Status object shortly after we are created or loaded from disk. - """ - existing_builds = [int(f) - for f in os.listdir(self.basedir) - if re.match("^\d+$", f)] - if existing_builds: - self.nextBuildNumber = max(existing_builds) + 1 - else: - self.nextBuildNumber = 0 - - def saveYourself(self): - for b in self.buildCache: - if not b.isFinished: - # interrupted build, need to save it anyway. - # BuildStatus.saveYourself will mark it as interrupted. - b.saveYourself() - filename = os.path.join(self.basedir, "builder") - tmpfilename = filename + ".tmp" - try: - dump(self, open(tmpfilename, "wb"), -1) - if sys.platform == 'win32': - # windows cannot rename a file on top of an existing one - if os.path.exists(filename): - os.unlink(filename) - os.rename(tmpfilename, filename) - except: - log.msg("unable to save builder %s" % self.name) - log.err() - - - # build cache management - - def addBuildToCache(self, build): - if build in self.buildCache: - return - self.buildCache.append(build) - while len(self.buildCache) > self.buildCacheSize: - self.buildCache.pop(0) - - def getBuildByNumber(self, number): - for b in self.currentBuilds: - if b.number == number: - return b - for build in self.buildCache: - if build.number == number: - return build - filename = os.path.join(self.basedir, "%d" % number) - try: - build = load(open(filename, "rb")) - styles.doUpgrade() - build.builder = self - # handle LogFiles from after 0.5.0 and before 0.6.5 - build.upgradeLogfiles() - self.addBuildToCache(build) - return build - except IOError: - raise IndexError("no such build %d" % number) - except EOFError: - raise IndexError("corrupted build pickle %d" % number) - - def prune(self): - return # TODO: change this to walk through the filesystem - # first, blow away all builds beyond our build horizon - self.builds = self.builds[-self.buildHorizon:] - # then prune steps in builds past the step horizon - for b in self.builds[0:-self.stepHorizon]: - b.pruneSteps() - - # IBuilderStatus methods - def getName(self): - return self.name - - def getState(self): - return (self.currentBigState, self.currentBuilds) - - def getSlaves(self): - return [self.status.getSlave(name) for name in self.slavenames] - - def getPendingBuilds(self): - return self.pendingBuilds - - def getCurrentBuilds(self): - return self.currentBuilds - - def getLastFinishedBuild(self): - b = self.getBuild(-1) - if not (b and b.isFinished()): - b = self.getBuild(-2) - return b - - def getBuild(self, number): - if number < 0: - number = self.nextBuildNumber + number - if number < 0 or number >= self.nextBuildNumber: - return None - - try: - return self.getBuildByNumber(number) - except IndexError: - return None - - def getEvent(self, number): - try: - return self.events[number] - except IndexError: - return None - - def generateFinishedBuilds(self, branches=[], - num_builds=None, - max_buildnum=None, - finished_before=None, - max_search=200): - got = 0 - for Nb in itertools.count(1): - if Nb > self.nextBuildNumber: - break - if Nb > max_search: - break - build = self.getBuild(-Nb) - if build is None: - continue - if max_buildnum is not None: - if build.getNumber() > max_buildnum: - continue - if not build.isFinished(): - continue - if finished_before is not None: - start, end = build.getTimes() - if end >= finished_before: - continue - if branches: - if build.getSourceStamp().branch not in branches: - continue - got += 1 - yield build - if num_builds is not None: - if got >= num_builds: - return - - def eventGenerator(self, branches=[]): - """This function creates a generator which will provide all of this - Builder's status events, starting with the most recent and - progressing backwards in time. """ - - # remember the oldest-to-earliest flow here. "next" means earlier. - - # TODO: interleave build steps and self.events by timestamp. - # TODO: um, I think we're already doing that. - - # TODO: there's probably something clever we could do here to - # interleave two event streams (one from self.getBuild and the other - # from self.getEvent), which would be simpler than this control flow - - eventIndex = -1 - e = self.getEvent(eventIndex) - for Nb in range(1, self.nextBuildNumber+1): - b = self.getBuild(-Nb) - if not b: - break - if branches and not b.getSourceStamp().branch in branches: - continue - steps = b.getSteps() - for Ns in range(1, len(steps)+1): - if steps[-Ns].started: - step_start = steps[-Ns].getTimes()[0] - while e is not None and e.getTimes()[0] > step_start: - yield e - eventIndex -= 1 - e = self.getEvent(eventIndex) - yield steps[-Ns] - yield b - while e is not None: - yield e - eventIndex -= 1 - e = self.getEvent(eventIndex) - - def subscribe(self, receiver): - # will get builderChangedState, buildStarted, and buildFinished - self.watchers.append(receiver) - self.publishState(receiver) - - def unsubscribe(self, receiver): - self.watchers.remove(receiver) - - ## Builder interface (methods called by the Builder which feeds us) - - def setSlavenames(self, names): - self.slavenames = names - - def addEvent(self, text=[], color=None): - # this adds a duration event. When it is done, the user should call - # e.finish(). They can also mangle it by modifying .text and .color - e = Event() - e.started = util.now() - e.text = text - e.color = color - self.events.append(e) - return e # they are free to mangle it further - - def addPointEvent(self, text=[], color=None): - # this adds a point event, one which occurs as a single atomic - # instant of time. - e = Event() - e.started = util.now() - e.finished = 0 - e.text = text - e.color = color - self.events.append(e) - return e # for consistency, but they really shouldn't touch it - - def setBigState(self, state): - needToUpdate = state != self.currentBigState - self.currentBigState = state - if needToUpdate: - self.publishState() - - def publishState(self, target=None): - state = self.currentBigState - - if target is not None: - # unicast - target.builderChangedState(self.name, state) - return - for w in self.watchers: - w.builderChangedState(self.name, state) - - def newBuild(self): - """The Builder has decided to start a build, but the Build object is - not yet ready to report status (it has not finished creating the - Steps). Create a BuildStatus object that it can use.""" - number = self.nextBuildNumber - self.nextBuildNumber += 1 - # TODO: self.saveYourself(), to make sure we don't forget about the - # build number we've just allocated. This is not quite as important - # as it was before we switch to determineNextBuildNumber, but I think - # it may still be useful to have the new build save itself. - s = BuildStatus(self, number) - s.waitUntilFinished().addCallback(self._buildFinished) - return s - - def addBuildRequest(self, brstatus): - self.pendingBuilds.append(brstatus) - def removeBuildRequest(self, brstatus): - self.pendingBuilds.remove(brstatus) - - # buildStarted is called by our child BuildStatus instances - def buildStarted(self, s): - """Now the BuildStatus object is ready to go (it knows all of its - Steps, its ETA, etc), so it is safe to notify our watchers.""" - - assert s.builder is self # paranoia - assert s.number == self.nextBuildNumber - 1 - assert s not in self.currentBuilds - self.currentBuilds.append(s) - self.addBuildToCache(s) - - # now that the BuildStatus is prepared to answer queries, we can - # announce the new build to all our watchers - - for w in self.watchers: # TODO: maybe do this later? callLater(0)? - receiver = w.buildStarted(self.getName(), s) - if receiver: - if type(receiver) == type(()): - s.subscribe(receiver[0], receiver[1]) - else: - s.subscribe(receiver) - d = s.waitUntilFinished() - d.addCallback(lambda s: s.unsubscribe(receiver)) - - - def _buildFinished(self, s): - assert s in self.currentBuilds - s.saveYourself() - self.currentBuilds.remove(s) - - name = self.getName() - results = s.getResults() - for w in self.watchers: - w.buildFinished(name, s, results) - - self.prune() # conserve disk - - - # waterfall display (history) - - # I want some kind of build event that holds everything about the build: - # why, what changes went into it, the results of the build, itemized - # test results, etc. But, I do kind of need something to be inserted in - # the event log first, because intermixing step events and the larger - # build event is fraught with peril. Maybe an Event-like-thing that - # doesn't have a file in it but does have links. Hmm, that's exactly - # what it does now. The only difference would be that this event isn't - # pushed to the clients. - - # publish to clients - def sendLastBuildStatus(self, client): - #client.newLastBuildStatus(self.lastBuildStatus) - pass - def sendCurrentActivityBigToEveryone(self): - for s in self.subscribers: - self.sendCurrentActivityBig(s) - def sendCurrentActivityBig(self, client): - state = self.currentBigState - if state == "offline": - client.currentlyOffline() - elif state == "idle": - client.currentlyIdle() - elif state == "building": - client.currentlyBuilding() - else: - log.msg("Hey, self.currentBigState is weird:", state) - - - ## HTML display interface - - def getEventNumbered(self, num): - # deal with dropped events, pruned events - first = self.events[0].number - if first + len(self.events)-1 != self.events[-1].number: - log.msg(self, - "lost an event somewhere: [0] is %d, [%d] is %d" % \ - (self.events[0].number, - len(self.events) - 1, - self.events[-1].number)) - for e in self.events: - log.msg("e[%d]: " % e.number, e) - return None - offset = num - first - log.msg(self, "offset", offset) - try: - return self.events[offset] - except IndexError: - return None - - ## Persistence of Status - def loadYourOldEvents(self): - if hasattr(self, "allEvents"): - # first time, nothing to get from file. Note that this is only if - # the Application gets .run() . If it gets .save()'ed, then the - # .allEvents attribute goes away in the initial __getstate__ and - # we try to load a non-existent file. - return - self.allEvents = self.loadFile("events", []) - if self.allEvents: - self.nextEventNumber = self.allEvents[-1].number + 1 - else: - self.nextEventNumber = 0 - def saveYourOldEvents(self): - self.saveFile("events", self.allEvents) - - ## clients - - def addClient(self, client): - if client not in self.subscribers: - self.subscribers.append(client) - self.sendLastBuildStatus(client) - self.sendCurrentActivityBig(client) - client.newEvent(self.currentSmall) - def removeClient(self, client): - if client in self.subscribers: - self.subscribers.remove(client) - -class SlaveStatus: - implements(interfaces.ISlaveStatus) - - admin = None - host = None - connected = False - - def __init__(self, name): - self.name = name - self._lastMessageReceived = 0 - self.runningBuilds = [] - - def getName(self): - return self.name - def getAdmin(self): - return self.admin - def getHost(self): - return self.host - def isConnected(self): - return self.connected - def lastMessageReceived(self): - return self._lastMessageReceived - def getRunningBuilds(self): - return self.runningBuilds - - def setAdmin(self, admin): - self.admin = admin - def setHost(self, host): - self.host = host - def setConnected(self, isConnected): - self.connected = isConnected - def setLastMessageReceived(self, when): - self._lastMessageReceived = when - - def buildStarted(self, build): - self.runningBuilds.append(build) - def buildFinished(self, build): - self.runningBuilds.remove(build) - -class Status: - """ - I represent the status of the buildmaster. - """ - implements(interfaces.IStatus) - - def __init__(self, botmaster, basedir): - """ - @type botmaster: L{buildbot.master.BotMaster} - @param botmaster: the Status object uses C{.botmaster} to get at - both the L{buildbot.master.BuildMaster} (for - various buildbot-wide parameters) and the - actual Builders (to get at their L{BuilderStatus} - objects). It is not allowed to change or influence - anything through this reference. - @type basedir: string - @param basedir: this provides a base directory in which saved status - information (changes.pck, saved Build status - pickles) can be stored - """ - self.botmaster = botmaster - self.basedir = basedir - self.watchers = [] - self.activeBuildSets = [] - assert os.path.isdir(basedir) - - - # methods called by our clients - - def getProjectName(self): - return self.botmaster.parent.projectName - def getProjectURL(self): - return self.botmaster.parent.projectURL - def getBuildbotURL(self): - return self.botmaster.parent.buildbotURL - - def getURLForThing(self, thing): - prefix = self.getBuildbotURL() - if not prefix: - return None - if interfaces.IStatus.providedBy(thing): - return prefix - if interfaces.ISchedulerStatus.providedBy(thing): - pass - if interfaces.IBuilderStatus.providedBy(thing): - builder = thing - return prefix + "builders/%s" % ( - urllib.quote(builder.getName(), safe=''), - ) - if interfaces.IBuildStatus.providedBy(thing): - build = thing - builder = build.getBuilder() - return prefix + "builders/%s/builds/%d" % ( - urllib.quote(builder.getName(), safe=''), - build.getNumber()) - if interfaces.IBuildStepStatus.providedBy(thing): - step = thing - build = step.getBuild() - builder = build.getBuilder() - return prefix + "builders/%s/builds/%d/steps/%s" % ( - urllib.quote(builder.getName(), safe=''), - build.getNumber(), - urllib.quote(step.getName(), safe='')) - # IBuildSetStatus - # IBuildRequestStatus - # ISlaveStatus - - # IStatusEvent - if interfaces.IStatusEvent.providedBy(thing): - from buildbot.changes import changes - # TODO: this is goofy, create IChange or something - if isinstance(thing, changes.Change): - change = thing - return "%schanges/%d" % (prefix, change.number) - - if interfaces.IStatusLog.providedBy(thing): - log = thing - step = log.getStep() - build = step.getBuild() - builder = build.getBuilder() - - logs = step.getLogs() - for i in range(len(logs)): - if log is logs[i]: - lognum = i - break - else: - return None - return prefix + "builders/%s/builds/%d/steps/%s/logs/%d" % ( - urllib.quote(builder.getName(), safe=''), - build.getNumber(), - urllib.quote(step.getName(), safe=''), - lognum) - - def getChangeSources(self): - return list(self.botmaster.parent.change_svc) - - def getChange(self, number): - return self.botmaster.parent.change_svc.getChangeNumbered(number) - - def getSchedulers(self): - return self.botmaster.parent.allSchedulers() - - def getBuilderNames(self, categories=None): - if categories == None: - return self.botmaster.builderNames[:] # don't let them break it - - l = [] - # respect addition order - for name in self.botmaster.builderNames: - builder = self.botmaster.builders[name] - if builder.builder_status.category in categories: - l.append(name) - return l - - def getBuilder(self, name): - """ - @rtype: L{BuilderStatus} - """ - return self.botmaster.builders[name].builder_status - - def getSlaveNames(self): - return self.botmaster.slaves.keys() - - def getSlave(self, slavename): - return self.botmaster.slaves[slavename].slave_status - - def getBuildSets(self): - return self.activeBuildSets[:] - - def generateFinishedBuilds(self, builders=[], branches=[], - num_builds=None, finished_before=None, - max_search=200): - - def want_builder(bn): - if builders: - return bn in builders - return True - builder_names = [bn - for bn in self.getBuilderNames() - if want_builder(bn)] - - # 'sources' is a list of generators, one for each Builder we're - # using. When the generator is exhausted, it is replaced in this list - # with None. - sources = [] - for bn in builder_names: - b = self.getBuilder(bn) - g = b.generateFinishedBuilds(branches, - finished_before=finished_before, - max_search=max_search) - sources.append(g) - - # next_build the next build from each source - next_build = [None] * len(sources) - - def refill(): - for i,g in enumerate(sources): - if next_build[i]: - # already filled - continue - if not g: - # already exhausted - continue - try: - next_build[i] = g.next() - except StopIteration: - next_build[i] = None - sources[i] = None - - got = 0 - while True: - refill() - # find the latest build among all the candidates - candidates = [(i, b, b.getTimes()[1]) - for i,b in enumerate(next_build) - if b is not None] - candidates.sort(lambda x,y: cmp(x[2], y[2])) - if not candidates: - return - - # and remove it from the list - i, build, finshed_time = candidates[-1] - next_build[i] = None - got += 1 - yield build - if num_builds is not None: - if got >= num_builds: - return - - def subscribe(self, target): - self.watchers.append(target) - for name in self.botmaster.builderNames: - self.announceNewBuilder(target, name, self.getBuilder(name)) - def unsubscribe(self, target): - self.watchers.remove(target) - - - # methods called by upstream objects - - def announceNewBuilder(self, target, name, builder_status): - t = target.builderAdded(name, builder_status) - if t: - builder_status.subscribe(t) - - def builderAdded(self, name, basedir, category=None): - """ - @rtype: L{BuilderStatus} - """ - filename = os.path.join(self.basedir, basedir, "builder") - log.msg("trying to load status pickle from %s" % filename) - builder_status = None - try: - builder_status = load(open(filename, "rb")) - styles.doUpgrade() - except IOError: - log.msg("no saved status pickle, creating a new one") - except: - log.msg("error while loading status pickle, creating a new one") - log.msg("error follows:") - log.err() - if not builder_status: - builder_status = BuilderStatus(name, category) - builder_status.addPointEvent(["builder", "created"]) - log.msg("added builder %s in category %s" % (name, category)) - # an unpickled object might not have category set from before, - # so set it here to make sure - builder_status.category = category - builder_status.basedir = os.path.join(self.basedir, basedir) - builder_status.name = name # it might have been updated - builder_status.status = self - - if not os.path.isdir(builder_status.basedir): - os.mkdir(builder_status.basedir) - builder_status.determineNextBuildNumber() - - builder_status.setBigState("offline") - - for t in self.watchers: - self.announceNewBuilder(t, name, builder_status) - - return builder_status - - def builderRemoved(self, name): - for t in self.watchers: - t.builderRemoved(name) - - def prune(self): - for b in self.botmaster.builders.values(): - b.builder_status.prune() - - def buildsetSubmitted(self, bss): - self.activeBuildSets.append(bss) - bss.waitUntilFinished().addCallback(self.activeBuildSets.remove) - for t in self.watchers: - t.buildsetSubmitted(bss) diff --git a/tools/buildbot/pylibs/buildbot/status/client.py b/tools/buildbot/pylibs/buildbot/status/client.py deleted file mode 100644 index c160c37..0000000 --- a/tools/buildbot/pylibs/buildbot/status/client.py +++ /dev/null @@ -1,568 +0,0 @@ -# -*- test-case-name: buildbot.test.test_status -*- - -from twisted.spread import pb -from twisted.python import components, log as twlog -from twisted.internet import reactor -from twisted.application import strports -from twisted.cred import portal, checkers - -from buildbot import interfaces -from zope.interface import Interface, implements -from buildbot.status import builder, base -from buildbot.changes import changes - -class IRemote(Interface): - pass - -def makeRemote(obj): - # we want IRemote(None) to be None, but you can't really do that with - # adapters, so we fake it - if obj is None: - return None - return IRemote(obj) - - -class RemoteBuildSet(pb.Referenceable): - def __init__(self, buildset): - self.b = buildset - - def remote_getSourceStamp(self): - return self.b.getSourceStamp() - - def remote_getReason(self): - return self.b.getReason() - - def remote_getID(self): - return self.b.getID() - - def remote_getBuilderNames(self): - return self.b.getBuilderNames() - - def remote_getBuildRequests(self): - """Returns a list of (builderName, BuildRequest) tuples.""" - return [(br.getBuilderName(), IRemote(br)) - for br in self.b.getBuildRequests()] - - def remote_isFinished(self): - return self.b.isFinished() - - def remote_waitUntilSuccess(self): - d = self.b.waitUntilSuccess() - d.addCallback(lambda res: self) - return d - - def remote_waitUntilFinished(self): - d = self.b.waitUntilFinished() - d.addCallback(lambda res: self) - return d - - def remote_getResults(self): - return self.b.getResults() - -components.registerAdapter(RemoteBuildSet, - interfaces.IBuildSetStatus, IRemote) - - -class RemoteBuilder(pb.Referenceable): - def __init__(self, builder): - self.b = builder - - def remote_getName(self): - return self.b.getName() - - def remote_getState(self): - state, builds = self.b.getState() - return (state, - None, # TODO: remove leftover ETA - [makeRemote(b) for b in builds]) - - def remote_getSlaves(self): - return [IRemote(s) for s in self.b.getSlaves()] - - def remote_getLastFinishedBuild(self): - return makeRemote(self.b.getLastFinishedBuild()) - - def remote_getCurrentBuilds(self): - return [IRemote(b) for b in self.b.getCurrentBuilds()] - - def remote_getBuild(self, number): - return makeRemote(self.b.getBuild(number)) - - def remote_getEvent(self, number): - return IRemote(self.b.getEvent(number)) - -components.registerAdapter(RemoteBuilder, - interfaces.IBuilderStatus, IRemote) - - -class RemoteBuildRequest(pb.Referenceable): - def __init__(self, buildreq): - self.b = buildreq - self.observers = [] - - def remote_getSourceStamp(self): - return self.b.getSourceStamp() - - def remote_getBuilderName(self): - return self.b.getBuilderName() - - def remote_subscribe(self, observer): - """The observer's remote_newbuild method will be called (with two - arguments: the RemoteBuild object, and our builderName) for each new - Build that is created to handle this BuildRequest.""" - self.observers.append(observer) - def send(bs): - d = observer.callRemote("newbuild", - IRemote(bs), self.b.getBuilderName()) - d.addErrback(lambda err: None) - reactor.callLater(0, self.b.subscribe, send) - - def remote_unsubscribe(self, observer): - # PB (well, at least oldpb) doesn't re-use RemoteReference instances, - # so sending the same object across the wire twice will result in two - # separate objects that compare as equal ('a is not b' and 'a == b'). - # That means we can't use a simple 'self.observers.remove(observer)' - # here. - for o in self.observers: - if o == observer: - self.observers.remove(o) - -components.registerAdapter(RemoteBuildRequest, - interfaces.IBuildRequestStatus, IRemote) - -class RemoteBuild(pb.Referenceable): - def __init__(self, build): - self.b = build - self.observers = [] - - def remote_getBuilderName(self): - return self.b.getBuilder().getName() - - def remote_getNumber(self): - return self.b.getNumber() - - def remote_getReason(self): - return self.b.getReason() - - def remote_getChanges(self): - return [IRemote(c) for c in self.b.getChanges()] - - def remote_getResponsibleUsers(self): - return self.b.getResponsibleUsers() - - def remote_getSteps(self): - return [IRemote(s) for s in self.b.getSteps()] - - def remote_getTimes(self): - return self.b.getTimes() - - def remote_isFinished(self): - return self.b.isFinished() - - def remote_waitUntilFinished(self): - # the Deferred returned by callRemote() will fire when this build is - # finished - d = self.b.waitUntilFinished() - d.addCallback(lambda res: self) - return d - - def remote_getETA(self): - return self.b.getETA() - - def remote_getCurrentStep(self): - return makeRemote(self.b.getCurrentStep()) - - def remote_getText(self): - return self.b.getText() - - def remote_getColor(self): - return self.b.getColor() - - def remote_getResults(self): - return self.b.getResults() - - def remote_getLogs(self): - logs = {} - for name,log in self.b.getLogs().items(): - logs[name] = IRemote(log) - return logs - - def remote_subscribe(self, observer, updateInterval=None): - """The observer will have remote_stepStarted(buildername, build, - stepname, step), remote_stepFinished(buildername, build, stepname, - step, results), and maybe remote_buildETAUpdate(buildername, build, - eta)) messages sent to it.""" - self.observers.append(observer) - s = BuildSubscriber(observer) - self.b.subscribe(s, updateInterval) - - def remote_unsubscribe(self, observer): - # TODO: is the observer automatically unsubscribed when the build - # finishes? Or are they responsible for unsubscribing themselves - # anyway? How do we avoid a race condition here? - for o in self.observers: - if o == observer: - self.observers.remove(o) - - -components.registerAdapter(RemoteBuild, - interfaces.IBuildStatus, IRemote) - -class BuildSubscriber: - def __init__(self, observer): - self.observer = observer - - def buildETAUpdate(self, build, eta): - self.observer.callRemote("buildETAUpdate", - build.getBuilder().getName(), - IRemote(build), - eta) - - def stepStarted(self, build, step): - self.observer.callRemote("stepStarted", - build.getBuilder().getName(), - IRemote(build), - step.getName(), IRemote(step)) - return None - - def stepFinished(self, build, step, results): - self.observer.callRemote("stepFinished", - build.getBuilder().getName(), - IRemote(build), - step.getName(), IRemote(step), - results) - - -class RemoteBuildStep(pb.Referenceable): - def __init__(self, step): - self.s = step - - def remote_getName(self): - return self.s.getName() - - def remote_getBuild(self): - return IRemote(self.s.getBuild()) - - def remote_getTimes(self): - return self.s.getTimes() - - def remote_getExpectations(self): - return self.s.getExpectations() - - def remote_getLogs(self): - logs = {} - for log in self.s.getLogs(): - logs[log.getName()] = IRemote(log) - return logs - - def remote_isFinished(self): - return self.s.isFinished() - - def remote_waitUntilFinished(self): - return self.s.waitUntilFinished() # returns a Deferred - - def remote_getETA(self): - return self.s.getETA() - - def remote_getText(self): - return self.s.getText() - - def remote_getColor(self): - return self.s.getColor() - - def remote_getResults(self): - return self.s.getResults() - -components.registerAdapter(RemoteBuildStep, - interfaces.IBuildStepStatus, IRemote) - -class RemoteSlave: - def __init__(self, slave): - self.s = slave - - def remote_getName(self): - return self.s.getName() - def remote_getAdmin(self): - return self.s.getAdmin() - def remote_getHost(self): - return self.s.getHost() - def remote_isConnected(self): - return self.s.isConnected() - -components.registerAdapter(RemoteSlave, - interfaces.ISlaveStatus, IRemote) - -class RemoteEvent: - def __init__(self, event): - self.e = event - - def remote_getTimes(self): - return self.s.getTimes() - def remote_getText(self): - return self.s.getText() - def remote_getColor(self): - return self.s.getColor() - -components.registerAdapter(RemoteEvent, - interfaces.IStatusEvent, IRemote) - -class RemoteLog(pb.Referenceable): - def __init__(self, log): - self.l = log - - def remote_getName(self): - return self.l.getName() - - def remote_isFinished(self): - return self.l.isFinished() - def remote_waitUntilFinished(self): - d = self.l.waitUntilFinished() - d.addCallback(lambda res: self) - return d - - def remote_getText(self): - return self.l.getText() - def remote_getTextWithHeaders(self): - return self.l.getTextWithHeaders() - def remote_getChunks(self): - return self.l.getChunks() - # TODO: subscription interface - -components.registerAdapter(RemoteLog, builder.LogFile, IRemote) -# TODO: something similar for builder.HTMLLogfile ? - -class RemoteChange: - def __init__(self, change): - self.c = change - - def getWho(self): - return self.c.who - def getFiles(self): - return self.c.files - def getComments(self): - return self.c.comments - -components.registerAdapter(RemoteChange, changes.Change, IRemote) - - -class StatusClientPerspective(base.StatusReceiverPerspective): - - subscribed = None - client = None - - def __init__(self, status): - self.status = status # the IStatus - self.subscribed_to_builders = [] # Builders to which we're subscribed - self.subscribed_to = [] # everything else we're subscribed to - - def __getstate__(self): - d = self.__dict__.copy() - d['client'] = None - return d - - def attached(self, mind): - #twlog.msg("StatusClientPerspective.attached") - return self - - def detached(self, mind): - twlog.msg("PB client detached") - self.client = None - for name in self.subscribed_to_builders: - twlog.msg(" unsubscribing from Builder(%s)" % name) - self.status.getBuilder(name).unsubscribe(self) - for s in self.subscribed_to: - twlog.msg(" unsubscribe from %s" % s) - s.unsubscribe(self) - self.subscribed = None - - def perspective_subscribe(self, mode, interval, target): - """The remote client wishes to subscribe to some set of events. - 'target' will be sent remote messages when these events happen. - 'mode' indicates which events are desired: it is a string with one - of the following values: - - 'builders': builderAdded, builderRemoved - 'builds': those plus builderChangedState, buildStarted, buildFinished - 'steps': all those plus buildETAUpdate, stepStarted, stepFinished - 'logs': all those plus stepETAUpdate, logStarted, logFinished - 'full': all those plus logChunk (with the log contents) - - - Messages are defined by buildbot.interfaces.IStatusReceiver . - 'interval' is used to specify how frequently ETAUpdate messages - should be sent. - - Raising or lowering the subscription level will take effect starting - with the next build or step.""" - - assert mode in ("builders", "builds", "steps", "logs", "full") - assert target - twlog.msg("PB subscribe(%s)" % mode) - - self.client = target - self.subscribed = mode - self.interval = interval - self.subscribed_to.append(self.status) - # wait a moment before subscribing, so the new-builder messages - # won't appear before this remote method finishes - reactor.callLater(0, self.status.subscribe, self) - return None - - def perspective_unsubscribe(self): - twlog.msg("PB unsubscribe") - self.status.unsubscribe(self) - self.subscribed_to.remove(self.status) - self.client = None - - def perspective_getBuildSets(self): - """This returns tuples of (buildset, bsid), because that is much more - convenient for tryclient.""" - return [(IRemote(s), s.getID()) for s in self.status.getBuildSets()] - - def perspective_getBuilderNames(self): - return self.status.getBuilderNames() - - def perspective_getBuilder(self, name): - b = self.status.getBuilder(name) - return IRemote(b) - - def perspective_getSlave(self, name): - s = self.status.getSlave(name) - return IRemote(s) - - # IStatusReceiver methods, invoked if we've subscribed - - # mode >= builder - def builderAdded(self, name, builder): - self.client.callRemote("builderAdded", name, IRemote(builder)) - if self.subscribed in ("builds", "steps", "logs", "full"): - self.subscribed_to_builders.append(name) - return self - return None - - def builderChangedState(self, name, state): - self.client.callRemote("builderChangedState", name, state, None) - # TODO: remove leftover ETA argument - - def builderRemoved(self, name): - if name in self.subscribed_to_builders: - self.subscribed_to_builders.remove(name) - self.client.callRemote("builderRemoved", name) - - def buildsetSubmitted(self, buildset): - # TODO: deliver to client, somehow - pass - - # mode >= builds - def buildStarted(self, name, build): - self.client.callRemote("buildStarted", name, IRemote(build)) - if self.subscribed in ("steps", "logs", "full"): - self.subscribed_to.append(build) - return (self, self.interval) - return None - - def buildFinished(self, name, build, results): - if build in self.subscribed_to: - # we might have joined during the build - self.subscribed_to.remove(build) - self.client.callRemote("buildFinished", - name, IRemote(build), results) - - # mode >= steps - def buildETAUpdate(self, build, eta): - self.client.callRemote("buildETAUpdate", - build.getBuilder().getName(), IRemote(build), - eta) - - def stepStarted(self, build, step): - # we add some information here so the client doesn't have to do an - # extra round-trip - self.client.callRemote("stepStarted", - build.getBuilder().getName(), IRemote(build), - step.getName(), IRemote(step)) - if self.subscribed in ("logs", "full"): - self.subscribed_to.append(step) - return (self, self.interval) - return None - - def stepFinished(self, build, step, results): - self.client.callRemote("stepFinished", - build.getBuilder().getName(), IRemote(build), - step.getName(), IRemote(step), - results) - if step in self.subscribed_to: - # eventually (through some new subscription method) we could - # join in the middle of the step - self.subscribed_to.remove(step) - - # mode >= logs - def stepETAUpdate(self, build, step, ETA, expectations): - self.client.callRemote("stepETAUpdate", - build.getBuilder().getName(), IRemote(build), - step.getName(), IRemote(step), - ETA, expectations) - - def logStarted(self, build, step, log): - # TODO: make the HTMLLog adapter - rlog = IRemote(log, None) - if not rlog: - print "hey, couldn't adapt %s to IRemote" % log - self.client.callRemote("logStarted", - build.getBuilder().getName(), IRemote(build), - step.getName(), IRemote(step), - log.getName(), IRemote(log, None)) - if self.subscribed in ("full",): - self.subscribed_to.append(log) - return self - return None - - def logFinished(self, build, step, log): - self.client.callRemote("logFinished", - build.getBuilder().getName(), IRemote(build), - step.getName(), IRemote(step), - log.getName(), IRemote(log, None)) - if log in self.subscribed_to: - self.subscribed_to.remove(log) - - # mode >= full - def logChunk(self, build, step, log, channel, text): - self.client.callRemote("logChunk", - build.getBuilder().getName(), IRemote(build), - step.getName(), IRemote(step), - log.getName(), IRemote(log), - channel, text) - - -class PBListener(base.StatusReceiverMultiService): - """I am a listener for PB-based status clients.""" - - compare_attrs = ["port", "cred"] - implements(portal.IRealm) - - def __init__(self, port, user="statusClient", passwd="clientpw"): - base.StatusReceiverMultiService.__init__(self) - if type(port) is int: - port = "tcp:%d" % port - self.port = port - self.cred = (user, passwd) - p = portal.Portal(self) - c = checkers.InMemoryUsernamePasswordDatabaseDontUse() - c.addUser(user, passwd) - p.registerChecker(c) - f = pb.PBServerFactory(p) - s = strports.service(port, f) - s.setServiceParent(self) - - def setServiceParent(self, parent): - base.StatusReceiverMultiService.setServiceParent(self, parent) - self.setup() - - def setup(self): - self.status = self.parent.getStatus() - - def requestAvatar(self, avatarID, mind, interface): - assert interface == pb.IPerspective - p = StatusClientPerspective(self.status) - p.attached(mind) # perhaps .callLater(0) ? - return (pb.IPerspective, p, - lambda p=p,mind=mind: p.detached(mind)) diff --git a/tools/buildbot/pylibs/buildbot/status/html.py b/tools/buildbot/pylibs/buildbot/status/html.py deleted file mode 100644 index cc36a4a..0000000 --- a/tools/buildbot/pylibs/buildbot/status/html.py +++ /dev/null @@ -1,6 +0,0 @@ - -# compatibility wrapper. This is currently the preferred place for master.cfg -# to import from. - -from buildbot.status.web.baseweb import Waterfall, WebStatus -_hush_pyflakes = [Waterfall, WebStatus] diff --git a/tools/buildbot/pylibs/buildbot/status/mail.py b/tools/buildbot/pylibs/buildbot/status/mail.py deleted file mode 100644 index a23a84c..0000000 --- a/tools/buildbot/pylibs/buildbot/status/mail.py +++ /dev/null @@ -1,361 +0,0 @@ -# -*- test-case-name: buildbot.test.test_status -*- - -# the email.MIMEMultipart module is only available in python-2.2.2 and later - -from email.Message import Message -from email.Utils import formatdate -from email.MIMEText import MIMEText -try: - from email.MIMEMultipart import MIMEMultipart - canDoAttachments = True -except ImportError: - canDoAttachments = False -import urllib - -from zope.interface import implements -from twisted.internet import defer -from twisted.mail.smtp import sendmail -from twisted.python import log as twlog - -from buildbot import interfaces, util -from buildbot.status import base -from buildbot.status.builder import FAILURE, SUCCESS, WARNINGS - - -class Domain(util.ComparableMixin): - implements(interfaces.IEmailLookup) - compare_attrs = ["domain"] - - def __init__(self, domain): - assert "@" not in domain - self.domain = domain - - def getAddress(self, name): - return name + "@" + self.domain - - -class MailNotifier(base.StatusReceiverMultiService): - """This is a status notifier which sends email to a list of recipients - upon the completion of each build. It can be configured to only send out - mail for certain builds, and only send messages when the build fails, or - when it transitions from success to failure. It can also be configured to - include various build logs in each message. - - By default, the message will be sent to the Interested Users list, which - includes all developers who made changes in the build. You can add - additional recipients with the extraRecipients argument. - - To get a simple one-message-per-build (say, for a mailing list), use - sendToInterestedUsers=False, extraRecipients=['listaddr@example.org'] - - Each MailNotifier sends mail to a single set of recipients. To send - different kinds of mail to different recipients, use multiple - MailNotifiers. - """ - - implements(interfaces.IEmailSender) - - compare_attrs = ["extraRecipients", "lookup", "fromaddr", "mode", - "categories", "builders", "addLogs", "relayhost", - "subject", "sendToInterestedUsers"] - - def __init__(self, fromaddr, mode="all", categories=None, builders=None, - addLogs=False, relayhost="localhost", - subject="buildbot %(result)s in %(projectName)s on %(builder)s", - lookup=None, extraRecipients=[], - sendToInterestedUsers=True): - """ - @type fromaddr: string - @param fromaddr: the email address to be used in the 'From' header. - @type sendToInterestedUsers: boolean - @param sendToInterestedUsers: if True (the default), send mail to all - of the Interested Users. If False, only - send mail to the extraRecipients list. - - @type extraRecipients: tuple of string - @param extraRecipients: a list of email addresses to which messages - should be sent (in addition to the - InterestedUsers list, which includes any - developers who made Changes that went into this - build). It is a good idea to create a small - mailing list and deliver to that, then let - subscribers come and go as they please. - - @type subject: string - @param subject: a string to be used as the subject line of the message. - %(builder)s will be replaced with the name of the - builder which provoked the message. - - @type mode: string (defaults to all) - @param mode: one of: - - 'all': send mail about all builds, passing and failing - - 'failing': only send mail about builds which fail - - 'passing': only send mail about builds which succeed - - 'problem': only send mail about a build which failed - when the previous build passed - - @type builders: list of strings - @param builders: a list of builder names for which mail should be - sent. Defaults to None (send mail for all builds). - Use either builders or categories, but not both. - - @type categories: list of strings - @param categories: a list of category names to serve status - information for. Defaults to None (all - categories). Use either builders or categories, - but not both. - - @type addLogs: boolean. - @param addLogs: if True, include all build logs as attachments to the - messages. These can be quite large. This can also be - set to a list of log names, to send a subset of the - logs. Defaults to False. - - @type relayhost: string - @param relayhost: the host to which the outbound SMTP connection - should be made. Defaults to 'localhost' - - @type lookup: implementor of {IEmailLookup} - @param lookup: object which provides IEmailLookup, which is - responsible for mapping User names (which come from - the VC system) into valid email addresses. If not - provided, the notifier will only be able to send mail - to the addresses in the extraRecipients list. Most of - the time you can use a simple Domain instance. As a - shortcut, you can pass as string: this will be - treated as if you had provided Domain(str). For - example, lookup='twistedmatrix.com' will allow mail - to be sent to all developers whose SVN usernames - match their twistedmatrix.com account names. - """ - - base.StatusReceiverMultiService.__init__(self) - assert isinstance(extraRecipients, (list, tuple)) - for r in extraRecipients: - assert isinstance(r, str) - assert "@" in r # require full email addresses, not User names - self.extraRecipients = extraRecipients - self.sendToInterestedUsers = sendToInterestedUsers - self.fromaddr = fromaddr - assert mode in ('all', 'failing', 'problem') - self.mode = mode - self.categories = categories - self.builders = builders - self.addLogs = addLogs - self.relayhost = relayhost - self.subject = subject - if lookup is not None: - if type(lookup) is str: - lookup = Domain(lookup) - assert interfaces.IEmailLookup.providedBy(lookup) - self.lookup = lookup - self.watched = [] - self.status = None - - # you should either limit on builders or categories, not both - if self.builders != None and self.categories != None: - twlog.err("Please specify only builders to ignore or categories to include") - raise # FIXME: the asserts above do not raise some Exception either - - def setServiceParent(self, parent): - """ - @type parent: L{buildbot.master.BuildMaster} - """ - base.StatusReceiverMultiService.setServiceParent(self, parent) - self.setup() - - def setup(self): - self.status = self.parent.getStatus() - self.status.subscribe(self) - - def disownServiceParent(self): - self.status.unsubscribe(self) - for w in self.watched: - w.unsubscribe(self) - return base.StatusReceiverMultiService.disownServiceParent(self) - - def builderAdded(self, name, builder): - # only subscribe to builders we are interested in - if self.categories != None and builder.category not in self.categories: - return None - - self.watched.append(builder) - return self # subscribe to this builder - - def builderRemoved(self, name): - pass - - def builderChangedState(self, name, state): - pass - def buildStarted(self, name, build): - pass - def buildFinished(self, name, build, results): - # here is where we actually do something. - builder = build.getBuilder() - if self.builders is not None and name not in self.builders: - return # ignore this build - if self.categories is not None and \ - builder.category not in self.categories: - return # ignore this build - - if self.mode == "failing" and results != FAILURE: - return - if self.mode == "passing" and results != SUCCESS: - return - if self.mode == "problem": - if results != FAILURE: - return - prev = build.getPreviousBuild() - if prev and prev.getResults() == FAILURE: - return - # for testing purposes, buildMessage returns a Deferred that fires - # when the mail has been sent. To help unit tests, we return that - # Deferred here even though the normal IStatusReceiver.buildFinished - # signature doesn't do anything with it. If that changes (if - # .buildFinished's return value becomes significant), we need to - # rearrange this. - return self.buildMessage(name, build, results) - - def buildMessage(self, name, build, results): - projectName = self.status.getProjectName() - text = "" - if self.mode == "all": - text += "The Buildbot has finished a build" - elif self.mode == "failing": - text += "The Buildbot has detected a failed build" - elif self.mode == "passing": - text += "The Buildbot has detected a passing build" - else: - text += "The Buildbot has detected a new failure" - text += " of %s on %s.\n" % (name, projectName) - buildurl = self.status.getURLForThing(build) - if buildurl: - text += "Full details are available at:\n %s\n" % buildurl - text += "\n" - - url = self.status.getBuildbotURL() - if url: - text += "Buildbot URL: %s\n\n" % urllib.quote(url, '/:') - - text += "Buildslave for this Build: %s\n\n" % build.getSlavename() - text += "Build Reason: %s\n" % build.getReason() - - patch = None - ss = build.getSourceStamp() - if ss is None: - source = "unavailable" - else: - source = "" - if ss.branch: - source += "[branch %s] " % ss.branch - if ss.revision: - source += ss.revision - else: - source += "HEAD" - if ss.patch is not None: - source += " (plus patch)" - patch = ss.patch - text += "Build Source Stamp: %s\n" % source - - text += "Blamelist: %s\n" % ",".join(build.getResponsibleUsers()) - - # TODO: maybe display changes here? or in an attachment? - text += "\n" - - t = build.getText() - if t: - t = ": " + " ".join(t) - else: - t = "" - - if results == SUCCESS: - text += "Build succeeded!\n" - res = "success" - elif results == WARNINGS: - text += "Build Had Warnings%s\n" % t - res = "warnings" - else: - text += "BUILD FAILED%s\n" % t - res = "failure" - - if self.addLogs and build.getLogs(): - text += "Logs are attached.\n" - - # TODO: it would be nice to provide a URL for the specific build - # here. That involves some coordination with html.Waterfall . - # Ideally we could do: - # helper = self.parent.getServiceNamed("html") - # if helper: - # url = helper.getURLForBuild(build) - - text += "\n" - text += "sincerely,\n" - text += " -The Buildbot\n" - text += "\n" - - haveAttachments = False - if patch or self.addLogs: - haveAttachments = True - if not canDoAttachments: - twlog.msg("warning: I want to send mail with attachments, " - "but this python is too old to have " - "email.MIMEMultipart . Please upgrade to python-2.3 " - "or newer to enable addLogs=True") - - if haveAttachments and canDoAttachments: - m = MIMEMultipart() - m.attach(MIMEText(text)) - else: - m = Message() - m.set_payload(text) - - m['Date'] = formatdate(localtime=True) - m['Subject'] = self.subject % { 'result': res, - 'projectName': projectName, - 'builder': name, - } - m['From'] = self.fromaddr - # m['To'] is added later - - if patch: - a = MIMEText(patch) - a.add_header('Content-Disposition', "attachment", - filename="source patch") - m.attach(a) - if self.addLogs: - for log in build.getLogs(): - name = "%s.%s" % (log.getStep().getName(), - log.getName()) - a = MIMEText(log.getText()) - a.add_header('Content-Disposition', "attachment", - filename=name) - m.attach(a) - - # now, who is this message going to? - dl = [] - recipients = self.extraRecipients[:] - if self.sendToInterestedUsers and self.lookup: - for u in build.getInterestedUsers(): - d = defer.maybeDeferred(self.lookup.getAddress, u) - d.addCallback(recipients.append) - dl.append(d) - d = defer.DeferredList(dl) - d.addCallback(self._gotRecipients, recipients, m) - return d - - def _gotRecipients(self, res, rlist, m): - recipients = [] - for r in rlist: - if r is not None and r not in recipients: - recipients.append(r) - recipients.sort() - m['To'] = ", ".join(recipients) - return self.sendMessage(m, recipients) - - def sendMessage(self, m, recipients): - s = m.as_string() - ds = [] - twlog.msg("sending mail (%d bytes) to" % len(s), recipients) - for recip in recipients: - ds.append(sendmail(self.relayhost, self.fromaddr, recip, s)) - return defer.DeferredList(ds) diff --git a/tools/buildbot/pylibs/buildbot/status/progress.py b/tools/buildbot/pylibs/buildbot/status/progress.py deleted file mode 100644 index dc4d3d5..0000000 --- a/tools/buildbot/pylibs/buildbot/status/progress.py +++ /dev/null @@ -1,308 +0,0 @@ -# -*- test-case-name: buildbot.test.test_status -*- - -from twisted.internet import reactor -from twisted.spread import pb -from twisted.python import log -from buildbot import util - -class StepProgress: - """I keep track of how much progress a single BuildStep has made. - - Progress is measured along various axes. Time consumed is one that is - available for all steps. Amount of command output is another, and may be - better quantified by scanning the output for markers to derive number of - files compiled, directories walked, tests run, etc. - - I am created when the build begins, and given to a BuildProgress object - so it can track the overall progress of the whole build. - - """ - - startTime = None - stopTime = None - expectedTime = None - buildProgress = None - debug = False - - def __init__(self, name, metricNames): - self.name = name - self.progress = {} - self.expectations = {} - for m in metricNames: - self.progress[m] = None - self.expectations[m] = None - - def setBuildProgress(self, bp): - self.buildProgress = bp - - def setExpectations(self, metrics): - """The step can call this to explicitly set a target value for one - of its metrics. E.g., ShellCommands knows how many commands it will - execute, so it could set the 'commands' expectation.""" - for metric, value in metrics.items(): - self.expectations[metric] = value - self.buildProgress.newExpectations() - - def setExpectedTime(self, seconds): - self.expectedTime = seconds - self.buildProgress.newExpectations() - - def start(self): - if self.debug: print "StepProgress.start[%s]" % self.name - self.startTime = util.now() - - def setProgress(self, metric, value): - """The step calls this as progress is made along various axes.""" - if self.debug: - print "setProgress[%s][%s] = %s" % (self.name, metric, value) - self.progress[metric] = value - if self.debug: - r = self.remaining() - print " step remaining:", r - self.buildProgress.newProgress() - - def finish(self): - """This stops the 'time' metric and marks the step as finished - overall. It should be called after the last .setProgress has been - done for each axis.""" - if self.debug: print "StepProgress.finish[%s]" % self.name - self.stopTime = util.now() - self.buildProgress.stepFinished(self.name) - - def totalTime(self): - if self.startTime != None and self.stopTime != None: - return self.stopTime - self.startTime - - def remaining(self): - if self.startTime == None: - return self.expectedTime - if self.stopTime != None: - return 0 # already finished - # TODO: replace this with cleverness that graphs each metric vs. - # time, then finds the inverse function. Will probably need to save - # a timestamp with each setProgress update, when finished, go back - # and find the 2% transition points, then save those 50 values in a - # list. On the next build, do linear interpolation between the two - # closest samples to come up with a percentage represented by that - # metric. - - # TODO: If no other metrics are available, just go with elapsed - # time. Given the non-time-uniformity of text output from most - # steps, this would probably be better than the text-percentage - # scheme currently implemented. - - percentages = [] - for metric, value in self.progress.items(): - expectation = self.expectations[metric] - if value != None and expectation != None: - p = 1.0 * value / expectation - percentages.append(p) - if percentages: - avg = reduce(lambda x,y: x+y, percentages) / len(percentages) - if avg > 1.0: - # overdue - avg = 1.0 - if avg < 0.0: - avg = 0.0 - if percentages and self.expectedTime != None: - return self.expectedTime - (avg * self.expectedTime) - if self.expectedTime is not None: - # fall back to pure time - return self.expectedTime - (util.now() - self.startTime) - return None # no idea - - -class WatcherState: - def __init__(self, interval): - self.interval = interval - self.timer = None - self.needUpdate = 0 - -class BuildProgress(pb.Referenceable): - """I keep track of overall build progress. I hold a list of StepProgress - objects. - """ - - def __init__(self, stepProgresses): - self.steps = {} - for s in stepProgresses: - self.steps[s.name] = s - s.setBuildProgress(self) - self.finishedSteps = [] - self.watchers = {} - self.debug = 0 - - def setExpectationsFrom(self, exp): - """Set our expectations from the builder's Expectations object.""" - for name, metrics in exp.steps.items(): - s = self.steps[name] - s.setExpectedTime(exp.times[name]) - s.setExpectations(exp.steps[name]) - - def newExpectations(self): - """Call this when one of the steps has changed its expectations. - This should trigger us to update our ETA value and notify any - subscribers.""" - pass # subscribers are not implemented: they just poll - - def stepFinished(self, stepname): - assert(stepname not in self.finishedSteps) - self.finishedSteps.append(stepname) - if len(self.finishedSteps) == len(self.steps.keys()): - self.sendLastUpdates() - - def newProgress(self): - r = self.remaining() - if self.debug: - print " remaining:", r - if r != None: - self.sendAllUpdates() - - def remaining(self): - # sum eta of all steps - sum = 0 - for name, step in self.steps.items(): - rem = step.remaining() - if rem == None: - return None # not sure - sum += rem - return sum - def eta(self): - left = self.remaining() - if left == None: - return None # not sure - done = util.now() + left - return done - - - def remote_subscribe(self, remote, interval=5): - # [interval, timer, needUpdate] - # don't send an update more than once per interval - self.watchers[remote] = WatcherState(interval) - remote.notifyOnDisconnect(self.removeWatcher) - self.updateWatcher(remote) - self.startTimer(remote) - log.msg("BuildProgress.remote_subscribe(%s)" % remote) - def remote_unsubscribe(self, remote): - # TODO: this doesn't work. I think 'remote' will always be different - # than the object that appeared in _subscribe. - log.msg("BuildProgress.remote_unsubscribe(%s)" % remote) - self.removeWatcher(remote) - #remote.dontNotifyOnDisconnect(self.removeWatcher) - def removeWatcher(self, remote): - #log.msg("removeWatcher(%s)" % remote) - try: - timer = self.watchers[remote].timer - if timer: - timer.cancel() - del self.watchers[remote] - except KeyError: - log.msg("Weird, removeWatcher on non-existent subscriber:", - remote) - def sendAllUpdates(self): - for r in self.watchers.keys(): - self.updateWatcher(r) - def updateWatcher(self, remote): - # an update wants to go to this watcher. Send it if we can, otherwise - # queue it for later - w = self.watchers[remote] - if not w.timer: - # no timer, so send update now and start the timer - self.sendUpdate(remote) - self.startTimer(remote) - else: - # timer is running, just mark as needing an update - w.needUpdate = 1 - def startTimer(self, remote): - w = self.watchers[remote] - timer = reactor.callLater(w.interval, self.watcherTimeout, remote) - w.timer = timer - def sendUpdate(self, remote, last=0): - self.watchers[remote].needUpdate = 0 - #text = self.asText() # TODO: not text, duh - try: - remote.callRemote("progress", self.remaining()) - if last: - remote.callRemote("finished", self) - except: - log.deferr() - self.removeWatcher(remote) - - def watcherTimeout(self, remote): - w = self.watchers.get(remote, None) - if not w: - return # went away - w.timer = None - if w.needUpdate: - self.sendUpdate(remote) - self.startTimer(remote) - def sendLastUpdates(self): - for remote in self.watchers.keys(): - self.sendUpdate(remote, 1) - self.removeWatcher(remote) - - -class Expectations: - debug = False - # decay=1.0 ignores all but the last build - # 0.9 is short time constant. 0.1 is very long time constant - # TODO: let decay be specified per-metric - decay = 0.5 - - def __init__(self, buildprogress): - """Create us from a successful build. We will expect each step to - take as long as it did in that build.""" - - # .steps maps stepname to dict2 - # dict2 maps metricname to final end-of-step value - self.steps = {} - - # .times maps stepname to per-step elapsed time - self.times = {} - - for name, step in buildprogress.steps.items(): - self.steps[name] = {} - for metric, value in step.progress.items(): - self.steps[name][metric] = value - self.times[name] = None - if step.startTime is not None and step.stopTime is not None: - self.times[name] = step.stopTime - step.startTime - - def wavg(self, old, current): - if old is None: - return current - if current is None: - return old - else: - return (current * self.decay) + (old * (1 - self.decay)) - - def update(self, buildprogress): - for name, stepprogress in buildprogress.steps.items(): - old = self.times[name] - current = stepprogress.totalTime() - if current == None: - log.msg("Expectations.update: current[%s] was None!" % name) - continue - new = self.wavg(old, current) - self.times[name] = new - if self.debug: - print "new expected time[%s] = %s, old %s, cur %s" % \ - (name, new, old, current) - - for metric, current in stepprogress.progress.items(): - old = self.steps[name][metric] - new = self.wavg(old, current) - if self.debug: - print "new expectation[%s][%s] = %s, old %s, cur %s" % \ - (name, metric, new, old, current) - self.steps[name][metric] = new - - def expectedBuildTime(self): - if None in self.times.values(): - return None - #return sum(self.times.values()) - # python-2.2 doesn't have 'sum'. TODO: drop python-2.2 support - s = 0 - for v in self.times.values(): - s += v - return s diff --git a/tools/buildbot/pylibs/buildbot/status/tests.py b/tools/buildbot/pylibs/buildbot/status/tests.py deleted file mode 100644 index 4c4c894..0000000 --- a/tools/buildbot/pylibs/buildbot/status/tests.py +++ /dev/null @@ -1,73 +0,0 @@ - -from twisted.web import resource -from twisted.web.error import NoResource - -# these are our test result types. Steps are responsible for mapping results -# into these values. -SKIP, EXPECTED_FAILURE, FAILURE, ERROR, UNEXPECTED_SUCCESS, SUCCESS = \ - "skip", "expected failure", "failure", "error", "unexpected success", \ - "success" -UNKNOWN = "unknown" # catch-all - - -class OneTest(resource.Resource): - isLeaf = 1 - def __init__(self, parent, testName, results): - self.parent = parent - self.testName = testName - self.resultType, self.results = results - - def render(self, request): - request.setHeader("content-type", "text/html") - if request.method == "HEAD": - request.setHeader("content-length", len(self.html(request))) - return '' - return self.html(request) - - def html(self, request): - # turn ourselves into HTML - raise NotImplementedError - -class TestResults(resource.Resource): - oneTestClass = OneTest - def __init__(self): - resource.Resource.__init__(self) - self.tests = {} - def addTest(self, testName, resultType, results=None): - self.tests[testName] = (resultType, results) - # TODO: .setName and .delete should be used on our Swappable - def countTests(self): - return len(self.tests) - def countFailures(self): - failures = 0 - for t in self.tests.values(): - if t[0] in (FAILURE, ERROR): - failures += 1 - return failures - def summary(self): - """Return a short list of text strings as a summary, suitable for - inclusion in an Event""" - return ["some", "tests"] - def describeOneTest(self, testname): - return "%s: %s\n" % (testname, self.tests[testname][0]) - def html(self): - data = "\nTest Results\n" - data += "\n" - data += "
\n"
-        tests = self.tests.keys()
-        tests.sort()
-        for testname in tests:
-            data += self.describeOneTest(testname)
-        data += "
\n" - data += "\n" - return data - def render(self, request): - request.setHeader("content-type", "text/html") - if request.method == "HEAD": - request.setHeader("content-length", len(self.html())) - return '' - return self.html() - def getChild(self, path, request): - if self.tests.has_key(path): - return self.oneTestClass(self, path, self.tests[path]) - return NoResource("No such test '%s'" % path) diff --git a/tools/buildbot/pylibs/buildbot/status/tinderbox.py b/tools/buildbot/pylibs/buildbot/status/tinderbox.py deleted file mode 100644 index 51d404b..0000000 --- a/tools/buildbot/pylibs/buildbot/status/tinderbox.py +++ /dev/null @@ -1,223 +0,0 @@ - -from email.Message import Message -from email.Utils import formatdate - -from zope.interface import implements -from twisted.internet import defer - -from buildbot import interfaces -from buildbot.status import mail -from buildbot.status.builder import SUCCESS, WARNINGS -from buildbot.steps.shell import WithProperties - -import zlib, bz2, base64 - -# TODO: docs, maybe a test of some sort just to make sure it actually imports -# and can format email without raising an exception. - -class TinderboxMailNotifier(mail.MailNotifier): - """This is a Tinderbox status notifier. It can send e-mail to a number of - different tinderboxes or people. E-mails are sent at the beginning and - upon completion of each build. It can be configured to send out e-mails - for only certain builds. - - The most basic usage is as follows:: - TinderboxMailNotifier(fromaddr="buildbot@localhost", - tree="MyTinderboxTree", - extraRecipients=["tinderboxdaemon@host.org"]) - - The builder name (as specified in master.cfg) is used as the "build" - tinderbox option. - - """ - implements(interfaces.IEmailSender) - - compare_attrs = ["extraRecipients", "fromaddr", "categories", "builders", - "addLogs", "relayhost", "subject", "binaryURL", "tree", - "logCompression", "errorparser", "columnName", - "useChangeTime"] - - def __init__(self, fromaddr, tree, extraRecipients, - categories=None, builders=None, relayhost="localhost", - subject="buildbot %(result)s in %(builder)s", binaryURL="", - logCompression="", errorparser="unix", columnName=None, - useChangeTime=False): - """ - @type fromaddr: string - @param fromaddr: the email address to be used in the 'From' header. - - @type tree: string - @param tree: The Tinderbox tree to post to. - - @type extraRecipients: tuple of string - @param extraRecipients: E-mail addresses of recipients. This should at - least include the tinderbox daemon. - - @type categories: list of strings - @param categories: a list of category names to serve status - information for. Defaults to None (all - categories). Use either builders or categories, - but not both. - - @type builders: list of strings - @param builders: a list of builder names for which mail should be - sent. Defaults to None (send mail for all builds). - Use either builders or categories, but not both. - - @type relayhost: string - @param relayhost: the host to which the outbound SMTP connection - should be made. Defaults to 'localhost' - - @type subject: string - @param subject: a string to be used as the subject line of the message. - %(builder)s will be replaced with the name of the - %builder which provoked the message. - This parameter is not significant for the tinderbox - daemon. - - @type binaryURL: string - @param binaryURL: If specified, this should be the location where final - binary for a build is located. - (ie. http://www.myproject.org/nightly/08-08-2006.tgz) - It will be posted to the Tinderbox. - - @type logCompression: string - @param logCompression: The type of compression to use on the log. - Valid options are"bzip2" and "gzip". gzip is - only known to work on Python 2.4 and above. - - @type errorparser: string - @param errorparser: The error parser that the Tinderbox server - should use when scanning the log file. - Default is "unix". - - @type columnName: string - @param columnName: When columnName is None, use the buildername as - the Tinderbox column name. When columnName is a - string this exact string will be used for all - builders that this TinderboxMailNotifier cares - about (not recommended). When columnName is a - WithProperties instance it will be interpolated - as such. See WithProperties for more detail. - @type useChangeTime: bool - @param useChangeTime: When True, the time of the first Change for a - build is used as the builddate. When False, - the current time is used as the builddate. - """ - - mail.MailNotifier.__init__(self, fromaddr, categories=categories, - builders=builders, relayhost=relayhost, - subject=subject, - extraRecipients=extraRecipients, - sendToInterestedUsers=False) - self.tree = tree - self.binaryURL = binaryURL - self.logCompression = logCompression - self.errorparser = errorparser - self.useChangeTime = useChangeTime - assert columnName is None or type(columnName) is str \ - or isinstance(columnName, WithProperties), \ - "columnName must be None, a string, or a WithProperties instance" - self.columnName = columnName - - def buildStarted(self, name, build): - builder = build.getBuilder() - if self.builders is not None and name not in self.builders: - return # ignore this Build - if self.categories is not None and \ - builder.category not in self.categories: - return # ignore this build - self.buildMessage(name, build, "building") - - def buildMessage(self, name, build, results): - text = "" - res = "" - # shortform - t = "tinderbox:" - - text += "%s tree: %s\n" % (t, self.tree) - # the start time - # getTimes() returns a fractioned time that tinderbox doesn't understand - builddate = int(build.getTimes()[0]) - # attempt to pull a Change time from this Build's Changes. - # if that doesn't work, fall back on the current time - if self.useChangeTime: - try: - builddate = build.getChanges()[-1].when - except: - pass - text += "%s builddate: %s\n" % (t, builddate) - text += "%s status: " % t - - if results == "building": - res = "building" - text += res - elif results == SUCCESS: - res = "success" - text += res - elif results == WARNINGS: - res = "testfailed" - text += res - else: - res += "busted" - text += res - - text += "\n"; - - if self.columnName is None: - # use the builder name - text += "%s build: %s\n" % (t, name) - elif type(self.columnName) is str: - # use the exact string given - text += "%s build: %s\n" % (t, self.columnName) - elif isinstance(self.columnName, WithProperties): - # interpolate the WithProperties instance, use that - text += "%s build: %s\n" % (t, build.getProperties().render(self.columnName)) - else: - raise Exception("columnName is an unhandled value") - text += "%s errorparser: %s\n" % (t, self.errorparser) - - # if the build just started... - if results == "building": - text += "%s END\n" % t - # if the build finished... - else: - text += "%s binaryurl: %s\n" % (t, self.binaryURL) - text += "%s logcompression: %s\n" % (t, self.logCompression) - - # logs will always be appended - logEncoding = "" - tinderboxLogs = "" - for log in build.getLogs(): - l = "" - if self.logCompression == "bzip2": - compressedLog = bz2.compress(log.getText()) - l = base64.encodestring(compressedLog) - logEncoding = "base64"; - elif self.logCompression == "gzip": - compressedLog = zlib.compress(log.getText()) - l = base64.encodestring(compressedLog) - logEncoding = "base64"; - else: - l = log.getText() - tinderboxLogs += l - - text += "%s logencoding: %s\n" % (t, logEncoding) - text += "%s END\n\n" % t - text += tinderboxLogs - text += "\n" - - m = Message() - m.set_payload(text) - - m['Date'] = formatdate(localtime=True) - m['Subject'] = self.subject % { 'result': res, - 'builder': name, - } - m['From'] = self.fromaddr - # m['To'] is added later - - d = defer.DeferredList([]) - d.addCallback(self._gotRecipients, self.extraRecipients, m) - return d - diff --git a/tools/buildbot/pylibs/buildbot/status/web/__init__.py b/tools/buildbot/pylibs/buildbot/status/web/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tools/buildbot/pylibs/buildbot/status/web/about.py b/tools/buildbot/pylibs/buildbot/status/web/about.py deleted file mode 100644 index 09748e6..0000000 --- a/tools/buildbot/pylibs/buildbot/status/web/about.py +++ /dev/null @@ -1,33 +0,0 @@ - -from twisted.web import html -from buildbot.status.web.base import HtmlResource -import buildbot -import twisted -import sys - -class AboutBuildbot(HtmlResource): - title = "About this Buildbot" - - def body(self, request): - data = '' - data += '

Welcome to the Buildbot

\n' - data += '

Version Information

\n' - data += '
    \n' - data += '
  • Buildbot: %s
  • \n' % html.escape(buildbot.version) - data += '
  • Twisted: %s
  • \n' % html.escape(twisted.__version__) - data += '
  • Python: %s
  • \n' % html.escape(sys.version) - data += '
  • Buildmaster platform: %s
  • \n' % html.escape(sys.platform) - data += '
\n' - - data += ''' -

Source code

- -

Buildbot is a free software project, released under the terms of the -GNU GPL.

- -

Please visit the Buildbot Home Page for -more information, including documentation, bug reports, and source -downloads.

-''' - return data - diff --git a/tools/buildbot/pylibs/buildbot/status/web/base.py b/tools/buildbot/pylibs/buildbot/status/web/base.py deleted file mode 100644 index a1e5a972..0000000 --- a/tools/buildbot/pylibs/buildbot/status/web/base.py +++ /dev/null @@ -1,395 +0,0 @@ - -import urlparse, urllib, time -from zope.interface import Interface -from twisted.web import html, resource -from buildbot.status import builder -from buildbot.status.builder import SUCCESS, WARNINGS, FAILURE, EXCEPTION - - -class ITopBox(Interface): - """I represent a box in the top row of the waterfall display: the one - which shows the status of the last build for each builder.""" - def getBox(self, request): - """Return a Box instance, which can produce a cell. - """ - -class ICurrentBox(Interface): - """I represent the 'current activity' box, just above the builder name.""" - def getBox(self, status): - """Return a Box instance, which can produce a cell. - """ - -class IBox(Interface): - """I represent a box in the waterfall display.""" - def getBox(self, request): - """Return a Box instance, which wraps an Event and can produce a - cell. - """ - -class IHTMLLog(Interface): - pass - -css_classes = {SUCCESS: "success", - WARNINGS: "warnings", - FAILURE: "failure", - EXCEPTION: "exception", - } - -ROW_TEMPLATE = ''' -
- %(label)s - %(field)s -
-''' - -def make_row(label, field): - """Create a name/value row for the HTML. - - `label` is plain text; it will be HTML-encoded. - - `field` is a bit of HTML structure; it will not be encoded in - any way. - """ - label = html.escape(label) - return ROW_TEMPLATE % {"label": label, "field": field} - -def make_stop_form(stopURL, on_all=False, label="Build"): - if on_all: - data = """
-

To stop all builds, fill out the following fields and - push the 'Stop' button

\n""" % stopURL - else: - data = """ -

To stop this build, fill out the following fields and - push the 'Stop' button

\n""" % stopURL - data += make_row("Your name:", - "") - data += make_row("Reason for stopping build:", - "") - data += '
\n' % label - return data - -def make_force_build_form(forceURL, on_all=False): - if on_all: - data = """
-

To force a build on all Builders, fill out the following fields - and push the 'Force Build' button

""" % forceURL - else: - data = """ -

To force a build, fill out the following fields and - push the 'Force Build' button

""" % forceURL - return (data - + make_row("Your name:", - "") - + make_row("Reason for build:", - "") - + make_row("Branch to build:", - "") - + make_row("Revision to build:", - "") - + '
\n') - -colormap = { - 'green': '#72ff75', - } -def td(text="", parms={}, **props): - data = "" - data += " " - #if not props.has_key("border"): - # props["border"] = 1 - props.update(parms) - if props.has_key("bgcolor"): - props["bgcolor"] = colormap.get(props["bgcolor"], props["bgcolor"]) - comment = props.get("comment", None) - if comment: - data += "" % comment - data += " '' - # /somewhere/lower : ['somewhere', 'lower'] -> '../' - # /somewhere/indexy/ : ['somewhere', 'indexy', ''] -> '../../' - # / : [] -> '' - if request.prepath: - segs = len(request.prepath) - 1 - else: - segs = 0 - root = "../" * segs - return root - -def path_to_builder(request, builderstatus): - return (path_to_root(request) + - "builders/" + - urllib.quote(builderstatus.getName(), safe='')) - -def path_to_build(request, buildstatus): - return (path_to_builder(request, buildstatus.getBuilder()) + - "/builds/%d" % buildstatus.getNumber()) - -def path_to_step(request, stepstatus): - return (path_to_build(request, stepstatus.getBuild()) + - "/steps/%s" % urllib.quote(stepstatus.getName(), safe='')) - -class Box: - # a Box wraps an Event. The Box has HTML parameters that Events - # lack, and it has a base URL to which each File's name is relative. - # Events don't know about HTML. - spacer = False - def __init__(self, text=[], color=None, class_=None, urlbase=None, - **parms): - self.text = text - self.color = color - self.class_ = class_ - self.urlbase = urlbase - self.show_idle = 0 - if parms.has_key('show_idle'): - del parms['show_idle'] - self.show_idle = 1 - - self.parms = parms - # parms is a dict of HTML parameters for the element that will - # represent this Event in the waterfall display. - - def td(self, **props): - props.update(self.parms) - text = self.text - if not text and self.show_idle: - text = ["[idle]"] - return td(text, props, bgcolor=self.color, class_=self.class_) - - -class HtmlResource(resource.Resource): - # this is a cheap sort of template thingy - contentType = "text/html; charset=UTF-8" - title = "Buildbot" - addSlash = False # adapted from Nevow - - def getChild(self, path, request): - if self.addSlash and path == "" and len(request.postpath) == 0: - return self - return resource.Resource.getChild(self, path, request) - - def render(self, request): - # tell the WebStatus about the HTTPChannel that got opened, so they - # can close it if we get reconfigured and the WebStatus goes away. - # They keep a weakref to this, since chances are good that it will be - # closed by the browser or by us before we get reconfigured. See - # ticket #102 for details. - if hasattr(request, "channel"): - # web.distrib.Request has no .channel - request.site.buildbot_service.registerChannel(request.channel) - - # Our pages no longer require that their URL end in a slash. Instead, - # they all use request.childLink() or some equivalent which takes the - # last path component into account. This clause is left here for - # historical and educational purposes. - if False and self.addSlash and request.prepath[-1] != '': - # this is intended to behave like request.URLPath().child('') - # but we need a relative URL, since we might be living behind a - # reverse proxy - # - # note that the Location: header (as used in redirects) are - # required to have absolute URIs, and my attempt to handle - # reverse-proxies gracefully violates rfc2616. This frequently - # works, but single-component paths sometimes break. The best - # strategy is to avoid these redirects whenever possible by using - # HREFs with trailing slashes, and only use the redirects for - # manually entered URLs. - url = request.prePathURL() - scheme, netloc, path, query, fragment = urlparse.urlsplit(url) - new_url = request.prepath[-1] + "/" - if query: - new_url += "?" + query - request.redirect(new_url) - return '' - - data = self.content(request) - if isinstance(data, unicode): - data = data.encode("utf-8") - request.setHeader("content-type", self.contentType) - if request.method == "HEAD": - request.setHeader("content-length", len(data)) - return '' - return data - - def getStatus(self, request): - return request.site.buildbot_service.getStatus() - def getControl(self, request): - return request.site.buildbot_service.getControl() - - def getChangemaster(self, request): - return request.site.buildbot_service.parent.change_svc - - def path_to_root(self, request): - return path_to_root(request) - - def getTitle(self, request): - return self.title - - def fillTemplate(self, template, request): - s = request.site.buildbot_service - values = s.template_values.copy() - values['root'] = self.path_to_root(request) - # e.g. to reference the top-level 'buildbot.css' page, use - # "%(root)sbuildbot.css" - values['title'] = self.getTitle(request) - return template % values - - def content(self, request): - s = request.site.buildbot_service - data = "" - data += self.fillTemplate(s.header, request) - data += "\n" - for he in s.head_elements: - data += " " + self.fillTemplate(he, request) + "\n" - data += self.head(request) - data += "\n\n" - - data += '\n' % " ".join(['%s="%s"' % (k,v) - for (k,v) in s.body_attrs.items()]) - data += self.body(request) - data += "\n" - data += self.fillTemplate(s.footer, request) - return data - - def head(self, request): - return "" - - def body(self, request): - return "Dummy\n" - -class StaticHTML(HtmlResource): - def __init__(self, body, title): - HtmlResource.__init__(self) - self.bodyHTML = body - self.title = title - def body(self, request): - return self.bodyHTML - -MINUTE = 60 -HOUR = 60*MINUTE -DAY = 24*HOUR -WEEK = 7*DAY -MONTH = 30*DAY - -def plural(word, words, num): - if int(num) == 1: - return "%d %s" % (num, word) - else: - return "%d %s" % (num, words) - -def abbreviate_age(age): - if age <= 90: - return "%s ago" % plural("second", "seconds", age) - if age < 90*MINUTE: - return "about %s ago" % plural("minute", "minutes", age / MINUTE) - if age < DAY: - return "about %s ago" % plural("hour", "hours", age / HOUR) - if age < 2*WEEK: - return "about %s ago" % plural("day", "days", age / DAY) - if age < 2*MONTH: - return "about %s ago" % plural("week", "weeks", age / WEEK) - return "a long time ago" - - -class OneLineMixin: - LINE_TIME_FORMAT = "%b %d %H:%M" - - def get_line_values(self, req, build): - ''' - Collect the data needed for each line display - ''' - builder_name = build.getBuilder().getName() - results = build.getResults() - text = build.getText() - try: - rev = build.getProperty("got_revision") - if rev is None: - rev = "??" - except KeyError: - rev = "??" - rev = str(rev) - if len(rev) > 20: - rev = "version is too-long" - root = self.path_to_root(req) - css_class = css_classes.get(results, "") - values = {'class': css_class, - 'builder_name': builder_name, - 'buildnum': build.getNumber(), - 'results': css_class, - 'text': " ".join(build.getText()), - 'buildurl': (root + - "builders/%s/builds/%d" % (builder_name, - build.getNumber())), - 'builderurl': (root + "builders/%s" % builder_name), - 'rev': rev, - 'time': time.strftime(self.LINE_TIME_FORMAT, - time.localtime(build.getTimes()[0])), - } - return values - - def make_line(self, req, build, include_builder=True): - ''' - Format and render a single line into HTML - ''' - values = self.get_line_values(req, build) - fmt_pieces = ['(%(time)s)', - 'rev=[%(rev)s]', - '%(results)s', - ] - if include_builder: - fmt_pieces.append('%(builder_name)s') - fmt_pieces.append('#%(buildnum)d:') - fmt_pieces.append('%(text)s') - data = " ".join(fmt_pieces) % values - return data - -def map_branches(branches): - # when the query args say "trunk", present that to things like - # IBuilderStatus.generateFinishedBuilds as None, since that's the - # convention in use. But also include 'trunk', because some VC systems - # refer to it that way. In the long run we should clean this up better, - # maybe with Branch objects or something. - if "trunk" in branches: - return branches + [None] - return branches diff --git a/tools/buildbot/pylibs/buildbot/status/web/baseweb.py b/tools/buildbot/pylibs/buildbot/status/web/baseweb.py deleted file mode 100644 index 149266cd..0000000 --- a/tools/buildbot/pylibs/buildbot/status/web/baseweb.py +++ /dev/null @@ -1,576 +0,0 @@ - -import os, sys, urllib, weakref -from itertools import count - -from zope.interface import implements -from twisted.python import log -from twisted.application import strports, service -from twisted.web import server, distrib, static, html -from twisted.spread import pb - -from buildbot.interfaces import IControl, IStatusReceiver - -from buildbot.status.web.base import HtmlResource, Box, \ - build_get_class, ICurrentBox, OneLineMixin, map_branches, \ - make_stop_form, make_force_build_form -from buildbot.status.web.waterfall import WaterfallStatusResource -from buildbot.status.web.grid import GridStatusResource -from buildbot.status.web.changes import ChangesResource -from buildbot.status.web.builder import BuildersResource -from buildbot.status.web.slaves import BuildSlavesResource -from buildbot.status.web.xmlrpc import XMLRPCServer -from buildbot.status.web.about import AboutBuildbot - -# this class contains the status services (WebStatus and the older Waterfall) -# which can be put in c['status']. It also contains some of the resources -# that are attached to the WebStatus at various well-known URLs, which the -# admin might wish to attach (using WebStatus.putChild) at other URLs. - - -class LastBuild(HtmlResource): - def body(self, request): - return "missing\n" - -def getLastNBuilds(status, numbuilds, builders=[], branches=[]): - """Return a list with the last few Builds, sorted by start time. - builder_names=None means all builders - """ - - # TODO: this unsorts the list of builder names, ick - builder_names = set(status.getBuilderNames()) - if builders: - builder_names = builder_names.intersection(set(builders)) - - # to make sure that we get everything, we must get 'numbuilds' builds - # from *each* source, then sort by ending time, then trim to the last - # 20. We could be more efficient, but it would require the same - # gnarly code that the Waterfall uses to generate one event at a - # time. TODO: factor that code out into some useful class. - events = [] - for builder_name in builder_names: - builder = status.getBuilder(builder_name) - for build_number in count(1): - if build_number > numbuilds: - break # enough from this builder, move on to another - build = builder.getBuild(-build_number) - if not build: - break # no more builds here, move on to the next builder - #if not build.isFinished(): - # continue - (build_start, build_end) = build.getTimes() - event = (build_start, builder_name, build) - events.append(event) - def _sorter(a, b): - return cmp( a[:2], b[:2] ) - events.sort(_sorter) - # now only return the actual build, and only return some of them - return [e[2] for e in events[-numbuilds:]] - - -# /one_line_per_build -# accepts builder=, branch=, numbuilds= -class OneLinePerBuild(HtmlResource, OneLineMixin): - """This shows one line per build, combining all builders together. Useful - query arguments: - - numbuilds=: how many lines to display - builder=: show only builds for this builder. Multiple builder= arguments - can be used to see builds from any builder in the set. - """ - - title = "Recent Builds" - - def __init__(self, numbuilds=20): - HtmlResource.__init__(self) - self.numbuilds = numbuilds - - def getChild(self, path, req): - status = self.getStatus(req) - builder = status.getBuilder(path) - return OneLinePerBuildOneBuilder(builder) - - def body(self, req): - status = self.getStatus(req) - control = self.getControl(req) - numbuilds = int(req.args.get("numbuilds", [self.numbuilds])[0]) - builders = req.args.get("builder", []) - branches = [b for b in req.args.get("branch", []) if b] - - g = status.generateFinishedBuilds(builders, map_branches(branches), - numbuilds) - - data = "" - - # really this is "up to %d builds" - data += "

Last %d finished builds: %s

\n" % \ - (numbuilds, ", ".join(branches)) - if builders: - data += ("

of builders: %s

\n" % (", ".join(builders))) - data += "
    \n" - got = 0 - building = False - online = 0 - for build in g: - got += 1 - data += "
  • " + self.make_line(req, build) + "
  • \n" - builder_status = build.getBuilder().getState()[0] - if builder_status == "building": - building = True - online += 1 - elif builder_status != "offline": - online += 1 - if not got: - data += "
  • No matching builds found
  • \n" - data += "
\n" - - if control is not None: - if building: - stopURL = "builders/_all/stop" - data += make_stop_form(stopURL, True, "Builds") - if online: - forceURL = "builders/_all/force" - data += make_force_build_form(forceURL, True) - - return data - - - -# /one_line_per_build/$BUILDERNAME -# accepts branch=, numbuilds= - -class OneLinePerBuildOneBuilder(HtmlResource, OneLineMixin): - def __init__(self, builder, numbuilds=20): - HtmlResource.__init__(self) - self.builder = builder - self.builder_name = builder.getName() - self.numbuilds = numbuilds - self.title = "Recent Builds of %s" % self.builder_name - - def body(self, req): - status = self.getStatus(req) - numbuilds = int(req.args.get("numbuilds", [self.numbuilds])[0]) - branches = [b for b in req.args.get("branch", []) if b] - - # walk backwards through all builds of a single builder - g = self.builder.generateFinishedBuilds(map_branches(branches), - numbuilds) - - data = "" - data += ("

Last %d builds of builder %s: %s

\n" % - (numbuilds, self.builder_name, ", ".join(branches))) - data += "
    \n" - got = 0 - for build in g: - got += 1 - data += "
  • " + self.make_line(req, build) + "
  • \n" - if not got: - data += "
  • No matching builds found
  • \n" - data += "
\n" - - return data - -# /one_box_per_builder -# accepts builder=, branch= -class OneBoxPerBuilder(HtmlResource): - """This shows a narrow table with one row per builder. The leftmost column - contains the builder name. The next column contains the results of the - most recent build. The right-hand column shows the builder's current - activity. - - builder=: show only builds for this builder. Multiple builder= arguments - can be used to see builds from any builder in the set. - """ - - title = "Latest Build" - - def body(self, req): - status = self.getStatus(req) - control = self.getControl(req) - - builders = req.args.get("builder", status.getBuilderNames()) - branches = [b for b in req.args.get("branch", []) if b] - - data = "" - - data += "

Latest builds: %s

\n" % ", ".join(branches) - data += "\n" - - building = False - online = 0 - base_builders_url = self.path_to_root(req) + "builders/" - for bn in builders: - base_builder_url = base_builders_url + urllib.quote(bn, safe='') - builder = status.getBuilder(bn) - data += "\n" - data += '\n' \ - % (base_builder_url, html.escape(bn)) - builds = list(builder.generateFinishedBuilds(map_branches(branches), - num_builds=1)) - if builds: - b = builds[0] - url = (base_builder_url + "/builds/%d" % b.getNumber()) - try: - label = b.getProperty("got_revision") - except KeyError: - label = None - if not label or len(str(label)) > 20: - label = "#%d" % b.getNumber() - text = ['%s' % (url, label)] - text.extend(b.getText()) - box = Box(text, b.getColor(), - class_="LastBuild box %s" % build_get_class(b)) - data += box.td(align="center") - else: - data += '\n' - current_box = ICurrentBox(builder).getBox(status) - data += current_box.td(align="center") - - builder_status = builder.getState()[0] - if builder_status == "building": - building = True - online += 1 - elif builder_status != "offline": - online += 1 - - data += "
%sno build
\n" - - if control is not None: - if building: - stopURL = "builders/_all/stop" - data += make_stop_form(stopURL, True, "Builds") - if online: - forceURL = "builders/_all/force" - data += make_force_build_form(forceURL, True) - - return data - - - -HEADER = ''' - - - -''' - -HEAD_ELEMENTS = [ - '%(title)s', - '', - ] -BODY_ATTRS = { - 'vlink': "#800080", - } - -FOOTER = ''' - -''' - - -class WebStatus(service.MultiService): - implements(IStatusReceiver) - # TODO: IStatusReceiver is really about things which subscribe to hear - # about buildbot events. We need a different interface (perhaps a parent - # of IStatusReceiver) for status targets that don't subscribe, like the - # WebStatus class. buildbot.master.BuildMaster.loadConfig:737 asserts - # that everything in c['status'] provides IStatusReceiver, but really it - # should check that they provide IStatusTarget instead. - - """ - The webserver provided by this class has the following resources: - - /waterfall : the big time-oriented 'waterfall' display, with links - to individual changes, builders, builds, steps, and logs. - A number of query-arguments can be added to influence - the display. - /grid : another summary display that shows a grid of builds, with - sourcestamps on the x axis, and builders on the y. Query - arguments similar to those for the waterfall can be added. - /builders/BUILDERNAME: a page summarizing the builder. This includes - references to the Schedulers that feed it, - any builds currently in the queue, which - buildslaves are designated or attached, and a - summary of the build process it uses. - /builders/BUILDERNAME/builds/NUM: a page describing a single Build - /builders/BUILDERNAME/builds/NUM/steps/STEPNAME: describes a single step - /builders/BUILDERNAME/builds/NUM/steps/STEPNAME/logs/LOGNAME: a StatusLog - /builders/BUILDERNAME/builds/NUM/tests : summarize test results - /builders/BUILDERNAME/builds/NUM/tests/TEST.NAME: results of one test - /builders/_all/{force,stop}: force a build/stop building on all builders. - /changes : summarize all ChangeSources - /changes/CHANGENUM: a page describing a single Change - /schedulers/SCHEDULERNAME: a page describing a Scheduler, including - a description of its behavior, a list of the - Builders it triggers, and list of the Changes - that are queued awaiting the tree-stable - timer, and controls to accelerate the timer. - /buildslaves : list all BuildSlaves - /buildslaves/SLAVENAME : describe a single BuildSlave - /one_line_per_build : summarize the last few builds, one line each - /one_line_per_build/BUILDERNAME : same, but only for a single builder - /one_box_per_builder : show the latest build and current activity - /about : describe this buildmaster (Buildbot and support library versions) - /xmlrpc : (not yet implemented) an XMLRPC server with build status - - - All URLs for pages which are not defined here are used to look for files - in BASEDIR/public_html/ , which means that /robots.txt or /buildbot.css - or /favicon.ico can be placed in that directory. - - If an index file (index.html, index.htm, or index, in that order) is - present in public_html/, it will be used for the root resource. If not, - the default behavior is to put a redirection to the /waterfall page. - - All of the resources provided by this service use relative URLs to reach - each other. The only absolute links are the c['projectURL'] links at the - top and bottom of the page, and the buildbot home-page link at the - bottom. - - This webserver defines class attributes on elements so they can be styled - with CSS stylesheets. All pages pull in public_html/buildbot.css, and you - can cause additional stylesheets to be loaded by adding a suitable - to the WebStatus instance's .head_elements attribute. - - Buildbot uses some generic classes to identify the type of object, and - some more specific classes for the various kinds of those types. It does - this by specifying both in the class attributes where applicable, - separated by a space. It is important that in your CSS you declare the - more generic class styles above the more specific ones. For example, - first define a style for .Event, and below that for .SUCCESS - - The following CSS class names are used: - - Activity, Event, BuildStep, LastBuild: general classes - - waiting, interlocked, building, offline, idle: Activity states - - start, running, success, failure, warnings, skipped, exception: - LastBuild and BuildStep states - - Change: box with change - - Builder: box for builder name (at top) - - Project - - Time - - """ - - # we are not a ComparableMixin, and therefore the webserver will be - # rebuilt every time we reconfig. This is because WebStatus.putChild() - # makes it too difficult to tell whether two instances are the same or - # not (we'd have to do a recursive traversal of all children to discover - # all the changes). - - def __init__(self, http_port=None, distrib_port=None, allowForce=False): - """Run a web server that provides Buildbot status. - - @type http_port: int or L{twisted.application.strports} string - @param http_port: a strports specification describing which port the - buildbot should use for its web server, with the - Waterfall display as the root page. For backwards - compatibility this can also be an int. Use - 'tcp:8000' to listen on that port, or - 'tcp:12345:interface=127.0.0.1' if you only want - local processes to connect to it (perhaps because - you are using an HTTP reverse proxy to make the - buildbot available to the outside world, and do not - want to make the raw port visible). - - @type distrib_port: int or L{twisted.application.strports} string - @param distrib_port: Use this if you want to publish the Waterfall - page using web.distrib instead. The most common - case is to provide a string that is an absolute - pathname to the unix socket on which the - publisher should listen - (C{os.path.expanduser(~/.twistd-web-pb)} will - match the default settings of a standard - twisted.web 'personal web server'). Another - possibility is to pass an integer, which means - the publisher should listen on a TCP socket, - allowing the web server to be on a different - machine entirely. Both forms are provided for - backwards compatibility; the preferred form is a - strports specification like - 'unix:/home/buildbot/.twistd-web-pb'. Providing - a non-absolute pathname will probably confuse - the strports parser. - @param allowForce: boolean, if True then the webserver will allow - visitors to trigger and cancel builds - """ - - service.MultiService.__init__(self) - if type(http_port) is int: - http_port = "tcp:%d" % http_port - self.http_port = http_port - if distrib_port is not None: - if type(distrib_port) is int: - distrib_port = "tcp:%d" % distrib_port - if distrib_port[0] in "/~.": # pathnames - distrib_port = "unix:%s" % distrib_port - self.distrib_port = distrib_port - self.allowForce = allowForce - - # this will be replaced once we've been attached to a parent (and - # thus have a basedir and can reference BASEDIR/public_html/) - root = static.Data("placeholder", "text/plain") - self.site = server.Site(root) - self.childrenToBeAdded = {} - - self.setupUsualPages() - - # the following items are accessed by HtmlResource when it renders - # each page. - self.site.buildbot_service = self - self.header = HEADER - self.head_elements = HEAD_ELEMENTS[:] - self.body_attrs = BODY_ATTRS.copy() - self.footer = FOOTER - self.template_values = {} - - # keep track of cached connections so we can break them when we shut - # down. See ticket #102 for more details. - self.channels = weakref.WeakKeyDictionary() - - if self.http_port is not None: - s = strports.service(self.http_port, self.site) - s.setServiceParent(self) - if self.distrib_port is not None: - f = pb.PBServerFactory(distrib.ResourcePublisher(self.site)) - s = strports.service(self.distrib_port, f) - s.setServiceParent(self) - - def setupUsualPages(self): - #self.putChild("", IndexOrWaterfallRedirection()) - self.putChild("waterfall", WaterfallStatusResource()) - self.putChild("grid", GridStatusResource()) - self.putChild("builders", BuildersResource()) # has builds/steps/logs - self.putChild("changes", ChangesResource()) - self.putChild("buildslaves", BuildSlavesResource()) - #self.putChild("schedulers", SchedulersResource()) - self.putChild("one_line_per_build", OneLinePerBuild()) - self.putChild("one_box_per_builder", OneBoxPerBuilder()) - self.putChild("xmlrpc", XMLRPCServer()) - self.putChild("about", AboutBuildbot()) - - def __repr__(self): - if self.http_port is None: - return "" % (self.distrib_port, - hex(id(self))) - if self.distrib_port is None: - return "" % (self.http_port, - hex(id(self))) - return ("" % - (self.http_port, self.distrib_port, hex(id(self)))) - - def setServiceParent(self, parent): - service.MultiService.setServiceParent(self, parent) - self.setupSite() - - def setupSite(self): - # this is responsible for creating the root resource. It isn't done - # at __init__ time because we need to reference the parent's basedir. - htmldir = os.path.join(self.parent.basedir, "public_html") - if os.path.isdir(htmldir): - log.msg("WebStatus using (%s)" % htmldir) - else: - log.msg("WebStatus: warning: %s is missing. Do you need to run" - " 'buildbot upgrade-master' on this buildmaster?" % htmldir) - # all static pages will get a 404 until upgrade-master is used to - # populate this directory. Create the directory, though, since - # otherwise we get internal server errors instead of 404s. - os.mkdir(htmldir) - root = static.File(htmldir) - - for name, child_resource in self.childrenToBeAdded.iteritems(): - root.putChild(name, child_resource) - - self.site.resource = root - - def putChild(self, name, child_resource): - """This behaves a lot like root.putChild() . """ - self.childrenToBeAdded[name] = child_resource - - def registerChannel(self, channel): - self.channels[channel] = 1 # weakrefs - - def stopService(self): - for channel in self.channels: - try: - channel.transport.loseConnection() - except: - log.msg("WebStatus.stopService: error while disconnecting" - " leftover clients") - log.err() - return service.MultiService.stopService(self) - - def getStatus(self): - return self.parent.getStatus() - def getControl(self): - if self.allowForce: - return IControl(self.parent) - return None - - def getPortnum(self): - # this is for the benefit of unit tests - s = list(self)[0] - return s._port.getHost().port - -# resources can get access to the IStatus by calling -# request.site.buildbot_service.getStatus() - -# this is the compatibility class for the old waterfall. It is exactly like a -# regular WebStatus except that the root resource (e.g. http://buildbot.net/) -# always redirects to a WaterfallStatusResource, and the old arguments are -# mapped into the new resource-tree approach. In the normal WebStatus, the -# root resource either redirects the browser to /waterfall or serves -# BASEDIR/public_html/index.html, and favicon/robots.txt are provided by -# having the admin write actual files into BASEDIR/public_html/ . - -# note: we don't use a util.Redirect here because HTTP requires that the -# Location: header provide an absolute URI, and it's non-trivial to figure -# out our absolute URI from here. - -class Waterfall(WebStatus): - - if hasattr(sys, "frozen"): - # all 'data' files are in the directory of our executable - here = os.path.dirname(sys.executable) - buildbot_icon = os.path.abspath(os.path.join(here, "buildbot.png")) - buildbot_css = os.path.abspath(os.path.join(here, "classic.css")) - else: - # running from source - # the icon is sibpath(__file__, "../buildbot.png") . This is for - # portability. - up = os.path.dirname - buildbot_icon = os.path.abspath(os.path.join(up(up(up(__file__))), - "buildbot.png")) - buildbot_css = os.path.abspath(os.path.join(up(__file__), - "classic.css")) - - compare_attrs = ["http_port", "distrib_port", "allowForce", - "categories", "css", "favicon", "robots_txt"] - - def __init__(self, http_port=None, distrib_port=None, allowForce=True, - categories=None, css=buildbot_css, favicon=buildbot_icon, - robots_txt=None): - import warnings - m = ("buildbot.status.html.Waterfall is deprecated as of 0.7.6 " - "and will be removed from a future release. " - "Please use html.WebStatus instead.") - warnings.warn(m, DeprecationWarning) - - WebStatus.__init__(self, http_port, distrib_port, allowForce) - self.css = css - if css: - if os.path.exists(os.path.join("public_html", "buildbot.css")): - # they've upgraded, so defer to that copy instead - pass - else: - data = open(css, "rb").read() - self.putChild("buildbot.css", static.Data(data, "text/plain")) - self.favicon = favicon - self.robots_txt = robots_txt - if favicon: - data = open(favicon, "rb").read() - self.putChild("favicon.ico", static.Data(data, "image/x-icon")) - if robots_txt: - data = open(robots_txt, "rb").read() - self.putChild("robots.txt", static.Data(data, "text/plain")) - self.putChild("", WaterfallStatusResource(categories)) diff --git a/tools/buildbot/pylibs/buildbot/status/web/build.py b/tools/buildbot/pylibs/buildbot/status/web/build.py deleted file mode 100644 index 905bedc..0000000 --- a/tools/buildbot/pylibs/buildbot/status/web/build.py +++ /dev/null @@ -1,289 +0,0 @@ - -from twisted.web import html -from twisted.web.util import Redirect, DeferredResource -from twisted.internet import defer, reactor - -import urllib, time -from twisted.python import log -from buildbot.status.web.base import HtmlResource, make_row, make_stop_form, \ - css_classes, path_to_builder - -from buildbot.status.web.tests import TestsResource -from buildbot.status.web.step import StepsResource -from buildbot import version, util - -# /builders/$builder/builds/$buildnum -class StatusResourceBuild(HtmlResource): - addSlash = True - - def __init__(self, build_status, build_control, builder_control): - HtmlResource.__init__(self) - self.build_status = build_status - self.build_control = build_control - self.builder_control = builder_control - - def getTitle(self, request): - return ("Buildbot: %s Build #%d" % - (html.escape(self.build_status.getBuilder().getName()), - self.build_status.getNumber())) - - def body(self, req): - b = self.build_status - status = self.getStatus(req) - projectURL = status.getProjectURL() - projectName = status.getProjectName() - data = ('\n' - % (self.path_to_root(req), projectName)) - # the color in the following line gives python-mode trouble - builder_name = b.getBuilder().getName() - data += ("

Builder %s: Build #%d

\n" - % (path_to_builder(req, b.getBuilder()), - builder_name, b.getNumber())) - - if not b.isFinished(): - data += "

Build In Progress

" - when = b.getETA() - if when is not None: - when_time = time.strftime("%H:%M:%S", - time.localtime(time.time() + when)) - data += "
ETA %ds (%s)
\n" % (when, when_time) - - if self.build_control is not None: - stopURL = urllib.quote(req.childLink("stop")) - data += make_stop_form(stopURL) - - if b.isFinished(): - results = b.getResults() - data += "

Results:

\n" - text = " ".join(b.getText()) - data += '%s\n' % (css_classes[results], - text) - if b.getTestResults(): - url = req.childLink("tests") - data += "

test results

\n" % url - - ss = b.getSourceStamp() - data += "

SourceStamp:

\n" - data += "
    \n" - if ss.branch: - data += "
  • Branch: %s
  • \n" % html.escape(ss.branch) - if ss.revision: - data += "
  • Revision: %s
  • \n" % html.escape(str(ss.revision)) - if ss.patch: - data += "
  • Patch: YES
  • \n" # TODO: provide link to .diff - if ss.changes: - data += "
  • Changes: see below
  • \n" - if (ss.branch is None and ss.revision is None and ss.patch is None - and not ss.changes): - data += "
  • build of most recent revision
  • \n" - got_revision = None - try: - got_revision = b.getProperty("got_revision") - except KeyError: - pass - if got_revision: - got_revision = str(got_revision) - if len(got_revision) > 40: - got_revision = "[revision string too long]" - data += "
  • Got Revision: %s
  • \n" % got_revision - data += "
\n" - - # TODO: turn this into a table, or some other sort of definition-list - # that doesn't take up quite so much vertical space - data += "

Buildslave:

\n %s\n" % html.escape(b.getSlavename()) - data += "

Reason:

\n%s\n" % html.escape(b.getReason()) - - data += "

Steps and Logfiles:

\n" - # TODO: -# urls = self.original.getURLs() -# ex_url_class = "BuildStep external" -# for name, target in urls.items(): -# text.append('[%s]' % -# (target, ex_url_class, html.escape(name))) - if b.getLogs(): - data += "
    \n" - for s in b.getSteps(): - name = s.getName() - data += ("
  1. %s [%s]\n" - % (req.childLink("steps/%s" % urllib.quote(name)), - name, - " ".join(s.getText()))) - if s.getLogs(): - data += "
      \n" - for logfile in s.getLogs(): - logname = logfile.getName() - logurl = req.childLink("steps/%s/logs/%s" % - (urllib.quote(name), - urllib.quote(logname))) - data += ("
    1. %s
    2. \n" % - (logurl, logfile.getName())) - data += "
    \n" - data += "
  2. \n" - data += "
\n" - - data += "

Build Properties:

\n" - data += "\n" - for name, value, source in b.getProperties().asList(): - value = str(value) - if len(value) > 500: - value = value[:500] + " .. [property value too long]" - data += "" - data += "" % html.escape(name) - data += "" % html.escape(value) - data += "" % html.escape(source) - data += "\n" - data += "
NameValueSource
%s%s%s
" - - data += "

Blamelist:

\n" - if list(b.getResponsibleUsers()): - data += "
    \n" - for who in b.getResponsibleUsers(): - data += "
  1. %s
  2. \n" % html.escape(who) - data += "
\n" - else: - data += "
no responsible users
\n" - - if ss.changes: - data += "

All Changes

\n" - data += "
    \n" - for c in ss.changes: - data += "
  1. " + c.asHTML() + "
  2. \n" - data += "
\n" - #data += html.PRE(b.changesText()) # TODO - - if b.isFinished() and self.builder_control is not None: - data += "

Resubmit Build:

\n" - # can we rebuild it exactly? - exactly = (ss.revision is not None) or b.getChanges() - if exactly: - data += ("

This tree was built from a specific set of \n" - "source files, and can be rebuilt exactly

\n") - else: - data += ("

This tree was built from the most recent " - "revision") - if ss.branch: - data += " (along some branch)" - data += (" and thus it might not be possible to rebuild it \n" - "exactly. Any changes that have been committed \n" - "after this build was started will be \n" - "included in a rebuild.

\n") - rebuildURL = urllib.quote(req.childLink("rebuild")) - data += ('
\n' - % rebuildURL) - data += make_row("Your name:", - "") - data += make_row("Reason for re-running build:", - "") - data += '\n' - data += '
\n' - - # TODO: this stuff should be generated by a template of some sort - data += '
\n' - - return data - - def stop(self, req): - b = self.build_status - c = self.build_control - log.msg("web stopBuild of build %s:%s" % \ - (b.getBuilder().getName(), b.getNumber())) - name = req.args.get("username", [""])[0] - comments = req.args.get("comments", [""])[0] - reason = ("The web-page 'stop build' button was pressed by " - "'%s': %s\n" % (name, comments)) - c.stopBuild(reason) - # we're at http://localhost:8080/svn-hello/builds/5/stop?[args] and - # we want to go to: http://localhost:8080/svn-hello - r = Redirect("../..") - d = defer.Deferred() - reactor.callLater(1, d.callback, r) - return DeferredResource(d) - - def rebuild(self, req): - b = self.build_status - bc = self.builder_control - builder_name = b.getBuilder().getName() - log.msg("web rebuild of build %s:%s" % (builder_name, b.getNumber())) - name = req.args.get("username", [""])[0] - comments = req.args.get("comments", [""])[0] - reason = ("The web-page 'rebuild' button was pressed by " - "'%s': %s\n" % (name, comments)) - if not bc or not b.isFinished(): - log.msg("could not rebuild: bc=%s, isFinished=%s" - % (bc, b.isFinished())) - # TODO: indicate an error - else: - bc.resubmitBuild(b, reason) - # we're at - # http://localhost:8080/builders/NAME/builds/5/rebuild?[args] - # Where should we send them? - # - # Ideally it would be to the per-build page that they just started, - # but we don't know the build number for it yet (besides, it might - # have to wait for a current build to finish). The next-most - # preferred place is somewhere that the user can see tangible - # evidence of their build starting (or to see the reason that it - # didn't start). This should be the Builder page. - r = Redirect("../..") # the Builder's page - d = defer.Deferred() - reactor.callLater(1, d.callback, r) - return DeferredResource(d) - - def getChild(self, path, req): - if path == "stop": - return self.stop(req) - if path == "rebuild": - return self.rebuild(req) - if path == "steps": - return StepsResource(self.build_status) - if path == "tests": - return TestsResource(self.build_status) - - return HtmlResource.getChild(self, path, req) - -# /builders/$builder/builds -class BuildsResource(HtmlResource): - addSlash = True - - def __init__(self, builder_status, builder_control): - HtmlResource.__init__(self) - self.builder_status = builder_status - self.builder_control = builder_control - - def getChild(self, path, req): - try: - num = int(path) - except ValueError: - num = None - if num is not None: - build_status = self.builder_status.getBuild(num) - if build_status: - if self.builder_control: - build_control = self.builder_control.getBuild(num) - else: - build_control = None - return StatusResourceBuild(build_status, build_control, - self.builder_control) - - return HtmlResource.getChild(self, path, req) - diff --git a/tools/buildbot/pylibs/buildbot/status/web/builder.py b/tools/buildbot/pylibs/buildbot/status/web/builder.py deleted file mode 100644 index d625d43..0000000 --- a/tools/buildbot/pylibs/buildbot/status/web/builder.py +++ /dev/null @@ -1,358 +0,0 @@ - -from twisted.web.error import NoResource -from twisted.web import html, static -from twisted.web.util import Redirect - -import re, urllib, time -from twisted.python import log -from buildbot import interfaces -from buildbot.status.web.base import HtmlResource, make_row, \ - make_force_build_form, OneLineMixin -from buildbot.process.base import BuildRequest -from buildbot.sourcestamp import SourceStamp -from buildbot import version, util - -from buildbot.status.web.build import BuildsResource, StatusResourceBuild - -# /builders/$builder -class StatusResourceBuilder(HtmlResource, OneLineMixin): - addSlash = True - - def __init__(self, builder_status, builder_control): - HtmlResource.__init__(self) - self.builder_status = builder_status - self.builder_control = builder_control - - def getTitle(self, request): - return "Buildbot: %s" % html.escape(self.builder_status.getName()) - - def build_line(self, build, req): - buildnum = build.getNumber() - buildurl = req.childLink("builds/%d" % buildnum) - data = '#%d ' % (buildurl, buildnum) - - when = build.getETA() - if when is not None: - when_time = time.strftime("%H:%M:%S", - time.localtime(time.time() + when)) - data += "ETA %ds (%s) " % (when, when_time) - step = build.getCurrentStep() - if step: - data += "[%s]" % step.getName() - else: - data += "[waiting for Lock]" - # TODO: is this necessarily the case? - - if self.builder_control is not None: - stopURL = urllib.quote(req.childLink("builds/%d/stop" % buildnum)) - data += ''' -
- -
''' % stopURL - return data - - def body(self, req): - b = self.builder_status - control = self.builder_control - status = self.getStatus(req) - - slaves = b.getSlaves() - connected_slaves = [s for s in slaves if s.isConnected()] - - projectName = status.getProjectName() - - data = '%s\n' % (self.path_to_root(req), projectName) - - data += "

Builder: %s

\n" % html.escape(b.getName()) - - # the first section shows builds which are currently running, if any. - - current = b.getCurrentBuilds() - if current: - data += "

Currently Building:

\n" - data += "
    \n" - for build in current: - data += "
  • " + self.build_line(build, req) + "
  • \n" - data += "
\n" - else: - data += "

no current builds

\n" - - # Then a section with the last 5 builds, with the most recent build - # distinguished from the rest. - - data += "

Recent Builds:

\n" - data += "
    \n" - for i,build in enumerate(b.generateFinishedBuilds(num_builds=5)): - data += "
  • " + self.make_line(req, build, False) + "
  • \n" - if i == 0: - data += "
    \n" # separator - # TODO: or empty list? - data += "
\n" - - - data += "

Buildslaves:

\n" - data += "
    \n" - for slave in slaves: - data += "
  1. %s: " % html.escape(slave.getName()) - if slave.isConnected(): - data += "CONNECTED\n" - if slave.getAdmin(): - data += make_row("Admin:", html.escape(slave.getAdmin())) - if slave.getHost(): - data += "Host info:\n" - data += html.PRE(slave.getHost()) - else: - data += ("NOT CONNECTED\n") - data += "
  2. \n" - data += "
\n" - - if control is not None and connected_slaves: - forceURL = urllib.quote(req.childLink("force")) - data += make_force_build_form(forceURL) - elif control is not None: - data += """ -

All buildslaves appear to be offline, so it's not possible - to force this build to execute at this time.

- """ - - if control is not None: - pingURL = urllib.quote(req.childLink("ping")) - data += """ -
-

To ping the buildslave(s), push the 'Ping' button

- - -
- """ % pingURL - - # TODO: this stuff should be generated by a template of some sort - projectURL = status.getProjectURL() - projectName = status.getProjectName() - data += '
\n' - - return data - - def force(self, req): - """ - - Custom properties can be passed from the web form. To do - this, subclass this class, overriding the force() method. You - can then determine the properties (usually from form values, - by inspecting req.args), then pass them to this superclass - force method. - - """ - name = req.args.get("username", [""])[0] - reason = req.args.get("comments", [""])[0] - branch = req.args.get("branch", [""])[0] - revision = req.args.get("revision", [""])[0] - - r = "The web-page 'force build' button was pressed by '%s': %s\n" \ - % (name, reason) - log.msg("web forcebuild of builder '%s', branch='%s', revision='%s'" - % (self.builder_status.getName(), branch, revision)) - - if not self.builder_control: - # TODO: tell the web user that their request was denied - log.msg("but builder control is disabled") - return Redirect("..") - - # keep weird stuff out of the branch and revision strings. TODO: - # centralize this somewhere. - if not re.match(r'^[\w\.\-\/]*$', branch): - log.msg("bad branch '%s'" % branch) - return Redirect("..") - if not re.match(r'^[\w\.\-\/]*$', revision): - log.msg("bad revision '%s'" % revision) - return Redirect("..") - if not branch: - branch = None - if not revision: - revision = None - - # TODO: if we can authenticate that a particular User pushed the - # button, use their name instead of None, so they'll be informed of - # the results. - s = SourceStamp(branch=branch, revision=revision) - req = BuildRequest(r, s, builderName=self.builder_status.getName()) - try: - self.builder_control.requestBuildSoon(req) - except interfaces.NoSlaveError: - # TODO: tell the web user that their request could not be - # honored - pass - # send the user back to the builder page - return Redirect(".") - - def ping(self, req): - log.msg("web ping of builder '%s'" % self.builder_status.getName()) - self.builder_control.ping() # TODO: there ought to be an ISlaveControl - # send the user back to the builder page - return Redirect(".") - - def getChild(self, path, req): - if path == "force": - return self.force(req) - if path == "ping": - return self.ping(req) - if path == "events": - num = req.postpath.pop(0) - req.prepath.append(num) - num = int(num) - # TODO: is this dead code? .statusbag doesn't exist,right? - log.msg("getChild['path']: %s" % req.uri) - return NoResource("events are unavailable until code gets fixed") - filename = req.postpath.pop(0) - req.prepath.append(filename) - e = self.builder_status.getEventNumbered(num) - if not e: - return NoResource("No such event '%d'" % num) - file = e.files.get(filename, None) - if file == None: - return NoResource("No such file '%s'" % filename) - if type(file) == type(""): - if file[:6] in ("", ""): - return static.Data(file, "text/html") - return static.Data(file, "text/plain") - return file - if path == "builds": - return BuildsResource(self.builder_status, self.builder_control) - - return HtmlResource.getChild(self, path, req) - - -# /builders/_all -class StatusResourceAllBuilders(HtmlResource, OneLineMixin): - - def __init__(self, status, control): - HtmlResource.__init__(self) - self.status = status - self.control = control - - def getChild(self, path, req): - if path == "force": - return self.force(req) - if path == "stop": - return self.stop(req) - - return HtmlResource.getChild(self, path, req) - - def force(self, req): - for bname in self.status.getBuilderNames(): - builder_status = self.status.getBuilder(bname) - builder_control = None - c = self.getControl(req) - if c: - builder_control = c.getBuilder(bname) - build = StatusResourceBuilder(builder_status, builder_control) - build.force(req) - # back to the welcome page - return Redirect("../..") - - def stop(self, req): - for bname in self.status.getBuilderNames(): - builder_status = self.status.getBuilder(bname) - builder_control = None - c = self.getControl(req) - if c: - builder_control = c.getBuilder(bname) - (state, current_builds) = builder_status.getState() - if state != "building": - continue - for b in current_builds: - build_status = builder_status.getBuild(b.number) - if not build_status: - continue - if builder_control: - build_control = builder_control.getBuild(b.number) - else: - build_control = None - build = StatusResourceBuild(build_status, build_control, - builder_control) - build.stop(req) - # go back to the welcome page - return Redirect("../..") - - -# /builders -class BuildersResource(HtmlResource): - title = "Builders" - addSlash = True - - def body(self, req): - s = self.getStatus(req) - data = "" - data += "

Builders

\n" - - # TODO: this is really basic. It should be expanded to include a - # brief one-line summary of the builder (perhaps with whatever the - # builder is currently doing) - data += "
    \n" - for bname in s.getBuilderNames(): - data += ('
  1. %s
  2. \n' % - (req.childLink(urllib.quote(bname, safe='')), - urllib.quote(bname, safe=''))) - data += "
\n" - - # TODO: this stuff should be generated by a template of some sort - projectURL = s.getProjectURL() - projectName = s.getProjectName() - data += '
\n' - - return data - - def getChild(self, path, req): - s = self.getStatus(req) - if path in s.getBuilderNames(): - builder_status = s.getBuilder(path) - builder_control = None - c = self.getControl(req) - if c: - builder_control = c.getBuilder(path) - return StatusResourceBuilder(builder_status, builder_control) - if path == "_all": - return StatusResourceAllBuilders(self.getStatus(req), - self.getControl(req)) - - return HtmlResource.getChild(self, path, req) - diff --git a/tools/buildbot/pylibs/buildbot/status/web/changes.py b/tools/buildbot/pylibs/buildbot/status/web/changes.py deleted file mode 100644 index d6b4110..0000000 --- a/tools/buildbot/pylibs/buildbot/status/web/changes.py +++ /dev/null @@ -1,41 +0,0 @@ - -from zope.interface import implements -from twisted.python import components -from twisted.web.error import NoResource - -from buildbot.changes.changes import Change -from buildbot.status.web.base import HtmlResource, StaticHTML, IBox, Box - -# /changes/NN -class ChangesResource(HtmlResource): - - def body(self, req): - data = "" - data += "Change sources:\n" - sources = self.getStatus(req).getChangeSources() - if sources: - data += "
    \n" - for s in sources: - data += "
  1. %s
  2. \n" % s.describe() - data += "
\n" - else: - data += "none (push only)\n" - return data - - def getChild(self, path, req): - num = int(path) - c = self.getStatus(req).getChange(num) - if not c: - return NoResource("No change number '%d'" % num) - return StaticHTML(c.asHTML(), "Change #%d" % num) - - -class ChangeBox(components.Adapter): - implements(IBox) - - def getBox(self, req): - url = req.childLink("../changes/%d" % self.original.number) - text = self.original.get_HTML_box(url) - return Box([text], color="white", class_="Change") -components.registerAdapter(ChangeBox, Change, IBox) - diff --git a/tools/buildbot/pylibs/buildbot/status/web/classic.css b/tools/buildbot/pylibs/buildbot/status/web/classic.css deleted file mode 100644 index d57736e..0000000 --- a/tools/buildbot/pylibs/buildbot/status/web/classic.css +++ /dev/null @@ -1,78 +0,0 @@ -a:visited { - color: #800080; -} - -td.Event, td.BuildStep, td.Activity, td.Change, td.Time, td.Builder { - border-top: 1px solid; - border-right: 1px solid; -} - -td.box { - border: 1px solid; -} - -/* Activity states */ -.offline { - background-color: red; -} -.idle { - background-color: white; -} -.waiting { - background-color: yellow; -} -.building { - background-color: yellow; -} - -/* LastBuild, BuildStep states */ -.success { - background-color: #72ff75; -} -.failure { - background-color: red; -} -.warnings { - background-color: #ff8000; -} -.exception { - background-color: #c000c0; -} -.start,.running { - background-color: yellow; -} - -/* grid styles */ - -table.Grid { - border-collapse: collapse; -} - -table.Grid tr td { - padding: 0.2em; - margin: 0px; - text-align: center; -} - -table.Grid tr td.title { - font-size: 90%; - border-right: 1px gray solid; - border-bottom: 1px gray solid; -} - -table.Grid tr td.sourcestamp { - font-size: 90%; -} - -table.Grid tr td.builder { - text-align: right; - font-size: 90%; -} - -table.Grid tr td.build { - border: 1px gray solid; -} - -div.footer { - font-size: 80%; -} diff --git a/tools/buildbot/pylibs/buildbot/status/web/grid.py b/tools/buildbot/pylibs/buildbot/status/web/grid.py deleted file mode 100644 index 59a25aa..0000000 --- a/tools/buildbot/pylibs/buildbot/status/web/grid.py +++ /dev/null @@ -1,263 +0,0 @@ -from __future__ import generators - -import sys, time, os.path -import urllib - -from buildbot import util -from buildbot import version -from buildbot.status.web.base import HtmlResource - -# set grid_css to the full pathname of the css file -if hasattr(sys, "frozen"): - # all 'data' files are in the directory of our executable - here = os.path.dirname(sys.executable) - grid_css = os.path.abspath(os.path.join(here, "grid.css")) -else: - # running from source; look for a sibling to __file__ - up = os.path.dirname - grid_css = os.path.abspath(os.path.join(up(__file__), "grid.css")) - -class ANYBRANCH: pass # a flag value, used below - -class GridStatusResource(HtmlResource): - # TODO: docs - status = None - control = None - changemaster = None - - def __init__(self, allowForce=True, css=None): - HtmlResource.__init__(self) - - self.allowForce = allowForce - self.css = css or grid_css - - def getTitle(self, request): - status = self.getStatus(request) - p = status.getProjectName() - if p: - return "BuildBot: %s" % p - else: - return "BuildBot" - - def getChangemaster(self, request): - # TODO: this wants to go away, access it through IStatus - return request.site.buildbot_service.parent.change_svc - - # handle reloads through an http header - # TODO: send this as a real header, rather than a tag - def get_reload_time(self, request): - if "reload" in request.args: - try: - reload_time = int(request.args["reload"][0]) - return max(reload_time, 15) - except ValueError: - pass - return None - - def head(self, request): - head = '' - reload_time = self.get_reload_time(request) - if reload_time is not None: - head += '\n' % reload_time - return head - -# def setBuildmaster(self, buildmaster): -# self.status = buildmaster.getStatus() -# if self.allowForce: -# self.control = interfaces.IControl(buildmaster) -# else: -# self.control = None -# self.changemaster = buildmaster.change_svc -# -# # try to set the page title -# p = self.status.getProjectName() -# if p: -# self.title = "BuildBot: %s" % p -# - def build_td(self, request, build): - if not build: - return ' \n' - - if build.isFinished(): - color = build.getColor() - if color == 'green': color = '#72ff75' # the "Buildbot Green" - - # get the text and annotate the first line with a link - text = build.getText() - if not text: text = [ "(no information)" ] - if text == [ "build", "successful" ]: text = [ "OK" ] - else: - color = 'yellow' # to match the yellow of the builder - text = [ 'building' ] - - name = build.getBuilder().getName() - number = build.getNumber() - url = "builders/%s/builds/%d" % (name, number) - text[0] = '%s' % (url, text[0]) - text = '
\n'.join(text) - - return '%s\n' % (color, text) - - def builder_td(self, request, builder): - state, builds = builder.getState() - - # look for upcoming builds. We say the state is "waiting" if the - # builder is otherwise idle and there is a scheduler which tells us a - # build will be performed some time in the near future. TODO: this - # functionality used to be in BuilderStatus.. maybe this code should - # be merged back into it. - upcoming = [] - builderName = builder.getName() - for s in self.getStatus(request).getSchedulers(): - if builderName in s.listBuilderNames(): - upcoming.extend(s.getPendingBuildTimes()) - if state == "idle" and upcoming: - state = "waiting" - - if state == "building": - color = "yellow" - elif state == "offline": - color = "red" - elif state == "idle": - color = "white" - elif state == "waiting": - color = "yellow" - else: - color = "white" - - # TODO: for now, this pending/upcoming stuff is in the "current - # activity" box, but really it should go into a "next activity" row - # instead. The only times it should show up in "current activity" is - # when the builder is otherwise idle. - - # are any builds pending? (waiting for a slave to be free) - url = 'builders/%s/' % urllib.quote(builder.getName(), safe='') - text = '%s' % (url, builder.getName()) - pbs = builder.getPendingBuilds() - if state != 'idle' or pbs: - if pbs: - text += "
(%s with %d pending)" % (state, len(pbs)) - else: - text += "
(%s)" % state - - return '%s\n' % \ - (color, text) - - def stamp_td(self, stamp): - text = stamp.getText() - return '%s\n' % \ - "
".join(text) - - def body(self, request): - "This method builds the main waterfall display." - - # get url parameters - numBuilds = int(request.args.get("width", [5])[0]) - categories = request.args.get("category", []) - branch = request.args.get("branch", [ANYBRANCH])[0] - if branch == 'trunk': branch = None - - # and the data we want to render - status = self.getStatus(request) - stamps = self.getRecentSourcestamps(status, numBuilds, categories, branch) - - projectURL = status.getProjectURL() - projectName = status.getProjectName() - - data = '\n' - data += '\n' - data += '\n' - for stamp in stamps: - data += self.stamp_td(stamp) - data += '\n' - - sortedBuilderNames = status.getBuilderNames()[:] - sortedBuilderNames.sort() - for bn in sortedBuilderNames: - builds = [None] * len(stamps) - - builder = status.getBuilder(bn) - if categories and builder.category not in categories: - continue - - build = builder.getBuild(-1) - while build and None in builds: - ss = build.getSourceStamp(absolute=True) - for i in range(len(stamps)): - if ss == stamps[i] and builds[i] is None: - builds[i] = build - build = build.getPreviousBuild() - - data += '\n' - data += self.builder_td(request, builder) - for build in builds: - data += self.build_td(request, build) - data += '\n' - - data += '
%s' % (projectURL, projectName) - if categories: - if len(categories) > 1: - data += '\n
Categories:
%s' % ('
'.join(categories)) - else: - data += '\n
Category: %s' % categories[0] - if branch != ANYBRANCH: - data += '\n
Branch: %s' % (branch or 'trunk') - data += '
\n' - - # TODO: this stuff should be generated by a template of some sort - data += '
\n' - return data - - def getRecentSourcestamps(self, status, numBuilds, categories, branch): - """ - get a list of the most recent NUMBUILDS SourceStamp tuples, sorted - by the earliest start we've seen for them - """ - # TODO: use baseweb's getLastNBuilds? - sourcestamps = { } # { ss-tuple : earliest time } - for bn in status.getBuilderNames(): - builder = status.getBuilder(bn) - if categories and builder.category not in categories: - continue - build = builder.getBuild(-1) - while build: - ss = build.getSourceStamp(absolute=True) - start = build.getTimes()[0] - build = build.getPreviousBuild() - - # skip un-started builds - if not start: continue - - # skip non-matching branches - if branch != ANYBRANCH and ss.branch != branch: continue - - sourcestamps[ss] = min(sourcestamps.get(ss, sys.maxint), start) - - # now sort those and take the NUMBUILDS most recent - sourcestamps = sourcestamps.items() - sourcestamps.sort(lambda x, y: cmp(x[1], y[1])) - sourcestamps = map(lambda tup : tup[0], sourcestamps) - sourcestamps = sourcestamps[-numBuilds:] - - return sourcestamps - diff --git a/tools/buildbot/pylibs/buildbot/status/web/index.html b/tools/buildbot/pylibs/buildbot/status/web/index.html deleted file mode 100644 index 23e6650..0000000 --- a/tools/buildbot/pylibs/buildbot/status/web/index.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - -Welcome to the Buildbot - - - -

Welcome to the Buildbot!

- - - - - diff --git a/tools/buildbot/pylibs/buildbot/status/web/logs.py b/tools/buildbot/pylibs/buildbot/status/web/logs.py deleted file mode 100644 index 20132ac..0000000 --- a/tools/buildbot/pylibs/buildbot/status/web/logs.py +++ /dev/null @@ -1,168 +0,0 @@ - -from zope.interface import implements -from twisted.python import components -from twisted.spread import pb -from twisted.web import html, server -from twisted.web.resource import Resource -from twisted.web.error import NoResource - -from buildbot import interfaces -from buildbot.status import builder -from buildbot.status.web.base import IHTMLLog, HtmlResource - - -textlog_stylesheet = """ - -""" - -class ChunkConsumer: - implements(interfaces.IStatusLogConsumer) - - def __init__(self, original, textlog): - self.original = original - self.textlog = textlog - def registerProducer(self, producer, streaming): - self.producer = producer - self.original.registerProducer(producer, streaming) - def unregisterProducer(self): - self.original.unregisterProducer() - def writeChunk(self, chunk): - formatted = self.textlog.content([chunk]) - try: - self.original.write(formatted) - except pb.DeadReferenceError: - self.producing.stopProducing() - def finish(self): - self.textlog.finished() - - -# /builders/$builder/builds/$buildnum/steps/$stepname/logs/$logname -class TextLog(Resource): - # a new instance of this Resource is created for each client who views - # it, so we can afford to track the request in the Resource. - implements(IHTMLLog) - - asText = False - subscribed = False - - def __init__(self, original): - Resource.__init__(self) - self.original = original - - def getChild(self, path, req): - if path == "text": - self.asText = True - return self - return HtmlResource.getChild(self, path, req) - - def htmlHeader(self, request): - title = "Log File contents" - data = "\n" + title + "\n" - data += textlog_stylesheet - data += "\n" - data += "\n" - texturl = request.childLink("text") - data += '(view as text)
\n' % texturl - data += "
\n"
-        return data
-
-    def content(self, entries):
-        spanfmt = '%s'
-        data = ""
-        for type, entry in entries:
-            if self.asText:
-                if type != builder.HEADER:
-                    data += entry
-            else:
-                data += spanfmt % (builder.ChunkTypes[type],
-                                   html.escape(entry))
-        return data
-
-    def htmlFooter(self):
-        data = "
\n" - data += "\n" - return data - - def render_HEAD(self, request): - if self.asText: - request.setHeader("content-type", "text/plain") - else: - request.setHeader("content-type", "text/html") - - # vague approximation, ignores markup - request.setHeader("content-length", self.original.length) - return '' - - def render_GET(self, req): - self.req = req - - if self.asText: - req.setHeader("content-type", "text/plain") - else: - req.setHeader("content-type", "text/html") - - if not self.asText: - req.write(self.htmlHeader(req)) - - self.original.subscribeConsumer(ChunkConsumer(req, self)) - return server.NOT_DONE_YET - - def finished(self): - if not self.req: - return - try: - if not self.asText: - self.req.write(self.htmlFooter()) - self.req.finish() - except pb.DeadReferenceError: - pass - # break the cycle, the Request's .notifications list includes the - # Deferred (from req.notifyFinish) that's pointing at us. - self.req = None - -components.registerAdapter(TextLog, interfaces.IStatusLog, IHTMLLog) - - -class HTMLLog(Resource): - implements(IHTMLLog) - - def __init__(self, original): - Resource.__init__(self) - self.original = original - - def render(self, request): - request.setHeader("content-type", "text/html") - return self.original.html - -components.registerAdapter(HTMLLog, builder.HTMLLogFile, IHTMLLog) - - -class LogsResource(HtmlResource): - addSlash = True - - def __init__(self, step_status): - HtmlResource.__init__(self) - self.step_status = step_status - - def getChild(self, path, req): - for log in self.step_status.getLogs(): - if path == log.getName(): - if log.hasContents(): - return IHTMLLog(interfaces.IStatusLog(log)) - return NoResource("Empty Log '%s'" % path) - return HtmlResource.getChild(self, path, req) diff --git a/tools/buildbot/pylibs/buildbot/status/web/robots.txt b/tools/buildbot/pylibs/buildbot/status/web/robots.txt deleted file mode 100644 index 47a9d27..0000000 --- a/tools/buildbot/pylibs/buildbot/status/web/robots.txt +++ /dev/null @@ -1,9 +0,0 @@ -User-agent: * -Disallow: /waterfall -Disallow: /builders -Disallow: /changes -Disallow: /buildslaves -Disallow: /schedulers -Disallow: /one_line_per_build -Disallow: /one_box_per_builder -Disallow: /xmlrpc diff --git a/tools/buildbot/pylibs/buildbot/status/web/slaves.py b/tools/buildbot/pylibs/buildbot/status/web/slaves.py deleted file mode 100644 index 62c4012..0000000 --- a/tools/buildbot/pylibs/buildbot/status/web/slaves.py +++ /dev/null @@ -1,71 +0,0 @@ - -import time -from buildbot.status.web.base import HtmlResource, abbreviate_age - -# /buildslaves/$slavename -class OneBuildSlaveResource(HtmlResource): - pass # TODO - -# /buildslaves -class BuildSlavesResource(HtmlResource): - title = "BuildSlaves" - addSlash = True - - def body(self, req): - s = self.getStatus(req) - data = "" - data += "

Build Slaves

\n" - - used_by_builder = {} - for bname in s.getBuilderNames(): - b = s.getBuilder(bname) - for bs in b.getSlaves(): - slavename = bs.getName() - if slavename not in used_by_builder: - used_by_builder[slavename] = [] - used_by_builder[slavename].append(bname) - - data += "
    \n" - for name in s.getSlaveNames(): - slave = s.getSlave(name) - slave_status = s.botmaster.slaves[name].slave_status - isBusy = len(slave_status.getRunningBuilds()) - data += "
  1. %s:\n" % name - data += "
      \n" - builder_links = ['%s' - % (req.childLink("../builders/%s" % bname),bname) - for bname in used_by_builder.get(name, [])] - if builder_links: - data += ("
    • Used by Builders: %s
    • \n" % - ", ".join(builder_links)) - else: - data += "
    • Not used by any Builders
    • \n" - if slave.isConnected(): - data += "
    • Slave is currently connected
    • \n" - admin = slave.getAdmin() - if admin: - # munge it to avoid feeding the spambot harvesters - admin = admin.replace("@", " -at- ") - data += "
    • Admin: %s
    • \n" % admin - last = slave.lastMessageReceived() - if last: - lt = time.strftime("%Y-%b-%d %H:%M:%S", - time.localtime(last)) - age = abbreviate_age(time.time() - last) - data += "
    • Last heard from: %s " % age - data += '(%s)' % lt - data += "
    • \n" - if isBusy: - data += "
    • Slave is currently building.
    • " - else: - data += "
    • Slave is idle.
    • " - else: - data += "
    • Slave is NOT currently connected
    • \n" - - data += "
    \n" - data += "
  2. \n" - data += "\n" - - data += "
\n" - - return data diff --git a/tools/buildbot/pylibs/buildbot/status/web/step.py b/tools/buildbot/pylibs/buildbot/status/web/step.py deleted file mode 100644 index c5b1aa6..0000000 --- a/tools/buildbot/pylibs/buildbot/status/web/step.py +++ /dev/null @@ -1,85 +0,0 @@ - -from twisted.web import html - -import urllib -from buildbot.status.web.base import HtmlResource, path_to_builder, \ - path_to_build -from buildbot.status.web.logs import LogsResource - -# /builders/$builder/builds/$buildnum/steps/$stepname -class StatusResourceBuildStep(HtmlResource): - title = "Build Step" - addSlash = True - - def __init__(self, build_status, step_status): - HtmlResource.__init__(self) - self.status = build_status - self.step_status = step_status - - def body(self, req): - s = self.step_status - b = s.getBuild() - builder_name = b.getBuilder().getName() - build_num = b.getNumber() - data = "" - data += ('

BuildStep %s:' % - (path_to_builder(req, b.getBuilder()), builder_name)) - data += '#%d' % (path_to_build(req, b), build_num) - data += ":%s

\n" % s.getName() - - if s.isFinished(): - data += ("

Finished

\n" - "

%s

\n" % html.escape("%s" % s.getText())) - else: - data += ("

Not Finished

\n" - "

ETA %s seconds

\n" % s.getETA()) - - exp = s.getExpectations() - if exp: - data += ("

Expectations

\n" - "
    \n") - for e in exp: - data += "
  • %s: current=%s, target=%s
  • \n" % \ - (html.escape(e[0]), e[1], e[2]) - data += "
\n" - logs = s.getLogs() - if logs: - data += ("

Logs

\n" - "
    \n") - for logfile in logs: - if logfile.hasContents(): - # FIXME: If the step name has a / in it, this is broken - # either way. If we quote it but say '/'s are safe, - # it chops up the step name. If we quote it and '/'s - # are not safe, it escapes the / that separates the - # step name from the log number. - logname = logfile.getName() - logurl = req.childLink("logs/%s" % urllib.quote(logname)) - data += ('
  • %s
  • \n' % - (logurl, html.escape(logname))) - else: - data += '
  • %s
  • \n' % html.escape(logname) - data += "
\n" - - return data - - def getChild(self, path, req): - if path == "logs": - return LogsResource(self.step_status) - return HtmlResource.getChild(self, path, req) - - - -# /builders/$builder/builds/$buildnum/steps -class StepsResource(HtmlResource): - addSlash = True - - def __init__(self, build_status): - HtmlResource.__init__(self) - self.build_status = build_status - - def getChild(self, path, req): - for s in self.build_status.getSteps(): - if s.getName() == path: - return StatusResourceBuildStep(self.build_status, s) - return HtmlResource.getChild(self, path, req) diff --git a/tools/buildbot/pylibs/buildbot/status/web/tests.py b/tools/buildbot/pylibs/buildbot/status/web/tests.py deleted file mode 100644 index b96bba2..0000000 --- a/tools/buildbot/pylibs/buildbot/status/web/tests.py +++ /dev/null @@ -1,64 +0,0 @@ - -from twisted.web.error import NoResource -from twisted.web import html - -from buildbot.status.web.base import HtmlResource - -# /builders/$builder/builds/$buildnum/tests/$testname -class TestResult(HtmlResource): - title = "Test Logs" - - def __init__(self, name, test_result): - HtmlResource.__init__(self) - self.name = name - self.test_result = test_result - - def body(self, request): - dotname = ".".join(self.name) - logs = self.test_result.getLogs() - lognames = logs.keys() - lognames.sort() - data = "

%s

\n" % html.escape(dotname) - for name in lognames: - data += "

%s

\n" % html.escape(name) - data += "
" + logs[name] + "
\n\n" - - return data - - -# /builders/$builder/builds/$buildnum/tests -class TestsResource(HtmlResource): - title = "Test Results" - - def __init__(self, build_status): - HtmlResource.__init__(self) - self.build_status = build_status - self.test_results = build_status.getTestResults() - - def body(self, request): - r = self.test_results - data = "

Test Results

\n" - data += "
    \n" - testnames = r.keys() - testnames.sort() - for name in testnames: - res = r[name] - dotname = ".".join(name) - data += "
  • %s: " % dotname - # TODO: this could break on weird test names. At the moment, - # test names only come from Trial tests, where the name - # components must be legal python names, but that won't always - # be a restriction. - url = request.childLink(dotname) - data += "%s" % (url, " ".join(res.getText())) - data += "
  • \n" - data += "
\n" - return data - - def getChild(self, path, request): - try: - name = tuple(path.split(".")) - result = self.test_results[name] - return TestResult(name, result) - except KeyError: - return NoResource("No such test name '%s'" % path) diff --git a/tools/buildbot/pylibs/buildbot/status/web/waterfall.py b/tools/buildbot/pylibs/buildbot/status/web/waterfall.py deleted file mode 100644 index 0fc04d1..0000000 --- a/tools/buildbot/pylibs/buildbot/status/web/waterfall.py +++ /dev/null @@ -1,981 +0,0 @@ -# -*- test-case-name: buildbot.test.test_web -*- - -from zope.interface import implements -from twisted.python import log, components -from twisted.web import html -import urllib - -import time -import operator - -from buildbot import interfaces, util -from buildbot import version -from buildbot.status import builder - -from buildbot.status.web.base import Box, HtmlResource, IBox, ICurrentBox, \ - ITopBox, td, build_get_class, path_to_build, path_to_step, map_branches - - - -class CurrentBox(components.Adapter): - # this provides the "current activity" box, just above the builder name - implements(ICurrentBox) - - def formatETA(self, prefix, eta): - if eta is None: - return [] - if eta < 0: - return ["Soon"] - eta_parts = [] - eta_secs = eta - if eta_secs > 3600: - eta_parts.append("%d hrs" % (eta_secs / 3600)) - eta_secs %= 3600 - if eta_secs > 60: - eta_parts.append("%d mins" % (eta_secs / 60)) - eta_secs %= 60 - eta_parts.append("%d secs" % eta_secs) - abstime = time.strftime("%H:%M:%S", time.localtime(util.now()+eta)) - return [prefix, ", ".join(eta_parts), "at %s" % abstime] - - def getBox(self, status): - # getState() returns offline, idle, or building - state, builds = self.original.getState() - - # look for upcoming builds. We say the state is "waiting" if the - # builder is otherwise idle and there is a scheduler which tells us a - # build will be performed some time in the near future. TODO: this - # functionality used to be in BuilderStatus.. maybe this code should - # be merged back into it. - upcoming = [] - builderName = self.original.getName() - for s in status.getSchedulers(): - if builderName in s.listBuilderNames(): - upcoming.extend(s.getPendingBuildTimes()) - if state == "idle" and upcoming: - state = "waiting" - - if state == "building": - color = "yellow" - text = ["building"] - if builds: - for b in builds: - eta = b.getETA() - text.extend(self.formatETA("ETA in", eta)) - elif state == "offline": - color = "red" - text = ["offline"] - elif state == "idle": - color = "white" - text = ["idle"] - elif state == "waiting": - color = "yellow" - text = ["waiting"] - else: - # just in case I add a state and forget to update this - color = "white" - text = [state] - - # TODO: for now, this pending/upcoming stuff is in the "current - # activity" box, but really it should go into a "next activity" row - # instead. The only times it should show up in "current activity" is - # when the builder is otherwise idle. - - # are any builds pending? (waiting for a slave to be free) - pbs = self.original.getPendingBuilds() - if pbs: - text.append("%d pending" % len(pbs)) - for t in upcoming: - eta = t - util.now() - text.extend(self.formatETA("next in", eta)) - return Box(text, color=color, class_="Activity " + state) - -components.registerAdapter(CurrentBox, builder.BuilderStatus, ICurrentBox) - - -class BuildTopBox(components.Adapter): - # this provides a per-builder box at the very top of the display, - # showing the results of the most recent build - implements(IBox) - - def getBox(self, req): - assert interfaces.IBuilderStatus(self.original) - branches = [b for b in req.args.get("branch", []) if b] - builder = self.original - builds = list(builder.generateFinishedBuilds(map_branches(branches), - num_builds=1)) - if not builds: - return Box(["none"], "white", class_="LastBuild") - b = builds[0] - name = b.getBuilder().getName() - number = b.getNumber() - url = path_to_build(req, b) - text = b.getText() - tests_failed = b.getSummaryStatistic('tests-failed', operator.add, 0) - if tests_failed: text.extend(["Failed tests: %d" % tests_failed]) - # TODO: maybe add logs? - # TODO: add link to the per-build page at 'url' - c = b.getColor() - class_ = build_get_class(b) - return Box(text, c, class_="LastBuild %s" % class_) -components.registerAdapter(BuildTopBox, builder.BuilderStatus, ITopBox) - -class BuildBox(components.Adapter): - # this provides the yellow "starting line" box for each build - implements(IBox) - - def getBox(self, req): - b = self.original - number = b.getNumber() - url = path_to_build(req, b) - reason = b.getReason() - text = ('Build %d' - % (html.escape(reason), url, number)) - color = "yellow" - class_ = "start" - if b.isFinished() and not b.getSteps(): - # the steps have been pruned, so there won't be any indication - # of whether it succeeded or failed. Color the box red or green - # to show its status - color = b.getColor() - class_ = build_get_class(b) - return Box([text], color=color, class_="BuildStep " + class_) -components.registerAdapter(BuildBox, builder.BuildStatus, IBox) - -class StepBox(components.Adapter): - implements(IBox) - - def getBox(self, req): - urlbase = path_to_step(req, self.original) - text = self.original.getText() - if text is None: - log.msg("getText() gave None", urlbase) - text = [] - text = text[:] - logs = self.original.getLogs() - for num in range(len(logs)): - name = logs[num].getName() - if logs[num].hasContents(): - url = urlbase + "/logs/%s" % urllib.quote(name) - text.append("%s" % (url, html.escape(name))) - else: - text.append(html.escape(name)) - urls = self.original.getURLs() - ex_url_class = "BuildStep external" - for name, target in urls.items(): - text.append('[%s]' % - (target, ex_url_class, html.escape(name))) - color = self.original.getColor() - class_ = "BuildStep " + build_get_class(self.original) - return Box(text, color, class_=class_) -components.registerAdapter(StepBox, builder.BuildStepStatus, IBox) - - -class EventBox(components.Adapter): - implements(IBox) - - def getBox(self, req): - text = self.original.getText() - color = self.original.getColor() - class_ = "Event" - if color: - class_ += " " + color - return Box(text, color, class_=class_) -components.registerAdapter(EventBox, builder.Event, IBox) - - -class Spacer: - implements(interfaces.IStatusEvent) - - def __init__(self, start, finish): - self.started = start - self.finished = finish - - def getTimes(self): - return (self.started, self.finished) - def getText(self): - return [] - def getColor(self): - return None - -class SpacerBox(components.Adapter): - implements(IBox) - - def getBox(self, req): - #b = Box(["spacer"], "white") - b = Box([]) - b.spacer = True - return b -components.registerAdapter(SpacerBox, Spacer, IBox) - -def insertGaps(g, lastEventTime, idleGap=2): - debug = False - - e = g.next() - starts, finishes = e.getTimes() - if debug: log.msg("E0", starts, finishes) - if finishes == 0: - finishes = starts - if debug: log.msg("E1 finishes=%s, gap=%s, lET=%s" % \ - (finishes, idleGap, lastEventTime)) - if finishes is not None and finishes + idleGap < lastEventTime: - if debug: log.msg(" spacer0") - yield Spacer(finishes, lastEventTime) - - followingEventStarts = starts - if debug: log.msg(" fES0", starts) - yield e - - while 1: - e = g.next() - starts, finishes = e.getTimes() - if debug: log.msg("E2", starts, finishes) - if finishes == 0: - finishes = starts - if finishes is not None and finishes + idleGap < followingEventStarts: - # there is a gap between the end of this event and the beginning - # of the next one. Insert an idle event so the waterfall display - # shows a gap here. - if debug: - log.msg(" finishes=%s, gap=%s, fES=%s" % \ - (finishes, idleGap, followingEventStarts)) - yield Spacer(finishes, followingEventStarts) - yield e - followingEventStarts = starts - if debug: log.msg(" fES1", starts) - -HELP = ''' -
- -

The Waterfall Display

- -

The Waterfall display can be controlled by adding query arguments to the -URL. For example, if your Waterfall is accessed via the URL -http://buildbot.example.org:8080, then you could add a -branch= argument (described below) by going to -http://buildbot.example.org:8080?branch=beta4 instead. Remember that -query arguments are separated from each other with ampersands, but they are -separated from the main URL with a question mark, so to add a -branch= and two builder= arguments, you would use -http://buildbot.example.org:8080?branch=beta4&builder=unix&builder=macos.

- -

Limiting the Displayed Interval

- -

The last_time= argument is a unix timestamp (seconds since the -start of 1970) that will be used as an upper bound on the interval of events -displayed: nothing will be shown that is more recent than the given time. -When no argument is provided, all events up to and including the most recent -steps are included.

- -

The first_time= argument provides the lower bound. No events will -be displayed that occurred before this timestamp. Instead of providing -first_time=, you can provide show_time=: in this case, -first_time will be set equal to last_time minus -show_time. show_time overrides first_time.

- -

The display normally shows the latest 200 events that occurred in the -given interval, where each timestamp on the left hand edge counts as a single -event. You can add a num_events= argument to override this this.

- -

Hiding non-Build events

- -

By passing show_events=false, you can remove the "buildslave -attached", "buildslave detached", and "builder reconfigured" events that -appear in-between the actual builds.

- -%(show_events_input)s - -

Showing only Certain Branches

- -

If you provide one or more branch= arguments, the display will be -limited to builds that used one of the given branches. If no branch= -arguments are given, builds from all branches will be displayed.

- -Erase the text from these "Show Branch:" boxes to remove that branch filter. - -%(show_branches_input)s - -

Limiting the Builders that are Displayed

- -

By adding one or more builder= arguments, the display will be -limited to showing builds that ran on the given builders. This serves to -limit the display to the specific named columns. If no builder= -arguments are provided, all Builders will be displayed.

- -

To view a Waterfall page with only a subset of Builders displayed, select -the Builders you are interested in here.

- -%(show_builders_input)s - - -

Auto-reloading the Page

- -

Adding a reload= argument will cause the page to automatically -reload itself after that many seconds.

- -%(show_reload_input)s - -

Reload Waterfall Page

- - -
-''' - -class WaterfallHelp(HtmlResource): - title = "Waterfall Help" - - def __init__(self, categories=None): - HtmlResource.__init__(self) - self.categories = categories - - def body(self, request): - data = '' - status = self.getStatus(request) - - showEvents_checked = 'checked="checked"' - if request.args.get("show_events", ["true"])[0].lower() == "true": - showEvents_checked = '' - show_events_input = ('

' - '' - 'Hide non-Build events' - '

\n' - ) % showEvents_checked - - branches = [b - for b in request.args.get("branch", []) - if b] - branches.append('') - show_branches_input = '\n' - for b in branches: - show_branches_input += ('' - '\n' - ) % (b,) - show_branches_input += '
Show Branch: ' - '' - '
\n' - - # this has a set of toggle-buttons to let the user choose the - # builders - showBuilders = request.args.get("show", []) - showBuilders.extend(request.args.get("builder", [])) - allBuilders = status.getBuilderNames(categories=self.categories) - - show_builders_input = '\n' - for bn in allBuilders: - checked = "" - if bn in showBuilders: - checked = 'checked="checked"' - show_builders_input += ('' - ' ' - '\n' - ) % (bn, checked, bn) - show_builders_input += '
%s
\n' - - # a couple of radio-button selectors for refresh time will appear - # just after that text - show_reload_input = '\n' - times = [("none", "None"), - ("60", "60 seconds"), - ("300", "5 minutes"), - ("600", "10 minutes"), - ] - current_reload_time = request.args.get("reload", ["none"]) - if current_reload_time: - current_reload_time = current_reload_time[0] - if current_reload_time not in [t[0] for t in times]: - times.insert(0, (current_reload_time, current_reload_time) ) - for value, name in times: - checked = "" - if value == current_reload_time: - checked = 'checked="checked"' - show_reload_input += ('' - ' ' - '\n' - ) % (value, checked, name) - show_reload_input += '
%s
\n' - - fields = {"show_events_input": show_events_input, - "show_branches_input": show_branches_input, - "show_builders_input": show_builders_input, - "show_reload_input": show_reload_input, - } - data += HELP % fields - return data - -class WaterfallStatusResource(HtmlResource): - """This builds the main status page, with the waterfall display, and - all child pages.""" - - def __init__(self, categories=None): - HtmlResource.__init__(self) - self.categories = categories - self.putChild("help", WaterfallHelp(categories)) - - def getTitle(self, request): - status = self.getStatus(request) - p = status.getProjectName() - if p: - return "BuildBot: %s" % p - else: - return "BuildBot" - - def getChangemaster(self, request): - # TODO: this wants to go away, access it through IStatus - return request.site.buildbot_service.parent.change_svc - - def get_reload_time(self, request): - if "reload" in request.args: - try: - reload_time = int(request.args["reload"][0]) - return max(reload_time, 15) - except ValueError: - pass - return None - - def head(self, request): - head = '' - reload_time = self.get_reload_time(request) - if reload_time is not None: - head += '\n' % reload_time - return head - - def body(self, request): - "This method builds the main waterfall display." - - status = self.getStatus(request) - data = '' - - projectName = status.getProjectName() - projectURL = status.getProjectURL() - - phase = request.args.get("phase",["2"]) - phase = int(phase[0]) - - # we start with all Builders available to this Waterfall: this is - # limited by the config-file -time categories= argument, and defaults - # to all defined Builders. - allBuilderNames = status.getBuilderNames(categories=self.categories) - builders = [status.getBuilder(name) for name in allBuilderNames] - - # but if the URL has one or more builder= arguments (or the old show= - # argument, which is still accepted for backwards compatibility), we - # use that set of builders instead. We still don't show anything - # outside the config-file time set limited by categories=. - showBuilders = request.args.get("show", []) - showBuilders.extend(request.args.get("builder", [])) - if showBuilders: - builders = [b for b in builders if b.name in showBuilders] - - # now, if the URL has one or category= arguments, use them as a - # filter: only show those builders which belong to one of the given - # categories. - showCategories = request.args.get("category", []) - if showCategories: - builders = [b for b in builders if b.category in showCategories] - - builderNames = [b.name for b in builders] - - if phase == -1: - return self.body0(request, builders) - (changeNames, builderNames, timestamps, eventGrid, sourceEvents) = \ - self.buildGrid(request, builders) - if phase == 0: - return self.phase0(request, (changeNames + builderNames), - timestamps, eventGrid) - # start the table: top-header material - data += '\n' - - if projectName and projectURL: - # TODO: this is going to look really ugly - topleft = '%s
last build' % \ - (projectURL, projectName) - else: - topleft = "last build" - data += ' \n' - data += td(topleft, align="right", colspan=2, class_="Project") - for b in builders: - box = ITopBox(b).getBox(request) - data += box.td(align="center") - data += " \n" - - data += ' \n' - data += td('current activity', align='right', colspan=2) - for b in builders: - box = ICurrentBox(b).getBox(status) - data += box.td(align="center") - data += " \n" - - data += " \n" - TZ = time.tzname[time.localtime()[-1]] - data += td("time (%s)" % TZ, align="center", class_="Time") - data += td('changes' % request.childLink("../changes"), - align="center", class_="Change") - for name in builderNames: - safename = urllib.quote(name, safe='') - data += td('%s' % - (request.childLink("../builders/%s" % safename), name), - align="center", class_="Builder") - data += " \n" - - if phase == 1: - f = self.phase1 - else: - f = self.phase2 - data += f(request, changeNames + builderNames, timestamps, eventGrid, - sourceEvents) - - data += "
\n" - - data += '
\n' - return data - - def body0(self, request, builders): - # build the waterfall display - data = "" - data += "

Basic display

\n" - data += '

See here' % request.childLink("../waterfall") - data += " for the waterfall display

\n" - - data += '\n' - names = map(lambda builder: builder.name, builders) - - # the top row is two blank spaces, then the top-level status boxes - data += " \n" - data += td("", colspan=2) - for b in builders: - text = "" - color = "#ca88f7" - state, builds = b.getState() - if state != "offline": - text += "%s
\n" % state #b.getCurrentBig().text[0] - else: - text += "OFFLINE
\n" - color = "#ffe0e0" - data += td(text, align="center", bgcolor=color) - - # the next row has the column headers: time, changes, builder names - data += " \n" - data += td("Time", align="center") - data += td("Changes", align="center") - for name in names: - data += td('%s' % - (request.childLink("../" + urllib.quote(name)), name), - align="center") - data += " \n" - - # all further rows involve timestamps, commit events, and build events - data += " \n" - data += td("04:00", align="bottom") - data += td("fred", align="center") - for name in names: - data += td("stuff", align="center", bgcolor="red") - data += " \n" - - data += "
\n" - return data - - def buildGrid(self, request, builders): - debug = False - # TODO: see if we can use a cached copy - - showEvents = False - if request.args.get("show_events", ["true"])[0].lower() == "true": - showEvents = True - filterBranches = [b for b in request.args.get("branch", []) if b] - filterBranches = map_branches(filterBranches) - maxTime = int(request.args.get("last_time", [util.now()])[0]) - if "show_time" in request.args: - minTime = maxTime - int(request.args["show_time"][0]) - elif "first_time" in request.args: - minTime = int(request.args["first_time"][0]) - else: - minTime = None - spanLength = 10 # ten-second chunks - maxPageLen = int(request.args.get("num_events", [200])[0]) - - # first step is to walk backwards in time, asking each column - # (commit, all builders) if they have any events there. Build up the - # array of events, and stop when we have a reasonable number. - - commit_source = self.getChangemaster(request) - - lastEventTime = util.now() - sources = [commit_source] + builders - changeNames = ["changes"] - builderNames = map(lambda builder: builder.getName(), builders) - sourceNames = changeNames + builderNames - sourceEvents = [] - sourceGenerators = [] - - def get_event_from(g): - try: - while True: - e = g.next() - # e might be builder.BuildStepStatus, - # builder.BuildStatus, builder.Event, - # waterfall.Spacer(builder.Event), or changes.Change . - # The showEvents=False flag means we should hide - # builder.Event . - if not showEvents and isinstance(e, builder.Event): - continue - break - event = interfaces.IStatusEvent(e) - if debug: - log.msg("gen %s gave1 %s" % (g, event.getText())) - except StopIteration: - event = None - return event - - for s in sources: - gen = insertGaps(s.eventGenerator(filterBranches), lastEventTime) - sourceGenerators.append(gen) - # get the first event - sourceEvents.append(get_event_from(gen)) - eventGrid = [] - timestamps = [] - - lastEventTime = 0 - for e in sourceEvents: - if e and e.getTimes()[0] > lastEventTime: - lastEventTime = e.getTimes()[0] - if lastEventTime == 0: - lastEventTime = util.now() - - spanStart = lastEventTime - spanLength - debugGather = 0 - - while 1: - if debugGather: log.msg("checking (%s,]" % spanStart) - # the tableau of potential events is in sourceEvents[]. The - # window crawls backwards, and we examine one source at a time. - # If the source's top-most event is in the window, is it pushed - # onto the events[] array and the tableau is refilled. This - # continues until the tableau event is not in the window (or is - # missing). - - spanEvents = [] # for all sources, in this span. row of eventGrid - firstTimestamp = None # timestamp of first event in the span - lastTimestamp = None # last pre-span event, for next span - - for c in range(len(sourceGenerators)): - events = [] # for this source, in this span. cell of eventGrid - event = sourceEvents[c] - while event and spanStart < event.getTimes()[0]: - # to look at windows that don't end with the present, - # condition the .append on event.time <= spanFinish - if not IBox(event, None): - log.msg("BAD EVENT", event, event.getText()) - assert 0 - if debug: - log.msg("pushing", event.getText(), event) - events.append(event) - starts, finishes = event.getTimes() - firstTimestamp = util.earlier(firstTimestamp, starts) - event = get_event_from(sourceGenerators[c]) - if debug: - log.msg("finished span") - - if event: - # this is the last pre-span event for this source - lastTimestamp = util.later(lastTimestamp, - event.getTimes()[0]) - if debugGather: - log.msg(" got %s from %s" % (events, sourceNames[c])) - sourceEvents[c] = event # refill the tableau - spanEvents.append(events) - - # only show events older than maxTime. This makes it possible to - # visit a page that shows what it would be like to scroll off the - # bottom of this one. - if firstTimestamp is not None and firstTimestamp <= maxTime: - eventGrid.append(spanEvents) - timestamps.append(firstTimestamp) - - if lastTimestamp: - spanStart = lastTimestamp - spanLength - else: - # no more events - break - if minTime is not None and lastTimestamp < minTime: - break - - if len(timestamps) > maxPageLen: - break - - - # now loop - - # loop is finished. now we have eventGrid[] and timestamps[] - if debugGather: log.msg("finished loop") - assert(len(timestamps) == len(eventGrid)) - return (changeNames, builderNames, timestamps, eventGrid, sourceEvents) - - def phase0(self, request, sourceNames, timestamps, eventGrid): - # phase0 rendering - if not timestamps: - return "no events" - data = "" - for r in range(0, len(timestamps)): - data += "

\n" - data += "[%s]
" % timestamps[r] - row = eventGrid[r] - assert(len(row) == len(sourceNames)) - for c in range(0, len(row)): - if row[c]: - data += "%s
\n" % sourceNames[c] - for e in row[c]: - log.msg("Event", r, c, sourceNames[c], e.getText()) - lognames = [loog.getName() for loog in e.getLogs()] - data += "%s: %s: %s %s
" % (e.getText(), - e.getTimes()[0], - e.getColor(), - lognames) - else: - data += "%s [none]
\n" % sourceNames[c] - return data - - def phase1(self, request, sourceNames, timestamps, eventGrid, - sourceEvents): - # phase1 rendering: table, but boxes do not overlap - data = "" - if not timestamps: - return data - lastDate = None - for r in range(0, len(timestamps)): - chunkstrip = eventGrid[r] - # chunkstrip is a horizontal strip of event blocks. Each block - # is a vertical list of events, all for the same source. - assert(len(chunkstrip) == len(sourceNames)) - maxRows = reduce(lambda x,y: max(x,y), - map(lambda x: len(x), chunkstrip)) - for i in range(maxRows): - data += " \n"; - if i == 0: - stuff = [] - # add the date at the beginning, and each time it changes - today = time.strftime("%d %b %Y", - time.localtime(timestamps[r])) - todayday = time.strftime("%a", - time.localtime(timestamps[r])) - if today != lastDate: - stuff.append(todayday) - stuff.append(today) - lastDate = today - stuff.append( - time.strftime("%H:%M:%S", - time.localtime(timestamps[r]))) - data += td(stuff, valign="bottom", align="center", - rowspan=maxRows, class_="Time") - for c in range(0, len(chunkstrip)): - block = chunkstrip[c] - assert(block != None) # should be [] instead - # bottom-justify - offset = maxRows - len(block) - if i < offset: - data += td("") - else: - e = block[i-offset] - box = IBox(e).getBox(request) - box.parms["show_idle"] = 1 - data += box.td(valign="top", align="center") - data += " \n" - - return data - - def phase2(self, request, sourceNames, timestamps, eventGrid, - sourceEvents): - data = "" - if not timestamps: - return data - # first pass: figure out the height of the chunks, populate grid - grid = [] - for i in range(1+len(sourceNames)): - grid.append([]) - # grid is a list of columns, one for the timestamps, and one per - # event source. Each column is exactly the same height. Each element - # of the list is a single box. - lastDate = time.strftime("%d %b %Y", - time.localtime(util.now())) - for r in range(0, len(timestamps)): - chunkstrip = eventGrid[r] - # chunkstrip is a horizontal strip of event blocks. Each block - # is a vertical list of events, all for the same source. - assert(len(chunkstrip) == len(sourceNames)) - maxRows = reduce(lambda x,y: max(x,y), - map(lambda x: len(x), chunkstrip)) - for i in range(maxRows): - if i != maxRows-1: - grid[0].append(None) - else: - # timestamp goes at the bottom of the chunk - stuff = [] - # add the date at the beginning (if it is not the same as - # today's date), and each time it changes - todayday = time.strftime("%a", - time.localtime(timestamps[r])) - today = time.strftime("%d %b %Y", - time.localtime(timestamps[r])) - if today != lastDate: - stuff.append(todayday) - stuff.append(today) - lastDate = today - stuff.append( - time.strftime("%H:%M:%S", - time.localtime(timestamps[r]))) - grid[0].append(Box(text=stuff, class_="Time", - valign="bottom", align="center")) - - # at this point the timestamp column has been populated with - # maxRows boxes, most None but the last one has the time string - for c in range(0, len(chunkstrip)): - block = chunkstrip[c] - assert(block != None) # should be [] instead - for i in range(maxRows - len(block)): - # fill top of chunk with blank space - grid[c+1].append(None) - for i in range(len(block)): - # so the events are bottom-justified - b = IBox(block[i]).getBox(request) - b.parms['valign'] = "top" - b.parms['align'] = "center" - grid[c+1].append(b) - # now all the other columns have maxRows new boxes too - # populate the last row, if empty - gridlen = len(grid[0]) - for i in range(len(grid)): - strip = grid[i] - assert(len(strip) == gridlen) - if strip[-1] == None: - if sourceEvents[i-1]: - filler = IBox(sourceEvents[i-1]).getBox(request) - else: - # this can happen if you delete part of the build history - filler = Box(text=["?"], align="center") - strip[-1] = filler - strip[-1].parms['rowspan'] = 1 - # second pass: bubble the events upwards to un-occupied locations - # Every square of the grid that has a None in it needs to have - # something else take its place. - noBubble = request.args.get("nobubble",['0']) - noBubble = int(noBubble[0]) - if not noBubble: - for col in range(len(grid)): - strip = grid[col] - if col == 1: # changes are handled differently - for i in range(2, len(strip)+1): - # only merge empty boxes. Don't bubble commit boxes. - if strip[-i] == None: - next = strip[-i+1] - assert(next) - if next: - #if not next.event: - if next.spacer: - # bubble the empty box up - strip[-i] = next - strip[-i].parms['rowspan'] += 1 - strip[-i+1] = None - else: - # we are above a commit box. Leave it - # be, and turn the current box into an - # empty one - strip[-i] = Box([], rowspan=1, - comment="commit bubble") - strip[-i].spacer = True - else: - # we are above another empty box, which - # somehow wasn't already converted. - # Shouldn't happen - pass - else: - for i in range(2, len(strip)+1): - # strip[-i] will go from next-to-last back to first - if strip[-i] == None: - # bubble previous item up - assert(strip[-i+1] != None) - strip[-i] = strip[-i+1] - strip[-i].parms['rowspan'] += 1 - strip[-i+1] = None - else: - strip[-i].parms['rowspan'] = 1 - # third pass: render the HTML table - for i in range(gridlen): - data += " \n"; - for strip in grid: - b = strip[i] - if b: - data += b.td() - else: - if noBubble: - data += td([]) - # Nones are left empty, rowspan should make it all fit - data += " \n" - return data - diff --git a/tools/buildbot/pylibs/buildbot/status/web/xmlrpc.py b/tools/buildbot/pylibs/buildbot/status/web/xmlrpc.py deleted file mode 100644 index 5794088..0000000 --- a/tools/buildbot/pylibs/buildbot/status/web/xmlrpc.py +++ /dev/null @@ -1,193 +0,0 @@ - -from twisted.python import log -from twisted.web import xmlrpc -from buildbot.status.builder import Results -from itertools import count - -class XMLRPCServer(xmlrpc.XMLRPC): - def __init__(self): - xmlrpc.XMLRPC.__init__(self) - - def render(self, req): - # extract the IStatus and IControl objects for later use, since they - # come from the request object. They'll be the same each time, but - # they aren't available until the first request arrives. - self.status = req.site.buildbot_service.getStatus() - self.control = req.site.buildbot_service.getControl() - return xmlrpc.XMLRPC.render(self, req) - - def xmlrpc_getAllBuilders(self): - """Return a list of all builder names - """ - log.msg("getAllBuilders") - return self.status.getBuilderNames() - - def xmlrpc_getLastBuildResults(self, builder_name): - """Return the result of the last build for the given builder - """ - builder = self.status.getBuilder(builder_name) - lastbuild = builder.getBuild(-1) - return Results[lastbuild.getResults()] - - def xmlrpc_getLastBuilds(self, builder_name, num_builds): - """Return the last N completed builds for the given builder. - 'builder_name' is the name of the builder to query - 'num_builds' is the number of builds to return - - Each build is returned in the same form as xmlrpc_getAllBuildsInInterval - """ - log.msg("getLastBuilds: %s - %d" % (builder_name, num_builds)) - builder = self.status.getBuilder(builder_name) - all_builds = [] - for build_number in range(1, num_builds+1): - build = builder.getBuild(-build_number) - if not build: - break - if not build.isFinished(): - continue - (build_start, build_end) = build.getTimes() - - ss = build.getSourceStamp() - branch = ss.branch - if branch is None: - branch = "" - try: - revision = build.getProperty("got_revision") - except KeyError: - revision = "" - revision = str(revision) - - answer = (builder_name, - build.getNumber(), - build_end, - branch, - revision, - Results[build.getResults()], - build.getText(), - ) - all_builds.append((build_end, answer)) - - # now we've gotten all the builds we're interested in. Sort them by - # end time. - all_builds.sort(lambda a,b: cmp(a[0], b[0])) - # and remove the timestamps - all_builds = [t[1] for t in all_builds] - - log.msg("ready to go: %s" % (all_builds,)) - - return all_builds - - - def xmlrpc_getAllBuildsInInterval(self, start, stop): - """Return a list of builds that have completed after the 'start' - timestamp and before the 'stop' timestamp. This looks at all - Builders. - - The timestamps are integers, interpreted as standard unix timestamps - (seconds since epoch). - - Each Build is returned as a tuple in the form:: - (buildername, buildnumber, build_end, branchname, revision, - results, text) - - The buildnumber is an integer. 'build_end' is an integer (seconds - since epoch) specifying when the build finished. - - The branchname is a string, which may be an empty string to indicate - None (i.e. the default branch). The revision is a string whose - meaning is specific to the VC system in use, and comes from the - 'got_revision' build property. The results are expressed as a string, - one of ('success', 'warnings', 'failure', 'exception'). The text is a - list of short strings that ought to be joined by spaces and include - slightly more data about the results of the build. - """ - #log.msg("start: %s %s %s" % (start, type(start), start.__class__)) - log.msg("getAllBuildsInInterval: %d - %d" % (start, stop)) - all_builds = [] - - for builder_name in self.status.getBuilderNames(): - builder = self.status.getBuilder(builder_name) - for build_number in count(1): - build = builder.getBuild(-build_number) - if not build: - break - if not build.isFinished(): - continue - (build_start, build_end) = build.getTimes() - # in reality, builds are mostly ordered by start time. For - # the purposes of this method, we pretend that they are - # strictly ordered by end time, so that we can stop searching - # when we start seeing builds that are outside the window. - if build_end > stop: - continue # keep looking - if build_end < start: - break # stop looking - - ss = build.getSourceStamp() - branch = ss.branch - if branch is None: - branch = "" - try: - revision = build.getProperty("got_revision") - except KeyError: - revision = "" - revision = str(revision) - - answer = (builder_name, - build.getNumber(), - build_end, - branch, - revision, - Results[build.getResults()], - build.getText(), - ) - all_builds.append((build_end, answer)) - # we've gotten all the builds that we care about from this - # particular builder, so now we can continue on the next builder - - # now we've gotten all the builds we're interested in. Sort them by - # end time. - all_builds.sort(lambda a,b: cmp(a[0], b[0])) - # and remove the timestamps - all_builds = [t[1] for t in all_builds] - - log.msg("ready to go: %s" % (all_builds,)) - - return all_builds - - def xmlrpc_getBuild(self, builder_name, build_number): - """Return information about a specific build. - - """ - builder = self.status.getBuilder(builder_name) - build = builder.getBuild(build_number) - info = {} - info['builder_name'] = builder.getName() - info['url'] = self.status.getURLForThing(build) - info['reason'] = build.getReason() - info['slavename'] = build.getSlavename() - info['results'] = build.getResults() - info['text'] = build.getText() - ss = build.getSourceStamp() - info['start'], info['end'] = build.getTimes() - - info_steps = [] - for s in build.getSteps(): - stepinfo = {} - stepinfo['name'] = s.getName() - stepinfo['start'], stepinfo['end'] = s.getTimes() - stepinfo['results'] = s.getResults() - info_steps.append(stepinfo) - info['steps'] = info_steps - - info_logs = [] - for l in build.getLogs(): - loginfo = {} - loginfo['name'] = l.getStep().getName() + "/" + l.getName() - #loginfo['text'] = l.getText() - loginfo['text'] = "HUGE" - info_logs.append(loginfo) - info['logs'] = info_logs - - return info - diff --git a/tools/buildbot/pylibs/buildbot/status/words.py b/tools/buildbot/pylibs/buildbot/status/words.py deleted file mode 100644 index a1b546c..0000000 --- a/tools/buildbot/pylibs/buildbot/status/words.py +++ /dev/null @@ -1,861 +0,0 @@ - -# code to deliver build status through twisted.words (instant messaging -# protocols: irc, etc) - -import re, shlex - -from zope.interface import Interface, implements -from twisted.internet import protocol, reactor -from twisted.words.protocols import irc -from twisted.python import log, failure -from twisted.application import internet - -from buildbot import interfaces, util -from buildbot import version -from buildbot.sourcestamp import SourceStamp -from buildbot.process.base import BuildRequest -from buildbot.status import base -from buildbot.status.builder import SUCCESS, WARNINGS, FAILURE, EXCEPTION -from buildbot.scripts.runner import ForceOptions - -class UsageError(ValueError): - def __init__(self, string = "Invalid usage", *more): - ValueError.__init__(self, string, *more) - -class IrcBuildRequest: - hasStarted = False - timer = None - - def __init__(self, parent): - self.parent = parent - self.timer = reactor.callLater(5, self.soon) - - def soon(self): - del self.timer - if not self.hasStarted: - self.parent.send("The build has been queued, I'll give a shout" - " when it starts") - - def started(self, c): - self.hasStarted = True - if self.timer: - self.timer.cancel() - del self.timer - s = c.getStatus() - eta = s.getETA() - response = "build #%d forced" % s.getNumber() - if eta is not None: - response = "build forced [ETA %s]" % self.parent.convertTime(eta) - self.parent.send(response) - self.parent.send("I'll give a shout when the build finishes") - d = s.waitUntilFinished() - d.addCallback(self.parent.buildFinished) - - -class Contact: - """I hold the state for a single user's interaction with the buildbot. - - This base class provides all the basic behavior (the queries and - responses). Subclasses for each channel type (IRC, different IM - protocols) are expected to provide the lower-level send/receive methods. - - There will be one instance of me for each user who interacts personally - with the buildbot. There will be an additional instance for each - 'broadcast contact' (chat rooms, IRC channels as a whole). - """ - - def __init__(self, channel): - self.channel = channel - self.notify_events = {} - self.subscribed = 0 - - silly = { - "What happen ?": "Somebody set up us the bomb.", - "It's You !!": ["How are you gentlemen !!", - "All your base are belong to us.", - "You are on the way to destruction."], - "What you say !!": ["You have no chance to survive make your time.", - "HA HA HA HA ...."], - } - - def getCommandMethod(self, command): - meth = getattr(self, 'command_' + command.upper(), None) - return meth - - def getBuilder(self, which): - try: - b = self.channel.status.getBuilder(which) - except KeyError: - raise UsageError, "no such builder '%s'" % which - return b - - def getControl(self, which): - if not self.channel.control: - raise UsageError("builder control is not enabled") - try: - bc = self.channel.control.getBuilder(which) - except KeyError: - raise UsageError("no such builder '%s'" % which) - return bc - - def getAllBuilders(self): - """ - @rtype: list of L{buildbot.process.builder.Builder} - """ - names = self.channel.status.getBuilderNames(categories=self.channel.categories) - names.sort() - builders = [self.channel.status.getBuilder(n) for n in names] - return builders - - def convertTime(self, seconds): - if seconds < 60: - return "%d seconds" % seconds - minutes = int(seconds / 60) - seconds = seconds - 60*minutes - if minutes < 60: - return "%dm%02ds" % (minutes, seconds) - hours = int(minutes / 60) - minutes = minutes - 60*hours - return "%dh%02dm%02ds" % (hours, minutes, seconds) - - def doSilly(self, message): - response = self.silly[message] - if type(response) != type([]): - response = [response] - when = 0.5 - for r in response: - reactor.callLater(when, self.send, r) - when += 2.5 - - def command_HELLO(self, args, who): - self.send("yes?") - - def command_VERSION(self, args, who): - self.send("buildbot-%s at your service" % version) - - def command_LIST(self, args, who): - args = args.split() - if len(args) == 0: - raise UsageError, "try 'list builders'" - if args[0] == 'builders': - builders = self.getAllBuilders() - str = "Configured builders: " - for b in builders: - str += b.name - state = b.getState()[0] - if state == 'offline': - str += "[offline]" - str += " " - str.rstrip() - self.send(str) - return - command_LIST.usage = "list builders - List configured builders" - - def command_STATUS(self, args, who): - args = args.split() - if len(args) == 0: - which = "all" - elif len(args) == 1: - which = args[0] - else: - raise UsageError, "try 'status '" - if which == "all": - builders = self.getAllBuilders() - for b in builders: - self.emit_status(b.name) - return - self.emit_status(which) - command_STATUS.usage = "status [] - List status of a builder (or all builders)" - - def validate_notification_event(self, event): - if not re.compile("^(started|finished|success|failed|exception)$").match(event): - raise UsageError("try 'notify on|off '") - - def list_notified_events(self): - self.send( "The following events are being notified: %r" % self.notify_events.keys() ) - - def notify_for(self, *events): - for event in events: - if self.notify_events.has_key(event): - return 1 - return 0 - - def subscribe_to_build_events(self): - self.channel.status.subscribe(self) - self.subscribed = 1 - - def unsubscribe_from_build_events(self): - self.channel.status.unsubscribe(self) - self.subscribed = 0 - - def add_notification_events(self, events): - for event in events: - self.validate_notification_event(event) - self.notify_events[event] = 1 - - def remove_notification_events(self, events): - for event in events: - self.validate_notification_event(event) - del self.notify_events[event] - - def remove_all_notification_events(self): - self.notify_events = {} - - def command_NOTIFY(self, args, who): - args = args.split() - - if not args: - raise UsageError("try 'notify on|off|list '") - action = args.pop(0) - events = args - - if action == "on": - if not events: events = ('started','finished') - self.add_notification_events(events) - - self.list_notified_events() - - elif action == "off": - if events: - self.remove_notification_events(events) - else: - self.remove_all_notification_events() - - self.list_notified_events() - - elif action == "list": - self.list_notified_events() - return - - else: - raise UsageError("try 'notify on|off '") - - if len(self.notify_events) > 0 and not self.subscribed: - self.subscribe_to_build_events() - - elif len(self.notify_events) == 0 and self.subscribed: - self.unsubscribe_from_build_events() - - command_NOTIFY.usage = "notify on|off|list [] ... - Notify me about build events. event should be one or more of: 'started', 'finished', 'failed', 'success', 'exception', 'successToFailed', 'failedToSuccess'" - - def command_WATCH(self, args, who): - args = args.split() - if len(args) != 1: - raise UsageError("try 'watch '") - which = args[0] - b = self.getBuilder(which) - builds = b.getCurrentBuilds() - if not builds: - self.send("there are no builds currently running") - return - for build in builds: - assert not build.isFinished() - d = build.waitUntilFinished() - d.addCallback(self.watchedBuildFinished) - r = "watching build %s #%d until it finishes" \ - % (which, build.getNumber()) - eta = build.getETA() - if eta is not None: - r += " [%s]" % self.convertTime(eta) - r += ".." - self.send(r) - command_WATCH.usage = "watch - announce the completion of an active build" - - def buildsetSubmitted(self, buildset): - log.msg('[Contact] Buildset %s added' % (buildset)) - - def builderAdded(self, builderName, builder): - log.msg('[Contact] Builder %s added' % (builder)) - builder.subscribe(self) - - def builderChangedState(self, builderName, state): - log.msg('[Contact] Builder %s changed state to %s' % (builderName, state)) - - def builderRemoved(self, builderName): - log.msg('[Contact] Builder %s removed' % (builderName)) - - def buildStarted(self, builderName, build): - builder = build.getBuilder() - log.msg('[Contact] Builder %r in category %s started' % (builder, builder.category)) - - # only notify about builders we are interested in - - if (self.channel.categories != None and - builder.category not in self.channel.categories): - log.msg('Not notifying for a build in the wrong category') - return - - if not self.notify_for('started'): - log.msg('Not notifying for a build when started-notification disabled') - return - - r = "build #%d of %s started" % \ - (build.getNumber(), - builder.getName()) - - r += " including [" + ", ".join(map(lambda c: repr(c.revision), build.getChanges())) + "]" - - self.send(r) - - def buildFinished(self, builderName, build, results): - builder = build.getBuilder() - - results_descriptions = { - SUCCESS: "Success", - WARNINGS: "Warnings", - FAILURE: "Failure", - EXCEPTION: "Exception", - } - - # only notify about builders we are interested in - log.msg('[Contact] builder %r in category %s finished' % (builder, builder.category)) - - if not self.notify_for('finished', 'failed', 'success', 'exception', 'failedToSuccess', 'successToFailed'): - return - - if (self.channel.categories != None and - builder.category not in self.channel.categories): - return - - results = build.getResults() - - r = "build #%d of %s is complete: %s" % \ - (build.getNumber(), - builder.getName(), - results_descriptions.get(results, "??")) - r += " [%s]" % " ".join(build.getText()) - buildurl = self.channel.status.getURLForThing(build) - if buildurl: - r += " Build details are at %s" % buildurl - - if (self.notify_for('finished')) or \ - (self.notify_for('success') and results == SUCCESS) or \ - (self.notify_for('failed') and results == FAILURE) or \ - (self.notify_for('exception') and results == EXCEPTION): - self.send(r) - return - - prevBuild = build.getPreviousBuild() - if prevBuild: - prevResult = prevBuild.getResult() - - if (self.notify_for('failureToSuccess') and prevResult == FAILURE and results == SUCCESS) or \ - (self.notify_for('successToFailure') and prevResult == SUCCESS and results == FAILURE): - self.send(r) - - def watchedBuildFinished(self, b): - results = {SUCCESS: "Success", - WARNINGS: "Warnings", - FAILURE: "Failure", - EXCEPTION: "Exception", - } - - # only notify about builders we are interested in - builder = b.getBuilder() - log.msg('builder %r in category %s finished' % (builder, - builder.category)) - if (self.channel.categories != None and - builder.category not in self.channel.categories): - return - - r = "Hey! build %s #%d is complete: %s" % \ - (b.getBuilder().getName(), - b.getNumber(), - results.get(b.getResults(), "??")) - r += " [%s]" % " ".join(b.getText()) - self.send(r) - buildurl = self.channel.status.getURLForThing(b) - if buildurl: - self.send("Build details are at %s" % buildurl) - - def command_FORCE(self, args, who): - args = shlex.split(args) # TODO: this requires python2.3 or newer - if not args: - raise UsageError("try 'force build WHICH '") - what = args.pop(0) - if what != "build": - raise UsageError("try 'force build WHICH '") - opts = ForceOptions() - opts.parseOptions(args) - - which = opts['builder'] - branch = opts['branch'] - revision = opts['revision'] - reason = opts['reason'] - - if which is None: - raise UsageError("you must provide a Builder, " - "try 'force build WHICH '") - - # keep weird stuff out of the branch and revision strings. TODO: - # centralize this somewhere. - if branch and not re.match(r'^[\w\.\-\/]*$', branch): - log.msg("bad branch '%s'" % branch) - self.send("sorry, bad branch '%s'" % branch) - return - if revision and not re.match(r'^[\w\.\-\/]*$', revision): - log.msg("bad revision '%s'" % revision) - self.send("sorry, bad revision '%s'" % revision) - return - - bc = self.getControl(which) - - r = "forced: by %s: %s" % (self.describeUser(who), reason) - # TODO: maybe give certain users the ability to request builds of - # certain branches - s = SourceStamp(branch=branch, revision=revision) - req = BuildRequest(r, s, which) - try: - bc.requestBuildSoon(req) - except interfaces.NoSlaveError: - self.send("sorry, I can't force a build: all slaves are offline") - return - ireq = IrcBuildRequest(self) - req.subscribe(ireq.started) - - - command_FORCE.usage = "force build - Force a build" - - def command_STOP(self, args, who): - args = args.split(None, 2) - if len(args) < 3 or args[0] != 'build': - raise UsageError, "try 'stop build WHICH '" - which = args[1] - reason = args[2] - - buildercontrol = self.getControl(which) - - r = "stopped: by %s: %s" % (self.describeUser(who), reason) - - # find an in-progress build - builderstatus = self.getBuilder(which) - builds = builderstatus.getCurrentBuilds() - if not builds: - self.send("sorry, no build is currently running") - return - for build in builds: - num = build.getNumber() - - # obtain the BuildControl object - buildcontrol = buildercontrol.getBuild(num) - - # make it stop - buildcontrol.stopBuild(r) - - self.send("build %d interrupted" % num) - - command_STOP.usage = "stop build - Stop a running build" - - def emit_status(self, which): - b = self.getBuilder(which) - str = "%s: " % which - state, builds = b.getState() - str += state - if state == "idle": - last = b.getLastFinishedBuild() - if last: - start,finished = last.getTimes() - str += ", last build %s secs ago: %s" % \ - (int(util.now() - finished), " ".join(last.getText())) - if state == "building": - t = [] - for build in builds: - step = build.getCurrentStep() - if step: - s = "(%s)" % " ".join(step.getText()) - else: - s = "(no current step)" - ETA = build.getETA() - if ETA is not None: - s += " [ETA %s]" % self.convertTime(ETA) - t.append(s) - str += ", ".join(t) - self.send(str) - - def emit_last(self, which): - last = self.getBuilder(which).getLastFinishedBuild() - if not last: - str = "(no builds run since last restart)" - else: - start,finish = last.getTimes() - str = "%s secs ago: " % (int(util.now() - finish)) - str += " ".join(last.getText()) - self.send("last build [%s]: %s" % (which, str)) - - def command_LAST(self, args, who): - args = args.split() - if len(args) == 0: - which = "all" - elif len(args) == 1: - which = args[0] - else: - raise UsageError, "try 'last '" - if which == "all": - builders = self.getAllBuilders() - for b in builders: - self.emit_last(b.name) - return - self.emit_last(which) - command_LAST.usage = "last - list last build status for builder " - - def build_commands(self): - commands = [] - for k in dir(self): - if k.startswith('command_'): - commands.append(k[8:].lower()) - commands.sort() - return commands - - def command_HELP(self, args, who): - args = args.split() - if len(args) == 0: - self.send("Get help on what? (try 'help ', or 'commands' for a command list)") - return - command = args[0] - meth = self.getCommandMethod(command) - if not meth: - raise UsageError, "no such command '%s'" % command - usage = getattr(meth, 'usage', None) - if usage: - self.send("Usage: %s" % usage) - else: - self.send("No usage info for '%s'" % command) - command_HELP.usage = "help - Give help for " - - def command_SOURCE(self, args, who): - banner = "My source can be found at http://buildbot.net/" - self.send(banner) - - def command_COMMANDS(self, args, who): - commands = self.build_commands() - str = "buildbot commands: " + ", ".join(commands) - self.send(str) - command_COMMANDS.usage = "commands - List available commands" - - def command_DESTROY(self, args, who): - self.act("readies phasers") - - def command_DANCE(self, args, who): - reactor.callLater(1.0, self.send, "0-<") - reactor.callLater(3.0, self.send, "0-/") - reactor.callLater(3.5, self.send, "0-\\") - - def command_EXCITED(self, args, who): - # like 'buildbot: destroy the sun!' - self.send("What you say!") - - def handleAction(self, data, user): - # this is sent when somebody performs an action that mentions the - # buildbot (like '/me kicks buildbot'). 'user' is the name/nick/id of - # the person who performed the action, so if their action provokes a - # response, they can be named. - if not data.endswith("s buildbot"): - return - words = data.split() - verb = words[-2] - timeout = 4 - if verb == "kicks": - response = "%s back" % verb - timeout = 1 - else: - response = "%s %s too" % (verb, user) - reactor.callLater(timeout, self.act, response) - -class IRCContact(Contact): - # this is the IRC-specific subclass of Contact - - def __init__(self, channel, dest): - Contact.__init__(self, channel) - # when people send us public messages ("buildbot: command"), - # self.dest is the name of the channel ("#twisted"). When they send - # us private messages (/msg buildbot command), self.dest is their - # username. - self.dest = dest - - def describeUser(self, user): - if self.dest[0] == "#": - return "IRC user <%s> on channel %s" % (user, self.dest) - return "IRC user <%s> (privmsg)" % user - - # userJoined(self, user, channel) - - def send(self, message): - self.channel.msg(self.dest, message) - def act(self, action): - self.channel.me(self.dest, action) - - def command_JOIN(self, args, who): - args = args.split() - to_join = args[0] - self.channel.join(to_join) - self.send("Joined %s" % to_join) - command_JOIN.usage = "join channel - Join another channel" - - def command_LEAVE(self, args, who): - args = args.split() - to_leave = args[0] - self.send("Buildbot has been told to leave %s" % to_leave) - self.channel.part(to_leave) - command_LEAVE.usage = "leave channel - Leave a channel" - - - def handleMessage(self, message, who): - # a message has arrived from 'who'. For broadcast contacts (i.e. when - # people do an irc 'buildbot: command'), this will be a string - # describing the sender of the message in some useful-to-log way, and - # a single Contact may see messages from a variety of users. For - # unicast contacts (i.e. when people do an irc '/msg buildbot - # command'), a single Contact will only ever see messages from a - # single user. - message = message.lstrip() - if self.silly.has_key(message): - return self.doSilly(message) - - parts = message.split(' ', 1) - if len(parts) == 1: - parts = parts + [''] - cmd, args = parts - log.msg("irc command", cmd) - - meth = self.getCommandMethod(cmd) - if not meth and message[-1] == '!': - meth = self.command_EXCITED - - error = None - try: - if meth: - meth(args.strip(), who) - except UsageError, e: - self.send(str(e)) - except: - f = failure.Failure() - log.err(f) - error = "Something bad happened (see logs): %s" % f.type - - if error: - try: - self.send(error) - except: - log.err() - - #self.say(channel, "count %d" % self.counter) - self.channel.counter += 1 - -class IChannel(Interface): - """I represent the buildbot's presence in a particular IM scheme. - - This provides the connection to the IRC server, or represents the - buildbot's account with an IM service. Each Channel will have zero or - more Contacts associated with it. - """ - -class IrcStatusBot(irc.IRCClient): - """I represent the buildbot to an IRC server. - """ - implements(IChannel) - - def __init__(self, nickname, password, channels, status, categories): - """ - @type nickname: string - @param nickname: the nickname by which this bot should be known - @type password: string - @param password: the password to use for identifying with Nickserv - @type channels: list of strings - @param channels: the bot will maintain a presence in these channels - @type status: L{buildbot.status.builder.Status} - @param status: the build master's Status object, through which the - bot retrieves all status information - """ - self.nickname = nickname - self.channels = channels - self.password = password - self.status = status - self.categories = categories - self.counter = 0 - self.hasQuit = 0 - self.contacts = {} - - def addContact(self, name, contact): - self.contacts[name] = contact - - def getContact(self, name): - if name in self.contacts: - return self.contacts[name] - new_contact = IRCContact(self, name) - self.contacts[name] = new_contact - return new_contact - - def deleteContact(self, contact): - name = contact.getName() - if name in self.contacts: - assert self.contacts[name] == contact - del self.contacts[name] - - def log(self, msg): - log.msg("%s: %s" % (self, msg)) - - - # the following irc.IRCClient methods are called when we have input - - def privmsg(self, user, channel, message): - user = user.split('!', 1)[0] # rest is ~user@hostname - # channel is '#twisted' or 'buildbot' (for private messages) - channel = channel.lower() - #print "privmsg:", user, channel, message - if channel == self.nickname: - # private message - contact = self.getContact(user) - contact.handleMessage(message, user) - return - # else it's a broadcast message, maybe for us, maybe not. 'channel' - # is '#twisted' or the like. - contact = self.getContact(channel) - if message.startswith("%s:" % self.nickname) or message.startswith("%s," % self.nickname): - message = message[len("%s:" % self.nickname):] - contact.handleMessage(message, user) - # to track users comings and goings, add code here - - def action(self, user, channel, data): - #log.msg("action: %s,%s,%s" % (user, channel, data)) - user = user.split('!', 1)[0] # rest is ~user@hostname - # somebody did an action (/me actions) in the broadcast channel - contact = self.getContact(channel) - if "buildbot" in data: - contact.handleAction(data, user) - - - - def signedOn(self): - if self.password: - self.msg("Nickserv", "IDENTIFY " + self.password) - for c in self.channels: - self.join(c) - - def joined(self, channel): - self.log("I have joined %s" % (channel,)) - def left(self, channel): - self.log("I have left %s" % (channel,)) - def kickedFrom(self, channel, kicker, message): - self.log("I have been kicked from %s by %s: %s" % (channel, - kicker, - message)) - - # we can using the following irc.IRCClient methods to send output. Most - # of these are used by the IRCContact class. - # - # self.say(channel, message) # broadcast - # self.msg(user, message) # unicast - # self.me(channel, action) # send action - # self.away(message='') - # self.quit(message='') - -class ThrottledClientFactory(protocol.ClientFactory): - lostDelay = 2 - failedDelay = 60 - def clientConnectionLost(self, connector, reason): - reactor.callLater(self.lostDelay, connector.connect) - def clientConnectionFailed(self, connector, reason): - reactor.callLater(self.failedDelay, connector.connect) - -class IrcStatusFactory(ThrottledClientFactory): - protocol = IrcStatusBot - - status = None - control = None - shuttingDown = False - p = None - - def __init__(self, nickname, password, channels, categories): - #ThrottledClientFactory.__init__(self) # doesn't exist - self.status = None - self.nickname = nickname - self.password = password - self.channels = channels - self.categories = categories - - def __getstate__(self): - d = self.__dict__.copy() - del d['p'] - return d - - def shutdown(self): - self.shuttingDown = True - if self.p: - self.p.quit("buildmaster reconfigured: bot disconnecting") - - def buildProtocol(self, address): - p = self.protocol(self.nickname, self.password, - self.channels, self.status, - self.categories) - p.factory = self - p.status = self.status - p.control = self.control - self.p = p - return p - - # TODO: I think a shutdown that occurs while the connection is being - # established will make this explode - - def clientConnectionLost(self, connector, reason): - if self.shuttingDown: - log.msg("not scheduling reconnection attempt") - return - ThrottledClientFactory.clientConnectionLost(self, connector, reason) - - def clientConnectionFailed(self, connector, reason): - if self.shuttingDown: - log.msg("not scheduling reconnection attempt") - return - ThrottledClientFactory.clientConnectionFailed(self, connector, reason) - - -class IRC(base.StatusReceiverMultiService): - """I am an IRC bot which can be queried for status information. I - connect to a single IRC server and am known by a single nickname on that - server, however I can join multiple channels.""" - - compare_attrs = ["host", "port", "nick", "password", - "channels", "allowForce", - "categories"] - - def __init__(self, host, nick, channels, port=6667, allowForce=True, - categories=None, password=None): - base.StatusReceiverMultiService.__init__(self) - - assert allowForce in (True, False) # TODO: implement others - - # need to stash these so we can detect changes later - self.host = host - self.port = port - self.nick = nick - self.channels = channels - self.password = password - self.allowForce = allowForce - self.categories = categories - - # need to stash the factory so we can give it the status object - self.f = IrcStatusFactory(self.nick, self.password, - self.channels, self.categories) - - c = internet.TCPClient(host, port, self.f) - c.setServiceParent(self) - - def setServiceParent(self, parent): - base.StatusReceiverMultiService.setServiceParent(self, parent) - self.f.status = parent.getStatus() - if self.allowForce: - self.f.control = interfaces.IControl(parent) - - def stopService(self): - # make sure the factory will stop reconnecting - self.f.shutdown() - return base.StatusReceiverMultiService.stopService(self) - - -## buildbot: list builders -# buildbot: watch quick -# print notification when current build in 'quick' finishes -## buildbot: status -## buildbot: status full-2.3 -## building, not, % complete, ETA -## buildbot: force build full-2.3 "reason" diff --git a/tools/buildbot/pylibs/buildbot/steps/__init__.py b/tools/buildbot/pylibs/buildbot/steps/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tools/buildbot/pylibs/buildbot/steps/dummy.py b/tools/buildbot/pylibs/buildbot/steps/dummy.py deleted file mode 100644 index 16338db..0000000 --- a/tools/buildbot/pylibs/buildbot/steps/dummy.py +++ /dev/null @@ -1,103 +0,0 @@ - -from twisted.internet import reactor -from buildbot.process.buildstep import BuildStep, LoggingBuildStep -from buildbot.process.buildstep import LoggedRemoteCommand -from buildbot.status.builder import SUCCESS, FAILURE - -# these classes are used internally by buildbot unit tests - -class Dummy(BuildStep): - """I am a dummy no-op step, which runs entirely on the master, and simply - waits 5 seconds before finishing with SUCCESS - """ - - haltOnFailure = True - name = "dummy" - - def __init__(self, timeout=5, **kwargs): - """ - @type timeout: int - @param timeout: the number of seconds to delay before completing - """ - BuildStep.__init__(self, **kwargs) - self.addFactoryArguments(timeout=timeout) - self.timeout = timeout - self.timer = None - - def start(self): - self.step_status.setColor("yellow") - self.step_status.setText(["delay", "%s secs" % self.timeout]) - self.timer = reactor.callLater(self.timeout, self.done) - - def interrupt(self, reason): - if self.timer: - self.timer.cancel() - self.timer = None - self.step_status.setColor("red") - self.step_status.setText(["delay", "interrupted"]) - self.finished(FAILURE) - - def done(self): - self.step_status.setColor("green") - self.finished(SUCCESS) - -class FailingDummy(Dummy): - """I am a dummy no-op step that 'runs' master-side and finishes (with a - FAILURE status) after 5 seconds.""" - - name = "failing dummy" - - def start(self): - self.step_status.setColor("yellow") - self.step_status.setText(["boom", "%s secs" % self.timeout]) - self.timer = reactor.callLater(self.timeout, self.done) - - def done(self): - self.step_status.setColor("red") - self.finished(FAILURE) - -class RemoteDummy(LoggingBuildStep): - """I am a dummy no-op step that runs on the remote side and - simply waits 5 seconds before completing with success. - See L{buildbot.slave.commands.DummyCommand} - """ - - haltOnFailure = True - name = "remote dummy" - - def __init__(self, timeout=5, **kwargs): - """ - @type timeout: int - @param timeout: the number of seconds to delay - """ - LoggingBuildStep.__init__(self, **kwargs) - self.addFactoryArguments(timeout=timeout) - self.timeout = timeout - self.description = ["remote", "delay", "%s secs" % timeout] - - def describe(self, done=False): - return self.description - - def start(self): - args = {'timeout': self.timeout} - cmd = LoggedRemoteCommand("dummy", args) - self.startCommand(cmd) - -class Wait(LoggingBuildStep): - """I start a command on the slave that waits for the unit test to - tell it when to finish. - """ - - name = "wait" - def __init__(self, handle, **kwargs): - LoggingBuildStep.__init__(self, **kwargs) - self.addFactoryArguments(handle=handle) - self.handle = handle - - def describe(self, done=False): - return ["wait: %s" % self.handle] - - def start(self): - args = {'handle': (self.handle, self.build.reason)} - cmd = LoggedRemoteCommand("dummy.wait", args) - self.startCommand(cmd) diff --git a/tools/buildbot/pylibs/buildbot/steps/maxq.py b/tools/buildbot/pylibs/buildbot/steps/maxq.py deleted file mode 100644 index 2a29ed8..0000000 --- a/tools/buildbot/pylibs/buildbot/steps/maxq.py +++ /dev/null @@ -1,46 +0,0 @@ -from buildbot.steps.shell import ShellCommand -from buildbot.status.builder import Event, SUCCESS, FAILURE - -class MaxQ(ShellCommand): - flunkOnFailure = True - name = "maxq" - - def __init__(self, testdir=None, **kwargs): - if not testdir: - raise TypeError("please pass testdir") - kwargs['command'] = 'run_maxq.py %s' % (testdir,) - ShellCommand.__init__(self, **kwargs) - self.addFactoryArguments(testdir=testdir) - - def startStatus(self): - evt = Event("yellow", ['running', 'maxq', 'tests'], - files={'log': self.log}) - self.setCurrentActivity(evt) - - - def finished(self, rc): - self.failures = 0 - if rc: - self.failures = 1 - output = self.log.getAll() - self.failures += output.count('\nTEST FAILURE:') - - result = (SUCCESS, ['maxq']) - - if self.failures: - result = (FAILURE, [str(self.failures), 'maxq', 'failures']) - - return self.stepComplete(result) - - def finishStatus(self, result): - if self.failures: - color = "red" - text = ["maxq", "failed"] - else: - color = "green" - text = ['maxq', 'tests'] - self.updateCurrentActivity(color=color, text=text) - self.finishStatusSummary() - self.finishCurrentActivity() - - diff --git a/tools/buildbot/pylibs/buildbot/steps/python.py b/tools/buildbot/pylibs/buildbot/steps/python.py deleted file mode 100644 index d6fa1bd..0000000 --- a/tools/buildbot/pylibs/buildbot/steps/python.py +++ /dev/null @@ -1,112 +0,0 @@ - -from buildbot.status.builder import SUCCESS, FAILURE, WARNINGS -from buildbot.steps.shell import ShellCommand - -try: - import cStringIO - StringIO = cStringIO.StringIO -except ImportError: - from StringIO import StringIO - - -class BuildEPYDoc(ShellCommand): - name = "epydoc" - command = ["make", "epydocs"] - description = ["building", "epydocs"] - descriptionDone = ["epydoc"] - - def createSummary(self, log): - import_errors = 0 - warnings = 0 - errors = 0 - - for line in StringIO(log.getText()): - if line.startswith("Error importing "): - import_errors += 1 - if line.find("Warning: ") != -1: - warnings += 1 - if line.find("Error: ") != -1: - errors += 1 - - self.descriptionDone = self.descriptionDone[:] - if import_errors: - self.descriptionDone.append("ierr=%d" % import_errors) - if warnings: - self.descriptionDone.append("warn=%d" % warnings) - if errors: - self.descriptionDone.append("err=%d" % errors) - - self.import_errors = import_errors - self.warnings = warnings - self.errors = errors - - def evaluateCommand(self, cmd): - if cmd.rc != 0: - return FAILURE - if self.warnings or self.errors: - return WARNINGS - return SUCCESS - - -class PyFlakes(ShellCommand): - name = "pyflakes" - command = ["make", "pyflakes"] - description = ["running", "pyflakes"] - descriptionDone = ["pyflakes"] - flunkOnFailure = False - flunkingIssues = ["undefined"] # any pyflakes lines like this cause FAILURE - - MESSAGES = ("unused", "undefined", "redefs", "import*", "misc") - - def createSummary(self, log): - counts = {} - summaries = {} - for m in self.MESSAGES: - counts[m] = 0 - summaries[m] = [] - - first = True - for line in StringIO(log.getText()).readlines(): - # the first few lines might contain echoed commands from a 'make - # pyflakes' step, so don't count these as warnings. Stop ignoring - # the initial lines as soon as we see one with a colon. - if first: - if line.find(":") != -1: - # there's the colon, this is the first real line - first = False - # fall through and parse the line - else: - # skip this line, keep skipping non-colon lines - continue - if line.find("imported but unused") != -1: - m = "unused" - elif line.find("*' used; unable to detect undefined names") != -1: - m = "import*" - elif line.find("undefined name") != -1: - m = "undefined" - elif line.find("redefinition of unused") != -1: - m = "redefs" - else: - m = "misc" - summaries[m].append(line) - counts[m] += 1 - - self.descriptionDone = self.descriptionDone[:] - for m in self.MESSAGES: - if counts[m]: - self.descriptionDone.append("%s=%d" % (m, counts[m])) - self.addCompleteLog(m, "".join(summaries[m])) - self.setProperty("pyflakes-%s" % m, counts[m], "pyflakes") - self.setProperty("pyflakes-total", sum(counts.values()), "pyflakes") - - - def evaluateCommand(self, cmd): - if cmd.rc != 0: - return FAILURE - for m in self.flunkingIssues: - if self.getProperty("pyflakes-%s" % m): - return FAILURE - if self.getProperty("pyflakes-total"): - return WARNINGS - return SUCCESS - diff --git a/tools/buildbot/pylibs/buildbot/steps/python_twisted.py b/tools/buildbot/pylibs/buildbot/steps/python_twisted.py deleted file mode 100644 index 3edff9d..0000000 --- a/tools/buildbot/pylibs/buildbot/steps/python_twisted.py +++ /dev/null @@ -1,820 +0,0 @@ -# -*- test-case-name: buildbot.test.test_twisted -*- - -from twisted.python import log - -from buildbot.status import builder -from buildbot.status.builder import SUCCESS, FAILURE, WARNINGS, SKIPPED -from buildbot.process.buildstep import LogLineObserver, OutputProgressObserver -from buildbot.process.buildstep import RemoteShellCommand -from buildbot.steps.shell import ShellCommand - -try: - import cStringIO - StringIO = cStringIO -except ImportError: - import StringIO -import re - -# BuildSteps that are specific to the Twisted source tree - -class HLint(ShellCommand): - """I run a 'lint' checker over a set of .xhtml files. Any deviations - from recommended style is flagged and put in the output log. - - This step looks at .changes in the parent Build to extract a list of - Lore XHTML files to check.""" - - name = "hlint" - description = ["running", "hlint"] - descriptionDone = ["hlint"] - warnOnWarnings = True - warnOnFailure = True - # TODO: track time, but not output - warnings = 0 - - def __init__(self, python=None, **kwargs): - ShellCommand.__init__(self, **kwargs) - self.addFactoryArguments(python=python) - self.python = python - - def start(self): - # create the command - htmlFiles = {} - for f in self.build.allFiles(): - if f.endswith(".xhtml") and not f.startswith("sandbox/"): - htmlFiles[f] = 1 - # remove duplicates - hlintTargets = htmlFiles.keys() - hlintTargets.sort() - if not hlintTargets: - return SKIPPED - self.hlintFiles = hlintTargets - c = [] - if self.python: - c.append(self.python) - c += ["bin/lore", "-p", "--output", "lint"] + self.hlintFiles - self.setCommand(c) - - # add an extra log file to show the .html files we're checking - self.addCompleteLog("files", "\n".join(self.hlintFiles)+"\n") - - ShellCommand.start(self) - - def commandComplete(self, cmd): - # TODO: remove the 'files' file (a list of .xhtml files that were - # submitted to hlint) because it is available in the logfile and - # mostly exists to give the user an idea of how long the step will - # take anyway). - lines = cmd.logs['stdio'].getText().split("\n") - warningLines = filter(lambda line:':' in line, lines) - if warningLines: - self.addCompleteLog("warnings", "".join(warningLines)) - warnings = len(warningLines) - self.warnings = warnings - - def evaluateCommand(self, cmd): - # warnings are in stdout, rc is always 0, unless the tools break - if cmd.rc != 0: - return FAILURE - if self.warnings: - return WARNINGS - return SUCCESS - - def getText2(self, cmd, results): - if cmd.rc != 0: - return ["hlint"] - return ["%d hlin%s" % (self.warnings, - self.warnings == 1 and 't' or 'ts')] - -def countFailedTests(output): - # start scanning 10kb from the end, because there might be a few kb of - # import exception tracebacks between the total/time line and the errors - # line - chunk = output[-10000:] - lines = chunk.split("\n") - lines.pop() # blank line at end - # lines[-3] is "Ran NN tests in 0.242s" - # lines[-2] is blank - # lines[-1] is 'OK' or 'FAILED (failures=1, errors=12)' - # or 'FAILED (failures=1)' - # or "PASSED (skips=N, successes=N)" (for Twisted-2.0) - # there might be other lines dumped here. Scan all the lines. - res = {'total': None, - 'failures': 0, - 'errors': 0, - 'skips': 0, - 'expectedFailures': 0, - 'unexpectedSuccesses': 0, - } - for l in lines: - out = re.search(r'Ran (\d+) tests', l) - if out: - res['total'] = int(out.group(1)) - if (l.startswith("OK") or - l.startswith("FAILED ") or - l.startswith("PASSED")): - # the extra space on FAILED_ is to distinguish the overall - # status from an individual test which failed. The lack of a - # space on the OK is because it may be printed without any - # additional text (if there are no skips,etc) - out = re.search(r'failures=(\d+)', l) - if out: res['failures'] = int(out.group(1)) - out = re.search(r'errors=(\d+)', l) - if out: res['errors'] = int(out.group(1)) - out = re.search(r'skips=(\d+)', l) - if out: res['skips'] = int(out.group(1)) - out = re.search(r'expectedFailures=(\d+)', l) - if out: res['expectedFailures'] = int(out.group(1)) - out = re.search(r'unexpectedSuccesses=(\d+)', l) - if out: res['unexpectedSuccesses'] = int(out.group(1)) - # successes= is a Twisted-2.0 addition, and is not currently used - out = re.search(r'successes=(\d+)', l) - if out: res['successes'] = int(out.group(1)) - - return res - - -class TrialTestCaseCounter(LogLineObserver): - _line_re = re.compile(r'^(?:Doctest: )?([\w\.]+) \.\.\. \[([^\]]+)\]$') - numTests = 0 - finished = False - - def outLineReceived(self, line): - # different versions of Twisted emit different per-test lines with - # the bwverbose reporter. - # 2.0.0: testSlave (buildbot.test.test_runner.Create) ... [OK] - # 2.1.0: buildbot.test.test_runner.Create.testSlave ... [OK] - # 2.4.0: buildbot.test.test_runner.Create.testSlave ... [OK] - # Let's just handle the most recent version, since it's the easiest. - # Note that doctests create lines line this: - # Doctest: viff.field.GF ... [OK] - - if self.finished: - return - if line.startswith("=" * 40): - self.finished = True - return - - m = self._line_re.search(line.strip()) - if m: - testname, result = m.groups() - self.numTests += 1 - self.step.setProgress('tests', self.numTests) - - -UNSPECIFIED=() # since None is a valid choice - -class Trial(ShellCommand): - """I run a unit test suite using 'trial', a unittest-like testing - framework that comes with Twisted. Trial is used to implement Twisted's - own unit tests, and is the unittest-framework of choice for many projects - that use Twisted internally. - - Projects that use trial typically have all their test cases in a 'test' - subdirectory of their top-level library directory. I.e. for my package - 'petmail', the tests are in 'petmail/test/test_*.py'. More complicated - packages (like Twisted itself) may have multiple test directories, like - 'twisted/test/test_*.py' for the core functionality and - 'twisted/mail/test/test_*.py' for the email-specific tests. - - To run trial tests, you run the 'trial' executable and tell it where the - test cases are located. The most common way of doing this is with a - module name. For petmail, I would run 'trial petmail.test' and it would - locate all the test_*.py files under petmail/test/, running every test - case it could find in them. Unlike the unittest.py that comes with - Python, you do not run the test_foo.py as a script; you always let trial - do the importing and running. The 'tests' parameter controls which tests - trial will run: it can be a string or a list of strings. - - You can also use a higher-level module name and pass the --recursive flag - to trial: this will search recursively within the named module to find - all test cases. For large multiple-test-directory projects like Twisted, - this means you can avoid specifying all the test directories explicitly. - Something like 'trial --recursive twisted' will pick up everything. - - To find these test cases, you must set a PYTHONPATH that allows something - like 'import petmail.test' to work. For packages that don't use a - separate top-level 'lib' directory, PYTHONPATH=. will work, and will use - the test cases (and the code they are testing) in-place. - PYTHONPATH=build/lib or PYTHONPATH=build/lib.$ARCH are also useful when - you do a'setup.py build' step first. The 'testpath' attribute of this - class controls what PYTHONPATH= is set to. - - Trial has the ability (through the --testmodule flag) to run only the set - of test cases named by special 'test-case-name' tags in source files. We - can get the list of changed source files from our parent Build and - provide them to trial, thus running the minimal set of test cases needed - to cover the Changes. This is useful for quick builds, especially in - trees with a lot of test cases. The 'testChanges' parameter controls this - feature: if set, it will override 'tests'. - - The trial executable itself is typically just 'trial' (which is usually - found on your $PATH as /usr/bin/trial), but it can be overridden with the - 'trial' parameter. This is useful for Twisted's own unittests, which want - to use the copy of bin/trial that comes with the sources. (when bin/trial - discovers that it is living in a subdirectory named 'Twisted', it assumes - it is being run from the source tree and adds that parent directory to - PYTHONPATH. Therefore the canonical way to run Twisted's own unittest - suite is './bin/trial twisted.test' rather than 'PYTHONPATH=. - /usr/bin/trial twisted.test', especially handy when /usr/bin/trial has - not yet been installed). - - To influence the version of python being used for the tests, or to add - flags to the command, set the 'python' parameter. This can be a string - (like 'python2.2') or a list (like ['python2.3', '-Wall']). - - Trial creates and switches into a directory named _trial_temp/ before - running the tests, and sends the twisted log (which includes all - exceptions) to a file named test.log . This file will be pulled up to - the master where it can be seen as part of the status output. - - There are some class attributes which may be usefully overridden - by subclasses. 'trialMode' and 'trialArgs' can influence the trial - command line. - """ - - name = "trial" - progressMetrics = ('output', 'tests', 'test.log') - # note: the slash only works on unix buildslaves, of course, but we have - # no way to know what the buildslave uses as a separator. TODO: figure - # out something clever. - logfiles = {"test.log": "_trial_temp/test.log"} - # we use test.log to track Progress at the end of __init__() - - flunkOnFailure = True - python = None - trial = "trial" - trialMode = ["--reporter=bwverbose"] # requires Twisted-2.1.0 or newer - # for Twisted-2.0.0 or 1.3.0, use ["-o"] instead - trialArgs = [] - testpath = UNSPECIFIED # required (but can be None) - testChanges = False # TODO: needs better name - recurse = False - reactor = None - randomly = False - tests = None # required - - def __init__(self, reactor=UNSPECIFIED, python=None, trial=None, - testpath=UNSPECIFIED, - tests=None, testChanges=None, - recurse=None, randomly=None, - trialMode=None, trialArgs=None, - **kwargs): - """ - @type testpath: string - @param testpath: use in PYTHONPATH when running the tests. If - None, do not set PYTHONPATH. Setting this to '.' will - cause the source files to be used in-place. - - @type python: string (without spaces) or list - @param python: which python executable to use. Will form the start of - the argv array that will launch trial. If you use this, - you should set 'trial' to an explicit path (like - /usr/bin/trial or ./bin/trial). Defaults to None, which - leaves it out entirely (running 'trial args' instead of - 'python ./bin/trial args'). Likely values are 'python', - ['python2.2'], ['python', '-Wall'], etc. - - @type trial: string - @param trial: which 'trial' executable to run. - Defaults to 'trial', which will cause $PATH to be - searched and probably find /usr/bin/trial . If you set - 'python', this should be set to an explicit path (because - 'python2.3 trial' will not work). - - @type trialMode: list of strings - @param trialMode: a list of arguments to pass to trial, specifically - to set the reporting mode. This defaults to ['-to'] - which means 'verbose colorless output' to the trial - that comes with Twisted-2.0.x and at least -2.1.0 . - Newer versions of Twisted may come with a trial - that prefers ['--reporter=bwverbose']. - - @type trialArgs: list of strings - @param trialArgs: a list of arguments to pass to trial, available to - turn on any extra flags you like. Defaults to []. - - @type tests: list of strings - @param tests: a list of test modules to run, like - ['twisted.test.test_defer', 'twisted.test.test_process']. - If this is a string, it will be converted into a one-item - list. - - @type testChanges: boolean - @param testChanges: if True, ignore the 'tests' parameter and instead - ask the Build for all the files that make up the - Changes going into this build. Pass these filenames - to trial and ask it to look for test-case-name - tags, running just the tests necessary to cover the - changes. - - @type recurse: boolean - @param recurse: If True, pass the --recurse option to trial, allowing - test cases to be found in deeper subdirectories of the - modules listed in 'tests'. This does not appear to be - necessary when using testChanges. - - @type reactor: string - @param reactor: which reactor to use, like 'gtk' or 'java'. If not - provided, the Twisted's usual platform-dependent - default is used. - - @type randomly: boolean - @param randomly: if True, add the --random=0 argument, which instructs - trial to run the unit tests in a random order each - time. This occasionally catches problems that might be - masked when one module always runs before another - (like failing to make registerAdapter calls before - lookups are done). - - @type kwargs: dict - @param kwargs: parameters. The following parameters are inherited from - L{ShellCommand} and may be useful to set: workdir, - haltOnFailure, flunkOnWarnings, flunkOnFailure, - warnOnWarnings, warnOnFailure, want_stdout, want_stderr, - timeout. - """ - ShellCommand.__init__(self, **kwargs) - self.addFactoryArguments(reactor=reactor, - python=python, - trial=trial, - testpath=testpath, - tests=tests, - testChanges=testChanges, - recurse=recurse, - randomly=randomly, - trialMode=trialMode, - trialArgs=trialArgs, - ) - - if python: - self.python = python - if self.python is not None: - if type(self.python) is str: - self.python = [self.python] - for s in self.python: - if " " in s: - # this is not strictly an error, but I suspect more - # people will accidentally try to use python="python2.3 - # -Wall" than will use embedded spaces in a python flag - log.msg("python= component '%s' has spaces") - log.msg("To add -Wall, use python=['python', '-Wall']") - why = "python= value has spaces, probably an error" - raise ValueError(why) - - if trial: - self.trial = trial - if " " in self.trial: - raise ValueError("trial= value has spaces") - if trialMode is not None: - self.trialMode = trialMode - if trialArgs is not None: - self.trialArgs = trialArgs - - if testpath is not UNSPECIFIED: - self.testpath = testpath - if self.testpath is UNSPECIFIED: - raise ValueError("You must specify testpath= (it can be None)") - assert isinstance(self.testpath, str) or self.testpath is None - - if reactor is not UNSPECIFIED: - self.reactor = reactor - - if tests is not None: - self.tests = tests - if type(self.tests) is str: - self.tests = [self.tests] - if testChanges is not None: - self.testChanges = testChanges - #self.recurse = True # not sure this is necessary - - if not self.testChanges and self.tests is None: - raise ValueError("Must either set testChanges= or provide tests=") - - if recurse is not None: - self.recurse = recurse - if randomly is not None: - self.randomly = randomly - - # build up most of the command, then stash it until start() - command = [] - if self.python: - command.extend(self.python) - command.append(self.trial) - command.extend(self.trialMode) - if self.recurse: - command.append("--recurse") - if self.reactor: - command.append("--reactor=%s" % reactor) - if self.randomly: - command.append("--random=0") - command.extend(self.trialArgs) - self.command = command - - if self.reactor: - self.description = ["testing", "(%s)" % self.reactor] - self.descriptionDone = ["tests"] - # commandComplete adds (reactorname) to self.text - else: - self.description = ["testing"] - self.descriptionDone = ["tests"] - - # this counter will feed Progress along the 'test cases' metric - self.addLogObserver('stdio', TrialTestCaseCounter()) - # this one just measures bytes of output in _trial_temp/test.log - self.addLogObserver('test.log', OutputProgressObserver('test.log')) - - def setupEnvironment(self, cmd): - ShellCommand.setupEnvironment(self, cmd) - if self.testpath != None: - e = cmd.args['env'] - if e is None: - cmd.args['env'] = {'PYTHONPATH': self.testpath} - else: - # TODO: somehow, each build causes another copy of - # self.testpath to get prepended - if e.get('PYTHONPATH', "") == "": - e['PYTHONPATH'] = self.testpath - else: - e['PYTHONPATH'] = self.testpath + ":" + e['PYTHONPATH'] - try: - p = cmd.args['env']['PYTHONPATH'] - if type(p) is not str: - log.msg("hey, not a string:", p) - assert False - except (KeyError, TypeError): - # KeyError if args doesn't have ['env'] - # KeyError if args['env'] doesn't have ['PYTHONPATH'] - # TypeError if args is None - pass - - def start(self): - # now that self.build.allFiles() is nailed down, finish building the - # command - if self.testChanges: - for f in self.build.allFiles(): - if f.endswith(".py"): - self.command.append("--testmodule=%s" % f) - else: - self.command.extend(self.tests) - log.msg("Trial.start: command is", self.command) - - # if our slave is too old to understand logfiles=, fetch them - # manually. This is a fallback for the Twisted buildbot and some old - # buildslaves. - self._needToPullTestDotLog = False - if self.slaveVersionIsOlderThan("shell", "2.1"): - log.msg("Trial: buildslave %s is too old to accept logfiles=" % - self.getSlaveName()) - log.msg(" falling back to 'cat _trial_temp/test.log' instead") - self.logfiles = {} - self._needToPullTestDotLog = True - - ShellCommand.start(self) - - - def commandComplete(self, cmd): - if not self._needToPullTestDotLog: - return self._gotTestDotLog(cmd) - - # if the buildslave was too old, pull test.log now - catcmd = ["cat", "_trial_temp/test.log"] - c2 = RemoteShellCommand(command=catcmd, workdir=self.workdir) - loog = self.addLog("test.log") - c2.useLog(loog, True, logfileName="stdio") - self.cmd = c2 # to allow interrupts - d = c2.run(self, self.remote) - d.addCallback(lambda res: self._gotTestDotLog(cmd)) - return d - - def rtext(self, fmt='%s'): - if self.reactor: - rtext = fmt % self.reactor - return rtext.replace("reactor", "") - return "" - - def _gotTestDotLog(self, cmd): - # figure out all status, then let the various hook functions return - # different pieces of it - - # 'cmd' is the original trial command, so cmd.logs['stdio'] is the - # trial output. We don't have access to test.log from here. - output = cmd.logs['stdio'].getText() - counts = countFailedTests(output) - - total = counts['total'] - failures, errors = counts['failures'], counts['errors'] - parsed = (total != None) - text = [] - text2 = "" - - if cmd.rc == 0: - if parsed: - results = SUCCESS - if total: - text += ["%d %s" % \ - (total, - total == 1 and "test" or "tests"), - "passed"] - else: - text += ["no tests", "run"] - else: - results = FAILURE - text += ["testlog", "unparseable"] - text2 = "tests" - else: - # something failed - results = FAILURE - if parsed: - text.append("tests") - if failures: - text.append("%d %s" % \ - (failures, - failures == 1 and "failure" or "failures")) - if errors: - text.append("%d %s" % \ - (errors, - errors == 1 and "error" or "errors")) - count = failures + errors - text2 = "%d tes%s" % (count, (count == 1 and 't' or 'ts')) - else: - text += ["tests", "failed"] - text2 = "tests" - - if counts['skips']: - text.append("%d %s" % \ - (counts['skips'], - counts['skips'] == 1 and "skip" or "skips")) - if counts['expectedFailures']: - text.append("%d %s" % \ - (counts['expectedFailures'], - counts['expectedFailures'] == 1 and "todo" - or "todos")) - if 0: # TODO - results = WARNINGS - if not text2: - text2 = "todo" - - if 0: - # ignore unexpectedSuccesses for now, but it should really mark - # the build WARNING - if counts['unexpectedSuccesses']: - text.append("%d surprises" % counts['unexpectedSuccesses']) - results = WARNINGS - if not text2: - text2 = "tests" - - if self.reactor: - text.append(self.rtext('(%s)')) - if text2: - text2 = "%s %s" % (text2, self.rtext('(%s)')) - - self.results = results - self.text = text - self.text2 = [text2] - - def addTestResult(self, testname, results, text, tlog): - if self.reactor is not None: - testname = (self.reactor,) + testname - tr = builder.TestResult(testname, results, text, logs={'log': tlog}) - #self.step_status.build.addTestResult(tr) - self.build.build_status.addTestResult(tr) - - def createSummary(self, loog): - output = loog.getText() - problems = "" - sio = StringIO.StringIO(output) - warnings = {} - while 1: - line = sio.readline() - if line == "": - break - if line.find(" exceptions.DeprecationWarning: ") != -1: - # no source - warning = line # TODO: consider stripping basedir prefix here - warnings[warning] = warnings.get(warning, 0) + 1 - elif (line.find(" DeprecationWarning: ") != -1 or - line.find(" UserWarning: ") != -1): - # next line is the source - warning = line + sio.readline() - warnings[warning] = warnings.get(warning, 0) + 1 - elif line.find("Warning: ") != -1: - warning = line - warnings[warning] = warnings.get(warning, 0) + 1 - - if line.find("=" * 60) == 0 or line.find("-" * 60) == 0: - problems += line - problems += sio.read() - break - - if problems: - self.addCompleteLog("problems", problems) - # now parse the problems for per-test results - pio = StringIO.StringIO(problems) - pio.readline() # eat the first separator line - testname = None - done = False - while not done: - while 1: - line = pio.readline() - if line == "": - done = True - break - if line.find("=" * 60) == 0: - break - if line.find("-" * 60) == 0: - # the last case has --- as a separator before the - # summary counts are printed - done = True - break - if testname is None: - # the first line after the === is like: -# EXPECTED FAILURE: testLackOfTB (twisted.test.test_failure.FailureTestCase) -# SKIPPED: testRETR (twisted.test.test_ftp.TestFTPServer) -# FAILURE: testBatchFile (twisted.conch.test.test_sftp.TestOurServerBatchFile) - r = re.search(r'^([^:]+): (\w+) \(([\w\.]+)\)', line) - if not r: - # TODO: cleanup, if there are no problems, - # we hit here - continue - result, name, case = r.groups() - testname = tuple(case.split(".") + [name]) - results = {'SKIPPED': SKIPPED, - 'EXPECTED FAILURE': SUCCESS, - 'UNEXPECTED SUCCESS': WARNINGS, - 'FAILURE': FAILURE, - 'ERROR': FAILURE, - 'SUCCESS': SUCCESS, # not reported - }.get(result, WARNINGS) - text = result.lower().split() - loog = line - # the next line is all dashes - loog += pio.readline() - else: - # the rest goes into the log - loog += line - if testname: - self.addTestResult(testname, results, text, loog) - testname = None - - if warnings: - lines = warnings.keys() - lines.sort() - self.addCompleteLog("warnings", "".join(lines)) - - def evaluateCommand(self, cmd): - return self.results - - def getText(self, cmd, results): - return self.text - def getText2(self, cmd, results): - return self.text2 - - -class ProcessDocs(ShellCommand): - """I build all docs. This requires some LaTeX packages to be installed. - It will result in the full documentation book (dvi, pdf, etc). - - """ - - name = "process-docs" - warnOnWarnings = 1 - command = ["admin/process-docs"] - description = ["processing", "docs"] - descriptionDone = ["docs"] - # TODO: track output and time - - def __init__(self, **kwargs): - """ - @type workdir: string - @keyword workdir: the workdir to start from: must be the base of the - Twisted tree - - @type results: triple of (int, int, string) - @keyword results: [rc, warnings, output] - - rc==0 if all files were converted successfully. - - warnings is a count of hlint warnings. - - output is the verbose output of the command. - """ - ShellCommand.__init__(self, **kwargs) - - def createSummary(self, log): - output = log.getText() - # hlint warnings are of the format: 'WARNING: file:line:col: stuff - # latex warnings start with "WARNING: LaTeX Warning: stuff", but - # sometimes wrap around to a second line. - lines = output.split("\n") - warningLines = [] - wantNext = False - for line in lines: - wantThis = wantNext - wantNext = False - if line.startswith("WARNING: "): - wantThis = True - wantNext = True - if wantThis: - warningLines.append(line) - - if warningLines: - self.addCompleteLog("warnings", "\n".join(warningLines) + "\n") - self.warnings = len(warningLines) - - def evaluateCommand(self, cmd): - if cmd.rc != 0: - return FAILURE - if self.warnings: - return WARNINGS - return SUCCESS - - def getText(self, cmd, results): - if results == SUCCESS: - return ["docs", "successful"] - if results == WARNINGS: - return ["docs", - "%d warnin%s" % (self.warnings, - self.warnings == 1 and 'g' or 'gs')] - if results == FAILURE: - return ["docs", "failed"] - - def getText2(self, cmd, results): - if results == WARNINGS: - return ["%d do%s" % (self.warnings, - self.warnings == 1 and 'c' or 'cs')] - return ["docs"] - - - -class BuildDebs(ShellCommand): - """I build the .deb packages.""" - - name = "debuild" - flunkOnFailure = 1 - command = ["debuild", "-uc", "-us"] - description = ["building", "debs"] - descriptionDone = ["debs"] - - def __init__(self, **kwargs): - """ - @type workdir: string - @keyword workdir: the workdir to start from (must be the base of the - Twisted tree) - @type results: double of [int, string] - @keyword results: [rc, output]. - - rc == 0 if all .debs were created successfully - - output: string with any errors or warnings - """ - ShellCommand.__init__(self, **kwargs) - - def commandComplete(self, cmd): - errors, warnings = 0, 0 - output = cmd.logs['stdio'].getText() - summary = "" - sio = StringIO.StringIO(output) - for line in sio.readlines(): - if line.find("E: ") == 0: - summary += line - errors += 1 - if line.find("W: ") == 0: - summary += line - warnings += 1 - if summary: - self.addCompleteLog("problems", summary) - self.errors = errors - self.warnings = warnings - - def evaluateCommand(self, cmd): - if cmd.rc != 0: - return FAILURE - if self.errors: - return FAILURE - if self.warnings: - return WARNINGS - return SUCCESS - - def getText(self, cmd, results): - text = ["debuild"] - if cmd.rc != 0: - text.append("failed") - errors, warnings = self.errors, self.warnings - if warnings or errors: - text.append("lintian:") - if warnings: - text.append("%d warnin%s" % (warnings, - warnings == 1 and 'g' or 'gs')) - if errors: - text.append("%d erro%s" % (errors, - errors == 1 and 'r' or 'rs')) - return text - - def getText2(self, cmd, results): - if cmd.rc != 0: - return ["debuild"] - if self.errors or self.warnings: - return ["%d lintian" % (self.errors + self.warnings)] - return [] - -class RemovePYCs(ShellCommand): - name = "remove-.pyc" - command = 'find . -name "*.pyc" | xargs rm' - description = ["removing", ".pyc", "files"] - descriptionDone = ["remove", ".pycs"] diff --git a/tools/buildbot/pylibs/buildbot/steps/shell.py b/tools/buildbot/pylibs/buildbot/steps/shell.py deleted file mode 100644 index 2108d77..0000000 --- a/tools/buildbot/pylibs/buildbot/steps/shell.py +++ /dev/null @@ -1,444 +0,0 @@ -# -*- test-case-name: buildbot.test.test_steps,buildbot.test.test_properties -*- - -import re -from twisted.python import log -from buildbot.process.buildstep import LoggingBuildStep, RemoteShellCommand -from buildbot.status.builder import SUCCESS, WARNINGS, FAILURE, STDOUT, STDERR - -# for existing configurations that import WithProperties from here. We like -# to move this class around just to keep our readers guessing. -from buildbot.process.properties import WithProperties -_hush_pyflakes = [WithProperties] -del _hush_pyflakes - -class ShellCommand(LoggingBuildStep): - """I run a single shell command on the buildslave. I return FAILURE if - the exit code of that command is non-zero, SUCCESS otherwise. To change - this behavior, override my .evaluateCommand method. - - By default, a failure of this step will mark the whole build as FAILURE. - To override this, give me an argument of flunkOnFailure=False . - - I create a single Log named 'log' which contains the output of the - command. To create additional summary Logs, override my .createSummary - method. - - The shell command I run (a list of argv strings) can be provided in - several ways: - - a class-level .command attribute - - a command= parameter to my constructor (overrides .command) - - set explicitly with my .setCommand() method (overrides both) - - @ivar command: a list of renderable objects (typically strings or - WithProperties instances). This will be used by start() - to create a RemoteShellCommand instance. - - @ivar logfiles: a dict mapping log NAMEs to workdir-relative FILENAMEs - of their corresponding logfiles. The contents of the file - named FILENAME will be put into a LogFile named NAME, ina - something approximating real-time. (note that logfiles= - is actually handled by our parent class LoggingBuildStep) - - """ - - name = "shell" - description = None # set this to a list of short strings to override - descriptionDone = None # alternate description when the step is complete - command = None # set this to a command, or set in kwargs - # logfiles={} # you can also set 'logfiles' to a dictionary, and it - # will be merged with any logfiles= argument passed in - # to __init__ - - # override this on a specific ShellCommand if you want to let it fail - # without dooming the entire build to a status of FAILURE - flunkOnFailure = True - - def __init__(self, workdir=None, - description=None, descriptionDone=None, - command=None, - **kwargs): - # most of our arguments get passed through to the RemoteShellCommand - # that we create, but first strip out the ones that we pass to - # BuildStep (like haltOnFailure and friends), and a couple that we - # consume ourselves. - - if description: - self.description = description - if isinstance(self.description, str): - self.description = [self.description] - if descriptionDone: - self.descriptionDone = descriptionDone - if isinstance(self.descriptionDone, str): - self.descriptionDone = [self.descriptionDone] - if command: - self.command = command - - # pull out the ones that LoggingBuildStep wants, then upcall - buildstep_kwargs = {} - for k in kwargs.keys()[:]: - if k in self.__class__.parms: - buildstep_kwargs[k] = kwargs[k] - del kwargs[k] - LoggingBuildStep.__init__(self, **buildstep_kwargs) - self.addFactoryArguments(workdir=workdir, - description=description, - descriptionDone=descriptionDone, - command=command) - - # everything left over goes to the RemoteShellCommand - kwargs['workdir'] = workdir # including a copy of 'workdir' - self.remote_kwargs = kwargs - # we need to stash the RemoteShellCommand's args too - self.addFactoryArguments(**kwargs) - - def setDefaultWorkdir(self, workdir): - rkw = self.remote_kwargs - rkw['workdir'] = rkw['workdir'] or workdir - - def setCommand(self, command): - self.command = command - - def describe(self, done=False): - """Return a list of short strings to describe this step, for the - status display. This uses the first few words of the shell command. - You can replace this by setting .description in your subclass, or by - overriding this method to describe the step better. - - @type done: boolean - @param done: whether the command is complete or not, to improve the - way the command is described. C{done=False} is used - while the command is still running, so a single - imperfect-tense verb is appropriate ('compiling', - 'testing', ...) C{done=True} is used when the command - has finished, and the default getText() method adds some - text, so a simple noun is appropriate ('compile', - 'tests' ...) - """ - - if done and self.descriptionDone is not None: - return self.descriptionDone - if self.description is not None: - return self.description - - properties = self.build.getProperties() - words = self.command - if isinstance(words, (str, unicode)): - words = words.split() - # render() each word to handle WithProperties objects - words = properties.render(words) - if len(words) < 1: - return ["???"] - if len(words) == 1: - return ["'%s'" % words[0]] - if len(words) == 2: - return ["'%s" % words[0], "%s'" % words[1]] - return ["'%s" % words[0], "%s" % words[1], "...'"] - - def setupEnvironment(self, cmd): - # XXX is this used? documented? replaced by properties? - # merge in anything from Build.slaveEnvironment . Earlier steps - # (perhaps ones which compile libraries or sub-projects that need to - # be referenced by later steps) can add keys to - # self.build.slaveEnvironment to affect later steps. - properties = self.build.getProperties() - slaveEnv = self.build.slaveEnvironment - if slaveEnv: - if cmd.args['env'] is None: - cmd.args['env'] = {} - cmd.args['env'].update(properties.render(slaveEnv)) - # note that each RemoteShellCommand gets its own copy of the - # dictionary, so we shouldn't be affecting anyone but ourselves. - - def checkForOldSlaveAndLogfiles(self): - if not self.logfiles: - return # doesn't matter - if not self.slaveVersionIsOlderThan("shell", "2.1"): - return # slave is new enough - # this buildslave is too old and will ignore the 'logfiles' - # argument. You'll either have to pull the logfiles manually - # (say, by using 'cat' in a separate RemoteShellCommand) or - # upgrade the buildslave. - msg1 = ("Warning: buildslave %s is too old " - "to understand logfiles=, ignoring it." - % self.getSlaveName()) - msg2 = "You will have to pull this logfile (%s) manually." - log.msg(msg1) - for logname,remotefilename in self.logfiles.items(): - newlog = self.addLog(logname) - newlog.addHeader(msg1 + "\n") - newlog.addHeader(msg2 % remotefilename + "\n") - newlog.finish() - # now prevent setupLogfiles() from adding them - self.logfiles = {} - - def start(self): - # this block is specific to ShellCommands. subclasses that don't need - # to set up an argv array, an environment, or extra logfiles= (like - # the Source subclasses) can just skip straight to startCommand() - properties = self.build.getProperties() - - # create the actual RemoteShellCommand instance now - kwargs = properties.render(self.remote_kwargs) - kwargs['command'] = properties.render(self.command) - kwargs['logfiles'] = self.logfiles - cmd = RemoteShellCommand(**kwargs) - self.setupEnvironment(cmd) - self.checkForOldSlaveAndLogfiles() - - self.startCommand(cmd) - - - -class TreeSize(ShellCommand): - name = "treesize" - command = ["du", "-s", "-k", "."] - kib = None - - def commandComplete(self, cmd): - out = cmd.logs['stdio'].getText() - m = re.search(r'^(\d+)', out) - if m: - self.kib = int(m.group(1)) - self.setProperty("tree-size-KiB", self.kib, "treesize") - - def evaluateCommand(self, cmd): - if cmd.rc != 0: - return FAILURE - if self.kib is None: - return WARNINGS # not sure how 'du' could fail, but whatever - return SUCCESS - - def getText(self, cmd, results): - if self.kib is not None: - return ["treesize", "%d KiB" % self.kib] - return ["treesize", "unknown"] - -class SetProperty(ShellCommand): - name = "setproperty" - - def __init__(self, **kwargs): - self.property = None - self.extract_fn = None - self.strip = True - - if kwargs.has_key('property'): - self.property = kwargs['property'] - del kwargs['property'] - if kwargs.has_key('extract_fn'): - self.extract_fn = kwargs['extract_fn'] - del kwargs['extract_fn'] - if kwargs.has_key('strip'): - self.strip = kwargs['strip'] - del kwargs['strip'] - - ShellCommand.__init__(self, **kwargs) - - self.addFactoryArguments(property=self.property) - self.addFactoryArguments(extract_fn=self.extract_fn) - self.addFactoryArguments(strip=self.strip) - - assert self.property or self.extract_fn, \ - "SetProperty step needs either property= or extract_fn=" - - self.property_changes = {} - - def commandComplete(self, cmd): - if self.property: - result = cmd.logs['stdio'].getText() - if self.strip: result = result.strip() - propname = self.build.getProperties().render(self.property) - self.setProperty(propname, result, "SetProperty Step") - self.property_changes[propname] = result - else: - log = cmd.logs['stdio'] - new_props = self.extract_fn(cmd.rc, - ''.join(log.getChunks([STDOUT], onlyText=True)), - ''.join(log.getChunks([STDERR], onlyText=True))) - for k,v in new_props.items(): - self.setProperty(k, v, "SetProperty Step") - self.property_changes = new_props - - def createSummary(self, log): - props_set = [ "%s: %r" % (k,v) for k,v in self.property_changes.items() ] - self.addCompleteLog('property changes', "\n".join(props_set)) - - def getText(self, cmd, results): - if self.property_changes: - return [ "set props:" ] + self.property_changes.keys() - else: - return [ "no change" ] - -class Configure(ShellCommand): - - name = "configure" - haltOnFailure = 1 - description = ["configuring"] - descriptionDone = ["configure"] - command = ["./configure"] - -class WarningCountingShellCommand(ShellCommand): - warnCount = 0 - warningPattern = '.*warning[: ].*' - - def __init__(self, **kwargs): - # See if we've been given a regular expression to use to match - # warnings. If not, use a default that assumes any line with "warning" - # present is a warning. This may lead to false positives in some cases. - wp = None - if kwargs.has_key('warningPattern'): - wp = kwargs['warningPattern'] - del kwargs['warningPattern'] - self.warningPattern = wp - - # And upcall to let the base class do its work - ShellCommand.__init__(self, **kwargs) - - if wp: - self.addFactoryArguments(warningPattern=wp) - - def createSummary(self, log): - self.warnCount = 0 - - # Now compile a regular expression from whichever warning pattern we're - # using - if not self.warningPattern: - return - - wre = self.warningPattern - if isinstance(wre, str): - wre = re.compile(wre) - - # Check if each line in the output from this command matched our - # warnings regular expressions. If did, bump the warnings count and - # add the line to the collection of lines with warnings - warnings = [] - # TODO: use log.readlines(), except we need to decide about stdout vs - # stderr - for line in log.getText().split("\n"): - if wre.match(line): - warnings.append(line) - self.warnCount += 1 - - # If there were any warnings, make the log if lines with warnings - # available - if self.warnCount: - self.addCompleteLog("warnings", "\n".join(warnings) + "\n") - - warnings_stat = self.step_status.getStatistic('warnings', 0) - self.step_status.setStatistic('warnings', warnings_stat + self.warnCount) - - try: - old_count = self.getProperty("warnings-count") - except KeyError: - old_count = 0 - self.setProperty("warnings-count", old_count + self.warnCount, "WarningCountingShellCommand") - - - def evaluateCommand(self, cmd): - if cmd.rc != 0: - return FAILURE - if self.warnCount: - return WARNINGS - return SUCCESS - - -class Compile(WarningCountingShellCommand): - - name = "compile" - haltOnFailure = 1 - description = ["compiling"] - descriptionDone = ["compile"] - command = ["make", "all"] - - OFFprogressMetrics = ('output',) - # things to track: number of files compiled, number of directories - # traversed (assuming 'make' is being used) - - def createSummary(self, cmd): - # TODO: grep for the characteristic GCC error lines and - # assemble them into a pair of buffers - WarningCountingShellCommand.createSummary(self, cmd) - pass - -class Test(WarningCountingShellCommand): - - name = "test" - warnOnFailure = 1 - description = ["testing"] - descriptionDone = ["test"] - command = ["make", "test"] - - def setTestResults(self, total=0, failed=0, passed=0, warnings=0): - """ - Called by subclasses to set the relevant statistics; this actually - adds to any statistics already present - """ - total += self.step_status.getStatistic('tests-total', 0) - self.step_status.setStatistic('tests-total', total) - failed += self.step_status.getStatistic('tests-failed', 0) - self.step_status.setStatistic('tests-failed', failed) - warnings += self.step_status.getStatistic('tests-warnings', 0) - self.step_status.setStatistic('tests-warnings', warnings) - passed += self.step_status.getStatistic('tests-passed', 0) - self.step_status.setStatistic('tests-passed', passed) - - def getText(self, cmd, results): - text = WarningCountingShellCommand.getText(self, cmd, results) - if self.step_status.hasStatistic('tests-total'): - total = self.step_status.getStatistic("tests-total", 0) - failed = self.step_status.getStatistic("tests-failed", 0) - passed = self.step_status.getStatistic("tests-passed", 0) - warnings = self.step_status.getStatistic("tests-warnings", 0) - if not total: - total = failed + passed + warnings - - if total: - text.append('%d tests' % total) - if passed: - text.append('%d passed' % passed) - if warnings: - text.append('%d warnings' % warnings) - if failed: - text.append('%d failed' % failed) - return text - -class PerlModuleTest(Test): - command=["prove", "--lib", "lib", "-r", "t"] - total = 0 - - def evaluateCommand(self, cmd): - lines = self.getLog('stdio').readlines() - - re_test_result = re.compile("^(All tests successful)|(\d+)/(\d+) subtests failed|Files=\d+, Tests=(\d+),") - - mos = map(lambda line: re_test_result.search(line), lines) - test_result_lines = [mo.groups() for mo in mos if mo] - - if not test_result_lines: - return cmd.rc - - test_result_line = test_result_lines[0] - - success = test_result_line[0] - - if success: - failed = 0 - - test_totals_line = test_result_lines[1] - total_str = test_totals_line[3] - - rc = SUCCESS - else: - failed_str = test_result_line[1] - failed = int(failed_str) - - total_str = test_result_line[2] - - rc = FAILURE - - total = int(total_str) - passed = total - failed - - self.setTestResults(total=total, failed=failed, passed=passed) - - return rc diff --git a/tools/buildbot/pylibs/buildbot/steps/source.py b/tools/buildbot/pylibs/buildbot/steps/source.py deleted file mode 100644 index 62a594c..0000000 --- a/tools/buildbot/pylibs/buildbot/steps/source.py +++ /dev/null @@ -1,1074 +0,0 @@ -# -*- test-case-name: buildbot.test.test_vc -*- - -from warnings import warn -from email.Utils import formatdate -from twisted.python import log -from buildbot.process.buildstep import LoggingBuildStep, LoggedRemoteCommand -from buildbot.interfaces import BuildSlaveTooOldError -from buildbot.status.builder import SKIPPED - - -class Source(LoggingBuildStep): - """This is a base class to generate a source tree in the buildslave. - Each version control system has a specialized subclass, and is expected - to override __init__ and implement computeSourceRevision() and - startVC(). The class as a whole builds up the self.args dictionary, then - starts a LoggedRemoteCommand with those arguments. - """ - - # if the checkout fails, there's no point in doing anything else - haltOnFailure = True - notReally = False - - branch = None # the default branch, should be set in __init__ - - def __init__(self, workdir=None, mode='update', alwaysUseLatest=False, - timeout=20*60, retry=None, **kwargs): - """ - @type workdir: string - @param workdir: local directory (relative to the Builder's root) - where the tree should be placed - - @type mode: string - @param mode: the kind of VC operation that is desired: - - 'update': specifies that the checkout/update should be - performed directly into the workdir. Each build is performed - in the same directory, allowing for incremental builds. This - minimizes disk space, bandwidth, and CPU time. However, it - may encounter problems if the build process does not handle - dependencies properly (if you must sometimes do a 'clean - build' to make sure everything gets compiled), or if source - files are deleted but generated files can influence test - behavior (e.g. python's .pyc files), or when source - directories are deleted but generated files prevent CVS from - removing them. - - - 'copy': specifies that the source-controlled workspace - should be maintained in a separate directory (called the - 'copydir'), using checkout or update as necessary. For each - build, a new workdir is created with a copy of the source - tree (rm -rf workdir; cp -R -P -p copydir workdir). This - doubles the disk space required, but keeps the bandwidth low - (update instead of a full checkout). A full 'clean' build - is performed each time. This avoids any generated-file - build problems, but is still occasionally vulnerable to - problems such as a CVS repository being manually rearranged - (causing CVS errors on update) which are not an issue with - a full checkout. - - - 'clobber': specifies that the working directory should be - deleted each time, necessitating a full checkout for each - build. This insures a clean build off a complete checkout, - avoiding any of the problems described above, but is - bandwidth intensive, as the whole source tree must be - pulled down for each build. - - - 'export': is like 'clobber', except that e.g. the 'cvs - export' command is used to create the working directory. - This command removes all VC metadata files (the - CVS/.svn/{arch} directories) from the tree, which is - sometimes useful for creating source tarballs (to avoid - including the metadata in the tar file). Not all VC systems - support export. - - @type alwaysUseLatest: boolean - @param alwaysUseLatest: whether to always update to the most - recent available sources for this build. - - Normally the Source step asks its Build for a list of all - Changes that are supposed to go into the build, then computes a - 'source stamp' (revision number or timestamp) that will cause - exactly that set of changes to be present in the checked out - tree. This is turned into, e.g., 'cvs update -D timestamp', or - 'svn update -r revnum'. If alwaysUseLatest=True, bypass this - computation and always update to the latest available sources - for each build. - - The source stamp helps avoid a race condition in which someone - commits a change after the master has decided to start a build - but before the slave finishes checking out the sources. At best - this results in a build which contains more changes than the - buildmaster thinks it has (possibly resulting in the wrong - person taking the blame for any problems that result), at worst - is can result in an incoherent set of sources (splitting a - non-atomic commit) which may not build at all. - - @type retry: tuple of ints (delay, repeats) (or None) - @param retry: if provided, VC update failures are re-attempted up - to REPEATS times, with DELAY seconds between each - attempt. Some users have slaves with poor connectivity - to their VC repository, and they say that up to 80% of - their build failures are due to transient network - failures that could be handled by simply retrying a - couple times. - - """ - - LoggingBuildStep.__init__(self, **kwargs) - self.addFactoryArguments(workdir=workdir, - mode=mode, - alwaysUseLatest=alwaysUseLatest, - timeout=timeout, - retry=retry, - ) - - assert mode in ("update", "copy", "clobber", "export") - if retry: - delay, repeats = retry - assert isinstance(repeats, int) - assert repeats > 0 - self.args = {'mode': mode, - 'workdir': workdir, - 'timeout': timeout, - 'retry': retry, - 'patch': None, # set during .start - } - self.alwaysUseLatest = alwaysUseLatest - - # Compute defaults for descriptions: - description = ["updating"] - descriptionDone = ["update"] - if mode == "clobber": - description = ["checkout"] - # because checkingouting takes too much space - descriptionDone = ["checkout"] - elif mode == "export": - description = ["exporting"] - descriptionDone = ["export"] - self.description = description - self.descriptionDone = descriptionDone - - def setDefaultWorkdir(self, workdir): - self.args['workdir'] = self.args['workdir'] or workdir - - def describe(self, done=False): - if done: - return self.descriptionDone - return self.description - - def computeSourceRevision(self, changes): - """Each subclass must implement this method to do something more - precise than -rHEAD every time. For version control systems that use - repository-wide change numbers (SVN, P4), this can simply take the - maximum such number from all the changes involved in this build. For - systems that do not (CVS), it needs to create a timestamp based upon - the latest Change, the Build's treeStableTimer, and an optional - self.checkoutDelay value.""" - return None - - def start(self): - if self.notReally: - log.msg("faking %s checkout/update" % self.name) - self.step_status.setColor("green") - self.step_status.setText(["fake", self.name, "successful"]) - self.addCompleteLog("log", - "Faked %s checkout/update 'successful'\n" \ - % self.name) - return SKIPPED - - # what source stamp would this build like to use? - s = self.build.getSourceStamp() - # if branch is None, then use the Step's "default" branch - branch = s.branch or self.branch - # if revision is None, use the latest sources (-rHEAD) - revision = s.revision - if not revision and not self.alwaysUseLatest: - revision = self.computeSourceRevision(s.changes) - # if patch is None, then do not patch the tree after checkout - - # 'patch' is None or a tuple of (patchlevel, diff) - patch = s.patch - if patch: - self.addCompleteLog("patch", patch[1]) - - self.startVC(branch, revision, patch) - - def commandComplete(self, cmd): - got_revision = None - if cmd.updates.has_key("got_revision"): - got_revision = str(cmd.updates["got_revision"][-1]) - self.setProperty("got_revision", got_revision, "Source") - - - -class CVS(Source): - """I do CVS checkout/update operations. - - Note: if you are doing anonymous/pserver CVS operations, you will need - to manually do a 'cvs login' on each buildslave before the slave has any - hope of success. XXX: fix then, take a cvs password as an argument and - figure out how to do a 'cvs login' on each build - """ - - name = "cvs" - - #progressMetrics = ('output',) - # - # additional things to track: update gives one stderr line per directory - # (starting with 'cvs server: Updating ') (and is fairly stable if files - # is empty), export gives one line per directory (starting with 'cvs - # export: Updating ') and another line per file (starting with U). Would - # be nice to track these, requires grepping LogFile data for lines, - # parsing each line. Might be handy to have a hook in LogFile that gets - # called with each complete line. - - def __init__(self, cvsroot, cvsmodule, - global_options=[], branch=None, checkoutDelay=None, - login=None, - **kwargs): - - """ - @type cvsroot: string - @param cvsroot: CVS Repository from which the source tree should - be obtained. '/home/warner/Repository' for local - or NFS-reachable repositories, - ':pserver:anon@foo.com:/cvs' for anonymous CVS, - 'user@host.com:/cvs' for non-anonymous CVS or - CVS over ssh. Lots of possibilities, check the - CVS documentation for more. - - @type cvsmodule: string - @param cvsmodule: subdirectory of CVS repository that should be - retrieved - - @type login: string or None - @param login: if not None, a string which will be provided as a - password to the 'cvs login' command, used when a - :pserver: method is used to access the repository. - This login is only needed once, but must be run - each time (just before the CVS operation) because - there is no way for the buildslave to tell whether - it was previously performed or not. - - @type branch: string - @param branch: the default branch name, will be used in a '-r' - argument to specify which branch of the source tree - should be used for this checkout. Defaults to None, - which means to use 'HEAD'. - - @type checkoutDelay: int or None - @param checkoutDelay: if not None, the number of seconds to put - between the last known Change and the - timestamp given to the -D argument. This - defaults to exactly half of the parent - Build's .treeStableTimer, but it could be - set to something else if your CVS change - notification has particularly weird - latency characteristics. - - @type global_options: list of strings - @param global_options: these arguments are inserted in the cvs - command line, before the - 'checkout'/'update' command word. See - 'cvs --help-options' for a list of what - may be accepted here. ['-r'] will make - the checked out files read only. ['-r', - '-R'] will also assume the repository is - read-only (I assume this means it won't - use locks to insure atomic access to the - ,v files).""" - - self.checkoutDelay = checkoutDelay - self.branch = branch - - Source.__init__(self, **kwargs) - self.addFactoryArguments(cvsroot=cvsroot, - cvsmodule=cvsmodule, - global_options=global_options, - branch=branch, - checkoutDelay=checkoutDelay, - login=login, - ) - - self.args.update({'cvsroot': cvsroot, - 'cvsmodule': cvsmodule, - 'global_options': global_options, - 'login': login, - }) - - def computeSourceRevision(self, changes): - if not changes: - return None - lastChange = max([c.when for c in changes]) - if self.checkoutDelay is not None: - when = lastChange + self.checkoutDelay - else: - lastSubmit = max([r.submittedAt for r in self.build.requests]) - when = (lastChange + lastSubmit) / 2 - return formatdate(when) - - def startVC(self, branch, revision, patch): - if self.slaveVersionIsOlderThan("cvs", "1.39"): - # the slave doesn't know to avoid re-using the same sourcedir - # when the branch changes. We have no way of knowing which branch - # the last build used, so if we're using a non-default branch and - # either 'update' or 'copy' modes, it is safer to refuse to - # build, and tell the user they need to upgrade the buildslave. - if (branch != self.branch - and self.args['mode'] in ("update", "copy")): - m = ("This buildslave (%s) does not know about multiple " - "branches, and using mode=%s would probably build the " - "wrong tree. " - "Refusing to build. Please upgrade the buildslave to " - "buildbot-0.7.0 or newer." % (self.build.slavename, - self.args['mode'])) - log.msg(m) - raise BuildSlaveTooOldError(m) - - if branch is None: - branch = "HEAD" - self.args['branch'] = branch - self.args['revision'] = revision - self.args['patch'] = patch - - if self.args['branch'] == "HEAD" and self.args['revision']: - # special case. 'cvs update -r HEAD -D today' gives no files - # TODO: figure out why, see if it applies to -r BRANCH - self.args['branch'] = None - - # deal with old slaves - warnings = [] - slavever = self.slaveVersion("cvs", "old") - - if slavever == "old": - # 0.5.0 - if self.args['mode'] == "export": - self.args['export'] = 1 - elif self.args['mode'] == "clobber": - self.args['clobber'] = 1 - elif self.args['mode'] == "copy": - self.args['copydir'] = "source" - self.args['tag'] = self.args['branch'] - assert not self.args['patch'] # 0.5.0 slave can't do patch - - cmd = LoggedRemoteCommand("cvs", self.args) - self.startCommand(cmd, warnings) - - -class SVN(Source): - """I perform Subversion checkout/update operations.""" - - name = 'svn' - - def __init__(self, svnurl=None, baseURL=None, defaultBranch=None, - directory=None, **kwargs): - """ - @type svnurl: string - @param svnurl: the URL which points to the Subversion server, - combining the access method (HTTP, ssh, local file), - the repository host/port, the repository path, the - sub-tree within the repository, and the branch to - check out. Using C{svnurl} does not enable builds of - alternate branches: use C{baseURL} to enable this. - Use exactly one of C{svnurl} and C{baseURL}. - - @param baseURL: if branches are enabled, this is the base URL to - which a branch name will be appended. It should - probably end in a slash. Use exactly one of - C{svnurl} and C{baseURL}. - - @param defaultBranch: if branches are enabled, this is the branch - to use if the Build does not specify one - explicitly. It will simply be appended - to C{baseURL} and the result handed to - the SVN command. - """ - - if not kwargs.has_key('workdir') and directory is not None: - # deal with old configs - warn("Please use workdir=, not directory=", DeprecationWarning) - kwargs['workdir'] = directory - - self.svnurl = svnurl - self.baseURL = baseURL - self.branch = defaultBranch - - Source.__init__(self, **kwargs) - self.addFactoryArguments(svnurl=svnurl, - baseURL=baseURL, - defaultBranch=defaultBranch, - directory=directory, - ) - - if not svnurl and not baseURL: - raise ValueError("you must use exactly one of svnurl and baseURL") - - - def computeSourceRevision(self, changes): - if not changes: - return None - lastChange = max([int(c.revision) for c in changes]) - return lastChange - - def startVC(self, branch, revision, patch): - - # handle old slaves - warnings = [] - slavever = self.slaveVersion("svn", "old") - if not slavever: - m = "slave does not have the 'svn' command" - raise BuildSlaveTooOldError(m) - - if self.slaveVersionIsOlderThan("svn", "1.39"): - # the slave doesn't know to avoid re-using the same sourcedir - # when the branch changes. We have no way of knowing which branch - # the last build used, so if we're using a non-default branch and - # either 'update' or 'copy' modes, it is safer to refuse to - # build, and tell the user they need to upgrade the buildslave. - if (branch != self.branch - and self.args['mode'] in ("update", "copy")): - m = ("This buildslave (%s) does not know about multiple " - "branches, and using mode=%s would probably build the " - "wrong tree. " - "Refusing to build. Please upgrade the buildslave to " - "buildbot-0.7.0 or newer." % (self.build.slavename, - self.args['mode'])) - raise BuildSlaveTooOldError(m) - - if slavever == "old": - # 0.5.0 compatibility - if self.args['mode'] in ("clobber", "copy"): - # TODO: use some shell commands to make up for the - # deficiency, by blowing away the old directory first (thus - # forcing a full checkout) - warnings.append("WARNING: this slave can only do SVN updates" - ", not mode=%s\n" % self.args['mode']) - log.msg("WARNING: this slave only does mode=update") - if self.args['mode'] == "export": - raise BuildSlaveTooOldError("old slave does not have " - "mode=export") - self.args['directory'] = self.args['workdir'] - if revision is not None: - # 0.5.0 can only do HEAD. We have no way of knowing whether - # the requested revision is HEAD or not, and for - # slowly-changing trees this will probably do the right - # thing, so let it pass with a warning - m = ("WARNING: old slave can only update to HEAD, not " - "revision=%s" % revision) - log.msg(m) - warnings.append(m + "\n") - revision = "HEAD" # interprets this key differently - if patch: - raise BuildSlaveTooOldError("old slave can't do patch") - - if self.svnurl: - assert not branch # we need baseURL= to use branches - self.args['svnurl'] = self.svnurl - else: - self.args['svnurl'] = self.baseURL + branch - self.args['revision'] = revision - self.args['patch'] = patch - - revstuff = [] - if branch is not None and branch != self.branch: - revstuff.append("[branch]") - if revision is not None: - revstuff.append("r%s" % revision) - if patch is not None: - revstuff.append("[patch]") - self.description.extend(revstuff) - self.descriptionDone.extend(revstuff) - - cmd = LoggedRemoteCommand("svn", self.args) - self.startCommand(cmd, warnings) - - -class Darcs(Source): - """Check out a source tree from a Darcs repository at 'repourl'. - - To the best of my knowledge, Darcs has no concept of file modes. This - means the eXecute-bit will be cleared on all source files. As a result, - you may need to invoke configuration scripts with something like: - - C{s(step.Configure, command=['/bin/sh', './configure'])} - """ - - name = "darcs" - - def __init__(self, repourl=None, baseURL=None, defaultBranch=None, - **kwargs): - """ - @type repourl: string - @param repourl: the URL which points at the Darcs repository. This - is used as the default branch. Using C{repourl} does - not enable builds of alternate branches: use - C{baseURL} to enable this. Use either C{repourl} or - C{baseURL}, not both. - - @param baseURL: if branches are enabled, this is the base URL to - which a branch name will be appended. It should - probably end in a slash. Use exactly one of - C{repourl} and C{baseURL}. - - @param defaultBranch: if branches are enabled, this is the branch - to use if the Build does not specify one - explicitly. It will simply be appended to - C{baseURL} and the result handed to the - 'darcs pull' command. - """ - self.repourl = repourl - self.baseURL = baseURL - self.branch = defaultBranch - Source.__init__(self, **kwargs) - self.addFactoryArguments(repourl=repourl, - baseURL=baseURL, - defaultBranch=defaultBranch, - ) - assert self.args['mode'] != "export", \ - "Darcs does not have an 'export' mode" - if (not repourl and not baseURL) or (repourl and baseURL): - raise ValueError("you must provide exactly one of repourl and" - " baseURL") - - def startVC(self, branch, revision, patch): - slavever = self.slaveVersion("darcs") - if not slavever: - m = "slave is too old, does not know about darcs" - raise BuildSlaveTooOldError(m) - - if self.slaveVersionIsOlderThan("darcs", "1.39"): - if revision: - # TODO: revisit this once we implement computeSourceRevision - m = "0.6.6 slaves can't handle args['revision']" - raise BuildSlaveTooOldError(m) - - # the slave doesn't know to avoid re-using the same sourcedir - # when the branch changes. We have no way of knowing which branch - # the last build used, so if we're using a non-default branch and - # either 'update' or 'copy' modes, it is safer to refuse to - # build, and tell the user they need to upgrade the buildslave. - if (branch != self.branch - and self.args['mode'] in ("update", "copy")): - m = ("This buildslave (%s) does not know about multiple " - "branches, and using mode=%s would probably build the " - "wrong tree. " - "Refusing to build. Please upgrade the buildslave to " - "buildbot-0.7.0 or newer." % (self.build.slavename, - self.args['mode'])) - raise BuildSlaveTooOldError(m) - - if self.repourl: - assert not branch # we need baseURL= to use branches - self.args['repourl'] = self.repourl - else: - self.args['repourl'] = self.baseURL + branch - self.args['revision'] = revision - self.args['patch'] = patch - - revstuff = [] - if branch is not None and branch != self.branch: - revstuff.append("[branch]") - self.description.extend(revstuff) - self.descriptionDone.extend(revstuff) - - cmd = LoggedRemoteCommand("darcs", self.args) - self.startCommand(cmd) - - -class Git(Source): - """Check out a source tree from a git repository 'repourl'.""" - - name = "git" - - def __init__(self, repourl, branch="master", **kwargs): - """ - @type repourl: string - @param repourl: the URL which points at the git repository - - @type branch: string - @param branch: The branch or tag to check out by default. If - a build specifies a different branch, it will - be used instead of this. - """ - Source.__init__(self, **kwargs) - self.addFactoryArguments(repourl=repourl, branch=branch) - self.args.update({'repourl': repourl, - 'branch': branch}) - - def computeSourceRevision(self, changes): - if not changes: - return None - return changes[-1].revision - - def startVC(self, branch, revision, patch): - self.args['branch'] = branch - self.args['revision'] = revision - self.args['patch'] = patch - slavever = self.slaveVersion("git") - if not slavever: - raise BuildSlaveTooOldError("slave is too old, does not know " - "about git") - cmd = LoggedRemoteCommand("git", self.args) - self.startCommand(cmd) - - -class Arch(Source): - """Check out a source tree from an Arch repository named 'archive' - available at 'url'. 'version' specifies which version number (development - line) will be used for the checkout: this is mostly equivalent to a - branch name. This version uses the 'tla' tool to do the checkout, to use - 'baz' see L{Bazaar} instead. - """ - - name = "arch" - # TODO: slaves >0.6.6 will accept args['build-config'], so use it - - def __init__(self, url, version, archive=None, **kwargs): - """ - @type url: string - @param url: the Arch coordinates of the repository. This is - typically an http:// URL, but could also be the absolute - pathname of a local directory instead. - - @type version: string - @param version: the category--branch--version to check out. This is - the default branch. If a build specifies a different - branch, it will be used instead of this. - - @type archive: string - @param archive: The archive name. If provided, it must match the one - that comes from the repository. If not, the - repository's default will be used. - """ - self.branch = version - Source.__init__(self, **kwargs) - self.addFactoryArguments(url=url, - version=version, - archive=archive, - ) - self.args.update({'url': url, - 'archive': archive, - }) - - def computeSourceRevision(self, changes): - # in Arch, fully-qualified revision numbers look like: - # arch@buildbot.sourceforge.net--2004/buildbot--dev--0--patch-104 - # For any given builder, all of this is fixed except the patch-104. - # The Change might have any part of the fully-qualified string, so we - # just look for the last part. We return the "patch-NN" string. - if not changes: - return None - lastChange = None - for c in changes: - if not c.revision: - continue - if c.revision.endswith("--base-0"): - rev = 0 - else: - i = c.revision.rindex("patch") - rev = int(c.revision[i+len("patch-"):]) - lastChange = max(lastChange, rev) - if lastChange is None: - return None - if lastChange == 0: - return "base-0" - return "patch-%d" % lastChange - - def checkSlaveVersion(self, cmd, branch): - warnings = [] - slavever = self.slaveVersion(cmd) - if not slavever: - m = "slave is too old, does not know about %s" % cmd - raise BuildSlaveTooOldError(m) - - # slave 1.28 and later understand 'revision' - if self.slaveVersionIsOlderThan(cmd, "1.28"): - if not self.alwaysUseLatest: - # we don't know whether our requested revision is the latest - # or not. If the tree does not change very quickly, this will - # probably build the right thing, so emit a warning rather - # than refuse to build at all - m = "WARNING, buildslave is too old to use a revision" - log.msg(m) - warnings.append(m + "\n") - - if self.slaveVersionIsOlderThan(cmd, "1.39"): - # the slave doesn't know to avoid re-using the same sourcedir - # when the branch changes. We have no way of knowing which branch - # the last build used, so if we're using a non-default branch and - # either 'update' or 'copy' modes, it is safer to refuse to - # build, and tell the user they need to upgrade the buildslave. - if (branch != self.branch - and self.args['mode'] in ("update", "copy")): - m = ("This buildslave (%s) does not know about multiple " - "branches, and using mode=%s would probably build the " - "wrong tree. " - "Refusing to build. Please upgrade the buildslave to " - "buildbot-0.7.0 or newer." % (self.build.slavename, - self.args['mode'])) - log.msg(m) - raise BuildSlaveTooOldError(m) - - return warnings - - def startVC(self, branch, revision, patch): - self.args['version'] = branch - self.args['revision'] = revision - self.args['patch'] = patch - warnings = self.checkSlaveVersion("arch", branch) - - revstuff = [] - if branch is not None and branch != self.branch: - revstuff.append("[branch]") - if revision is not None: - revstuff.append("patch%s" % revision) - self.description.extend(revstuff) - self.descriptionDone.extend(revstuff) - - cmd = LoggedRemoteCommand("arch", self.args) - self.startCommand(cmd, warnings) - - -class Bazaar(Arch): - """Bazaar is an alternative client for Arch repositories. baz is mostly - compatible with tla, but archive registration is slightly different.""" - - # TODO: slaves >0.6.6 will accept args['build-config'], so use it - - def __init__(self, url, version, archive, **kwargs): - """ - @type url: string - @param url: the Arch coordinates of the repository. This is - typically an http:// URL, but could also be the absolute - pathname of a local directory instead. - - @type version: string - @param version: the category--branch--version to check out - - @type archive: string - @param archive: The archive name (required). This must always match - the one that comes from the repository, otherwise the - buildslave will attempt to get sources from the wrong - archive. - """ - self.branch = version - Source.__init__(self, **kwargs) - self.addFactoryArguments(url=url, - version=version, - archive=archive, - ) - self.args.update({'url': url, - 'archive': archive, - }) - - def startVC(self, branch, revision, patch): - self.args['version'] = branch - self.args['revision'] = revision - self.args['patch'] = patch - warnings = self.checkSlaveVersion("bazaar", branch) - - revstuff = [] - if branch is not None and branch != self.branch: - revstuff.append("[branch]") - if revision is not None: - revstuff.append("patch%s" % revision) - self.description.extend(revstuff) - self.descriptionDone.extend(revstuff) - - cmd = LoggedRemoteCommand("bazaar", self.args) - self.startCommand(cmd, warnings) - -class Bzr(Source): - """Check out a source tree from a bzr (Bazaar) repository at 'repourl'. - - """ - - name = "bzr" - - def __init__(self, repourl=None, baseURL=None, defaultBranch=None, - **kwargs): - """ - @type repourl: string - @param repourl: the URL which points at the bzr repository. This - is used as the default branch. Using C{repourl} does - not enable builds of alternate branches: use - C{baseURL} to enable this. Use either C{repourl} or - C{baseURL}, not both. - - @param baseURL: if branches are enabled, this is the base URL to - which a branch name will be appended. It should - probably end in a slash. Use exactly one of - C{repourl} and C{baseURL}. - - @param defaultBranch: if branches are enabled, this is the branch - to use if the Build does not specify one - explicitly. It will simply be appended to - C{baseURL} and the result handed to the - 'bzr checkout pull' command. - """ - self.repourl = repourl - self.baseURL = baseURL - self.branch = defaultBranch - Source.__init__(self, **kwargs) - self.addFactoryArguments(repourl=repourl, - baseURL=baseURL, - defaultBranch=defaultBranch, - ) - if (not repourl and not baseURL) or (repourl and baseURL): - raise ValueError("you must provide exactly one of repourl and" - " baseURL") - - def computeSourceRevision(self, changes): - if not changes: - return None - lastChange = max([int(c.revision) for c in changes]) - return lastChange - - def startVC(self, branch, revision, patch): - slavever = self.slaveVersion("bzr") - if not slavever: - m = "slave is too old, does not know about bzr" - raise BuildSlaveTooOldError(m) - - if self.repourl: - assert not branch # we need baseURL= to use branches - self.args['repourl'] = self.repourl - else: - self.args['repourl'] = self.baseURL + branch - self.args['revision'] = revision - self.args['patch'] = patch - - revstuff = [] - if branch is not None and branch != self.branch: - revstuff.append("[branch]") - self.description.extend(revstuff) - self.descriptionDone.extend(revstuff) - - cmd = LoggedRemoteCommand("bzr", self.args) - self.startCommand(cmd) - - -class Mercurial(Source): - """Check out a source tree from a mercurial repository 'repourl'.""" - - name = "hg" - - def __init__(self, repourl=None, baseURL=None, defaultBranch=None, - **kwargs): - """ - @type repourl: string - @param repourl: the URL which points at the Mercurial repository. - This is used as the default branch. Using C{repourl} - does not enable builds of alternate branches: use - C{baseURL} to enable this. Use either C{repourl} or - C{baseURL}, not both. - - @param baseURL: if branches are enabled, this is the base URL to - which a branch name will be appended. It should - probably end in a slash. Use exactly one of - C{repourl} and C{baseURL}. - - @param defaultBranch: if branches are enabled, this is the branch - to use if the Build does not specify one - explicitly. It will simply be appended to - C{baseURL} and the result handed to the - 'hg clone' command. - """ - self.repourl = repourl - self.baseURL = baseURL - self.branch = defaultBranch - Source.__init__(self, **kwargs) - self.addFactoryArguments(repourl=repourl, - baseURL=baseURL, - defaultBranch=defaultBranch, - ) - if (not repourl and not baseURL) or (repourl and baseURL): - raise ValueError("you must provide exactly one of repourl and" - " baseURL") - - def startVC(self, branch, revision, patch): - slavever = self.slaveVersion("hg") - if not slavever: - raise BuildSlaveTooOldError("slave is too old, does not know " - "about hg") - - if self.repourl: - assert not branch # we need baseURL= to use branches - self.args['repourl'] = self.repourl - else: - self.args['repourl'] = self.baseURL + branch - self.args['revision'] = revision - self.args['patch'] = patch - - revstuff = [] - if branch is not None and branch != self.branch: - revstuff.append("[branch]") - self.description.extend(revstuff) - self.descriptionDone.extend(revstuff) - - cmd = LoggedRemoteCommand("hg", self.args) - self.startCommand(cmd) - - def computeSourceRevision(self, changes): - if not changes: - return None - # without knowing the revision ancestry graph, we can't sort the - # changes at all. So for now, assume they were given to us in sorted - # order, and just pay attention to the last one. See ticket #103 for - # more details. - if len(changes) > 1: - log.msg("Mercurial.computeSourceRevision: warning: " - "there are %d changes here, assuming the last one is " - "the most recent" % len(changes)) - return changes[-1].revision - - -class P4(Source): - """ P4 is a class for accessing perforce revision control""" - name = "p4" - - def __init__(self, p4base, defaultBranch=None, p4port=None, p4user=None, - p4passwd=None, p4extra_views=[], - p4client='buildbot_%(slave)s_%(builder)s', **kwargs): - """ - @type p4base: string - @param p4base: A view into a perforce depot, typically - "//depot/proj/" - - @type defaultBranch: string - @param defaultBranch: Identify a branch to build by default. Perforce - is a view based branching system. So, the branch - is normally the name after the base. For example, - branch=1.0 is view=//depot/proj/1.0/... - branch=1.1 is view=//depot/proj/1.1/... - - @type p4port: string - @param p4port: Specify the perforce server to connection in the format - :. Example "perforce.example.com:1666" - - @type p4user: string - @param p4user: The perforce user to run the command as. - - @type p4passwd: string - @param p4passwd: The password for the perforce user. - - @type p4extra_views: list of tuples - @param p4extra_views: Extra views to be added to - the client that is being used. - - @type p4client: string - @param p4client: The perforce client to use for this buildslave. - """ - - self.branch = defaultBranch - Source.__init__(self, **kwargs) - self.addFactoryArguments(p4base=p4base, - defaultBranch=defaultBranch, - p4port=p4port, - p4user=p4user, - p4passwd=p4passwd, - p4extra_views=p4extra_views, - p4client=p4client, - ) - self.args['p4port'] = p4port - self.args['p4user'] = p4user - self.args['p4passwd'] = p4passwd - self.args['p4base'] = p4base - self.args['p4extra_views'] = p4extra_views - self.p4client = p4client - - def setBuild(self, build): - Source.setBuild(self, build) - self.args['p4client'] = self.p4client % { - 'slave': build.slavename, - 'builder': build.builder.name, - } - - def computeSourceRevision(self, changes): - if not changes: - return None - lastChange = max([int(c.revision) for c in changes]) - return lastChange - - def startVC(self, branch, revision, patch): - slavever = self.slaveVersion("p4") - assert slavever, "slave is too old, does not know about p4" - args = dict(self.args) - args['branch'] = branch or self.branch - args['revision'] = revision - args['patch'] = patch - cmd = LoggedRemoteCommand("p4", args) - self.startCommand(cmd) - -class P4Sync(Source): - """This is a partial solution for using a P4 source repository. You are - required to manually set up each build slave with a useful P4 - environment, which means setting various per-slave environment variables, - and creating a P4 client specification which maps the right files into - the slave's working directory. Once you have done that, this step merely - performs a 'p4 sync' to update that workspace with the newest files. - - Each slave needs the following environment: - - - PATH: the 'p4' binary must be on the slave's PATH - - P4USER: each slave needs a distinct user account - - P4CLIENT: each slave needs a distinct client specification - - You should use 'p4 client' (?) to set up a client view spec which maps - the desired files into $SLAVEBASE/$BUILDERBASE/source . - """ - - name = "p4sync" - - def __init__(self, p4port, p4user, p4passwd, p4client, **kwargs): - assert kwargs['mode'] == "copy", "P4Sync can only be used in mode=copy" - self.branch = None - Source.__init__(self, **kwargs) - self.addFactoryArguments(p4port=p4port, - p4user=p4user, - p4passwd=p4passwd, - p4client=p4client, - ) - self.args['p4port'] = p4port - self.args['p4user'] = p4user - self.args['p4passwd'] = p4passwd - self.args['p4client'] = p4client - - def computeSourceRevision(self, changes): - if not changes: - return None - lastChange = max([int(c.revision) for c in changes]) - return lastChange - - def startVC(self, branch, revision, patch): - slavever = self.slaveVersion("p4sync") - assert slavever, "slave is too old, does not know about p4" - cmd = LoggedRemoteCommand("p4sync", self.args) - self.startCommand(cmd) - -class Monotone(Source): - """Check out a revision from a monotone server at 'server_addr', - branch 'branch'. 'revision' specifies which revision id to check - out. - - This step will first create a local database, if necessary, and then pull - the contents of the server into the database. Then it will do the - checkout/update from this database.""" - - name = "monotone" - - def __init__(self, server_addr, branch, db_path="monotone.db", - monotone="monotone", - **kwargs): - Source.__init__(self, **kwargs) - self.addFactoryArguments(server_addr=server_addr, - branch=branch, - db_path=db_path, - monotone=monotone, - ) - self.args.update({"server_addr": server_addr, - "branch": branch, - "db_path": db_path, - "monotone": monotone}) - - def computeSourceRevision(self, changes): - if not changes: - return None - return changes[-1].revision - - def startVC(self): - slavever = self.slaveVersion("monotone") - assert slavever, "slave is too old, does not know about monotone" - cmd = LoggedRemoteCommand("monotone", self.args) - self.startCommand(cmd) - diff --git a/tools/buildbot/pylibs/buildbot/steps/transfer.py b/tools/buildbot/pylibs/buildbot/steps/transfer.py deleted file mode 100644 index 67da277..0000000 --- a/tools/buildbot/pylibs/buildbot/steps/transfer.py +++ /dev/null @@ -1,295 +0,0 @@ -# -*- test-case-name: buildbot.test.test_transfer -*- - -import os.path -from twisted.internet import reactor -from twisted.spread import pb -from twisted.python import log -from buildbot.process.buildstep import RemoteCommand, BuildStep -from buildbot.process.buildstep import SUCCESS, FAILURE -from buildbot.interfaces import BuildSlaveTooOldError - - -class _FileWriter(pb.Referenceable): - """ - Helper class that acts as a file-object with write access - """ - - def __init__(self, destfile, maxsize, mode): - self.destfile = destfile - self.fp = open(destfile, "wb") - if mode is not None: - os.chmod(destfile, mode) - self.remaining = maxsize - - def remote_write(self, data): - """ - Called from remote slave to write L{data} to L{fp} within boundaries - of L{maxsize} - - @type data: C{string} - @param data: String of data to write - """ - if self.remaining is not None: - if len(data) > self.remaining: - data = data[:self.remaining] - self.fp.write(data) - self.remaining = self.remaining - len(data) - else: - self.fp.write(data) - - def remote_close(self): - """ - Called by remote slave to state that no more data will be transfered - """ - self.fp.close() - self.fp = None - - def __del__(self): - # unclean shutdown, the file is probably truncated, so delete it - # altogether rather than deliver a corrupted file - fp = getattr(self, "fp", None) - if fp: - fp.close() - os.unlink(self.destfile) - - -class StatusRemoteCommand(RemoteCommand): - def __init__(self, remote_command, args): - RemoteCommand.__init__(self, remote_command, args) - - self.rc = None - self.stderr = '' - - def remoteUpdate(self, update): - #log.msg('StatusRemoteCommand: update=%r' % update) - if 'rc' in update: - self.rc = update['rc'] - if 'stderr' in update: - self.stderr = self.stderr + update['stderr'] + '\n' - - -class FileUpload(BuildStep): - """ - Build step to transfer a file from the slave to the master. - - arguments: - - - ['slavesrc'] filename of source file at slave, relative to workdir - - ['masterdest'] filename of destination file at master - - ['workdir'] string with slave working directory relative to builder - base dir, default 'build' - - ['maxsize'] maximum size of the file, default None (=unlimited) - - ['blocksize'] maximum size of each block being transfered - - ['mode'] file access mode for the resulting master-side file. - The default (=None) is to leave it up to the umask of - the buildmaster process. - - """ - - name = 'upload' - - def __init__(self, slavesrc, masterdest, - workdir="build", maxsize=None, blocksize=16*1024, mode=None, - **buildstep_kwargs): - BuildStep.__init__(self, **buildstep_kwargs) - self.addFactoryArguments(slavesrc=slavesrc, - masterdest=masterdest, - workdir=workdir, - maxsize=maxsize, - blocksize=blocksize, - mode=mode, - ) - - self.slavesrc = slavesrc - self.masterdest = masterdest - self.workdir = workdir - self.maxsize = maxsize - self.blocksize = blocksize - assert isinstance(mode, (int, type(None))) - self.mode = mode - - def start(self): - version = self.slaveVersion("uploadFile") - properties = self.build.getProperties() - - if not version: - m = "slave is too old, does not know about uploadFile" - raise BuildSlaveTooOldError(m) - - source = properties.render(self.slavesrc) - masterdest = properties.render(self.masterdest) - # we rely upon the fact that the buildmaster runs chdir'ed into its - # basedir to make sure that relative paths in masterdest are expanded - # properly. TODO: maybe pass the master's basedir all the way down - # into the BuildStep so we can do this better. - masterdest = os.path.expanduser(masterdest) - log.msg("FileUpload started, from slave %r to master %r" - % (source, masterdest)) - - self.step_status.setColor('yellow') - self.step_status.setText(['uploading', os.path.basename(source)]) - - # we use maxsize to limit the amount of data on both sides - fileWriter = _FileWriter(masterdest, self.maxsize, self.mode) - - # default arguments - args = { - 'slavesrc': source, - 'workdir': self.workdir, - 'writer': fileWriter, - 'maxsize': self.maxsize, - 'blocksize': self.blocksize, - } - - self.cmd = StatusRemoteCommand('uploadFile', args) - d = self.runCommand(self.cmd) - d.addCallback(self.finished).addErrback(self.failed) - - def finished(self, result): - if self.cmd.stderr != '': - self.addCompleteLog('stderr', self.cmd.stderr) - - if self.cmd.rc is None or self.cmd.rc == 0: - self.step_status.setColor('green') - return BuildStep.finished(self, SUCCESS) - self.step_status.setColor('red') - return BuildStep.finished(self, FAILURE) - - - - - -class _FileReader(pb.Referenceable): - """ - Helper class that acts as a file-object with read access - """ - - def __init__(self, fp): - self.fp = fp - - def remote_read(self, maxlength): - """ - Called from remote slave to read at most L{maxlength} bytes of data - - @type maxlength: C{integer} - @param maxlength: Maximum number of data bytes that can be returned - - @return: Data read from L{fp} - @rtype: C{string} of bytes read from file - """ - if self.fp is None: - return '' - - data = self.fp.read(maxlength) - return data - - def remote_close(self): - """ - Called by remote slave to state that no more data will be transfered - """ - if self.fp is not None: - self.fp.close() - self.fp = None - - -class FileDownload(BuildStep): - """ - Download the first 'maxsize' bytes of a file, from the buildmaster to the - buildslave. Set the mode of the file - - Arguments:: - - ['mastersrc'] filename of source file at master - ['slavedest'] filename of destination file at slave - ['workdir'] string with slave working directory relative to builder - base dir, default 'build' - ['maxsize'] maximum size of the file, default None (=unlimited) - ['blocksize'] maximum size of each block being transfered - ['mode'] use this to set the access permissions of the resulting - buildslave-side file. This is traditionally an octal - integer, like 0644 to be world-readable (but not - world-writable), or 0600 to only be readable by - the buildslave account, or 0755 to be world-executable. - The default (=None) is to leave it up to the umask of - the buildslave process. - - """ - - name = 'download' - - def __init__(self, mastersrc, slavedest, - workdir="build", maxsize=None, blocksize=16*1024, mode=None, - **buildstep_kwargs): - BuildStep.__init__(self, **buildstep_kwargs) - self.addFactoryArguments(mastersrc=mastersrc, - slavedest=slavedest, - workdir=workdir, - maxsize=maxsize, - blocksize=blocksize, - mode=mode, - ) - - self.mastersrc = mastersrc - self.slavedest = slavedest - self.workdir = workdir - self.maxsize = maxsize - self.blocksize = blocksize - assert isinstance(mode, (int, type(None))) - self.mode = mode - - def start(self): - properties = self.build.getProperties() - - version = self.slaveVersion("downloadFile") - if not version: - m = "slave is too old, does not know about downloadFile" - raise BuildSlaveTooOldError(m) - - # we are currently in the buildmaster's basedir, so any non-absolute - # paths will be interpreted relative to that - source = os.path.expanduser(properties.render(self.mastersrc)) - slavedest = properties.render(self.slavedest) - log.msg("FileDownload started, from master %r to slave %r" % - (source, slavedest)) - - self.step_status.setColor('yellow') - self.step_status.setText(['downloading', "to", - os.path.basename(slavedest)]) - - # setup structures for reading the file - try: - fp = open(source, 'rb') - except IOError: - # if file does not exist, bail out with an error - self.addCompleteLog('stderr', - 'File %r not available at master' % source) - # TODO: once BuildStep.start() gets rewritten to use - # maybeDeferred, just re-raise the exception here. - reactor.callLater(0, BuildStep.finished, self, FAILURE) - return - fileReader = _FileReader(fp) - - # default arguments - args = { - 'slavedest': slavedest, - 'maxsize': self.maxsize, - 'reader': fileReader, - 'blocksize': self.blocksize, - 'workdir': self.workdir, - 'mode': self.mode, - } - - self.cmd = StatusRemoteCommand('downloadFile', args) - d = self.runCommand(self.cmd) - d.addCallback(self.finished).addErrback(self.failed) - - def finished(self, result): - if self.cmd.stderr != '': - self.addCompleteLog('stderr', self.cmd.stderr) - - if self.cmd.rc is None or self.cmd.rc == 0: - self.step_status.setColor('green') - return BuildStep.finished(self, SUCCESS) - self.step_status.setColor('red') - return BuildStep.finished(self, FAILURE) - diff --git a/tools/buildbot/pylibs/buildbot/steps/trigger.py b/tools/buildbot/pylibs/buildbot/steps/trigger.py deleted file mode 100644 index 8bb987a..0000000 --- a/tools/buildbot/pylibs/buildbot/steps/trigger.py +++ /dev/null @@ -1,127 +0,0 @@ -from buildbot.process.buildstep import LoggingBuildStep, SUCCESS, FAILURE, EXCEPTION -from buildbot.process.properties import Properties -from buildbot.scheduler import Triggerable -from twisted.internet import defer - -class Trigger(LoggingBuildStep): - """I trigger a scheduler.Triggerable, to use one or more Builders as if - they were a single buildstep (like a subroutine call). - """ - name = "trigger" - - flunkOnFailure = True - - def __init__(self, schedulerNames=[], updateSourceStamp=True, - waitForFinish=False, set_properties={}, **kwargs): - """ - Trigger the given schedulers when this step is executed. - - @param schedulerNames: A list of scheduler names that should be - triggered. Schedulers can be specified using - WithProperties, if desired. - - @param updateSourceStamp: If True (the default), I will try to give - the schedulers an absolute SourceStamp for - their builds, so that a HEAD build will use - the same revision even if more changes have - occurred since my build's update step was - run. If False, I will use the original - SourceStamp unmodified. - - @param waitForFinish: If False (the default), this step will finish - as soon as I've started the triggered - schedulers. If True, I will wait until all of - the triggered schedulers have finished their - builds. - - @param set_properties: A dictionary of properties to set for any - builds resulting from this trigger. To copy - existing properties, use WithProperties. These - properties will override properties set in the - Triggered scheduler's constructor. - - """ - assert schedulerNames, "You must specify a scheduler to trigger" - self.schedulerNames = schedulerNames - self.updateSourceStamp = updateSourceStamp - self.waitForFinish = waitForFinish - self.set_properties = set_properties - self.running = False - LoggingBuildStep.__init__(self, **kwargs) - self.addFactoryArguments(schedulerNames=schedulerNames, - updateSourceStamp=updateSourceStamp, - waitForFinish=waitForFinish) - - def interrupt(self, reason): - # TODO: this doesn't actually do anything. - if self.running: - self.step_status.setColor("red") - self.step_status.setText(["interrupted"]) - - def start(self): - properties = self.build.getProperties() - - # make a new properties object from a dict rendered by the old - # properties object - props_to_set = Properties() - props_to_set.update(properties.render(self.set_properties), "Trigger") - - self.running = True - ss = self.build.getSourceStamp() - if self.updateSourceStamp: - got = properties.getProperty('got_revision') - if got: - ss = ss.getAbsoluteSourceStamp(got) - - # (is there an easier way to find the BuildMaster?) - all_schedulers = self.build.builder.botmaster.parent.allSchedulers() - all_schedulers = dict([(sch.name, sch) for sch in all_schedulers]) - unknown_schedulers = [] - triggered_schedulers = [] - - # TODO: don't fire any schedulers if we discover an unknown one - dl = [] - for scheduler in self.schedulerNames: - scheduler = properties.render(scheduler) - if all_schedulers.has_key(scheduler): - sch = all_schedulers[scheduler] - if isinstance(sch, Triggerable): - dl.append(sch.trigger(ss, set_props=props_to_set)) - triggered_schedulers.append(scheduler) - else: - unknown_schedulers.append(scheduler) - else: - unknown_schedulers.append(scheduler) - - if unknown_schedulers: - self.step_status.setColor("red") - self.step_status.setText(['no scheduler:'] + unknown_schedulers) - rc = FAILURE - else: - rc = SUCCESS - self.step_status.setText(['triggered'] + triggered_schedulers) - if self.waitForFinish: - self.step_status.setColor("yellow") - else: - self.step_status.setColor("green") - - if self.waitForFinish: - d = defer.DeferredList(dl, consumeErrors=1) - else: - d = defer.succeed([]) - - def cb(rclist): - rc = SUCCESS # (this rc is not the same variable as that above) - for was_cb, buildsetstatus in rclist: - # TODO: make this algo more configurable - if not was_cb: - rc = EXCEPTION - break - if buildsetstatus.getResults() == FAILURE: - rc = FAILURE - return self.finished(rc) - - def eb(why): - return self.finished(FAILURE) - - d.addCallbacks(cb, eb) diff --git a/tools/buildbot/pylibs/buildbot/test/__init__.py b/tools/buildbot/pylibs/buildbot/test/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tools/buildbot/pylibs/buildbot/test/emit.py b/tools/buildbot/pylibs/buildbot/test/emit.py deleted file mode 100644 index 1e23e92..0000000 --- a/tools/buildbot/pylibs/buildbot/test/emit.py +++ /dev/null @@ -1,11 +0,0 @@ - -import os, sys - -sys.stdout.write("this is stdout\n") -sys.stderr.write("this is stderr\n") -if os.environ.has_key("EMIT_TEST"): - sys.stdout.write("EMIT_TEST: %s\n" % os.environ["EMIT_TEST"]) -open("log1.out","wt").write("this is log1\n") - -rc = int(sys.argv[1]) -sys.exit(rc) diff --git a/tools/buildbot/pylibs/buildbot/test/emitlogs.py b/tools/buildbot/pylibs/buildbot/test/emitlogs.py deleted file mode 100644 index 1430235..0000000 --- a/tools/buildbot/pylibs/buildbot/test/emitlogs.py +++ /dev/null @@ -1,42 +0,0 @@ -import sys, time, os.path, StringIO - -mode = 0 -if len(sys.argv) > 1: - mode = int(sys.argv[1]) - -if mode == 0: - log2 = open("log2.out", "wt") - log3 = open("log3.out", "wt") -elif mode == 1: - # delete the logfiles first, and wait a moment to exercise a failure path - if os.path.exists("log2.out"): - os.unlink("log2.out") - if os.path.exists("log3.out"): - os.unlink("log3.out") - time.sleep(2) - log2 = open("log2.out", "wt") - log3 = open("log3.out", "wt") -elif mode == 2: - # don't create the logfiles at all - log2 = StringIO.StringIO() - log3 = StringIO.StringIO() - -def write(i): - log2.write("this is log2 %d\n" % i) - log2.flush() - log3.write("this is log3 %d\n" % i) - log3.flush() - sys.stdout.write("this is stdout %d\n" % i) - sys.stdout.flush() - -write(0) -time.sleep(1) -write(1) -sys.stdin.read(1) -write(2) - -log2.close() -log3.close() - -sys.exit(0) - diff --git a/tools/buildbot/pylibs/buildbot/test/mail/freshcvs.1 b/tools/buildbot/pylibs/buildbot/test/mail/freshcvs.1 deleted file mode 100644 index cc8442e..0000000 --- a/tools/buildbot/pylibs/buildbot/test/mail/freshcvs.1 +++ /dev/null @@ -1,68 +0,0 @@ -Return-Path: -Delivered-To: warner-twistedcvs@luther.lothar.com -Received: (qmail 11151 invoked by uid 1000); 11 Jan 2003 17:10:04 -0000 -Delivered-To: warner-twistedcvs@lothar.com -Received: (qmail 1548 invoked by uid 13574); 11 Jan 2003 17:06:39 -0000 -Received: from unknown (HELO pyramid.twistedmatrix.com) ([64.123.27.105]) (envelope-sender ) - by 130.94.181.6 (qmail-ldap-1.03) with SMTP - for ; 11 Jan 2003 17:06:39 -0000 -Received: from localhost ([127.0.0.1] helo=pyramid.twistedmatrix.com) - by pyramid.twistedmatrix.com with esmtp (Exim 3.35 #1 (Debian)) - id 18XP0U-0002Mq-00; Sat, 11 Jan 2003 11:01:14 -0600 -Received: from acapnotic by pyramid.twistedmatrix.com with local (Exim 3.35 #1 (Debian)) - id 18XP02-0002MN-00 - for ; Sat, 11 Jan 2003 11:00:46 -0600 -To: twisted-commits@twistedmatrix.com -From: moshez CVS -Reply-To: twisted-python@twistedmatrix.com -X-Mailer: CVSToys -From: moshez CVS -Reply-To: twisted-python@twistedmatrix.com -Message-Id: -Subject: [Twisted-commits] Instance massenger, apparently -Sender: twisted-commits-admin@twistedmatrix.com -Errors-To: twisted-commits-admin@twistedmatrix.com -X-BeenThere: twisted-commits@twistedmatrix.com -X-Mailman-Version: 2.0.11 -Precedence: bulk -List-Help: -List-Post: -List-Subscribe: , - -List-Id: -List-Unsubscribe: , - -List-Archive: -Date: Sat, 11 Jan 2003 11:00:46 -0600 -Status: - -Modified files: -Twisted/debian/python-twisted.menu.in 1.3 1.4 - -Log message: -Instance massenger, apparently - - -ViewCVS links: -http://twistedmatrix.com/users/jh.twistd/viewcvs/cgi/viewcvs.cgi/debian/python-twisted.menu.in.diff?r1=text&tr1=1.3&r2=text&tr2=1.4&cvsroot=Twisted - -Index: Twisted/debian/python-twisted.menu.in -diff -u Twisted/debian/python-twisted.menu.in:1.3 Twisted/debian/python-twisted.menu.in:1.4 ---- Twisted/debian/python-twisted.menu.in:1.3 Sat Dec 28 10:02:12 2002 -+++ Twisted/debian/python-twisted.menu.in Sat Jan 11 09:00:44 2003 -@@ -1,7 +1,7 @@ - ?package(python@VERSION@-twisted):\ - needs=x11\ - section="Apps/Net"\ --title="Twisted Instant Messenger (@VERSION@)"\ -+title="Twisted Instance Messenger (@VERSION@)"\ - command="/usr/bin/t-im@VERSION@" - - ?package(python@VERSION@-twisted):\ - -. - -_______________________________________________ -Twisted-commits mailing list -Twisted-commits@twistedmatrix.com -http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-commits diff --git a/tools/buildbot/pylibs/buildbot/test/mail/freshcvs.2 b/tools/buildbot/pylibs/buildbot/test/mail/freshcvs.2 deleted file mode 100644 index ada1311..0000000 --- a/tools/buildbot/pylibs/buildbot/test/mail/freshcvs.2 +++ /dev/null @@ -1,101 +0,0 @@ -Return-Path: -Delivered-To: warner-twistedcvs@luther.lothar.com -Received: (qmail 32220 invoked by uid 1000); 14 Jan 2003 21:50:04 -0000 -Delivered-To: warner-twistedcvs@lothar.com -Received: (qmail 7923 invoked by uid 13574); 14 Jan 2003 21:49:48 -0000 -Received: from unknown (HELO pyramid.twistedmatrix.com) ([64.123.27.105]) (envelope-sender ) - by 130.94.181.6 (qmail-ldap-1.03) with SMTP - for ; 14 Jan 2003 21:49:48 -0000 -Received: from localhost ([127.0.0.1] helo=pyramid.twistedmatrix.com) - by pyramid.twistedmatrix.com with esmtp (Exim 3.35 #1 (Debian)) - id 18YYr0-0005en-00; Tue, 14 Jan 2003 15:44:14 -0600 -Received: from acapnotic by pyramid.twistedmatrix.com with local (Exim 3.35 #1 (Debian)) - id 18YYq7-0005eQ-00 - for ; Tue, 14 Jan 2003 15:43:19 -0600 -To: twisted-commits@twistedmatrix.com -From: itamarst CVS -Reply-To: twisted-python@twistedmatrix.com -X-Mailer: CVSToys -From: itamarst CVS -Reply-To: twisted-python@twistedmatrix.com -Message-Id: -Subject: [Twisted-commits] submit formmethod now subclass of Choice -Sender: twisted-commits-admin@twistedmatrix.com -Errors-To: twisted-commits-admin@twistedmatrix.com -X-BeenThere: twisted-commits@twistedmatrix.com -X-Mailman-Version: 2.0.11 -Precedence: bulk -List-Help: -List-Post: -List-Subscribe: , - -List-Id: -List-Unsubscribe: , - -List-Archive: -Date: Tue, 14 Jan 2003 15:43:19 -0600 -Status: - -Modified files: -Twisted/twisted/web/woven/form.py 1.20 1.21 -Twisted/twisted/python/formmethod.py 1.12 1.13 - -Log message: -submit formmethod now subclass of Choice - - -ViewCVS links: -http://twistedmatrix.com/users/jh.twistd/viewcvs/cgi/viewcvs.cgi/twisted/web/woven/form.py.diff?r1=text&tr1=1.20&r2=text&tr2=1.21&cvsroot=Twisted -http://twistedmatrix.com/users/jh.twistd/viewcvs/cgi/viewcvs.cgi/twisted/python/formmethod.py.diff?r1=text&tr1=1.12&r2=text&tr2=1.13&cvsroot=Twisted - -Index: Twisted/twisted/web/woven/form.py -diff -u Twisted/twisted/web/woven/form.py:1.20 Twisted/twisted/web/woven/form.py:1.21 ---- Twisted/twisted/web/woven/form.py:1.20 Tue Jan 14 12:07:29 2003 -+++ Twisted/twisted/web/woven/form.py Tue Jan 14 13:43:16 2003 -@@ -140,8 +140,8 @@ - - def input_submit(self, request, content, arg): - div = content.div() -- for value in arg.buttons: -- div.input(type="submit", name=arg.name, value=value) -+ for tag, value, desc in arg.choices: -+ div.input(type="submit", name=arg.name, value=tag) - div.text(" ") - if arg.reset: - div.input(type="reset") - -Index: Twisted/twisted/python/formmethod.py -diff -u Twisted/twisted/python/formmethod.py:1.12 Twisted/twisted/python/formmethod.py:1.13 ---- Twisted/twisted/python/formmethod.py:1.12 Tue Jan 14 12:07:30 2003 -+++ Twisted/twisted/python/formmethod.py Tue Jan 14 13:43:17 2003 -@@ -180,19 +180,13 @@ - return 1 - - --class Submit(Argument): -+class Submit(Choice): - """Submit button or a reasonable facsimile thereof.""" - -- def __init__(self, name, buttons=["Submit"], reset=0, shortDesc=None, longDesc=None): -- Argument.__init__(self, name, shortDesc=shortDesc, longDesc=longDesc) -- self.buttons = buttons -+ def __init__(self, name, choices=[("Submit", "submit", "Submit form")], -+ reset=0, shortDesc=None, longDesc=None): -+ Choice.__init__(self, name, choices=choices, shortDesc=shortDesc, longDesc=longDesc) - self.reset = reset -- -- def coerce(self, val): -- if val in self.buttons: -- return val -- else: -- raise InputError, "no such action" - - - class PresentationHint: - -. - -_______________________________________________ -Twisted-commits mailing list -Twisted-commits@twistedmatrix.com -http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-commits diff --git a/tools/buildbot/pylibs/buildbot/test/mail/freshcvs.3 b/tools/buildbot/pylibs/buildbot/test/mail/freshcvs.3 deleted file mode 100644 index f9ff199..0000000 --- a/tools/buildbot/pylibs/buildbot/test/mail/freshcvs.3 +++ /dev/null @@ -1,97 +0,0 @@ -Return-Path: -Delivered-To: warner-twistedcvs@luther.lothar.com -Received: (qmail 32220 invoked by uid 1000); 14 Jan 2003 21:50:04 -0000 -Delivered-To: warner-twistedcvs@lothar.com -Received: (qmail 7923 invoked by uid 13574); 14 Jan 2003 21:49:48 -0000 -Received: from unknown (HELO pyramid.twistedmatrix.com) ([64.123.27.105]) (envelope-sender ) - by 130.94.181.6 (qmail-ldap-1.03) with SMTP - for ; 14 Jan 2003 21:49:48 -0000 -Received: from localhost ([127.0.0.1] helo=pyramid.twistedmatrix.com) - by pyramid.twistedmatrix.com with esmtp (Exim 3.35 #1 (Debian)) - id 18YYr0-0005en-00; Tue, 14 Jan 2003 15:44:14 -0600 -Received: from acapnotic by pyramid.twistedmatrix.com with local (Exim 3.35 #1 (Debian)) - id 18YYq7-0005eQ-00 - for ; Tue, 14 Jan 2003 15:43:19 -0600 -To: twisted-commits@twistedmatrix.com -From: itamarst CVS -Reply-To: twisted-python@twistedmatrix.com -X-Mailer: CVSToys -From: itamarst CVS -Reply-To: twisted-python@twistedmatrix.com -Message-Id: -Subject: [Twisted-commits] submit formmethod now subclass of Choice -Sender: twisted-commits-admin@twistedmatrix.com -Errors-To: twisted-commits-admin@twistedmatrix.com -X-BeenThere: twisted-commits@twistedmatrix.com -X-Mailman-Version: 2.0.11 -Precedence: bulk -List-Help: -List-Post: -List-Subscribe: , - -List-Id: -List-Unsubscribe: , - -List-Archive: -Date: Tue, 14 Jan 2003 15:43:19 -0600 -Status: - -Modified files: -Twisted/twisted/web/woven/form.py 1.20 1.21 -Twisted/twisted/python/formmethod.py 1.12 1.13 - -Log message: -submit formmethod now subclass of Choice - - -Index: Twisted/twisted/web/woven/form.py -diff -u Twisted/twisted/web/woven/form.py:1.20 Twisted/twisted/web/woven/form.py:1.21 ---- Twisted/twisted/web/woven/form.py:1.20 Tue Jan 14 12:07:29 2003 -+++ Twisted/twisted/web/woven/form.py Tue Jan 14 13:43:16 2003 -@@ -140,8 +140,8 @@ - - def input_submit(self, request, content, arg): - div = content.div() -- for value in arg.buttons: -- div.input(type="submit", name=arg.name, value=value) -+ for tag, value, desc in arg.choices: -+ div.input(type="submit", name=arg.name, value=tag) - div.text(" ") - if arg.reset: - div.input(type="reset") - -Index: Twisted/twisted/python/formmethod.py -diff -u Twisted/twisted/python/formmethod.py:1.12 Twisted/twisted/python/formmethod.py:1.13 ---- Twisted/twisted/python/formmethod.py:1.12 Tue Jan 14 12:07:30 2003 -+++ Twisted/twisted/python/formmethod.py Tue Jan 14 13:43:17 2003 -@@ -180,19 +180,13 @@ - return 1 - - --class Submit(Argument): -+class Submit(Choice): - """Submit button or a reasonable facsimile thereof.""" - -- def __init__(self, name, buttons=["Submit"], reset=0, shortDesc=None, longDesc=None): -- Argument.__init__(self, name, shortDesc=shortDesc, longDesc=longDesc) -- self.buttons = buttons -+ def __init__(self, name, choices=[("Submit", "submit", "Submit form")], -+ reset=0, shortDesc=None, longDesc=None): -+ Choice.__init__(self, name, choices=choices, shortDesc=shortDesc, longDesc=longDesc) - self.reset = reset -- -- def coerce(self, val): -- if val in self.buttons: -- return val -- else: -- raise InputError, "no such action" - - - class PresentationHint: - -. - -_______________________________________________ -Twisted-commits mailing list -Twisted-commits@twistedmatrix.com -http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-commits diff --git a/tools/buildbot/pylibs/buildbot/test/mail/freshcvs.4 b/tools/buildbot/pylibs/buildbot/test/mail/freshcvs.4 deleted file mode 100644 index 9e674dc..0000000 --- a/tools/buildbot/pylibs/buildbot/test/mail/freshcvs.4 +++ /dev/null @@ -1,45 +0,0 @@ -Return-Path: -Delivered-To: warner-twistedcvs@luther.lothar.com -Received: (qmail 32220 invoked by uid 1000); 14 Jan 2003 21:50:04 -0000 -Delivered-To: warner-twistedcvs@lothar.com -Received: (qmail 7923 invoked by uid 13574); 14 Jan 2003 21:49:48 -0000 -Received: from unknown (HELO pyramid.twistedmatrix.com) ([64.123.27.105]) (envelope-sender ) - by 130.94.181.6 (qmail-ldap-1.03) with SMTP - for ; 14 Jan 2003 21:49:48 -0000 -Received: from localhost ([127.0.0.1] helo=pyramid.twistedmatrix.com) - by pyramid.twistedmatrix.com with esmtp (Exim 3.35 #1 (Debian)) - id 18YYr0-0005en-00; Tue, 14 Jan 2003 15:44:14 -0600 -Received: from acapnotic by pyramid.twistedmatrix.com with local (Exim 3.35 #1 (Debian)) - id 18YYq7-0005eQ-00 - for ; Tue, 14 Jan 2003 15:43:19 -0600 -To: twisted-commits@twistedmatrix.com -From: itamarst CVS -Reply-To: twisted-python@twistedmatrix.com -X-Mailer: CVSToys -From: itamarst CVS -Reply-To: twisted-python@twistedmatrix.com -Message-Id: -Subject: [Twisted-commits] submit formmethod now subclass of Choice -Sender: twisted-commits-admin@twistedmatrix.com -Errors-To: twisted-commits-admin@twistedmatrix.com -X-BeenThere: twisted-commits@twistedmatrix.com -X-Mailman-Version: 2.0.11 -Precedence: bulk -List-Help: -List-Post: -List-Subscribe: , - -List-Id: -List-Unsubscribe: , - -List-Archive: -Date: Tue, 14 Jan 2003 15:43:19 -0600 -Status: - -Modified files: -Twisted/twisted/web/woven/form.py 1.20 1.21 -Twisted/twisted/python/formmethod.py 1.12 1.13 - -Log message: -submit formmethod now subclass of Choice - diff --git a/tools/buildbot/pylibs/buildbot/test/mail/freshcvs.5 b/tools/buildbot/pylibs/buildbot/test/mail/freshcvs.5 deleted file mode 100644 index f20a958..0000000 --- a/tools/buildbot/pylibs/buildbot/test/mail/freshcvs.5 +++ /dev/null @@ -1,54 +0,0 @@ -Return-Path: -Delivered-To: warner-twistedcvs@luther.lothar.com -Received: (qmail 5865 invoked by uid 1000); 17 Jan 2003 07:00:04 -0000 -Delivered-To: warner-twistedcvs@lothar.com -Received: (qmail 40460 invoked by uid 13574); 17 Jan 2003 06:51:55 -0000 -Received: from unknown (HELO pyramid.twistedmatrix.com) ([64.123.27.105]) (envelope-sender ) - by 130.94.181.6 (qmail-ldap-1.03) with SMTP - for ; 17 Jan 2003 06:51:55 -0000 -Received: from localhost ([127.0.0.1] helo=pyramid.twistedmatrix.com) - by pyramid.twistedmatrix.com with esmtp (Exim 3.35 #1 (Debian)) - id 18ZQGk-0003WL-00; Fri, 17 Jan 2003 00:46:22 -0600 -Received: from acapnotic by pyramid.twistedmatrix.com with local (Exim 3.35 #1 (Debian)) - id 18ZQFy-0003VP-00 - for ; Fri, 17 Jan 2003 00:45:34 -0600 -To: twisted-commits@twistedmatrix.com -From: etrepum CVS -Reply-To: twisted-python@twistedmatrix.com -X-Mailer: CVSToys -From: etrepum CVS -Reply-To: twisted-python@twistedmatrix.com -Message-Id: -Subject: [Twisted-commits] Directory /cvs/Twisted/doc/examples/cocoaDemo added to the repository -Sender: twisted-commits-admin@twistedmatrix.com -Errors-To: twisted-commits-admin@twistedmatrix.com -X-BeenThere: twisted-commits@twistedmatrix.com -X-Mailman-Version: 2.0.11 -Precedence: bulk -List-Help: -List-Post: -List-Subscribe: , - -List-Id: -List-Unsubscribe: , - -List-Archive: -Date: Fri, 17 Jan 2003 00:45:34 -0600 -Status: - -Modified files: -Twisted/doc/examples/cocoaDemo 0 0 - -Log message: -Directory /cvs/Twisted/doc/examples/cocoaDemo added to the repository - - -ViewCVS links: -http://twistedmatrix.com/users/jh.twistd/viewcvs/cgi/viewcvs.cgi/doc/examples/cocoaDemo.diff?r1=text&tr1=NONE&r2=text&tr2=NONE&cvsroot=Twisted - -. - -_______________________________________________ -Twisted-commits mailing list -Twisted-commits@twistedmatrix.com -http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-commits diff --git a/tools/buildbot/pylibs/buildbot/test/mail/freshcvs.6 b/tools/buildbot/pylibs/buildbot/test/mail/freshcvs.6 deleted file mode 100644 index 20719f4..0000000 --- a/tools/buildbot/pylibs/buildbot/test/mail/freshcvs.6 +++ /dev/null @@ -1,70 +0,0 @@ -Return-Path: -Delivered-To: warner-twistedcvs@luther.lothar.com -Received: (qmail 7252 invoked by uid 1000); 17 Jan 2003 07:10:04 -0000 -Delivered-To: warner-twistedcvs@lothar.com -Received: (qmail 43115 invoked by uid 13574); 17 Jan 2003 07:07:57 -0000 -Received: from unknown (HELO pyramid.twistedmatrix.com) ([64.123.27.105]) (envelope-sender ) - by 130.94.181.6 (qmail-ldap-1.03) with SMTP - for ; 17 Jan 2003 07:07:57 -0000 -Received: from localhost ([127.0.0.1] helo=pyramid.twistedmatrix.com) - by pyramid.twistedmatrix.com with esmtp (Exim 3.35 #1 (Debian)) - id 18ZQW6-0003dA-00; Fri, 17 Jan 2003 01:02:14 -0600 -Received: from acapnotic by pyramid.twistedmatrix.com with local (Exim 3.35 #1 (Debian)) - id 18ZQV7-0003cm-00 - for ; Fri, 17 Jan 2003 01:01:13 -0600 -To: twisted-commits@twistedmatrix.com -From: etrepum CVS -Reply-To: twisted-python@twistedmatrix.com -X-Mailer: CVSToys -From: etrepum CVS -Reply-To: twisted-python@twistedmatrix.com -Message-Id: -Subject: [Twisted-commits] Cocoa (OS X) clone of the QT demo, using polling reactor -Sender: twisted-commits-admin@twistedmatrix.com -Errors-To: twisted-commits-admin@twistedmatrix.com -X-BeenThere: twisted-commits@twistedmatrix.com -X-Mailman-Version: 2.0.11 -Precedence: bulk -List-Help: -List-Post: -List-Subscribe: , - -List-Id: -List-Unsubscribe: , - -List-Archive: -Date: Fri, 17 Jan 2003 01:01:13 -0600 -Status: - -Modified files: -Twisted/doc/examples/cocoaDemo/MyAppDelegate.py None 1.1 -Twisted/doc/examples/cocoaDemo/__main__.py None 1.1 -Twisted/doc/examples/cocoaDemo/bin-python-main.m None 1.1 -Twisted/doc/examples/cocoaDemo/English.lproj/InfoPlist.strings None 1.1 -Twisted/doc/examples/cocoaDemo/English.lproj/MainMenu.nib/classes.nib None 1.1 -Twisted/doc/examples/cocoaDemo/English.lproj/MainMenu.nib/info.nib None 1.1 -Twisted/doc/examples/cocoaDemo/English.lproj/MainMenu.nib/keyedobjects.nib None 1.1 -Twisted/doc/examples/cocoaDemo/cocoaDemo.pbproj/project.pbxproj None 1.1 - -Log message: -Cocoa (OS X) clone of the QT demo, using polling reactor - -Requires pyobjc ( http://pyobjc.sourceforge.net ), it's not much different than the template project. The reactor is iterated periodically by a repeating NSTimer. - - -ViewCVS links: -http://twistedmatrix.com/users/jh.twistd/viewcvs/cgi/viewcvs.cgi/doc/examples/cocoaDemo/MyAppDelegate.py.diff?r1=text&tr1=None&r2=text&tr2=1.1&cvsroot=Twisted -http://twistedmatrix.com/users/jh.twistd/viewcvs/cgi/viewcvs.cgi/doc/examples/cocoaDemo/__main__.py.diff?r1=text&tr1=None&r2=text&tr2=1.1&cvsroot=Twisted -http://twistedmatrix.com/users/jh.twistd/viewcvs/cgi/viewcvs.cgi/doc/examples/cocoaDemo/bin-python-main.m.diff?r1=text&tr1=None&r2=text&tr2=1.1&cvsroot=Twisted -http://twistedmatrix.com/users/jh.twistd/viewcvs/cgi/viewcvs.cgi/doc/examples/cocoaDemo/English.lproj/InfoPlist.strings.diff?r1=text&tr1=None&r2=text&tr2=1.1&cvsroot=Twisted -http://twistedmatrix.com/users/jh.twistd/viewcvs/cgi/viewcvs.cgi/doc/examples/cocoaDemo/English.lproj/MainMenu.nib/classes.nib.diff?r1=text&tr1=None&r2=text&tr2=1.1&cvsroot=Twisted -http://twistedmatrix.com/users/jh.twistd/viewcvs/cgi/viewcvs.cgi/doc/examples/cocoaDemo/English.lproj/MainMenu.nib/info.nib.diff?r1=text&tr1=None&r2=text&tr2=1.1&cvsroot=Twisted -http://twistedmatrix.com/users/jh.twistd/viewcvs/cgi/viewcvs.cgi/doc/examples/cocoaDemo/English.lproj/MainMenu.nib/keyedobjects.nib.diff?r1=text&tr1=None&r2=text&tr2=1.1&cvsroot=Twisted -http://twistedmatrix.com/users/jh.twistd/viewcvs/cgi/viewcvs.cgi/doc/examples/cocoaDemo/cocoaDemo.pbproj/project.pbxproj.diff?r1=text&tr1=None&r2=text&tr2=1.1&cvsroot=Twisted - -. - -_______________________________________________ -Twisted-commits mailing list -Twisted-commits@twistedmatrix.com -http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-commits diff --git a/tools/buildbot/pylibs/buildbot/test/mail/freshcvs.7 b/tools/buildbot/pylibs/buildbot/test/mail/freshcvs.7 deleted file mode 100644 index 515be1d..0000000 --- a/tools/buildbot/pylibs/buildbot/test/mail/freshcvs.7 +++ /dev/null @@ -1,68 +0,0 @@ -Return-Path: -Delivered-To: warner-twistedcvs@luther.lothar.com -Received: (qmail 8665 invoked by uid 1000); 17 Jan 2003 08:00:03 -0000 -Delivered-To: warner-twistedcvs@lothar.com -Received: (qmail 50728 invoked by uid 13574); 17 Jan 2003 07:51:14 -0000 -Received: from unknown (HELO pyramid.twistedmatrix.com) ([64.123.27.105]) (envelope-sender ) - by 130.94.181.6 (qmail-ldap-1.03) with SMTP - for ; 17 Jan 2003 07:51:14 -0000 -Received: from localhost ([127.0.0.1] helo=pyramid.twistedmatrix.com) - by pyramid.twistedmatrix.com with esmtp (Exim 3.35 #1 (Debian)) - id 18ZRBm-0003pN-00; Fri, 17 Jan 2003 01:45:18 -0600 -Received: from acapnotic by pyramid.twistedmatrix.com with local (Exim 3.35 #1 (Debian)) - id 18ZRBQ-0003ou-00 - for ; Fri, 17 Jan 2003 01:44:56 -0600 -To: twisted-commits@twistedmatrix.com -From: etrepum CVS -Reply-To: twisted-python@twistedmatrix.com -X-Mailer: CVSToys -From: etrepum CVS -Reply-To: twisted-python@twistedmatrix.com -Message-Id: -Subject: [Twisted-commits] Directories break debian build script, waiting for reasonable fix -Sender: twisted-commits-admin@twistedmatrix.com -Errors-To: twisted-commits-admin@twistedmatrix.com -X-BeenThere: twisted-commits@twistedmatrix.com -X-Mailman-Version: 2.0.11 -Precedence: bulk -List-Help: -List-Post: -List-Subscribe: , - -List-Id: -List-Unsubscribe: , - -List-Archive: -Date: Fri, 17 Jan 2003 01:44:56 -0600 -Status: - -Modified files: -Twisted/doc/examples/cocoaDemo/MyAppDelegate.py 1.1 None -Twisted/doc/examples/cocoaDemo/__main__.py 1.1 None -Twisted/doc/examples/cocoaDemo/bin-python-main.m 1.1 None -Twisted/doc/examples/cocoaDemo/English.lproj/InfoPlist.strings 1.1 None -Twisted/doc/examples/cocoaDemo/English.lproj/MainMenu.nib/classes.nib 1.1 None -Twisted/doc/examples/cocoaDemo/English.lproj/MainMenu.nib/info.nib 1.1 None -Twisted/doc/examples/cocoaDemo/English.lproj/MainMenu.nib/keyedobjects.nib 1.1 None -Twisted/doc/examples/cocoaDemo/cocoaDemo.pbproj/project.pbxproj 1.1 None - -Log message: -Directories break debian build script, waiting for reasonable fix - - -ViewCVS links: -http://twistedmatrix.com/users/jh.twistd/viewcvs/cgi/viewcvs.cgi/doc/examples/cocoaDemo/MyAppDelegate.py.diff?r1=text&tr1=1.1&r2=text&tr2=None&cvsroot=Twisted -http://twistedmatrix.com/users/jh.twistd/viewcvs/cgi/viewcvs.cgi/doc/examples/cocoaDemo/__main__.py.diff?r1=text&tr1=1.1&r2=text&tr2=None&cvsroot=Twisted -http://twistedmatrix.com/users/jh.twistd/viewcvs/cgi/viewcvs.cgi/doc/examples/cocoaDemo/bin-python-main.m.diff?r1=text&tr1=1.1&r2=text&tr2=None&cvsroot=Twisted -http://twistedmatrix.com/users/jh.twistd/viewcvs/cgi/viewcvs.cgi/doc/examples/cocoaDemo/English.lproj/InfoPlist.strings.diff?r1=text&tr1=1.1&r2=text&tr2=None&cvsroot=Twisted -http://twistedmatrix.com/users/jh.twistd/viewcvs/cgi/viewcvs.cgi/doc/examples/cocoaDemo/English.lproj/MainMenu.nib/classes.nib.diff?r1=text&tr1=1.1&r2=text&tr2=None&cvsroot=Twisted -http://twistedmatrix.com/users/jh.twistd/viewcvs/cgi/viewcvs.cgi/doc/examples/cocoaDemo/English.lproj/MainMenu.nib/info.nib.diff?r1=text&tr1=1.1&r2=text&tr2=None&cvsroot=Twisted -http://twistedmatrix.com/users/jh.twistd/viewcvs/cgi/viewcvs.cgi/doc/examples/cocoaDemo/English.lproj/MainMenu.nib/keyedobjects.nib.diff?r1=text&tr1=1.1&r2=text&tr2=None&cvsroot=Twisted -http://twistedmatrix.com/users/jh.twistd/viewcvs/cgi/viewcvs.cgi/doc/examples/cocoaDemo/cocoaDemo.pbproj/project.pbxproj.diff?r1=text&tr1=1.1&r2=text&tr2=None&cvsroot=Twisted - -. - -_______________________________________________ -Twisted-commits mailing list -Twisted-commits@twistedmatrix.com -http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-commits diff --git a/tools/buildbot/pylibs/buildbot/test/mail/freshcvs.8 b/tools/buildbot/pylibs/buildbot/test/mail/freshcvs.8 deleted file mode 100644 index 9b1e4fd..0000000 --- a/tools/buildbot/pylibs/buildbot/test/mail/freshcvs.8 +++ /dev/null @@ -1,61 +0,0 @@ -Return-Path: -Delivered-To: warner-twistedcvs@luther.lothar.com -Received: (qmail 10804 invoked by uid 1000); 19 Jan 2003 14:10:03 -0000 -Delivered-To: warner-twistedcvs@lothar.com -Received: (qmail 6704 invoked by uid 13574); 19 Jan 2003 14:00:20 -0000 -Received: from unknown (HELO pyramid.twistedmatrix.com) ([64.123.27.105]) (envelope-sender ) - by 130.94.181.6 (qmail-ldap-1.03) with SMTP - for ; 19 Jan 2003 14:00:20 -0000 -Received: from localhost ([127.0.0.1] helo=pyramid.twistedmatrix.com) - by pyramid.twistedmatrix.com with esmtp (Exim 3.35 #1 (Debian)) - id 18aFtx-0002WS-00; Sun, 19 Jan 2003 07:54:17 -0600 -Received: from acapnotic by pyramid.twistedmatrix.com with local (Exim 3.35 #1 (Debian)) - id 18aFtH-0002W3-00 - for ; Sun, 19 Jan 2003 07:53:35 -0600 -To: twisted-commits@twistedmatrix.com -From: acapnotic CVS -X-Mailer: CVSToys -Message-Id: -Subject: [Twisted-commits] it doesn't work with invalid syntax -Sender: twisted-commits-admin@twistedmatrix.com -Errors-To: twisted-commits-admin@twistedmatrix.com -X-BeenThere: twisted-commits@twistedmatrix.com -X-Mailman-Version: 2.0.11 -Precedence: bulk -List-Help: -List-Post: -List-Subscribe: , - -List-Id: -List-Unsubscribe: , - -List-Archive: -Date: Sun, 19 Jan 2003 07:53:35 -0600 -Status: - -Modified files: -CVSROOT/freshCfg 1.16 1.17 - -Log message: -it doesn't work with invalid syntax - - -Index: CVSROOT/freshCfg -diff -u CVSROOT/freshCfg:1.16 CVSROOT/freshCfg:1.17 ---- CVSROOT/freshCfg:1.16 Sun Jan 19 05:52:34 2003 -+++ CVSROOT/freshCfg Sun Jan 19 05:53:34 2003 -@@ -27,7 +27,7 @@ - ('/cvs', '^Reality', None, MailNotification(['reality-commits'])), - ('/cvs', '^Twistby', None, MailNotification(['acapnotic'])), - ('/cvs', '^CVSToys', None, -- MailNotification(['CVSToys-list'] -+ MailNotification(['CVSToys-list'], - "http://twistedmatrix.com/users/jh.twistd/" - "viewcvs/cgi/viewcvs.cgi/", - replyTo="cvstoys-list@twistedmatrix.com"),) - - -_______________________________________________ -Twisted-commits mailing list -Twisted-commits@twistedmatrix.com -http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-commits diff --git a/tools/buildbot/pylibs/buildbot/test/mail/freshcvs.9 b/tools/buildbot/pylibs/buildbot/test/mail/freshcvs.9 deleted file mode 100644 index fd4f785..0000000 --- a/tools/buildbot/pylibs/buildbot/test/mail/freshcvs.9 +++ /dev/null @@ -1,18 +0,0 @@ -From twisted-python@twistedmatrix.com Fri Dec 26 07:25:13 2003 -From: twisted-python@twistedmatrix.com (exarkun CVS) -Date: Fri, 26 Dec 2003 00:25:13 -0700 -Subject: [Twisted-commits] Directory /cvs/Twisted/sandbox/exarkun/persist-plugin added to the repository -Message-ID: - -Modified files: -Twisted/sandbox/exarkun/persist-plugin - -Log message: -Directory /cvs/Twisted/sandbox/exarkun/persist-plugin added to the repository - - -ViewCVS links: -http://cvs.twistedmatrix.com/cvs/sandbox/exarkun/persist-plugin?cvsroot=Twisted - - - diff --git a/tools/buildbot/pylibs/buildbot/test/mail/svn-commit.1 b/tools/buildbot/pylibs/buildbot/test/mail/svn-commit.1 deleted file mode 100644 index 591dfee..0000000 --- a/tools/buildbot/pylibs/buildbot/test/mail/svn-commit.1 +++ /dev/null @@ -1,67 +0,0 @@ -X-Original-To: jm@jmason.org -Delivered-To: jm@dogma.boxhost.net -Received: from localhost [127.0.0.1] - by localhost with IMAP (fetchmail-6.2.5) - for jm@localhost (single-drop); Wed, 12 Apr 2006 01:52:04 +0100 (IST) -Received: from mail.apache.org (hermes.apache.org [209.237.227.199]) - by dogma.boxhost.net (Postfix) with SMTP id 34F07310051 - for ; Wed, 12 Apr 2006 01:44:17 +0100 (IST) -Received: (qmail 71414 invoked by uid 500); 12 Apr 2006 00:44:16 -0000 -Mailing-List: contact commits-help@spamassassin.apache.org; run by ezmlm -Precedence: bulk -list-help: -list-unsubscribe: -List-Post: -Reply-To: "SpamAssassin Dev" -List-Id: -Delivered-To: mailing list commits@spamassassin.apache.org -Received: (qmail 71403 invoked by uid 99); 12 Apr 2006 00:44:16 -0000 -Received: from asf.osuosl.org (HELO asf.osuosl.org) (140.211.166.49) - by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 11 Apr 2006 17:44:16 -0700 -X-ASF-Spam-Status: No, hits=-9.4 required=10.0 - tests=ALL_TRUSTED,NO_REAL_NAME -Received: from [209.237.227.194] (HELO minotaur.apache.org) (209.237.227.194) - by apache.org (qpsmtpd/0.29) with SMTP; Tue, 11 Apr 2006 17:44:15 -0700 -Received: (qmail 51950 invoked by uid 65534); 12 Apr 2006 00:43:55 -0000 -Message-ID: <20060412004355.51949.qmail@minotaur.apache.org> -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: svn commit: r393348 - /spamassassin/trunk/sa-update.raw -Date: Wed, 12 Apr 2006 00:43:54 -0000 -To: commits@spamassassin.apache.org -From: felicity@apache.org -X-Mailer: svnmailer-1.0.7 -X-Virus-Checked: Checked by ClamAV on apache.org -Status: O -X-UID: 62932 -X-Keywords: - -Author: felicity -Date: Tue Apr 11 17:43:54 2006 -New Revision: 393348 - -URL: http://svn.apache.org/viewcvs?rev=393348&view=rev -Log: -bug 4864: remove extraneous front-slash from gpghomedir path - -Modified: - spamassassin/trunk/sa-update.raw - -Modified: spamassassin/trunk/sa-update.raw -URL: http://svn.apache.org/viewcvs/spamassassin/trunk/sa-update.raw?rev=393348&r1=393347&r2=393348&view=diff -============================================================================== ---- spamassassin/trunk/sa-update.raw (original) -+++ spamassassin/trunk/sa-update.raw Tue Apr 11 17:43:54 2006 -@@ -120,7 +120,7 @@ - @{$opt{'channel'}} = (); - my $GPG_ENABLED = 1; - --$opt{'gpghomedir'} = File::Spec->catfile($LOCAL_RULES_DIR, '/sa-update-keys'); -+$opt{'gpghomedir'} = File::Spec->catfile($LOCAL_RULES_DIR, 'sa-update-keys'); - - Getopt::Long::Configure( - qw(bundling no_getopt_compat no_auto_abbrev no_ignore_case)); - - - diff --git a/tools/buildbot/pylibs/buildbot/test/mail/svn-commit.2 b/tools/buildbot/pylibs/buildbot/test/mail/svn-commit.2 deleted file mode 100644 index eeef001..0000000 --- a/tools/buildbot/pylibs/buildbot/test/mail/svn-commit.2 +++ /dev/null @@ -1,1218 +0,0 @@ -X-Original-To: jm@jmason.org -Delivered-To: jm@dogma.boxhost.net -Received: from localhost [127.0.0.1] - by localhost with IMAP (fetchmail-6.2.5) - for jm@localhost (single-drop); Thu, 09 Mar 2006 21:44:57 +0000 (GMT) -Received: from minotaur.apache.org (minotaur.apache.org [209.237.227.194]) - by dogma.boxhost.net (Postfix) with SMTP id 0D3463105BF - for ; Thu, 9 Mar 2006 19:52:50 +0000 (GMT) -Received: (qmail 30661 invoked by uid 1833); 9 Mar 2006 19:52:44 -0000 -Delivered-To: jm@locus.apache.org -Received: (qmail 30451 invoked from network); 9 Mar 2006 19:52:38 -0000 -Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) - by minotaur.apache.org with SMTP; 9 Mar 2006 19:52:38 -0000 -Received: (qmail 97860 invoked by uid 500); 9 Mar 2006 19:52:29 -0000 -Delivered-To: apmail-jm@apache.org -Received: (qmail 97837 invoked by uid 500); 9 Mar 2006 19:52:28 -0000 -Mailing-List: contact commits-help@spamassassin.apache.org; run by ezmlm -Precedence: bulk -list-help: -list-unsubscribe: -List-Post: -Reply-To: "SpamAssassin Dev" -List-Id: -Delivered-To: mailing list commits@spamassassin.apache.org -Received: (qmail 97826 invoked by uid 99); 9 Mar 2006 19:52:28 -0000 -Received: from asf.osuosl.org (HELO asf.osuosl.org) (140.211.166.49) - by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 09 Mar 2006 11:52:28 -0800 -X-ASF-Spam-Status: No, hits=-9.4 required=10.0 - tests=ALL_TRUSTED,NO_REAL_NAME -Received: from [209.237.227.194] (HELO minotaur.apache.org) (209.237.227.194) - by apache.org (qpsmtpd/0.29) with SMTP; Thu, 09 Mar 2006 11:52:26 -0800 -Received: (qmail 29644 invoked by uid 65534); 9 Mar 2006 19:52:06 -0000 -Message-ID: <20060309195206.29643.qmail@minotaur.apache.org> -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: svn commit: r384590 - in /spamassassin/branches/3.1: ./ - lib/Mail/SpamAssassin/ lib/Mail/SpamAssassin/Plugin/ spamd/ -Date: Thu, 09 Mar 2006 19:52:02 -0000 -To: commits@spamassassin.apache.org -From: sidney@apache.org -X-Mailer: svnmailer-1.0.7 -X-Virus-Checked: Checked by ClamAV on apache.org -Status: O -X-UID: 60795 -X-Keywords: - -Author: sidney -Date: Thu Mar 9 11:51:59 2006 -New Revision: 384590 - -URL: http://svn.apache.org/viewcvs?rev=384590&view=rev -Log: -Bug 4696: consolidated fixes for timeout bugs - -Added: - spamassassin/branches/3.1/lib/Mail/SpamAssassin/Timeout.pm -Modified: - spamassassin/branches/3.1/MANIFEST - spamassassin/branches/3.1/lib/Mail/SpamAssassin/Logger.pm - spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/DCC.pm - spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/DomainKeys.pm - spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/Pyzor.pm - spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/Razor2.pm - spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/SPF.pm - spamassassin/branches/3.1/lib/Mail/SpamAssassin/SpamdForkScaling.pm - spamassassin/branches/3.1/spamd/spamd.raw - -Modified: spamassassin/branches/3.1/MANIFEST -URL: http://svn.apache.org/viewcvs/spamassassin/branches/3.1/MANIFEST?rev=384590&r1=384589&r2=384590&view=diff -============================================================================== ---- spamassassin/branches/3.1/MANIFEST (original) -+++ spamassassin/branches/3.1/MANIFEST Thu Mar 9 11:51:59 2006 -@@ -89,6 +89,7 @@ - lib/Mail/SpamAssassin/SQLBasedAddrList.pm - lib/Mail/SpamAssassin/SpamdForkScaling.pm - lib/Mail/SpamAssassin/SubProcBackChannel.pm -+lib/Mail/SpamAssassin/Timeout.pm - lib/Mail/SpamAssassin/Util.pm - lib/Mail/SpamAssassin/Util/DependencyInfo.pm - lib/Mail/SpamAssassin/Util/Progress.pm - -Modified: spamassassin/branches/3.1/lib/Mail/SpamAssassin/Logger.pm -URL: http://svn.apache.org/viewcvs/spamassassin/branches/3.1/lib/Mail/SpamAssassin/Logger.pm?rev=384590&r1=384589&r2=384590&view=diff -============================================================================== ---- spamassassin/branches/3.1/lib/Mail/SpamAssassin/Logger.pm (original) -+++ spamassassin/branches/3.1/lib/Mail/SpamAssassin/Logger.pm Thu Mar 9 11:51:59 2006 -@@ -142,7 +142,7 @@ - - if ($level eq "error") { - # don't log alarm timeouts or broken pipes of various plugins' network checks -- return if ($message[0] =~ /__(?:alarm|brokenpipe)__ignore__/); -+ return if ($message[0] =~ /__ignore__/); - - # dos: we can safely ignore any die's that we eval'd in our own modules so - # don't log them -- this is caller 0, the use'ing package is 1, the eval is 2 - -Modified: spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/DCC.pm -URL: http://svn.apache.org/viewcvs/spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/DCC.pm?rev=384590&r1=384589&r2=384590&view=diff -============================================================================== ---- spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/DCC.pm (original) -+++ spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/DCC.pm Thu Mar 9 11:51:59 2006 -@@ -44,6 +44,7 @@ - - use Mail::SpamAssassin::Plugin; - use Mail::SpamAssassin::Logger; -+use Mail::SpamAssassin::Timeout; - use IO::Socket; - use strict; - use warnings; -@@ -375,15 +376,10 @@ - - $permsgstatus->enter_helper_run_mode(); - -- my $oldalarm = 0; -+ my $timer = Mail::SpamAssassin::Timeout->new({ secs => $timeout }); -+ my $err = $timer->run_and_catch(sub { - -- eval { -- # safe to use $SIG{ALRM} here instead of Util::trap_sigalrm_fully(), -- # since there are no killer regexp hang dangers here -- local $SIG{ALRM} = sub { die "__alarm__ignore__\n" }; -- local $SIG{__DIE__}; # bug 4631 -- -- $oldalarm = alarm $timeout; -+ local $SIG{PIPE} = sub { die "__brokenpipe__ignore__\n" }; - - my $sock = IO::Socket::UNIX->new(Type => SOCK_STREAM, - Peer => $sockpath) || dbg("dcc: failed to open socket") && die; -@@ -419,28 +415,20 @@ - } - - dbg("dcc: dccifd got response: $response"); -+ -+ }); - -- if (defined $oldalarm) { -- alarm $oldalarm; $oldalarm = undef; -- } -- }; -+ $permsgstatus->leave_helper_run_mode(); - -- my $err = $@; -- if (defined $oldalarm) { -- alarm $oldalarm; $oldalarm = undef; -+ if ($timer->timed_out()) { -+ dbg("dcc: dccifd check timed out after $timeout secs."); -+ return 0; - } -- $permsgstatus->leave_helper_run_mode(); - - if ($err) { - chomp $err; -- $response = undef; -- if ($err eq "__alarm__ignore__") { -- dbg("dcc: dccifd check timed out after $timeout secs."); -- return 0; -- } else { -- warn("dcc: dccifd -> check skipped: $! $err"); -- return 0; -- } -+ warn("dcc: dccifd -> check skipped: $! $err"); -+ return 0; - } - - if (!defined $response || $response !~ /^X-DCC/) { -@@ -494,17 +482,12 @@ - - # use a temp file here -- open2() is unreliable, buffering-wise, under spamd - my $tmpf = $permsgstatus->create_fulltext_tmpfile($fulltext); -- my $oldalarm = 0; -- - my $pid; -- eval { -- # safe to use $SIG{ALRM} here instead of Util::trap_sigalrm_fully(), -- # since there are no killer regexp hang dangers here -- local $SIG{ALRM} = sub { die "__alarm__ignore__\n" }; -- local $SIG{PIPE} = sub { die "__brokenpipe__ignore__\n" }; -- local $SIG{__DIE__}; # bug 4631 - -- $oldalarm = alarm $timeout; -+ my $timer = Mail::SpamAssassin::Timeout->new({ secs => $timeout }); -+ my $err = $timer->run_and_catch(sub { -+ -+ local $SIG{PIPE} = sub { die "__brokenpipe__ignore__\n" }; - - # note: not really tainted, this came from system configuration file - my $path = Mail::SpamAssassin::Util::untaint_file_path($self->{main}->{conf}->{dcc_path}); -@@ -542,17 +525,7 @@ - - dbg("dcc: got response: $response"); - -- # note: this must be called BEFORE leave_helper_run_mode() -- # $self->cleanup_kids($pid); -- if (defined $oldalarm) { -- alarm $oldalarm; $oldalarm = undef; -- } -- }; -- -- my $err = $@; -- if (defined $oldalarm) { -- alarm $oldalarm; $oldalarm = undef; -- } -+ }); - - if (defined(fileno(*DCC))) { # still open - if ($pid) { -@@ -564,11 +537,14 @@ - } - $permsgstatus->leave_helper_run_mode(); - -+ if ($timer->timed_out()) { -+ dbg("dcc: check timed out after $timeout seconds"); -+ return 0; -+ } -+ - if ($err) { - chomp $err; -- if ($err eq "__alarm__ignore__") { -- dbg("dcc: check timed out after $timeout seconds"); -- } elsif ($err eq "__brokenpipe__ignore__") { -+ if ($err eq "__brokenpipe__ignore__") { - dbg("dcc: check failed: broken pipe"); - } elsif ($err eq "no response") { - dbg("dcc: check failed: no response"); -@@ -645,47 +621,37 @@ - my ($self, $options, $tmpf) = @_; - my $timeout = $options->{report}->{conf}->{dcc_timeout}; - -- $options->{report}->enter_helper_run_mode(); -+ # note: not really tainted, this came from system configuration file -+ my $path = Mail::SpamAssassin::Util::untaint_file_path($options->{report}->{conf}->{dcc_path}); - -- my $oldalarm = 0; -+ my $opts = $options->{report}->{conf}->{dcc_options} || ''; - -- eval { -- local $SIG{ALRM} = sub { die "__alarm__ignore__\n" }; -- local $SIG{PIPE} = sub { die "__brokenpipe__ignore__\n" }; -- local $SIG{__DIE__}; # bug 4631 -+ my $timer = Mail::SpamAssassin::Timeout->new({ secs => $timeout }); - -- $oldalarm = alarm $timeout; -- -- # note: not really tainted, this came from system configuration file -- my $path = Mail::SpamAssassin::Util::untaint_file_path($options->{report}->{conf}->{dcc_path}); -+ $options->{report}->enter_helper_run_mode(); -+ my $err = $timer->run_and_catch(sub { - -- my $opts = $options->{report}->{conf}->{dcc_options} || ''; -+ local $SIG{PIPE} = sub { die "__brokenpipe__ignore__\n" }; - - my $pid = Mail::SpamAssassin::Util::helper_app_pipe_open(*DCC, -- $tmpf, 1, $path, "-t", "many", split(' ', $opts)); -+ $tmpf, 1, $path, "-t", "many", split(' ', $opts)); - $pid or die "$!\n"; - - my @ignored = ; - $options->{report}->close_pipe_fh(\*DCC); -- - waitpid ($pid, 0); -- if (defined $oldalarm) { -- alarm $oldalarm; $oldalarm = undef; -- } -- }; -+ -+ }); -+ $options->{report}->leave_helper_run_mode(); - -- my $err = $@; -- if (defined $oldalarm) { -- alarm $oldalarm; $oldalarm = undef; -+ if ($timer->timed_out()) { -+ dbg("reporter: DCC report timed out after $timeout seconds"); -+ return 0; - } - -- $options->{report}->leave_helper_run_mode(); -- - if ($err) { - chomp $err; -- if ($err eq "__alarm__ignore__") { -- dbg("reporter: DCC report timed out after $timeout seconds"); -- } elsif ($err eq "__brokenpipe__ignore__") { -+ if ($err eq "__brokenpipe__ignore__") { - dbg("reporter: DCC report failed: broken pipe"); - } else { - warn("reporter: DCC report failed: $err\n"); - -Modified: spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/DomainKeys.pm -URL: http://svn.apache.org/viewcvs/spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/DomainKeys.pm?rev=384590&r1=384589&r2=384590&view=diff -============================================================================== ---- spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/DomainKeys.pm (original) -+++ spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/DomainKeys.pm Thu Mar 9 11:51:59 2006 -@@ -34,6 +34,8 @@ - - use Mail::SpamAssassin::Plugin; - use Mail::SpamAssassin::Logger; -+use Mail::SpamAssassin::Timeout; -+ - use strict; - use warnings; - use bytes; -@@ -165,30 +167,22 @@ - } - - my $timeout = $scan->{conf}->{domainkeys_timeout}; -- my $oldalarm = 0; - -- eval { -- local $SIG{ALRM} = sub { die "__alarm__ignore__\n" }; -- local $SIG{__DIE__}; # bug 4631 -- $oldalarm = alarm($timeout); -+ my $timer = Mail::SpamAssassin::Timeout->new({ secs => $timeout }); -+ my $err = $timer->run_and_catch(sub { -+ - $self->_dk_lookup_trapped($scan, $message, $domain); -- if (defined $oldalarm) { -- alarm $oldalarm; $oldalarm = undef; -- } -- }; -- -- my $err = $@; -- if (defined $oldalarm) { -- alarm $oldalarm; $oldalarm = undef; -+ -+ }); -+ -+ if ($timer->timed_out()) { -+ dbg("dk: lookup timed out after $timeout seconds"); -+ return 0; - } - - if ($err) { - chomp $err; -- if ($err eq "__alarm__ignore__") { -- dbg("dk: lookup timed out after $timeout seconds"); -- } else { -- warn("dk: lookup failed: $err\n"); -- } -+ warn("dk: lookup failed: $err\n"); - return 0; - } - - -Modified: spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/Pyzor.pm -URL: http://svn.apache.org/viewcvs/spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/Pyzor.pm?rev=384590&r1=384589&r2=384590&view=diff -============================================================================== ---- spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/Pyzor.pm (original) -+++ spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/Pyzor.pm Thu Mar 9 11:51:59 2006 -@@ -35,6 +35,7 @@ - - use Mail::SpamAssassin::Plugin; - use Mail::SpamAssassin::Logger; -+use Mail::SpamAssassin::Timeout; - use strict; - use warnings; - use bytes; -@@ -229,27 +230,22 @@ - - $pyzor_count = 0; - $pyzor_whitelisted = 0; -- -- $permsgstatus->enter_helper_run_mode(); -+ my $pid; - - # use a temp file here -- open2() is unreliable, buffering-wise, under spamd - my $tmpf = $permsgstatus->create_fulltext_tmpfile($fulltext); -- my $oldalarm = 0; - -- my $pid; -- eval { -- # safe to use $SIG{ALRM} here instead of Util::trap_sigalrm_fully(), -- # since there are no killer regexp hang dangers here -- local $SIG{ALRM} = sub { die "__alarm__ignore__\n" }; -- local $SIG{PIPE} = sub { die "__brokenpipe__ignore__\n" }; -- local $SIG{__DIE__}; # bug 4631 -+ # note: not really tainted, this came from system configuration file -+ my $path = Mail::SpamAssassin::Util::untaint_file_path($self->{main}->{conf}->{pyzor_path}); -+ -+ my $opts = $self->{main}->{conf}->{pyzor_options} || ''; - -- $oldalarm = alarm $timeout; -+ $permsgstatus->enter_helper_run_mode(); - -- # note: not really tainted, this came from system configuration file -- my $path = Mail::SpamAssassin::Util::untaint_file_path($self->{main}->{conf}->{pyzor_path}); -+ my $timer = Mail::SpamAssassin::Timeout->new({ secs => $timeout }); -+ my $err = $timer->run_and_catch(sub { - -- my $opts = $self->{main}->{conf}->{pyzor_options} || ''; -+ local $SIG{PIPE} = sub { die "__brokenpipe__ignore__\n" }; - - dbg("pyzor: opening pipe: " . join(' ', $path, $opts, "check", "< $tmpf")); - -@@ -273,21 +269,7 @@ - die("internal error\n"); - } - -- # note: this must be called BEFORE leave_helper_run_mode() -- # $self->cleanup_kids($pid); -- -- # attempt to call this inside the eval, as leaving this scope is -- # a slow operation and timing *that* out is pointless -- if (defined $oldalarm) { -- alarm $oldalarm; $oldalarm = undef; -- } -- }; -- -- # clear the alarm before doing lots of time-consuming hard work -- my $err = $@; -- if (defined $oldalarm) { -- alarm $oldalarm; $oldalarm = undef; -- } -+ }); - - if (defined(fileno(*PYZOR))) { # still open - if ($pid) { -@@ -299,11 +281,14 @@ - } - $permsgstatus->leave_helper_run_mode(); - -+ if ($timer->timed_out()) { -+ dbg("pyzor: check timed out after $timeout seconds"); -+ return 0; -+ } -+ - if ($err) { - chomp $err; -- if ($err eq "__alarm__ignore__") { -- dbg("pyzor: check timed out after $timeout seconds"); -- } elsif ($err eq "__brokenpipe__ignore__") { -+ if ($err eq "__brokenpipe__ignore__") { - dbg("pyzor: check failed: broken pipe"); - } elsif ($err eq "no response") { - dbg("pyzor: check failed: no response"); -@@ -364,23 +349,19 @@ - - sub pyzor_report { - my ($self, $options, $tmpf) = @_; -+ -+ # note: not really tainted, this came from system configuration file -+ my $path = Mail::SpamAssassin::Util::untaint_file_path($options->{report}->{conf}->{pyzor_path}); -+ -+ my $opts = $options->{report}->{conf}->{pyzor_options} || ''; - my $timeout = $self->{main}->{conf}->{pyzor_timeout}; - - $options->{report}->enter_helper_run_mode(); - -- my $oldalarm = 0; -+ my $timer = Mail::SpamAssassin::Timeout->new({ secs => $timeout }); -+ my $err = $timer->run_and_catch(sub { - -- eval { -- local $SIG{ALRM} = sub { die "__alarm__ignore__\n" }; - local $SIG{PIPE} = sub { die "__brokenpipe__ignore__\n" }; -- local $SIG{__DIE__}; # bug 4631 -- -- $oldalarm = alarm $timeout; -- -- # note: not really tainted, this came from system configuration file -- my $path = Mail::SpamAssassin::Util::untaint_file_path($options->{report}->{conf}->{pyzor_path}); -- -- my $opts = $options->{report}->{conf}->{pyzor_options} || ''; - - dbg("pyzor: opening pipe: " . join(' ', $path, $opts, "report", "< $tmpf")); - -@@ -391,23 +372,19 @@ - my @ignored = ; - $options->{report}->close_pipe_fh(\*PYZOR); - -- if (defined $oldalarm) { -- alarm $oldalarm; $oldalarm = undef; -- } - waitpid ($pid, 0); -- }; -+ }); - -- my $err = $@; -- if (defined $oldalarm) { -- alarm $oldalarm; $oldalarm = undef; -- } - $options->{report}->leave_helper_run_mode(); - -+ if ($timer->timed_out()) { -+ dbg("reporter: pyzor report timed out after $timeout seconds"); -+ return 0; -+ } -+ - if ($err) { - chomp $err; -- if ($err eq '__alarm__ignore__') { -- dbg("reporter: pyzor report timed out after $timeout seconds"); -- } elsif ($err eq '__brokenpipe__ignore__') { -+ if ($err eq '__brokenpipe__ignore__') { - dbg("reporter: pyzor report failed: broken pipe"); - } else { - warn("reporter: pyzor report failed: $err\n"); - -Modified: spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/Razor2.pm -URL: http://svn.apache.org/viewcvs/spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/Razor2.pm?rev=384590&r1=384589&r2=384590&view=diff -============================================================================== ---- spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/Razor2.pm (original) -+++ spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/Razor2.pm Thu Mar 9 11:51:59 2006 -@@ -143,14 +143,11 @@ - } - - Mail::SpamAssassin::PerMsgStatus::enter_helper_run_mode($self); -- my $oldalarm = 0; - -- eval { -- local ($^W) = 0; # argh, warnings in Razor -+ my $timer = Mail::SpamAssassin::Timeout->new({ secs => $timeout }); -+ my $err = $timer->run_and_catch(sub { - -- local $SIG{ALRM} = sub { die "__alarm__ignore__\n" }; -- local $SIG{__DIE__}; # bug 4631 -- $oldalarm = alarm $timeout; -+ local ($^W) = 0; # argh, warnings in Razor - - # everything's in the module! - my $rc = Razor2::Client::Agent->new("razor-$type"); -@@ -184,7 +181,7 @@ - # let's reset the alarm since get_server_info() calls - # nextserver() which calls discover() which very likely will - # reset the alarm for us ... how polite. :( -- alarm $timeout; -+ $timer->reset(); - - # no facility prefix on this die - my $sigs = $rc->compute_sigs($objects) -@@ -219,100 +216,96 @@ - my $error = $rc->errprefix("$debug: spamassassin") || "$debug: razor2 had unknown error during disconnect"; - die $error; - } -+ } - -- # if we got here, we're done doing remote stuff, abort the alert -- if (defined $oldalarm) { -- alarm $oldalarm; $oldalarm = undef; -- } -- -- # Razor 2.14 says that if we get here, we did ok. -- $return = 1; -+ # Razor 2.14 says that if we get here, we did ok. -+ $return = 1; - -- # figure out if we have a log file we need to close... -- if (ref($rc->{logref}) && exists $rc->{logref}->{fd}) { -- # the fd can be stdout or stderr, so we need to find out if it is -- # so we don't close them by accident. Note: we can't just -- # undef the fd here (like the IO::Handle manpage says we can) -- # because it won't actually close, unfortunately. :( -- my $untie = 1; -- foreach my $log (*STDOUT{IO}, *STDERR{IO}) { -- if ($log == $rc->{logref}->{fd}) { -- $untie = 0; -- last; -- } -- } -- close $rc->{logref}->{fd} if ($untie); -- } -- -- if ($type eq 'check') { -- # so $objects->[0] is the first (only) message, and ->{spam} is a general yes/no -- push(@results, { result => $objects->[0]->{spam} }); -+ # figure out if we have a log file we need to close... -+ if (ref($rc->{logref}) && exists $rc->{logref}->{fd}) { -+ # the fd can be stdout or stderr, so we need to find out if it is -+ # so we don't close them by accident. Note: we can't just -+ # undef the fd here (like the IO::Handle manpage says we can) -+ # because it won't actually close, unfortunately. :( -+ my $untie = 1; -+ foreach my $log (*STDOUT{IO}, *STDERR{IO}) { -+ if ($log == $rc->{logref}->{fd}) { -+ $untie = 0; -+ last; -+ } -+ } -+ close $rc->{logref}->{fd} if ($untie); -+ } - -- # great for debugging, but leave this off! -- #use Data::Dumper; -- #print Dumper($objects),"\n"; -- -- # ->{p} is for each part of the message -- # so go through each part, taking the highest cf we find -- # of any part that isn't contested (ct). This helps avoid false -- # positives. equals logic_method 4. -- # -- # razor-agents < 2.14 have a different object format, so we now support both. -- # $objects->[0]->{resp} vs $objects->[0]->{p}->[part #]->{resp} -- my $part = 0; -- my $arrayref = $objects->[0]->{p} || $objects; -- if (defined $arrayref) { -- foreach my $cf (@{$arrayref}) { -- if (exists $cf->{resp}) { -- for (my $response=0; $response<@{$cf->{resp}}; $response++) { -- my $tmp = $cf->{resp}->[$response]; -- my $tmpcf = $tmp->{cf}; # Part confidence -- my $tmpct = $tmp->{ct}; # Part contested? -- my $engine = $cf->{sent}->[$response]->{e}; -- -- # These should always be set, but just in case ... -- $tmpcf = 0 unless defined $tmpcf; -- $tmpct = 0 unless defined $tmpct; -- $engine = 0 unless defined $engine; -- -- push(@results, -- { part => $part, engine => $engine, contested => $tmpct, confidence => $tmpcf }); -- } -- } -- else { -- push(@results, { part => $part, noresponse => 1 }); -- } -- $part++; -- } -- } -- else { -- # If we have some new $objects format that isn't close to -- # the current razor-agents 2.x version, we won't FP but we -- # should alert in debug. -- dbg("$debug: it looks like the internal Razor object has changed format!"); -- } -- } -+ if ($type eq 'check') { -+ # so $objects->[0] is the first (only) message, and ->{spam} is a general yes/no -+ push(@results, { result => $objects->[0]->{spam} }); -+ -+ # great for debugging, but leave this off! -+ #use Data::Dumper; -+ #print Dumper($objects),"\n"; -+ -+ # ->{p} is for each part of the message -+ # so go through each part, taking the highest cf we find -+ # of any part that isn't contested (ct). This helps avoid false -+ # positives. equals logic_method 4. -+ # -+ # razor-agents < 2.14 have a different object format, so we now support both. -+ # $objects->[0]->{resp} vs $objects->[0]->{p}->[part #]->{resp} -+ my $part = 0; -+ my $arrayref = $objects->[0]->{p} || $objects; -+ if (defined $arrayref) { -+ foreach my $cf (@{$arrayref}) { -+ if (exists $cf->{resp}) { -+ for (my $response=0; $response<@{$cf->{resp}}; $response++) { -+ my $tmp = $cf->{resp}->[$response]; -+ my $tmpcf = $tmp->{cf}; # Part confidence -+ my $tmpct = $tmp->{ct}; # Part contested? -+ my $engine = $cf->{sent}->[$response]->{e}; -+ -+ # These should always be set, but just in case ... -+ $tmpcf = 0 unless defined $tmpcf; -+ $tmpct = 0 unless defined $tmpct; -+ $engine = 0 unless defined $engine; -+ -+ push(@results, -+ { part => $part, engine => $engine, contested => $tmpct, confidence => $tmpcf }); -+ } -+ } -+ else { -+ push(@results, { part => $part, noresponse => 1 }); -+ } -+ $part++; -+ } -+ } -+ else { -+ # If we have some new $objects format that isn't close to -+ # the current razor-agents 2.x version, we won't FP but we -+ # should alert in debug. -+ dbg("$debug: it looks like the internal Razor object has changed format!"); -+ } - } - } - else { - warn "$debug: undefined Razor2::Client::Agent\n"; - } - -- if (defined $oldalarm) { -- alarm $oldalarm; $oldalarm = undef; -- } -- }; -+ }); -+ -+ # OK, that's enough Razor stuff. now, reset all that global -+ # state it futzes with :( -+ # work around serious brain damage in Razor2 (constant seed) -+ srand; - -- my $err = $@; -- if (defined $oldalarm) { -- alarm $oldalarm; $oldalarm = undef; -+ Mail::SpamAssassin::PerMsgStatus::leave_helper_run_mode($self); -+ -+ if ($timer->timed_out()) { -+ dbg("$debug: razor2 $type timed out after $timeout seconds"); - } - - if ($err) { - chomp $err; -- if ($err eq "__alarm__ignore__") { -- dbg("$debug: razor2 $type timed out after $timeout seconds"); -- } elsif ($err =~ /(?:could not connect|network is unreachable)/) { -+ if ($err =~ /(?:could not connect|network is unreachable)/) { - # make this a dbg(); SpamAssassin will still continue, - # but without Razor checking. otherwise there may be - # DSNs and errors in syslog etc., yuck -@@ -323,11 +316,6 @@ - warn("$debug: razor2 $type failed: $! $err"); - } - } -- -- # work around serious brain damage in Razor2 (constant seed) -- srand; -- -- Mail::SpamAssassin::PerMsgStatus::leave_helper_run_mode($self); - - # razor also debugs to stdout. argh. fix it to stderr... - if (would_log('dbg', $debug)) { - -Modified: spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/SPF.pm -URL: http://svn.apache.org/viewcvs/spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/SPF.pm?rev=384590&r1=384589&r2=384590&view=diff -============================================================================== ---- spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/SPF.pm (original) -+++ spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/SPF.pm Thu Mar 9 11:51:59 2006 -@@ -34,6 +34,7 @@ - - use Mail::SpamAssassin::Plugin; - use Mail::SpamAssassin::Logger; -+use Mail::SpamAssassin::Timeout; - use strict; - use warnings; - use bytes; -@@ -300,30 +301,17 @@ - - my ($result, $comment); - my $timeout = $scanner->{conf}->{spf_timeout}; -- my $oldalarm = 0; - -- eval { -- local $SIG{ALRM} = sub { die "__alarm__ignore__\n" }; -- local $SIG{__DIE__}; # bug 4631 -- $oldalarm = alarm($timeout); -+ my $timer = Mail::SpamAssassin::Timeout->new({ secs => $timeout }); -+ my $err = $timer->run_and_catch(sub { -+ - ($result, $comment) = $query->result(); -- if (defined $oldalarm) { -- alarm $oldalarm; $oldalarm = undef; -- } -- }; - -- my $err = $@; -- if (defined $oldalarm) { -- alarm $oldalarm; $oldalarm = undef; -- } -+ }); - - if ($err) { - chomp $err; -- if ($err eq "__alarm__ignore__") { -- dbg("spf: lookup timed out after $timeout seconds"); -- } else { -- warn("spf: lookup failed: $err\n"); -- } -+ warn("spf: lookup failed: $err\n"); - return 0; - } - - -Modified: spamassassin/branches/3.1/lib/Mail/SpamAssassin/SpamdForkScaling.pm -URL: http://svn.apache.org/viewcvs/spamassassin/branches/3.1/lib/Mail/SpamAssassin/SpamdForkScaling.pm?rev=384590&r1=384589&r2=384590&view=diff -============================================================================== ---- spamassassin/branches/3.1/lib/Mail/SpamAssassin/SpamdForkScaling.pm (original) -+++ spamassassin/branches/3.1/lib/Mail/SpamAssassin/SpamdForkScaling.pm Thu Mar 9 11:51:59 2006 -@@ -25,6 +25,7 @@ - - use Mail::SpamAssassin::Util; - use Mail::SpamAssassin::Logger; -+use Mail::SpamAssassin::Timeout; - - use vars qw { - @PFSTATE_VARS %EXPORT_TAGS @EXPORT_OK -@@ -109,6 +110,9 @@ - - delete $self->{kids}->{$pid}; - -+ # note this for the select()-caller's benefit -+ $self->{child_just_exited} = 1; -+ - # remove the child from the backchannel list, too - $self->{backchannel}->delete_socket_for_child($pid); - -@@ -188,24 +192,63 @@ - vec($rin, $self->{server_fileno}, 1) = 0; - } - -- my ($rout, $eout, $nfound, $timeleft); -+ my ($rout, $eout, $nfound, $timeleft, $selerr); -+ -+ # use alarm to back up select()'s built-in alarm, to debug Theo's bug. -+ # not that I can remember what Theo's bug was, but hey ;) A good -+ # 60 seconds extra on the alarm() should make that quite rare... -+ -+ my $timer = Mail::SpamAssassin::Timeout->new({ secs => ($tout*2) + 60 }); - -- # use alarm to back up select()'s built-in alarm, to debug theo's bug -- eval { -- Mail::SpamAssassin::Util::trap_sigalrm_fully(sub { die "tcp timeout"; }); -- alarm ($tout*2) if ($tout); -+ $timer->run(sub { -+ -+ $self->{child_just_exited} = 0; - ($nfound, $timeleft) = select($rout=$rin, undef, $eout=$rin, $tout); -- }; -- alarm 0; -+ $selerr = $!; - -- if ($@) { -- warn "prefork: select timeout failed! recovering\n"; -- sleep 1; # avoid overload -- return; -- } -+ }); -+ -+ # bug 4696: under load, the process can go for such a long time without -+ # being context-switched in, that when it does return the alarm() fires -+ # before the select() timeout does. Treat this as a select() timeout -+ if ($timer->timed_out) { -+ dbg("prefork: select timed out (via alarm)"); -+ $nfound = 0; -+ $timeleft = 0; -+ } -+ -+ # errors; handle undef *or* -1 returned. do this before "errors on -+ # the handle" below, since an error condition is signalled both via -+ # a -1 return and a $eout bit. -+ if (!defined $nfound || $nfound < 0) -+ { -+ if (exists &Errno::EINTR && $selerr == &Errno::EINTR) -+ { -+ # this happens if the process is signalled during the select(), -+ # for example if someone sends SIGHUP to reload the configuration. -+ # just return inmmediately -+ dbg("prefork: select returned err $selerr, probably signalled"); -+ return; -+ } -+ -+ # if a child exits during that select() call, it generates a spurious -+ # error, like this: -+ # -+ # Jan 29 12:53:17 dogma spamd[18518]: prefork: child states: BI -+ # Jan 29 12:53:17 dogma spamd[18518]: spamd: handled cleanup of child pid 13101 due to SIGCHLD -+ # Jan 29 12:53:17 dogma spamd[18518]: prefork: select returned -1! recovering: -+ # -+ # avoid by setting a boolean in the child_exited() callback and checking -+ # it here. log $! just in case, though. -+ if ($self->{child_just_exited} && $nfound == -1) { -+ dbg("prefork: select returned -1 due to child exiting, ignored ($selerr)"); -+ return; -+ } -+ -+ warn "prefork: select returned ". -+ (defined $nfound ? $nfound : "undef"). -+ "! recovering: $selerr\n"; - -- if (!defined $nfound) { -- warn "prefork: select returned undef! recovering\n"; - sleep 1; # avoid overload - return; - } -@@ -213,7 +256,7 @@ - # errors on the handle? - # return them immediately, they may be from a SIGHUP restart signal - if (vec ($eout, $self->{server_fileno}, 1)) { -- warn "prefork: select returned error on server filehandle: $!\n"; -+ warn "prefork: select returned error on server filehandle: $selerr $!\n"; - return; - } - -@@ -282,7 +325,7 @@ - - my ($sock, $kid); - while (($kid, $sock) = each %{$self->{backchannel}->{kids}}) { -- $self->syswrite_with_retry($sock, PF_PING_ORDER) and next; -+ $self->syswrite_with_retry($sock, PF_PING_ORDER, $kid, 3) and next; - - warn "prefork: write of ping failed to $kid fd=".$sock->fileno.": ".$!; - -@@ -353,7 +396,7 @@ - return $self->order_idle_child_to_accept(); - } - -- if (!$self->syswrite_with_retry($sock, PF_ACCEPT_ORDER)) -+ if (!$self->syswrite_with_retry($sock, PF_ACCEPT_ORDER, $kid)) - { - # failure to write to the child; bad news. call it dead - warn "prefork: killing rogue child $kid, failed to write on fd ".$sock->fileno.": $!\n"; -@@ -396,7 +439,7 @@ - my ($self, $kid) = @_; - if ($self->{waiting_for_idle_child}) { - my $sock = $self->{backchannel}->get_socket_for_child($kid); -- $self->syswrite_with_retry($sock, PF_ACCEPT_ORDER) -+ $self->syswrite_with_retry($sock, PF_ACCEPT_ORDER, $kid) - or die "prefork: $kid claimed it was ready, but write failed on fd ". - $sock->fileno.": ".$!; - $self->{waiting_for_idle_child} = 0; -@@ -426,7 +469,7 @@ - sub report_backchannel_socket { - my ($self, $str) = @_; - my $sock = $self->{backchannel}->get_parent_socket(); -- $self->syswrite_with_retry($sock, $str) -+ $self->syswrite_with_retry($sock, $str, 'parent') - or write "syswrite() to parent failed: $!"; - } - -@@ -537,12 +580,31 @@ - } - - sub syswrite_with_retry { -- my ($self, $sock, $buf) = @_; -+ my ($self, $sock, $buf, $targetname, $numretries) = @_; -+ $numretries ||= 10; # default 10 retries - - my $written = 0; -+ my $try = 0; - - retry_write: -+ -+ $try++; -+ if ($try > 1) { -+ warn "prefork: syswrite(".$sock->fileno.") to $targetname failed on try $try"; -+ if ($try > $numretries) { -+ warn "prefork: giving up"; -+ return undef; -+ } -+ else { -+ # give it 1 second to recover. we retry indefinitely. -+ my $rout = ''; -+ vec($rout, $sock->fileno, 1) = 1; -+ select(undef, $rout, undef, 1); -+ } -+ } -+ - my $nbytes = $sock->syswrite($buf); -+ - if (!defined $nbytes) { - unless ((exists &Errno::EAGAIN && $! == &Errno::EAGAIN) - || (exists &Errno::EWOULDBLOCK && $! == &Errno::EWOULDBLOCK)) -@@ -551,13 +613,7 @@ - return undef; - } - -- warn "prefork: syswrite(".$sock->fileno.") failed, retrying..."; -- -- # give it 5 seconds to recover. we retry indefinitely. -- my $rout = ''; -- vec($rout, $sock->fileno, 1) = 1; -- select(undef, $rout, undef, 5); -- -+ warn "prefork: retrying syswrite(): $!"; - goto retry_write; - } - else { -@@ -568,7 +624,8 @@ - return $written; # it's complete, we can return - } - else { -- warn "prefork: partial write of $nbytes, towrite=".length($buf). -+ warn "prefork: partial write of $nbytes to ". -+ $targetname.", towrite=".length($buf). - " sofar=".$written." fd=".$sock->fileno.", recovering"; - goto retry_write; - } - -Added: spamassassin/branches/3.1/lib/Mail/SpamAssassin/Timeout.pm -URL: http://svn.apache.org/viewcvs/spamassassin/branches/3.1/lib/Mail/SpamAssassin/Timeout.pm?rev=384590&view=auto -============================================================================== ---- spamassassin/branches/3.1/lib/Mail/SpamAssassin/Timeout.pm (added) -+++ spamassassin/branches/3.1/lib/Mail/SpamAssassin/Timeout.pm Thu Mar 9 11:51:59 2006 -@@ -0,0 +1,215 @@ -+# <@LICENSE> -+# Copyright 2004 Apache Software Foundation -+# -+# Licensed under the Apache License, Version 2.0 (the "License"); -+# you may not use this file except in compliance with the License. -+# You may obtain a copy of the License at -+# -+# http://www.apache.org/licenses/LICENSE-2.0 -+# -+# Unless required by applicable law or agreed to in writing, software -+# distributed under the License is distributed on an "AS IS" BASIS, -+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+# See the License for the specific language governing permissions and -+# limitations under the License. -+# -+ -+=head1 NAME -+ -+Mail::SpamAssassin::Timeout - safe, reliable timeouts in perl -+ -+=head1 SYNOPSIS -+ -+ # non-timeout code... -+ -+ my $t = Mail::SpamAssassin::Timeout->new({ secs => 5 }); -+ -+ $t->run(sub { -+ # code to run with a 5-second timeout... -+ }); -+ -+ if ($t->timed_out()) { -+ # do something... -+ } -+ -+ # more non-timeout code... -+ -+=head1 DESCRIPTION -+ -+This module provides a safe, reliable and clean API to provide -+C-based timeouts for perl code. -+ -+Note that C<$SIG{ALRM}> is used to provide the timeout, so this will not -+interrupt out-of-control regular expression matches. -+ -+Nested timeouts are supported. -+ -+=head1 PUBLIC METHODS -+ -+=over 4 -+ -+=cut -+ -+package Mail::SpamAssassin::Timeout; -+ -+use strict; -+use warnings; -+use bytes; -+ -+use vars qw{ -+ @ISA -+}; -+ -+@ISA = qw(); -+ -+########################################################################### -+ -+=item my $t = Mail::SpamAssassin::Timeout->new({ ... options ... }); -+ -+Constructor. Options include: -+ -+=over 4 -+ -+=item secs => $seconds -+ -+timeout, in seconds. Optional; if not specified, no timeouts will be applied. -+ -+=back -+ -+=cut -+ -+sub new { -+ my ($class, $opts) = @_; -+ $class = ref($class) || $class; -+ my %selfval = $opts ? %{$opts} : (); -+ my $self = \%selfval; -+ -+ bless ($self, $class); -+ $self; -+} -+ -+########################################################################### -+ -+=item $t->run($coderef) -+ -+Run a code reference within the currently-defined timeout. -+ -+The timeout is as defined by the B parameter to the constructor. -+ -+Returns whatever the subroutine returns, or C on timeout. -+If the timer times out, C<$t-timed_out()> will return C<1>. -+ -+Time elapsed is not cumulative; multiple runs of C will restart the -+timeout from scratch. -+ -+=item $t->run_and_catch($coderef) -+ -+Run a code reference, as per C<$t-run()>, but also catching any -+C calls within the code reference. -+ -+Returns C if no C call was executed and C<$@> was unset, or the -+value of C<$@> if it was set. (The timeout event doesn't count as a C.) -+ -+=cut -+ -+sub run { $_[0]->_run($_[1], 0); } -+ -+sub run_and_catch { $_[0]->_run($_[1], 1); } -+ -+sub _run { # private -+ my ($self, $sub, $and_catch) = @_; -+ -+ delete $self->{timed_out}; -+ -+ if (!$self->{secs}) { # no timeout! just call the sub and return. -+ return &$sub; -+ } -+ -+ # assertion -+ if ($self->{secs} < 0) { -+ die "Mail::SpamAssassin::Timeout: oops? neg value for 'secs': $self->{secs}"; -+ } -+ -+ my $oldalarm = 0; -+ my $ret; -+ -+ eval { -+ # note use of local to ensure closed scope here -+ local $SIG{ALRM} = sub { die "__alarm__ignore__\n" }; -+ local $SIG{__DIE__}; # bug 4631 -+ -+ $oldalarm = alarm($self->{secs}); -+ -+ $ret = &$sub; -+ -+ # Unset the alarm() before we leave eval{ } scope, as that stack-pop -+ # operation can take a second or two under load. Note: previous versions -+ # restored $oldalarm here; however, that is NOT what we want to do, since -+ # it creates a new race condition, namely that an old alarm could then fire -+ # while the stack-pop was underway, thereby appearing to be *this* timeout -+ # timing out. In terms of how we might possibly have nested timeouts in -+ # SpamAssassin, this is an academic issue with little impact, but it's -+ # still worth avoiding anyway. -+ -+ alarm 0; -+ }; -+ -+ my $err = $@; -+ -+ if (defined $oldalarm) { -+ # now, we could have died from a SIGALRM == timed out. if so, -+ # restore the previously-active one, or zero all timeouts if none -+ # were previously active. -+ alarm $oldalarm; -+ } -+ -+ if ($err) { -+ if ($err =~ /__alarm__ignore__/) { -+ $self->{timed_out} = 1; -+ } else { -+ if ($and_catch) { -+ return $@; -+ } else { -+ die $@; # propagate any "real" errors -+ } -+ } -+ } -+ -+ if ($and_catch) { -+ return; # undef -+ } else { -+ return $ret; -+ } -+} -+ -+########################################################################### -+ -+=item $t->timed_out() -+ -+Returns C<1> if the most recent code executed in C timed out, or -+C if it did not. -+ -+=cut -+ -+sub timed_out { -+ my ($self) = @_; -+ return $self->{timed_out}; -+} -+ -+########################################################################### -+ -+=item $t->reset() -+ -+If called within a C code reference, causes the current alarm timer to -+be reset to its starting value. -+ -+=cut -+ -+sub reset { -+ my ($self) = @_; -+ alarm($self->{secs}); -+} -+ -+########################################################################### -+ -+1; - -Modified: spamassassin/branches/3.1/spamd/spamd.raw -URL: http://svn.apache.org/viewcvs/spamassassin/branches/3.1/spamd/spamd.raw?rev=384590&r1=384589&r2=384590&view=diff -============================================================================== ---- spamassassin/branches/3.1/spamd/spamd.raw (original) -+++ spamassassin/branches/3.1/spamd/spamd.raw Thu Mar 9 11:51:59 2006 -@@ -2049,6 +2049,9 @@ - foreach (keys %children) { - kill 'INT' => $_; - my $pid = waitpid($_, 0); -+ if ($scaling) { -+ $scaling->child_exited($pid); -+ } - info("spamd: child $pid killed successfully"); - } - %children = (); - - - - - \ No newline at end of file diff --git a/tools/buildbot/pylibs/buildbot/test/mail/syncmail.1 b/tools/buildbot/pylibs/buildbot/test/mail/syncmail.1 deleted file mode 100644 index eb35e25..0000000 --- a/tools/buildbot/pylibs/buildbot/test/mail/syncmail.1 +++ /dev/null @@ -1,152 +0,0 @@ -Return-Path: -Delivered-To: warner-sourceforge@luther.lothar.com -Received: (qmail 23758 invoked by uid 1000); 28 Jul 2003 07:22:14 -0000 -Delivered-To: warner-sourceforge@lothar.com -Received: (qmail 62715 invoked by uid 13574); 28 Jul 2003 07:22:03 -0000 -Received: from unknown (HELO sc8-sf-list1.sourceforge.net) ([66.35.250.206]) (envelope-sender ) - by 130.94.181.6 (qmail-ldap-1.03) with SMTP - for ; 28 Jul 2003 07:22:03 -0000 -Received: from sc8-sf-sshgate.sourceforge.net ([66.35.250.220] helo=sc8-sf-netmisc.sourceforge.net) - by sc8-sf-list1.sourceforge.net with esmtp - (Cipher TLSv1:DES-CBC3-SHA:168) (Exim 3.31-VA-mm2 #1 (Debian)) - id 19h2KY-0004Nr-00 - for ; Mon, 28 Jul 2003 00:22:02 -0700 -Received: from sc8-pr-cvs1-b.sourceforge.net ([10.5.1.7] helo=sc8-pr-cvs1.sourceforge.net) - by sc8-sf-netmisc.sourceforge.net with esmtp (Exim 3.36 #1 (Debian)) - id 19h2KY-0001rv-00 - for ; Mon, 28 Jul 2003 00:22:02 -0700 -Received: from localhost ([127.0.0.1] helo=sc8-pr-cvs1.sourceforge.net) - by sc8-pr-cvs1.sourceforge.net with esmtp (Exim 3.22 #1 (Debian)) - id 19h2KY-0003r4-00 - for ; Mon, 28 Jul 2003 00:22:02 -0700 -From: warner@users.sourceforge.net -To: warner@users.sourceforge.net -Subject: buildbot/buildbot/changes freshcvsmail.py,1.2,1.3 -Message-Id: -Date: Mon, 28 Jul 2003 00:22:02 -0700 -Status: - -Update of /cvsroot/buildbot/buildbot/buildbot/changes -In directory sc8-pr-cvs1:/tmp/cvs-serv14795/buildbot/changes - -Modified Files: - freshcvsmail.py -Log Message: -remove leftover code, leave a temporary compatibility import. Note! Start -importing FCMaildirSource from changes.mail instead of changes.freshcvsmail - - -Index: freshcvsmail.py -=================================================================== -RCS file: /cvsroot/buildbot/buildbot/buildbot/changes/freshcvsmail.py,v -retrieving revision 1.2 -retrieving revision 1.3 -diff -C2 -d -r1.2 -r1.3 -*** freshcvsmail.py 27 Jul 2003 18:54:08 -0000 1.2 ---- freshcvsmail.py 28 Jul 2003 07:22:00 -0000 1.3 -*************** -*** 1,96 **** - #! /usr/bin/python - -! from buildbot.interfaces import IChangeSource -! from buildbot.changes.maildirtwisted import MaildirTwisted -! from buildbot.changes.changes import Change -! from rfc822 import Message -! import os, os.path -! -! def parseFreshCVSMail(fd, prefix=None): -! """Parse mail sent by FreshCVS""" -! # this uses rfc822.Message so it can run under python2.1 . In the future -! # it will be updated to use python2.2's "email" module. -! -! m = Message(fd) -! # FreshCVS sets From: to "user CVS ", but the <> part may be -! # modified by the MTA (to include a local domain) -! name, addr = m.getaddr("from") -! if not name: -! return None # no From means this message isn't from FreshCVS -! cvs = name.find(" CVS") -! if cvs == -1: -! return None # this message isn't from FreshCVS -! who = name[:cvs] -! -! # we take the time of receipt as the time of checkin. Not correct, -! # but it avoids the out-of-order-changes issue -! #when = m.getdate() # and convert from 9-tuple, and handle timezone -! -! files = [] -! comments = "" -! isdir = 0 -! lines = m.fp.readlines() -! while lines: -! line = lines.pop(0) -! if line == "Modified files:\n": -! break -! while lines: -! line = lines.pop(0) -! if line == "\n": -! break -! line = line.rstrip("\n") -! file, junk = line.split(None, 1) -! if prefix: -! # insist that the file start with the prefix: FreshCVS sends -! # changes we don't care about too -! bits = file.split(os.sep) -! if bits[0] == prefix: -! file = apply(os.path.join, bits[1:]) -! else: -! break -! if junk == "0 0": -! isdir = 1 -! files.append(file) -! while lines: -! line = lines.pop(0) -! if line == "Log message:\n": -! break -! # message is terminated by "ViewCVS links:" or "Index:..." (patch) -! while lines: -! line = lines.pop(0) -! if line == "ViewCVS links:\n": -! break -! if line.find("Index: ") == 0: -! break -! comments += line -! comments = comments.rstrip() + "\n" -! -! if not files: -! return None -! -! change = Change(who, files, comments, isdir) -! -! return change -! -! -! -! class FCMaildirSource(MaildirTwisted): -! """This source will watch a maildir that is subscribed to a FreshCVS -! change-announcement mailing list. -! """ -! -! __implements__ = IChangeSource, - -! def __init__(self, maildir, prefix=None): -! MaildirTwisted.__init__(self, maildir) -! self.changemaster = None # filled in when added -! self.prefix = prefix -! def describe(self): -! return "FreshCVS mailing list in maildir %s" % self.maildir.where -! def messageReceived(self, filename): -! path = os.path.join(self.basedir, "new", filename) -! change = parseFreshCVSMail(open(path, "r"), self.prefix) -! if change: -! self.changemaster.addChange(change) -! os.rename(os.path.join(self.basedir, "new", filename), -! os.path.join(self.basedir, "cur", filename)) ---- 1,5 ---- - #! /usr/bin/python - -! # leftover import for compatibility - -! from buildbot.changes.mail import FCMaildirSource - - diff --git a/tools/buildbot/pylibs/buildbot/test/mail/syncmail.2 b/tools/buildbot/pylibs/buildbot/test/mail/syncmail.2 deleted file mode 100644 index 5296cbe..0000000 --- a/tools/buildbot/pylibs/buildbot/test/mail/syncmail.2 +++ /dev/null @@ -1,56 +0,0 @@ -Return-Path: -Delivered-To: warner-sourceforge@luther.lothar.com -Received: (qmail 23221 invoked by uid 1000); 28 Jul 2003 06:53:15 -0000 -Delivered-To: warner-sourceforge@lothar.com -Received: (qmail 58537 invoked by uid 13574); 28 Jul 2003 06:53:09 -0000 -Received: from unknown (HELO sc8-sf-list1.sourceforge.net) ([66.35.250.206]) (envelope-sender ) - by 130.94.181.6 (qmail-ldap-1.03) with SMTP - for ; 28 Jul 2003 06:53:09 -0000 -Received: from sc8-sf-sshgate.sourceforge.net ([66.35.250.220] helo=sc8-sf-netmisc.sourceforge.net) - by sc8-sf-list1.sourceforge.net with esmtp - (Cipher TLSv1:DES-CBC3-SHA:168) (Exim 3.31-VA-mm2 #1 (Debian)) - id 19h1sb-0003nw-00 - for ; Sun, 27 Jul 2003 23:53:09 -0700 -Received: from sc8-pr-cvs1-b.sourceforge.net ([10.5.1.7] helo=sc8-pr-cvs1.sourceforge.net) - by sc8-sf-netmisc.sourceforge.net with esmtp (Exim 3.36 #1 (Debian)) - id 19h1sa-00018t-00 - for ; Sun, 27 Jul 2003 23:53:08 -0700 -Received: from localhost ([127.0.0.1] helo=sc8-pr-cvs1.sourceforge.net) - by sc8-pr-cvs1.sourceforge.net with esmtp (Exim 3.22 #1 (Debian)) - id 19h1sa-0002mX-00 - for ; Sun, 27 Jul 2003 23:53:08 -0700 -From: warner@users.sourceforge.net -To: warner@users.sourceforge.net -Subject: buildbot ChangeLog,1.93,1.94 -Message-Id: -Date: Sun, 27 Jul 2003 23:53:08 -0700 -Status: - -Update of /cvsroot/buildbot/buildbot -In directory sc8-pr-cvs1:/tmp/cvs-serv10689 - -Modified Files: - ChangeLog -Log Message: - * NEWS: started adding new features - - -Index: ChangeLog -=================================================================== -RCS file: /cvsroot/buildbot/buildbot/ChangeLog,v -retrieving revision 1.93 -retrieving revision 1.94 -diff -C2 -d -r1.93 -r1.94 -*** ChangeLog 27 Jul 2003 22:53:27 -0000 1.93 ---- ChangeLog 28 Jul 2003 06:53:06 -0000 1.94 -*************** -*** 1,4 **** ---- 1,6 ---- - 2003-07-27 Brian Warner - -+ * NEWS: started adding new features -+ - * buildbot/changes/mail.py: start work on Syncmail parser, move - mail sources into their own file - - diff --git a/tools/buildbot/pylibs/buildbot/test/mail/syncmail.3 b/tools/buildbot/pylibs/buildbot/test/mail/syncmail.3 deleted file mode 100644 index eee19b1..0000000 --- a/tools/buildbot/pylibs/buildbot/test/mail/syncmail.3 +++ /dev/null @@ -1,39 +0,0 @@ -Return-Path: -Delivered-To: warner-sourceforge@luther.lothar.com -Received: (qmail 23196 invoked by uid 1000); 28 Jul 2003 06:51:53 -0000 -Delivered-To: warner-sourceforge@lothar.com -Received: (qmail 58269 invoked by uid 13574); 28 Jul 2003 06:51:46 -0000 -Received: from unknown (HELO sc8-sf-list1.sourceforge.net) ([66.35.250.206]) (envelope-sender ) - by 130.94.181.6 (qmail-ldap-1.03) with SMTP - for ; 28 Jul 2003 06:51:46 -0000 -Received: from sc8-sf-sshgate.sourceforge.net ([66.35.250.220] helo=sc8-sf-netmisc.sourceforge.net) - by sc8-sf-list1.sourceforge.net with esmtp - (Cipher TLSv1:DES-CBC3-SHA:168) (Exim 3.31-VA-mm2 #1 (Debian)) - id 19h1rF-00027s-00 - for ; Sun, 27 Jul 2003 23:51:46 -0700 -Received: from sc8-pr-cvs1-b.sourceforge.net ([10.5.1.7] helo=sc8-pr-cvs1.sourceforge.net) - by sc8-sf-netmisc.sourceforge.net with esmtp (Exim 3.36 #1 (Debian)) - id 19h1rF-00017O-00 - for ; Sun, 27 Jul 2003 23:51:45 -0700 -Received: from localhost ([127.0.0.1] helo=sc8-pr-cvs1.sourceforge.net) - by sc8-pr-cvs1.sourceforge.net with esmtp (Exim 3.22 #1 (Debian)) - id 19h1rF-0002jg-00 - for ; Sun, 27 Jul 2003 23:51:45 -0700 -From: warner@users.sourceforge.net -To: warner@users.sourceforge.net -Subject: CVSROOT syncmail,1.1,NONE -Message-Id: -Date: Sun, 27 Jul 2003 23:51:45 -0700 -Status: - -Update of /cvsroot/buildbot/CVSROOT -In directory sc8-pr-cvs1:/tmp/cvs-serv10515 - -Removed Files: - syncmail -Log Message: -nevermind - ---- syncmail DELETED --- - - diff --git a/tools/buildbot/pylibs/buildbot/test/mail/syncmail.4 b/tools/buildbot/pylibs/buildbot/test/mail/syncmail.4 deleted file mode 100644 index 44bda5d..0000000 --- a/tools/buildbot/pylibs/buildbot/test/mail/syncmail.4 +++ /dev/null @@ -1,290 +0,0 @@ -Return-Path: -Delivered-To: warner-sourceforge@luther.lothar.com -Received: (qmail 24111 invoked by uid 1000); 28 Jul 2003 08:01:54 -0000 -Delivered-To: warner-sourceforge@lothar.com -Received: (qmail 68756 invoked by uid 13574); 28 Jul 2003 08:01:46 -0000 -Received: from unknown (HELO sc8-sf-list1.sourceforge.net) ([66.35.250.206]) (envelope-sender ) - by 130.94.181.6 (qmail-ldap-1.03) with SMTP - for ; 28 Jul 2003 08:01:46 -0000 -Received: from sc8-sf-sshgate.sourceforge.net ([66.35.250.220] helo=sc8-sf-netmisc.sourceforge.net) - by sc8-sf-list1.sourceforge.net with esmtp - (Cipher TLSv1:DES-CBC3-SHA:168) (Exim 3.31-VA-mm2 #1 (Debian)) - id 19h2wz-00029d-00 - for ; Mon, 28 Jul 2003 01:01:45 -0700 -Received: from sc8-pr-cvs1-b.sourceforge.net ([10.5.1.7] helo=sc8-pr-cvs1.sourceforge.net) - by sc8-sf-netmisc.sourceforge.net with esmtp (Exim 3.36 #1 (Debian)) - id 19h2wz-0002XB-00 - for ; Mon, 28 Jul 2003 01:01:45 -0700 -Received: from localhost ([127.0.0.1] helo=sc8-pr-cvs1.sourceforge.net) - by sc8-pr-cvs1.sourceforge.net with esmtp (Exim 3.22 #1 (Debian)) - id 19h2wz-0005a9-00 - for ; Mon, 28 Jul 2003 01:01:45 -0700 -From: warner@users.sourceforge.net -To: warner@users.sourceforge.net -Subject: buildbot/test/mail syncmail.1,NONE,1.1 syncmail.2,NONE,1.1 syncmail.3,NONE,1.1 -Message-Id: -Date: Mon, 28 Jul 2003 01:01:45 -0700 -Status: - -Update of /cvsroot/buildbot/buildbot/test/mail -In directory sc8-pr-cvs1:/tmp/cvs-serv21445 - -Added Files: - syncmail.1 syncmail.2 syncmail.3 -Log Message: -test cases for syncmail parser - ---- NEW FILE: syncmail.1 --- -Return-Path: -Delivered-To: warner-sourceforge@luther.lothar.com -Received: (qmail 23758 invoked by uid 1000); 28 Jul 2003 07:22:14 -0000 -Delivered-To: warner-sourceforge@lothar.com -Received: (qmail 62715 invoked by uid 13574); 28 Jul 2003 07:22:03 -0000 -Received: from unknown (HELO sc8-sf-list1.sourceforge.net) ([66.35.250.206]) (envelope-sender ) - by 130.94.181.6 (qmail-ldap-1.03) with SMTP - for ; 28 Jul 2003 07:22:03 -0000 -Received: from sc8-sf-sshgate.sourceforge.net ([66.35.250.220] helo=sc8-sf-netmisc.sourceforge.net) - by sc8-sf-list1.sourceforge.net with esmtp - (Cipher TLSv1:DES-CBC3-SHA:168) (Exim 3.31-VA-mm2 #1 (Debian)) - id 19h2KY-0004Nr-00 - for ; Mon, 28 Jul 2003 00:22:02 -0700 -Received: from sc8-pr-cvs1-b.sourceforge.net ([10.5.1.7] helo=sc8-pr-cvs1.sourceforge.net) - by sc8-sf-netmisc.sourceforge.net with esmtp (Exim 3.36 #1 (Debian)) - id 19h2KY-0001rv-00 - for ; Mon, 28 Jul 2003 00:22:02 -0700 -Received: from localhost ([127.0.0.1] helo=sc8-pr-cvs1.sourceforge.net) - by sc8-pr-cvs1.sourceforge.net with esmtp (Exim 3.22 #1 (Debian)) - id 19h2KY-0003r4-00 - for ; Mon, 28 Jul 2003 00:22:02 -0700 -From: warner@users.sourceforge.net -To: warner@users.sourceforge.net -Subject: buildbot/buildbot/changes freshcvsmail.py,1.2,1.3 -Message-Id: -Date: Mon, 28 Jul 2003 00:22:02 -0700 -Status: - -Update of /cvsroot/buildbot/buildbot/buildbot/changes -In directory sc8-pr-cvs1:/tmp/cvs-serv14795/buildbot/changes - -Modified Files: - freshcvsmail.py -Log Message: -remove leftover code, leave a temporary compatibility import. Note! Start -importing FCMaildirSource from changes.mail instead of changes.freshcvsmail - - -Index: freshcvsmail.py -=================================================================== -RCS file: /cvsroot/buildbot/buildbot/buildbot/changes/freshcvsmail.py,v -retrieving revision 1.2 -retrieving revision 1.3 -diff -C2 -d -r1.2 -r1.3 -*** freshcvsmail.py 27 Jul 2003 18:54:08 -0000 1.2 ---- freshcvsmail.py 28 Jul 2003 07:22:00 -0000 1.3 -*************** -*** 1,96 **** - #! /usr/bin/python - -! from buildbot.interfaces import IChangeSource -! from buildbot.changes.maildirtwisted import MaildirTwisted -! from buildbot.changes.changes import Change -! from rfc822 import Message -! import os, os.path -! -! def parseFreshCVSMail(fd, prefix=None): -! """Parse mail sent by FreshCVS""" -! # this uses rfc822.Message so it can run under python2.1 . In the future -! # it will be updated to use python2.2's "email" module. -! -! m = Message(fd) -! # FreshCVS sets From: to "user CVS ", but the <> part may be -! # modified by the MTA (to include a local domain) -! name, addr = m.getaddr("from") -! if not name: -! return None # no From means this message isn't from FreshCVS -! cvs = name.find(" CVS") -! if cvs == -1: -! return None # this message isn't from FreshCVS -! who = name[:cvs] -! -! # we take the time of receipt as the time of checkin. Not correct, -! # but it avoids the out-of-order-changes issue -! #when = m.getdate() # and convert from 9-tuple, and handle timezone -! -! files = [] -! comments = "" -! isdir = 0 -! lines = m.fp.readlines() -! while lines: -! line = lines.pop(0) -! if line == "Modified files:\n": -! break -! while lines: -! line = lines.pop(0) -! if line == "\n": -! break -! line = line.rstrip("\n") -! file, junk = line.split(None, 1) -! if prefix: -! # insist that the file start with the prefix: FreshCVS sends -! # changes we don't care about too -! bits = file.split(os.sep) -! if bits[0] == prefix: -! file = apply(os.path.join, bits[1:]) -! else: -! break -! if junk == "0 0": -! isdir = 1 -! files.append(file) -! while lines: -! line = lines.pop(0) -! if line == "Log message:\n": -! break -! # message is terminated by "ViewCVS links:" or "Index:..." (patch) -! while lines: -! line = lines.pop(0) -! if line == "ViewCVS links:\n": -! break -! if line.find("Index: ") == 0: -! break -! comments += line -! comments = comments.rstrip() + "\n" -! -! if not files: -! return None -! -! change = Change(who, files, comments, isdir) -! -! return change -! -! -! -! class FCMaildirSource(MaildirTwisted): -! """This source will watch a maildir that is subscribed to a FreshCVS -! change-announcement mailing list. -! """ -! -! __implements__ = IChangeSource, - -! def __init__(self, maildir, prefix=None): -! MaildirTwisted.__init__(self, maildir) -! self.changemaster = None # filled in when added -! self.prefix = prefix -! def describe(self): -! return "FreshCVS mailing list in maildir %s" % self.maildir.where -! def messageReceived(self, filename): -! path = os.path.join(self.basedir, "new", filename) -! change = parseFreshCVSMail(open(path, "r"), self.prefix) -! if change: -! self.changemaster.addChange(change) -! os.rename(os.path.join(self.basedir, "new", filename), -! os.path.join(self.basedir, "cur", filename)) ---- 1,5 ---- - #! /usr/bin/python - -! # leftover import for compatibility - -! from buildbot.changes.mail import FCMaildirSource - - - ---- NEW FILE: syncmail.2 --- -Return-Path: -Delivered-To: warner-sourceforge@luther.lothar.com -Received: (qmail 23221 invoked by uid 1000); 28 Jul 2003 06:53:15 -0000 -Delivered-To: warner-sourceforge@lothar.com -Received: (qmail 58537 invoked by uid 13574); 28 Jul 2003 06:53:09 -0000 -Received: from unknown (HELO sc8-sf-list1.sourceforge.net) ([66.35.250.206]) (envelope-sender ) - by 130.94.181.6 (qmail-ldap-1.03) with SMTP - for ; 28 Jul 2003 06:53:09 -0000 -Received: from sc8-sf-sshgate.sourceforge.net ([66.35.250.220] helo=sc8-sf-netmisc.sourceforge.net) - by sc8-sf-list1.sourceforge.net with esmtp - (Cipher TLSv1:DES-CBC3-SHA:168) (Exim 3.31-VA-mm2 #1 (Debian)) - id 19h1sb-0003nw-00 - for ; Sun, 27 Jul 2003 23:53:09 -0700 -Received: from sc8-pr-cvs1-b.sourceforge.net ([10.5.1.7] helo=sc8-pr-cvs1.sourceforge.net) - by sc8-sf-netmisc.sourceforge.net with esmtp (Exim 3.36 #1 (Debian)) - id 19h1sa-00018t-00 - for ; Sun, 27 Jul 2003 23:53:08 -0700 -Received: from localhost ([127.0.0.1] helo=sc8-pr-cvs1.sourceforge.net) - by sc8-pr-cvs1.sourceforge.net with esmtp (Exim 3.22 #1 (Debian)) - id 19h1sa-0002mX-00 - for ; Sun, 27 Jul 2003 23:53:08 -0700 -From: warner@users.sourceforge.net -To: warner@users.sourceforge.net -Subject: buildbot ChangeLog,1.93,1.94 -Message-Id: -Date: Sun, 27 Jul 2003 23:53:08 -0700 -Status: - -Update of /cvsroot/buildbot/buildbot -In directory sc8-pr-cvs1:/tmp/cvs-serv10689 - -Modified Files: - ChangeLog -Log Message: - * NEWS: started adding new features - - -Index: ChangeLog -=================================================================== -RCS file: /cvsroot/buildbot/buildbot/ChangeLog,v -retrieving revision 1.93 -retrieving revision 1.94 -diff -C2 -d -r1.93 -r1.94 -*** ChangeLog 27 Jul 2003 22:53:27 -0000 1.93 ---- ChangeLog 28 Jul 2003 06:53:06 -0000 1.94 -*************** -*** 1,4 **** ---- 1,6 ---- - 2003-07-27 Brian Warner - -+ * NEWS: started adding new features -+ - * buildbot/changes/mail.py: start work on Syncmail parser, move - mail sources into their own file - - - ---- NEW FILE: syncmail.3 --- -Return-Path: -Delivered-To: warner-sourceforge@luther.lothar.com -Received: (qmail 23196 invoked by uid 1000); 28 Jul 2003 06:51:53 -0000 -Delivered-To: warner-sourceforge@lothar.com -Received: (qmail 58269 invoked by uid 13574); 28 Jul 2003 06:51:46 -0000 -Received: from unknown (HELO sc8-sf-list1.sourceforge.net) ([66.35.250.206]) (envelope-sender ) - by 130.94.181.6 (qmail-ldap-1.03) with SMTP - for ; 28 Jul 2003 06:51:46 -0000 -Received: from sc8-sf-sshgate.sourceforge.net ([66.35.250.220] helo=sc8-sf-netmisc.sourceforge.net) - by sc8-sf-list1.sourceforge.net with esmtp - (Cipher TLSv1:DES-CBC3-SHA:168) (Exim 3.31-VA-mm2 #1 (Debian)) - id 19h1rF-00027s-00 - for ; Sun, 27 Jul 2003 23:51:46 -0700 -Received: from sc8-pr-cvs1-b.sourceforge.net ([10.5.1.7] helo=sc8-pr-cvs1.sourceforge.net) - by sc8-sf-netmisc.sourceforge.net with esmtp (Exim 3.36 #1 (Debian)) - id 19h1rF-00017O-00 - for ; Sun, 27 Jul 2003 23:51:45 -0700 -Received: from localhost ([127.0.0.1] helo=sc8-pr-cvs1.sourceforge.net) - by sc8-pr-cvs1.sourceforge.net with esmtp (Exim 3.22 #1 (Debian)) - id 19h1rF-0002jg-00 - for ; Sun, 27 Jul 2003 23:51:45 -0700 -From: warner@users.sourceforge.net -To: warner@users.sourceforge.net -Subject: CVSROOT syncmail,1.1,NONE -Message-Id: -Date: Sun, 27 Jul 2003 23:51:45 -0700 -Status: - -Update of /cvsroot/buildbot/CVSROOT -In directory sc8-pr-cvs1:/tmp/cvs-serv10515 - -Removed Files: - syncmail -Log Message: -nevermind - ---- syncmail DELETED --- - - - - diff --git a/tools/buildbot/pylibs/buildbot/test/mail/syncmail.5 b/tools/buildbot/pylibs/buildbot/test/mail/syncmail.5 deleted file mode 100644 index 82ba451..0000000 --- a/tools/buildbot/pylibs/buildbot/test/mail/syncmail.5 +++ /dev/null @@ -1,70 +0,0 @@ -From thomas@otto.amantes Mon Feb 21 17:46:45 2005 -Return-Path: -Received: from otto.amantes (otto.amantes [127.0.0.1]) by otto.amantes - (8.13.1/8.13.1) with ESMTP id j1LGkjr3011986 for ; Mon, - 21 Feb 2005 17:46:45 +0100 -Message-Id: <200502211646.j1LGkjr3011986@otto.amantes> -From: Thomas Vander Stichele -To: thomas@otto.amantes -Subject: test1 s -Date: Mon, 21 Feb 2005 16:46:45 +0000 -X-Mailer: Python syncmail $Revision: 1.1 $ - -Content-Transfer-Encoding: 8bit -Mime-Version: 1.0 - -Update of /home/cvs/test/test1 -In directory otto.amantes:/home/thomas/dev/tests/cvs/test1 - -Added Files: - Tag: BRANCH-DEVEL - MANIFEST Makefile.am autogen.sh configure.in -Log Message: -stuff on the branch - ---- NEW FILE: Makefile.am --- -SUBDIRS = src - -# normally I wouldn't distribute autogen.sh and friends with a tarball -# but this one is specifically distributed for demonstration purposes - -EXTRA_DIST = autogen.sh - -# target for making the "import this into svn" tarball -test: - mkdir test - for a in `cat MANIFEST`; do \ - cp -pr $$a test/$$a; done - tar czf test.tar.gz test - rm -rf test - ---- NEW FILE: MANIFEST --- -MANIFEST -autogen.sh -configure.in -Makefile.am -src -src/Makefile.am -src/test.c - ---- NEW FILE: autogen.sh --- -#!/bin/sh - -set -x - -aclocal && \ -autoheader && \ -autoconf && \ -automake -a --foreign && \ -./configure $@ - ---- NEW FILE: configure.in --- -dnl configure.ac for version macro -AC_INIT - -AM_CONFIG_HEADER(config.h) - -AM_INIT_AUTOMAKE(test, 0.0.0) -AC_PROG_CC - -AC_OUTPUT(Makefile src/Makefile) diff --git a/tools/buildbot/pylibs/buildbot/test/runutils.py b/tools/buildbot/pylibs/buildbot/test/runutils.py deleted file mode 100644 index ebd40d1..0000000 --- a/tools/buildbot/pylibs/buildbot/test/runutils.py +++ /dev/null @@ -1,514 +0,0 @@ - -import signal -import shutil, os, errno -from cStringIO import StringIO -from twisted.internet import defer, reactor, protocol -from twisted.python import log, util - -from buildbot import master, interfaces -from buildbot.slave import bot -from buildbot.buildslave import BuildSlave -from buildbot.process.builder import Builder -from buildbot.process.base import BuildRequest, Build -from buildbot.process.buildstep import BuildStep -from buildbot.sourcestamp import SourceStamp -from buildbot.status import builder -from buildbot.process.properties import Properties - - - -class _PutEverythingGetter(protocol.ProcessProtocol): - def __init__(self, deferred, stdin): - self.deferred = deferred - self.outBuf = StringIO() - self.errBuf = StringIO() - self.outReceived = self.outBuf.write - self.errReceived = self.errBuf.write - self.stdin = stdin - - def connectionMade(self): - if self.stdin is not None: - self.transport.write(self.stdin) - self.transport.closeStdin() - - def processEnded(self, reason): - out = self.outBuf.getvalue() - err = self.errBuf.getvalue() - e = reason.value - code = e.exitCode - if e.signal: - self.deferred.errback((out, err, e.signal)) - else: - self.deferred.callback((out, err, code)) - -def myGetProcessOutputAndValue(executable, args=(), env={}, path='.', - _reactor_ignored=None, stdin=None): - """Like twisted.internet.utils.getProcessOutputAndValue but takes - stdin, too.""" - d = defer.Deferred() - p = _PutEverythingGetter(d, stdin) - reactor.spawnProcess(p, executable, (executable,)+tuple(args), env, path) - return d - - -class MyBot(bot.Bot): - def remote_getSlaveInfo(self): - return self.parent.info - -class MyBuildSlave(bot.BuildSlave): - botClass = MyBot - -def rmtree(d): - try: - shutil.rmtree(d, ignore_errors=1) - except OSError, e: - # stupid 2.2 appears to ignore ignore_errors - if e.errno != errno.ENOENT: - raise - -class RunMixin: - master = None - - def rmtree(self, d): - rmtree(d) - - def setUp(self): - self.slaves = {} - self.rmtree("basedir") - os.mkdir("basedir") - self.master = master.BuildMaster("basedir") - self.status = self.master.getStatus() - self.control = interfaces.IControl(self.master) - - def connectOneSlave(self, slavename, opts={}): - port = self.master.slavePort._port.getHost().port - self.rmtree("slavebase-%s" % slavename) - os.mkdir("slavebase-%s" % slavename) - slave = MyBuildSlave("localhost", port, slavename, "sekrit", - "slavebase-%s" % slavename, - keepalive=0, usePTY=False, debugOpts=opts) - slave.info = {"admin": "one"} - self.slaves[slavename] = slave - slave.startService() - - def connectSlave(self, builders=["dummy"], slavename="bot1", - opts={}): - # connect buildslave 'slavename' and wait for it to connect to all of - # the given builders - dl = [] - # initiate call for all of them, before waiting on result, - # otherwise we might miss some - for b in builders: - dl.append(self.master.botmaster.waitUntilBuilderAttached(b)) - d = defer.DeferredList(dl) - self.connectOneSlave(slavename, opts) - return d - - def connectSlaves(self, slavenames, builders): - dl = [] - # initiate call for all of them, before waiting on result, - # otherwise we might miss some - for b in builders: - dl.append(self.master.botmaster.waitUntilBuilderAttached(b)) - d = defer.DeferredList(dl) - for name in slavenames: - self.connectOneSlave(name) - return d - - def connectSlave2(self): - # this takes over for bot1, so it has to share the slavename - port = self.master.slavePort._port.getHost().port - self.rmtree("slavebase-bot2") - os.mkdir("slavebase-bot2") - # this uses bot1, really - slave = MyBuildSlave("localhost", port, "bot1", "sekrit", - "slavebase-bot2", keepalive=0, usePTY=False) - slave.info = {"admin": "two"} - self.slaves['bot2'] = slave - slave.startService() - - def connectSlaveFastTimeout(self): - # this slave has a very fast keepalive timeout - port = self.master.slavePort._port.getHost().port - self.rmtree("slavebase-bot1") - os.mkdir("slavebase-bot1") - slave = MyBuildSlave("localhost", port, "bot1", "sekrit", - "slavebase-bot1", keepalive=2, usePTY=False, - keepaliveTimeout=1) - slave.info = {"admin": "one"} - self.slaves['bot1'] = slave - slave.startService() - d = self.master.botmaster.waitUntilBuilderAttached("dummy") - return d - - # things to start builds - def requestBuild(self, builder): - # returns a Deferred that fires with an IBuildStatus object when the - # build is finished - req = BuildRequest("forced build", SourceStamp()) - self.control.getBuilder(builder).requestBuild(req) - return req.waitUntilFinished() - - def failUnlessBuildSucceeded(self, bs): - if bs.getResults() != builder.SUCCESS: - log.msg("failUnlessBuildSucceeded noticed that the build failed") - self.logBuildResults(bs) - self.failUnlessEqual(bs.getResults(), builder.SUCCESS) - return bs # useful for chaining - - def logBuildResults(self, bs): - # emit the build status and the contents of all logs to test.log - log.msg("logBuildResults starting") - log.msg(" bs.getResults() == %s" % builder.Results[bs.getResults()]) - log.msg(" bs.isFinished() == %s" % bs.isFinished()) - for s in bs.getSteps(): - for l in s.getLogs(): - log.msg("--- START step %s / log %s ---" % (s.getName(), - l.getName())) - if not l.getName().endswith(".html"): - log.msg(l.getTextWithHeaders()) - log.msg("--- STOP ---") - log.msg("logBuildResults finished") - - def tearDown(self): - log.msg("doing tearDown") - d = self.shutdownAllSlaves() - d.addCallback(self._tearDown_1) - d.addCallback(self._tearDown_2) - return d - def _tearDown_1(self, res): - if self.master: - return defer.maybeDeferred(self.master.stopService) - def _tearDown_2(self, res): - self.master = None - log.msg("tearDown done") - - - # various forms of slave death - - def shutdownAllSlaves(self): - # the slave has disconnected normally: they SIGINT'ed it, or it shut - # down willingly. This will kill child processes and give them a - # chance to finish up. We return a Deferred that will fire when - # everything is finished shutting down. - - log.msg("doing shutdownAllSlaves") - dl = [] - for slave in self.slaves.values(): - dl.append(slave.waitUntilDisconnected()) - dl.append(defer.maybeDeferred(slave.stopService)) - d = defer.DeferredList(dl) - d.addCallback(self._shutdownAllSlavesDone) - return d - def _shutdownAllSlavesDone(self, res): - for name in self.slaves.keys(): - del self.slaves[name] - return self.master.botmaster.waitUntilBuilderFullyDetached("dummy") - - def shutdownSlave(self, slavename, buildername): - # this slave has disconnected normally: they SIGINT'ed it, or it shut - # down willingly. This will kill child processes and give them a - # chance to finish up. We return a Deferred that will fire when - # everything is finished shutting down, and the given Builder knows - # that the slave has gone away. - - s = self.slaves[slavename] - dl = [self.master.botmaster.waitUntilBuilderDetached(buildername), - s.waitUntilDisconnected()] - d = defer.DeferredList(dl) - d.addCallback(self._shutdownSlave_done, slavename) - s.stopService() - return d - def _shutdownSlave_done(self, res, slavename): - del self.slaves[slavename] - - def killSlave(self): - # the slave has died, its host sent a FIN. The .notifyOnDisconnect - # callbacks will terminate the current step, so the build should be - # flunked (no further steps should be started). - self.slaves['bot1'].bf.continueTrying = 0 - bot = self.slaves['bot1'].getServiceNamed("bot") - broker = bot.builders["dummy"].remote.broker - broker.transport.loseConnection() - del self.slaves['bot1'] - - def disappearSlave(self, slavename="bot1", buildername="dummy", - allowReconnect=False): - # the slave's host has vanished off the net, leaving the connection - # dangling. This will be detected quickly by app-level keepalives or - # a ping, or slowly by TCP timeouts. - - # simulate this by replacing the slave Broker's .dataReceived method - # with one that just throws away all data. - def discard(data): - pass - bot = self.slaves[slavename].getServiceNamed("bot") - broker = bot.builders[buildername].remote.broker - broker.dataReceived = discard # seal its ears - broker.transport.write = discard # and take away its voice - if not allowReconnect: - # also discourage it from reconnecting once the connection goes away - assert self.slaves[slavename].bf.continueTrying - self.slaves[slavename].bf.continueTrying = False - - def ghostSlave(self): - # the slave thinks it has lost the connection, and initiated a - # reconnect. The master doesn't yet realize it has lost the previous - # connection, and sees two connections at once. - raise NotImplementedError - - -def setupBuildStepStatus(basedir): - """Return a BuildStep with a suitable BuildStepStatus object, ready to - use.""" - os.mkdir(basedir) - botmaster = None - s0 = builder.Status(botmaster, basedir) - s1 = s0.builderAdded("buildername", "buildername") - s2 = builder.BuildStatus(s1, 1) - s3 = builder.BuildStepStatus(s2) - s3.setName("foostep") - s3.started = True - s3.stepStarted() - return s3 - -def fake_slaveVersion(command, oldversion=None): - from buildbot.slave.registry import commandRegistry - return commandRegistry[command] - -class FakeBuildMaster: - properties = Properties(masterprop="master") - -class FakeBotMaster: - parent = FakeBuildMaster() - -def makeBuildStep(basedir, step_class=BuildStep, **kwargs): - bss = setupBuildStepStatus(basedir) - - ss = SourceStamp() - setup = {'name': "builder1", "slavename": "bot1", - 'builddir': "builddir", 'factory': None} - b0 = Builder(setup, bss.getBuild().getBuilder()) - b0.botmaster = FakeBotMaster() - br = BuildRequest("reason", ss) - b = Build([br]) - b.setBuilder(b0) - s = step_class(**kwargs) - s.setBuild(b) - s.setStepStatus(bss) - b.build_status = bss.getBuild() - b.setupProperties() - s.slaveVersion = fake_slaveVersion - return s - - -def findDir(): - # the same directory that holds this script - return util.sibpath(__file__, ".") - -class SignalMixin: - sigchldHandler = None - - def setUpClass(self): - # make sure SIGCHLD handler is installed, as it should be on - # reactor.run(). problem is reactor may not have been run when this - # test runs. - if hasattr(reactor, "_handleSigchld") and hasattr(signal, "SIGCHLD"): - self.sigchldHandler = signal.signal(signal.SIGCHLD, - reactor._handleSigchld) - - def tearDownClass(self): - if self.sigchldHandler: - signal.signal(signal.SIGCHLD, self.sigchldHandler) - -# these classes are used to test SlaveCommands in isolation - -class FakeSlaveBuilder: - debug = False - def __init__(self, usePTY, basedir): - self.updates = [] - self.basedir = basedir - self.usePTY = usePTY - - def sendUpdate(self, data): - if self.debug: - print "FakeSlaveBuilder.sendUpdate", data - self.updates.append(data) - - -class SlaveCommandTestBase(SignalMixin): - usePTY = False - - def setUpBuilder(self, basedir): - if not os.path.exists(basedir): - os.mkdir(basedir) - self.builder = FakeSlaveBuilder(self.usePTY, basedir) - - def startCommand(self, cmdclass, args): - stepId = 0 - self.cmd = c = cmdclass(self.builder, stepId, args) - c.running = True - d = c.doStart() - return d - - def collectUpdates(self, res=None): - logs = {} - for u in self.builder.updates: - for k in u.keys(): - if k == "log": - logname,data = u[k] - oldlog = logs.get(("log",logname), "") - logs[("log",logname)] = oldlog + data - elif k == "rc": - pass - else: - logs[k] = logs.get(k, "") + u[k] - return logs - - def findRC(self): - for u in self.builder.updates: - if "rc" in u: - return u["rc"] - return None - - def printStderr(self): - for u in self.builder.updates: - if "stderr" in u: - print u["stderr"] - -# ---------------------------------------- - -class LocalWrapper: - # r = pb.Referenceable() - # w = LocalWrapper(r) - # now you can do things like w.callRemote() - def __init__(self, target): - self.target = target - - def callRemote(self, name, *args, **kwargs): - # callRemote is not allowed to fire its Deferred in the same turn - d = defer.Deferred() - d.addCallback(self._callRemote, *args, **kwargs) - reactor.callLater(0, d.callback, name) - return d - - def _callRemote(self, name, *args, **kwargs): - method = getattr(self.target, "remote_"+name) - return method(*args, **kwargs) - - def notifyOnDisconnect(self, observer): - pass - def dontNotifyOnDisconnect(self, observer): - pass - - -class LocalSlaveBuilder(bot.SlaveBuilder): - """I am object that behaves like a pb.RemoteReference, but in fact I - invoke methods locally.""" - _arg_filter = None - - def setArgFilter(self, filter): - self._arg_filter = filter - - def remote_startCommand(self, stepref, stepId, command, args): - if self._arg_filter: - args = self._arg_filter(args) - # stepref should be a RemoteReference to the RemoteCommand - return bot.SlaveBuilder.remote_startCommand(self, - LocalWrapper(stepref), - stepId, command, args) - -class StepTester: - """Utility class to exercise BuildSteps and RemoteCommands, without - really using a Build or a Bot. No networks are used. - - Use this as follows:: - - class MyTest(StepTester, unittest.TestCase): - def testOne(self): - self.slavebase = 'testOne.slave' - self.masterbase = 'testOne.master' - sb = self.makeSlaveBuilder() - step = self.makeStep(stepclass, **kwargs) - d = self.runStep(step) - d.addCallback(_checkResults) - return d - """ - - #slavebase = "slavebase" - slavebuilderbase = "slavebuilderbase" - #masterbase = "masterbase" - - def makeSlaveBuilder(self): - os.mkdir(self.slavebase) - os.mkdir(os.path.join(self.slavebase, self.slavebuilderbase)) - b = bot.Bot(self.slavebase, False) - b.startService() - sb = LocalSlaveBuilder("slavebuildername", False) - sb.setArgFilter(self.filterArgs) - sb.usePTY = False - sb.setServiceParent(b) - sb.setBuilddir(self.slavebuilderbase) - self.remote = LocalWrapper(sb) - return sb - - workdir = "build" - def makeStep(self, factory, **kwargs): - step = makeBuildStep(self.masterbase, factory, **kwargs) - step.setBuildSlave(BuildSlave("name", "password")) - step.setDefaultWorkdir(self.workdir) - return step - - def runStep(self, step): - d = defer.maybeDeferred(step.startStep, self.remote) - return d - - def wrap(self, target): - return LocalWrapper(target) - - def filterArgs(self, args): - # this can be overridden - return args - -# ---------------------------------------- - -_flags = {} - -def setTestFlag(flagname, value): - _flags[flagname] = value - -class SetTestFlagStep(BuildStep): - """ - A special BuildStep to set a named flag; this can be used with the - TestFlagMixin to monitor what has and has not run in a particular - configuration. - """ - def __init__(self, flagname='flag', value=1, **kwargs): - BuildStep.__init__(self, **kwargs) - self.flagname = flagname - self.value = value - - def start(self): - properties = self.build.getProperties() - _flags[self.flagname] = properties.render(self.value) - self.finished(builder.SUCCESS) - -class TestFlagMixin: - def clearFlags(self): - """ - Set up for a test by clearing all flags; call this from your test - function. - """ - _flags.clear() - - def failIfFlagSet(self, flagname, msg=None): - if not msg: msg = "flag '%s' is set" % flagname - self.failIf(_flags.has_key(flagname), msg=msg) - - def failIfFlagNotSet(self, flagname, msg=None): - if not msg: msg = "flag '%s' is not set" % flagname - self.failUnless(_flags.has_key(flagname), msg=msg) - - def getFlag(self, flagname): - self.failIfFlagNotSet(flagname, "flag '%s' not set" % flagname) - return _flags.get(flagname) diff --git a/tools/buildbot/pylibs/buildbot/test/sleep.py b/tools/buildbot/pylibs/buildbot/test/sleep.py deleted file mode 100644 index 4662852..0000000 --- a/tools/buildbot/pylibs/buildbot/test/sleep.py +++ /dev/null @@ -1,8 +0,0 @@ - -import sys, time -delay = int(sys.argv[1]) - -sys.stdout.write("sleeping for %d seconds\n" % delay) -time.sleep(delay) -sys.stdout.write("woke up\n") -sys.exit(0) diff --git a/tools/buildbot/pylibs/buildbot/test/subdir/emit.py b/tools/buildbot/pylibs/buildbot/test/subdir/emit.py deleted file mode 100644 index 42d2ca9..0000000 --- a/tools/buildbot/pylibs/buildbot/test/subdir/emit.py +++ /dev/null @@ -1,11 +0,0 @@ -#! /usr/bin/python - -import os, sys - -sys.stdout.write("this is stdout in subdir\n") -sys.stderr.write("this is stderr\n") -if os.environ.has_key("EMIT_TEST"): - sys.stdout.write("EMIT_TEST: %s\n" % os.environ["EMIT_TEST"]) -open("log1.out","wt").write("this is log1\n") -rc = int(sys.argv[1]) -sys.exit(rc) diff --git a/tools/buildbot/pylibs/buildbot/test/test__versions.py b/tools/buildbot/pylibs/buildbot/test/test__versions.py deleted file mode 100644 index a69fcc4..0000000 --- a/tools/buildbot/pylibs/buildbot/test/test__versions.py +++ /dev/null @@ -1,16 +0,0 @@ - -# This is a fake test which just logs the version of Twisted, to make it -# easier to track down failures in other tests. - -from twisted.trial import unittest -from twisted.python import log -from twisted import copyright -import sys -import buildbot - -class Versions(unittest.TestCase): - def test_versions(self): - log.msg("Python Version: %s" % sys.version) - log.msg("Twisted Version: %s" % copyright.version) - log.msg("Buildbot Version: %s" % buildbot.version) - diff --git a/tools/buildbot/pylibs/buildbot/test/test_bonsaipoller.py b/tools/buildbot/pylibs/buildbot/test/test_bonsaipoller.py deleted file mode 100644 index f4ca233..0000000 --- a/tools/buildbot/pylibs/buildbot/test/test_bonsaipoller.py +++ /dev/null @@ -1,244 +0,0 @@ -# -*- test-case-name: buildbot.test.test_bonsaipoller -*- - -from twisted.trial import unittest -from buildbot.changes.bonsaipoller import FileNode, CiNode, BonsaiResult, \ - BonsaiParser, BonsaiPoller, InvalidResultError, EmptyResult -from buildbot.changes.changes import ChangeMaster - -from copy import deepcopy -import re - -log1 = "Add Bug 338541a" -who1 = "sar@gmail.com" -date1 = 1161908700 -log2 = "bug 357427 add static ctor/dtor methods" -who2 = "aarrg@ooacm.org" -date2 = 1161910620 -log3 = "Testing log #3 lbah blah" -who3 = "huoents@hueont.net" -date3 = 1889822728 -rev1 = "1.8" -file1 = "mozilla/testing/mochitest/tests/index.html" -rev2 = "1.1" -file2 = "mozilla/testing/mochitest/tests/test_bug338541.xhtml" -rev3 = "1.1812" -file3 = "mozilla/xpcom/threads/nsAutoLock.cpp" -rev4 = "1.3" -file4 = "mozilla/xpcom/threads/nsAutoLock.h" -rev5 = "2.4" -file5 = "mozilla/xpcom/threads/test.cpp" - -nodes = [] -files = [] -files.append(FileNode(rev1,file1)) -nodes.append(CiNode(log1, who1, date1, files)) - -files = [] -files.append(FileNode(rev2, file2)) -files.append(FileNode(rev3, file3)) -nodes.append(CiNode(log2, who2, date2, files)) - -nodes.append(CiNode(log3, who3, date3, [])) - -goodParsedResult = BonsaiResult(nodes) - -goodUnparsedResult = """\ - - - - %s - - %s - - - - %s - - %s - %s - - - - %s - - - - -""" % (who1, date1, log1, rev1, file1, - who2, date2, log2, rev2, file2, rev3, file3, - who3, date3, log3) - -badUnparsedResult = deepcopy(goodUnparsedResult) -badUnparsedResult = badUnparsedResult.replace("", "") - -invalidDateResult = deepcopy(goodUnparsedResult) -invalidDateResult = invalidDateResult.replace(str(date1), "foobar") - -missingFilenameResult = deepcopy(goodUnparsedResult) -missingFilenameResult = missingFilenameResult.replace(file2, "") - -duplicateLogResult = deepcopy(goodUnparsedResult) -duplicateLogResult = re.sub(""+log1+"", - "blahblah", - duplicateLogResult) - -duplicateFilesResult = deepcopy(goodUnparsedResult) -duplicateFilesResult = re.sub("\s*", - "", - duplicateFilesResult) - -missingCiResult = deepcopy(goodUnparsedResult) -r = re.compile("", re.DOTALL | re.MULTILINE) -missingCiResult = re.sub(r, "", missingCiResult) - -badResultMsgs = { 'badUnparsedResult': - "BonsaiParser did not raise an exception when given a bad query", - 'invalidDateResult': - "BonsaiParser did not raise an exception when given an invalid date", - 'missingRevisionResult': - "BonsaiParser did not raise an exception when a revision was missing", - 'missingFilenameResult': - "BonsaiParser did not raise an exception when a filename was missing", - 'duplicateLogResult': - "BonsaiParser did not raise an exception when there was two tags", - 'duplicateFilesResult': - "BonsaiParser did not raise an exception when there was two tags", - 'missingCiResult': - "BonsaiParser did not raise an exception when there was no tags" -} - -noCheckinMsgResult = """\ - - - - - - first/file.ext - - - - - - second/file.ext - - - - - - third/file.ext - - - -""" - -noCheckinMsgRef = [dict(filename="first/file.ext", - revision="1.1"), - dict(filename="second/file.ext", - revision="1.2"), - dict(filename="third/file.ext", - revision="1.3")] - -class FakeChangeMaster(ChangeMaster): - def __init__(self): - ChangeMaster.__init__(self) - - def addChange(self, change): - pass - -class FakeBonsaiPoller(BonsaiPoller): - def __init__(self): - BonsaiPoller.__init__(self, "fake url", "fake module", "fake branch") - self.parent = FakeChangeMaster() - -class TestBonsaiPoller(unittest.TestCase): - def testFullyFormedResult(self): - br = BonsaiParser(goodUnparsedResult) - result = br.getData() - # make sure the result is a BonsaiResult - self.failUnless(isinstance(result, BonsaiResult)) - # test for successful parsing - self.failUnlessEqual(goodParsedResult, result, - "BonsaiParser did not return the expected BonsaiResult") - - def testBadUnparsedResult(self): - try: - BonsaiParser(badUnparsedResult) - self.fail(badResultMsgs["badUnparsedResult"]) - except InvalidResultError: - pass - - def testInvalidDateResult(self): - try: - BonsaiParser(invalidDateResult) - self.fail(badResultMsgs["invalidDateResult"]) - except InvalidResultError: - pass - - def testMissingFilenameResult(self): - try: - BonsaiParser(missingFilenameResult) - self.fail(badResultMsgs["missingFilenameResult"]) - except InvalidResultError: - pass - - def testDuplicateLogResult(self): - try: - BonsaiParser(duplicateLogResult) - self.fail(badResultMsgs["duplicateLogResult"]) - except InvalidResultError: - pass - - def testDuplicateFilesResult(self): - try: - BonsaiParser(duplicateFilesResult) - self.fail(badResultMsgs["duplicateFilesResult"]) - except InvalidResultError: - pass - - def testMissingCiResult(self): - try: - BonsaiParser(missingCiResult) - self.fail(badResultMsgs["missingCiResult"]) - except EmptyResult: - pass - - def testChangeNotSubmitted(self): - "Make sure a change is not submitted if the BonsaiParser fails" - poller = FakeBonsaiPoller() - lastChangeBefore = poller.lastChange - poller._process_changes(badUnparsedResult) - # self.lastChange will not be updated if the change was not submitted - self.failUnlessEqual(lastChangeBefore, poller.lastChange) - - def testParserWorksAfterInvalidResult(self): - """Make sure the BonsaiPoller still works after catching an - InvalidResultError""" - - poller = FakeBonsaiPoller() - - lastChangeBefore = poller.lastChange - # generate an exception first. pretend that we're doing a poll and - # increment the timestamp, otherwise the failIfEqual test at the - # bottom will depend upon there being a noticeable difference between - # two successive calls to time.time(). - poller.lastPoll += 1.0 - poller._process_changes(badUnparsedResult) - # now give it a valid one... - poller.lastPoll += 1.0 - poller._process_changes(goodUnparsedResult) - # if poller.lastChange has not been updated then the good result - # was not parsed - self.failIfEqual(lastChangeBefore, poller.lastChange) - - def testMergeEmptyLogMsg(self): - """Ensure that BonsaiPoller works around the bonsai xml output - issue when the check-in comment is empty""" - bp = BonsaiParser(noCheckinMsgResult) - result = bp.getData() - self.failUnlessEqual(len(result.nodes), 1) - self.failUnlessEqual(result.nodes[0].who, "johndoe@domain.tld") - self.failUnlessEqual(result.nodes[0].date, 12345678) - self.failUnlessEqual(result.nodes[0].log, "") - for file, ref in zip(result.nodes[0].files, noCheckinMsgRef): - self.failUnlessEqual(file.filename, ref['filename']) - self.failUnlessEqual(file.revision, ref['revision']) diff --git a/tools/buildbot/pylibs/buildbot/test/test_buildreq.py b/tools/buildbot/pylibs/buildbot/test/test_buildreq.py deleted file mode 100644 index ecbec48..0000000 --- a/tools/buildbot/pylibs/buildbot/test/test_buildreq.py +++ /dev/null @@ -1,181 +0,0 @@ -# -*- test-case-name: buildbot.test.test_buildreq -*- - -from twisted.trial import unittest - -from buildbot import buildset, interfaces, sourcestamp -from buildbot.process import base -from buildbot.status import builder -from buildbot.changes.changes import Change - -class Request(unittest.TestCase): - def testMerge(self): - R = base.BuildRequest - S = sourcestamp.SourceStamp - b1 = R("why", S("branch1", None, None, None)) - b1r1 = R("why2", S("branch1", "rev1", None, None)) - b1r1a = R("why not", S("branch1", "rev1", None, None)) - b1r2 = R("why3", S("branch1", "rev2", None, None)) - b2r2 = R("why4", S("branch2", "rev2", None, None)) - b1r1p1 = R("why5", S("branch1", "rev1", (3, "diff"), None)) - c1 = Change("alice", [], "changed stuff", branch="branch1") - c2 = Change("alice", [], "changed stuff", branch="branch1") - c3 = Change("alice", [], "changed stuff", branch="branch1") - c4 = Change("alice", [], "changed stuff", branch="branch1") - c5 = Change("alice", [], "changed stuff", branch="branch1") - c6 = Change("alice", [], "changed stuff", branch="branch1") - b1c1 = R("changes", S("branch1", None, None, [c1,c2,c3])) - b1c2 = R("changes", S("branch1", None, None, [c4,c5,c6])) - - self.failUnless(b1.canBeMergedWith(b1)) - self.failIf(b1.canBeMergedWith(b1r1)) - self.failIf(b1.canBeMergedWith(b2r2)) - self.failIf(b1.canBeMergedWith(b1r1p1)) - self.failIf(b1.canBeMergedWith(b1c1)) - - self.failIf(b1r1.canBeMergedWith(b1)) - self.failUnless(b1r1.canBeMergedWith(b1r1)) - self.failIf(b1r1.canBeMergedWith(b2r2)) - self.failIf(b1r1.canBeMergedWith(b1r1p1)) - self.failIf(b1r1.canBeMergedWith(b1c1)) - - self.failIf(b1r2.canBeMergedWith(b1)) - self.failIf(b1r2.canBeMergedWith(b1r1)) - self.failUnless(b1r2.canBeMergedWith(b1r2)) - self.failIf(b1r2.canBeMergedWith(b2r2)) - self.failIf(b1r2.canBeMergedWith(b1r1p1)) - - self.failIf(b1r1p1.canBeMergedWith(b1)) - self.failIf(b1r1p1.canBeMergedWith(b1r1)) - self.failIf(b1r1p1.canBeMergedWith(b1r2)) - self.failIf(b1r1p1.canBeMergedWith(b2r2)) - self.failIf(b1r1p1.canBeMergedWith(b1c1)) - - self.failIf(b1c1.canBeMergedWith(b1)) - self.failIf(b1c1.canBeMergedWith(b1r1)) - self.failIf(b1c1.canBeMergedWith(b1r2)) - self.failIf(b1c1.canBeMergedWith(b2r2)) - self.failIf(b1c1.canBeMergedWith(b1r1p1)) - self.failUnless(b1c1.canBeMergedWith(b1c1)) - self.failUnless(b1c1.canBeMergedWith(b1c2)) - - sm = b1.mergeWith([]) - self.failUnlessEqual(sm.branch, "branch1") - self.failUnlessEqual(sm.revision, None) - self.failUnlessEqual(sm.patch, None) - self.failUnlessEqual(sm.changes, ()) - - ss = b1r1.mergeWith([b1r1]) - self.failUnlessEqual(ss, S("branch1", "rev1", None, None)) - why = b1r1.mergeReasons([b1r1]) - self.failUnlessEqual(why, "why2") - why = b1r1.mergeReasons([b1r1a]) - self.failUnlessEqual(why, "why2, why not") - - ss = b1c1.mergeWith([b1c2]) - self.failUnlessEqual(ss, S("branch1", None, None, [c1,c2,c3,c4,c5,c6])) - why = b1c1.mergeReasons([b1c2]) - self.failUnlessEqual(why, "changes") - - -class FakeBuilder: - name = "fake" - def __init__(self): - self.requests = [] - def submitBuildRequest(self, req): - self.requests.append(req) - - -class Set(unittest.TestCase): - def testBuildSet(self): - S = buildset.BuildSet - a,b = FakeBuilder(), FakeBuilder() - - # two builds, the first one fails, the second one succeeds. The - # waitUntilSuccess watcher fires as soon as the first one fails, - # while the waitUntilFinished watcher doesn't fire until all builds - # are complete. - - source = sourcestamp.SourceStamp() - s = S(["a","b"], source, "forced build") - s.start([a,b]) - self.failUnlessEqual(len(a.requests), 1) - self.failUnlessEqual(len(b.requests), 1) - r1 = a.requests[0] - self.failUnlessEqual(r1.reason, s.reason) - self.failUnlessEqual(r1.source, s.source) - - st = s.status - self.failUnlessEqual(st.getSourceStamp(), source) - self.failUnlessEqual(st.getReason(), "forced build") - self.failUnlessEqual(st.getBuilderNames(), ["a","b"]) - self.failIf(st.isFinished()) - brs = st.getBuildRequests() - self.failUnlessEqual(len(brs), 2) - - res = [] - d1 = s.waitUntilSuccess() - d1.addCallback(lambda r: res.append(("success", r))) - d2 = s.waitUntilFinished() - d2.addCallback(lambda r: res.append(("finished", r))) - - self.failUnlessEqual(res, []) - - # the first build finishes here, with FAILURE - builderstatus_a = builder.BuilderStatus("a") - bsa = builder.BuildStatus(builderstatus_a, 1) - bsa.setResults(builder.FAILURE) - a.requests[0].finished(bsa) - - # any FAILURE flunks the BuildSet immediately, so the - # waitUntilSuccess deferred fires right away. However, the - # waitUntilFinished deferred must wait until all builds have - # completed. - self.failUnlessEqual(len(res), 1) - self.failUnlessEqual(res[0][0], "success") - bss = res[0][1] - self.failUnless(interfaces.IBuildSetStatus(bss, None)) - self.failUnlessEqual(bss.getResults(), builder.FAILURE) - - # here we finish the second build - builderstatus_b = builder.BuilderStatus("b") - bsb = builder.BuildStatus(builderstatus_b, 1) - bsb.setResults(builder.SUCCESS) - b.requests[0].finished(bsb) - - # .. which ought to fire the waitUntilFinished deferred - self.failUnlessEqual(len(res), 2) - self.failUnlessEqual(res[1][0], "finished") - self.failUnlessEqual(res[1][1], bss) - - # and finish the BuildSet overall - self.failUnless(st.isFinished()) - self.failUnlessEqual(st.getResults(), builder.FAILURE) - - def testSuccess(self): - S = buildset.BuildSet - a,b = FakeBuilder(), FakeBuilder() - # this time, both builds succeed - - source = sourcestamp.SourceStamp() - s = S(["a","b"], source, "forced build") - s.start([a,b]) - - st = s.status - self.failUnlessEqual(st.getSourceStamp(), source) - self.failUnlessEqual(st.getReason(), "forced build") - self.failUnlessEqual(st.getBuilderNames(), ["a","b"]) - self.failIf(st.isFinished()) - - builderstatus_a = builder.BuilderStatus("a") - bsa = builder.BuildStatus(builderstatus_a, 1) - bsa.setResults(builder.SUCCESS) - a.requests[0].finished(bsa) - - builderstatus_b = builder.BuilderStatus("b") - bsb = builder.BuildStatus(builderstatus_b, 1) - bsb.setResults(builder.SUCCESS) - b.requests[0].finished(bsb) - - self.failUnless(st.isFinished()) - self.failUnlessEqual(st.getResults(), builder.SUCCESS) - diff --git a/tools/buildbot/pylibs/buildbot/test/test_buildstep.py b/tools/buildbot/pylibs/buildbot/test/test_buildstep.py deleted file mode 100644 index 5eb556b..0000000 --- a/tools/buildbot/pylibs/buildbot/test/test_buildstep.py +++ /dev/null @@ -1,134 +0,0 @@ -# -*- test-case-name: buildbot.test.test_buildstep -*- - -# test cases for buildbot.process.buildstep - -from twisted.trial import unittest - -from buildbot import interfaces -from buildbot.process import buildstep - -# have to subclass LogObserver in order to test it, since the default -# implementations of outReceived() and errReceived() do nothing -class MyLogObserver(buildstep.LogObserver): - def __init__(self): - self._out = [] # list of chunks - self._err = [] - - def outReceived(self, data): - self._out.append(data) - - def errReceived(self, data): - self._err.append(data) - -class ObserverTestCase(unittest.TestCase): - observer_cls = None # must be set by subclass - - def setUp(self): - self.observer = self.observer_cls() - - def _logStdout(self, chunk): - # why does LogObserver.logChunk() take 'build', 'step', and - # 'log' arguments when it clearly doesn't use them for anything? - self.observer.logChunk(None, None, None, interfaces.LOG_CHANNEL_STDOUT, chunk) - - def _logStderr(self, chunk): - self.observer.logChunk(None, None, None, interfaces.LOG_CHANNEL_STDERR, chunk) - - def _assertStdout(self, expect_lines): - self.assertEqual(self.observer._out, expect_lines) - - def _assertStderr(self, expect_lines): - self.assertEqual(self.observer._err, expect_lines) - -class LogObserver(ObserverTestCase): - - observer_cls = MyLogObserver - - def testLogChunk(self): - self._logStdout("foo") - self._logStderr("argh") - self._logStdout(" wubba\n") - self._logStderr("!!!\n") - - self._assertStdout(["foo", " wubba\n"]) - self._assertStderr(["argh", "!!!\n"]) - -# again, have to subclass LogLineObserver in order to test it, because the -# default implementations of data-receiving methods are empty -class MyLogLineObserver(buildstep.LogLineObserver): - def __init__(self): - #super(MyLogLineObserver, self).__init__() - buildstep.LogLineObserver.__init__(self) - - self._out = [] # list of lines - self._err = [] - - def outLineReceived(self, line): - self._out.append(line) - - def errLineReceived(self, line): - self._err.append(line) - -class LogLineObserver(ObserverTestCase): - observer_cls = MyLogLineObserver - - def testLineBuffered(self): - # no challenge here: we feed it chunks that are already lines - # (like a program writing to stdout in line-buffered mode) - self._logStdout("stdout line 1\n") - self._logStdout("stdout line 2\n") - self._logStderr("stderr line 1\n") - self._logStdout("stdout line 3\n") - - self._assertStdout(["stdout line 1", - "stdout line 2", - "stdout line 3"]) - self._assertStderr(["stderr line 1"]) - - def testShortBrokenLines(self): - self._logStdout("stdout line 1 starts ") - self._logStderr("an intervening line of error\n") - self._logStdout("and continues ") - self._logStdout("but finishes here\n") - self._logStderr("more error\n") - self._logStdout("and another line of stdout\n") - - self._assertStdout(["stdout line 1 starts and continues but finishes here", - "and another line of stdout"]) - self._assertStderr(["an intervening line of error", - "more error"]) - - def testLongLine(self): - chunk = "." * 1024 - self._logStdout(chunk) - self._logStdout(chunk) - self._logStdout(chunk) - self._logStdout(chunk) - self._logStdout(chunk) - self._logStdout("\n") - - self._assertStdout([chunk * 5]) - self._assertStderr([]) - - def testBigChunk(self): - chunk = "." * 5000 - self._logStdout(chunk) - self._logStdout("\n") - - self._assertStdout([chunk]) - self._assertStderr([]) - - def testReallyLongLine(self): - # A single line of > 16384 bytes is dropped on the floor (bug #201). - # In real life, I observed such a line being broken into chunks of - # 4095 bytes, so that's how I'm breaking it here. - self.observer.setMaxLineLength(65536) - chunk = "." * 4095 - self._logStdout(chunk) - self._logStdout(chunk) - self._logStdout(chunk) - self._logStdout(chunk) # now we're up to 16380 bytes - self._logStdout("12345\n") - - self._assertStdout([chunk*4 + "12345"]) - self._assertStderr([]) diff --git a/tools/buildbot/pylibs/buildbot/test/test_changes.py b/tools/buildbot/pylibs/buildbot/test/test_changes.py deleted file mode 100644 index 0857a2a..0000000 --- a/tools/buildbot/pylibs/buildbot/test/test_changes.py +++ /dev/null @@ -1,228 +0,0 @@ -# -*- test-case-name: buildbot.test.test_changes -*- - -from twisted.trial import unittest -from twisted.internet import defer, reactor - -from buildbot import master -from buildbot.changes import pb -from buildbot.scripts import runner - -d1 = {'files': ["Project/foo.c", "Project/bar/boo.c"], - 'who': "marvin", - 'comments': "Some changes in Project"} -d2 = {'files': ["OtherProject/bar.c"], - 'who': "zaphod", - 'comments': "other changes"} -d3 = {'files': ["Project/baz.c", "OtherProject/bloo.c"], - 'who': "alice", - 'comments': "mixed changes"} -d4 = {'files': ["trunk/baz.c", "branches/foobranch/foo.c", "trunk/bar.c"], - 'who': "alice", - 'comments': "mixed changes"} - -class TestChangePerspective(unittest.TestCase): - - def setUp(self): - self.changes = [] - - def addChange(self, c): - self.changes.append(c) - - def testNoPrefix(self): - p = pb.ChangePerspective(self, None) - p.perspective_addChange(d1) - self.failUnlessEqual(len(self.changes), 1) - c1 = self.changes[0] - self.failUnlessEqual(c1.files, - ["Project/foo.c", "Project/bar/boo.c"]) - self.failUnlessEqual(c1.comments, "Some changes in Project") - self.failUnlessEqual(c1.who, "marvin") - - def testPrefix(self): - p = pb.ChangePerspective(self, "Project/") - - p.perspective_addChange(d1) - self.failUnlessEqual(len(self.changes), 1) - c1 = self.changes[-1] - self.failUnlessEqual(c1.files, ["foo.c", "bar/boo.c"]) - self.failUnlessEqual(c1.comments, "Some changes in Project") - self.failUnlessEqual(c1.who, "marvin") - - p.perspective_addChange(d2) # should be ignored - self.failUnlessEqual(len(self.changes), 1) - - p.perspective_addChange(d3) # should ignore the OtherProject file - self.failUnlessEqual(len(self.changes), 2) - - c3 = self.changes[-1] - self.failUnlessEqual(c3.files, ["baz.c"]) - self.failUnlessEqual(c3.comments, "mixed changes") - self.failUnlessEqual(c3.who, "alice") - - def testPrefix2(self): - p = pb.ChangePerspective(self, "Project/bar/") - - p.perspective_addChange(d1) - self.failUnlessEqual(len(self.changes), 1) - c1 = self.changes[-1] - self.failUnlessEqual(c1.files, ["boo.c"]) - self.failUnlessEqual(c1.comments, "Some changes in Project") - self.failUnlessEqual(c1.who, "marvin") - - p.perspective_addChange(d2) # should be ignored - self.failUnlessEqual(len(self.changes), 1) - - p.perspective_addChange(d3) # should ignore this too - self.failUnlessEqual(len(self.changes), 1) - - def testPrefix3(self): - p = pb.ChangePerspective(self, "trunk/") - - p.perspective_addChange(d4) - self.failUnlessEqual(len(self.changes), 1) - c1 = self.changes[-1] - self.failUnlessEqual(c1.files, ["baz.c", "bar.c"]) - self.failUnlessEqual(c1.comments, "mixed changes") - - def testPrefix4(self): - p = pb.ChangePerspective(self, "branches/foobranch/") - - p.perspective_addChange(d4) - self.failUnlessEqual(len(self.changes), 1) - c1 = self.changes[-1] - self.failUnlessEqual(c1.files, ["foo.c"]) - self.failUnlessEqual(c1.comments, "mixed changes") - - - -config_empty = """ -BuildmasterConfig = c = {} -c['slaves'] = [] -c['builders'] = [] -c['schedulers'] = [] -c['slavePortnum'] = 0 -""" - -config_sender = config_empty + \ -""" -from buildbot.changes import pb -c['change_source'] = pb.PBChangeSource(port=None) -""" - -class Sender(unittest.TestCase): - def setUp(self): - self.master = master.BuildMaster(".") - def tearDown(self): - d = defer.maybeDeferred(self.master.stopService) - # TODO: something in Twisted-2.0.0 (and probably 2.0.1) doesn't shut - # down the Broker listening socket when it's supposed to. - # Twisted-1.3.0, and current SVN (which will be post-2.0.1) are ok. - # This iterate() is a quick hack to deal with the problem. I need to - # investigate more thoroughly and find a better solution. - d.addCallback(self.stall, 0.1) - return d - - def stall(self, res, timeout): - d = defer.Deferred() - reactor.callLater(timeout, d.callback, res) - return d - - def testSender(self): - self.master.loadConfig(config_empty) - self.master.startService() - # TODO: BuildMaster.loadChanges replaces the change_svc object, so we - # have to load it twice. Clean this up. - d = self.master.loadConfig(config_sender) - d.addCallback(self._testSender_1) - return d - - def _testSender_1(self, res): - self.cm = cm = self.master.change_svc - s1 = list(self.cm)[0] - port = self.master.slavePort._port.getHost().port - - self.options = {'username': "alice", - 'master': "localhost:%d" % port, - 'files': ["foo.c"], - } - - d = runner.sendchange(self.options) - d.addCallback(self._testSender_2) - return d - - def _testSender_2(self, res): - # now check that the change was received - self.failUnlessEqual(len(self.cm.changes), 1) - c = self.cm.changes.pop() - self.failUnlessEqual(c.who, "alice") - self.failUnlessEqual(c.files, ["foo.c"]) - self.failUnlessEqual(c.comments, "") - self.failUnlessEqual(c.revision, None) - - self.options['revision'] = "r123" - self.options['comments'] = "test change" - - d = runner.sendchange(self.options) - d.addCallback(self._testSender_3) - return d - - def _testSender_3(self, res): - self.failUnlessEqual(len(self.cm.changes), 1) - c = self.cm.changes.pop() - self.failUnlessEqual(c.who, "alice") - self.failUnlessEqual(c.files, ["foo.c"]) - self.failUnlessEqual(c.comments, "test change") - self.failUnlessEqual(c.revision, "r123") - - # test options['logfile'] by creating a temporary file - logfile = self.mktemp() - f = open(logfile, "wt") - f.write("longer test change") - f.close() - self.options['comments'] = None - self.options['logfile'] = logfile - - d = runner.sendchange(self.options) - d.addCallback(self._testSender_4) - return d - - def _testSender_4(self, res): - self.failUnlessEqual(len(self.cm.changes), 1) - c = self.cm.changes.pop() - self.failUnlessEqual(c.who, "alice") - self.failUnlessEqual(c.files, ["foo.c"]) - self.failUnlessEqual(c.comments, "longer test change") - self.failUnlessEqual(c.revision, "r123") - - # make sure that numeric revisions work too - self.options['logfile'] = None - del self.options['revision'] - self.options['revision_number'] = 42 - - d = runner.sendchange(self.options) - d.addCallback(self._testSender_5) - return d - - def _testSender_5(self, res): - self.failUnlessEqual(len(self.cm.changes), 1) - c = self.cm.changes.pop() - self.failUnlessEqual(c.who, "alice") - self.failUnlessEqual(c.files, ["foo.c"]) - self.failUnlessEqual(c.comments, "") - self.failUnlessEqual(c.revision, 42) - - # verify --branch too - self.options['branch'] = "branches/test" - - d = runner.sendchange(self.options) - d.addCallback(self._testSender_6) - return d - - def _testSender_6(self, res): - self.failUnlessEqual(len(self.cm.changes), 1) - c = self.cm.changes.pop() - self.failUnlessEqual(c.who, "alice") - self.failUnlessEqual(c.files, ["foo.c"]) - self.failUnlessEqual(c.comments, "") - self.failUnlessEqual(c.revision, 42) - self.failUnlessEqual(c.branch, "branches/test") diff --git a/tools/buildbot/pylibs/buildbot/test/test_config.py b/tools/buildbot/pylibs/buildbot/test/test_config.py deleted file mode 100644 index 3160ee3..0000000 --- a/tools/buildbot/pylibs/buildbot/test/test_config.py +++ /dev/null @@ -1,1276 +0,0 @@ -# -*- test-case-name: buildbot.test.test_config -*- - -import os, warnings, exceptions - -from twisted.trial import unittest -from twisted.python import failure -from twisted.internet import defer - -from buildbot.master import BuildMaster -from buildbot import scheduler -from twisted.application import service, internet -from twisted.spread import pb -from twisted.web.server import Site -from twisted.web.distrib import ResourcePublisher -from buildbot.process.builder import Builder -from buildbot.process.factory import BasicBuildFactory -from buildbot.changes.pb import PBChangeSource -from buildbot.changes.mail import SyncmailMaildirSource -from buildbot.steps.source import CVS, Darcs -from buildbot.steps.shell import Compile, Test, ShellCommand -from buildbot.status import base -from buildbot.steps import dummy, maxq, python, python_twisted, shell, \ - source, transfer -words = None -try: - from buildbot.status import words -except ImportError: - pass - -emptyCfg = \ -""" -from buildbot.buildslave import BuildSlave -BuildmasterConfig = c = {} -c['slaves'] = [] -c['schedulers'] = [] -c['builders'] = [] -c['slavePortnum'] = 9999 -c['projectName'] = 'dummy project' -c['projectURL'] = 'http://dummy.example.com' -c['buildbotURL'] = 'http://dummy.example.com/buildbot' -""" - -buildersCfg = \ -""" -from buildbot.process.factory import BasicBuildFactory -from buildbot.buildslave import BuildSlave -BuildmasterConfig = c = {} -c['slaves'] = [BuildSlave('bot1', 'pw1')] -c['schedulers'] = [] -c['slavePortnum'] = 9999 -f1 = BasicBuildFactory('cvsroot', 'cvsmodule') -c['builders'] = [{'name':'builder1', 'slavename':'bot1', - 'builddir':'workdir', 'factory':f1}] -""" - -buildersCfg2 = buildersCfg + \ -""" -f1 = BasicBuildFactory('cvsroot', 'cvsmodule2') -c['builders'] = [{'name':'builder1', 'slavename':'bot1', - 'builddir':'workdir', 'factory':f1}] -""" - -buildersCfg3 = buildersCfg2 + \ -""" -c['builders'].append({'name': 'builder2', 'slavename': 'bot1', - 'builddir': 'workdir2', 'factory': f1 }) -""" - -buildersCfg4 = buildersCfg2 + \ -""" -c['builders'] = [{ 'name': 'builder1', 'slavename': 'bot1', - 'builddir': 'newworkdir', 'factory': f1 }, - { 'name': 'builder2', 'slavename': 'bot1', - 'builddir': 'workdir2', 'factory': f1 }] -""" - -wpCfg1 = buildersCfg + \ -""" -from buildbot.steps import shell -f1 = BasicBuildFactory('cvsroot', 'cvsmodule') -f1.addStep(shell.ShellCommand, command=[shell.WithProperties('echo')]) -c['builders'] = [{'name':'builder1', 'slavename':'bot1', - 'builddir':'workdir1', 'factory': f1}] -""" - -wpCfg2 = buildersCfg + \ -""" -from buildbot.steps import shell -f1 = BasicBuildFactory('cvsroot', 'cvsmodule') -f1.addStep(shell.ShellCommand, - command=[shell.WithProperties('echo %s', 'revision')]) -c['builders'] = [{'name':'builder1', 'slavename':'bot1', - 'builddir':'workdir1', 'factory': f1}] -""" - - - -ircCfg1 = emptyCfg + \ -""" -from buildbot.status import words -c['status'] = [words.IRC('irc.us.freenode.net', 'buildbot', ['twisted'])] -""" - -ircCfg2 = emptyCfg + \ -""" -from buildbot.status import words -c['status'] = [words.IRC('irc.us.freenode.net', 'buildbot', ['twisted']), - words.IRC('irc.example.com', 'otherbot', ['chan1', 'chan2'])] -""" - -ircCfg3 = emptyCfg + \ -""" -from buildbot.status import words -c['status'] = [words.IRC('irc.us.freenode.net', 'buildbot', ['knotted'])] -""" - -webCfg1 = emptyCfg + \ -""" -from buildbot.status import html -c['status'] = [html.Waterfall(http_port=9980)] -""" - -webCfg2 = emptyCfg + \ -""" -from buildbot.status import html -c['status'] = [html.Waterfall(http_port=9981)] -""" - -webCfg3 = emptyCfg + \ -""" -from buildbot.status import html -c['status'] = [html.Waterfall(http_port='tcp:9981:interface=127.0.0.1')] -""" - -webNameCfg1 = emptyCfg + \ -""" -from buildbot.status import html -c['status'] = [html.Waterfall(distrib_port='~/.twistd-web-pb')] -""" - -webNameCfg2 = emptyCfg + \ -""" -from buildbot.status import html -c['status'] = [html.Waterfall(distrib_port='./bar.socket')] -""" - -debugPasswordCfg = emptyCfg + \ -""" -c['debugPassword'] = 'sekrit' -""" - -interlockCfgBad = \ -""" -from buildbot.process.factory import BasicBuildFactory -from buildbot.buildslave import BuildSlave -c = {} -c['slaves'] = [BuildSlave('bot1', 'pw1')] -c['schedulers'] = [] -f1 = BasicBuildFactory('cvsroot', 'cvsmodule') -c['builders'] = [ - { 'name': 'builder1', 'slavename': 'bot1', - 'builddir': 'workdir', 'factory': f1 }, - { 'name': 'builder2', 'slavename': 'bot1', - 'builddir': 'workdir2', 'factory': f1 }, - ] -# interlocks have been removed -c['interlocks'] = [('lock1', ['builder1'], ['builder2', 'builder3']), - ] -c['slavePortnum'] = 9999 -BuildmasterConfig = c -""" - -lockCfgBad1 = \ -""" -from buildbot.steps.dummy import Dummy -from buildbot.process.factory import BuildFactory, s -from buildbot.locks import MasterLock -from buildbot.buildslave import BuildSlave -c = {} -c['slaves'] = [BuildSlave('bot1', 'pw1')] -c['schedulers'] = [] -l1 = MasterLock('lock1') -l2 = MasterLock('lock1') # duplicate lock name -f1 = BuildFactory([s(Dummy, locks=[])]) -c['builders'] = [ - { 'name': 'builder1', 'slavename': 'bot1', - 'builddir': 'workdir', 'factory': f1, 'locks': [l1, l2] }, - { 'name': 'builder2', 'slavename': 'bot1', - 'builddir': 'workdir2', 'factory': f1 }, - ] -c['slavePortnum'] = 9999 -BuildmasterConfig = c -""" - -lockCfgBad2 = \ -""" -from buildbot.steps.dummy import Dummy -from buildbot.process.factory import BuildFactory, s -from buildbot.locks import MasterLock, SlaveLock -from buildbot.buildslave import BuildSlave -c = {} -c['slaves'] = [BuildSlave('bot1', 'pw1')] -c['schedulers'] = [] -l1 = MasterLock('lock1') -l2 = SlaveLock('lock1') # duplicate lock name -f1 = BuildFactory([s(Dummy, locks=[])]) -c['builders'] = [ - { 'name': 'builder1', 'slavename': 'bot1', - 'builddir': 'workdir', 'factory': f1, 'locks': [l1, l2] }, - { 'name': 'builder2', 'slavename': 'bot1', - 'builddir': 'workdir2', 'factory': f1 }, - ] -c['slavePortnum'] = 9999 -BuildmasterConfig = c -""" - -lockCfgBad3 = \ -""" -from buildbot.steps.dummy import Dummy -from buildbot.process.factory import BuildFactory, s -from buildbot.locks import MasterLock -from buildbot.buildslave import BuildSlave -c = {} -c['slaves'] = [BuildSlave('bot1', 'pw1')] -c['schedulers'] = [] -l1 = MasterLock('lock1') -l2 = MasterLock('lock1') # duplicate lock name -f1 = BuildFactory([s(Dummy, locks=[l2])]) -f2 = BuildFactory([s(Dummy)]) -c['builders'] = [ - { 'name': 'builder1', 'slavename': 'bot1', - 'builddir': 'workdir', 'factory': f2, 'locks': [l1] }, - { 'name': 'builder2', 'slavename': 'bot1', - 'builddir': 'workdir2', 'factory': f1 }, - ] -c['slavePortnum'] = 9999 -BuildmasterConfig = c -""" - -lockCfg1a = \ -""" -from buildbot.process.factory import BasicBuildFactory -from buildbot.locks import MasterLock -from buildbot.buildslave import BuildSlave -c = {} -c['slaves'] = [BuildSlave('bot1', 'pw1')] -c['schedulers'] = [] -f1 = BasicBuildFactory('cvsroot', 'cvsmodule') -l1 = MasterLock('lock1') -l2 = MasterLock('lock2') -c['builders'] = [ - { 'name': 'builder1', 'slavename': 'bot1', - 'builddir': 'workdir', 'factory': f1, 'locks': [l1, l2] }, - { 'name': 'builder2', 'slavename': 'bot1', - 'builddir': 'workdir2', 'factory': f1 }, - ] -c['slavePortnum'] = 9999 -BuildmasterConfig = c -""" - -lockCfg1b = \ -""" -from buildbot.process.factory import BasicBuildFactory -from buildbot.locks import MasterLock -from buildbot.buildslave import BuildSlave -c = {} -c['slaves'] = [BuildSlave('bot1', 'pw1')] -c['schedulers'] = [] -f1 = BasicBuildFactory('cvsroot', 'cvsmodule') -l1 = MasterLock('lock1') -l2 = MasterLock('lock2') -c['builders'] = [ - { 'name': 'builder1', 'slavename': 'bot1', - 'builddir': 'workdir', 'factory': f1, 'locks': [l1] }, - { 'name': 'builder2', 'slavename': 'bot1', - 'builddir': 'workdir2', 'factory': f1 }, - ] -c['slavePortnum'] = 9999 -BuildmasterConfig = c -""" - -# test out step Locks -lockCfg2a = \ -""" -from buildbot.steps.dummy import Dummy -from buildbot.process.factory import BuildFactory, s -from buildbot.locks import MasterLock -from buildbot.buildslave import BuildSlave -c = {} -c['slaves'] = [BuildSlave('bot1', 'pw1')] -c['schedulers'] = [] -l1 = MasterLock('lock1') -l2 = MasterLock('lock2') -f1 = BuildFactory([s(Dummy, locks=[l1,l2])]) -f2 = BuildFactory([s(Dummy)]) - -c['builders'] = [ - { 'name': 'builder1', 'slavename': 'bot1', - 'builddir': 'workdir', 'factory': f1 }, - { 'name': 'builder2', 'slavename': 'bot1', - 'builddir': 'workdir2', 'factory': f2 }, - ] -c['slavePortnum'] = 9999 -BuildmasterConfig = c -""" - -lockCfg2b = \ -""" -from buildbot.steps.dummy import Dummy -from buildbot.process.factory import BuildFactory, s -from buildbot.locks import MasterLock -from buildbot.buildslave import BuildSlave -c = {} -c['slaves'] = [BuildSlave('bot1', 'pw1')] -c['schedulers'] = [] -l1 = MasterLock('lock1') -l2 = MasterLock('lock2') -f1 = BuildFactory([s(Dummy, locks=[l1])]) -f2 = BuildFactory([s(Dummy)]) - -c['builders'] = [ - { 'name': 'builder1', 'slavename': 'bot1', - 'builddir': 'workdir', 'factory': f1 }, - { 'name': 'builder2', 'slavename': 'bot1', - 'builddir': 'workdir2', 'factory': f2 }, - ] -c['slavePortnum'] = 9999 -BuildmasterConfig = c -""" - -lockCfg2c = \ -""" -from buildbot.steps.dummy import Dummy -from buildbot.process.factory import BuildFactory, s -from buildbot.locks import MasterLock -from buildbot.buildslave import BuildSlave -c = {} -c['slaves'] = [BuildSlave('bot1', 'pw1')] -c['schedulers'] = [] -l1 = MasterLock('lock1') -l2 = MasterLock('lock2') -f1 = BuildFactory([s(Dummy)]) -f2 = BuildFactory([s(Dummy)]) - -c['builders'] = [ - { 'name': 'builder1', 'slavename': 'bot1', - 'builddir': 'workdir', 'factory': f1 }, - { 'name': 'builder2', 'slavename': 'bot1', - 'builddir': 'workdir2', 'factory': f2 }, - ] -c['slavePortnum'] = 9999 -BuildmasterConfig = c -""" - -schedulersCfg = \ -""" -from buildbot.scheduler import Scheduler, Dependent -from buildbot.process.factory import BasicBuildFactory -from buildbot.buildslave import BuildSlave -c = {} -c['slaves'] = [BuildSlave('bot1', 'pw1')] -f1 = BasicBuildFactory('cvsroot', 'cvsmodule') -b1 = {'name':'builder1', 'slavename':'bot1', - 'builddir':'workdir', 'factory':f1} -c['builders'] = [b1] -c['schedulers'] = [Scheduler('full', None, 60, ['builder1'])] -c['slavePortnum'] = 9999 -c['projectName'] = 'dummy project' -c['projectURL'] = 'http://dummy.example.com' -c['buildbotURL'] = 'http://dummy.example.com/buildbot' -BuildmasterConfig = c -""" - -class ConfigTest(unittest.TestCase): - def setUp(self): - # this class generates several deprecation warnings, which the user - # doesn't need to see. - warnings.simplefilter('ignore', exceptions.DeprecationWarning) - self.buildmaster = BuildMaster(".") - - def failUnlessListsEquivalent(self, list1, list2): - l1 = list1[:] - l1.sort() - l2 = list2[:] - l2.sort() - self.failUnlessEqual(l1, l2) - - def servers(self, s, types): - # perform a recursive search of s.services, looking for instances of - # twisted.application.internet.TCPServer, then extract their .args - # values to find the TCP ports they want to listen on - for child in s: - if service.IServiceCollection.providedBy(child): - for gc in self.servers(child, types): - yield gc - if isinstance(child, types): - yield child - - def TCPports(self, s): - return list(self.servers(s, internet.TCPServer)) - def UNIXports(self, s): - return list(self.servers(s, internet.UNIXServer)) - def TCPclients(self, s): - return list(self.servers(s, internet.TCPClient)) - - def checkPorts(self, svc, expected): - """Verify that the TCPServer and UNIXServer children of the given - service have the expected portnum/pathname and factory classes. As a - side-effect, return a list of servers in the same order as the - 'expected' list. This can be used to verify properties of the - factories contained therein.""" - - expTCP = [e for e in expected if type(e[0]) == int] - expUNIX = [e for e in expected if type(e[0]) == str] - haveTCP = [(p.args[0], p.args[1].__class__) - for p in self.TCPports(svc)] - haveUNIX = [(p.args[0], p.args[1].__class__) - for p in self.UNIXports(svc)] - self.failUnlessListsEquivalent(expTCP, haveTCP) - self.failUnlessListsEquivalent(expUNIX, haveUNIX) - ret = [] - for e in expected: - for have in self.TCPports(svc) + self.UNIXports(svc): - if have.args[0] == e[0]: - ret.append(have) - continue - assert(len(ret) == len(expected)) - return ret - - def testEmpty(self): - self.failUnlessRaises(KeyError, self.buildmaster.loadConfig, "") - - def testSimple(self): - # covers slavePortnum, base checker passwords - master = self.buildmaster - master.loadChanges() - - master.loadConfig(emptyCfg) - # note: this doesn't actually start listening, because the app - # hasn't been started running - self.failUnlessEqual(master.slavePortnum, "tcp:9999") - self.checkPorts(master, [(9999, pb.PBServerFactory)]) - self.failUnlessEqual(list(master.change_svc), []) - self.failUnlessEqual(master.botmaster.builders, {}) - self.failUnlessEqual(master.checker.users, - {"change": "changepw"}) - self.failUnlessEqual(master.projectName, "dummy project") - self.failUnlessEqual(master.projectURL, "http://dummy.example.com") - self.failUnlessEqual(master.buildbotURL, - "http://dummy.example.com/buildbot") - - def testSlavePortnum(self): - master = self.buildmaster - master.loadChanges() - - master.loadConfig(emptyCfg) - self.failUnlessEqual(master.slavePortnum, "tcp:9999") - ports = self.checkPorts(master, [(9999, pb.PBServerFactory)]) - p = ports[0] - - master.loadConfig(emptyCfg) - self.failUnlessEqual(master.slavePortnum, "tcp:9999") - ports = self.checkPorts(master, [(9999, pb.PBServerFactory)]) - self.failUnlessIdentical(p, ports[0], - "the slave port was changed even " + \ - "though the configuration was not") - - master.loadConfig(emptyCfg + "c['slavePortnum'] = 9000\n") - self.failUnlessEqual(master.slavePortnum, "tcp:9000") - ports = self.checkPorts(master, [(9000, pb.PBServerFactory)]) - self.failIf(p is ports[0], - "slave port was unchanged but configuration was changed") - - def testSlaves(self): - master = self.buildmaster - master.loadChanges() - master.loadConfig(emptyCfg) - self.failUnlessEqual(master.botmaster.builders, {}) - self.failUnlessEqual(master.checker.users, - {"change": "changepw"}) - # 'botsCfg' is testing backwards compatibility, for 0.7.5 config - # files that have not yet been updated to 0.7.6 . This compatibility - # (and this test) is scheduled for removal in 0.8.0 . - botsCfg = (emptyCfg + - "c['bots'] = [('bot1', 'pw1'), ('bot2', 'pw2')]\n") - master.loadConfig(botsCfg) - self.failUnlessEqual(master.checker.users, - {"change": "changepw", - "bot1": "pw1", - "bot2": "pw2"}) - master.loadConfig(botsCfg) - self.failUnlessEqual(master.checker.users, - {"change": "changepw", - "bot1": "pw1", - "bot2": "pw2"}) - master.loadConfig(emptyCfg) - self.failUnlessEqual(master.checker.users, - {"change": "changepw"}) - slavesCfg = (emptyCfg + - "from buildbot.buildslave import BuildSlave\n" - "c['slaves'] = [BuildSlave('bot1','pw1'), " - "BuildSlave('bot2','pw2')]\n") - master.loadConfig(slavesCfg) - self.failUnlessEqual(master.checker.users, - {"change": "changepw", - "bot1": "pw1", - "bot2": "pw2"}) - - - def testChangeSource(self): - master = self.buildmaster - master.loadChanges() - master.loadConfig(emptyCfg) - self.failUnlessEqual(list(master.change_svc), []) - - sourcesCfg = emptyCfg + \ -""" -from buildbot.changes.pb import PBChangeSource -c['change_source'] = PBChangeSource() -""" - - d = master.loadConfig(sourcesCfg) - def _check1(res): - self.failUnlessEqual(len(list(self.buildmaster.change_svc)), 1) - s1 = list(self.buildmaster.change_svc)[0] - self.failUnless(isinstance(s1, PBChangeSource)) - self.failUnlessEqual(s1, list(self.buildmaster.change_svc)[0]) - self.failUnless(s1.parent) - - # verify that unchanged sources are not interrupted - d1 = self.buildmaster.loadConfig(sourcesCfg) - - def _check2(res): - self.failUnlessEqual(len(list(self.buildmaster.change_svc)), 1) - s2 = list(self.buildmaster.change_svc)[0] - self.failUnlessIdentical(s1, s2) - self.failUnless(s1.parent) - d1.addCallback(_check2) - return d1 - d.addCallback(_check1) - - # make sure we can get rid of the sources too - d.addCallback(lambda res: self.buildmaster.loadConfig(emptyCfg)) - - def _check3(res): - self.failUnlessEqual(list(self.buildmaster.change_svc), []) - d.addCallback(_check3) - - return d - - def testChangeSources(self): - # make sure we can accept a list - master = self.buildmaster - master.loadChanges() - master.loadConfig(emptyCfg) - self.failUnlessEqual(list(master.change_svc), []) - - sourcesCfg = emptyCfg + \ -""" -from buildbot.changes.pb import PBChangeSource -from buildbot.changes.mail import SyncmailMaildirSource -c['change_source'] = [PBChangeSource(), - SyncmailMaildirSource('.'), - ] -""" - - d = master.loadConfig(sourcesCfg) - def _check1(res): - self.failUnlessEqual(len(list(self.buildmaster.change_svc)), 2) - s1,s2 = list(self.buildmaster.change_svc) - if isinstance(s2, PBChangeSource): - s1,s2 = s2,s1 - self.failUnless(isinstance(s1, PBChangeSource)) - self.failUnless(s1.parent) - self.failUnless(isinstance(s2, SyncmailMaildirSource)) - self.failUnless(s2.parent) - d.addCallback(_check1) - return d - - def testSources(self): - # test backwards compatibility. c['sources'] is deprecated. - master = self.buildmaster - master.loadChanges() - master.loadConfig(emptyCfg) - self.failUnlessEqual(list(master.change_svc), []) - - sourcesCfg = emptyCfg + \ -""" -from buildbot.changes.pb import PBChangeSource -c['sources'] = [PBChangeSource()] -""" - - d = master.loadConfig(sourcesCfg) - def _check1(res): - self.failUnlessEqual(len(list(self.buildmaster.change_svc)), 1) - s1 = list(self.buildmaster.change_svc)[0] - self.failUnless(isinstance(s1, PBChangeSource)) - self.failUnless(s1.parent) - d.addCallback(_check1) - return d - - def shouldBeFailure(self, res, *expected): - self.failUnless(isinstance(res, failure.Failure), - "we expected this to fail, not produce %s" % (res,)) - res.trap(*expected) - return None # all is good - - def testSchedulerErrors(self): - master = self.buildmaster - master.loadChanges() - master.loadConfig(emptyCfg) - self.failUnlessEqual(master.allSchedulers(), []) - - def _shouldBeFailure(res, hint=None): - self.shouldBeFailure(res, AssertionError, ValueError) - if hint: - self.failUnless(str(res).find(hint) != -1) - - def _loadConfig(res, newcfg): - return self.buildmaster.loadConfig(newcfg) - d = defer.succeed(None) - - # c['schedulers'] must be a list - badcfg = schedulersCfg + \ -""" -c['schedulers'] = Scheduler('full', None, 60, ['builder1']) -""" - d.addCallback(_loadConfig, badcfg) - d.addBoth(_shouldBeFailure, - "c['schedulers'] must be a list of Scheduler instances") - - # c['schedulers'] must be a list of IScheduler objects - badcfg = schedulersCfg + \ -""" -c['schedulers'] = ['oops', 'problem'] -""" - d.addCallback(_loadConfig, badcfg) - d.addBoth(_shouldBeFailure, - "c['schedulers'] must be a list of Scheduler instances") - - # c['schedulers'] must point at real builders - badcfg = schedulersCfg + \ -""" -c['schedulers'] = [Scheduler('full', None, 60, ['builder-bogus'])] -""" - d.addCallback(_loadConfig, badcfg) - d.addBoth(_shouldBeFailure, "uses unknown builder") - - # builderNames= must be a list - badcfg = schedulersCfg + \ -""" -c['schedulers'] = [Scheduler('full', None, 60, 'builder1')] -""" - d.addCallback(_loadConfig, badcfg) - d.addBoth(_shouldBeFailure, - "must be a list of Builder description names") - - # builderNames= must be a list of strings, not dicts - badcfg = schedulersCfg + \ -""" -c['schedulers'] = [Scheduler('full', None, 60, [b1])] -""" - d.addCallback(_loadConfig, badcfg) - d.addBoth(_shouldBeFailure, - "must be a list of Builder description names") - - # builderNames= must be a list of strings, not a dict - badcfg = schedulersCfg + \ -""" -c['schedulers'] = [Scheduler('full', None, 60, b1)] -""" - d.addCallback(_loadConfig, badcfg) - d.addBoth(_shouldBeFailure, - "must be a list of Builder description names") - - # each Scheduler must have a unique name - badcfg = schedulersCfg + \ -""" -c['schedulers'] = [Scheduler('dup', None, 60, []), - Scheduler('dup', None, 60, [])] -""" - d.addCallback(_loadConfig, badcfg) - d.addBoth(_shouldBeFailure, "Schedulers must have unique names") - - return d - - def testSchedulers(self): - master = self.buildmaster - master.loadChanges() - master.loadConfig(emptyCfg) - self.failUnlessEqual(master.allSchedulers(), []) - - d = self.buildmaster.loadConfig(schedulersCfg) - d.addCallback(self._testSchedulers_1) - return d - - def _testSchedulers_1(self, res): - sch = self.buildmaster.allSchedulers() - self.failUnlessEqual(len(sch), 1) - s = sch[0] - self.failUnless(isinstance(s, scheduler.Scheduler)) - self.failUnlessEqual(s.name, "full") - self.failUnlessEqual(s.branch, None) - self.failUnlessEqual(s.treeStableTimer, 60) - self.failUnlessEqual(s.builderNames, ['builder1']) - - newcfg = schedulersCfg + \ -""" -s1 = Scheduler('full', None, 60, ['builder1']) -c['schedulers'] = [s1, Dependent('downstream', s1, ['builder1'])] -""" - d = self.buildmaster.loadConfig(newcfg) - d.addCallback(self._testSchedulers_2, newcfg) - return d - def _testSchedulers_2(self, res, newcfg): - sch = self.buildmaster.allSchedulers() - self.failUnlessEqual(len(sch), 2) - s = sch[0] - self.failUnless(isinstance(s, scheduler.Scheduler)) - s = sch[1] - self.failUnless(isinstance(s, scheduler.Dependent)) - self.failUnlessEqual(s.name, "downstream") - self.failUnlessEqual(s.builderNames, ['builder1']) - - # reloading the same config file should leave the schedulers in place - d = self.buildmaster.loadConfig(newcfg) - d.addCallback(self._testSchedulers_3, sch) - return d - def _testSchedulers_3(self, res, sch1): - sch2 = self.buildmaster.allSchedulers() - self.failUnlessEqual(len(sch2), 2) - sch1.sort() - sch2.sort() - self.failUnlessEqual(sch1, sch2) - self.failUnlessIdentical(sch1[0], sch2[0]) - self.failUnlessIdentical(sch1[1], sch2[1]) - self.failUnlessIdentical(sch1[0].parent, self.buildmaster) - self.failUnlessIdentical(sch1[1].parent, self.buildmaster) - - - - def testBuilders(self): - master = self.buildmaster - master.loadConfig(emptyCfg) - self.failUnlessEqual(master.botmaster.builders, {}) - - master.loadConfig(buildersCfg) - self.failUnlessEqual(master.botmaster.builderNames, ["builder1"]) - self.failUnlessEqual(master.botmaster.builders.keys(), ["builder1"]) - b = master.botmaster.builders["builder1"] - self.failUnless(isinstance(b, Builder)) - self.failUnlessEqual(b.name, "builder1") - self.failUnlessEqual(b.slavenames, ["bot1"]) - self.failUnlessEqual(b.builddir, "workdir") - f1 = b.buildFactory - self.failUnless(isinstance(f1, BasicBuildFactory)) - steps = f1.steps - self.failUnlessEqual(len(steps), 3) - self.failUnlessEqual(steps[0], (CVS, - {'cvsroot': 'cvsroot', - 'cvsmodule': 'cvsmodule', - 'mode': 'clobber'})) - self.failUnlessEqual(steps[1], (Compile, - {'command': 'make all'})) - self.failUnlessEqual(steps[2], (Test, - {'command': 'make check'})) - - - # make sure a reload of the same data doesn't interrupt the Builder - master.loadConfig(buildersCfg) - self.failUnlessEqual(master.botmaster.builderNames, ["builder1"]) - self.failUnlessEqual(master.botmaster.builders.keys(), ["builder1"]) - b2 = master.botmaster.builders["builder1"] - self.failUnlessIdentical(b, b2) - # TODO: test that the BuilderStatus object doesn't change - #statusbag2 = master.client_svc.statusbags["builder1"] - #self.failUnlessIdentical(statusbag, statusbag2) - - # but changing something should result in a new Builder - master.loadConfig(buildersCfg2) - self.failUnlessEqual(master.botmaster.builderNames, ["builder1"]) - self.failUnlessEqual(master.botmaster.builders.keys(), ["builder1"]) - b3 = master.botmaster.builders["builder1"] - self.failIf(b is b3) - # the statusbag remains the same TODO - #statusbag3 = master.client_svc.statusbags["builder1"] - #self.failUnlessIdentical(statusbag, statusbag3) - - # adding new builder - master.loadConfig(buildersCfg3) - self.failUnlessEqual(master.botmaster.builderNames, ["builder1", - "builder2"]) - self.failUnlessListsEquivalent(master.botmaster.builders.keys(), - ["builder1", "builder2"]) - b4 = master.botmaster.builders["builder1"] - self.failUnlessIdentical(b3, b4) - - # changing first builder should leave it at the same place in the list - master.loadConfig(buildersCfg4) - self.failUnlessEqual(master.botmaster.builderNames, ["builder1", - "builder2"]) - self.failUnlessListsEquivalent(master.botmaster.builders.keys(), - ["builder1", "builder2"]) - b5 = master.botmaster.builders["builder1"] - self.failIf(b4 is b5) - - # and removing it should make the Builder go away - master.loadConfig(emptyCfg) - self.failUnlessEqual(master.botmaster.builderNames, []) - self.failUnlessEqual(master.botmaster.builders, {}) - #self.failUnlessEqual(master.client_svc.statusbags, {}) # TODO - - def testWithProperties(self): - master = self.buildmaster - master.loadConfig(wpCfg1) - self.failUnlessEqual(master.botmaster.builderNames, ["builder1"]) - self.failUnlessEqual(master.botmaster.builders.keys(), ["builder1"]) - b1 = master.botmaster.builders["builder1"] - - # reloading the same config should leave the builder unchanged - master.loadConfig(wpCfg1) - b2 = master.botmaster.builders["builder1"] - self.failUnlessIdentical(b1, b2) - - # but changing the parameters of the WithProperties should change it - master.loadConfig(wpCfg2) - b3 = master.botmaster.builders["builder1"] - self.failIf(b1 is b3) - - # again, reloading same config should leave the builder unchanged - master.loadConfig(wpCfg2) - b4 = master.botmaster.builders["builder1"] - self.failUnlessIdentical(b3, b4) - - def checkIRC(self, m, expected): - ircs = {} - for irc in self.servers(m, words.IRC): - ircs[irc.host] = (irc.nick, irc.channels) - self.failUnlessEqual(ircs, expected) - - def testIRC(self): - if not words: - raise unittest.SkipTest("Twisted Words package is not installed") - master = self.buildmaster - master.loadChanges() - d = master.loadConfig(emptyCfg) - e1 = {} - d.addCallback(lambda res: self.checkIRC(master, e1)) - d.addCallback(lambda res: master.loadConfig(ircCfg1)) - e2 = {'irc.us.freenode.net': ('buildbot', ['twisted'])} - d.addCallback(lambda res: self.checkIRC(master, e2)) - d.addCallback(lambda res: master.loadConfig(ircCfg2)) - e3 = {'irc.us.freenode.net': ('buildbot', ['twisted']), - 'irc.example.com': ('otherbot', ['chan1', 'chan2'])} - d.addCallback(lambda res: self.checkIRC(master, e3)) - d.addCallback(lambda res: master.loadConfig(ircCfg3)) - e4 = {'irc.us.freenode.net': ('buildbot', ['knotted'])} - d.addCallback(lambda res: self.checkIRC(master, e4)) - d.addCallback(lambda res: master.loadConfig(ircCfg1)) - e5 = {'irc.us.freenode.net': ('buildbot', ['twisted'])} - d.addCallback(lambda res: self.checkIRC(master, e5)) - return d - - def testWebPortnum(self): - master = self.buildmaster - master.loadChanges() - - d = master.loadConfig(webCfg1) - def _check1(res): - ports = self.checkPorts(self.buildmaster, - [(9999, pb.PBServerFactory), (9980, Site)]) - p = ports[1] - self.p = p - # nothing should be changed - d.addCallback(_check1) - - d.addCallback(lambda res: self.buildmaster.loadConfig(webCfg1)) - def _check2(res): - ports = self.checkPorts(self.buildmaster, - [(9999, pb.PBServerFactory), (9980, Site)]) - self.failUnlessIdentical(self.p, ports[1], - "web port was changed even though " - "configuration was not") - # WebStatus is no longer a ComparableMixin, so it will be - # rebuilt on each reconfig - #d.addCallback(_check2) - - d.addCallback(lambda res: self.buildmaster.loadConfig(webCfg2)) - # changes port to 9981 - def _check3(p): - ports = self.checkPorts(self.buildmaster, - [(9999, pb.PBServerFactory), (9981, Site)]) - self.failIf(self.p is ports[1], - "configuration was changed but web port was unchanged") - d.addCallback(_check3) - - d.addCallback(lambda res: self.buildmaster.loadConfig(webCfg3)) - # make 9981 on only localhost - def _check4(p): - ports = self.checkPorts(self.buildmaster, - [(9999, pb.PBServerFactory), (9981, Site)]) - self.failUnlessEqual(ports[1].kwargs['interface'], "127.0.0.1") - d.addCallback(_check4) - - d.addCallback(lambda res: self.buildmaster.loadConfig(emptyCfg)) - d.addCallback(lambda res: - self.checkPorts(self.buildmaster, - [(9999, pb.PBServerFactory)])) - return d - - def testWebPathname(self): - master = self.buildmaster - master.loadChanges() - - d = master.loadConfig(webNameCfg1) - def _check1(res): - self.checkPorts(self.buildmaster, - [(9999, pb.PBServerFactory), - ('~/.twistd-web-pb', pb.PBServerFactory)]) - unixports = self.UNIXports(self.buildmaster) - self.f = f = unixports[0].args[1] - self.failUnless(isinstance(f.root, ResourcePublisher)) - d.addCallback(_check1) - - d.addCallback(lambda res: self.buildmaster.loadConfig(webNameCfg1)) - # nothing should be changed - def _check2(res): - self.checkPorts(self.buildmaster, - [(9999, pb.PBServerFactory), - ('~/.twistd-web-pb', pb.PBServerFactory)]) - newf = self.UNIXports(self.buildmaster)[0].args[1] - self.failUnlessIdentical(self.f, newf, - "web factory was changed even though " - "configuration was not") - # WebStatus is no longer a ComparableMixin, so it will be - # rebuilt on each reconfig - #d.addCallback(_check2) - - d.addCallback(lambda res: self.buildmaster.loadConfig(webNameCfg2)) - def _check3(res): - self.checkPorts(self.buildmaster, - [(9999, pb.PBServerFactory), - ('./bar.socket', pb.PBServerFactory)]) - newf = self.UNIXports(self.buildmaster)[0].args[1], - self.failIf(self.f is newf, - "web factory was unchanged but " - "configuration was changed") - d.addCallback(_check3) - - d.addCallback(lambda res: self.buildmaster.loadConfig(emptyCfg)) - d.addCallback(lambda res: - self.checkPorts(self.buildmaster, - [(9999, pb.PBServerFactory)])) - return d - - def testDebugPassword(self): - master = self.buildmaster - - master.loadConfig(debugPasswordCfg) - self.failUnlessEqual(master.checker.users, - {"change": "changepw", - "debug": "sekrit"}) - - master.loadConfig(debugPasswordCfg) - self.failUnlessEqual(master.checker.users, - {"change": "changepw", - "debug": "sekrit"}) - - master.loadConfig(emptyCfg) - self.failUnlessEqual(master.checker.users, - {"change": "changepw"}) - - def testLocks(self): - master = self.buildmaster - botmaster = master.botmaster - - # make sure that c['interlocks'] is rejected properly - self.failUnlessRaises(KeyError, master.loadConfig, interlockCfgBad) - # and that duplicate-named Locks are caught - self.failUnlessRaises(ValueError, master.loadConfig, lockCfgBad1) - self.failUnlessRaises(ValueError, master.loadConfig, lockCfgBad2) - self.failUnlessRaises(ValueError, master.loadConfig, lockCfgBad3) - - # create a Builder that uses Locks - master.loadConfig(lockCfg1a) - b1 = master.botmaster.builders["builder1"] - self.failUnlessEqual(len(b1.locks), 2) - - # reloading the same config should not change the Builder - master.loadConfig(lockCfg1a) - self.failUnlessIdentical(b1, master.botmaster.builders["builder1"]) - # but changing the set of locks used should change it - master.loadConfig(lockCfg1b) - self.failIfIdentical(b1, master.botmaster.builders["builder1"]) - b1 = master.botmaster.builders["builder1"] - self.failUnlessEqual(len(b1.locks), 1) - - # similar test with step-scoped locks - master.loadConfig(lockCfg2a) - b1 = master.botmaster.builders["builder1"] - # reloading the same config should not change the Builder - master.loadConfig(lockCfg2a) - self.failUnlessIdentical(b1, master.botmaster.builders["builder1"]) - # but changing the set of locks used should change it - master.loadConfig(lockCfg2b) - self.failIfIdentical(b1, master.botmaster.builders["builder1"]) - b1 = master.botmaster.builders["builder1"] - # remove the locks entirely - master.loadConfig(lockCfg2c) - self.failIfIdentical(b1, master.botmaster.builders["builder1"]) - -class ConfigElements(unittest.TestCase): - # verify that ComparableMixin is working - def testSchedulers(self): - s1 = scheduler.Scheduler(name='quick', branch=None, - treeStableTimer=30, - builderNames=['quick']) - s2 = scheduler.Scheduler(name="all", branch=None, - treeStableTimer=5*60, - builderNames=["a", "b"]) - s3 = scheduler.Try_Userpass("try", ["a","b"], port=9989, - userpass=[("foo","bar")]) - s1a = scheduler.Scheduler(name='quick', branch=None, - treeStableTimer=30, - builderNames=['quick']) - s2a = scheduler.Scheduler(name="all", branch=None, - treeStableTimer=5*60, - builderNames=["a", "b"]) - s3a = scheduler.Try_Userpass("try", ["a","b"], port=9989, - userpass=[("foo","bar")]) - self.failUnless(s1 == s1) - self.failUnless(s1 == s1a) - self.failUnless(s1a in [s1, s2, s3]) - self.failUnless(s2a in [s1, s2, s3]) - self.failUnless(s3a in [s1, s2, s3]) - - - -class ConfigFileTest(unittest.TestCase): - - def testFindConfigFile(self): - os.mkdir("test_cf") - open(os.path.join("test_cf", "master.cfg"), "w").write(emptyCfg) - slaveportCfg = emptyCfg + "c['slavePortnum'] = 9000\n" - open(os.path.join("test_cf", "alternate.cfg"), "w").write(slaveportCfg) - - m = BuildMaster("test_cf") - m.loadTheConfigFile() - self.failUnlessEqual(m.slavePortnum, "tcp:9999") - - m = BuildMaster("test_cf", "alternate.cfg") - m.loadTheConfigFile() - self.failUnlessEqual(m.slavePortnum, "tcp:9000") - - -class MyTarget(base.StatusReceiverMultiService): - def __init__(self, name): - self.name = name - base.StatusReceiverMultiService.__init__(self) - def startService(self): - # make a note in a list stashed in the BuildMaster - self.parent.targetevents.append(("start", self.name)) - return base.StatusReceiverMultiService.startService(self) - def stopService(self): - self.parent.targetevents.append(("stop", self.name)) - return base.StatusReceiverMultiService.stopService(self) - -class MySlowTarget(MyTarget): - def stopService(self): - from twisted.internet import reactor - d = base.StatusReceiverMultiService.stopService(self) - def stall(res): - d2 = defer.Deferred() - reactor.callLater(0.1, d2.callback, res) - return d2 - d.addCallback(stall) - m = self.parent - def finishedStalling(res): - m.targetevents.append(("stop", self.name)) - return res - d.addCallback(finishedStalling) - return d - -# we can't actually startService a buildmaster with a config that uses a -# fixed slavePortnum like 9999, so instead this makes it possible to pass '0' -# for the first time, and then substitute back in the allocated port number -# on subsequent passes. -startableEmptyCfg = emptyCfg + \ -""" -c['slavePortnum'] = %d -""" - -targetCfg1 = startableEmptyCfg + \ -""" -from buildbot.test.test_config import MyTarget -c['status'] = [MyTarget('a')] -""" - -targetCfg2 = startableEmptyCfg + \ -""" -from buildbot.test.test_config import MySlowTarget -c['status'] = [MySlowTarget('b')] -""" - -class StartService(unittest.TestCase): - def tearDown(self): - return self.master.stopService() - - def testStartService(self): - os.mkdir("test_ss") - self.master = m = BuildMaster("test_ss") - # inhibit the usual read-config-on-startup behavior - m.readConfig = True - m.startService() - d = m.loadConfig(startableEmptyCfg % 0) - d.addCallback(self._testStartService_0) - return d - - def _testStartService_0(self, res): - m = self.master - m.targetevents = [] - # figure out what port got allocated - self.portnum = m.slavePort._port.getHost().port - d = m.loadConfig(targetCfg1 % self.portnum) - d.addCallback(self._testStartService_1) - return d - - def _testStartService_1(self, res): - self.failUnlessEqual(len(self.master.statusTargets), 1) - self.failUnless(isinstance(self.master.statusTargets[0], MyTarget)) - self.failUnlessEqual(self.master.targetevents, - [('start', 'a')]) - self.master.targetevents = [] - # reloading the same config should not start or stop the target - d = self.master.loadConfig(targetCfg1 % self.portnum) - d.addCallback(self._testStartService_2) - return d - - def _testStartService_2(self, res): - self.failUnlessEqual(self.master.targetevents, []) - # but loading a new config file should stop the old one, then - # start the new one - d = self.master.loadConfig(targetCfg2 % self.portnum) - d.addCallback(self._testStartService_3) - return d - - def _testStartService_3(self, res): - self.failUnlessEqual(self.master.targetevents, - [('stop', 'a'), ('start', 'b')]) - self.master.targetevents = [] - # and going back to the old one should do the same, in the same - # order, even though the current MySlowTarget takes a moment to shut - # down - d = self.master.loadConfig(targetCfg1 % self.portnum) - d.addCallback(self._testStartService_4) - return d - - def _testStartService_4(self, res): - self.failUnlessEqual(self.master.targetevents, - [('stop', 'b'), ('start', 'a')]) - -cfg1 = \ -""" -from buildbot.process.factory import BuildFactory, s -from buildbot.steps.shell import ShellCommand -from buildbot.steps.source import Darcs -from buildbot.buildslave import BuildSlave -BuildmasterConfig = c = {} -c['slaves'] = [BuildSlave('bot1', 'pw1')] -c['schedulers'] = [] -c['slavePortnum'] = 9999 -f1 = BuildFactory([ShellCommand(command='echo yes'), - s(ShellCommand, command='old-style'), - ]) -f1.addStep(Darcs(repourl='http://buildbot.net/repos/trunk')) -f1.addStep(ShellCommand, command='echo old-style') -c['builders'] = [{'name':'builder1', 'slavename':'bot1', - 'builddir':'workdir', 'factory':f1}] -""" - -class Factories(unittest.TestCase): - - def failUnlessExpectedShell(self, factory, defaults=True, **kwargs): - shell_args = {} - if defaults: - shell_args.update({'descriptionDone': None, - 'description': None, - 'workdir': None, - 'logfiles': {}, - }) - shell_args.update(kwargs) - self.failUnlessIdentical(factory[0], ShellCommand) - if factory[1] != shell_args: - print - print "factory had:" - for k in sorted(factory[1].keys()): - print k - print "but we were expecting:" - for k in sorted(shell_args.keys()): - print k - self.failUnlessEqual(factory[1], shell_args) - - def failUnlessExpectedDarcs(self, factory, **kwargs): - darcs_args = {'workdir': None, - 'alwaysUseLatest': False, - 'mode': 'update', - 'timeout': 1200, - 'retry': None, - 'baseURL': None, - 'defaultBranch': None, - 'logfiles': {}, - } - darcs_args.update(kwargs) - self.failUnlessIdentical(factory[0], Darcs) - if factory[1] != darcs_args: - print - print "factory had:" - for k in sorted(factory[1].keys()): - print k - print "but we were expecting:" - for k in sorted(darcs_args.keys()): - print k - self.failUnlessEqual(factory[1], darcs_args) - - def testSteps(self): - m = BuildMaster(".") - m.loadConfig(cfg1) - b = m.botmaster.builders["builder1"] - steps = b.buildFactory.steps - self.failUnlessEqual(len(steps), 4) - - self.failUnlessExpectedShell(steps[0], command="echo yes") - self.failUnlessExpectedShell(steps[1], defaults=False, - command="old-style") - self.failUnlessExpectedDarcs(steps[2], - repourl="http://buildbot.net/repos/trunk") - self.failUnlessExpectedShell(steps[3], defaults=False, - command="echo old-style") - - def _loop(self, orig): - step_class, kwargs = orig.getStepFactory() - newstep = step_class(**kwargs) - return newstep - - def testAllSteps(self): - # make sure that steps can be created from the factories that they - # return - for s in ( dummy.Dummy(), dummy.FailingDummy(), dummy.RemoteDummy(), - maxq.MaxQ("testdir"), - python.BuildEPYDoc(), python.PyFlakes(), - python_twisted.HLint(), - python_twisted.Trial(testpath=None, tests="tests"), - python_twisted.ProcessDocs(), python_twisted.BuildDebs(), - python_twisted.RemovePYCs(), - shell.ShellCommand(), shell.TreeSize(), - shell.Configure(), shell.Compile(), shell.Test(), - source.CVS("cvsroot", "module"), - source.SVN("svnurl"), source.Darcs("repourl"), - source.Git("repourl"), - source.Arch("url", "version"), - source.Bazaar("url", "version", "archive"), - source.Bzr("repourl"), - source.Mercurial("repourl"), - source.P4("p4base"), - source.P4Sync(1234, "p4user", "passwd", "client", - mode="copy"), - source.Monotone("server", "branch"), - transfer.FileUpload("src", "dest"), - transfer.FileDownload("src", "dest"), - ): - try: - self._loop(s) - except: - print "error checking %s" % s - raise - diff --git a/tools/buildbot/pylibs/buildbot/test/test_control.py b/tools/buildbot/pylibs/buildbot/test/test_control.py deleted file mode 100644 index ced6332..0000000 --- a/tools/buildbot/pylibs/buildbot/test/test_control.py +++ /dev/null @@ -1,104 +0,0 @@ -# -*- test-case-name: buildbot.test.test_control -*- - -import os - -from twisted.trial import unittest -from twisted.internet import defer - -from buildbot import master, interfaces -from buildbot.sourcestamp import SourceStamp -from buildbot.slave import bot -from buildbot.status.builder import SUCCESS -from buildbot.process import base -from buildbot.test.runutils import rmtree - -config = """ -from buildbot.process import factory -from buildbot.steps import dummy -from buildbot.buildslave import BuildSlave - -def s(klass, **kwargs): - return (klass, kwargs) - -f1 = factory.BuildFactory([ - s(dummy.Dummy, timeout=1), - ]) -c = {} -c['slaves'] = [BuildSlave('bot1', 'sekrit')] -c['schedulers'] = [] -c['builders'] = [{'name': 'force', 'slavename': 'bot1', - 'builddir': 'force-dir', 'factory': f1}] -c['slavePortnum'] = 0 -BuildmasterConfig = c -""" - -class FakeBuilder: - name = "fake" - def getSlaveCommandVersion(self, command, oldversion=None): - return "1.10" - - -class Force(unittest.TestCase): - - def rmtree(self, d): - rmtree(d) - - def setUp(self): - self.master = None - self.slave = None - self.rmtree("control_basedir") - os.mkdir("control_basedir") - self.master = master.BuildMaster("control_basedir") - self.slavebase = os.path.abspath("control_slavebase") - self.rmtree(self.slavebase) - os.mkdir("control_slavebase") - - def connectSlave(self): - port = self.master.slavePort._port.getHost().port - slave = bot.BuildSlave("localhost", port, "bot1", "sekrit", - self.slavebase, keepalive=0, usePTY=1) - self.slave = slave - slave.startService() - d = self.master.botmaster.waitUntilBuilderAttached("force") - return d - - def tearDown(self): - dl = [] - if self.slave: - dl.append(self.master.botmaster.waitUntilBuilderDetached("force")) - dl.append(defer.maybeDeferred(self.slave.stopService)) - if self.master: - dl.append(defer.maybeDeferred(self.master.stopService)) - return defer.DeferredList(dl) - - def testRequest(self): - m = self.master - m.loadConfig(config) - m.startService() - d = self.connectSlave() - d.addCallback(self._testRequest_1) - return d - def _testRequest_1(self, res): - c = interfaces.IControl(self.master) - req = base.BuildRequest("I was bored", SourceStamp()) - builder_control = c.getBuilder("force") - d = defer.Deferred() - req.subscribe(d.callback) - builder_control.requestBuild(req) - d.addCallback(self._testRequest_2) - # we use the same check-the-results code as testForce - return d - - def _testRequest_2(self, build_control): - self.failUnless(interfaces.IBuildControl.providedBy(build_control)) - d = build_control.getStatus().waitUntilFinished() - d.addCallback(self._testRequest_3) - return d - - def _testRequest_3(self, bs): - self.failUnless(interfaces.IBuildStatus.providedBy(bs)) - self.failUnless(bs.isFinished()) - self.failUnlessEqual(bs.getResults(), SUCCESS) - #self.failUnlessEqual(bs.getResponsibleUsers(), ["bob"]) # TODO - self.failUnlessEqual(bs.getChanges(), ()) - #self.failUnlessEqual(bs.getReason(), "forced") # TODO diff --git a/tools/buildbot/pylibs/buildbot/test/test_dependencies.py b/tools/buildbot/pylibs/buildbot/test/test_dependencies.py deleted file mode 100644 index 624efc4..0000000 --- a/tools/buildbot/pylibs/buildbot/test/test_dependencies.py +++ /dev/null @@ -1,166 +0,0 @@ -# -*- test-case-name: buildbot.test.test_dependencies -*- - -from twisted.trial import unittest - -from twisted.internet import reactor, defer - -from buildbot.test.runutils import RunMixin -from buildbot.status import base - -config_1 = """ -from buildbot import scheduler -from buildbot.process import factory -from buildbot.steps import dummy -from buildbot.buildslave import BuildSlave -s = factory.s -from buildbot.test.test_locks import LockStep - -BuildmasterConfig = c = {} -c['slaves'] = [BuildSlave('bot1', 'sekrit'), BuildSlave('bot2', 'sekrit')] -c['schedulers'] = [] -c['slavePortnum'] = 0 - -# upstream1 (fastfail, slowpass) -# -> downstream2 (b3, b4) -# upstream3 (slowfail, slowpass) -# -> downstream4 (b3, b4) -# -> downstream5 (b5) - -s1 = scheduler.Scheduler('upstream1', None, 10, ['slowpass', 'fastfail']) -s2 = scheduler.Dependent('downstream2', s1, ['b3', 'b4']) -s3 = scheduler.Scheduler('upstream3', None, 10, ['fastpass', 'slowpass']) -s4 = scheduler.Dependent('downstream4', s3, ['b3', 'b4']) -s5 = scheduler.Dependent('downstream5', s4, ['b5']) -c['schedulers'] = [s1, s2, s3, s4, s5] - -f_fastpass = factory.BuildFactory([s(dummy.Dummy, timeout=1)]) -f_slowpass = factory.BuildFactory([s(dummy.Dummy, timeout=2)]) -f_fastfail = factory.BuildFactory([s(dummy.FailingDummy, timeout=1)]) - -def builder(name, f): - d = {'name': name, 'slavename': 'bot1', 'builddir': name, 'factory': f} - return d - -c['builders'] = [builder('slowpass', f_slowpass), - builder('fastfail', f_fastfail), - builder('fastpass', f_fastpass), - builder('b3', f_fastpass), - builder('b4', f_fastpass), - builder('b5', f_fastpass), - ] -""" - -class Logger(base.StatusReceiverMultiService): - def __init__(self, master): - base.StatusReceiverMultiService.__init__(self) - self.builds = [] - for bn in master.status.getBuilderNames(): - master.status.getBuilder(bn).subscribe(self) - - def buildStarted(self, builderName, build): - self.builds.append(builderName) - -class Dependencies(RunMixin, unittest.TestCase): - def setUp(self): - RunMixin.setUp(self) - self.master.loadConfig(config_1) - self.master.startService() - d = self.connectSlave(["slowpass", "fastfail", "fastpass", - "b3", "b4", "b5"]) - return d - - def findScheduler(self, name): - for s in self.master.allSchedulers(): - if s.name == name: - return s - raise KeyError("No Scheduler named '%s'" % name) - - def testParse(self): - self.master.loadConfig(config_1) - # that's it, just make sure this config file is loaded successfully - - def testRun_Fail(self): - # add an extra status target to make pay attention to which builds - # start and which don't. - self.logger = Logger(self.master) - - # kick off upstream1, which has a failing Builder and thus will not - # trigger downstream3 - s = self.findScheduler("upstream1") - # this is an internal function of the Scheduler class - s.fireTimer() # fires a build - # t=0: two builders start: 'slowpass' and 'fastfail' - # t=1: builder 'fastfail' finishes - # t=2: builder 'slowpass' finishes - d = defer.Deferred() - d.addCallback(self._testRun_Fail_1) - reactor.callLater(5, d.callback, None) - return d - - def _testRun_Fail_1(self, res): - # 'slowpass' and 'fastfail' should have run one build each - b = self.status.getBuilder('slowpass').getLastFinishedBuild() - self.failUnless(b) - self.failUnlessEqual(b.getNumber(), 0) - b = self.status.getBuilder('fastfail').getLastFinishedBuild() - self.failUnless(b) - self.failUnlessEqual(b.getNumber(), 0) - - # none of the other builders should have run - self.failIf(self.status.getBuilder('b3').getLastFinishedBuild()) - self.failIf(self.status.getBuilder('b4').getLastFinishedBuild()) - self.failIf(self.status.getBuilder('b5').getLastFinishedBuild()) - - # in fact, none of them should have even started - self.failUnlessEqual(len(self.logger.builds), 2) - self.failUnless("slowpass" in self.logger.builds) - self.failUnless("fastfail" in self.logger.builds) - self.failIf("b3" in self.logger.builds) - self.failIf("b4" in self.logger.builds) - self.failIf("b5" in self.logger.builds) - - def testRun_Pass(self): - # kick off upstream3, which will fire downstream4 and then - # downstream5 - s = self.findScheduler("upstream3") - # this is an internal function of the Scheduler class - s.fireTimer() # fires a build - # t=0: slowpass and fastpass start - # t=1: builder 'fastpass' finishes - # t=2: builder 'slowpass' finishes - # scheduler 'downstream4' fires - # builds b3 and b4 are started - # t=3: builds b3 and b4 finish - # scheduler 'downstream5' fires - # build b5 is started - # t=4: build b5 is finished - d = defer.Deferred() - d.addCallback(self._testRun_Pass_1) - reactor.callLater(5, d.callback, None) - return d - - def _testRun_Pass_1(self, res): - # 'fastpass' and 'slowpass' should have run one build each - b = self.status.getBuilder('fastpass').getLastFinishedBuild() - self.failUnless(b) - self.failUnlessEqual(b.getNumber(), 0) - - b = self.status.getBuilder('slowpass').getLastFinishedBuild() - self.failUnless(b) - self.failUnlessEqual(b.getNumber(), 0) - - self.failIf(self.status.getBuilder('fastfail').getLastFinishedBuild()) - - b = self.status.getBuilder('b3').getLastFinishedBuild() - self.failUnless(b) - self.failUnlessEqual(b.getNumber(), 0) - - b = self.status.getBuilder('b4').getLastFinishedBuild() - self.failUnless(b) - self.failUnlessEqual(b.getNumber(), 0) - - b = self.status.getBuilder('b4').getLastFinishedBuild() - self.failUnless(b) - self.failUnlessEqual(b.getNumber(), 0) - - diff --git a/tools/buildbot/pylibs/buildbot/test/test_locks.py b/tools/buildbot/pylibs/buildbot/test/test_locks.py deleted file mode 100644 index 812f896..0000000 --- a/tools/buildbot/pylibs/buildbot/test/test_locks.py +++ /dev/null @@ -1,425 +0,0 @@ -# -*- test-case-name: buildbot.test.test_locks -*- - -import random - -from twisted.trial import unittest -from twisted.internet import defer, reactor - -from buildbot import master -from buildbot.steps import dummy -from buildbot.sourcestamp import SourceStamp -from buildbot.process.base import BuildRequest -from buildbot.test.runutils import RunMixin -from buildbot import locks - -def claimHarder(lock, owner): - """Return a Deferred that will fire when the lock is claimed. Keep trying - until we succeed.""" - if lock.isAvailable(): - #print "claimHarder(%s): claiming" % owner - lock.claim(owner) - return defer.succeed(lock) - #print "claimHarder(%s): waiting" % owner - d = lock.waitUntilMaybeAvailable(owner) - d.addCallback(claimHarder, owner) - return d - -def hold(lock, owner, mode="now"): - if mode == "now": - lock.release(owner) - elif mode == "very soon": - reactor.callLater(0, lock.release, owner) - elif mode == "soon": - reactor.callLater(0.1, lock.release, owner) - - -class Unit(unittest.TestCase): - def testNow(self): - l = locks.BaseLock("name") - self.failUnless(l.isAvailable()) - l.claim("owner1") - self.failIf(l.isAvailable()) - l.release("owner1") - self.failUnless(l.isAvailable()) - - def testLater(self): - lock = locks.BaseLock("name") - d = claimHarder(lock, "owner1") - d.addCallback(lambda lock: lock.release("owner1")) - return d - - def testCompetition(self): - lock = locks.BaseLock("name") - d = claimHarder(lock, "owner1") - d.addCallback(self._claim1) - return d - def _claim1(self, lock): - # we should have claimed it by now - self.failIf(lock.isAvailable()) - # now set up two competing owners. We don't know which will get the - # lock first. - d2 = claimHarder(lock, "owner2") - d2.addCallback(hold, "owner2", "now") - d3 = claimHarder(lock, "owner3") - d3.addCallback(hold, "owner3", "soon") - dl = defer.DeferredList([d2,d3]) - dl.addCallback(self._cleanup, lock) - # and release the lock in a moment - reactor.callLater(0.1, lock.release, "owner1") - return dl - - def _cleanup(self, res, lock): - d = claimHarder(lock, "cleanup") - d.addCallback(lambda lock: lock.release("cleanup")) - return d - - def testRandom(self): - lock = locks.BaseLock("name") - dl = [] - for i in range(100): - owner = "owner%d" % i - mode = random.choice(["now", "very soon", "soon"]) - d = claimHarder(lock, owner) - d.addCallback(hold, owner, mode) - dl.append(d) - d = defer.DeferredList(dl) - d.addCallback(self._cleanup, lock) - return d - -class Multi(unittest.TestCase): - def testNow(self): - lock = locks.BaseLock("name", 2) - self.failUnless(lock.isAvailable()) - lock.claim("owner1") - self.failUnless(lock.isAvailable()) - lock.claim("owner2") - self.failIf(lock.isAvailable()) - lock.release("owner1") - self.failUnless(lock.isAvailable()) - lock.release("owner2") - self.failUnless(lock.isAvailable()) - - def testLater(self): - lock = locks.BaseLock("name", 2) - lock.claim("owner1") - lock.claim("owner2") - d = claimHarder(lock, "owner3") - d.addCallback(lambda lock: lock.release("owner3")) - lock.release("owner2") - lock.release("owner1") - return d - - def _cleanup(self, res, lock, count): - dl = [] - for i in range(count): - d = claimHarder(lock, "cleanup%d" % i) - dl.append(d) - d2 = defer.DeferredList(dl) - # once all locks are claimed, we know that any previous owners have - # been flushed out - def _release(res): - for i in range(count): - lock.release("cleanup%d" % i) - d2.addCallback(_release) - return d2 - - def testRandom(self): - COUNT = 5 - lock = locks.BaseLock("name", COUNT) - dl = [] - for i in range(100): - owner = "owner%d" % i - mode = random.choice(["now", "very soon", "soon"]) - d = claimHarder(lock, owner) - def _check(lock): - self.failIf(len(lock.owners) > COUNT) - return lock - d.addCallback(_check) - d.addCallback(hold, owner, mode) - dl.append(d) - d = defer.DeferredList(dl) - d.addCallback(self._cleanup, lock, COUNT) - return d - -class Dummy: - pass - -def slave(slavename): - slavebuilder = Dummy() - slavebuilder.slave = Dummy() - slavebuilder.slave.slavename = slavename - return slavebuilder - -class MakeRealLock(unittest.TestCase): - - def make(self, lockid): - return lockid.lockClass(lockid) - - def testMaster(self): - mid1 = locks.MasterLock("name1") - mid2 = locks.MasterLock("name1") - mid3 = locks.MasterLock("name3") - mid4 = locks.MasterLock("name1", 3) - self.failUnlessEqual(mid1, mid2) - self.failIfEqual(mid1, mid3) - # they should all be hashable - d = {mid1: 1, mid2: 2, mid3: 3, mid4: 4} - - l1 = self.make(mid1) - self.failUnlessEqual(l1.name, "name1") - self.failUnlessEqual(l1.maxCount, 1) - self.failUnlessIdentical(l1.getLock(slave("slave1")), l1) - l4 = self.make(mid4) - self.failUnlessEqual(l4.name, "name1") - self.failUnlessEqual(l4.maxCount, 3) - self.failUnlessIdentical(l4.getLock(slave("slave1")), l4) - - def testSlave(self): - sid1 = locks.SlaveLock("name1") - sid2 = locks.SlaveLock("name1") - sid3 = locks.SlaveLock("name3") - sid4 = locks.SlaveLock("name1", maxCount=3) - mcfs = {"bigslave": 4, "smallslave": 1} - sid5 = locks.SlaveLock("name1", maxCount=3, maxCountForSlave=mcfs) - mcfs2 = {"bigslave": 4, "smallslave": 1} - sid5a = locks.SlaveLock("name1", maxCount=3, maxCountForSlave=mcfs2) - mcfs3 = {"bigslave": 1, "smallslave": 99} - sid5b = locks.SlaveLock("name1", maxCount=3, maxCountForSlave=mcfs3) - self.failUnlessEqual(sid1, sid2) - self.failIfEqual(sid1, sid3) - self.failIfEqual(sid1, sid4) - self.failIfEqual(sid1, sid5) - self.failUnlessEqual(sid5, sid5a) - self.failIfEqual(sid5a, sid5b) - # they should all be hashable - d = {sid1: 1, sid2: 2, sid3: 3, sid4: 4, sid5: 5, sid5a: 6, sid5b: 7} - - l1 = self.make(sid1) - self.failUnlessEqual(l1.name, "name1") - self.failUnlessEqual(l1.maxCount, 1) - l1s1 = l1.getLock(slave("slave1")) - self.failIfIdentical(l1s1, l1) - - l4 = self.make(sid4) - self.failUnlessEqual(l4.maxCount, 3) - l4s1 = l4.getLock(slave("slave1")) - self.failUnlessEqual(l4s1.maxCount, 3) - - l5 = self.make(sid5) - l5s1 = l5.getLock(slave("bigslave")) - l5s2 = l5.getLock(slave("smallslave")) - l5s3 = l5.getLock(slave("unnamedslave")) - self.failUnlessEqual(l5s1.maxCount, 4) - self.failUnlessEqual(l5s2.maxCount, 1) - self.failUnlessEqual(l5s3.maxCount, 3) - -class GetLock(unittest.TestCase): - def testGet(self): - # the master.cfg file contains "lock ids", which are instances of - # MasterLock and SlaveLock but which are not actually Locks per se. - # When the build starts, these markers are turned into RealMasterLock - # and RealSlaveLock instances. This insures that any builds running - # on slaves that were unaffected by the config change are still - # referring to the same Lock instance as new builds by builders that - # *were* affected by the change. There have been bugs in the past in - # which this didn't happen, and the Locks were bypassed because half - # the builders were using one incarnation of the lock while the other - # half were using a separate (but equal) incarnation. - # - # Changing the lock id in any way should cause it to be replaced in - # the BotMaster. This will result in a couple of funky artifacts: - # builds in progress might pay attention to a different lock, so we - # might bypass the locking for the duration of a couple builds. - # There's also the problem of old Locks lingering around in - # BotMaster.locks, but they're small and shouldn't really cause a - # problem. - - b = master.BotMaster() - l1 = locks.MasterLock("one") - l1a = locks.MasterLock("one") - l2 = locks.MasterLock("one", maxCount=4) - - rl1 = b.getLockByID(l1) - rl2 = b.getLockByID(l1a) - self.failUnlessIdentical(rl1, rl2) - rl3 = b.getLockByID(l2) - self.failIfIdentical(rl1, rl3) - - s1 = locks.SlaveLock("one") - s1a = locks.SlaveLock("one") - s2 = locks.SlaveLock("one", maxCount=4) - s3 = locks.SlaveLock("one", maxCount=4, - maxCountForSlave={"a":1, "b":2}) - s3a = locks.SlaveLock("one", maxCount=4, - maxCountForSlave={"a":1, "b":2}) - s4 = locks.SlaveLock("one", maxCount=4, - maxCountForSlave={"a":4, "b":4}) - - rl1 = b.getLockByID(s1) - rl2 = b.getLockByID(s1a) - self.failUnlessIdentical(rl1, rl2) - rl3 = b.getLockByID(s2) - self.failIfIdentical(rl1, rl3) - rl4 = b.getLockByID(s3) - self.failIfIdentical(rl1, rl4) - self.failIfIdentical(rl3, rl4) - rl5 = b.getLockByID(s3a) - self.failUnlessIdentical(rl4, rl5) - rl6 = b.getLockByID(s4) - self.failIfIdentical(rl5, rl6) - - - -class LockStep(dummy.Dummy): - def start(self): - number = self.build.requests[0].number - self.build.requests[0].events.append(("start", number)) - dummy.Dummy.start(self) - def done(self): - number = self.build.requests[0].number - self.build.requests[0].events.append(("done", number)) - dummy.Dummy.done(self) - -config_1 = """ -from buildbot import locks -from buildbot.process import factory -from buildbot.buildslave import BuildSlave -s = factory.s -from buildbot.test.test_locks import LockStep - -BuildmasterConfig = c = {} -c['slaves'] = [BuildSlave('bot1', 'sekrit'), BuildSlave('bot2', 'sekrit')] -c['schedulers'] = [] -c['slavePortnum'] = 0 - -first_lock = locks.SlaveLock('first') -second_lock = locks.MasterLock('second') -f1 = factory.BuildFactory([s(LockStep, timeout=2, locks=[first_lock])]) -f2 = factory.BuildFactory([s(LockStep, timeout=3, locks=[second_lock])]) -f3 = factory.BuildFactory([s(LockStep, timeout=2, locks=[])]) - -b1a = {'name': 'full1a', 'slavename': 'bot1', 'builddir': '1a', 'factory': f1} -b1b = {'name': 'full1b', 'slavename': 'bot1', 'builddir': '1b', 'factory': f1} -b1c = {'name': 'full1c', 'slavename': 'bot1', 'builddir': '1c', 'factory': f3, - 'locks': [first_lock, second_lock]} -b1d = {'name': 'full1d', 'slavename': 'bot1', 'builddir': '1d', 'factory': f2} -b2a = {'name': 'full2a', 'slavename': 'bot2', 'builddir': '2a', 'factory': f1} -b2b = {'name': 'full2b', 'slavename': 'bot2', 'builddir': '2b', 'factory': f3, - 'locks': [second_lock]} -c['builders'] = [b1a, b1b, b1c, b1d, b2a, b2b] -""" - -config_1a = config_1 + \ -""" -b1b = {'name': 'full1b', 'slavename': 'bot1', 'builddir': '1B', 'factory': f1} -c['builders'] = [b1a, b1b, b1c, b1d, b2a, b2b] -""" - - -class Locks(RunMixin, unittest.TestCase): - def setUp(self): - RunMixin.setUp(self) - self.req1 = req1 = BuildRequest("forced build", SourceStamp()) - req1.number = 1 - self.req2 = req2 = BuildRequest("forced build", SourceStamp()) - req2.number = 2 - self.req3 = req3 = BuildRequest("forced build", SourceStamp()) - req3.number = 3 - req1.events = req2.events = req3.events = self.events = [] - d = self.master.loadConfig(config_1) - d.addCallback(lambda res: self.master.startService()) - d.addCallback(lambda res: self.connectSlaves(["bot1", "bot2"], - ["full1a", "full1b", - "full1c", "full1d", - "full2a", "full2b"])) - return d - - def testLock1(self): - self.control.getBuilder("full1a").requestBuild(self.req1) - self.control.getBuilder("full1b").requestBuild(self.req2) - d = defer.DeferredList([self.req1.waitUntilFinished(), - self.req2.waitUntilFinished()]) - d.addCallback(self._testLock1_1) - return d - - def _testLock1_1(self, res): - # full1a should complete its step before full1b starts it - self.failUnlessEqual(self.events, - [("start", 1), ("done", 1), - ("start", 2), ("done", 2)]) - - def testLock1a(self): - # just like testLock1, but we reload the config file first, with a - # change that causes full1b to be changed. This tickles a design bug - # in which full1a and full1b wind up with distinct Lock instances. - d = self.master.loadConfig(config_1a) - d.addCallback(self._testLock1a_1) - return d - def _testLock1a_1(self, res): - self.control.getBuilder("full1a").requestBuild(self.req1) - self.control.getBuilder("full1b").requestBuild(self.req2) - d = defer.DeferredList([self.req1.waitUntilFinished(), - self.req2.waitUntilFinished()]) - d.addCallback(self._testLock1a_2) - return d - - def _testLock1a_2(self, res): - # full1a should complete its step before full1b starts it - self.failUnlessEqual(self.events, - [("start", 1), ("done", 1), - ("start", 2), ("done", 2)]) - - def testLock2(self): - # two builds run on separate slaves with slave-scoped locks should - # not interfere - self.control.getBuilder("full1a").requestBuild(self.req1) - self.control.getBuilder("full2a").requestBuild(self.req2) - d = defer.DeferredList([self.req1.waitUntilFinished(), - self.req2.waitUntilFinished()]) - d.addCallback(self._testLock2_1) - return d - - def _testLock2_1(self, res): - # full2a should start its step before full1a finishes it. They run on - # different slaves, however, so they might start in either order. - self.failUnless(self.events[:2] == [("start", 1), ("start", 2)] or - self.events[:2] == [("start", 2), ("start", 1)]) - - def testLock3(self): - # two builds run on separate slaves with master-scoped locks should - # not overlap - self.control.getBuilder("full1c").requestBuild(self.req1) - self.control.getBuilder("full2b").requestBuild(self.req2) - d = defer.DeferredList([self.req1.waitUntilFinished(), - self.req2.waitUntilFinished()]) - d.addCallback(self._testLock3_1) - return d - - def _testLock3_1(self, res): - # full2b should not start until after full1c finishes. The builds run - # on different slaves, so we can't really predict which will start - # first. The important thing is that they don't overlap. - self.failUnless(self.events == [("start", 1), ("done", 1), - ("start", 2), ("done", 2)] - or self.events == [("start", 2), ("done", 2), - ("start", 1), ("done", 1)] - ) - - def testLock4(self): - self.control.getBuilder("full1a").requestBuild(self.req1) - self.control.getBuilder("full1c").requestBuild(self.req2) - self.control.getBuilder("full1d").requestBuild(self.req3) - d = defer.DeferredList([self.req1.waitUntilFinished(), - self.req2.waitUntilFinished(), - self.req3.waitUntilFinished()]) - d.addCallback(self._testLock4_1) - return d - - def _testLock4_1(self, res): - # full1a starts, then full1d starts (because they do not interfere). - # Once both are done, full1c can run. - self.failUnlessEqual(self.events, - [("start", 1), ("start", 3), - ("done", 1), ("done", 3), - ("start", 2), ("done", 2)]) - diff --git a/tools/buildbot/pylibs/buildbot/test/test_maildir.py b/tools/buildbot/pylibs/buildbot/test/test_maildir.py deleted file mode 100644 index b79cbd3..0000000 --- a/tools/buildbot/pylibs/buildbot/test/test_maildir.py +++ /dev/null @@ -1,92 +0,0 @@ -# -*- test-case-name: buildbot.test.test_maildir -*- - -from twisted.trial import unittest -import os, shutil -from buildbot.changes.mail import FCMaildirSource -from twisted.internet import defer, reactor, task -from twisted.python import util, log - -class TimeOutError(Exception): - """The message were not received in a timely fashion""" - -class MaildirTest(unittest.TestCase): - SECONDS_PER_MESSAGE = 1.0 - - def setUp(self): - log.msg("creating empty maildir") - self.maildir = "test-maildir" - if os.path.isdir(self.maildir): - shutil.rmtree(self.maildir) - log.msg("removing stale maildir") - os.mkdir(self.maildir) - os.mkdir(os.path.join(self.maildir, "cur")) - os.mkdir(os.path.join(self.maildir, "new")) - os.mkdir(os.path.join(self.maildir, "tmp")) - self.source = None - - def tearDown(self): - log.msg("removing old maildir") - shutil.rmtree(self.maildir) - if self.source: - return self.source.stopService() - - def addChange(self, c): - # NOTE: this assumes every message results in a Change, which isn't - # true for msg8-prefix - log.msg("got change") - self.changes.append(c) - - def deliverMail(self, msg): - log.msg("delivering", msg) - newdir = os.path.join(self.maildir, "new") - # to do this right, use safecat - shutil.copy(msg, newdir) - - def poll(self, changes, count, d): - if len(changes) == count: - d.callback("passed") - - def testMaildir(self): - self.changes = [] - s = self.source = FCMaildirSource(self.maildir) - s.parent = self - s.startService() - testfiles_dir = util.sibpath(__file__, "mail") - testfiles = [msg for msg in os.listdir(testfiles_dir) - if msg.startswith("freshcvs")] - assert testfiles - testfiles.sort() - count = len(testfiles) - d = defer.Deferred() - - i = 1 - for i in range(count): - msg = testfiles[i] - reactor.callLater(self.SECONDS_PER_MESSAGE*i, self.deliverMail, - os.path.join(testfiles_dir, msg)) - self.loop = task.LoopingCall(self.poll, self.changes, count, d) - self.loop.start(0.1) - t = reactor.callLater(self.SECONDS_PER_MESSAGE*count + 15, - d.errback, TimeOutError) - # TODO: verify the messages, should use code from test_mailparse but - # I'm not sure how to factor the verification routines out in a - # useful fashion - - #for i in range(count): - # msg, check = test_messages[i] - # check(self, self.changes[i]) - - def _shutdown(res): - if t.active(): - t.cancel() - self.loop.stop() - return res - d.addBoth(_shutdown) - - return d - - # TODO: it would be nice to set this timeout after counting the number of - # messages in buildbot/test/mail/msg*, but I suspect trial wants to have - # this number before the method starts, and maybe even before setUp() - testMaildir.timeout = SECONDS_PER_MESSAGE*9 + 15 - diff --git a/tools/buildbot/pylibs/buildbot/test/test_mailparse.py b/tools/buildbot/pylibs/buildbot/test/test_mailparse.py deleted file mode 100644 index fb89b27..0000000 --- a/tools/buildbot/pylibs/buildbot/test/test_mailparse.py +++ /dev/null @@ -1,293 +0,0 @@ -# -*- test-case-name: buildbot.test.test_mailparse -*- - -from twisted.trial import unittest -from twisted.python import util -from buildbot.changes import mail - -class TestFreshCVS(unittest.TestCase): - - def get(self, msg): - msg = util.sibpath(__file__, msg) - s = mail.FCMaildirSource(None) - return s.parse_file(open(msg, "r")) - - def testMsg1(self): - c = self.get("mail/freshcvs.1") - self.assertEqual(c.who, "moshez") - self.assertEqual(c.files, ["Twisted/debian/python-twisted.menu.in"]) - self.assertEqual(c.comments, "Instance massenger, apparently\n") - self.assertEqual(c.isdir, 0) - - def testMsg2(self): - c = self.get("mail/freshcvs.2") - self.assertEqual(c.who, "itamarst") - self.assertEqual(c.files, ["Twisted/twisted/web/woven/form.py", - "Twisted/twisted/python/formmethod.py"]) - self.assertEqual(c.comments, - "submit formmethod now subclass of Choice\n") - self.assertEqual(c.isdir, 0) - - def testMsg3(self): - # same as msg2 but missing the ViewCVS section - c = self.get("mail/freshcvs.3") - self.assertEqual(c.who, "itamarst") - self.assertEqual(c.files, ["Twisted/twisted/web/woven/form.py", - "Twisted/twisted/python/formmethod.py"]) - self.assertEqual(c.comments, - "submit formmethod now subclass of Choice\n") - self.assertEqual(c.isdir, 0) - - def testMsg4(self): - # same as msg3 but also missing CVS patch section - c = self.get("mail/freshcvs.4") - self.assertEqual(c.who, "itamarst") - self.assertEqual(c.files, ["Twisted/twisted/web/woven/form.py", - "Twisted/twisted/python/formmethod.py"]) - self.assertEqual(c.comments, - "submit formmethod now subclass of Choice\n") - self.assertEqual(c.isdir, 0) - - def testMsg5(self): - # creates a directory - c = self.get("mail/freshcvs.5") - self.assertEqual(c.who, "etrepum") - self.assertEqual(c.files, ["Twisted/doc/examples/cocoaDemo"]) - self.assertEqual(c.comments, - "Directory /cvs/Twisted/doc/examples/cocoaDemo added to the repository\n") - self.assertEqual(c.isdir, 1) - - def testMsg6(self): - # adds files - c = self.get("mail/freshcvs.6") - self.assertEqual(c.who, "etrepum") - self.assertEqual(c.files, [ - "Twisted/doc/examples/cocoaDemo/MyAppDelegate.py", - "Twisted/doc/examples/cocoaDemo/__main__.py", - "Twisted/doc/examples/cocoaDemo/bin-python-main.m", - "Twisted/doc/examples/cocoaDemo/English.lproj/InfoPlist.strings", - "Twisted/doc/examples/cocoaDemo/English.lproj/MainMenu.nib/classes.nib", - "Twisted/doc/examples/cocoaDemo/English.lproj/MainMenu.nib/info.nib", - "Twisted/doc/examples/cocoaDemo/English.lproj/MainMenu.nib/keyedobjects.nib", - "Twisted/doc/examples/cocoaDemo/cocoaDemo.pbproj/project.pbxproj"]) - self.assertEqual(c.comments, - "Cocoa (OS X) clone of the QT demo, using polling reactor\n\nRequires pyobjc ( http://pyobjc.sourceforge.net ), it's not much different than the template project. The reactor is iterated periodically by a repeating NSTimer.\n") - self.assertEqual(c.isdir, 0) - - def testMsg7(self): - # deletes files - c = self.get("mail/freshcvs.7") - self.assertEqual(c.who, "etrepum") - self.assertEqual(c.files, [ - "Twisted/doc/examples/cocoaDemo/MyAppDelegate.py", - "Twisted/doc/examples/cocoaDemo/__main__.py", - "Twisted/doc/examples/cocoaDemo/bin-python-main.m", - "Twisted/doc/examples/cocoaDemo/English.lproj/InfoPlist.strings", - "Twisted/doc/examples/cocoaDemo/English.lproj/MainMenu.nib/classes.nib", - "Twisted/doc/examples/cocoaDemo/English.lproj/MainMenu.nib/info.nib", - "Twisted/doc/examples/cocoaDemo/English.lproj/MainMenu.nib/keyedobjects.nib", - "Twisted/doc/examples/cocoaDemo/cocoaDemo.pbproj/project.pbxproj"]) - self.assertEqual(c.comments, - "Directories break debian build script, waiting for reasonable fix\n") - self.assertEqual(c.isdir, 0) - - def testMsg8(self): - # files outside Twisted/ - c = self.get("mail/freshcvs.8") - self.assertEqual(c.who, "acapnotic") - self.assertEqual(c.files, [ "CVSROOT/freshCfg" ]) - self.assertEqual(c.comments, "it doesn't work with invalid syntax\n") - self.assertEqual(c.isdir, 0) - - def testMsg9(self): - # also creates a directory - c = self.get("mail/freshcvs.9") - self.assertEqual(c.who, "exarkun") - self.assertEqual(c.files, ["Twisted/sandbox/exarkun/persist-plugin"]) - self.assertEqual(c.comments, - "Directory /cvs/Twisted/sandbox/exarkun/persist-plugin added to the repository\n") - self.assertEqual(c.isdir, 1) - - -class TestFreshCVS_Prefix(unittest.TestCase): - def get(self, msg): - msg = util.sibpath(__file__, msg) - s = mail.FCMaildirSource(None) - return s.parse_file(open(msg, "r"), prefix="Twisted/") - - def testMsg1p(self): - c = self.get("mail/freshcvs.1") - self.assertEqual(c.who, "moshez") - self.assertEqual(c.files, ["debian/python-twisted.menu.in"]) - self.assertEqual(c.comments, "Instance massenger, apparently\n") - - def testMsg2p(self): - c = self.get("mail/freshcvs.2") - self.assertEqual(c.who, "itamarst") - self.assertEqual(c.files, ["twisted/web/woven/form.py", - "twisted/python/formmethod.py"]) - self.assertEqual(c.comments, - "submit formmethod now subclass of Choice\n") - - def testMsg3p(self): - # same as msg2 but missing the ViewCVS section - c = self.get("mail/freshcvs.3") - self.assertEqual(c.who, "itamarst") - self.assertEqual(c.files, ["twisted/web/woven/form.py", - "twisted/python/formmethod.py"]) - self.assertEqual(c.comments, - "submit formmethod now subclass of Choice\n") - - def testMsg4p(self): - # same as msg3 but also missing CVS patch section - c = self.get("mail/freshcvs.4") - self.assertEqual(c.who, "itamarst") - self.assertEqual(c.files, ["twisted/web/woven/form.py", - "twisted/python/formmethod.py"]) - self.assertEqual(c.comments, - "submit formmethod now subclass of Choice\n") - - def testMsg5p(self): - # creates a directory - c = self.get("mail/freshcvs.5") - self.assertEqual(c.who, "etrepum") - self.assertEqual(c.files, ["doc/examples/cocoaDemo"]) - self.assertEqual(c.comments, - "Directory /cvs/Twisted/doc/examples/cocoaDemo added to the repository\n") - self.assertEqual(c.isdir, 1) - - def testMsg6p(self): - # adds files - c = self.get("mail/freshcvs.6") - self.assertEqual(c.who, "etrepum") - self.assertEqual(c.files, [ - "doc/examples/cocoaDemo/MyAppDelegate.py", - "doc/examples/cocoaDemo/__main__.py", - "doc/examples/cocoaDemo/bin-python-main.m", - "doc/examples/cocoaDemo/English.lproj/InfoPlist.strings", - "doc/examples/cocoaDemo/English.lproj/MainMenu.nib/classes.nib", - "doc/examples/cocoaDemo/English.lproj/MainMenu.nib/info.nib", - "doc/examples/cocoaDemo/English.lproj/MainMenu.nib/keyedobjects.nib", - "doc/examples/cocoaDemo/cocoaDemo.pbproj/project.pbxproj"]) - self.assertEqual(c.comments, - "Cocoa (OS X) clone of the QT demo, using polling reactor\n\nRequires pyobjc ( http://pyobjc.sourceforge.net ), it's not much different than the template project. The reactor is iterated periodically by a repeating NSTimer.\n") - self.assertEqual(c.isdir, 0) - - def testMsg7p(self): - # deletes files - c = self.get("mail/freshcvs.7") - self.assertEqual(c.who, "etrepum") - self.assertEqual(c.files, [ - "doc/examples/cocoaDemo/MyAppDelegate.py", - "doc/examples/cocoaDemo/__main__.py", - "doc/examples/cocoaDemo/bin-python-main.m", - "doc/examples/cocoaDemo/English.lproj/InfoPlist.strings", - "doc/examples/cocoaDemo/English.lproj/MainMenu.nib/classes.nib", - "doc/examples/cocoaDemo/English.lproj/MainMenu.nib/info.nib", - "doc/examples/cocoaDemo/English.lproj/MainMenu.nib/keyedobjects.nib", - "doc/examples/cocoaDemo/cocoaDemo.pbproj/project.pbxproj"]) - self.assertEqual(c.comments, - "Directories break debian build script, waiting for reasonable fix\n") - self.assertEqual(c.isdir, 0) - - def testMsg8p(self): - # files outside Twisted/ - c = self.get("mail/freshcvs.8") - self.assertEqual(c, None) - - -class TestSyncmail(unittest.TestCase): - def get(self, msg): - msg = util.sibpath(__file__, msg) - s = mail.SyncmailMaildirSource(None) - return s.parse_file(open(msg, "r"), prefix="buildbot/") - - def getNoPrefix(self, msg): - msg = util.sibpath(__file__, msg) - s = mail.SyncmailMaildirSource(None) - return s.parse_file(open(msg, "r")) - - def testMsgS1(self): - c = self.get("mail/syncmail.1") - self.failUnless(c is not None) - self.assertEqual(c.who, "warner") - self.assertEqual(c.files, ["buildbot/changes/freshcvsmail.py"]) - self.assertEqual(c.comments, - "remove leftover code, leave a temporary compatibility import. Note! Start\nimporting FCMaildirSource from changes.mail instead of changes.freshcvsmail\n") - self.assertEqual(c.isdir, 0) - - def testMsgS2(self): - c = self.get("mail/syncmail.2") - self.assertEqual(c.who, "warner") - self.assertEqual(c.files, ["ChangeLog"]) - self.assertEqual(c.comments, "\t* NEWS: started adding new features\n") - self.assertEqual(c.isdir, 0) - - def testMsgS3(self): - c = self.get("mail/syncmail.3") - self.failUnless(c == None) - - def testMsgS4(self): - c = self.get("mail/syncmail.4") - self.assertEqual(c.who, "warner") - self.assertEqual(c.files, ["test/mail/syncmail.1", - "test/mail/syncmail.2", - "test/mail/syncmail.3" - ]) - self.assertEqual(c.comments, "test cases for syncmail parser\n") - self.assertEqual(c.isdir, 0) - self.assertEqual(c.branch, None) - - # tests a tag - def testMsgS5(self): - c = self.getNoPrefix("mail/syncmail.5") - self.failUnless(c) - self.assertEqual(c.who, "thomas") - self.assertEqual(c.files, ['test1/MANIFEST', - 'test1/Makefile.am', - 'test1/autogen.sh', - 'test1/configure.in' - ]) - self.assertEqual(c.branch, "BRANCH-DEVEL") - self.assertEqual(c.isdir, 0) - - -class TestSVNCommitEmail(unittest.TestCase): - def get(self, msg, prefix): - msg = util.sibpath(__file__, msg) - s = mail.SVNCommitEmailMaildirSource(None) - return s.parse_file(open(msg, "r"), prefix) - - def test1(self): - c = self.get("mail/svn-commit.1", "spamassassin/trunk/") - self.failUnless(c) - self.failUnlessEqual(c.who, "felicity") - self.failUnlessEqual(c.files, ["sa-update.raw"]) - self.failUnlessEqual(c.branch, None) - self.failUnlessEqual(c.comments, - "bug 4864: remove extraneous front-slash " - "from gpghomedir path\n") - - def test2a(self): - c = self.get("mail/svn-commit.2", "spamassassin/trunk/") - self.failIf(c) - - def test2b(self): - c = self.get("mail/svn-commit.2", "spamassassin/branches/3.1/") - self.failUnless(c) - self.failUnlessEqual(c.who, "sidney") - self.failUnlessEqual(c.files, - ["lib/Mail/SpamAssassin/Timeout.pm", - "MANIFEST", - "lib/Mail/SpamAssassin/Logger.pm", - "lib/Mail/SpamAssassin/Plugin/DCC.pm", - "lib/Mail/SpamAssassin/Plugin/DomainKeys.pm", - "lib/Mail/SpamAssassin/Plugin/Pyzor.pm", - "lib/Mail/SpamAssassin/Plugin/Razor2.pm", - "lib/Mail/SpamAssassin/Plugin/SPF.pm", - "lib/Mail/SpamAssassin/SpamdForkScaling.pm", - "spamd/spamd.raw", - ]) - self.failUnlessEqual(c.comments, - "Bug 4696: consolidated fixes for timeout bugs\n") - - diff --git a/tools/buildbot/pylibs/buildbot/test/test_p4poller.py b/tools/buildbot/pylibs/buildbot/test/test_p4poller.py deleted file mode 100644 index 54c6325..0000000 --- a/tools/buildbot/pylibs/buildbot/test/test_p4poller.py +++ /dev/null @@ -1,213 +0,0 @@ -import time - -from twisted.internet import defer -from twisted.trial import unittest - -from buildbot.changes.changes import Change -from buildbot.changes.p4poller import P4Source, get_simple_split - -first_p4changes = \ -"""Change 1 on 2006/04/13 by slamb@testclient 'first rev' -""" - -second_p4changes = \ -"""Change 3 on 2006/04/13 by bob@testclient 'short desc truncated' -Change 2 on 2006/04/13 by slamb@testclient 'bar' -""" - -third_p4changes = \ -"""Change 5 on 2006/04/13 by mpatel@testclient 'first rev' -""" - -change_4_log = \ -"""Change 4 by mpatel@testclient on 2006/04/13 21:55:39 - - short desc truncated because this is a long description. -""" -change_3_log = \ -"""Change 3 by bob@testclient on 2006/04/13 21:51:39 - - short desc truncated because this is a long description. -""" - -change_2_log = \ -"""Change 2 by slamb@testclient on 2006/04/13 21:46:23 - - creation -""" - -p4change = { - 3: change_3_log + -"""Affected files ... - -... //depot/myproject/branch_b/branch_b_file#1 add -... //depot/myproject/branch_b/whatbranch#1 branch -... //depot/myproject/branch_c/whatbranch#1 branch -""", - 2: change_2_log + -"""Affected files ... - -... //depot/myproject/trunk/whatbranch#1 add -... //depot/otherproject/trunk/something#1 add -""", - 5: change_4_log + -"""Affected files ... - -... //depot/myproject/branch_b/branch_b_file#1 add -... //depot/myproject/branch_b#75 edit -... //depot/myproject/branch_c/branch_c_file#1 add -""", -} - - -class MockP4Source(P4Source): - """Test P4Source which doesn't actually invoke p4.""" - invocation = 0 - - def __init__(self, p4changes, p4change, *args, **kwargs): - P4Source.__init__(self, *args, **kwargs) - self.p4changes = p4changes - self.p4change = p4change - - def _get_changes(self): - assert self.working - result = self.p4changes[self.invocation] - self.invocation += 1 - return defer.succeed(result) - - def _get_describe(self, dummy, num): - assert self.working - return defer.succeed(self.p4change[num]) - -class TestP4Poller(unittest.TestCase): - def setUp(self): - self.changes = [] - self.addChange = self.changes.append - - def failUnlessIn(self, substr, string): - # this is for compatibility with python2.2 - if isinstance(string, str): - self.failUnless(string.find(substr) != -1) - else: - self.assertIn(substr, string) - - def testCheck(self): - """successful checks""" - self.t = MockP4Source(p4changes=[first_p4changes, second_p4changes], - p4change=p4change, - p4port=None, p4user=None, - p4base='//depot/myproject/', - split_file=lambda x: x.split('/', 1)) - self.t.parent = self - - # The first time, it just learns the change to start at. - self.assert_(self.t.last_change is None) - self.assert_(not self.t.working) - return self.t.checkp4().addCallback(self._testCheck2) - - def _testCheck2(self, res): - self.assertEquals(self.changes, []) - self.assertEquals(self.t.last_change, 1) - - # Subsequent times, it returns Change objects for new changes. - return self.t.checkp4().addCallback(self._testCheck3) - - def _testCheck3(self, res): - self.assertEquals(len(self.changes), 3) - self.assertEquals(self.t.last_change, 3) - self.assert_(not self.t.working) - - # They're supposed to go oldest to newest, so this one must be first. - self.assertEquals(self.changes[0].asText(), - Change(who='slamb', - files=['whatbranch'], - comments=change_2_log, - revision='2', - when=self.makeTime("2006/04/13 21:46:23"), - branch='trunk').asText()) - - # These two can happen in either order, since they're from the same - # Perforce change. - self.failUnlessIn( - Change(who='bob', - files=['branch_b_file', - 'whatbranch'], - comments=change_3_log, - revision='3', - when=self.makeTime("2006/04/13 21:51:39"), - branch='branch_b').asText(), - [c.asText() for c in self.changes]) - self.failUnlessIn( - Change(who='bob', - files=['whatbranch'], - comments=change_3_log, - revision='3', - when=self.makeTime("2006/04/13 21:51:39"), - branch='branch_c').asText(), - [c.asText() for c in self.changes]) - - def makeTime(self, timestring): - datefmt = '%Y/%m/%d %H:%M:%S' - when = time.mktime(time.strptime(timestring, datefmt)) - return when - - def testFailedChanges(self): - """'p4 changes' failure is properly ignored""" - self.t = MockP4Source(p4changes=['Perforce client error:\n...'], - p4change={}, - p4port=None, p4user=None) - self.t.parent = self - d = self.t.checkp4() - d.addCallback(self._testFailedChanges2) - return d - - def _testFailedChanges2(self, f): - self.failUnlessEqual(f, None) - self.assert_(not self.t.working) - - def testFailedDescribe(self): - """'p4 describe' failure is properly ignored""" - c = dict(p4change) - c[3] = 'Perforce client error:\n...' - self.t = MockP4Source(p4changes=[first_p4changes, second_p4changes], - p4change=c, p4port=None, p4user=None) - self.t.parent = self - d = self.t.checkp4() - d.addCallback(self._testFailedDescribe2) - return d - - def _testFailedDescribe2(self, res): - # first time finds nothing; check again. - return self.t.checkp4().addCallback(self._testFailedDescribe3) - - def _testFailedDescribe3(self, f): - self.failUnlessEqual(f, None) - self.assert_(not self.t.working) - self.assertEquals(self.t.last_change, 2) - - def testAlreadyWorking(self): - """don't launch a new poll while old is still going""" - self.t = P4Source() - self.t.working = True - self.assert_(self.t.last_change is None) - d = self.t.checkp4() - d.addCallback(self._testAlreadyWorking2) - - def _testAlreadyWorking2(self, res): - self.assert_(self.t.last_change is None) - - def testSplitFile(self): - """Make sure split file works on branch only changes""" - self.t = MockP4Source(p4changes=[third_p4changes], - p4change=p4change, - p4port=None, p4user=None, - p4base='//depot/myproject/', - split_file=get_simple_split) - self.t.parent = self - self.t.last_change = 50 - d = self.t.checkp4() - d.addCallback(self._testSplitFile) - - def _testSplitFile(self, res): - self.assertEquals(len(self.changes), 2) - self.assertEquals(self.t.last_change, 5) diff --git a/tools/buildbot/pylibs/buildbot/test/test_properties.py b/tools/buildbot/pylibs/buildbot/test/test_properties.py deleted file mode 100644 index b8579f4..0000000 --- a/tools/buildbot/pylibs/buildbot/test/test_properties.py +++ /dev/null @@ -1,273 +0,0 @@ -# -*- test-case-name: buildbot.test.test_properties -*- - -import os - -from twisted.trial import unittest - -from buildbot.sourcestamp import SourceStamp -from buildbot.process import base -from buildbot.process.properties import WithProperties, Properties -from buildbot.status import builder -from buildbot.slave.commands import rmdirRecursive -from buildbot.test.runutils import RunMixin - - -class FakeBuild: - pass -class FakeBuildMaster: - properties = Properties(masterprop="master") -class FakeBotMaster: - parent = FakeBuildMaster() -class FakeBuilder: - statusbag = None - name = "fakebuilder" - botmaster = FakeBotMaster() -class FakeSlave: - slavename = "bot12" - properties = Properties(slavename="bot12") -class FakeSlaveBuilder: - slave = FakeSlave() - def getSlaveCommandVersion(self, command, oldversion=None): - return "1.10" -class FakeScheduler: - name = "fakescheduler" - -class TestProperties(unittest.TestCase): - def setUp(self): - self.props = Properties() - - def testDictBehavior(self): - self.props.setProperty("do-tests", 1, "scheduler") - self.props.setProperty("do-install", 2, "scheduler") - - self.assert_(self.props.has_key('do-tests')) - self.failUnlessEqual(self.props['do-tests'], 1) - self.failUnlessEqual(self.props['do-install'], 2) - self.assertRaises(KeyError, lambda : self.props['do-nothing']) - self.failUnlessEqual(self.props.getProperty('do-install'), 2) - - def testUpdate(self): - self.props.setProperty("x", 24, "old") - newprops = { 'a' : 1, 'b' : 2 } - self.props.update(newprops, "new") - - self.failUnlessEqual(self.props.getProperty('x'), 24) - self.failUnlessEqual(self.props.getPropertySource('x'), 'old') - self.failUnlessEqual(self.props.getProperty('a'), 1) - self.failUnlessEqual(self.props.getPropertySource('a'), 'new') - - def testUpdateFromProperties(self): - self.props.setProperty("x", 24, "old") - newprops = Properties() - newprops.setProperty('a', 1, "new") - newprops.setProperty('b', 2, "new") - self.props.updateFromProperties(newprops) - - self.failUnlessEqual(self.props.getProperty('x'), 24) - self.failUnlessEqual(self.props.getPropertySource('x'), 'old') - self.failUnlessEqual(self.props.getProperty('a'), 1) - self.failUnlessEqual(self.props.getPropertySource('a'), 'new') - - # render() is pretty well tested by TestWithProperties - -class TestWithProperties(unittest.TestCase): - def setUp(self): - self.props = Properties() - - def testBasic(self): - # test basic substitution with WithProperties - self.props.setProperty("revision", "47", "test") - command = WithProperties("build-%s.tar.gz", "revision") - self.failUnlessEqual(self.props.render(command), - "build-47.tar.gz") - - def testDict(self): - # test dict-style substitution with WithProperties - self.props.setProperty("other", "foo", "test") - command = WithProperties("build-%(other)s.tar.gz") - self.failUnlessEqual(self.props.render(command), - "build-foo.tar.gz") - - def testDictColonMinus(self): - # test dict-style substitution with WithProperties - self.props.setProperty("prop1", "foo", "test") - command = WithProperties("build-%(prop1:-empty)s-%(prop2:-empty)s.tar.gz") - self.failUnlessEqual(self.props.render(command), - "build-foo-empty.tar.gz") - - def testDictColonPlus(self): - # test dict-style substitution with WithProperties - self.props.setProperty("prop1", "foo", "test") - command = WithProperties("build-%(prop1:+exists)s-%(prop2:+exists)s.tar.gz") - self.failUnlessEqual(self.props.render(command), - "build-exists-.tar.gz") - - def testEmpty(self): - # None should render as '' - self.props.setProperty("empty", None, "test") - command = WithProperties("build-%(empty)s.tar.gz") - self.failUnlessEqual(self.props.render(command), - "build-.tar.gz") - - def testRecursiveList(self): - self.props.setProperty("x", 10, "test") - self.props.setProperty("y", 20, "test") - command = [ WithProperties("%(x)s %(y)s"), "and", - WithProperties("%(y)s %(x)s") ] - self.failUnlessEqual(self.props.render(command), - ["10 20", "and", "20 10"]) - - def testRecursiveTuple(self): - self.props.setProperty("x", 10, "test") - self.props.setProperty("y", 20, "test") - command = ( WithProperties("%(x)s %(y)s"), "and", - WithProperties("%(y)s %(x)s") ) - self.failUnlessEqual(self.props.render(command), - ("10 20", "and", "20 10")) - - def testRecursiveDict(self): - self.props.setProperty("x", 10, "test") - self.props.setProperty("y", 20, "test") - command = { WithProperties("%(x)s %(y)s") : - WithProperties("%(y)s %(x)s") } - self.failUnlessEqual(self.props.render(command), - {"10 20" : "20 10"}) - -class BuildProperties(unittest.TestCase): - """Test the properties that a build should have.""" - def setUp(self): - self.builder = FakeBuilder() - self.builder_status = builder.BuilderStatus("fakebuilder") - self.builder_status.basedir = "test_properties" - self.builder_status.nextBuildNumber = 5 - rmdirRecursive(self.builder_status.basedir) - os.mkdir(self.builder_status.basedir) - self.build_status = self.builder_status.newBuild() - req = base.BuildRequest("reason", - SourceStamp(branch="branch2", revision="1234"), - properties=Properties(scheduler="fakescheduler")) - self.build = base.Build([req]) - self.build.build_status = self.build_status - self.build.setBuilder(self.builder) - self.build.setupProperties() - self.build.setupSlaveBuilder(FakeSlaveBuilder()) - - def testProperties(self): - self.failUnlessEqual(self.build.getProperty("scheduler"), "fakescheduler") - self.failUnlessEqual(self.build.getProperty("branch"), "branch2") - self.failUnlessEqual(self.build.getProperty("revision"), "1234") - self.failUnlessEqual(self.build.getProperty("slavename"), "bot12") - self.failUnlessEqual(self.build.getProperty("buildnumber"), 5) - self.failUnlessEqual(self.build.getProperty("buildername"), "fakebuilder") - self.failUnlessEqual(self.build.getProperty("masterprop"), "master") - -run_config = """ -from buildbot.process import factory -from buildbot.steps.shell import ShellCommand, WithProperties -from buildbot.buildslave import BuildSlave -s = factory.s - -BuildmasterConfig = c = {} -c['slaves'] = [BuildSlave('bot1', 'sekrit', properties={'slprop':'slprop'})] -c['schedulers'] = [] -c['slavePortnum'] = 0 -c['properties'] = { 'global' : 'global' } - -# Note: when run against twisted-1.3.0, this locks up about 5% of the time. I -# suspect that a command with no output that finishes quickly triggers a race -# condition in 1.3.0's process-reaping code. The 'touch' process becomes a -# zombie and the step never completes. To keep this from messing up the unit -# tests too badly, this step runs with a reduced timeout. - -f1 = factory.BuildFactory([s(ShellCommand, - flunkOnFailure=True, - command=['touch', - WithProperties('%s-%s-%s', - 'slavename', 'global', 'slprop'), - ], - workdir='.', - timeout=10, - )]) - -b1 = {'name': 'full1', 'slavename': 'bot1', 'builddir': 'bd1', 'factory': f1} -c['builders'] = [b1] - -""" - -class Run(RunMixin, unittest.TestCase): - def testInterpolate(self): - # run an actual build with a step that interpolates a build property - d = self.master.loadConfig(run_config) - d.addCallback(lambda res: self.master.startService()) - d.addCallback(lambda res: self.connectOneSlave("bot1")) - d.addCallback(lambda res: self.requestBuild("full1")) - d.addCallback(self.failUnlessBuildSucceeded) - def _check_touch(res): - f = os.path.join("slavebase-bot1", "bd1", "bot1-global-slprop") - self.failUnless(os.path.exists(f)) - return res - d.addCallback(_check_touch) - return d - - SetProperty_base_config = """ -from buildbot.process import factory -from buildbot.steps.shell import ShellCommand, SetProperty, WithProperties -from buildbot.buildslave import BuildSlave -s = factory.s - -BuildmasterConfig = c = {} -c['slaves'] = [BuildSlave('bot1', 'sekrit')] -c['schedulers'] = [] -c['slavePortnum'] = 0 - -f1 = factory.BuildFactory([ -##STEPS## -]) - -b1 = {'name': 'full1', 'slavename': 'bot1', 'builddir': 'bd1', 'factory': f1} -c['builders'] = [b1] -""" - - SetPropertySimple_config = SetProperty_base_config.replace("##STEPS##", """ - SetProperty(property='foo', command="echo foo"), - SetProperty(property=WithProperties('wp'), command="echo wp"), - SetProperty(property='bar', command="echo bar", strip=False), - """) - - def testSetPropertySimple(self): - d = self.master.loadConfig(self.SetPropertySimple_config) - d.addCallback(lambda res: self.master.startService()) - d.addCallback(lambda res: self.connectOneSlave("bot1")) - d.addCallback(lambda res: self.requestBuild("full1")) - d.addCallback(self.failUnlessBuildSucceeded) - def _check_props(bs): - self.failUnlessEqual(bs.getProperty("foo"), "foo") - self.failUnlessEqual(bs.getProperty("wp"), "wp") - # (will this fail on some platforms, due to newline differences?) - self.failUnlessEqual(bs.getProperty("bar"), "bar\n") - return bs - d.addCallback(_check_props) - return d - - SetPropertyExtractFn_config = SetProperty_base_config.replace("##STEPS##", """ - SetProperty( - extract_fn=lambda rc,stdout,stderr : { - 'foo' : stdout.strip(), - 'bar' : stderr.strip() }, - command="echo foo; echo bar >&2"), - """) - - def testSetPropertyExtractFn(self): - d = self.master.loadConfig(self.SetPropertyExtractFn_config) - d.addCallback(lambda res: self.master.startService()) - d.addCallback(lambda res: self.connectOneSlave("bot1")) - d.addCallback(lambda res: self.requestBuild("full1")) - d.addCallback(self.failUnlessBuildSucceeded) - def _check_props(bs): - self.failUnlessEqual(bs.getProperty("foo"), "foo") - self.failUnlessEqual(bs.getProperty("bar"), "bar") - return bs - d.addCallback(_check_props) - return d - -# we test got_revision in test_vc diff --git a/tools/buildbot/pylibs/buildbot/test/test_run.py b/tools/buildbot/pylibs/buildbot/test/test_run.py deleted file mode 100644 index 3a2af65..0000000 --- a/tools/buildbot/pylibs/buildbot/test/test_run.py +++ /dev/null @@ -1,845 +0,0 @@ -# -*- test-case-name: buildbot.test.test_run -*- - -from twisted.trial import unittest -from twisted.internet import reactor, defer -import os - -from buildbot import master, interfaces -from buildbot.sourcestamp import SourceStamp -from buildbot.changes import changes -from buildbot.status import builder -from buildbot.process.base import BuildRequest - -from buildbot.test.runutils import RunMixin, TestFlagMixin, rmtree - -config_base = """ -from buildbot.process import factory -from buildbot.steps import dummy -from buildbot.buildslave import BuildSlave -s = factory.s - -f1 = factory.QuickBuildFactory('fakerep', 'cvsmodule', configure=None) - -f2 = factory.BuildFactory([ - s(dummy.Dummy, timeout=1), - s(dummy.RemoteDummy, timeout=2), - ]) - -BuildmasterConfig = c = {} -c['slaves'] = [BuildSlave('bot1', 'sekrit')] -c['schedulers'] = [] -c['builders'] = [] -c['builders'].append({'name':'quick', 'slavename':'bot1', - 'builddir': 'quickdir', 'factory': f1}) -c['slavePortnum'] = 0 -""" - -config_run = config_base + """ -from buildbot.scheduler import Scheduler -c['schedulers'] = [Scheduler('quick', None, 120, ['quick'])] -""" - -config_can_build = config_base + """ -from buildbot.buildslave import BuildSlave -c['slaves'] = [ BuildSlave('bot1', 'sekrit') ] - -from buildbot.scheduler import Scheduler -c['schedulers'] = [Scheduler('dummy', None, 0.1, ['dummy'])] - -c['builders'] = [{'name': 'dummy', 'slavename': 'bot1', - 'builddir': 'dummy1', 'factory': f2}] -""" - -config_cant_build = config_can_build + """ -class MyBuildSlave(BuildSlave): - def canStartBuild(self): return False -c['slaves'] = [ MyBuildSlave('bot1', 'sekrit') ] -""" - -config_concurrency = config_base + """ -from buildbot.buildslave import BuildSlave -c['slaves'] = [ BuildSlave('bot1', 'sekrit', max_builds=1) ] - -from buildbot.scheduler import Scheduler -c['schedulers'] = [Scheduler('dummy', None, 0.1, ['dummy', 'dummy2'])] - -c['builders'].append({'name': 'dummy', 'slavename': 'bot1', - 'builddir': 'dummy', 'factory': f2}) -c['builders'].append({'name': 'dummy2', 'slavename': 'bot1', - 'builddir': 'dummy2', 'factory': f2}) -""" - -config_2 = config_base + """ -c['builders'] = [{'name': 'dummy', 'slavename': 'bot1', - 'builddir': 'dummy1', 'factory': f2}, - {'name': 'testdummy', 'slavename': 'bot1', - 'builddir': 'dummy2', 'factory': f2, 'category': 'test'}] -""" - -config_3 = config_2 + """ -c['builders'].append({'name': 'adummy', 'slavename': 'bot1', - 'builddir': 'adummy3', 'factory': f2}) -c['builders'].append({'name': 'bdummy', 'slavename': 'bot1', - 'builddir': 'adummy4', 'factory': f2, - 'category': 'test'}) -""" - -config_4 = config_base + """ -c['builders'] = [{'name': 'dummy', 'slavename': 'bot1', - 'builddir': 'dummy', 'factory': f2}] -""" - -config_4_newbasedir = config_4 + """ -c['builders'] = [{'name': 'dummy', 'slavename': 'bot1', - 'builddir': 'dummy2', 'factory': f2}] -""" - -config_4_newbuilder = config_4_newbasedir + """ -c['builders'].append({'name': 'dummy2', 'slavename': 'bot1', - 'builddir': 'dummy23', 'factory': f2}) -""" - -class Run(unittest.TestCase): - def rmtree(self, d): - rmtree(d) - - def testMaster(self): - self.rmtree("basedir") - os.mkdir("basedir") - m = master.BuildMaster("basedir") - m.loadConfig(config_run) - m.readConfig = True - m.startService() - cm = m.change_svc - c = changes.Change("bob", ["Makefile", "foo/bar.c"], "changed stuff") - cm.addChange(c) - # verify that the Scheduler is now waiting - s = m.allSchedulers()[0] - self.failUnless(s.timer) - # halting the service will also stop the timer - d = defer.maybeDeferred(m.stopService) - return d - -class CanStartBuild(RunMixin, unittest.TestCase): - def rmtree(self, d): - rmtree(d) - - def testCanStartBuild(self): - return self.do_test(config_can_build, True) - - def testCantStartBuild(self): - return self.do_test(config_cant_build, False) - - def do_test(self, config, builder_should_run): - self.master.loadConfig(config) - self.master.readConfig = True - self.master.startService() - d = self.connectSlave() - - # send a change - cm = self.master.change_svc - c = changes.Change("bob", ["Makefile", "foo/bar.c"], "changed stuff") - cm.addChange(c) - - d.addCallback(self._do_test1, builder_should_run) - - return d - - def _do_test1(self, res, builder_should_run): - # delay a little bit. Note that relying upon timers is a bit fragile, - # in this case we're hoping that our 0.5 second timer will land us - # somewhere in the middle of the [0.1s, 3.1s] window (after the 0.1 - # second Scheduler fires, then during the 3-second build), so that - # when we sample BuildSlave.state, we'll see BUILDING (or IDLE if the - # slave was told to be unavailable). On a heavily loaded system, our - # 0.5 second timer might not actually fire until after the build has - # completed. In the long run, it would be good to change this test to - # pass under those circumstances too. - d = defer.Deferred() - reactor.callLater(.5, d.callback, builder_should_run) - d.addCallback(self._do_test2) - return d - - def _do_test2(self, builder_should_run): - b = self.master.botmaster.builders['dummy'] - self.failUnless(len(b.slaves) == 1) - - bs = b.slaves[0] - from buildbot.process.builder import IDLE, BUILDING - if builder_should_run: - self.failUnlessEqual(bs.state, BUILDING) - else: - self.failUnlessEqual(bs.state, IDLE) - - -class ConcurrencyLimit(RunMixin, unittest.TestCase): - - def testConcurrencyLimit(self): - d = self.master.loadConfig(config_concurrency) - d.addCallback(lambda res: self.master.startService()) - d.addCallback(lambda res: self.connectSlave()) - - def _send(res): - # send a change. This will trigger both builders at the same - # time, but since they share a slave, the max_builds=1 setting - # will insure that only one of the two builds gets to run. - cm = self.master.change_svc - c = changes.Change("bob", ["Makefile", "foo/bar.c"], - "changed stuff") - cm.addChange(c) - d.addCallback(_send) - - def _delay(res): - d1 = defer.Deferred() - reactor.callLater(1, d1.callback, None) - # this test depends upon this 1s delay landing us in the middle - # of one of the builds. - return d1 - d.addCallback(_delay) - - def _check(res): - builders = [ self.master.botmaster.builders[bn] - for bn in ('dummy', 'dummy2') ] - for builder in builders: - self.failUnless(len(builder.slaves) == 1) - - from buildbot.process.builder import BUILDING - building_bs = [ builder - for builder in builders - if builder.slaves[0].state == BUILDING ] - # assert that only one build is running right now. If the - # max_builds= weren't in effect, this would be 2. - self.failUnlessEqual(len(building_bs), 1) - d.addCallback(_check) - - return d - - -class Ping(RunMixin, unittest.TestCase): - def testPing(self): - self.master.loadConfig(config_2) - self.master.readConfig = True - self.master.startService() - - d = self.connectSlave() - d.addCallback(self._testPing_1) - return d - - def _testPing_1(self, res): - d = interfaces.IControl(self.master).getBuilder("dummy").ping(1) - d.addCallback(self._testPing_2) - return d - - def _testPing_2(self, res): - pass - -class BuilderNames(unittest.TestCase): - - def testGetBuilderNames(self): - os.mkdir("bnames") - m = master.BuildMaster("bnames") - s = m.getStatus() - - m.loadConfig(config_3) - m.readConfig = True - - self.failUnlessEqual(s.getBuilderNames(), - ["dummy", "testdummy", "adummy", "bdummy"]) - self.failUnlessEqual(s.getBuilderNames(categories=['test']), - ["testdummy", "bdummy"]) - -class Disconnect(RunMixin, unittest.TestCase): - - def setUp(self): - RunMixin.setUp(self) - - # verify that disconnecting the slave during a build properly - # terminates the build - m = self.master - s = self.status - c = self.control - - m.loadConfig(config_2) - m.readConfig = True - m.startService() - - self.failUnlessEqual(s.getBuilderNames(), ["dummy", "testdummy"]) - self.s1 = s1 = s.getBuilder("dummy") - self.failUnlessEqual(s1.getName(), "dummy") - self.failUnlessEqual(s1.getState(), ("offline", [])) - self.failUnlessEqual(s1.getCurrentBuilds(), []) - self.failUnlessEqual(s1.getLastFinishedBuild(), None) - self.failUnlessEqual(s1.getBuild(-1), None) - - d = self.connectSlave() - d.addCallback(self._disconnectSetup_1) - return d - - def _disconnectSetup_1(self, res): - self.failUnlessEqual(self.s1.getState(), ("idle", [])) - - - def verifyDisconnect(self, bs): - self.failUnless(bs.isFinished()) - - step1 = bs.getSteps()[0] - self.failUnlessEqual(step1.getText(), ["delay", "interrupted"]) - self.failUnlessEqual(step1.getResults()[0], builder.FAILURE) - - self.failUnlessEqual(bs.getResults(), builder.FAILURE) - - def verifyDisconnect2(self, bs): - self.failUnless(bs.isFinished()) - - step1 = bs.getSteps()[1] - self.failUnlessEqual(step1.getText(), ["remote", "delay", "2 secs", - "failed", "slave", "lost"]) - self.failUnlessEqual(step1.getResults()[0], builder.FAILURE) - - self.failUnlessEqual(bs.getResults(), builder.FAILURE) - - def submitBuild(self): - ss = SourceStamp() - br = BuildRequest("forced build", ss, "dummy") - self.control.getBuilder("dummy").requestBuild(br) - d = defer.Deferred() - def _started(bc): - br.unsubscribe(_started) - d.callback(bc) - br.subscribe(_started) - return d - - def testIdle2(self): - # now suppose the slave goes missing - self.disappearSlave(allowReconnect=False) - - # forcing a build will work: the build detect that the slave is no - # longer available and will be re-queued. Wait 5 seconds, then check - # to make sure the build is still in the 'waiting for a slave' queue. - self.control.getBuilder("dummy").original.START_BUILD_TIMEOUT = 1 - req = BuildRequest("forced build", SourceStamp()) - self.failUnlessEqual(req.startCount, 0) - self.control.getBuilder("dummy").requestBuild(req) - # this should ping the slave, which doesn't respond, and then give up - # after a second. The BuildRequest will be re-queued, and its - # .startCount will be incremented. - d = defer.Deferred() - d.addCallback(self._testIdle2_1, req) - reactor.callLater(3, d.callback, None) - return d - testIdle2.timeout = 5 - - def _testIdle2_1(self, res, req): - self.failUnlessEqual(req.startCount, 1) - cancelled = req.cancel() - self.failUnless(cancelled) - - - def testBuild1(self): - # this next sequence is timing-dependent. The dummy build takes at - # least 3 seconds to complete, and this batch of commands must - # complete within that time. - # - d = self.submitBuild() - d.addCallback(self._testBuild1_1) - return d - - def _testBuild1_1(self, bc): - bs = bc.getStatus() - # now kill the slave before it gets to start the first step - d = self.shutdownAllSlaves() # dies before it gets started - d.addCallback(self._testBuild1_2, bs) - return d # TODO: this used to have a 5-second timeout - - def _testBuild1_2(self, res, bs): - # now examine the just-stopped build and make sure it is really - # stopped. This is checking for bugs in which the slave-detach gets - # missed or causes an exception which prevents the build from being - # marked as "finished due to an error". - d = bs.waitUntilFinished() - d2 = self.master.botmaster.waitUntilBuilderDetached("dummy") - dl = defer.DeferredList([d, d2]) - dl.addCallback(self._testBuild1_3, bs) - return dl # TODO: this had a 5-second timeout too - - def _testBuild1_3(self, res, bs): - self.failUnlessEqual(self.s1.getState()[0], "offline") - self.verifyDisconnect(bs) - - - def testBuild2(self): - # this next sequence is timing-dependent - d = self.submitBuild() - d.addCallback(self._testBuild2_1) - return d - testBuild2.timeout = 30 - - def _testBuild2_1(self, bc): - bs = bc.getStatus() - # shutdown the slave while it's running the first step - reactor.callLater(0.5, self.shutdownAllSlaves) - - d = bs.waitUntilFinished() - d.addCallback(self._testBuild2_2, bs) - return d - - def _testBuild2_2(self, res, bs): - # we hit here when the build has finished. The builder is still being - # torn down, however, so spin for another second to allow the - # callLater(0) in Builder.detached to fire. - d = defer.Deferred() - reactor.callLater(1, d.callback, None) - d.addCallback(self._testBuild2_3, bs) - return d - - def _testBuild2_3(self, res, bs): - self.failUnlessEqual(self.s1.getState()[0], "offline") - self.verifyDisconnect(bs) - - - def testBuild3(self): - # this next sequence is timing-dependent - d = self.submitBuild() - d.addCallback(self._testBuild3_1) - return d - testBuild3.timeout = 30 - - def _testBuild3_1(self, bc): - bs = bc.getStatus() - # kill the slave while it's running the first step - reactor.callLater(0.5, self.killSlave) - d = bs.waitUntilFinished() - d.addCallback(self._testBuild3_2, bs) - return d - - def _testBuild3_2(self, res, bs): - # the builder is still being torn down, so give it another second - d = defer.Deferred() - reactor.callLater(1, d.callback, None) - d.addCallback(self._testBuild3_3, bs) - return d - - def _testBuild3_3(self, res, bs): - self.failUnlessEqual(self.s1.getState()[0], "offline") - self.verifyDisconnect(bs) - - - def testBuild4(self): - # this next sequence is timing-dependent - d = self.submitBuild() - d.addCallback(self._testBuild4_1) - return d - testBuild4.timeout = 30 - - def _testBuild4_1(self, bc): - bs = bc.getStatus() - # kill the slave while it's running the second (remote) step - reactor.callLater(1.5, self.killSlave) - d = bs.waitUntilFinished() - d.addCallback(self._testBuild4_2, bs) - return d - - def _testBuild4_2(self, res, bs): - # at this point, the slave is in the process of being removed, so it - # could either be 'idle' or 'offline'. I think there is a - # reactor.callLater(0) standing between here and the offline state. - #reactor.iterate() # TODO: remove the need for this - - self.failUnlessEqual(self.s1.getState()[0], "offline") - self.verifyDisconnect2(bs) - - - def testInterrupt(self): - # this next sequence is timing-dependent - d = self.submitBuild() - d.addCallback(self._testInterrupt_1) - return d - testInterrupt.timeout = 30 - - def _testInterrupt_1(self, bc): - bs = bc.getStatus() - # halt the build while it's running the first step - reactor.callLater(0.5, bc.stopBuild, "bang go splat") - d = bs.waitUntilFinished() - d.addCallback(self._testInterrupt_2, bs) - return d - - def _testInterrupt_2(self, res, bs): - self.verifyDisconnect(bs) - - - def testDisappear(self): - bc = self.control.getBuilder("dummy") - - # ping should succeed - d = bc.ping(1) - d.addCallback(self._testDisappear_1, bc) - return d - - def _testDisappear_1(self, res, bc): - self.failUnlessEqual(res, True) - - # now, before any build is run, make the slave disappear - self.disappearSlave(allowReconnect=False) - - # at this point, a ping to the slave should timeout - d = bc.ping(1) - d.addCallback(self. _testDisappear_2) - return d - def _testDisappear_2(self, res): - self.failUnlessEqual(res, False) - - def testDuplicate(self): - bc = self.control.getBuilder("dummy") - bs = self.status.getBuilder("dummy") - ss = bs.getSlaves()[0] - - self.failUnless(ss.isConnected()) - self.failUnlessEqual(ss.getAdmin(), "one") - - # now, before any build is run, make the first slave disappear - self.disappearSlave(allowReconnect=False) - - d = self.master.botmaster.waitUntilBuilderDetached("dummy") - # now let the new slave take over - self.connectSlave2() - d.addCallback(self._testDuplicate_1, ss) - return d - testDuplicate.timeout = 5 - - def _testDuplicate_1(self, res, ss): - d = self.master.botmaster.waitUntilBuilderAttached("dummy") - d.addCallback(self._testDuplicate_2, ss) - return d - - def _testDuplicate_2(self, res, ss): - self.failUnless(ss.isConnected()) - self.failUnlessEqual(ss.getAdmin(), "two") - - -class Disconnect2(RunMixin, unittest.TestCase): - - def setUp(self): - RunMixin.setUp(self) - # verify that disconnecting the slave during a build properly - # terminates the build - m = self.master - s = self.status - c = self.control - - m.loadConfig(config_2) - m.readConfig = True - m.startService() - - self.failUnlessEqual(s.getBuilderNames(), ["dummy", "testdummy"]) - self.s1 = s1 = s.getBuilder("dummy") - self.failUnlessEqual(s1.getName(), "dummy") - self.failUnlessEqual(s1.getState(), ("offline", [])) - self.failUnlessEqual(s1.getCurrentBuilds(), []) - self.failUnlessEqual(s1.getLastFinishedBuild(), None) - self.failUnlessEqual(s1.getBuild(-1), None) - - d = self.connectSlaveFastTimeout() - d.addCallback(self._setup_disconnect2_1) - return d - - def _setup_disconnect2_1(self, res): - self.failUnlessEqual(self.s1.getState(), ("idle", [])) - - - def testSlaveTimeout(self): - # now suppose the slave goes missing. We want to find out when it - # creates a new Broker, so we reach inside and mark it with the - # well-known sigil of impending messy death. - bd = self.slaves['bot1'].getServiceNamed("bot").builders["dummy"] - broker = bd.remote.broker - broker.redshirt = 1 - - # make sure the keepalives will keep the connection up - d = defer.Deferred() - reactor.callLater(5, d.callback, None) - d.addCallback(self._testSlaveTimeout_1) - return d - testSlaveTimeout.timeout = 20 - - def _testSlaveTimeout_1(self, res): - bd = self.slaves['bot1'].getServiceNamed("bot").builders["dummy"] - if not bd.remote or not hasattr(bd.remote.broker, "redshirt"): - self.fail("slave disconnected when it shouldn't have") - - d = self.master.botmaster.waitUntilBuilderDetached("dummy") - # whoops! how careless of me. - self.disappearSlave(allowReconnect=True) - # the slave will realize the connection is lost within 2 seconds, and - # reconnect. - d.addCallback(self._testSlaveTimeout_2) - return d - - def _testSlaveTimeout_2(self, res): - # the ReconnectingPBClientFactory will attempt a reconnect in two - # seconds. - d = self.master.botmaster.waitUntilBuilderAttached("dummy") - d.addCallback(self._testSlaveTimeout_3) - return d - - def _testSlaveTimeout_3(self, res): - # make sure it is a new connection (i.e. a new Broker) - bd = self.slaves['bot1'].getServiceNamed("bot").builders["dummy"] - self.failUnless(bd.remote, "hey, slave isn't really connected") - self.failIf(hasattr(bd.remote.broker, "redshirt"), - "hey, slave's Broker is still marked for death") - - -class Basedir(RunMixin, unittest.TestCase): - def testChangeBuilddir(self): - m = self.master - m.loadConfig(config_4) - m.readConfig = True - m.startService() - - d = self.connectSlave() - d.addCallback(self._testChangeBuilddir_1) - return d - - def _testChangeBuilddir_1(self, res): - self.bot = bot = self.slaves['bot1'].bot - self.builder = builder = bot.builders.get("dummy") - self.failUnless(builder) - self.failUnlessEqual(builder.builddir, "dummy") - self.failUnlessEqual(builder.basedir, - os.path.join("slavebase-bot1", "dummy")) - - d = self.master.loadConfig(config_4_newbasedir) - d.addCallback(self._testChangeBuilddir_2) - return d - - def _testChangeBuilddir_2(self, res): - bot = self.bot - # this does NOT cause the builder to be replaced - builder = bot.builders.get("dummy") - self.failUnless(builder) - self.failUnlessIdentical(self.builder, builder) - # the basedir should be updated - self.failUnlessEqual(builder.builddir, "dummy2") - self.failUnlessEqual(builder.basedir, - os.path.join("slavebase-bot1", "dummy2")) - - # add a new builder, which causes the basedir list to be reloaded - d = self.master.loadConfig(config_4_newbuilder) - return d - -class Triggers(RunMixin, TestFlagMixin, unittest.TestCase): - config_trigger = config_base + """ -from buildbot.scheduler import Triggerable, Scheduler -from buildbot.steps.trigger import Trigger -from buildbot.steps.dummy import Dummy -from buildbot.test.runutils import SetTestFlagStep -c['schedulers'] = [ - Scheduler('triggerer', None, 0.1, ['triggerer']), - Triggerable('triggeree', ['triggeree']) -] -triggerer = factory.BuildFactory([ - s(SetTestFlagStep, flagname='triggerer_started'), - s(Trigger, flunkOnFailure=True, @ARGS@), - s(SetTestFlagStep, flagname='triggerer_finished'), - ]) -triggeree = factory.BuildFactory([ - s(SetTestFlagStep, flagname='triggeree_started'), - s(@DUMMYCLASS@), - s(SetTestFlagStep, flagname='triggeree_finished'), - ]) -c['builders'] = [{'name': 'triggerer', 'slavename': 'bot1', - 'builddir': 'triggerer', 'factory': triggerer}, - {'name': 'triggeree', 'slavename': 'bot1', - 'builddir': 'triggeree', 'factory': triggeree}] -""" - - def mkConfig(self, args, dummyclass="Dummy"): - return self.config_trigger.replace("@ARGS@", args).replace("@DUMMYCLASS@", dummyclass) - - def setupTest(self, args, dummyclass, checkFn): - self.clearFlags() - m = self.master - m.loadConfig(self.mkConfig(args, dummyclass)) - m.readConfig = True - m.startService() - - c = changes.Change("bob", ["Makefile", "foo/bar.c"], "changed stuff") - m.change_svc.addChange(c) - - d = self.connectSlave(builders=['triggerer', 'triggeree']) - d.addCallback(self.startTimer, 0.5, checkFn) - return d - - def startTimer(self, res, time, next_fn): - d = defer.Deferred() - reactor.callLater(time, d.callback, None) - d.addCallback(next_fn) - return d - - def testTriggerBuild(self): - return self.setupTest("schedulerNames=['triggeree']", - "Dummy", - self._checkTriggerBuild) - - def _checkTriggerBuild(self, res): - self.failIfFlagNotSet('triggerer_started') - self.failIfFlagNotSet('triggeree_started') - self.failIfFlagSet('triggeree_finished') - self.failIfFlagNotSet('triggerer_finished') - - def testTriggerBuildWait(self): - return self.setupTest("schedulerNames=['triggeree'], waitForFinish=1", - "Dummy", - self._checkTriggerBuildWait) - - def _checkTriggerBuildWait(self, res): - self.failIfFlagNotSet('triggerer_started') - self.failIfFlagNotSet('triggeree_started') - self.failIfFlagSet('triggeree_finished') - self.failIfFlagSet('triggerer_finished') - -class PropertyPropagation(RunMixin, TestFlagMixin, unittest.TestCase): - def setupTest(self, config, builders, checkFn): - self.clearFlags() - m = self.master - m.loadConfig(config) - m.readConfig = True - m.startService() - - c = changes.Change("bob", ["Makefile", "foo/bar.c"], "changed stuff") - m.change_svc.addChange(c) - - d = self.connectSlave(builders=builders) - d.addCallback(self.startTimer, 0.5, checkFn) - return d - - def startTimer(self, res, time, next_fn): - d = defer.Deferred() - reactor.callLater(time, d.callback, None) - d.addCallback(next_fn) - return d - - config_schprop = config_base + """ -from buildbot.scheduler import Scheduler -from buildbot.steps.dummy import Dummy -from buildbot.test.runutils import SetTestFlagStep -from buildbot.process.properties import WithProperties -c['schedulers'] = [ - Scheduler('mysched', None, 0.1, ['flagcolor'], properties={'color':'red'}), -] -factory = factory.BuildFactory([ - s(SetTestFlagStep, flagname='testresult', - value=WithProperties('color=%(color)s sched=%(scheduler)s')), - ]) -c['builders'] = [{'name': 'flagcolor', 'slavename': 'bot1', - 'builddir': 'test', 'factory': factory}, - ] -""" - - def testScheduler(self): - def _check(res): - self.failUnlessEqual(self.getFlag('testresult'), - 'color=red sched=mysched') - return self.setupTest(self.config_schprop, ['flagcolor'], _check) - - config_slaveprop = config_base + """ -from buildbot.scheduler import Scheduler -from buildbot.steps.dummy import Dummy -from buildbot.test.runutils import SetTestFlagStep -from buildbot.process.properties import WithProperties -c['schedulers'] = [ - Scheduler('mysched', None, 0.1, ['flagcolor']) -] -c['slaves'] = [BuildSlave('bot1', 'sekrit', properties={'color':'orange'})] -factory = factory.BuildFactory([ - s(SetTestFlagStep, flagname='testresult', - value=WithProperties('color=%(color)s slavename=%(slavename)s')), - ]) -c['builders'] = [{'name': 'flagcolor', 'slavename': 'bot1', - 'builddir': 'test', 'factory': factory}, - ] -""" - def testSlave(self): - def _check(res): - self.failUnlessEqual(self.getFlag('testresult'), - 'color=orange slavename=bot1') - return self.setupTest(self.config_slaveprop, ['flagcolor'], _check) - - config_trigger = config_base + """ -from buildbot.scheduler import Triggerable, Scheduler -from buildbot.steps.trigger import Trigger -from buildbot.steps.dummy import Dummy -from buildbot.test.runutils import SetTestFlagStep -from buildbot.process.properties import WithProperties -c['schedulers'] = [ - Scheduler('triggerer', None, 0.1, ['triggerer'], - properties={'color':'mauve', 'pls_trigger':'triggeree'}), - Triggerable('triggeree', ['triggeree'], properties={'color':'invisible'}) -] -triggerer = factory.BuildFactory([ - s(SetTestFlagStep, flagname='testresult', value='wrongone'), - s(Trigger, flunkOnFailure=True, - schedulerNames=[WithProperties('%(pls_trigger)s')], - set_properties={'color' : WithProperties('%(color)s')}), - s(SetTestFlagStep, flagname='testresult', value='triggered'), - ]) -triggeree = factory.BuildFactory([ - s(SetTestFlagStep, flagname='testresult', - value=WithProperties('sched=%(scheduler)s color=%(color)s')), - ]) -c['builders'] = [{'name': 'triggerer', 'slavename': 'bot1', - 'builddir': 'triggerer', 'factory': triggerer}, - {'name': 'triggeree', 'slavename': 'bot1', - 'builddir': 'triggeree', 'factory': triggeree}] -""" - def testTrigger(self): - def _check(res): - self.failUnlessEqual(self.getFlag('testresult'), - 'sched=triggeree color=mauve') - return self.setupTest(self.config_trigger, - ['triggerer', 'triggeree'], _check) - - -config_test_flag = config_base + """ -from buildbot.scheduler import Scheduler -c['schedulers'] = [Scheduler('quick', None, 0.1, ['dummy'])] - -from buildbot.test.runutils import SetTestFlagStep -f3 = factory.BuildFactory([ - s(SetTestFlagStep, flagname='foo', value='bar'), - ]) - -c['builders'] = [{'name': 'dummy', 'slavename': 'bot1', - 'builddir': 'dummy', 'factory': f3}] -""" - -class TestFlag(RunMixin, TestFlagMixin, unittest.TestCase): - """Test for the TestFlag functionality in runutils""" - def testTestFlag(self): - m = self.master - m.loadConfig(config_test_flag) - m.readConfig = True - m.startService() - - c = changes.Change("bob", ["Makefile", "foo/bar.c"], "changed stuff") - m.change_svc.addChange(c) - - d = self.connectSlave() - d.addCallback(self._testTestFlag_1) - return d - - def _testTestFlag_1(self, res): - d = defer.Deferred() - reactor.callLater(0.5, d.callback, None) - d.addCallback(self._testTestFlag_2) - return d - - def _testTestFlag_2(self, res): - self.failUnlessEqual(self.getFlag('foo'), 'bar') - -# TODO: test everything, from Change submission to Scheduler to Build to -# Status. Use all the status types. Specifically I want to catch recurrences -# of the bug where I forgot to make Waterfall inherit from StatusReceiver -# such that buildSetSubmitted failed. - diff --git a/tools/buildbot/pylibs/buildbot/test/test_runner.py b/tools/buildbot/pylibs/buildbot/test/test_runner.py deleted file mode 100644 index d94ef5f..0000000 --- a/tools/buildbot/pylibs/buildbot/test/test_runner.py +++ /dev/null @@ -1,392 +0,0 @@ - -# this file tests the 'buildbot' command, with its various sub-commands - -from twisted.trial import unittest -from twisted.python import usage -import os, shutil, shlex -import sets - -from buildbot.scripts import runner, tryclient - -class Options(unittest.TestCase): - optionsFile = "SDFsfsFSdfsfsFSD" - - def make(self, d, key): - # we use a wacky filename here in case the test code discovers the - # user's real ~/.buildbot/ directory - os.makedirs(os.sep.join(d + [".buildbot"])) - f = open(os.sep.join(d + [".buildbot", self.optionsFile]), "w") - f.write("key = '%s'\n" % key) - f.close() - - def check(self, d, key): - basedir = os.sep.join(d) - options = runner.loadOptions(self.optionsFile, here=basedir, - home=self.home) - if key is None: - self.failIf(options.has_key('key')) - else: - self.failUnlessEqual(options['key'], key) - - def testFindOptions(self): - self.make(["home", "dir1", "dir2", "dir3"], "one") - self.make(["home", "dir1", "dir2"], "two") - self.make(["home"], "home") - self.home = os.path.abspath("home") - - self.check(["home", "dir1", "dir2", "dir3"], "one") - self.check(["home", "dir1", "dir2"], "two") - self.check(["home", "dir1"], "home") - - self.home = os.path.abspath("nothome") - os.makedirs(os.sep.join(["nothome", "dir1"])) - self.check(["nothome", "dir1"], None) - - def doForce(self, args, expected): - o = runner.ForceOptions() - o.parseOptions(args) - self.failUnlessEqual(o.keys(), expected.keys()) - for k in o.keys(): - self.failUnlessEqual(o[k], expected[k], - "[%s] got %s instead of %s" % (k, o[k], - expected[k])) - - def testForceOptions(self): - if not hasattr(shlex, "split"): - raise unittest.SkipTest("need python>=2.3 for shlex.split") - - exp = {"builder": "b1", "reason": "reason", - "branch": None, "revision": None} - self.doForce(shlex.split("b1 reason"), exp) - self.doForce(shlex.split("b1 'reason'"), exp) - self.failUnlessRaises(usage.UsageError, self.doForce, - shlex.split("--builder b1 'reason'"), exp) - self.doForce(shlex.split("--builder b1 --reason reason"), exp) - self.doForce(shlex.split("--builder b1 --reason 'reason'"), exp) - self.doForce(shlex.split("--builder b1 --reason \"reason\""), exp) - - exp['reason'] = "longer reason" - self.doForce(shlex.split("b1 'longer reason'"), exp) - self.doForce(shlex.split("b1 longer reason"), exp) - self.doForce(shlex.split("--reason 'longer reason' b1"), exp) - - -class Create(unittest.TestCase): - def failUnlessIn(self, substring, string, msg=None): - # trial provides a version of this that requires python-2.3 to test - # strings. - self.failUnless(string.find(substring) != -1, msg) - def failUnlessExists(self, filename): - self.failUnless(os.path.exists(filename), "%s should exist" % filename) - def failIfExists(self, filename): - self.failIf(os.path.exists(filename), "%s should not exist" % filename) - - def setUp(self): - self.cwd = os.getcwd() - - def tearDown(self): - os.chdir(self.cwd) - - def testMaster(self): - basedir = "test_runner.master" - options = runner.MasterOptions() - options.parseOptions(["-q", basedir]) - cwd = os.getcwd() - runner.createMaster(options) - os.chdir(cwd) - - tac = os.path.join(basedir, "buildbot.tac") - self.failUnless(os.path.exists(tac)) - tacfile = open(tac,"rt").read() - self.failUnlessIn("basedir", tacfile) - self.failUnlessIn("configfile = r'master.cfg'", tacfile) - self.failUnlessIn("BuildMaster(basedir, configfile)", tacfile) - - cfg = os.path.join(basedir, "master.cfg") - self.failIfExists(cfg) - samplecfg = os.path.join(basedir, "master.cfg.sample") - self.failUnlessExists(samplecfg) - cfgfile = open(samplecfg,"rt").read() - self.failUnlessIn("This is a sample buildmaster config file", cfgfile) - - makefile = os.path.join(basedir, "Makefile.sample") - self.failUnlessExists(makefile) - - # now verify that running it a second time (with the same options) - # does the right thing: nothing changes - runner.createMaster(options) - os.chdir(cwd) - - self.failIfExists(os.path.join(basedir, "buildbot.tac.new")) - self.failUnlessExists(os.path.join(basedir, "master.cfg.sample")) - - oldtac = open(os.path.join(basedir, "buildbot.tac"), "rt").read() - - # mutate Makefile.sample, since it should be rewritten - f = open(os.path.join(basedir, "Makefile.sample"), "rt") - oldmake = f.read() - f = open(os.path.join(basedir, "Makefile.sample"), "wt") - f.write(oldmake) - f.write("# additional line added\n") - f.close() - - # also mutate master.cfg.sample - f = open(os.path.join(basedir, "master.cfg.sample"), "rt") - oldsamplecfg = f.read() - f = open(os.path.join(basedir, "master.cfg.sample"), "wt") - f.write(oldsamplecfg) - f.write("# additional line added\n") - f.close() - - # now run it again (with different options) - options = runner.MasterOptions() - options.parseOptions(["-q", "--config", "other.cfg", basedir]) - runner.createMaster(options) - os.chdir(cwd) - - tac = open(os.path.join(basedir, "buildbot.tac"), "rt").read() - self.failUnlessEqual(tac, oldtac, "shouldn't change existing .tac") - self.failUnlessExists(os.path.join(basedir, "buildbot.tac.new")) - - make = open(os.path.join(basedir, "Makefile.sample"), "rt").read() - self.failUnlessEqual(make, oldmake, "*should* rewrite Makefile.sample") - - samplecfg = open(os.path.join(basedir, "master.cfg.sample"), - "rt").read() - self.failUnlessEqual(samplecfg, oldsamplecfg, - "*should* rewrite master.cfg.sample") - - def testUpgradeMaster(self): - # first, create a master, run it briefly, then upgrade it. Nothing - # should change. - basedir = "test_runner.master2" - options = runner.MasterOptions() - options.parseOptions(["-q", basedir]) - cwd = os.getcwd() - runner.createMaster(options) - os.chdir(cwd) - - f = open(os.path.join(basedir, "master.cfg"), "w") - f.write(open(os.path.join(basedir, "master.cfg.sample"), "r").read()) - f.close() - - # the upgrade process (specifically the verify-master.cfg step) will - # create any builder status directories that weren't already created. - # Create those ahead of time. - os.mkdir(os.path.join(basedir, "full")) - - files1 = self.record_files(basedir) - - # upgrade it - options = runner.UpgradeMasterOptions() - options.parseOptions(["--quiet", basedir]) - cwd = os.getcwd() - runner.upgradeMaster(options) - os.chdir(cwd) - - files2 = self.record_files(basedir) - self.failUnlessSameFiles(files1, files2) - - # now make it look like the one that 0.7.5 creates: no public_html - for fn in os.listdir(os.path.join(basedir, "public_html")): - os.unlink(os.path.join(basedir, "public_html", fn)) - os.rmdir(os.path.join(basedir, "public_html")) - - # and make sure that upgrading it re-populates public_html - options = runner.UpgradeMasterOptions() - options.parseOptions(["-q", basedir]) - cwd = os.getcwd() - runner.upgradeMaster(options) - os.chdir(cwd) - - files3 = self.record_files(basedir) - self.failUnlessSameFiles(files1, files3) - - # now induce an error in master.cfg and make sure that upgrade - # notices it. - f = open(os.path.join(basedir, "master.cfg"), "a") - f.write("raise RuntimeError('catch me please')\n") - f.close() - - options = runner.UpgradeMasterOptions() - options.parseOptions(["-q", basedir]) - cwd = os.getcwd() - rc = runner.upgradeMaster(options) - os.chdir(cwd) - self.failUnless(rc != 0, rc) - # TODO: change the way runner.py works to let us pass in a stderr - # filehandle, and use a StringIO to capture its output, and make sure - # the right error messages appear therein. - - - def failUnlessSameFiles(self, files1, files2): - f1 = sets.Set(files1.keys()) - f2 = sets.Set(files2.keys()) - msg = "" - if f2 - f1: - msg += "Missing from files1: %s\n" % (list(f2-f1),) - if f1 - f2: - msg += "Missing from files2: %s\n" % (list(f1-f2),) - if msg: - self.fail(msg) - - def record_files(self, basedir): - allfiles = {} - for root, dirs, files in os.walk(basedir): - for f in files: - fn = os.path.join(root, f) - allfiles[fn] = ("FILE", open(fn,"rb").read()) - for d in dirs: - allfiles[os.path.join(root, d)] = ("DIR",) - return allfiles - - - def testSlave(self): - basedir = "test_runner.slave" - options = runner.SlaveOptions() - options.parseOptions(["-q", basedir, "buildmaster:1234", - "botname", "passwd"]) - cwd = os.getcwd() - runner.createSlave(options) - os.chdir(cwd) - - tac = os.path.join(basedir, "buildbot.tac") - self.failUnless(os.path.exists(tac)) - tacfile = open(tac,"rt").read() - self.failUnlessIn("basedir", tacfile) - self.failUnlessIn("buildmaster_host = 'buildmaster'", tacfile) - self.failUnlessIn("port = 1234", tacfile) - self.failUnlessIn("slavename = 'botname'", tacfile) - self.failUnlessIn("passwd = 'passwd'", tacfile) - self.failUnlessIn("keepalive = 600", tacfile) - self.failUnlessIn("BuildSlave(buildmaster_host, port, slavename", - tacfile) - - makefile = os.path.join(basedir, "Makefile.sample") - self.failUnlessExists(makefile) - - self.failUnlessExists(os.path.join(basedir, "info", "admin")) - self.failUnlessExists(os.path.join(basedir, "info", "host")) - # edit one to make sure the later install doesn't change it - f = open(os.path.join(basedir, "info", "admin"), "wt") - f.write("updated@buildbot.example.org\n") - f.close() - - # now verify that running it a second time (with the same options) - # does the right thing: nothing changes - runner.createSlave(options) - os.chdir(cwd) - - self.failIfExists(os.path.join(basedir, "buildbot.tac.new")) - admin = open(os.path.join(basedir, "info", "admin"), "rt").read() - self.failUnlessEqual(admin, "updated@buildbot.example.org\n") - - - # mutate Makefile.sample, since it should be rewritten - oldmake = open(os.path.join(basedir, "Makefile.sample"), "rt").read() - f = open(os.path.join(basedir, "Makefile.sample"), "wt") - f.write(oldmake) - f.write("# additional line added\n") - f.close() - oldtac = open(os.path.join(basedir, "buildbot.tac"), "rt").read() - - # now run it again (with different options) - options = runner.SlaveOptions() - options.parseOptions(["-q", "--keepalive", "30", - basedir, "buildmaster:9999", - "newbotname", "passwd"]) - runner.createSlave(options) - os.chdir(cwd) - - tac = open(os.path.join(basedir, "buildbot.tac"), "rt").read() - self.failUnlessEqual(tac, oldtac, "shouldn't change existing .tac") - self.failUnlessExists(os.path.join(basedir, "buildbot.tac.new")) - tacfile = open(os.path.join(basedir, "buildbot.tac.new"),"rt").read() - self.failUnlessIn("basedir", tacfile) - self.failUnlessIn("buildmaster_host = 'buildmaster'", tacfile) - self.failUnlessIn("port = 9999", tacfile) - self.failUnlessIn("slavename = 'newbotname'", tacfile) - self.failUnlessIn("passwd = 'passwd'", tacfile) - self.failUnlessIn("keepalive = 30", tacfile) - self.failUnlessIn("BuildSlave(buildmaster_host, port, slavename", - tacfile) - - make = open(os.path.join(basedir, "Makefile.sample"), "rt").read() - self.failUnlessEqual(make, oldmake, "*should* rewrite Makefile.sample") - -class Try(unittest.TestCase): - # test some aspects of the 'buildbot try' command - def makeOptions(self, contents): - if os.path.exists(".buildbot"): - shutil.rmtree(".buildbot") - os.mkdir(".buildbot") - open(os.path.join(".buildbot", "options"), "w").write(contents) - - def testGetopt1(self): - opts = "try_connect = 'ssh'\n" + "try_builders = ['a']\n" - self.makeOptions(opts) - config = runner.TryOptions() - config.parseOptions([]) - t = tryclient.Try(config) - self.failUnlessEqual(t.connect, "ssh") - self.failUnlessEqual(t.builderNames, ['a']) - - def testGetopt2(self): - opts = "" - self.makeOptions(opts) - config = runner.TryOptions() - config.parseOptions(['--connect=ssh', '--builder', 'a']) - t = tryclient.Try(config) - self.failUnlessEqual(t.connect, "ssh") - self.failUnlessEqual(t.builderNames, ['a']) - - def testGetopt3(self): - opts = "" - self.makeOptions(opts) - config = runner.TryOptions() - config.parseOptions(['--connect=ssh', - '--builder', 'a', '--builder=b']) - t = tryclient.Try(config) - self.failUnlessEqual(t.connect, "ssh") - self.failUnlessEqual(t.builderNames, ['a', 'b']) - - def testGetopt4(self): - opts = "try_connect = 'ssh'\n" + "try_builders = ['a']\n" - self.makeOptions(opts) - config = runner.TryOptions() - config.parseOptions(['--builder=b']) - t = tryclient.Try(config) - self.failUnlessEqual(t.connect, "ssh") - self.failUnlessEqual(t.builderNames, ['b']) - - def testGetTopdir(self): - os.mkdir("gettopdir") - os.mkdir(os.path.join("gettopdir", "foo")) - os.mkdir(os.path.join("gettopdir", "foo", "bar")) - open(os.path.join("gettopdir", "1"),"w").write("1") - open(os.path.join("gettopdir", "foo", "2"),"w").write("2") - open(os.path.join("gettopdir", "foo", "bar", "3"),"w").write("3") - - target = os.path.abspath("gettopdir") - t = tryclient.getTopdir("1", "gettopdir") - self.failUnlessEqual(os.path.abspath(t), target) - t = tryclient.getTopdir("1", os.path.join("gettopdir", "foo")) - self.failUnlessEqual(os.path.abspath(t), target) - t = tryclient.getTopdir("1", os.path.join("gettopdir", "foo", "bar")) - self.failUnlessEqual(os.path.abspath(t), target) - - target = os.path.abspath(os.path.join("gettopdir", "foo")) - t = tryclient.getTopdir("2", os.path.join("gettopdir", "foo")) - self.failUnlessEqual(os.path.abspath(t), target) - t = tryclient.getTopdir("2", os.path.join("gettopdir", "foo", "bar")) - self.failUnlessEqual(os.path.abspath(t), target) - - target = os.path.abspath(os.path.join("gettopdir", "foo", "bar")) - t = tryclient.getTopdir("3", os.path.join("gettopdir", "foo", "bar")) - self.failUnlessEqual(os.path.abspath(t), target) - - nonexistent = "nonexistent\n29fis3kq\tBAR" - # hopefully there won't be a real file with that name between here - # and the filesystem root. - self.failUnlessRaises(ValueError, tryclient.getTopdir, nonexistent) - diff --git a/tools/buildbot/pylibs/buildbot/test/test_scheduler.py b/tools/buildbot/pylibs/buildbot/test/test_scheduler.py deleted file mode 100644 index 5b93517..0000000 --- a/tools/buildbot/pylibs/buildbot/test/test_scheduler.py +++ /dev/null @@ -1,313 +0,0 @@ -# -*- test-case-name: buildbot.test.test_scheduler -*- - -import os, time - -from twisted.trial import unittest -from twisted.internet import defer, reactor -from twisted.application import service -from twisted.spread import pb - -from buildbot import scheduler, sourcestamp, buildset, status -from buildbot.changes.changes import Change -from buildbot.scripts import tryclient - - -class FakeMaster(service.MultiService): - d = None - def submitBuildSet(self, bs): - self.sets.append(bs) - if self.d: - reactor.callLater(0, self.d.callback, bs) - self.d = None - return pb.Referenceable() # makes the cleanup work correctly - -class Scheduling(unittest.TestCase): - def setUp(self): - self.master = master = FakeMaster() - master.sets = [] - master.startService() - - def tearDown(self): - d = self.master.stopService() - return d - - def addScheduler(self, s): - s.setServiceParent(self.master) - - def testPeriodic1(self): - self.addScheduler(scheduler.Periodic("quickly", ["a","b"], 2)) - d = defer.Deferred() - reactor.callLater(5, d.callback, None) - d.addCallback(self._testPeriodic1_1) - return d - def _testPeriodic1_1(self, res): - self.failUnless(len(self.master.sets) > 1) - s1 = self.master.sets[0] - self.failUnlessEqual(s1.builderNames, ["a","b"]) - self.failUnlessEqual(s1.reason, "The Periodic scheduler named 'quickly' triggered this build") - - def testNightly(self): - # now == 15-Nov-2005, 00:05:36 AM . By using mktime, this is - # converted into the local timezone, which happens to match what - # Nightly is going to do anyway. - MIN=60; HOUR=60*MIN; DAY=24*3600 - now = time.mktime((2005, 11, 15, 0, 5, 36, 1, 319, 0)) - - s = scheduler.Nightly('nightly', ["a"], hour=3) - t = s.calculateNextRunTimeFrom(now) - self.failUnlessEqual(int(t-now), 2*HOUR+54*MIN+24) - - s = scheduler.Nightly('nightly', ["a"], minute=[3,8,54]) - t = s.calculateNextRunTimeFrom(now) - self.failUnlessEqual(int(t-now), 2*MIN+24) - - s = scheduler.Nightly('nightly', ["a"], - dayOfMonth=16, hour=1, minute=6) - t = s.calculateNextRunTimeFrom(now) - self.failUnlessEqual(int(t-now), DAY+HOUR+24) - - s = scheduler.Nightly('nightly', ["a"], - dayOfMonth=16, hour=1, minute=3) - t = s.calculateNextRunTimeFrom(now) - self.failUnlessEqual(int(t-now), DAY+57*MIN+24) - - s = scheduler.Nightly('nightly', ["a"], - dayOfMonth=15, hour=1, minute=3) - t = s.calculateNextRunTimeFrom(now) - self.failUnlessEqual(int(t-now), 57*MIN+24) - - s = scheduler.Nightly('nightly', ["a"], - dayOfMonth=15, hour=0, minute=3) - t = s.calculateNextRunTimeFrom(now) - self.failUnlessEqual(int(t-now), 30*DAY-3*MIN+24) - - - def isImportant(self, change): - if "important" in change.files: - return True - return False - - def testBranch(self): - s = scheduler.Scheduler("b1", "branch1", 2, ["a","b"], - fileIsImportant=self.isImportant) - self.addScheduler(s) - - c0 = Change("carol", ["important"], "other branch", branch="other") - s.addChange(c0) - self.failIf(s.timer) - self.failIf(s.importantChanges) - - c1 = Change("alice", ["important", "not important"], "some changes", - branch="branch1") - s.addChange(c1) - c2 = Change("bob", ["not important", "boring"], "some more changes", - branch="branch1") - s.addChange(c2) - c3 = Change("carol", ["important", "dull"], "even more changes", - branch="branch1") - s.addChange(c3) - - self.failUnlessEqual(s.importantChanges, [c1,c3]) - self.failUnlessEqual(s.unimportantChanges, [c2]) - self.failUnless(s.timer) - - d = defer.Deferred() - reactor.callLater(4, d.callback, None) - d.addCallback(self._testBranch_1) - return d - def _testBranch_1(self, res): - self.failUnlessEqual(len(self.master.sets), 1) - s = self.master.sets[0].source - self.failUnlessEqual(s.branch, "branch1") - self.failUnlessEqual(s.revision, None) - self.failUnlessEqual(len(s.changes), 3) - self.failUnlessEqual(s.patch, None) - - - def testAnyBranch(self): - s = scheduler.AnyBranchScheduler("b1", None, 1, ["a","b"], - fileIsImportant=self.isImportant) - self.addScheduler(s) - - c1 = Change("alice", ["important", "not important"], "some changes", - branch="branch1") - s.addChange(c1) - c2 = Change("bob", ["not important", "boring"], "some more changes", - branch="branch1") - s.addChange(c2) - c3 = Change("carol", ["important", "dull"], "even more changes", - branch="branch1") - s.addChange(c3) - - c4 = Change("carol", ["important"], "other branch", branch="branch2") - s.addChange(c4) - - c5 = Change("carol", ["important"], "default branch", branch=None) - s.addChange(c5) - - d = defer.Deferred() - reactor.callLater(2, d.callback, None) - d.addCallback(self._testAnyBranch_1) - return d - def _testAnyBranch_1(self, res): - self.failUnlessEqual(len(self.master.sets), 3) - self.master.sets.sort(lambda a,b: cmp(a.source.branch, - b.source.branch)) - - s1 = self.master.sets[0].source - self.failUnlessEqual(s1.branch, None) - self.failUnlessEqual(s1.revision, None) - self.failUnlessEqual(len(s1.changes), 1) - self.failUnlessEqual(s1.patch, None) - - s2 = self.master.sets[1].source - self.failUnlessEqual(s2.branch, "branch1") - self.failUnlessEqual(s2.revision, None) - self.failUnlessEqual(len(s2.changes), 3) - self.failUnlessEqual(s2.patch, None) - - s3 = self.master.sets[2].source - self.failUnlessEqual(s3.branch, "branch2") - self.failUnlessEqual(s3.revision, None) - self.failUnlessEqual(len(s3.changes), 1) - self.failUnlessEqual(s3.patch, None) - - def testAnyBranch2(self): - # like testAnyBranch but without fileIsImportant - s = scheduler.AnyBranchScheduler("b1", None, 2, ["a","b"]) - self.addScheduler(s) - c1 = Change("alice", ["important", "not important"], "some changes", - branch="branch1") - s.addChange(c1) - c2 = Change("bob", ["not important", "boring"], "some more changes", - branch="branch1") - s.addChange(c2) - c3 = Change("carol", ["important", "dull"], "even more changes", - branch="branch1") - s.addChange(c3) - - c4 = Change("carol", ["important"], "other branch", branch="branch2") - s.addChange(c4) - - d = defer.Deferred() - reactor.callLater(2, d.callback, None) - d.addCallback(self._testAnyBranch2_1) - return d - def _testAnyBranch2_1(self, res): - self.failUnlessEqual(len(self.master.sets), 2) - self.master.sets.sort(lambda a,b: cmp(a.source.branch, - b.source.branch)) - s1 = self.master.sets[0].source - self.failUnlessEqual(s1.branch, "branch1") - self.failUnlessEqual(s1.revision, None) - self.failUnlessEqual(len(s1.changes), 3) - self.failUnlessEqual(s1.patch, None) - - s2 = self.master.sets[1].source - self.failUnlessEqual(s2.branch, "branch2") - self.failUnlessEqual(s2.revision, None) - self.failUnlessEqual(len(s2.changes), 1) - self.failUnlessEqual(s2.patch, None) - - - def createMaildir(self, jobdir): - os.mkdir(jobdir) - os.mkdir(os.path.join(jobdir, "new")) - os.mkdir(os.path.join(jobdir, "cur")) - os.mkdir(os.path.join(jobdir, "tmp")) - - jobcounter = 1 - def pushJob(self, jobdir, job): - while 1: - filename = "job_%d" % self.jobcounter - self.jobcounter += 1 - if os.path.exists(os.path.join(jobdir, "new", filename)): - continue - if os.path.exists(os.path.join(jobdir, "tmp", filename)): - continue - if os.path.exists(os.path.join(jobdir, "cur", filename)): - continue - break - f = open(os.path.join(jobdir, "tmp", filename), "w") - f.write(job) - f.close() - os.rename(os.path.join(jobdir, "tmp", filename), - os.path.join(jobdir, "new", filename)) - - def testTryJobdir(self): - self.master.basedir = "try_jobdir" - os.mkdir(self.master.basedir) - jobdir = "jobdir1" - jobdir_abs = os.path.join(self.master.basedir, jobdir) - self.createMaildir(jobdir_abs) - s = scheduler.Try_Jobdir("try1", ["a", "b"], jobdir) - self.addScheduler(s) - self.failIf(self.master.sets) - job1 = tryclient.createJobfile("buildsetID", - "branch1", "123", 1, "diff", - ["a", "b"]) - self.master.d = d = defer.Deferred() - self.pushJob(jobdir_abs, job1) - d.addCallback(self._testTryJobdir_1) - # N.B.: if we don't have DNotify, we poll every 10 seconds, so don't - # set a .timeout here shorter than that. TODO: make it possible to - # set the polling interval, so we can make it shorter. - return d - - def _testTryJobdir_1(self, bs): - self.failUnlessEqual(bs.builderNames, ["a", "b"]) - self.failUnlessEqual(bs.source.branch, "branch1") - self.failUnlessEqual(bs.source.revision, "123") - self.failUnlessEqual(bs.source.patch, (1, "diff")) - - - def testTryUserpass(self): - up = [("alice","pw1"), ("bob","pw2")] - s = scheduler.Try_Userpass("try2", ["a", "b"], 0, userpass=up) - self.addScheduler(s) - port = s.getPort() - config = {'connect': 'pb', - 'username': 'alice', - 'passwd': 'pw1', - 'master': "localhost:%d" % port, - 'builders': ["a", "b"], - } - t = tryclient.Try(config) - ss = sourcestamp.SourceStamp("branch1", "123", (1, "diff")) - t.sourcestamp = ss - d2 = self.master.d = defer.Deferred() - d = t.deliverJob() - d.addCallback(self._testTryUserpass_1, t, d2) - return d - testTryUserpass.timeout = 5 - def _testTryUserpass_1(self, res, t, d2): - # at this point, the Try object should have a RemoteReference to the - # status object. The FakeMaster returns a stub. - self.failUnless(t.buildsetStatus) - d2.addCallback(self._testTryUserpass_2, t) - return d2 - def _testTryUserpass_2(self, bs, t): - # this should be the BuildSet submitted by the TryScheduler - self.failUnlessEqual(bs.builderNames, ["a", "b"]) - self.failUnlessEqual(bs.source.branch, "branch1") - self.failUnlessEqual(bs.source.revision, "123") - self.failUnlessEqual(bs.source.patch, (1, "diff")) - - t.cleanup() - - # twisted-2.0.1 (but not later versions) seems to require a reactor - # iteration before stopListening actually works. TODO: investigate - # this. - d = defer.Deferred() - reactor.callLater(0, d.callback, None) - return d - - def testGetBuildSets(self): - # validate IStatus.getBuildSets - s = status.builder.Status(None, ".") - bs1 = buildset.BuildSet(["a","b"], sourcestamp.SourceStamp(), - reason="one", bsid="1") - s.buildsetSubmitted(bs1.status) - self.failUnlessEqual(s.getBuildSets(), [bs1.status]) - bs1.status.notifyFinishedWatchers() - self.failUnlessEqual(s.getBuildSets(), []) diff --git a/tools/buildbot/pylibs/buildbot/test/test_shell.py b/tools/buildbot/pylibs/buildbot/test/test_shell.py deleted file mode 100644 index 52a17f4..0000000 --- a/tools/buildbot/pylibs/buildbot/test/test_shell.py +++ /dev/null @@ -1,138 +0,0 @@ - - -# test step.ShellCommand and the slave-side commands.ShellCommand - -import sys, time, os -from twisted.trial import unittest -from twisted.internet import reactor, defer -from twisted.python import util -from buildbot.slave.commands import SlaveShellCommand -from buildbot.test.runutils import SlaveCommandTestBase - -class SlaveSide(SlaveCommandTestBase, unittest.TestCase): - def testOne(self): - self.setUpBuilder("test_shell.testOne") - emitcmd = util.sibpath(__file__, "emit.py") - args = { - 'command': [sys.executable, emitcmd, "0"], - 'workdir': ".", - } - d = self.startCommand(SlaveShellCommand, args) - d.addCallback(self.collectUpdates) - def _check(logs): - self.failUnlessEqual(logs['stdout'], "this is stdout\n") - self.failUnlessEqual(logs['stderr'], "this is stderr\n") - d.addCallback(_check) - return d - - # TODO: move test_slavecommand.Shell and .ShellPTY over here - - def _generateText(self, filename): - lines = [] - for i in range(3): - lines.append("this is %s %d\n" % (filename, i)) - return "".join(lines) - - def testLogFiles_0(self): - return self._testLogFiles(0) - - def testLogFiles_1(self): - return self._testLogFiles(1) - - def testLogFiles_2(self): - return self._testLogFiles(2) - - def testLogFiles_3(self): - return self._testLogFiles(3) - - def _testLogFiles(self, mode): - basedir = "test_shell.testLogFiles" - self.setUpBuilder(basedir) - # emitlogs.py writes two lines to stdout and two logfiles, one second - # apart. Then it waits for us to write something to stdin, then it - # writes one more line. - - if mode != 3: - # we write something to the log file first, to exercise the logic - # that distinguishes between the old file and the one as modified - # by the ShellCommand. We set the timestamp back 5 seconds so - # that timestamps can be used to distinguish old from new. - log2file = os.path.join(basedir, "log2.out") - f = open(log2file, "w") - f.write("dummy text\n") - f.close() - earlier = time.time() - 5 - os.utime(log2file, (earlier, earlier)) - - if mode == 3: - # mode=3 doesn't create the old logfiles in the first place, but - # then behaves like mode=1 (where the command pauses before - # creating them). - mode = 1 - - # mode=1 will cause emitlogs.py to delete the old logfiles first, and - # then wait two seconds before creating the new files. mode=0 does - # not do this. - args = { - 'command': [sys.executable, - util.sibpath(__file__, "emitlogs.py"), - "%s" % mode], - 'workdir': ".", - 'logfiles': {"log2": "log2.out", - "log3": "log3.out"}, - 'keep_stdin_open': True, - } - finishd = self.startCommand(SlaveShellCommand, args) - # The first batch of lines is written immediately. The second is - # written after a pause of one second. We poll once per second until - # we see both batches. - - self._check_timeout = 10 - d = self._check_and_wait() - def _wait_for_finish(res, finishd): - return finishd - d.addCallback(_wait_for_finish, finishd) - d.addCallback(self.collectUpdates) - def _check(logs): - self.failUnlessEqual(logs['stdout'], self._generateText("stdout")) - if mode == 2: - self.failIf(('log','log2') in logs) - self.failIf(('log','log3') in logs) - else: - self.failUnlessEqual(logs[('log','log2')], - self._generateText("log2")) - self.failUnlessEqual(logs[('log','log3')], - self._generateText("log3")) - d.addCallback(_check) - d.addBoth(self._maybePrintError) - return d - - def _check_and_wait(self, res=None): - self._check_timeout -= 1 - if self._check_timeout <= 0: - raise defer.TimeoutError("gave up on command") - logs = self.collectUpdates() - if logs.get('stdout') == "this is stdout 0\nthis is stdout 1\n": - # the emitlogs.py process is now waiting for something to arrive - # on stdin - self.cmd.command.pp.transport.write("poke\n") - return - if not self.cmd.running: - self.fail("command finished too early") - spin = defer.Deferred() - spin.addCallback(self._check_and_wait) - reactor.callLater(1, spin.callback, None) - return spin - - def _maybePrintError(self, res): - rc = self.findRC() - if rc != 0: - print "Command ended with rc=%s" % rc - print "STDERR:" - self.printStderr() - return res - - # MAYBE TODO: a command which appends to an existing logfile should - # result in only the new text being sent up to the master. I need to - # think about this more first. - diff --git a/tools/buildbot/pylibs/buildbot/test/test_slavecommand.py b/tools/buildbot/pylibs/buildbot/test/test_slavecommand.py deleted file mode 100644 index 64eb33c..0000000 --- a/tools/buildbot/pylibs/buildbot/test/test_slavecommand.py +++ /dev/null @@ -1,289 +0,0 @@ -# -*- test-case-name: buildbot.test.test_slavecommand -*- - -from twisted.trial import unittest -from twisted.internet import reactor, interfaces -from twisted.python import runtime, failure, util - -import os, sys - -from buildbot.slave import commands -SlaveShellCommand = commands.SlaveShellCommand - -from buildbot.test.runutils import SignalMixin, FakeSlaveBuilder - -# test slavecommand.py by running the various commands with a fake -# SlaveBuilder object that logs the calls to sendUpdate() - -class Utilities(unittest.TestCase): - def mkdir(self, basedir, path, mode=None): - fn = os.path.join(basedir, path) - os.makedirs(fn) - if mode is not None: - os.chmod(fn, mode) - - def touch(self, basedir, path, mode=None): - fn = os.path.join(basedir, path) - f = open(fn, "w") - f.write("touch\n") - f.close() - if mode is not None: - os.chmod(fn, mode) - - def test_rmdirRecursive(self): - basedir = "slavecommand/Utilities/test_rmdirRecursive" - os.makedirs(basedir) - d = os.path.join(basedir, "doomed") - self.mkdir(d, "a/b") - self.touch(d, "a/b/1.txt") - self.touch(d, "a/b/2.txt", 0444) - self.touch(d, "a/b/3.txt", 0) - self.mkdir(d, "a/c") - self.touch(d, "a/c/1.txt") - self.touch(d, "a/c/2.txt", 0444) - self.touch(d, "a/c/3.txt", 0) - os.chmod(os.path.join(d, "a/c"), 0444) - self.mkdir(d, "a/d") - self.touch(d, "a/d/1.txt") - self.touch(d, "a/d/2.txt", 0444) - self.touch(d, "a/d/3.txt", 0) - os.chmod(os.path.join(d, "a/d"), 0) - - commands.rmdirRecursive(d) - self.failIf(os.path.exists(d)) - - -class ShellBase(SignalMixin): - - def setUp(self): - self.basedir = "test_slavecommand" - if not os.path.isdir(self.basedir): - os.mkdir(self.basedir) - self.subdir = os.path.join(self.basedir, "subdir") - if not os.path.isdir(self.subdir): - os.mkdir(self.subdir) - self.builder = FakeSlaveBuilder(self.usePTY, self.basedir) - self.emitcmd = util.sibpath(__file__, "emit.py") - self.subemitcmd = os.path.join(util.sibpath(__file__, "subdir"), - "emit.py") - self.sleepcmd = util.sibpath(__file__, "sleep.py") - - def failUnlessIn(self, substring, string): - self.failUnless(string.find(substring) != -1, - "'%s' not in '%s'" % (substring, string)) - - def getfile(self, which): - got = "" - for r in self.builder.updates: - if r.has_key(which): - got += r[which] - return got - - def checkOutput(self, expected): - """ - @type expected: list of (streamname, contents) tuples - @param expected: the expected output - """ - expected_linesep = os.linesep - if self.usePTY: - # PTYs change the line ending. I'm not sure why. - expected_linesep = "\r\n" - expected = [(stream, contents.replace("\n", expected_linesep, 1000)) - for (stream, contents) in expected] - if self.usePTY: - # PTYs merge stdout+stderr into a single stream - expected = [('stdout', contents) - for (stream, contents) in expected] - # now merge everything into one string per stream - streams = {} - for (stream, contents) in expected: - streams[stream] = streams.get(stream, "") + contents - for (stream, contents) in streams.items(): - got = self.getfile(stream) - self.assertEquals(got, contents) - - def getrc(self): - self.failUnless(self.builder.updates[-1].has_key('rc')) - got = self.builder.updates[-1]['rc'] - return got - def checkrc(self, expected): - got = self.getrc() - self.assertEquals(got, expected) - - def testShell1(self): - targetfile = os.path.join(self.basedir, "log1.out") - if os.path.exists(targetfile): - os.unlink(targetfile) - cmd = "%s %s 0" % (sys.executable, self.emitcmd) - args = {'command': cmd, 'workdir': '.', 'timeout': 60} - c = SlaveShellCommand(self.builder, None, args) - d = c.start() - expected = [('stdout', "this is stdout\n"), - ('stderr', "this is stderr\n")] - d.addCallback(self._checkPass, expected, 0) - def _check_targetfile(res): - self.failUnless(os.path.exists(targetfile)) - d.addCallback(_check_targetfile) - return d - - def _checkPass(self, res, expected, rc): - self.checkOutput(expected) - self.checkrc(rc) - - def testShell2(self): - cmd = [sys.executable, self.emitcmd, "0"] - args = {'command': cmd, 'workdir': '.', 'timeout': 60} - c = SlaveShellCommand(self.builder, None, args) - d = c.start() - expected = [('stdout', "this is stdout\n"), - ('stderr', "this is stderr\n")] - d.addCallback(self._checkPass, expected, 0) - return d - - def testShellRC(self): - cmd = [sys.executable, self.emitcmd, "1"] - args = {'command': cmd, 'workdir': '.', 'timeout': 60} - c = SlaveShellCommand(self.builder, None, args) - d = c.start() - expected = [('stdout', "this is stdout\n"), - ('stderr', "this is stderr\n")] - d.addCallback(self._checkPass, expected, 1) - return d - - def testShellEnv(self): - cmd = "%s %s 0" % (sys.executable, self.emitcmd) - args = {'command': cmd, 'workdir': '.', - 'env': {'EMIT_TEST': "envtest"}, 'timeout': 60} - c = SlaveShellCommand(self.builder, None, args) - d = c.start() - expected = [('stdout', "this is stdout\n"), - ('stderr', "this is stderr\n"), - ('stdout', "EMIT_TEST: envtest\n"), - ] - d.addCallback(self._checkPass, expected, 0) - return d - - def testShellSubdir(self): - targetfile = os.path.join(self.basedir, "subdir", "log1.out") - if os.path.exists(targetfile): - os.unlink(targetfile) - cmd = "%s %s 0" % (sys.executable, self.subemitcmd) - args = {'command': cmd, 'workdir': "subdir", 'timeout': 60} - c = SlaveShellCommand(self.builder, None, args) - d = c.start() - expected = [('stdout', "this is stdout in subdir\n"), - ('stderr', "this is stderr\n")] - d.addCallback(self._checkPass, expected, 0) - def _check_targetfile(res): - self.failUnless(os.path.exists(targetfile)) - d.addCallback(_check_targetfile) - return d - - def testShellMissingCommand(self): - args = {'command': "/bin/EndWorldHungerAndMakePigsFly", - 'workdir': '.', 'timeout': 10, - 'env': {"LC_ALL": "C"}, - } - c = SlaveShellCommand(self.builder, None, args) - d = c.start() - d.addCallback(self._testShellMissingCommand_1) - return d - def _testShellMissingCommand_1(self, res): - self.failIfEqual(self.getrc(), 0) - # we used to check the error message to make sure it said something - # about a missing command, but there are a variety of shells out - # there, and they emit message sin a variety of languages, so we - # stopped trying. - - def testTimeout(self): - args = {'command': [sys.executable, self.sleepcmd, "10"], - 'workdir': '.', 'timeout': 2} - c = SlaveShellCommand(self.builder, None, args) - d = c.start() - d.addCallback(self._testTimeout_1) - return d - def _testTimeout_1(self, res): - self.failIfEqual(self.getrc(), 0) - got = self.getfile('header') - self.failUnlessIn("command timed out: 2 seconds without output", got) - if runtime.platformType == "posix": - # the "killing pid" message is not present in windows - self.failUnlessIn("killing pid", got) - # but the process *ought* to be killed somehow - self.failUnlessIn("process killed by signal", got) - #print got - if runtime.platformType != 'posix': - testTimeout.todo = "timeout doesn't appear to work under windows" - - def testInterrupt1(self): - args = {'command': [sys.executable, self.sleepcmd, "10"], - 'workdir': '.', 'timeout': 20} - c = SlaveShellCommand(self.builder, None, args) - d = c.start() - reactor.callLater(1, c.interrupt) - d.addCallback(self._testInterrupt1_1) - return d - def _testInterrupt1_1(self, res): - self.failIfEqual(self.getrc(), 0) - got = self.getfile('header') - self.failUnlessIn("command interrupted", got) - if runtime.platformType == "posix": - self.failUnlessIn("process killed by signal", got) - if runtime.platformType != 'posix': - testInterrupt1.todo = "interrupt doesn't appear to work under windows" - - - # todo: twisted-specific command tests - -class Shell(ShellBase, unittest.TestCase): - usePTY = False - - def testInterrupt2(self): - # test the backup timeout. This doesn't work under a PTY, because the - # transport.loseConnection we do in the timeout handler actually - # *does* kill the process. - args = {'command': [sys.executable, self.sleepcmd, "5"], - 'workdir': '.', 'timeout': 20} - c = SlaveShellCommand(self.builder, None, args) - d = c.start() - c.command.BACKUP_TIMEOUT = 1 - # make it unable to kill the child, by changing the signal it uses - # from SIGKILL to the do-nothing signal 0. - c.command.KILL = None - reactor.callLater(1, c.interrupt) - d.addBoth(self._testInterrupt2_1) - return d - def _testInterrupt2_1(self, res): - # the slave should raise a TimeoutError exception. In a normal build - # process (i.e. one that uses step.RemoteShellCommand), this - # exception will be handed to the Step, which will acquire an ERROR - # status. In our test environment, it isn't such a big deal. - self.failUnless(isinstance(res, failure.Failure), - "res is not a Failure: %s" % (res,)) - self.failUnless(res.check(commands.TimeoutError)) - self.checkrc(-1) - return - # the command is still actually running. Start another command, to - # make sure that a) the old command's output doesn't interfere with - # the new one, and b) the old command's actual termination doesn't - # break anything - args = {'command': [sys.executable, self.sleepcmd, "5"], - 'workdir': '.', 'timeout': 20} - c = SlaveShellCommand(self.builder, None, args) - d = c.start() - d.addCallback(self._testInterrupt2_2) - return d - def _testInterrupt2_2(self, res): - self.checkrc(0) - # N.B.: under windows, the trial process hangs out for another few - # seconds. I assume that the win32eventreactor is waiting for one of - # the lingering child processes to really finish. - -haveProcess = interfaces.IReactorProcess(reactor, None) -if runtime.platformType == 'posix': - # test with PTYs also - class ShellPTY(ShellBase, unittest.TestCase): - usePTY = True - if not haveProcess: - ShellPTY.skip = "this reactor doesn't support IReactorProcess" -if not haveProcess: - Shell.skip = "this reactor doesn't support IReactorProcess" diff --git a/tools/buildbot/pylibs/buildbot/test/test_slaves.py b/tools/buildbot/pylibs/buildbot/test/test_slaves.py deleted file mode 100644 index e95cd7d..0000000 --- a/tools/buildbot/pylibs/buildbot/test/test_slaves.py +++ /dev/null @@ -1,623 +0,0 @@ -# -*- test-case-name: buildbot.test.test_slaves -*- - -from twisted.trial import unittest -from twisted.internet import defer, reactor -from twisted.python import log - -from buildbot.test.runutils import RunMixin -from buildbot.sourcestamp import SourceStamp -from buildbot.process.base import BuildRequest -from buildbot.status.builder import SUCCESS -from buildbot.status import mail -from buildbot.slave import bot - -config_1 = """ -from buildbot.process import factory -from buildbot.steps import dummy -from buildbot.buildslave import BuildSlave -s = factory.s - -BuildmasterConfig = c = {} -c['slaves'] = [BuildSlave('bot1', 'sekrit'), BuildSlave('bot2', 'sekrit'), - BuildSlave('bot3', 'sekrit')] -c['schedulers'] = [] -c['slavePortnum'] = 0 -c['schedulers'] = [] - -f1 = factory.BuildFactory([s(dummy.RemoteDummy, timeout=1)]) -f2 = factory.BuildFactory([s(dummy.RemoteDummy, timeout=2)]) -f3 = factory.BuildFactory([s(dummy.RemoteDummy, timeout=3)]) -f4 = factory.BuildFactory([s(dummy.RemoteDummy, timeout=5)]) - -c['builders'] = [ - {'name': 'b1', 'slavenames': ['bot1','bot2','bot3'], - 'builddir': 'b1', 'factory': f1}, - ] -""" - -config_2 = config_1 + """ - -c['builders'] = [ - {'name': 'b1', 'slavenames': ['bot1','bot2','bot3'], - 'builddir': 'b1', 'factory': f2}, - ] - -""" - -config_busyness = config_1 + """ -c['builders'] = [ - {'name': 'b1', 'slavenames': ['bot1'], - 'builddir': 'b1', 'factory': f3}, - {'name': 'b2', 'slavenames': ['bot1'], - 'builddir': 'b2', 'factory': f4}, - ] -""" - -class Slave(RunMixin, unittest.TestCase): - - def setUp(self): - RunMixin.setUp(self) - self.master.loadConfig(config_1) - self.master.startService() - d = self.connectSlave(["b1"]) - d.addCallback(lambda res: self.connectSlave(["b1"], "bot2")) - return d - - def doBuild(self, buildername): - br = BuildRequest("forced", SourceStamp()) - d = br.waitUntilFinished() - self.control.getBuilder(buildername).requestBuild(br) - return d - - def testSequence(self): - # make sure both slaves appear in the list. - attached_slaves = [c for c in self.master.botmaster.slaves.values() - if c.slave] - self.failUnlessEqual(len(attached_slaves), 2) - b = self.master.botmaster.builders["b1"] - self.failUnlessEqual(len(b.slaves), 2) - - # since the current scheduling algorithm is simple and does not - # rotate or attempt any sort of load-balancing, two builds in - # sequence should both use the first slave. This may change later if - # we move to a more sophisticated scheme. - b.CHOOSE_SLAVES_RANDOMLY = False - - d = self.doBuild("b1") - d.addCallback(self._testSequence_1) - return d - def _testSequence_1(self, res): - self.failUnlessEqual(res.getResults(), SUCCESS) - self.failUnlessEqual(res.getSlavename(), "bot1") - - d = self.doBuild("b1") - d.addCallback(self._testSequence_2) - return d - def _testSequence_2(self, res): - self.failUnlessEqual(res.getSlavename(), "bot1") - - - def testSimultaneous(self): - # make sure we can actually run two builds at the same time - d1 = self.doBuild("b1") - d2 = self.doBuild("b1") - d1.addCallback(self._testSimultaneous_1, d2) - return d1 - def _testSimultaneous_1(self, res, d2): - self.failUnlessEqual(res.getResults(), SUCCESS) - b1_slavename = res.getSlavename() - d2.addCallback(self._testSimultaneous_2, b1_slavename) - return d2 - def _testSimultaneous_2(self, res, b1_slavename): - self.failUnlessEqual(res.getResults(), SUCCESS) - b2_slavename = res.getSlavename() - # make sure the two builds were run by different slaves - slavenames = [b1_slavename, b2_slavename] - slavenames.sort() - self.failUnlessEqual(slavenames, ["bot1", "bot2"]) - - def testFallback1(self): - # detach the first slave, verify that a build is run using the second - # slave instead - d = self.shutdownSlave("bot1", "b1") - d.addCallback(self._testFallback1_1) - return d - def _testFallback1_1(self, res): - attached_slaves = [c for c in self.master.botmaster.slaves.values() - if c.slave] - self.failUnlessEqual(len(attached_slaves), 1) - self.failUnlessEqual(len(self.master.botmaster.builders["b1"].slaves), - 1) - d = self.doBuild("b1") - d.addCallback(self._testFallback1_2) - return d - def _testFallback1_2(self, res): - self.failUnlessEqual(res.getResults(), SUCCESS) - self.failUnlessEqual(res.getSlavename(), "bot2") - - def testFallback2(self): - # Disable the first slave, so that a slaveping will timeout. Then - # start a build, and verify that the non-failing (second) one is - # claimed for the build, and that the failing one is removed from the - # list. - - b1 = self.master.botmaster.builders["b1"] - # reduce the ping time so we'll failover faster - b1.START_BUILD_TIMEOUT = 1 - assert b1.CHOOSE_SLAVES_RANDOMLY - b1.CHOOSE_SLAVES_RANDOMLY = False - self.disappearSlave("bot1", "b1", allowReconnect=False) - d = self.doBuild("b1") - d.addCallback(self._testFallback2_1) - return d - def _testFallback2_1(self, res): - self.failUnlessEqual(res.getResults(), SUCCESS) - self.failUnlessEqual(res.getSlavename(), "bot2") - b1slaves = self.master.botmaster.builders["b1"].slaves - self.failUnlessEqual(len(b1slaves), 1, "whoops: %s" % (b1slaves,)) - self.failUnlessEqual(b1slaves[0].slave.slavename, "bot2") - - - def notFinished(self, brs): - # utility method - builds = brs.getBuilds() - self.failIf(len(builds) > 1) - if builds: - self.failIf(builds[0].isFinished()) - - def testDontClaimPingingSlave(self): - # have two slaves connect for the same builder. Do something to the - # first one so that slavepings are delayed (but do not fail - # outright). - timers = [] - self.slaves['bot1'].debugOpts["stallPings"] = (10, timers) - br = BuildRequest("forced", SourceStamp()) - d1 = br.waitUntilFinished() - self.master.botmaster.builders["b1"].CHOOSE_SLAVES_RANDOMLY = False - self.control.getBuilder("b1").requestBuild(br) - s1 = br.status # this is a BuildRequestStatus - # give it a chance to start pinging - d2 = defer.Deferred() - d2.addCallback(self._testDontClaimPingingSlave_1, d1, s1, timers) - reactor.callLater(1, d2.callback, None) - return d2 - def _testDontClaimPingingSlave_1(self, res, d1, s1, timers): - # now the first build is running (waiting on the ping), so start the - # second build. This should claim the second slave, not the first, - # because the first is busy doing the ping. - self.notFinished(s1) - d3 = self.doBuild("b1") - d3.addCallback(self._testDontClaimPingingSlave_2, d1, s1, timers) - return d3 - def _testDontClaimPingingSlave_2(self, res, d1, s1, timers): - self.failUnlessEqual(res.getSlavename(), "bot2") - self.notFinished(s1) - # now let the ping complete - self.failUnlessEqual(len(timers), 1) - timers[0].reset(0) - d1.addCallback(self._testDontClaimPingingSlave_3) - return d1 - def _testDontClaimPingingSlave_3(self, res): - self.failUnlessEqual(res.getSlavename(), "bot1") - - -class SlaveBusyness(RunMixin, unittest.TestCase): - - def setUp(self): - RunMixin.setUp(self) - self.master.loadConfig(config_busyness) - self.master.startService() - d = self.connectSlave(["b1", "b2"]) - return d - - def doBuild(self, buildername): - br = BuildRequest("forced", SourceStamp()) - d = br.waitUntilFinished() - self.control.getBuilder(buildername).requestBuild(br) - return d - - def getRunningBuilds(self): - return len(self.status.getSlave("bot1").getRunningBuilds()) - - def testSlaveNotBusy(self): - self.failUnlessEqual(self.getRunningBuilds(), 0) - # now kick a build, wait for it to finish, then check again - d = self.doBuild("b1") - d.addCallback(self._testSlaveNotBusy_1) - return d - - def _testSlaveNotBusy_1(self, res): - self.failUnlessEqual(self.getRunningBuilds(), 0) - - def testSlaveBusyOneBuild(self): - d1 = self.doBuild("b1") - d2 = defer.Deferred() - reactor.callLater(.5, d2.callback, None) - d2.addCallback(self._testSlaveBusyOneBuild_1) - d1.addCallback(self._testSlaveBusyOneBuild_finished_1) - return defer.DeferredList([d1,d2]) - - def _testSlaveBusyOneBuild_1(self, res): - self.failUnlessEqual(self.getRunningBuilds(), 1) - - def _testSlaveBusyOneBuild_finished_1(self, res): - self.failUnlessEqual(self.getRunningBuilds(), 0) - - def testSlaveBusyTwoBuilds(self): - d1 = self.doBuild("b1") - d2 = self.doBuild("b2") - d3 = defer.Deferred() - reactor.callLater(.5, d3.callback, None) - d3.addCallback(self._testSlaveBusyTwoBuilds_1) - d1.addCallback(self._testSlaveBusyTwoBuilds_finished_1, d2) - return defer.DeferredList([d1,d3]) - - def _testSlaveBusyTwoBuilds_1(self, res): - self.failUnlessEqual(self.getRunningBuilds(), 2) - - def _testSlaveBusyTwoBuilds_finished_1(self, res, d2): - self.failUnlessEqual(self.getRunningBuilds(), 1) - d2.addCallback(self._testSlaveBusyTwoBuilds_finished_2) - return d2 - - def _testSlaveBusyTwoBuilds_finished_2(self, res): - self.failUnlessEqual(self.getRunningBuilds(), 0) - - def testSlaveDisconnect(self): - d1 = self.doBuild("b1") - d2 = defer.Deferred() - reactor.callLater(.5, d2.callback, None) - d2.addCallback(self._testSlaveDisconnect_1) - d1.addCallback(self._testSlaveDisconnect_finished_1) - return defer.DeferredList([d1, d2]) - - def _testSlaveDisconnect_1(self, res): - self.failUnlessEqual(self.getRunningBuilds(), 1) - return self.shutdownAllSlaves() - - def _testSlaveDisconnect_finished_1(self, res): - self.failUnlessEqual(self.getRunningBuilds(), 0) - -config_3 = """ -from buildbot.process import factory -from buildbot.steps import dummy -from buildbot.buildslave import BuildSlave -s = factory.s - -BuildmasterConfig = c = {} -c['slaves'] = [BuildSlave('bot1', 'sekrit')] -c['schedulers'] = [] -c['slavePortnum'] = 0 -c['schedulers'] = [] - -f1 = factory.BuildFactory([s(dummy.Wait, handle='one')]) -f2 = factory.BuildFactory([s(dummy.Wait, handle='two')]) -f3 = factory.BuildFactory([s(dummy.Wait, handle='three')]) - -c['builders'] = [ - {'name': 'b1', 'slavenames': ['bot1'], - 'builddir': 'b1', 'factory': f1}, - ] -""" - -config_4 = config_3 + """ -c['builders'] = [ - {'name': 'b1', 'slavenames': ['bot1'], - 'builddir': 'b1', 'factory': f2}, - ] -""" - -config_5 = config_3 + """ -c['builders'] = [ - {'name': 'b1', 'slavenames': ['bot1'], - 'builddir': 'b1', 'factory': f3}, - ] -""" - -from buildbot.slave.commands import waitCommandRegistry - -class Reconfig(RunMixin, unittest.TestCase): - - def setUp(self): - RunMixin.setUp(self) - self.master.loadConfig(config_3) - self.master.startService() - d = self.connectSlave(["b1"]) - return d - - def _one_started(self): - log.msg("testReconfig._one_started") - self.build1_started = True - self.d1.callback(None) - return self.d2 - - def _two_started(self): - log.msg("testReconfig._two_started") - self.build2_started = True - self.d3.callback(None) - return self.d4 - - def _three_started(self): - log.msg("testReconfig._three_started") - self.build3_started = True - self.d5.callback(None) - return self.d6 - - def testReconfig(self): - # reconfiguring a Builder should not interrupt any running Builds. No - # queued BuildRequests should be lost. The next Build started should - # use the new process. - slave1 = self.slaves['bot1'] - bot1 = slave1.getServiceNamed('bot') - sb1 = bot1.builders['b1'] - self.failUnless(isinstance(sb1, bot.SlaveBuilder)) - self.failUnless(sb1.running) - b1 = self.master.botmaster.builders['b1'] - self.orig_b1 = b1 - - self.d1 = d1 = defer.Deferred() - self.d2 = d2 = defer.Deferred() - self.d3, self.d4 = defer.Deferred(), defer.Deferred() - self.d5, self.d6 = defer.Deferred(), defer.Deferred() - self.build1_started = False - self.build2_started = False - self.build3_started = False - waitCommandRegistry[("one","build1")] = self._one_started - waitCommandRegistry[("two","build2")] = self._two_started - waitCommandRegistry[("three","build3")] = self._three_started - - # use different branches to make sure these cannot be merged - br1 = BuildRequest("build1", SourceStamp(branch="1")) - b1.submitBuildRequest(br1) - br2 = BuildRequest("build2", SourceStamp(branch="2")) - b1.submitBuildRequest(br2) - br3 = BuildRequest("build3", SourceStamp(branch="3")) - b1.submitBuildRequest(br3) - self.requests = (br1, br2, br3) - # all three are now in the queue - - # wait until the first one has started - d1.addCallback(self._testReconfig_2) - return d1 - - def _testReconfig_2(self, res): - log.msg("_testReconfig_2") - # confirm that it is building - brs = self.requests[0].status.getBuilds() - self.failUnlessEqual(len(brs), 1) - self.build1 = brs[0] - self.failUnlessEqual(self.build1.getCurrentStep().getName(), "wait") - # br1 is building, br2 and br3 are in the queue (in that order). Now - # we reconfigure the Builder. - self.failUnless(self.build1_started) - d = self.master.loadConfig(config_4) - d.addCallback(self._testReconfig_3) - return d - - def _testReconfig_3(self, res): - log.msg("_testReconfig_3") - # now check to see that br1 is still building, and that br2 and br3 - # are in the queue of the new builder - b1 = self.master.botmaster.builders['b1'] - self.failIfIdentical(b1, self.orig_b1) - self.failIf(self.build1.isFinished()) - self.failUnlessEqual(self.build1.getCurrentStep().getName(), "wait") - self.failUnlessEqual(len(b1.buildable), 2) - self.failUnless(self.requests[1] in b1.buildable) - self.failUnless(self.requests[2] in b1.buildable) - - # allow br1 to finish, and make sure its status is delivered normally - d = self.requests[0].waitUntilFinished() - d.addCallback(self._testReconfig_4) - self.d2.callback(None) - return d - - def _testReconfig_4(self, bs): - log.msg("_testReconfig_4") - self.failUnlessEqual(bs.getReason(), "build1") - self.failUnless(bs.isFinished()) - self.failUnlessEqual(bs.getResults(), SUCCESS) - - # at this point, the first build has finished, and there is a pending - # call to start the second build. Once that pending call fires, there - # is a network roundtrip before the 'wait' RemoteCommand is delivered - # to the slave. We need to wait for both events to happen before we - # can check to make sure it is using the correct process. Just wait a - # full second. - d = defer.Deferred() - d.addCallback(self._testReconfig_5) - reactor.callLater(1, d.callback, None) - return d - - def _testReconfig_5(self, res): - log.msg("_testReconfig_5") - # at this point the next build ought to be running - b1 = self.master.botmaster.builders['b1'] - self.failUnlessEqual(len(b1.buildable), 1) - self.failUnless(self.requests[2] in b1.buildable) - self.failUnlessEqual(len(b1.building), 1) - # and it ought to be using the new process - self.failUnless(self.build2_started) - - # now, while the second build is running, change the config multiple - # times. - - d = self.master.loadConfig(config_3) - d.addCallback(lambda res: self.master.loadConfig(config_4)) - d.addCallback(lambda res: self.master.loadConfig(config_5)) - def _done(res): - # then once that's done, allow the second build to finish and - # wait for it to complete - da = self.requests[1].waitUntilFinished() - self.d4.callback(None) - return da - d.addCallback(_done) - def _done2(res): - # and once *that*'s done, wait another second to let the third - # build start - db = defer.Deferred() - reactor.callLater(1, db.callback, None) - return db - d.addCallback(_done2) - d.addCallback(self._testReconfig_6) - return d - - def _testReconfig_6(self, res): - log.msg("_testReconfig_6") - # now check to see that the third build is running - self.failUnless(self.build3_started) - - # we're done - - - -class Slave2(RunMixin, unittest.TestCase): - - revision = 0 - - def setUp(self): - RunMixin.setUp(self) - self.master.loadConfig(config_1) - self.master.startService() - - def doBuild(self, buildername, reason="forced"): - # we need to prevent these builds from being merged, so we create - # each of them with a different revision specifier. The revision is - # ignored because our build process does not have a source checkout - # step. - self.revision += 1 - br = BuildRequest(reason, SourceStamp(revision=self.revision)) - d = br.waitUntilFinished() - self.control.getBuilder(buildername).requestBuild(br) - return d - - def testFirstComeFirstServed(self): - # submit three builds, then connect a slave which fails the - # slaveping. The first build will claim the slave, do the slaveping, - # give up, and re-queue the build. Verify that the build gets - # re-queued in front of all other builds. This may be tricky, because - # the other builds may attempt to claim the just-failed slave. - - d1 = self.doBuild("b1", "first") - d2 = self.doBuild("b1", "second") - #buildable = self.master.botmaster.builders["b1"].buildable - #print [b.reason for b in buildable] - - # specifically, I want the poor build to get precedence over any - # others that were waiting. To test this, we need more builds than - # slaves. - - # now connect a broken slave. The first build started as soon as it - # connects, so by the time we get to our _1 method, the ill-fated - # build has already started. - d = self.connectSlave(["b1"], opts={"failPingOnce": True}) - d.addCallback(self._testFirstComeFirstServed_1, d1, d2) - return d - def _testFirstComeFirstServed_1(self, res, d1, d2): - # the master has send the slaveping. When this is received, it will - # fail, causing the master to hang up on the slave. When it - # reconnects, it should find the first build at the front of the - # queue. If we simply wait for both builds to complete, then look at - # the status logs, we should see that the builds ran in the correct - # order. - - d = defer.DeferredList([d1,d2]) - d.addCallback(self._testFirstComeFirstServed_2) - return d - def _testFirstComeFirstServed_2(self, res): - b = self.status.getBuilder("b1") - builds = b.getBuild(0), b.getBuild(1) - reasons = [build.getReason() for build in builds] - self.failUnlessEqual(reasons, ["first", "second"]) - -config_multi_builders = config_1 + """ -c['builders'] = [ - {'name': 'dummy', 'slavenames': ['bot1','bot2','bot3'], - 'builddir': 'b1', 'factory': f2}, - {'name': 'dummy2', 'slavenames': ['bot1','bot2','bot3'], - 'builddir': 'b2', 'factory': f2}, - {'name': 'dummy3', 'slavenames': ['bot1','bot2','bot3'], - 'builddir': 'b3', 'factory': f2}, - ] - -""" - -config_mail_missing = config_1 + """ -c['slaves'] = [BuildSlave('bot1', 'sekrit', notify_on_missing='admin', - missing_timeout=1)] -c['builders'] = [ - {'name': 'dummy', 'slavenames': ['bot1'], - 'builddir': 'b1', 'factory': f1}, - ] -c['projectName'] = 'myproject' -c['projectURL'] = 'myURL' -""" - -class FakeMailer(mail.MailNotifier): - def sendMessage(self, m, recipients): - self.messages.append((m,recipients)) - return defer.succeed(None) - -class BuildSlave(RunMixin, unittest.TestCase): - def test_track_builders(self): - self.master.loadConfig(config_multi_builders) - self.master.readConfig = True - self.master.startService() - d = self.connectSlave() - - def _check(res): - b = self.master.botmaster.builders['dummy'] - self.failUnless(len(b.slaves) == 1) # just bot1 - - bs = b.slaves[0].slave - self.failUnless(len(bs.slavebuilders) == 3) - self.failUnless(b in [sb.builder for sb in bs.slavebuilders]) - - d.addCallback(_check) - return d - - def test_mail_on_missing(self): - self.master.loadConfig(config_mail_missing) - self.master.readConfig = True - self.master.startService() - fm = FakeMailer("buildbot@example.org") - fm.messages = [] - fm.setServiceParent(self.master) - self.master.statusTargets.append(fm) - - d = self.connectSlave() - d.addCallback(self.stall, 1) - d.addCallback(lambda res: self.shutdownSlave("bot1", "dummy")) - def _not_yet(res): - self.failIf(fm.messages) - d.addCallback(_not_yet) - # we reconnect right away, so the timer shouldn't fire - d.addCallback(lambda res: self.connectSlave()) - d.addCallback(self.stall, 3) - d.addCallback(_not_yet) - d.addCallback(lambda res: self.shutdownSlave("bot1", "dummy")) - d.addCallback(_not_yet) - # now we let it sit disconnected for long enough for the timer to - # fire - d.addCallback(self.stall, 3) - def _check(res): - self.failUnlessEqual(len(fm.messages), 1) - msg,recips = fm.messages[0] - self.failUnlessEqual(recips, ["admin"]) - body = msg.as_string() - self.failUnlessIn("To: admin", body) - self.failUnlessIn("Subject: Buildbot: buildslave bot1 was lost", - body) - self.failUnlessIn("From: buildbot@example.org", body) - self.failUnlessIn("working for 'myproject'", body) - self.failUnlessIn("has noticed that the buildslave named bot1 went away", - body) - self.failUnlessIn("was 'one'", body) - self.failUnlessIn("myURL", body) - d.addCallback(_check) - return d - - def stall(self, result, delay=1): - d = defer.Deferred() - reactor.callLater(delay, d.callback, result) - return d diff --git a/tools/buildbot/pylibs/buildbot/test/test_status.py b/tools/buildbot/pylibs/buildbot/test/test_status.py deleted file mode 100644 index 9c24ee0..0000000 --- a/tools/buildbot/pylibs/buildbot/test/test_status.py +++ /dev/null @@ -1,1230 +0,0 @@ -# -*- test-case-name: buildbot.test.test_status -*- - -import email, os -import operator - -from zope.interface import implements -from twisted.internet import defer, reactor -from twisted.trial import unittest - -from buildbot import interfaces -from buildbot.sourcestamp import SourceStamp -from buildbot.process.base import BuildRequest -from buildbot.status import builder, base, words -from buildbot.changes.changes import Change - -mail = None -try: - from buildbot.status import mail -except ImportError: - pass -from buildbot.status import progress, client # NEEDS COVERAGE -from buildbot.test.runutils import RunMixin - -class MyStep: - build = None - def getName(self): - return "step" - -class MyLogFileProducer(builder.LogFileProducer): - # The reactor.callLater(0) in LogFileProducer.resumeProducing is a bit of - # a nuisance from a testing point of view. This subclass adds a Deferred - # to that call so we can find out when it is complete. - def resumeProducing(self): - d = defer.Deferred() - reactor.callLater(0, self._resumeProducing, d) - return d - def _resumeProducing(self, d): - builder.LogFileProducer._resumeProducing(self) - reactor.callLater(0, d.callback, None) - -class MyLog(builder.LogFile): - def __init__(self, basedir, name, text=None, step=None): - self.fakeBuilderBasedir = basedir - if not step: - step = MyStep() - builder.LogFile.__init__(self, step, name, name) - if text: - self.addStdout(text) - self.finish() - def getFilename(self): - return os.path.join(self.fakeBuilderBasedir, self.name) - - def subscribeConsumer(self, consumer): - p = MyLogFileProducer(self, consumer) - d = p.resumeProducing() - return d - -class MyHTMLLog(builder.HTMLLogFile): - def __init__(self, basedir, name, html): - step = MyStep() - builder.HTMLLogFile.__init__(self, step, name, name, html) - -class MyLogSubscriber: - def __init__(self): - self.chunks = [] - def logChunk(self, build, step, log, channel, text): - self.chunks.append((channel, text)) - -class MyLogConsumer: - def __init__(self, limit=None): - self.chunks = [] - self.finished = False - self.limit = limit - def registerProducer(self, producer, streaming): - self.producer = producer - self.streaming = streaming - def unregisterProducer(self): - self.producer = None - def writeChunk(self, chunk): - self.chunks.append(chunk) - if self.limit: - self.limit -= 1 - if self.limit == 0: - self.producer.pauseProducing() - def finish(self): - self.finished = True - -if mail: - class MyMailer(mail.MailNotifier): - def sendMessage(self, m, recipients): - self.parent.messages.append((m, recipients)) - -class MyStatus: - def getBuildbotURL(self): - return self.url - def getURLForThing(self, thing): - return None - -class MyBuilder(builder.BuilderStatus): - nextBuildNumber = 0 - -class MyBuild(builder.BuildStatus): - testlogs = [] - def __init__(self, parent, number, results): - builder.BuildStatus.__init__(self, parent, number) - self.results = results - self.source = SourceStamp(revision="1.14") - self.reason = "build triggered by changes" - self.finished = True - def getLogs(self): - return self.testlogs - -class MyLookup: - implements(interfaces.IEmailLookup) - - def getAddress(self, user): - d = defer.Deferred() - # With me now is Mr Thomas Walters of West Hartlepool who is totally - # invisible. - if user == "Thomas_Walters": - d.callback(None) - else: - d.callback(user + "@" + "dev.com") - return d - -class Mail(unittest.TestCase): - - def setUp(self): - self.builder = MyBuilder("builder1") - - def stall(self, res, timeout): - d = defer.Deferred() - reactor.callLater(timeout, d.callback, res) - return d - - def makeBuild(self, number, results): - return MyBuild(self.builder, number, results) - - def failUnlessIn(self, substring, string): - self.failUnless(string.find(substring) != -1, - "didn't see '%s' in '%s'" % (substring, string)) - - def getProjectName(self): - return "PROJECT" - - def getBuildbotURL(self): - return "BUILDBOT_URL" - - def getURLForThing(self, thing): - return None - - def testBuild1(self): - mailer = MyMailer(fromaddr="buildbot@example.com", - extraRecipients=["recip@example.com", - "recip2@example.com"], - lookup=mail.Domain("dev.com")) - mailer.parent = self - mailer.status = self - self.messages = [] - - b1 = self.makeBuild(3, builder.SUCCESS) - b1.blamelist = ["bob"] - - mailer.buildFinished("builder1", b1, b1.results) - self.failUnless(len(self.messages) == 1) - m,r = self.messages.pop() - t = m.as_string() - self.failUnlessIn("To: bob@dev.com, recip2@example.com, " - "recip@example.com\n", t) - self.failUnlessIn("From: buildbot@example.com\n", t) - self.failUnlessIn("Subject: buildbot success in PROJECT on builder1\n", t) - self.failUnlessIn("Date: ", t) - self.failUnlessIn("Build succeeded!\n", t) - self.failUnlessIn("Buildbot URL: BUILDBOT_URL\n", t) - - def testBuild2(self): - mailer = MyMailer(fromaddr="buildbot@example.com", - extraRecipients=["recip@example.com", - "recip2@example.com"], - lookup="dev.com", - sendToInterestedUsers=False) - mailer.parent = self - mailer.status = self - self.messages = [] - - b1 = self.makeBuild(3, builder.SUCCESS) - b1.blamelist = ["bob"] - - mailer.buildFinished("builder1", b1, b1.results) - self.failUnless(len(self.messages) == 1) - m,r = self.messages.pop() - t = m.as_string() - self.failUnlessIn("To: recip2@example.com, " - "recip@example.com\n", t) - self.failUnlessIn("From: buildbot@example.com\n", t) - self.failUnlessIn("Subject: buildbot success in PROJECT on builder1\n", t) - self.failUnlessIn("Build succeeded!\n", t) - self.failUnlessIn("Buildbot URL: BUILDBOT_URL\n", t) - - def testBuildStatusCategory(self): - # a status client only interested in a category should only receive - # from that category - mailer = MyMailer(fromaddr="buildbot@example.com", - extraRecipients=["recip@example.com", - "recip2@example.com"], - lookup="dev.com", - sendToInterestedUsers=False, - categories=["debug"]) - - mailer.parent = self - mailer.status = self - self.messages = [] - - b1 = self.makeBuild(3, builder.SUCCESS) - b1.blamelist = ["bob"] - - mailer.buildFinished("builder1", b1, b1.results) - self.failIf(self.messages) - - def testBuilderCategory(self): - # a builder in a certain category should notify status clients that - # did not list categories, or categories including this one - mailer1 = MyMailer(fromaddr="buildbot@example.com", - extraRecipients=["recip@example.com", - "recip2@example.com"], - lookup="dev.com", - sendToInterestedUsers=False) - mailer2 = MyMailer(fromaddr="buildbot@example.com", - extraRecipients=["recip@example.com", - "recip2@example.com"], - lookup="dev.com", - sendToInterestedUsers=False, - categories=["active"]) - mailer3 = MyMailer(fromaddr="buildbot@example.com", - extraRecipients=["recip@example.com", - "recip2@example.com"], - lookup="dev.com", - sendToInterestedUsers=False, - categories=["active", "debug"]) - - builderd = MyBuilder("builder2", "debug") - - mailer1.parent = self - mailer1.status = self - mailer2.parent = self - mailer2.status = self - mailer3.parent = self - mailer3.status = self - self.messages = [] - - t = mailer1.builderAdded("builder2", builderd) - self.assertEqual(len(mailer1.watched), 1) - self.assertEqual(t, mailer1) - t = mailer2.builderAdded("builder2", builderd) - self.assertEqual(len(mailer2.watched), 0) - self.assertEqual(t, None) - t = mailer3.builderAdded("builder2", builderd) - self.assertEqual(len(mailer3.watched), 1) - self.assertEqual(t, mailer3) - - b2 = MyBuild(builderd, 3, builder.SUCCESS) - b2.blamelist = ["bob"] - - mailer1.buildFinished("builder2", b2, b2.results) - self.failUnlessEqual(len(self.messages), 1) - self.messages = [] - mailer2.buildFinished("builder2", b2, b2.results) - self.failUnlessEqual(len(self.messages), 0) - self.messages = [] - mailer3.buildFinished("builder2", b2, b2.results) - self.failUnlessEqual(len(self.messages), 1) - - def testFailure(self): - mailer = MyMailer(fromaddr="buildbot@example.com", mode="problem", - extraRecipients=["recip@example.com", - "recip2@example.com"], - lookup=MyLookup()) - mailer.parent = self - mailer.status = self - self.messages = [] - - b1 = self.makeBuild(3, builder.SUCCESS) - b1.blamelist = ["dev1", "dev2"] - b2 = self.makeBuild(4, builder.FAILURE) - b2.setText(["snarkleack", "polarization", "failed"]) - b2.blamelist = ["dev3", "dev3", "dev3", "dev4", - "Thomas_Walters"] - mailer.buildFinished("builder1", b1, b1.results) - self.failIf(self.messages) - mailer.buildFinished("builder1", b2, b2.results) - self.failUnless(len(self.messages) == 1) - m,r = self.messages.pop() - t = m.as_string() - self.failUnlessIn("To: dev3@dev.com, dev4@dev.com, " - "recip2@example.com, recip@example.com\n", t) - self.failUnlessIn("From: buildbot@example.com\n", t) - self.failUnlessIn("Subject: buildbot failure in PROJECT on builder1\n", t) - self.failUnlessIn("The Buildbot has detected a new failure", t) - self.failUnlessIn("BUILD FAILED: snarkleack polarization failed\n", t) - self.failUnlessEqual(r, ["dev3@dev.com", "dev4@dev.com", - "recip2@example.com", "recip@example.com"]) - - def testLogs(self): - basedir = "test_status_logs" - os.mkdir(basedir) - mailer = MyMailer(fromaddr="buildbot@example.com", addLogs=True, - extraRecipients=["recip@example.com", - "recip2@example.com"]) - mailer.parent = self - mailer.status = self - self.messages = [] - - b1 = self.makeBuild(3, builder.WARNINGS) - b1.testlogs = [MyLog(basedir, 'compile', "Compile log here\n"), - MyLog(basedir, - 'test', "Test log here\nTest 4 failed\n"), - ] - b1.text = ["unusual", "gnarzzler", "output"] - mailer.buildFinished("builder1", b1, b1.results) - self.failUnless(len(self.messages) == 1) - m,r = self.messages.pop() - t = m.as_string() - self.failUnlessIn("Subject: buildbot warnings in PROJECT on builder1\n", t) - m2 = email.message_from_string(t) - p = m2.get_payload() - self.failUnlessEqual(len(p), 3) - - self.failUnlessIn("Build Had Warnings: unusual gnarzzler output\n", - p[0].get_payload()) - - self.failUnlessEqual(p[1].get_filename(), "step.compile") - self.failUnlessEqual(p[1].get_payload(), "Compile log here\n") - - self.failUnlessEqual(p[2].get_filename(), "step.test") - self.failUnlessIn("Test log here\n", p[2].get_payload()) - - def testMail(self): - basedir = "test_status_mail" - os.mkdir(basedir) - dest = os.environ.get("BUILDBOT_TEST_MAIL") - if not dest: - raise unittest.SkipTest("define BUILDBOT_TEST_MAIL=dest to run this") - mailer = mail.MailNotifier(fromaddr="buildbot@example.com", - addLogs=True, - extraRecipients=[dest]) - s = MyStatus() - s.url = "project URL" - mailer.status = s - - b1 = self.makeBuild(3, builder.SUCCESS) - b1.testlogs = [MyLog(basedir, 'compile', "Compile log here\n"), - MyLog(basedir, - 'test', "Test log here\nTest 4 failed\n"), - ] - - print "sending mail to", dest - d = mailer.buildFinished("builder1", b1, b1.results) - # When this fires, the mail has been sent, but the SMTP connection is - # still up (because smtp.sendmail relies upon the server to hang up). - # Spin for a moment to avoid the "unclean reactor" warning that Trial - # gives us if we finish before the socket is disconnected. Really, - # sendmail() ought to hang up the connection once it is finished: - # otherwise a malicious SMTP server could make us consume lots of - # memory. - d.addCallback(self.stall, 0.1) - return d - -if not mail: - Mail.skip = "the Twisted Mail package is not installed" - -class Progress(unittest.TestCase): - def testWavg(self): - bp = progress.BuildProgress([]) - e = progress.Expectations(bp) - # wavg(old, current) - self.failUnlessEqual(e.wavg(None, None), None) - self.failUnlessEqual(e.wavg(None, 3), 3) - self.failUnlessEqual(e.wavg(3, None), 3) - self.failUnlessEqual(e.wavg(3, 4), 3.5) - e.decay = 0.1 - self.failUnlessEqual(e.wavg(3, 4), 3.1) - - -class Results(unittest.TestCase): - - def testAddResults(self): - b = builder.BuildStatus(builder.BuilderStatus("test"), 12) - testname = ("buildbot", "test", "test_status", "Results", - "testAddResults") - r1 = builder.TestResult(name=testname, - results=builder.SUCCESS, - text=["passed"], - logs={'output': ""}, - ) - b.addTestResult(r1) - - res = b.getTestResults() - self.failUnlessEqual(res.keys(), [testname]) - t = res[testname] - self.failUnless(interfaces.ITestResult.providedBy(t)) - self.failUnlessEqual(t.getName(), testname) - self.failUnlessEqual(t.getResults(), builder.SUCCESS) - self.failUnlessEqual(t.getText(), ["passed"]) - self.failUnlessEqual(t.getLogs(), {'output': ""}) - -class Log(unittest.TestCase): - def setUpClass(self): - self.basedir = "status_log_add" - os.mkdir(self.basedir) - - def testAdd(self): - l = MyLog(self.basedir, "compile", step=13) - self.failUnlessEqual(l.getName(), "compile") - self.failUnlessEqual(l.getStep(), 13) - l.addHeader("HEADER\n") - l.addStdout("Some text\n") - l.addStderr("Some error\n") - l.addStdout("Some more text\n") - self.failIf(l.isFinished()) - l.finish() - self.failUnless(l.isFinished()) - self.failUnlessEqual(l.getText(), - "Some text\nSome error\nSome more text\n") - self.failUnlessEqual(l.getTextWithHeaders(), - "HEADER\n" + - "Some text\nSome error\nSome more text\n") - self.failUnlessEqual(len(list(l.getChunks())), 4) - - self.failUnless(l.hasContents()) - os.unlink(l.getFilename()) - self.failIf(l.hasContents()) - - def TODO_testDuplicate(self): - # create multiple logs for the same step with the same logname, make - # sure their on-disk filenames are suitably uniquified. This - # functionality actually lives in BuildStepStatus and BuildStatus, so - # this test must involve more than just the MyLog class. - - # naieve approach, doesn't work - l1 = MyLog(self.basedir, "duplicate") - l1.addStdout("Some text\n") - l1.finish() - l2 = MyLog(self.basedir, "duplicate") - l2.addStdout("Some more text\n") - l2.finish() - self.failIfEqual(l1.getFilename(), l2.getFilename()) - - def testMerge1(self): - l = MyLog(self.basedir, "merge1") - l.addHeader("HEADER\n") - l.addStdout("Some text\n") - l.addStdout("Some more text\n") - l.addStdout("more\n") - l.finish() - self.failUnlessEqual(l.getText(), - "Some text\nSome more text\nmore\n") - self.failUnlessEqual(l.getTextWithHeaders(), - "HEADER\n" + - "Some text\nSome more text\nmore\n") - self.failUnlessEqual(len(list(l.getChunks())), 2) - - def testMerge2(self): - l = MyLog(self.basedir, "merge2") - l.addHeader("HEADER\n") - for i in xrange(1000): - l.addStdout("aaaa") - for i in xrange(30): - l.addStderr("bbbb") - for i in xrange(10): - l.addStdout("cc") - target = 1000*"aaaa" + 30 * "bbbb" + 10 * "cc" - self.failUnlessEqual(len(l.getText()), len(target)) - self.failUnlessEqual(l.getText(), target) - l.finish() - self.failUnlessEqual(len(l.getText()), len(target)) - self.failUnlessEqual(l.getText(), target) - self.failUnlessEqual(len(list(l.getChunks())), 4) - - def testMerge3(self): - l = MyLog(self.basedir, "merge3") - l.chunkSize = 100 - l.addHeader("HEADER\n") - for i in xrange(8): - l.addStdout(10*"a") - for i in xrange(8): - l.addStdout(10*"a") - self.failUnlessEqual(list(l.getChunks()), - [(builder.HEADER, "HEADER\n"), - (builder.STDOUT, 100*"a"), - (builder.STDOUT, 60*"a")]) - l.finish() - self.failUnlessEqual(l.getText(), 160*"a") - - def testReadlines(self): - l = MyLog(self.basedir, "chunks") - l.addHeader("HEADER\n") # should be ignored - l.addStdout("Some text\n") - l.addStdout("Some More Text\nAnd Some More\n") - l.addStderr("Some Stderr\n") - l.addStdout("Last line\n") - l.finish() - alllines = list(l.readlines()) - self.failUnlessEqual(len(alllines), 4) - self.failUnlessEqual(alllines[0], "Some text\n") - self.failUnlessEqual(alllines[2], "And Some More\n") - self.failUnlessEqual(alllines[3], "Last line\n") - stderr = list(l.readlines(interfaces.LOG_CHANNEL_STDERR)) - self.failUnlessEqual(len(stderr), 1) - self.failUnlessEqual(stderr[0], "Some Stderr\n") - lines = l.readlines() - if False: # TODO: l.readlines() is not yet an iterator - # verify that it really is an iterator - line0 = lines.next() - self.failUnlessEqual(line0, "Some text\n") - line1 = lines.next() - line2 = lines.next() - self.failUnlessEqual(line2, "And Some More\n") - - - def testChunks(self): - l = MyLog(self.basedir, "chunks") - c1 = l.getChunks() - l.addHeader("HEADER\n") - l.addStdout("Some text\n") - self.failUnlessEqual("".join(l.getChunks(onlyText=True)), - "HEADER\nSome text\n") - c2 = l.getChunks() - - l.addStdout("Some more text\n") - self.failUnlessEqual("".join(l.getChunks(onlyText=True)), - "HEADER\nSome text\nSome more text\n") - c3 = l.getChunks() - - l.addStdout("more\n") - l.finish() - - self.failUnlessEqual(list(c1), []) - self.failUnlessEqual(list(c2), [(builder.HEADER, "HEADER\n"), - (builder.STDOUT, "Some text\n")]) - self.failUnlessEqual(list(c3), [(builder.HEADER, "HEADER\n"), - (builder.STDOUT, - "Some text\nSome more text\n")]) - - self.failUnlessEqual(l.getText(), - "Some text\nSome more text\nmore\n") - self.failUnlessEqual(l.getTextWithHeaders(), - "HEADER\n" + - "Some text\nSome more text\nmore\n") - self.failUnlessEqual(len(list(l.getChunks())), 2) - - def testUpgrade(self): - l = MyLog(self.basedir, "upgrade") - l.addHeader("HEADER\n") - l.addStdout("Some text\n") - l.addStdout("Some more text\n") - l.addStdout("more\n") - l.finish() - self.failUnless(l.hasContents()) - # now doctor it to look like a 0.6.4-era non-upgraded logfile - l.entries = list(l.getChunks()) - del l.filename - os.unlink(l.getFilename()) - # now make sure we can upgrade it - l.upgrade("upgrade") - self.failUnlessEqual(l.getText(), - "Some text\nSome more text\nmore\n") - self.failUnlessEqual(len(list(l.getChunks())), 2) - self.failIf(l.entries) - - # now, do it again, but make it look like an upgraded 0.6.4 logfile - # (i.e. l.filename is missing, but the contents are there on disk) - l.entries = list(l.getChunks()) - del l.filename - l.upgrade("upgrade") - self.failUnlessEqual(l.getText(), - "Some text\nSome more text\nmore\n") - self.failUnlessEqual(len(list(l.getChunks())), 2) - self.failIf(l.entries) - self.failUnless(l.hasContents()) - - def testHTMLUpgrade(self): - l = MyHTMLLog(self.basedir, "upgrade", "log contents") - l.upgrade("filename") - - def testSubscribe(self): - l1 = MyLog(self.basedir, "subscribe1") - l1.finish() - self.failUnless(l1.isFinished()) - - s = MyLogSubscriber() - l1.subscribe(s, True) - l1.unsubscribe(s) - self.failIf(s.chunks) - - s = MyLogSubscriber() - l1.subscribe(s, False) - l1.unsubscribe(s) - self.failIf(s.chunks) - - finished = [] - l2 = MyLog(self.basedir, "subscribe2") - l2.waitUntilFinished().addCallback(finished.append) - l2.addHeader("HEADER\n") - s1 = MyLogSubscriber() - l2.subscribe(s1, True) - s2 = MyLogSubscriber() - l2.subscribe(s2, False) - self.failUnlessEqual(s1.chunks, [(builder.HEADER, "HEADER\n")]) - self.failUnlessEqual(s2.chunks, []) - - l2.addStdout("Some text\n") - self.failUnlessEqual(s1.chunks, [(builder.HEADER, "HEADER\n"), - (builder.STDOUT, "Some text\n")]) - self.failUnlessEqual(s2.chunks, [(builder.STDOUT, "Some text\n")]) - l2.unsubscribe(s1) - - l2.addStdout("Some more text\n") - self.failUnlessEqual(s1.chunks, [(builder.HEADER, "HEADER\n"), - (builder.STDOUT, "Some text\n")]) - self.failUnlessEqual(s2.chunks, [(builder.STDOUT, "Some text\n"), - (builder.STDOUT, "Some more text\n"), - ]) - self.failIf(finished) - l2.finish() - self.failUnlessEqual(finished, [l2]) - - def testConsumer(self): - l1 = MyLog(self.basedir, "consumer1") - l1.finish() - self.failUnless(l1.isFinished()) - - s = MyLogConsumer() - d = l1.subscribeConsumer(s) - d.addCallback(self._testConsumer_1, s) - return d - testConsumer.timeout = 5 - def _testConsumer_1(self, res, s): - self.failIf(s.chunks) - self.failUnless(s.finished) - self.failIf(s.producer) # producer should be registered and removed - - l2 = MyLog(self.basedir, "consumer2") - l2.addHeader("HEADER\n") - l2.finish() - self.failUnless(l2.isFinished()) - - s = MyLogConsumer() - d = l2.subscribeConsumer(s) - d.addCallback(self._testConsumer_2, s) - return d - def _testConsumer_2(self, res, s): - self.failUnlessEqual(s.chunks, [(builder.HEADER, "HEADER\n")]) - self.failUnless(s.finished) - self.failIf(s.producer) # producer should be registered and removed - - - l2 = MyLog(self.basedir, "consumer3") - l2.chunkSize = 1000 - l2.addHeader("HEADER\n") - l2.addStdout(800*"a") - l2.addStdout(800*"a") # should now have two chunks on disk, 1000+600 - l2.addStdout(800*"b") # HEADER,1000+600*a on disk, 800*a in memory - l2.addStdout(800*"b") # HEADER,1000+600*a,1000+600*b on disk - l2.addStdout(200*"c") # HEADER,1000+600*a,1000+600*b on disk, - # 200*c in memory - - s = MyLogConsumer(limit=1) - d = l2.subscribeConsumer(s) - d.addCallback(self._testConsumer_3, l2, s) - return d - def _testConsumer_3(self, res, l2, s): - self.failUnless(s.streaming) - self.failUnlessEqual(s.chunks, [(builder.HEADER, "HEADER\n")]) - s.limit = 1 - d = s.producer.resumeProducing() - d.addCallback(self._testConsumer_4, l2, s) - return d - def _testConsumer_4(self, res, l2, s): - self.failUnlessEqual(s.chunks, [(builder.HEADER, "HEADER\n"), - (builder.STDOUT, 1000*"a"), - ]) - s.limit = None - d = s.producer.resumeProducing() - d.addCallback(self._testConsumer_5, l2, s) - return d - def _testConsumer_5(self, res, l2, s): - self.failUnlessEqual(s.chunks, [(builder.HEADER, "HEADER\n"), - (builder.STDOUT, 1000*"a"), - (builder.STDOUT, 600*"a"), - (builder.STDOUT, 1000*"b"), - (builder.STDOUT, 600*"b"), - (builder.STDOUT, 200*"c")]) - l2.addStdout(1000*"c") # HEADER,1600*a,1600*b,1200*c on disk - self.failUnlessEqual(s.chunks, [(builder.HEADER, "HEADER\n"), - (builder.STDOUT, 1000*"a"), - (builder.STDOUT, 600*"a"), - (builder.STDOUT, 1000*"b"), - (builder.STDOUT, 600*"b"), - (builder.STDOUT, 200*"c"), - (builder.STDOUT, 1000*"c")]) - l2.finish() - self.failUnlessEqual(s.chunks, [(builder.HEADER, "HEADER\n"), - (builder.STDOUT, 1000*"a"), - (builder.STDOUT, 600*"a"), - (builder.STDOUT, 1000*"b"), - (builder.STDOUT, 600*"b"), - (builder.STDOUT, 200*"c"), - (builder.STDOUT, 1000*"c")]) - self.failIf(s.producer) - self.failUnless(s.finished) - - def testLargeSummary(self): - bigtext = "a" * 200000 # exceed the NetstringReceiver 100KB limit - l = MyLog(self.basedir, "large", bigtext) - s = MyLogConsumer() - d = l.subscribeConsumer(s) - def _check(res): - for ctype,chunk in s.chunks: - self.failUnless(len(chunk) < 100000) - merged = "".join([c[1] for c in s.chunks]) - self.failUnless(merged == bigtext) - d.addCallback(_check) - # when this fails, it fails with a timeout, and there is an exception - # sent to log.err(). This AttributeError exception is in - # NetstringReceiver.dataReceived where it does - # self.transport.loseConnection() because of the NetstringParseError, - # however self.transport is None - return d - testLargeSummary.timeout = 5 - -config_base = """ -from buildbot.process import factory -from buildbot.steps import dummy -from buildbot.buildslave import BuildSlave -s = factory.s - -f1 = factory.QuickBuildFactory('fakerep', 'cvsmodule', configure=None) - -f2 = factory.BuildFactory([ - s(dummy.Dummy, timeout=1), - s(dummy.RemoteDummy, timeout=2), - ]) - -BuildmasterConfig = c = {} -c['slaves'] = [BuildSlave('bot1', 'sekrit')] -c['schedulers'] = [] -c['builders'] = [] -c['builders'].append({'name':'quick', 'slavename':'bot1', - 'builddir': 'quickdir', 'factory': f1}) -c['slavePortnum'] = 0 -""" - -config_2 = config_base + """ -c['builders'] = [{'name': 'dummy', 'slavename': 'bot1', - 'builddir': 'dummy1', 'factory': f2}, - {'name': 'testdummy', 'slavename': 'bot1', - 'builddir': 'dummy2', 'factory': f2, 'category': 'test'}] -""" - -class STarget(base.StatusReceiver): - debug = False - - def __init__(self, mode): - self.mode = mode - self.events = [] - def announce(self): - if self.debug: - print self.events[-1] - - def builderAdded(self, name, builder): - self.events.append(("builderAdded", name, builder)) - self.announce() - if "builder" in self.mode: - return self - def builderChangedState(self, name, state): - self.events.append(("builderChangedState", name, state)) - self.announce() - def buildStarted(self, name, build): - self.events.append(("buildStarted", name, build)) - self.announce() - if "eta" in self.mode: - self.eta_build = build.getETA() - if "build" in self.mode: - return self - def buildETAUpdate(self, build, ETA): - self.events.append(("buildETAUpdate", build, ETA)) - self.announce() - def stepStarted(self, build, step): - self.events.append(("stepStarted", build, step)) - self.announce() - if 0 and "eta" in self.mode: - print "TIMES", step.getTimes() - print "ETA", step.getETA() - print "EXP", step.getExpectations() - if "step" in self.mode: - return self - def stepETAUpdate(self, build, step, ETA, expectations): - self.events.append(("stepETAUpdate", build, step, ETA, expectations)) - self.announce() - def logStarted(self, build, step, log): - self.events.append(("logStarted", build, step, log)) - self.announce() - def logFinished(self, build, step, log): - self.events.append(("logFinished", build, step, log)) - self.announce() - def stepFinished(self, build, step, results): - self.events.append(("stepFinished", build, step, results)) - if 0 and "eta" in self.mode: - print "post-EXP", step.getExpectations() - self.announce() - def buildFinished(self, name, build, results): - self.events.append(("buildFinished", name, build, results)) - self.announce() - def builderRemoved(self, name): - self.events.append(("builderRemoved", name)) - self.announce() - -class Subscription(RunMixin, unittest.TestCase): - # verify that StatusTargets can subscribe/unsubscribe properly - - def testSlave(self): - m = self.master - s = m.getStatus() - self.t1 = t1 = STarget(["builder"]) - #t1.debug = True; print - s.subscribe(t1) - self.failUnlessEqual(len(t1.events), 0) - - self.t3 = t3 = STarget(["builder", "build", "step"]) - s.subscribe(t3) - - m.loadConfig(config_2) - m.readConfig = True - m.startService() - - self.failUnlessEqual(len(t1.events), 4) - self.failUnlessEqual(t1.events[0][0:2], ("builderAdded", "dummy")) - self.failUnlessEqual(t1.events[1], - ("builderChangedState", "dummy", "offline")) - self.failUnlessEqual(t1.events[2][0:2], ("builderAdded", "testdummy")) - self.failUnlessEqual(t1.events[3], - ("builderChangedState", "testdummy", "offline")) - t1.events = [] - - self.failUnlessEqual(s.getBuilderNames(), ["dummy", "testdummy"]) - self.failUnlessEqual(s.getBuilderNames(categories=['test']), - ["testdummy"]) - self.s1 = s1 = s.getBuilder("dummy") - self.failUnlessEqual(s1.getName(), "dummy") - self.failUnlessEqual(s1.getState(), ("offline", [])) - self.failUnlessEqual(s1.getCurrentBuilds(), []) - self.failUnlessEqual(s1.getLastFinishedBuild(), None) - self.failUnlessEqual(s1.getBuild(-1), None) - #self.failUnlessEqual(s1.getEvent(-1), foo("created")) - - # status targets should, upon being subscribed, immediately get a - # list of all current builders matching their category - self.t2 = t2 = STarget([]) - s.subscribe(t2) - self.failUnlessEqual(len(t2.events), 2) - self.failUnlessEqual(t2.events[0][0:2], ("builderAdded", "dummy")) - self.failUnlessEqual(t2.events[1][0:2], ("builderAdded", "testdummy")) - - d = self.connectSlave(builders=["dummy", "testdummy"]) - d.addCallback(self._testSlave_1, t1) - return d - - def _testSlave_1(self, res, t1): - self.failUnlessEqual(len(t1.events), 2) - self.failUnlessEqual(t1.events[0], - ("builderChangedState", "dummy", "idle")) - self.failUnlessEqual(t1.events[1], - ("builderChangedState", "testdummy", "idle")) - t1.events = [] - - c = interfaces.IControl(self.master) - req = BuildRequest("forced build for testing", SourceStamp()) - c.getBuilder("dummy").requestBuild(req) - d = req.waitUntilFinished() - d2 = self.master.botmaster.waitUntilBuilderIdle("dummy") - dl = defer.DeferredList([d, d2]) - dl.addCallback(self._testSlave_2) - return dl - - def _testSlave_2(self, res): - # t1 subscribes to builds, but not anything lower-level - ev = self.t1.events - self.failUnlessEqual(len(ev), 4) - self.failUnlessEqual(ev[0][0:3], - ("builderChangedState", "dummy", "building")) - self.failUnlessEqual(ev[1][0], "buildStarted") - self.failUnlessEqual(ev[2][0:2]+ev[2][3:4], - ("buildFinished", "dummy", builder.SUCCESS)) - self.failUnlessEqual(ev[3][0:3], - ("builderChangedState", "dummy", "idle")) - - self.failUnlessEqual([ev[0] for ev in self.t3.events], - ["builderAdded", - "builderChangedState", # offline - "builderAdded", - "builderChangedState", # idle - "builderChangedState", # offline - "builderChangedState", # idle - "builderChangedState", # building - "buildStarted", - "stepStarted", "stepETAUpdate", "stepFinished", - "stepStarted", "stepETAUpdate", - "logStarted", "logFinished", "stepFinished", - "buildFinished", - "builderChangedState", # idle - ]) - - b = self.s1.getLastFinishedBuild() - self.failUnless(b) - self.failUnlessEqual(b.getBuilder().getName(), "dummy") - self.failUnlessEqual(b.getNumber(), 0) - self.failUnlessEqual(b.getSourceStamp().branch, None) - self.failUnlessEqual(b.getSourceStamp().patch, None) - self.failUnlessEqual(b.getSourceStamp().revision, None) - self.failUnlessEqual(b.getReason(), "forced build for testing") - self.failUnlessEqual(b.getChanges(), ()) - self.failUnlessEqual(b.getResponsibleUsers(), []) - self.failUnless(b.isFinished()) - self.failUnlessEqual(b.getText(), ['build', 'successful']) - self.failUnlessEqual(b.getColor(), "green") - self.failUnlessEqual(b.getResults(), builder.SUCCESS) - - steps = b.getSteps() - self.failUnlessEqual(len(steps), 2) - - eta = 0 - st1 = steps[0] - self.failUnlessEqual(st1.getName(), "dummy") - self.failUnless(st1.isFinished()) - self.failUnlessEqual(st1.getText(), ["delay", "1 secs"]) - start,finish = st1.getTimes() - self.failUnless(0.5 < (finish-start) < 10) - self.failUnlessEqual(st1.getExpectations(), []) - self.failUnlessEqual(st1.getLogs(), []) - eta += finish-start - - st2 = steps[1] - self.failUnlessEqual(st2.getName(), "remote dummy") - self.failUnless(st2.isFinished()) - self.failUnlessEqual(st2.getText(), - ["remote", "delay", "2 secs"]) - start,finish = st2.getTimes() - self.failUnless(1.5 < (finish-start) < 10) - eta += finish-start - self.failUnlessEqual(st2.getExpectations(), [('output', 38, None)]) - logs = st2.getLogs() - self.failUnlessEqual(len(logs), 1) - self.failUnlessEqual(logs[0].getName(), "stdio") - self.failUnlessEqual(logs[0].getText(), "data") - - self.eta = eta - # now we run it a second time, and we should have an ETA - - self.t4 = t4 = STarget(["builder", "build", "eta"]) - self.master.getStatus().subscribe(t4) - c = interfaces.IControl(self.master) - req = BuildRequest("forced build for testing", SourceStamp()) - c.getBuilder("dummy").requestBuild(req) - d = req.waitUntilFinished() - d2 = self.master.botmaster.waitUntilBuilderIdle("dummy") - dl = defer.DeferredList([d, d2]) - dl.addCallback(self._testSlave_3) - return dl - - def _testSlave_3(self, res): - t4 = self.t4 - eta = self.eta - self.failUnless(eta-1 < t4.eta_build < eta+1, # should be 3 seconds - "t4.eta_build was %g, not in (%g,%g)" - % (t4.eta_build, eta-1, eta+1)) - - -class Client(unittest.TestCase): - def testAdaptation(self): - b = builder.BuilderStatus("bname") - b2 = client.makeRemote(b) - self.failUnless(isinstance(b2, client.RemoteBuilder)) - b3 = client.makeRemote(None) - self.failUnless(b3 is None) - - -class ContactTester(unittest.TestCase): - def test_notify_invalid_syntax(self): - irc = MyContact() - self.assertRaises(words.UsageError, lambda args, who: irc.command_NOTIFY(args, who), "", "mynick") - - def test_notify_list(self): - irc = MyContact() - irc.command_NOTIFY("list", "mynick") - self.failUnlessEqual(irc.message, "The following events are being notified: []", "empty notify list") - - irc.message = "" - irc.command_NOTIFY("on started", "mynick") - self.failUnlessEqual(irc.message, "The following events are being notified: ['started']", "on started") - - irc.message = "" - irc.command_NOTIFY("on finished", "mynick") - self.failUnlessEqual(irc.message, "The following events are being notified: ['started', 'finished']", "on finished") - - irc.message = "" - irc.command_NOTIFY("off", "mynick") - self.failUnlessEqual(irc.message, "The following events are being notified: []", "off all") - - irc.message = "" - irc.command_NOTIFY("on", "mynick") - self.failUnlessEqual(irc.message, "The following events are being notified: ['started', 'finished']", "on default set") - - irc.message = "" - irc.command_NOTIFY("off started", "mynick") - self.failUnlessEqual(irc.message, "The following events are being notified: ['finished']", "off started") - - irc.message = "" - irc.command_NOTIFY("on success failed exception", "mynick") - self.failUnlessEqual(irc.message, "The following events are being notified: ['failed', 'finished', 'exception', 'success']", "on multiple events") - - def test_notification_default(self): - irc = MyContact() - - my_builder = MyBuilder("builder78") - my_build = MyIrcBuild(my_builder, 23, builder.SUCCESS) - - irc.buildStarted(my_builder.getName(), my_build) - self.failUnlessEqual(irc.message, "", "No notification with default settings") - - irc.buildFinished(my_builder.getName(), my_build, None) - self.failUnlessEqual(irc.message, "", "No notification with default settings") - - def test_notification_started(self): - irc = MyContact() - - my_builder = MyBuilder("builder78") - my_build = MyIrcBuild(my_builder, 23, builder.SUCCESS) - my_build.changes = ( - Change(who = 'author1', files = ['file1'], comments = 'comment1', revision = 123), - Change(who = 'author2', files = ['file2'], comments = 'comment2', revision = 456), - ) - - irc.command_NOTIFY("on started", "mynick") - - irc.message = "" - irc.buildStarted(my_builder.getName(), my_build) - self.failUnlessEqual(irc.message, "build #23 of builder78 started including [123, 456]", "Start notification generated with notify_events=['started']") - - irc.message = "" - irc.buildFinished(my_builder.getName(), my_build, None) - self.failUnlessEqual(irc.message, "", "No finished notification with notify_events=['started']") - - def test_notification_finished(self): - irc = MyContact() - - my_builder = MyBuilder("builder834") - my_build = MyIrcBuild(my_builder, 862, builder.SUCCESS) - my_build.changes = ( - Change(who = 'author1', files = ['file1'], comments = 'comment1', revision = 943), - ) - - irc.command_NOTIFY("on finished", "mynick") - - irc.message = "" - irc.buildStarted(my_builder.getName(), my_build) - self.failUnlessEqual(irc.message, "", "No started notification with notify_events=['finished']") - - irc.message = "" - irc.buildFinished(my_builder.getName(), my_build, None) - self.failUnlessEqual(irc.message, "build #862 of builder834 is complete: Success [step1 step2] Build details are at http://myserver/mypath?build=765", "Finish notification generated with notify_events=['finished']") - - def test_notification_success(self): - irc = MyContact() - - my_builder = MyBuilder("builder834") - my_build = MyIrcBuild(my_builder, 862, builder.SUCCESS) - my_build.changes = ( - Change(who = 'author1', files = ['file1'], comments = 'comment1', revision = 943), - ) - - irc.command_NOTIFY("on success", "mynick") - - irc.message = "" - irc.buildStarted(my_builder.getName(), my_build) - self.failUnlessEqual(irc.message, "", "No started notification with notify_events=['success']") - - irc.message = "" - irc.buildFinished(my_builder.getName(), my_build, None) - self.failUnlessEqual(irc.message, "build #862 of builder834 is complete: Success [step1 step2] Build details are at http://myserver/mypath?build=765", "Finish notification generated on success with notify_events=['success']") - - irc.message = "" - my_build.results = builder.FAILURE - irc.buildFinished(my_builder.getName(), my_build, None) - self.failUnlessEqual(irc.message, "", "No finish notification generated on failure with notify_events=['success']") - - irc.message = "" - my_build.results = builder.EXCEPTION - irc.buildFinished(my_builder.getName(), my_build, None) - self.failUnlessEqual(irc.message, "", "No finish notification generated on exception with notify_events=['success']") - - def test_notification_failed(self): - irc = MyContact() - - my_builder = MyBuilder("builder834") - my_build = MyIrcBuild(my_builder, 862, builder.FAILURE) - my_build.changes = ( - Change(who = 'author1', files = ['file1'], comments = 'comment1', revision = 943), - ) - - irc.command_NOTIFY("on failed", "mynick") - - irc.message = "" - irc.buildStarted(my_builder.getName(), my_build) - self.failUnlessEqual(irc.message, "", "No started notification with notify_events=['failed']") - - irc.message = "" - irc.buildFinished(my_builder.getName(), my_build, None) - self.failUnlessEqual(irc.message, "build #862 of builder834 is complete: Failure [step1 step2] Build details are at http://myserver/mypath?build=765", "Finish notification generated on failure with notify_events=['failed']") - - irc.message = "" - my_build.results = builder.SUCCESS - irc.buildFinished(my_builder.getName(), my_build, None) - self.failUnlessEqual(irc.message, "", "No finish notification generated on success with notify_events=['failed']") - - irc.message = "" - my_build.results = builder.EXCEPTION - irc.buildFinished(my_builder.getName(), my_build, None) - self.failUnlessEqual(irc.message, "", "No finish notification generated on exception with notify_events=['failed']") - - def test_notification_exception(self): - irc = MyContact() - - my_builder = MyBuilder("builder834") - my_build = MyIrcBuild(my_builder, 862, builder.EXCEPTION) - my_build.changes = ( - Change(who = 'author1', files = ['file1'], comments = 'comment1', revision = 943), - ) - - irc.command_NOTIFY("on exception", "mynick") - - irc.message = "" - irc.buildStarted(my_builder.getName(), my_build) - self.failUnlessEqual(irc.message, "", "No started notification with notify_events=['exception']") - - irc.message = "" - irc.buildFinished(my_builder.getName(), my_build, None) - self.failUnlessEqual(irc.message, "build #862 of builder834 is complete: Exception [step1 step2] Build details are at http://myserver/mypath?build=765", "Finish notification generated on failure with notify_events=['exception']") - - irc.message = "" - my_build.results = builder.SUCCESS - irc.buildFinished(my_builder.getName(), my_build, None) - self.failUnlessEqual(irc.message, "", "No finish notification generated on success with notify_events=['exception']") - - irc.message = "" - my_build.results = builder.FAILURE - irc.buildFinished(my_builder.getName(), my_build, None) - self.failUnlessEqual(irc.message, "", "No finish notification generated on exception with notify_events=['exception']") - -class MyIrcBuild(builder.BuildStatus): - results = None - - def __init__(self, parent, number, results): - builder.BuildStatus.__init__(self, parent, number) - self.results = results - - def getResults(self): - return self.results - - def getText(self): - return ('step1', 'step2') - -class URLProducer: - def getURLForThing(self, build): - return 'http://myserver/mypath?build=765' - -class MyChannel: - categories = None - status = URLProducer() - - def __init__(self): - pass - -class MyContact(words.Contact): - message = "" - - def __init__(self, channel = MyChannel()): - words.Contact.__init__(self, channel) - self.message = "" - - def subscribe_to_build_events(self): - pass - - def unsubscribe_from_build_events(self): - pass - - def send(self, msg): - self.message += msg - -class StepStatistics(unittest.TestCase): - def testStepStatistics(self): - status = builder.BuildStatus(builder.BuilderStatus("test"), 123) - status.addStepWithName('step1') - status.addStepWithName('step2') - status.addStepWithName('step3') - status.addStepWithName('step4') - - steps = status.getSteps() - (step1, step2, step3, step4) = steps - - step1.setStatistic('test-prop', 1) - step3.setStatistic('test-prop', 2) - step4.setStatistic('test-prop', 4) - - step1.setStatistic('other-prop', 27) - # Just to have some other properties around - - self.failUnlessEqual(step1.getStatistic('test-prop'), 1, - 'Retrieve an existing property') - self.failUnlessEqual(step1.getStatistic('test-prop', 99), 1, - "Don't default an existing property") - self.failUnlessEqual(step2.getStatistic('test-prop', 99), 99, - 'Default a non-existant property') - - self.failUnlessEqual( - status.getSummaryStatistic('test-prop', operator.add), 7, - 'Sum property across the build') - - self.failUnlessEqual( - status.getSummaryStatistic('test-prop', operator.add, 13), 20, - 'Sum property across the build with initial value') diff --git a/tools/buildbot/pylibs/buildbot/test/test_steps.py b/tools/buildbot/pylibs/buildbot/test/test_steps.py deleted file mode 100644 index 8809db6..0000000 --- a/tools/buildbot/pylibs/buildbot/test/test_steps.py +++ /dev/null @@ -1,678 +0,0 @@ -# -*- test-case-name: buildbot.test.test_steps -*- - -# create the BuildStep with a fake .remote instance that logs the -# .callRemote invocations and compares them against the expected calls. Then -# the test harness should send statusUpdate() messages in with assorted -# data, eventually calling remote_complete(). Then we can verify that the -# Step's rc was correct, and that the status it was supposed to return -# matches. - -# sometimes, .callRemote should raise an exception because of a stale -# reference. Sometimes it should errBack with an UnknownCommand failure. -# Or other failure. - -# todo: test batched updates, by invoking remote_update(updates) instead of -# statusUpdate(update). Also involves interrupted builds. - -import os - -from twisted.trial import unittest -from twisted.internet import reactor, defer - -from buildbot.sourcestamp import SourceStamp -from buildbot.process import buildstep, base, factory -from buildbot.buildslave import BuildSlave -from buildbot.steps import shell, source, python -from buildbot.status import builder -from buildbot.status.builder import SUCCESS, WARNINGS, FAILURE -from buildbot.test.runutils import RunMixin, rmtree -from buildbot.test.runutils import makeBuildStep, StepTester -from buildbot.slave import commands, registry - - -class MyShellCommand(shell.ShellCommand): - started = False - def runCommand(self, c): - self.started = True - self.rc = c - return shell.ShellCommand.runCommand(self, c) - -class FakeBuild: - pass -class FakeBuilder: - statusbag = None - name = "fakebuilder" -class FakeSlaveBuilder: - def getSlaveCommandVersion(self, command, oldversion=None): - return "1.10" - -class FakeRemote: - def __init__(self): - self.events = [] - self.remoteCalls = 0 - #self.callRemoteNotifier = None - def callRemote(self, methname, *args): - event = ["callRemote", methname, args] - self.events.append(event) -## if self.callRemoteNotifier: -## reactor.callLater(0, self.callRemoteNotifier, event) - self.remoteCalls += 1 - self.deferred = defer.Deferred() - return self.deferred - def notifyOnDisconnect(self, callback): - pass - def dontNotifyOnDisconnect(self, callback): - pass - - -class BuildStep(unittest.TestCase): - - def setUp(self): - rmtree("test_steps") - self.builder = FakeBuilder() - self.builder_status = builder.BuilderStatus("fakebuilder") - self.builder_status.basedir = "test_steps" - self.builder_status.nextBuildNumber = 0 - os.mkdir(self.builder_status.basedir) - self.build_status = self.builder_status.newBuild() - req = base.BuildRequest("reason", SourceStamp()) - self.build = base.Build([req]) - self.build.build_status = self.build_status # fake it - self.build.builder = self.builder - self.build.slavebuilder = FakeSlaveBuilder() - self.remote = FakeRemote() - self.finished = 0 - - def callback(self, results): - self.failed = 0 - self.failure = None - self.results = results - self.finished = 1 - def errback(self, failure): - self.failed = 1 - self.failure = failure - self.results = None - self.finished = 1 - - def testShellCommand1(self): - cmd = "argle bargle" - dir = "murkle" - self.expectedEvents = [] - buildstep.RemoteCommand.commandCounter[0] = 3 - c = MyShellCommand(workdir=dir, command=cmd, timeout=10) - c.setBuild(self.build) - c.setBuildSlave(BuildSlave("name", "password")) - self.assertEqual(self.remote.events, self.expectedEvents) - c.step_status = self.build_status.addStepWithName("myshellcommand") - d = c.startStep(self.remote) - self.failUnless(c.started) - d.addCallbacks(self.callback, self.errback) - d2 = self.poll() - d2.addCallback(self._testShellCommand1_2, c) - return d2 - testShellCommand1.timeout = 10 - - def poll(self, ignored=None): - # TODO: This is gross, but at least it's no longer using - # reactor.iterate() . Still, get rid of this some day soon. - if self.remote.remoteCalls == 0: - d = defer.Deferred() - d.addCallback(self.poll) - reactor.callLater(0.1, d.callback, None) - return d - return defer.succeed(None) - - def _testShellCommand1_2(self, res, c): - rc = c.rc - self.expectedEvents.append(["callRemote", "startCommand", - (rc, "3", - "shell", - {'command': "argle bargle", - 'workdir': "murkle", - 'want_stdout': 1, - 'want_stderr': 1, - 'logfiles': {}, - 'timeout': 10, - 'env': None}) ] ) - self.assertEqual(self.remote.events, self.expectedEvents) - - # we could do self.remote.deferred.errback(UnknownCommand) here. We - # could also do .callback(), but generally the master end silently - # ignores the slave's ack - - logs = c.step_status.getLogs() - for log in logs: - if log.getName() == "log": - break - - rc.remoteUpdate({'header': - "command 'argle bargle' in dir 'murkle'\n\n"}) - rc.remoteUpdate({'stdout': "foo\n"}) - self.assertEqual(log.getText(), "foo\n") - self.assertEqual(log.getTextWithHeaders(), - "command 'argle bargle' in dir 'murkle'\n\n" - "foo\n") - rc.remoteUpdate({'stderr': "bar\n"}) - self.assertEqual(log.getText(), "foo\nbar\n") - self.assertEqual(log.getTextWithHeaders(), - "command 'argle bargle' in dir 'murkle'\n\n" - "foo\nbar\n") - rc.remoteUpdate({'rc': 0}) - self.assertEqual(rc.rc, 0) - - rc.remote_complete() - # that should fire the Deferred - d = self.poll2() - d.addCallback(self._testShellCommand1_3) - return d - - def poll2(self, ignored=None): - if not self.finished: - d = defer.Deferred() - d.addCallback(self.poll2) - reactor.callLater(0.1, d.callback, None) - return d - return defer.succeed(None) - - def _testShellCommand1_3(self, res): - self.assertEqual(self.failed, 0) - self.assertEqual(self.results, 0) - - -class MyObserver(buildstep.LogObserver): - out = "" - def outReceived(self, data): - self.out = self.out + data - -class Steps(unittest.TestCase): - def testMultipleStepInstances(self): - steps = [ - (source.CVS, {'cvsroot': "root", 'cvsmodule': "module"}), - (shell.Configure, {'command': "./configure"}), - (shell.Compile, {'command': "make"}), - (shell.Compile, {'command': "make more"}), - (shell.Compile, {'command': "make evenmore"}), - (shell.Test, {'command': "make test"}), - (shell.Test, {'command': "make testharder"}), - ] - f = factory.ConfigurableBuildFactory(steps) - req = base.BuildRequest("reason", SourceStamp()) - b = f.newBuild([req]) - #for s in b.steps: print s.name - - def failUnlessClones(self, s1, attrnames): - f1 = s1.getStepFactory() - f,args = f1 - s2 = f(**args) - for name in attrnames: - self.failUnlessEqual(getattr(s1, name), getattr(s2, name)) - - def clone(self, s1): - f1 = s1.getStepFactory() - f,args = f1 - s2 = f(**args) - return s2 - - def testClone(self): - s1 = shell.ShellCommand(command=["make", "test"], - timeout=1234, - workdir="here", - description="yo", - descriptionDone="yoyo", - env={'key': 'value'}, - want_stdout=False, - want_stderr=False, - logfiles={"name": "filename"}, - ) - shellparms = (buildstep.BuildStep.parms + - ("remote_kwargs description descriptionDone " - "command logfiles").split() ) - self.failUnlessClones(s1, shellparms) - - - # test the various methods available to buildsteps - - def test_getProperty(self): - s = makeBuildStep("test_steps.Steps.test_getProperty") - bs = s.step_status.getBuild() - - s.setProperty("prop1", "value1", "test") - s.setProperty("prop2", "value2", "test") - self.failUnlessEqual(s.getProperty("prop1"), "value1") - self.failUnlessEqual(bs.getProperty("prop1"), "value1") - self.failUnlessEqual(s.getProperty("prop2"), "value2") - self.failUnlessEqual(bs.getProperty("prop2"), "value2") - s.setProperty("prop1", "value1a", "test") - self.failUnlessEqual(s.getProperty("prop1"), "value1a") - self.failUnlessEqual(bs.getProperty("prop1"), "value1a") - - - def test_addURL(self): - s = makeBuildStep("test_steps.Steps.test_addURL") - s.addURL("coverage", "http://coverage.example.org/target") - s.addURL("icon", "http://coverage.example.org/icon.png") - bs = s.step_status - links = bs.getURLs() - expected = {"coverage": "http://coverage.example.org/target", - "icon": "http://coverage.example.org/icon.png", - } - self.failUnlessEqual(links, expected) - - def test_addLog(self): - s = makeBuildStep("test_steps.Steps.test_addLog") - l = s.addLog("newlog") - l.addStdout("some stdout here") - l.finish() - bs = s.step_status - logs = bs.getLogs() - self.failUnlessEqual(len(logs), 1) - l1 = logs[0] - self.failUnlessEqual(l1.getText(), "some stdout here") - l1a = s.getLog("newlog") - self.failUnlessEqual(l1a.getText(), "some stdout here") - - def test_addHTMLLog(self): - s = makeBuildStep("test_steps.Steps.test_addHTMLLog") - l = s.addHTMLLog("newlog", "some html here") - bs = s.step_status - logs = bs.getLogs() - self.failUnlessEqual(len(logs), 1) - l1 = logs[0] - self.failUnless(isinstance(l1, builder.HTMLLogFile)) - self.failUnlessEqual(l1.getText(), "some html here") - - def test_addCompleteLog(self): - s = makeBuildStep("test_steps.Steps.test_addCompleteLog") - l = s.addCompleteLog("newlog", "some stdout here") - bs = s.step_status - logs = bs.getLogs() - self.failUnlessEqual(len(logs), 1) - l1 = logs[0] - self.failUnlessEqual(l1.getText(), "some stdout here") - l1a = s.getLog("newlog") - self.failUnlessEqual(l1a.getText(), "some stdout here") - - def test_addLogObserver(self): - s = makeBuildStep("test_steps.Steps.test_addLogObserver") - bss = s.step_status - o1,o2,o3 = MyObserver(), MyObserver(), MyObserver() - - # add the log before the observer - l1 = s.addLog("one") - l1.addStdout("onestuff") - s.addLogObserver("one", o1) - self.failUnlessEqual(o1.out, "onestuff") - l1.addStdout(" morestuff") - self.failUnlessEqual(o1.out, "onestuff morestuff") - - # add the observer before the log - s.addLogObserver("two", o2) - l2 = s.addLog("two") - l2.addStdout("twostuff") - self.failUnlessEqual(o2.out, "twostuff") - - # test more stuff about ShellCommands - - def test_description(self): - s = makeBuildStep("test_steps.Steps.test_description.1", - step_class=shell.ShellCommand, - workdir="dummy", - description=["list", "of", "strings"], - descriptionDone=["another", "list"]) - self.failUnlessEqual(s.description, ["list", "of", "strings"]) - self.failUnlessEqual(s.descriptionDone, ["another", "list"]) - - s = makeBuildStep("test_steps.Steps.test_description.2", - step_class=shell.ShellCommand, - workdir="dummy", - description="single string", - descriptionDone="another string") - self.failUnlessEqual(s.description, ["single string"]) - self.failUnlessEqual(s.descriptionDone, ["another string"]) - -class VersionCheckingStep(buildstep.BuildStep): - def start(self): - # give our test a chance to run. It is non-trivial for a buildstep to - # claw its way back out to the test case which is currently running. - master = self.build.builder.botmaster.parent - checker = master._checker - checker(self) - # then complete - self.finished(buildstep.SUCCESS) - -version_config = """ -from buildbot.process import factory -from buildbot.test.test_steps import VersionCheckingStep -from buildbot.buildslave import BuildSlave -BuildmasterConfig = c = {} -f1 = factory.BuildFactory([ - factory.s(VersionCheckingStep), - ]) -c['slaves'] = [BuildSlave('bot1', 'sekrit')] -c['schedulers'] = [] -c['builders'] = [{'name':'quick', 'slavename':'bot1', - 'builddir': 'quickdir', 'factory': f1}] -c['slavePortnum'] = 0 -""" - -class SlaveVersion(RunMixin, unittest.TestCase): - def setUp(self): - RunMixin.setUp(self) - self.master.loadConfig(version_config) - self.master.startService() - d = self.connectSlave(["quick"]) - return d - - def doBuild(self, buildername): - br = base.BuildRequest("forced", SourceStamp()) - d = br.waitUntilFinished() - self.control.getBuilder(buildername).requestBuild(br) - return d - - - def checkCompare(self, s): - cver = commands.command_version - v = s.slaveVersion("svn", None) - # this insures that we are getting the version correctly - self.failUnlessEqual(s.slaveVersion("svn", None), cver) - # and that non-existent commands do not provide a version - self.failUnlessEqual(s.slaveVersion("NOSUCHCOMMAND"), None) - # TODO: verify that a <=0.5.0 buildslave (which does not implement - # remote_getCommands) handles oldversion= properly. This requires a - # mutant slave which does not offer that method. - #self.failUnlessEqual(s.slaveVersion("NOSUCHCOMMAND", "old"), "old") - - # now check the comparison functions - self.failIf(s.slaveVersionIsOlderThan("svn", cver)) - self.failIf(s.slaveVersionIsOlderThan("svn", "1.1")) - self.failUnless(s.slaveVersionIsOlderThan("svn", cver + ".1")) - - self.failUnlessEqual(s.getSlaveName(), "bot1") - - def testCompare(self): - self.master._checker = self.checkCompare - d = self.doBuild("quick") - return d - - -class _SimpleBuildStep(buildstep.BuildStep): - def start(self): - args = {"arg1": "value"} - cmd = buildstep.RemoteCommand("simple", args) - d = self.runCommand(cmd) - d.addCallback(lambda res: self.finished(SUCCESS)) - -class _SimpleCommand(commands.Command): - def start(self): - self.builder.flag = True - self.builder.flag_args = self.args - return defer.succeed(None) - -class CheckStepTester(StepTester, unittest.TestCase): - def testSimple(self): - self.slavebase = "testSimple.slave" - self.masterbase = "testSimple.master" - sb = self.makeSlaveBuilder() - sb.flag = False - registry.registerSlaveCommand("simple", _SimpleCommand, "1") - step = self.makeStep(_SimpleBuildStep) - d = self.runStep(step) - def _checkSimple(results): - self.failUnless(sb.flag) - self.failUnlessEqual(sb.flag_args, {"arg1": "value"}) - d.addCallback(_checkSimple) - return d - -class Python(StepTester, unittest.TestCase): - def testPyFlakes1(self): - self.masterbase = "Python.testPyFlakes1" - step = self.makeStep(python.PyFlakes) - output = \ -"""pyflakes buildbot -buildbot/changes/freshcvsmail.py:5: 'FCMaildirSource' imported but unused -buildbot/clients/debug.py:9: redefinition of unused 'gtk' from line 9 -buildbot/clients/debug.py:9: 'gnome' imported but unused -buildbot/scripts/runner.py:323: redefinition of unused 'run' from line 321 -buildbot/scripts/runner.py:325: redefinition of unused 'run' from line 323 -buildbot/scripts/imaginary.py:12: undefined name 'size' -buildbot/scripts/imaginary.py:18: 'from buildbot import *' used; unable to detect undefined names -""" - log = step.addLog("stdio") - log.addStdout(output) - log.finish() - step.createSummary(log) - desc = step.descriptionDone - self.failUnless("unused=2" in desc) - self.failUnless("undefined=1" in desc) - self.failUnless("redefs=3" in desc) - self.failUnless("import*=1" in desc) - self.failIf("misc=" in desc) - - self.failUnlessEqual(step.getProperty("pyflakes-unused"), 2) - self.failUnlessEqual(step.getProperty("pyflakes-undefined"), 1) - self.failUnlessEqual(step.getProperty("pyflakes-redefs"), 3) - self.failUnlessEqual(step.getProperty("pyflakes-import*"), 1) - self.failUnlessEqual(step.getProperty("pyflakes-misc"), 0) - self.failUnlessEqual(step.getProperty("pyflakes-total"), 7) - - logs = {} - for log in step.step_status.getLogs(): - logs[log.getName()] = log - - for name in ["unused", "undefined", "redefs", "import*"]: - self.failUnless(name in logs) - self.failIf("misc" in logs) - lines = logs["unused"].readlines() - self.failUnlessEqual(len(lines), 2) - self.failUnlessEqual(lines[0], "buildbot/changes/freshcvsmail.py:5: 'FCMaildirSource' imported but unused\n") - - cmd = buildstep.RemoteCommand(None, {}) - cmd.rc = 0 - results = step.evaluateCommand(cmd) - self.failUnlessEqual(results, FAILURE) # because of the 'undefined' - - def testPyFlakes2(self): - self.masterbase = "Python.testPyFlakes2" - step = self.makeStep(python.PyFlakes) - output = \ -"""pyflakes buildbot -some more text here that should be ignored -buildbot/changes/freshcvsmail.py:5: 'FCMaildirSource' imported but unused -buildbot/clients/debug.py:9: redefinition of unused 'gtk' from line 9 -buildbot/clients/debug.py:9: 'gnome' imported but unused -buildbot/scripts/runner.py:323: redefinition of unused 'run' from line 321 -buildbot/scripts/runner.py:325: redefinition of unused 'run' from line 323 -buildbot/scripts/imaginary.py:12: undefined name 'size' -could not compile 'blah/blah.py':3: -pretend there was an invalid line here -buildbot/scripts/imaginary.py:18: 'from buildbot import *' used; unable to detect undefined names -""" - log = step.addLog("stdio") - log.addStdout(output) - log.finish() - step.createSummary(log) - desc = step.descriptionDone - self.failUnless("unused=2" in desc) - self.failUnless("undefined=1" in desc) - self.failUnless("redefs=3" in desc) - self.failUnless("import*=1" in desc) - self.failUnless("misc=2" in desc) - - - def testPyFlakes3(self): - self.masterbase = "Python.testPyFlakes3" - step = self.makeStep(python.PyFlakes) - output = \ -"""buildbot/changes/freshcvsmail.py:5: 'FCMaildirSource' imported but unused -buildbot/clients/debug.py:9: redefinition of unused 'gtk' from line 9 -buildbot/clients/debug.py:9: 'gnome' imported but unused -buildbot/scripts/runner.py:323: redefinition of unused 'run' from line 321 -buildbot/scripts/runner.py:325: redefinition of unused 'run' from line 323 -buildbot/scripts/imaginary.py:12: undefined name 'size' -buildbot/scripts/imaginary.py:18: 'from buildbot import *' used; unable to detect undefined names -""" - log = step.addLog("stdio") - log.addStdout(output) - log.finish() - step.createSummary(log) - desc = step.descriptionDone - self.failUnless("unused=2" in desc) - self.failUnless("undefined=1" in desc) - self.failUnless("redefs=3" in desc) - self.failUnless("import*=1" in desc) - self.failIf("misc" in desc) - - -class OrdinaryCompile(shell.Compile): - warningPattern = "ordinary line" - -class Warnings(StepTester, unittest.TestCase): - def testCompile1(self): - self.masterbase = "Warnings.testCompile1" - step = self.makeStep(shell.Compile) - output = \ -"""Compile started -normal line -warning: oh noes! -ordinary line -error (but we aren't looking for errors now, are we) -line 23: warning: we are now on line 23 -ending line -""" - log = step.addLog("stdio") - log.addStdout(output) - log.finish() - step.createSummary(log) - self.failUnlessEqual(step.getProperty("warnings-count"), 2) - logs = {} - for log in step.step_status.getLogs(): - logs[log.getName()] = log - self.failUnless("warnings" in logs) - lines = logs["warnings"].readlines() - self.failUnlessEqual(len(lines), 2) - self.failUnlessEqual(lines[0], "warning: oh noes!\n") - self.failUnlessEqual(lines[1], - "line 23: warning: we are now on line 23\n") - - cmd = buildstep.RemoteCommand(None, {}) - cmd.rc = 0 - results = step.evaluateCommand(cmd) - self.failUnlessEqual(results, WARNINGS) - - def testCompile2(self): - self.masterbase = "Warnings.testCompile2" - step = self.makeStep(shell.Compile, warningPattern="ordinary line") - output = \ -"""Compile started -normal line -warning: oh noes! -ordinary line -error (but we aren't looking for errors now, are we) -line 23: warning: we are now on line 23 -ending line -""" - log = step.addLog("stdio") - log.addStdout(output) - log.finish() - step.createSummary(log) - self.failUnlessEqual(step.getProperty("warnings-count"), 1) - logs = {} - for log in step.step_status.getLogs(): - logs[log.getName()] = log - self.failUnless("warnings" in logs) - lines = logs["warnings"].readlines() - self.failUnlessEqual(len(lines), 1) - self.failUnlessEqual(lines[0], "ordinary line\n") - - cmd = buildstep.RemoteCommand(None, {}) - cmd.rc = 0 - results = step.evaluateCommand(cmd) - self.failUnlessEqual(results, WARNINGS) - - def testCompile3(self): - self.masterbase = "Warnings.testCompile3" - step = self.makeStep(OrdinaryCompile) - output = \ -"""Compile started -normal line -warning: oh noes! -ordinary line -error (but we aren't looking for errors now, are we) -line 23: warning: we are now on line 23 -ending line -""" - step.setProperty("warnings-count", 10, "test") - log = step.addLog("stdio") - log.addStdout(output) - log.finish() - step.createSummary(log) - self.failUnlessEqual(step.getProperty("warnings-count"), 11) - logs = {} - for log in step.step_status.getLogs(): - logs[log.getName()] = log - self.failUnless("warnings" in logs) - lines = logs["warnings"].readlines() - self.failUnlessEqual(len(lines), 1) - self.failUnlessEqual(lines[0], "ordinary line\n") - - cmd = buildstep.RemoteCommand(None, {}) - cmd.rc = 0 - results = step.evaluateCommand(cmd) - self.failUnlessEqual(results, WARNINGS) - - -class TreeSize(StepTester, unittest.TestCase): - def testTreeSize(self): - self.slavebase = "TreeSize.testTreeSize.slave" - self.masterbase = "TreeSize.testTreeSize.master" - - sb = self.makeSlaveBuilder() - step = self.makeStep(shell.TreeSize) - d = self.runStep(step) - def _check(results): - self.failUnlessEqual(results, SUCCESS) - kib = step.getProperty("tree-size-KiB") - self.failUnless(isinstance(kib, int)) - self.failUnless(kib < 100) # should be empty, I get '4' - s = step.step_status - self.failUnlessEqual(" ".join(s.getText()), - "treesize %d KiB" % kib) - d.addCallback(_check) - return d - -class PerlModuleTest(StepTester, unittest.TestCase): - def testAllTestsPassed(self): - self.masterbase = "Warnings.testAllTestsPassed" - step = self.makeStep(shell.PerlModuleTest) - output = \ -"""ok 1 -ok 2 -All tests successful -Files=1, Tests=123, other stuff -""" - log = step.addLog("stdio") - log.addStdout(output) - log.finish() - step.evaluateCommand(log) - ss = step.step_status - self.failUnlessEqual(ss.getStatistic('tests-failed'), 0) - self.failUnlessEqual(ss.getStatistic('tests-total'), 123) - self.failUnlessEqual(ss.getStatistic('tests-passed'), 123) - - def testFailures(self): - self.masterbase = "Warnings.testFailures" - step = self.makeStep(shell.PerlModuleTest) - output = \ -""" -ok 1 -ok 2 -3/7 subtests failed -""" - log = step.addLog("stdio") - log.addStdout(output) - log.finish() - step.evaluateCommand(log) - ss = step.step_status - self.failUnlessEqual(ss.getStatistic('tests-failed'), 3) - self.failUnlessEqual(ss.getStatistic('tests-total'), 7) - self.failUnlessEqual(ss.getStatistic('tests-passed'), 4) diff --git a/tools/buildbot/pylibs/buildbot/test/test_svnpoller.py b/tools/buildbot/pylibs/buildbot/test/test_svnpoller.py deleted file mode 100644 index 452a514..0000000 --- a/tools/buildbot/pylibs/buildbot/test/test_svnpoller.py +++ /dev/null @@ -1,476 +0,0 @@ -# -*- test-case-name: buildbot.test.test_svnpoller -*- - -import time -from twisted.internet import defer -from twisted.trial import unittest -from buildbot.changes.svnpoller import SVNPoller - -# this is the output of "svn info --xml -# svn+ssh://svn.twistedmatrix.com/svn/Twisted/trunk" -prefix_output = """\ - - - -svn+ssh://svn.twistedmatrix.com/svn/Twisted/trunk - -svn+ssh://svn.twistedmatrix.com/svn/Twisted -bbbe8e31-12d6-0310-92fd-ac37d47ddeeb - - -jml -2006-10-01T02:37:34.063255Z - - - -""" - -# and this is "svn info --xml svn://svn.twistedmatrix.com/svn/Twisted". I -# think this is kind of a degenerate case.. it might even be a form of error. -prefix_output_2 = """\ - - - -""" - -# this is the svn info output for a local repository, svn info --xml -# file:///home/warner/stuff/Projects/BuildBot/trees/svnpoller/_trial_temp/test_vc/repositories/SVN-Repository -prefix_output_3 = """\ - - - -file:///home/warner/stuff/Projects/BuildBot/trees/svnpoller/_trial_temp/test_vc/repositories/SVN-Repository - -file:///home/warner/stuff/Projects/BuildBot/trees/svnpoller/_trial_temp/test_vc/repositories/SVN-Repository -c0f47ff4-ba1e-0410-96b5-d44cc5c79e7f - - -warner -2006-10-01T07:37:04.182499Z - - - -""" - -# % svn info --xml file:///home/warner/stuff/Projects/BuildBot/trees/svnpoller/_trial_temp/test_vc/repositories/SVN-Repository/sample/trunk - -prefix_output_4 = """\ - - - -file:///home/warner/stuff/Projects/BuildBot/trees/svnpoller/_trial_temp/test_vc/repositories/SVN-Repository/sample/trunk - -file:///home/warner/stuff/Projects/BuildBot/trees/svnpoller/_trial_temp/test_vc/repositories/SVN-Repository -c0f47ff4-ba1e-0410-96b5-d44cc5c79e7f - - -warner -2006-10-01T07:37:02.286440Z - - - -""" - - - -class ComputePrefix(unittest.TestCase): - def test1(self): - base = "svn+ssh://svn.twistedmatrix.com/svn/Twisted/trunk" - s = SVNPoller(base + "/") - self.failUnlessEqual(s.svnurl, base) # certify slash-stripping - prefix = s.determine_prefix(prefix_output) - self.failUnlessEqual(prefix, "trunk") - self.failUnlessEqual(s._prefix, prefix) - - def test2(self): - base = "svn+ssh://svn.twistedmatrix.com/svn/Twisted" - s = SVNPoller(base) - self.failUnlessEqual(s.svnurl, base) - prefix = s.determine_prefix(prefix_output_2) - self.failUnlessEqual(prefix, "") - - def test3(self): - base = "file:///home/warner/stuff/Projects/BuildBot/trees/svnpoller/_trial_temp/test_vc/repositories/SVN-Repository" - s = SVNPoller(base) - self.failUnlessEqual(s.svnurl, base) - prefix = s.determine_prefix(prefix_output_3) - self.failUnlessEqual(prefix, "") - - def test4(self): - base = "file:///home/warner/stuff/Projects/BuildBot/trees/svnpoller/_trial_temp/test_vc/repositories/SVN-Repository/sample/trunk" - s = SVNPoller(base) - self.failUnlessEqual(s.svnurl, base) - prefix = s.determine_prefix(prefix_output_4) - self.failUnlessEqual(prefix, "sample/trunk") - -# output from svn log on .../SVN-Repository/sample -# (so it includes trunk and branches) -sample_base = "file:///usr/home/warner/stuff/Projects/BuildBot/trees/misc/_trial_temp/test_vc/repositories/SVN-Repository/sample" -sample_logentries = [None] * 6 - -sample_logentries[5] = """\ - -warner -2006-10-01T19:35:16.165664Z - -/sample/branch/version.c - -revised_to_2 - -""" - -sample_logentries[4] = """\ - -warner -2006-10-01T19:35:16.165664Z - -/sample/branch - -revised_to_2 - -""" - -sample_logentries[3] = """\ - -warner -2006-10-01T19:35:16.165664Z - -/sample/trunk/version.c - -revised_to_2 - -""" - -sample_logentries[2] = """\ - -warner -2006-10-01T19:35:10.215692Z - -/sample/branch/main.c - -commit_on_branch - -""" - -sample_logentries[1] = """\ - -warner -2006-10-01T19:35:09.154973Z - -/sample/branch - -make_branch - -""" - -sample_logentries[0] = """\ - -warner -2006-10-01T19:35:08.642045Z - -/sample -/sample/trunk -/sample/trunk/subdir/subdir.c -/sample/trunk/main.c -/sample/trunk/version.c -/sample/trunk/subdir - -sample_project_files - -""" - -sample_info_output = """\ - - - -file:///usr/home/warner/stuff/Projects/BuildBot/trees/misc/_trial_temp/test_vc/repositories/SVN-Repository/sample - -file:///usr/home/warner/stuff/Projects/BuildBot/trees/misc/_trial_temp/test_vc/repositories/SVN-Repository -4f94adfc-c41e-0410-92d5-fbf86b7c7689 - - -warner -2006-10-01T19:35:16.165664Z - - - -""" - - -changes_output_template = """\ - - -%s -""" - -def make_changes_output(maxrevision): - # return what 'svn log' would have just after the given revision was - # committed - logs = sample_logentries[0:maxrevision] - assert len(logs) == maxrevision - logs.reverse() - output = changes_output_template % ("".join(logs)) - return output - -def split_file(path): - pieces = path.split("/") - if pieces[0] == "branch": - return "branch", "/".join(pieces[1:]) - if pieces[0] == "trunk": - return None, "/".join(pieces[1:]) - raise RuntimeError("there shouldn't be any files like %s" % path) - -class MySVNPoller(SVNPoller): - def __init__(self, *args, **kwargs): - SVNPoller.__init__(self, *args, **kwargs) - self.pending_commands = [] - self.finished_changes = [] - - def getProcessOutput(self, args): - d = defer.Deferred() - self.pending_commands.append((args, d)) - return d - - def submit_changes(self, changes): - self.finished_changes.extend(changes) - -class ComputeChanges(unittest.TestCase): - def test1(self): - base = "file:///home/warner/stuff/Projects/BuildBot/trees/svnpoller/_trial_temp/test_vc/repositories/SVN-Repository/sample" - s = SVNPoller(base) - s._prefix = "sample" - output = make_changes_output(4) - doc = s.parse_logs(output) - - newlast, logentries = s._filter_new_logentries(doc, 4) - self.failUnlessEqual(newlast, 4) - self.failUnlessEqual(len(logentries), 0) - - newlast, logentries = s._filter_new_logentries(doc, 3) - self.failUnlessEqual(newlast, 4) - self.failUnlessEqual(len(logentries), 1) - - newlast, logentries = s._filter_new_logentries(doc, 1) - self.failUnlessEqual(newlast, 4) - self.failUnlessEqual(len(logentries), 3) - - newlast, logentries = s._filter_new_logentries(doc, None) - self.failUnlessEqual(newlast, 4) - self.failUnlessEqual(len(logentries), 0) - - def testChanges(self): - base = "file:///home/warner/stuff/Projects/BuildBot/trees/svnpoller/_trial_temp/test_vc/repositories/SVN-Repository/sample" - s = SVNPoller(base, split_file=split_file) - s._prefix = "sample" - doc = s.parse_logs(make_changes_output(3)) - newlast, logentries = s._filter_new_logentries(doc, 1) - # so we see revisions 2 and 3 as being new - self.failUnlessEqual(newlast, 3) - changes = s.create_changes(logentries) - self.failUnlessEqual(len(changes), 2) - self.failUnlessEqual(changes[0].branch, "branch") - self.failUnlessEqual(changes[0].revision, '2') - self.failUnlessEqual(changes[1].branch, "branch") - self.failUnlessEqual(changes[1].files, ["main.c"]) - self.failUnlessEqual(changes[1].revision, '3') - - # and now pull in r4 - doc = s.parse_logs(make_changes_output(4)) - newlast, logentries = s._filter_new_logentries(doc, newlast) - self.failUnlessEqual(newlast, 4) - # so we see revision 4 as being new - changes = s.create_changes(logentries) - self.failUnlessEqual(len(changes), 1) - self.failUnlessEqual(changes[0].branch, None) - self.failUnlessEqual(changes[0].revision, '4') - self.failUnlessEqual(changes[0].files, ["version.c"]) - - # and now pull in r5 (should *not* create a change as it's a - # branch deletion - doc = s.parse_logs(make_changes_output(5)) - newlast, logentries = s._filter_new_logentries(doc, newlast) - self.failUnlessEqual(newlast, 5) - # so we see revision 5 as being new - changes = s.create_changes(logentries) - self.failUnlessEqual(len(changes), 0) - - # and now pull in r6 (should create a change as it's not - # deleting an entire branch - doc = s.parse_logs(make_changes_output(6)) - newlast, logentries = s._filter_new_logentries(doc, newlast) - self.failUnlessEqual(newlast, 6) - # so we see revision 6 as being new - changes = s.create_changes(logentries) - self.failUnlessEqual(len(changes), 1) - self.failUnlessEqual(changes[0].branch, 'branch') - self.failUnlessEqual(changes[0].revision, '6') - self.failUnlessEqual(changes[0].files, ["version.c"]) - - def testFirstTime(self): - base = "file:///home/warner/stuff/Projects/BuildBot/trees/svnpoller/_trial_temp/test_vc/repositories/SVN-Repository/sample" - s = SVNPoller(base, split_file=split_file) - s._prefix = "sample" - doc = s.parse_logs(make_changes_output(4)) - logentries = s.get_new_logentries(doc) - # SVNPoller ignores all changes that happened before it was started - self.failUnlessEqual(len(logentries), 0) - self.failUnlessEqual(s.last_change, 4) - -class Misc(unittest.TestCase): - def testAlreadyWorking(self): - base = "file:///home/warner/stuff/Projects/BuildBot/trees/svnpoller/_trial_temp/test_vc/repositories/SVN-Repository/sample" - s = MySVNPoller(base) - d = s.checksvn() - # the SVNPoller is now waiting for its getProcessOutput to finish - self.failUnlessEqual(s.overrun_counter, 0) - d2 = s.checksvn() - self.failUnlessEqual(s.overrun_counter, 1) - self.failUnlessEqual(len(s.pending_commands), 1) - - def testGetRoot(self): - base = "svn+ssh://svn.twistedmatrix.com/svn/Twisted/trunk" - s = MySVNPoller(base) - d = s.checksvn() - # the SVNPoller is now waiting for its getProcessOutput to finish - self.failUnlessEqual(len(s.pending_commands), 1) - self.failUnlessEqual(s.pending_commands[0][0], - ["info", "--xml", "--non-interactive", base]) - -def makeTime(timestring): - datefmt = '%Y/%m/%d %H:%M:%S' - when = time.mktime(time.strptime(timestring, datefmt)) - return when - - -class Everything(unittest.TestCase): - def test1(self): - s = MySVNPoller(sample_base, split_file=split_file) - d = s.checksvn() - # the SVNPoller is now waiting for its getProcessOutput to finish - self.failUnlessEqual(len(s.pending_commands), 1) - self.failUnlessEqual(s.pending_commands[0][0], - ["info", "--xml", "--non-interactive", - sample_base]) - d = s.pending_commands[0][1] - s.pending_commands.pop(0) - d.callback(sample_info_output) - # now it should be waiting for the 'svn log' command - self.failUnlessEqual(len(s.pending_commands), 1) - self.failUnlessEqual(s.pending_commands[0][0], - ["log", "--xml", "--verbose", "--non-interactive", - "--limit=100", sample_base]) - d = s.pending_commands[0][1] - s.pending_commands.pop(0) - d.callback(make_changes_output(1)) - # the command ignores the first batch of changes - self.failUnlessEqual(len(s.finished_changes), 0) - self.failUnlessEqual(s.last_change, 1) - - # now fire it again, nothing changing - d = s.checksvn() - self.failUnlessEqual(s.pending_commands[0][0], - ["log", "--xml", "--verbose", "--non-interactive", - "--limit=100", sample_base]) - d = s.pending_commands[0][1] - s.pending_commands.pop(0) - d.callback(make_changes_output(1)) - # nothing has changed - self.failUnlessEqual(len(s.finished_changes), 0) - self.failUnlessEqual(s.last_change, 1) - - # and again, with r2 this time - d = s.checksvn() - self.failUnlessEqual(s.pending_commands[0][0], - ["log", "--xml", "--verbose", "--non-interactive", - "--limit=100", sample_base]) - d = s.pending_commands[0][1] - s.pending_commands.pop(0) - d.callback(make_changes_output(2)) - # r2 should appear - self.failUnlessEqual(len(s.finished_changes), 1) - self.failUnlessEqual(s.last_change, 2) - - c = s.finished_changes[0] - self.failUnlessEqual(c.branch, "branch") - self.failUnlessEqual(c.revision, '2') - self.failUnlessEqual(c.files, ['']) - # TODO: this is what creating the branch looks like: a Change with a - # zero-length file. We should decide if we want filenames like this - # in the Change (and make sure nobody else gets confused by it) or if - # we want to strip them out. - self.failUnlessEqual(c.comments, "make_branch") - - # and again at r2, so nothing should change - d = s.checksvn() - self.failUnlessEqual(s.pending_commands[0][0], - ["log", "--xml", "--verbose", "--non-interactive", - "--limit=100", sample_base]) - d = s.pending_commands[0][1] - s.pending_commands.pop(0) - d.callback(make_changes_output(2)) - # nothing has changed - self.failUnlessEqual(len(s.finished_changes), 1) - self.failUnlessEqual(s.last_change, 2) - - # and again with both r3 and r4 appearing together - d = s.checksvn() - self.failUnlessEqual(s.pending_commands[0][0], - ["log", "--xml", "--verbose", "--non-interactive", - "--limit=100", sample_base]) - d = s.pending_commands[0][1] - s.pending_commands.pop(0) - d.callback(make_changes_output(4)) - self.failUnlessEqual(len(s.finished_changes), 3) - self.failUnlessEqual(s.last_change, 4) - - c3 = s.finished_changes[1] - self.failUnlessEqual(c3.branch, "branch") - self.failUnlessEqual(c3.revision, '3') - self.failUnlessEqual(c3.files, ["main.c"]) - self.failUnlessEqual(c3.comments, "commit_on_branch") - - c4 = s.finished_changes[2] - self.failUnlessEqual(c4.branch, None) - self.failUnlessEqual(c4.revision, '4') - self.failUnlessEqual(c4.files, ["version.c"]) - self.failUnlessEqual(c4.comments, "revised_to_2") - self.failUnless(abs(c4.when - time.time()) < 60) - - -# TODO: -# get coverage of split_file returning None -# point at a live SVN server for a little while diff --git a/tools/buildbot/pylibs/buildbot/test/test_transfer.py b/tools/buildbot/pylibs/buildbot/test/test_transfer.py deleted file mode 100644 index 283c057..0000000 --- a/tools/buildbot/pylibs/buildbot/test/test_transfer.py +++ /dev/null @@ -1,368 +0,0 @@ -# -*- test-case-name: buildbot.test.test_transfer -*- - -import os -from stat import ST_MODE -from twisted.trial import unittest -from buildbot.steps.transfer import FileUpload, FileDownload -from buildbot.test.runutils import StepTester -from buildbot.status.builder import SUCCESS, FAILURE - -# these steps pass a pb.Referenceable inside their arguments, so we have to -# catch and wrap them. If the LocalAsRemote wrapper were a proper membrane, -# we wouldn't have to do this. - -class Upload(StepTester, unittest.TestCase): - - def filterArgs(self, args): - if "writer" in args: - args["writer"] = self.wrap(args["writer"]) - return args - - def testSuccess(self): - self.slavebase = "Upload.testSuccess.slave" - self.masterbase = "Upload.testSuccess.master" - sb = self.makeSlaveBuilder() - os.mkdir(os.path.join(self.slavebase, self.slavebuilderbase, - "build")) - # the buildmaster normally runs chdir'ed into masterbase, so uploaded - # files will appear there. Under trial, we're chdir'ed into - # _trial_temp instead, so use a different masterdest= to keep the - # uploaded file in a test-local directory - masterdest = os.path.join(self.masterbase, "dest.text") - step = self.makeStep(FileUpload, - slavesrc="source.txt", - masterdest=masterdest) - slavesrc = os.path.join(self.slavebase, - self.slavebuilderbase, - "build", - "source.txt") - contents = "this is the source file\n" * 1000 - open(slavesrc, "w").write(contents) - f = open(masterdest, "w") - f.write("overwrite me\n") - f.close() - - d = self.runStep(step) - def _checkUpload(results): - step_status = step.step_status - #l = step_status.getLogs() - #if l: - # logtext = l[0].getText() - # print logtext - self.failUnlessEqual(results, SUCCESS) - self.failUnless(os.path.exists(masterdest)) - masterdest_contents = open(masterdest, "r").read() - self.failUnlessEqual(masterdest_contents, contents) - d.addCallback(_checkUpload) - return d - - def testMaxsize(self): - self.slavebase = "Upload.testMaxsize.slave" - self.masterbase = "Upload.testMaxsize.master" - sb = self.makeSlaveBuilder() - os.mkdir(os.path.join(self.slavebase, self.slavebuilderbase, - "build")) - masterdest = os.path.join(self.masterbase, "dest2.text") - step = self.makeStep(FileUpload, - slavesrc="source.txt", - masterdest=masterdest, - maxsize=12345) - slavesrc = os.path.join(self.slavebase, - self.slavebuilderbase, - "build", - "source.txt") - contents = "this is the source file\n" * 1000 - open(slavesrc, "w").write(contents) - f = open(masterdest, "w") - f.write("overwrite me\n") - f.close() - - d = self.runStep(step) - def _checkUpload(results): - step_status = step.step_status - #l = step_status.getLogs() - #if l: - # logtext = l[0].getText() - # print logtext - self.failUnlessEqual(results, FAILURE) - self.failUnless(os.path.exists(masterdest)) - masterdest_contents = open(masterdest, "r").read() - self.failUnlessEqual(len(masterdest_contents), 12345) - self.failUnlessEqual(masterdest_contents, contents[:12345]) - d.addCallback(_checkUpload) - return d - - def testMode(self): - self.slavebase = "Upload.testMode.slave" - self.masterbase = "Upload.testMode.master" - sb = self.makeSlaveBuilder() - os.mkdir(os.path.join(self.slavebase, self.slavebuilderbase, - "build")) - masterdest = os.path.join(self.masterbase, "dest3.text") - step = self.makeStep(FileUpload, - slavesrc="source.txt", - masterdest=masterdest, - mode=0755) - slavesrc = os.path.join(self.slavebase, - self.slavebuilderbase, - "build", - "source.txt") - contents = "this is the source file\n" - open(slavesrc, "w").write(contents) - f = open(masterdest, "w") - f.write("overwrite me\n") - f.close() - - d = self.runStep(step) - def _checkUpload(results): - step_status = step.step_status - #l = step_status.getLogs() - #if l: - # logtext = l[0].getText() - # print logtext - self.failUnlessEqual(results, SUCCESS) - self.failUnless(os.path.exists(masterdest)) - masterdest_contents = open(masterdest, "r").read() - self.failUnlessEqual(masterdest_contents, contents) - # and with 0777 to ignore sticky bits - dest_mode = os.stat(masterdest)[ST_MODE] & 0777 - self.failUnlessEqual(dest_mode, 0755, - "target mode was %o, we wanted %o" % - (dest_mode, 0755)) - d.addCallback(_checkUpload) - return d - - def testMissingFile(self): - self.slavebase = "Upload.testMissingFile.slave" - self.masterbase = "Upload.testMissingFile.master" - sb = self.makeSlaveBuilder() - step = self.makeStep(FileUpload, - slavesrc="MISSING.txt", - masterdest="dest.txt") - masterdest = os.path.join(self.masterbase, "dest4.txt") - - d = self.runStep(step) - def _checkUpload(results): - step_status = step.step_status - self.failUnlessEqual(results, FAILURE) - self.failIf(os.path.exists(masterdest)) - l = step_status.getLogs() - logtext = l[0].getText().strip() - self.failUnless(logtext.startswith("Cannot open file")) - self.failUnless(logtext.endswith("for upload")) - d.addCallback(_checkUpload) - return d - - def testLotsOfBlocks(self): - self.slavebase = "Upload.testLotsOfBlocks.slave" - self.masterbase = "Upload.testLotsOfBlocks.master" - sb = self.makeSlaveBuilder() - os.mkdir(os.path.join(self.slavebase, self.slavebuilderbase, - "build")) - # the buildmaster normally runs chdir'ed into masterbase, so uploaded - # files will appear there. Under trial, we're chdir'ed into - # _trial_temp instead, so use a different masterdest= to keep the - # uploaded file in a test-local directory - masterdest = os.path.join(self.masterbase, "dest.text") - step = self.makeStep(FileUpload, - slavesrc="source.txt", - masterdest=masterdest, - blocksize=15) - slavesrc = os.path.join(self.slavebase, - self.slavebuilderbase, - "build", - "source.txt") - contents = "".join(["this is the source file #%d\n" % i - for i in range(1000)]) - open(slavesrc, "w").write(contents) - f = open(masterdest, "w") - f.write("overwrite me\n") - f.close() - - d = self.runStep(step) - def _checkUpload(results): - step_status = step.step_status - #l = step_status.getLogs() - #if l: - # logtext = l[0].getText() - # print logtext - self.failUnlessEqual(results, SUCCESS) - self.failUnless(os.path.exists(masterdest)) - masterdest_contents = open(masterdest, "r").read() - self.failUnlessEqual(masterdest_contents, contents) - d.addCallback(_checkUpload) - return d - - -class Download(StepTester, unittest.TestCase): - - def filterArgs(self, args): - if "reader" in args: - args["reader"] = self.wrap(args["reader"]) - return args - - def testSuccess(self): - self.slavebase = "Download.testSuccess.slave" - self.masterbase = "Download.testSuccess.master" - sb = self.makeSlaveBuilder() - os.mkdir(os.path.join(self.slavebase, self.slavebuilderbase, - "build")) - mastersrc = os.path.join(self.masterbase, "source.text") - slavedest = os.path.join(self.slavebase, - self.slavebuilderbase, - "build", - "dest.txt") - step = self.makeStep(FileDownload, - mastersrc=mastersrc, - slavedest="dest.txt") - contents = "this is the source file\n" * 1000 # 24kb, so two blocks - open(mastersrc, "w").write(contents) - f = open(slavedest, "w") - f.write("overwrite me\n") - f.close() - - d = self.runStep(step) - def _checkDownload(results): - step_status = step.step_status - self.failUnlessEqual(results, SUCCESS) - self.failUnless(os.path.exists(slavedest)) - slavedest_contents = open(slavedest, "r").read() - self.failUnlessEqual(slavedest_contents, contents) - d.addCallback(_checkDownload) - return d - - def testMaxsize(self): - self.slavebase = "Download.testMaxsize.slave" - self.masterbase = "Download.testMaxsize.master" - sb = self.makeSlaveBuilder() - os.mkdir(os.path.join(self.slavebase, self.slavebuilderbase, - "build")) - mastersrc = os.path.join(self.masterbase, "source.text") - slavedest = os.path.join(self.slavebase, - self.slavebuilderbase, - "build", - "dest.txt") - step = self.makeStep(FileDownload, - mastersrc=mastersrc, - slavedest="dest.txt", - maxsize=12345) - contents = "this is the source file\n" * 1000 # 24kb, so two blocks - open(mastersrc, "w").write(contents) - f = open(slavedest, "w") - f.write("overwrite me\n") - f.close() - - d = self.runStep(step) - def _checkDownload(results): - step_status = step.step_status - # the file should be truncated, and the step a FAILURE - self.failUnlessEqual(results, FAILURE) - self.failUnless(os.path.exists(slavedest)) - slavedest_contents = open(slavedest, "r").read() - self.failUnlessEqual(len(slavedest_contents), 12345) - self.failUnlessEqual(slavedest_contents, contents[:12345]) - d.addCallback(_checkDownload) - return d - - def testMode(self): - self.slavebase = "Download.testMode.slave" - self.masterbase = "Download.testMode.master" - sb = self.makeSlaveBuilder() - os.mkdir(os.path.join(self.slavebase, self.slavebuilderbase, - "build")) - mastersrc = os.path.join(self.masterbase, "source.text") - slavedest = os.path.join(self.slavebase, - self.slavebuilderbase, - "build", - "dest.txt") - step = self.makeStep(FileDownload, - mastersrc=mastersrc, - slavedest="dest.txt", - mode=0755) - contents = "this is the source file\n" - open(mastersrc, "w").write(contents) - f = open(slavedest, "w") - f.write("overwrite me\n") - f.close() - - d = self.runStep(step) - def _checkDownload(results): - step_status = step.step_status - self.failUnlessEqual(results, SUCCESS) - self.failUnless(os.path.exists(slavedest)) - slavedest_contents = open(slavedest, "r").read() - self.failUnlessEqual(slavedest_contents, contents) - # and with 0777 to ignore sticky bits - dest_mode = os.stat(slavedest)[ST_MODE] & 0777 - self.failUnlessEqual(dest_mode, 0755, - "target mode was %o, we wanted %o" % - (dest_mode, 0755)) - d.addCallback(_checkDownload) - return d - - def testMissingFile(self): - self.slavebase = "Download.testMissingFile.slave" - self.masterbase = "Download.testMissingFile.master" - sb = self.makeSlaveBuilder() - os.mkdir(os.path.join(self.slavebase, self.slavebuilderbase, - "build")) - mastersrc = os.path.join(self.masterbase, "MISSING.text") - slavedest = os.path.join(self.slavebase, - self.slavebuilderbase, - "build", - "dest.txt") - step = self.makeStep(FileDownload, - mastersrc=mastersrc, - slavedest="dest.txt") - - d = self.runStep(step) - def _checkDownload(results): - step_status = step.step_status - self.failUnlessEqual(results, FAILURE) - self.failIf(os.path.exists(slavedest)) - l = step_status.getLogs() - logtext = l[0].getText().strip() - self.failUnless(logtext.endswith(" not available at master")) - d.addCallbacks(_checkDownload) - - return d - - def testLotsOfBlocks(self): - self.slavebase = "Download.testLotsOfBlocks.slave" - self.masterbase = "Download.testLotsOfBlocks.master" - sb = self.makeSlaveBuilder() - os.mkdir(os.path.join(self.slavebase, self.slavebuilderbase, - "build")) - mastersrc = os.path.join(self.masterbase, "source.text") - slavedest = os.path.join(self.slavebase, - self.slavebuilderbase, - "build", - "dest.txt") - step = self.makeStep(FileDownload, - mastersrc=mastersrc, - slavedest="dest.txt", - blocksize=15) - contents = "".join(["this is the source file #%d\n" % i - for i in range(1000)]) - open(mastersrc, "w").write(contents) - f = open(slavedest, "w") - f.write("overwrite me\n") - f.close() - - d = self.runStep(step) - def _checkDownload(results): - step_status = step.step_status - self.failUnlessEqual(results, SUCCESS) - self.failUnless(os.path.exists(slavedest)) - slavedest_contents = open(slavedest, "r").read() - self.failUnlessEqual(slavedest_contents, contents) - d.addCallback(_checkDownload) - return d - - -# TODO: -# test relative paths, ~/paths -# need to implement expanduser() for slave-side -# test error message when master-side file is in a missing directory -# remove workdir= default? - diff --git a/tools/buildbot/pylibs/buildbot/test/test_twisted.py b/tools/buildbot/pylibs/buildbot/test/test_twisted.py deleted file mode 100644 index 7b4f9bfb..0000000 --- a/tools/buildbot/pylibs/buildbot/test/test_twisted.py +++ /dev/null @@ -1,219 +0,0 @@ -# -*- test-case-name: buildbot.test.test_twisted -*- - -from twisted.trial import unittest - -from buildbot import interfaces -from buildbot.steps.python_twisted import countFailedTests -from buildbot.steps.python_twisted import Trial, TrialTestCaseCounter -from buildbot.status import builder - -noisy = 0 -if noisy: - from twisted.python.log import startLogging - import sys - startLogging(sys.stdout) - -out1 = """ -------------------------------------------------------------------------------- -Ran 13 tests in 1.047s - -OK -""" - -out2 = """ -------------------------------------------------------------------------------- -Ran 12 tests in 1.040s - -FAILED (failures=1) -""" - -out3 = """ - NotImplementedError -------------------------------------------------------------------------------- -Ran 13 tests in 1.042s - -FAILED (failures=1, errors=1) -""" - -out4 = """ -unparseable -""" - -out5 = """ - File "/usr/home/warner/stuff/python/twisted/Twisted-CVS/twisted/test/test_defer.py", line 79, in testTwoCallbacks - self.fail("just because") - File "/usr/home/warner/stuff/python/twisted/Twisted-CVS/twisted/trial/unittest.py", line 21, in fail - raise AssertionError, message - AssertionError: just because -unparseable -""" - -out6 = """ -=============================================================================== -SKIPPED: testProtocolLocalhost (twisted.flow.test.test_flow.FlowTest) -------------------------------------------------------------------------------- -XXX freezes, fixme -=============================================================================== -SKIPPED: testIPv6 (twisted.names.test.test_names.HostsTestCase) -------------------------------------------------------------------------------- -IPv6 support is not in our hosts resolver yet -=============================================================================== -EXPECTED FAILURE: testSlots (twisted.test.test_rebuild.NewStyleTestCase) -------------------------------------------------------------------------------- -Traceback (most recent call last): - File "/Users/buildbot/Buildbot/twisted/OSX-full2.3/Twisted/twisted/trial/unittest.py", line 240, in _runPhase - stage(*args, **kwargs) - File "/Users/buildbot/Buildbot/twisted/OSX-full2.3/Twisted/twisted/trial/unittest.py", line 262, in _main - self.runner(self.method) - File "/Users/buildbot/Buildbot/twisted/OSX-full2.3/Twisted/twisted/trial/runner.py", line 95, in runTest - method() - File "/Users/buildbot/Buildbot/twisted/OSX-full2.3/Twisted/twisted/test/test_rebuild.py", line 130, in testSlots - rebuild.updateInstance(self.m.SlottedClass()) - File "/Users/buildbot/Buildbot/twisted/OSX-full2.3/Twisted/twisted/python/rebuild.py", line 114, in updateInstance - self.__class__ = latestClass(self.__class__) -TypeError: __class__ assignment: 'SlottedClass' object layout differs from 'SlottedClass' -=============================================================================== -FAILURE: testBatchFile (twisted.conch.test.test_sftp.TestOurServerBatchFile) -------------------------------------------------------------------------------- -Traceback (most recent call last): - File "/Users/buildbot/Buildbot/twisted/OSX-full2.3/Twisted/twisted/trial/unittest.py", line 240, in _runPhase - stage(*args, **kwargs) - File "/Users/buildbot/Buildbot/twisted/OSX-full2.3/Twisted/twisted/trial/unittest.py", line 262, in _main - self.runner(self.method) - File "/Users/buildbot/Buildbot/twisted/OSX-full2.3/Twisted/twisted/trial/runner.py", line 95, in runTest - method() - File "/Users/buildbot/Buildbot/twisted/OSX-full2.3/Twisted/twisted/conch/test/test_sftp.py", line 450, in testBatchFile - self.failUnlessEqual(res[1:-2], ['testDirectory', 'testRemoveFile', 'testRenameFile', 'testfile1']) - File "/Users/buildbot/Buildbot/twisted/OSX-full2.3/Twisted/twisted/trial/unittest.py", line 115, in failUnlessEqual - raise FailTest, (msg or '%r != %r' % (first, second)) -FailTest: [] != ['testDirectory', 'testRemoveFile', 'testRenameFile', 'testfile1'] -------------------------------------------------------------------------------- -Ran 1454 tests in 911.579s - -FAILED (failures=2, skips=49, expectedFailures=9) -Exception exceptions.AttributeError: "'NoneType' object has no attribute 'StringIO'" in > ignored -""" - -class MyTrial(Trial): - def addTestResult(self, testname, results, text, logs): - self.results.append((testname, results, text, logs)) - def addCompleteLog(self, name, log): - pass - -class MyLogFile: - def __init__(self, text): - self.text = text - def getText(self): - return self.text - - -class Count(unittest.TestCase): - - def count(self, total, failures=0, errors=0, - expectedFailures=0, unexpectedSuccesses=0, skips=0): - d = { - 'total': total, - 'failures': failures, - 'errors': errors, - 'expectedFailures': expectedFailures, - 'unexpectedSuccesses': unexpectedSuccesses, - 'skips': skips, - } - return d - - def testCountFailedTests(self): - count = countFailedTests(out1) - self.assertEquals(count, self.count(total=13)) - count = countFailedTests(out2) - self.assertEquals(count, self.count(total=12, failures=1)) - count = countFailedTests(out3) - self.assertEquals(count, self.count(total=13, failures=1, errors=1)) - count = countFailedTests(out4) - self.assertEquals(count, self.count(total=None)) - count = countFailedTests(out5) - self.assertEquals(count, self.count(total=None)) - -class Counter(unittest.TestCase): - - def setProgress(self, metric, value): - self.progress = (metric, value) - - def testCounter(self): - self.progress = (None,None) - c = TrialTestCaseCounter() - c.setStep(self) - STDOUT = interfaces.LOG_CHANNEL_STDOUT - def add(text): - c.logChunk(None, None, None, STDOUT, text) - add("\n\n") - self.failUnlessEqual(self.progress, (None,None)) - add("bogus line\n") - self.failUnlessEqual(self.progress, (None,None)) - add("buildbot.test.test_config.ConfigTest.testBots ... [OK]\n") - self.failUnlessEqual(self.progress, ("tests", 1)) - add("buildbot.test.test_config.ConfigTest.tes") - self.failUnlessEqual(self.progress, ("tests", 1)) - add("tBuilders ... [OK]\n") - self.failUnlessEqual(self.progress, ("tests", 2)) - # confirm alternative delimiters work too.. ptys seem to emit - # something different - add("buildbot.test.test_config.ConfigTest.testIRC ... [OK]\r\n") - self.failUnlessEqual(self.progress, ("tests", 3)) - add("===============================================================================\n") - self.failUnlessEqual(self.progress, ("tests", 3)) - add("buildbot.test.test_config.IOnlyLookLikeA.testLine ... [OK]\n") - self.failUnlessEqual(self.progress, ("tests", 3)) - - - -class Parse(unittest.TestCase): - def failUnlessIn(self, substr, string): - self.failUnless(string.find(substr) != -1) - - def testParse(self): - t = MyTrial(build=None, workdir=".", testpath=None, testChanges=True) - t.results = [] - log = MyLogFile(out6) - t.createSummary(log) - - self.failUnlessEqual(len(t.results), 4) - r1, r2, r3, r4 = t.results - testname, results, text, logs = r1 - self.failUnlessEqual(testname, - ("twisted", "flow", "test", "test_flow", - "FlowTest", "testProtocolLocalhost")) - self.failUnlessEqual(results, builder.SKIPPED) - self.failUnlessEqual(text, ['skipped']) - self.failUnlessIn("XXX freezes, fixme", logs) - self.failUnless(logs.startswith("SKIPPED:")) - self.failUnless(logs.endswith("fixme\n")) - - testname, results, text, logs = r2 - self.failUnlessEqual(testname, - ("twisted", "names", "test", "test_names", - "HostsTestCase", "testIPv6")) - self.failUnlessEqual(results, builder.SKIPPED) - self.failUnlessEqual(text, ['skipped']) - self.failUnless(logs.startswith("SKIPPED: testIPv6")) - self.failUnless(logs.endswith("IPv6 support is not in our hosts resolver yet\n")) - - testname, results, text, logs = r3 - self.failUnlessEqual(testname, - ("twisted", "test", "test_rebuild", - "NewStyleTestCase", "testSlots")) - self.failUnlessEqual(results, builder.SUCCESS) - self.failUnlessEqual(text, ['expected', 'failure']) - self.failUnless(logs.startswith("EXPECTED FAILURE: ")) - self.failUnlessIn("\nTraceback ", logs) - self.failUnless(logs.endswith("layout differs from 'SlottedClass'\n")) - - testname, results, text, logs = r4 - self.failUnlessEqual(testname, - ("twisted", "conch", "test", "test_sftp", - "TestOurServerBatchFile", "testBatchFile")) - self.failUnlessEqual(results, builder.FAILURE) - self.failUnlessEqual(text, ['failure']) - self.failUnless(logs.startswith("FAILURE: ")) - self.failUnlessIn("Traceback ", logs) - self.failUnless(logs.endswith("'testRenameFile', 'testfile1']\n")) - diff --git a/tools/buildbot/pylibs/buildbot/test/test_util.py b/tools/buildbot/pylibs/buildbot/test/test_util.py deleted file mode 100644 index b375390..0000000 --- a/tools/buildbot/pylibs/buildbot/test/test_util.py +++ /dev/null @@ -1,26 +0,0 @@ -# -*- test-case-name: buildbot.test.test_util -*- - -from twisted.trial import unittest - -from buildbot import util - - -class Foo(util.ComparableMixin): - compare_attrs = ["a", "b"] - - def __init__(self, a, b, c): - self.a, self.b, self.c = a,b,c - - -class Bar(Foo, util.ComparableMixin): - compare_attrs = ["b", "c"] - -class Compare(unittest.TestCase): - def testCompare(self): - f1 = Foo(1, 2, 3) - f2 = Foo(1, 2, 4) - f3 = Foo(1, 3, 4) - b1 = Bar(1, 2, 3) - self.failUnless(f1 == f2) - self.failIf(f1 == f3) - self.failIf(f1 == b1) diff --git a/tools/buildbot/pylibs/buildbot/test/test_vc.py b/tools/buildbot/pylibs/buildbot/test/test_vc.py deleted file mode 100644 index ce86b58..0000000 --- a/tools/buildbot/pylibs/buildbot/test/test_vc.py +++ /dev/null @@ -1,2796 +0,0 @@ -# -*- test-case-name: buildbot.test.test_vc -*- - -import sys, os, time, re -from email.Utils import mktime_tz, parsedate_tz - -from twisted.trial import unittest -from twisted.internet import defer, reactor, utils, protocol, task, error -from twisted.python import failure -from twisted.python.procutils import which -from twisted.web import client, static, server - -#defer.Deferred.debug = True - -from twisted.python import log -#log.startLogging(sys.stderr) - -from buildbot import master, interfaces -from buildbot.slave import bot, commands -from buildbot.slave.commands import rmdirRecursive -from buildbot.status.builder import SUCCESS, FAILURE -from buildbot.process import base -from buildbot.steps import source -from buildbot.changes import changes -from buildbot.sourcestamp import SourceStamp -from buildbot.scripts import tryclient -from buildbot.test.runutils import SignalMixin, myGetProcessOutputAndValue - -#step.LoggedRemoteCommand.debug = True - -from twisted.internet.defer import waitForDeferred, deferredGenerator - -# Most of these tests (all but SourceStamp) depend upon having a set of -# repositories from which we can perform checkouts. These repositories are -# created by the setUp method at the start of each test class. In earlier -# versions these repositories were created offline and distributed with a -# separate tarball named 'buildbot-test-vc-1.tar.gz'. This is no longer -# necessary. - -# CVS requires a local file repository. Providing remote access is beyond -# the feasible abilities of this test program (needs pserver or ssh). - -# SVN requires a local file repository. To provide remote access over HTTP -# requires an apache server with DAV support and mod_svn, way beyond what we -# can test from here. - -# Arch and Darcs both allow remote (read-only) operation with any web -# server. We test both local file access and HTTP access (by spawning a -# small web server to provide access to the repository files while the test -# is running). - -# Perforce starts the daemon running on localhost. Unfortunately, it must -# use a predetermined Internet-domain port number, unless we want to go -# all-out: bind the listen socket ourselves and pretend to be inetd. - -config_vc = """ -from buildbot.process import factory -from buildbot.steps import source -from buildbot.buildslave import BuildSlave -s = factory.s - -f1 = factory.BuildFactory([ - %s, - ]) -c = {} -c['slaves'] = [BuildSlave('bot1', 'sekrit')] -c['schedulers'] = [] -c['builders'] = [{'name': 'vc', 'slavename': 'bot1', - 'builddir': 'vc-dir', 'factory': f1}] -c['slavePortnum'] = 0 -BuildmasterConfig = c -""" - -p0_diff = r""" -Index: subdir/subdir.c -=================================================================== -RCS file: /home/warner/stuff/Projects/BuildBot/code-arch/_trial_temp/test_vc/repositories/CVS-Repository/sample/subdir/subdir.c,v -retrieving revision 1.1.1.1 -diff -u -r1.1.1.1 subdir.c ---- subdir/subdir.c 14 Aug 2005 01:32:49 -0000 1.1.1.1 -+++ subdir/subdir.c 14 Aug 2005 01:36:15 -0000 -@@ -4,6 +4,6 @@ - int - main(int argc, const char *argv[]) - { -- printf("Hello subdir.\n"); -+ printf("Hello patched subdir.\n"); - return 0; - } -""" - -# this patch does not include the filename headers, so it is -# patchlevel-neutral -TRY_PATCH = ''' -@@ -5,6 +5,6 @@ - int - main(int argc, const char *argv[]) - { -- printf("Hello subdir.\\n"); -+ printf("Hello try.\\n"); - return 0; - } -''' - -MAIN_C = ''' -// this is main.c -#include - -int -main(int argc, const char *argv[]) -{ - printf("Hello world.\\n"); - return 0; -} -''' - -BRANCH_C = ''' -// this is main.c -#include - -int -main(int argc, const char *argv[]) -{ - printf("Hello branch.\\n"); - return 0; -} -''' - -VERSION_C = ''' -// this is version.c -#include - -int -main(int argc, const char *argv[]) -{ - printf("Hello world, version=%d\\n"); - return 0; -} -''' - -SUBDIR_C = ''' -// this is subdir/subdir.c -#include - -int -main(int argc, const char *argv[]) -{ - printf("Hello subdir.\\n"); - return 0; -} -''' - -TRY_C = ''' -// this is subdir/subdir.c -#include - -int -main(int argc, const char *argv[]) -{ - printf("Hello try.\\n"); - return 0; -} -''' - -def qw(s): - return s.split() - -class VCS_Helper: - # this is a helper class which keeps track of whether each VC system is - # available, and whether the repository for each has been created. There - # is one instance of this class, at module level, shared between all test - # cases. - - def __init__(self): - self._helpers = {} - self._isCapable = {} - self._excuses = {} - self._repoReady = {} - - def registerVC(self, name, helper): - self._helpers[name] = helper - self._repoReady[name] = False - - def skipIfNotCapable(self, name): - """Either return None, or raise SkipTest""" - d = self.capable(name) - def _maybeSkip(res): - if not res[0]: - raise unittest.SkipTest(res[1]) - d.addCallback(_maybeSkip) - return d - - def capable(self, name): - """Return a Deferred that fires with (True,None) if this host offers - the given VC tool, or (False,excuse) if it does not (and therefore - the tests should be skipped).""" - - if self._isCapable.has_key(name): - if self._isCapable[name]: - return defer.succeed((True,None)) - else: - return defer.succeed((False, self._excuses[name])) - d = defer.maybeDeferred(self._helpers[name].capable) - def _capable(res): - if res[0]: - self._isCapable[name] = True - else: - self._excuses[name] = res[1] - return res - d.addCallback(_capable) - return d - - def getHelper(self, name): - return self._helpers[name] - - def createRepository(self, name): - """Return a Deferred that fires when the repository is set up.""" - if self._repoReady[name]: - return defer.succeed(True) - d = self._helpers[name].createRepository() - def _ready(res): - self._repoReady[name] = True - d.addCallback(_ready) - return d - -VCS = VCS_Helper() - - -# the overall plan here: -# -# Each VC system is tested separately, all using the same source tree defined -# in the 'files' dictionary above. Each VC system gets its own TestCase -# subclass. The first test case that is run will create the repository during -# setUp(), making two branches: 'trunk' and 'branch'. The trunk gets a copy -# of all the files in 'files'. The variant of good.c is committed on the -# branch. -# -# then testCheckout is run, which does a number of checkout/clobber/update -# builds. These all use trunk r1. It then runs self.fix(), which modifies -# 'fixable.c', then performs another build and makes sure the tree has been -# updated. -# -# testBranch uses trunk-r1 and branch-r1, making sure that we clobber the -# tree properly when we switch between them -# -# testPatch does a trunk-r1 checkout and applies a patch. -# -# testTryGetPatch performs a trunk-r1 checkout, modifies some files, then -# verifies that tryclient.getSourceStamp figures out the base revision and -# what got changed. - - -# vc_create makes a repository at r1 with three files: main.c, version.c, and -# subdir/foo.c . It also creates a branch from r1 (called b1) in which main.c -# says "hello branch" instead of "hello world". self.trunk[] contains -# revision stamps for everything on the trunk, and self.branch[] does the -# same for the branch. - -# vc_revise() checks out a tree at HEAD, changes version.c, then checks it -# back in. The new version stamp is appended to self.trunk[]. The tree is -# removed afterwards. - -# vc_try_checkout(workdir, rev) checks out a tree at REV, then changes -# subdir/subdir.c to say 'Hello try' -# vc_try_finish(workdir) removes the tree and cleans up any VC state -# necessary (like deleting the Arch archive entry). - - -class BaseHelper: - def __init__(self): - self.trunk = [] - self.branch = [] - self.allrevs = [] - - def capable(self): - # this is also responsible for setting self.vcexe - raise NotImplementedError - - def createBasedir(self): - # you must call this from createRepository - self.repbase = os.path.abspath(os.path.join("test_vc", - "repositories")) - if not os.path.isdir(self.repbase): - os.makedirs(self.repbase) - - def createRepository(self): - # this will only be called once per process - raise NotImplementedError - - def populate(self, basedir): - if not os.path.exists(basedir): - os.makedirs(basedir) - os.makedirs(os.path.join(basedir, "subdir")) - open(os.path.join(basedir, "main.c"), "w").write(MAIN_C) - self.version = 1 - version_c = VERSION_C % self.version - open(os.path.join(basedir, "version.c"), "w").write(version_c) - open(os.path.join(basedir, "main.c"), "w").write(MAIN_C) - open(os.path.join(basedir, "subdir", "subdir.c"), "w").write(SUBDIR_C) - - def populate_branch(self, basedir): - open(os.path.join(basedir, "main.c"), "w").write(BRANCH_C) - - def addTrunkRev(self, rev): - self.trunk.append(rev) - self.allrevs.append(rev) - def addBranchRev(self, rev): - self.branch.append(rev) - self.allrevs.append(rev) - - def runCommand(self, basedir, command, failureIsOk=False, - stdin=None, env=None): - # all commands passed to do() should be strings or lists. If they are - # strings, none of the arguments may have spaces. This makes the - # commands less verbose at the expense of restricting what they can - # specify. - if type(command) not in (list, tuple): - command = command.split(" ") - DEBUG = False - if DEBUG: - print "do %s" % command - print " in basedir %s" % basedir - if stdin: - print " STDIN:\n", stdin, "\n--STDIN DONE" - - if not env: - env = os.environ.copy() - env['LC_ALL'] = "C" - d = myGetProcessOutputAndValue(command[0], command[1:], - env=env, path=basedir, - stdin=stdin) - def check((out, err, code)): - if DEBUG: - print - print "command was: %s" % command - if out: print "out: %s" % out - if err: print "err: %s" % err - print "code: %s" % code - if code != 0 and not failureIsOk: - log.msg("command %s finished with exit code %d" % - (command, code)) - log.msg(" and stdout %s" % (out,)) - log.msg(" and stderr %s" % (err,)) - raise RuntimeError("command %s finished with exit code %d" - % (command, code) - + ": see logs for stdout") - return out - d.addCallback(check) - return d - - def do(self, basedir, command, failureIsOk=False, stdin=None, env=None): - d = self.runCommand(basedir, command, failureIsOk=failureIsOk, - stdin=stdin, env=env) - return waitForDeferred(d) - - def dovc(self, basedir, command, failureIsOk=False, stdin=None, env=None): - """Like do(), but the VC binary will be prepended to COMMAND.""" - if isinstance(command, (str, unicode)): - command = self.vcexe + " " + command - else: - # command is a list - command = [self.vcexe] + command - return self.do(basedir, command, failureIsOk, stdin, env) - -class VCBase(SignalMixin): - metadir = None - createdRepository = False - master = None - slave = None - helper = None - httpServer = None - httpPort = None - skip = None - has_got_revision = False - has_got_revision_branches_are_merged = False # for SVN - - def failUnlessIn(self, substring, string, msg=None): - # trial provides a version of this that requires python-2.3 to test - # strings. - if msg is None: - msg = ("did not see the expected substring '%s' in string '%s'" % - (substring, string)) - self.failUnless(string.find(substring) != -1, msg) - - def setUp(self): - d = VCS.skipIfNotCapable(self.vc_name) - d.addCallback(self._setUp1) - return d - - def _setUp1(self, res): - self.helper = VCS.getHelper(self.vc_name) - - if os.path.exists("basedir"): - rmdirRecursive("basedir") - os.mkdir("basedir") - self.master = master.BuildMaster("basedir") - self.slavebase = os.path.abspath("slavebase") - if os.path.exists(self.slavebase): - rmdirRecursive(self.slavebase) - os.mkdir("slavebase") - - d = VCS.createRepository(self.vc_name) - return d - - def connectSlave(self): - port = self.master.slavePort._port.getHost().port - slave = bot.BuildSlave("localhost", port, "bot1", "sekrit", - self.slavebase, keepalive=0, usePTY=False) - self.slave = slave - slave.startService() - d = self.master.botmaster.waitUntilBuilderAttached("vc") - return d - - def loadConfig(self, config): - # reloading the config file causes a new 'listDirs' command to be - # sent to the slave. To synchronize on this properly, it is easiest - # to stop and restart the slave. - d = defer.succeed(None) - if self.slave: - d = self.master.botmaster.waitUntilBuilderDetached("vc") - self.slave.stopService() - d.addCallback(lambda res: self.master.loadConfig(config)) - d.addCallback(lambda res: self.connectSlave()) - return d - - def serveHTTP(self): - # launch an HTTP server to serve the repository files - self.root = static.File(self.helper.repbase) - self.site = server.Site(self.root) - self.httpServer = reactor.listenTCP(0, self.site) - self.httpPort = self.httpServer.getHost().port - - def doBuild(self, shouldSucceed=True, ss=None): - c = interfaces.IControl(self.master) - - if ss is None: - ss = SourceStamp() - #print "doBuild(ss: b=%s rev=%s)" % (ss.branch, ss.revision) - req = base.BuildRequest("test_vc forced build", ss) - d = req.waitUntilFinished() - c.getBuilder("vc").requestBuild(req) - d.addCallback(self._doBuild_1, shouldSucceed) - return d - def _doBuild_1(self, bs, shouldSucceed): - r = bs.getResults() - if r != SUCCESS and shouldSucceed: - print - print - if not bs.isFinished(): - print "Hey, build wasn't even finished!" - print "Build did not succeed:", r, bs.getText() - for s in bs.getSteps(): - for l in s.getLogs(): - print "--- START step %s / log %s ---" % (s.getName(), - l.getName()) - print l.getTextWithHeaders() - print "--- STOP ---" - print - self.fail("build did not succeed") - return bs - - def printLogs(self, bs): - for s in bs.getSteps(): - for l in s.getLogs(): - print "--- START step %s / log %s ---" % (s.getName(), - l.getName()) - print l.getTextWithHeaders() - print "--- STOP ---" - print - - def touch(self, d, f): - open(os.path.join(d,f),"w").close() - def shouldExist(self, *args): - target = os.path.join(*args) - self.failUnless(os.path.exists(target), - "expected to find %s but didn't" % target) - def shouldNotExist(self, *args): - target = os.path.join(*args) - self.failIf(os.path.exists(target), - "expected to NOT find %s, but did" % target) - def shouldContain(self, d, f, contents): - c = open(os.path.join(d, f), "r").read() - self.failUnlessIn(contents, c) - - def checkGotRevision(self, bs, expected): - if self.has_got_revision: - self.failUnlessEqual(bs.getProperty("got_revision"), str(expected)) - - def checkGotRevisionIsLatest(self, bs): - expected = self.helper.trunk[-1] - if self.has_got_revision_branches_are_merged: - expected = self.helper.allrevs[-1] - self.checkGotRevision(bs, expected) - - def do_vctest(self, testRetry=True): - vctype = self.vctype - args = self.helper.vcargs - m = self.master - self.vcdir = os.path.join(self.slavebase, "vc-dir", "source") - self.workdir = os.path.join(self.slavebase, "vc-dir", "build") - # woo double-substitution - s = "s(%s, timeout=200, workdir='build', mode='%%s'" % (vctype,) - for k,v in args.items(): - s += ", %s=%s" % (k, repr(v)) - s += ")" - config = config_vc % s - - m.loadConfig(config % 'clobber') - m.readConfig = True - m.startService() - - d = self.connectSlave() - d.addCallback(lambda res: log.msg("testing clobber")) - d.addCallback(self._do_vctest_clobber) - d.addCallback(lambda res: log.msg("doing update")) - d.addCallback(lambda res: self.loadConfig(config % 'update')) - d.addCallback(lambda res: log.msg("testing update")) - d.addCallback(self._do_vctest_update) - if testRetry: - d.addCallback(lambda res: log.msg("testing update retry")) - d.addCallback(self._do_vctest_update_retry) - d.addCallback(lambda res: log.msg("doing copy")) - d.addCallback(lambda res: self.loadConfig(config % 'copy')) - d.addCallback(lambda res: log.msg("testing copy")) - d.addCallback(self._do_vctest_copy) - d.addCallback(lambda res: log.msg("did copy test")) - if self.metadir: - d.addCallback(lambda res: log.msg("doing export")) - d.addCallback(lambda res: self.loadConfig(config % 'export')) - d.addCallback(lambda res: log.msg("testing export")) - d.addCallback(self._do_vctest_export) - d.addCallback(lambda res: log.msg("did export test")) - return d - - def _do_vctest_clobber(self, res): - d = self.doBuild() # initial checkout - d.addCallback(self._do_vctest_clobber_1) - return d - def _do_vctest_clobber_1(self, bs): - self.shouldExist(self.workdir, "main.c") - self.shouldExist(self.workdir, "version.c") - self.shouldExist(self.workdir, "subdir", "subdir.c") - if self.metadir: - self.shouldExist(self.workdir, self.metadir) - self.failUnlessEqual(bs.getProperty("revision"), None) - self.failUnlessEqual(bs.getProperty("branch"), None) - self.checkGotRevisionIsLatest(bs) - - self.touch(self.workdir, "newfile") - self.shouldExist(self.workdir, "newfile") - d = self.doBuild() # rebuild clobbers workdir - d.addCallback(self._do_vctest_clobber_2) - return d - def _do_vctest_clobber_2(self, res): - self.shouldNotExist(self.workdir, "newfile") - # do a checkout to a specific version. Mercurial-over-HTTP (when - # either client or server is older than hg-0.9.2) cannot do this - # directly, so it must checkout HEAD and then update back to the - # requested revision. - d = self.doBuild(ss=SourceStamp(revision=self.helper.trunk[0])) - d.addCallback(self._do_vctest_clobber_3) - return d - def _do_vctest_clobber_3(self, bs): - self.shouldExist(self.workdir, "main.c") - self.shouldExist(self.workdir, "version.c") - self.shouldExist(self.workdir, "subdir", "subdir.c") - if self.metadir: - self.shouldExist(self.workdir, self.metadir) - self.failUnlessEqual(bs.getProperty("revision"), self.helper.trunk[0] or None) - self.failUnlessEqual(bs.getProperty("branch"), None) - self.checkGotRevision(bs, self.helper.trunk[0]) - # leave the tree at HEAD - return self.doBuild() - - - def _do_vctest_update(self, res): - log.msg("_do_vctest_update") - d = self.doBuild() # rebuild with update - d.addCallback(self._do_vctest_update_1) - return d - def _do_vctest_update_1(self, bs): - log.msg("_do_vctest_update_1") - self.shouldExist(self.workdir, "main.c") - self.shouldExist(self.workdir, "version.c") - self.shouldContain(self.workdir, "version.c", - "version=%d" % self.helper.version) - if self.metadir: - self.shouldExist(self.workdir, self.metadir) - self.failUnlessEqual(bs.getProperty("revision"), None) - self.checkGotRevisionIsLatest(bs) - - self.touch(self.workdir, "newfile") - d = self.doBuild() # update rebuild leaves new files - d.addCallback(self._do_vctest_update_2) - return d - def _do_vctest_update_2(self, bs): - log.msg("_do_vctest_update_2") - self.shouldExist(self.workdir, "main.c") - self.shouldExist(self.workdir, "version.c") - self.touch(self.workdir, "newfile") - # now make a change to the repository and make sure we pick it up - d = self.helper.vc_revise() - d.addCallback(lambda res: self.doBuild()) - d.addCallback(self._do_vctest_update_3) - return d - def _do_vctest_update_3(self, bs): - log.msg("_do_vctest_update_3") - self.shouldExist(self.workdir, "main.c") - self.shouldExist(self.workdir, "version.c") - self.shouldContain(self.workdir, "version.c", - "version=%d" % self.helper.version) - self.shouldExist(self.workdir, "newfile") - self.failUnlessEqual(bs.getProperty("revision"), None) - self.checkGotRevisionIsLatest(bs) - - # now "update" to an older revision - d = self.doBuild(ss=SourceStamp(revision=self.helper.trunk[-2])) - d.addCallback(self._do_vctest_update_4) - return d - def _do_vctest_update_4(self, bs): - log.msg("_do_vctest_update_4") - self.shouldExist(self.workdir, "main.c") - self.shouldExist(self.workdir, "version.c") - self.shouldContain(self.workdir, "version.c", - "version=%d" % (self.helper.version-1)) - self.failUnlessEqual(bs.getProperty("revision"), - self.helper.trunk[-2] or None) - self.checkGotRevision(bs, self.helper.trunk[-2]) - - # now update to the newer revision - d = self.doBuild(ss=SourceStamp(revision=self.helper.trunk[-1])) - d.addCallback(self._do_vctest_update_5) - return d - def _do_vctest_update_5(self, bs): - log.msg("_do_vctest_update_5") - self.shouldExist(self.workdir, "main.c") - self.shouldExist(self.workdir, "version.c") - self.shouldContain(self.workdir, "version.c", - "version=%d" % self.helper.version) - self.failUnlessEqual(bs.getProperty("revision"), - self.helper.trunk[-1] or None) - self.checkGotRevision(bs, self.helper.trunk[-1]) - - - def _do_vctest_update_retry(self, res): - # certain local changes will prevent an update from working. The - # most common is to replace a file with a directory, or vice - # versa. The slave code should spot the failure and do a - # clobber/retry. - os.unlink(os.path.join(self.workdir, "main.c")) - os.mkdir(os.path.join(self.workdir, "main.c")) - self.touch(os.path.join(self.workdir, "main.c"), "foo") - self.touch(self.workdir, "newfile") - - d = self.doBuild() # update, but must clobber to handle the error - d.addCallback(self._do_vctest_update_retry_1) - return d - def _do_vctest_update_retry_1(self, bs): - # SVN-1.4.0 doesn't seem to have any problem with the - # file-turned-directory issue (although older versions did). So don't - # actually check that the tree was clobbered.. as long as the update - # succeeded (checked by doBuild), that should be good enough. - #self.shouldNotExist(self.workdir, "newfile") - pass - - def _do_vctest_copy(self, res): - log.msg("_do_vctest_copy 1") - d = self.doBuild() # copy rebuild clobbers new files - d.addCallback(self._do_vctest_copy_1) - return d - def _do_vctest_copy_1(self, bs): - log.msg("_do_vctest_copy 2") - if self.metadir: - self.shouldExist(self.workdir, self.metadir) - self.shouldNotExist(self.workdir, "newfile") - self.touch(self.workdir, "newfile") - self.touch(self.vcdir, "newvcfile") - self.failUnlessEqual(bs.getProperty("revision"), None) - self.checkGotRevisionIsLatest(bs) - - d = self.doBuild() # copy rebuild clobbers new files - d.addCallback(self._do_vctest_copy_2) - return d - def _do_vctest_copy_2(self, bs): - log.msg("_do_vctest_copy 3") - if self.metadir: - self.shouldExist(self.workdir, self.metadir) - self.shouldNotExist(self.workdir, "newfile") - self.shouldExist(self.vcdir, "newvcfile") - self.shouldExist(self.workdir, "newvcfile") - self.failUnlessEqual(bs.getProperty("revision"), None) - self.checkGotRevisionIsLatest(bs) - self.touch(self.workdir, "newfile") - - def _do_vctest_export(self, res): - d = self.doBuild() # export rebuild clobbers new files - d.addCallback(self._do_vctest_export_1) - return d - def _do_vctest_export_1(self, bs): - self.shouldNotExist(self.workdir, self.metadir) - self.shouldNotExist(self.workdir, "newfile") - self.failUnlessEqual(bs.getProperty("revision"), None) - #self.checkGotRevisionIsLatest(bs) - # VC 'export' is not required to have a got_revision - self.touch(self.workdir, "newfile") - - d = self.doBuild() # export rebuild clobbers new files - d.addCallback(self._do_vctest_export_2) - return d - def _do_vctest_export_2(self, bs): - self.shouldNotExist(self.workdir, self.metadir) - self.shouldNotExist(self.workdir, "newfile") - self.failUnlessEqual(bs.getProperty("revision"), None) - #self.checkGotRevisionIsLatest(bs) - # VC 'export' is not required to have a got_revision - - def do_patch(self): - vctype = self.vctype - args = self.helper.vcargs - m = self.master - self.vcdir = os.path.join(self.slavebase, "vc-dir", "source") - self.workdir = os.path.join(self.slavebase, "vc-dir", "build") - s = "s(%s, timeout=200, workdir='build', mode='%%s'" % (vctype,) - for k,v in args.items(): - s += ", %s=%s" % (k, repr(v)) - s += ")" - self.config = config_vc % s - - m.loadConfig(self.config % "clobber") - m.readConfig = True - m.startService() - - ss = SourceStamp(revision=self.helper.trunk[-1], patch=(0, p0_diff)) - - d = self.connectSlave() - d.addCallback(lambda res: self.doBuild(ss=ss)) - d.addCallback(self._doPatch_1) - return d - def _doPatch_1(self, bs): - self.shouldContain(self.workdir, "version.c", - "version=%d" % self.helper.version) - # make sure the file actually got patched - subdir_c = os.path.join(self.slavebase, "vc-dir", "build", - "subdir", "subdir.c") - data = open(subdir_c, "r").read() - self.failUnlessIn("Hello patched subdir.\\n", data) - self.failUnlessEqual(bs.getProperty("revision"), - self.helper.trunk[-1] or None) - self.checkGotRevision(bs, self.helper.trunk[-1]) - - # make sure that a rebuild does not use the leftover patched workdir - d = self.master.loadConfig(self.config % "update") - d.addCallback(lambda res: self.doBuild(ss=None)) - d.addCallback(self._doPatch_2) - return d - def _doPatch_2(self, bs): - # make sure the file is back to its original - subdir_c = os.path.join(self.slavebase, "vc-dir", "build", - "subdir", "subdir.c") - data = open(subdir_c, "r").read() - self.failUnlessIn("Hello subdir.\\n", data) - self.failUnlessEqual(bs.getProperty("revision"), None) - self.checkGotRevisionIsLatest(bs) - - # now make sure we can patch an older revision. We need at least two - # revisions here, so we might have to create one first - if len(self.helper.trunk) < 2: - d = self.helper.vc_revise() - d.addCallback(self._doPatch_3) - return d - return self._doPatch_3() - - def _doPatch_3(self, res=None): - ss = SourceStamp(revision=self.helper.trunk[-2], patch=(0, p0_diff)) - d = self.doBuild(ss=ss) - d.addCallback(self._doPatch_4) - return d - def _doPatch_4(self, bs): - self.shouldContain(self.workdir, "version.c", - "version=%d" % (self.helper.version-1)) - # and make sure the file actually got patched - subdir_c = os.path.join(self.slavebase, "vc-dir", "build", - "subdir", "subdir.c") - data = open(subdir_c, "r").read() - self.failUnlessIn("Hello patched subdir.\\n", data) - self.failUnlessEqual(bs.getProperty("revision"), - self.helper.trunk[-2] or None) - self.checkGotRevision(bs, self.helper.trunk[-2]) - - # now check that we can patch a branch - ss = SourceStamp(branch=self.helper.branchname, - revision=self.helper.branch[-1], - patch=(0, p0_diff)) - d = self.doBuild(ss=ss) - d.addCallback(self._doPatch_5) - return d - def _doPatch_5(self, bs): - self.shouldContain(self.workdir, "version.c", - "version=%d" % 1) - self.shouldContain(self.workdir, "main.c", "Hello branch.") - subdir_c = os.path.join(self.slavebase, "vc-dir", "build", - "subdir", "subdir.c") - data = open(subdir_c, "r").read() - self.failUnlessIn("Hello patched subdir.\\n", data) - self.failUnlessEqual(bs.getProperty("revision"), - self.helper.branch[-1] or None) - self.failUnlessEqual(bs.getProperty("branch"), self.helper.branchname or None) - self.checkGotRevision(bs, self.helper.branch[-1]) - - - def do_vctest_once(self, shouldSucceed): - m = self.master - vctype = self.vctype - args = self.helper.vcargs - vcdir = os.path.join(self.slavebase, "vc-dir", "source") - workdir = os.path.join(self.slavebase, "vc-dir", "build") - # woo double-substitution - s = "s(%s, timeout=200, workdir='build', mode='clobber'" % (vctype,) - for k,v in args.items(): - s += ", %s=%s" % (k, repr(v)) - s += ")" - config = config_vc % s - - m.loadConfig(config) - m.readConfig = True - m.startService() - - self.connectSlave() - d = self.doBuild(shouldSucceed) # initial checkout - return d - - def do_branch(self): - log.msg("do_branch") - vctype = self.vctype - args = self.helper.vcargs - m = self.master - self.vcdir = os.path.join(self.slavebase, "vc-dir", "source") - self.workdir = os.path.join(self.slavebase, "vc-dir", "build") - s = "s(%s, timeout=200, workdir='build', mode='%%s'" % (vctype,) - for k,v in args.items(): - s += ", %s=%s" % (k, repr(v)) - s += ")" - self.config = config_vc % s - - m.loadConfig(self.config % "update") - m.readConfig = True - m.startService() - - # first we do a build of the trunk - d = self.connectSlave() - d.addCallback(lambda res: self.doBuild(ss=SourceStamp())) - d.addCallback(self._doBranch_1) - return d - def _doBranch_1(self, bs): - log.msg("_doBranch_1") - # make sure the checkout was of the trunk - main_c = os.path.join(self.slavebase, "vc-dir", "build", "main.c") - data = open(main_c, "r").read() - self.failUnlessIn("Hello world.", data) - - # now do a checkout on the branch. The change in branch name should - # trigger a clobber. - self.touch(self.workdir, "newfile") - d = self.doBuild(ss=SourceStamp(branch=self.helper.branchname)) - d.addCallback(self._doBranch_2) - return d - def _doBranch_2(self, bs): - log.msg("_doBranch_2") - # make sure it was on the branch - main_c = os.path.join(self.slavebase, "vc-dir", "build", "main.c") - data = open(main_c, "r").read() - self.failUnlessIn("Hello branch.", data) - # and make sure the tree was clobbered - self.shouldNotExist(self.workdir, "newfile") - - # doing another build on the same branch should not clobber the tree - self.touch(self.workdir, "newbranchfile") - d = self.doBuild(ss=SourceStamp(branch=self.helper.branchname)) - d.addCallback(self._doBranch_3) - return d - def _doBranch_3(self, bs): - log.msg("_doBranch_3") - # make sure it is still on the branch - main_c = os.path.join(self.slavebase, "vc-dir", "build", "main.c") - data = open(main_c, "r").read() - self.failUnlessIn("Hello branch.", data) - # and make sure the tree was not clobbered - self.shouldExist(self.workdir, "newbranchfile") - - # now make sure that a non-branch checkout clobbers the tree - d = self.doBuild(ss=SourceStamp()) - d.addCallback(self._doBranch_4) - return d - def _doBranch_4(self, bs): - log.msg("_doBranch_4") - # make sure it was on the trunk - main_c = os.path.join(self.slavebase, "vc-dir", "build", "main.c") - data = open(main_c, "r").read() - self.failUnlessIn("Hello world.", data) - self.shouldNotExist(self.workdir, "newbranchfile") - - def do_getpatch(self, doBranch=True): - log.msg("do_getpatch") - # prepare a buildslave to do checkouts - vctype = self.vctype - args = self.helper.vcargs - m = self.master - self.vcdir = os.path.join(self.slavebase, "vc-dir", "source") - self.workdir = os.path.join(self.slavebase, "vc-dir", "build") - # woo double-substitution - s = "s(%s, timeout=200, workdir='build', mode='%%s'" % (vctype,) - for k,v in args.items(): - s += ", %s=%s" % (k, repr(v)) - s += ")" - config = config_vc % s - - m.loadConfig(config % 'clobber') - m.readConfig = True - m.startService() - - d = self.connectSlave() - - # then set up the "developer's tree". first we modify a tree from the - # head of the trunk - tmpdir = "try_workdir" - self.trydir = os.path.join(self.helper.repbase, tmpdir) - rmdirRecursive(self.trydir) - d.addCallback(self.do_getpatch_trunkhead) - d.addCallback(self.do_getpatch_trunkold) - if doBranch: - d.addCallback(self.do_getpatch_branch) - d.addCallback(self.do_getpatch_finish) - return d - - def do_getpatch_finish(self, res): - log.msg("do_getpatch_finish") - self.helper.vc_try_finish(self.trydir) - return res - - def try_shouldMatch(self, filename): - devfilename = os.path.join(self.trydir, filename) - devfile = open(devfilename, "r").read() - slavefilename = os.path.join(self.workdir, filename) - slavefile = open(slavefilename, "r").read() - self.failUnlessEqual(devfile, slavefile, - ("slavefile (%s) contains '%s'. " - "developer's file (%s) contains '%s'. " - "These ought to match") % - (slavefilename, slavefile, - devfilename, devfile)) - - def do_getpatch_trunkhead(self, res): - log.msg("do_getpatch_trunkhead") - d = self.helper.vc_try_checkout(self.trydir, self.helper.trunk[-1]) - d.addCallback(self._do_getpatch_trunkhead_1) - return d - def _do_getpatch_trunkhead_1(self, res): - log.msg("_do_getpatch_trunkhead_1") - d = tryclient.getSourceStamp(self.vctype_try, self.trydir, None) - d.addCallback(self._do_getpatch_trunkhead_2) - return d - def _do_getpatch_trunkhead_2(self, ss): - log.msg("_do_getpatch_trunkhead_2") - d = self.doBuild(ss=ss) - d.addCallback(self._do_getpatch_trunkhead_3) - return d - def _do_getpatch_trunkhead_3(self, res): - log.msg("_do_getpatch_trunkhead_3") - # verify that the resulting buildslave tree matches the developer's - self.try_shouldMatch("main.c") - self.try_shouldMatch("version.c") - self.try_shouldMatch(os.path.join("subdir", "subdir.c")) - - def do_getpatch_trunkold(self, res): - log.msg("do_getpatch_trunkold") - # now try a tree from an older revision. We need at least two - # revisions here, so we might have to create one first - if len(self.helper.trunk) < 2: - d = self.helper.vc_revise() - d.addCallback(self._do_getpatch_trunkold_1) - return d - return self._do_getpatch_trunkold_1() - def _do_getpatch_trunkold_1(self, res=None): - log.msg("_do_getpatch_trunkold_1") - d = self.helper.vc_try_checkout(self.trydir, self.helper.trunk[-2]) - d.addCallback(self._do_getpatch_trunkold_2) - return d - def _do_getpatch_trunkold_2(self, res): - log.msg("_do_getpatch_trunkold_2") - d = tryclient.getSourceStamp(self.vctype_try, self.trydir, None) - d.addCallback(self._do_getpatch_trunkold_3) - return d - def _do_getpatch_trunkold_3(self, ss): - log.msg("_do_getpatch_trunkold_3") - d = self.doBuild(ss=ss) - d.addCallback(self._do_getpatch_trunkold_4) - return d - def _do_getpatch_trunkold_4(self, res): - log.msg("_do_getpatch_trunkold_4") - # verify that the resulting buildslave tree matches the developer's - self.try_shouldMatch("main.c") - self.try_shouldMatch("version.c") - self.try_shouldMatch(os.path.join("subdir", "subdir.c")) - - def do_getpatch_branch(self, res): - log.msg("do_getpatch_branch") - # now try a tree from a branch - d = self.helper.vc_try_checkout(self.trydir, self.helper.branch[-1], - self.helper.branchname) - d.addCallback(self._do_getpatch_branch_1) - return d - def _do_getpatch_branch_1(self, res): - log.msg("_do_getpatch_branch_1") - d = tryclient.getSourceStamp(self.vctype_try, self.trydir, - self.helper.try_branchname) - d.addCallback(self._do_getpatch_branch_2) - return d - def _do_getpatch_branch_2(self, ss): - log.msg("_do_getpatch_branch_2") - d = self.doBuild(ss=ss) - d.addCallback(self._do_getpatch_branch_3) - return d - def _do_getpatch_branch_3(self, res): - log.msg("_do_getpatch_branch_3") - # verify that the resulting buildslave tree matches the developer's - self.try_shouldMatch("main.c") - self.try_shouldMatch("version.c") - self.try_shouldMatch(os.path.join("subdir", "subdir.c")) - - - def dumpPatch(self, patch): - # this exists to help me figure out the right 'patchlevel' value - # should be returned by tryclient.getSourceStamp - n = self.mktemp() - open(n,"w").write(patch) - d = self.runCommand(".", ["lsdiff", n]) - def p(res): print "lsdiff:", res.strip().split("\n") - d.addCallback(p) - return d - - - def tearDown(self): - d = defer.succeed(None) - if self.slave: - d2 = self.master.botmaster.waitUntilBuilderDetached("vc") - d.addCallback(lambda res: self.slave.stopService()) - d.addCallback(lambda res: d2) - if self.master: - d.addCallback(lambda res: self.master.stopService()) - if self.httpServer: - d.addCallback(lambda res: self.httpServer.stopListening()) - def stopHTTPTimer(): - from twisted.web import http - http._logDateTimeStop() # shut down the internal timer. DUMB! - d.addCallback(lambda res: stopHTTPTimer()) - d.addCallback(lambda res: self.tearDown2()) - return d - - def tearDown2(self): - pass - -class CVSHelper(BaseHelper): - branchname = "branch" - try_branchname = "branch" - - def capable(self): - cvspaths = which('cvs') - if not cvspaths: - return (False, "CVS is not installed") - # cvs-1.10 (as shipped with OS-X 10.3 "Panther") is too old for this - # test. There is a situation where we check out a tree, make a - # change, then commit it back, and CVS refuses to believe that we're - # operating in a CVS tree. I tested cvs-1.12.9 and it works ok, OS-X - # 10.4 "Tiger" comes with cvs-1.11, but I haven't tested that yet. - # For now, skip the tests if we've got 1.10 . - log.msg("running %s --version.." % (cvspaths[0],)) - d = utils.getProcessOutput(cvspaths[0], ["--version"], - env=os.environ) - d.addCallback(self._capable, cvspaths[0]) - return d - - def _capable(self, v, vcexe): - m = re.search(r'\(CVS\) ([\d\.]+) ', v) - if not m: - log.msg("couldn't identify CVS version number in output:") - log.msg("'''%s'''" % v) - log.msg("skipping tests") - return (False, "Found CVS but couldn't identify its version") - ver = m.group(1) - log.msg("found CVS version '%s'" % ver) - if ver == "1.10": - return (False, "Found CVS, but it is too old") - self.vcexe = vcexe - return (True, None) - - def getdate(self): - # this timestamp is eventually passed to CVS in a -D argument, and - # strftime's %z specifier doesn't seem to work reliably (I get +0000 - # where I should get +0700 under linux sometimes, and windows seems - # to want to put a verbose 'Eastern Standard Time' in there), so - # leave off the timezone specifier and treat this as localtime. A - # valid alternative would be to use a hard-coded +0000 and - # time.gmtime(). - return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) - - def createRepository(self): - self.createBasedir() - self.cvsrep = cvsrep = os.path.join(self.repbase, "CVS-Repository") - tmp = os.path.join(self.repbase, "cvstmp") - - w = self.dovc(self.repbase, "-d %s init" % cvsrep) - yield w; w.getResult() # we must getResult() to raise any exceptions - - self.populate(tmp) - cmd = ("-d %s import" % cvsrep + - " -m sample_project_files sample vendortag start") - w = self.dovc(tmp, cmd) - yield w; w.getResult() - rmdirRecursive(tmp) - # take a timestamp as the first revision number - time.sleep(2) - self.addTrunkRev(self.getdate()) - time.sleep(2) - - w = self.dovc(self.repbase, - "-d %s checkout -d cvstmp sample" % self.cvsrep) - yield w; w.getResult() - - w = self.dovc(tmp, "tag -b %s" % self.branchname) - yield w; w.getResult() - self.populate_branch(tmp) - w = self.dovc(tmp, - "commit -m commit_on_branch -r %s" % self.branchname) - yield w; w.getResult() - rmdirRecursive(tmp) - time.sleep(2) - self.addBranchRev(self.getdate()) - time.sleep(2) - self.vcargs = { 'cvsroot': self.cvsrep, 'cvsmodule': "sample" } - createRepository = deferredGenerator(createRepository) - - - def vc_revise(self): - tmp = os.path.join(self.repbase, "cvstmp") - - w = self.dovc(self.repbase, - "-d %s checkout -d cvstmp sample" % self.cvsrep) - yield w; w.getResult() - self.version += 1 - version_c = VERSION_C % self.version - open(os.path.join(tmp, "version.c"), "w").write(version_c) - w = self.dovc(tmp, - "commit -m revised_to_%d version.c" % self.version) - yield w; w.getResult() - rmdirRecursive(tmp) - time.sleep(2) - self.addTrunkRev(self.getdate()) - time.sleep(2) - vc_revise = deferredGenerator(vc_revise) - - def vc_try_checkout(self, workdir, rev, branch=None): - # 'workdir' is an absolute path - assert os.path.abspath(workdir) == workdir - cmd = [self.vcexe, "-d", self.cvsrep, "checkout", - "-d", workdir, - "-D", rev] - if branch is not None: - cmd.append("-r") - cmd.append(branch) - cmd.append("sample") - w = self.do(self.repbase, cmd) - yield w; w.getResult() - open(os.path.join(workdir, "subdir", "subdir.c"), "w").write(TRY_C) - vc_try_checkout = deferredGenerator(vc_try_checkout) - - def vc_try_finish(self, workdir): - rmdirRecursive(workdir) - -class CVS(VCBase, unittest.TestCase): - vc_name = "cvs" - - metadir = "CVS" - vctype = "source.CVS" - vctype_try = "cvs" - # CVS gives us got_revision, but it is based entirely upon the local - # clock, which means it is unlikely to match the timestamp taken earlier. - # This might be enough for common use, but won't be good enough for our - # tests to accept, so pretend it doesn't have got_revision at all. - has_got_revision = False - - def testCheckout(self): - d = self.do_vctest() - return d - - def testPatch(self): - d = self.do_patch() - return d - - def testCheckoutBranch(self): - d = self.do_branch() - return d - - def testTry(self): - d = self.do_getpatch(doBranch=False) - return d - -VCS.registerVC(CVS.vc_name, CVSHelper()) - - -class SVNHelper(BaseHelper): - branchname = "sample/branch" - try_branchname = "sample/branch" - - def capable(self): - svnpaths = which('svn') - svnadminpaths = which('svnadmin') - if not svnpaths: - return (False, "SVN is not installed") - if not svnadminpaths: - return (False, "svnadmin is not installed") - # we need svn to be compiled with the ra_local access - # module - log.msg("running svn --version..") - env = os.environ.copy() - env['LC_ALL'] = "C" - d = utils.getProcessOutput(svnpaths[0], ["--version"], - env=env) - d.addCallback(self._capable, svnpaths[0], svnadminpaths[0]) - return d - - def _capable(self, v, vcexe, svnadmin): - if v.find("handles 'file' schem") != -1: - # older versions say 'schema', 1.2.0 and beyond say 'scheme' - self.vcexe = vcexe - self.svnadmin = svnadmin - return (True, None) - excuse = ("%s found but it does not support 'file:' " + - "schema, skipping svn tests") % vcexe - log.msg(excuse) - return (False, excuse) - - def createRepository(self): - self.createBasedir() - self.svnrep = os.path.join(self.repbase, - "SVN-Repository").replace('\\','/') - tmp = os.path.join(self.repbase, "svntmp") - if sys.platform == 'win32': - # On Windows Paths do not start with a / - self.svnurl = "file:///%s" % self.svnrep - else: - self.svnurl = "file://%s" % self.svnrep - self.svnurl_trunk = self.svnurl + "/sample/trunk" - self.svnurl_branch = self.svnurl + "/sample/branch" - - w = self.do(self.repbase, self.svnadmin+" create %s" % self.svnrep) - yield w; w.getResult() - - self.populate(tmp) - w = self.dovc(tmp, - "import -m sample_project_files %s" % - self.svnurl_trunk) - yield w; out = w.getResult() - rmdirRecursive(tmp) - m = re.search(r'Committed revision (\d+)\.', out) - assert m.group(1) == "1" # first revision is always "1" - self.addTrunkRev(int(m.group(1))) - - w = self.dovc(self.repbase, - "checkout %s svntmp" % self.svnurl_trunk) - yield w; w.getResult() - - w = self.dovc(tmp, "cp -m make_branch %s %s" % (self.svnurl_trunk, - self.svnurl_branch)) - yield w; w.getResult() - w = self.dovc(tmp, "switch %s" % self.svnurl_branch) - yield w; w.getResult() - self.populate_branch(tmp) - w = self.dovc(tmp, "commit -m commit_on_branch") - yield w; out = w.getResult() - rmdirRecursive(tmp) - m = re.search(r'Committed revision (\d+)\.', out) - self.addBranchRev(int(m.group(1))) - createRepository = deferredGenerator(createRepository) - - def vc_revise(self): - tmp = os.path.join(self.repbase, "svntmp") - rmdirRecursive(tmp) - log.msg("vc_revise" + self.svnurl_trunk) - w = self.dovc(self.repbase, - "checkout %s svntmp" % self.svnurl_trunk) - yield w; w.getResult() - self.version += 1 - version_c = VERSION_C % self.version - open(os.path.join(tmp, "version.c"), "w").write(version_c) - w = self.dovc(tmp, "commit -m revised_to_%d" % self.version) - yield w; out = w.getResult() - m = re.search(r'Committed revision (\d+)\.', out) - self.addTrunkRev(int(m.group(1))) - rmdirRecursive(tmp) - vc_revise = deferredGenerator(vc_revise) - - def vc_try_checkout(self, workdir, rev, branch=None): - assert os.path.abspath(workdir) == workdir - if os.path.exists(workdir): - rmdirRecursive(workdir) - if not branch: - svnurl = self.svnurl_trunk - else: - # N.B.: this is *not* os.path.join: SVN URLs use slashes - # regardless of the host operating system's filepath separator - svnurl = self.svnurl + "/" + branch - w = self.dovc(self.repbase, - "checkout %s %s" % (svnurl, workdir)) - yield w; w.getResult() - open(os.path.join(workdir, "subdir", "subdir.c"), "w").write(TRY_C) - vc_try_checkout = deferredGenerator(vc_try_checkout) - - def vc_try_finish(self, workdir): - rmdirRecursive(workdir) - - -class SVN(VCBase, unittest.TestCase): - vc_name = "svn" - - metadir = ".svn" - vctype = "source.SVN" - vctype_try = "svn" - has_got_revision = True - has_got_revision_branches_are_merged = True - - def testCheckout(self): - # we verify this one with the svnurl style of vcargs. We test the - # baseURL/defaultBranch style in testPatch and testCheckoutBranch. - self.helper.vcargs = { 'svnurl': self.helper.svnurl_trunk } - d = self.do_vctest() - return d - - def testPatch(self): - self.helper.vcargs = { 'baseURL': self.helper.svnurl + "/", - 'defaultBranch': "sample/trunk", - } - d = self.do_patch() - return d - - def testCheckoutBranch(self): - self.helper.vcargs = { 'baseURL': self.helper.svnurl + "/", - 'defaultBranch': "sample/trunk", - } - d = self.do_branch() - return d - - def testTry(self): - # extract the base revision and patch from a modified tree, use it to - # create the same contents on the buildslave - self.helper.vcargs = { 'baseURL': self.helper.svnurl + "/", - 'defaultBranch': "sample/trunk", - } - d = self.do_getpatch() - return d - -VCS.registerVC(SVN.vc_name, SVNHelper()) - - -class P4Helper(BaseHelper): - branchname = "branch" - p4port = 'localhost:1666' - pid = None - base_descr = 'Change: new\nDescription: asdf\nFiles:\n' - - def capable(self): - p4paths = which('p4') - p4dpaths = which('p4d') - if not p4paths: - return (False, "p4 is not installed") - if not p4dpaths: - return (False, "p4d is not installed") - self.vcexe = p4paths[0] - self.p4dexe = p4dpaths[0] - return (True, None) - - class _P4DProtocol(protocol.ProcessProtocol): - def __init__(self): - self.started = defer.Deferred() - self.ended = defer.Deferred() - - def outReceived(self, data): - # When it says starting, it has bound to the socket. - if self.started: - if data.startswith('Perforce Server starting...'): - self.started.callback(None) - else: - print "p4d said %r" % data - try: - raise Exception('p4d said %r' % data) - except: - self.started.errback(failure.Failure()) - self.started = None - - def errReceived(self, data): - print "p4d stderr: %s" % data - - def processEnded(self, status_object): - if status_object.check(error.ProcessDone): - self.ended.callback(None) - else: - self.ended.errback(status_object) - - def _start_p4d(self): - proto = self._P4DProtocol() - reactor.spawnProcess(proto, self.p4dexe, ['p4d', '-p', self.p4port], - env=os.environ, path=self.p4rep) - return proto.started, proto.ended - - def dop4(self, basedir, command, failureIsOk=False, stdin=None): - # p4 looks at $PWD instead of getcwd(), which causes confusion when - # we spawn commands without an intervening shell (sh -c). We can - # override this with a -d argument. - command = "-p %s -d %s %s" % (self.p4port, basedir, command) - return self.dovc(basedir, command, failureIsOk, stdin) - - def createRepository(self): - # this is only called once per VC system, so start p4d here. - - self.createBasedir() - tmp = os.path.join(self.repbase, "p4tmp") - self.p4rep = os.path.join(self.repbase, 'P4-Repository') - os.mkdir(self.p4rep) - - # Launch p4d. - started, self.p4d_shutdown = self._start_p4d() - w = waitForDeferred(started) - yield w; w.getResult() - - # Create client spec. - os.mkdir(tmp) - clispec = 'Client: creator\n' - clispec += 'Root: %s\n' % tmp - clispec += 'View:\n' - clispec += '\t//depot/... //creator/...\n' - w = self.dop4(tmp, 'client -i', stdin=clispec) - yield w; w.getResult() - - # Create first rev (trunk). - self.populate(os.path.join(tmp, 'trunk')) - files = ['main.c', 'version.c', 'subdir/subdir.c'] - w = self.dop4(tmp, "-c creator add " - + " ".join(['trunk/%s' % f for f in files])) - yield w; w.getResult() - descr = self.base_descr - for file in files: - descr += '\t//depot/trunk/%s\n' % file - w = self.dop4(tmp, "-c creator submit -i", stdin=descr) - yield w; out = w.getResult() - m = re.search(r'Change (\d+) submitted.', out) - assert m.group(1) == '1' - self.addTrunkRev(m.group(1)) - - # Create second rev (branch). - w = self.dop4(tmp, '-c creator integrate ' - + '//depot/trunk/... //depot/branch/...') - yield w; w.getResult() - w = self.dop4(tmp, "-c creator edit branch/main.c") - yield w; w.getResult() - self.populate_branch(os.path.join(tmp, 'branch')) - descr = self.base_descr - for file in files: - descr += '\t//depot/branch/%s\n' % file - w = self.dop4(tmp, "-c creator submit -i", stdin=descr) - yield w; out = w.getResult() - m = re.search(r'Change (\d+) submitted.', out) - self.addBranchRev(m.group(1)) - createRepository = deferredGenerator(createRepository) - - def vc_revise(self): - tmp = os.path.join(self.repbase, "p4tmp") - self.version += 1 - version_c = VERSION_C % self.version - w = self.dop4(tmp, '-c creator edit trunk/version.c') - yield w; w.getResult() - open(os.path.join(tmp, "trunk/version.c"), "w").write(version_c) - descr = self.base_descr + '\t//depot/trunk/version.c\n' - w = self.dop4(tmp, "-c creator submit -i", stdin=descr) - yield w; out = w.getResult() - m = re.search(r'Change (\d+) submitted.', out) - self.addTrunkRev(m.group(1)) - vc_revise = deferredGenerator(vc_revise) - - def shutdown_p4d(self): - d = self.runCommand(self.repbase, '%s -p %s admin stop' - % (self.vcexe, self.p4port)) - return d.addCallback(lambda _: self.p4d_shutdown) - -class P4(VCBase, unittest.TestCase): - metadir = None - vctype = "source.P4" - vc_name = "p4" - - def tearDownClass(self): - if self.helper: - return self.helper.shutdown_p4d() - - def testCheckout(self): - self.helper.vcargs = { 'p4port': self.helper.p4port, - 'p4base': '//depot/', - 'defaultBranch': 'trunk' } - d = self.do_vctest(testRetry=False) - # TODO: like arch and darcs, sync does nothing when server is not - # changed. - return d - - def testCheckoutBranch(self): - self.helper.vcargs = { 'p4port': self.helper.p4port, - 'p4base': '//depot/', - 'defaultBranch': 'trunk' } - d = self.do_branch() - return d - - def testPatch(self): - self.helper.vcargs = { 'p4port': self.helper.p4port, - 'p4base': '//depot/', - 'defaultBranch': 'trunk' } - d = self.do_patch() - return d - -VCS.registerVC(P4.vc_name, P4Helper()) - - -class DarcsHelper(BaseHelper): - branchname = "branch" - try_branchname = "branch" - - def capable(self): - darcspaths = which('darcs') - if not darcspaths: - return (False, "Darcs is not installed") - self.vcexe = darcspaths[0] - return (True, None) - - def createRepository(self): - self.createBasedir() - self.darcs_base = os.path.join(self.repbase, "Darcs-Repository") - self.rep_trunk = os.path.join(self.darcs_base, "trunk") - self.rep_branch = os.path.join(self.darcs_base, "branch") - tmp = os.path.join(self.repbase, "darcstmp") - - os.makedirs(self.rep_trunk) - w = self.dovc(self.rep_trunk, ["initialize"]) - yield w; w.getResult() - os.makedirs(self.rep_branch) - w = self.dovc(self.rep_branch, ["initialize"]) - yield w; w.getResult() - - self.populate(tmp) - w = self.dovc(tmp, qw("initialize")) - yield w; w.getResult() - w = self.dovc(tmp, qw("add -r .")) - yield w; w.getResult() - w = self.dovc(tmp, qw("record -a -m initial_import --skip-long-comment -A test@buildbot.sf.net")) - yield w; w.getResult() - w = self.dovc(tmp, ["push", "-a", self.rep_trunk]) - yield w; w.getResult() - w = self.dovc(tmp, qw("changes --context")) - yield w; out = w.getResult() - self.addTrunkRev(out) - - self.populate_branch(tmp) - w = self.dovc(tmp, qw("record -a --ignore-times -m commit_on_branch --skip-long-comment -A test@buildbot.sf.net")) - yield w; w.getResult() - w = self.dovc(tmp, ["push", "-a", self.rep_branch]) - yield w; w.getResult() - w = self.dovc(tmp, qw("changes --context")) - yield w; out = w.getResult() - self.addBranchRev(out) - rmdirRecursive(tmp) - createRepository = deferredGenerator(createRepository) - - def vc_revise(self): - tmp = os.path.join(self.repbase, "darcstmp") - os.makedirs(tmp) - w = self.dovc(tmp, qw("initialize")) - yield w; w.getResult() - w = self.dovc(tmp, ["pull", "-a", self.rep_trunk]) - yield w; w.getResult() - - self.version += 1 - version_c = VERSION_C % self.version - open(os.path.join(tmp, "version.c"), "w").write(version_c) - w = self.dovc(tmp, qw("record -a --ignore-times -m revised_to_%d --skip-long-comment -A test@buildbot.sf.net" % self.version)) - yield w; w.getResult() - w = self.dovc(tmp, ["push", "-a", self.rep_trunk]) - yield w; w.getResult() - w = self.dovc(tmp, qw("changes --context")) - yield w; out = w.getResult() - self.addTrunkRev(out) - rmdirRecursive(tmp) - vc_revise = deferredGenerator(vc_revise) - - def vc_try_checkout(self, workdir, rev, branch=None): - assert os.path.abspath(workdir) == workdir - if os.path.exists(workdir): - rmdirRecursive(workdir) - os.makedirs(workdir) - w = self.dovc(workdir, qw("initialize")) - yield w; w.getResult() - if not branch: - rep = self.rep_trunk - else: - rep = os.path.join(self.darcs_base, branch) - w = self.dovc(workdir, ["pull", "-a", rep]) - yield w; w.getResult() - open(os.path.join(workdir, "subdir", "subdir.c"), "w").write(TRY_C) - vc_try_checkout = deferredGenerator(vc_try_checkout) - - def vc_try_finish(self, workdir): - rmdirRecursive(workdir) - - -class Darcs(VCBase, unittest.TestCase): - vc_name = "darcs" - - # Darcs has a metadir="_darcs", but it does not have an 'export' - # mode - metadir = None - vctype = "source.Darcs" - vctype_try = "darcs" - has_got_revision = True - - def testCheckout(self): - self.helper.vcargs = { 'repourl': self.helper.rep_trunk } - d = self.do_vctest(testRetry=False) - - # TODO: testRetry has the same problem with Darcs as it does for - # Arch - return d - - def testPatch(self): - self.helper.vcargs = { 'baseURL': self.helper.darcs_base + "/", - 'defaultBranch': "trunk" } - d = self.do_patch() - return d - - def testCheckoutBranch(self): - self.helper.vcargs = { 'baseURL': self.helper.darcs_base + "/", - 'defaultBranch': "trunk" } - d = self.do_branch() - return d - - def testCheckoutHTTP(self): - self.serveHTTP() - repourl = "http://localhost:%d/Darcs-Repository/trunk" % self.httpPort - self.helper.vcargs = { 'repourl': repourl } - d = self.do_vctest(testRetry=False) - return d - - def testTry(self): - self.helper.vcargs = { 'baseURL': self.helper.darcs_base + "/", - 'defaultBranch': "trunk" } - d = self.do_getpatch() - return d - -VCS.registerVC(Darcs.vc_name, DarcsHelper()) - - -class ArchCommon: - def registerRepository(self, coordinates): - a = self.archname - w = self.dovc(self.repbase, "archives %s" % a) - yield w; out = w.getResult() - if out: - w = self.dovc(self.repbase, "register-archive -d %s" % a) - yield w; w.getResult() - w = self.dovc(self.repbase, "register-archive %s" % coordinates) - yield w; w.getResult() - registerRepository = deferredGenerator(registerRepository) - - def unregisterRepository(self): - a = self.archname - w = self.dovc(self.repbase, "archives %s" % a) - yield w; out = w.getResult() - if out: - w = self.dovc(self.repbase, "register-archive -d %s" % a) - yield w; out = w.getResult() - unregisterRepository = deferredGenerator(unregisterRepository) - -class TlaHelper(BaseHelper, ArchCommon): - defaultbranch = "testvc--mainline--1" - branchname = "testvc--branch--1" - try_branchname = None # TlaExtractor can figure it out by itself - archcmd = "tla" - - def capable(self): - tlapaths = which('tla') - if not tlapaths: - return (False, "Arch (tla) is not installed") - self.vcexe = tlapaths[0] - return (True, None) - - def do_get(self, basedir, archive, branch, newdir): - # the 'get' syntax is different between tla and baz. baz, while - # claiming to honor an --archive argument, in fact ignores it. The - # correct invocation is 'baz get archive/revision newdir'. - if self.archcmd == "tla": - w = self.dovc(basedir, - "get -A %s %s %s" % (archive, branch, newdir)) - else: - w = self.dovc(basedir, - "get %s/%s %s" % (archive, branch, newdir)) - return w - - def createRepository(self): - self.createBasedir() - # first check to see if bazaar is around, since we'll need to know - # later - d = VCS.capable(Bazaar.vc_name) - d.addCallback(self._createRepository_1) - return d - - def _createRepository_1(self, res): - has_baz = res[0] - - # pick a hopefully unique string for the archive name, in the form - # test-%d@buildbot.sf.net--testvc, since otherwise multiple copies of - # the unit tests run in the same user account will collide (since the - # archive names are kept in the per-user ~/.arch-params/ directory). - pid = os.getpid() - self.archname = "test-%s-%d@buildbot.sf.net--testvc" % (self.archcmd, - pid) - trunk = self.defaultbranch - branch = self.branchname - - repword = self.archcmd.capitalize() - self.archrep = os.path.join(self.repbase, "%s-Repository" % repword) - tmp = os.path.join(self.repbase, "archtmp") - a = self.archname - - self.populate(tmp) - - w = self.dovc(tmp, "my-id", failureIsOk=True) - yield w; res = w.getResult() - if not res: - # tla will fail a lot of operations if you have not set an ID - w = self.do(tmp, [self.vcexe, "my-id", - "Buildbot Test Suite "]) - yield w; w.getResult() - - if has_baz: - # bazaar keeps a cache of revisions, but this test creates a new - # archive each time it is run, so the cache causes errors. - # Disable the cache to avoid these problems. This will be - # slightly annoying for people who run the buildbot tests under - # the same UID as one which uses baz on a regular basis, but - # bazaar doesn't give us a way to disable the cache just for this - # one archive. - cmd = "%s cache-config --disable" % VCS.getHelper('bazaar').vcexe - w = self.do(tmp, cmd) - yield w; w.getResult() - - w = waitForDeferred(self.unregisterRepository()) - yield w; w.getResult() - - # these commands can be run in any directory - w = self.dovc(tmp, "make-archive -l %s %s" % (a, self.archrep)) - yield w; w.getResult() - if self.archcmd == "tla": - w = self.dovc(tmp, "archive-setup -A %s %s" % (a, trunk)) - yield w; w.getResult() - w = self.dovc(tmp, "archive-setup -A %s %s" % (a, branch)) - yield w; w.getResult() - else: - # baz does not require an 'archive-setup' step - pass - - # these commands must be run in the directory that is to be imported - w = self.dovc(tmp, "init-tree --nested %s/%s" % (a, trunk)) - yield w; w.getResult() - files = " ".join(["main.c", "version.c", "subdir", - os.path.join("subdir", "subdir.c")]) - w = self.dovc(tmp, "add-id %s" % files) - yield w; w.getResult() - - w = self.dovc(tmp, "import %s/%s" % (a, trunk)) - yield w; out = w.getResult() - self.addTrunkRev("base-0") - - # create the branch - if self.archcmd == "tla": - branchstart = "%s--base-0" % trunk - w = self.dovc(tmp, "tag -A %s %s %s" % (a, branchstart, branch)) - yield w; w.getResult() - else: - w = self.dovc(tmp, "branch %s" % branch) - yield w; w.getResult() - - rmdirRecursive(tmp) - - # check out the branch - w = self.do_get(self.repbase, a, branch, "archtmp") - yield w; w.getResult() - # and edit the file - self.populate_branch(tmp) - logfile = "++log.%s--%s" % (branch, a) - logmsg = "Summary: commit on branch\nKeywords:\n\n" - open(os.path.join(tmp, logfile), "w").write(logmsg) - w = self.dovc(tmp, "commit") - yield w; out = w.getResult() - m = re.search(r'committed %s/%s--([\S]+)' % (a, branch), - out) - assert (m.group(1) == "base-0" or m.group(1).startswith("patch-")) - self.addBranchRev(m.group(1)) - - w = waitForDeferred(self.unregisterRepository()) - yield w; w.getResult() - rmdirRecursive(tmp) - - # we unregister the repository each time, because we might have - # changed the coordinates (since we switch from a file: URL to an - # http: URL for various tests). The buildslave code doesn't forcibly - # unregister the archive, so we have to do it here. - w = waitForDeferred(self.unregisterRepository()) - yield w; w.getResult() - - _createRepository_1 = deferredGenerator(_createRepository_1) - - def vc_revise(self): - # the fix needs to be done in a workspace that is linked to a - # read-write version of the archive (i.e., using file-based - # coordinates instead of HTTP ones), so we re-register the repository - # before we begin. We unregister it when we're done to make sure the - # build will re-register the correct one for whichever test is - # currently being run. - - # except, that source.Bazaar really doesn't like it when the archive - # gets unregistered behind its back. The slave tries to do a 'baz - # replay' in a tree with an archive that is no longer recognized, and - # baz aborts with a botched invariant exception. This causes - # mode=update to fall back to clobber+get, which flunks one of the - # tests (the 'newfile' check in _do_vctest_update_3 fails) - - # to avoid this, we take heroic steps here to leave the archive - # registration in the same state as we found it. - - tmp = os.path.join(self.repbase, "archtmp") - a = self.archname - - w = self.dovc(self.repbase, "archives %s" % a) - yield w; out = w.getResult() - assert out - lines = out.split("\n") - coordinates = lines[1].strip() - - # now register the read-write location - w = waitForDeferred(self.registerRepository(self.archrep)) - yield w; w.getResult() - - trunk = self.defaultbranch - - w = self.do_get(self.repbase, a, trunk, "archtmp") - yield w; w.getResult() - - # tla appears to use timestamps to determine which files have - # changed, so wait long enough for the new file to have a different - # timestamp - time.sleep(2) - self.version += 1 - version_c = VERSION_C % self.version - open(os.path.join(tmp, "version.c"), "w").write(version_c) - - logfile = "++log.%s--%s" % (trunk, a) - logmsg = "Summary: revised_to_%d\nKeywords:\n\n" % self.version - open(os.path.join(tmp, logfile), "w").write(logmsg) - w = self.dovc(tmp, "commit") - yield w; out = w.getResult() - m = re.search(r'committed %s/%s--([\S]+)' % (a, trunk), - out) - assert (m.group(1) == "base-0" or m.group(1).startswith("patch-")) - self.addTrunkRev(m.group(1)) - - # now re-register the original coordinates - w = waitForDeferred(self.registerRepository(coordinates)) - yield w; w.getResult() - rmdirRecursive(tmp) - vc_revise = deferredGenerator(vc_revise) - - def vc_try_checkout(self, workdir, rev, branch=None): - assert os.path.abspath(workdir) == workdir - if os.path.exists(workdir): - rmdirRecursive(workdir) - - a = self.archname - - # register the read-write location, if it wasn't already registered - w = waitForDeferred(self.registerRepository(self.archrep)) - yield w; w.getResult() - - w = self.do_get(self.repbase, a, "testvc--mainline--1", workdir) - yield w; w.getResult() - - # timestamps. ick. - time.sleep(2) - open(os.path.join(workdir, "subdir", "subdir.c"), "w").write(TRY_C) - vc_try_checkout = deferredGenerator(vc_try_checkout) - - def vc_try_finish(self, workdir): - rmdirRecursive(workdir) - -class Arch(VCBase, unittest.TestCase): - vc_name = "tla" - - metadir = None - # Arch has a metadir="{arch}", but it does not have an 'export' mode. - vctype = "source.Arch" - vctype_try = "tla" - has_got_revision = True - - def testCheckout(self): - # these are the coordinates of the read-write archive used by all the - # non-HTTP tests. testCheckoutHTTP overrides these. - self.helper.vcargs = {'url': self.helper.archrep, - 'version': self.helper.defaultbranch } - d = self.do_vctest(testRetry=False) - # the current testRetry=True logic doesn't have the desired effect: - # "update" is a no-op because arch knows that the repository hasn't - # changed. Other VC systems will re-checkout missing files on - # update, arch just leaves the tree untouched. TODO: come up with - # some better test logic, probably involving a copy of the - # repository that has a few changes checked in. - - return d - - def testCheckoutHTTP(self): - self.serveHTTP() - url = "http://localhost:%d/Tla-Repository" % self.httpPort - self.helper.vcargs = { 'url': url, - 'version': "testvc--mainline--1" } - d = self.do_vctest(testRetry=False) - return d - - def testPatch(self): - self.helper.vcargs = {'url': self.helper.archrep, - 'version': self.helper.defaultbranch } - d = self.do_patch() - return d - - def testCheckoutBranch(self): - self.helper.vcargs = {'url': self.helper.archrep, - 'version': self.helper.defaultbranch } - d = self.do_branch() - return d - - def testTry(self): - self.helper.vcargs = {'url': self.helper.archrep, - 'version': self.helper.defaultbranch } - d = self.do_getpatch() - return d - -VCS.registerVC(Arch.vc_name, TlaHelper()) - - -class BazaarHelper(TlaHelper): - archcmd = "baz" - - def capable(self): - bazpaths = which('baz') - if not bazpaths: - return (False, "Arch (baz) is not installed") - self.vcexe = bazpaths[0] - return (True, None) - - def setUp2(self, res): - # we unregister the repository each time, because we might have - # changed the coordinates (since we switch from a file: URL to an - # http: URL for various tests). The buildslave code doesn't forcibly - # unregister the archive, so we have to do it here. - d = self.unregisterRepository() - return d - - -class Bazaar(Arch): - vc_name = "bazaar" - - vctype = "source.Bazaar" - vctype_try = "baz" - has_got_revision = True - - fixtimer = None - - def testCheckout(self): - self.helper.vcargs = {'url': self.helper.archrep, - # Baz adds the required 'archive' argument - 'archive': self.helper.archname, - 'version': self.helper.defaultbranch, - } - d = self.do_vctest(testRetry=False) - # the current testRetry=True logic doesn't have the desired effect: - # "update" is a no-op because arch knows that the repository hasn't - # changed. Other VC systems will re-checkout missing files on - # update, arch just leaves the tree untouched. TODO: come up with - # some better test logic, probably involving a copy of the - # repository that has a few changes checked in. - - return d - - def testCheckoutHTTP(self): - self.serveHTTP() - url = "http://localhost:%d/Baz-Repository" % self.httpPort - self.helper.vcargs = { 'url': url, - 'archive': self.helper.archname, - 'version': self.helper.defaultbranch, - } - d = self.do_vctest(testRetry=False) - return d - - def testPatch(self): - self.helper.vcargs = {'url': self.helper.archrep, - # Baz adds the required 'archive' argument - 'archive': self.helper.archname, - 'version': self.helper.defaultbranch, - } - d = self.do_patch() - return d - - def testCheckoutBranch(self): - self.helper.vcargs = {'url': self.helper.archrep, - # Baz adds the required 'archive' argument - 'archive': self.helper.archname, - 'version': self.helper.defaultbranch, - } - d = self.do_branch() - return d - - def testTry(self): - self.helper.vcargs = {'url': self.helper.archrep, - # Baz adds the required 'archive' argument - 'archive': self.helper.archname, - 'version': self.helper.defaultbranch, - } - d = self.do_getpatch() - return d - - def fixRepository(self): - self.fixtimer = None - self.site.resource = self.root - - def testRetry(self): - # we want to verify that source.Source(retry=) works, and the easiest - # way to make VC updates break (temporarily) is to break the HTTP - # server that's providing the repository. Anything else pretty much - # requires mutating the (read-only) BUILDBOT_TEST_VC repository, or - # modifying the buildslave's checkout command while it's running. - - # this test takes a while to run, so don't bother doing it with - # anything other than baz - - self.serveHTTP() - - # break the repository server - from twisted.web import static - self.site.resource = static.Data("Sorry, repository is offline", - "text/plain") - # and arrange to fix it again in 5 seconds, while the test is - # running. - self.fixtimer = reactor.callLater(5, self.fixRepository) - - url = "http://localhost:%d/Baz-Repository" % self.httpPort - self.helper.vcargs = { 'url': url, - 'archive': self.helper.archname, - 'version': self.helper.defaultbranch, - 'retry': (5.0, 4), - } - d = self.do_vctest_once(True) - d.addCallback(self._testRetry_1) - return d - def _testRetry_1(self, bs): - # make sure there was mention of the retry attempt in the logs - l = bs.getLogs()[0] - self.failUnlessIn("unable to access URL", l.getText(), - "funny, VC operation didn't fail at least once") - self.failUnlessIn("update failed, trying 4 more times after 5 seconds", - l.getTextWithHeaders(), - "funny, VC operation wasn't reattempted") - - def testRetryFails(self): - # make sure that the build eventually gives up on a repository which - # is completely unavailable - - self.serveHTTP() - - # break the repository server, and leave it broken - from twisted.web import static - self.site.resource = static.Data("Sorry, repository is offline", - "text/plain") - - url = "http://localhost:%d/Baz-Repository" % self.httpPort - self.helper.vcargs = {'url': url, - 'archive': self.helper.archname, - 'version': self.helper.defaultbranch, - 'retry': (0.5, 3), - } - d = self.do_vctest_once(False) - d.addCallback(self._testRetryFails_1) - return d - def _testRetryFails_1(self, bs): - self.failUnlessEqual(bs.getResults(), FAILURE) - - def tearDown2(self): - if self.fixtimer: - self.fixtimer.cancel() - # tell tla to get rid of the leftover archive this test leaves in the - # user's 'tla archives' listing. The name of this archive is provided - # by the repository tarball, so the following command must use the - # same name. We could use archive= to set it explicitly, but if you - # change it from the default, then 'tla update' won't work. - d = self.helper.unregisterRepository() - return d - -VCS.registerVC(Bazaar.vc_name, BazaarHelper()) - -class BzrHelper(BaseHelper): - branchname = "branch" - try_branchname = "branch" - - def capable(self): - bzrpaths = which('bzr') - if not bzrpaths: - return (False, "bzr is not installed") - self.vcexe = bzrpaths[0] - return (True, None) - - def get_revision_number(self, out): - for line in out.split("\n"): - colon = line.index(":") - key, value = line[:colon], line[colon+2:] - if key == "revno": - return int(value) - raise RuntimeError("unable to find revno: in bzr output: '%s'" % out) - - def createRepository(self): - self.createBasedir() - self.bzr_base = os.path.join(self.repbase, "Bzr-Repository") - self.rep_trunk = os.path.join(self.bzr_base, "trunk") - self.rep_branch = os.path.join(self.bzr_base, "branch") - tmp = os.path.join(self.repbase, "bzrtmp") - btmp = os.path.join(self.repbase, "bzrtmp-branch") - - os.makedirs(self.rep_trunk) - w = self.dovc(self.rep_trunk, ["init"]) - yield w; w.getResult() - w = self.dovc(self.bzr_base, - ["branch", self.rep_trunk, self.rep_branch]) - yield w; w.getResult() - - w = self.dovc(self.repbase, ["checkout", self.rep_trunk, tmp]) - yield w; w.getResult() - self.populate(tmp) - w = self.dovc(tmp, qw("add")) - yield w; w.getResult() - w = self.dovc(tmp, qw("commit -m initial_import")) - yield w; w.getResult() - w = self.dovc(tmp, qw("version-info")) - yield w; out = w.getResult() - self.addTrunkRev(self.get_revision_number(out)) - rmdirRecursive(tmp) - - # pull all trunk revisions to the branch - w = self.dovc(self.rep_branch, qw("pull")) - yield w; w.getResult() - # obtain a branch tree - w = self.dovc(self.repbase, ["checkout", self.rep_branch, btmp]) - yield w; w.getResult() - # modify it - self.populate_branch(btmp) - w = self.dovc(btmp, qw("add")) - yield w; w.getResult() - w = self.dovc(btmp, qw("commit -m commit_on_branch")) - yield w; w.getResult() - w = self.dovc(btmp, qw("version-info")) - yield w; out = w.getResult() - self.addBranchRev(self.get_revision_number(out)) - rmdirRecursive(btmp) - createRepository = deferredGenerator(createRepository) - - def vc_revise(self): - tmp = os.path.join(self.repbase, "bzrtmp") - w = self.dovc(self.repbase, ["checkout", self.rep_trunk, tmp]) - yield w; w.getResult() - - self.version += 1 - version_c = VERSION_C % self.version - open(os.path.join(tmp, "version.c"), "w").write(version_c) - w = self.dovc(tmp, qw("commit -m revised_to_%d" % self.version)) - yield w; w.getResult() - w = self.dovc(tmp, qw("version-info")) - yield w; out = w.getResult() - self.addTrunkRev(self.get_revision_number(out)) - rmdirRecursive(tmp) - vc_revise = deferredGenerator(vc_revise) - - def vc_try_checkout(self, workdir, rev, branch=None): - assert os.path.abspath(workdir) == workdir - if os.path.exists(workdir): - rmdirRecursive(workdir) - #os.makedirs(workdir) - if not branch: - rep = self.rep_trunk - else: - rep = os.path.join(self.bzr_base, branch) - w = self.dovc(self.bzr_base, ["checkout", rep, workdir]) - yield w; w.getResult() - open(os.path.join(workdir, "subdir", "subdir.c"), "w").write(TRY_C) - vc_try_checkout = deferredGenerator(vc_try_checkout) - - def vc_try_finish(self, workdir): - rmdirRecursive(workdir) - -class Bzr(VCBase, unittest.TestCase): - vc_name = "bzr" - - metadir = ".bzr" - vctype = "source.Bzr" - vctype_try = "bzr" - has_got_revision = True - - def testCheckout(self): - self.helper.vcargs = { 'repourl': self.helper.rep_trunk } - d = self.do_vctest(testRetry=False) - - # TODO: testRetry has the same problem with Bzr as it does for - # Arch - return d - - def testPatch(self): - self.helper.vcargs = { 'baseURL': self.helper.bzr_base + "/", - 'defaultBranch': "trunk" } - d = self.do_patch() - return d - - def testCheckoutBranch(self): - self.helper.vcargs = { 'baseURL': self.helper.bzr_base + "/", - 'defaultBranch': "trunk" } - d = self.do_branch() - return d - - def testCheckoutHTTP(self): - self.serveHTTP() - repourl = "http://localhost:%d/Bzr-Repository/trunk" % self.httpPort - self.helper.vcargs = { 'repourl': repourl } - d = self.do_vctest(testRetry=False) - return d - - - def fixRepository(self): - self.fixtimer = None - self.site.resource = self.root - - def testRetry(self): - # this test takes a while to run - self.serveHTTP() - - # break the repository server - from twisted.web import static - self.site.resource = static.Data("Sorry, repository is offline", - "text/plain") - # and arrange to fix it again in 5 seconds, while the test is - # running. - self.fixtimer = reactor.callLater(5, self.fixRepository) - - repourl = "http://localhost:%d/Bzr-Repository/trunk" % self.httpPort - self.helper.vcargs = { 'repourl': repourl, - 'retry': (5.0, 4), - } - d = self.do_vctest_once(True) - d.addCallback(self._testRetry_1) - return d - def _testRetry_1(self, bs): - # make sure there was mention of the retry attempt in the logs - l = bs.getLogs()[0] - self.failUnlessIn("ERROR: Not a branch: ", l.getText(), - "funny, VC operation didn't fail at least once") - self.failUnlessIn("update failed, trying 4 more times after 5 seconds", - l.getTextWithHeaders(), - "funny, VC operation wasn't reattempted") - - def testRetryFails(self): - # make sure that the build eventually gives up on a repository which - # is completely unavailable - - self.serveHTTP() - - # break the repository server, and leave it broken - from twisted.web import static - self.site.resource = static.Data("Sorry, repository is offline", - "text/plain") - - repourl = "http://localhost:%d/Bzr-Repository/trunk" % self.httpPort - self.helper.vcargs = { 'repourl': repourl, - 'retry': (0.5, 3), - } - d = self.do_vctest_once(False) - d.addCallback(self._testRetryFails_1) - return d - def _testRetryFails_1(self, bs): - self.failUnlessEqual(bs.getResults(), FAILURE) - - - def testTry(self): - self.helper.vcargs = { 'baseURL': self.helper.bzr_base + "/", - 'defaultBranch': "trunk" } - d = self.do_getpatch() - return d - -VCS.registerVC(Bzr.vc_name, BzrHelper()) - - -class MercurialHelper(BaseHelper): - branchname = "branch" - try_branchname = "branch" - - def capable(self): - hgpaths = which("hg") - if not hgpaths: - return (False, "Mercurial is not installed") - self.vcexe = hgpaths[0] - return (True, None) - - def extract_id(self, output): - m = re.search(r'^(\w+)', output) - return m.group(0) - - def createRepository(self): - self.createBasedir() - self.hg_base = os.path.join(self.repbase, "Mercurial-Repository") - self.rep_trunk = os.path.join(self.hg_base, "trunk") - self.rep_branch = os.path.join(self.hg_base, "branch") - tmp = os.path.join(self.hg_base, "hgtmp") - - os.makedirs(self.rep_trunk) - w = self.dovc(self.rep_trunk, "init") - yield w; w.getResult() - os.makedirs(self.rep_branch) - w = self.dovc(self.rep_branch, "init") - yield w; w.getResult() - - self.populate(tmp) - w = self.dovc(tmp, "init") - yield w; w.getResult() - w = self.dovc(tmp, "add") - yield w; w.getResult() - w = self.dovc(tmp, "commit -m initial_import") - yield w; w.getResult() - w = self.dovc(tmp, "push %s" % self.rep_trunk) - # note that hg-push does not actually update the working directory - yield w; w.getResult() - w = self.dovc(tmp, "identify") - yield w; out = w.getResult() - self.addTrunkRev(self.extract_id(out)) - - self.populate_branch(tmp) - w = self.dovc(tmp, "commit -m commit_on_branch") - yield w; w.getResult() - w = self.dovc(tmp, "push %s" % self.rep_branch) - yield w; w.getResult() - w = self.dovc(tmp, "identify") - yield w; out = w.getResult() - self.addBranchRev(self.extract_id(out)) - rmdirRecursive(tmp) - createRepository = deferredGenerator(createRepository) - - def vc_revise(self): - tmp = os.path.join(self.hg_base, "hgtmp2") - w = self.dovc(self.hg_base, "clone %s %s" % (self.rep_trunk, tmp)) - yield w; w.getResult() - - self.version += 1 - version_c = VERSION_C % self.version - version_c_filename = os.path.join(tmp, "version.c") - open(version_c_filename, "w").write(version_c) - # hg uses timestamps to distinguish files which have changed, so we - # force the mtime forward a little bit - future = time.time() + 2*self.version - os.utime(version_c_filename, (future, future)) - w = self.dovc(tmp, "commit -m revised_to_%d" % self.version) - yield w; w.getResult() - w = self.dovc(tmp, "push %s" % self.rep_trunk) - yield w; w.getResult() - w = self.dovc(tmp, "identify") - yield w; out = w.getResult() - self.addTrunkRev(self.extract_id(out)) - rmdirRecursive(tmp) - vc_revise = deferredGenerator(vc_revise) - - def vc_try_checkout(self, workdir, rev, branch=None): - assert os.path.abspath(workdir) == workdir - if os.path.exists(workdir): - rmdirRecursive(workdir) - if branch: - src = self.rep_branch - else: - src = self.rep_trunk - w = self.dovc(self.hg_base, "clone %s %s" % (src, workdir)) - yield w; w.getResult() - try_c_filename = os.path.join(workdir, "subdir", "subdir.c") - open(try_c_filename, "w").write(TRY_C) - future = time.time() + 2*self.version - os.utime(try_c_filename, (future, future)) - vc_try_checkout = deferredGenerator(vc_try_checkout) - - def vc_try_finish(self, workdir): - rmdirRecursive(workdir) - -class MercurialServerPP(protocol.ProcessProtocol): - def outReceived(self, data): - log.msg("hg-serve-stdout: %s" % (data,)) - def errReceived(self, data): - print "HG-SERVE-STDERR:", data - log.msg("hg-serve-stderr: %s" % (data,)) - -class Mercurial(VCBase, unittest.TestCase): - vc_name = "hg" - - # Mercurial has a metadir=".hg", but it does not have an 'export' mode. - metadir = None - vctype = "source.Mercurial" - vctype_try = "hg" - has_got_revision = True - _hg_server = None - _wait_for_server_poller = None - - def testCheckout(self): - self.helper.vcargs = { 'repourl': self.helper.rep_trunk } - d = self.do_vctest(testRetry=False) - - # TODO: testRetry has the same problem with Mercurial as it does for - # Arch - return d - - def testPatch(self): - self.helper.vcargs = { 'baseURL': self.helper.hg_base + "/", - 'defaultBranch': "trunk" } - d = self.do_patch() - return d - - def testCheckoutBranch(self): - self.helper.vcargs = { 'baseURL': self.helper.hg_base + "/", - 'defaultBranch': "trunk" } - d = self.do_branch() - return d - - def serveHTTP(self): - # the easiest way to publish hg over HTTP is by running 'hg serve' as - # a child process while the test is running. (you can also use a CGI - # script, which sounds difficult, or you can publish the files - # directly, which isn't well documented). - - # grr.. 'hg serve' doesn't let you use --port=0 to mean "pick a free - # port", instead it uses it as a signal to use the default (port - # 8000). This means there is no way to make it choose a free port, so - # we are forced to make it use a statically-defined one, making it - # harder to avoid collisions. - self.httpPort = 8300 + (os.getpid() % 200) - args = [self.helper.vcexe, - "serve", "--port", str(self.httpPort), "--verbose"] - - # in addition, hg doesn't flush its stdout, so we can't wait for the - # "listening at" message to know when it's safe to start the test. - # Instead, poll every second until a getPage works. - - pp = MercurialServerPP() # logs+discards everything - # this serves one tree at a time, so we serve trunk. TODO: test hg's - # in-repo branches, for which a single tree will hold all branches. - self._hg_server = reactor.spawnProcess(pp, self.helper.vcexe, args, - os.environ, - self.helper.rep_trunk) - log.msg("waiting for hg serve to start") - done_d = defer.Deferred() - def poll(): - d = client.getPage("http://localhost:%d/" % self.httpPort) - def success(res): - log.msg("hg serve appears to have started") - self._wait_for_server_poller.stop() - done_d.callback(None) - def ignore_connection_refused(f): - f.trap(error.ConnectionRefusedError) - d.addCallbacks(success, ignore_connection_refused) - d.addErrback(done_d.errback) - return d - self._wait_for_server_poller = task.LoopingCall(poll) - self._wait_for_server_poller.start(0.5, True) - return done_d - - def tearDown(self): - if self._wait_for_server_poller: - if self._wait_for_server_poller.running: - self._wait_for_server_poller.stop() - if self._hg_server: - try: - self._hg_server.signalProcess("KILL") - except error.ProcessExitedAlready: - pass - self._hg_server = None - return VCBase.tearDown(self) - - def testCheckoutHTTP(self): - d = self.serveHTTP() - def _started(res): - repourl = "http://localhost:%d/" % self.httpPort - self.helper.vcargs = { 'repourl': repourl } - return self.do_vctest(testRetry=False) - d.addCallback(_started) - return d - - def testTry(self): - self.helper.vcargs = { 'baseURL': self.helper.hg_base + "/", - 'defaultBranch': "trunk" } - d = self.do_getpatch() - return d - -VCS.registerVC(Mercurial.vc_name, MercurialHelper()) - -class GitHelper(BaseHelper): - branchname = "branch" - try_branchname = "branch" - - def capable(self): - gitpaths = which('git') - if not gitpaths: - return (False, "GIT is not installed") - d = utils.getProcessOutput(gitpaths[0], ["--version"], env=os.environ) - d.addCallback(self._capable, gitpaths[0]) - return d - - def _capable(self, v, vcexe): - m = re.search(r'\b([\d\.]+)\b', v) - if not m: - log.msg("couldn't identify git version number in output:") - log.msg("'''%s'''" % v) - log.msg("skipping tests") - return (False, - "Found git (%s) but couldn't identify its version" % vcexe) - ver_s = m.group(1) - ver = tuple([int(num) for num in ver_s.split(".")]) - - # git-1.1.3 (as shipped with Dapper) doesn't understand 'git - # init' (it wants 'git init-db'), and fails unit tests that - # involve branches. git-1.5.3.6 (on my debian/unstable system) - # works. I don't know where the dividing point is: if someone can - # figure it out (or figure out how to make buildbot support more - # versions), please update this check. - if ver < (1,2): - return (False, "Found git (%s) but it is older than 1.2.x" % vcexe) - self.vcexe = vcexe - return (True, None) - - def createRepository(self): - self.createBasedir() - self.gitrepo = os.path.join(self.repbase, - "GIT-Repository") - tmp = os.path.join(self.repbase, "gittmp") - - env = os.environ.copy() - env['GIT_DIR'] = self.gitrepo - w = self.dovc(self.repbase, "init", env=env) - yield w; w.getResult() - - self.populate(tmp) - w = self.dovc(tmp, "init") - yield w; w.getResult() - w = self.dovc(tmp, ["add", "."]) - yield w; w.getResult() - w = self.dovc(tmp, ["config", "user.email", "buildbot-trial@localhost"]) - yield w; w.getResult() - w = self.dovc(tmp, ["config", "user.name", "Buildbot Trial"]) - yield w; w.getResult() - w = self.dovc(tmp, ["commit", "-m", "initial_import"]) - yield w; w.getResult() - - w = self.dovc(tmp, ["checkout", "-b", self.branchname]) - yield w; w.getResult() - self.populate_branch(tmp) - w = self.dovc(tmp, ["commit", "-a", "-m", "commit_on_branch"]) - yield w; w.getResult() - - w = self.dovc(tmp, ["rev-parse", "master", self.branchname]) - yield w; out = w.getResult() - revs = out.splitlines() - self.addTrunkRev(revs[0]) - self.addBranchRev(revs[1]) - - w = self.dovc(tmp, ["push", self.gitrepo, "master", self.branchname]) - yield w; w.getResult() - - rmdirRecursive(tmp) - createRepository = deferredGenerator(createRepository) - - def vc_revise(self): - tmp = os.path.join(self.repbase, "gittmp") - rmdirRecursive(tmp) - log.msg("vc_revise" + self.gitrepo) - w = self.dovc(self.repbase, ["clone", self.gitrepo, "gittmp"]) - yield w; w.getResult() - w = self.dovc(tmp, ["config", "user.email", "buildbot-trial@localhost"]) - yield w; w.getResult() - w = self.dovc(tmp, ["config", "user.name", "Buildbot Trial"]) - yield w; w.getResult() - - self.version += 1 - version_c = VERSION_C % self.version - open(os.path.join(tmp, "version.c"), "w").write(version_c) - - w = self.dovc(tmp, ["commit", "-m", "revised_to_%d" % self.version, - "version.c"]) - yield w; w.getResult() - w = self.dovc(tmp, ["rev-parse", "master"]) - yield w; out = w.getResult() - self.addTrunkRev(out.strip()) - - w = self.dovc(tmp, ["push", self.gitrepo, "master"]) - yield w; out = w.getResult() - rmdirRecursive(tmp) - vc_revise = deferredGenerator(vc_revise) - - def vc_try_checkout(self, workdir, rev, branch=None): - assert os.path.abspath(workdir) == workdir - if os.path.exists(workdir): - rmdirRecursive(workdir) - - w = self.dovc(self.repbase, ["clone", self.gitrepo, workdir]) - yield w; w.getResult() - w = self.dovc(workdir, ["config", "user.email", "buildbot-trial@localhost"]) - yield w; w.getResult() - w = self.dovc(workdir, ["config", "user.name", "Buildbot Trial"]) - yield w; w.getResult() - - if branch is not None: - w = self.dovc(workdir, ["checkout", "-b", branch, - "origin/%s" % branch]) - yield w; w.getResult() - - # Hmm...why do nobody else bother to check out the correct - # revision? - w = self.dovc(workdir, ["reset", "--hard", rev]) - yield w; w.getResult() - - try_c_filename = os.path.join(workdir, "subdir", "subdir.c") - open(try_c_filename, "w").write(TRY_C) - vc_try_checkout = deferredGenerator(vc_try_checkout) - - def vc_try_finish(self, workdir): - rmdirRecursive(workdir) - -class Git(VCBase, unittest.TestCase): - vc_name = "git" - - # No 'export' mode yet... - # metadir = ".git" - vctype = "source.Git" - vctype_try = "git" - has_got_revision = True - - def testCheckout(self): - self.helper.vcargs = { 'repourl': self.helper.gitrepo } - d = self.do_vctest() - return d - - def testPatch(self): - self.helper.vcargs = { 'repourl': self.helper.gitrepo, - 'branch': "master" } - d = self.do_patch() - return d - - def testCheckoutBranch(self): - self.helper.vcargs = { 'repourl': self.helper.gitrepo, - 'branch': "master" } - d = self.do_branch() - return d - - def testTry(self): - self.helper.vcargs = { 'repourl': self.helper.gitrepo, - 'branch': "master" } - d = self.do_getpatch() - return d - -VCS.registerVC(Git.vc_name, GitHelper()) - - -class Sources(unittest.TestCase): - # TODO: this needs serious rethink - def makeChange(self, when=None, revision=None): - if when: - when = mktime_tz(parsedate_tz(when)) - return changes.Change("fred", [], "", when=when, revision=revision) - - def testCVS1(self): - r = base.BuildRequest("forced build", SourceStamp()) - b = base.Build([r]) - s = source.CVS(cvsroot=None, cvsmodule=None) - s.setBuild(b) - self.failUnlessEqual(s.computeSourceRevision(b.allChanges()), None) - - def testCVS2(self): - c = [] - c.append(self.makeChange("Wed, 08 Sep 2004 09:00:00 -0700")) - c.append(self.makeChange("Wed, 08 Sep 2004 09:01:00 -0700")) - c.append(self.makeChange("Wed, 08 Sep 2004 09:02:00 -0700")) - r = base.BuildRequest("forced", SourceStamp(changes=c)) - submitted = "Wed, 08 Sep 2004 09:04:00 -0700" - r.submittedAt = mktime_tz(parsedate_tz(submitted)) - b = base.Build([r]) - s = source.CVS(cvsroot=None, cvsmodule=None) - s.setBuild(b) - self.failUnlessEqual(s.computeSourceRevision(b.allChanges()), - "Wed, 08 Sep 2004 16:03:00 -0000") - - def testCVS3(self): - c = [] - c.append(self.makeChange("Wed, 08 Sep 2004 09:00:00 -0700")) - c.append(self.makeChange("Wed, 08 Sep 2004 09:01:00 -0700")) - c.append(self.makeChange("Wed, 08 Sep 2004 09:02:00 -0700")) - r = base.BuildRequest("forced", SourceStamp(changes=c)) - submitted = "Wed, 08 Sep 2004 09:04:00 -0700" - r.submittedAt = mktime_tz(parsedate_tz(submitted)) - b = base.Build([r]) - s = source.CVS(cvsroot=None, cvsmodule=None, checkoutDelay=10) - s.setBuild(b) - self.failUnlessEqual(s.computeSourceRevision(b.allChanges()), - "Wed, 08 Sep 2004 16:02:10 -0000") - - def testCVS4(self): - c = [] - c.append(self.makeChange("Wed, 08 Sep 2004 09:00:00 -0700")) - c.append(self.makeChange("Wed, 08 Sep 2004 09:01:00 -0700")) - c.append(self.makeChange("Wed, 08 Sep 2004 09:02:00 -0700")) - r1 = base.BuildRequest("forced", SourceStamp(changes=c)) - submitted = "Wed, 08 Sep 2004 09:04:00 -0700" - r1.submittedAt = mktime_tz(parsedate_tz(submitted)) - - c = [] - c.append(self.makeChange("Wed, 08 Sep 2004 09:05:00 -0700")) - r2 = base.BuildRequest("forced", SourceStamp(changes=c)) - submitted = "Wed, 08 Sep 2004 09:07:00 -0700" - r2.submittedAt = mktime_tz(parsedate_tz(submitted)) - - b = base.Build([r1, r2]) - s = source.CVS(cvsroot=None, cvsmodule=None) - s.setBuild(b) - self.failUnlessEqual(s.computeSourceRevision(b.allChanges()), - "Wed, 08 Sep 2004 16:06:00 -0000") - - def testSVN1(self): - r = base.BuildRequest("forced", SourceStamp()) - b = base.Build([r]) - s = source.SVN(svnurl="dummy") - s.setBuild(b) - self.failUnlessEqual(s.computeSourceRevision(b.allChanges()), None) - - def testSVN2(self): - c = [] - c.append(self.makeChange(revision=4)) - c.append(self.makeChange(revision=10)) - c.append(self.makeChange(revision=67)) - r = base.BuildRequest("forced", SourceStamp(changes=c)) - b = base.Build([r]) - s = source.SVN(svnurl="dummy") - s.setBuild(b) - self.failUnlessEqual(s.computeSourceRevision(b.allChanges()), 67) - -class Patch(VCBase, unittest.TestCase): - def setUp(self): - pass - - def tearDown(self): - pass - - def testPatch(self): - # invoke 'patch' all by itself, to see if it works the way we think - # it should. This is intended to ferret out some windows test - # failures. - helper = BaseHelper() - self.workdir = os.path.join("test_vc", "testPatch") - helper.populate(self.workdir) - patch = which("patch")[0] - - command = [patch, "-p0"] - class FakeBuilder: - usePTY = False - def sendUpdate(self, status): - pass - c = commands.ShellCommand(FakeBuilder(), command, self.workdir, - sendRC=False, initialStdin=p0_diff) - d = c.start() - d.addCallback(self._testPatch_1) - return d - - def _testPatch_1(self, res): - # make sure the file actually got patched - subdir_c = os.path.join(self.workdir, "subdir", "subdir.c") - data = open(subdir_c, "r").read() - self.failUnlessIn("Hello patched subdir.\\n", data) diff --git a/tools/buildbot/pylibs/buildbot/test/test_web.py b/tools/buildbot/pylibs/buildbot/test/test_web.py deleted file mode 100644 index 9a7d355..0000000 --- a/tools/buildbot/pylibs/buildbot/test/test_web.py +++ /dev/null @@ -1,535 +0,0 @@ -# -*- test-case-name: buildbot.test.test_web -*- - -import os, time, shutil -from twisted.python import components - -from twisted.trial import unittest -from buildbot.test.runutils import RunMixin - -from twisted.internet import reactor, defer, protocol -from twisted.internet.interfaces import IReactorUNIX -from twisted.web import client - -from buildbot import master, interfaces, sourcestamp -from buildbot.status import html, builder -from buildbot.status.web import waterfall -from buildbot.changes.changes import Change -from buildbot.process import base -from buildbot.process.buildstep import BuildStep -from buildbot.test.runutils import setupBuildStepStatus - -class ConfiguredMaster(master.BuildMaster): - """This BuildMaster variant has a static config file, provided as a - string when it is created.""" - - def __init__(self, basedir, config): - self.config = config - master.BuildMaster.__init__(self, basedir) - - def loadTheConfigFile(self): - self.loadConfig(self.config) - -components.registerAdapter(master.Control, ConfiguredMaster, - interfaces.IControl) - - -base_config = """ -from buildbot.changes.pb import PBChangeSource -from buildbot.status import html -from buildbot.buildslave import BuildSlave -from buildbot.scheduler import Scheduler -from buildbot.process.factory import BuildFactory - -BuildmasterConfig = c = { - 'change_source': PBChangeSource(), - 'slaves': [BuildSlave('bot1name', 'bot1passwd')], - 'schedulers': [Scheduler('name', None, 60, ['builder1'])], - 'builders': [{'name': 'builder1', 'slavename': 'bot1name', - 'builddir': 'builder1', 'factory': BuildFactory()}], - 'slavePortnum': 0, - } -""" - - - -class DistribUNIX: - def __init__(self, unixpath): - from twisted.web import server, resource, distrib - root = resource.Resource() - self.r = r = distrib.ResourceSubscription("unix", unixpath) - root.putChild('remote', r) - self.p = p = reactor.listenTCP(0, server.Site(root)) - self.portnum = p.getHost().port - def shutdown(self): - d = defer.maybeDeferred(self.p.stopListening) - return d - -class DistribTCP: - def __init__(self, port): - from twisted.web import server, resource, distrib - root = resource.Resource() - self.r = r = distrib.ResourceSubscription("localhost", port) - root.putChild('remote', r) - self.p = p = reactor.listenTCP(0, server.Site(root)) - self.portnum = p.getHost().port - def shutdown(self): - d = defer.maybeDeferred(self.p.stopListening) - d.addCallback(self._shutdown_1) - return d - def _shutdown_1(self, res): - return self.r.publisher.broker.transport.loseConnection() - -class SlowReader(protocol.Protocol): - didPause = False - count = 0 - data = "" - def __init__(self, req): - self.req = req - self.d = defer.Deferred() - def connectionMade(self): - self.transport.write(self.req) - def dataReceived(self, data): - self.data += data - self.count += len(data) - if not self.didPause and self.count > 10*1000: - self.didPause = True - self.transport.pauseProducing() - reactor.callLater(2, self.resume) - def resume(self): - self.transport.resumeProducing() - def connectionLost(self, why): - self.d.callback(None) - -class CFactory(protocol.ClientFactory): - def __init__(self, p): - self.p = p - def buildProtocol(self, addr): - self.p.factory = self - return self.p - -def stopHTTPLog(): - # grr. - from twisted.web import http - http._logDateTimeStop() - -class BaseWeb: - master = None - - def failUnlessIn(self, substr, string, note=None): - self.failUnless(string.find(substr) != -1, note) - - def tearDown(self): - stopHTTPLog() - if self.master: - d = self.master.stopService() - return d - - def find_webstatus(self, master): - for child in list(master): - if isinstance(child, html.WebStatus): - return child - - def find_waterfall(self, master): - for child in list(master): - if isinstance(child, html.Waterfall): - return child - -class Ports(BaseWeb, unittest.TestCase): - - def test_webPortnum(self): - # run a regular web server on a TCP socket - config = base_config + "c['status'] = [html.WebStatus(http_port=0)]\n" - os.mkdir("test_web1") - self.master = m = ConfiguredMaster("test_web1", config) - m.startService() - # hack to find out what randomly-assigned port it is listening on - port = self.find_webstatus(m).getPortnum() - - d = client.getPage("http://localhost:%d/waterfall" % port) - def _check(page): - #print page - self.failUnless(page) - d.addCallback(_check) - return d - test_webPortnum.timeout = 10 - - def test_webPathname(self): - # running a t.web.distrib server over a UNIX socket - if not IReactorUNIX.providedBy(reactor): - raise unittest.SkipTest("UNIX sockets not supported here") - config = (base_config + - "c['status'] = [html.WebStatus(distrib_port='.web-pb')]\n") - os.mkdir("test_web2") - self.master = m = ConfiguredMaster("test_web2", config) - m.startService() - - p = DistribUNIX("test_web2/.web-pb") - - d = client.getPage("http://localhost:%d/remote/waterfall" % p.portnum) - def _check(page): - self.failUnless(page) - d.addCallback(_check) - def _done(res): - d1 = p.shutdown() - d1.addCallback(lambda x: res) - return d1 - d.addBoth(_done) - return d - test_webPathname.timeout = 10 - - - def test_webPathname_port(self): - # running a t.web.distrib server over TCP - config = (base_config + - "c['status'] = [html.WebStatus(distrib_port=0)]\n") - os.mkdir("test_web3") - self.master = m = ConfiguredMaster("test_web3", config) - m.startService() - dport = self.find_webstatus(m).getPortnum() - - p = DistribTCP(dport) - - d = client.getPage("http://localhost:%d/remote/waterfall" % p.portnum) - def _check(page): - self.failUnlessIn("BuildBot", page) - d.addCallback(_check) - def _done(res): - d1 = p.shutdown() - d1.addCallback(lambda x: res) - return d1 - d.addBoth(_done) - return d - test_webPathname_port.timeout = 10 - - -class Waterfall(BaseWeb, unittest.TestCase): - def test_waterfall(self): - os.mkdir("test_web4") - os.mkdir("my-maildir"); os.mkdir("my-maildir/new") - self.robots_txt = os.path.abspath(os.path.join("test_web4", - "robots.txt")) - self.robots_txt_contents = "User-agent: *\nDisallow: /\n" - f = open(self.robots_txt, "w") - f.write(self.robots_txt_contents) - f.close() - # this is the right way to configure the Waterfall status - config1 = base_config + """ -from buildbot.changes import mail -c['change_source'] = mail.SyncmailMaildirSource('my-maildir') -c['status'] = [html.Waterfall(http_port=0, robots_txt=%s)] -""" % repr(self.robots_txt) - - self.master = m = ConfiguredMaster("test_web4", config1) - m.startService() - port = self.find_waterfall(m).getPortnum() - self.port = port - # insert an event - m.change_svc.addChange(Change("user", ["foo.c"], "comments")) - - d = client.getPage("http://localhost:%d/" % port) - - def _check1(page): - self.failUnless(page) - self.failUnlessIn("current activity", page) - self.failUnlessIn("Syncmail mailing list in maildir " + - "my-maildir", changes) - - return client.getPage("http://localhost:%d/robots.txt" % self.port) - d.addCallback(_check3) - - def _check4(robotstxt): - self.failUnless(robotstxt == self.robots_txt_contents) - d.addCallback(_check4) - - return d - - test_waterfall.timeout = 10 - -class WaterfallSteps(unittest.TestCase): - - # failUnlessSubstring copied from twisted-2.1.0, because this helps us - # maintain compatibility with python2.2. - def failUnlessSubstring(self, substring, astring, msg=None): - """a python2.2 friendly test to assert that substring is found in - astring parameters follow the semantics of failUnlessIn - """ - if astring.find(substring) == -1: - raise self.failureException(msg or "%r not found in %r" - % (substring, astring)) - return substring - assertSubstring = failUnlessSubstring - - def test_urls(self): - s = setupBuildStepStatus("test_web.test_urls") - s.addURL("coverage", "http://coverage.example.org/target") - s.addURL("icon", "http://coverage.example.org/icon.png") - class FakeRequest: - prepath = [] - postpath = [] - def childLink(self, name): - return name - req = FakeRequest() - box = waterfall.IBox(s).getBox(req) - td = box.td() - e1 = '[coverage]' - self.failUnlessSubstring(e1, td) - e2 = '[icon]' - self.failUnlessSubstring(e2, td) - - - -geturl_config = """ -from buildbot.status import html -from buildbot.changes import mail -from buildbot.process import factory -from buildbot.steps import dummy -from buildbot.scheduler import Scheduler -from buildbot.changes.base import ChangeSource -from buildbot.buildslave import BuildSlave -s = factory.s - -class DiscardScheduler(Scheduler): - def addChange(self, change): - pass -class DummyChangeSource(ChangeSource): - pass - -BuildmasterConfig = c = {} -c['slaves'] = [BuildSlave('bot1', 'sekrit'), BuildSlave('bot2', 'sekrit')] -c['change_source'] = DummyChangeSource() -c['schedulers'] = [DiscardScheduler('discard', None, 60, ['b1'])] -c['slavePortnum'] = 0 -c['status'] = [html.Waterfall(http_port=0)] - -f = factory.BuildFactory([s(dummy.RemoteDummy, timeout=1)]) - -c['builders'] = [ - {'name': 'b1', 'slavenames': ['bot1','bot2'], - 'builddir': 'b1', 'factory': f}, - ] -c['buildbotURL'] = 'http://dummy.example.org:8010/' - -""" - -class GetURL(RunMixin, unittest.TestCase): - - def setUp(self): - RunMixin.setUp(self) - self.master.loadConfig(geturl_config) - self.master.startService() - d = self.connectSlave(["b1"]) - return d - - def tearDown(self): - stopHTTPLog() - return RunMixin.tearDown(self) - - def doBuild(self, buildername): - br = base.BuildRequest("forced", sourcestamp.SourceStamp()) - d = br.waitUntilFinished() - self.control.getBuilder(buildername).requestBuild(br) - return d - - def assertNoURL(self, target): - self.failUnlessIdentical(self.status.getURLForThing(target), None) - - def assertURLEqual(self, target, expected): - got = self.status.getURLForThing(target) - full_expected = "http://dummy.example.org:8010/" + expected - self.failUnlessEqual(got, full_expected) - - def testMissingBase(self): - noweb_config1 = geturl_config + "del c['buildbotURL']\n" - d = self.master.loadConfig(noweb_config1) - d.addCallback(self._testMissingBase_1) - return d - def _testMissingBase_1(self, res): - s = self.status - self.assertNoURL(s) - builder_s = s.getBuilder("b1") - self.assertNoURL(builder_s) - - def testBase(self): - s = self.status - self.assertURLEqual(s, "") - builder_s = s.getBuilder("b1") - self.assertURLEqual(builder_s, "builders/b1") - - def testChange(self): - s = self.status - c = Change("user", ["foo.c"], "comments") - self.master.change_svc.addChange(c) - # TODO: something more like s.getChanges(), requires IChange and - # an accessor in IStatus. The HTML page exists already, though - self.assertURLEqual(c, "changes/1") - - def testBuild(self): - # first we do some stuff so we'll have things to look at. - s = self.status - d = self.doBuild("b1") - # maybe check IBuildSetStatus here? - d.addCallback(self._testBuild_1) - return d - - def _testBuild_1(self, res): - s = self.status - builder_s = s.getBuilder("b1") - build_s = builder_s.getLastFinishedBuild() - self.assertURLEqual(build_s, "builders/b1/builds/0") - # no page for builder.getEvent(-1) - step = build_s.getSteps()[0] - self.assertURLEqual(step, "builders/b1/builds/0/steps/remote%20dummy") - # maybe page for build.getTestResults? - self.assertURLEqual(step.getLogs()[0], - "builders/b1/builds/0/steps/remote%20dummy/logs/0") - - - -class Logfile(BaseWeb, RunMixin, unittest.TestCase): - def setUp(self): - config = """ -from buildbot.status import html -from buildbot.process.factory import BasicBuildFactory -from buildbot.buildslave import BuildSlave -f1 = BasicBuildFactory('cvsroot', 'cvsmodule') -BuildmasterConfig = { - 'slaves': [BuildSlave('bot1', 'passwd1')], - 'schedulers': [], - 'builders': [{'name': 'builder1', 'slavename': 'bot1', - 'builddir':'workdir', 'factory':f1}], - 'slavePortnum': 0, - 'status': [html.WebStatus(http_port=0)], - } -""" - if os.path.exists("test_logfile"): - shutil.rmtree("test_logfile") - os.mkdir("test_logfile") - self.master = m = ConfiguredMaster("test_logfile", config) - m.startService() - # hack to find out what randomly-assigned port it is listening on - port = self.find_webstatus(m).getPortnum() - self.port = port - # insert an event - - req = base.BuildRequest("reason", sourcestamp.SourceStamp()) - build1 = base.Build([req]) - bs = m.status.getBuilder("builder1").newBuild() - bs.setReason("reason") - bs.buildStarted(build1) - - step1 = BuildStep(name="setup") - step1.setBuild(build1) - bss = bs.addStepWithName("setup") - step1.setStepStatus(bss) - bss.stepStarted() - - log1 = step1.addLog("output") - log1.addStdout("some stdout\n") - log1.finish() - - log2 = step1.addHTMLLog("error", "ouch") - - log3 = step1.addLog("big") - log3.addStdout("big log\n") - for i in range(1000): - log3.addStdout("a" * 500) - log3.addStderr("b" * 500) - log3.finish() - - log4 = step1.addCompleteLog("bigcomplete", - "big2 log\n" + "a" * 1*1000*1000) - - step1.step_status.stepFinished(builder.SUCCESS) - bs.buildFinished() - - def getLogPath(self, stepname, logname): - return ("/builders/builder1/builds/0/steps/%s/logs/%s" % - (stepname, logname)) - - def getLogURL(self, stepname, logname): - return ("http://localhost:%d" % self.port - + self.getLogPath(stepname, logname)) - - def test_logfile1(self): - d = client.getPage("http://localhost:%d/" % self.port) - def _check(page): - self.failUnless(page) - d.addCallback(_check) - return d - - def test_logfile2(self): - logurl = self.getLogURL("setup", "output") - d = client.getPage(logurl) - def _check(logbody): - self.failUnless(logbody) - d.addCallback(_check) - return d - - def test_logfile3(self): - logurl = self.getLogURL("setup", "output") - d = client.getPage(logurl + "/text") - def _check(logtext): - self.failUnlessEqual(logtext, "some stdout\n") - d.addCallback(_check) - return d - - def test_logfile4(self): - logurl = self.getLogURL("setup", "error") - d = client.getPage(logurl) - def _check(logbody): - self.failUnlessEqual(logbody, "ouch") - d.addCallback(_check) - return d - - def test_logfile5(self): - # this is log3, which is about 1MB in size, made up of alternating - # stdout/stderr chunks. buildbot-0.6.6, when run against - # twisted-1.3.0, fails to resume sending chunks after the client - # stalls for a few seconds, because of a recursive doWrite() call - # that was fixed in twisted-2.0.0 - p = SlowReader("GET %s HTTP/1.0\r\n\r\n" - % self.getLogPath("setup", "big")) - cf = CFactory(p) - c = reactor.connectTCP("localhost", self.port, cf) - d = p.d - def _check(res): - self.failUnlessIn("big log", p.data) - self.failUnlessIn("a"*100, p.data) - self.failUnless(p.count > 1*1000*1000) - d.addCallback(_check) - return d - - def test_logfile6(self): - # this is log4, which is about 1MB in size, one big chunk. - # buildbot-0.6.6 dies as the NetstringReceiver barfs on the - # saved logfile, because it was using one big chunk and exceeding - # NetstringReceiver.MAX_LENGTH - p = SlowReader("GET %s HTTP/1.0\r\n\r\n" - % self.getLogPath("setup", "bigcomplete")) - cf = CFactory(p) - c = reactor.connectTCP("localhost", self.port, cf) - d = p.d - def _check(res): - self.failUnlessIn("big2 log", p.data) - self.failUnlessIn("a"*100, p.data) - self.failUnless(p.count > 1*1000*1000) - d.addCallback(_check) - return d - - diff --git a/tools/buildbot/pylibs/buildbot/test/test_webparts.py b/tools/buildbot/pylibs/buildbot/test/test_webparts.py deleted file mode 100644 index 71dd59e..0000000 --- a/tools/buildbot/pylibs/buildbot/test/test_webparts.py +++ /dev/null @@ -1,141 +0,0 @@ - -import os -from twisted.trial import unittest -from twisted.internet import defer -from twisted.web import client -from twisted.web.error import Error as WebError -from buildbot.slave.commands import rmdirRecursive -from buildbot.status import html -from test_web import BaseWeb, base_config, ConfiguredMaster -from buildbot.scripts import runner - -class Webparts(BaseWeb, unittest.TestCase): - - def find_webstatus(self, master): - return filter(lambda child: isinstance(child, html.WebStatus), - list(master)) - - def startMaster(self, extraconfig): - config = base_config + extraconfig - rmdirRecursive("test_webparts") - os.mkdir("test_webparts") - runner.upgradeMaster({'basedir': "test_webparts", - 'quiet': True, - }) - self.master = m = ConfiguredMaster("test_webparts", config) - m.startService() - # hack to find out what randomly-assigned port it is listening on - port = list(self.find_webstatus(m)[0])[0]._port.getHost().port - self.baseurl = "http://localhost:%d/" % port - - def reconfigMaster(self, extraconfig): - config = base_config + extraconfig - d = self.master.loadConfig(config) - def _done(res): - m = self.master - port = list(self.find_webstatus(m)[0])[0]._port.getHost().port - self.baseurl = "http://localhost:%d/" % port - d.addCallback(_done) - return d - - def getAndCheck(self, url, substring, show=False): - d = client.getPage(url) - def _show_weberror(why): - why.trap(WebError) - self.fail("error for %s: %s" % (url, why)) - d.addErrback(_show_weberror) - d.addCallback(self._getAndCheck, substring, show) - return d - def _getAndCheck(self, page, substring, show): - if show: - print page - self.failUnlessIn(substring, page, - "Couldn't find substring '%s' in page:\n%s" % - (substring, page)) - - def testInit(self): - extraconfig = """ -from twisted.web import static -ws = html.WebStatus(http_port=0) -c['status'] = [ws] -ws.putChild('child.html', static.Data('I am the child', 'text/plain')) -""" - self.startMaster(extraconfig) - d = self.getAndCheck(self.baseurl + "child.html", - "I am the child") - return d - testInit.timeout = 10 - - def testStatic(self): - extraconfig = """ -from twisted.web import static -ws = html.WebStatus(http_port=0) -c['status'] = [ws] -ws.putChild('child.html', static.Data('I am the child', 'text/plain')) -""" - self.startMaster(extraconfig) - os.mkdir(os.path.join("test_webparts", "public_html", "subdir")) - f = open(os.path.join("test_webparts", "public_html", "foo.html"), "wt") - f.write("see me foo\n") - f.close() - f = open(os.path.join("test_webparts", "public_html", "subdir", - "bar.html"), "wt") - f.write("see me subdir/bar\n") - f.close() - d = self.getAndCheck(self.baseurl + "child.html", "I am the child") - d.addCallback(lambda res: - self.getAndCheck(self.baseurl+"foo.html", - "see me foo")) - d.addCallback(lambda res: - self.getAndCheck(self.baseurl+"subdir/bar.html", - "see me subdir/bar")) - return d - - def _check(self, res, suburl, substring, show=False): - d = self.getAndCheck(self.baseurl + suburl, substring, show) - return d - - def testPages(self): - extraconfig = """ -ws = html.WebStatus(http_port=0) -c['status'] = [ws] -""" - self.startMaster(extraconfig) - d = defer.succeed(None) - d.addCallback(self._do_page_tests) - extraconfig2 = """ -ws = html.WebStatus(http_port=0, allowForce=True) -c['status'] = [ws] -""" - d.addCallback(lambda res: self.reconfigMaster(extraconfig2)) - d.addCallback(self._do_page_tests) - return d - - def _do_page_tests(self, res): - d = defer.succeed(None) - d.addCallback(self._check, "", "Welcome to the Buildbot") - d.addCallback(self._check, "waterfall", "current activity") - d.addCallback(self._check, "about", "Buildbot is a free software") - d.addCallback(self._check, "changes", "PBChangeSource listener") - d.addCallback(self._check, "buildslaves", "Build Slaves") - d.addCallback(self._check, "one_line_per_build", - "Last 20 finished builds") - d.addCallback(self._check, "one_box_per_builder", "Latest builds") - d.addCallback(self._check, "builders", "Builders") - d.addCallback(self._check, "builders/builder1", "Builder: builder1") - d.addCallback(self._check, "builders/builder1/builds", "") # dummy - # TODO: the pages beyond here would be great to test, but that would - # require causing a build to complete. - #d.addCallback(self._check, "builders/builder1/builds/1", "") - # it'd be nice to assert that the Build page has a "Stop Build" button - #d.addCallback(self._check, "builders/builder1/builds/1/steps", "") - #d.addCallback(self._check, - # "builders/builder1/builds/1/steps/compile", "") - #d.addCallback(self._check, - # "builders/builder1/builds/1/steps/compile/logs", "") - #d.addCallback(self._check, - # "builders/builder1/builds/1/steps/compile/logs/stdio","") - #d.addCallback(self._check, - # "builders/builder1/builds/1/steps/compile/logs/stdio/text", "") - return d - diff --git a/tools/buildbot/pylibs/buildbot/util.py b/tools/buildbot/pylibs/buildbot/util.py deleted file mode 100644 index 84b965d..0000000 --- a/tools/buildbot/pylibs/buildbot/util.py +++ /dev/null @@ -1,70 +0,0 @@ -# -*- test-case-name: buildbot.test.test_util -*- - -from twisted.internet.defer import Deferred -from twisted.spread import pb -import time - -def now(): - #return int(time.time()) - return time.time() - -def earlier(old, new): - # minimum of two things, but "None" counts as +infinity - if old: - if new < old: - return new - return old - return new - -def later(old, new): - # maximum of two things, but "None" counts as -infinity - if old: - if new > old: - return new - return old - return new - -class CancelableDeferred(Deferred): - """I am a version of Deferred that can be canceled by calling my - .cancel() method. After being canceled, no callbacks or errbacks will be - executed. - """ - def __init__(self): - Deferred.__init__(self) - self.canceled = 0 - def cancel(self): - self.canceled = 1 - def _runCallbacks(self): - if self.canceled: - self.callbacks = [] - return - Deferred._runCallbacks(self) - -def ignoreStaleRefs(failure): - """d.addErrback(util.ignoreStaleRefs)""" - r = failure.trap(pb.DeadReferenceError, pb.PBConnectionLost) - return None - -class _None: - pass - -class ComparableMixin: - """Specify a list of attributes that are 'important'. These will be used - for all comparison operations.""" - - compare_attrs = [] - - def __hash__(self): - alist = [self.__class__] + \ - [getattr(self, name, _None) for name in self.compare_attrs] - return hash(tuple(alist)) - - def __cmp__(self, them): - if cmp(type(self), type(them)): - return cmp(type(self), type(them)) - if cmp(self.__class__, them.__class__): - return cmp(self.__class__, them.__class__) - assert self.compare_attrs == them.compare_attrs - self_list= [getattr(self, name, _None) for name in self.compare_attrs] - them_list= [getattr(them, name, _None) for name in self.compare_attrs] - return cmp(self_list, them_list) diff --git a/tools/buildbot/pylibs/pytz/EGG-INFO/PKG-INFO b/tools/buildbot/pylibs/pytz/EGG-INFO/PKG-INFO deleted file mode 100644 index 33fcee9..0000000 --- a/tools/buildbot/pylibs/pytz/EGG-INFO/PKG-INFO +++ /dev/null @@ -1,52 +0,0 @@ -Metadata-Version: 1.0 -Name: pytz -Version: 2007k -Summary: World timezone definitions, modern and historical -Home-page: http://pytz.sourceforge.net -Author: Stuart Bishop -Author-email: stuart@stuartbishop.net -License: Copyright (c) 2003-2007 Stuart Bishop - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. - -Download-URL: http://cheeseshop.python.org/pypi/pytz -Description: World modern and historical timezone definitions, implemented as - Python tzinfo subclasses suitable for use my Python's datetime module. - Timezone information was provided by the Olson Timezone database. - Using these timezone definitions resolves all ambiguous daylight savings - time transitions. All DST trantions have been tested against the reference - implementation of zdump found in the Olson database to confirm even - the obscure historical cases work. This test suite is available separatly - as it is rather large (75558 comparisons), as is the program used - to generate this package. - - The Olson Timezone database is updated several times per year, - usually with obscure and generally unnoticable changes. These files - will be regenerated and rereleased soon after updated editions of the - Olson database are made available. - -Keywords: timezone,tzinfo,datetime,olson,time -Platform: Independant -Classifier: Development Status :: 6 - Mature -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: MIT License -Classifier: Natural Language :: English -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Topic :: Software Development :: Libraries :: Python Modules diff --git a/tools/buildbot/pylibs/pytz/EGG-INFO/SOURCES.txt b/tools/buildbot/pylibs/pytz/EGG-INFO/SOURCES.txt deleted file mode 100644 index b9e73d1..0000000 --- a/tools/buildbot/pylibs/pytz/EGG-INFO/SOURCES.txt +++ /dev/null @@ -1,581 +0,0 @@ -CHANGES.txt -LICENSE.txt -MANIFEST.in -PythonAPI.txt -README.txt -setup.py -pytz/__init__.py -pytz/reference.py -pytz/tzfile.py -pytz/tzinfo.py -pytz.egg-info/PKG-INFO -pytz.egg-info/SOURCES.txt -pytz.egg-info/dependency_links.txt -pytz.egg-info/top_level.txt -pytz.egg-info/zip-safe -pytz/tests/test_docs.py -pytz/tests/test_tzinfo.py -pytz/zoneinfo/CET -pytz/zoneinfo/CST6CDT -pytz/zoneinfo/Cuba -pytz/zoneinfo/EET -pytz/zoneinfo/EST -pytz/zoneinfo/EST5EDT -pytz/zoneinfo/Egypt -pytz/zoneinfo/Eire -pytz/zoneinfo/Factory -pytz/zoneinfo/GB -pytz/zoneinfo/GB-Eire -pytz/zoneinfo/GMT -pytz/zoneinfo/GMT+0 -pytz/zoneinfo/GMT-0 -pytz/zoneinfo/GMT0 -pytz/zoneinfo/Greenwich -pytz/zoneinfo/HST -pytz/zoneinfo/Hongkong -pytz/zoneinfo/Iceland -pytz/zoneinfo/Iran -pytz/zoneinfo/Israel -pytz/zoneinfo/Jamaica -pytz/zoneinfo/Japan -pytz/zoneinfo/Kwajalein -pytz/zoneinfo/Libya -pytz/zoneinfo/MET -pytz/zoneinfo/MST -pytz/zoneinfo/MST7MDT -pytz/zoneinfo/NZ -pytz/zoneinfo/NZ-CHAT -pytz/zoneinfo/Navajo -pytz/zoneinfo/PRC -pytz/zoneinfo/PST8PDT -pytz/zoneinfo/Poland -pytz/zoneinfo/Portugal -pytz/zoneinfo/ROC -pytz/zoneinfo/ROK -pytz/zoneinfo/Singapore -pytz/zoneinfo/Turkey -pytz/zoneinfo/UCT -pytz/zoneinfo/UTC -pytz/zoneinfo/Universal -pytz/zoneinfo/W-SU -pytz/zoneinfo/WET -pytz/zoneinfo/Zulu -pytz/zoneinfo/iso3166.tab -pytz/zoneinfo/localtime -pytz/zoneinfo/posixrules -pytz/zoneinfo/zone.tab -pytz/zoneinfo/Africa/Abidjan -pytz/zoneinfo/Africa/Accra -pytz/zoneinfo/Africa/Addis_Ababa -pytz/zoneinfo/Africa/Algiers -pytz/zoneinfo/Africa/Asmara -pytz/zoneinfo/Africa/Asmera -pytz/zoneinfo/Africa/Bamako -pytz/zoneinfo/Africa/Bangui -pytz/zoneinfo/Africa/Banjul -pytz/zoneinfo/Africa/Bissau -pytz/zoneinfo/Africa/Blantyre -pytz/zoneinfo/Africa/Brazzaville -pytz/zoneinfo/Africa/Bujumbura -pytz/zoneinfo/Africa/Cairo -pytz/zoneinfo/Africa/Casablanca -pytz/zoneinfo/Africa/Ceuta -pytz/zoneinfo/Africa/Conakry -pytz/zoneinfo/Africa/Dakar -pytz/zoneinfo/Africa/Dar_es_Salaam -pytz/zoneinfo/Africa/Djibouti -pytz/zoneinfo/Africa/Douala -pytz/zoneinfo/Africa/El_Aaiun -pytz/zoneinfo/Africa/Freetown -pytz/zoneinfo/Africa/Gaborone -pytz/zoneinfo/Africa/Harare -pytz/zoneinfo/Africa/Johannesburg -pytz/zoneinfo/Africa/Kampala -pytz/zoneinfo/Africa/Khartoum -pytz/zoneinfo/Africa/Kigali -pytz/zoneinfo/Africa/Kinshasa -pytz/zoneinfo/Africa/Lagos -pytz/zoneinfo/Africa/Libreville -pytz/zoneinfo/Africa/Lome -pytz/zoneinfo/Africa/Luanda -pytz/zoneinfo/Africa/Lubumbashi -pytz/zoneinfo/Africa/Lusaka -pytz/zoneinfo/Africa/Malabo -pytz/zoneinfo/Africa/Maputo -pytz/zoneinfo/Africa/Maseru -pytz/zoneinfo/Africa/Mbabane -pytz/zoneinfo/Africa/Mogadishu -pytz/zoneinfo/Africa/Monrovia -pytz/zoneinfo/Africa/Nairobi -pytz/zoneinfo/Africa/Ndjamena -pytz/zoneinfo/Africa/Niamey -pytz/zoneinfo/Africa/Nouakchott -pytz/zoneinfo/Africa/Ouagadougou -pytz/zoneinfo/Africa/Porto-Novo -pytz/zoneinfo/Africa/Sao_Tome -pytz/zoneinfo/Africa/Timbuktu -pytz/zoneinfo/Africa/Tripoli -pytz/zoneinfo/Africa/Tunis -pytz/zoneinfo/Africa/Windhoek -pytz/zoneinfo/America/Adak -pytz/zoneinfo/America/Anchorage -pytz/zoneinfo/America/Anguilla -pytz/zoneinfo/America/Antigua -pytz/zoneinfo/America/Araguaina -pytz/zoneinfo/America/Aruba -pytz/zoneinfo/America/Asuncion -pytz/zoneinfo/America/Atikokan -pytz/zoneinfo/America/Atka -pytz/zoneinfo/America/Bahia -pytz/zoneinfo/America/Barbados -pytz/zoneinfo/America/Belem -pytz/zoneinfo/America/Belize -pytz/zoneinfo/America/Blanc-Sablon -pytz/zoneinfo/America/Boa_Vista -pytz/zoneinfo/America/Bogota -pytz/zoneinfo/America/Boise -pytz/zoneinfo/America/Buenos_Aires -pytz/zoneinfo/America/Cambridge_Bay -pytz/zoneinfo/America/Campo_Grande -pytz/zoneinfo/America/Cancun -pytz/zoneinfo/America/Caracas -pytz/zoneinfo/America/Catamarca -pytz/zoneinfo/America/Cayenne -pytz/zoneinfo/America/Cayman -pytz/zoneinfo/America/Chicago -pytz/zoneinfo/America/Chihuahua -pytz/zoneinfo/America/Coral_Harbour -pytz/zoneinfo/America/Cordoba -pytz/zoneinfo/America/Costa_Rica -pytz/zoneinfo/America/Cuiaba -pytz/zoneinfo/America/Curacao -pytz/zoneinfo/America/Danmarkshavn -pytz/zoneinfo/America/Dawson -pytz/zoneinfo/America/Dawson_Creek -pytz/zoneinfo/America/Denver -pytz/zoneinfo/America/Detroit -pytz/zoneinfo/America/Dominica -pytz/zoneinfo/America/Edmonton -pytz/zoneinfo/America/Eirunepe -pytz/zoneinfo/America/El_Salvador -pytz/zoneinfo/America/Ensenada -pytz/zoneinfo/America/Fort_Wayne -pytz/zoneinfo/America/Fortaleza -pytz/zoneinfo/America/Glace_Bay -pytz/zoneinfo/America/Godthab -pytz/zoneinfo/America/Goose_Bay -pytz/zoneinfo/America/Grand_Turk -pytz/zoneinfo/America/Grenada -pytz/zoneinfo/America/Guadeloupe -pytz/zoneinfo/America/Guatemala -pytz/zoneinfo/America/Guayaquil -pytz/zoneinfo/America/Guyana -pytz/zoneinfo/America/Halifax -pytz/zoneinfo/America/Havana -pytz/zoneinfo/America/Hermosillo -pytz/zoneinfo/America/Indianapolis -pytz/zoneinfo/America/Inuvik -pytz/zoneinfo/America/Iqaluit -pytz/zoneinfo/America/Jamaica -pytz/zoneinfo/America/Jujuy -pytz/zoneinfo/America/Juneau -pytz/zoneinfo/America/Knox_IN -pytz/zoneinfo/America/La_Paz -pytz/zoneinfo/America/Lima -pytz/zoneinfo/America/Los_Angeles -pytz/zoneinfo/America/Louisville -pytz/zoneinfo/America/Maceio -pytz/zoneinfo/America/Managua -pytz/zoneinfo/America/Manaus -pytz/zoneinfo/America/Marigot -pytz/zoneinfo/America/Martinique -pytz/zoneinfo/America/Mazatlan -pytz/zoneinfo/America/Mendoza -pytz/zoneinfo/America/Menominee -pytz/zoneinfo/America/Merida -pytz/zoneinfo/America/Mexico_City -pytz/zoneinfo/America/Miquelon -pytz/zoneinfo/America/Moncton -pytz/zoneinfo/America/Monterrey -pytz/zoneinfo/America/Montevideo -pytz/zoneinfo/America/Montreal -pytz/zoneinfo/America/Montserrat -pytz/zoneinfo/America/Nassau -pytz/zoneinfo/America/New_York -pytz/zoneinfo/America/Nipigon -pytz/zoneinfo/America/Nome -pytz/zoneinfo/America/Noronha -pytz/zoneinfo/America/Panama -pytz/zoneinfo/America/Pangnirtung -pytz/zoneinfo/America/Paramaribo -pytz/zoneinfo/America/Phoenix -pytz/zoneinfo/America/Port-au-Prince -pytz/zoneinfo/America/Port_of_Spain -pytz/zoneinfo/America/Porto_Acre -pytz/zoneinfo/America/Porto_Velho -pytz/zoneinfo/America/Puerto_Rico -pytz/zoneinfo/America/Rainy_River -pytz/zoneinfo/America/Rankin_Inlet -pytz/zoneinfo/America/Recife -pytz/zoneinfo/America/Regina -pytz/zoneinfo/America/Resolute -pytz/zoneinfo/America/Rio_Branco -pytz/zoneinfo/America/Rosario -pytz/zoneinfo/America/Santiago -pytz/zoneinfo/America/Santo_Domingo -pytz/zoneinfo/America/Sao_Paulo -pytz/zoneinfo/America/Scoresbysund -pytz/zoneinfo/America/Shiprock -pytz/zoneinfo/America/St_Barthelemy -pytz/zoneinfo/America/St_Johns -pytz/zoneinfo/America/St_Kitts -pytz/zoneinfo/America/St_Lucia -pytz/zoneinfo/America/St_Thomas -pytz/zoneinfo/America/St_Vincent -pytz/zoneinfo/America/Swift_Current -pytz/zoneinfo/America/Tegucigalpa -pytz/zoneinfo/America/Thule -pytz/zoneinfo/America/Thunder_Bay -pytz/zoneinfo/America/Tijuana -pytz/zoneinfo/America/Toronto -pytz/zoneinfo/America/Tortola -pytz/zoneinfo/America/Vancouver -pytz/zoneinfo/America/Virgin -pytz/zoneinfo/America/Whitehorse -pytz/zoneinfo/America/Winnipeg -pytz/zoneinfo/America/Yakutat -pytz/zoneinfo/America/Yellowknife -pytz/zoneinfo/America/Argentina/Buenos_Aires -pytz/zoneinfo/America/Argentina/Catamarca -pytz/zoneinfo/America/Argentina/ComodRivadavia -pytz/zoneinfo/America/Argentina/Cordoba -pytz/zoneinfo/America/Argentina/Jujuy -pytz/zoneinfo/America/Argentina/La_Rioja -pytz/zoneinfo/America/Argentina/Mendoza -pytz/zoneinfo/America/Argentina/Rio_Gallegos -pytz/zoneinfo/America/Argentina/San_Juan -pytz/zoneinfo/America/Argentina/Tucuman -pytz/zoneinfo/America/Argentina/Ushuaia -pytz/zoneinfo/America/Indiana/Indianapolis -pytz/zoneinfo/America/Indiana/Knox -pytz/zoneinfo/America/Indiana/Marengo -pytz/zoneinfo/America/Indiana/Petersburg -pytz/zoneinfo/America/Indiana/Tell_City -pytz/zoneinfo/America/Indiana/Vevay -pytz/zoneinfo/America/Indiana/Vincennes -pytz/zoneinfo/America/Indiana/Winamac -pytz/zoneinfo/America/Kentucky/Louisville -pytz/zoneinfo/America/Kentucky/Monticello -pytz/zoneinfo/America/North_Dakota/Center -pytz/zoneinfo/America/North_Dakota/New_Salem -pytz/zoneinfo/Antarctica/Casey -pytz/zoneinfo/Antarctica/Davis -pytz/zoneinfo/Antarctica/DumontDUrville -pytz/zoneinfo/Antarctica/Mawson -pytz/zoneinfo/Antarctica/McMurdo -pytz/zoneinfo/Antarctica/Palmer -pytz/zoneinfo/Antarctica/Rothera -pytz/zoneinfo/Antarctica/South_Pole -pytz/zoneinfo/Antarctica/Syowa -pytz/zoneinfo/Antarctica/Vostok -pytz/zoneinfo/Arctic/Longyearbyen -pytz/zoneinfo/Asia/Aden -pytz/zoneinfo/Asia/Almaty -pytz/zoneinfo/Asia/Amman -pytz/zoneinfo/Asia/Anadyr -pytz/zoneinfo/Asia/Aqtau -pytz/zoneinfo/Asia/Aqtobe -pytz/zoneinfo/Asia/Ashgabat -pytz/zoneinfo/Asia/Ashkhabad -pytz/zoneinfo/Asia/Baghdad -pytz/zoneinfo/Asia/Bahrain -pytz/zoneinfo/Asia/Baku -pytz/zoneinfo/Asia/Bangkok -pytz/zoneinfo/Asia/Beirut -pytz/zoneinfo/Asia/Bishkek -pytz/zoneinfo/Asia/Brunei -pytz/zoneinfo/Asia/Calcutta -pytz/zoneinfo/Asia/Choibalsan -pytz/zoneinfo/Asia/Chongqing -pytz/zoneinfo/Asia/Chungking -pytz/zoneinfo/Asia/Colombo -pytz/zoneinfo/Asia/Dacca -pytz/zoneinfo/Asia/Damascus -pytz/zoneinfo/Asia/Dhaka -pytz/zoneinfo/Asia/Dili -pytz/zoneinfo/Asia/Dubai -pytz/zoneinfo/Asia/Dushanbe -pytz/zoneinfo/Asia/Gaza -pytz/zoneinfo/Asia/Harbin -pytz/zoneinfo/Asia/Hong_Kong -pytz/zoneinfo/Asia/Hovd -pytz/zoneinfo/Asia/Irkutsk -pytz/zoneinfo/Asia/Istanbul -pytz/zoneinfo/Asia/Jakarta -pytz/zoneinfo/Asia/Jayapura -pytz/zoneinfo/Asia/Jerusalem -pytz/zoneinfo/Asia/Kabul -pytz/zoneinfo/Asia/Kamchatka -pytz/zoneinfo/Asia/Karachi -pytz/zoneinfo/Asia/Kashgar -pytz/zoneinfo/Asia/Katmandu -pytz/zoneinfo/Asia/Krasnoyarsk -pytz/zoneinfo/Asia/Kuala_Lumpur -pytz/zoneinfo/Asia/Kuching -pytz/zoneinfo/Asia/Kuwait -pytz/zoneinfo/Asia/Macao -pytz/zoneinfo/Asia/Macau -pytz/zoneinfo/Asia/Magadan -pytz/zoneinfo/Asia/Makassar -pytz/zoneinfo/Asia/Manila -pytz/zoneinfo/Asia/Muscat -pytz/zoneinfo/Asia/Nicosia -pytz/zoneinfo/Asia/Novosibirsk -pytz/zoneinfo/Asia/Omsk -pytz/zoneinfo/Asia/Oral -pytz/zoneinfo/Asia/Phnom_Penh -pytz/zoneinfo/Asia/Pontianak -pytz/zoneinfo/Asia/Pyongyang -pytz/zoneinfo/Asia/Qatar -pytz/zoneinfo/Asia/Qyzylorda -pytz/zoneinfo/Asia/Rangoon -pytz/zoneinfo/Asia/Riyadh -pytz/zoneinfo/Asia/Riyadh87 -pytz/zoneinfo/Asia/Riyadh88 -pytz/zoneinfo/Asia/Riyadh89 -pytz/zoneinfo/Asia/Saigon -pytz/zoneinfo/Asia/Sakhalin -pytz/zoneinfo/Asia/Samarkand -pytz/zoneinfo/Asia/Seoul -pytz/zoneinfo/Asia/Shanghai -pytz/zoneinfo/Asia/Singapore -pytz/zoneinfo/Asia/Taipei -pytz/zoneinfo/Asia/Tashkent -pytz/zoneinfo/Asia/Tbilisi -pytz/zoneinfo/Asia/Tehran -pytz/zoneinfo/Asia/Tel_Aviv -pytz/zoneinfo/Asia/Thimbu -pytz/zoneinfo/Asia/Thimphu -pytz/zoneinfo/Asia/Tokyo -pytz/zoneinfo/Asia/Ujung_Pandang -pytz/zoneinfo/Asia/Ulaanbaatar -pytz/zoneinfo/Asia/Ulan_Bator -pytz/zoneinfo/Asia/Urumqi -pytz/zoneinfo/Asia/Vientiane -pytz/zoneinfo/Asia/Vladivostok -pytz/zoneinfo/Asia/Yakutsk -pytz/zoneinfo/Asia/Yekaterinburg -pytz/zoneinfo/Asia/Yerevan -pytz/zoneinfo/Atlantic/Azores -pytz/zoneinfo/Atlantic/Bermuda -pytz/zoneinfo/Atlantic/Canary -pytz/zoneinfo/Atlantic/Cape_Verde -pytz/zoneinfo/Atlantic/Faeroe -pytz/zoneinfo/Atlantic/Faroe -pytz/zoneinfo/Atlantic/Jan_Mayen -pytz/zoneinfo/Atlantic/Madeira -pytz/zoneinfo/Atlantic/Reykjavik -pytz/zoneinfo/Atlantic/South_Georgia -pytz/zoneinfo/Atlantic/St_Helena -pytz/zoneinfo/Atlantic/Stanley -pytz/zoneinfo/Australia/ACT -pytz/zoneinfo/Australia/Adelaide -pytz/zoneinfo/Australia/Brisbane -pytz/zoneinfo/Australia/Broken_Hill -pytz/zoneinfo/Australia/Canberra -pytz/zoneinfo/Australia/Currie -pytz/zoneinfo/Australia/Darwin -pytz/zoneinfo/Australia/Eucla -pytz/zoneinfo/Australia/Hobart -pytz/zoneinfo/Australia/LHI -pytz/zoneinfo/Australia/Lindeman -pytz/zoneinfo/Australia/Lord_Howe -pytz/zoneinfo/Australia/Melbourne -pytz/zoneinfo/Australia/NSW -pytz/zoneinfo/Australia/North -pytz/zoneinfo/Australia/Perth -pytz/zoneinfo/Australia/Queensland -pytz/zoneinfo/Australia/South -pytz/zoneinfo/Australia/Sydney -pytz/zoneinfo/Australia/Tasmania -pytz/zoneinfo/Australia/Victoria -pytz/zoneinfo/Australia/West -pytz/zoneinfo/Australia/Yancowinna -pytz/zoneinfo/Brazil/Acre -pytz/zoneinfo/Brazil/DeNoronha -pytz/zoneinfo/Brazil/East -pytz/zoneinfo/Brazil/West -pytz/zoneinfo/Canada/Atlantic -pytz/zoneinfo/Canada/Central -pytz/zoneinfo/Canada/East-Saskatchewan -pytz/zoneinfo/Canada/Eastern -pytz/zoneinfo/Canada/Mountain -pytz/zoneinfo/Canada/Newfoundland -pytz/zoneinfo/Canada/Pacific -pytz/zoneinfo/Canada/Saskatchewan -pytz/zoneinfo/Canada/Yukon -pytz/zoneinfo/Chile/Continental -pytz/zoneinfo/Chile/EasterIsland -pytz/zoneinfo/Etc/GMT -pytz/zoneinfo/Etc/GMT+0 -pytz/zoneinfo/Etc/GMT+1 -pytz/zoneinfo/Etc/GMT+10 -pytz/zoneinfo/Etc/GMT+11 -pytz/zoneinfo/Etc/GMT+12 -pytz/zoneinfo/Etc/GMT+2 -pytz/zoneinfo/Etc/GMT+3 -pytz/zoneinfo/Etc/GMT+4 -pytz/zoneinfo/Etc/GMT+5 -pytz/zoneinfo/Etc/GMT+6 -pytz/zoneinfo/Etc/GMT+7 -pytz/zoneinfo/Etc/GMT+8 -pytz/zoneinfo/Etc/GMT+9 -pytz/zoneinfo/Etc/GMT-0 -pytz/zoneinfo/Etc/GMT-1 -pytz/zoneinfo/Etc/GMT-10 -pytz/zoneinfo/Etc/GMT-11 -pytz/zoneinfo/Etc/GMT-12 -pytz/zoneinfo/Etc/GMT-13 -pytz/zoneinfo/Etc/GMT-14 -pytz/zoneinfo/Etc/GMT-2 -pytz/zoneinfo/Etc/GMT-3 -pytz/zoneinfo/Etc/GMT-4 -pytz/zoneinfo/Etc/GMT-5 -pytz/zoneinfo/Etc/GMT-6 -pytz/zoneinfo/Etc/GMT-7 -pytz/zoneinfo/Etc/GMT-8 -pytz/zoneinfo/Etc/GMT-9 -pytz/zoneinfo/Etc/GMT0 -pytz/zoneinfo/Etc/Greenwich -pytz/zoneinfo/Etc/UCT -pytz/zoneinfo/Etc/UTC -pytz/zoneinfo/Etc/Universal -pytz/zoneinfo/Etc/Zulu -pytz/zoneinfo/Europe/Amsterdam -pytz/zoneinfo/Europe/Andorra -pytz/zoneinfo/Europe/Athens -pytz/zoneinfo/Europe/Belfast -pytz/zoneinfo/Europe/Belgrade -pytz/zoneinfo/Europe/Berlin -pytz/zoneinfo/Europe/Bratislava -pytz/zoneinfo/Europe/Brussels -pytz/zoneinfo/Europe/Bucharest -pytz/zoneinfo/Europe/Budapest -pytz/zoneinfo/Europe/Chisinau -pytz/zoneinfo/Europe/Copenhagen -pytz/zoneinfo/Europe/Dublin -pytz/zoneinfo/Europe/Gibraltar -pytz/zoneinfo/Europe/Guernsey -pytz/zoneinfo/Europe/Helsinki -pytz/zoneinfo/Europe/Isle_of_Man -pytz/zoneinfo/Europe/Istanbul -pytz/zoneinfo/Europe/Jersey -pytz/zoneinfo/Europe/Kaliningrad -pytz/zoneinfo/Europe/Kiev -pytz/zoneinfo/Europe/Lisbon -pytz/zoneinfo/Europe/Ljubljana -pytz/zoneinfo/Europe/London -pytz/zoneinfo/Europe/Luxembourg -pytz/zoneinfo/Europe/Madrid -pytz/zoneinfo/Europe/Malta -pytz/zoneinfo/Europe/Mariehamn -pytz/zoneinfo/Europe/Minsk -pytz/zoneinfo/Europe/Monaco -pytz/zoneinfo/Europe/Moscow -pytz/zoneinfo/Europe/Nicosia -pytz/zoneinfo/Europe/Oslo -pytz/zoneinfo/Europe/Paris -pytz/zoneinfo/Europe/Podgorica -pytz/zoneinfo/Europe/Prague -pytz/zoneinfo/Europe/Riga -pytz/zoneinfo/Europe/Rome -pytz/zoneinfo/Europe/Samara -pytz/zoneinfo/Europe/San_Marino -pytz/zoneinfo/Europe/Sarajevo -pytz/zoneinfo/Europe/Simferopol -pytz/zoneinfo/Europe/Skopje -pytz/zoneinfo/Europe/Sofia -pytz/zoneinfo/Europe/Stockholm -pytz/zoneinfo/Europe/Tallinn -pytz/zoneinfo/Europe/Tirane -pytz/zoneinfo/Europe/Tiraspol -pytz/zoneinfo/Europe/Uzhgorod -pytz/zoneinfo/Europe/Vaduz -pytz/zoneinfo/Europe/Vatican -pytz/zoneinfo/Europe/Vienna -pytz/zoneinfo/Europe/Vilnius -pytz/zoneinfo/Europe/Volgograd -pytz/zoneinfo/Europe/Warsaw -pytz/zoneinfo/Europe/Zagreb -pytz/zoneinfo/Europe/Zaporozhye -pytz/zoneinfo/Europe/Zurich -pytz/zoneinfo/Indian/Antananarivo -pytz/zoneinfo/Indian/Chagos -pytz/zoneinfo/Indian/Christmas -pytz/zoneinfo/Indian/Cocos -pytz/zoneinfo/Indian/Comoro -pytz/zoneinfo/Indian/Kerguelen -pytz/zoneinfo/Indian/Mahe -pytz/zoneinfo/Indian/Maldives -pytz/zoneinfo/Indian/Mauritius -pytz/zoneinfo/Indian/Mayotte -pytz/zoneinfo/Indian/Reunion -pytz/zoneinfo/Mexico/BajaNorte -pytz/zoneinfo/Mexico/BajaSur -pytz/zoneinfo/Mexico/General -pytz/zoneinfo/Mideast/Riyadh87 -pytz/zoneinfo/Mideast/Riyadh88 -pytz/zoneinfo/Mideast/Riyadh89 -pytz/zoneinfo/Pacific/Apia -pytz/zoneinfo/Pacific/Auckland -pytz/zoneinfo/Pacific/Chatham -pytz/zoneinfo/Pacific/Easter -pytz/zoneinfo/Pacific/Efate -pytz/zoneinfo/Pacific/Enderbury -pytz/zoneinfo/Pacific/Fakaofo -pytz/zoneinfo/Pacific/Fiji -pytz/zoneinfo/Pacific/Funafuti -pytz/zoneinfo/Pacific/Galapagos -pytz/zoneinfo/Pacific/Gambier -pytz/zoneinfo/Pacific/Guadalcanal -pytz/zoneinfo/Pacific/Guam -pytz/zoneinfo/Pacific/Honolulu -pytz/zoneinfo/Pacific/Johnston -pytz/zoneinfo/Pacific/Kiritimati -pytz/zoneinfo/Pacific/Kosrae -pytz/zoneinfo/Pacific/Kwajalein -pytz/zoneinfo/Pacific/Majuro -pytz/zoneinfo/Pacific/Marquesas -pytz/zoneinfo/Pacific/Midway -pytz/zoneinfo/Pacific/Nauru -pytz/zoneinfo/Pacific/Niue -pytz/zoneinfo/Pacific/Norfolk -pytz/zoneinfo/Pacific/Noumea -pytz/zoneinfo/Pacific/Pago_Pago -pytz/zoneinfo/Pacific/Palau -pytz/zoneinfo/Pacific/Pitcairn -pytz/zoneinfo/Pacific/Ponape -pytz/zoneinfo/Pacific/Port_Moresby -pytz/zoneinfo/Pacific/Rarotonga -pytz/zoneinfo/Pacific/Saipan -pytz/zoneinfo/Pacific/Samoa -pytz/zoneinfo/Pacific/Tahiti -pytz/zoneinfo/Pacific/Tarawa -pytz/zoneinfo/Pacific/Tongatapu -pytz/zoneinfo/Pacific/Truk -pytz/zoneinfo/Pacific/Wake -pytz/zoneinfo/Pacific/Wallis -pytz/zoneinfo/Pacific/Yap -pytz/zoneinfo/US/Alaska -pytz/zoneinfo/US/Aleutian -pytz/zoneinfo/US/Arizona -pytz/zoneinfo/US/Central -pytz/zoneinfo/US/East-Indiana -pytz/zoneinfo/US/Eastern -pytz/zoneinfo/US/Hawaii -pytz/zoneinfo/US/Indiana-Starke -pytz/zoneinfo/US/Michigan -pytz/zoneinfo/US/Mountain -pytz/zoneinfo/US/Pacific -pytz/zoneinfo/US/Pacific-New -pytz/zoneinfo/US/Samoa diff --git a/tools/buildbot/pylibs/pytz/EGG-INFO/dependency_links.txt b/tools/buildbot/pylibs/pytz/EGG-INFO/dependency_links.txt deleted file mode 100644 index 8b13789..0000000 --- a/tools/buildbot/pylibs/pytz/EGG-INFO/dependency_links.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tools/buildbot/pylibs/pytz/EGG-INFO/top_level.txt b/tools/buildbot/pylibs/pytz/EGG-INFO/top_level.txt deleted file mode 100644 index af44f19..0000000 --- a/tools/buildbot/pylibs/pytz/EGG-INFO/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -pytz diff --git a/tools/buildbot/pylibs/pytz/EGG-INFO/zip-safe b/tools/buildbot/pylibs/pytz/EGG-INFO/zip-safe deleted file mode 100644 index 8b13789..0000000 --- a/tools/buildbot/pylibs/pytz/EGG-INFO/zip-safe +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tools/buildbot/pylibs/pytz/README.google b/tools/buildbot/pylibs/pytz/README.google deleted file mode 100644 index 0aa7f72..0000000 --- a/tools/buildbot/pylibs/pytz/README.google +++ /dev/null @@ -1,4 +0,0 @@ -URL: http://pytz.sourceforge.net -Version: 2007k -License: MIT -License File: EGG-INFO\PKG-INFO diff --git a/tools/buildbot/pylibs/pytz/__init__.py b/tools/buildbot/pylibs/pytz/__init__.py deleted file mode 100644 index 1488c05..0000000 --- a/tools/buildbot/pylibs/pytz/__init__.py +++ /dev/null @@ -1,1400 +0,0 @@ -''' -datetime.tzinfo timezone definitions generated from the -Olson timezone database: - - ftp://elsie.nci.nih.gov/pub/tz*.tar.gz - -See the datetime section of the Python Library Reference for information -on how to use these modules. -''' - -# The Olson database has historically been updated about 4 times a year -OLSON_VERSION = '2007k' -VERSION = OLSON_VERSION -#VERSION = OLSON_VERSION + '.2' -__version__ = OLSON_VERSION - -OLSEN_VERSION = OLSON_VERSION # Old releases had this misspelling - -__all__ = [ - 'timezone', 'utc', 'country_timezones', - 'AmbiguousTimeError', 'UnknownTimeZoneError', - 'all_timezones', 'all_timezones_set', - 'common_timezones', 'common_timezones_set', - ] - -import sys, datetime, os.path, gettext - -try: - from pkg_resources import resource_stream -except ImportError: - resource_stream = None - -from tzinfo import AmbiguousTimeError, unpickler -from tzfile import build_tzinfo - -# Use 2.3 sets module implementation if set builtin is not available -try: - set -except NameError: - from sets import Set as set - - -def open_resource(name): - """Open a resource from the zoneinfo subdir for reading. - - Uses the pkg_resources module if available. - """ - if resource_stream is not None: - return resource_stream(__name__, 'zoneinfo/' + name) - else: - name_parts = name.lstrip('/').split('/') - for part in name_parts: - if part == os.path.pardir or os.path.sep in part: - raise ValueError('Bad path segment: %r' % part) - filename = os.path.join(os.path.dirname(__file__), - 'zoneinfo', *name_parts) - return open(filename, 'rb') - - -# Enable this when we get some translations? -# We want an i18n API that is useful to programs using Python's gettext -# module, as well as the Zope3 i18n package. Perhaps we should just provide -# the POT file and translations, and leave it up to callers to make use -# of them. -# -# t = gettext.translation( -# 'pytz', os.path.join(os.path.dirname(__file__), 'locales'), -# fallback=True -# ) -# def _(timezone_name): -# """Translate a timezone name using the current locale, returning Unicode""" -# return t.ugettext(timezone_name) - - -class UnknownTimeZoneError(KeyError): - '''Exception raised when pytz is passed an unknown timezone. - - >>> isinstance(UnknownTimeZoneError(), LookupError) - True - - This class is actually a subclass of KeyError to provide backwards - compatibility with code relying on the undocumented behavior of earlier - pytz releases. - - >>> isinstance(UnknownTimeZoneError(), KeyError) - True - ''' - pass - - -_tzinfo_cache = {} - -def timezone(zone): - r''' Return a datetime.tzinfo implementation for the given timezone - - >>> from datetime import datetime, timedelta - >>> utc = timezone('UTC') - >>> eastern = timezone('US/Eastern') - >>> eastern.zone - 'US/Eastern' - >>> timezone(u'US/Eastern') is eastern - True - >>> utc_dt = datetime(2002, 10, 27, 6, 0, 0, tzinfo=utc) - >>> loc_dt = utc_dt.astimezone(eastern) - >>> fmt = '%Y-%m-%d %H:%M:%S %Z (%z)' - >>> loc_dt.strftime(fmt) - '2002-10-27 01:00:00 EST (-0500)' - >>> (loc_dt - timedelta(minutes=10)).strftime(fmt) - '2002-10-27 00:50:00 EST (-0500)' - >>> eastern.normalize(loc_dt - timedelta(minutes=10)).strftime(fmt) - '2002-10-27 01:50:00 EDT (-0400)' - >>> (loc_dt + timedelta(minutes=10)).strftime(fmt) - '2002-10-27 01:10:00 EST (-0500)' - - Raises UnknownTimeZoneError if passed an unknown zone. - - >>> timezone('Asia/Shangri-La') - Traceback (most recent call last): - ... - UnknownTimeZoneError: 'Asia/Shangri-La' - - >>> timezone(u'\N{TRADE MARK SIGN}') - Traceback (most recent call last): - ... - UnknownTimeZoneError: u'\u2122' - ''' - if zone.upper() == 'UTC': - return utc - - try: - zone = zone.encode('US-ASCII') - except UnicodeEncodeError: - # All valid timezones are ASCII - raise UnknownTimeZoneError(zone) - - zone = _unmunge_zone(zone) - if zone not in _tzinfo_cache: - if zone in all_timezones_set: - _tzinfo_cache[zone] = build_tzinfo(zone, open_resource(zone)) - else: - raise UnknownTimeZoneError(zone) - - return _tzinfo_cache[zone] - - -def _unmunge_zone(zone): - """Undo the time zone name munging done by older versions of pytz.""" - return zone.replace('_plus_', '+').replace('_minus_', '-') - - -ZERO = datetime.timedelta(0) -HOUR = datetime.timedelta(hours=1) - - -class UTC(datetime.tzinfo): - """UTC - - Identical to the reference UTC implementation given in Python docs except - that it unpickles using the single module global instance defined beneath - this class declaration. - - Also contains extra attributes and methods to match other pytz tzinfo - instances. - """ - zone = "UTC" - - def utcoffset(self, dt): - return ZERO - - def tzname(self, dt): - return "UTC" - - def dst(self, dt): - return ZERO - - def __reduce__(self): - return _UTC, () - - def localize(self, dt, is_dst=False): - '''Convert naive time to local time''' - if dt.tzinfo is not None: - raise ValueError, 'Not naive datetime (tzinfo is already set)' - return dt.replace(tzinfo=self) - - def normalize(self, dt, is_dst=False): - '''Correct the timezone information on the given datetime''' - if dt.tzinfo is None: - raise ValueError, 'Naive time - no tzinfo set' - return dt.replace(tzinfo=self) - - def __repr__(self): - return "" - - def __str__(self): - return "UTC" - - -UTC = utc = UTC() # UTC is a singleton - - -def _UTC(): - """Factory function for utc unpickling. - - Makes sure that unpickling a utc instance always returns the same - module global. - - These examples belong in the UTC class above, but it is obscured; or in - the README.txt, but we are not depending on Python 2.4 so integrating - the README.txt examples with the unit tests is not trivial. - - >>> import datetime, pickle - >>> dt = datetime.datetime(2005, 3, 1, 14, 13, 21, tzinfo=utc) - >>> naive = dt.replace(tzinfo=None) - >>> p = pickle.dumps(dt, 1) - >>> naive_p = pickle.dumps(naive, 1) - >>> len(p), len(naive_p), len(p) - len(naive_p) - (60, 43, 17) - >>> new = pickle.loads(p) - >>> new == dt - True - >>> new is dt - False - >>> new.tzinfo is dt.tzinfo - True - >>> utc is UTC is timezone('UTC') - True - >>> utc is timezone('GMT') - False - """ - return utc -_UTC.__safe_for_unpickling__ = True - - -def _p(*args): - """Factory function for unpickling pytz tzinfo instances. - - Just a wrapper around tzinfo.unpickler to save a few bytes in each pickle - by shortening the path. - """ - return unpickler(*args) -_p.__safe_for_unpickling__ = True - -_country_timezones_cache = {} - -def country_timezones(iso3166_code): - """Return a list of timezones used in a particular country. - - iso3166_code is the two letter code used to identify the country. - - >>> country_timezones('ch') - ['Europe/Zurich'] - >>> country_timezones('CH') - ['Europe/Zurich'] - >>> country_timezones(u'ch') - ['Europe/Zurich'] - >>> country_timezones('XXX') - Traceback (most recent call last): - ... - KeyError: 'XXX' - """ - iso3166_code = iso3166_code.upper() - if not _country_timezones_cache: - zone_tab = open_resource('zone.tab') - for line in zone_tab: - if line.startswith('#'): - continue - code, coordinates, zone = line.split(None, 4)[:3] - try: - _country_timezones_cache[code].append(zone) - except KeyError: - _country_timezones_cache[code] = [zone] - return _country_timezones_cache[iso3166_code] - - -# Time-zone info based solely on fixed offsets - -class _FixedOffset(datetime.tzinfo): - - zone = None # to match the standard pytz API - - def __init__(self, minutes): - if abs(minutes) >= 1440: - raise ValueError("absolute offset is too large", minutes) - self._minutes = minutes - self._offset = datetime.timedelta(minutes=minutes) - - def utcoffset(self, dt): - return self._offset - - def __reduce__(self): - return FixedOffset, (self._minutes, ) - - def dst(self, dt): - return None - - def tzname(self, dt): - return None - - def __repr__(self): - return 'pytz.FixedOffset(%d)' % self._minutes - - def localize(self, dt, is_dst=False): - '''Convert naive time to local time''' - if dt.tzinfo is not None: - raise ValueError, 'Not naive datetime (tzinfo is already set)' - return dt.replace(tzinfo=self) - - def normalize(self, dt, is_dst=False): - '''Correct the timezone information on the given datetime''' - if dt.tzinfo is None: - raise ValueError, 'Naive time - no tzinfo set' - return dt.replace(tzinfo=self) - - -def FixedOffset(offset, _tzinfos = {}): - """return a fixed-offset timezone based off a number of minutes. - - >>> one = FixedOffset(-330) - >>> one - pytz.FixedOffset(-330) - >>> one.utcoffset(datetime.datetime.now()) - datetime.timedelta(-1, 66600) - - >>> two = FixedOffset(1380) - >>> two - pytz.FixedOffset(1380) - >>> two.utcoffset(datetime.datetime.now()) - datetime.timedelta(0, 82800) - - The datetime.timedelta must be between the range of -1 and 1 day, - non-inclusive. - - >>> FixedOffset(1440) - Traceback (most recent call last): - ... - ValueError: ('absolute offset is too large', 1440) - - >>> FixedOffset(-1440) - Traceback (most recent call last): - ... - ValueError: ('absolute offset is too large', -1440) - - An offset of 0 is special-cased to return UTC. - - >>> FixedOffset(0) is UTC - True - - There should always be only one instance of a FixedOffset per timedelta. - This should be true for multiple creation calls. - - >>> FixedOffset(-330) is one - True - >>> FixedOffset(1380) is two - True - - It should also be true for pickling. - - >>> import pickle - >>> pickle.loads(pickle.dumps(one)) is one - True - >>> pickle.loads(pickle.dumps(two)) is two - True - """ - if offset == 0: - return UTC - - info = _tzinfos.get(offset) - if info is None: - # We haven't seen this one before. we need to save it. - - # Use setdefault to avoid a race condition and make sure we have - # only one - info = _tzinfos.setdefault(offset, _FixedOffset(offset)) - - return info - -FixedOffset.__safe_for_unpickling__ = True - - -def _test(): - import doctest, os, sys - sys.path.insert(0, os.pardir) - import pytz - return doctest.testmod(pytz) - -if __name__ == '__main__': - _test() - -common_timezones = \ -['Africa/Abidjan', - 'Africa/Accra', - 'Africa/Addis_Ababa', - 'Africa/Algiers', - 'Africa/Asmara', - 'Africa/Asmera', - 'Africa/Bamako', - 'Africa/Bangui', - 'Africa/Banjul', - 'Africa/Bissau', - 'Africa/Blantyre', - 'Africa/Brazzaville', - 'Africa/Bujumbura', - 'Africa/Cairo', - 'Africa/Casablanca', - 'Africa/Ceuta', - 'Africa/Conakry', - 'Africa/Dakar', - 'Africa/Dar_es_Salaam', - 'Africa/Djibouti', - 'Africa/Douala', - 'Africa/El_Aaiun', - 'Africa/Freetown', - 'Africa/Gaborone', - 'Africa/Harare', - 'Africa/Johannesburg', - 'Africa/Kampala', - 'Africa/Khartoum', - 'Africa/Kigali', - 'Africa/Kinshasa', - 'Africa/Lagos', - 'Africa/Libreville', - 'Africa/Lome', - 'Africa/Luanda', - 'Africa/Lubumbashi', - 'Africa/Lusaka', - 'Africa/Malabo', - 'Africa/Maputo', - 'Africa/Maseru', - 'Africa/Mbabane', - 'Africa/Mogadishu', - 'Africa/Monrovia', - 'Africa/Nairobi', - 'Africa/Ndjamena', - 'Africa/Niamey', - 'Africa/Nouakchott', - 'Africa/Ouagadougou', - 'Africa/Porto-Novo', - 'Africa/Sao_Tome', - 'Africa/Timbuktu', - 'Africa/Tripoli', - 'Africa/Tunis', - 'Africa/Windhoek', - 'America/Adak', - 'America/Anchorage', - 'America/Anguilla', - 'America/Antigua', - 'America/Araguaina', - 'America/Aruba', - 'America/Asuncion', - 'America/Atikokan', - 'America/Atka', - 'America/Bahia', - 'America/Barbados', - 'America/Belem', - 'America/Belize', - 'America/Blanc-Sablon', - 'America/Boa_Vista', - 'America/Bogota', - 'America/Boise', - 'America/Buenos_Aires', - 'America/Cambridge_Bay', - 'America/Campo_Grande', - 'America/Cancun', - 'America/Caracas', - 'America/Catamarca', - 'America/Cayenne', - 'America/Cayman', - 'America/Chicago', - 'America/Chihuahua', - 'America/Coral_Harbour', - 'America/Cordoba', - 'America/Costa_Rica', - 'America/Cuiaba', - 'America/Curacao', - 'America/Danmarkshavn', - 'America/Dawson', - 'America/Dawson_Creek', - 'America/Denver', - 'America/Detroit', - 'America/Dominica', - 'America/Edmonton', - 'America/Eirunepe', - 'America/El_Salvador', - 'America/Ensenada', - 'America/Fort_Wayne', - 'America/Fortaleza', - 'America/Glace_Bay', - 'America/Godthab', - 'America/Goose_Bay', - 'America/Grand_Turk', - 'America/Grenada', - 'America/Guadeloupe', - 'America/Guatemala', - 'America/Guayaquil', - 'America/Guyana', - 'America/Halifax', - 'America/Havana', - 'America/Hermosillo', - 'America/Indianapolis', - 'America/Inuvik', - 'America/Iqaluit', - 'America/Jamaica', - 'America/Jujuy', - 'America/Juneau', - 'America/Knox_IN', - 'America/La_Paz', - 'America/Lima', - 'America/Los_Angeles', - 'America/Louisville', - 'America/Maceio', - 'America/Managua', - 'America/Manaus', - 'America/Marigot', - 'America/Martinique', - 'America/Mazatlan', - 'America/Mendoza', - 'America/Menominee', - 'America/Merida', - 'America/Mexico_City', - 'America/Miquelon', - 'America/Moncton', - 'America/Monterrey', - 'America/Montevideo', - 'America/Montreal', - 'America/Montserrat', - 'America/Nassau', - 'America/New_York', - 'America/Nipigon', - 'America/Nome', - 'America/Noronha', - 'America/Panama', - 'America/Pangnirtung', - 'America/Paramaribo', - 'America/Phoenix', - 'America/Port-au-Prince', - 'America/Port_of_Spain', - 'America/Porto_Acre', - 'America/Porto_Velho', - 'America/Puerto_Rico', - 'America/Rainy_River', - 'America/Rankin_Inlet', - 'America/Recife', - 'America/Regina', - 'America/Resolute', - 'America/Rio_Branco', - 'America/Rosario', - 'America/Santiago', - 'America/Santo_Domingo', - 'America/Sao_Paulo', - 'America/Scoresbysund', - 'America/Shiprock', - 'America/St_Barthelemy', - 'America/St_Johns', - 'America/St_Kitts', - 'America/St_Lucia', - 'America/St_Thomas', - 'America/St_Vincent', - 'America/Swift_Current', - 'America/Tegucigalpa', - 'America/Thule', - 'America/Thunder_Bay', - 'America/Tijuana', - 'America/Toronto', - 'America/Tortola', - 'America/Vancouver', - 'America/Virgin', - 'America/Whitehorse', - 'America/Winnipeg', - 'America/Yakutat', - 'America/Yellowknife', - 'Antarctica/Casey', - 'Antarctica/Davis', - 'Antarctica/DumontDUrville', - 'Antarctica/Mawson', - 'Antarctica/McMurdo', - 'Antarctica/Palmer', - 'Antarctica/Rothera', - 'Antarctica/South_Pole', - 'Antarctica/Syowa', - 'Antarctica/Vostok', - 'Arctic/Longyearbyen', - 'Asia/Aden', - 'Asia/Almaty', - 'Asia/Amman', - 'Asia/Anadyr', - 'Asia/Aqtau', - 'Asia/Aqtobe', - 'Asia/Ashgabat', - 'Asia/Ashkhabad', - 'Asia/Baghdad', - 'Asia/Bahrain', - 'Asia/Baku', - 'Asia/Bangkok', - 'Asia/Beirut', - 'Asia/Bishkek', - 'Asia/Brunei', - 'Asia/Calcutta', - 'Asia/Choibalsan', - 'Asia/Chongqing', - 'Asia/Chungking', - 'Asia/Colombo', - 'Asia/Dacca', - 'Asia/Damascus', - 'Asia/Dhaka', - 'Asia/Dili', - 'Asia/Dubai', - 'Asia/Dushanbe', - 'Asia/Gaza', - 'Asia/Harbin', - 'Asia/Hong_Kong', - 'Asia/Hovd', - 'Asia/Irkutsk', - 'Asia/Istanbul', - 'Asia/Jakarta', - 'Asia/Jayapura', - 'Asia/Jerusalem', - 'Asia/Kabul', - 'Asia/Kamchatka', - 'Asia/Karachi', - 'Asia/Kashgar', - 'Asia/Katmandu', - 'Asia/Krasnoyarsk', - 'Asia/Kuala_Lumpur', - 'Asia/Kuching', - 'Asia/Kuwait', - 'Asia/Macao', - 'Asia/Macau', - 'Asia/Magadan', - 'Asia/Makassar', - 'Asia/Manila', - 'Asia/Muscat', - 'Asia/Nicosia', - 'Asia/Novosibirsk', - 'Asia/Omsk', - 'Asia/Oral', - 'Asia/Phnom_Penh', - 'Asia/Pontianak', - 'Asia/Pyongyang', - 'Asia/Qatar', - 'Asia/Qyzylorda', - 'Asia/Rangoon', - 'Asia/Riyadh', - 'Asia/Saigon', - 'Asia/Sakhalin', - 'Asia/Samarkand', - 'Asia/Seoul', - 'Asia/Shanghai', - 'Asia/Singapore', - 'Asia/Taipei', - 'Asia/Tashkent', - 'Asia/Tbilisi', - 'Asia/Tehran', - 'Asia/Tel_Aviv', - 'Asia/Thimbu', - 'Asia/Thimphu', - 'Asia/Tokyo', - 'Asia/Ujung_Pandang', - 'Asia/Ulaanbaatar', - 'Asia/Ulan_Bator', - 'Asia/Urumqi', - 'Asia/Vientiane', - 'Asia/Vladivostok', - 'Asia/Yakutsk', - 'Asia/Yekaterinburg', - 'Asia/Yerevan', - 'Atlantic/Azores', - 'Atlantic/Bermuda', - 'Atlantic/Canary', - 'Atlantic/Cape_Verde', - 'Atlantic/Faeroe', - 'Atlantic/Faroe', - 'Atlantic/Jan_Mayen', - 'Atlantic/Madeira', - 'Atlantic/Reykjavik', - 'Atlantic/South_Georgia', - 'Atlantic/St_Helena', - 'Atlantic/Stanley', - 'Australia/ACT', - 'Australia/Adelaide', - 'Australia/Brisbane', - 'Australia/Broken_Hill', - 'Australia/Canberra', - 'Australia/Currie', - 'Australia/Darwin', - 'Australia/Eucla', - 'Australia/Hobart', - 'Australia/LHI', - 'Australia/Lindeman', - 'Australia/Lord_Howe', - 'Australia/Melbourne', - 'Australia/NSW', - 'Australia/North', - 'Australia/Perth', - 'Australia/Queensland', - 'Australia/South', - 'Australia/Sydney', - 'Australia/Tasmania', - 'Australia/Victoria', - 'Australia/West', - 'Australia/Yancowinna', - 'Brazil/Acre', - 'Brazil/DeNoronha', - 'Brazil/East', - 'Brazil/West', - 'Canada/Atlantic', - 'Canada/Central', - 'Canada/East-Saskatchewan', - 'Canada/Eastern', - 'Canada/Mountain', - 'Canada/Newfoundland', - 'Canada/Pacific', - 'Canada/Saskatchewan', - 'Canada/Yukon', - 'Chile/Continental', - 'Chile/EasterIsland', - 'Europe/Amsterdam', - 'Europe/Andorra', - 'Europe/Athens', - 'Europe/Belfast', - 'Europe/Belgrade', - 'Europe/Berlin', - 'Europe/Bratislava', - 'Europe/Brussels', - 'Europe/Bucharest', - 'Europe/Budapest', - 'Europe/Chisinau', - 'Europe/Copenhagen', - 'Europe/Dublin', - 'Europe/Gibraltar', - 'Europe/Guernsey', - 'Europe/Helsinki', - 'Europe/Isle_of_Man', - 'Europe/Istanbul', - 'Europe/Jersey', - 'Europe/Kaliningrad', - 'Europe/Kiev', - 'Europe/Lisbon', - 'Europe/Ljubljana', - 'Europe/London', - 'Europe/Luxembourg', - 'Europe/Madrid', - 'Europe/Malta', - 'Europe/Mariehamn', - 'Europe/Minsk', - 'Europe/Monaco', - 'Europe/Moscow', - 'Europe/Nicosia', - 'Europe/Oslo', - 'Europe/Paris', - 'Europe/Podgorica', - 'Europe/Prague', - 'Europe/Riga', - 'Europe/Rome', - 'Europe/Samara', - 'Europe/San_Marino', - 'Europe/Sarajevo', - 'Europe/Simferopol', - 'Europe/Skopje', - 'Europe/Sofia', - 'Europe/Stockholm', - 'Europe/Tallinn', - 'Europe/Tirane', - 'Europe/Tiraspol', - 'Europe/Uzhgorod', - 'Europe/Vaduz', - 'Europe/Vatican', - 'Europe/Vienna', - 'Europe/Vilnius', - 'Europe/Volgograd', - 'Europe/Warsaw', - 'Europe/Zagreb', - 'Europe/Zaporozhye', - 'Europe/Zurich', - 'GMT', - 'Indian/Antananarivo', - 'Indian/Chagos', - 'Indian/Christmas', - 'Indian/Cocos', - 'Indian/Comoro', - 'Indian/Kerguelen', - 'Indian/Mahe', - 'Indian/Maldives', - 'Indian/Mauritius', - 'Indian/Mayotte', - 'Indian/Reunion', - 'Mexico/BajaNorte', - 'Mexico/BajaSur', - 'Mexico/General', - 'Pacific/Apia', - 'Pacific/Auckland', - 'Pacific/Chatham', - 'Pacific/Easter', - 'Pacific/Efate', - 'Pacific/Enderbury', - 'Pacific/Fakaofo', - 'Pacific/Fiji', - 'Pacific/Funafuti', - 'Pacific/Galapagos', - 'Pacific/Gambier', - 'Pacific/Guadalcanal', - 'Pacific/Guam', - 'Pacific/Honolulu', - 'Pacific/Johnston', - 'Pacific/Kiritimati', - 'Pacific/Kosrae', - 'Pacific/Kwajalein', - 'Pacific/Majuro', - 'Pacific/Marquesas', - 'Pacific/Midway', - 'Pacific/Nauru', - 'Pacific/Niue', - 'Pacific/Norfolk', - 'Pacific/Noumea', - 'Pacific/Pago_Pago', - 'Pacific/Palau', - 'Pacific/Pitcairn', - 'Pacific/Ponape', - 'Pacific/Port_Moresby', - 'Pacific/Rarotonga', - 'Pacific/Saipan', - 'Pacific/Samoa', - 'Pacific/Tahiti', - 'Pacific/Tarawa', - 'Pacific/Tongatapu', - 'Pacific/Truk', - 'Pacific/Wake', - 'Pacific/Wallis', - 'Pacific/Yap', - 'US/Alaska', - 'US/Aleutian', - 'US/Arizona', - 'US/Central', - 'US/East-Indiana', - 'US/Eastern', - 'US/Hawaii', - 'US/Indiana-Starke', - 'US/Michigan', - 'US/Mountain', - 'US/Pacific', - 'US/Pacific-New', - 'US/Samoa', - 'UTC'] -common_timezones_set = set(common_timezones) - -all_timezones = \ -['Africa/Abidjan', - 'Africa/Accra', - 'Africa/Addis_Ababa', - 'Africa/Algiers', - 'Africa/Asmara', - 'Africa/Asmera', - 'Africa/Bamako', - 'Africa/Bangui', - 'Africa/Banjul', - 'Africa/Bissau', - 'Africa/Blantyre', - 'Africa/Brazzaville', - 'Africa/Bujumbura', - 'Africa/Cairo', - 'Africa/Casablanca', - 'Africa/Ceuta', - 'Africa/Conakry', - 'Africa/Dakar', - 'Africa/Dar_es_Salaam', - 'Africa/Djibouti', - 'Africa/Douala', - 'Africa/El_Aaiun', - 'Africa/Freetown', - 'Africa/Gaborone', - 'Africa/Harare', - 'Africa/Johannesburg', - 'Africa/Kampala', - 'Africa/Khartoum', - 'Africa/Kigali', - 'Africa/Kinshasa', - 'Africa/Lagos', - 'Africa/Libreville', - 'Africa/Lome', - 'Africa/Luanda', - 'Africa/Lubumbashi', - 'Africa/Lusaka', - 'Africa/Malabo', - 'Africa/Maputo', - 'Africa/Maseru', - 'Africa/Mbabane', - 'Africa/Mogadishu', - 'Africa/Monrovia', - 'Africa/Nairobi', - 'Africa/Ndjamena', - 'Africa/Niamey', - 'Africa/Nouakchott', - 'Africa/Ouagadougou', - 'Africa/Porto-Novo', - 'Africa/Sao_Tome', - 'Africa/Timbuktu', - 'Africa/Tripoli', - 'Africa/Tunis', - 'Africa/Windhoek', - 'America/Adak', - 'America/Anchorage', - 'America/Anguilla', - 'America/Antigua', - 'America/Araguaina', - 'America/Argentina/Buenos_Aires', - 'America/Argentina/Catamarca', - 'America/Argentina/ComodRivadavia', - 'America/Argentina/Cordoba', - 'America/Argentina/Jujuy', - 'America/Argentina/La_Rioja', - 'America/Argentina/Mendoza', - 'America/Argentina/Rio_Gallegos', - 'America/Argentina/San_Juan', - 'America/Argentina/Tucuman', - 'America/Argentina/Ushuaia', - 'America/Aruba', - 'America/Asuncion', - 'America/Atikokan', - 'America/Atka', - 'America/Bahia', - 'America/Barbados', - 'America/Belem', - 'America/Belize', - 'America/Blanc-Sablon', - 'America/Boa_Vista', - 'America/Bogota', - 'America/Boise', - 'America/Buenos_Aires', - 'America/Cambridge_Bay', - 'America/Campo_Grande', - 'America/Cancun', - 'America/Caracas', - 'America/Catamarca', - 'America/Cayenne', - 'America/Cayman', - 'America/Chicago', - 'America/Chihuahua', - 'America/Coral_Harbour', - 'America/Cordoba', - 'America/Costa_Rica', - 'America/Cuiaba', - 'America/Curacao', - 'America/Danmarkshavn', - 'America/Dawson', - 'America/Dawson_Creek', - 'America/Denver', - 'America/Detroit', - 'America/Dominica', - 'America/Edmonton', - 'America/Eirunepe', - 'America/El_Salvador', - 'America/Ensenada', - 'America/Fort_Wayne', - 'America/Fortaleza', - 'America/Glace_Bay', - 'America/Godthab', - 'America/Goose_Bay', - 'America/Grand_Turk', - 'America/Grenada', - 'America/Guadeloupe', - 'America/Guatemala', - 'America/Guayaquil', - 'America/Guyana', - 'America/Halifax', - 'America/Havana', - 'America/Hermosillo', - 'America/Indiana/Indianapolis', - 'America/Indiana/Knox', - 'America/Indiana/Marengo', - 'America/Indiana/Petersburg', - 'America/Indiana/Tell_City', - 'America/Indiana/Vevay', - 'America/Indiana/Vincennes', - 'America/Indiana/Winamac', - 'America/Indianapolis', - 'America/Inuvik', - 'America/Iqaluit', - 'America/Jamaica', - 'America/Jujuy', - 'America/Juneau', - 'America/Kentucky/Louisville', - 'America/Kentucky/Monticello', - 'America/Knox_IN', - 'America/La_Paz', - 'America/Lima', - 'America/Los_Angeles', - 'America/Louisville', - 'America/Maceio', - 'America/Managua', - 'America/Manaus', - 'America/Marigot', - 'America/Martinique', - 'America/Mazatlan', - 'America/Mendoza', - 'America/Menominee', - 'America/Merida', - 'America/Mexico_City', - 'America/Miquelon', - 'America/Moncton', - 'America/Monterrey', - 'America/Montevideo', - 'America/Montreal', - 'America/Montserrat', - 'America/Nassau', - 'America/New_York', - 'America/Nipigon', - 'America/Nome', - 'America/Noronha', - 'America/North_Dakota/Center', - 'America/North_Dakota/New_Salem', - 'America/Panama', - 'America/Pangnirtung', - 'America/Paramaribo', - 'America/Phoenix', - 'America/Port-au-Prince', - 'America/Port_of_Spain', - 'America/Porto_Acre', - 'America/Porto_Velho', - 'America/Puerto_Rico', - 'America/Rainy_River', - 'America/Rankin_Inlet', - 'America/Recife', - 'America/Regina', - 'America/Resolute', - 'America/Rio_Branco', - 'America/Rosario', - 'America/Santiago', - 'America/Santo_Domingo', - 'America/Sao_Paulo', - 'America/Scoresbysund', - 'America/Shiprock', - 'America/St_Barthelemy', - 'America/St_Johns', - 'America/St_Kitts', - 'America/St_Lucia', - 'America/St_Thomas', - 'America/St_Vincent', - 'America/Swift_Current', - 'America/Tegucigalpa', - 'America/Thule', - 'America/Thunder_Bay', - 'America/Tijuana', - 'America/Toronto', - 'America/Tortola', - 'America/Vancouver', - 'America/Virgin', - 'America/Whitehorse', - 'America/Winnipeg', - 'America/Yakutat', - 'America/Yellowknife', - 'Antarctica/Casey', - 'Antarctica/Davis', - 'Antarctica/DumontDUrville', - 'Antarctica/Mawson', - 'Antarctica/McMurdo', - 'Antarctica/Palmer', - 'Antarctica/Rothera', - 'Antarctica/South_Pole', - 'Antarctica/Syowa', - 'Antarctica/Vostok', - 'Arctic/Longyearbyen', - 'Asia/Aden', - 'Asia/Almaty', - 'Asia/Amman', - 'Asia/Anadyr', - 'Asia/Aqtau', - 'Asia/Aqtobe', - 'Asia/Ashgabat', - 'Asia/Ashkhabad', - 'Asia/Baghdad', - 'Asia/Bahrain', - 'Asia/Baku', - 'Asia/Bangkok', - 'Asia/Beirut', - 'Asia/Bishkek', - 'Asia/Brunei', - 'Asia/Calcutta', - 'Asia/Choibalsan', - 'Asia/Chongqing', - 'Asia/Chungking', - 'Asia/Colombo', - 'Asia/Dacca', - 'Asia/Damascus', - 'Asia/Dhaka', - 'Asia/Dili', - 'Asia/Dubai', - 'Asia/Dushanbe', - 'Asia/Gaza', - 'Asia/Harbin', - 'Asia/Hong_Kong', - 'Asia/Hovd', - 'Asia/Irkutsk', - 'Asia/Istanbul', - 'Asia/Jakarta', - 'Asia/Jayapura', - 'Asia/Jerusalem', - 'Asia/Kabul', - 'Asia/Kamchatka', - 'Asia/Karachi', - 'Asia/Kashgar', - 'Asia/Katmandu', - 'Asia/Krasnoyarsk', - 'Asia/Kuala_Lumpur', - 'Asia/Kuching', - 'Asia/Kuwait', - 'Asia/Macao', - 'Asia/Macau', - 'Asia/Magadan', - 'Asia/Makassar', - 'Asia/Manila', - 'Asia/Muscat', - 'Asia/Nicosia', - 'Asia/Novosibirsk', - 'Asia/Omsk', - 'Asia/Oral', - 'Asia/Phnom_Penh', - 'Asia/Pontianak', - 'Asia/Pyongyang', - 'Asia/Qatar', - 'Asia/Qyzylorda', - 'Asia/Rangoon', - 'Asia/Riyadh', - 'Asia/Saigon', - 'Asia/Sakhalin', - 'Asia/Samarkand', - 'Asia/Seoul', - 'Asia/Shanghai', - 'Asia/Singapore', - 'Asia/Taipei', - 'Asia/Tashkent', - 'Asia/Tbilisi', - 'Asia/Tehran', - 'Asia/Tel_Aviv', - 'Asia/Thimbu', - 'Asia/Thimphu', - 'Asia/Tokyo', - 'Asia/Ujung_Pandang', - 'Asia/Ulaanbaatar', - 'Asia/Ulan_Bator', - 'Asia/Urumqi', - 'Asia/Vientiane', - 'Asia/Vladivostok', - 'Asia/Yakutsk', - 'Asia/Yekaterinburg', - 'Asia/Yerevan', - 'Atlantic/Azores', - 'Atlantic/Bermuda', - 'Atlantic/Canary', - 'Atlantic/Cape_Verde', - 'Atlantic/Faeroe', - 'Atlantic/Faroe', - 'Atlantic/Jan_Mayen', - 'Atlantic/Madeira', - 'Atlantic/Reykjavik', - 'Atlantic/South_Georgia', - 'Atlantic/St_Helena', - 'Atlantic/Stanley', - 'Australia/ACT', - 'Australia/Adelaide', - 'Australia/Brisbane', - 'Australia/Broken_Hill', - 'Australia/Canberra', - 'Australia/Currie', - 'Australia/Darwin', - 'Australia/Eucla', - 'Australia/Hobart', - 'Australia/LHI', - 'Australia/Lindeman', - 'Australia/Lord_Howe', - 'Australia/Melbourne', - 'Australia/NSW', - 'Australia/North', - 'Australia/Perth', - 'Australia/Queensland', - 'Australia/South', - 'Australia/Sydney', - 'Australia/Tasmania', - 'Australia/Victoria', - 'Australia/West', - 'Australia/Yancowinna', - 'Brazil/Acre', - 'Brazil/DeNoronha', - 'Brazil/East', - 'Brazil/West', - 'CET', - 'CST6CDT', - 'Canada/Atlantic', - 'Canada/Central', - 'Canada/East-Saskatchewan', - 'Canada/Eastern', - 'Canada/Mountain', - 'Canada/Newfoundland', - 'Canada/Pacific', - 'Canada/Saskatchewan', - 'Canada/Yukon', - 'Chile/Continental', - 'Chile/EasterIsland', - 'Cuba', - 'EET', - 'EST', - 'EST5EDT', - 'Egypt', - 'Eire', - 'Etc/GMT', - 'Etc/GMT+0', - 'Etc/GMT+1', - 'Etc/GMT+10', - 'Etc/GMT+11', - 'Etc/GMT+12', - 'Etc/GMT+2', - 'Etc/GMT+3', - 'Etc/GMT+4', - 'Etc/GMT+5', - 'Etc/GMT+6', - 'Etc/GMT+7', - 'Etc/GMT+8', - 'Etc/GMT+9', - 'Etc/GMT-0', - 'Etc/GMT-1', - 'Etc/GMT-10', - 'Etc/GMT-11', - 'Etc/GMT-12', - 'Etc/GMT-13', - 'Etc/GMT-14', - 'Etc/GMT-2', - 'Etc/GMT-3', - 'Etc/GMT-4', - 'Etc/GMT-5', - 'Etc/GMT-6', - 'Etc/GMT-7', - 'Etc/GMT-8', - 'Etc/GMT-9', - 'Etc/GMT0', - 'Etc/Greenwich', - 'Etc/UCT', - 'Etc/UTC', - 'Etc/Universal', - 'Etc/Zulu', - 'Europe/Amsterdam', - 'Europe/Andorra', - 'Europe/Athens', - 'Europe/Belfast', - 'Europe/Belgrade', - 'Europe/Berlin', - 'Europe/Bratislava', - 'Europe/Brussels', - 'Europe/Bucharest', - 'Europe/Budapest', - 'Europe/Chisinau', - 'Europe/Copenhagen', - 'Europe/Dublin', - 'Europe/Gibraltar', - 'Europe/Guernsey', - 'Europe/Helsinki', - 'Europe/Isle_of_Man', - 'Europe/Istanbul', - 'Europe/Jersey', - 'Europe/Kaliningrad', - 'Europe/Kiev', - 'Europe/Lisbon', - 'Europe/Ljubljana', - 'Europe/London', - 'Europe/Luxembourg', - 'Europe/Madrid', - 'Europe/Malta', - 'Europe/Mariehamn', - 'Europe/Minsk', - 'Europe/Monaco', - 'Europe/Moscow', - 'Europe/Nicosia', - 'Europe/Oslo', - 'Europe/Paris', - 'Europe/Podgorica', - 'Europe/Prague', - 'Europe/Riga', - 'Europe/Rome', - 'Europe/Samara', - 'Europe/San_Marino', - 'Europe/Sarajevo', - 'Europe/Simferopol', - 'Europe/Skopje', - 'Europe/Sofia', - 'Europe/Stockholm', - 'Europe/Tallinn', - 'Europe/Tirane', - 'Europe/Tiraspol', - 'Europe/Uzhgorod', - 'Europe/Vaduz', - 'Europe/Vatican', - 'Europe/Vienna', - 'Europe/Vilnius', - 'Europe/Volgograd', - 'Europe/Warsaw', - 'Europe/Zagreb', - 'Europe/Zaporozhye', - 'Europe/Zurich', - 'GB', - 'GB-Eire', - 'GMT', - 'GMT+0', - 'GMT-0', - 'GMT0', - 'Greenwich', - 'HST', - 'Hongkong', - 'Iceland', - 'Indian/Antananarivo', - 'Indian/Chagos', - 'Indian/Christmas', - 'Indian/Cocos', - 'Indian/Comoro', - 'Indian/Kerguelen', - 'Indian/Mahe', - 'Indian/Maldives', - 'Indian/Mauritius', - 'Indian/Mayotte', - 'Indian/Reunion', - 'Iran', - 'Israel', - 'Jamaica', - 'Japan', - 'Kwajalein', - 'Libya', - 'MET', - 'MST', - 'MST7MDT', - 'Mexico/BajaNorte', - 'Mexico/BajaSur', - 'Mexico/General', - 'NZ', - 'NZ-CHAT', - 'Navajo', - 'PRC', - 'PST8PDT', - 'Pacific/Apia', - 'Pacific/Auckland', - 'Pacific/Chatham', - 'Pacific/Easter', - 'Pacific/Efate', - 'Pacific/Enderbury', - 'Pacific/Fakaofo', - 'Pacific/Fiji', - 'Pacific/Funafuti', - 'Pacific/Galapagos', - 'Pacific/Gambier', - 'Pacific/Guadalcanal', - 'Pacific/Guam', - 'Pacific/Honolulu', - 'Pacific/Johnston', - 'Pacific/Kiritimati', - 'Pacific/Kosrae', - 'Pacific/Kwajalein', - 'Pacific/Majuro', - 'Pacific/Marquesas', - 'Pacific/Midway', - 'Pacific/Nauru', - 'Pacific/Niue', - 'Pacific/Norfolk', - 'Pacific/Noumea', - 'Pacific/Pago_Pago', - 'Pacific/Palau', - 'Pacific/Pitcairn', - 'Pacific/Ponape', - 'Pacific/Port_Moresby', - 'Pacific/Rarotonga', - 'Pacific/Saipan', - 'Pacific/Samoa', - 'Pacific/Tahiti', - 'Pacific/Tarawa', - 'Pacific/Tongatapu', - 'Pacific/Truk', - 'Pacific/Wake', - 'Pacific/Wallis', - 'Pacific/Yap', - 'Poland', - 'Portugal', - 'ROC', - 'ROK', - 'Singapore', - 'Turkey', - 'UCT', - 'US/Alaska', - 'US/Aleutian', - 'US/Arizona', - 'US/Central', - 'US/East-Indiana', - 'US/Eastern', - 'US/Hawaii', - 'US/Indiana-Starke', - 'US/Michigan', - 'US/Mountain', - 'US/Pacific', - 'US/Pacific-New', - 'US/Samoa', - 'UTC', - 'Universal', - 'W-SU', - 'WET', - 'Zulu', - 'posixrules'] -all_timezones_set = set(all_timezones) diff --git a/tools/buildbot/pylibs/pytz/reference.py b/tools/buildbot/pylibs/pytz/reference.py deleted file mode 100644 index 3dda13e..0000000 --- a/tools/buildbot/pylibs/pytz/reference.py +++ /dev/null @@ -1,127 +0,0 @@ -''' -Reference tzinfo implementations from the Python docs. -Used for testing against as they are only correct for the years -1987 to 2006. Do not use these for real code. -''' - -from datetime import tzinfo, timedelta, datetime -from pytz import utc, UTC, HOUR, ZERO - -# A class building tzinfo objects for fixed-offset time zones. -# Note that FixedOffset(0, "UTC") is a different way to build a -# UTC tzinfo object. - -class FixedOffset(tzinfo): - """Fixed offset in minutes east from UTC.""" - - def __init__(self, offset, name): - self.__offset = timedelta(minutes = offset) - self.__name = name - - def utcoffset(self, dt): - return self.__offset - - def tzname(self, dt): - return self.__name - - def dst(self, dt): - return ZERO - -# A class capturing the platform's idea of local time. - -import time as _time - -STDOFFSET = timedelta(seconds = -_time.timezone) -if _time.daylight: - DSTOFFSET = timedelta(seconds = -_time.altzone) -else: - DSTOFFSET = STDOFFSET - -DSTDIFF = DSTOFFSET - STDOFFSET - -class LocalTimezone(tzinfo): - - def utcoffset(self, dt): - if self._isdst(dt): - return DSTOFFSET - else: - return STDOFFSET - - def dst(self, dt): - if self._isdst(dt): - return DSTDIFF - else: - return ZERO - - def tzname(self, dt): - return _time.tzname[self._isdst(dt)] - - def _isdst(self, dt): - tt = (dt.year, dt.month, dt.day, - dt.hour, dt.minute, dt.second, - dt.weekday(), 0, -1) - stamp = _time.mktime(tt) - tt = _time.localtime(stamp) - return tt.tm_isdst > 0 - -Local = LocalTimezone() - -# A complete implementation of current DST rules for major US time zones. - -def first_sunday_on_or_after(dt): - days_to_go = 6 - dt.weekday() - if days_to_go: - dt += timedelta(days_to_go) - return dt - -# In the US, DST starts at 2am (standard time) on the first Sunday in April. -DSTSTART = datetime(1, 4, 1, 2) -# and ends at 2am (DST time; 1am standard time) on the last Sunday of Oct. -# which is the first Sunday on or after Oct 25. -DSTEND = datetime(1, 10, 25, 1) - -class USTimeZone(tzinfo): - - def __init__(self, hours, reprname, stdname, dstname): - self.stdoffset = timedelta(hours=hours) - self.reprname = reprname - self.stdname = stdname - self.dstname = dstname - - def __repr__(self): - return self.reprname - - def tzname(self, dt): - if self.dst(dt): - return self.dstname - else: - return self.stdname - - def utcoffset(self, dt): - return self.stdoffset + self.dst(dt) - - def dst(self, dt): - if dt is None or dt.tzinfo is None: - # An exception may be sensible here, in one or both cases. - # It depends on how you want to treat them. The default - # fromutc() implementation (called by the default astimezone() - # implementation) passes a datetime with dt.tzinfo is self. - return ZERO - assert dt.tzinfo is self - - # Find first Sunday in April & the last in October. - start = first_sunday_on_or_after(DSTSTART.replace(year=dt.year)) - end = first_sunday_on_or_after(DSTEND.replace(year=dt.year)) - - # Can't compare naive to aware objects, so strip the timezone from - # dt first. - if start <= dt.replace(tzinfo=None) < end: - return HOUR - else: - return ZERO - -Eastern = USTimeZone(-5, "Eastern", "EST", "EDT") -Central = USTimeZone(-6, "Central", "CST", "CDT") -Mountain = USTimeZone(-7, "Mountain", "MST", "MDT") -Pacific = USTimeZone(-8, "Pacific", "PST", "PDT") - diff --git a/tools/buildbot/pylibs/pytz/tzfile.py b/tools/buildbot/pylibs/pytz/tzfile.py deleted file mode 100644 index 56b8397..0000000 --- a/tools/buildbot/pylibs/pytz/tzfile.py +++ /dev/null @@ -1,113 +0,0 @@ -#!/usr/bin/env python -''' -$Id: tzfile.py,v 1.8 2004/06/03 00:15:24 zenzen Exp $ -''' - -from cStringIO import StringIO -from datetime import datetime, timedelta -from struct import unpack, calcsize - -from pytz.tzinfo import StaticTzInfo, DstTzInfo, memorized_ttinfo -from pytz.tzinfo import memorized_datetime, memorized_timedelta - - -def build_tzinfo(zone, fp): - head_fmt = '>4s 16x 6l' - head_size = calcsize(head_fmt) - (magic,ttisgmtcnt,ttisstdcnt,leapcnt, - timecnt,typecnt,charcnt) = unpack(head_fmt, fp.read(head_size)) - - # Make sure it is a tzinfo(5) file - assert magic == 'TZif' - - # Read out the transition times, localtime indices and ttinfo structures. - data_fmt = '>%(timecnt)dl %(timecnt)dB %(ttinfo)s %(charcnt)ds' % dict( - timecnt=timecnt, ttinfo='lBB'*typecnt, charcnt=charcnt) - data_size = calcsize(data_fmt) - data = unpack(data_fmt, fp.read(data_size)) - - # make sure we unpacked the right number of values - assert len(data) == 2 * timecnt + 3 * typecnt + 1 - transitions = [memorized_datetime(trans) - for trans in data[:timecnt]] - lindexes = list(data[timecnt:2 * timecnt]) - ttinfo_raw = data[2 * timecnt:-1] - tznames_raw = data[-1] - del data - - # Process ttinfo into separate structs - ttinfo = [] - tznames = {} - i = 0 - while i < len(ttinfo_raw): - # have we looked up this timezone name yet? - tzname_offset = ttinfo_raw[i+2] - if tzname_offset not in tznames: - nul = tznames_raw.find('\0', tzname_offset) - if nul < 0: - nul = len(tznames_raw) - tznames[tzname_offset] = tznames_raw[tzname_offset:nul] - ttinfo.append((ttinfo_raw[i], - bool(ttinfo_raw[i+1]), - tznames[tzname_offset])) - i += 3 - - # Now build the timezone object - if len(transitions) == 0: - ttinfo[0][0], ttinfo[0][2] - cls = type(zone, (StaticTzInfo,), dict( - zone=zone, - _utcoffset=memorized_timedelta(ttinfo[0][0]), - _tzname=ttinfo[0][2])) - else: - # Early dates use the first standard time ttinfo - i = 0 - while ttinfo[i][1]: - i += 1 - if ttinfo[i] == ttinfo[lindexes[0]]: - transitions[0] = datetime.min - else: - transitions.insert(0, datetime.min) - lindexes.insert(0, i) - - # calculate transition info - transition_info = [] - for i in range(len(transitions)): - inf = ttinfo[lindexes[i]] - utcoffset = inf[0] - if not inf[1]: - dst = 0 - else: - for j in range(i-1, -1, -1): - prev_inf = ttinfo[lindexes[j]] - if not prev_inf[1]: - break - dst = inf[0] - prev_inf[0] # dst offset - tzname = inf[2] - - # Round utcoffset and dst to the nearest minute or the - # datetime library will complain. Conversions to these timezones - # might be up to plus or minus 30 seconds out, but it is - # the best we can do. - utcoffset = int((utcoffset + 30) / 60) * 60 - dst = int((dst + 30) / 60) * 60 - transition_info.append(memorized_ttinfo(utcoffset, dst, tzname)) - - cls = type(zone, (DstTzInfo,), dict( - zone=zone, - _utc_transition_times=transitions, - _transition_info=transition_info)) - - return cls() - -if __name__ == '__main__': - import os.path - from pprint import pprint - base = os.path.join(os.path.dirname(__file__), 'zoneinfo') - tz = build_tzinfo('Australia/Melbourne', - open(os.path.join(base,'Australia','Melbourne'), 'rb')) - tz = build_tzinfo('US/Eastern', - open(os.path.join(base,'US','Eastern'), 'rb')) - pprint(tz._utc_transition_times) - #print tz.asPython(4) - #print tz.transitions_mapping diff --git a/tools/buildbot/pylibs/pytz/tzinfo.py b/tools/buildbot/pylibs/pytz/tzinfo.py deleted file mode 100644 index 456fbf6..0000000 --- a/tools/buildbot/pylibs/pytz/tzinfo.py +++ /dev/null @@ -1,382 +0,0 @@ -'''Base classes and helpers for building zone specific tzinfo classes''' - -from datetime import datetime, timedelta, tzinfo -from bisect import bisect_right -from sets import Set - -import pytz - -__all__ = [] - -_timedelta_cache = {} -def memorized_timedelta(seconds): - '''Create only one instance of each distinct timedelta''' - try: - return _timedelta_cache[seconds] - except KeyError: - delta = timedelta(seconds=seconds) - _timedelta_cache[seconds] = delta - return delta - -_epoch = datetime.utcfromtimestamp(0) -_datetime_cache = {0: _epoch} -def memorized_datetime(seconds): - '''Create only one instance of each distinct datetime''' - try: - return _datetime_cache[seconds] - except KeyError: - # NB. We can't just do datetime.utcfromtimestamp(seconds) as this - # fails with negative values under Windows (Bug #90096) - dt = _epoch + timedelta(seconds=seconds) - _datetime_cache[seconds] = dt - return dt - -_ttinfo_cache = {} -def memorized_ttinfo(*args): - '''Create only one instance of each distinct tuple''' - try: - return _ttinfo_cache[args] - except KeyError: - ttinfo = ( - memorized_timedelta(args[0]), - memorized_timedelta(args[1]), - args[2] - ) - _ttinfo_cache[args] = ttinfo - return ttinfo - -_notime = memorized_timedelta(0) - -def _to_seconds(td): - '''Convert a timedelta to seconds''' - return td.seconds + td.days * 24 * 60 * 60 - - -class BaseTzInfo(tzinfo): - # Overridden in subclass - _utcoffset = None - _tzname = None - zone = None - - def __str__(self): - return self.zone - - -class StaticTzInfo(BaseTzInfo): - '''A timezone that has a constant offset from UTC - - These timezones are rare, as most regions have changed their - offset from UTC at some point in their history - ''' - def fromutc(self, dt): - '''See datetime.tzinfo.fromutc''' - return (dt + self._utcoffset).replace(tzinfo=self) - - def utcoffset(self,dt): - '''See datetime.tzinfo.utcoffset''' - return self._utcoffset - - def dst(self,dt): - '''See datetime.tzinfo.dst''' - return _notime - - def tzname(self,dt): - '''See datetime.tzinfo.tzname''' - return self._tzname - - def localize(self, dt, is_dst=False): - '''Convert naive time to local time''' - if dt.tzinfo is not None: - raise ValueError, 'Not naive datetime (tzinfo is already set)' - return dt.replace(tzinfo=self) - - def normalize(self, dt, is_dst=False): - '''Correct the timezone information on the given datetime''' - if dt.tzinfo is None: - raise ValueError, 'Naive time - no tzinfo set' - return dt.replace(tzinfo=self) - - def __repr__(self): - return '' % (self.zone,) - - def __reduce__(self): - # Special pickle to zone remains a singleton and to cope with - # database changes. - return pytz._p, (self.zone,) - - -class DstTzInfo(BaseTzInfo): - '''A timezone that has a variable offset from UTC - - The offset might change if daylight savings time comes into effect, - or at a point in history when the region decides to change their - timezone definition. - - ''' - # Overridden in subclass - _utc_transition_times = None # Sorted list of DST transition times in UTC - _transition_info = None # [(utcoffset, dstoffset, tzname)] corresponding - # to _utc_transition_times entries - zone = None - - # Set in __init__ - _tzinfos = None - _dst = None # DST offset - - def __init__(self, _inf=None, _tzinfos=None): - if _inf: - self._tzinfos = _tzinfos - self._utcoffset, self._dst, self._tzname = _inf - else: - _tzinfos = {} - self._tzinfos = _tzinfos - self._utcoffset, self._dst, self._tzname = self._transition_info[0] - _tzinfos[self._transition_info[0]] = self - for inf in self._transition_info[1:]: - if not _tzinfos.has_key(inf): - _tzinfos[inf] = self.__class__(inf, _tzinfos) - - def fromutc(self, dt): - '''See datetime.tzinfo.fromutc''' - dt = dt.replace(tzinfo=None) - idx = max(0, bisect_right(self._utc_transition_times, dt) - 1) - inf = self._transition_info[idx] - return (dt + inf[0]).replace(tzinfo=self._tzinfos[inf]) - - def normalize(self, dt): - '''Correct the timezone information on the given datetime - - If date arithmetic crosses DST boundaries, the tzinfo - is not magically adjusted. This method normalizes the - tzinfo to the correct one. - - To test, first we need to do some setup - - >>> from pytz import timezone - >>> utc = timezone('UTC') - >>> eastern = timezone('US/Eastern') - >>> fmt = '%Y-%m-%d %H:%M:%S %Z (%z)' - - We next create a datetime right on an end-of-DST transition point, - the instant when the wallclocks are wound back one hour. - - >>> utc_dt = datetime(2002, 10, 27, 6, 0, 0, tzinfo=utc) - >>> loc_dt = utc_dt.astimezone(eastern) - >>> loc_dt.strftime(fmt) - '2002-10-27 01:00:00 EST (-0500)' - - Now, if we subtract a few minutes from it, note that the timezone - information has not changed. - - >>> before = loc_dt - timedelta(minutes=10) - >>> before.strftime(fmt) - '2002-10-27 00:50:00 EST (-0500)' - - But we can fix that by calling the normalize method - - >>> before = eastern.normalize(before) - >>> before.strftime(fmt) - '2002-10-27 01:50:00 EDT (-0400)' - - ''' - if dt.tzinfo is None: - raise ValueError, 'Naive time - no tzinfo set' - - # Convert dt in localtime to UTC - offset = dt.tzinfo._utcoffset - dt = dt.replace(tzinfo=None) - dt = dt - offset - # convert it back, and return it - return self.fromutc(dt) - - def localize(self, dt, is_dst=False): - '''Convert naive time to local time. - - This method should be used to construct localtimes, rather - than passing a tzinfo argument to a datetime constructor. - - is_dst is used to determine the correct timezone in the ambigous - period at the end of daylight savings time. - - >>> from pytz import timezone - >>> fmt = '%Y-%m-%d %H:%M:%S %Z (%z)' - >>> amdam = timezone('Europe/Amsterdam') - >>> dt = datetime(2004, 10, 31, 2, 0, 0) - >>> loc_dt1 = amdam.localize(dt, is_dst=True) - >>> loc_dt2 = amdam.localize(dt, is_dst=False) - >>> loc_dt1.strftime(fmt) - '2004-10-31 02:00:00 CEST (+0200)' - >>> loc_dt2.strftime(fmt) - '2004-10-31 02:00:00 CET (+0100)' - >>> str(loc_dt2 - loc_dt1) - '1:00:00' - - Use is_dst=None to raise an AmbiguousTimeError for ambiguous - times at the end of daylight savings - - >>> try: - ... loc_dt1 = amdam.localize(dt, is_dst=None) - ... except AmbiguousTimeError: - ... print 'Oops' - Oops - - >>> loc_dt1 = amdam.localize(dt, is_dst=None) - Traceback (most recent call last): - [...] - AmbiguousTimeError: 2004-10-31 02:00:00 - - is_dst defaults to False - - >>> amdam.localize(dt) == amdam.localize(dt, False) - True - - ''' - if dt.tzinfo is not None: - raise ValueError, 'Not naive datetime (tzinfo is already set)' - - # Find the possibly correct timezones. We probably just have one, - # but we might end up with two if we are in the end-of-DST - # transition period. Or possibly more in some particularly confused - # location... - possible_loc_dt = Set() - for tzinfo in self._tzinfos.values(): - loc_dt = tzinfo.normalize(dt.replace(tzinfo=tzinfo)) - if loc_dt.replace(tzinfo=None) == dt: - possible_loc_dt.add(loc_dt) - - if len(possible_loc_dt) == 1: - return possible_loc_dt.pop() - - # If told to be strict, raise an exception since we have an - # ambiguous case - if is_dst is None: - raise AmbiguousTimeError(dt) - - # Filter out the possiblilities that don't match the requested - # is_dst - filtered_possible_loc_dt = [ - p for p in possible_loc_dt - if bool(p.tzinfo._dst) == is_dst - ] - - # Hopefully we only have one possibility left. Return it. - if len(filtered_possible_loc_dt) == 1: - return filtered_possible_loc_dt[0] - - if len(filtered_possible_loc_dt) == 0: - filtered_possible_loc_dt = list(possible_loc_dt) - - # If we get this far, we have in a wierd timezone transition - # where the clocks have been wound back but is_dst is the same - # in both (eg. Europe/Warsaw 1915 when they switched to CET). - # At this point, we just have to guess unless we allow more - # hints to be passed in (such as the UTC offset or abbreviation), - # but that is just getting silly. - # - # Choose the earliest (by UTC) applicable timezone. - def mycmp(a,b): - return cmp( - a.replace(tzinfo=None) - a.tzinfo._utcoffset, - b.replace(tzinfo=None) - b.tzinfo._utcoffset, - ) - filtered_possible_loc_dt.sort(mycmp) - return filtered_possible_loc_dt[0] - - def utcoffset(self, dt): - '''See datetime.tzinfo.utcoffset''' - return self._utcoffset - - def dst(self, dt): - '''See datetime.tzinfo.dst''' - return self._dst - - def tzname(self, dt): - '''See datetime.tzinfo.tzname''' - return self._tzname - - def __repr__(self): - if self._dst: - dst = 'DST' - else: - dst = 'STD' - if self._utcoffset > _notime: - return '' % ( - self.zone, self._tzname, self._utcoffset, dst - ) - else: - return '' % ( - self.zone, self._tzname, self._utcoffset, dst - ) - - def __reduce__(self): - # Special pickle to zone remains a singleton and to cope with - # database changes. - return pytz._p, ( - self.zone, - _to_seconds(self._utcoffset), - _to_seconds(self._dst), - self._tzname - ) - - -class AmbiguousTimeError(Exception): - '''Exception raised when attempting to create an ambiguous wallclock time. - - At the end of a DST transition period, a particular wallclock time will - occur twice (once before the clocks are set back, once after). Both - possibilities may be correct, unless further information is supplied. - - See DstTzInfo.normalize() for more info - ''' - - -def unpickler(zone, utcoffset=None, dstoffset=None, tzname=None): - """Factory function for unpickling pytz tzinfo instances. - - This is shared for both StaticTzInfo and DstTzInfo instances, because - database changes could cause a zones implementation to switch between - these two base classes and we can't break pickles on a pytz version - upgrade. - """ - # Raises a KeyError if zone no longer exists, which should never happen - # and would be a bug. - tz = pytz.timezone(zone) - - # A StaticTzInfo - just return it - if utcoffset is None: - return tz - - # This pickle was created from a DstTzInfo. We need to - # determine which of the list of tzinfo instances for this zone - # to use in order to restore the state of any datetime instances using - # it correctly. - utcoffset = memorized_timedelta(utcoffset) - dstoffset = memorized_timedelta(dstoffset) - try: - return tz._tzinfos[(utcoffset, dstoffset, tzname)] - except KeyError: - # The particular state requested in this timezone no longer exists. - # This indicates a corrupt pickle, or the timezone database has been - # corrected violently enough to make this particular - # (utcoffset,dstoffset) no longer exist in the zone, or the - # abbreviation has been changed. - pass - - # See if we can find an entry differing only by tzname. Abbreviations - # get changed from the initial guess by the database maintainers to - # match reality when this information is discovered. - for localized_tz in tz._tzinfos.values(): - if (localized_tz._utcoffset == utcoffset - and localized_tz._dst == dstoffset): - return localized_tz - - # This (utcoffset, dstoffset) information has been removed from the - # zone. Add it back. This might occur when the database maintainers have - # corrected incorrect information. datetime instances using this - # incorrect information will continue to do so, exactly as they were - # before being pickled. This is purely an overly paranoid safety net - I - # doubt this will ever been needed in real life. - inf = (utcoffset, dstoffset, tzname) - tz._tzinfos[inf] = tz.__class__(inf, tz._tzinfos) - return tz._tzinfos[inf] - diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Abidjan b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Abidjan deleted file mode 100644 index 65d19ec..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Abidjan and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Accra b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Accra deleted file mode 100644 index 8c473ed..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Accra and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Addis_Ababa b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Addis_Ababa deleted file mode 100644 index 5a95ab6..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Addis_Ababa and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Algiers b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Algiers deleted file mode 100644 index c888831..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Algiers and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Asmara b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Asmara deleted file mode 100644 index d1e876e..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Asmara and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Asmera b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Asmera deleted file mode 100644 index d1e876e..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Asmera and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Bamako b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Bamako deleted file mode 100644 index a9259a6..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Bamako and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Bangui b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Bangui deleted file mode 100644 index 883e597..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Bangui and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Banjul b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Banjul deleted file mode 100644 index a85a7d8..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Banjul and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Bissau b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Bissau deleted file mode 100644 index ab4a195..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Bissau and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Blantyre b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Blantyre deleted file mode 100644 index 2972580..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Blantyre and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Brazzaville b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Brazzaville deleted file mode 100644 index abb0c08..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Brazzaville and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Bujumbura b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Bujumbura deleted file mode 100644 index cac5652..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Bujumbura and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Cairo b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Cairo deleted file mode 100644 index 39caffb..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Cairo and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Casablanca b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Casablanca deleted file mode 100644 index c4856d8..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Casablanca and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Ceuta b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Ceuta deleted file mode 100644 index c9b0c08..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Ceuta and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Conakry b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Conakry deleted file mode 100644 index 45bcce1..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Conakry and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Dakar b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Dakar deleted file mode 100644 index 3110413..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Dakar and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Dar_es_Salaam b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Dar_es_Salaam deleted file mode 100644 index 05643e9..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Dar_es_Salaam and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Djibouti b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Djibouti deleted file mode 100644 index 297d93a..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Djibouti and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Douala b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Douala deleted file mode 100644 index 8627f2e..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Douala and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/El_Aaiun b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/El_Aaiun deleted file mode 100644 index 3275161..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/El_Aaiun and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Freetown b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Freetown deleted file mode 100644 index 720b8e3..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Freetown and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Gaborone b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Gaborone deleted file mode 100644 index ffc7795..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Gaborone and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Harare b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Harare deleted file mode 100644 index 258b3936..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Harare and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Johannesburg b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Johannesburg deleted file mode 100644 index d1bec73..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Johannesburg and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Kampala b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Kampala deleted file mode 100644 index 1afbe23..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Kampala and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Khartoum b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Khartoum deleted file mode 100644 index 6f62fd7..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Khartoum and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Kigali b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Kigali deleted file mode 100644 index c9623c5..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Kigali and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Kinshasa b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Kinshasa deleted file mode 100644 index e8481f3..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Kinshasa and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Lagos b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Lagos deleted file mode 100644 index cbdc045..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Lagos and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Libreville b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Libreville deleted file mode 100644 index d7691ae..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Libreville and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Lome b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Lome deleted file mode 100644 index 297ec5d..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Lome and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Luanda b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Luanda deleted file mode 100644 index 576b204..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Luanda and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Lubumbashi b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Lubumbashi deleted file mode 100644 index d3fab52..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Lubumbashi and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Lusaka b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Lusaka deleted file mode 100644 index 87d7a95..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Lusaka and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Malabo b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Malabo deleted file mode 100644 index c70de1f..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Malabo and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Maputo b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Maputo deleted file mode 100644 index 31cfad7..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Maputo and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Maseru b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Maseru deleted file mode 100644 index 117006e..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Maseru and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Mbabane b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Mbabane deleted file mode 100644 index be6ed60..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Mbabane and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Mogadishu b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Mogadishu deleted file mode 100644 index 9ce97a6..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Mogadishu and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Monrovia b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Monrovia deleted file mode 100644 index bd2fa4e..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Monrovia and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Nairobi b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Nairobi deleted file mode 100644 index e557234..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Nairobi and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Ndjamena b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Ndjamena deleted file mode 100644 index 8779590..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Ndjamena and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Niamey b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Niamey deleted file mode 100644 index 799381c..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Niamey and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Nouakchott b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Nouakchott deleted file mode 100644 index 10ca866..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Nouakchott and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Ouagadougou b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Ouagadougou deleted file mode 100644 index df782a4..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Ouagadougou and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Porto-Novo b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Porto-Novo deleted file mode 100644 index 600a30d..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Porto-Novo and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Sao_Tome b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Sao_Tome deleted file mode 100644 index ddf7fb4..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Sao_Tome and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Timbuktu b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Timbuktu deleted file mode 100644 index a9259a6..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Timbuktu and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Tripoli b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Tripoli deleted file mode 100644 index 943f9a3..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Tripoli and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Tunis b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Tunis deleted file mode 100644 index 94d01da..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Tunis and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Windhoek b/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Windhoek deleted file mode 100644 index 6f22b0a..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Africa/Windhoek and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Adak b/tools/buildbot/pylibs/pytz/zoneinfo/America/Adak deleted file mode 100644 index 391ec98..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Adak and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Anchorage b/tools/buildbot/pylibs/pytz/zoneinfo/America/Anchorage deleted file mode 100644 index d147350..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Anchorage and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Anguilla b/tools/buildbot/pylibs/pytz/zoneinfo/America/Anguilla deleted file mode 100644 index 20bc946..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Anguilla and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Antigua b/tools/buildbot/pylibs/pytz/zoneinfo/America/Antigua deleted file mode 100644 index 608b635..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Antigua and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Araguaina b/tools/buildbot/pylibs/pytz/zoneinfo/America/Araguaina deleted file mode 100644 index 34d9caf..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Araguaina and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/Buenos_Aires b/tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/Buenos_Aires deleted file mode 100644 index 4bd3b2c..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/Buenos_Aires and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/Catamarca b/tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/Catamarca deleted file mode 100644 index e46272f..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/Catamarca and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/ComodRivadavia b/tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/ComodRivadavia deleted file mode 100644 index e46272f..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/ComodRivadavia and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/Cordoba b/tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/Cordoba deleted file mode 100644 index 1a335d4..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/Cordoba and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/Jujuy b/tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/Jujuy deleted file mode 100644 index 45b806b..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/Jujuy and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/La_Rioja b/tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/La_Rioja deleted file mode 100644 index 7546d5f..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/La_Rioja and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/Mendoza b/tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/Mendoza deleted file mode 100644 index 7ebf85e..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/Mendoza and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/Rio_Gallegos b/tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/Rio_Gallegos deleted file mode 100644 index d95ae41..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/Rio_Gallegos and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/San_Juan b/tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/San_Juan deleted file mode 100644 index 37f7b5d..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/San_Juan and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/Tucuman b/tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/Tucuman deleted file mode 100644 index 93dc0dc..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/Tucuman and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/Ushuaia b/tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/Ushuaia deleted file mode 100644 index 5222e4c..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Argentina/Ushuaia and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Aruba b/tools/buildbot/pylibs/pytz/zoneinfo/America/Aruba deleted file mode 100644 index 73bb7ea..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Aruba and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Asuncion b/tools/buildbot/pylibs/pytz/zoneinfo/America/Asuncion deleted file mode 100644 index 492d943..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Asuncion and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Atikokan b/tools/buildbot/pylibs/pytz/zoneinfo/America/Atikokan deleted file mode 100644 index c63a32a..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Atikokan and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Atka b/tools/buildbot/pylibs/pytz/zoneinfo/America/Atka deleted file mode 100644 index 391ec98..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Atka and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Bahia b/tools/buildbot/pylibs/pytz/zoneinfo/America/Bahia deleted file mode 100644 index 34b2d7a..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Bahia and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Barbados b/tools/buildbot/pylibs/pytz/zoneinfo/America/Barbados deleted file mode 100644 index 63ca138..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Barbados and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Belem b/tools/buildbot/pylibs/pytz/zoneinfo/America/Belem deleted file mode 100644 index 9c37b6a..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Belem and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Belize b/tools/buildbot/pylibs/pytz/zoneinfo/America/Belize deleted file mode 100644 index a18cd39..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Belize and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Blanc-Sablon b/tools/buildbot/pylibs/pytz/zoneinfo/America/Blanc-Sablon deleted file mode 100644 index 8526259..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Blanc-Sablon and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Boa_Vista b/tools/buildbot/pylibs/pytz/zoneinfo/America/Boa_Vista deleted file mode 100644 index cb15afb..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Boa_Vista and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Bogota b/tools/buildbot/pylibs/pytz/zoneinfo/America/Bogota deleted file mode 100644 index 9df037e..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Bogota and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Boise b/tools/buildbot/pylibs/pytz/zoneinfo/America/Boise deleted file mode 100644 index 441afe5..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Boise and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Buenos_Aires b/tools/buildbot/pylibs/pytz/zoneinfo/America/Buenos_Aires deleted file mode 100644 index 4bd3b2c..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Buenos_Aires and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Cambridge_Bay b/tools/buildbot/pylibs/pytz/zoneinfo/America/Cambridge_Bay deleted file mode 100644 index 9aa642b..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Cambridge_Bay and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Campo_Grande b/tools/buildbot/pylibs/pytz/zoneinfo/America/Campo_Grande deleted file mode 100644 index 4d95b68..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Campo_Grande and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Cancun b/tools/buildbot/pylibs/pytz/zoneinfo/America/Cancun deleted file mode 100644 index 3d56e51..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Cancun and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Caracas b/tools/buildbot/pylibs/pytz/zoneinfo/America/Caracas deleted file mode 100644 index a2144137..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Caracas and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Catamarca b/tools/buildbot/pylibs/pytz/zoneinfo/America/Catamarca deleted file mode 100644 index e46272f..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Catamarca and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Cayenne b/tools/buildbot/pylibs/pytz/zoneinfo/America/Cayenne deleted file mode 100644 index 7109a98..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Cayenne and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Cayman b/tools/buildbot/pylibs/pytz/zoneinfo/America/Cayman deleted file mode 100644 index a4095d3..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Cayman and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Chicago b/tools/buildbot/pylibs/pytz/zoneinfo/America/Chicago deleted file mode 100644 index e932c6d..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Chicago and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Chihuahua b/tools/buildbot/pylibs/pytz/zoneinfo/America/Chihuahua deleted file mode 100644 index 8758bab..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Chihuahua and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Coral_Harbour b/tools/buildbot/pylibs/pytz/zoneinfo/America/Coral_Harbour deleted file mode 100644 index c63a32a..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Coral_Harbour and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Cordoba b/tools/buildbot/pylibs/pytz/zoneinfo/America/Cordoba deleted file mode 100644 index 1a335d4..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Cordoba and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Costa_Rica b/tools/buildbot/pylibs/pytz/zoneinfo/America/Costa_Rica deleted file mode 100644 index 2029eb6..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Costa_Rica and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Cuiaba b/tools/buildbot/pylibs/pytz/zoneinfo/America/Cuiaba deleted file mode 100644 index 0b122462..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Cuiaba and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Curacao b/tools/buildbot/pylibs/pytz/zoneinfo/America/Curacao deleted file mode 100644 index 6733d24..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Curacao and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Danmarkshavn b/tools/buildbot/pylibs/pytz/zoneinfo/America/Danmarkshavn deleted file mode 100644 index 9feacfb..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Danmarkshavn and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Dawson b/tools/buildbot/pylibs/pytz/zoneinfo/America/Dawson deleted file mode 100644 index fab0609..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Dawson and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Dawson_Creek b/tools/buildbot/pylibs/pytz/zoneinfo/America/Dawson_Creek deleted file mode 100644 index 01ed535..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Dawson_Creek and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Denver b/tools/buildbot/pylibs/pytz/zoneinfo/America/Denver deleted file mode 100644 index f8908fe..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Denver and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Detroit b/tools/buildbot/pylibs/pytz/zoneinfo/America/Detroit deleted file mode 100644 index da53d46..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Detroit and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Dominica b/tools/buildbot/pylibs/pytz/zoneinfo/America/Dominica deleted file mode 100644 index 7783831b..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Dominica and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Edmonton b/tools/buildbot/pylibs/pytz/zoneinfo/America/Edmonton deleted file mode 100644 index ba6dbb4..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Edmonton and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Eirunepe b/tools/buildbot/pylibs/pytz/zoneinfo/America/Eirunepe deleted file mode 100644 index bc6558f2..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Eirunepe and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/El_Salvador b/tools/buildbot/pylibs/pytz/zoneinfo/America/El_Salvador deleted file mode 100644 index ac774e8..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/El_Salvador and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Ensenada b/tools/buildbot/pylibs/pytz/zoneinfo/America/Ensenada deleted file mode 100644 index 1bf00cd..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Ensenada and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Fort_Wayne b/tools/buildbot/pylibs/pytz/zoneinfo/America/Fort_Wayne deleted file mode 100644 index aa3dfc4..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Fort_Wayne and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Fortaleza b/tools/buildbot/pylibs/pytz/zoneinfo/America/Fortaleza deleted file mode 100644 index 2598c53..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Fortaleza and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Glace_Bay b/tools/buildbot/pylibs/pytz/zoneinfo/America/Glace_Bay deleted file mode 100644 index 199f0b0..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Glace_Bay and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Godthab b/tools/buildbot/pylibs/pytz/zoneinfo/America/Godthab deleted file mode 100644 index 85623ce..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Godthab and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Goose_Bay b/tools/buildbot/pylibs/pytz/zoneinfo/America/Goose_Bay deleted file mode 100644 index 07c88e5..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Goose_Bay and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Grand_Turk b/tools/buildbot/pylibs/pytz/zoneinfo/America/Grand_Turk deleted file mode 100644 index 733c179..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Grand_Turk and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Grenada b/tools/buildbot/pylibs/pytz/zoneinfo/America/Grenada deleted file mode 100644 index df1b689..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Grenada and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Guadeloupe b/tools/buildbot/pylibs/pytz/zoneinfo/America/Guadeloupe deleted file mode 100644 index 15c0f1f..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Guadeloupe and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Guatemala b/tools/buildbot/pylibs/pytz/zoneinfo/America/Guatemala deleted file mode 100644 index 6118b5c..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Guatemala and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Guayaquil b/tools/buildbot/pylibs/pytz/zoneinfo/America/Guayaquil deleted file mode 100644 index e6de7f8..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Guayaquil and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Guyana b/tools/buildbot/pylibs/pytz/zoneinfo/America/Guyana deleted file mode 100644 index 5f98c4a..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Guyana and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Halifax b/tools/buildbot/pylibs/pytz/zoneinfo/America/Halifax deleted file mode 100644 index b98c3a7..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Halifax and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Havana b/tools/buildbot/pylibs/pytz/zoneinfo/America/Havana deleted file mode 100644 index f7bc5f7..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Havana and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Hermosillo b/tools/buildbot/pylibs/pytz/zoneinfo/America/Hermosillo deleted file mode 100644 index 08ce31c..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Hermosillo and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Indiana/Indianapolis b/tools/buildbot/pylibs/pytz/zoneinfo/America/Indiana/Indianapolis deleted file mode 100644 index aa3dfc4..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Indiana/Indianapolis and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Indiana/Knox b/tools/buildbot/pylibs/pytz/zoneinfo/America/Indiana/Knox deleted file mode 100644 index 6e66a41..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Indiana/Knox and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Indiana/Marengo b/tools/buildbot/pylibs/pytz/zoneinfo/America/Indiana/Marengo deleted file mode 100644 index 255b739..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Indiana/Marengo and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Indiana/Petersburg b/tools/buildbot/pylibs/pytz/zoneinfo/America/Indiana/Petersburg deleted file mode 100644 index c611106..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Indiana/Petersburg and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Indiana/Tell_City b/tools/buildbot/pylibs/pytz/zoneinfo/America/Indiana/Tell_City deleted file mode 100644 index de7b730..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Indiana/Tell_City and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Indiana/Vevay b/tools/buildbot/pylibs/pytz/zoneinfo/America/Indiana/Vevay deleted file mode 100644 index de6167c..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Indiana/Vevay and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Indiana/Vincennes b/tools/buildbot/pylibs/pytz/zoneinfo/America/Indiana/Vincennes deleted file mode 100644 index b79f672..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Indiana/Vincennes and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Indiana/Winamac b/tools/buildbot/pylibs/pytz/zoneinfo/America/Indiana/Winamac deleted file mode 100644 index b2611e7..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Indiana/Winamac and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Indianapolis b/tools/buildbot/pylibs/pytz/zoneinfo/America/Indianapolis deleted file mode 100644 index aa3dfc4..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Indianapolis and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Inuvik b/tools/buildbot/pylibs/pytz/zoneinfo/America/Inuvik deleted file mode 100644 index c17af37..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Inuvik and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Iqaluit b/tools/buildbot/pylibs/pytz/zoneinfo/America/Iqaluit deleted file mode 100644 index a8640e5..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Iqaluit and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Jamaica b/tools/buildbot/pylibs/pytz/zoneinfo/America/Jamaica deleted file mode 100644 index 09e3eb9..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Jamaica and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Jujuy b/tools/buildbot/pylibs/pytz/zoneinfo/America/Jujuy deleted file mode 100644 index 45b806b..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Jujuy and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Juneau b/tools/buildbot/pylibs/pytz/zoneinfo/America/Juneau deleted file mode 100644 index 7ca47f6..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Juneau and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Kentucky/Louisville b/tools/buildbot/pylibs/pytz/zoneinfo/America/Kentucky/Louisville deleted file mode 100644 index 65e7e19..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Kentucky/Louisville and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Kentucky/Monticello b/tools/buildbot/pylibs/pytz/zoneinfo/America/Kentucky/Monticello deleted file mode 100644 index fc2f1b0..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Kentucky/Monticello and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Knox_IN b/tools/buildbot/pylibs/pytz/zoneinfo/America/Knox_IN deleted file mode 100644 index 6e66a41..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Knox_IN and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/La_Paz b/tools/buildbot/pylibs/pytz/zoneinfo/America/La_Paz deleted file mode 100644 index 2a5a15e..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/La_Paz and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Lima b/tools/buildbot/pylibs/pytz/zoneinfo/America/Lima deleted file mode 100644 index a37eeff..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Lima and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Los_Angeles b/tools/buildbot/pylibs/pytz/zoneinfo/America/Los_Angeles deleted file mode 100644 index 3b7ce1d..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Los_Angeles and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Louisville b/tools/buildbot/pylibs/pytz/zoneinfo/America/Louisville deleted file mode 100644 index 65e7e19..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Louisville and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Maceio b/tools/buildbot/pylibs/pytz/zoneinfo/America/Maceio deleted file mode 100644 index b5201e8..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Maceio and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Managua b/tools/buildbot/pylibs/pytz/zoneinfo/America/Managua deleted file mode 100644 index 54c8237..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Managua and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Manaus b/tools/buildbot/pylibs/pytz/zoneinfo/America/Manaus deleted file mode 100644 index 1129211..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Manaus and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Marigot b/tools/buildbot/pylibs/pytz/zoneinfo/America/Marigot deleted file mode 100644 index 15c0f1f..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Marigot and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Martinique b/tools/buildbot/pylibs/pytz/zoneinfo/America/Martinique deleted file mode 100644 index c223ef5..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Martinique and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Mazatlan b/tools/buildbot/pylibs/pytz/zoneinfo/America/Mazatlan deleted file mode 100644 index 6486aa1..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Mazatlan and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Mendoza b/tools/buildbot/pylibs/pytz/zoneinfo/America/Mendoza deleted file mode 100644 index 7ebf85e..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Mendoza and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Menominee b/tools/buildbot/pylibs/pytz/zoneinfo/America/Menominee deleted file mode 100644 index c07a950..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Menominee and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Merida b/tools/buildbot/pylibs/pytz/zoneinfo/America/Merida deleted file mode 100644 index 38c794c..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Merida and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Mexico_City b/tools/buildbot/pylibs/pytz/zoneinfo/America/Mexico_City deleted file mode 100644 index 1434ab0..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Mexico_City and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Miquelon b/tools/buildbot/pylibs/pytz/zoneinfo/America/Miquelon deleted file mode 100644 index 52cd391..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Miquelon and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Moncton b/tools/buildbot/pylibs/pytz/zoneinfo/America/Moncton deleted file mode 100644 index 3312575..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Moncton and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Monterrey b/tools/buildbot/pylibs/pytz/zoneinfo/America/Monterrey deleted file mode 100644 index 7dc5057..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Monterrey and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Montevideo b/tools/buildbot/pylibs/pytz/zoneinfo/America/Montevideo deleted file mode 100644 index 40fc865..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Montevideo and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Montreal b/tools/buildbot/pylibs/pytz/zoneinfo/America/Montreal deleted file mode 100644 index 0ddffb2..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Montreal and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Montserrat b/tools/buildbot/pylibs/pytz/zoneinfo/America/Montserrat deleted file mode 100644 index ee5043a..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Montserrat and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Nassau b/tools/buildbot/pylibs/pytz/zoneinfo/America/Nassau deleted file mode 100644 index aff956c..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Nassau and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/New_York b/tools/buildbot/pylibs/pytz/zoneinfo/America/New_York deleted file mode 100644 index b2c2377..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/New_York and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Nipigon b/tools/buildbot/pylibs/pytz/zoneinfo/America/Nipigon deleted file mode 100644 index fced633..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Nipigon and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Nome b/tools/buildbot/pylibs/pytz/zoneinfo/America/Nome deleted file mode 100644 index b682bfd..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Nome and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Noronha b/tools/buildbot/pylibs/pytz/zoneinfo/America/Noronha deleted file mode 100644 index c602390..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Noronha and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/North_Dakota/Center b/tools/buildbot/pylibs/pytz/zoneinfo/America/North_Dakota/Center deleted file mode 100644 index 786ba17..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/North_Dakota/Center and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/North_Dakota/New_Salem b/tools/buildbot/pylibs/pytz/zoneinfo/America/North_Dakota/New_Salem deleted file mode 100644 index 3488e46..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/North_Dakota/New_Salem and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Panama b/tools/buildbot/pylibs/pytz/zoneinfo/America/Panama deleted file mode 100644 index 3a4ff2a..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Panama and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Pangnirtung b/tools/buildbot/pylibs/pytz/zoneinfo/America/Pangnirtung deleted file mode 100644 index bb42847..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Pangnirtung and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Paramaribo b/tools/buildbot/pylibs/pytz/zoneinfo/America/Paramaribo deleted file mode 100644 index 6f889cc..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Paramaribo and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Phoenix b/tools/buildbot/pylibs/pytz/zoneinfo/America/Phoenix deleted file mode 100644 index 6758902..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Phoenix and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Port-au-Prince b/tools/buildbot/pylibs/pytz/zoneinfo/America/Port-au-Prince deleted file mode 100644 index cd10479..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Port-au-Prince and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Port_of_Spain b/tools/buildbot/pylibs/pytz/zoneinfo/America/Port_of_Spain deleted file mode 100644 index bdedd1b..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Port_of_Spain and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Porto_Acre b/tools/buildbot/pylibs/pytz/zoneinfo/America/Porto_Acre deleted file mode 100644 index edd9a57..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Porto_Acre and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Porto_Velho b/tools/buildbot/pylibs/pytz/zoneinfo/America/Porto_Velho deleted file mode 100644 index 1277479..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Porto_Velho and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Puerto_Rico b/tools/buildbot/pylibs/pytz/zoneinfo/America/Puerto_Rico deleted file mode 100644 index eada37a..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Puerto_Rico and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Rainy_River b/tools/buildbot/pylibs/pytz/zoneinfo/America/Rainy_River deleted file mode 100644 index a5288ed..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Rainy_River and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Rankin_Inlet b/tools/buildbot/pylibs/pytz/zoneinfo/America/Rankin_Inlet deleted file mode 100644 index cbc3499..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Rankin_Inlet and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Recife b/tools/buildbot/pylibs/pytz/zoneinfo/America/Recife deleted file mode 100644 index 0903a77..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Recife and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Regina b/tools/buildbot/pylibs/pytz/zoneinfo/America/Regina deleted file mode 100644 index fa9c6ee..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Regina and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Resolute b/tools/buildbot/pylibs/pytz/zoneinfo/America/Resolute deleted file mode 100644 index 49dea46..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Resolute and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Rio_Branco b/tools/buildbot/pylibs/pytz/zoneinfo/America/Rio_Branco deleted file mode 100644 index edd9a57..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Rio_Branco and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Rosario b/tools/buildbot/pylibs/pytz/zoneinfo/America/Rosario deleted file mode 100644 index 1a335d4..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Rosario and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Santiago b/tools/buildbot/pylibs/pytz/zoneinfo/America/Santiago deleted file mode 100644 index f5eb930..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Santiago and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Santo_Domingo b/tools/buildbot/pylibs/pytz/zoneinfo/America/Santo_Domingo deleted file mode 100644 index 23ace9adc..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Santo_Domingo and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Sao_Paulo b/tools/buildbot/pylibs/pytz/zoneinfo/America/Sao_Paulo deleted file mode 100644 index 846caab..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Sao_Paulo and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Scoresbysund b/tools/buildbot/pylibs/pytz/zoneinfo/America/Scoresbysund deleted file mode 100644 index fae3757..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Scoresbysund and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Shiprock b/tools/buildbot/pylibs/pytz/zoneinfo/America/Shiprock deleted file mode 100644 index f8908fe..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Shiprock and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/St_Barthelemy b/tools/buildbot/pylibs/pytz/zoneinfo/America/St_Barthelemy deleted file mode 100644 index 15c0f1f..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/St_Barthelemy and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/St_Johns b/tools/buildbot/pylibs/pytz/zoneinfo/America/St_Johns deleted file mode 100644 index 4842874..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/St_Johns and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/St_Kitts b/tools/buildbot/pylibs/pytz/zoneinfo/America/St_Kitts deleted file mode 100644 index 911d222..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/St_Kitts and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/St_Lucia b/tools/buildbot/pylibs/pytz/zoneinfo/America/St_Lucia deleted file mode 100644 index b37a1cf..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/St_Lucia and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/St_Thomas b/tools/buildbot/pylibs/pytz/zoneinfo/America/St_Thomas deleted file mode 100644 index 482f0b54..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/St_Thomas and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/St_Vincent b/tools/buildbot/pylibs/pytz/zoneinfo/America/St_Vincent deleted file mode 100644 index e553af7..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/St_Vincent and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Swift_Current b/tools/buildbot/pylibs/pytz/zoneinfo/America/Swift_Current deleted file mode 100644 index 8224028..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Swift_Current and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Tegucigalpa b/tools/buildbot/pylibs/pytz/zoneinfo/America/Tegucigalpa deleted file mode 100644 index 477e939..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Tegucigalpa and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Thule b/tools/buildbot/pylibs/pytz/zoneinfo/America/Thule deleted file mode 100644 index 2969ebe..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Thule and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Thunder_Bay b/tools/buildbot/pylibs/pytz/zoneinfo/America/Thunder_Bay deleted file mode 100644 index 34f750b..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Thunder_Bay and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Tijuana b/tools/buildbot/pylibs/pytz/zoneinfo/America/Tijuana deleted file mode 100644 index 1bf00cd..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Tijuana and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Toronto b/tools/buildbot/pylibs/pytz/zoneinfo/America/Toronto deleted file mode 100644 index b126bc6..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Toronto and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Tortola b/tools/buildbot/pylibs/pytz/zoneinfo/America/Tortola deleted file mode 100644 index 6f9d932..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Tortola and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Vancouver b/tools/buildbot/pylibs/pytz/zoneinfo/America/Vancouver deleted file mode 100644 index b69358c..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Vancouver and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Virgin b/tools/buildbot/pylibs/pytz/zoneinfo/America/Virgin deleted file mode 100644 index 482f0b54..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Virgin and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Whitehorse b/tools/buildbot/pylibs/pytz/zoneinfo/America/Whitehorse deleted file mode 100644 index 15216d5..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Whitehorse and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Winnipeg b/tools/buildbot/pylibs/pytz/zoneinfo/America/Winnipeg deleted file mode 100644 index 5f9e35c..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Winnipeg and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Yakutat b/tools/buildbot/pylibs/pytz/zoneinfo/America/Yakutat deleted file mode 100644 index 8071602..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Yakutat and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/America/Yellowknife b/tools/buildbot/pylibs/pytz/zoneinfo/America/Yellowknife deleted file mode 100644 index 947bec9..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/America/Yellowknife and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/Casey b/tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/Casey deleted file mode 100644 index 19bc896..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/Casey and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/Davis b/tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/Davis deleted file mode 100644 index 79932d3..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/Davis and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/DumontDUrville b/tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/DumontDUrville deleted file mode 100644 index 5ea18e6..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/DumontDUrville and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/Mawson b/tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/Mawson deleted file mode 100644 index bda4421..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/Mawson and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/McMurdo b/tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/McMurdo deleted file mode 100644 index 62ac42f..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/McMurdo and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/Palmer b/tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/Palmer deleted file mode 100644 index 614c9b9..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/Palmer and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/Rothera b/tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/Rothera deleted file mode 100644 index b5dc735..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/Rothera and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/South_Pole b/tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/South_Pole deleted file mode 100644 index 62ac42f..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/South_Pole and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/Syowa b/tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/Syowa deleted file mode 100644 index ba6e5f3..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/Syowa and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/Vostok b/tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/Vostok deleted file mode 100644 index e19e2b7..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Antarctica/Vostok and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Arctic/Longyearbyen b/tools/buildbot/pylibs/pytz/zoneinfo/Arctic/Longyearbyen deleted file mode 100644 index 6326961..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Arctic/Longyearbyen and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Aden b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Aden deleted file mode 100644 index 5aa5a32..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Aden and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Almaty b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Almaty deleted file mode 100644 index 52f941e..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Almaty and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Amman b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Amman deleted file mode 100644 index befc1e2..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Amman and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Anadyr b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Anadyr deleted file mode 100644 index ddbdac3..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Anadyr and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Aqtau b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Aqtau deleted file mode 100644 index 31195d7..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Aqtau and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Aqtobe b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Aqtobe deleted file mode 100644 index 3683be2..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Aqtobe and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Ashgabat b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Ashgabat deleted file mode 100644 index 589dbc1..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Ashgabat and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Ashkhabad b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Ashkhabad deleted file mode 100644 index 589dbc1..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Ashkhabad and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Baghdad b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Baghdad deleted file mode 100644 index 0713557..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Baghdad and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Bahrain b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Bahrain deleted file mode 100644 index d87b7ce..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Bahrain and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Baku b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Baku deleted file mode 100644 index 72ae96e..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Baku and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Bangkok b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Bangkok deleted file mode 100644 index 44a1018..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Bangkok and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Beirut b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Beirut deleted file mode 100644 index c1270bc..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Beirut and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Bishkek b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Bishkek deleted file mode 100644 index fc827d8..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Bishkek and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Brunei b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Brunei deleted file mode 100644 index d6e713d..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Brunei and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Calcutta b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Calcutta deleted file mode 100644 index bc909c9..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Calcutta and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Choibalsan b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Choibalsan deleted file mode 100644 index 01692c6..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Choibalsan and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Chongqing b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Chongqing deleted file mode 100644 index 8a7a28a..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Chongqing and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Chungking b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Chungking deleted file mode 100644 index 8a7a28a..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Chungking and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Colombo b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Colombo deleted file mode 100644 index e5aa06d..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Colombo and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Dacca b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Dacca deleted file mode 100644 index 2e4ce78b..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Dacca and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Damascus b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Damascus deleted file mode 100644 index a8c7e74..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Damascus and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Dhaka b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Dhaka deleted file mode 100644 index 2e4ce78b..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Dhaka and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Dili b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Dili deleted file mode 100644 index b7ac96e..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Dili and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Dubai b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Dubai deleted file mode 100644 index 53f70d5..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Dubai and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Dushanbe b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Dushanbe deleted file mode 100644 index c65ff2a..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Dushanbe and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Gaza b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Gaza deleted file mode 100644 index 02aa4c8..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Gaza and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Harbin b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Harbin deleted file mode 100644 index 292bcb2..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Harbin and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Hong_Kong b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Hong_Kong deleted file mode 100644 index 426f8c0..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Hong_Kong and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Hovd b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Hovd deleted file mode 100644 index 27fab05..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Hovd and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Irkutsk b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Irkutsk deleted file mode 100644 index 617621f..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Irkutsk and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Istanbul b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Istanbul deleted file mode 100644 index a7c16e7..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Istanbul and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Jakarta b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Jakarta deleted file mode 100644 index a4cbe0c..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Jakarta and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Jayapura b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Jayapura deleted file mode 100644 index af227c0..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Jayapura and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Jerusalem b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Jerusalem deleted file mode 100644 index f64f3af..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Jerusalem and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Kabul b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Kabul deleted file mode 100644 index 7392c04..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Kabul and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Kamchatka b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Kamchatka deleted file mode 100644 index 4e53daa..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Kamchatka and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Karachi b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Karachi deleted file mode 100644 index 29de561..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Karachi and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Kashgar b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Kashgar deleted file mode 100644 index 25e6494..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Kashgar and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Katmandu b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Katmandu deleted file mode 100644 index 65c7b63..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Katmandu and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Krasnoyarsk b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Krasnoyarsk deleted file mode 100644 index 9b2fb8e..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Krasnoyarsk and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Kuala_Lumpur b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Kuala_Lumpur deleted file mode 100644 index 41bba37..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Kuala_Lumpur and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Kuching b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Kuching deleted file mode 100644 index 272f4654..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Kuching and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Kuwait b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Kuwait deleted file mode 100644 index 1dab31c..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Kuwait and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Macao b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Macao deleted file mode 100644 index 7c93779..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Macao and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Macau b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Macau deleted file mode 100644 index 7c93779..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Macau and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Magadan b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Magadan deleted file mode 100644 index 7b3d505..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Magadan and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Makassar b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Makassar deleted file mode 100644 index 736a25b..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Makassar and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Manila b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Manila deleted file mode 100644 index efef03e..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Manila and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Muscat b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Muscat deleted file mode 100644 index 729d95e..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Muscat and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Nicosia b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Nicosia deleted file mode 100644 index f7f10ab..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Nicosia and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Novosibirsk b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Novosibirsk deleted file mode 100644 index 806ca1a..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Novosibirsk and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Omsk b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Omsk deleted file mode 100644 index 77b82ed..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Omsk and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Oral b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Oral deleted file mode 100644 index 8da2a1d..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Oral and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Phnom_Penh b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Phnom_Penh deleted file mode 100644 index b9768b1..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Phnom_Penh and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Pontianak b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Pontianak deleted file mode 100644 index 3e882dc..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Pontianak and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Pyongyang b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Pyongyang deleted file mode 100644 index e072692..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Pyongyang and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Qatar b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Qatar deleted file mode 100644 index 49668c2..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Qatar and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Qyzylorda b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Qyzylorda deleted file mode 100644 index fc3bf46..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Qyzylorda and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Rangoon b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Rangoon deleted file mode 100644 index efae261..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Rangoon and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Riyadh b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Riyadh deleted file mode 100644 index 6ebe393..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Riyadh and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Riyadh87 b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Riyadh87 deleted file mode 100644 index 2edb566..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Riyadh87 and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Riyadh88 b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Riyadh88 deleted file mode 100644 index 0dac63b..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Riyadh88 and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Riyadh89 b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Riyadh89 deleted file mode 100644 index daba1e7..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Riyadh89 and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Saigon b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Saigon deleted file mode 100644 index e8dc806..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Saigon and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Sakhalin b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Sakhalin deleted file mode 100644 index b1fda9a..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Sakhalin and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Samarkand b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Samarkand deleted file mode 100644 index 191c07c..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Samarkand and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Seoul b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Seoul deleted file mode 100644 index 1c3c15f..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Seoul and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Shanghai b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Shanghai deleted file mode 100644 index 240c4c6..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Shanghai and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Singapore b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Singapore deleted file mode 100644 index a6f2db8..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Singapore and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Taipei b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Taipei deleted file mode 100644 index 9063636..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Taipei and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Tashkent b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Tashkent deleted file mode 100644 index 5bc8062..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Tashkent and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Tbilisi b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Tbilisi deleted file mode 100644 index 6cca2d4..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Tbilisi and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Tehran b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Tehran deleted file mode 100644 index 9166940..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Tehran and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Tel_Aviv b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Tel_Aviv deleted file mode 100644 index f64f3af..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Tel_Aviv and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Thimbu b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Thimbu deleted file mode 100644 index 90294ae..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Thimbu and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Thimphu b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Thimphu deleted file mode 100644 index 90294ae..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Thimphu and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Tokyo b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Tokyo deleted file mode 100644 index 058c1e9..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Tokyo and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Ujung_Pandang b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Ujung_Pandang deleted file mode 100644 index 736a25b..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Ujung_Pandang and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Ulaanbaatar b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Ulaanbaatar deleted file mode 100644 index 39bdd89..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Ulaanbaatar and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Ulan_Bator b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Ulan_Bator deleted file mode 100644 index 39bdd89..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Ulan_Bator and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Urumqi b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Urumqi deleted file mode 100644 index f46ff38..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Urumqi and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Vientiane b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Vientiane deleted file mode 100644 index 9352adf..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Vientiane and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Vladivostok b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Vladivostok deleted file mode 100644 index 8f880ce..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Vladivostok and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Yakutsk b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Yakutsk deleted file mode 100644 index 5887a10..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Yakutsk and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Yekaterinburg b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Yekaterinburg deleted file mode 100644 index 106477e..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Yekaterinburg and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Yerevan b/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Yerevan deleted file mode 100644 index 3b4fb19..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Asia/Yerevan and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Azores b/tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Azores deleted file mode 100644 index 19e4004..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Azores and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Bermuda b/tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Bermuda deleted file mode 100644 index 54dd33d..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Bermuda and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Canary b/tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Canary deleted file mode 100644 index 972388b..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Canary and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Cape_Verde b/tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Cape_Verde deleted file mode 100644 index 5238ac8..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Cape_Verde and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Faeroe b/tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Faeroe deleted file mode 100644 index 4dab7ef..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Faeroe and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Faroe b/tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Faroe deleted file mode 100644 index 4dab7ef..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Faroe and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Jan_Mayen b/tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Jan_Mayen deleted file mode 100644 index 6326961..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Jan_Mayen and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Madeira b/tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Madeira deleted file mode 100644 index 2175096..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Madeira and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Reykjavik b/tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Reykjavik deleted file mode 100644 index e97f13a..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Reykjavik and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/South_Georgia b/tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/South_Georgia deleted file mode 100644 index ab2c823..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/South_Georgia and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/St_Helena b/tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/St_Helena deleted file mode 100644 index d365e3d..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/St_Helena and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Stanley b/tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Stanley deleted file mode 100644 index 33a6bbe..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Atlantic/Stanley and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/ACT b/tools/buildbot/pylibs/pytz/zoneinfo/Australia/ACT deleted file mode 100644 index d95c245..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/ACT and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Adelaide b/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Adelaide deleted file mode 100644 index b350cb6..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Adelaide and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Brisbane b/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Brisbane deleted file mode 100644 index 3e899a1..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Brisbane and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Broken_Hill b/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Broken_Hill deleted file mode 100644 index d8f3155..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Broken_Hill and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Canberra b/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Canberra deleted file mode 100644 index d95c245..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Canberra and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Currie b/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Currie deleted file mode 100644 index 43ca1e4..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Currie and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Darwin b/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Darwin deleted file mode 100644 index c44512f..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Darwin and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Eucla b/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Eucla deleted file mode 100644 index e78c2d4..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Eucla and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Hobart b/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Hobart deleted file mode 100644 index c4604e5..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Hobart and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/LHI b/tools/buildbot/pylibs/pytz/zoneinfo/Australia/LHI deleted file mode 100644 index 1f542d3..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/LHI and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Lindeman b/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Lindeman deleted file mode 100644 index 05c3c1c..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Lindeman and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Lord_Howe b/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Lord_Howe deleted file mode 100644 index 1f542d3..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Lord_Howe and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Melbourne b/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Melbourne deleted file mode 100644 index af3152f..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Melbourne and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/NSW b/tools/buildbot/pylibs/pytz/zoneinfo/Australia/NSW deleted file mode 100644 index d95c245..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/NSW and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/North b/tools/buildbot/pylibs/pytz/zoneinfo/Australia/North deleted file mode 100644 index c44512f..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/North and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Perth b/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Perth deleted file mode 100644 index 1c7ebb7..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Perth and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Queensland b/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Queensland deleted file mode 100644 index 3e899a1..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Queensland and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/South b/tools/buildbot/pylibs/pytz/zoneinfo/Australia/South deleted file mode 100644 index b350cb6..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/South and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Sydney b/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Sydney deleted file mode 100644 index d95c245..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Sydney and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Tasmania b/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Tasmania deleted file mode 100644 index c4604e5..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Tasmania and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Victoria b/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Victoria deleted file mode 100644 index af3152f..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Victoria and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/West b/tools/buildbot/pylibs/pytz/zoneinfo/Australia/West deleted file mode 100644 index 1c7ebb7..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/West and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Yancowinna b/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Yancowinna deleted file mode 100644 index d8f3155..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Australia/Yancowinna and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Brazil/Acre b/tools/buildbot/pylibs/pytz/zoneinfo/Brazil/Acre deleted file mode 100644 index edd9a57..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Brazil/Acre and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Brazil/DeNoronha b/tools/buildbot/pylibs/pytz/zoneinfo/Brazil/DeNoronha deleted file mode 100644 index c602390..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Brazil/DeNoronha and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Brazil/East b/tools/buildbot/pylibs/pytz/zoneinfo/Brazil/East deleted file mode 100644 index 846caab..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Brazil/East and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Brazil/West b/tools/buildbot/pylibs/pytz/zoneinfo/Brazil/West deleted file mode 100644 index 1129211..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Brazil/West and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/CET b/tools/buildbot/pylibs/pytz/zoneinfo/CET deleted file mode 100644 index 28650ac..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/CET and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/CST6CDT b/tools/buildbot/pylibs/pytz/zoneinfo/CST6CDT deleted file mode 100644 index 5c8a1d9..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/CST6CDT and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Canada/Atlantic b/tools/buildbot/pylibs/pytz/zoneinfo/Canada/Atlantic deleted file mode 100644 index b98c3a7..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Canada/Atlantic and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Canada/Central b/tools/buildbot/pylibs/pytz/zoneinfo/Canada/Central deleted file mode 100644 index 5f9e35c..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Canada/Central and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Canada/East-Saskatchewan b/tools/buildbot/pylibs/pytz/zoneinfo/Canada/East-Saskatchewan deleted file mode 100644 index fa9c6ee..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Canada/East-Saskatchewan and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Canada/Eastern b/tools/buildbot/pylibs/pytz/zoneinfo/Canada/Eastern deleted file mode 100644 index b126bc6..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Canada/Eastern and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Canada/Mountain b/tools/buildbot/pylibs/pytz/zoneinfo/Canada/Mountain deleted file mode 100644 index ba6dbb4..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Canada/Mountain and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Canada/Newfoundland b/tools/buildbot/pylibs/pytz/zoneinfo/Canada/Newfoundland deleted file mode 100644 index 4842874..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Canada/Newfoundland and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Canada/Pacific b/tools/buildbot/pylibs/pytz/zoneinfo/Canada/Pacific deleted file mode 100644 index b69358c..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Canada/Pacific and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Canada/Saskatchewan b/tools/buildbot/pylibs/pytz/zoneinfo/Canada/Saskatchewan deleted file mode 100644 index fa9c6ee..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Canada/Saskatchewan and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Canada/Yukon b/tools/buildbot/pylibs/pytz/zoneinfo/Canada/Yukon deleted file mode 100644 index 15216d5..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Canada/Yukon and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Chile/Continental b/tools/buildbot/pylibs/pytz/zoneinfo/Chile/Continental deleted file mode 100644 index f5eb930..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Chile/Continental and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Chile/EasterIsland b/tools/buildbot/pylibs/pytz/zoneinfo/Chile/EasterIsland deleted file mode 100644 index 28c3dcb..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Chile/EasterIsland and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Cuba b/tools/buildbot/pylibs/pytz/zoneinfo/Cuba deleted file mode 100644 index f7bc5f7..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Cuba and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/EET b/tools/buildbot/pylibs/pytz/zoneinfo/EET deleted file mode 100644 index beb273a..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/EET and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/EST b/tools/buildbot/pylibs/pytz/zoneinfo/EST deleted file mode 100644 index 074a4fc..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/EST and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/EST5EDT b/tools/buildbot/pylibs/pytz/zoneinfo/EST5EDT deleted file mode 100644 index 54541fc..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/EST5EDT and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Egypt b/tools/buildbot/pylibs/pytz/zoneinfo/Egypt deleted file mode 100644 index 39caffb..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Egypt and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Eire b/tools/buildbot/pylibs/pytz/zoneinfo/Eire deleted file mode 100644 index 3dec026..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Eire and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT b/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT deleted file mode 100644 index 2ee1429..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+0 b/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+0 deleted file mode 100644 index 2ee1429..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+0 and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+1 b/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+1 deleted file mode 100644 index 67b88c9..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+1 and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+10 b/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+10 deleted file mode 100644 index d564b28..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+10 and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+11 b/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+11 deleted file mode 100644 index 52eb573..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+11 and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+12 b/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+12 deleted file mode 100644 index c54cead..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+12 and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+2 b/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+2 deleted file mode 100644 index e43b63f..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+2 and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+3 b/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+3 deleted file mode 100644 index f029bac..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+3 and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+4 b/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+4 deleted file mode 100644 index 0ad0ee3..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+4 and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+5 b/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+5 deleted file mode 100644 index e53f3fe..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+5 and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+6 b/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+6 deleted file mode 100644 index b411496..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+6 and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+7 b/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+7 deleted file mode 100644 index 32fa6dc..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+7 and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+8 b/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+8 deleted file mode 100644 index 512578c..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+8 and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+9 b/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+9 deleted file mode 100644 index d3e47e7..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT+9 and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-0 b/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-0 deleted file mode 100644 index 2ee1429..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-0 and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-1 b/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-1 deleted file mode 100644 index 9a6adeb..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-1 and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-10 b/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-10 deleted file mode 100644 index 37b93fb..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-10 and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-11 b/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-11 deleted file mode 100644 index f1af0e2..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-11 and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-12 b/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-12 deleted file mode 100644 index 0fa4a8d..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-12 and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-13 b/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-13 deleted file mode 100644 index 0a5dbe16..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-13 and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-14 b/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-14 deleted file mode 100644 index 41c6a1d..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-14 and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-2 b/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-2 deleted file mode 100644 index 9f63268..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-2 and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-3 b/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-3 deleted file mode 100644 index 38ccd8a..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-3 and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-4 b/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-4 deleted file mode 100644 index 43badfb..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-4 and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-5 b/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-5 deleted file mode 100644 index c88cf21..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-5 and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-6 b/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-6 deleted file mode 100644 index c1a0634..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-6 and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-7 b/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-7 deleted file mode 100644 index bc152ef..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-7 and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-8 b/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-8 deleted file mode 100644 index 2c0de20..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-8 and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-9 b/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-9 deleted file mode 100644 index 8a3bd45..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT-9 and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT0 b/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT0 deleted file mode 100644 index 2ee1429..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/GMT0 and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/Greenwich b/tools/buildbot/pylibs/pytz/zoneinfo/Etc/Greenwich deleted file mode 100644 index 2ee1429..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/Greenwich and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/UCT b/tools/buildbot/pylibs/pytz/zoneinfo/Etc/UCT deleted file mode 100644 index a88c4b6..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/UCT and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/UTC b/tools/buildbot/pylibs/pytz/zoneinfo/Etc/UTC deleted file mode 100644 index 5583f5b..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/UTC and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/Universal b/tools/buildbot/pylibs/pytz/zoneinfo/Etc/Universal deleted file mode 100644 index 5583f5b..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/Universal and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/Zulu b/tools/buildbot/pylibs/pytz/zoneinfo/Etc/Zulu deleted file mode 100644 index 5583f5b..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Etc/Zulu and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Amsterdam b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Amsterdam deleted file mode 100644 index 30ca324..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Amsterdam and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Andorra b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Andorra deleted file mode 100644 index cf9533a..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Andorra and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Athens b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Athens deleted file mode 100644 index 726e56c..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Athens and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Belfast b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Belfast deleted file mode 100644 index fe63ff7..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Belfast and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Belgrade b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Belgrade deleted file mode 100644 index b817364..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Belgrade and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Berlin b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Berlin deleted file mode 100644 index 95ae6f9..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Berlin and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Bratislava b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Bratislava deleted file mode 100644 index 9ab78e9..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Bratislava and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Brussels b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Brussels deleted file mode 100644 index 2791edeb..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Brussels and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Bucharest b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Bucharest deleted file mode 100644 index de2a5f0..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Bucharest and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Budapest b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Budapest deleted file mode 100644 index 2806529..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Budapest and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Chisinau b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Chisinau deleted file mode 100644 index 983cc70..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Chisinau and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Copenhagen b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Copenhagen deleted file mode 100644 index af7e926..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Copenhagen and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Dublin b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Dublin deleted file mode 100644 index 3dec026..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Dublin and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Gibraltar b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Gibraltar deleted file mode 100644 index f3dbeb6..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Gibraltar and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Guernsey b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Guernsey deleted file mode 100644 index fe63ff7..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Guernsey and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Helsinki b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Helsinki deleted file mode 100644 index 97229f3..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Helsinki and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Isle_of_Man b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Isle_of_Man deleted file mode 100644 index fe63ff7..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Isle_of_Man and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Istanbul b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Istanbul deleted file mode 100644 index a7c16e7..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Istanbul and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Jersey b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Jersey deleted file mode 100644 index fe63ff7..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Jersey and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Kaliningrad b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Kaliningrad deleted file mode 100644 index 98ebee9..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Kaliningrad and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Kiev b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Kiev deleted file mode 100644 index 075cc02..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Kiev and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Lisbon b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Lisbon deleted file mode 100644 index 168accf..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Lisbon and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Ljubljana b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Ljubljana deleted file mode 100644 index b817364..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Ljubljana and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/London b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/London deleted file mode 100644 index fe63ff7..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/London and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Luxembourg b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Luxembourg deleted file mode 100644 index 6c194a5..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Luxembourg and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Madrid b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Madrid deleted file mode 100644 index 9311959..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Madrid and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Malta b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Malta deleted file mode 100644 index 5f518a1..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Malta and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Mariehamn b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Mariehamn deleted file mode 100644 index 97229f3..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Mariehamn and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Minsk b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Minsk deleted file mode 100644 index 6a45115..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Minsk and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Monaco b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Monaco deleted file mode 100644 index 664f616..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Monaco and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Moscow b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Moscow deleted file mode 100644 index eb7619c..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Moscow and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Nicosia b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Nicosia deleted file mode 100644 index f7f10ab..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Nicosia and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Oslo b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Oslo deleted file mode 100644 index 6326961..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Oslo and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Paris b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Paris deleted file mode 100644 index fd8ea7d..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Paris and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Podgorica b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Podgorica deleted file mode 100644 index b817364..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Podgorica and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Prague b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Prague deleted file mode 100644 index 9ab78e9..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Prague and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Riga b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Riga deleted file mode 100644 index abea45d3..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Riga and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Rome b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Rome deleted file mode 100644 index 28ddffe..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Rome and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Samara b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Samara deleted file mode 100644 index 196bd1d..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Samara and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/San_Marino b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/San_Marino deleted file mode 100644 index 28ddffe..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/San_Marino and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Sarajevo b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Sarajevo deleted file mode 100644 index b817364..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Sarajevo and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Simferopol b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Simferopol deleted file mode 100644 index ebb63b4..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Simferopol and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Skopje b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Skopje deleted file mode 100644 index b817364..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Skopje and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Sofia b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Sofia deleted file mode 100644 index 2ae3559..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Sofia and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Stockholm b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Stockholm deleted file mode 100644 index 3bc6dbd..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Stockholm and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Tallinn b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Tallinn deleted file mode 100644 index 4ba4424..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Tallinn and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Tirane b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Tirane deleted file mode 100644 index 0b86017..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Tirane and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Tiraspol b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Tiraspol deleted file mode 100644 index 983cc70..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Tiraspol and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Uzhgorod b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Uzhgorod deleted file mode 100644 index 7032ab9..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Uzhgorod and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Vaduz b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Vaduz deleted file mode 100644 index c4e20db..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Vaduz and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Vatican b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Vatican deleted file mode 100644 index 28ddffe..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Vatican and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Vienna b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Vienna deleted file mode 100644 index 8025ba5..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Vienna and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Vilnius b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Vilnius deleted file mode 100644 index b6545b2..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Vilnius and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Volgograd b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Volgograd deleted file mode 100644 index 6580758..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Volgograd and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Warsaw b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Warsaw deleted file mode 100644 index 3797b1c..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Warsaw and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Zagreb b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Zagreb deleted file mode 100644 index b817364..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Zagreb and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Zaporozhye b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Zaporozhye deleted file mode 100644 index 2ccf899..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Zaporozhye and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Zurich b/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Zurich deleted file mode 100644 index 1f0c3da..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Europe/Zurich and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Factory b/tools/buildbot/pylibs/pytz/zoneinfo/Factory deleted file mode 100644 index a65f97e..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Factory and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/GB b/tools/buildbot/pylibs/pytz/zoneinfo/GB deleted file mode 100644 index fe63ff7..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/GB and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/GB-Eire b/tools/buildbot/pylibs/pytz/zoneinfo/GB-Eire deleted file mode 100644 index fe63ff7..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/GB-Eire and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/GMT b/tools/buildbot/pylibs/pytz/zoneinfo/GMT deleted file mode 100644 index 2ee1429..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/GMT and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/GMT+0 b/tools/buildbot/pylibs/pytz/zoneinfo/GMT+0 deleted file mode 100644 index 2ee1429..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/GMT+0 and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/GMT-0 b/tools/buildbot/pylibs/pytz/zoneinfo/GMT-0 deleted file mode 100644 index 2ee1429..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/GMT-0 and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/GMT0 b/tools/buildbot/pylibs/pytz/zoneinfo/GMT0 deleted file mode 100644 index 2ee1429..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/GMT0 and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Greenwich b/tools/buildbot/pylibs/pytz/zoneinfo/Greenwich deleted file mode 100644 index 2ee1429..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Greenwich and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/HST b/tools/buildbot/pylibs/pytz/zoneinfo/HST deleted file mode 100644 index 616c31b..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/HST and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Hongkong b/tools/buildbot/pylibs/pytz/zoneinfo/Hongkong deleted file mode 100644 index 426f8c0..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Hongkong and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Iceland b/tools/buildbot/pylibs/pytz/zoneinfo/Iceland deleted file mode 100644 index e97f13a..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Iceland and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Indian/Antananarivo b/tools/buildbot/pylibs/pytz/zoneinfo/Indian/Antananarivo deleted file mode 100644 index ef6e745..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Indian/Antananarivo and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Indian/Chagos b/tools/buildbot/pylibs/pytz/zoneinfo/Indian/Chagos deleted file mode 100644 index 864d3e2..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Indian/Chagos and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Indian/Christmas b/tools/buildbot/pylibs/pytz/zoneinfo/Indian/Christmas deleted file mode 100644 index 686d5b3c..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Indian/Christmas and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Indian/Cocos b/tools/buildbot/pylibs/pytz/zoneinfo/Indian/Cocos deleted file mode 100644 index 6f7d869..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Indian/Cocos and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Indian/Comoro b/tools/buildbot/pylibs/pytz/zoneinfo/Indian/Comoro deleted file mode 100644 index 297c6db..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Indian/Comoro and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Indian/Kerguelen b/tools/buildbot/pylibs/pytz/zoneinfo/Indian/Kerguelen deleted file mode 100644 index 1f42bbc..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Indian/Kerguelen and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Indian/Mahe b/tools/buildbot/pylibs/pytz/zoneinfo/Indian/Mahe deleted file mode 100644 index d048242..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Indian/Mahe and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Indian/Maldives b/tools/buildbot/pylibs/pytz/zoneinfo/Indian/Maldives deleted file mode 100644 index 65e7eee..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Indian/Maldives and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Indian/Mauritius b/tools/buildbot/pylibs/pytz/zoneinfo/Indian/Mauritius deleted file mode 100644 index b2848b5..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Indian/Mauritius and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Indian/Mayotte b/tools/buildbot/pylibs/pytz/zoneinfo/Indian/Mayotte deleted file mode 100644 index 8401a37..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Indian/Mayotte and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Indian/Reunion b/tools/buildbot/pylibs/pytz/zoneinfo/Indian/Reunion deleted file mode 100644 index 9b3830e..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Indian/Reunion and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Iran b/tools/buildbot/pylibs/pytz/zoneinfo/Iran deleted file mode 100644 index 9166940..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Iran and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Israel b/tools/buildbot/pylibs/pytz/zoneinfo/Israel deleted file mode 100644 index f64f3af..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Israel and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Jamaica b/tools/buildbot/pylibs/pytz/zoneinfo/Jamaica deleted file mode 100644 index 09e3eb9..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Jamaica and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Japan b/tools/buildbot/pylibs/pytz/zoneinfo/Japan deleted file mode 100644 index 058c1e9..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Japan and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Kwajalein b/tools/buildbot/pylibs/pytz/zoneinfo/Kwajalein deleted file mode 100644 index b572372..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Kwajalein and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Libya b/tools/buildbot/pylibs/pytz/zoneinfo/Libya deleted file mode 100644 index 943f9a3..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Libya and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/MET b/tools/buildbot/pylibs/pytz/zoneinfo/MET deleted file mode 100644 index fee1909..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/MET and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/MST b/tools/buildbot/pylibs/pytz/zoneinfo/MST deleted file mode 100644 index da3e926..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/MST and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/MST7MDT b/tools/buildbot/pylibs/pytz/zoneinfo/MST7MDT deleted file mode 100644 index 726a7e5..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/MST7MDT and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Mexico/BajaNorte b/tools/buildbot/pylibs/pytz/zoneinfo/Mexico/BajaNorte deleted file mode 100644 index 1bf00cd..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Mexico/BajaNorte and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Mexico/BajaSur b/tools/buildbot/pylibs/pytz/zoneinfo/Mexico/BajaSur deleted file mode 100644 index 6486aa1..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Mexico/BajaSur and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Mexico/General b/tools/buildbot/pylibs/pytz/zoneinfo/Mexico/General deleted file mode 100644 index 1434ab0..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Mexico/General and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Mideast/Riyadh87 b/tools/buildbot/pylibs/pytz/zoneinfo/Mideast/Riyadh87 deleted file mode 100644 index 2edb566..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Mideast/Riyadh87 and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Mideast/Riyadh88 b/tools/buildbot/pylibs/pytz/zoneinfo/Mideast/Riyadh88 deleted file mode 100644 index 0dac63b..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Mideast/Riyadh88 and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Mideast/Riyadh89 b/tools/buildbot/pylibs/pytz/zoneinfo/Mideast/Riyadh89 deleted file mode 100644 index daba1e7..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Mideast/Riyadh89 and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/NZ b/tools/buildbot/pylibs/pytz/zoneinfo/NZ deleted file mode 100644 index a40767d..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/NZ and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/NZ-CHAT b/tools/buildbot/pylibs/pytz/zoneinfo/NZ-CHAT deleted file mode 100644 index 6329e4f..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/NZ-CHAT and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Navajo b/tools/buildbot/pylibs/pytz/zoneinfo/Navajo deleted file mode 100644 index f8908fe..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Navajo and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/PRC b/tools/buildbot/pylibs/pytz/zoneinfo/PRC deleted file mode 100644 index 240c4c6..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/PRC and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/PST8PDT b/tools/buildbot/pylibs/pytz/zoneinfo/PST8PDT deleted file mode 100644 index 6242ac0..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/PST8PDT and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Apia b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Apia deleted file mode 100644 index b8d5890..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Apia and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Auckland b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Auckland deleted file mode 100644 index a40767d..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Auckland and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Chatham b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Chatham deleted file mode 100644 index 6329e4f..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Chatham and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Easter b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Easter deleted file mode 100644 index 28c3dcb..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Easter and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Efate b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Efate deleted file mode 100644 index c46154a8..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Efate and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Enderbury b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Enderbury deleted file mode 100644 index 69e75d7..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Enderbury and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Fakaofo b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Fakaofo deleted file mode 100644 index b3991ee..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Fakaofo and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Fiji b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Fiji deleted file mode 100644 index 2a762c2..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Fiji and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Funafuti b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Funafuti deleted file mode 100644 index 66cf5e1..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Funafuti and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Galapagos b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Galapagos deleted file mode 100644 index 7504cc6..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Galapagos and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Gambier b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Gambier deleted file mode 100644 index fc49c03..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Gambier and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Guadalcanal b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Guadalcanal deleted file mode 100644 index 3a4ec12..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Guadalcanal and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Guam b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Guam deleted file mode 100644 index a05292f4..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Guam and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Honolulu b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Honolulu deleted file mode 100644 index 9297d8c..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Honolulu and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Johnston b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Johnston deleted file mode 100644 index 616c31b..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Johnston and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Kiritimati b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Kiritimati deleted file mode 100644 index 7131453c..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Kiritimati and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Kosrae b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Kosrae deleted file mode 100644 index 6cac75a..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Kosrae and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Kwajalein b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Kwajalein deleted file mode 100644 index b572372..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Kwajalein and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Majuro b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Majuro deleted file mode 100644 index eab93a2..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Majuro and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Marquesas b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Marquesas deleted file mode 100644 index cd2d5b0..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Marquesas and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Midway b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Midway deleted file mode 100644 index 8889a26..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Midway and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Nauru b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Nauru deleted file mode 100644 index 1d8179b..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Nauru and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Niue b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Niue deleted file mode 100644 index b9f18a5..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Niue and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Norfolk b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Norfolk deleted file mode 100644 index 2e989c2..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Norfolk and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Noumea b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Noumea deleted file mode 100644 index ae9e138..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Noumea and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Pago_Pago b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Pago_Pago deleted file mode 100644 index fa084ba..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Pago_Pago and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Palau b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Palau deleted file mode 100644 index efc556b..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Palau and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Pitcairn b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Pitcairn deleted file mode 100644 index 51f01c6..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Pitcairn and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Ponape b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Ponape deleted file mode 100644 index f175ea5..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Ponape and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Port_Moresby b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Port_Moresby deleted file mode 100644 index 8d4d12c..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Port_Moresby and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Rarotonga b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Rarotonga deleted file mode 100644 index 5812997..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Rarotonga and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Saipan b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Saipan deleted file mode 100644 index 519c86e..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Saipan and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Samoa b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Samoa deleted file mode 100644 index fa084ba..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Samoa and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Tahiti b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Tahiti deleted file mode 100644 index 22f8697..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Tahiti and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Tarawa b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Tarawa deleted file mode 100644 index 065dcd8..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Tarawa and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Tongatapu b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Tongatapu deleted file mode 100644 index 01ab6b8..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Tongatapu and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Truk b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Truk deleted file mode 100644 index 4bb15e1..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Truk and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Wake b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Wake deleted file mode 100644 index f89c528..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Wake and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Wallis b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Wallis deleted file mode 100644 index 9aaf558..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Wallis and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Yap b/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Yap deleted file mode 100644 index 4bb15e1..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Pacific/Yap and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Poland b/tools/buildbot/pylibs/pytz/zoneinfo/Poland deleted file mode 100644 index 3797b1c..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Poland and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Portugal b/tools/buildbot/pylibs/pytz/zoneinfo/Portugal deleted file mode 100644 index 168accf..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Portugal and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/ROC b/tools/buildbot/pylibs/pytz/zoneinfo/ROC deleted file mode 100644 index 9063636..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/ROC and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/ROK b/tools/buildbot/pylibs/pytz/zoneinfo/ROK deleted file mode 100644 index 1c3c15f..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/ROK and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Singapore b/tools/buildbot/pylibs/pytz/zoneinfo/Singapore deleted file mode 100644 index a6f2db8..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Singapore and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Turkey b/tools/buildbot/pylibs/pytz/zoneinfo/Turkey deleted file mode 100644 index a7c16e7..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Turkey and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/UCT b/tools/buildbot/pylibs/pytz/zoneinfo/UCT deleted file mode 100644 index a88c4b6..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/UCT and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/US/Alaska b/tools/buildbot/pylibs/pytz/zoneinfo/US/Alaska deleted file mode 100644 index d147350..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/US/Alaska and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/US/Aleutian b/tools/buildbot/pylibs/pytz/zoneinfo/US/Aleutian deleted file mode 100644 index 391ec98..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/US/Aleutian and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/US/Arizona b/tools/buildbot/pylibs/pytz/zoneinfo/US/Arizona deleted file mode 100644 index 6758902..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/US/Arizona and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/US/Central b/tools/buildbot/pylibs/pytz/zoneinfo/US/Central deleted file mode 100644 index e932c6d..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/US/Central and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/US/East-Indiana b/tools/buildbot/pylibs/pytz/zoneinfo/US/East-Indiana deleted file mode 100644 index aa3dfc4..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/US/East-Indiana and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/US/Eastern b/tools/buildbot/pylibs/pytz/zoneinfo/US/Eastern deleted file mode 100644 index b2c2377..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/US/Eastern and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/US/Hawaii b/tools/buildbot/pylibs/pytz/zoneinfo/US/Hawaii deleted file mode 100644 index 9297d8c..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/US/Hawaii and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/US/Indiana-Starke b/tools/buildbot/pylibs/pytz/zoneinfo/US/Indiana-Starke deleted file mode 100644 index 6e66a41..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/US/Indiana-Starke and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/US/Michigan b/tools/buildbot/pylibs/pytz/zoneinfo/US/Michigan deleted file mode 100644 index da53d46..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/US/Michigan and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/US/Mountain b/tools/buildbot/pylibs/pytz/zoneinfo/US/Mountain deleted file mode 100644 index f8908fe..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/US/Mountain and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/US/Pacific b/tools/buildbot/pylibs/pytz/zoneinfo/US/Pacific deleted file mode 100644 index 3b7ce1d..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/US/Pacific and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/US/Pacific-New b/tools/buildbot/pylibs/pytz/zoneinfo/US/Pacific-New deleted file mode 100644 index 3b7ce1d..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/US/Pacific-New and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/US/Samoa b/tools/buildbot/pylibs/pytz/zoneinfo/US/Samoa deleted file mode 100644 index fa084ba..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/US/Samoa and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/UTC b/tools/buildbot/pylibs/pytz/zoneinfo/UTC deleted file mode 100644 index 5583f5b..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/UTC and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Universal b/tools/buildbot/pylibs/pytz/zoneinfo/Universal deleted file mode 100644 index 5583f5b..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Universal and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/W-SU b/tools/buildbot/pylibs/pytz/zoneinfo/W-SU deleted file mode 100644 index eb7619c..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/W-SU and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/WET b/tools/buildbot/pylibs/pytz/zoneinfo/WET deleted file mode 100644 index 444a1933..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/WET and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/Zulu b/tools/buildbot/pylibs/pytz/zoneinfo/Zulu deleted file mode 100644 index 5583f5b..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/Zulu and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/iso3166.tab b/tools/buildbot/pylibs/pytz/zoneinfo/iso3166.tab deleted file mode 100644 index 8d62399..0000000 --- a/tools/buildbot/pylibs/pytz/zoneinfo/iso3166.tab +++ /dev/null @@ -1,269 +0,0 @@ -# ISO 3166 alpha-2 country codes -# -# @(#)iso3166.tab 8.5 -# -# From Paul Eggert (2006-09-27): -# -# This file contains a table with the following columns: -# 1. ISO 3166-1 alpha-2 country code, current as of -# ISO 3166-1 Newsletter VI-1 (2007-09-21). See: -# -# ISO 3166 Maintenance agency (ISO 3166/MA) -# . -# 2. The usual English name for the country, -# chosen so that alphabetic sorting of subsets produces helpful lists. -# This is not the same as the English name in the ISO 3166 tables. -# -# Columns are separated by a single tab. -# The table is sorted by country code. -# -# Lines beginning with `#' are comments. -# -#country- -#code country name -AD Andorra -AE United Arab Emirates -AF Afghanistan -AG Antigua & Barbuda -AI Anguilla -AL Albania -AM Armenia -AN Netherlands Antilles -AO Angola -AQ Antarctica -AR Argentina -AS Samoa (American) -AT Austria -AU Australia -AW Aruba -AX Aaland Islands -AZ Azerbaijan -BA Bosnia & Herzegovina -BB Barbados -BD Bangladesh -BE Belgium -BF Burkina Faso -BG Bulgaria -BH Bahrain -BI Burundi -BJ Benin -BL St Barthelemy -BM Bermuda -BN Brunei -BO Bolivia -BR Brazil -BS Bahamas -BT Bhutan -BV Bouvet Island -BW Botswana -BY Belarus -BZ Belize -CA Canada -CC Cocos (Keeling) Islands -CD Congo (Dem. Rep.) -CF Central African Rep. -CG Congo (Rep.) -CH Switzerland -CI Cote d'Ivoire -CK Cook Islands -CL Chile -CM Cameroon -CN China -CO Colombia -CR Costa Rica -CU Cuba -CV Cape Verde -CX Christmas Island -CY Cyprus -CZ Czech Republic -DE Germany -DJ Djibouti -DK Denmark -DM Dominica -DO Dominican Republic -DZ Algeria -EC Ecuador -EE Estonia -EG Egypt -EH Western Sahara -ER Eritrea -ES Spain -ET Ethiopia -FI Finland -FJ Fiji -FK Falkland Islands -FM Micronesia -FO Faroe Islands -FR France -GA Gabon -GB Britain (UK) -GD Grenada -GE Georgia -GF French Guiana -GG Guernsey -GH Ghana -GI Gibraltar -GL Greenland -GM Gambia -GN Guinea -GP Guadeloupe -GQ Equatorial Guinea -GR Greece -GS South Georgia & the South Sandwich Islands -GT Guatemala -GU Guam -GW Guinea-Bissau -GY Guyana -HK Hong Kong -HM Heard Island & McDonald Islands -HN Honduras -HR Croatia -HT Haiti -HU Hungary -ID Indonesia -IE Ireland -IL Israel -IM Isle of Man -IN India -IO British Indian Ocean Territory -IQ Iraq -IR Iran -IS Iceland -IT Italy -JE Jersey -JM Jamaica -JO Jordan -JP Japan -KE Kenya -KG Kyrgyzstan -KH Cambodia -KI Kiribati -KM Comoros -KN St Kitts & Nevis -KP Korea (North) -KR Korea (South) -KW Kuwait -KY Cayman Islands -KZ Kazakhstan -LA Laos -LB Lebanon -LC St Lucia -LI Liechtenstein -LK Sri Lanka -LR Liberia -LS Lesotho -LT Lithuania -LU Luxembourg -LV Latvia -LY Libya -MA Morocco -MC Monaco -MD Moldova -ME Montenegro -MF St Martin (French part) -MG Madagascar -MH Marshall Islands -MK Macedonia -ML Mali -MM Myanmar (Burma) -MN Mongolia -MO Macau -MP Northern Mariana Islands -MQ Martinique -MR Mauritania -MS Montserrat -MT Malta -MU Mauritius -MV Maldives -MW Malawi -MX Mexico -MY Malaysia -MZ Mozambique -NA Namibia -NC New Caledonia -NE Niger -NF Norfolk Island -NG Nigeria -NI Nicaragua -NL Netherlands -NO Norway -NP Nepal -NR Nauru -NU Niue -NZ New Zealand -OM Oman -PA Panama -PE Peru -PF French Polynesia -PG Papua New Guinea -PH Philippines -PK Pakistan -PL Poland -PM St Pierre & Miquelon -PN Pitcairn -PR Puerto Rico -PS Palestine -PT Portugal -PW Palau -PY Paraguay -QA Qatar -RE Reunion -RO Romania -RS Serbia -RU Russia -RW Rwanda -SA Saudi Arabia -SB Solomon Islands -SC Seychelles -SD Sudan -SE Sweden -SG Singapore -SH St Helena -SI Slovenia -SJ Svalbard & Jan Mayen -SK Slovakia -SL Sierra Leone -SM San Marino -SN Senegal -SO Somalia -SR Suriname -ST Sao Tome & Principe -SV El Salvador -SY Syria -SZ Swaziland -TC Turks & Caicos Is -TD Chad -TF French Southern & Antarctic Lands -TG Togo -TH Thailand -TJ Tajikistan -TK Tokelau -TL East Timor -TM Turkmenistan -TN Tunisia -TO Tonga -TR Turkey -TT Trinidad & Tobago -TV Tuvalu -TW Taiwan -TZ Tanzania -UA Ukraine -UG Uganda -UM US minor outlying islands -US United States -UY Uruguay -UZ Uzbekistan -VA Vatican City -VC St Vincent -VE Venezuela -VG Virgin Islands (UK) -VI Virgin Islands (US) -VN Vietnam -VU Vanuatu -WF Wallis & Futuna -WS Samoa (western) -YE Yemen -YT Mayotte -ZA South Africa -ZM Zambia -ZW Zimbabwe diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/localtime b/tools/buildbot/pylibs/pytz/zoneinfo/localtime deleted file mode 100644 index a65f97e..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/localtime and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/posixrules b/tools/buildbot/pylibs/pytz/zoneinfo/posixrules deleted file mode 100644 index b2c2377..0000000 Binary files a/tools/buildbot/pylibs/pytz/zoneinfo/posixrules and /dev/null differ diff --git a/tools/buildbot/pylibs/pytz/zoneinfo/zone.tab b/tools/buildbot/pylibs/pytz/zoneinfo/zone.tab deleted file mode 100644 index 6366945..0000000 --- a/tools/buildbot/pylibs/pytz/zoneinfo/zone.tab +++ /dev/null @@ -1,422 +0,0 @@ -# @(#)zone.tab 8.13 -# -# TZ zone descriptions -# -# From Paul Eggert (1996-08-05): -# -# This file contains a table with the following columns: -# 1. ISO 3166 2-character country code. See the file `iso3166.tab'. -# 2. Latitude and longitude of the zone's principal location -# in ISO 6709 sign-degrees-minutes-seconds format, -# either +-DDMM+-DDDMM or +-DDMMSS+-DDDMMSS, -# first latitude (+ is north), then longitude (+ is east). -# 3. Zone name used in value of TZ environment variable. -# 4. Comments; present if and only if the country has multiple rows. -# -# Columns are separated by a single tab. -# The table is sorted first by country, then an order within the country that -# (1) makes some geographical sense, and -# (2) puts the most populous zones first, where that does not contradict (1). -# -# Lines beginning with `#' are comments. -# -#country- -#code coordinates TZ comments -AD +4230+00131 Europe/Andorra -AE +2518+05518 Asia/Dubai -AF +3431+06912 Asia/Kabul -AG +1703-06148 America/Antigua -AI +1812-06304 America/Anguilla -AL +4120+01950 Europe/Tirane -AM +4011+04430 Asia/Yerevan -AN +1211-06900 America/Curacao -AO -0848+01314 Africa/Luanda -AQ -7750+16636 Antarctica/McMurdo McMurdo Station, Ross Island -AQ -9000+00000 Antarctica/South_Pole Amundsen-Scott Station, South Pole -AQ -6734-06808 Antarctica/Rothera Rothera Station, Adelaide Island -AQ -6448-06406 Antarctica/Palmer Palmer Station, Anvers Island -AQ -6736+06253 Antarctica/Mawson Mawson Station, Holme Bay -AQ -6835+07758 Antarctica/Davis Davis Station, Vestfold Hills -AQ -6617+11031 Antarctica/Casey Casey Station, Bailey Peninsula -AQ -7824+10654 Antarctica/Vostok Vostok Station, S Magnetic Pole -AQ -6640+14001 Antarctica/DumontDUrville Dumont-d'Urville Station, Terre Adelie -AQ -690022+0393524 Antarctica/Syowa Syowa Station, E Ongul I -AR -3436-05827 America/Argentina/Buenos_Aires Buenos Aires (BA, CF) -AR -3124-06411 America/Argentina/Cordoba most locations (CB, CC, CN, ER, FM, LP, MN, NQ, RN, SA, SE, SF, SL) -AR -2411-06518 America/Argentina/Jujuy Jujuy (JY) -AR -2649-06513 America/Argentina/Tucuman Tucuman (TM) -AR -2828-06547 America/Argentina/Catamarca Catamarca (CT), Chubut (CH) -AR -2926-06651 America/Argentina/La_Rioja La Rioja (LR) -AR -3132-06831 America/Argentina/San_Juan San Juan (SJ) -AR -3253-06849 America/Argentina/Mendoza Mendoza (MZ) -AR -5138-06913 America/Argentina/Rio_Gallegos Santa Cruz (SC) -AR -5448-06818 America/Argentina/Ushuaia Tierra del Fuego (TF) -AS -1416-17042 Pacific/Pago_Pago -AT +4813+01620 Europe/Vienna -AU -3133+15905 Australia/Lord_Howe Lord Howe Island -AU -4253+14719 Australia/Hobart Tasmania - most locations -AU -3956+14352 Australia/Currie Tasmania - King Island -AU -3749+14458 Australia/Melbourne Victoria -AU -3352+15113 Australia/Sydney New South Wales - most locations -AU -3157+14127 Australia/Broken_Hill New South Wales - Yancowinna -AU -2728+15302 Australia/Brisbane Queensland - most locations -AU -2016+14900 Australia/Lindeman Queensland - Holiday Islands -AU -3455+13835 Australia/Adelaide South Australia -AU -1228+13050 Australia/Darwin Northern Territory -AU -3157+11551 Australia/Perth Western Australia - most locations -AU -3143+12852 Australia/Eucla Western Australia - Eucla area -AW +1230-06958 America/Aruba -AX +6006+01957 Europe/Mariehamn -AZ +4023+04951 Asia/Baku -BA +4352+01825 Europe/Sarajevo -BB +1306-05937 America/Barbados -BD +2343+09025 Asia/Dhaka -BE +5050+00420 Europe/Brussels -BF +1222-00131 Africa/Ouagadougou -BG +4241+02319 Europe/Sofia -BH +2623+05035 Asia/Bahrain -BI -0323+02922 Africa/Bujumbura -BJ +0629+00237 Africa/Porto-Novo -BL +1753-06251 America/St_Barthelemy -BM +3217-06446 Atlantic/Bermuda -BN +0456+11455 Asia/Brunei -BO -1630-06809 America/La_Paz -BR -0351-03225 America/Noronha Atlantic islands -BR -0127-04829 America/Belem Amapa, E Para -BR -0343-03830 America/Fortaleza NE Brazil (MA, PI, CE, RN, PB) -BR -0803-03454 America/Recife Pernambuco -BR -0712-04812 America/Araguaina Tocantins -BR -0940-03543 America/Maceio Alagoas, Sergipe -BR -1259-03831 America/Bahia Bahia -BR -2332-04637 America/Sao_Paulo S & SE Brazil (GO, DF, MG, ES, RJ, SP, PR, SC, RS) -BR -2027-05437 America/Campo_Grande Mato Grosso do Sul -BR -1535-05605 America/Cuiaba Mato Grosso -BR -0846-06354 America/Porto_Velho W Para, Rondonia -BR +0249-06040 America/Boa_Vista Roraima -BR -0308-06001 America/Manaus E Amazonas -BR -0640-06952 America/Eirunepe W Amazonas -BR -0958-06748 America/Rio_Branco Acre -BS +2505-07721 America/Nassau -BT +2728+08939 Asia/Thimphu -BW -2545+02555 Africa/Gaborone -BY +5354+02734 Europe/Minsk -BZ +1730-08812 America/Belize -CA +4734-05243 America/St_Johns Newfoundland Time, including SE Labrador -CA +4439-06336 America/Halifax Atlantic Time - Nova Scotia (most places), PEI -CA +4612-05957 America/Glace_Bay Atlantic Time - Nova Scotia - places that did not observe DST 1966-1971 -CA +4606-06447 America/Moncton Atlantic Time - New Brunswick -CA +5320-06025 America/Goose_Bay Atlantic Time - Labrador - most locations -CA +5125-05707 America/Blanc-Sablon Atlantic Standard Time - Quebec - Lower North Shore -CA +4531-07334 America/Montreal Eastern Time - Quebec - most locations -CA +4339-07923 America/Toronto Eastern Time - Ontario - most locations -CA +4901-08816 America/Nipigon Eastern Time - Ontario & Quebec - places that did not observe DST 1967-1973 -CA +4823-08915 America/Thunder_Bay Eastern Time - Thunder Bay, Ontario -CA +6344-06828 America/Iqaluit Eastern Time - east Nunavut - most locations -CA +6608-06544 America/Pangnirtung Eastern Time - Pangnirtung, Nunavut -CA +744144-0944945 America/Resolute Eastern Time - Resolute, Nunavut -CA +484531-0913718 America/Atikokan Eastern Standard Time - Atikokan, Ontario and Southampton I, Nunavut -CA +624900-0920459 America/Rankin_Inlet Central Time - central Nunavut -CA +4953-09709 America/Winnipeg Central Time - Manitoba & west Ontario -CA +4843-09434 America/Rainy_River Central Time - Rainy River & Fort Frances, Ontario -CA +5024-10439 America/Regina Central Standard Time - Saskatchewan - most locations -CA +5017-10750 America/Swift_Current Central Standard Time - Saskatchewan - midwest -CA +5333-11328 America/Edmonton Mountain Time - Alberta, east British Columbia & west Saskatchewan -CA +690650-1050310 America/Cambridge_Bay Mountain Time - west Nunavut -CA +6227-11421 America/Yellowknife Mountain Time - central Northwest Territories -CA +682059-1334300 America/Inuvik Mountain Time - west Northwest Territories -CA +5946-12014 America/Dawson_Creek Mountain Standard Time - Dawson Creek & Fort Saint John, British Columbia -CA +4916-12307 America/Vancouver Pacific Time - west British Columbia -CA +6043-13503 America/Whitehorse Pacific Time - south Yukon -CA +6404-13925 America/Dawson Pacific Time - north Yukon -CC -1210+09655 Indian/Cocos -CD -0418+01518 Africa/Kinshasa west Dem. Rep. of Congo -CD -1140+02728 Africa/Lubumbashi east Dem. Rep. of Congo -CF +0422+01835 Africa/Bangui -CG -0416+01517 Africa/Brazzaville -CH +4723+00832 Europe/Zurich -CI +0519-00402 Africa/Abidjan -CK -2114-15946 Pacific/Rarotonga -CL -3327-07040 America/Santiago most locations -CL -2709-10926 Pacific/Easter Easter Island & Sala y Gomez -CM +0403+00942 Africa/Douala -CN +3114+12128 Asia/Shanghai east China - Beijing, Guangdong, Shanghai, etc. -CN +4545+12641 Asia/Harbin Heilongjiang (except Mohe), Jilin -CN +2934+10635 Asia/Chongqing central China - Sichuan, Yunnan, Guangxi, Shaanxi, Guizhou, etc. -CN +4348+08735 Asia/Urumqi most of Tibet & Xinjiang -CN +3929+07559 Asia/Kashgar west Tibet & Xinjiang -CO +0436-07405 America/Bogota -CR +0956-08405 America/Costa_Rica -CU +2308-08222 America/Havana -CV +1455-02331 Atlantic/Cape_Verde -CX -1025+10543 Indian/Christmas -CY +3510+03322 Asia/Nicosia -CZ +5005+01426 Europe/Prague -DE +5230+01322 Europe/Berlin -DJ +1136+04309 Africa/Djibouti -DK +5540+01235 Europe/Copenhagen -DM +1518-06124 America/Dominica -DO +1828-06954 America/Santo_Domingo -DZ +3647+00303 Africa/Algiers -EC -0210-07950 America/Guayaquil mainland -EC -0054-08936 Pacific/Galapagos Galapagos Islands -EE +5925+02445 Europe/Tallinn -EG +3003+03115 Africa/Cairo -EH +2709-01312 Africa/El_Aaiun -ER +1520+03853 Africa/Asmara -ES +4024-00341 Europe/Madrid mainland -ES +3553-00519 Africa/Ceuta Ceuta & Melilla -ES +2806-01524 Atlantic/Canary Canary Islands -ET +0902+03842 Africa/Addis_Ababa -FI +6010+02458 Europe/Helsinki -FJ -1808+17825 Pacific/Fiji -FK -5142-05751 Atlantic/Stanley -FM +0725+15147 Pacific/Truk Truk (Chuuk) and Yap -FM +0658+15813 Pacific/Ponape Ponape (Pohnpei) -FM +0519+16259 Pacific/Kosrae Kosrae -FO +6201-00646 Atlantic/Faroe -FR +4852+00220 Europe/Paris -GA +0023+00927 Africa/Libreville -GB +513030-0000731 Europe/London -GD +1203-06145 America/Grenada -GE +4143+04449 Asia/Tbilisi -GF +0456-05220 America/Cayenne -GG +4927-00232 Europe/Guernsey -GH +0533-00013 Africa/Accra -GI +3608-00521 Europe/Gibraltar -GL +6411-05144 America/Godthab most locations -GL +7646-01840 America/Danmarkshavn east coast, north of Scoresbysund -GL +7029-02158 America/Scoresbysund Scoresbysund / Ittoqqortoormiit -GL +7634-06847 America/Thule Thule / Pituffik -GM +1328-01639 Africa/Banjul -GN +0931-01343 Africa/Conakry -GP +1614-06132 America/Guadeloupe -GQ +0345+00847 Africa/Malabo -GR +3758+02343 Europe/Athens -GS -5416-03632 Atlantic/South_Georgia -GT +1438-09031 America/Guatemala -GU +1328+14445 Pacific/Guam -GW +1151-01535 Africa/Bissau -GY +0648-05810 America/Guyana -HK +2217+11409 Asia/Hong_Kong -HN +1406-08713 America/Tegucigalpa -HR +4548+01558 Europe/Zagreb -HT +1832-07220 America/Port-au-Prince -HU +4730+01905 Europe/Budapest -ID -0610+10648 Asia/Jakarta Java & Sumatra -ID -0002+10920 Asia/Pontianak west & central Borneo -ID -0507+11924 Asia/Makassar east & south Borneo, Celebes, Bali, Nusa Tengarra, west Timor -ID -0232+14042 Asia/Jayapura Irian Jaya & the Moluccas -IE +5320-00615 Europe/Dublin -IL +3146+03514 Asia/Jerusalem -IM +5409-00428 Europe/Isle_of_Man -IN +2232+08822 Asia/Calcutta -IO -0720+07225 Indian/Chagos -IQ +3321+04425 Asia/Baghdad -IR +3540+05126 Asia/Tehran -IS +6409-02151 Atlantic/Reykjavik -IT +4154+01229 Europe/Rome -JE +4912-00207 Europe/Jersey -JM +1800-07648 America/Jamaica -JO +3157+03556 Asia/Amman -JP +353916+1394441 Asia/Tokyo -KE -0117+03649 Africa/Nairobi -KG +4254+07436 Asia/Bishkek -KH +1133+10455 Asia/Phnom_Penh -KI +0125+17300 Pacific/Tarawa Gilbert Islands -KI -0308-17105 Pacific/Enderbury Phoenix Islands -KI +0152-15720 Pacific/Kiritimati Line Islands -KM -1141+04316 Indian/Comoro -KN +1718-06243 America/St_Kitts -KP +3901+12545 Asia/Pyongyang -KR +3733+12658 Asia/Seoul -KW +2920+04759 Asia/Kuwait -KY +1918-08123 America/Cayman -KZ +4315+07657 Asia/Almaty most locations -KZ +4448+06528 Asia/Qyzylorda Qyzylorda (Kyzylorda, Kzyl-Orda) -KZ +5017+05710 Asia/Aqtobe Aqtobe (Aktobe) -KZ +4431+05016 Asia/Aqtau Atyrau (Atirau, Gur'yev), Mangghystau (Mankistau) -KZ +5113+05121 Asia/Oral West Kazakhstan -LA +1758+10236 Asia/Vientiane -LB +3353+03530 Asia/Beirut -LC +1401-06100 America/St_Lucia -LI +4709+00931 Europe/Vaduz -LK +0656+07951 Asia/Colombo -LR +0618-01047 Africa/Monrovia -LS -2928+02730 Africa/Maseru -LT +5441+02519 Europe/Vilnius -LU +4936+00609 Europe/Luxembourg -LV +5657+02406 Europe/Riga -LY +3254+01311 Africa/Tripoli -MA +3339-00735 Africa/Casablanca -MC +4342+00723 Europe/Monaco -MD +4700+02850 Europe/Chisinau -ME +4226+01916 Europe/Podgorica -MF +1804-06305 America/Marigot -MG -1855+04731 Indian/Antananarivo -MH +0709+17112 Pacific/Majuro most locations -MH +0905+16720 Pacific/Kwajalein Kwajalein -MK +4159+02126 Europe/Skopje -ML +1239-00800 Africa/Bamako -MM +1647+09610 Asia/Rangoon -MN +4755+10653 Asia/Ulaanbaatar most locations -MN +4801+09139 Asia/Hovd Bayan-Olgiy, Govi-Altai, Hovd, Uvs, Zavkhan -MN +4804+11430 Asia/Choibalsan Dornod, Sukhbaatar -MO +2214+11335 Asia/Macau -MP +1512+14545 Pacific/Saipan -MQ +1436-06105 America/Martinique -MR +1806-01557 Africa/Nouakchott -MS +1643-06213 America/Montserrat -MT +3554+01431 Europe/Malta -MU -2010+05730 Indian/Mauritius -MV +0410+07330 Indian/Maldives -MW -1547+03500 Africa/Blantyre -MX +1924-09909 America/Mexico_City Central Time - most locations -MX +2105-08646 America/Cancun Central Time - Quintana Roo -MX +2058-08937 America/Merida Central Time - Campeche, Yucatan -MX +2540-10019 America/Monterrey Central Time - Coahuila, Durango, Nuevo Leon, Tamaulipas -MX +2313-10625 America/Mazatlan Mountain Time - S Baja, Nayarit, Sinaloa -MX +2838-10605 America/Chihuahua Mountain Time - Chihuahua -MX +2904-11058 America/Hermosillo Mountain Standard Time - Sonora -MX +3232-11701 America/Tijuana Pacific Time -MY +0310+10142 Asia/Kuala_Lumpur peninsular Malaysia -MY +0133+11020 Asia/Kuching Sabah & Sarawak -MZ -2558+03235 Africa/Maputo -NA -2234+01706 Africa/Windhoek -NC -2216+16530 Pacific/Noumea -NE +1331+00207 Africa/Niamey -NF -2903+16758 Pacific/Norfolk -NG +0627+00324 Africa/Lagos -NI +1209-08617 America/Managua -NL +5222+00454 Europe/Amsterdam -NO +5955+01045 Europe/Oslo -NP +2743+08519 Asia/Katmandu -NR -0031+16655 Pacific/Nauru -NU -1901+16955 Pacific/Niue -NZ -3652+17446 Pacific/Auckland most locations -NZ -4357-17633 Pacific/Chatham Chatham Islands -OM +2336+05835 Asia/Muscat -PA +0858-07932 America/Panama -PE -1203-07703 America/Lima -PF -1732-14934 Pacific/Tahiti Society Islands -PF -0900-13930 Pacific/Marquesas Marquesas Islands -PF -2308-13457 Pacific/Gambier Gambier Islands -PG -0930+14710 Pacific/Port_Moresby -PH +1435+12100 Asia/Manila -PK +2452+06703 Asia/Karachi -PL +5215+02100 Europe/Warsaw -PM +4703-05620 America/Miquelon -PN -2504-13005 Pacific/Pitcairn -PR +182806-0660622 America/Puerto_Rico -PS +3130+03428 Asia/Gaza -PT +3843-00908 Europe/Lisbon mainland -PT +3238-01654 Atlantic/Madeira Madeira Islands -PT +3744-02540 Atlantic/Azores Azores -PW +0720+13429 Pacific/Palau -PY -2516-05740 America/Asuncion -QA +2517+05132 Asia/Qatar -RE -2052+05528 Indian/Reunion -RO +4426+02606 Europe/Bucharest -RS +4450+02030 Europe/Belgrade -RU +5443+02030 Europe/Kaliningrad Moscow-01 - Kaliningrad -RU +5545+03735 Europe/Moscow Moscow+00 - west Russia -RU +4844+04425 Europe/Volgograd Moscow+00 - Caspian Sea -RU +5312+05009 Europe/Samara Moscow+01 - Samara, Udmurtia -RU +5651+06036 Asia/Yekaterinburg Moscow+02 - Urals -RU +5500+07324 Asia/Omsk Moscow+03 - west Siberia -RU +5502+08255 Asia/Novosibirsk Moscow+03 - Novosibirsk -RU +5601+09250 Asia/Krasnoyarsk Moscow+04 - Yenisei River -RU +5216+10420 Asia/Irkutsk Moscow+05 - Lake Baikal -RU +6200+12940 Asia/Yakutsk Moscow+06 - Lena River -RU +4310+13156 Asia/Vladivostok Moscow+07 - Amur River -RU +4658+14242 Asia/Sakhalin Moscow+07 - Sakhalin Island -RU +5934+15048 Asia/Magadan Moscow+08 - Magadan -RU +5301+15839 Asia/Kamchatka Moscow+09 - Kamchatka -RU +6445+17729 Asia/Anadyr Moscow+10 - Bering Sea -RW -0157+03004 Africa/Kigali -SA +2438+04643 Asia/Riyadh -SB -0932+16012 Pacific/Guadalcanal -SC -0440+05528 Indian/Mahe -SD +1536+03232 Africa/Khartoum -SE +5920+01803 Europe/Stockholm -SG +0117+10351 Asia/Singapore -SH -1555-00542 Atlantic/St_Helena -SI +4603+01431 Europe/Ljubljana -SJ +7800+01600 Arctic/Longyearbyen -SK +4809+01707 Europe/Bratislava -SL +0830-01315 Africa/Freetown -SM +4355+01228 Europe/San_Marino -SN +1440-01726 Africa/Dakar -SO +0204+04522 Africa/Mogadishu -SR +0550-05510 America/Paramaribo -ST +0020+00644 Africa/Sao_Tome -SV +1342-08912 America/El_Salvador -SY +3330+03618 Asia/Damascus -SZ -2618+03106 Africa/Mbabane -TC +2128-07108 America/Grand_Turk -TD +1207+01503 Africa/Ndjamena -TF -492110+0701303 Indian/Kerguelen -TG +0608+00113 Africa/Lome -TH +1345+10031 Asia/Bangkok -TJ +3835+06848 Asia/Dushanbe -TK -0922-17114 Pacific/Fakaofo -TL -0833+12535 Asia/Dili -TM +3757+05823 Asia/Ashgabat -TN +3648+01011 Africa/Tunis -TO -2110+17510 Pacific/Tongatapu -TR +4101+02858 Europe/Istanbul -TT +1039-06131 America/Port_of_Spain -TV -0831+17913 Pacific/Funafuti -TW +2503+12130 Asia/Taipei -TZ -0648+03917 Africa/Dar_es_Salaam -UA +5026+03031 Europe/Kiev most locations -UA +4837+02218 Europe/Uzhgorod Ruthenia -UA +4750+03510 Europe/Zaporozhye Zaporozh'ye, E Lugansk / Zaporizhia, E Luhansk -UA +4457+03406 Europe/Simferopol central Crimea -UG +0019+03225 Africa/Kampala -UM +1645-16931 Pacific/Johnston Johnston Atoll -UM +2813-17722 Pacific/Midway Midway Islands -UM +1917+16637 Pacific/Wake Wake Island -US +404251-0740023 America/New_York Eastern Time -US +421953-0830245 America/Detroit Eastern Time - Michigan - most locations -US +381515-0854534 America/Kentucky/Louisville Eastern Time - Kentucky - Louisville area -US +364947-0845057 America/Kentucky/Monticello Eastern Time - Kentucky - Wayne County -US +394606-0860929 America/Indiana/Indianapolis Eastern Time - Indiana - most locations -US +384038-0873143 America/Indiana/Vincennes Eastern Time - Indiana - Daviess, Dubois, Knox & Martin Counties -US +411745-0863730 America/Indiana/Knox Eastern Time - Indiana - Starke County -US +410305-0863611 America/Indiana/Winamac Eastern Time - Indiana - Pulaski County -US +382232-0862041 America/Indiana/Marengo Eastern Time - Indiana - Crawford County -US +384452-0850402 America/Indiana/Vevay Eastern Time - Indiana - Switzerland County -US +415100-0873900 America/Chicago Central Time -US +375711-0864541 America/Indiana/Tell_City Central Time - Indiana - Perry County -US +382931-0871643 America/Indiana/Petersburg Central Time - Indiana - Pike County -US +450628-0873651 America/Menominee Central Time - Michigan - Dickinson, Gogebic, Iron & Menominee Counties -US +470659-1011757 America/North_Dakota/Center Central Time - North Dakota - Oliver County -US +465042-1012439 America/North_Dakota/New_Salem Central Time - North Dakota - Morton County (except Mandan area) -US +394421-1045903 America/Denver Mountain Time -US +433649-1161209 America/Boise Mountain Time - south Idaho & east Oregon -US +364708-1084111 America/Shiprock Mountain Time - Navajo -US +332654-1120424 America/Phoenix Mountain Standard Time - Arizona -US +340308-1181434 America/Los_Angeles Pacific Time -US +611305-1495401 America/Anchorage Alaska Time -US +581807-1342511 America/Juneau Alaska Time - Alaska panhandle -US +593249-1394338 America/Yakutat Alaska Time - Alaska panhandle neck -US +643004-1652423 America/Nome Alaska Time - west Alaska -US +515248-1763929 America/Adak Aleutian Islands -US +211825-1575130 Pacific/Honolulu Hawaii -UY -3453-05611 America/Montevideo -UZ +3940+06648 Asia/Samarkand west Uzbekistan -UZ +4120+06918 Asia/Tashkent east Uzbekistan -VA +4154+01227 Europe/Vatican -VC +1309-06114 America/St_Vincent -VE +1030-06656 America/Caracas -VG +1827-06437 America/Tortola -VI +1821-06456 America/St_Thomas -VN +1045+10640 Asia/Saigon -VU -1740+16825 Pacific/Efate -WF -1318-17610 Pacific/Wallis -WS -1350-17144 Pacific/Apia -YE +1245+04512 Asia/Aden -YT -1247+04514 Indian/Mayotte -ZA -2615+02800 Africa/Johannesburg -ZM -1525+02817 Africa/Lusaka -ZW -1750+03103 Africa/Harare diff --git a/tools/buildbot/pylibs/simplejson/README.google b/tools/buildbot/pylibs/simplejson/README.google deleted file mode 100644 index 7f726ce..0000000 --- a/tools/buildbot/pylibs/simplejson/README.google +++ /dev/null @@ -1,11 +0,0 @@ -URL: http://undefined.org/python/#simplejson -Version: 1.7.3 -License: MIT -License File: LICENSE.txt - -Description: -simplejson is a JSON encoder and decoder for Python. - - -Local Modifications: -Removed unit tests from current distribution. diff --git a/tools/buildbot/pylibs/simplejson/__init__.py b/tools/buildbot/pylibs/simplejson/__init__.py deleted file mode 100644 index 38d6229..0000000 --- a/tools/buildbot/pylibs/simplejson/__init__.py +++ /dev/null @@ -1,287 +0,0 @@ -r""" -A simple, fast, extensible JSON encoder and decoder - -JSON (JavaScript Object Notation) is a subset of -JavaScript syntax (ECMA-262 3rd edition) used as a lightweight data -interchange format. - -simplejson exposes an API familiar to uses of the standard library -marshal and pickle modules. - -Encoding basic Python object hierarchies:: - - >>> import simplejson - >>> simplejson.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}]) - '["foo", {"bar": ["baz", null, 1.0, 2]}]' - >>> print simplejson.dumps("\"foo\bar") - "\"foo\bar" - >>> print simplejson.dumps(u'\u1234') - "\u1234" - >>> print simplejson.dumps('\\') - "\\" - >>> print simplejson.dumps({"c": 0, "b": 0, "a": 0}, sort_keys=True) - {"a": 0, "b": 0, "c": 0} - >>> from StringIO import StringIO - >>> io = StringIO() - >>> simplejson.dump(['streaming API'], io) - >>> io.getvalue() - '["streaming API"]' - -Compact encoding:: - - >>> import simplejson - >>> simplejson.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',',':')) - '[1,2,3,{"4":5,"6":7}]' - -Pretty printing:: - - >>> import simplejson - >>> print simplejson.dumps({'4': 5, '6': 7}, sort_keys=True, indent=4) - { - "4": 5, - "6": 7 - } - -Decoding JSON:: - - >>> import simplejson - >>> simplejson.loads('["foo", {"bar":["baz", null, 1.0, 2]}]') - [u'foo', {u'bar': [u'baz', None, 1.0, 2]}] - >>> simplejson.loads('"\\"foo\\bar"') - u'"foo\x08ar' - >>> from StringIO import StringIO - >>> io = StringIO('["streaming API"]') - >>> simplejson.load(io) - [u'streaming API'] - -Specializing JSON object decoding:: - - >>> import simplejson - >>> def as_complex(dct): - ... if '__complex__' in dct: - ... return complex(dct['real'], dct['imag']) - ... return dct - ... - >>> simplejson.loads('{"__complex__": true, "real": 1, "imag": 2}', - ... object_hook=as_complex) - (1+2j) - -Extending JSONEncoder:: - - >>> import simplejson - >>> class ComplexEncoder(simplejson.JSONEncoder): - ... def default(self, obj): - ... if isinstance(obj, complex): - ... return [obj.real, obj.imag] - ... return simplejson.JSONEncoder.default(self, obj) - ... - >>> dumps(2 + 1j, cls=ComplexEncoder) - '[2.0, 1.0]' - >>> ComplexEncoder().encode(2 + 1j) - '[2.0, 1.0]' - >>> list(ComplexEncoder().iterencode(2 + 1j)) - ['[', '2.0', ', ', '1.0', ']'] - - -Note that the JSON produced by this module's default settings -is a subset of YAML, so it may be used as a serializer for that as well. -""" -__version__ = '1.7.3' -__all__ = [ - 'dump', 'dumps', 'load', 'loads', - 'JSONDecoder', 'JSONEncoder', -] - -from decoder import JSONDecoder -from encoder import JSONEncoder - -_default_encoder = JSONEncoder( - skipkeys=False, - ensure_ascii=True, - check_circular=True, - allow_nan=True, - indent=None, - separators=None, - encoding='utf-8' -) - -def dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True, - allow_nan=True, cls=None, indent=None, separators=None, - encoding='utf-8', **kw): - """ - Serialize ``obj`` as a JSON formatted stream to ``fp`` (a - ``.write()``-supporting file-like object). - - If ``skipkeys`` is ``True`` then ``dict`` keys that are not basic types - (``str``, ``unicode``, ``int``, ``long``, ``float``, ``bool``, ``None``) - will be skipped instead of raising a ``TypeError``. - - If ``ensure_ascii`` is ``False``, then the some chunks written to ``fp`` - may be ``unicode`` instances, subject to normal Python ``str`` to - ``unicode`` coercion rules. Unless ``fp.write()`` explicitly - understands ``unicode`` (as in ``codecs.getwriter()``) this is likely - to cause an error. - - If ``check_circular`` is ``False``, then the circular reference check - for container types will be skipped and a circular reference will - result in an ``OverflowError`` (or worse). - - If ``allow_nan`` is ``False``, then it will be a ``ValueError`` to - serialize out of range ``float`` values (``nan``, ``inf``, ``-inf``) - in strict compliance of the JSON specification, instead of using the - JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``). - - If ``indent`` is a non-negative integer, then JSON array elements and object - members will be pretty-printed with that indent level. An indent level - of 0 will only insert newlines. ``None`` is the most compact representation. - - If ``separators`` is an ``(item_separator, dict_separator)`` tuple - then it will be used instead of the default ``(', ', ': ')`` separators. - ``(',', ':')`` is the most compact JSON representation. - - ``encoding`` is the character encoding for str instances, default is UTF-8. - - To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the - ``.default()`` method to serialize additional types), specify it with - the ``cls`` kwarg. - """ - # cached encoder - if (skipkeys is False and ensure_ascii is True and - check_circular is True and allow_nan is True and - cls is None and indent is None and separators is None and - encoding == 'utf-8' and not kw): - iterable = _default_encoder.iterencode(obj) - else: - if cls is None: - cls = JSONEncoder - iterable = cls(skipkeys=skipkeys, ensure_ascii=ensure_ascii, - check_circular=check_circular, allow_nan=allow_nan, indent=indent, - separators=separators, encoding=encoding, **kw).iterencode(obj) - # could accelerate with writelines in some versions of Python, at - # a debuggability cost - for chunk in iterable: - fp.write(chunk) - - -def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True, - allow_nan=True, cls=None, indent=None, separators=None, - encoding='utf-8', **kw): - """ - Serialize ``obj`` to a JSON formatted ``str``. - - If ``skipkeys`` is ``True`` then ``dict`` keys that are not basic types - (``str``, ``unicode``, ``int``, ``long``, ``float``, ``bool``, ``None``) - will be skipped instead of raising a ``TypeError``. - - If ``ensure_ascii`` is ``False``, then the return value will be a - ``unicode`` instance subject to normal Python ``str`` to ``unicode`` - coercion rules instead of being escaped to an ASCII ``str``. - - If ``check_circular`` is ``False``, then the circular reference check - for container types will be skipped and a circular reference will - result in an ``OverflowError`` (or worse). - - If ``allow_nan`` is ``False``, then it will be a ``ValueError`` to - serialize out of range ``float`` values (``nan``, ``inf``, ``-inf``) in - strict compliance of the JSON specification, instead of using the - JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``). - - If ``indent`` is a non-negative integer, then JSON array elements and - object members will be pretty-printed with that indent level. An indent - level of 0 will only insert newlines. ``None`` is the most compact - representation. - - If ``separators`` is an ``(item_separator, dict_separator)`` tuple - then it will be used instead of the default ``(', ', ': ')`` separators. - ``(',', ':')`` is the most compact JSON representation. - - ``encoding`` is the character encoding for str instances, default is UTF-8. - - To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the - ``.default()`` method to serialize additional types), specify it with - the ``cls`` kwarg. - """ - # cached encoder - if (skipkeys is False and ensure_ascii is True and - check_circular is True and allow_nan is True and - cls is None and indent is None and separators is None and - encoding == 'utf-8' and not kw): - return _default_encoder.encode(obj) - if cls is None: - cls = JSONEncoder - return cls( - skipkeys=skipkeys, ensure_ascii=ensure_ascii, - check_circular=check_circular, allow_nan=allow_nan, indent=indent, - separators=separators, encoding=encoding, - **kw).encode(obj) - -_default_decoder = JSONDecoder(encoding=None, object_hook=None) - -def load(fp, encoding=None, cls=None, object_hook=None, **kw): - """ - Deserialize ``fp`` (a ``.read()``-supporting file-like object containing - a JSON document) to a Python object. - - If the contents of ``fp`` is encoded with an ASCII based encoding other - than utf-8 (e.g. latin-1), then an appropriate ``encoding`` name must - be specified. Encodings that are not ASCII based (such as UCS-2) are - not allowed, and should be wrapped with - ``codecs.getreader(fp)(encoding)``, or simply decoded to a ``unicode`` - object and passed to ``loads()`` - - ``object_hook`` is an optional function that will be called with the - result of any object literal decode (a ``dict``). The return value of - ``object_hook`` will be used instead of the ``dict``. This feature - can be used to implement custom decoders (e.g. JSON-RPC class hinting). - - To use a custom ``JSONDecoder`` subclass, specify it with the ``cls`` - kwarg. - """ - return loads(fp.read(), - encoding=encoding, cls=cls, object_hook=object_hook, **kw) - -def loads(s, encoding=None, cls=None, object_hook=None, **kw): - """ - Deserialize ``s`` (a ``str`` or ``unicode`` instance containing a JSON - document) to a Python object. - - If ``s`` is a ``str`` instance and is encoded with an ASCII based encoding - other than utf-8 (e.g. latin-1) then an appropriate ``encoding`` name - must be specified. Encodings that are not ASCII based (such as UCS-2) - are not allowed and should be decoded to ``unicode`` first. - - ``object_hook`` is an optional function that will be called with the - result of any object literal decode (a ``dict``). The return value of - ``object_hook`` will be used instead of the ``dict``. This feature - can be used to implement custom decoders (e.g. JSON-RPC class hinting). - - To use a custom ``JSONDecoder`` subclass, specify it with the ``cls`` - kwarg. - """ - if cls is None and encoding is None and object_hook is None and not kw: - return _default_decoder.decode(s) - if cls is None: - cls = JSONDecoder - if object_hook is not None: - kw['object_hook'] = object_hook - return cls(encoding=encoding, **kw).decode(s) - -def read(s): - """ - json-py API compatibility hook. Use loads(s) instead. - """ - import warnings - warnings.warn("simplejson.loads(s) should be used instead of read(s)", - DeprecationWarning) - return loads(s) - -def write(obj): - """ - json-py API compatibility hook. Use dumps(s) instead. - """ - import warnings - warnings.warn("simplejson.dumps(s) should be used instead of write(s)", - DeprecationWarning) - return dumps(obj) - - diff --git a/tools/buildbot/pylibs/simplejson/_speedups.c b/tools/buildbot/pylibs/simplejson/_speedups.c deleted file mode 100644 index 8f290bb4..0000000 --- a/tools/buildbot/pylibs/simplejson/_speedups.c +++ /dev/null @@ -1,215 +0,0 @@ -#include "Python.h" -#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) -typedef int Py_ssize_t; -#define PY_SSIZE_T_MAX INT_MAX -#define PY_SSIZE_T_MIN INT_MIN -#endif - -static Py_ssize_t -ascii_escape_char(Py_UNICODE c, char *output, Py_ssize_t chars); -static PyObject * -ascii_escape_unicode(PyObject *pystr); -static PyObject * -ascii_escape_str(PyObject *pystr); -static PyObject * -py_encode_basestring_ascii(PyObject* self __attribute__((__unused__)), PyObject *pystr); -void init_speedups(void); - -#define S_CHAR(c) (c >= ' ' && c <= '~' && c != '\\' && c != '/' && c != '"') - -#define MIN_EXPANSION 6 -#ifdef Py_UNICODE_WIDE -#define MAX_EXPANSION (2 * MIN_EXPANSION) -#else -#define MAX_EXPANSION MIN_EXPANSION -#endif - -static Py_ssize_t -ascii_escape_char(Py_UNICODE c, char *output, Py_ssize_t chars) { - Py_UNICODE x; - output[chars++] = '\\'; - switch (c) { - case '/': output[chars++] = (char)c; break; - case '\\': output[chars++] = (char)c; break; - case '"': output[chars++] = (char)c; break; - case '\b': output[chars++] = 'b'; break; - case '\f': output[chars++] = 'f'; break; - case '\n': output[chars++] = 'n'; break; - case '\r': output[chars++] = 'r'; break; - case '\t': output[chars++] = 't'; break; - default: -#ifdef Py_UNICODE_WIDE - if (c >= 0x10000) { - /* UTF-16 surrogate pair */ - Py_UNICODE v = c - 0x10000; - c = 0xd800 | ((v >> 10) & 0x3ff); - output[chars++] = 'u'; - x = (c & 0xf000) >> 12; - output[chars++] = (x < 10) ? '0' + x : 'a' + (x - 10); - x = (c & 0x0f00) >> 8; - output[chars++] = (x < 10) ? '0' + x : 'a' + (x - 10); - x = (c & 0x00f0) >> 4; - output[chars++] = (x < 10) ? '0' + x : 'a' + (x - 10); - x = (c & 0x000f); - output[chars++] = (x < 10) ? '0' + x : 'a' + (x - 10); - c = 0xdc00 | (v & 0x3ff); - output[chars++] = '\\'; - } -#endif - output[chars++] = 'u'; - x = (c & 0xf000) >> 12; - output[chars++] = (x < 10) ? '0' + x : 'a' + (x - 10); - x = (c & 0x0f00) >> 8; - output[chars++] = (x < 10) ? '0' + x : 'a' + (x - 10); - x = (c & 0x00f0) >> 4; - output[chars++] = (x < 10) ? '0' + x : 'a' + (x - 10); - x = (c & 0x000f); - output[chars++] = (x < 10) ? '0' + x : 'a' + (x - 10); - } - return chars; -} - -static PyObject * -ascii_escape_unicode(PyObject *pystr) { - Py_ssize_t i; - Py_ssize_t input_chars; - Py_ssize_t output_size; - Py_ssize_t chars; - PyObject *rval; - char *output; - Py_UNICODE *input_unicode; - - input_chars = PyUnicode_GET_SIZE(pystr); - input_unicode = PyUnicode_AS_UNICODE(pystr); - /* One char input can be up to 6 chars output, estimate 4 of these */ - output_size = 2 + (MIN_EXPANSION * 4) + input_chars; - rval = PyString_FromStringAndSize(NULL, output_size); - if (rval == NULL) { - return NULL; - } - output = PyString_AS_STRING(rval); - chars = 0; - output[chars++] = '"'; - for (i = 0; i < input_chars; i++) { - Py_UNICODE c = input_unicode[i]; - if (S_CHAR(c)) { - output[chars++] = (char)c; - } else { - chars = ascii_escape_char(c, output, chars); - } - if (output_size - chars < (1 + MAX_EXPANSION)) { - /* There's more than four, so let's resize by a lot */ - output_size *= 2; - /* This is an upper bound */ - if (output_size > 2 + (input_chars * MAX_EXPANSION)) { - output_size = 2 + (input_chars * MAX_EXPANSION); - } - if (_PyString_Resize(&rval, output_size) == -1) { - return NULL; - } - output = PyString_AS_STRING(rval); - } - } - output[chars++] = '"'; - if (_PyString_Resize(&rval, chars) == -1) { - return NULL; - } - return rval; -} - -static PyObject * -ascii_escape_str(PyObject *pystr) { - Py_ssize_t i; - Py_ssize_t input_chars; - Py_ssize_t output_size; - Py_ssize_t chars; - PyObject *rval; - char *output; - char *input_str; - - input_chars = PyString_GET_SIZE(pystr); - input_str = PyString_AS_STRING(pystr); - /* One char input can be up to 6 chars output, estimate 4 of these */ - output_size = 2 + (MIN_EXPANSION * 4) + input_chars; - rval = PyString_FromStringAndSize(NULL, output_size); - if (rval == NULL) { - return NULL; - } - output = PyString_AS_STRING(rval); - chars = 0; - output[chars++] = '"'; - for (i = 0; i < input_chars; i++) { - Py_UNICODE c = (Py_UNICODE)input_str[i]; - if (S_CHAR(c)) { - output[chars++] = (char)c; - } else if (c > 0x7F) { - /* We hit a non-ASCII character, bail to unicode mode */ - PyObject *uni; - Py_DECREF(rval); - uni = PyUnicode_DecodeUTF8(input_str, input_chars, "strict"); - if (uni == NULL) { - return NULL; - } - rval = ascii_escape_unicode(uni); - Py_DECREF(uni); - return rval; - } else { - chars = ascii_escape_char(c, output, chars); - } - /* An ASCII char can't possibly expand to a surrogate! */ - if (output_size - chars < (1 + MIN_EXPANSION)) { - /* There's more than four, so let's resize by a lot */ - output_size *= 2; - if (output_size > 2 + (input_chars * MIN_EXPANSION)) { - output_size = 2 + (input_chars * MIN_EXPANSION); - } - if (_PyString_Resize(&rval, output_size) == -1) { - return NULL; - } - output = PyString_AS_STRING(rval); - } - } - output[chars++] = '"'; - if (_PyString_Resize(&rval, chars) == -1) { - return NULL; - } - return rval; -} - -PyDoc_STRVAR(pydoc_encode_basestring_ascii, - "encode_basestring_ascii(basestring) -> str\n" - "\n" - "..." -); - -static PyObject * -py_encode_basestring_ascii(PyObject* self __attribute__((__unused__)), PyObject *pystr) { - /* METH_O */ - if (PyString_Check(pystr)) { - return ascii_escape_str(pystr); - } else if (PyUnicode_Check(pystr)) { - return ascii_escape_unicode(pystr); - } - PyErr_SetString(PyExc_TypeError, "first argument must be a string"); - return NULL; -} - -#define DEFN(n, k) \ - { \ - #n, \ - (PyCFunction)py_ ##n, \ - k, \ - pydoc_ ##n \ - } -static PyMethodDef speedups_methods[] = { - DEFN(encode_basestring_ascii, METH_O), - {} -}; -#undef DEFN - -void -init_speedups(void) -{ - PyObject *m; - m = Py_InitModule4("_speedups", speedups_methods, NULL, NULL, PYTHON_API_VERSION); -} diff --git a/tools/buildbot/pylibs/simplejson/decoder.py b/tools/buildbot/pylibs/simplejson/decoder.py deleted file mode 100644 index a1b53b2..0000000 --- a/tools/buildbot/pylibs/simplejson/decoder.py +++ /dev/null @@ -1,273 +0,0 @@ -""" -Implementation of JSONDecoder -""" -import re - -from simplejson.scanner import Scanner, pattern - -FLAGS = re.VERBOSE | re.MULTILINE | re.DOTALL - -def _floatconstants(): - import struct - import sys - _BYTES = '7FF80000000000007FF0000000000000'.decode('hex') - if sys.byteorder != 'big': - _BYTES = _BYTES[:8][::-1] + _BYTES[8:][::-1] - nan, inf = struct.unpack('dd', _BYTES) - return nan, inf, -inf - -NaN, PosInf, NegInf = _floatconstants() - -def linecol(doc, pos): - lineno = doc.count('\n', 0, pos) + 1 - if lineno == 1: - colno = pos - else: - colno = pos - doc.rindex('\n', 0, pos) - return lineno, colno - -def errmsg(msg, doc, pos, end=None): - lineno, colno = linecol(doc, pos) - if end is None: - return '%s: line %d column %d (char %d)' % (msg, lineno, colno, pos) - endlineno, endcolno = linecol(doc, end) - return '%s: line %d column %d - line %d column %d (char %d - %d)' % ( - msg, lineno, colno, endlineno, endcolno, pos, end) - -_CONSTANTS = { - '-Infinity': NegInf, - 'Infinity': PosInf, - 'NaN': NaN, - 'true': True, - 'false': False, - 'null': None, -} - -def JSONConstant(match, context, c=_CONSTANTS): - return c[match.group(0)], None -pattern('(-?Infinity|NaN|true|false|null)')(JSONConstant) - -def JSONNumber(match, context): - match = JSONNumber.regex.match(match.string, *match.span()) - integer, frac, exp = match.groups() - if frac or exp: - res = float(integer + (frac or '') + (exp or '')) - else: - res = int(integer) - return res, None -pattern(r'(-?(?:0|[1-9]\d*))(\.\d+)?([eE][-+]?\d+)?')(JSONNumber) - -STRINGCHUNK = re.compile(r'(.*?)(["\\])', FLAGS) -BACKSLASH = { - '"': u'"', '\\': u'\\', '/': u'/', - 'b': u'\b', 'f': u'\f', 'n': u'\n', 'r': u'\r', 't': u'\t', -} - -DEFAULT_ENCODING = "utf-8" - -def scanstring(s, end, encoding=None, _b=BACKSLASH, _m=STRINGCHUNK.match): - if encoding is None: - encoding = DEFAULT_ENCODING - chunks = [] - _append = chunks.append - begin = end - 1 - while 1: - chunk = _m(s, end) - if chunk is None: - raise ValueError( - errmsg("Unterminated string starting at", s, begin)) - end = chunk.end() - content, terminator = chunk.groups() - if content: - if not isinstance(content, unicode): - content = unicode(content, encoding) - _append(content) - if terminator == '"': - break - try: - esc = s[end] - except IndexError: - raise ValueError( - errmsg("Unterminated string starting at", s, begin)) - if esc != 'u': - try: - m = _b[esc] - except KeyError: - raise ValueError( - errmsg("Invalid \\escape: %r" % (esc,), s, end)) - end += 1 - else: - esc = s[end + 1:end + 5] - try: - m = unichr(int(esc, 16)) - if len(esc) != 4 or not esc.isalnum(): - raise ValueError - except ValueError: - raise ValueError(errmsg("Invalid \\uXXXX escape", s, end)) - end += 5 - _append(m) - return u''.join(chunks), end - -def JSONString(match, context): - encoding = getattr(context, 'encoding', None) - return scanstring(match.string, match.end(), encoding) -pattern(r'"')(JSONString) - -WHITESPACE = re.compile(r'\s*', FLAGS) - -def JSONObject(match, context, _w=WHITESPACE.match): - pairs = {} - s = match.string - end = _w(s, match.end()).end() - nextchar = s[end:end + 1] - # trivial empty object - if nextchar == '}': - return pairs, end + 1 - if nextchar != '"': - raise ValueError(errmsg("Expecting property name", s, end)) - end += 1 - encoding = getattr(context, 'encoding', None) - iterscan = JSONScanner.iterscan - while True: - key, end = scanstring(s, end, encoding) - end = _w(s, end).end() - if s[end:end + 1] != ':': - raise ValueError(errmsg("Expecting : delimiter", s, end)) - end = _w(s, end + 1).end() - try: - value, end = iterscan(s, idx=end, context=context).next() - except StopIteration: - raise ValueError(errmsg("Expecting object", s, end)) - pairs[key] = value - end = _w(s, end).end() - nextchar = s[end:end + 1] - end += 1 - if nextchar == '}': - break - if nextchar != ',': - raise ValueError(errmsg("Expecting , delimiter", s, end - 1)) - end = _w(s, end).end() - nextchar = s[end:end + 1] - end += 1 - if nextchar != '"': - raise ValueError(errmsg("Expecting property name", s, end - 1)) - object_hook = getattr(context, 'object_hook', None) - if object_hook is not None: - pairs = object_hook(pairs) - return pairs, end -pattern(r'{')(JSONObject) - -def JSONArray(match, context, _w=WHITESPACE.match): - values = [] - s = match.string - end = _w(s, match.end()).end() - # look-ahead for trivial empty array - nextchar = s[end:end + 1] - if nextchar == ']': - return values, end + 1 - iterscan = JSONScanner.iterscan - while True: - try: - value, end = iterscan(s, idx=end, context=context).next() - except StopIteration: - raise ValueError(errmsg("Expecting object", s, end)) - values.append(value) - end = _w(s, end).end() - nextchar = s[end:end + 1] - end += 1 - if nextchar == ']': - break - if nextchar != ',': - raise ValueError(errmsg("Expecting , delimiter", s, end)) - end = _w(s, end).end() - return values, end -pattern(r'\[')(JSONArray) - -ANYTHING = [ - JSONObject, - JSONArray, - JSONString, - JSONConstant, - JSONNumber, -] - -JSONScanner = Scanner(ANYTHING) - -class JSONDecoder(object): - """ - Simple JSON decoder - - Performs the following translations in decoding: - - +---------------+-------------------+ - | JSON | Python | - +===============+===================+ - | object | dict | - +---------------+-------------------+ - | array | list | - +---------------+-------------------+ - | string | unicode | - +---------------+-------------------+ - | number (int) | int, long | - +---------------+-------------------+ - | number (real) | float | - +---------------+-------------------+ - | true | True | - +---------------+-------------------+ - | false | False | - +---------------+-------------------+ - | null | None | - +---------------+-------------------+ - - It also understands ``NaN``, ``Infinity``, and ``-Infinity`` as - their corresponding ``float`` values, which is outside the JSON spec. - """ - - _scanner = Scanner(ANYTHING) - __all__ = ['__init__', 'decode', 'raw_decode'] - - def __init__(self, encoding=None, object_hook=None): - """ - ``encoding`` determines the encoding used to interpret any ``str`` - objects decoded by this instance (utf-8 by default). It has no - effect when decoding ``unicode`` objects. - - Note that currently only encodings that are a superset of ASCII work, - strings of other encodings should be passed in as ``unicode``. - - ``object_hook``, if specified, will be called with the result - of every JSON object decoded and its return value will be used in - place of the given ``dict``. This can be used to provide custom - deserializations (e.g. to support JSON-RPC class hinting). - """ - self.encoding = encoding - self.object_hook = object_hook - - def decode(self, s, _w=WHITESPACE.match): - """ - Return the Python representation of ``s`` (a ``str`` or ``unicode`` - instance containing a JSON document) - """ - obj, end = self.raw_decode(s, idx=_w(s, 0).end()) - end = _w(s, end).end() - if end != len(s): - raise ValueError(errmsg("Extra data", s, end, len(s))) - return obj - - def raw_decode(self, s, **kw): - """ - Decode a JSON document from ``s`` (a ``str`` or ``unicode`` beginning - with a JSON document) and return a 2-tuple of the Python - representation and the index in ``s`` where the document ended. - - This can be used to decode a JSON document from a string that may - have extraneous data at the end. - """ - kw.setdefault('context', self) - try: - obj, end = self._scanner.iterscan(s, **kw).next() - except StopIteration: - raise ValueError("No JSON object could be decoded") - return obj, end - -__all__ = ['JSONDecoder'] diff --git a/tools/buildbot/pylibs/simplejson/encoder.py b/tools/buildbot/pylibs/simplejson/encoder.py deleted file mode 100644 index d29919a..0000000 --- a/tools/buildbot/pylibs/simplejson/encoder.py +++ /dev/null @@ -1,371 +0,0 @@ -""" -Implementation of JSONEncoder -""" -import re -try: - from simplejson import _speedups -except ImportError: - _speedups = None - -ESCAPE = re.compile(r'[\x00-\x19\\"\b\f\n\r\t]') -ESCAPE_ASCII = re.compile(r'([\\"/]|[^\ -~])') -ESCAPE_DCT = { - # escape all forward slashes to prevent attack - '/': '\\/', - '\\': '\\\\', - '"': '\\"', - '\b': '\\b', - '\f': '\\f', - '\n': '\\n', - '\r': '\\r', - '\t': '\\t', -} -for i in range(0x20): - ESCAPE_DCT.setdefault(chr(i), '\\u%04x' % (i,)) - -# assume this produces an infinity on all machines (probably not guaranteed) -INFINITY = float('1e66666') - -def floatstr(o, allow_nan=True): - # Check for specials. Note that this type of test is processor- and/or - # platform-specific, so do tests which don't depend on the internals. - - if o != o: - text = 'NaN' - elif o == INFINITY: - text = 'Infinity' - elif o == -INFINITY: - text = '-Infinity' - else: - return repr(o) - - if not allow_nan: - raise ValueError("Out of range float values are not JSON compliant: %r" - % (o,)) - - return text - - -def encode_basestring(s): - """ - Return a JSON representation of a Python string - """ - def replace(match): - return ESCAPE_DCT[match.group(0)] - return '"' + ESCAPE.sub(replace, s) + '"' - -def encode_basestring_ascii(s): - def replace(match): - s = match.group(0) - try: - return ESCAPE_DCT[s] - except KeyError: - n = ord(s) - if n < 0x10000: - return '\\u%04x' % (n,) - else: - # surrogate pair - n -= 0x10000 - s1 = 0xd800 | ((n >> 10) & 0x3ff) - s2 = 0xdc00 | (n & 0x3ff) - return '\\u%04x\\u%04x' % (s1, s2) - return '"' + str(ESCAPE_ASCII.sub(replace, s)) + '"' - -try: - encode_basestring_ascii = _speedups.encode_basestring_ascii - _need_utf8 = True -except AttributeError: - _need_utf8 = False - -class JSONEncoder(object): - """ - Extensible JSON encoder for Python data structures. - - Supports the following objects and types by default: - - +-------------------+---------------+ - | Python | JSON | - +===================+===============+ - | dict | object | - +-------------------+---------------+ - | list, tuple | array | - +-------------------+---------------+ - | str, unicode | string | - +-------------------+---------------+ - | int, long, float | number | - +-------------------+---------------+ - | True | true | - +-------------------+---------------+ - | False | false | - +-------------------+---------------+ - | None | null | - +-------------------+---------------+ - - To extend this to recognize other objects, subclass and implement a - ``.default()`` method with another method that returns a serializable - object for ``o`` if possible, otherwise it should call the superclass - implementation (to raise ``TypeError``). - """ - __all__ = ['__init__', 'default', 'encode', 'iterencode'] - item_separator = ', ' - key_separator = ': ' - def __init__(self, skipkeys=False, ensure_ascii=True, - check_circular=True, allow_nan=True, sort_keys=False, - indent=None, separators=None, encoding='utf-8'): - """ - Constructor for JSONEncoder, with sensible defaults. - - If skipkeys is False, then it is a TypeError to attempt - encoding of keys that are not str, int, long, float or None. If - skipkeys is True, such items are simply skipped. - - If ensure_ascii is True, the output is guaranteed to be str - objects with all incoming unicode characters escaped. If - ensure_ascii is false, the output will be unicode object. - - If check_circular is True, then lists, dicts, and custom encoded - objects will be checked for circular references during encoding to - prevent an infinite recursion (which would cause an OverflowError). - Otherwise, no such check takes place. - - If allow_nan is True, then NaN, Infinity, and -Infinity will be - encoded as such. This behavior is not JSON specification compliant, - but is consistent with most JavaScript based encoders and decoders. - Otherwise, it will be a ValueError to encode such floats. - - If sort_keys is True, then the output of dictionaries will be - sorted by key; this is useful for regression tests to ensure - that JSON serializations can be compared on a day-to-day basis. - - If indent is a non-negative integer, then JSON array - elements and object members will be pretty-printed with that - indent level. An indent level of 0 will only insert newlines. - None is the most compact representation. - - If specified, separators should be a (item_separator, key_separator) - tuple. The default is (', ', ': '). To get the most compact JSON - representation you should specify (',', ':') to eliminate whitespace. - - If encoding is not None, then all input strings will be - transformed into unicode using that encoding prior to JSON-encoding. - The default is UTF-8. - """ - - self.skipkeys = skipkeys - self.ensure_ascii = ensure_ascii - self.check_circular = check_circular - self.allow_nan = allow_nan - self.sort_keys = sort_keys - self.indent = indent - self.current_indent_level = 0 - if separators is not None: - self.item_separator, self.key_separator = separators - self.encoding = encoding - - def _newline_indent(self): - return '\n' + (' ' * (self.indent * self.current_indent_level)) - - def _iterencode_list(self, lst, markers=None): - if not lst: - yield '[]' - return - if markers is not None: - markerid = id(lst) - if markerid in markers: - raise ValueError("Circular reference detected") - markers[markerid] = lst - yield '[' - if self.indent is not None: - self.current_indent_level += 1 - newline_indent = self._newline_indent() - separator = self.item_separator + newline_indent - yield newline_indent - else: - newline_indent = None - separator = self.item_separator - first = True - for value in lst: - if first: - first = False - else: - yield separator - for chunk in self._iterencode(value, markers): - yield chunk - if newline_indent is not None: - self.current_indent_level -= 1 - yield self._newline_indent() - yield ']' - if markers is not None: - del markers[markerid] - - def _iterencode_dict(self, dct, markers=None): - if not dct: - yield '{}' - return - if markers is not None: - markerid = id(dct) - if markerid in markers: - raise ValueError("Circular reference detected") - markers[markerid] = dct - yield '{' - key_separator = self.key_separator - if self.indent is not None: - self.current_indent_level += 1 - newline_indent = self._newline_indent() - item_separator = self.item_separator + newline_indent - yield newline_indent - else: - newline_indent = None - item_separator = self.item_separator - first = True - if self.ensure_ascii: - encoder = encode_basestring_ascii - else: - encoder = encode_basestring - allow_nan = self.allow_nan - if self.sort_keys: - keys = dct.keys() - keys.sort() - items = [(k, dct[k]) for k in keys] - else: - items = dct.iteritems() - _encoding = self.encoding - _do_decode = (_encoding is not None - and not (_need_utf8 and _encoding == 'utf-8')) - for key, value in items: - if isinstance(key, str): - if _do_decode: - key = key.decode(_encoding) - elif isinstance(key, basestring): - pass - # JavaScript is weakly typed for these, so it makes sense to - # also allow them. Many encoders seem to do something like this. - elif isinstance(key, float): - key = floatstr(key, allow_nan) - elif isinstance(key, (int, long)): - key = str(key) - elif key is True: - key = 'true' - elif key is False: - key = 'false' - elif key is None: - key = 'null' - elif self.skipkeys: - continue - else: - raise TypeError("key %r is not a string" % (key,)) - if first: - first = False - else: - yield item_separator - yield encoder(key) - yield key_separator - for chunk in self._iterencode(value, markers): - yield chunk - if newline_indent is not None: - self.current_indent_level -= 1 - yield self._newline_indent() - yield '}' - if markers is not None: - del markers[markerid] - - def _iterencode(self, o, markers=None): - if isinstance(o, basestring): - if self.ensure_ascii: - encoder = encode_basestring_ascii - else: - encoder = encode_basestring - _encoding = self.encoding - if (_encoding is not None and isinstance(o, str) - and not (_need_utf8 and _encoding == 'utf-8')): - o = o.decode(_encoding) - yield encoder(o) - elif o is None: - yield 'null' - elif o is True: - yield 'true' - elif o is False: - yield 'false' - elif isinstance(o, (int, long)): - yield str(o) - elif isinstance(o, float): - yield floatstr(o, self.allow_nan) - elif isinstance(o, (list, tuple)): - for chunk in self._iterencode_list(o, markers): - yield chunk - elif isinstance(o, dict): - for chunk in self._iterencode_dict(o, markers): - yield chunk - else: - if markers is not None: - markerid = id(o) - if markerid in markers: - raise ValueError("Circular reference detected") - markers[markerid] = o - for chunk in self._iterencode_default(o, markers): - yield chunk - if markers is not None: - del markers[markerid] - - def _iterencode_default(self, o, markers=None): - newobj = self.default(o) - return self._iterencode(newobj, markers) - - def default(self, o): - """ - Implement this method in a subclass such that it returns - a serializable object for ``o``, or calls the base implementation - (to raise a ``TypeError``). - - For example, to support arbitrary iterators, you could - implement default like this:: - - def default(self, o): - try: - iterable = iter(o) - except TypeError: - pass - else: - return list(iterable) - return JSONEncoder.default(self, o) - """ - raise TypeError("%r is not JSON serializable" % (o,)) - - def encode(self, o): - """ - Return a JSON string representation of a Python data structure. - - >>> JSONEncoder().encode({"foo": ["bar", "baz"]}) - '{"foo":["bar", "baz"]}' - """ - # This is for extremely simple cases and benchmarks... - if isinstance(o, basestring): - if isinstance(o, str): - _encoding = self.encoding - if (_encoding is not None - and not (_encoding == 'utf-8' and _need_utf8)): - o = o.decode(_encoding) - return encode_basestring_ascii(o) - # This doesn't pass the iterator directly to ''.join() because it - # sucks at reporting exceptions. It's going to do this internally - # anyway because it uses PySequence_Fast or similar. - chunks = list(self.iterencode(o)) - return ''.join(chunks) - - def iterencode(self, o): - """ - Encode the given object and yield each string - representation as available. - - For example:: - - for chunk in JSONEncoder().iterencode(bigobject): - mysocket.write(chunk) - """ - if self.check_circular: - markers = {} - else: - markers = None - return self._iterencode(o, markers) - -__all__ = ['JSONEncoder'] diff --git a/tools/buildbot/pylibs/simplejson/jsonfilter.py b/tools/buildbot/pylibs/simplejson/jsonfilter.py deleted file mode 100644 index 01ca21d..0000000 --- a/tools/buildbot/pylibs/simplejson/jsonfilter.py +++ /dev/null @@ -1,40 +0,0 @@ -import simplejson -import cgi - -class JSONFilter(object): - def __init__(self, app, mime_type='text/x-json'): - self.app = app - self.mime_type = mime_type - - def __call__(self, environ, start_response): - # Read JSON POST input to jsonfilter.json if matching mime type - response = {'status': '200 OK', 'headers': []} - def json_start_response(status, headers): - response['status'] = status - response['headers'].extend(headers) - environ['jsonfilter.mime_type'] = self.mime_type - if environ.get('REQUEST_METHOD', '') == 'POST': - if environ.get('CONTENT_TYPE', '') == self.mime_type: - args = [_ for _ in [environ.get('CONTENT_LENGTH')] if _] - data = environ['wsgi.input'].read(*map(int, args)) - environ['jsonfilter.json'] = simplejson.loads(data) - res = simplejson.dumps(self.app(environ, json_start_response)) - jsonp = cgi.parse_qs(environ.get('QUERY_STRING', '')).get('jsonp') - if jsonp: - content_type = 'text/javascript' - res = ''.join(jsonp + ['(', res, ')']) - elif 'Opera' in environ.get('HTTP_USER_AGENT', ''): - # Opera has bunk XMLHttpRequest support for most mime types - content_type = 'text/plain' - else: - content_type = self.mime_type - headers = [ - ('Content-type', content_type), - ('Content-length', len(res)), - ] - headers.extend(response['headers']) - start_response(response['status'], headers) - return [res] - -def factory(app, global_conf, **kw): - return JSONFilter(app, **kw) diff --git a/tools/buildbot/pylibs/simplejson/scanner.py b/tools/buildbot/pylibs/simplejson/scanner.py deleted file mode 100644 index 64f4999..0000000 --- a/tools/buildbot/pylibs/simplejson/scanner.py +++ /dev/null @@ -1,63 +0,0 @@ -""" -Iterator based sre token scanner -""" -import sre_parse, sre_compile, sre_constants -from sre_constants import BRANCH, SUBPATTERN -from re import VERBOSE, MULTILINE, DOTALL -import re - -__all__ = ['Scanner', 'pattern'] - -FLAGS = (VERBOSE | MULTILINE | DOTALL) -class Scanner(object): - def __init__(self, lexicon, flags=FLAGS): - self.actions = [None] - # combine phrases into a compound pattern - s = sre_parse.Pattern() - s.flags = flags - p = [] - for idx, token in enumerate(lexicon): - phrase = token.pattern - try: - subpattern = sre_parse.SubPattern(s, - [(SUBPATTERN, (idx + 1, sre_parse.parse(phrase, flags)))]) - except sre_constants.error: - raise - p.append(subpattern) - self.actions.append(token) - - p = sre_parse.SubPattern(s, [(BRANCH, (None, p))]) - self.scanner = sre_compile.compile(p) - - - def iterscan(self, string, idx=0, context=None): - """ - Yield match, end_idx for each match - """ - match = self.scanner.scanner(string, idx).match - actions = self.actions - lastend = idx - end = len(string) - while True: - m = match() - if m is None: - break - matchbegin, matchend = m.span() - if lastend == matchend: - break - action = actions[m.lastindex] - if action is not None: - rval, next_pos = action(m, context) - if next_pos is not None and next_pos != matchend: - # "fast forward" the scanner - matchend = next_pos - match = self.scanner.scanner(string, matchend).match - yield rval, matchend - lastend = matchend - -def pattern(pattern, flags=FLAGS): - def decorator(fn): - fn.pattern = pattern - fn.regex = re.compile(pattern, flags) - return fn - return decorator diff --git a/tools/buildbot/pylibs/twisted/LICENSE b/tools/buildbot/pylibs/twisted/LICENSE deleted file mode 100644 index 14a8acd..0000000 --- a/tools/buildbot/pylibs/twisted/LICENSE +++ /dev/null @@ -1,51 +0,0 @@ -Copyright (c) 2001-2008 -Allen Short -Andrew Bennetts -Apple Computer, Inc. -Benjamin Bruheim -Bob Ippolito -Canonical Limited -Christopher Armstrong -David Reid -Donovan Preston -Eric Mangold -Itamar Shtull-Trauring -James Knight -Jason A. Mobarak -Jonathan Lange -Jonathan D. Simms -Jp Calderone -Jürgen Hermann -Kevin Turner -Mary Gardiner -Matthew Lefkowitz -Massachusetts Institute of Technology -Moshe Zadka -Paul Swartz -Pavel Pergamenshchik -Ralph Meijer -Sean Riley -Travis B. Hartwell -Thomas Herve -Eyal Lotem -Antoine Pitrou -Andy Gayton - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/tools/buildbot/pylibs/twisted/README.google b/tools/buildbot/pylibs/twisted/README.google deleted file mode 100644 index 60919f0..0000000 --- a/tools/buildbot/pylibs/twisted/README.google +++ /dev/null @@ -1,11 +0,0 @@ -URL: http://twistedmatrix.com/trac/ -Version: 8.1.0 -License file: LICENSE - - -Local modifications: - -internet/_dumbwin32proc.py: - Edited _init__() to save the created process's PID. Edited kill() to run - taskkill on that PID rather than calling TerminateProcess(), so that steps' - children are also killed. Original version saved as _dumbwin32proc_orig.py. diff --git a/tools/buildbot/pylibs/twisted/__init__.py b/tools/buildbot/pylibs/twisted/__init__.py deleted file mode 100644 index 9fa050d..0000000 --- a/tools/buildbot/pylibs/twisted/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -# -*- test-case-name: twisted -*- - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Twisted: The Framework Of Your Internet. -""" - -# Ensure the user is running the version of python we require. -import sys -if not hasattr(sys, "version_info") or sys.version_info < (2,3): - raise RuntimeError("Twisted requires Python 2.3 or later.") -del sys - -# Ensure compat gets imported -from twisted.python import compat -del compat - -# setup version -from twisted._version import version -__version__ = version.short() - diff --git a/tools/buildbot/pylibs/twisted/_version.py b/tools/buildbot/pylibs/twisted/_version.py deleted file mode 100644 index 76586ee..0000000 --- a/tools/buildbot/pylibs/twisted/_version.py +++ /dev/null @@ -1,3 +0,0 @@ -# This is an auto-generated file. Do not edit it. -from twisted.python import versions -version = versions.Version('twisted', 8, 1, 0) diff --git a/tools/buildbot/pylibs/twisted/application/__init__.py b/tools/buildbot/pylibs/twisted/application/__init__.py deleted file mode 100644 index 6169281..0000000 --- a/tools/buildbot/pylibs/twisted/application/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -""" -Configuration objects for Twisted Applications -""" diff --git a/tools/buildbot/pylibs/twisted/application/app.py b/tools/buildbot/pylibs/twisted/application/app.py deleted file mode 100644 index 3bc841d..0000000 --- a/tools/buildbot/pylibs/twisted/application/app.py +++ /dev/null @@ -1,653 +0,0 @@ -# -*- test-case-name: twisted.test.test_application,twisted.test.test_twistd -*- -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -import sys, os, pdb, getpass, traceback, signal, warnings - -from twisted.python import runtime, log, usage, failure, util, logfile -from twisted.persisted import sob -from twisted.application import service, reactors -from twisted.internet import defer -from twisted import copyright - -# Expose the new implementation of installReactor at the old location. -from twisted.application.reactors import installReactor -from twisted.application.reactors import NoSuchReactor - - - -class _BasicProfiler(object): - """ - @ivar saveStats: if C{True}, save the stats information instead of the - human readable format - @type saveStats: C{bool} - - @ivar profileOutput: the name of the file use to print profile data. - @type profileOutput: C{str} - """ - - def __init__(self, profileOutput, saveStats): - self.profileOutput = profileOutput - self.saveStats = saveStats - - - def _reportImportError(self, module, e): - """ - Helper method to report an import error with a profile module. This - has to be explicit because some of these modules are removed by - distributions due to them being non-free. - """ - s = "Failed to import module %s: %s" % (module, e) - s += """ -This is most likely caused by your operating system not including -the module due to it being non-free. Either do not use the option ---profile, or install the module; your operating system vendor -may provide it in a separate package. -""" - raise SystemExit(s) - - - -class ProfileRunner(_BasicProfiler): - """ - Runner for the standard profile module. - """ - - def run(self, reactor): - """ - Run reactor under the standard profiler. - """ - try: - import profile - except ImportError, e: - self._reportImportError("profile", e) - - p = profile.Profile() - p.runcall(reactor.run) - if self.saveStats: - p.dump_stats(self.profileOutput) - else: - tmp, sys.stdout = sys.stdout, open(self.profileOutput, 'a') - try: - p.print_stats() - finally: - sys.stdout, tmp = tmp, sys.stdout - tmp.close() - - - -class HotshotRunner(_BasicProfiler): - """ - Runner for the hotshot profile module. - """ - - def run(self, reactor): - """ - Run reactor under the hotshot profiler. - """ - try: - import hotshot.stats - except (ImportError, SystemExit), e: - # Certain versions of Debian (and Debian derivatives) raise - # SystemExit when importing hotshot if the "non-free" profiler - # module is not installed. Someone eventually recognized this - # as a bug and changed the Debian packaged Python to raise - # ImportError instead. Handle both exception types here in - # order to support the versions of Debian which have this - # behavior. The bug report which prompted the introduction of - # this highly undesirable behavior should be available online at - # . - # There seems to be no corresponding bug report which resulted - # in the behavior being removed. -exarkun - self._reportImportError("hotshot", e) - - # this writes stats straight out - p = hotshot.Profile(self.profileOutput) - p.runcall(reactor.run) - if self.saveStats: - # stats are automatically written to file, nothing to do - return - else: - s = hotshot.stats.load(self.profileOutput) - s.strip_dirs() - s.sort_stats(-1) - if getattr(s, 'stream', None) is not None: - # Python 2.5 and above supports a stream attribute - s.stream = open(self.profileOutput, 'w') - s.print_stats() - s.stream.close() - else: - # But we have to use a trick for Python < 2.5 - tmp, sys.stdout = sys.stdout, open(self.profileOutput, 'w') - try: - s.print_stats() - finally: - sys.stdout, tmp = tmp, sys.stdout - tmp.close() - - - -class CProfileRunner(_BasicProfiler): - """ - Runner for the cProfile module. - """ - - def run(self, reactor): - """ - Run reactor under the cProfile profiler. - """ - try: - import cProfile, pstats - except ImportError, e: - self._reportImportError("cProfile", e) - - p = cProfile.Profile() - p.runcall(reactor.run) - if self.saveStats: - p.dump_stats(self.profileOutput) - else: - stream = open(self.profileOutput, 'w') - s = pstats.Stats(p, stream=stream) - s.strip_dirs() - s.sort_stats(-1) - s.print_stats() - stream.close() - - - -class AppProfiler(object): - """ - Class which selects a specific profile runner based on configuration - options. - - @ivar profiler: the name of the selected profiler. - @type profiler: C{str} - """ - profilers = {"profile": ProfileRunner, "hotshot": HotshotRunner, - "cProfile": CProfileRunner} - - def __init__(self, options): - saveStats = options.get("savestats", False) - profileOutput = options.get("profile", None) - self.profiler = options.get("profiler", None) - if options.get("nothotshot", False): - warnings.warn("The --nothotshot option is deprecated. Please " - "specify the profiler name using the --profiler " - "option", category=DeprecationWarning) - self.profiler = "profile" - if self.profiler in self.profilers: - profiler = self.profilers[self.profiler](profileOutput, saveStats) - self.run = profiler.run - else: - raise SystemExit("Unsupported profiler name: %s" % (self.profiler,)) - - - -def runWithProfiler(reactor, config): - """ - DEPRECATED in Twisted 8.0. - - Run reactor under standard profiler. - """ - warnings.warn("runWithProfiler is deprecated since Twisted 8.0. " - "Use ProfileRunner instead.", DeprecationWarning, 2) - item = AppProfiler(config) - return item.run(reactor) - - - -def runWithHotshot(reactor, config): - """ - DEPRECATED in Twisted 8.0. - - Run reactor under hotshot profiler. - """ - warnings.warn("runWithHotshot is deprecated since Twisted 8.0. " - "Use HotshotRunner instead.", DeprecationWarning, 2) - item = AppProfiler(config) - return item.run(reactor) - - - -def fixPdb(): - def do_stop(self, arg): - self.clear_all_breaks() - self.set_continue() - from twisted.internet import reactor - reactor.callLater(0, reactor.stop) - return 1 - - def help_stop(self): - print """stop - Continue execution, then cleanly shutdown the twisted reactor.""" - - def set_quit(self): - os._exit(0) - - pdb.Pdb.set_quit = set_quit - pdb.Pdb.do_stop = do_stop - pdb.Pdb.help_stop = help_stop - - - -def runReactorWithLogging(config, oldstdout, oldstderr, profiler=None, reactor=None): - """ - Start the reactor, using profiling if specified by the configuration, and - log any error happening in the process. - - @param config: configuration of the twistd application. - @type config: L{ServerOptions} - - @param oldstdout: initial value of C{sys.stdout}. - @type oldstdout: C{file} - - @param oldstderr: initial value of C{sys.stderr}. - @type oldstderr: C{file} - - @param profiler: object used to run the reactor with profiling. - @type profiler: L{AppProfiler} - - @param reactor: The reactor to use. If C{None}, the global reactor will - be used. - """ - if reactor is None: - from twisted.internet import reactor - try: - if config['profile']: - if profiler is not None: - profiler.run(reactor) - else: - # Backward compatible code - if not config['nothotshot']: - runWithHotshot(reactor, config) - else: - runWithProfiler(reactor, config) - elif config['debug']: - sys.stdout = oldstdout - sys.stderr = oldstderr - if runtime.platformType == 'posix': - signal.signal(signal.SIGUSR2, lambda *args: pdb.set_trace()) - signal.signal(signal.SIGINT, lambda *args: pdb.set_trace()) - fixPdb() - pdb.runcall(reactor.run) - else: - reactor.run() - except: - if config['nodaemon']: - file = oldstdout - else: - file = open("TWISTD-CRASH.log",'a') - traceback.print_exc(file=file) - file.flush() - - - -def getPassphrase(needed): - if needed: - return getpass.getpass('Passphrase: ') - else: - return None - - - -def getSavePassphrase(needed): - if needed: - passphrase = util.getPassword("Encryption passphrase: ") - else: - return None - - - -class ApplicationRunner(object): - """ - An object which helps running an application based on a config object. - - Subclass me and implement preApplication and postApplication - methods. postApplication generally will want to run the reactor - after starting the application. - - @ivar config: The config object, which provides a dict-like interface. - - @ivar application: Available in postApplication, but not - preApplication. This is the application object. - - @ivar profilerFactory: Factory for creating a profiler object, able to - profile the application if options are set accordingly. - - @ivar profiler: Instance provided by C{profilerFactory}. - """ - profilerFactory = AppProfiler - - def __init__(self, config): - self.config = config - self.profiler = self.profilerFactory(config) - - - def run(self): - """ - Run the application. - """ - self.preApplication() - self.application = self.createOrGetApplication() - - # Later, try adapting self.application to ILogObserverFactory or - # whatever and getting an observer from it, instead. Fall back to - # self.getLogObserver if the adaption fails. - self.startLogging(self.getLogObserver()) - - self.postApplication() - - - def startReactor(self, reactor, oldstdout, oldstderr): - """ - Run the reactor with the given configuration. Subclasses should - probably call this from C{postApplication}. - - @see: L{runReactorWithLogging} - """ - runReactorWithLogging( - self.config, oldstdout, oldstderr, self.profiler, reactor) - - - def preApplication(self): - """ - Override in subclass. - - This should set up any state necessary before loading and - running the Application. - """ - raise NotImplementedError() - - - def startLogging(self, observer): - """ - Initialize the logging system. - - @param observer: The observer to add to the logging system. - """ - log.startLoggingWithObserver(observer) - sys.stdout.flush() - initialLog() - - - def getLogObserver(self): - """ - Create a log observer to be added to the logging system before running - this application. - """ - raise NotImplementedError() - - - def postApplication(self): - """ - Override in subclass. - - This will be called after the application has been loaded (so - the C{application} attribute will be set). Generally this - should start the application and run the reactor. - """ - raise NotImplementedError - - - def createOrGetApplication(self): - """ - Create or load an Application based on the parameters found in the - given L{ServerOptions} instance. - - If a subcommand was used, the L{service.IServiceMaker} that it - represents will be used to construct a service to be added to - a newly-created Application. - - Otherwise, an application will be loaded based on parameters in - the config. - """ - if self.config.subCommand: - # If a subcommand was given, it's our responsibility to create - # the application, instead of load it from a file. - - # loadedPlugins is set up by the ServerOptions.subCommands - # property, which is iterated somewhere in the bowels of - # usage.Options. - plg = self.config.loadedPlugins[self.config.subCommand] - ser = plg.makeService(self.config.subOptions) - application = service.Application(plg.tapname) - ser.setServiceParent(application) - else: - passphrase = getPassphrase(self.config['encrypted']) - application = getApplication(self.config, passphrase) - return application - - - -def getApplication(config, passphrase): - s = [(config[t], t) - for t in ['python', 'xml', 'source', 'file'] if config[t]][0] - filename, style = s[0], {'file':'pickle'}.get(s[1],s[1]) - try: - log.msg("Loading %s..." % filename) - application = service.loadApplication(filename, style, passphrase) - log.msg("Loaded.") - except Exception, e: - s = "Failed to load application: %s" % e - if isinstance(e, KeyError) and e.args[0] == "application": - s += """ -Could not find 'application' in the file. To use 'twistd -y', your .tac -file must create a suitable object (e.g., by calling service.Application()) -and store it in a variable named 'application'. twistd loads your .tac file -and scans the global variables for one of this name. - -Please read the 'Using Application' HOWTO for details. -""" - traceback.print_exc(file=log.logfile) - log.msg(s) - log.deferr() - sys.exit('\n' + s + '\n') - return application - - - -def reportProfile(report_profile, name): - """ - DEPRECATED since Twisted 8.0. This does nothing. - """ - warnings.warn("reportProfile is deprecated and a no-op since Twisted 8.0.", - category=DeprecationWarning) - - - -def _reactorZshAction(): - return "(%s)" % " ".join([r.shortName for r in reactors.getReactorTypes()]) - -class ReactorSelectionMixin: - """ - Provides options for selecting a reactor to install. - """ - zsh_actions = {"reactor" : _reactorZshAction} - messageOutput = sys.stdout - - - def opt_help_reactors(self): - """ - Display a list of possibly available reactor names. - """ - for r in reactors.getReactorTypes(): - self.messageOutput.write(' %-4s\t%s\n' % - (r.shortName, r.description)) - raise SystemExit(0) - - - def opt_reactor(self, shortName): - """ - Which reactor to use (see --help-reactors for a list of possibilities) - """ - # Actually actually actually install the reactor right at this very - # moment, before any other code (for example, a sub-command plugin) - # runs and accidentally imports and installs the default reactor. - # - # This could probably be improved somehow. - try: - installReactor(shortName) - except NoSuchReactor: - msg = ("The specified reactor does not exist: '%s'.\n" - "See the list of available reactors with " - "--help-reactors" % (shortName,)) - raise usage.UsageError(msg) - except Exception, e: - msg = ("The specified reactor cannot be used, failed with error: " - "%s.\nSee the list of available reactors with " - "--help-reactors" % (e,)) - raise usage.UsageError(msg) - opt_r = opt_reactor - - - - -class ServerOptions(usage.Options, ReactorSelectionMixin): - - optFlags = [['savestats', None, - "save the Stats object rather than the text output of " - "the profiler."], - ['no_save','o', "do not save state on shutdown"], - ['encrypted', 'e', - "The specified tap/aos/xml file is encrypted."], - ['nothotshot', None, - "DEPRECATED. Don't use the 'hotshot' profiler even if " - "it's available."]] - - optParameters = [['logfile','l', None, - "log to a specified file, - for stdout"], - ['profile', 'p', None, - "Run in profile mode, dumping results to specified file"], - ['profiler', None, "hotshot", - "Name of the profiler to use, 'hotshot' or 'profile'."], - ['file','f','twistd.tap', - "read the given .tap file"], - ['python','y', None, - "read an application from within a Python file (implies -o)"], - ['xml', 'x', None, - "Read an application from a .tax file " - "(Marmalade format)."], - ['source', 's', None, - "Read an application from a .tas file (AOT format)."], - ['rundir','d','.', - 'Change to a supplied directory before running'], - ['report-profile', None, None, - 'E-mail address to use when reporting dynamic execution ' - 'profiler stats. This should not be combined with ' - 'other profiling options. This will only take effect ' - 'if the application to be run has an application ' - 'name.']] - - #zsh_altArgDescr = {"foo":"use this description for foo instead"} - #zsh_multiUse = ["foo", "bar"] - zsh_mutuallyExclusive = [("file", "python", "xml", "source")] - zsh_actions = {"file":'_files -g "*.tap"', - "python":'_files -g "*.(tac|py)"', - "xml":'_files -g "*.tax"', - "source":'_files -g "*.tas"', - "rundir":"_dirs"} - #zsh_actionDescr = {"logfile":"log file name", "random":"random seed"} - - def __init__(self, *a, **kw): - self['debug'] = False - usage.Options.__init__(self, *a, **kw) - - def opt_debug(self): - """ - run the application in the Python Debugger (implies nodaemon), - sending SIGUSR2 will drop into debugger - """ - defer.setDebugging(True) - failure.startDebugMode() - self['debug'] = True - opt_b = opt_debug - - - def opt_spew(self): - """Print an insanely verbose log of everything that happens. - Useful when debugging freezes or locks in complex code.""" - sys.settrace(util.spewer) - try: - import threading - except ImportError: - return - threading.settrace(util.spewer) - - - def opt_report_profile(self, value): - """ - DEPRECATED. - - Manage --report-profile option, which does nothing currently. - """ - warnings.warn("--report-profile option is deprecated and a no-op " - "since Twisted 8.0.", category=DeprecationWarning) - - - def parseOptions(self, options=None): - if options is None: - options = sys.argv[1:] or ["--help"] - usage.Options.parseOptions(self, options) - - def postOptions(self): - if self.subCommand or self['python']: - self['no_save'] = True - - def subCommands(self): - from twisted import plugin - plugins = plugin.getPlugins(service.IServiceMaker) - self.loadedPlugins = {} - for plug in plugins: - self.loadedPlugins[plug.tapname] = plug - yield (plug.tapname, None, lambda: plug.options(), plug.description) - subCommands = property(subCommands) - - - -def run(runApp, ServerOptions): - config = ServerOptions() - try: - config.parseOptions() - except usage.error, ue: - print config - print "%s: %s" % (sys.argv[0], ue) - else: - runApp(config) - - -def initialLog(): - from twisted.internet import reactor - log.msg("twistd %s (%s %s) starting up" % (copyright.version, - sys.executable, - runtime.shortPythonVersion())) - log.msg('reactor class: %s' % reactor.__class__) - - -def convertStyle(filein, typein, passphrase, fileout, typeout, encrypt): - application = service.loadApplication(filein, typein, passphrase) - sob.IPersistable(application).setStyle(typeout) - passphrase = getSavePassphrase(encrypt) - if passphrase: - fileout = None - sob.IPersistable(application).save(filename=fileout, passphrase=passphrase) - -def startApplication(application, save): - from twisted.internet import reactor - service.IService(application).startService() - if save: - p = sob.IPersistable(application) - reactor.addSystemEventTrigger('after', 'shutdown', p.save, 'shutdown') - reactor.addSystemEventTrigger('before', 'shutdown', - service.IService(application).stopService) - -def getLogFile(logfilename): - """ - Build a log file from the full path. - """ - import warnings - warnings.warn( - "app.getLogFile is deprecated. Use " - "twisted.python.logfile.LogFile.fromFullPath instead", - DeprecationWarning, stacklevel=2) - - return logfile.LogFile.fromFullPath(logfilename) - diff --git a/tools/buildbot/pylibs/twisted/application/internet.py b/tools/buildbot/pylibs/twisted/application/internet.py deleted file mode 100644 index 5ca2d18..0000000 --- a/tools/buildbot/pylibs/twisted/application/internet.py +++ /dev/null @@ -1,270 +0,0 @@ -# -*- test-case-name: twisted.test.test_application,twisted.test.test_cooperator -*- - -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Reactor-based Services - -Here are services to run clients, servers and periodic services using -the reactor. - -This module (dynamically) defines various Service subclasses that let -you represent clients and servers in a Service hierarchy. - -They are as follows:: - - TCPServer, TCPClient, - UNIXServer, UNIXClient, - SSLServer, SSLClient, - UDPServer, UDPClient, - UNIXDatagramServer, UNIXDatagramClient, - MulticastServer - -These classes take arbitrary arguments in their constructors and pass -them straight on to their respective reactor.listenXXX or -reactor.connectXXX calls. - -For example, the following service starts a web server on port 8080: -C{TCPServer(8080, server.Site(r))}. See the documentation for the -reactor.listen/connect* methods for more information. - -Maintainer: U{Moshe Zadka} -""" - -from twisted.python import log -from twisted.application import service -from twisted.internet import task - - -class _VolatileDataService(service.Service): - - volatile = [] - - def __getstate__(self): - d = service.Service.__getstate__(self) - for attr in self.volatile: - if attr in d: - del d[attr] - return d - - - -class _AbstractServer(_VolatileDataService): - """ - @cvar volatile: list of attribute to remove from pickling. - @type volatile: C{list} - - @ivar method: the type of method to call on the reactor, one of B{TCP}, - B{UDP}, B{SSL} or B{UNIX}. - @type method: C{str} - - @ivar reactor: the current running reactor. - @type reactor: a provider of C{IReactorTCP}, C{IReactorUDP}, - C{IReactorSSL} or C{IReactorUnix}. - - @ivar _port: instance of port set when the service is started. - @type _port: a provider of C{IListeningPort}. - """ - - volatile = ['_port'] - method = None - reactor = None - - _port = None - - def __init__(self, *args, **kwargs): - self.args = args - if 'reactor' in kwargs: - self.reactor = kwargs.pop("reactor") - self.kwargs = kwargs - - - def privilegedStartService(self): - service.Service.privilegedStartService(self) - self._port = self._getPort() - - - def startService(self): - service.Service.startService(self) - if self._port is None: - self._port = self._getPort() - - - def stopService(self): - service.Service.stopService(self) - # TODO: if startup failed, should shutdown skip stopListening? - # _port won't exist - if self._port is not None: - d = self._port.stopListening() - del self._port - return d - - - def _getPort(self): - """ - Wrapper around the appropriate listen method of the reactor. - - @return: the port object returned by the listen method. - @rtype: an object providing L{IListeningPort}. - """ - if self.reactor is None: - from twisted.internet import reactor - else: - reactor = self.reactor - return getattr(reactor, 'listen%s' % (self.method,))( - *self.args, **self.kwargs) - - - -class _AbstractClient(_VolatileDataService): - """ - @cvar volatile: list of attribute to remove from pickling. - @type volatile: C{list} - - @ivar method: the type of method to call on the reactor, one of B{TCP}, - B{UDP}, B{SSL} or B{UNIX}. - @type method: C{str} - - @ivar reactor: the current running reactor. - @type reactor: a provider of C{IReactorTCP}, C{IReactorUDP}, - C{IReactorSSL} or C{IReactorUnix}. - - @ivar _connection: instance of connection set when the service is started. - @type _connection: a provider of C{IConnector}. - """ - volatile = ['_connection'] - method = None - reactor = None - - _connection = None - - def __init__(self, *args, **kwargs): - self.args = args - if 'reactor' in kwargs: - self.reactor = kwargs.pop("reactor") - self.kwargs = kwargs - - - def startService(self): - service.Service.startService(self) - self._connection = self._getConnection() - - - def stopService(self): - service.Service.stopService(self) - if self._connection is not None: - self._connection.disconnect() - del self._connection - - - def _getConnection(self): - """ - Wrapper around the appropriate connect method of the reactor. - - @return: the port object returned by the connect method. - @rtype: an object providing L{IConnector}. - """ - if self.reactor is None: - from twisted.internet import reactor - else: - reactor = self.reactor - return getattr(reactor, 'connect%s' % (self.method,))( - *self.args, **self.kwargs) - - - -_doc={ -'Client': -"""Connect to %(tran)s - -Call reactor.connect%(method)s when the service starts, with the -arguments given to the constructor. -""", -'Server': -"""Serve %(tran)s clients - -Call reactor.listen%(method)s when the service starts, with the -arguments given to the constructor. When the service stops, -stop listening. See twisted.internet.interfaces for documentation -on arguments to the reactor method. -""", -} - -import new -for tran in 'Generic TCP UNIX SSL UDP UNIXDatagram Multicast'.split(): - for side in 'Server Client'.split(): - if tran == "Multicast" and side == "Client": - continue - base = globals()['_Abstract'+side] - method = {'Generic': 'With'}.get(tran, tran) - doc = _doc[side]%vars() - klass = new.classobj(tran+side, (base,), - {'method': method, '__doc__': doc}) - globals()[tran+side] = klass - - -class TimerService(_VolatileDataService): - - """Service to periodically call a function - - Every C{step} seconds call the given function with the given arguments. - The service starts the calls when it starts, and cancels them - when it stops. - """ - - volatile = ['_loop'] - - def __init__(self, step, callable, *args, **kwargs): - self.step = step - self.call = (callable, args, kwargs) - - def startService(self): - service.Service.startService(self) - callable, args, kwargs = self.call - # we have to make a new LoopingCall each time we're started, because - # an active LoopingCall remains active when serialized. If - # LoopingCall were a _VolatileDataService, we wouldn't need to do - # this. - self._loop = task.LoopingCall(callable, *args, **kwargs) - self._loop.start(self.step, now=True).addErrback(self._failed) - - def _failed(self, why): - # make a note that the LoopingCall is no longer looping, so we don't - # try to shut it down a second time in stopService. I think this - # should be in LoopingCall. -warner - self._loop.running = False - log.err(why) - - def stopService(self): - if self._loop.running: - self._loop.stop() - return service.Service.stopService(self) - - - -class CooperatorService(service.Service): - """ - Simple L{service.IService} which starts and stops a L{twisted.internet.task.Cooperator}. - """ - def __init__(self): - self.coop = task.Cooperator(started=False) - - - def coiterate(self, iterator): - return self.coop.coiterate(iterator) - - - def startService(self): - self.coop.start() - - - def stopService(self): - self.coop.stop() - - - -__all__ = (['TimerService', 'CooperatorService'] + - [tran+side - for tran in 'Generic TCP UNIX SSL UDP UNIXDatagram Multicast'.split() - for side in 'Server Client'.split()]) diff --git a/tools/buildbot/pylibs/twisted/application/reactors.py b/tools/buildbot/pylibs/twisted/application/reactors.py deleted file mode 100644 index c15c948..0000000 --- a/tools/buildbot/pylibs/twisted/application/reactors.py +++ /dev/null @@ -1,83 +0,0 @@ -# -*- test-case-name: twisted.test.test_application -*- -# Copyright (c) 2006-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Plugin-based system for enumerating available reactors and installing one of -them. -""" - -from zope.interface import Interface, Attribute, implements - -from twisted.plugin import IPlugin, getPlugins -from twisted.python.reflect import namedAny - - -class IReactorInstaller(Interface): - """ - Definition of a reactor which can probably be installed. - """ - shortName = Attribute(""" - A brief string giving the user-facing name of this reactor. - """) - - description = Attribute(""" - A longer string giving a user-facing description of this reactor. - """) - - def install(): - """ - Install this reactor. - """ - - # TODO - A method which provides a best-guess as to whether this reactor - # can actually be used in the execution environment. - - - -class NoSuchReactor(KeyError): - """ - Raised when an attempt is made to install a reactor which cannot be found. - """ - - -class Reactor(object): - """ - @ivar moduleName: The fully-qualified Python name of the module of which - the install callable is an attribute. - """ - implements(IPlugin, IReactorInstaller) - - - def __init__(self, shortName, moduleName, description): - self.shortName = shortName - self.moduleName = moduleName - self.description = description - - - def install(self): - namedAny(self.moduleName).install() - - - -def getReactorTypes(): - """ - Return an iterator of L{IReactorInstaller} plugins. - """ - return getPlugins(IReactorInstaller) - - - -def installReactor(shortName): - """ - Install the reactor with the given C{shortName} attribute. - - @raise NoSuchReactor: If no reactor is found with a matching C{shortName}. - - @raise: anything that the specified reactor can raise when installed. - """ - for installer in getReactorTypes(): - if installer.shortName == shortName: - return installer.install() - raise NoSuchReactor(shortName) - diff --git a/tools/buildbot/pylibs/twisted/application/service.py b/tools/buildbot/pylibs/twisted/application/service.py deleted file mode 100644 index 97b13bf..0000000 --- a/tools/buildbot/pylibs/twisted/application/service.py +++ /dev/null @@ -1,376 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -""" -Service architecture for Twisted - -Services are arranged in a hierarchy. At the leafs of the hierarchy, -the services which actually interact with the outside world are started. -Services can be named or anonymous -- usually, they will be named if -there is need to access them through the hierarchy (from a parent or -a sibling). - -Maintainer: U{Moshe Zadka} -""" - -from zope.interface import implements, Interface, Attribute - -from twisted.python.reflect import namedAny -from twisted.python import components -from twisted.internet import defer -from twisted.persisted import sob -from twisted.plugin import IPlugin - -class IServiceMaker(Interface): - """ - An object which can be used to construct services in a flexible - way. - - This interface should most often be implemented along with - twisted.plugin.IPlugin, and will most often be used by the - 'twistd' command. - """ - tapname = Attribute( - "A short string naming this Twisted plugin, for example 'web' or " - "'pencil'. This name will be used as the subcommand of 'twistd'.") - - description = Attribute( - "A brief summary of the features provided by this " - "Twisted application plugin.") - - options = Attribute( - "A C{twisted.python.usage.Options} subclass defining the" - "configuration options for this application.") - - - def makeService(options): - """ - Create and return an object providing - L{twisted.application.service.IService}. - - @param options: A mapping (typically a C{dict} or - C{twisted.python.usage.Options} instance) of configuration - options to desired configuration values. - """ - - - -class ServiceMaker(object): - """ - Utility class to simplify the definition of L{IServiceMaker} plugins. - """ - implements(IPlugin, IServiceMaker) - - def __init__(self, name, module, description, tapname): - self.name = name - self.module = module - self.description = description - self.tapname = tapname - - - def options(): - def get(self): - return namedAny(self.module).Options - return get, - options = property(*options()) - - - def makeService(): - def get(self): - return namedAny(self.module).makeService - return get, - makeService = property(*makeService()) - - - -class IService(Interface): - """ - A service. - - Run start-up and shut-down code at the appropriate times. - - @type name: C{string} - @ivar name: The name of the service (or None) - @type running: C{boolean} - @ivar running: Whether the service is running. - """ - - def setName(name): - """Set the name of the service. - - @type name: C{str} - @raise RuntimeError: Raised if the service already has a parent. - """ - - def setServiceParent(parent): - """Set the parent of the service. - - @type name: L{IServiceCollection} - @raise RuntimeError: Raised if the service already has a parent - or if the service has a name and the parent already has a child - by that name. - """ - - def disownServiceParent(): - """Remove the parent of the service. - - @rtype: L{Deferred} - @return: a deferred which is triggered when the service has - finished shutting down. If shutting down is immediate, - a value can be returned (usually, None). - """ - - def startService(): - """Start the service.""" - - def stopService(): - """Stop the service. - - @rtype: L{Deferred} - @return: a deferred which is triggered when the service has - finished shutting down. If shutting down is immediate, - a value can be returned (usually, None). - """ - - def privilegedStartService(): - """Do preparation work for starting the service. - - Here things which should be done before changing directory, - root or shedding privileges are done.""" - - -class Service: - - """ - Base class for services - - Most services should inherit from this class. It handles the - book-keeping reponsibilities of starting and stopping, as well - as not serializing this book-keeping information. - """ - - implements(IService) - - running = 0 - name = None - parent = None - - def __getstate__(self): - dict = self.__dict__.copy() - if dict.has_key("running"): - del dict['running'] - return dict - - def setName(self, name): - if self.parent is not None: - raise RuntimeError("cannot change name when parent exists") - self.name = name - - def setServiceParent(self, parent): - if self.parent is not None: - self.disownServiceParent() - parent = IServiceCollection(parent, parent) - self.parent = parent - self.parent.addService(self) - - def disownServiceParent(self): - d = self.parent.removeService(self) - self.parent = None - return d - - def privilegedStartService(self): - pass - - def startService(self): - self.running = 1 - - def stopService(self): - self.running = 0 - - - -class IServiceCollection(Interface): - - """Collection of services. - - Contain several services, and manage their start-up/shut-down. - Services can be accessed by name if they have a name, and it - is always possible to iterate over them. - """ - - def getServiceNamed(name): - """Get the child service with a given name. - - @type name: C{str} - @rtype: L{IService} - @raise KeyError: Raised if the service has no child with the - given name. - """ - - def __iter__(): - """Get an iterator over all child services""" - - def addService(service): - """Add a child service. - - @type service: L{IService} - @raise RuntimeError: Raised if the service has a child with - the given name. - """ - - def removeService(service): - """Remove a child service. - - @type service: L{IService} - @raise ValueError: Raised if the given service is not a child. - @rtype: L{Deferred} - @return: a deferred which is triggered when the service has - finished shutting down. If shutting down is immediate, - a value can be returned (usually, None). - """ - - - -class MultiService(Service): - - """Straightforward Service Container - - Hold a collection of services, and manage them in a simplistic - way. No service will wait for another, but this object itself - will not finish shutting down until all of its child services - will finish. - """ - - implements(IServiceCollection) - - def __init__(self): - self.services = [] - self.namedServices = {} - self.parent = None - - def privilegedStartService(self): - Service.privilegedStartService(self) - for service in self: - service.privilegedStartService() - - def startService(self): - Service.startService(self) - for service in self: - service.startService() - - def stopService(self): - Service.stopService(self) - l = [] - services = list(self) - services.reverse() - for service in services: - l.append(defer.maybeDeferred(service.stopService)) - return defer.DeferredList(l) - - def getServiceNamed(self, name): - return self.namedServices[name] - - def __iter__(self): - return iter(self.services) - - def addService(self, service): - if service.name is not None: - if self.namedServices.has_key(service.name): - raise RuntimeError("cannot have two services with same name" - " '%s'" % service.name) - self.namedServices[service.name] = service - self.services.append(service) - if self.running: - # It may be too late for that, but we will do our best - service.privilegedStartService() - service.startService() - - def removeService(self, service): - if service.name: - del self.namedServices[service.name] - self.services.remove(service) - if self.running: - # Returning this so as not to lose information from the - # MultiService.stopService deferred. - return service.stopService() - else: - return None - - - -class IProcess(Interface): - - """Process running parameters - - Represents parameters for how processes should be run. - - @ivar processName: the name the process should have in ps (or None) - @type processName: C{str} - @ivar uid: the user-id the process should run under. - @type uid: C{int} - @ivar gid: the group-id the process should run under. - @type gid: C{int} - """ - - -class Process: - """Process running parameters - - Sets up uid/gid in the constructor, and has a default - of C{None} as C{processName}. - """ - implements(IProcess) - processName = None - - def __init__(self, uid=None, gid=None): - """Set uid and gid. - - @param uid: The user ID as whom to execute the process. If - this is None, no attempt will be made to change the UID. - - @param gid: The group ID as whom to execute the process. If - this is None, no attempt will be made to change the GID. - """ - self.uid = uid - self.gid = gid - - -def Application(name, uid=None, gid=None): - """Return a compound class. - - Return an object supporting the L{IService}, L{IServiceCollection}, - L{IProcess} and L{sob.IPersistable} interfaces, with the given - parameters. Always access the return value by explicit casting to - one of the interfaces. - """ - ret = components.Componentized() - for comp in (MultiService(), sob.Persistent(ret, name), Process(uid, gid)): - ret.addComponent(comp, ignoreClass=1) - IService(ret).setName(name) - return ret - - - -def loadApplication(filename, kind, passphrase=None): - """Load Application from a given file. - - The serialization format it was saved in should be given as - C{kind}, and is one of 'pickle', 'source', 'xml' or 'python'. If - C{passphrase} is given, the application was encrypted with the - given passphrase. - - @type filename: C{str} - @type kind: C{str} - @type passphrase: C{str} - """ - if kind == 'python': - application = sob.loadValueFromFile(filename, 'application', passphrase) - else: - application = sob.load(filename, kind, passphrase) - return application - - -__all__ = ['IServiceMaker', 'IService', 'Service', - 'IServiceCollection', 'MultiService', - 'IProcess', 'Process', 'Application', 'loadApplication'] diff --git a/tools/buildbot/pylibs/twisted/application/strports.py b/tools/buildbot/pylibs/twisted/application/strports.py deleted file mode 100644 index 18ac64e..0000000 --- a/tools/buildbot/pylibs/twisted/application/strports.py +++ /dev/null @@ -1,175 +0,0 @@ -# -*- test-case-name: twisted.test.test_strports -*- - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -""" -Port description language - -This module implements a description mini-language for ports, and provides -functions to parse it and to use it to directly construct appropriate -network server services or to directly listen on them. - -Here are some examples:: - >>> s=service("80", server.Site()) - >>> s=service("tcp:80", server.Site()) - >>> s=service("tcp:80:interface=127.0.0.1", server.Site()) - >>> s=service("ssl:443", server.Site()) - >>> s=service("ssl:443:privateKey=mykey.pem", server.Site()) - >>> s=service("ssl:443:privateKey=mykey.pem:certKey=cert.pem", server.Site()) - >>> s=service("unix:/var/run/finger", FingerFactory()) - >>> s=service("unix:/var/run/finger:mode=660", FingerFactory()) - >>> p=listen("80", server.Site()) - >>> p=listen("tcp:80", server.Site()) - >>> p=listen("tcp:80:interface=127.0.0.1", server.Site()) - >>> p=listen("ssl:443", server.Site()) - >>> p=listen("ssl:443:privateKey=mykey.pem", server.Site()) - >>> p=listen("ssl:443:privateKey=mykey.pem:certKey=cert.pem", server.Site()) - >>> p=listen("unix:/var/run/finger", FingerFactory()) - >>> p=listen("unix:/var/run/finger:mode=660", FingerFactory()) - -See specific function documentation for more information. - -Maintainer: U{Moshe Zadka} -""" -from __future__ import generators - -def _parseTCP(factory, port, interface="", backlog=50): - return (int(port), factory), {'interface': interface, - 'backlog': int(backlog)} - -def _parseUNIX(factory, address, mode='666', backlog=50): - return (address, factory), {'mode': int(mode, 8), 'backlog': int(backlog)} - -def _parseSSL(factory, port, privateKey="server.pem", certKey=None, - sslmethod=None, interface='', backlog=50): - from twisted.internet import ssl - if certKey is None: - certKey = privateKey - kw = {} - if sslmethod is not None: - kw['sslmethod'] = getattr(ssl.SSL, sslmethod) - cf = ssl.DefaultOpenSSLContextFactory(privateKey, certKey, **kw) - return ((int(port), factory, cf), - {'interface': interface, 'backlog': int(backlog)}) - -_funcs = {"tcp": _parseTCP, - "unix": _parseUNIX, - "ssl": _parseSSL} - -_OP, _STRING = range(2) -def _tokenize(description): - current = '' - ops = ':=' - nextOps = {':': ':=', '=': ':'} - description = iter(description) - for n in description: - if n in ops: - yield _STRING, current - yield _OP, n - current = '' - ops = nextOps[n] - elif n=='\\': - current += description.next() - else: - current += n - yield _STRING, current - -def _parse(description): - args, kw = [], {} - def add(sofar): - if len(sofar)==1: - args.append(sofar[0]) - else: - kw[sofar[0]] = sofar[1] - sofar = () - for (type, value) in _tokenize(description): - if type is _STRING: - sofar += (value,) - elif value==':': - add(sofar) - sofar = () - add(sofar) - return args, kw - -def parse(description, factory, default=None): - """ - Parse the description of a reliable virtual circuit server (that is, a - TCP port, a UNIX domain socket or an SSL port) and return the data - necessary to call the reactor methods to listen on the given socket with - the given factory. - - An argument with no colons means a default port. Usually the default - type is C{tcp}, but passing a non-C{None} value as C{default} will set - that as the default. Otherwise, it is a colon-separated string. The - first part means the type -- currently, it can only be ssl, unix or tcp. - After that, comes a list of arguments. Arguments can be positional or - keyword, and can be mixed. Keyword arguments are indicated by - C{'name=value'}. If a value is supposed to contain a C{':'}, a C{'='} or - a C{'\\'}, escape it with a C{'\\'}. - - For TCP, the arguments are the port (port number) and, optionally the - interface (interface on which to listen) and backlog (how many clients - to keep in the backlog). - - For UNIX domain sockets, the arguments are address (the file name of the - socket) and optionally the mode (the mode bits of the file, as an octal - number) and the backlog (how many clients to keep in the backlog). - - For SSL sockets, the arguments are the port (port number) and, - optionally, the privateKey (file in which the private key is in), - certKey (file in which the certification is in), sslmethod (the name of - the SSL method to allow), the interface (interface on which to listen) - and the backlog (how many clients to keep in the backlog). - - @type description: C{str} - @type factory: L{twisted.internet.interfaces.IProtocolFactory} - @type default: C{str} or C{None} - @rtype: C{tuple} - @return: a tuple of string, tuple and dictionary. The string is the name - of the method (sans C{'listen'}) to call, and the tuple and dictionary - are the arguments and keyword arguments to the method. - @raises ValueError: if the string is formatted incorrectly. - @raises KeyError: if the type is other than unix, ssl or tcp. - """ - args, kw = _parse(description) - if not args or (len(args)==1 and not kw): - args[0:0] = [default or 'tcp'] - return (args[0].upper(),)+_funcs[args[0]](factory, *args[1:], **kw) - -def service(description, factory, default=None): - """Return the service corresponding to a description - - @type description: C{str} - @type factory: L{twisted.internet.interfaces.IProtocolFactory} - @type default: C{str} or C{None} - @rtype: C{twisted.application.service.IService} - @return: the service corresponding to a description of a reliable - virtual circuit server. - - See the documentation of the C{parse} function for description - of the semantics of the arguments. - """ - from twisted.application import internet - name, args, kw = parse(description, factory, default) - return getattr(internet, name+'Server')(*args, **kw) - -def listen(description, factory, default=None): - """Listen on a port corresponding to a description - - @type description: C{str} - @type factory: L{twisted.internet.interfaces.IProtocolFactory} - @type default: C{str} or C{None} - @rtype: C{twisted.internet.interfaces.IListeningPort} - @return: the port corresponding to a description of a reliable - virtual circuit server. - - See the documentation of the C{parse} function for description - of the semantics of the arguments. - """ - from twisted.internet import reactor - name, args, kw = parse(description, factory, default) - return getattr(reactor, 'listen'+name)(*args, **kw) - -__all__ = ['parse', 'service', 'listen'] diff --git a/tools/buildbot/pylibs/twisted/conch/__init__.py b/tools/buildbot/pylibs/twisted/conch/__init__.py deleted file mode 100644 index 50213f0..0000000 --- a/tools/buildbot/pylibs/twisted/conch/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- test-case-name: twisted.conch.test -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - - -""" -Twisted.Conch: The Twisted Shell. Terminal emulation, SSHv2 and telnet. - -Currently this contains the SSHv2 implementation, but it may work over other -protocols in the future. (i.e. Telnet) - -Maintainer: U{Paul Swartz} -""" - -from twisted.conch._version import version -__version__ = version.short() diff --git a/tools/buildbot/pylibs/twisted/conch/_version.py b/tools/buildbot/pylibs/twisted/conch/_version.py deleted file mode 100644 index f5de6b7..0000000 --- a/tools/buildbot/pylibs/twisted/conch/_version.py +++ /dev/null @@ -1,3 +0,0 @@ -# This is an auto-generated file. Do not edit it. -from twisted.python import versions -version = versions.Version('twisted.conch', 8, 1, 0) diff --git a/tools/buildbot/pylibs/twisted/conch/avatar.py b/tools/buildbot/pylibs/twisted/conch/avatar.py deleted file mode 100644 index a914da3..0000000 --- a/tools/buildbot/pylibs/twisted/conch/avatar.py +++ /dev/null @@ -1,37 +0,0 @@ -# -*- test-case-name: twisted.conch.test.test_conch -*- -from interfaces import IConchUser -from error import ConchError -from ssh.connection import OPEN_UNKNOWN_CHANNEL_TYPE -from twisted.python import log -from zope import interface - -class ConchUser: - interface.implements(IConchUser) - - def __init__(self): - self.channelLookup = {} - self.subsystemLookup = {} - - def lookupChannel(self, channelType, windowSize, maxPacket, data): - klass = self.channelLookup.get(channelType, None) - if not klass: - raise ConchError(OPEN_UNKNOWN_CHANNEL_TYPE, "unknown channel") - else: - return klass(remoteWindow = windowSize, - remoteMaxPacket = maxPacket, - data=data, avatar=self) - - def lookupSubsystem(self, subsystem, data): - log.msg(repr(self.subsystemLookup)) - klass = self.subsystemLookup.get(subsystem, None) - if not klass: - return False - return klass(data, avatar=self) - - def gotGlobalRequest(self, requestType, data): - # XXX should this use method dispatch? - requestType = requestType.replace('-','_') - f = getattr(self, "global_%s" % requestType, None) - if not f: - return 0 - return f(data) diff --git a/tools/buildbot/pylibs/twisted/conch/checkers.py b/tools/buildbot/pylibs/twisted/conch/checkers.py deleted file mode 100644 index 90512f4..0000000 --- a/tools/buildbot/pylibs/twisted/conch/checkers.py +++ /dev/null @@ -1,176 +0,0 @@ -import os, base64, binascii -try: - import pwd -except ImportError: - pwd = None -else: - import crypt - -try: - # get this from http://www.twistedmatrix.com/users/z3p/files/pyshadow-0.2.tar.gz - import shadow -except: - shadow = None - -try: - import pamauth -except ImportError: - pamauth = None - -from twisted.conch import error -from twisted.conch.ssh import keys -from twisted.cred.checkers import ICredentialsChecker -from twisted.cred.credentials import IUsernamePassword, ISSHPrivateKey, IPluggableAuthenticationModules -from twisted.cred.error import UnauthorizedLogin, UnhandledCredentials -from twisted.internet import defer -from twisted.python import failure, reflect, log -from zope import interface - -def verifyCryptedPassword(crypted, pw): - if crypted[0] == '$': # md5_crypt encrypted - salt = '$1$' + crypted.split('$')[2] - else: - salt = crypted[:2] - return crypt.crypt(pw, salt) == crypted - -class UNIXPasswordDatabase: - credentialInterfaces = IUsernamePassword, - interface.implements(ICredentialsChecker) - - def requestAvatarId(self, credentials): - if pwd: - try: - cryptedPass = pwd.getpwnam(credentials.username)[1] - except KeyError: - return defer.fail(UnauthorizedLogin()) - else: - if cryptedPass not in ['*', 'x'] and \ - verifyCryptedPassword(cryptedPass, credentials.password): - return defer.succeed(credentials.username) - if shadow: - gid = os.getegid() - uid = os.geteuid() - os.setegid(0) - os.seteuid(0) - try: - shadowPass = shadow.getspnam(credentials.username)[1] - except KeyError: - os.setegid(gid) - os.seteuid(uid) - return defer.fail(UnauthorizedLogin()) - os.setegid(gid) - os.seteuid(uid) - if verifyCryptedPassword(shadowPass, credentials.password): - return defer.succeed(credentials.username) - return defer.fail(UnauthorizedLogin()) - - return defer.fail(UnauthorizedLogin()) - - -class SSHPublicKeyDatabase: - credentialInterfaces = ISSHPrivateKey, - interface.implements(ICredentialsChecker) - - def requestAvatarId(self, credentials): - d = defer.maybeDeferred(self.checkKey, credentials) - d.addCallback(self._cbRequestAvatarId, credentials) - d.addErrback(self._ebRequestAvatarId) - return d - - def _cbRequestAvatarId(self, validKey, credentials): - if not validKey: - return failure.Failure(UnauthorizedLogin()) - if not credentials.signature: - return failure.Failure(error.ValidPublicKey()) - else: - try: - pubKey = keys.getPublicKeyObject(data = credentials.blob) - if keys.verifySignature(pubKey, credentials.signature, - credentials.sigData): - return credentials.username - except: # any error should be treated as a failed login - f = failure.Failure() - log.err() - return f - return failure.Failure(UnauthorizedLogin()) - - def checkKey(self, credentials): - sshDir = os.path.expanduser('~%s/.ssh/' % credentials.username) - if sshDir.startswith('~'): # didn't expand - return 0 - uid, gid = os.geteuid(), os.getegid() - ouid, ogid = pwd.getpwnam(credentials.username)[2:4] - os.setegid(0) - os.seteuid(0) - os.setegid(ogid) - os.seteuid(ouid) - for name in ['authorized_keys2', 'authorized_keys']: - if not os.path.exists(sshDir+name): - continue - lines = open(sshDir+name).xreadlines() - os.setegid(0) - os.seteuid(0) - os.setegid(gid) - os.seteuid(uid) - for l in lines: - l2 = l.split() - if len(l2) < 2: - continue - try: - if base64.decodestring(l2[1]) == credentials.blob: - return 1 - except binascii.Error: - continue - return 0 - - def _ebRequestAvatarId(self, f): - if not f.check(UnauthorizedLogin, error.ValidPublicKey): - log.msg(f) - return failure.Failure(UnauthorizedLogin()) - return f - - -class SSHProtocolChecker: - interface.implements(ICredentialsChecker) - - checkers = {} - - successfulCredentials = {} - - def get_credentialInterfaces(self): - return self.checkers.keys() - - credentialInterfaces = property(get_credentialInterfaces) - - def registerChecker(self, checker, *credentialInterfaces): - if not credentialInterfaces: - credentialInterfaces = checker.credentialInterfaces - for credentialInterface in credentialInterfaces: - self.checkers[credentialInterface] = checker - - def requestAvatarId(self, credentials): - ifac = interface.providedBy(credentials) - for i in ifac: - c = self.checkers.get(i) - if c is not None: - return c.requestAvatarId(credentials).addCallback( - self._cbGoodAuthentication, credentials) - return defer.fail(UnhandledCredentials("No checker for %s" % \ - ', '.join(map(reflect.qal, ifac)))) - - def _cbGoodAuthentication(self, avatarId, credentials): - if avatarId not in self.successfulCredentials: - self.successfulCredentials[avatarId] = [] - self.successfulCredentials[avatarId].append(credentials) - if self.areDone(avatarId): - del self.successfulCredentials[avatarId] - return avatarId - else: - raise error.NotEnoughAuthentication() - - def areDone(self, avatarId): - """Override to determine if the authentication is finished for a given - avatarId. - """ - return 1 - diff --git a/tools/buildbot/pylibs/twisted/conch/client/__init__.py b/tools/buildbot/pylibs/twisted/conch/client/__init__.py deleted file mode 100644 index 593942a..0000000 --- a/tools/buildbot/pylibs/twisted/conch/client/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -""" -Client support code for Conch. - -Maintainer: U{Paul Swartz} -""" diff --git a/tools/buildbot/pylibs/twisted/conch/client/agent.py b/tools/buildbot/pylibs/twisted/conch/client/agent.py deleted file mode 100644 index 8383e09..0000000 --- a/tools/buildbot/pylibs/twisted/conch/client/agent.py +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -""" -Accesses the key agent for user authentication. - -Maintainer: U{Paul Swartz} -""" - -from twisted.conch.ssh import agent, channel -from twisted.internet import protocol -from twisted.python import log - -class SSHAgentClient(agent.SSHAgentClient): - - def __init__(self): - agent.SSHAgentClient.__init__(self) - self.blobs = [] - - def getPublicKeys(self): - return self.requestIdentities().addCallback(self._cbPublicKeys) - - def _cbPublicKeys(self, blobcomm): - log.msg('got %i public keys' % len(blobcomm)) - self.blobs = [x[0] for x in blobcomm] - - def getPublicKey(self): - if self.blobs: - return self.blobs.pop(0) - return None - -class SSHAgentForwardingChannel(channel.SSHChannel): - - def channelOpen(self, specificData): - cc = protocol.ClientCreator(reactor, SSHAgentForwardingLocal) - d = cc.connectUNIX(os.environ['SSH_AUTH_SOCK']) - d.addCallback(self._cbGotLocal) - d.addErrback(lambda x:self.loseConnection()) - self.buf = '' - - def _cbGotLocal(self, local): - self.local = local - self.dataReceived = self.local.transport.write - self.local.dataReceived = self.write - - def dataReceived(self, data): - self.buf += data - - def closed(self): - if self.local: - self.local.loseConnection() - self.local = None - -class SSHAgentForwardingLocal(protocol.Protocol): pass - diff --git a/tools/buildbot/pylibs/twisted/conch/client/connect.py b/tools/buildbot/pylibs/twisted/conch/client/connect.py deleted file mode 100644 index cf5fd16..0000000 --- a/tools/buildbot/pylibs/twisted/conch/client/connect.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -import direct, unix - -connectTypes = {"direct" : direct.connect, - "unix" : unix.connect} - -def connect(host, port, options, verifyHostKey, userAuthObject): - useConnects = options.conns or ['unix', 'direct'] - return _ebConnect(None, useConnects, host, port, options, verifyHostKey, - userAuthObject) - -def _ebConnect(f, useConnects, host, port, options, vhk, uao): - if not useConnects: - return f - connectType = useConnects.pop(0) - f = connectTypes[connectType] - d = f(host, port, options, vhk, uao) - d.addErrback(_ebConnect, useConnects, host, port, options, vhk, uao) - return d diff --git a/tools/buildbot/pylibs/twisted/conch/client/default.py b/tools/buildbot/pylibs/twisted/conch/client/default.py deleted file mode 100644 index 9b8003f..0000000 --- a/tools/buildbot/pylibs/twisted/conch/client/default.py +++ /dev/null @@ -1,209 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -from twisted.conch.error import ConchError -from twisted.conch.ssh import common, keys, userauth, agent -from twisted.internet import defer, protocol, reactor -from twisted.python import log - -import agent - -import os, sys, base64, getpass - -def verifyHostKey(transport, host, pubKey, fingerprint): - goodKey = isInKnownHosts(host, pubKey, transport.factory.options) - if goodKey == 1: # good key - return defer.succeed(1) - elif goodKey == 2: # AAHHHHH changed - return defer.fail(ConchError('changed host key')) - else: - oldout, oldin = sys.stdout, sys.stdin - sys.stdin = sys.stdout = open('/dev/tty','r+') - if host == transport.transport.getPeer().host: - khHost = host - else: - host = '%s (%s)' % (host, - transport.transport.getPeer().host) - khHost = '%s,%s' % (host, - transport.transport.getPeer().host) - keyType = common.getNS(pubKey)[0] - print """The authenticity of host '%s' can't be established. -%s key fingerprint is %s.""" % (host, - {'ssh-dss':'DSA', 'ssh-rsa':'RSA'}[keyType], - fingerprint) - try: - ans = raw_input('Are you sure you want to continue connecting (yes/no)? ') - except KeyboardInterrupt: - return defer.fail(ConchError("^C")) - while ans.lower() not in ('yes', 'no'): - ans = raw_input("Please type 'yes' or 'no': ") - sys.stdout,sys.stdin=oldout,oldin - if ans == 'no': - print 'Host key verification failed.' - return defer.fail(ConchError('bad host key')) - print "Warning: Permanently added '%s' (%s) to the list of known hosts." % (khHost, {'ssh-dss':'DSA', 'ssh-rsa':'RSA'}[keyType]) - known_hosts = open(os.path.expanduser('~/.ssh/known_hosts'), 'r+') - known_hosts.seek(-1, 2) - if known_hosts.read(1) != '\n': - known_hosts.write('\n') - encodedKey = base64.encodestring(pubKey).replace('\n', '') - known_hosts.write('%s %s %s\n' % (khHost, keyType, encodedKey)) - known_hosts.close() - return defer.succeed(1) - -def isInKnownHosts(host, pubKey, options): - """checks to see if host is in the known_hosts file for the user. - returns 0 if it isn't, 1 if it is and is the same, 2 if it's changed. - """ - keyType = common.getNS(pubKey)[0] - retVal = 0 - - if not options['known-hosts'] and not os.path.exists(os.path.expanduser('~/.ssh/')): - print 'Creating ~/.ssh directory...' - os.mkdir(os.path.expanduser('~/.ssh')) - kh_file = options['known-hosts'] or '~/.ssh/known_hosts' - try: - known_hosts = open(os.path.expanduser(kh_file)) - except IOError: - return 0 - for line in known_hosts.xreadlines(): - split = line.split() - if len(split) < 3: - continue - hosts, hostKeyType, encodedKey = split[:3] - if host not in hosts.split(','): # incorrect host - continue - if hostKeyType != keyType: # incorrect type of key - continue - try: - decodedKey = base64.decodestring(encodedKey) - except: - continue - if decodedKey == pubKey: - return 1 - else: - retVal = 2 - return retVal - -class SSHUserAuthClient(userauth.SSHUserAuthClient): - - def __init__(self, user, options, *args): - userauth.SSHUserAuthClient.__init__(self, user, *args) - self.keyAgent = None - self.options = options - self.usedFiles = [] - if not options.identitys: - options.identitys = ['~/.ssh/id_rsa', '~/.ssh/id_dsa'] - - def serviceStarted(self): - if 'SSH_AUTH_SOCK' in os.environ and not self.options['noagent']: - log.msg('using agent') - cc = protocol.ClientCreator(reactor, agent.SSHAgentClient) - d = cc.connectUNIX(os.environ['SSH_AUTH_SOCK']) - d.addCallback(self._setAgent) - d.addErrback(self._ebSetAgent) - else: - userauth.SSHUserAuthClient.serviceStarted(self) - - def serviceStopped(self): - if self.keyAgent: - self.keyAgent.transport.loseConnection() - self.keyAgent = None - - def _setAgent(self, a): - self.keyAgent = a - d = self.keyAgent.getPublicKeys() - d.addBoth(self._ebSetAgent) - return d - - def _ebSetAgent(self, f): - userauth.SSHUserAuthClient.serviceStarted(self) - - def _getPassword(self, prompt): - try: - oldout, oldin = sys.stdout, sys.stdin - sys.stdin = sys.stdout = open('/dev/tty','r+') - p=getpass.getpass(prompt) - sys.stdout,sys.stdin=oldout,oldin - return p - except (KeyboardInterrupt, IOError): - print - raise ConchError('PEBKAC') - - def getPassword(self, prompt = None): - if not prompt: - prompt = "%s@%s's password: " % (self.user, self.transport.transport.getPeer().host) - try: - p = self._getPassword(prompt) - return defer.succeed(p) - except ConchError: - return defer.fail() - - def getPublicKey(self): - if self.keyAgent: - blob = self.keyAgent.getPublicKey() - if blob: - return blob - files = [x for x in self.options.identitys if x not in self.usedFiles] - log.msg(str(self.options.identitys)) - log.msg(str(files)) - if not files: - return None - file = files[0] - log.msg(file) - self.usedFiles.append(file) - file = os.path.expanduser(file) - file += '.pub' - if not os.path.exists(file): - return self.getPublicKey() # try again - try: - return keys.getPublicKeyString(file) - except: - return self.getPublicKey() # try again - - def signData(self, publicKey, signData): - if not self.usedFiles: # agent key - return self.keyAgent.signData(publicKey, signData) - else: - return userauth.SSHUserAuthClient.signData(self, publicKey, signData) - - def getPrivateKey(self): - file = os.path.expanduser(self.usedFiles[-1]) - if not os.path.exists(file): - return None - try: - return defer.succeed(keys.getPrivateKeyObject(file)) - except keys.BadKeyError, e: - if e.args[0] == 'encrypted key with no passphrase': - for i in range(3): - prompt = "Enter passphrase for key '%s': " % \ - self.usedFiles[-1] - try: - p = self._getPassword(prompt) - return defer.succeed(keys.getPrivateKeyObject(file, passphrase = p)) - except (keys.BadKeyError, ConchError): - pass - return defer.fail(ConchError('bad password')) - raise - except KeyboardInterrupt: - print - reactor.stop() - - def getGenericAnswers(self, name, instruction, prompts): - responses = [] - try: - oldout, oldin = sys.stdout, sys.stdin - sys.stdin = sys.stdout = open('/dev/tty','r+') - if name: - print name - if instruction: - print instruction - for prompt, echo in prompts: - if echo: - responses.append(raw_input(prompt)) - else: - responses.append(getpass.getpass(prompt)) - finally: - sys.stdout,sys.stdin=oldout,oldin - return defer.succeed(responses) diff --git a/tools/buildbot/pylibs/twisted/conch/client/direct.py b/tools/buildbot/pylibs/twisted/conch/client/direct.py deleted file mode 100644 index eea27f4..0000000 --- a/tools/buildbot/pylibs/twisted/conch/client/direct.py +++ /dev/null @@ -1,124 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -import os - -from twisted.internet import defer, protocol, reactor -from twisted.conch import error -from twisted.conch.ssh import transport -from twisted.python import log - -from twisted.conch.client import unix - - - -class SSHClientFactory(protocol.ClientFactory): - - def __init__(self, d, options, verifyHostKey, userAuthObject): - self.d = d - self.options = options - self.verifyHostKey = verifyHostKey - self.userAuthObject = userAuthObject - - - def clientConnectionLost(self, connector, reason): - if self.options['reconnect']: - connector.connect() - - - def clientConnectionFailed(self, connector, reason): - if self.d is None: - return - d, self.d = self.d, None - d.errback(reason) - - - def buildProtocol(self, addr): - trans = SSHClientTransport(self) - if self.options['ciphers']: - trans.supportedCiphers = self.options['ciphers'] - if self.options['macs']: - trans.supportedMACs = self.options['macs'] - if self.options['compress']: - trans.supportedCompressions[0:1] = ['zlib'] - if self.options['host-key-algorithms']: - trans.supportedPublicKeys = self.options['host-key-algorithms'] - return trans - - - -class SSHClientTransport(transport.SSHClientTransport): - - def __init__(self, factory): - self.factory = factory - self.unixServer = None - - - def connectionLost(self, reason): - if self.unixServer: - d = self.unixServer.stopListening() - self.unixServer = None - else: - d = defer.succeed(None) - d.addCallback(lambda x: - transport.SSHClientTransport.connectionLost(self, reason)) - - - def receiveError(self, code, desc): - if self.factory.d is None: - return - d, self.factory.d = self.factory.d, None - d.errback(error.ConchError(desc, code)) - - - def sendDisconnect(self, code, reason): - if self.factory.d is None: - return - d, self.factory.d = self.factory.d, None - transport.SSHClientTransport.sendDisconnect(self, code, reason) - d.errback(error.ConchError(reason, code)) - - - def receiveDebug(self, alwaysDisplay, message, lang): - log.msg('Received Debug Message: %s' % message) - if alwaysDisplay: # XXX what should happen here? - print message - - - def verifyHostKey(self, pubKey, fingerprint): - return self.factory.verifyHostKey(self, self.transport.getPeer().host, pubKey, - fingerprint) - - - def setService(self, service): - log.msg('setting client server to %s' % service) - transport.SSHClientTransport.setService(self, service) - if service.name == 'ssh-connection': - # listen for UNIX - if not self.factory.options['nocache']: - user = self.factory.userAuthObject.user - peer = self.transport.getPeer() - filename = os.path.expanduser("~/.conch-%s-%s-%i" % (user, peer.host, peer.port)) - u = unix.SSHUnixServerFactory(service) - try: - self.unixServer = reactor.listenUNIX(filename, u, mode=0600, wantPID=1) - except: - if self.factory.d is not None: - d, self.factory.d = self.factory.d, None - d.errback(None) - if service.name != 'ssh-userauth' and self.factory.d is not None: - d, self.factory.d = self.factory.d, None - d.callback(None) - - - def connectionSecure(self): - self.requestService(self.factory.userAuthObject) - - - -def connect(host, port, options, verifyHostKey, userAuthObject): - d = defer.Deferred() - factory = SSHClientFactory(d, options, verifyHostKey, userAuthObject) - reactor.connectTCP(host, port, factory) - return d diff --git a/tools/buildbot/pylibs/twisted/conch/client/options.py b/tools/buildbot/pylibs/twisted/conch/client/options.py deleted file mode 100644 index 8907a81..0000000 --- a/tools/buildbot/pylibs/twisted/conch/client/options.py +++ /dev/null @@ -1,104 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -from twisted.conch.ssh.transport import SSHClientTransport, SSHCiphers -from twisted.python import usage - -import connect - -import sys - -class ConchOptions(usage.Options): - - optParameters = [['user', 'l', None, 'Log in using this user name.'], - ['identity', 'i', None], - ['ciphers', 'c', None], - ['macs', 'm', None], - ['connection-usage', 'K', None], - ['port', 'p', None, 'Connect to this port. Server must be on the same port.'], - ['option', 'o', None, 'Ignored OpenSSH options'], - ['host-key-algorithms', '', None], - ['known-hosts', '', None, 'File to check for host keys'], - ['user-authentications', '', None, 'Types of user authentications to use.'], - ['logfile', '', None, 'File to log to, or - for stdout'], - ] - - optFlags = [['version', 'V', 'Display version number only.'], - ['compress', 'C', 'Enable compression.'], - ['log', 'v', 'Enable logging (defaults to stderr)'], - ['nocache', 'I', 'Do not allow connection sharing over this connection.'], - ['nox11', 'x', 'Disable X11 connection forwarding (default)'], - ['agent', 'A', 'Enable authentication agent forwarding'], - ['noagent', 'a', 'Disable authentication agent forwarding (default)'], - ['reconnect', 'r', 'Reconnect to the server if the connection is lost.'], - ] - zsh_altArgDescr = {"connection-usage":"Connection types to use"} - #zsh_multiUse = ["foo", "bar"] - zsh_mutuallyExclusive = [("agent", "noagent")] - zsh_actions = {"user":"_users", - "ciphers":"_values -s , 'ciphers to choose from' %s" % - " ".join(SSHCiphers.cipherMap.keys()), - "macs":"_values -s , 'macs to choose from' %s" % - " ".join(SSHCiphers.macMap.keys()), - "host-key-algorithms":"_values -s , 'host key algorithms to choose from' %s" % - " ".join(SSHClientTransport.supportedPublicKeys), - "connection-usage":"_values -s , 'connection types to choose from' %s" % - " ".join(connect.connectTypes.keys()), - #"user-authentications":"_values -s , 'user authentication types to choose from' %s" % - # " ".join(???), - } - #zsh_actionDescr = {"logfile":"log file name", "random":"random seed"} - # user, host, or user@host completion similar to zsh's ssh completion - zsh_extras = ['1:host | user@host:{_ssh;if compset -P "*@"; then _wanted hosts expl "remote host name" _ssh_hosts && ret=0 elif compset -S "@*"; then _wanted users expl "login name" _ssh_users -S "" && ret=0 else if (( $+opt_args[-l] )); then tmp=() else tmp=( "users:login name:_ssh_users -qS@" ) fi; _alternative "hosts:remote host name:_ssh_hosts" "$tmp[@]" && ret=0 fi}'] - - def __init__(self, *args, **kw): - usage.Options.__init__(self, *args, **kw) - self.identitys = [] - self.conns = None - - def opt_identity(self, i): - """Identity for public-key authentication""" - self.identitys.append(i) - - def opt_ciphers(self, ciphers): - "Select encryption algorithms" - ciphers = ciphers.split(',') - for cipher in ciphers: - if not SSHCiphers.cipherMap.has_key(cipher): - sys.exit("Unknown cipher type '%s'" % cipher) - self['ciphers'] = ciphers - - - def opt_macs(self, macs): - "Specify MAC algorithms" - macs = macs.split(',') - for mac in macs: - if not SSHCiphers.macMap.has_key(mac): - sys.exit("Unknown mac type '%s'" % mac) - self['macs'] = macs - - def opt_host_key_algorithms(self, hkas): - "Select host key algorithms" - hkas = hkas.split(',') - for hka in hkas: - if hka not in SSHClientTransport.supportedPublicKeys: - sys.exit("Unknown host key type '%s'" % hka) - self['host-key-algorithms'] = hkas - - def opt_user_authentications(self, uas): - "Choose how to authenticate to the remote server" - self['user-authentications'] = uas.split(',') - - def opt_connection_usage(self, conns): - conns = conns.split(',') - connTypes = connect.connectTypes.keys() - for conn in conns: - if conn not in connTypes: - sys.exit("Unknown connection type '%s'" % conn) - self.conns = conns - -# def opt_compress(self): -# "Enable compression" -# self.enableCompression = 1 -# SSHClientTransport.supportedCompressions[0:1] = ['zlib'] diff --git a/tools/buildbot/pylibs/twisted/conch/client/unix.py b/tools/buildbot/pylibs/twisted/conch/client/unix.py deleted file mode 100644 index 721aeb0..0000000 --- a/tools/buildbot/pylibs/twisted/conch/client/unix.py +++ /dev/null @@ -1,396 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -from twisted.conch.error import ConchError -from twisted.conch.ssh import channel, connection -from twisted.internet import defer, protocol, reactor -from twisted.python import log -from twisted.spread import banana - -import os, stat, pickle -import types # this is for evil - -class SSHUnixClientFactory(protocol.ClientFactory): -# noisy = 1 - - def __init__(self, d, options, userAuthObject): - self.d = d - self.options = options - self.userAuthObject = userAuthObject - - def clientConnectionLost(self, connector, reason): - if self.options['reconnect']: - connector.connect() - #log.err(reason) - if not self.d: return - d = self.d - self.d = None - d.errback(reason) - - - def clientConnectionFailed(self, connector, reason): - #try: - # os.unlink(connector.transport.addr) - #except: - # pass - #log.err(reason) - if not self.d: return - d = self.d - self.d = None - d.errback(reason) - #reactor.connectTCP(options['host'], options['port'], SSHClientFactory()) - - def startedConnecting(self, connector): - fd = connector.transport.fileno() - stats = os.fstat(fd) - try: - filestats = os.stat(connector.transport.addr) - except: - connector.stopConnecting() - return - if stat.S_IMODE(filestats[0]) != 0600: - log.msg("socket mode is not 0600: %s" % oct(stat.S_IMODE(stats[0]))) - elif filestats[4] != os.getuid(): - log.msg("socket not owned by us: %s" % stats[4]) - elif filestats[5] != os.getgid(): - log.msg("socket not owned by our group: %s" % stats[5]) - # XXX reenable this when i can fix it for cygwin - #elif filestats[-3:] != stats[-3:]: - # log.msg("socket doesn't have same create times") - else: - log.msg('conecting OK') - return - connector.stopConnecting() - - def buildProtocol(self, addr): - # here comes the EVIL - obj = self.userAuthObject.instance - bases = [] - for base in obj.__class__.__bases__: - if base == connection.SSHConnection: - bases.append(SSHUnixClientProtocol) - else: - bases.append(base) - newClass = types.ClassType(obj.__class__.__name__, tuple(bases), obj.__class__.__dict__) - obj.__class__ = newClass - SSHUnixClientProtocol.__init__(obj) - log.msg('returning %s' % obj) - if self.d: - d = self.d - self.d = None - d.callback(None) - return obj - -class SSHUnixServerFactory(protocol.Factory): - def __init__(self, conn): - self.conn = conn - - def buildProtocol(self, addr): - return SSHUnixServerProtocol(self.conn) - -class SSHUnixProtocol(banana.Banana): - - knownDialects = ['none'] - - def __init__(self): - banana.Banana.__init__(self) - self.deferredQueue = [] - self.deferreds = {} - self.deferredID = 0 - - def connectionMade(self): - log.msg('connection made %s' % self) - banana.Banana.connectionMade(self) - - def expressionReceived(self, lst): - vocabName = lst[0] - fn = "msg_%s" % vocabName - func = getattr(self, fn) - func(lst[1:]) - - def sendMessage(self, vocabName, *tup): - self.sendEncoded([vocabName] + list(tup)) - - def returnDeferredLocal(self): - d = defer.Deferred() - self.deferredQueue.append(d) - return d - - def returnDeferredWire(self, d): - di = self.deferredID - self.deferredID += 1 - self.sendMessage('returnDeferred', di) - d.addCallback(self._cbDeferred, di) - d.addErrback(self._ebDeferred, di) - - def _cbDeferred(self, result, di): - self.sendMessage('callbackDeferred', di, pickle.dumps(result)) - - def _ebDeferred(self, reason, di): - self.sendMessage('errbackDeferred', di, pickle.dumps(reason)) - - def msg_returnDeferred(self, lst): - deferredID = lst[0] - self.deferreds[deferredID] = self.deferredQueue.pop(0) - - def msg_callbackDeferred(self, lst): - deferredID, result = lst - d = self.deferreds[deferredID] - del self.deferreds[deferredID] - d.callback(pickle.loads(result)) - - def msg_errbackDeferred(self, lst): - deferredID, result = lst - d = self.deferreds[deferredID] - del self.deferreds[deferredID] - d.errback(pickle.loads(result)) - -class SSHUnixClientProtocol(SSHUnixProtocol): - - def __init__(self): - SSHUnixProtocol.__init__(self) - self.isClient = 1 - self.channelQueue = [] - self.channels = {} - - def logPrefix(self): - return "SSHUnixClientProtocol (%i) on %s" % (id(self), self.transport.logPrefix()) - - def connectionReady(self): - log.msg('connection ready') - self.serviceStarted() - - def connectionLost(self, reason): - self.serviceStopped() - - def requestRemoteForwarding(self, remotePort, hostport): - self.sendMessage('requestRemoteForwarding', remotePort, hostport) - - def cancelRemoteForwarding(self, remotePort): - self.sendMessage('cancelRemoteForwarding', remotePort) - - def sendGlobalRequest(self, request, data, wantReply = 0): - self.sendMessage('sendGlobalRequest', request, data, wantReply) - if wantReply: - return self.returnDeferredLocal() - - def openChannel(self, channel, extra = ''): - self.channelQueue.append(channel) - channel.conn = self - self.sendMessage('openChannel', channel.name, - channel.localWindowSize, - channel.localMaxPacket, extra) - - def sendRequest(self, channel, requestType, data, wantReply = 0): - self.sendMessage('sendRequest', channel.id, requestType, data, wantReply) - if wantReply: - return self.returnDeferredLocal() - - def adjustWindow(self, channel, bytesToAdd): - self.sendMessage('adjustWindow', channel.id, bytesToAdd) - - def sendData(self, channel, data): - self.sendMessage('sendData', channel.id, data) - - def sendExtendedData(self, channel, dataType, data): - self.sendMessage('sendExtendedData', channel.id, data) - - def sendEOF(self, channel): - self.sendMessage('sendEOF', channel.id) - - def sendClose(self, channel): - self.sendMessage('sendClose', channel.id) - - def msg_channelID(self, lst): - channelID = lst[0] - self.channels[channelID] = self.channelQueue.pop(0) - self.channels[channelID].id = channelID - - def msg_channelOpen(self, lst): - channelID, remoteWindow, remoteMax, specificData = lst - channel = self.channels[channelID] - channel.remoteWindowLeft = remoteWindow - channel.remoteMaxPacket = remoteMax - channel.channelOpen(specificData) - - def msg_openFailed(self, lst): - channelID, reason = lst - self.channels[channelID].openFailed(pickle.loads(reason)) - del self.channels[channelID] - - def msg_addWindowBytes(self, lst): - channelID, bytes = lst - self.channels[channelID].addWindowBytes(bytes) - - def msg_requestReceived(self, lst): - channelID, requestType, data = lst - d = defer.maybeDeferred(self.channels[channelID].requestReceived, requestType, data) - self.returnDeferredWire(d) - - def msg_dataReceived(self, lst): - channelID, data = lst - self.channels[channelID].dataReceived(data) - - def msg_extReceived(self, lst): - channelID, dataType, data = lst - self.channels[channelID].extReceived(dataType, data) - - def msg_eofReceived(self, lst): - channelID = lst[0] - self.channels[channelID].eofReceived() - - def msg_closeReceived(self, lst): - channelID = lst[0] - channel = self.channels[channelID] - channel.remoteClosed = 1 - channel.closeReceived() - - def msg_closed(self, lst): - channelID = lst[0] - channel = self.channels[channelID] - self.channelClosed(channel) - - def channelClosed(self, channel): - channel.localClosed = channel.remoteClosed = 1 - del self.channels[channel.id] - log.callWithLogger(channel, channel.closed) - - # just in case the user doesn't override - - def serviceStarted(self): - pass - - def serviceStopped(self): - pass - -class SSHUnixServerProtocol(SSHUnixProtocol): - - def __init__(self, conn): - SSHUnixProtocol.__init__(self) - self.isClient = 0 - self.conn = conn - - def connectionLost(self, reason): - for channel in self.conn.channels.values(): - if isinstance(channel, SSHUnixChannel) and channel.unix == self: - log.msg('forcibly closing %s' % channel) - try: - self.conn.sendClose(channel) - except: - pass - - def haveChannel(self, channelID): - return self.conn.channels.has_key(channelID) - - def getChannel(self, channelID): - channel = self.conn.channels[channelID] - if not isinstance(channel, SSHUnixChannel): - raise ConchError('nice try bub') - return channel - - def msg_requestRemoteForwarding(self, lst): - remotePort, hostport = lst - hostport = tuple(hostport) - self.conn.requestRemoteForwarding(remotePort, hostport) - - def msg_cancelRemoteForwarding(self, lst): - [remotePort] = lst - self.conn.cancelRemoteForwarding(remotePort) - - def msg_sendGlobalRequest(self, lst): - requestName, data, wantReply = lst - d = self.conn.sendGlobalRequest(requestName, data, wantReply) - if wantReply: - self.returnDeferredWire(d) - - def msg_openChannel(self, lst): - name, windowSize, maxPacket, extra = lst - channel = SSHUnixChannel(self, name, windowSize, maxPacket) - self.conn.openChannel(channel, extra) - self.sendMessage('channelID', channel.id) - - def msg_sendRequest(self, lst): - cn, requestType, data, wantReply = lst - if not self.haveChannel(cn): - if wantReply: - self.returnDeferredWire(defer.fail(ConchError("no channel"))) - channel = self.getChannel(cn) - d = self.conn.sendRequest(channel, requestType, data, wantReply) - if wantReply: - self.returnDeferredWire(d) - - def msg_adjustWindow(self, lst): - cn, bytesToAdd = lst - if not self.haveChannel(cn): return - channel = self.getChannel(cn) - self.conn.adjustWindow(channel, bytesToAdd) - - def msg_sendData(self, lst): - cn, data = lst - if not self.haveChannel(cn): return - channel = self.getChannel(cn) - self.conn.sendData(channel, data) - - def msg_sendExtended(self, lst): - cn, dataType, data = lst - if not self.haveChannel(cn): return - channel = self.getChannel(cn) - self.conn.sendExtendedData(channel, dataType, data) - - def msg_sendEOF(self, lst): - (cn, ) = lst - if not self.haveChannel(cn): return - channel = self.getChannel(cn) - self.conn.sendEOF(channel) - - def msg_sendClose(self, lst): - (cn, ) = lst - if not self.haveChannel(cn): return - channel = self.getChannel(cn) - self.conn.sendClose(channel) - -class SSHUnixChannel(channel.SSHChannel): - def __init__(self, unix, name, windowSize, maxPacket): - channel.SSHChannel.__init__(self, windowSize, maxPacket, conn = unix.conn) - self.unix = unix - self.name = name - - def channelOpen(self, specificData): - self.unix.sendMessage('channelOpen', self.id, self.remoteWindowLeft, - self.remoteMaxPacket, specificData) - - def openFailed(self, reason): - self.unix.sendMessage('openFailed', self.id, pickle.dumps(reason)) - - def addWindowBytes(self, bytes): - self.unix.sendMessage('addWindowBytes', self.id, bytes) - - def dataReceived(self, data): - self.unix.sendMessage('dataReceived', self.id, data) - - def requestReceived(self, reqType, data): - self.unix.sendMessage('requestReceived', self.id, reqType, data) - return self.unix.returnDeferredLocal() - - def extReceived(self, dataType, data): - self.unix.sendMessage('extReceived', self.id, dataType, data) - - def eofReceived(self): - self.unix.sendMessage('eofReceived', self.id) - - def closeReceived(self): - self.unix.sendMessage('closeReceived', self.id) - - def closed(self): - self.unix.sendMessage('closed', self.id) - -def connect(host, port, options, verifyHostKey, userAuthObject): - if options['nocache']: - return defer.fail(ConchError('not using connection caching')) - d = defer.Deferred() - filename = os.path.expanduser("~/.conch-%s-%s-%i" % (userAuthObject.user, host, port)) - factory = SSHUnixClientFactory(d, options, userAuthObject) - reactor.connectUNIX(filename, factory, timeout=2, checkPID=1) - return d diff --git a/tools/buildbot/pylibs/twisted/conch/error.py b/tools/buildbot/pylibs/twisted/conch/error.py deleted file mode 100644 index e1e887f..0000000 --- a/tools/buildbot/pylibs/twisted/conch/error.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -# Paul, why didn't you check in an error.py? - -""" -An error to represent bad things happening in Conch. - -Maintainer: U{Paul Swartz} -""" - -class ConchError(Exception): - def __init__(self, value, data = None): - Exception.__init__(self, value, data) - self.value = value - self.data = data - -class NotEnoughAuthentication(Exception): - """This is thrown if the authentication is valid, but is not enough to - successfully verify the user. i.e. don't retry this type of - authentication, try another one. - """ - -class ValidPublicKey(Exception): - """This is thrown during the authentication process if the public key - is valid for the user. - """ - -class IgnoreAuthentication(Exception): - """This is thrown to let the UserAuthServer know it doesn't need to handle - the authentication anymore. - """ diff --git a/tools/buildbot/pylibs/twisted/conch/insults/__init__.py b/tools/buildbot/pylibs/twisted/conch/insults/__init__.py deleted file mode 100644 index 3d83876..0000000 --- a/tools/buildbot/pylibs/twisted/conch/insults/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -""" -Insults: a replacement for Curses/S-Lang. - -Very basic at the moment.""" diff --git a/tools/buildbot/pylibs/twisted/conch/insults/client.py b/tools/buildbot/pylibs/twisted/conch/insults/client.py deleted file mode 100644 index 89c79cd..0000000 --- a/tools/buildbot/pylibs/twisted/conch/insults/client.py +++ /dev/null @@ -1,138 +0,0 @@ -""" -You don't really want to use this module. Try insults.py instead. -""" - -from twisted.internet import protocol - -class InsultsClient(protocol.Protocol): - - escapeTimeout = 0.2 - - def __init__(self): - self.width = self.height = None - self.xpos = self.ypos = 0 - self.commandQueue = [] - self.inEscape = '' - - def setSize(self, width, height): - call = 0 - if self.width: - call = 1 - self.width = width - self.height = height - if call: - self.windowSizeChanged() - - def dataReceived(self, data): - from twisted.internet import reactor - for ch in data: - if ch == '\x1b': - if self.inEscape: - self.keyReceived(ch) - self.inEscape = '' - else: - self.inEscape = ch - self.escapeCall = reactor.callLater(self.escapeTimeout, - self.endEscape) - elif ch in 'ABCD' and self.inEscape: - self.inEscape = '' - self.escapeCall.cancel() - if ch == 'A': - self.keyReceived('') - elif ch == 'B': - self.keyReceived('') - elif ch == 'C': - self.keyReceived('') - elif ch == 'D': - self.keyReceived('') - elif self.inEscape: - self.inEscape += ch - else: - self.keyReceived(ch) - - def endEscape(self): - ch = self.inEscape - self.inEscape = '' - self.keyReceived(ch) - - def initScreen(self): - self.transport.write('\x1b=\x1b[?1h') - - def gotoXY(self, x, y): - """Go to a position on the screen. - """ - self.xpos = x - self.ypos = y - self.commandQueue.append(('gotoxy', x, y)) - - def writeCh(self, ch): - """Write a character to the screen. If we're at the end of the row, - ignore the write. - """ - if self.xpos < self.width - 1: - self.commandQueue.append(('write', ch)) - self.xpos += 1 - - def writeStr(self, s): - """Write a string to the screen. This does not wrap a the edge of the - screen, and stops at \\r and \\n. - """ - s = s[:self.width-self.xpos] - if '\n' in s: - s=s[:s.find('\n')] - if '\r' in s: - s=s[:s.find('\r')] - self.commandQueue.append(('write', s)) - self.xpos += len(s) - - def eraseToLine(self): - """Erase from the current position to the end of the line. - """ - self.commandQueue.append(('eraseeol',)) - - def eraseToScreen(self): - """Erase from the current position to the end of the screen. - """ - self.commandQueue.append(('eraseeos',)) - - def clearScreen(self): - """Clear the screen, and return the cursor to 0, 0. - """ - self.commandQueue = [('cls',)] - self.xpos = self.ypos = 0 - - def setAttributes(self, *attrs): - """Set the attributes for drawing on the screen. - """ - self.commandQueue.append(('attributes', attrs)) - - def refresh(self): - """Redraw the screen. - """ - redraw = '' - for command in self.commandQueue: - if command[0] == 'gotoxy': - redraw += '\x1b[%i;%iH' % (command[2]+1, command[1]+1) - elif command[0] == 'write': - redraw += command[1] - elif command[0] == 'eraseeol': - redraw += '\x1b[0K' - elif command[0] == 'eraseeos': - redraw += '\x1b[OJ' - elif command[0] == 'cls': - redraw += '\x1b[H\x1b[J' - elif command[0] == 'attributes': - redraw += '\x1b[%sm' % ';'.join(map(str, command[1])) - else: - print command - self.commandQueue = [] - self.transport.write(redraw) - - def windowSizeChanged(self): - """Called when the size of the window changes. - Might want to redraw the screen here, or something. - """ - - def keyReceived(self, key): - """Called when the user hits a key. - """ diff --git a/tools/buildbot/pylibs/twisted/conch/insults/colors.py b/tools/buildbot/pylibs/twisted/conch/insults/colors.py deleted file mode 100644 index c12ab16..0000000 --- a/tools/buildbot/pylibs/twisted/conch/insults/colors.py +++ /dev/null @@ -1,29 +0,0 @@ -""" -You don't really want to use this module. Try helper.py instead. -""" - -CLEAR = 0 -BOLD = 1 -DIM = 2 -ITALIC = 3 -UNDERSCORE = 4 -BLINK_SLOW = 5 -BLINK_FAST = 6 -REVERSE = 7 -CONCEALED = 8 -FG_BLACK = 30 -FG_RED = 31 -FG_GREEN = 32 -FG_YELLOW = 33 -FG_BLUE = 34 -FG_MAGENTA = 35 -FG_CYAN = 36 -FG_WHITE = 37 -BG_BLACK = 40 -BG_RED = 41 -BG_GREEN = 42 -BG_YELLOW = 43 -BG_BLUE = 44 -BG_MAGENTA = 45 -BG_CYAN = 46 -BG_WHITE = 47 diff --git a/tools/buildbot/pylibs/twisted/conch/insults/helper.py b/tools/buildbot/pylibs/twisted/conch/insults/helper.py deleted file mode 100644 index 5dfa7bb..0000000 --- a/tools/buildbot/pylibs/twisted/conch/insults/helper.py +++ /dev/null @@ -1,450 +0,0 @@ -# -*- test-case-name: twisted.conch.test.test_helper -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Partial in-memory terminal emulator - -@author: U{Jp Calderone} -""" - -import re, string - -from zope.interface import implements - -from twisted.internet import defer, protocol, reactor -from twisted.python import log - -from twisted.conch.insults import insults - -FOREGROUND = 30 -BACKGROUND = 40 -BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, N_COLORS = range(9) - -class CharacterAttribute: - """Represents the attributes of a single character. - - Character set, intensity, underlinedness, blinkitude, video - reversal, as well as foreground and background colors made up a - character's attributes. - """ - def __init__(self, charset=insults.G0, - bold=False, underline=False, - blink=False, reverseVideo=False, - foreground=WHITE, background=BLACK, - - _subtracting=False): - self.charset = charset - self.bold = bold - self.underline = underline - self.blink = blink - self.reverseVideo = reverseVideo - self.foreground = foreground - self.background = background - - self._subtracting = _subtracting - - def __eq__(self, other): - return vars(self) == vars(other) - - def __ne__(self, other): - return not self.__eq__(other) - - def copy(self): - c = self.__class__() - c.__dict__.update(vars(self)) - return c - - def wantOne(self, **kw): - k, v = kw.popitem() - if getattr(self, k) != v: - attr = self.copy() - attr._subtracting = not v - setattr(attr, k, v) - return attr - else: - return self.copy() - - def toVT102(self): - # Spit out a vt102 control sequence that will set up - # all the attributes set here. Except charset. - attrs = [] - if self._subtracting: - attrs.append(0) - if self.bold: - attrs.append(insults.BOLD) - if self.underline: - attrs.append(insults.UNDERLINE) - if self.blink: - attrs.append(insults.BLINK) - if self.reverseVideo: - attrs.append(insults.REVERSE_VIDEO) - if self.foreground != WHITE: - attrs.append(FOREGROUND + self.foreground) - if self.background != BLACK: - attrs.append(BACKGROUND + self.background) - if attrs: - return '\x1b[' + ';'.join(map(str, attrs)) + 'm' - return '' - -# XXX - need to support scroll regions and scroll history -class TerminalBuffer(protocol.Protocol): - """ - An in-memory terminal emulator. - """ - implements(insults.ITerminalTransport) - - for keyID in ('UP_ARROW', 'DOWN_ARROW', 'RIGHT_ARROW', 'LEFT_ARROW', - 'HOME', 'INSERT', 'DELETE', 'END', 'PGUP', 'PGDN', - 'F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'F9', - 'F10', 'F11', 'F12'): - exec '%s = object()' % (keyID,) - - TAB = '\t' - BACKSPACE = '\x7f' - - width = 80 - height = 24 - - fill = ' ' - void = object() - - def getCharacter(self, x, y): - return self.lines[y][x] - - def connectionMade(self): - self.reset() - - def write(self, bytes): - """ - Add the given printable bytes to the terminal. - - Line feeds in C{bytes} will be replaced with carriage return / line - feed pairs. - """ - for b in bytes.replace('\n', '\r\n'): - self.insertAtCursor(b) - - def _currentCharacterAttributes(self): - return CharacterAttribute(self.activeCharset, **self.graphicRendition) - - def insertAtCursor(self, b): - """ - Add one byte to the terminal at the cursor and make consequent state - updates. - - If b is a carriage return, move the cursor to the beginning of the - current row. - - If b is a line feed, move the cursor to the next row or scroll down if - the cursor is already in the last row. - - Otherwise, if b is printable, put it at the cursor position (inserting - or overwriting as dictated by the current mode) and move the cursor. - """ - if b == '\r': - self.x = 0 - elif b == '\n': - self._scrollDown() - elif b in string.printable: - if self.x >= self.width: - self.nextLine() - ch = (b, self._currentCharacterAttributes()) - if self.modes.get(insults.modes.IRM): - self.lines[self.y][self.x:self.x] = [ch] - self.lines[self.y].pop() - else: - self.lines[self.y][self.x] = ch - self.x += 1 - - def _emptyLine(self, width): - return [(self.void, self._currentCharacterAttributes()) for i in xrange(width)] - - def _scrollDown(self): - self.y += 1 - if self.y >= self.height: - self.y -= 1 - del self.lines[0] - self.lines.append(self._emptyLine(self.width)) - - def _scrollUp(self): - self.y -= 1 - if self.y < 0: - self.y = 0 - del self.lines[-1] - self.lines.insert(0, self._emptyLine(self.width)) - - def cursorUp(self, n=1): - self.y = max(0, self.y - n) - - def cursorDown(self, n=1): - self.y = min(self.height - 1, self.y + n) - - def cursorBackward(self, n=1): - self.x = max(0, self.x - n) - - def cursorForward(self, n=1): - self.x = min(self.width, self.x + n) - - def cursorPosition(self, column, line): - self.x = column - self.y = line - - def cursorHome(self): - self.x = self.home.x - self.y = self.home.y - - def index(self): - self._scrollDown() - - def reverseIndex(self): - self._scrollUp() - - def nextLine(self): - """ - Update the cursor position attributes and scroll down if appropriate. - """ - self.x = 0 - self._scrollDown() - - def saveCursor(self): - self._savedCursor = (self.x, self.y) - - def restoreCursor(self): - self.x, self.y = self._savedCursor - del self._savedCursor - - def setModes(self, modes): - for m in modes: - self.modes[m] = True - - def resetModes(self, modes): - for m in modes: - try: - del self.modes[m] - except KeyError: - pass - - - def setPrivateModes(self, modes): - """ - Enable the given modes. - - Track which modes have been enabled so that the implementations of - other L{insults.ITerminalTransport} methods can be properly implemented - to respect these settings. - - @see: L{resetPrivateModes} - @see: L{insults.ITerminalTransport.setPrivateModes} - """ - for m in modes: - self.privateModes[m] = True - - - def resetPrivateModes(self, modes): - """ - Disable the given modes. - - @see: L{setPrivateModes} - @see: L{insults.ITerminalTransport.resetPrivateModes} - """ - for m in modes: - try: - del self.privateModes[m] - except KeyError: - pass - - - def applicationKeypadMode(self): - self.keypadMode = 'app' - - def numericKeypadMode(self): - self.keypadMode = 'num' - - def selectCharacterSet(self, charSet, which): - self.charsets[which] = charSet - - def shiftIn(self): - self.activeCharset = insults.G0 - - def shiftOut(self): - self.activeCharset = insults.G1 - - def singleShift2(self): - oldActiveCharset = self.activeCharset - self.activeCharset = insults.G2 - f = self.insertAtCursor - def insertAtCursor(b): - f(b) - del self.insertAtCursor - self.activeCharset = oldActiveCharset - self.insertAtCursor = insertAtCursor - - def singleShift3(self): - oldActiveCharset = self.activeCharset - self.activeCharset = insults.G3 - f = self.insertAtCursor - def insertAtCursor(b): - f(b) - del self.insertAtCursor - self.activeCharset = oldActiveCharset - self.insertAtCursor = insertAtCursor - - def selectGraphicRendition(self, *attributes): - for a in attributes: - if a == insults.NORMAL: - self.graphicRendition = { - 'bold': False, - 'underline': False, - 'blink': False, - 'reverseVideo': False, - 'foreground': WHITE, - 'background': BLACK} - elif a == insults.BOLD: - self.graphicRendition['bold'] = True - elif a == insults.UNDERLINE: - self.graphicRendition['underline'] = True - elif a == insults.BLINK: - self.graphicRendition['blink'] = True - elif a == insults.REVERSE_VIDEO: - self.graphicRendition['reverseVideo'] = True - else: - try: - v = int(a) - except ValueError: - log.msg("Unknown graphic rendition attribute: " + repr(a)) - else: - if FOREGROUND <= v <= FOREGROUND + N_COLORS: - self.graphicRendition['foreground'] = v - FOREGROUND - elif BACKGROUND <= v <= BACKGROUND + N_COLORS: - self.graphicRendition['background'] = v - BACKGROUND - else: - log.msg("Unknown graphic rendition attribute: " + repr(a)) - - def eraseLine(self): - self.lines[self.y] = self._emptyLine(self.width) - - def eraseToLineEnd(self): - width = self.width - self.x - self.lines[self.y][self.x:] = self._emptyLine(width) - - def eraseToLineBeginning(self): - self.lines[self.y][:self.x + 1] = self._emptyLine(self.x + 1) - - def eraseDisplay(self): - self.lines = [self._emptyLine(self.width) for i in xrange(self.height)] - - def eraseToDisplayEnd(self): - self.eraseToLineEnd() - height = self.height - self.y - 1 - self.lines[self.y + 1:] = [self._emptyLine(self.width) for i in range(height)] - - def eraseToDisplayBeginning(self): - self.eraseToLineBeginning() - self.lines[:self.y] = [self._emptyLine(self.width) for i in range(self.y)] - - def deleteCharacter(self, n=1): - del self.lines[self.y][self.x:self.x+n] - self.lines[self.y].extend(self._emptyLine(min(self.width - self.x, n))) - - def insertLine(self, n=1): - self.lines[self.y:self.y] = [self._emptyLine(self.width) for i in range(n)] - del self.lines[self.height:] - - def deleteLine(self, n=1): - del self.lines[self.y:self.y+n] - self.lines.extend([self._emptyLine(self.width) for i in range(n)]) - - def reportCursorPosition(self): - return (self.x, self.y) - - def reset(self): - self.home = insults.Vector(0, 0) - self.x = self.y = 0 - self.modes = {} - self.privateModes = {} - self.setPrivateModes([insults.privateModes.AUTO_WRAP, - insults.privateModes.CURSOR_MODE]) - self.numericKeypad = 'app' - self.activeCharset = insults.G0 - self.graphicRendition = { - 'bold': False, - 'underline': False, - 'blink': False, - 'reverseVideo': False, - 'foreground': WHITE, - 'background': BLACK} - self.charsets = { - insults.G0: insults.CS_US, - insults.G1: insults.CS_US, - insults.G2: insults.CS_ALTERNATE, - insults.G3: insults.CS_ALTERNATE_SPECIAL} - self.eraseDisplay() - - def unhandledControlSequence(self, buf): - print 'Could not handle', repr(buf) - - def __str__(self): - lines = [] - for L in self.lines: - buf = [] - length = 0 - for (ch, attr) in L: - if ch is not self.void: - buf.append(ch) - length = len(buf) - else: - buf.append(self.fill) - lines.append(''.join(buf[:length])) - return '\n'.join(lines) - -class ExpectationTimeout(Exception): - pass - -class ExpectableBuffer(TerminalBuffer): - _mark = 0 - - def connectionMade(self): - TerminalBuffer.connectionMade(self) - self._expecting = [] - - def write(self, bytes): - TerminalBuffer.write(self, bytes) - self._checkExpected() - - def cursorHome(self): - TerminalBuffer.cursorHome(self) - self._mark = 0 - - def _timeoutExpected(self, d): - d.errback(ExpectationTimeout()) - self._checkExpected() - - def _checkExpected(self): - s = str(self)[self._mark:] - while self._expecting: - expr, timer, deferred = self._expecting[0] - if timer and not timer.active(): - del self._expecting[0] - continue - for match in expr.finditer(s): - if timer: - timer.cancel() - del self._expecting[0] - self._mark += match.end() - s = s[match.end():] - deferred.callback(match) - break - else: - return - - def expect(self, expression, timeout=None, scheduler=reactor): - d = defer.Deferred() - timer = None - if timeout: - timer = scheduler.callLater(timeout, self._timeoutExpected, d) - self._expecting.append((re.compile(expression), timer, d)) - self._checkExpected() - return d - -__all__ = ['CharacterAttribute', 'TerminalBuffer', 'ExpectableBuffer'] diff --git a/tools/buildbot/pylibs/twisted/conch/insults/insults.py b/tools/buildbot/pylibs/twisted/conch/insults/insults.py deleted file mode 100644 index 121a8fb..0000000 --- a/tools/buildbot/pylibs/twisted/conch/insults/insults.py +++ /dev/null @@ -1,1067 +0,0 @@ -# -*- test-case-name: twisted.conch.test.test_insults -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -VT102 and VT220 terminal manipulation. - -@author: U{Jp Calderone} -""" - -from zope.interface import implements, Interface - -from twisted.internet import protocol, defer, interfaces as iinternet - -class ITerminalProtocol(Interface): - def makeConnection(transport): - """Called with an L{ITerminalTransport} when a connection is established. - """ - - def keystrokeReceived(keyID, modifier): - """A keystroke was received. - - Each keystroke corresponds to one invocation of this method. - keyID is a string identifier for that key. Printable characters - are represented by themselves. Control keys, such as arrows and - function keys, are represented with symbolic constants on - L{ServerProtocol}. - """ - - def terminalSize(width, height): - """Called to indicate the size of the terminal. - - A terminal of 80x24 should be assumed if this method is not - called. This method might not be called for real terminals. - """ - - def unhandledControlSequence(seq): - """Called when an unsupported control sequence is received. - - @type seq: C{str} - @param seq: The whole control sequence which could not be interpreted. - """ - - def connectionLost(reason): - """Called when the connection has been lost. - - reason is a Failure describing why. - """ - -class TerminalProtocol(object): - implements(ITerminalProtocol) - - def makeConnection(self, terminal): - # assert ITerminalTransport.providedBy(transport), "TerminalProtocol.makeConnection must be passed an ITerminalTransport implementor" - self.terminal = terminal - self.connectionMade() - - def connectionMade(self): - """Called after a connection has been established. - """ - - def keystrokeReceived(self, keyID, modifier): - pass - - def terminalSize(self, width, height): - pass - - def unhandledControlSequence(self, seq): - pass - - def connectionLost(self, reason): - pass - -class ITerminalTransport(iinternet.ITransport): - def cursorUp(n=1): - """Move the cursor up n lines. - """ - - def cursorDown(n=1): - """Move the cursor down n lines. - """ - - def cursorForward(n=1): - """Move the cursor right n columns. - """ - - def cursorBackward(n=1): - """Move the cursor left n columns. - """ - - def cursorPosition(column, line): - """Move the cursor to the given line and column. - """ - - def cursorHome(): - """Move the cursor home. - """ - - def index(): - """Move the cursor down one line, performing scrolling if necessary. - """ - - def reverseIndex(): - """Move the cursor up one line, performing scrolling if necessary. - """ - - def nextLine(): - """Move the cursor to the first position on the next line, performing scrolling if necessary. - """ - - def saveCursor(): - """Save the cursor position, character attribute, character set, and origin mode selection. - """ - - def restoreCursor(): - """Restore the previously saved cursor position, character attribute, character set, and origin mode selection. - - If no cursor state was previously saved, move the cursor to the home position. - """ - - def setModes(modes): - """Set the given modes on the terminal. - """ - - def resetModes(mode): - """Reset the given modes on the terminal. - """ - - - def setPrivateModes(modes): - """ - Set the given DEC private modes on the terminal. - """ - - - def resetPrivateModes(modes): - """ - Reset the given DEC private modes on the terminal. - """ - - - def applicationKeypadMode(): - """Cause keypad to generate control functions. - - Cursor key mode selects the type of characters generated by cursor keys. - """ - - def numericKeypadMode(): - """Cause keypad to generate normal characters. - """ - - def selectCharacterSet(charSet, which): - """Select a character set. - - charSet should be one of CS_US, CS_UK, CS_DRAWING, CS_ALTERNATE, or - CS_ALTERNATE_SPECIAL. - - which should be one of G0 or G1. - """ - - def shiftIn(): - """Activate the G0 character set. - """ - - def shiftOut(): - """Activate the G1 character set. - """ - - def singleShift2(): - """Shift to the G2 character set for a single character. - """ - - def singleShift3(): - """Shift to the G3 character set for a single character. - """ - - def selectGraphicRendition(*attributes): - """Enabled one or more character attributes. - - Arguments should be one or more of UNDERLINE, REVERSE_VIDEO, BLINK, or BOLD. - NORMAL may also be specified to disable all character attributes. - """ - - def horizontalTabulationSet(): - """Set a tab stop at the current cursor position. - """ - - def tabulationClear(): - """Clear the tab stop at the current cursor position. - """ - - def tabulationClearAll(): - """Clear all tab stops. - """ - - def doubleHeightLine(top=True): - """Make the current line the top or bottom half of a double-height, double-width line. - - If top is True, the current line is the top half. Otherwise, it is the bottom half. - """ - - def singleWidthLine(): - """Make the current line a single-width, single-height line. - """ - - def doubleWidthLine(): - """Make the current line a double-width line. - """ - - def eraseToLineEnd(): - """Erase from the cursor to the end of line, including cursor position. - """ - - def eraseToLineBeginning(): - """Erase from the cursor to the beginning of the line, including the cursor position. - """ - - def eraseLine(): - """Erase the entire cursor line. - """ - - def eraseToDisplayEnd(): - """Erase from the cursor to the end of the display, including the cursor position. - """ - - def eraseToDisplayBeginning(): - """Erase from the cursor to the beginning of the display, including the cursor position. - """ - - def eraseDisplay(): - """Erase the entire display. - """ - - def deleteCharacter(n=1): - """Delete n characters starting at the cursor position. - - Characters to the right of deleted characters are shifted to the left. - """ - - def insertLine(n=1): - """Insert n lines at the cursor position. - - Lines below the cursor are shifted down. Lines moved past the bottom margin are lost. - This command is ignored when the cursor is outside the scroll region. - """ - - def deleteLine(n=1): - """Delete n lines starting at the cursor position. - - Lines below the cursor are shifted up. This command is ignored when the cursor is outside - the scroll region. - """ - - def reportCursorPosition(): - """Return a Deferred that fires with a two-tuple of (x, y) indicating the cursor position. - """ - - def reset(): - """Reset the terminal to its initial state. - """ - - def unhandledControlSequence(seq): - """Called when an unsupported control sequence is received. - - @type seq: C{str} - @param seq: The whole control sequence which could not be interpreted. - """ - - -CSI = '\x1b' -CST = {'~': 'tilde'} - -class modes: - """ECMA 48 standardized modes - """ - - # BREAKS YOPUR KEYBOARD MOFO - KEYBOARD_ACTION = KAM = 2 - - # When set, enables character insertion. New display characters - # move old display characters to the right. Characters moved past - # the right margin are lost. - - # When reset, enables replacement mode (disables character - # insertion). New display characters replace old display - # characters at cursor position. The old character is erased. - INSERTION_REPLACEMENT = IRM = 4 - - # Set causes a received linefeed, form feed, or vertical tab to - # move cursor to first column of next line. RETURN transmits both - # a carriage return and linefeed. This selection is also called - # new line option. - - # Reset causes a received linefeed, form feed, or vertical tab to - # move cursor to next line in current column. RETURN transmits a - # carriage return. - LINEFEED_NEWLINE = LNM = 20 - - -class privateModes: - """ANSI-Compatible Private Modes - """ - ERROR = 0 - CURSOR_KEY = 1 - ANSI_VT52 = 2 - COLUMN = 3 - SCROLL = 4 - SCREEN = 5 - ORIGIN = 6 - AUTO_WRAP = 7 - AUTO_REPEAT = 8 - PRINTER_FORM_FEED = 18 - PRINTER_EXTENT = 19 - - # Toggle cursor visibility (reset hides it) - CURSOR_MODE = 25 - - -# Character sets -CS_US = 'CS_US' -CS_UK = 'CS_UK' -CS_DRAWING = 'CS_DRAWING' -CS_ALTERNATE = 'CS_ALTERNATE' -CS_ALTERNATE_SPECIAL = 'CS_ALTERNATE_SPECIAL' - -# Groupings (or something?? These are like variables that can be bound to character sets) -G0 = 'G0' -G1 = 'G1' - -# G2 and G3 cannot be changed, but they can be shifted to. -G2 = 'G2' -G3 = 'G3' - -# Character attributes - -NORMAL = 0 -BOLD = 1 -UNDERLINE = 4 -BLINK = 5 -REVERSE_VIDEO = 7 - -class Vector: - def __init__(self, x, y): - self.x = x - self.y = y - -def log(s): - file('log', 'a').write(str(s) + '\n') - -# XXX TODO - These attributes are really part of the -# ITerminalTransport interface, I think. -_KEY_NAMES = ('UP_ARROW', 'DOWN_ARROW', 'RIGHT_ARROW', 'LEFT_ARROW', - 'HOME', 'INSERT', 'DELETE', 'END', 'PGUP', 'PGDN', 'NUMPAD_MIDDLE', - 'F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'F9', - 'F10', 'F11', 'F12', - - 'ALT', 'SHIFT', 'CONTROL') - -class _const(object): - """ - @ivar name: A string naming this constant - """ - def __init__(self, name): - self.name = name - - def __repr__(self): - return '[' + self.name + ']' - - -FUNCTION_KEYS = [ - _const(_name) for _name in _KEY_NAMES] - -class ServerProtocol(protocol.Protocol): - implements(ITerminalTransport) - - protocolFactory = None - terminalProtocol = None - - TAB = '\t' - BACKSPACE = '\x7f' - ## - - lastWrite = '' - - state = 'data' - - termSize = Vector(80, 24) - cursorPos = Vector(0, 0) - scrollRegion = None - - # Factory who instantiated me - factory = None - - def __init__(self, protocolFactory=None, *a, **kw): - """ - @param protocolFactory: A callable which will be invoked with - *a, **kw and should return an ITerminalProtocol implementor. - This will be invoked when a connection to this ServerProtocol - is established. - - @param a: Any positional arguments to pass to protocolFactory. - @param kw: Any keyword arguments to pass to protocolFactory. - """ - # assert protocolFactory is None or ITerminalProtocol.implementedBy(protocolFactory), "ServerProtocol.__init__ must be passed an ITerminalProtocol implementor" - if protocolFactory is not None: - self.protocolFactory = protocolFactory - self.protocolArgs = a - self.protocolKwArgs = kw - - self._cursorReports = [] - - def connectionMade(self): - if self.protocolFactory is not None: - self.terminalProtocol = self.protocolFactory(*self.protocolArgs, **self.protocolKwArgs) - - try: - factory = self.factory - except AttributeError: - pass - else: - self.terminalProtocol.factory = factory - - self.terminalProtocol.makeConnection(self) - - def dataReceived(self, data): - for ch in data: - if self.state == 'data': - if ch == '\x1b': - self.state = 'escaped' - else: - self.terminalProtocol.keystrokeReceived(ch, None) - elif self.state == 'escaped': - if ch == '[': - self.state = 'bracket-escaped' - self.escBuf = [] - elif ch == 'O': - self.state = 'low-function-escaped' - else: - self.state = 'data' - self._handleShortControlSequence(ch) - elif self.state == 'bracket-escaped': - if ch == 'O': - self.state = 'low-function-escaped' - elif ch.isalpha() or ch == '~': - self._handleControlSequence(''.join(self.escBuf) + ch) - del self.escBuf - self.state = 'data' - else: - self.escBuf.append(ch) - elif self.state == 'low-function-escaped': - self._handleLowFunctionControlSequence(ch) - self.state = 'data' - else: - raise ValueError("Illegal state") - - def _handleShortControlSequence(self, ch): - self.terminalProtocol.keystrokeReceived(ch, self.ALT) - - def _handleControlSequence(self, buf): - buf = '\x1b[' + buf - f = getattr(self.controlSequenceParser, CST.get(buf[-1], buf[-1]), None) - if f is None: - self.unhandledControlSequence(buf) - else: - f(self, self.terminalProtocol, buf[:-1]) - - def unhandledControlSequence(self, buf): - self.terminalProtocol.unhandledControlSequence(buf) - - def _handleLowFunctionControlSequence(self, ch): - map = {'P': self.F1, 'Q': self.F2, 'R': self.F3, 'S': self.F4} - keyID = map.get(ch) - if keyID is not None: - self.terminalProtocol.keystrokeReceived(keyID, None) - else: - self.terminalProtocol.unhandledControlSequence('\x1b[O' + ch) - - class ControlSequenceParser: - def A(self, proto, handler, buf): - if buf == '\x1b[': - handler.keystrokeReceived(proto.UP_ARROW, None) - else: - handler.unhandledControlSequence(buf + 'A') - - def B(self, proto, handler, buf): - if buf == '\x1b[': - handler.keystrokeReceived(proto.DOWN_ARROW, None) - else: - handler.unhandledControlSequence(buf + 'B') - - def C(self, proto, handler, buf): - if buf == '\x1b[': - handler.keystrokeReceived(proto.RIGHT_ARROW, None) - else: - handler.unhandledControlSequence(buf + 'C') - - def D(self, proto, handler, buf): - if buf == '\x1b[': - handler.keystrokeReceived(proto.LEFT_ARROW, None) - else: - handler.unhandledControlSequence(buf + 'D') - - def E(self, proto, handler, buf): - if buf == '\x1b[': - handler.keystrokeReceived(proto.NUMPAD_MIDDLE, None) - else: - handler.unhandledControlSequence(buf + 'E') - - def F(self, proto, handler, buf): - if buf == '\x1b[': - handler.keystrokeReceived(proto.END, None) - else: - handler.unhandledControlSequence(buf + 'F') - - def H(self, proto, handler, buf): - if buf == '\x1b[': - handler.keystrokeReceived(proto.HOME, None) - else: - handler.unhandledControlSequence(buf + 'H') - - def R(self, proto, handler, buf): - if not proto._cursorReports: - handler.unhandledControlSequence(buf + 'R') - elif buf.startswith('\x1b['): - report = buf[2:] - parts = report.split(';') - if len(parts) != 2: - handler.unhandledControlSequence(buf + 'R') - else: - Pl, Pc = parts - try: - Pl, Pc = int(Pl), int(Pc) - except ValueError: - handler.unhandledControlSequence(buf + 'R') - else: - d = proto._cursorReports.pop(0) - d.callback((Pc - 1, Pl - 1)) - else: - handler.unhandledControlSequence(buf + 'R') - - def Z(self, proto, handler, buf): - if buf == '\x1b[': - handler.keystrokeReceived(proto.TAB, proto.SHIFT) - else: - handler.unhandledControlSequence(buf + 'Z') - - def tilde(self, proto, handler, buf): - map = {1: proto.HOME, 2: proto.INSERT, 3: proto.DELETE, - 4: proto.END, 5: proto.PGUP, 6: proto.PGDN, - - 15: proto.F5, 17: proto.F6, 18: proto.F7, - 19: proto.F8, 20: proto.F9, 21: proto.F10, - 23: proto.F11, 24: proto.F12} - - if buf.startswith('\x1b['): - ch = buf[2:] - try: - v = int(ch) - except ValueError: - handler.unhandledControlSequence(buf + '~') - else: - symbolic = map.get(v) - if symbolic is not None: - handler.keystrokeReceived(map[v], None) - else: - handler.unhandledControlSequence(buf + '~') - else: - handler.unhandledControlSequence(buf + '~') - - controlSequenceParser = ControlSequenceParser() - - # ITerminalTransport - def cursorUp(self, n=1): - assert n >= 1 - self.cursorPos.y = max(self.cursorPos.y - n, 0) - self.write('\x1b[%dA' % (n,)) - - def cursorDown(self, n=1): - assert n >= 1 - self.cursorPos.y = min(self.cursorPos.y + n, self.termSize.y - 1) - self.write('\x1b[%dB' % (n,)) - - def cursorForward(self, n=1): - assert n >= 1 - self.cursorPos.x = min(self.cursorPos.x + n, self.termSize.x - 1) - self.write('\x1b[%dC' % (n,)) - - def cursorBackward(self, n=1): - assert n >= 1 - self.cursorPos.x = max(self.cursorPos.x - n, 0) - self.write('\x1b[%dD' % (n,)) - - def cursorPosition(self, column, line): - self.write('\x1b[%d;%dH' % (line + 1, column + 1)) - - def cursorHome(self): - self.cursorPos.x = self.cursorPos.y = 0 - self.write('\x1b[H') - - def index(self): - self.cursorPos.y = min(self.cursorPos.y + 1, self.termSize.y - 1) - self.write('\x1bD') - - def reverseIndex(self): - self.cursorPos.y = max(self.cursorPos.y - 1, 0) - self.write('\x1bM') - - def nextLine(self): - self.cursorPos.x = 0 - self.cursorPos.y = min(self.cursorPos.y + 1, self.termSize.y - 1) - self.write('\n') - - def saveCursor(self): - self._savedCursorPos = Vector(self.cursorPos.x, self.cursorPos.y) - self.write('\x1b7') - - def restoreCursor(self): - self.cursorPos = self._savedCursorPos - del self._savedCursorPos - self.write('\x1b8') - - def setModes(self, modes): - # XXX Support ANSI-Compatible private modes - self.write('\x1b[%sh' % (';'.join(map(str, modes)),)) - - def setPrivateModes(self, modes): - self.write('\x1b[?%sh' % (';'.join(map(str, modes)),)) - - def resetModes(self, modes): - # XXX Support ANSI-Compatible private modes - self.write('\x1b[%sl' % (';'.join(map(str, modes)),)) - - def resetPrivateModes(self, modes): - self.write('\x1b[?%sl' % (';'.join(map(str, modes)),)) - - def applicationKeypadMode(self): - self.write('\x1b=') - - def numericKeypadMode(self): - self.write('\x1b>') - - def selectCharacterSet(self, charSet, which): - # XXX Rewrite these as dict lookups - if which == G0: - which = '(' - elif which == G1: - which = ')' - else: - raise ValueError("`which' argument to selectCharacterSet must be G0 or G1") - if charSet == CS_UK: - charSet = 'A' - elif charSet == CS_US: - charSet = 'B' - elif charSet == CS_DRAWING: - charSet = '0' - elif charSet == CS_ALTERNATE: - charSet = '1' - elif charSet == CS_ALTERNATE_SPECIAL: - charSet = '2' - else: - raise ValueError("Invalid `charSet' argument to selectCharacterSet") - self.write('\x1b' + which + charSet) - - def shiftIn(self): - self.write('\x15') - - def shiftOut(self): - self.write('\x14') - - def singleShift2(self): - self.write('\x1bN') - - def singleShift3(self): - self.write('\x1bO') - - def selectGraphicRendition(self, *attributes): - attrs = [] - for a in attributes: - attrs.append(a) - self.write('\x1b[%sm' % (';'.join(attrs),)) - - def horizontalTabulationSet(self): - self.write('\x1bH') - - def tabulationClear(self): - self.write('\x1b[q') - - def tabulationClearAll(self): - self.write('\x1b[3q') - - def doubleHeightLine(self, top=True): - if top: - self.write('\x1b#3') - else: - self.write('\x1b#4') - - def singleWidthLine(self): - self.write('\x1b#5') - - def doubleWidthLine(self): - self.write('\x1b#6') - - def eraseToLineEnd(self): - self.write('\x1b[K') - - def eraseToLineBeginning(self): - self.write('\x1b[1K') - - def eraseLine(self): - self.write('\x1b[2K') - - def eraseToDisplayEnd(self): - self.write('\x1b[J') - - def eraseToDisplayBeginning(self): - self.write('\x1b[1J') - - def eraseDisplay(self): - self.write('\x1b[2J') - - def deleteCharacter(self, n=1): - self.write('\x1b[%dP' % (n,)) - - def insertLine(self, n=1): - self.write('\x1b[%dL' % (n,)) - - def deleteLine(self, n=1): - self.write('\x1b[%dM' % (n,)) - - def setScrollRegion(self, first=None, last=None): - if first is not None: - first = '%d' % (first,) - else: - first = '' - if last is not None: - last = '%d' % (last,) - else: - last = '' - self.write('\x1b[%s;%sr' % (first, last)) - - def resetScrollRegion(self): - self.setScrollRegion() - - def reportCursorPosition(self): - d = defer.Deferred() - self._cursorReports.append(d) - self.write('\x1b[6n') - return d - - def reset(self): - self.cursorPos.x = self.cursorPos.y = 0 - try: - del self._savedCursorPos - except AttributeError: - pass - self.write('\x1bc') - - # ITransport - def write(self, bytes): - if bytes: - self.lastWrite = bytes - self.transport.write('\r\n'.join(bytes.split('\n'))) - - def writeSequence(self, bytes): - self.write(''.join(bytes)) - - def loseConnection(self): - self.reset() - self.transport.loseConnection() - - def connectionLost(self, reason): - if self.terminalProtocol is not None: - try: - self.terminalProtocol.connectionLost(reason) - finally: - self.terminalProtocol = None -# Add symbolic names for function keys -for name, const in zip(_KEY_NAMES, FUNCTION_KEYS): - setattr(ServerProtocol, name, const) - - - -class ClientProtocol(protocol.Protocol): - - terminalFactory = None - terminal = None - - state = 'data' - - _escBuf = None - - _shorts = { - 'D': 'index', - 'M': 'reverseIndex', - 'E': 'nextLine', - '7': 'saveCursor', - '8': 'restoreCursor', - '=': 'applicationKeypadMode', - '>': 'numericKeypadMode', - 'N': 'singleShift2', - 'O': 'singleShift3', - 'H': 'horizontalTabulationSet', - 'c': 'reset'} - - _longs = { - '[': 'bracket-escape', - '(': 'select-g0', - ')': 'select-g1', - '#': 'select-height-width'} - - _charsets = { - 'A': CS_UK, - 'B': CS_US, - '0': CS_DRAWING, - '1': CS_ALTERNATE, - '2': CS_ALTERNATE_SPECIAL} - - # Factory who instantiated me - factory = None - - def __init__(self, terminalFactory=None, *a, **kw): - """ - @param terminalFactory: A callable which will be invoked with - *a, **kw and should return an ITerminalTransport provider. - This will be invoked when this ClientProtocol establishes a - connection. - - @param a: Any positional arguments to pass to terminalFactory. - @param kw: Any keyword arguments to pass to terminalFactory. - """ - # assert terminalFactory is None or ITerminalTransport.implementedBy(terminalFactory), "ClientProtocol.__init__ must be passed an ITerminalTransport implementor" - if terminalFactory is not None: - self.terminalFactory = terminalFactory - self.terminalArgs = a - self.terminalKwArgs = kw - - def connectionMade(self): - if self.terminalFactory is not None: - self.terminal = self.terminalFactory(*self.terminalArgs, **self.terminalKwArgs) - self.terminal.factory = self.factory - self.terminal.makeConnection(self) - - def connectionLost(self, reason): - if self.terminal is not None: - try: - self.terminal.connectionLost(reason) - finally: - del self.terminal - - def dataReceived(self, bytes): - for b in bytes: - if self.state == 'data': - if b == '\x1b': - self.state = 'escaped' - elif b == '\x14': - self.terminal.shiftOut() - elif b == '\x15': - self.terminal.shiftIn() - elif b == '\x08': - self.terminal.cursorBackward() - else: - self.terminal.write(b) - elif self.state == 'escaped': - fName = self._shorts.get(b) - if fName is not None: - self.state = 'data' - getattr(self.terminal, fName)() - else: - state = self._longs.get(b) - if state is not None: - self.state = state - else: - self.terminal.unhandledControlSequence('\x1b' + b) - self.state = 'data' - elif self.state == 'bracket-escape': - if self._escBuf is None: - self._escBuf = [] - if b.isalpha() or b == '~': - self._handleControlSequence(''.join(self._escBuf), b) - del self._escBuf - self.state = 'data' - else: - self._escBuf.append(b) - elif self.state == 'select-g0': - self.terminal.selectCharacterSet(self._charsets.get(b, b), G0) - self.state = 'data' - elif self.state == 'select-g1': - self.terminal.selectCharacterSet(self._charsets.get(b, b), G1) - self.state = 'data' - elif self.state == 'select-height-width': - self._handleHeightWidth(b) - self.state = 'data' - else: - raise ValueError("Illegal state") - - def _handleControlSequence(self, buf, terminal): - f = getattr(self.controlSequenceParser, CST.get(terminal, terminal), None) - if f is None: - self.terminal.unhandledControlSequence('\x1b[' + buf + terminal) - else: - f(self, self.terminal, buf) - - class ControlSequenceParser: - def _makeSimple(ch, fName): - n = 'cursor' + fName - def simple(self, proto, handler, buf): - if not buf: - getattr(handler, n)(1) - else: - try: - m = int(buf) - except ValueError: - handler.unhandledControlSequence('\x1b[' + buf + ch) - else: - getattr(handler, n)(m) - return simple - for (ch, fName) in (('A', 'Up'), - ('B', 'Down'), - ('C', 'Forward'), - ('D', 'Backward')): - exec ch + " = _makeSimple(ch, fName)" - del _makeSimple - - def h(self, proto, handler, buf): - # XXX - Handle '?' to introduce ANSI-Compatible private modes. - try: - modes = map(int, buf.split(';')) - except ValueError: - handler.unhandledControlSequence('\x1b[' + buf + 'h') - else: - handler.setModes(modes) - - def l(self, proto, handler, buf): - # XXX - Handle '?' to introduce ANSI-Compatible private modes. - try: - modes = map(int, buf.split(';')) - except ValueError: - handler.unhandledControlSequence('\x1b[' + buf + 'l') - else: - handler.resetModes(modes) - - def r(self, proto, handler, buf): - parts = buf.split(';') - if len(parts) == 1: - handler.setScrollRegion(None, None) - elif len(parts) == 2: - try: - if parts[0]: - pt = int(parts[0]) - else: - pt = None - if parts[1]: - pb = int(parts[1]) - else: - pb = None - except ValueError: - handler.unhandledControlSequence('\x1b[' + buf + 'r') - else: - handler.setScrollRegion(pt, pb) - else: - handler.unhandledControlSequence('\x1b[' + buf + 'r') - - def K(self, proto, handler, buf): - if not buf: - handler.eraseToLineEnd() - elif buf == '1': - handler.eraseToLineBeginning() - elif buf == '2': - handler.eraseLine() - else: - handler.unhandledControlSequence('\x1b[' + buf + 'K') - - def H(self, proto, handler, buf): - handler.cursorHome() - - def J(self, proto, handler, buf): - if not buf: - handler.eraseToDisplayEnd() - elif buf == '1': - handler.eraseToDisplayBeginning() - elif buf == '2': - handler.eraseDisplay() - else: - handler.unhandledControlSequence('\x1b[' + buf + 'J') - - def P(self, proto, handler, buf): - if not buf: - handler.deleteCharacter(1) - else: - try: - n = int(buf) - except ValueError: - handler.unhandledControlSequence('\x1b[' + buf + 'P') - else: - handler.deleteCharacter(n) - - def L(self, proto, handler, buf): - if not buf: - handler.insertLine(1) - else: - try: - n = int(buf) - except ValueError: - handler.unhandledControlSequence('\x1b[' + buf + 'L') - else: - handler.insertLine(n) - - def M(self, proto, handler, buf): - if not buf: - handler.deleteLine(1) - else: - try: - n = int(buf) - except ValueError: - handler.unhandledControlSequence('\x1b[' + buf + 'M') - else: - handler.deleteLine(n) - - def n(self, proto, handler, buf): - if buf == '6': - x, y = handler.reportCursorPosition() - proto.transport.write('\x1b[%d;%dR' % (x + 1, y + 1)) - else: - handler.unhandledControlSequence('\x1b[' + buf + 'n') - - def m(self, proto, handler, buf): - if not buf: - handler.selectGraphicRendition(NORMAL) - else: - attrs = [] - for a in buf.split(';'): - try: - a = int(a) - except ValueError: - pass - attrs.append(a) - handler.selectGraphicRendition(*attrs) - - controlSequenceParser = ControlSequenceParser() - - def _handleHeightWidth(self, b): - if b == '3': - self.terminal.doubleHeightLine(True) - elif b == '4': - self.terminal.doubleHeightLine(False) - elif b == '5': - self.terminal.singleWidthLine() - elif b == '6': - self.terminal.doubleWidthLine() - else: - self.terminal.unhandledControlSequence('\x1b#' + b) - - -__all__ = [ - # Interfaces - 'ITerminalProtocol', 'ITerminalTransport', - - # Symbolic constants - 'modes', 'privateModes', 'FUNCTION_KEYS', - - 'CS_US', 'CS_UK', 'CS_DRAWING', 'CS_ALTERNATE', 'CS_ALTERNATE_SPECIAL', - 'G0', 'G1', 'G2', 'G3', - - 'UNDERLINE', 'REVERSE_VIDEO', 'BLINK', 'BOLD', 'NORMAL', - - # Protocol classes - 'ServerProtocol', 'ClientProtocol'] diff --git a/tools/buildbot/pylibs/twisted/conch/insults/text.py b/tools/buildbot/pylibs/twisted/conch/insults/text.py deleted file mode 100644 index e6cbf1c..0000000 --- a/tools/buildbot/pylibs/twisted/conch/insults/text.py +++ /dev/null @@ -1,186 +0,0 @@ -# -*- test-case-name: twisted.conch.test.test_text -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Character attribute manipulation API - -This module provides a domain-specific language (using Python syntax) -for the creation of text with additional display attributes associated -with it. It is intended as an alternative to manually building up -strings containing ECMA 48 character attribute control codes. It -currently supports foreground and background colors (black, red, -green, yellow, blue, magenta, cyan, and white), intensity selection, -underlining, blinking and reverse video. Character set selection -support is planned. - -Character attributes are specified by using two Python operations: -attribute lookup and indexing. For example, the string \"Hello -world\" with red foreground and all other attributes set to their -defaults, assuming the name twisted.conch.insults.text.attributes has -been imported and bound to the name \"A\" (with the statement C{from -twisted.conch.insults.text import attributes as A}, for example) one -uses this expression:: - - | A.fg.red[\"Hello world\"] - -Other foreground colors are set by substituting their name for -\"red\". To set both a foreground and a background color, this -expression is used:: - - | A.fg.red[A.bg.green[\"Hello world\"]] - -Note that either A.bg.green can be nested within A.fg.red or vice -versa. Also note that multiple items can be nested within a single -index operation by separating them with commas:: - - | A.bg.green[A.fg.red[\"Hello\"], " ", A.fg.blue[\"world\"]] - -Other character attributes are set in a similar fashion. To specify a -blinking version of the previous expression:: - - | A.blink[A.bg.green[A.fg.red[\"Hello\"], " ", A.fg.blue[\"world\"]]] - -C{A.reverseVideo}, C{A.underline}, and C{A.bold} are also valid. - -A third operation is actually supported: unary negation. This turns -off an attribute when an enclosing expression would otherwise have -caused it to be on. For example:: - - | A.underline[A.fg.red[\"Hello\", -A.underline[\" world\"]]] - -@author: U{Jp Calderone} -""" - -from twisted.conch.insults import helper, insults - -class _Attribute(object): - def __init__(self): - self.children = [] - - def __getitem__(self, item): - assert isinstance(item, (list, tuple, _Attribute, str)) - if isinstance(item, (list, tuple)): - self.children.extend(item) - else: - self.children.append(item) - return self - - def serialize(self, write, attrs=None): - if attrs is None: - attrs = helper.CharacterAttribute() - for ch in self.children: - if isinstance(ch, _Attribute): - ch.serialize(write, attrs.copy()) - else: - write(attrs.toVT102()) - write(ch) - -class _NormalAttr(_Attribute): - def serialize(self, write, attrs): - attrs.__init__() - super(_NormalAttr, self).serialize(write, attrs) - -class _OtherAttr(_Attribute): - def __init__(self, attrname, attrvalue): - self.attrname = attrname - self.attrvalue = attrvalue - self.children = [] - - def __neg__(self): - result = _OtherAttr(self.attrname, not self.attrvalue) - result.children.extend(self.children) - return result - - def serialize(self, write, attrs): - attrs = attrs.wantOne(**{self.attrname: self.attrvalue}) - super(_OtherAttr, self).serialize(write, attrs) - -class _ColorAttr(_Attribute): - def __init__(self, color, ground): - self.color = color - self.ground = ground - self.children = [] - - def serialize(self, write, attrs): - attrs = attrs.wantOne(**{self.ground: self.color}) - super(_ColorAttr, self).serialize(write, attrs) - -class _ForegroundColorAttr(_ColorAttr): - def __init__(self, color): - super(_ForegroundColorAttr, self).__init__(color, 'foreground') - -class _BackgroundColorAttr(_ColorAttr): - def __init__(self, color): - super(_BackgroundColorAttr, self).__init__(color, 'background') - -class CharacterAttributes(object): - class _ColorAttribute(object): - def __init__(self, ground): - self.ground = ground - - attrs = { - 'black': helper.BLACK, - 'red': helper.RED, - 'green': helper.GREEN, - 'yellow': helper.YELLOW, - 'blue': helper.BLUE, - 'magenta': helper.MAGENTA, - 'cyan': helper.CYAN, - 'white': helper.WHITE} - - def __getattr__(self, name): - try: - return self.ground(self.attrs[name]) - except KeyError: - raise AttributeError(name) - - fg = _ColorAttribute(_ForegroundColorAttr) - bg = _ColorAttribute(_BackgroundColorAttr) - - attrs = { - 'bold': insults.BOLD, - 'blink': insults.BLINK, - 'underline': insults.UNDERLINE, - 'reverseVideo': insults.REVERSE_VIDEO} - - def __getattr__(self, name): - if name == 'normal': - return _NormalAttr() - if name in self.attrs: - return _OtherAttr(name, True) - raise AttributeError(name) - -def flatten(output, attrs): - """Serialize a sequence of characters with attribute information - - The resulting string can be interpreted by VT102-compatible - terminals so that the contained characters are displayed and, for - those attributes which the terminal supports, have the attributes - specified in the input. - - For example, if your terminal is VT102 compatible, you might run - this for a colorful variation on the \"hello world\" theme:: - - | from twisted.conch.insults.text import flatten, attributes as A - | from twisted.conch.insults.helper import CharacterAttribute - | print flatten( - | A.normal[A.bold[A.fg.red['He'], A.fg.green['ll'], A.fg.magenta['o'], ' ', - | A.fg.yellow['Wo'], A.fg.blue['rl'], A.fg.cyan['d!']]], - | CharacterAttribute()) - - @param output: Object returned by accessing attributes of the - module-level attributes object. - - @param attrs: A L{twisted.conch.insults.helper.CharacterAttribute} - instance - - @return: A VT102-friendly string - """ - L = [] - output.serialize(L.append, attrs) - return ''.join(L) - -attributes = CharacterAttributes() - -__all__ = ['attributes', 'flatten'] diff --git a/tools/buildbot/pylibs/twisted/conch/insults/window.py b/tools/buildbot/pylibs/twisted/conch/insults/window.py deleted file mode 100644 index 51487f8..0000000 --- a/tools/buildbot/pylibs/twisted/conch/insults/window.py +++ /dev/null @@ -1,864 +0,0 @@ -# -*- test-case-name: twisted.conch.test.test_window -*- - -""" -Simple insults-based widget library - -@author: U{Jp Calderone} -""" - -import array - -from twisted.conch.insults import insults, helper -from twisted.python import text as tptext - -class YieldFocus(Exception): - """Input focus manipulation exception - """ - -class BoundedTerminalWrapper(object): - def __init__(self, terminal, width, height, xoff, yoff): - self.width = width - self.height = height - self.xoff = xoff - self.yoff = yoff - self.terminal = terminal - self.cursorForward = terminal.cursorForward - self.selectCharacterSet = terminal.selectCharacterSet - self.selectGraphicRendition = terminal.selectGraphicRendition - self.saveCursor = terminal.saveCursor - self.restoreCursor = terminal.restoreCursor - - def cursorPosition(self, x, y): - return self.terminal.cursorPosition( - self.xoff + min(self.width, x), - self.yoff + min(self.height, y) - ) - - def cursorHome(self): - return self.terminal.cursorPosition( - self.xoff, self.yoff) - - def write(self, bytes): - return self.terminal.write(bytes) - -class Widget(object): - focused = False - parent = None - dirty = False - width = height = None - - def repaint(self): - if not self.dirty: - self.dirty = True - if self.parent is not None and not self.parent.dirty: - self.parent.repaint() - - def filthy(self): - self.dirty = True - - def redraw(self, width, height, terminal): - self.filthy() - self.draw(width, height, terminal) - - def draw(self, width, height, terminal): - if width != self.width or height != self.height or self.dirty: - self.width = width - self.height = height - self.dirty = False - self.render(width, height, terminal) - - def render(self, width, height, terminal): - pass - - def sizeHint(self): - return None - - def keystrokeReceived(self, keyID, modifier): - if keyID == '\t': - self.tabReceived(modifier) - elif keyID == '\x7f': - self.backspaceReceived() - elif keyID in insults.FUNCTION_KEYS: - self.functionKeyReceived(keyID, modifier) - else: - self.characterReceived(keyID, modifier) - - def tabReceived(self, modifier): - # XXX TODO - Handle shift+tab - raise YieldFocus() - - def focusReceived(self): - """Called when focus is being given to this widget. - - May raise YieldFocus is this widget does not want focus. - """ - self.focused = True - self.repaint() - - def focusLost(self): - self.focused = False - self.repaint() - - def backspaceReceived(self): - pass - - def functionKeyReceived(self, keyID, modifier): - func = getattr(self, 'func_' + keyID.name, None) - if func is not None: - func(modifier) - - def characterReceived(self, keyID, modifier): - pass - -class ContainerWidget(Widget): - """ - @ivar focusedChild: The contained widget which currently has - focus, or None. - """ - focusedChild = None - focused = False - - def __init__(self): - Widget.__init__(self) - self.children = [] - - def addChild(self, child): - assert child.parent is None - child.parent = self - self.children.append(child) - if self.focusedChild is None and self.focused: - try: - child.focusReceived() - except YieldFocus: - pass - else: - self.focusedChild = child - self.repaint() - - def remChild(self, child): - assert child.parent is self - child.parent = None - self.children.remove(child) - self.repaint() - - def filthy(self): - for ch in self.children: - ch.filthy() - Widget.filthy(self) - - def render(self, width, height, terminal): - for ch in self.children: - ch.draw(width, height, terminal) - - def changeFocus(self): - self.repaint() - - if self.focusedChild is not None: - self.focusedChild.focusLost() - focusedChild = self.focusedChild - self.focusedChild = None - try: - curFocus = self.children.index(focusedChild) + 1 - except ValueError: - raise YieldFocus() - else: - curFocus = 0 - while curFocus < len(self.children): - try: - self.children[curFocus].focusReceived() - except YieldFocus: - curFocus += 1 - else: - self.focusedChild = self.children[curFocus] - return - # None of our children wanted focus - raise YieldFocus() - - - def focusReceived(self): - self.changeFocus() - self.focused = True - - - def keystrokeReceived(self, keyID, modifier): - if self.focusedChild is not None: - try: - self.focusedChild.keystrokeReceived(keyID, modifier) - except YieldFocus: - self.changeFocus() - self.repaint() - else: - Widget.keystrokeReceived(self, keyID, modifier) - - -class TopWindow(ContainerWidget): - """ - A top-level container object which provides focus wrap-around and paint - scheduling. - - @ivar painter: A no-argument callable which will be invoked when this - widget needs to be redrawn. - - @ivar scheduler: A one-argument callable which will be invoked with a - no-argument callable and should arrange for it to invoked at some point in - the near future. The no-argument callable will cause this widget and all - its children to be redrawn. It is typically beneficial for the no-argument - callable to be invoked at the end of handling for whatever event is - currently active; for example, it might make sense to call it at the end of - L{twisted.conch.insults.insults.ITerminalProtocol.keystrokeReceived}. - Note, however, that since calls to this may also be made in response to no - apparent event, arrangements should be made for the function to be called - even if an event handler such as C{keystrokeReceived} is not on the call - stack (eg, using C{reactor.callLater} with a short timeout). - """ - focused = True - - def __init__(self, painter, scheduler): - ContainerWidget.__init__(self) - self.painter = painter - self.scheduler = scheduler - - _paintCall = None - def repaint(self): - if self._paintCall is None: - self._paintCall = object() - self.scheduler(self._paint) - ContainerWidget.repaint(self) - - def _paint(self): - self._paintCall = None - self.painter() - - def changeFocus(self): - try: - ContainerWidget.changeFocus(self) - except YieldFocus: - try: - ContainerWidget.changeFocus(self) - except YieldFocus: - pass - - def keystrokeReceived(self, keyID, modifier): - try: - ContainerWidget.keystrokeReceived(self, keyID, modifier) - except YieldFocus: - self.changeFocus() - - -class AbsoluteBox(ContainerWidget): - def moveChild(self, child, x, y): - for n in range(len(self.children)): - if self.children[n][0] is child: - self.children[n] = (child, x, y) - break - else: - raise ValueError("No such child", child) - - def render(self, width, height, terminal): - for (ch, x, y) in self.children: - wrap = BoundedTerminalWrapper(terminal, width - x, height - y, x, y) - ch.draw(width, height, wrap) - - -class _Box(ContainerWidget): - TOP, CENTER, BOTTOM = range(3) - - def __init__(self, gravity=CENTER): - ContainerWidget.__init__(self) - self.gravity = gravity - - def sizeHint(self): - height = 0 - width = 0 - for ch in self.children: - hint = ch.sizeHint() - if hint is None: - hint = (None, None) - - if self.variableDimension == 0: - if hint[0] is None: - width = None - elif width is not None: - width += hint[0] - if hint[1] is None: - height = None - elif height is not None: - height = max(height, hint[1]) - else: - if hint[0] is None: - width = None - elif width is not None: - width = max(width, hint[0]) - if hint[1] is None: - height = None - elif height is not None: - height += hint[1] - - return width, height - - - def render(self, width, height, terminal): - if not self.children: - return - - greedy = 0 - wants = [] - for ch in self.children: - hint = ch.sizeHint() - if hint is None: - hint = (None, None) - if hint[self.variableDimension] is None: - greedy += 1 - wants.append(hint[self.variableDimension]) - - length = (width, height)[self.variableDimension] - totalWant = sum([w for w in wants if w is not None]) - if greedy: - leftForGreedy = int((length - totalWant) / greedy) - - widthOffset = heightOffset = 0 - - for want, ch in zip(wants, self.children): - if want is None: - want = leftForGreedy - - subWidth, subHeight = width, height - if self.variableDimension == 0: - subWidth = want - else: - subHeight = want - - wrap = BoundedTerminalWrapper( - terminal, - subWidth, - subHeight, - widthOffset, - heightOffset, - ) - ch.draw(subWidth, subHeight, wrap) - if self.variableDimension == 0: - widthOffset += want - else: - heightOffset += want - - -class HBox(_Box): - variableDimension = 0 - -class VBox(_Box): - variableDimension = 1 - - -class Packer(ContainerWidget): - def render(self, width, height, terminal): - if not self.children: - return - - root = int(len(self.children) ** 0.5 + 0.5) - boxes = [VBox() for n in range(root)] - for n, ch in enumerate(self.children): - boxes[n % len(boxes)].addChild(ch) - h = HBox() - map(h.addChild, boxes) - h.render(width, height, terminal) - - -class Canvas(Widget): - focused = False - - contents = None - - def __init__(self): - Widget.__init__(self) - self.resize(1, 1) - - def resize(self, width, height): - contents = array.array('c', ' ' * width * height) - if self.contents is not None: - for x in range(min(width, self._width)): - for y in range(min(height, self._height)): - contents[width * y + x] = self[x, y] - self.contents = contents - self._width = width - self._height = height - if self.x >= width: - self.x = width - 1 - if self.y >= height: - self.y = height - 1 - - def __getitem__(self, (x, y)): - return self.contents[(self._width * y) + x] - - def __setitem__(self, (x, y), value): - self.contents[(self._width * y) + x] = value - - def clear(self): - self.contents = array.array('c', ' ' * len(self.contents)) - - def render(self, width, height, terminal): - if not width or not height: - return - - if width != self._width or height != self._height: - self.resize(width, height) - for i in range(height): - terminal.cursorPosition(0, i) - terminal.write(''.join(self.contents[self._width * i:self._width * i + self._width])[:width]) - - -def horizontalLine(terminal, y, left, right): - terminal.selectCharacterSet(insults.CS_DRAWING, insults.G0) - terminal.cursorPosition(left, y) - terminal.write(chr(0161) * (right - left)) - terminal.selectCharacterSet(insults.CS_US, insults.G0) - -def verticalLine(terminal, x, top, bottom): - terminal.selectCharacterSet(insults.CS_DRAWING, insults.G0) - for n in xrange(top, bottom): - terminal.cursorPosition(x, n) - terminal.write(chr(0170)) - terminal.selectCharacterSet(insults.CS_US, insults.G0) - - -def rectangle(terminal, (top, left), (width, height)): - terminal.selectCharacterSet(insults.CS_DRAWING, insults.G0) - - terminal.cursorPosition(top, left) - terminal.write(chr(0154)) - terminal.write(chr(0161) * (width - 2)) - terminal.write(chr(0153)) - for n in range(height - 2): - terminal.cursorPosition(left, top + n + 1) - terminal.write(chr(0170)) - terminal.cursorForward(width - 2) - terminal.write(chr(0170)) - terminal.cursorPosition(0, top + height - 1) - terminal.write(chr(0155)) - terminal.write(chr(0161) * (width - 2)) - terminal.write(chr(0152)) - - terminal.selectCharacterSet(insults.CS_US, insults.G0) - -class Border(Widget): - def __init__(self, containee): - Widget.__init__(self) - self.containee = containee - self.containee.parent = self - - def focusReceived(self): - return self.containee.focusReceived() - - def focusLost(self): - return self.containee.focusLost() - - def keystrokeReceived(self, keyID, modifier): - return self.containee.keystrokeReceived(keyID, modifier) - - def sizeHint(self): - hint = self.containee.sizeHint() - if hint is None: - hint = (None, None) - if hint[0] is None: - x = None - else: - x = hint[0] + 2 - if hint[1] is None: - y = None - else: - y = hint[1] + 2 - return x, y - - def filthy(self): - self.containee.filthy() - Widget.filthy(self) - - def render(self, width, height, terminal): - if self.containee.focused: - terminal.write('\x1b[31m') - rectangle(terminal, (0, 0), (width, height)) - terminal.write('\x1b[0m') - wrap = BoundedTerminalWrapper(terminal, width - 2, height - 2, 1, 1) - self.containee.draw(width - 2, height - 2, wrap) - - -class Button(Widget): - def __init__(self, label, onPress): - Widget.__init__(self) - self.label = label - self.onPress = onPress - - def sizeHint(self): - return len(self.label), 1 - - def characterReceived(self, keyID, modifier): - if keyID == '\r': - self.onPress() - - def render(self, width, height, terminal): - terminal.cursorPosition(0, 0) - if self.focused: - terminal.write('\x1b[1m' + self.label + '\x1b[0m') - else: - terminal.write(self.label) - -class TextInput(Widget): - def __init__(self, maxwidth, onSubmit): - Widget.__init__(self) - self.onSubmit = onSubmit - self.maxwidth = maxwidth - self.buffer = '' - self.cursor = 0 - - def setText(self, text): - self.buffer = text[:self.maxwidth] - self.cursor = len(self.buffer) - self.repaint() - - def func_LEFT_ARROW(self, modifier): - if self.cursor > 0: - self.cursor -= 1 - self.repaint() - - def func_RIGHT_ARROW(self, modifier): - if self.cursor < len(self.buffer): - self.cursor += 1 - self.repaint() - - def backspaceReceived(self): - if self.cursor > 0: - self.buffer = self.buffer[:self.cursor - 1] + self.buffer[self.cursor:] - self.cursor -= 1 - self.repaint() - - def characterReceived(self, keyID, modifier): - if keyID == '\r': - self.onSubmit(self.buffer) - else: - if len(self.buffer) < self.maxwidth: - self.buffer = self.buffer[:self.cursor] + keyID + self.buffer[self.cursor:] - self.cursor += 1 - self.repaint() - - def sizeHint(self): - return self.maxwidth + 1, 1 - - def render(self, width, height, terminal): - currentText = self._renderText() - terminal.cursorPosition(0, 0) - if self.focused: - terminal.write(currentText[:self.cursor]) - cursor(terminal, currentText[self.cursor:self.cursor+1] or ' ') - terminal.write(currentText[self.cursor+1:]) - terminal.write(' ' * (self.maxwidth - len(currentText) + 1)) - else: - more = self.maxwidth - len(currentText) - terminal.write(currentText + '_' * more) - - def _renderText(self): - return self.buffer - -class PasswordInput(TextInput): - def _renderText(self): - return '*' * len(self.buffer) - -class TextOutput(Widget): - text = '' - - def __init__(self, size=None): - Widget.__init__(self) - self.size = size - - def sizeHint(self): - return self.size - - def render(self, width, height, terminal): - terminal.cursorPosition(0, 0) - text = self.text[:width] - terminal.write(text + ' ' * (width - len(text))) - - def setText(self, text): - self.text = text - self.repaint() - - def focusReceived(self): - raise YieldFocus() - -class TextOutputArea(TextOutput): - WRAP, TRUNCATE = range(2) - - def __init__(self, size=None, longLines=WRAP): - TextOutput.__init__(self, size) - self.longLines = longLines - - def render(self, width, height, terminal): - n = 0 - inputLines = self.text.splitlines() - outputLines = [] - while inputLines: - if self.longLines == self.WRAP: - wrappedLines = tptext.greedyWrap(inputLines.pop(0), width) - outputLines.extend(wrappedLines or ['']) - else: - outputLines.append(inputLines.pop(0)[:width]) - if len(outputLines) >= height: - break - for n, L in enumerate(outputLines[:height]): - terminal.cursorPosition(0, n) - terminal.write(L) - -class Viewport(Widget): - _xOffset = 0 - _yOffset = 0 - - def xOffset(): - def get(self): - return self._xOffset - def set(self, value): - if self._xOffset != value: - self._xOffset = value - self.repaint() - return get, set - xOffset = property(*xOffset()) - - def yOffset(): - def get(self): - return self._yOffset - def set(self, value): - if self._yOffset != value: - self._yOffset = value - self.repaint() - return get, set - yOffset = property(*yOffset()) - - _width = 160 - _height = 24 - - def __init__(self, containee): - Widget.__init__(self) - self.containee = containee - self.containee.parent = self - - self._buf = helper.TerminalBuffer() - self._buf.width = self._width - self._buf.height = self._height - self._buf.connectionMade() - - def filthy(self): - self.containee.filthy() - Widget.filthy(self) - - def render(self, width, height, terminal): - self.containee.draw(self._width, self._height, self._buf) - - # XXX /Lame/ - for y, line in enumerate(self._buf.lines[self._yOffset:self._yOffset + height]): - terminal.cursorPosition(0, y) - n = 0 - for n, (ch, attr) in enumerate(line[self._xOffset:self._xOffset + width]): - if ch is self._buf.void: - ch = ' ' - terminal.write(ch) - if n < width: - terminal.write(' ' * (width - n - 1)) - - -class _Scrollbar(Widget): - def __init__(self, onScroll): - Widget.__init__(self) - self.onScroll = onScroll - self.percent = 0.0 - - def smaller(self): - self.percent = min(1.0, max(0.0, self.onScroll(-1))) - self.repaint() - - def bigger(self): - self.percent = min(1.0, max(0.0, self.onScroll(+1))) - self.repaint() - - -class HorizontalScrollbar(_Scrollbar): - def sizeHint(self): - return (None, 1) - - def func_LEFT_ARROW(self, modifier): - self.smaller() - - def func_RIGHT_ARROW(self, modifier): - self.bigger() - - _left = u'\N{BLACK LEFT-POINTING TRIANGLE}' - _right = u'\N{BLACK RIGHT-POINTING TRIANGLE}' - _bar = u'\N{LIGHT SHADE}' - _slider = u'\N{DARK SHADE}' - def render(self, width, height, terminal): - terminal.cursorPosition(0, 0) - n = width - 3 - before = int(n * self.percent) - after = n - before - me = self._left + (self._bar * before) + self._slider + (self._bar * after) + self._right - terminal.write(me.encode('utf-8')) - - -class VerticalScrollbar(_Scrollbar): - def sizeHint(self): - return (1, None) - - def func_UP_ARROW(self, modifier): - self.smaller() - - def func_DOWN_ARROW(self, modifier): - self.bigger() - - _up = u'\N{BLACK UP-POINTING TRIANGLE}' - _down = u'\N{BLACK DOWN-POINTING TRIANGLE}' - _bar = u'\N{LIGHT SHADE}' - _slider = u'\N{DARK SHADE}' - def render(self, width, height, terminal): - terminal.cursorPosition(0, 0) - knob = int(self.percent * (height - 2)) - terminal.write(self._up.encode('utf-8')) - for i in xrange(1, height - 1): - terminal.cursorPosition(0, i) - if i != (knob + 1): - terminal.write(self._bar.encode('utf-8')) - else: - terminal.write(self._slider.encode('utf-8')) - terminal.cursorPosition(0, height - 1) - terminal.write(self._down.encode('utf-8')) - - -class ScrolledArea(Widget): - def __init__(self, containee): - Widget.__init__(self, containee) - self._viewport = Viewport(containee) - self._horiz = HorizontalScrollbar(self._horizScroll) - self._vert = VerticalScrollbar(self._vertScroll) - - for w in self._viewport, self._horiz, self._vert: - w.parent = self - - def _horizScroll(self, n): - self._viewport.xOffset += n - self._viewport.xOffset = max(0, self._viewport.xOffset) - return self._viewport.xOffset / 25.0 - - def _vertScroll(self, n): - self._viewport.yOffset += n - self._viewport.yOffset = max(0, self._viewport.yOffset) - return self._viewport.yOffset / 25.0 - - def func_UP_ARROW(self, modifier): - self._vert.smaller() - - def func_DOWN_ARROW(self, modifier): - self._vert.bigger() - - def func_LEFT_ARROW(self, modifier): - self._horiz.smaller() - - def func_RIGHT_ARROW(self, modifier): - self._horiz.bigger() - - def filthy(self): - self._viewport.filthy() - self._horiz.filthy() - self._vert.filthy() - Widget.filthy(self) - - def render(self, width, height, terminal): - wrapper = BoundedTerminalWrapper(terminal, width - 2, height - 2, 1, 1) - self._viewport.draw(width - 2, height - 2, wrapper) - if self.focused: - terminal.write('\x1b[31m') - horizontalLine(terminal, 0, 1, width - 1) - verticalLine(terminal, 0, 1, height - 1) - self._vert.draw(1, height - 1, BoundedTerminalWrapper(terminal, 1, height - 1, width - 1, 0)) - self._horiz.draw(width, 1, BoundedTerminalWrapper(terminal, width, 1, 0, height - 1)) - terminal.write('\x1b[0m') - -def cursor(terminal, ch): - terminal.saveCursor() - terminal.selectGraphicRendition(str(insults.REVERSE_VIDEO)) - terminal.write(ch) - terminal.restoreCursor() - terminal.cursorForward() - -class Selection(Widget): - # Index into the sequence - focusedIndex = 0 - - # Offset into the displayed subset of the sequence - renderOffset = 0 - - def __init__(self, sequence, onSelect, minVisible=None): - Widget.__init__(self) - self.sequence = sequence - self.onSelect = onSelect - self.minVisible = minVisible - if minVisible is not None: - self._width = max(map(len, self.sequence)) - - def sizeHint(self): - if self.minVisible is not None: - return self._width, self.minVisible - - def func_UP_ARROW(self, modifier): - if self.focusedIndex > 0: - self.focusedIndex -= 1 - if self.renderOffset > 0: - self.renderOffset -= 1 - self.repaint() - - def func_PGUP(self, modifier): - if self.renderOffset != 0: - self.focusedIndex -= self.renderOffset - self.renderOffset = 0 - else: - self.focusedIndex = max(0, self.focusedIndex - self.height) - self.repaint() - - def func_DOWN_ARROW(self, modifier): - if self.focusedIndex < len(self.sequence) - 1: - self.focusedIndex += 1 - if self.renderOffset < self.height - 1: - self.renderOffset += 1 - self.repaint() - - - def func_PGDN(self, modifier): - if self.renderOffset != self.height - 1: - change = self.height - self.renderOffset - 1 - if change + self.focusedIndex >= len(self.sequence): - change = len(self.sequence) - self.focusedIndex - 1 - self.focusedIndex += change - self.renderOffset = self.height - 1 - else: - self.focusedIndex = min(len(self.sequence) - 1, self.focusedIndex + self.height) - self.repaint() - - def characterReceived(self, keyID, modifier): - if keyID == '\r': - self.onSelect(self.sequence[self.focusedIndex]) - - def render(self, width, height, terminal): - self.height = height - start = self.focusedIndex - self.renderOffset - if start > len(self.sequence) - height: - start = max(0, len(self.sequence) - height) - - elements = self.sequence[start:start+height] - - for n, ele in enumerate(elements): - terminal.cursorPosition(0, n) - if n == self.renderOffset: - terminal.saveCursor() - if self.focused: - modes = str(insults.REVERSE_VIDEO), str(insults.BOLD) - else: - modes = str(insults.REVERSE_VIDEO), - terminal.selectGraphicRendition(*modes) - text = ele[:width] - terminal.write(text + (' ' * (width - len(text)))) - if n == self.renderOffset: - terminal.restoreCursor() diff --git a/tools/buildbot/pylibs/twisted/conch/interfaces.py b/tools/buildbot/pylibs/twisted/conch/interfaces.py deleted file mode 100644 index 901d87b..0000000 --- a/tools/buildbot/pylibs/twisted/conch/interfaces.py +++ /dev/null @@ -1,354 +0,0 @@ -# Copyright (c) 2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -from zope.interface import Interface - -class IConchUser(Interface): - """A user who has been authenticated to Cred through Conch. This is - the interface between the SSH connection and the user. - - @ivar conn: The SSHConnection object for this user. - """ - - def lookupChannel(channelType, windowSize, maxPacket, data): - """ - The other side requested a channel of some sort. - channelType is the type of channel being requested, - windowSize is the initial size of the remote window, - maxPacket is the largest packet we should send, - data is any other packet data (often nothing). - - We return a subclass of L{SSHChannel}. If - an appropriate channel can not be found, an exception will be - raised. If a L{ConchError} is raised, the .value - will be the message, and the .data will be the error code. - - @type channelType: C{str} - @type windowSize: C{int} - @type maxPacket: C{int} - @type data: C{str} - @rtype: subclass of L{SSHChannel}/C{tuple} - """ - - def lookupSubsystem(subsystem, data): - """ - The other side requested a subsystem. - subsystem is the name of the subsystem being requested. - data is any other packet data (often nothing). - - We return a L{Protocol}. - """ - - def gotGlobalRequest(requestType, data): - """ - A global request was sent from the other side. - - By default, this dispatches to a method 'channel_channelType' with any - non-alphanumerics in the channelType replace with _'s. If it cannot - find a suitable method, it returns an OPEN_UNKNOWN_CHANNEL_TYPE error. - The method is called with arguments of windowSize, maxPacket, data. - """ - -class ISession(Interface): - - def getPty(term, windowSize, modes): - """ - Get a psuedo-terminal for use by a shell or command. - - If a psuedo-terminal is not available, or the request otherwise - fails, raise an exception. - """ - - def openShell(proto): - """ - Open a shell and connect it to proto. - - @param proto: a L{ProcessProtocol} instance. - """ - - def execCommand(proto, command): - """ - Execute a command. - - @param proto: a L{ProcessProtocol} instance. - """ - - def windowChanged(newWindowSize): - """ - Called when the size of the remote screen has changed. - """ - - def eofReceived(): - """ - Called when the other side has indicated no more data will be sent. - """ - - def closed(): - """ - Called when the session is closed. - """ - - -class ISFTPServer(Interface): - """ - The only attribute of this class is "avatar". It is the avatar - returned by the Realm that we are authenticated with, and - represents the logged-in user. Each method should check to verify - that the user has permission for their actions. - """ - - def gotVersion(otherVersion, extData): - """ - Called when the client sends their version info. - - otherVersion is an integer representing the version of the SFTP - protocol they are claiming. - extData is a dictionary of extended_name : extended_data items. - These items are sent by the client to indicate additional features. - - This method should return a dictionary of extended_name : extended_data - items. These items are the additional features (if any) supported - by the server. - """ - return {} - - def openFile(filename, flags, attrs): - """ - Called when the clients asks to open a file. - - @param filename: a string representing the file to open. - - @param flags: an integer of the flags to open the file with, ORed together. - The flags and their values are listed at the bottom of this file. - - @param attrs: a list of attributes to open the file with. It is a - dictionary, consisting of 0 or more keys. The possible keys are:: - - size: the size of the file in bytes - uid: the user ID of the file as an integer - gid: the group ID of the file as an integer - permissions: the permissions of the file with as an integer. - the bit representation of this field is defined by POSIX. - atime: the access time of the file as seconds since the epoch. - mtime: the modification time of the file as seconds since the epoch. - ext_*: extended attributes. The server is not required to - understand this, but it may. - - NOTE: there is no way to indicate text or binary files. it is up - to the SFTP client to deal with this. - - This method returns an object that meets the ISFTPFile interface. - Alternatively, it can return a L{Deferred} that will be called back - with the object. - """ - - def removeFile(filename): - """ - Remove the given file. - - This method returns when the remove succeeds, or a Deferred that is - called back when it succeeds. - - @param filename: the name of the file as a string. - """ - - def renameFile(oldpath, newpath): - """ - Rename the given file. - - This method returns when the rename succeeds, or a L{Deferred} that is - called back when it succeeds. If the rename fails, C{renameFile} will - raise an implementation-dependent exception. - - @param oldpath: the current location of the file. - @param newpath: the new file name. - """ - - def makeDirectory(path, attrs): - """ - Make a directory. - - This method returns when the directory is created, or a Deferred that - is called back when it is created. - - @param path: the name of the directory to create as a string. - @param attrs: a dictionary of attributes to create the directory with. - Its meaning is the same as the attrs in the L{openFile} method. - """ - - def removeDirectory(path): - """ - Remove a directory (non-recursively) - - It is an error to remove a directory that has files or directories in - it. - - This method returns when the directory is removed, or a Deferred that - is called back when it is removed. - - @param path: the directory to remove. - """ - - def openDirectory(path): - """ - Open a directory for scanning. - - This method returns an iterable object that has a close() method, - or a Deferred that is called back with same. - - The close() method is called when the client is finished reading - from the directory. At this point, the iterable will no longer - be used. - - The iterable should return triples of the form (filename, - longname, attrs) or Deferreds that return the same. The - sequence must support __getitem__, but otherwise may be any - 'sequence-like' object. - - filename is the name of the file relative to the directory. - logname is an expanded format of the filename. The recommended format - is: - -rwxr-xr-x 1 mjos staff 348911 Mar 25 14:29 t-filexfer - 1234567890 123 12345678 12345678 12345678 123456789012 - - The first line is sample output, the second is the length of the field. - The fields are: permissions, link count, user owner, group owner, - size in bytes, modification time. - - attrs is a dictionary in the format of the attrs argument to openFile. - - @param path: the directory to open. - """ - - def getAttrs(path, followLinks): - """ - Return the attributes for the given path. - - This method returns a dictionary in the same format as the attrs - argument to openFile or a Deferred that is called back with same. - - @param path: the path to return attributes for as a string. - @param followLinks: a boolean. If it is True, follow symbolic links - and return attributes for the real path at the base. If it is False, - return attributes for the specified path. - """ - - def setAttrs(path, attrs): - """ - Set the attributes for the path. - - This method returns when the attributes are set or a Deferred that is - called back when they are. - - @param path: the path to set attributes for as a string. - @param attrs: a dictionary in the same format as the attrs argument to - L{openFile}. - """ - - def readLink(path): - """ - Find the root of a set of symbolic links. - - This method returns the target of the link, or a Deferred that - returns the same. - - @param path: the path of the symlink to read. - """ - - def makeLink(linkPath, targetPath): - """ - Create a symbolic link. - - This method returns when the link is made, or a Deferred that - returns the same. - - @param linkPath: the pathname of the symlink as a string. - @param targetPath: the path of the target of the link as a string. - """ - - def realPath(path): - """ - Convert any path to an absolute path. - - This method returns the absolute path as a string, or a Deferred - that returns the same. - - @param path: the path to convert as a string. - """ - - def extendedRequest(extendedName, extendedData): - """ - This is the extension mechanism for SFTP. The other side can send us - arbitrary requests. - - If we don't implement the request given by extendedName, raise - NotImplementedError. - - The return value is a string, or a Deferred that will be called - back with a string. - - @param extendedName: the name of the request as a string. - @param extendedData: the data the other side sent with the request, - as a string. - """ - -class ISFTPFile(Interface): - """ - This represents an open file on the server. An object adhering to this - interface should be returned from L{openFile}(). - """ - - def close(): - """ - Close the file. - - This method returns nothing if the close succeeds immediately, or a - Deferred that is called back when the close succeeds. - """ - - def readChunk(offset, length): - """ - Read from the file. - - If EOF is reached before any data is read, raise EOFError. - - This method returns the data as a string, or a Deferred that is - called back with same. - - @param offset: an integer that is the index to start from in the file. - @param length: the maximum length of data to return. The actual amount - returned may less than this. For normal disk files, however, - this should read the requested number (up to the end of the file). - """ - - def writeChunk(offset, data): - """ - Write to the file. - - This method returns when the write completes, or a Deferred that is - called when it completes. - - @param offset: an integer that is the index to start from in the file. - @param data: a string that is the data to write. - """ - - def getAttrs(): - """ - Return the attributes for the file. - - This method returns a dictionary in the same format as the attrs - argument to L{openFile} or a L{Deferred} that is called back with same. - """ - - def setAttrs(attrs): - """ - Set the attributes for the file. - - This method returns when the attributes are set or a Deferred that is - called back when they are. - - @param attrs: a dictionary in the same format as the attrs argument to - L{openFile}. - """ - - diff --git a/tools/buildbot/pylibs/twisted/conch/ls.py b/tools/buildbot/pylibs/twisted/conch/ls.py deleted file mode 100644 index ebc962f..0000000 --- a/tools/buildbot/pylibs/twisted/conch/ls.py +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright (c) 2001-2005 Twisted Matrix Laboratories. -# See LICENSE for details. - -import array -import stat -import time - -def lsLine(name, s): - mode = s.st_mode - perms = array.array('c', '-'*10) - ft = stat.S_IFMT(mode) - if stat.S_ISDIR(ft): perms[0] = 'd' - elif stat.S_ISCHR(ft): perms[0] = 'c' - elif stat.S_ISBLK(ft): perms[0] = 'b' - elif stat.S_ISREG(ft): perms[0] = '-' - elif stat.S_ISFIFO(ft): perms[0] = 'f' - elif stat.S_ISLNK(ft): perms[0] = 'l' - elif stat.S_ISSOCK(ft): perms[0] = 's' - else: perms[0] = '!' - # user - if mode&stat.S_IRUSR:perms[1] = 'r' - if mode&stat.S_IWUSR:perms[2] = 'w' - if mode&stat.S_IXUSR:perms[3] = 'x' - # group - if mode&stat.S_IRGRP:perms[4] = 'r' - if mode&stat.S_IWGRP:perms[5] = 'w' - if mode&stat.S_IXGRP:perms[6] = 'x' - # other - if mode&stat.S_IROTH:perms[7] = 'r' - if mode&stat.S_IWOTH:perms[8] = 'w' - if mode&stat.S_IXOTH:perms[9] = 'x' - # suid/sgid - if mode&stat.S_ISUID: - if perms[3] == 'x': perms[3] = 's' - else: perms[3] = 'S' - if mode&stat.S_ISGID: - if perms[6] == 'x': perms[6] = 's' - else: perms[6] = 'S' - l = perms.tostring() - l += str(s.st_nlink).rjust(5) + ' ' - un = str(s.st_uid) - l += un.ljust(9) - gr = str(s.st_gid) - l += gr.ljust(9) - sz = str(s.st_size) - l += sz.rjust(8) - l += ' ' - sixmo = 60 * 60 * 24 * 7 * 26 - if s.st_mtime + sixmo < time.time(): # last edited more than 6mo ago - l += time.strftime("%b %2d %Y ", time.localtime(s.st_mtime)) - else: - l += time.strftime("%b %2d %H:%S ", time.localtime(s.st_mtime)) - l += name - return l - diff --git a/tools/buildbot/pylibs/twisted/conch/manhole.py b/tools/buildbot/pylibs/twisted/conch/manhole.py deleted file mode 100644 index 50c52d5..0000000 --- a/tools/buildbot/pylibs/twisted/conch/manhole.py +++ /dev/null @@ -1,336 +0,0 @@ -# -*- test-case-name: twisted.conch.test.test_manhole -*- -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Line-input oriented interactive interpreter loop. - -Provides classes for handling Python source input and arbitrary output -interactively from a Twisted application. Also included is syntax coloring -code with support for VT102 terminals, control code handling (^C, ^D, ^Q), -and reasonable handling of Deferreds. - -@author: U{Jp Calderone} -""" - -import code, sys, StringIO, tokenize - -from twisted.conch import recvline - -from twisted.internet import defer -from twisted.python.htmlizer import TokenPrinter - -class FileWrapper: - """Minimal write-file-like object. - - Writes are translated into addOutput calls on an object passed to - __init__. Newlines are also converted from network to local style. - """ - - softspace = 0 - state = 'normal' - - def __init__(self, o): - self.o = o - - def flush(self): - pass - - def write(self, data): - self.o.addOutput(data.replace('\r\n', '\n')) - - def writelines(self, lines): - self.write(''.join(lines)) - -class ManholeInterpreter(code.InteractiveInterpreter): - """Interactive Interpreter with special output and Deferred support. - - Aside from the features provided by L{code.InteractiveInterpreter}, this - class captures sys.stdout output and redirects it to the appropriate - location (the Manhole protocol instance). It also treats Deferreds - which reach the top-level specially: each is formatted to the user with - a unique identifier and a new callback and errback added to it, each of - which will format the unique identifier and the result with which the - Deferred fires and then pass it on to the next participant in the - callback chain. - """ - - numDeferreds = 0 - def __init__(self, handler, locals=None, filename=""): - code.InteractiveInterpreter.__init__(self, locals) - self._pendingDeferreds = {} - self.handler = handler - self.filename = filename - self.resetBuffer() - - def resetBuffer(self): - """Reset the input buffer.""" - self.buffer = [] - - def push(self, line): - """Push a line to the interpreter. - - The line should not have a trailing newline; it may have - internal newlines. The line is appended to a buffer and the - interpreter's runsource() method is called with the - concatenated contents of the buffer as source. If this - indicates that the command was executed or invalid, the buffer - is reset; otherwise, the command is incomplete, and the buffer - is left as it was after the line was appended. The return - value is 1 if more input is required, 0 if the line was dealt - with in some way (this is the same as runsource()). - - """ - self.buffer.append(line) - source = "\n".join(self.buffer) - more = self.runsource(source, self.filename) - if not more: - self.resetBuffer() - return more - - def runcode(self, *a, **kw): - orighook, sys.displayhook = sys.displayhook, self.displayhook - try: - origout, sys.stdout = sys.stdout, FileWrapper(self.handler) - try: - code.InteractiveInterpreter.runcode(self, *a, **kw) - finally: - sys.stdout = origout - finally: - sys.displayhook = orighook - - def displayhook(self, obj): - self.locals['_'] = obj - if isinstance(obj, defer.Deferred): - # XXX Ick, where is my "hasFired()" interface? - if hasattr(obj, "result"): - self.write(repr(obj)) - elif id(obj) in self._pendingDeferreds: - self.write("" % (self._pendingDeferreds[id(obj)][0],)) - else: - d = self._pendingDeferreds - k = self.numDeferreds - d[id(obj)] = (k, obj) - self.numDeferreds += 1 - obj.addCallbacks(self._cbDisplayDeferred, self._ebDisplayDeferred, - callbackArgs=(k, obj), errbackArgs=(k, obj)) - self.write("" % (k,)) - elif obj is not None: - self.write(repr(obj)) - - def _cbDisplayDeferred(self, result, k, obj): - self.write("Deferred #%d called back: %r" % (k, result), True) - del self._pendingDeferreds[id(obj)] - return result - - def _ebDisplayDeferred(self, failure, k, obj): - self.write("Deferred #%d failed: %r" % (k, failure.getErrorMessage()), True) - del self._pendingDeferreds[id(obj)] - return failure - - def write(self, data, async=False): - self.handler.addOutput(data, async) - -CTRL_C = '\x03' -CTRL_D = '\x04' -CTRL_BACKSLASH = '\x1c' -CTRL_L = '\x0c' - -class Manhole(recvline.HistoricRecvLine): - """Mediator between a fancy line source and an interactive interpreter. - - This accepts lines from its transport and passes them on to a - L{ManholeInterpreter}. Control commands (^C, ^D, ^\) are also handled - with something approximating their normal terminal-mode behavior. It - can optionally be constructed with a dict which will be used as the - local namespace for any code executed. - """ - - namespace = None - - def __init__(self, namespace=None): - recvline.HistoricRecvLine.__init__(self) - if namespace is not None: - self.namespace = namespace.copy() - - def connectionMade(self): - recvline.HistoricRecvLine.connectionMade(self) - self.interpreter = ManholeInterpreter(self, self.namespace) - self.keyHandlers[CTRL_C] = self.handle_INT - self.keyHandlers[CTRL_D] = self.handle_EOF - self.keyHandlers[CTRL_L] = self.handle_FF - self.keyHandlers[CTRL_BACKSLASH] = self.handle_QUIT - - - def handle_INT(self): - """ - Handle ^C as an interrupt keystroke by resetting the current input - variables to their initial state. - """ - self.pn = 0 - self.lineBuffer = [] - self.lineBufferIndex = 0 - self.interpreter.resetBuffer() - - self.terminal.nextLine() - self.terminal.write("KeyboardInterrupt") - self.terminal.nextLine() - self.terminal.write(self.ps[self.pn]) - - - def handle_EOF(self): - if self.lineBuffer: - self.terminal.write('\a') - else: - self.handle_QUIT() - - - def handle_FF(self): - """ - Handle a 'form feed' byte - generally used to request a screen - refresh/redraw. - """ - self.terminal.eraseDisplay() - self.terminal.cursorHome() - self.drawInputLine() - - - def handle_QUIT(self): - self.terminal.loseConnection() - - - def _needsNewline(self): - w = self.terminal.lastWrite - return not w.endswith('\n') and not w.endswith('\x1bE') - - def addOutput(self, bytes, async=False): - if async: - self.terminal.eraseLine() - self.terminal.cursorBackward(len(self.lineBuffer) + len(self.ps[self.pn])) - - self.terminal.write(bytes) - - if async: - if self._needsNewline(): - self.terminal.nextLine() - - self.terminal.write(self.ps[self.pn]) - - if self.lineBuffer: - oldBuffer = self.lineBuffer - self.lineBuffer = [] - self.lineBufferIndex = 0 - - self._deliverBuffer(oldBuffer) - - def lineReceived(self, line): - more = self.interpreter.push(line) - self.pn = bool(more) - if self._needsNewline(): - self.terminal.nextLine() - self.terminal.write(self.ps[self.pn]) - -class VT102Writer: - """Colorizer for Python tokens. - - A series of tokens are written to instances of this object. Each is - colored in a particular way. The final line of the result of this is - generally added to the output. - """ - - typeToColor = { - 'identifier': '\x1b[31m', - 'keyword': '\x1b[32m', - 'parameter': '\x1b[33m', - 'variable': '\x1b[1;33m', - 'string': '\x1b[35m', - 'number': '\x1b[36m', - 'op': '\x1b[37m'} - - normalColor = '\x1b[0m' - - def __init__(self): - self.written = [] - - def color(self, type): - r = self.typeToColor.get(type, '') - return r - - def write(self, token, type=None): - if token and token != '\r': - c = self.color(type) - if c: - self.written.append(c) - self.written.append(token) - if c: - self.written.append(self.normalColor) - - def __str__(self): - s = ''.join(self.written) - return s.strip('\n').splitlines()[-1] - -def lastColorizedLine(source): - """Tokenize and colorize the given Python source. - - Returns a VT102-format colorized version of the last line of C{source}. - """ - w = VT102Writer() - p = TokenPrinter(w.write).printtoken - s = StringIO.StringIO(source) - - tokenize.tokenize(s.readline, p) - - return str(w) - -class ColoredManhole(Manhole): - """A REPL which syntax colors input as users type it. - """ - - def getSource(self): - """Return a string containing the currently entered source. - - This is only the code which will be considered for execution - next. - """ - return ('\n'.join(self.interpreter.buffer) + - '\n' + - ''.join(self.lineBuffer)) - - - def characterReceived(self, ch, moreCharactersComing): - if self.mode == 'insert': - self.lineBuffer.insert(self.lineBufferIndex, ch) - else: - self.lineBuffer[self.lineBufferIndex:self.lineBufferIndex+1] = [ch] - self.lineBufferIndex += 1 - - if moreCharactersComing: - # Skip it all, we'll get called with another character in - # like 2 femtoseconds. - return - - if ch == ' ': - # Don't bother to try to color whitespace - self.terminal.write(ch) - return - - source = self.getSource() - - # Try to write some junk - try: - coloredLine = lastColorizedLine(source) - except tokenize.TokenError: - # We couldn't do it. Strange. Oh well, just add the character. - self.terminal.write(ch) - else: - # Success! Clear the source on this line. - self.terminal.eraseLine() - self.terminal.cursorBackward(len(self.lineBuffer) + len(self.ps[self.pn]) - 1) - - # And write a new, colorized one. - self.terminal.write(self.ps[self.pn] + coloredLine) - - # And move the cursor to where it belongs - n = len(self.lineBuffer) - self.lineBufferIndex - if n: - self.terminal.cursorBackward(n) diff --git a/tools/buildbot/pylibs/twisted/conch/manhole_ssh.py b/tools/buildbot/pylibs/twisted/conch/manhole_ssh.py deleted file mode 100644 index 7757fad..0000000 --- a/tools/buildbot/pylibs/twisted/conch/manhole_ssh.py +++ /dev/null @@ -1,146 +0,0 @@ -# -*- test-case-name: twisted.conch.test.test_manhole -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -insults/SSH integration support. - -@author: U{Jp Calderone} -""" - -from zope.interface import implements - -from twisted.conch import avatar, interfaces as iconch, error as econch -from twisted.conch.ssh import factory, keys, session -from twisted.cred import credentials, checkers, portal -from twisted.python import components - -from twisted.conch.insults import insults - -class _Glue: - """A feeble class for making one attribute look like another. - - This should be replaced with a real class at some point, probably. - Try not to write new code that uses it. - """ - def __init__(self, **kw): - self.__dict__.update(kw) - - def __getattr__(self, name): - raise AttributeError(self.name, "has no attribute", name) - -class TerminalSessionTransport: - def __init__(self, proto, chainedProtocol, avatar, width, height): - self.proto = proto - self.avatar = avatar - self.chainedProtocol = chainedProtocol - - session = self.proto.session - - self.proto.makeConnection( - _Glue(write=self.chainedProtocol.dataReceived, - loseConnection=lambda: avatar.conn.sendClose(session), - name="SSH Proto Transport")) - - def loseConnection(): - self.proto.loseConnection() - - self.chainedProtocol.makeConnection( - _Glue(write=self.proto.write, - loseConnection=loseConnection, - name="Chained Proto Transport")) - - # XXX TODO - # chainedProtocol is supposed to be an ITerminalTransport, - # maybe. That means perhaps its terminalProtocol attribute is - # an ITerminalProtocol, it could be. So calling terminalSize - # on that should do the right thing But it'd be nice to clean - # this bit up. - self.chainedProtocol.terminalProtocol.terminalSize(width, height) - -class TerminalSession(components.Adapter): - implements(iconch.ISession) - - transportFactory = TerminalSessionTransport - chainedProtocolFactory = insults.ServerProtocol - - def getPty(self, term, windowSize, attrs): - self.height, self.width = windowSize[:2] - - def openShell(self, proto): - self.transportFactory( - proto, self.chainedProtocolFactory(), - iconch.IConchUser(self.original), - self.width, self.height) - - def execCommand(self, proto, cmd): - raise econch.ConchError("Cannot execute commands") - - def closed(self): - pass - -class TerminalUser(avatar.ConchUser, components.Adapter): - def __init__(self, original, avatarId): - components.Adapter.__init__(self, original) - avatar.ConchUser.__init__(self) - self.channelLookup['session'] = session.SSHSession - -class TerminalRealm: - userFactory = TerminalUser - sessionFactory = TerminalSession - - transportFactory = TerminalSessionTransport - chainedProtocolFactory = insults.ServerProtocol - - def _getAvatar(self, avatarId): - comp = components.Componentized() - user = self.userFactory(comp, avatarId) - sess = self.sessionFactory(comp) - - sess.transportFactory = self.transportFactory - sess.chainedProtocolFactory = self.chainedProtocolFactory - - comp.setComponent(iconch.IConchUser, user) - comp.setComponent(iconch.ISession, sess) - - return user - - def __init__(self, transportFactory=None): - if transportFactory is not None: - self.transportFactory = transportFactory - - def requestAvatar(self, avatarId, mind, *interfaces): - for i in interfaces: - if i is iconch.IConchUser: - return (iconch.IConchUser, - self._getAvatar(avatarId), - lambda: None) - raise NotImplementedError() - -class ConchFactory(factory.SSHFactory): - publicKey = 'ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAGEArzJx8OYOnJmzf4tfBEvLi8DVPrJ3/c9k2I/Az64fxjHf9imyRJbixtQhlH9lfNjUIx+4LmrJH5QNRsFporcHDKOTwTTYLh5KmRpslkYHRivcJSkbh/C+BR3utDS555mV' - - publicKeys = { - 'ssh-rsa' : keys.Key.fromString(publicKey) - } - del publicKey - - privateKey = """-----BEGIN RSA PRIVATE KEY----- -MIIByAIBAAJhAK8ycfDmDpyZs3+LXwRLy4vA1T6yd/3PZNiPwM+uH8Yx3/YpskSW -4sbUIZR/ZXzY1CMfuC5qyR+UDUbBaaK3Bwyjk8E02C4eSpkabJZGB0Yr3CUpG4fw -vgUd7rQ0ueeZlQIBIwJgbh+1VZfr7WftK5lu7MHtqE1S1vPWZQYE3+VUn8yJADyb -Z4fsZaCrzW9lkIqXkE3GIY+ojdhZhkO1gbG0118sIgphwSWKRxK0mvh6ERxKqIt1 -xJEJO74EykXZV4oNJ8sjAjEA3J9r2ZghVhGN6V8DnQrTk24Td0E8hU8AcP0FVP+8 -PQm/g/aXf2QQkQT+omdHVEJrAjEAy0pL0EBH6EVS98evDCBtQw22OZT52qXlAwZ2 -gyTriKFVoqjeEjt3SZKKqXHSApP/AjBLpF99zcJJZRq2abgYlf9lv1chkrWqDHUu -DZttmYJeEfiFBBavVYIF1dOlZT0G8jMCMBc7sOSZodFnAiryP+Qg9otSBjJ3bQML -pSTqy7c3a2AScC/YyOwkDaICHnnD3XyjMwIxALRzl0tQEKMXs6hH8ToUdlLROCrP -EhQ0wahUTCk1gKA4uPD6TMTChavbh4K63OvbKg== ------END RSA PRIVATE KEY-----""" - privateKeys = { - 'ssh-rsa' : keys.Key.fromString(privateKey) - } - del privateKey - - def __init__(self, portal): - self.portal = portal diff --git a/tools/buildbot/pylibs/twisted/conch/manhole_tap.py b/tools/buildbot/pylibs/twisted/conch/manhole_tap.py deleted file mode 100644 index a0e7d60..0000000 --- a/tools/buildbot/pylibs/twisted/conch/manhole_tap.py +++ /dev/null @@ -1,128 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -TAP plugin for creating telnet- and ssh-accessible manhole servers. - -@author: U{Jp Calderone} -""" - -from zope.interface import implements - -from twisted.internet import protocol -from twisted.application import service, strports -from twisted.conch.ssh import session -from twisted.conch import interfaces as iconch -from twisted.cred import portal, checkers -from twisted.python import usage - -from twisted.conch.insults import insults -from twisted.conch import manhole, manhole_ssh, telnet - -class makeTelnetProtocol: - def __init__(self, portal): - self.portal = portal - - def __call__(self): - auth = telnet.AuthenticatingTelnetProtocol - args = (self.portal,) - return telnet.TelnetTransport(auth, *args) - -class chainedProtocolFactory: - def __init__(self, namespace): - self.namespace = namespace - - def __call__(self): - return insults.ServerProtocol(manhole.ColoredManhole, self.namespace) - -class _StupidRealm: - implements(portal.IRealm) - - def __init__(self, proto, *a, **kw): - self.protocolFactory = proto - self.protocolArgs = a - self.protocolKwArgs = kw - - def requestAvatar(self, avatarId, *interfaces): - if telnet.ITelnetProtocol in interfaces: - return (telnet.ITelnetProtocol, - self.protocolFactory(*self.protocolArgs, **self.protocolKwArgs), - lambda: None) - raise NotImplementedError() - -class Options(usage.Options): - optParameters = [ - ["telnetPort", "t", None, "strports description of the address on which to listen for telnet connections"], - ["sshPort", "s", None, "strports description of the address on which to listen for ssh connections"], - ["passwd", "p", "/etc/passwd", "name of a passwd(5)-format username/password file"]] - - def __init__(self): - usage.Options.__init__(self) - self.users = [] - self['namespace'] = None - - def opt_user(self, name): - self.users.append(name) - - def postOptions(self): - if self['telnetPort'] is None and self['sshPort'] is None: - raise usage.UsageError("At least one of --telnetPort and --sshPort must be specified") - -def makeService(options): - """Create a manhole server service. - - @type options: C{dict} - @param options: A mapping describing the configuration of - the desired service. Recognized key/value pairs are:: - - "telnetPort": strports description of the address on which - to listen for telnet connections. If None, - no telnet service will be started. - - "sshPort": strports description of the address on which to - listen for ssh connections. If None, no ssh - service will be started. - - "namespace": dictionary containing desired initial locals - for manhole connections. If None, an empty - dictionary will be used. - - "passwd": Name of a passwd(5)-format username/password file. - - @rtype: L{twisted.application.service.IService} - @return: A manhole service. - """ - - svc = service.MultiService() - - namespace = options['namespace'] - if namespace is None: - namespace = {} - - checker = checkers.FilePasswordDB(options['passwd']) - - if options['telnetPort']: - telnetRealm = _StupidRealm(telnet.TelnetBootstrapProtocol, - insults.ServerProtocol, - manhole.ColoredManhole, - namespace) - - telnetPortal = portal.Portal(telnetRealm, [checker]) - - telnetFactory = protocol.ServerFactory() - telnetFactory.protocol = makeTelnetProtocol(telnetPortal) - telnetService = strports.service(options['telnetPort'], - telnetFactory) - telnetService.setServiceParent(svc) - - if options['sshPort']: - sshRealm = manhole_ssh.TerminalRealm() - sshRealm.chainedProtocolFactory = chainedProtocolFactory(namespace) - - sshPortal = portal.Portal(sshRealm, [checker]) - sshFactory = manhole_ssh.ConchFactory(sshPortal) - sshService = strports.service(options['sshPort'], - sshFactory) - sshService.setServiceParent(svc) - - return svc diff --git a/tools/buildbot/pylibs/twisted/conch/mixin.py b/tools/buildbot/pylibs/twisted/conch/mixin.py deleted file mode 100644 index 5dbbab1..0000000 --- a/tools/buildbot/pylibs/twisted/conch/mixin.py +++ /dev/null @@ -1,49 +0,0 @@ -# -*- test-case-name: twisted.conch.test.test_mixin -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Experimental optimization - -This module provides a single mixin class which allows protocols to -collapse numerous small writes into a single larger one. - -@author: U{Jp Calderone} -""" - -from twisted.internet import reactor - -class BufferingMixin: - """Mixin which adds write buffering. - """ - _delayedWriteCall = None - bytes = None - - DELAY = 0.0 - - def schedule(self): - return reactor.callLater(self.DELAY, self.flush) - - def reschedule(self, token): - token.reset(self.DELAY) - - def write(self, bytes): - """Buffer some bytes to be written soon. - - Every call to this function delays the real write by C{self.DELAY} - seconds. When the delay expires, all collected bytes are written - to the underlying transport using L{ITransport.writeSequence}. - """ - if self._delayedWriteCall is None: - self.bytes = [] - self._delayedWriteCall = self.schedule() - else: - self.reschedule(self._delayedWriteCall) - self.bytes.append(bytes) - - def flush(self): - """Flush the buffer immediately. - """ - self._delayedWriteCall = None - self.transport.writeSequence(self.bytes) - self.bytes = None diff --git a/tools/buildbot/pylibs/twisted/conch/openssh_compat/__init__.py b/tools/buildbot/pylibs/twisted/conch/openssh_compat/__init__.py deleted file mode 100644 index 5903d84..0000000 --- a/tools/buildbot/pylibs/twisted/conch/openssh_compat/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -""" -Support for OpenSSH configuration files. - -Maintainer: U{Paul Swartz} -""" - diff --git a/tools/buildbot/pylibs/twisted/conch/openssh_compat/factory.py b/tools/buildbot/pylibs/twisted/conch/openssh_compat/factory.py deleted file mode 100644 index e14d7e2..0000000 --- a/tools/buildbot/pylibs/twisted/conch/openssh_compat/factory.py +++ /dev/null @@ -1,43 +0,0 @@ -from twisted.conch.ssh import keys, factory, common -from twisted.python import log -import primes -import os - -class OpenSSHFactory(factory.SSHFactory): - dataRoot = '/usr/local/etc' - moduliRoot = '/usr/local/etc' # for openbsd which puts moduli in a different - # directory from keys - def getPublicKeys(self): - ks = {} - for file in os.listdir(self.dataRoot): - if file[:9] == 'ssh_host_' and file[-8:]=='_key.pub': - try: - k = keys.getPublicKeyString(self.dataRoot+'/'+file) - t = common.getNS(k)[0] - ks[t] = k - except Exception, e: - log.msg('bad public key file %s: %s' % (file,e)) - return ks - def getPrivateKeys(self): - ks = {} - euid,egid = os.geteuid(), os.getegid() - os.setegid(0) # gain priviledges - os.seteuid(0) - for file in os.listdir(self.dataRoot): - if file[:9] == 'ssh_host_' and file[-4:]=='_key': - try: - k = keys.getPrivateKeyObject(self.dataRoot+'/'+file) - t = keys.objectType(k) - ks[t] = k - except Exception, e: - log.msg('bad private key file %s: %s' % (file, e)) - os.setegid(egid) # drop them just as quickily - os.seteuid(euid) - return ks - - def getPrimes(self): - try: - return primes.parseModuliFile(self.moduliRoot+'/moduli') - except IOError: - return None - diff --git a/tools/buildbot/pylibs/twisted/conch/openssh_compat/primes.py b/tools/buildbot/pylibs/twisted/conch/openssh_compat/primes.py deleted file mode 100644 index e47ad97..0000000 --- a/tools/buildbot/pylibs/twisted/conch/openssh_compat/primes.py +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -""" -Parsing for the moduli file, which contains Diffie-Hellman prime groups. - -Maintainer: U{Paul Swartz} -""" - -def parseModuliFile(filename): - lines = open(filename).readlines() - primes = {} - for l in lines: - l = l.strip() - if not l or l[0]=='#': - continue - tim, typ, tst, tri, size, gen, mod = l.split() - size = int(size) + 1 - gen = long(gen) - mod = long(mod, 16) - if not primes.has_key(size): - primes[size] = [] - primes[size].append((gen, mod)) - return primes diff --git a/tools/buildbot/pylibs/twisted/conch/recvline.py b/tools/buildbot/pylibs/twisted/conch/recvline.py deleted file mode 100644 index 6f1a0ca..0000000 --- a/tools/buildbot/pylibs/twisted/conch/recvline.py +++ /dev/null @@ -1,328 +0,0 @@ -# -*- test-case-name: twisted.conch.test.test_recvline -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Basic line editing support. - -@author: U{Jp Calderone} -""" - -import string - -from zope.interface import implements - -from twisted.conch.insults import insults, helper - -from twisted.python import log, reflect - -_counters = {} -class Logging(object): - """Wrapper which logs attribute lookups. - - This was useful in debugging something, I guess. I forget what. - It can probably be deleted or moved somewhere more appropriate. - Nothing special going on here, really. - """ - def __init__(self, original): - self.original = original - key = reflect.qual(original.__class__) - count = _counters.get(key, 0) - _counters[key] = count + 1 - self._logFile = file(key + '-' + str(count), 'w') - - def __str__(self): - return str(super(Logging, self).__getattribute__('original')) - - def __repr__(self): - return repr(super(Logging, self).__getattribute__('original')) - - def __getattribute__(self, name): - original = super(Logging, self).__getattribute__('original') - logFile = super(Logging, self).__getattribute__('_logFile') - logFile.write(name + '\n') - return getattr(original, name) - -class TransportSequence(object): - """An L{ITerminalTransport} implementation which forwards calls to - one or more other L{ITerminalTransport}s. - - This is a cheap way for servers to keep track of the state they - expect the client to see, since all terminal manipulations can be - send to the real client and to a terminal emulator that lives in - the server process. - """ - implements(insults.ITerminalTransport) - - for keyID in ('UP_ARROW', 'DOWN_ARROW', 'RIGHT_ARROW', 'LEFT_ARROW', - 'HOME', 'INSERT', 'DELETE', 'END', 'PGUP', 'PGDN', - 'F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'F9', - 'F10', 'F11', 'F12'): - exec '%s = object()' % (keyID,) - - TAB = '\t' - BACKSPACE = '\x7f' - - def __init__(self, *transports): - assert transports, "Cannot construct a TransportSequence with no transports" - self.transports = transports - - for method in insults.ITerminalTransport: - exec """\ -def %s(self, *a, **kw): - for tpt in self.transports: - result = tpt.%s(*a, **kw) - return result -""" % (method, method) - -class LocalTerminalBufferMixin(object): - """A mixin for RecvLine subclasses which records the state of the terminal. - - This is accomplished by performing all L{ITerminalTransport} operations on both - the transport passed to makeConnection and an instance of helper.TerminalBuffer. - - @ivar terminalCopy: A L{helper.TerminalBuffer} instance which efforts - will be made to keep up to date with the actual terminal - associated with this protocol instance. - """ - - def makeConnection(self, transport): - self.terminalCopy = helper.TerminalBuffer() - self.terminalCopy.connectionMade() - return super(LocalTerminalBufferMixin, self).makeConnection( - TransportSequence(transport, self.terminalCopy)) - - def __str__(self): - return str(self.terminalCopy) - -class RecvLine(insults.TerminalProtocol): - """L{TerminalProtocol} which adds line editing features. - - Clients will be prompted for lines of input with all the usual - features: character echoing, left and right arrow support for - moving the cursor to different areas of the line buffer, backspace - and delete for removing characters, and insert for toggling - between typeover and insert mode. Tabs will be expanded to enough - spaces to move the cursor to the next tabstop (every four - characters by default). Enter causes the line buffer to be - cleared and the line to be passed to the lineReceived() method - which, by default, does nothing. Subclasses are responsible for - redrawing the input prompt (this will probably change). - """ - width = 80 - height = 24 - - TABSTOP = 4 - - ps = ('>>> ', '... ') - pn = 0 - - def connectionMade(self): - # A list containing the characters making up the current line - self.lineBuffer = [] - - # A zero-based (wtf else?) index into self.lineBuffer. - # Indicates the current cursor position. - self.lineBufferIndex = 0 - - t = self.terminal - # A map of keyIDs to bound instance methods. - self.keyHandlers = { - t.LEFT_ARROW: self.handle_LEFT, - t.RIGHT_ARROW: self.handle_RIGHT, - t.TAB: self.handle_TAB, - - # Both of these should not be necessary, but figuring out - # which is necessary is a huge hassle. - '\r': self.handle_RETURN, - '\n': self.handle_RETURN, - - t.BACKSPACE: self.handle_BACKSPACE, - t.DELETE: self.handle_DELETE, - t.INSERT: self.handle_INSERT, - t.HOME: self.handle_HOME, - t.END: self.handle_END} - - self.initializeScreen() - - def initializeScreen(self): - # Hmm, state sucks. Oh well. - # For now we will just take over the whole terminal. - self.terminal.reset() - self.terminal.write(self.ps[self.pn]) - # XXX Note: I would prefer to default to starting in insert - # mode, however this does not seem to actually work! I do not - # know why. This is probably of interest to implementors - # subclassing RecvLine. - - # XXX XXX Note: But the unit tests all expect the initial mode - # to be insert right now. Fuck, there needs to be a way to - # query the current mode or something. - # self.setTypeoverMode() - self.setInsertMode() - - def currentLineBuffer(self): - s = ''.join(self.lineBuffer) - return s[:self.lineBufferIndex], s[self.lineBufferIndex:] - - def setInsertMode(self): - self.mode = 'insert' - self.terminal.setModes([insults.modes.IRM]) - - def setTypeoverMode(self): - self.mode = 'typeover' - self.terminal.resetModes([insults.modes.IRM]) - - def drawInputLine(self): - """ - Write a line containing the current input prompt and the current line - buffer at the current cursor position. - """ - self.terminal.write(self.ps[self.pn] + ''.join(self.lineBuffer)) - - def terminalSize(self, width, height): - # XXX - Clear the previous input line, redraw it at the new - # cursor position - self.terminal.eraseDisplay() - self.terminal.cursorHome() - self.width = width - self.height = height - self.drawInputLine() - - def unhandledControlSequence(self, seq): - pass - - def keystrokeReceived(self, keyID, modifier): - m = self.keyHandlers.get(keyID) - if m is not None: - m() - elif keyID in string.printable: - self.characterReceived(keyID, False) - else: - log.msg("Received unhandled keyID: %r" % (keyID,)) - - def characterReceived(self, ch, moreCharactersComing): - if self.mode == 'insert': - self.lineBuffer.insert(self.lineBufferIndex, ch) - else: - self.lineBuffer[self.lineBufferIndex:self.lineBufferIndex+1] = [ch] - self.lineBufferIndex += 1 - self.terminal.write(ch) - - def handle_TAB(self): - n = self.TABSTOP - (len(self.lineBuffer) % self.TABSTOP) - self.terminal.cursorForward(n) - self.lineBufferIndex += n - self.lineBuffer.extend(' ' * n) - - def handle_LEFT(self): - if self.lineBufferIndex > 0: - self.lineBufferIndex -= 1 - self.terminal.cursorBackward() - - def handle_RIGHT(self): - if self.lineBufferIndex < len(self.lineBuffer): - self.lineBufferIndex += 1 - self.terminal.cursorForward() - - def handle_HOME(self): - if self.lineBufferIndex: - self.terminal.cursorBackward(self.lineBufferIndex) - self.lineBufferIndex = 0 - - def handle_END(self): - offset = len(self.lineBuffer) - self.lineBufferIndex - if offset: - self.terminal.cursorForward(offset) - self.lineBufferIndex = len(self.lineBuffer) - - def handle_BACKSPACE(self): - if self.lineBufferIndex > 0: - self.lineBufferIndex -= 1 - del self.lineBuffer[self.lineBufferIndex] - self.terminal.cursorBackward() - self.terminal.deleteCharacter() - - def handle_DELETE(self): - if self.lineBufferIndex < len(self.lineBuffer): - del self.lineBuffer[self.lineBufferIndex] - self.terminal.deleteCharacter() - - def handle_RETURN(self): - line = ''.join(self.lineBuffer) - self.lineBuffer = [] - self.lineBufferIndex = 0 - self.terminal.nextLine() - self.lineReceived(line) - - def handle_INSERT(self): - assert self.mode in ('typeover', 'insert') - if self.mode == 'typeover': - self.setInsertMode() - else: - self.setTypeoverMode() - - def lineReceived(self, line): - pass - -class HistoricRecvLine(RecvLine): - """L{TerminalProtocol} which adds both basic line-editing features and input history. - - Everything supported by L{RecvLine} is also supported by this class. In addition, the - up and down arrows traverse the input history. Each received line is automatically - added to the end of the input history. - """ - def connectionMade(self): - RecvLine.connectionMade(self) - - self.historyLines = [] - self.historyPosition = 0 - - t = self.terminal - self.keyHandlers.update({t.UP_ARROW: self.handle_UP, - t.DOWN_ARROW: self.handle_DOWN}) - - def currentHistoryBuffer(self): - b = tuple(self.historyLines) - return b[:self.historyPosition], b[self.historyPosition:] - - def _deliverBuffer(self, buf): - if buf: - for ch in buf[:-1]: - self.characterReceived(ch, True) - self.characterReceived(buf[-1], False) - - def handle_UP(self): - if self.lineBuffer and self.historyPosition == len(self.historyLines): - self.historyLines.append(self.lineBuffer) - if self.historyPosition > 0: - self.handle_HOME() - self.terminal.eraseToLineEnd() - - self.historyPosition -= 1 - self.lineBuffer = [] - - self._deliverBuffer(self.historyLines[self.historyPosition]) - - def handle_DOWN(self): - if self.historyPosition < len(self.historyLines) - 1: - self.handle_HOME() - self.terminal.eraseToLineEnd() - - self.historyPosition += 1 - self.lineBuffer = [] - - self._deliverBuffer(self.historyLines[self.historyPosition]) - else: - self.handle_HOME() - self.terminal.eraseToLineEnd() - - self.historyPosition = len(self.historyLines) - self.lineBuffer = [] - self.lineBufferIndex = 0 - - def handle_RETURN(self): - if self.lineBuffer: - self.historyLines.append(''.join(self.lineBuffer)) - self.historyPosition = len(self.historyLines) - return RecvLine.handle_RETURN(self) diff --git a/tools/buildbot/pylibs/twisted/conch/scripts/__init__.py b/tools/buildbot/pylibs/twisted/conch/scripts/__init__.py deleted file mode 100644 index 63fdb3d..0000000 --- a/tools/buildbot/pylibs/twisted/conch/scripts/__init__.py +++ /dev/null @@ -1 +0,0 @@ -'conch scripts' diff --git a/tools/buildbot/pylibs/twisted/conch/scripts/cftp.py b/tools/buildbot/pylibs/twisted/conch/scripts/cftp.py deleted file mode 100644 index 9a77b8d..0000000 --- a/tools/buildbot/pylibs/twisted/conch/scripts/cftp.py +++ /dev/null @@ -1,799 +0,0 @@ -# -*- test-case-name: twisted.conch.test.test_cftp -*- -# -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -# $Id: cftp.py,v 1.65 2004/03/11 00:29:14 z3p Exp $ - -#""" Implementation module for the `cftp` command. -#""" -from twisted.conch.client import agent, connect, default, options -from twisted.conch.error import ConchError -from twisted.conch.ssh import connection, common -from twisted.conch.ssh import channel, filetransfer -from twisted.protocols import basic -from twisted.internet import reactor, stdio, defer, utils -from twisted.python import log, usage, failure - -import os, sys, getpass, struct, tty, fcntl, base64, signal, stat, errno -import fnmatch, pwd, time, glob - -class ClientOptions(options.ConchOptions): - - synopsis = """Usage: cftp [options] [user@]host - cftp [options] [user@]host[:dir[/]] - cftp [options] [user@]host[:file [localfile]] -""" - - optParameters = [ - ['buffersize', 'B', 32768, 'Size of the buffer to use for sending/receiving.'], - ['batchfile', 'b', None, 'File to read commands from, or \'-\' for stdin.'], - ['requests', 'R', 5, 'Number of requests to make before waiting for a reply.'], - ['subsystem', 's', 'sftp', 'Subsystem/server program to connect to.']] - zsh_altArgDescr = {"buffersize":"Size of send/receive buffer (default: 32768)"} - #zsh_multiUse = ["foo", "bar"] - #zsh_mutuallyExclusive = [("foo", "bar"), ("bar", "baz")] - #zsh_actions = {"foo":'_files -g "*.foo"', "bar":"(one two three)"} - #zsh_actionDescr = {"logfile":"log file name", "random":"random seed"} - zsh_extras = ['2::localfile:{if [[ $words[1] == *:* ]]; then; _files; fi}'] - - def parseArgs(self, host, localPath=None): - self['remotePath'] = '' - if ':' in host: - host, self['remotePath'] = host.split(':', 1) - self['remotePath'].rstrip('/') - self['host'] = host - self['localPath'] = localPath - -def run(): -# import hotshot -# prof = hotshot.Profile('cftp.prof') -# prof.start() - args = sys.argv[1:] - if '-l' in args: # cvs is an idiot - i = args.index('-l') - args = args[i:i+2]+args - del args[i+2:i+4] - options = ClientOptions() - try: - options.parseOptions(args) - except usage.UsageError, u: - print 'ERROR: %s' % u - sys.exit(1) - if options['log']: - realout = sys.stdout - log.startLogging(sys.stderr) - sys.stdout = realout - else: - log.discardLogs() - doConnect(options) - reactor.run() -# prof.stop() -# prof.close() - -def handleError(): - from twisted.python import failure - global exitStatus - exitStatus = 2 - try: - reactor.stop() - except: pass - log.err(failure.Failure()) - raise - -def doConnect(options): -# log.deferr = handleError # HACK - if '@' in options['host']: - options['user'], options['host'] = options['host'].split('@',1) - host = options['host'] - if not options['user']: - options['user'] = getpass.getuser() - if not options['port']: - options['port'] = 22 - else: - options['port'] = int(options['port']) - host = options['host'] - port = options['port'] - conn = SSHConnection() - conn.options = options - vhk = default.verifyHostKey - uao = default.SSHUserAuthClient(options['user'], options, conn) - connect.connect(host, port, options, vhk, uao).addErrback(_ebExit) - -def _ebExit(f): - #global exitStatus - if hasattr(f.value, 'value'): - s = f.value.value - else: - s = str(f) - print s - #exitStatus = "conch: exiting with error %s" % f - try: - reactor.stop() - except: pass - -def _ignore(*args): pass - -class FileWrapper: - - def __init__(self, f): - self.f = f - self.total = 0.0 - f.seek(0, 2) # seek to the end - self.size = f.tell() - - def __getattr__(self, attr): - return getattr(self.f, attr) - -class StdioClient(basic.LineReceiver): - - ps = 'cftp> ' - delimiter = '\n' - - def __init__(self, client, f = None): - self.client = client - self.currentDirectory = '' - self.file = f - self.useProgressBar = (not f and 1) or 0 - - def connectionMade(self): - self.client.realPath('').addCallback(self._cbSetCurDir) - - def _cbSetCurDir(self, path): - self.currentDirectory = path - self._newLine() - - def lineReceived(self, line): - if self.client.transport.localClosed: - return - log.msg('got line %s' % repr(line)) - line = line.lstrip() - if not line: - self._newLine() - return - if self.file and line.startswith('-'): - self.ignoreErrors = 1 - line = line[1:] - else: - self.ignoreErrors = 0 - if ' ' in line: - command, rest = line.split(' ', 1) - rest = rest.lstrip() - else: - command, rest = line, '' - if command.startswith('!'): # command - f = self.cmd_EXEC - rest = (command[1:] + ' ' + rest).strip() - else: - command = command.upper() - log.msg('looking up cmd %s' % command) - f = getattr(self, 'cmd_%s' % command, None) - if f is not None: - d = defer.maybeDeferred(f, rest) - d.addCallback(self._cbCommand) - d.addErrback(self._ebCommand) - else: - self._ebCommand(failure.Failure(NotImplementedError( - "No command called `%s'" % command))) - self._newLine() - - def _printFailure(self, f): - log.msg(f) - e = f.trap(NotImplementedError, filetransfer.SFTPError, OSError, IOError) - if e == NotImplementedError: - self.transport.write(self.cmd_HELP('')) - elif e == filetransfer.SFTPError: - self.transport.write("remote error %i: %s\n" % - (f.value.code, f.value.message)) - elif e in (OSError, IOError): - self.transport.write("local error %i: %s\n" % - (f.value.errno, f.value.strerror)) - - def _newLine(self): - if self.client.transport.localClosed: - return - self.transport.write(self.ps) - self.ignoreErrors = 0 - if self.file: - l = self.file.readline() - if not l: - self.client.transport.loseConnection() - else: - self.transport.write(l) - self.lineReceived(l.strip()) - - def _cbCommand(self, result): - if result is not None: - self.transport.write(result) - if not result.endswith('\n'): - self.transport.write('\n') - self._newLine() - - def _ebCommand(self, f): - self._printFailure(f) - if self.file and not self.ignoreErrors: - self.client.transport.loseConnection() - self._newLine() - - def cmd_CD(self, path): - path, rest = self._getFilename(path) - if not path.endswith('/'): - path += '/' - newPath = path and os.path.join(self.currentDirectory, path) or '' - d = self.client.openDirectory(newPath) - d.addCallback(self._cbCd) - d.addErrback(self._ebCommand) - return d - - def _cbCd(self, directory): - directory.close() - d = self.client.realPath(directory.name) - d.addCallback(self._cbCurDir) - return d - - def _cbCurDir(self, path): - self.currentDirectory = path - - def cmd_CHGRP(self, rest): - grp, rest = rest.split(None, 1) - path, rest = self._getFilename(rest) - grp = int(grp) - d = self.client.getAttrs(path) - d.addCallback(self._cbSetUsrGrp, path, grp=grp) - return d - - def cmd_CHMOD(self, rest): - mod, rest = rest.split(None, 1) - path, rest = self._getFilename(rest) - mod = int(mod, 8) - d = self.client.setAttrs(path, {'permissions':mod}) - d.addCallback(_ignore) - return d - - def cmd_CHOWN(self, rest): - usr, rest = rest.split(None, 1) - path, rest = self._getFilename(rest) - usr = int(usr) - d = self.client.getAttrs(path) - d.addCallback(self._cbSetUsrGrp, path, usr=usr) - return d - - def _cbSetUsrGrp(self, attrs, path, usr=None, grp=None): - new = {} - new['uid'] = (usr is not None) and usr or attrs['uid'] - new['gid'] = (grp is not None) and grp or attrs['gid'] - d = self.client.setAttrs(path, new) - d.addCallback(_ignore) - return d - - def cmd_GET(self, rest): - remote, rest = self._getFilename(rest) - if '*' in remote or '?' in remote: # wildcard - if rest: - local, rest = self._getFilename(rest) - if not os.path.isdir(local): - return "Wildcard get with non-directory target." - else: - local = '' - d = self._remoteGlob(remote) - d.addCallback(self._cbGetMultiple, local) - return d - if rest: - local, rest = self._getFilename(rest) - else: - local = os.path.split(remote)[1] - log.msg((remote, local)) - lf = file(local, 'w', 0) - path = os.path.join(self.currentDirectory, remote) - d = self.client.openFile(path, filetransfer.FXF_READ, {}) - d.addCallback(self._cbGetOpenFile, lf) - d.addErrback(self._ebCloseLf, lf) - return d - - def _cbGetMultiple(self, files, local): - #if self._useProgressBar: # one at a time - # XXX this can be optimized for times w/o progress bar - return self._cbGetMultipleNext(None, files, local) - - def _cbGetMultipleNext(self, res, files, local): - if isinstance(res, failure.Failure): - self._printFailure(res) - elif res: - self.transport.write(res) - if not res.endswith('\n'): - self.transport.write('\n') - if not files: - return - f = files.pop(0)[0] - lf = file(os.path.join(local, os.path.split(f)[1]), 'w', 0) - path = os.path.join(self.currentDirectory, f) - d = self.client.openFile(path, filetransfer.FXF_READ, {}) - d.addCallback(self._cbGetOpenFile, lf) - d.addErrback(self._ebCloseLf, lf) - d.addBoth(self._cbGetMultipleNext, files, local) - return d - - def _ebCloseLf(self, f, lf): - lf.close() - return f - - def _cbGetOpenFile(self, rf, lf): - return rf.getAttrs().addCallback(self._cbGetFileSize, rf, lf) - - def _cbGetFileSize(self, attrs, rf, lf): - if not stat.S_ISREG(attrs['permissions']): - rf.close() - lf.close() - return "Can't get non-regular file: %s" % rf.name - rf.size = attrs['size'] - bufferSize = self.client.transport.conn.options['buffersize'] - numRequests = self.client.transport.conn.options['requests'] - rf.total = 0.0 - dList = [] - chunks = [] - startTime = time.time() - for i in range(numRequests): - d = self._cbGetRead('', rf, lf, chunks, 0, bufferSize, startTime) - dList.append(d) - dl = defer.DeferredList(dList, fireOnOneErrback=1) - dl.addCallback(self._cbGetDone, rf, lf) - return dl - - def _getNextChunk(self, chunks): - end = 0 - for chunk in chunks: - if end == 'eof': - return # nothing more to get - if end != chunk[0]: - i = chunks.index(chunk) - chunks.insert(i, (end, chunk[0])) - return (end, chunk[0] - end) - end = chunk[1] - bufSize = int(self.client.transport.conn.options['buffersize']) - chunks.append((end, end + bufSize)) - return (end, bufSize) - - def _cbGetRead(self, data, rf, lf, chunks, start, size, startTime): - if data and isinstance(data, failure.Failure): - log.msg('get read err: %s' % data) - reason = data - reason.trap(EOFError) - i = chunks.index((start, start + size)) - del chunks[i] - chunks.insert(i, (start, 'eof')) - elif data: - log.msg('get read data: %i' % len(data)) - lf.seek(start) - lf.write(data) - if len(data) != size: - log.msg('got less than we asked for: %i < %i' % - (len(data), size)) - i = chunks.index((start, start + size)) - del chunks[i] - chunks.insert(i, (start, start + len(data))) - rf.total += len(data) - if self.useProgressBar: - self._printProgessBar(rf, startTime) - chunk = self._getNextChunk(chunks) - if not chunk: - return - else: - start, length = chunk - log.msg('asking for %i -> %i' % (start, start+length)) - d = rf.readChunk(start, length) - d.addBoth(self._cbGetRead, rf, lf, chunks, start, length, startTime) - return d - - def _cbGetDone(self, ignored, rf, lf): - log.msg('get done') - rf.close() - lf.close() - if self.useProgressBar: - self.transport.write('\n') - return "Transferred %s to %s" % (rf.name, lf.name) - - def cmd_PUT(self, rest): - local, rest = self._getFilename(rest) - if '*' in local or '?' in local: # wildcard - if rest: - remote, rest = self._getFilename(rest) - path = os.path.join(self.currentDirectory, remote) - d = self.client.getAttrs(path) - d.addCallback(self._cbPutTargetAttrs, remote, local) - return d - else: - remote = '' - files = glob.glob(local) - return self._cbPutMultipleNext(None, files, remote) - if rest: - remote, rest = self._getFilename(rest) - else: - remote = os.path.split(local)[1] - lf = file(local, 'r') - path = os.path.join(self.currentDirectory, remote) - d = self.client.openFile(path, filetransfer.FXF_WRITE|filetransfer.FXF_CREAT, {}) - d.addCallback(self._cbPutOpenFile, lf) - d.addErrback(self._ebCloseLf, lf) - return d - - def _cbPutTargetAttrs(self, attrs, path, local): - if not stat.S_ISDIR(attrs['permissions']): - return "Wildcard put with non-directory target." - return self._cbPutMultipleNext(None, files, path) - - def _cbPutMultipleNext(self, res, files, path): - if isinstance(res, failure.Failure): - self._printFailure(res) - elif res: - self.transport.write(res) - if not res.endswith('\n'): - self.transport.write('\n') - f = None - while files and not f: - try: - f = files.pop(0) - lf = file(f, 'r') - except: - self._printFailure(failure.Failure()) - f = None - if not f: - return - name = os.path.split(f)[1] - remote = os.path.join(self.currentDirectory, path, name) - log.msg((name, remote, path)) - d = self.client.openFile(remote, filetransfer.FXF_WRITE|filetransfer.FXF_CREAT, {}) - d.addCallback(self._cbPutOpenFile, lf) - d.addErrback(self._ebCloseLf, lf) - d.addBoth(self._cbPutMultipleNext, files, path) - return d - - def _cbPutOpenFile(self, rf, lf): - numRequests = self.client.transport.conn.options['requests'] - if self.useProgressBar: - lf = FileWrapper(lf) - dList = [] - chunks = [] - startTime = time.time() - for i in range(numRequests): - d = self._cbPutWrite(None, rf, lf, chunks, startTime) - if d: - dList.append(d) - dl = defer.DeferredList(dList, fireOnOneErrback=1) - dl.addCallback(self._cbPutDone, rf, lf) - return dl - - def _cbPutWrite(self, ignored, rf, lf, chunks, startTime): - chunk = self._getNextChunk(chunks) - start, size = chunk - lf.seek(start) - data = lf.read(size) - if self.useProgressBar: - lf.total += len(data) - self._printProgessBar(lf, startTime) - if data: - d = rf.writeChunk(start, data) - d.addCallback(self._cbPutWrite, rf, lf, chunks, startTime) - return d - else: - return - - def _cbPutDone(self, ignored, rf, lf): - lf.close() - rf.close() - if self.useProgressBar: - self.transport.write('\n') - return 'Transferred %s to %s' % (lf.name, rf.name) - - def cmd_LCD(self, path): - os.chdir(path) - - def cmd_LN(self, rest): - linkpath, rest = self._getFilename(rest) - targetpath, rest = self._getFilename(rest) - linkpath, targetpath = map( - lambda x: os.path.join(self.currentDirectory, x), - (linkpath, targetpath)) - return self.client.makeLink(linkpath, targetpath).addCallback(_ignore) - - def cmd_LS(self, rest): - # possible lines: - # ls current directory - # ls name_of_file that file - # ls name_of_directory that directory - # ls some_glob_string current directory, globbed for that string - options = [] - rest = rest.split() - while rest and rest[0] and rest[0][0] == '-': - opts = rest.pop(0)[1:] - for o in opts: - if o == 'l': - options.append('verbose') - elif o == 'a': - options.append('all') - rest = ' '.join(rest) - path, rest = self._getFilename(rest) - if not path: - fullPath = self.currentDirectory + '/' - else: - fullPath = os.path.join(self.currentDirectory, path) - d = self._remoteGlob(fullPath) - d.addCallback(self._cbDisplayFiles, options) - return d - - def _cbDisplayFiles(self, files, options): - files.sort() - if 'all' not in options: - files = [f for f in files if not f[0].startswith('.')] - if 'verbose' in options: - lines = [f[1] for f in files] - else: - lines = [f[0] for f in files] - if not lines: - return None - else: - return '\n'.join(lines) - - def cmd_MKDIR(self, path): - path, rest = self._getFilename(path) - path = os.path.join(self.currentDirectory, path) - return self.client.makeDirectory(path, {}).addCallback(_ignore) - - def cmd_RMDIR(self, path): - path, rest = self._getFilename(path) - path = os.path.join(self.currentDirectory, path) - return self.client.removeDirectory(path).addCallback(_ignore) - - def cmd_LMKDIR(self, path): - os.system("mkdir %s" % path) - - def cmd_RM(self, path): - path, rest = self._getFilename(path) - path = os.path.join(self.currentDirectory, path) - return self.client.removeFile(path).addCallback(_ignore) - - def cmd_LLS(self, rest): - os.system("ls %s" % rest) - - def cmd_RENAME(self, rest): - oldpath, rest = self._getFilename(rest) - newpath, rest = self._getFilename(rest) - oldpath, newpath = map ( - lambda x: os.path.join(self.currentDirectory, x), - (oldpath, newpath)) - return self.client.renameFile(oldpath, newpath).addCallback(_ignore) - - def cmd_EXIT(self, ignored): - self.client.transport.loseConnection() - - cmd_QUIT = cmd_EXIT - - def cmd_VERSION(self, ignored): - return "SFTP version %i" % self.client.version - - def cmd_HELP(self, ignored): - return """Available commands: -cd path Change remote directory to 'path'. -chgrp gid path Change gid of 'path' to 'gid'. -chmod mode path Change mode of 'path' to 'mode'. -chown uid path Change uid of 'path' to 'uid'. -exit Disconnect from the server. -get remote-path [local-path] Get remote file. -help Get a list of available commands. -lcd path Change local directory to 'path'. -lls [ls-options] [path] Display local directory listing. -lmkdir path Create local directory. -ln linkpath targetpath Symlink remote file. -lpwd Print the local working directory. -ls [-l] [path] Display remote directory listing. -mkdir path Create remote directory. -progress Toggle progress bar. -put local-path [remote-path] Put local file. -pwd Print the remote working directory. -quit Disconnect from the server. -rename oldpath newpath Rename remote file. -rmdir path Remove remote directory. -rm path Remove remote file. -version Print the SFTP version. -? Synonym for 'help'. -""" - - def cmd_PWD(self, ignored): - return self.currentDirectory - - def cmd_LPWD(self, ignored): - return os.getcwd() - - def cmd_PROGRESS(self, ignored): - self.useProgressBar = not self.useProgressBar - return "%ssing progess bar." % (self.useProgressBar and "U" or "Not u") - - def cmd_EXEC(self, rest): - shell = pwd.getpwnam(getpass.getuser())[6] - print repr(rest) - if rest: - cmds = ['-c', rest] - return utils.getProcessOutput(shell, cmds, errortoo=1) - else: - os.system(shell) - - # accessory functions - - def _remoteGlob(self, fullPath): - log.msg('looking up %s' % fullPath) - head, tail = os.path.split(fullPath) - if '*' in tail or '?' in tail: - glob = 1 - else: - glob = 0 - if tail and not glob: # could be file or directory - # try directory first - d = self.client.openDirectory(fullPath) - d.addCallback(self._cbOpenList, '') - d.addErrback(self._ebNotADirectory, head, tail) - else: - d = self.client.openDirectory(head) - d.addCallback(self._cbOpenList, tail) - return d - - def _cbOpenList(self, directory, glob): - files = [] - d = directory.read() - d.addBoth(self._cbReadFile, files, directory, glob) - return d - - def _ebNotADirectory(self, reason, path, glob): - d = self.client.openDirectory(path) - d.addCallback(self._cbOpenList, glob) - return d - - def _cbReadFile(self, files, l, directory, glob): - if not isinstance(files, failure.Failure): - if glob: - l.extend([f for f in files if fnmatch.fnmatch(f[0], glob)]) - else: - l.extend(files) - d = directory.read() - d.addBoth(self._cbReadFile, l, directory, glob) - return d - else: - reason = files - reason.trap(EOFError) - directory.close() - return l - - def _abbrevSize(self, size): - # from http://mail.python.org/pipermail/python-list/1999-December/018395.html - _abbrevs = [ - (1<<50L, 'PB'), - (1<<40L, 'TB'), - (1<<30L, 'GB'), - (1<<20L, 'MB'), - (1<<10L, 'kb'), - (1, '') - ] - - for factor, suffix in _abbrevs: - if size > factor: - break - return '%.1f' % (size/factor) + suffix - - def _abbrevTime(self, t): - if t > 3600: # 1 hour - hours = int(t / 3600) - t -= (3600 * hours) - mins = int(t / 60) - t -= (60 * mins) - return "%i:%02i:%02i" % (hours, mins, t) - else: - mins = int(t/60) - t -= (60 * mins) - return "%02i:%02i" % (mins, t) - - def _printProgessBar(self, f, startTime): - diff = time.time() - startTime - total = f.total - try: - winSize = struct.unpack('4H', - fcntl.ioctl(0, tty.TIOCGWINSZ, '12345679')) - except IOError: - winSize = [None, 80] - speed = total/diff - if speed: - timeLeft = (f.size - total) / speed - else: - timeLeft = 0 - front = f.name - back = '%3i%% %s %sps %s ' % ((total/f.size)*100, self._abbrevSize(total), - self._abbrevSize(total/diff), self._abbrevTime(timeLeft)) - spaces = (winSize[1] - (len(front) + len(back) + 1)) * ' ' - self.transport.write('\r%s%s%s' % (front, spaces, back)) - - def _getFilename(self, line): - line.lstrip() - if not line: - return None, '' - if line[0] in '\'"': - ret = [] - line = list(line) - try: - for i in range(1,len(line)): - c = line[i] - if c == line[0]: - return ''.join(ret), ''.join(line[i+1:]).lstrip() - elif c == '\\': # quoted character - del line[i] - if line[i] not in '\'"\\': - raise IndexError, "bad quote: \\%s" % line[i] - ret.append(line[i]) - else: - ret.append(line[i]) - except IndexError: - raise IndexError, "unterminated quote" - ret = line.split(None, 1) - if len(ret) == 1: - return ret[0], '' - else: - return ret - -StdioClient.__dict__['cmd_?'] = StdioClient.cmd_HELP - -class SSHConnection(connection.SSHConnection): - def serviceStarted(self): - self.openChannel(SSHSession()) - -class SSHSession(channel.SSHChannel): - - name = 'session' - - def channelOpen(self, foo): - log.msg('session %s open' % self.id) - if self.conn.options['subsystem'].startswith('/'): - request = 'exec' - else: - request = 'subsystem' - d = self.conn.sendRequest(self, request, \ - common.NS(self.conn.options['subsystem']), wantReply=1) - d.addCallback(self._cbSubsystem) - d.addErrback(_ebExit) - - def _cbSubsystem(self, result): - self.client = filetransfer.FileTransferClient() - self.client.makeConnection(self) - self.dataReceived = self.client.dataReceived - f = None - if self.conn.options['batchfile']: - fn = self.conn.options['batchfile'] - if fn != '-': - f = file(fn) - self.stdio = stdio.StandardIO(StdioClient(self.client, f)) - - def extReceived(self, t, data): - if t==connection.EXTENDED_DATA_STDERR: - log.msg('got %s stderr data' % len(data)) - sys.stderr.write(data) - sys.stderr.flush() - - def eofReceived(self): - log.msg('got eof') - self.stdio.closeStdin() - - def closeReceived(self): - log.msg('remote side closed %s' % self) - self.conn.sendClose(self) - - def closed(self): - try: - reactor.stop() - except: - pass - - def stopWriting(self): - self.stdio.pauseProducing() - - def startWriting(self): - self.stdio.resumeProducing() - -if __name__ == '__main__': - run() - diff --git a/tools/buildbot/pylibs/twisted/conch/scripts/ckeygen.py b/tools/buildbot/pylibs/twisted/conch/scripts/ckeygen.py deleted file mode 100644 index 065c844..0000000 --- a/tools/buildbot/pylibs/twisted/conch/scripts/ckeygen.py +++ /dev/null @@ -1,180 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -# $Id: ckeygen.py,v 1.8 2003/05/10 14:03:40 spiv Exp $ - -#""" Implementation module for the `ckeygen` command. -#""" - -from twisted.conch.ssh import keys -from twisted.python import log, usage, randbytes - -import sys, os, getpass, md5, socket -if getpass.getpass == getpass.unix_getpass: - try: - import termios # hack around broken termios - termios.tcgetattr, termios.tcsetattr - except (ImportError, AttributeError): - sys.modules['termios'] = None - reload(getpass) - -class GeneralOptions(usage.Options): - synopsis = """Usage: ckeygen [options] - """ - - optParameters = [['bits', 'b', 1024, 'Number of bits in the key to create.'], - ['filename', 'f', None, 'Filename of the key file.'], - ['type', 't', None, 'Specify type of key to create.'], - ['comment', 'C', None, 'Provide new comment.'], - ['newpass', 'N', None, 'Provide new passphrase.'], - ['pass', 'P', None, 'Provide old passphrase']] - - optFlags = [['fingerprint', 'l', 'Show fingerprint of key file.'], - ['changepass', 'p', 'Change passphrase of private key file.'], - ['quiet', 'q', 'Quiet.'], - ['showpub', 'y', 'Read private key file and print public key.']] - - #zsh_altArgDescr = {"bits":"Number of bits in the key (default: 1024)"} - #zsh_multiUse = ["foo", "bar"] - #zsh_mutuallyExclusive = [("foo", "bar"), ("bar", "baz")] - zsh_actions = {"type":"(rsa dsa)"} - #zsh_actionDescr = {"logfile":"log file name", "random":"random seed"} - -def run(): - options = GeneralOptions() - try: - options.parseOptions(sys.argv[1:]) - except usage.UsageError, u: - print 'ERROR: %s' % u - options.opt_help() - sys.exit(1) - log.discardLogs() - log.deferr = handleError # HACK - if options['type']: - if options['type'] == 'rsa': - generateRSAkey(options) - elif options['type'] == 'dsa': - generateDSAkey(options) - else: - sys.exit('Key type was %s, must be one of: rsa, dsa' % options['type']) - elif options['fingerprint']: - printFingerprint(options) - elif options['changepass']: - changePassPhrase(options) - elif options['showpub']: - displayPublicKey(options) - else: - options.opt_help() - sys.exit(1) - -def handleError(): - from twisted.python import failure - global exitStatus - exitStatus = 2 - log.err(failure.Failure()) - reactor.stop() - raise - -def generateRSAkey(options): - from Crypto.PublicKey import RSA - print 'Generating public/private rsa key pair.' - key = RSA.generate(int(options['bits']), randbytes.secureRandom) - _saveKey(key, options) - -def generateDSAkey(options): - from Crypto.PublicKey import DSA - print 'Generating public/private dsa key pair.' - key = DSA.generate(int(options['bits']), randbytes.secureRandom) - _saveKey(key, options) - -def printFingerprint(options): - if not options['filename']: - filename = os.path.expanduser('~/.ssh/id_rsa') - options['filename'] = raw_input('Enter file in which the key is (%s): ' % filename) - if os.path.exists(options['filename']+'.pub'): - options['filename'] += '.pub' - try: - string = keys.getPublicKeyString(options['filename']) - obj = keys.getPublicKeyObject(string) - print '%s %s %s' % ( - obj.size()+1, - ':'.join(['%02x' % ord(x) for x in md5.new(string).digest()]), - os.path.basename(options['filename'])) - except: - sys.exit('bad key') - -def changePassPhrase(options): - if not options['filename']: - filename = os.path.expanduser('~/.ssh/id_rsa') - options['filename'] = raw_input('Enter file in which the key is (%s): ' % filename) - try: - key = keys.getPrivateKeyObject(options['filename']) - except keys.BadKeyError, e: - if e.args[0] != 'encrypted key with no passphrase': - raise - else: - if not options['pass']: - options['pass'] = getpass.getpass('Enter old passphrase: ') - key = keys.getPrivateKeyObject(options['filename'], passphrase = options['pass']) - if not options['newpass']: - while 1: - p1 = getpass.getpass('Enter new passphrase (empty for no passphrase): ') - p2 = getpass.getpass('Enter same passphrase again: ') - if p1 == p2: - break - print 'Passphrases do not match. Try again.' - options['newpass'] = p1 - open(options['filename'], 'w').write( - keys.makePrivateKeyString(key, passphrase=options['newpass'])) - print 'Your identification has been saved with the new passphrase.' - -def displayPublicKey(options): - if not options['filename']: - filename = os.path.expanduser('~/.ssh/id_rsa') - options['filename'] = raw_input('Enter file in which the key is (%s): ' % filename) - try: - key = keys.getPrivateKeyObject(options['filename']) - except keys.BadKeyError, e: - if e.args[0] != 'encrypted key with no passphrase': - raise - else: - if not options['pass']: - options['pass'] = getpass.getpass('Enter passphrase: ') - key = keys.getPrivateKeyObject(options['filename'], passphrase = options['pass']) - print keys.makePublicKeyString(key) - -def _saveKey(key, options): - if not options['filename']: - kind = keys.objectType(key) - kind = {'ssh-rsa':'rsa','ssh-dss':'dsa'}[kind] - filename = os.path.expanduser('~/.ssh/id_%s'%kind) - options['filename'] = raw_input('Enter file in which to save the key (%s): '%filename).strip() or filename - if os.path.exists(options['filename']): - print '%s already exists.' % options['filename'] - yn = raw_input('Overwrite (y/n)? ') - if yn[0].lower() != 'y': - sys.exit() - if not options['pass']: - while 1: - p1 = getpass.getpass('Enter passphrase (empty for no passphrase): ') - p2 = getpass.getpass('Enter same passphrase again: ') - if p1 == p2: - break - print 'Passphrases do not match. Try again.' - options['pass'] = p1 - comment = '%s@%s' % (getpass.getuser(), socket.gethostname()) - open(options['filename'], 'w').write( - keys.makePrivateKeyString(key, passphrase=options['pass'])) - os.chmod(options['filename'], 33152) - open(options['filename']+'.pub', 'w').write( - keys.makePublicKeyString(key, comment = comment)) - pubKey = keys.getPublicKeyString(data=keys.makePublicKeyString(key, comment=comment)) - print 'Your identification has been saved in %s' % options['filename'] - print 'Your public key has been saved in %s.pub' % options['filename'] - print 'The key fingerprint is:' - print ':'.join(['%02x' % ord(x) for x in md5.new(pubKey).digest()]) - -if __name__ == '__main__': - run() - diff --git a/tools/buildbot/pylibs/twisted/conch/scripts/conch.py b/tools/buildbot/pylibs/twisted/conch/scripts/conch.py deleted file mode 100644 index cc7b803..0000000 --- a/tools/buildbot/pylibs/twisted/conch/scripts/conch.py +++ /dev/null @@ -1,525 +0,0 @@ -# -*- test-case-name: twisted.conch.test.test_conch -*- -# -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -# $Id: conch.py,v 1.65 2004/03/11 00:29:14 z3p Exp $ - -#""" Implementation module for the `conch` command. -#""" -from twisted.conch.client import agent, connect, default, options -from twisted.conch.error import ConchError -from twisted.conch.ssh import connection, common -from twisted.conch.ssh import session, forwarding, channel -from twisted.internet import reactor, stdio, defer, task -from twisted.python import log, usage - -import os, sys, getpass, struct, tty, fcntl, base64, signal, stat, errno - -class ClientOptions(options.ConchOptions): - - synopsis = """Usage: conch [options] host [command] -""" - - optParameters = [['escape', 'e', '~'], - ['localforward', 'L', None, 'listen-port:host:port Forward local port to remote address'], - ['remoteforward', 'R', None, 'listen-port:host:port Forward remote port to local address'], - ] - - optFlags = [['null', 'n', 'Redirect input from /dev/null.'], - ['fork', 'f', 'Fork to background after authentication.'], - ['tty', 't', 'Tty; allocate a tty even if command is given.'], - ['notty', 'T', 'Do not allocate a tty.'], - ['noshell', 'N', 'Do not execute a shell or command.'], - ['subsystem', 's', 'Invoke command (mandatory) as SSH2 subsystem.'], - ] - - #zsh_altArgDescr = {"foo":"use this description for foo instead"} - #zsh_multiUse = ["foo", "bar"] - #zsh_mutuallyExclusive = [("foo", "bar"), ("bar", "baz")] - #zsh_actions = {"foo":'_files -g "*.foo"', "bar":"(one two three)"} - zsh_actionDescr = {"localforward":"listen-port:host:port", - "remoteforward":"listen-port:host:port"} - zsh_extras = ["*:command: "] - - localForwards = [] - remoteForwards = [] - - def opt_escape(self, esc): - "Set escape character; ``none'' = disable" - if esc == 'none': - self['escape'] = None - elif esc[0] == '^' and len(esc) == 2: - self['escape'] = chr(ord(esc[1])-64) - elif len(esc) == 1: - self['escape'] = esc - else: - sys.exit("Bad escape character '%s'." % esc) - - def opt_localforward(self, f): - "Forward local port to remote address (lport:host:port)" - localPort, remoteHost, remotePort = f.split(':') # doesn't do v6 yet - localPort = int(localPort) - remotePort = int(remotePort) - self.localForwards.append((localPort, (remoteHost, remotePort))) - - def opt_remoteforward(self, f): - """Forward remote port to local address (rport:host:port)""" - remotePort, connHost, connPort = f.split(':') # doesn't do v6 yet - remotePort = int(remotePort) - connPort = int(connPort) - self.remoteForwards.append((remotePort, (connHost, connPort))) - - def parseArgs(self, host, *command): - self['host'] = host - self['command'] = ' '.join(command) - -# Rest of code in "run" -options = None -conn = None -exitStatus = 0 -old = None -_inRawMode = 0 -_savedRawMode = None - -def run(): - global options, old - args = sys.argv[1:] - if '-l' in args: # cvs is an idiot - i = args.index('-l') - args = args[i:i+2]+args - del args[i+2:i+4] - for arg in args[:]: - try: - i = args.index(arg) - if arg[:2] == '-o' and args[i+1][0]!='-': - args[i:i+2] = [] # suck on it scp - except ValueError: - pass - options = ClientOptions() - try: - options.parseOptions(args) - except usage.UsageError, u: - print 'ERROR: %s' % u - options.opt_help() - sys.exit(1) - if options['log']: - if options['logfile']: - if options['logfile'] == '-': - f = sys.stdout - else: - f = file(options['logfile'], 'a+') - else: - f = sys.stderr - realout = sys.stdout - log.startLogging(f) - sys.stdout = realout - else: - log.discardLogs() - doConnect() - fd = sys.stdin.fileno() - try: - old = tty.tcgetattr(fd) - except: - old = None - try: - oldUSR1 = signal.signal(signal.SIGUSR1, lambda *a: reactor.callLater(0, reConnect)) - except: - oldUSR1 = None - try: - reactor.run() - finally: - if old: - tty.tcsetattr(fd, tty.TCSANOW, old) - if oldUSR1: - signal.signal(signal.SIGUSR1, oldUSR1) - if (options['command'] and options['tty']) or not options['notty']: - signal.signal(signal.SIGWINCH, signal.SIG_DFL) - if sys.stdout.isatty() and not options['command']: - print 'Connection to %s closed.' % options['host'] - sys.exit(exitStatus) - -def handleError(): - from twisted.python import failure - global exitStatus - exitStatus = 2 - reactor.callLater(0.01, _stopReactor) - log.err(failure.Failure()) - raise - -def _stopReactor(): - try: - reactor.stop() - except: pass - -def doConnect(): -# log.deferr = handleError # HACK - if '@' in options['host']: - options['user'], options['host'] = options['host'].split('@',1) - if not options.identitys: - options.identitys = ['~/.ssh/id_rsa', '~/.ssh/id_dsa'] - host = options['host'] - if not options['user']: - options['user'] = getpass.getuser() - if not options['port']: - options['port'] = 22 - else: - options['port'] = int(options['port']) - host = options['host'] - port = options['port'] - vhk = default.verifyHostKey - uao = default.SSHUserAuthClient(options['user'], options, SSHConnection()) - connect.connect(host, port, options, vhk, uao).addErrback(_ebExit) - -def _ebExit(f): - global exitStatus - if hasattr(f.value, 'value'): - s = f.value.value - else: - s = str(f) - exitStatus = "conch: exiting with error %s" % f - reactor.callLater(0.1, _stopReactor) - -def onConnect(): -# if keyAgent and options['agent']: -# cc = protocol.ClientCreator(reactor, SSHAgentForwardingLocal, conn) -# cc.connectUNIX(os.environ['SSH_AUTH_SOCK']) - if hasattr(conn.transport, 'sendIgnore'): - _KeepAlive(conn) - if options.localForwards: - for localPort, hostport in options.localForwards: - s = reactor.listenTCP(localPort, - forwarding.SSHListenForwardingFactory(conn, - hostport, - SSHListenClientForwardingChannel)) - conn.localForwards.append(s) - if options.remoteForwards: - for remotePort, hostport in options.remoteForwards: - log.msg('asking for remote forwarding for %s:%s' % - (remotePort, hostport)) - conn.requestRemoteForwarding(remotePort, hostport) - reactor.addSystemEventTrigger('before', 'shutdown', beforeShutdown) - if not options['noshell'] or options['agent']: - conn.openChannel(SSHSession()) - if options['fork']: - if os.fork(): - os._exit(0) - os.setsid() - for i in range(3): - try: - os.close(i) - except OSError, e: - import errno - if e.errno != errno.EBADF: - raise - -def reConnect(): - beforeShutdown() - conn.transport.transport.loseConnection() - -def beforeShutdown(): - remoteForwards = options.remoteForwards - for remotePort, hostport in remoteForwards: - log.msg('cancelling %s:%s' % (remotePort, hostport)) - conn.cancelRemoteForwarding(remotePort) - -def stopConnection(): - if not options['reconnect']: - reactor.callLater(0.1, _stopReactor) - -class _KeepAlive: - - def __init__(self, conn): - self.conn = conn - self.globalTimeout = None - self.lc = task.LoopingCall(self.sendGlobal) - self.lc.start(300) - - def sendGlobal(self): - d = self.conn.sendGlobalRequest("conch-keep-alive@twistedmatrix.com", - "", wantReply = 1) - d.addBoth(self._cbGlobal) - self.globalTimeout = reactor.callLater(30, self._ebGlobal) - - def _cbGlobal(self, res): - if self.globalTimeout: - self.globalTimeout.cancel() - self.globalTimeout = None - - def _ebGlobal(self): - if self.globalTimeout: - self.globalTimeout = None - self.conn.transport.loseConnection() - -class SSHConnection(connection.SSHConnection): - def serviceStarted(self): - global conn - conn = self - self.localForwards = [] - self.remoteForwards = {} - if not isinstance(self, connection.SSHConnection): - # make these fall through - del self.__class__.requestRemoteForwarding - del self.__class__.cancelRemoteForwarding - onConnect() - - def serviceStopped(self): - lf = self.localForwards - self.localForwards = [] - for s in lf: - s.loseConnection() - stopConnection() - - def requestRemoteForwarding(self, remotePort, hostport): - data = forwarding.packGlobal_tcpip_forward(('0.0.0.0', remotePort)) - d = self.sendGlobalRequest('tcpip-forward', data, - wantReply=1) - log.msg('requesting remote forwarding %s:%s' %(remotePort, hostport)) - d.addCallback(self._cbRemoteForwarding, remotePort, hostport) - d.addErrback(self._ebRemoteForwarding, remotePort, hostport) - - def _cbRemoteForwarding(self, result, remotePort, hostport): - log.msg('accepted remote forwarding %s:%s' % (remotePort, hostport)) - self.remoteForwards[remotePort] = hostport - log.msg(repr(self.remoteForwards)) - - def _ebRemoteForwarding(self, f, remotePort, hostport): - log.msg('remote forwarding %s:%s failed' % (remotePort, hostport)) - log.msg(f) - - def cancelRemoteForwarding(self, remotePort): - data = forwarding.packGlobal_tcpip_forward(('0.0.0.0', remotePort)) - self.sendGlobalRequest('cancel-tcpip-forward', data) - log.msg('cancelling remote forwarding %s' % remotePort) - try: - del self.remoteForwards[remotePort] - except: - pass - log.msg(repr(self.remoteForwards)) - - def channel_forwarded_tcpip(self, windowSize, maxPacket, data): - log.msg('%s %s' % ('FTCP', repr(data))) - remoteHP, origHP = forwarding.unpackOpen_forwarded_tcpip(data) - log.msg(self.remoteForwards) - log.msg(remoteHP) - if self.remoteForwards.has_key(remoteHP[1]): - connectHP = self.remoteForwards[remoteHP[1]] - log.msg('connect forwarding %s' % (connectHP,)) - return SSHConnectForwardingChannel(connectHP, - remoteWindow = windowSize, - remoteMaxPacket = maxPacket, - conn = self) - else: - raise ConchError(connection.OPEN_CONNECT_FAILED, "don't know about that port") - -# def channel_auth_agent_openssh_com(self, windowSize, maxPacket, data): -# if options['agent'] and keyAgent: -# return agent.SSHAgentForwardingChannel(remoteWindow = windowSize, -# remoteMaxPacket = maxPacket, -# conn = self) -# else: -# return connection.OPEN_CONNECT_FAILED, "don't have an agent" - - def channelClosed(self, channel): - log.msg('connection closing %s' % channel) - log.msg(self.channels) - if len(self.channels) == 1 and not (options['noshell'] and not options['nocache']): # just us left - log.msg('stopping connection') - stopConnection() - else: - # because of the unix thing - self.__class__.__bases__[0].channelClosed(self, channel) - -class SSHSession(channel.SSHChannel): - - name = 'session' - - def channelOpen(self, foo): - log.msg('session %s open' % self.id) - if options['agent']: - d = self.conn.sendRequest(self, 'auth-agent-req@openssh.com', '', wantReply=1) - d.addBoth(lambda x:log.msg(x)) - if options['noshell']: return - if (options['command'] and options['tty']) or not options['notty']: - _enterRawMode() - c = session.SSHSessionClient() - if options['escape'] and not options['notty']: - self.escapeMode = 1 - c.dataReceived = self.handleInput - else: - c.dataReceived = self.write - c.connectionLost = lambda x=None,s=self:s.sendEOF() - self.stdio = stdio.StandardIO(c) - fd = 0 - if options['subsystem']: - self.conn.sendRequest(self, 'subsystem', \ - common.NS(options['command'])) - elif options['command']: - if options['tty']: - term = os.environ['TERM'] - winsz = fcntl.ioctl(fd, tty.TIOCGWINSZ, '12345678') - winSize = struct.unpack('4H', winsz) - ptyReqData = session.packRequest_pty_req(term, winSize, '') - self.conn.sendRequest(self, 'pty-req', ptyReqData) - signal.signal(signal.SIGWINCH, self._windowResized) - self.conn.sendRequest(self, 'exec', \ - common.NS(options['command'])) - else: - if not options['notty']: - term = os.environ['TERM'] - winsz = fcntl.ioctl(fd, tty.TIOCGWINSZ, '12345678') - winSize = struct.unpack('4H', winsz) - ptyReqData = session.packRequest_pty_req(term, winSize, '') - self.conn.sendRequest(self, 'pty-req', ptyReqData) - signal.signal(signal.SIGWINCH, self._windowResized) - self.conn.sendRequest(self, 'shell', '') - #if hasattr(conn.transport, 'transport'): - # conn.transport.transport.setTcpNoDelay(1) - - def handleInput(self, char): - #log.msg('handling %s' % repr(char)) - if char in ('\n', '\r'): - self.escapeMode = 1 - self.write(char) - elif self.escapeMode == 1 and char == options['escape']: - self.escapeMode = 2 - elif self.escapeMode == 2: - self.escapeMode = 1 # so we can chain escapes together - if char == '.': # disconnect - log.msg('disconnecting from escape') - stopConnection() - return - elif char == '\x1a': # ^Z, suspend - def _(): - _leaveRawMode() - sys.stdout.flush() - sys.stdin.flush() - os.kill(os.getpid(), signal.SIGTSTP) - _enterRawMode() - reactor.callLater(0, _) - return - elif char == 'R': # rekey connection - log.msg('rekeying connection') - self.conn.transport.sendKexInit() - return - elif char == '#': # display connections - self.stdio.write('\r\nThe following connections are open:\r\n') - channels = self.conn.channels.keys() - channels.sort() - for channelId in channels: - self.stdio.write(' #%i %s\r\n' % (channelId, str(self.conn.channels[channelId]))) - return - self.write('~' + char) - else: - self.escapeMode = 0 - self.write(char) - - def dataReceived(self, data): - self.stdio.write(data) - - def extReceived(self, t, data): - if t==connection.EXTENDED_DATA_STDERR: - log.msg('got %s stderr data' % len(data)) - sys.stderr.write(data) - - def eofReceived(self): - log.msg('got eof') - self.stdio.closeStdin() - - def closeReceived(self): - log.msg('remote side closed %s' % self) - self.conn.sendClose(self) - - def closed(self): - global old - log.msg('closed %s' % self) - log.msg(repr(self.conn.channels)) - if not options['nocache']: # fork into the background - if os.fork(): - if old: - fd = sys.stdin.fileno() - tty.tcsetattr(fd, tty.TCSANOW, old) - if (options['command'] and options['tty']) or \ - not options['notty']: - signal.signal(signal.SIGWINCH, signal.SIG_DFL) - os._exit(0) - os.setsid() - for i in range(3): - try: - os.close(i) - except OSError, e: - import errno - if e.errno != errno.EBADF: - raise - - def request_exit_status(self, data): - global exitStatus - exitStatus = int(struct.unpack('>L', data)[0]) - log.msg('exit status: %s' % exitStatus) - - def sendEOF(self): - self.conn.sendEOF(self) - - def stopWriting(self): - self.stdio.pauseProducing() - - def startWriting(self): - self.stdio.resumeProducing() - - def _windowResized(self, *args): - winsz = fcntl.ioctl(0, tty.TIOCGWINSZ, '12345678') - winSize = struct.unpack('4H', winsz) - newSize = winSize[1], winSize[0], winSize[2], winSize[3] - self.conn.sendRequest(self, 'window-change', struct.pack('!4L', *newSize)) - - -class SSHListenClientForwardingChannel(forwarding.SSHListenClientForwardingChannel): pass -class SSHConnectForwardingChannel(forwarding.SSHConnectForwardingChannel): pass - -def _leaveRawMode(): - global _inRawMode - if not _inRawMode: - return - fd = sys.stdin.fileno() - tty.tcsetattr(fd, tty.TCSANOW, _savedMode) - _inRawMode = 0 - -def _enterRawMode(): - global _inRawMode, _savedMode - if _inRawMode: - return - fd = sys.stdin.fileno() - try: - old = tty.tcgetattr(fd) - new = old[:] - except: - log.msg('not a typewriter!') - else: - # iflage - new[0] = new[0] | tty.IGNPAR - new[0] = new[0] & ~(tty.ISTRIP | tty.INLCR | tty.IGNCR | tty.ICRNL | - tty.IXON | tty.IXANY | tty.IXOFF) - if hasattr(tty, 'IUCLC'): - new[0] = new[0] & ~tty.IUCLC - - # lflag - new[3] = new[3] & ~(tty.ISIG | tty.ICANON | tty.ECHO | tty.ECHO | - tty.ECHOE | tty.ECHOK | tty.ECHONL) - if hasattr(tty, 'IEXTEN'): - new[3] = new[3] & ~tty.IEXTEN - - #oflag - new[1] = new[1] & ~tty.OPOST - - new[6][tty.VMIN] = 1 - new[6][tty.VTIME] = 0 - - _savedMode = old - tty.tcsetattr(fd, tty.TCSANOW, new) - #tty.setraw(fd) - _inRawMode = 1 - -if __name__ == '__main__': - run() - diff --git a/tools/buildbot/pylibs/twisted/conch/scripts/tkconch.py b/tools/buildbot/pylibs/twisted/conch/scripts/tkconch.py deleted file mode 100644 index da20b17..0000000 --- a/tools/buildbot/pylibs/twisted/conch/scripts/tkconch.py +++ /dev/null @@ -1,572 +0,0 @@ -# -*- test-case-name: twisted.conch.test.test_scripts -*- -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -# $Id: tkconch.py,v 1.6 2003/02/22 08:10:15 z3p Exp $ - -""" Implementation module for the `tkconch` command. -""" - -from __future__ import nested_scopes - -import Tkinter, tkFileDialog, tkFont, tkMessageBox, string -from twisted.conch.ui import tkvt100 -from twisted.conch.ssh import transport, userauth, connection, common, keys -from twisted.conch.ssh import session, forwarding, channel -from twisted.conch.client.default import isInKnownHosts -from twisted.internet import reactor, defer, protocol, tksupport -from twisted.python import usage, log - -import os, sys, getpass, struct, base64, signal - -class TkConchMenu(Tkinter.Frame): - def __init__(self, *args, **params): - ## Standard heading: initialization - apply(Tkinter.Frame.__init__, (self,) + args, params) - - self.master.title('TkConch') - self.localRemoteVar = Tkinter.StringVar() - self.localRemoteVar.set('local') - - Tkinter.Label(self, anchor='w', justify='left', text='Hostname').grid(column=1, row=1, sticky='w') - self.host = Tkinter.Entry(self) - self.host.grid(column=2, columnspan=2, row=1, sticky='nesw') - - Tkinter.Label(self, anchor='w', justify='left', text='Port').grid(column=1, row=2, sticky='w') - self.port = Tkinter.Entry(self) - self.port.grid(column=2, columnspan=2, row=2, sticky='nesw') - - Tkinter.Label(self, anchor='w', justify='left', text='Username').grid(column=1, row=3, sticky='w') - self.user = Tkinter.Entry(self) - self.user.grid(column=2, columnspan=2, row=3, sticky='nesw') - - Tkinter.Label(self, anchor='w', justify='left', text='Command').grid(column=1, row=4, sticky='w') - self.command = Tkinter.Entry(self) - self.command.grid(column=2, columnspan=2, row=4, sticky='nesw') - - Tkinter.Label(self, anchor='w', justify='left', text='Identity').grid(column=1, row=5, sticky='w') - self.identity = Tkinter.Entry(self) - self.identity.grid(column=2, row=5, sticky='nesw') - Tkinter.Button(self, command=self.getIdentityFile, text='Browse').grid(column=3, row=5, sticky='nesw') - - Tkinter.Label(self, text='Port Forwarding').grid(column=1, row=6, sticky='w') - self.forwards = Tkinter.Listbox(self, height=0, width=0) - self.forwards.grid(column=2, columnspan=2, row=6, sticky='nesw') - Tkinter.Button(self, text='Add', command=self.addForward).grid(column=1, row=7) - Tkinter.Button(self, text='Remove', command=self.removeForward).grid(column=1, row=8) - self.forwardPort = Tkinter.Entry(self) - self.forwardPort.grid(column=2, row=7, sticky='nesw') - Tkinter.Label(self, text='Port').grid(column=3, row=7, sticky='nesw') - self.forwardHost = Tkinter.Entry(self) - self.forwardHost.grid(column=2, row=8, sticky='nesw') - Tkinter.Label(self, text='Host').grid(column=3, row=8, sticky='nesw') - self.localForward = Tkinter.Radiobutton(self, text='Local', variable=self.localRemoteVar, value='local') - self.localForward.grid(column=2, row=9) - self.remoteForward = Tkinter.Radiobutton(self, text='Remote', variable=self.localRemoteVar, value='remote') - self.remoteForward.grid(column=3, row=9) - - Tkinter.Label(self, text='Advanced Options').grid(column=1, columnspan=3, row=10, sticky='nesw') - - Tkinter.Label(self, anchor='w', justify='left', text='Cipher').grid(column=1, row=11, sticky='w') - self.cipher = Tkinter.Entry(self, name='cipher') - self.cipher.grid(column=2, columnspan=2, row=11, sticky='nesw') - - Tkinter.Label(self, anchor='w', justify='left', text='MAC').grid(column=1, row=12, sticky='w') - self.mac = Tkinter.Entry(self, name='mac') - self.mac.grid(column=2, columnspan=2, row=12, sticky='nesw') - - Tkinter.Label(self, anchor='w', justify='left', text='Escape Char').grid(column=1, row=13, sticky='w') - self.escape = Tkinter.Entry(self, name='escape') - self.escape.grid(column=2, columnspan=2, row=13, sticky='nesw') - Tkinter.Button(self, text='Connect!', command=self.doConnect).grid(column=1, columnspan=3, row=14, sticky='nesw') - - # Resize behavior(s) - self.grid_rowconfigure(6, weight=1, minsize=64) - self.grid_columnconfigure(2, weight=1, minsize=2) - - self.master.protocol("WM_DELETE_WINDOW", sys.exit) - - - def getIdentityFile(self): - r = tkFileDialog.askopenfilename() - if r: - self.identity.delete(0, Tkinter.END) - self.identity.insert(Tkinter.END, r) - - def addForward(self): - port = self.forwardPort.get() - self.forwardPort.delete(0, Tkinter.END) - host = self.forwardHost.get() - self.forwardHost.delete(0, Tkinter.END) - if self.localRemoteVar.get() == 'local': - self.forwards.insert(Tkinter.END, 'L:%s:%s' % (port, host)) - else: - self.forwards.insert(Tkinter.END, 'R:%s:%s' % (port, host)) - - def removeForward(self): - cur = self.forwards.curselection() - if cur: - self.forwards.remove(cur[0]) - - def doConnect(self): - finished = 1 - options['host'] = self.host.get() - options['port'] = self.port.get() - options['user'] = self.user.get() - options['command'] = self.command.get() - cipher = self.cipher.get() - mac = self.mac.get() - escape = self.escape.get() - if cipher: - if cipher in SSHClientTransport.supportedCiphers: - SSHClientTransport.supportedCiphers = [cipher] - else: - tkMessageBox.showerror('TkConch', 'Bad cipher.') - finished = 0 - - if mac: - if mac in SSHClientTransport.supportedMACs: - SSHClientTransport.supportedMACs = [mac] - elif finished: - tkMessageBox.showerror('TkConch', 'Bad MAC.') - finished = 0 - - if escape: - if escape == 'none': - options['escape'] = None - elif escape[0] == '^' and len(escape) == 2: - options['escape'] = chr(ord(escape[1])-64) - elif len(escape) == 1: - options['escape'] = escape - elif finished: - tkMessageBox.showerror('TkConch', "Bad escape character '%s'." % escape) - finished = 0 - - if self.identity.get(): - options.identitys.append(self.identity.get()) - - for line in self.forwards.get(0,Tkinter.END): - if line[0]=='L': - options.opt_localforward(line[2:]) - else: - options.opt_remoteforward(line[2:]) - - if '@' in options['host']: - options['user'], options['host'] = options['host'].split('@',1) - - if (not options['host'] or not options['user']) and finished: - tkMessageBox.showerror('TkConch', 'Missing host or username.') - finished = 0 - if finished: - self.master.quit() - self.master.destroy() - if options['log']: - realout = sys.stdout - log.startLogging(sys.stderr) - sys.stdout = realout - else: - log.discardLogs() - log.deferr = handleError # HACK - if not options.identitys: - options.identitys = ['~/.ssh/id_rsa', '~/.ssh/id_dsa'] - host = options['host'] - port = int(options['port'] or 22) - log.msg((host,port)) - reactor.connectTCP(host, port, SSHClientFactory()) - frame.master.deiconify() - frame.master.title('%s@%s - TkConch' % (options['user'], options['host'])) - else: - self.focus() - -class GeneralOptions(usage.Options): - synopsis = """Usage: tkconch [options] host [command] - """ - - optParameters = [['user', 'l', None, 'Log in using this user name.'], - ['identity', 'i', '~/.ssh/identity', 'Identity for public key authentication'], - ['escape', 'e', '~', "Set escape character; ``none'' = disable"], - ['cipher', 'c', None, 'Select encryption algorithm.'], - ['macs', 'm', None, 'Specify MAC algorithms for protocol version 2.'], - ['port', 'p', None, 'Connect to this port. Server must be on the same port.'], - ['localforward', 'L', None, 'listen-port:host:port Forward local port to remote address'], - ['remoteforward', 'R', None, 'listen-port:host:port Forward remote port to local address'], - ] - - optFlags = [['tty', 't', 'Tty; allocate a tty even if command is given.'], - ['notty', 'T', 'Do not allocate a tty.'], - ['version', 'V', 'Display version number only.'], - ['compress', 'C', 'Enable compression.'], - ['noshell', 'N', 'Do not execute a shell or command.'], - ['subsystem', 's', 'Invoke command (mandatory) as SSH2 subsystem.'], - ['log', 'v', 'Log to stderr'], - ['ansilog', 'a', 'Print the receieved data to stdout']] - - #zsh_altArgDescr = {"foo":"use this description for foo instead"} - #zsh_multiUse = ["foo", "bar"] - zsh_mutuallyExclusive = [("tty", "notty")] - zsh_actions = {"cipher":"(%s)" % " ".join(transport.SSHClientTransport.supportedCiphers), - "macs":"(%s)" % " ".join(transport.SSHClientTransport.supportedMACs)} - zsh_actionDescr = {"localforward":"listen-port:host:port", - "remoteforward":"listen-port:host:port"} - # user, host, or user@host completion similar to zsh's ssh completion - zsh_extras = ['1:host | user@host:{_ssh;if compset -P "*@"; then _wanted hosts expl "remote host name" _ssh_hosts && ret=0 elif compset -S "@*"; then _wanted users expl "login name" _ssh_users -S "" && ret=0 else if (( $+opt_args[-l] )); then tmp=() else tmp=( "users:login name:_ssh_users -qS@" ) fi; _alternative "hosts:remote host name:_ssh_hosts" "$tmp[@]" && ret=0 fi}', - '*:command: '] - - identitys = [] - localForwards = [] - remoteForwards = [] - - def opt_identity(self, i): - self.identitys.append(i) - - def opt_localforward(self, f): - localPort, remoteHost, remotePort = f.split(':') # doesn't do v6 yet - localPort = int(localPort) - remotePort = int(remotePort) - self.localForwards.append((localPort, (remoteHost, remotePort))) - - def opt_remoteforward(self, f): - remotePort, connHost, connPort = f.split(':') # doesn't do v6 yet - remotePort = int(remotePort) - connPort = int(connPort) - self.remoteForwards.append((remotePort, (connHost, connPort))) - - def opt_compress(self): - SSHClientTransport.supportedCompressions[0:1] = ['zlib'] - - def parseArgs(self, *args): - if args: - self['host'] = args[0] - self['command'] = ' '.join(args[1:]) - else: - self['host'] = '' - self['command'] = '' - -# Rest of code in "run" -options = None -menu = None -exitStatus = 0 -frame = None - -def deferredAskFrame(question, echo): - if frame.callback: - raise ValueError("can't ask 2 questions at once!") - d = defer.Deferred() - resp = [] - def gotChar(ch, resp=resp): - if not ch: return - if ch=='\x03': # C-c - reactor.stop() - if ch=='\r': - frame.write('\r\n') - stresp = ''.join(resp) - del resp - frame.callback = None - d.callback(stresp) - return - elif 32 <= ord(ch) < 127: - resp.append(ch) - if echo: - frame.write(ch) - elif ord(ch) == 8 and resp: # BS - if echo: frame.write('\x08 \x08') - resp.pop() - frame.callback = gotChar - frame.write(question) - frame.canvas.focus_force() - return d - -def run(): - global menu, options, frame - args = sys.argv[1:] - if '-l' in args: # cvs is an idiot - i = args.index('-l') - args = args[i:i+2]+args - del args[i+2:i+4] - for arg in args[:]: - try: - i = args.index(arg) - if arg[:2] == '-o' and args[i+1][0]!='-': - args[i:i+2] = [] # suck on it scp - except ValueError: - pass - root = Tkinter.Tk() - root.withdraw() - top = Tkinter.Toplevel() - menu = TkConchMenu(top) - menu.pack(side=Tkinter.TOP, fill=Tkinter.BOTH, expand=1) - options = GeneralOptions() - try: - options.parseOptions(args) - except usage.UsageError, u: - print 'ERROR: %s' % u - options.opt_help() - sys.exit(1) - for k,v in options.items(): - if v and hasattr(menu, k): - getattr(menu,k).insert(Tkinter.END, v) - for (p, (rh, rp)) in options.localForwards: - menu.forwards.insert(Tkinter.END, 'L:%s:%s:%s' % (p, rh, rp)) - options.localForwards = [] - for (p, (rh, rp)) in options.remoteForwards: - menu.forwards.insert(Tkinter.END, 'R:%s:%s:%s' % (p, rh, rp)) - options.remoteForwards = [] - frame = tkvt100.VT100Frame(root, callback=None) - root.geometry('%dx%d'%(tkvt100.fontWidth*frame.width+3, tkvt100.fontHeight*frame.height+3)) - frame.pack(side = Tkinter.TOP) - tksupport.install(root) - root.withdraw() - if (options['host'] and options['user']) or '@' in options['host']: - menu.doConnect() - else: - top.mainloop() - reactor.run() - sys.exit(exitStatus) - -def handleError(): - from twisted.python import failure - global exitStatus - exitStatus = 2 - log.err(failure.Failure()) - reactor.stop() - raise - -class SSHClientFactory(protocol.ClientFactory): - noisy = 1 - - def stopFactory(self): - reactor.stop() - - def buildProtocol(self, addr): - return SSHClientTransport() - - def clientConnectionFailed(self, connector, reason): - tkMessageBox.showwarning('TkConch','Connection Failed, Reason:\n %s: %s' % (reason.type, reason.value)) - -class SSHClientTransport(transport.SSHClientTransport): - - def receiveError(self, code, desc): - global exitStatus - exitStatus = 'conch:\tRemote side disconnected with error code %i\nconch:\treason: %s' % (code, desc) - - def sendDisconnect(self, code, reason): - global exitStatus - exitStatus = 'conch:\tSending disconnect with error code %i\nconch:\treason: %s' % (code, reason) - transport.SSHClientTransport.sendDisconnect(self, code, reason) - - def receiveDebug(self, alwaysDisplay, message, lang): - global options - if alwaysDisplay or options['log']: - log.msg('Received Debug Message: %s' % message) - - def verifyHostKey(self, pubKey, fingerprint): - #d = defer.Deferred() - #d.addCallback(lambda x:defer.succeed(1)) - #d.callback(2) - #return d - goodKey = isInKnownHosts(options['host'], pubKey, {'known-hosts': None}) - if goodKey == 1: # good key - return defer.succeed(1) - elif goodKey == 2: # AAHHHHH changed - return defer.fail(error.ConchError('bad host key')) - else: - if options['host'] == self.transport.getPeer()[1]: - host = options['host'] - khHost = options['host'] - else: - host = '%s (%s)' % (options['host'], - self.transport.getPeer()[1]) - khHost = '%s,%s' % (options['host'], - self.transport.getPeer()[1]) - keyType = common.getNS(pubKey)[0] - ques = """The authenticity of host '%s' can't be established.\r -%s key fingerprint is %s.""" % (host, - {'ssh-dss':'DSA', 'ssh-rsa':'RSA'}[keyType], - fingerprint) - ques+='\r\nAre you sure you want to continue connecting (yes/no)? ' - return deferredAskFrame(ques, 1).addCallback(self._cbVerifyHostKey, pubKey, khHost, keyType) - - def _cbVerifyHostKey(self, ans, pubKey, khHost, keyType): - if ans.lower() not in ('yes', 'no'): - return deferredAskFrame("Please type 'yes' or 'no': ",1).addCallback(self._cbVerifyHostKey, pubKey, khHost, keyType) - if ans.lower() == 'no': - frame.write('Host key verification failed.\r\n') - raise error.ConchError('bad host key') - try: - frame.write("Warning: Permanently added '%s' (%s) to the list of known hosts.\r\n" % (khHost, {'ssh-dss':'DSA', 'ssh-rsa':'RSA'}[keyType])) - known_hosts = open(os.path.expanduser('~/.ssh/known_hosts'), 'a') - encodedKey = base64.encodestring(pubKey).replace('\n', '') - known_hosts.write('\n%s %s %s' % (khHost, keyType, encodedKey)) - known_hosts.close() - except: - log.deferr() - raise error.ConchError - - def connectionSecure(self): - if options['user']: - user = options['user'] - else: - user = getpass.getuser() - self.requestService(SSHUserAuthClient(user, SSHConnection())) - -class SSHUserAuthClient(userauth.SSHUserAuthClient): - usedFiles = [] - - def getPassword(self, prompt = None): - if not prompt: - prompt = "%s@%s's password: " % (self.user, options['host']) - return deferredAskFrame(prompt,0) - - def getPublicKey(self): - files = [x for x in options.identitys if x not in self.usedFiles] - if not files: - return None - file = files[0] - log.msg(file) - self.usedFiles.append(file) - file = os.path.expanduser(file) - file += '.pub' - if not os.path.exists(file): - return - try: - return keys.getPublicKeyString(file) - except: - return self.getPublicKey() # try again - - def getPrivateKey(self): - file = os.path.expanduser(self.usedFiles[-1]) - if not os.path.exists(file): - return None - try: - return defer.succeed(keys.getPrivateKeyObject(file)) - except keys.BadKeyError, e: - if e.args[0] == 'encrypted key with no password': - prompt = "Enter passphrase for key '%s': " % \ - self.usedFiles[-1] - return deferredAskFrame(prompt, 0).addCallback(self._cbGetPrivateKey, 0) - def _cbGetPrivateKey(self, ans, count): - file = os.path.expanduser(self.usedFiles[-1]) - try: - return keys.getPrivateKeyObject(file, password = ans) - except keys.BadKeyError: - if count == 2: - raise - prompt = "Enter passphrase for key '%s': " % \ - self.usedFiles[-1] - return deferredAskFrame(prompt, 0).addCallback(self._cbGetPrivateKey, count+1) - -class SSHConnection(connection.SSHConnection): - def serviceStarted(self): - if not options['noshell']: - self.openChannel(SSHSession()) - if options.localForwards: - for localPort, hostport in options.localForwards: - reactor.listenTCP(localPort, - forwarding.SSHListenForwardingFactory(self, - hostport, - forwarding.SSHListenClientForwardingChannel)) - if options.remoteForwards: - for remotePort, hostport in options.remoteForwards: - log.msg('asking for remote forwarding for %s:%s' % - (remotePort, hostport)) - data = forwarding.packGlobal_tcpip_forward( - ('0.0.0.0', remotePort)) - d = self.sendGlobalRequest('tcpip-forward', data) - self.remoteForwards[remotePort] = hostport - -class SSHSession(channel.SSHChannel): - - name = 'session' - - def channelOpen(self, foo): - #global globalSession - #globalSession = self - # turn off local echo - self.escapeMode = 1 - c = session.SSHSessionClient() - if options['escape']: - c.dataReceived = self.handleInput - else: - c.dataReceived = self.write - c.connectionLost = self.sendEOF - frame.callback = c.dataReceived - frame.canvas.focus_force() - if options['subsystem']: - self.conn.sendRequest(self, 'subsystem', \ - common.NS(options['command'])) - elif options['command']: - if options['tty']: - term = os.environ.get('TERM', 'xterm') - #winsz = fcntl.ioctl(fd, tty.TIOCGWINSZ, '12345678') - winSize = (25,80,0,0) #struct.unpack('4H', winsz) - ptyReqData = session.packRequest_pty_req(term, winSize, '') - self.conn.sendRequest(self, 'pty-req', ptyReqData) - self.conn.sendRequest(self, 'exec', \ - common.NS(options['command'])) - else: - if not options['notty']: - term = os.environ.get('TERM', 'xterm') - #winsz = fcntl.ioctl(fd, tty.TIOCGWINSZ, '12345678') - winSize = (25,80,0,0) #struct.unpack('4H', winsz) - ptyReqData = session.packRequest_pty_req(term, winSize, '') - self.conn.sendRequest(self, 'pty-req', ptyReqData) - self.conn.sendRequest(self, 'shell', '') - self.conn.transport.transport.setTcpNoDelay(1) - - def handleInput(self, char): - #log.msg('handling %s' % repr(char)) - if char in ('\n', '\r'): - self.escapeMode = 1 - self.write(char) - elif self.escapeMode == 1 and char == options['escape']: - self.escapeMode = 2 - elif self.escapeMode == 2: - self.escapeMode = 1 # so we can chain escapes together - if char == '.': # disconnect - log.msg('disconnecting from escape') - reactor.stop() - return - elif char == '\x1a': # ^Z, suspend - # following line courtesy of Erwin@freenode - os.kill(os.getpid(), signal.SIGSTOP) - return - elif char == 'R': # rekey connection - log.msg('rekeying connection') - self.conn.transport.sendKexInit() - return - self.write('~' + char) - else: - self.escapeMode = 0 - self.write(char) - - def dataReceived(self, data): - if options['ansilog']: - print repr(data) - frame.write(data) - - def extReceived(self, t, data): - if t==connection.EXTENDED_DATA_STDERR: - log.msg('got %s stderr data' % len(data)) - sys.stderr.write(data) - sys.stderr.flush() - - def eofReceived(self): - log.msg('got eof') - sys.stdin.close() - - def closed(self): - log.msg('closed %s' % self) - if len(self.conn.channels) == 1: # just us left - reactor.stop() - - def request_exit_status(self, data): - global exitStatus - exitStatus = int(struct.unpack('>L', data)[0]) - log.msg('exit status: %s' % exitStatus) - - def sendEOF(self): - self.conn.sendEOF(self) - -if __name__=="__main__": - run() diff --git a/tools/buildbot/pylibs/twisted/conch/ssh/__init__.py b/tools/buildbot/pylibs/twisted/conch/ssh/__init__.py deleted file mode 100644 index 00c5e68..0000000 --- a/tools/buildbot/pylibs/twisted/conch/ssh/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -""" -An SSHv2 implementation for Twisted. Part of the Twisted.Conch package. - -Maintainer: U{Paul Swartz} -""" diff --git a/tools/buildbot/pylibs/twisted/conch/ssh/agent.py b/tools/buildbot/pylibs/twisted/conch/ssh/agent.py deleted file mode 100644 index b9f70ae..0000000 --- a/tools/buildbot/pylibs/twisted/conch/ssh/agent.py +++ /dev/null @@ -1,145 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -""" -Implements the old SSHv1 key agent protocol. - -Maintainer: U{Paul Swartz} -""" - -import struct -from common import NS, getNS -from twisted.conch.error import ConchError -from twisted.internet import defer, protocol - -class SSHAgentClient(protocol.Protocol): - - def __init__(self): - self.buf = '' - self.deferreds = [] - - def dataReceived(self, data): - self.buf += data - while 1: - if len(self.buf) <= 4: return - packLen = struct.unpack('!L', self.buf[:4])[0] - if len(self.buf) < 4+packLen: return - packet, self.buf = self.buf[4:4+packLen], self.buf[4+packLen:] - reqType = ord(packet[0]) - d = self.deferreds.pop(0) - if reqType == AGENT_FAILURE: - d.errback(ConchError('agent failure')) - elif reqType == AGENT_SUCCESS: - d.callback('') - else: - d.callback(packet) - - def sendRequest(self, reqType, data): - pack = struct.pack('!LB',len(data)+1, reqType)+data - self.transport.write(pack) - d = defer.Deferred() - self.deferreds.append(d) - return d - - def requestIdentities(self): - return self.sendRequest(AGENTC_REQUEST_IDENTITIES, '').addCallback(self._cbRequestIdentities) - - def _cbRequestIdentities(self, data): - if ord(data[0]) != AGENT_IDENTITIES_ANSWER: - return ConchError('unexpected respone: %i' % ord(data[0])) - numKeys = struct.unpack('!L', data[1:5])[0] - keys = [] - data = data[5:] - for i in range(numKeys): - blobLen = struct.unpack('!L', data[:4])[0] - blob, data = data[4:4+blobLen], data[4+blobLen:] - commLen = struct.unpack('!L', data[:4])[0] - comm, data = data[4:4+commLen], data[4+commLen:] - keys.append((blob, comm)) - return keys - - def addIdentity(self, blob, comment = ''): - req = blob - req += NS(comment) - co - return self.sendRequest(AGENTC_ADD_IDENTITY, req) - - def signData(self, blob, data): - req = NS(blob) - req += NS(data) - req += '\000\000\000\000' # flags - return self.sendRequest(AGENTC_SIGN_REQUEST, req).addCallback(self._cbSignData) - - def _cbSignData(self, data): - if data[0] != chr(AGENT_SIGN_RESPONSE): - return ConchError('unexpected data: %i' % ord(data[0])) - signature = getNS(data[1:])[0] - return signature - - def removeIdentity(self, blob): - req = NS(blob) - return self.sendRequest(AGENTC_REMOVE_IDENTITY, req) - - def removeAllIdentities(self): - return self.sendRequest(AGENTC_REMOVE_ALL_IDENTITIES, '') - -class SSHAgentServer(protocol.Protocol): - - def __init__(self): - self.buf = '' - - def dataReceived(self, data): - self.buf += data - while 1: - if len(self.buf) <= 4: return - packLen = struct.unpack('!L', self.buf[:4])[0] - if len(self.buf) < 4+packLen: return - packet, self.buf = self.buf[4:4+packLen], self.buf[4+packLen:] - reqType = ord(packet[0]) - reqName = messages.get(reqType, None) - if not reqName: - print 'bad request', reqType - f = getattr(self, 'agentc_%s' % reqName) - f(packet[1:]) - - def sendResponse(self, reqType, data): - pack = struct.pack('!LB', len(data)+1, reqType) + data - self.transport.write(pack) - - def agentc_REQUEST_IDENTITIES(self, data): - assert data == '' - numKeys = len(self.keys) - s = struct.pack('!L', numKeys) - for k in self.keys: - s += struct.pack('!L', len(k)) + k - s += struct.pack('!L', len(self.keys[k][1])) + self.keys[k][1] - self.sendResponse(AGENT_IDENTITIES_ANSWER, s) - - def agentc_SIGN_REQUEST(self, data): - blob, data = common.getNS(data) - if blob not in self.keys: - return self.sendResponse(AGENT_FAILURE, '') - signData, data = common.getNS(data) - assert data == '\000\000\000\000' - self.sendResponse(AGENT_SIGN_RESPONSE, common.NS(keys.signData(self.keys[blob][0], signData))) - - def agentc_ADD_IDENTITY(self, data): pass - def agentc_REMOVE_IDENTITY(self, data): pass - def agentc_REMOVE_ALL_IDENTITIES(self, data): pass - -AGENT_FAILURE = 5 -AGENT_SUCCESS = 6 -AGENTC_REQUEST_IDENTITIES = 11 -AGENT_IDENTITIES_ANSWER = 12 -AGENTC_SIGN_REQUEST = 13 -AGENT_SIGN_RESPONSE = 14 -AGENTC_ADD_IDENTITY = 17 -AGENTC_REMOVE_IDENTITY = 18 -AGENTC_REMOVE_ALL_IDENTITIES = 19 - -messages = {} -import agent -for v in dir(agent): - if v.startswith('AGENTC_'): - messages[getattr(agent, v)] = v[7:] diff --git a/tools/buildbot/pylibs/twisted/conch/ssh/asn1.py b/tools/buildbot/pylibs/twisted/conch/ssh/asn1.py deleted file mode 100644 index c665910..0000000 --- a/tools/buildbot/pylibs/twisted/conch/ssh/asn1.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -""" -A basic ASN.1 parser to parse private SSH keys. - -Maintainer: U{Paul Swartz} -""" - -from Crypto.Util import number - -def parse(data): - things = [] - while data: - t = ord(data[0]) - assert (t & 0xc0) == 0, 'not a universal value: 0x%02x' % t - #assert t & 0x20, 'not a constructed value: 0x%02x' % t - l = ord(data[1]) - assert data != 0x80, "shouldn't be an indefinite length" - if l & 0x80: # long form - ll = l & 0x7f - l = number.bytes_to_long(data[2:2+ll]) - s = 2 + ll - else: - s = 2 - body, data = data[s:s+l], data[s+l:] - t = t&(~0x20) - assert t in (SEQUENCE, INTEGER), 'bad type: 0x%02x' % t - if t == SEQUENCE: - things.append(parse(body)) - elif t == INTEGER: - #assert (ord(body[0])&0x80) == 0, "shouldn't have negative number" - things.append(number.bytes_to_long(body)) - if len(things) == 1: - return things[0] - return things - -def pack(data): - ret = '' - for part in data: - if type(part) in (type(()), type([])): - partData = pack(part) - partType = SEQUENCE|0x20 - elif type(part) in (type(1), type(1L)): - partData = number.long_to_bytes(part) - if ord(partData[0])&(0x80): - partData = '\x00' + partData - partType = INTEGER - else: - raise ValueError('unknown type %s' % (type(part),)) - - ret += chr(partType) - if len(partData) > 127: - l = number.long_to_bytes(len(partData)) - ret += chr(len(l)|0x80) + l - else: - ret += chr(len(partData)) - ret += partData - return ret - -INTEGER = 0x02 -SEQUENCE = 0x10 - diff --git a/tools/buildbot/pylibs/twisted/conch/ssh/channel.py b/tools/buildbot/pylibs/twisted/conch/ssh/channel.py deleted file mode 100644 index 496ab44a7..0000000 --- a/tools/buildbot/pylibs/twisted/conch/ssh/channel.py +++ /dev/null @@ -1,281 +0,0 @@ -# -*- test-case-name: twisted.conch.test.test_channel -*- -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -""" -The parent class for all the SSH Channels. Currently implemented channels -are session. direct-tcp, and forwarded-tcp. - -Maintainer: U{Paul Swartz} -""" - -from twisted.python import log -from twisted.internet import interfaces -from zope.interface import implements - - -class SSHChannel(log.Logger): - """ - A class that represents a multiplexed channel over an SSH connection. - The channel has a local window which is the maximum amount of data it will - receive, and a remote which is the maximum amount of data the remote side - will accept. There is also a maximum packet size for any individual data - packet going each way. - - @ivar name: the name of the channel. - @type name: C{str} - @ivar localWindowSize: the maximum size of the local window in bytes. - @type localWindowSize: C{int} - @ivar localWindowLeft: how many bytes are left in the local window. - @type localWindowLeft: C{int} - @ivar localMaxPacket: the maximum size of packet we will accept in bytes. - @type localMaxPacket: C{int} - @ivar remoteWindowLeft: how many bytes are left in the remote window. - @type remoteWindowLeft: C{int} - @ivar remoteMaxPacket: the maximum size of a packet the remote side will - accept in bytes. - @type remoteMaxPacket: C{int} - @ivar conn: the connection this channel is multiplexed through. - @type conn: L{SSHConnection} - @ivar data: any data to send to the other size when the channel is - requested. - @type data: C{str} - @ivar avatar: an avatar for the logged-in user (if a server channel) - @ivar localClosed: True if we aren't accepting more data. - @type localClosed: C{bool} - @ivar remoteClosed: True if the other size isn't accepting more data. - @type remoteClosed: C{bool} - """ - - implements(interfaces.ITransport) - - name = None # only needed for client channels - - def __init__(self, localWindow = 0, localMaxPacket = 0, - remoteWindow = 0, remoteMaxPacket = 0, - conn = None, data=None, avatar = None): - self.localWindowSize = localWindow or 131072 - self.localWindowLeft = self.localWindowSize - self.localMaxPacket = localMaxPacket or 32768 - self.remoteWindowLeft = remoteWindow - self.remoteMaxPacket = remoteMaxPacket - self.areWriting = 1 - self.conn = conn - self.data = data - self.avatar = avatar - self.specificData = '' - self.buf = '' - self.extBuf = [] - self.closing = 0 - self.localClosed = 0 - self.remoteClosed = 0 - self.id = None # gets set later by SSHConnection - - def __str__(self): - return '' % (self.name, - self.localWindowLeft, self.remoteWindowLeft) - - def logPrefix(self): - id = (self.id is not None and str(self.id)) or "unknown" - return "SSHChannel %s (%s) on %s" % (self.name, id, - self.conn.logPrefix()) - - def channelOpen(self, specificData): - """ - Called when the channel is opened. specificData is any data that the - other side sent us when opening the channel. - - @type specificData: C{str} - """ - log.msg('channel open') - - def openFailed(self, reason): - """ - Called when the the open failed for some reason. - reason.desc is a string descrption, reason.code the the SSH error code. - - @type reason: L{error.ConchError} - """ - log.msg('other side refused open\nreason: %s'% reason) - - def addWindowBytes(self, bytes): - """ - Called when bytes are added to the remote window. By default it clears - the data buffers. - - @type bytes: C{int} - """ - self.remoteWindowLeft = self.remoteWindowLeft+bytes - if not self.areWriting and not self.closing: - self.areWriting = True - self.startWriting() - if self.buf: - b = self.buf - self.buf = '' - self.write(b) - if self.extBuf: - b = self.extBuf - self.extBuf = [] - for (type, data) in b: - self.writeExtended(type, data) - - def requestReceived(self, requestType, data): - """ - Called when a request is sent to this channel. By default it delegates - to self.request_. - If this function returns true, the request succeeded, otherwise it - failed. - - @type requestType: C{str} - @type data: C{str} - @rtype: C{bool} - """ - foo = requestType.replace('-', '_') - f = getattr(self, 'request_%s'%foo, None) - if f: - return f(data) - log.msg('unhandled request for %s'%requestType) - return 0 - - def dataReceived(self, data): - """ - Called when we receive data. - - @type data: C{str} - """ - log.msg('got data %s'%repr(data)) - - def extReceived(self, dataType, data): - """ - Called when we receive extended data (usually standard error). - - @type dataType: C{int} - @type data: C{str} - """ - log.msg('got extended data %s %s'%(dataType, repr(data))) - - def eofReceived(self): - """ - Called when the other side will send no more data. - """ - log.msg('remote eof') - - def closeReceived(self): - """ - Called when the other side has closed the channel. - """ - log.msg('remote close') - self.loseConnection() - - def closed(self): - """ - Called when the channel is closed. This means that both our side and - the remote side have closed the channel. - """ - log.msg('closed') - - # transport stuff - def write(self, data): - """ - Write some data to the channel. If there is not enough remote window - available, buffer until it is. Otherwise, split the data into - packets of length remoteMaxPacket and send them. - - @type data: C{str} - """ - if self.buf: - self.buf += data - return - top = len(data) - if top > self.remoteWindowLeft: - data, self.buf = (data[:self.remoteWindowLeft], - data[self.remoteWindowLeft:]) - self.areWriting = 0 - self.stopWriting() - top = self.remoteWindowLeft - rmp = self.remoteMaxPacket - write = self.conn.sendData - r = range(0, top, rmp) - for offset in r: - write(self, data[offset: offset+rmp]) - self.remoteWindowLeft -= top - if self.closing and not self.buf: - self.loseConnection() # try again - - def writeExtended(self, dataType, data): - """ - Send extended data to this channel. If there is not enough remote - window available, buffer until there is. Otherwise, split the data - into packets of length remoteMaxPacket and send them. - - @type dataType: C{int} - @type data: C{str} - """ - if self.extBuf: - if self.extBuf[-1][0] == dataType: - self.extBuf[-1][1] += data - else: - self.extBuf.append([dataType, data]) - return - if len(data) > self.remoteWindowLeft: - data, self.extBuf = (data[:self.remoteWindowLeft], - [[dataType, data[self.remoteWindowLeft:]]]) - self.areWriting = 0 - self.stopWriting() - while len(data) > self.remoteMaxPacket: - self.conn.sendExtendedData(self, dataType, - data[:self.remoteMaxPacket]) - data = data[self.remoteMaxPacket:] - self.remoteWindowLeft -= self.remoteMaxPacket - if data: - self.conn.sendExtendedData(self, dataType, data) - self.remoteWindowLeft -= len(data) - if self.closing: - self.loseConnection() # try again - - def writeSequence(self, data): - """ - Part of the Transport interface. Write a list of strings to the - channel. - - @type data: C{list} of C{str} - """ - self.write(''.join(data)) - - def loseConnection(self): - """ - Close the channel if there is no buferred data. Otherwise, note the - request and return. - """ - self.closing = 1 - if not self.buf and not self.extBuf: - self.conn.sendClose(self) - - def getPeer(self): - """ - Return a tuple describing the other side of the connection. - - @rtype: C{tuple} - """ - return('SSH', )+self.conn.transport.getPeer() - - def getHost(self): - """ - Return a tuple describing our side of the connection. - - @rtype: C{tuple} - """ - return('SSH', )+self.conn.transport.getHost() - - def stopWriting(self): - """ - Called when the remote buffer is full, as a hint to stop writing. - This can be ignored, but it can be helpful. - """ - - def startWriting(self): - """ - Called when the remote buffer has more room, as a hint to continue - writing. - """ diff --git a/tools/buildbot/pylibs/twisted/conch/ssh/common.py b/tools/buildbot/pylibs/twisted/conch/ssh/common.py deleted file mode 100644 index 8392dc2..0000000 --- a/tools/buildbot/pylibs/twisted/conch/ssh/common.py +++ /dev/null @@ -1,130 +0,0 @@ -# -*- test-case-name: twisted.conch.test.test_ssh -*- -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Common functions for the SSH classes. - -Maintainer: U{Paul Swartz} -""" - -import struct, warnings - -try: - from Crypto import Util -except ImportError: - warnings.warn("PyCrypto not installed, but continuing anyways!", - RuntimeWarning) - -from twisted.python import randbytes - -class Entropy(object): - """ - A Crypto.Util.randpool.RandomPool mock for compatibility. - """ - def get_bytes(self, numBytes): - """ - Get a number of random bytes. - """ - warnings.warn("entropy.get_bytes is deprecated, please use " - "twisted.python.randbytes.secureRandom instead.", - category=DeprecationWarning, stacklevel=2) - return randbytes.secureRandom(numBytes) - -entropy = Entropy() - - -def NS(t): - """ - net string - """ - return struct.pack('!L',len(t)) + t - -def getNS(s, count=1): - """ - get net string - """ - ns = [] - c = 0 - for i in range(count): - l, = struct.unpack('!L',s[c:c+4]) - ns.append(s[c+4:4+l+c]) - c += 4 + l - return tuple(ns) + (s[c:],) - -def MP(number): - if number==0: return '\000'*4 - assert number>0 - bn = Util.number.long_to_bytes(number) - if ord(bn[0])&128: - bn = '\000' + bn - return struct.pack('>L',len(bn)) + bn - -def getMP(data, count=1): - """ - Get multiple precision integer out of the string. A multiple precision - integer is stored as a 4-byte length followed by length bytes of the - integer. If count is specified, get count integers out of the string. - The return value is a tuple of count integers followed by the rest of - the data. - """ - mp = [] - c = 0 - for i in range(count): - length, = struct.unpack('>L',data[c:c+4]) - mp.append(Util.number.bytes_to_long(data[c+4:c+4+length])) - c += 4 + length - return tuple(mp) + (data[c:],) - -def _MPpow(x, y, z): - """return the MP version of (x**y)%z - """ - return MP(pow(x,y,z)) - -def ffs(c, s): - """ - first from second - goes through the first list, looking for items in the second, returns the first one - """ - for i in c: - if i in s: return i - -getMP_py = getMP -MP_py = MP -_MPpow_py = _MPpow -pyPow = pow - -def _fastgetMP(data, count=1): - mp = [] - c = 0 - for i in range(count): - length = struct.unpack('!L', data[c:c+4])[0] - mp.append(long(gmpy.mpz(data[c + 4:c + 4 + length][::-1] + '\x00', 256))) - c += length + 4 - return tuple(mp) + (data[c:],) - -def _fastMP(i): - i2 = gmpy.mpz(i).binary()[::-1] - return struct.pack('!L', len(i2)) + i2 - -def _fastMPpow(x, y, z=None): - r = pyPow(gmpy.mpz(x),y,z).binary()[::-1] - return struct.pack('!L', len(r)) + r - -def _fastpow(x, y, z=None): - return pyPow(gmpy.mpz(x), y, z) - -def install(): - global getMP, MP, _MPpow - getMP = _fastgetMP - MP = _fastMP - _MPpow = _fastMPpow - __builtins__['pow'] = _fastpow # evil evil - -try: - import gmpy - install() -except ImportError: - pass - diff --git a/tools/buildbot/pylibs/twisted/conch/ssh/connection.py b/tools/buildbot/pylibs/twisted/conch/ssh/connection.py deleted file mode 100644 index bc86f02..0000000 --- a/tools/buildbot/pylibs/twisted/conch/ssh/connection.py +++ /dev/null @@ -1,613 +0,0 @@ -# -*- test-case-name: twisted.conch.test.test_connection -*- -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -""" -This module contains the implementation of the ssh-connection service, which -allows access to the shell and port-forwarding. - -Maintainer: U{Paul Swartz} -""" - -import struct - -from twisted.conch.ssh import service, common -from twisted.conch import error -from twisted.internet import defer -from twisted.python import log - -class SSHConnection(service.SSHService): - """ - An implementation of the 'ssh-connection' service. It is used to - multiplex multiple channels over the single SSH connection. - - @ivar localChannelID: the next number to use as a local channel ID. - @type localChannelID: C{int} - @ivar channels: a C{dict} mapping a local channel ID to C{SSHChannel} - subclasses. - @type channels: C{dict} - @ivar localToRemoteChannel: a C{dict} mapping a local channel ID to a - remote channel ID. - @type localToRemoteChannel: C{dict} - @ivar channelsToRemoteChannel: a C{dict} mapping a C{SSHChannel} subclass - to remote channel ID. - @type channelsToRemoteChannel: C{dict} - @ivar deferreds: a C{dict} mapping a local channel ID to a C{list} of - C{Deferreds} for outstanding channel requests. Also, the 'global' - key stores the C{list} of pending global request C{Deferred}s. - """ - name = 'ssh-connection' - - def __init__(self): - self.localChannelID = 0 # this is the current # to use for channel ID - self.localToRemoteChannel = {} # local channel ID -> remote channel ID - self.channels = {} # local channel ID -> subclass of SSHChannel - self.channelsToRemoteChannel = {} # subclass of SSHChannel -> - # remote channel ID - self.deferreds = {} # local channel -> list of deferreds for pending - # requests or 'global' -> list of deferreds for - # global requests - self.transport = None # gets set later - - def serviceStarted(self): - if hasattr(self.transport, 'avatar'): - self.transport.avatar.conn = self - - def serviceStopped(self): - map(self.channelClosed, self.channels.values()) - - # packet methods - def ssh_GLOBAL_REQUEST(self, packet): - """ - The other side has made a global request. Payload:: - string request type - bool want reply - - - This dispatches to self.gotGlobalRequest. - """ - requestType, rest = common.getNS(packet) - wantReply, rest = ord(rest[0]), rest[1:] - ret = self.gotGlobalRequest(requestType, rest) - if wantReply: - reply = MSG_REQUEST_FAILURE - data = '' - if ret: - reply = MSG_REQUEST_SUCCESS - if isinstance(ret, (tuple, list)): - data = ret[1] - self.transport.sendPacket(reply, data) - - def ssh_REQUEST_SUCCESS(self, packet): - """ - Our global request succeeded. Get the appropriate Deferred and call - it back with the packet we received. - """ - log.msg('RS') - self.deferreds['global'].pop(0).callback(packet) - - def ssh_REQUEST_FAILURE(self, packet): - """ - Our global request failed. Get the appropriate Deferred and errback - it with the packet we received. - """ - log.msg('RF') - self.deferreds['global'].pop(0).errback( - error.ConchError('global request failed', packet)) - - def ssh_CHANNEL_OPEN(self, packet): - """ - The other side wants to get a channel. Payload:: - string channel name - uint32 remote channel number - uint32 remote window size - uint32 remote maximum packet size - - - We get a channel from self.getChannel(), give it a local channel number - and notify the other side. Then notify the channel by calling its - channelOpen method. - """ - channelType, rest = common.getNS(packet) - senderChannel, windowSize, maxPacket = struct.unpack('>3L', rest[:12]) - packet = rest[12:] - try: - channel = self.getChannel(channelType, windowSize, maxPacket, - packet) - localChannel = self.localChannelID - self.localChannelID += 1 - channel.id = localChannel - self.channels[localChannel] = channel - self.channelsToRemoteChannel[channel] = senderChannel - self.localToRemoteChannel[localChannel] = senderChannel - self.transport.sendPacket(MSG_CHANNEL_OPEN_CONFIRMATION, - struct.pack('>4L', senderChannel, localChannel, - channel.localWindowSize, - channel.localMaxPacket)+channel.specificData) - log.callWithLogger(channel, channel.channelOpen, packet) - except Exception, e: - log.msg('channel open failed') - log.err(e) - if isinstance(e, error.ConchError): - textualInfo, reason = e.args - else: - reason = OPEN_CONNECT_FAILED - textualInfo = "unknown failure" - self.transport.sendPacket(MSG_CHANNEL_OPEN_FAILURE, - struct.pack('>2L', senderChannel, reason) + - common.NS(textualInfo) + common.NS('')) - - def ssh_CHANNEL_OPEN_CONFIRMATION(self, packet): - """ - The other side accepted our MSG_CHANNEL_OPEN request. Payload:: - uint32 local channel number - uint32 remote channel number - uint32 remote window size - uint32 remote maximum packet size - - - Find the channel using the local channel number and notify its - channelOpen method. - """ - (localChannel, remoteChannel, windowSize, - maxPacket) = struct.unpack('>4L', packet[: 16]) - specificData = packet[16:] - channel = self.channels[localChannel] - channel.conn = self - self.localToRemoteChannel[localChannel] = remoteChannel - self.channelsToRemoteChannel[channel] = remoteChannel - channel.remoteWindowLeft = windowSize - channel.remoteMaxPacket = maxPacket - log.callWithLogger(channel, channel.channelOpen, specificData) - - def ssh_CHANNEL_OPEN_FAILURE(self, packet): - """ - The other side did not accept our MSG_CHANNEL_OPEN request. Payload:: - uint32 local channel number - uint32 reason code - string reason description - - Find the channel using the local channel number and notify it by - calling its openFailed() method. - """ - localChannel, reasonCode = struct.unpack('>2L', packet[:8]) - reasonDesc = common.getNS(packet[8:])[0] - channel = self.channels[localChannel] - del self.channels[localChannel] - channel.conn = self - reason = error.ConchError(reasonDesc, reasonCode) - log.callWithLogger(channel, channel.openFailed, reason) - - def ssh_CHANNEL_WINDOW_ADJUST(self, packet): - """ - The other side is adding bytes to its window. Payload:: - uint32 local channel number - uint32 bytes to add - - Call the channel's addWindowBytes() method to add new bytes to the - remote window. - """ - localChannel, bytesToAdd = struct.unpack('>2L', packet[:8]) - channel = self.channels[localChannel] - log.callWithLogger(channel, channel.addWindowBytes, bytesToAdd) - - def ssh_CHANNEL_DATA(self, packet): - """ - The other side is sending us data. Payload:: - uint32 local channel number - string data - - Check to make sure the other side hasn't sent too much data (more - than what's in the window, or more than the maximum packet size). If - they have, close the channel. Otherwise, decrease the available - window and pass the data to the channel's dataReceived(). - """ - localChannel, dataLength = struct.unpack('>2L', packet[:8]) - channel = self.channels[localChannel] - # XXX should this move to dataReceived to put client in charge? - if (dataLength > channel.localWindowLeft or - dataLength > channel.localMaxPacket): # more data than we want - log.callWithLogger(channel, log.msg, 'too much data') - self.sendClose(channel) - return - #packet = packet[:channel.localWindowLeft+4] - data = common.getNS(packet[4:])[0] - channel.localWindowLeft -= dataLength - if channel.localWindowLeft < channel.localWindowSize / 2: - self.adjustWindow(channel, channel.localWindowSize - \ - channel.localWindowLeft) - #log.msg('local window left: %s/%s' % (channel.localWindowLeft, - # channel.localWindowSize)) - log.callWithLogger(channel, channel.dataReceived, data) - - def ssh_CHANNEL_EXTENDED_DATA(self, packet): - """ - The other side is sending us exteneded data. Payload:: - uint32 local channel number - uint32 type code - string data - - Check to make sure the other side hasn't sent too much data (more - than what's in the window, or or than the maximum packet size). If - they have, close the channel. Otherwise, decrease the available - window and pass the data and type code to the channel's - extReceived(). - """ - localChannel, typeCode, dataLength = struct.unpack('>3L', packet[:12]) - channel = self.channels[localChannel] - if (dataLength > channel.localWindowLeft or - dataLength > channel.localMaxPacket): - log.callWithLogger(channel, log.msg, 'too much extdata') - self.sendClose(channel) - return - data = common.getNS(packet[8:])[0] - channel.localWindowLeft -= dataLength - if channel.localWindowLeft < channel.localWindowSize / 2: - self.adjustWindow(channel, channel.localWindowSize - - channel.localWindowLeft) - log.callWithLogger(channel, channel.extReceived, typeCode, data) - - def ssh_CHANNEL_EOF(self, packet): - """ - The other side is not sending any more data. Payload:: - uint32 local channel number - - Notify the channel by calling its eofReceived() method. - """ - localChannel = struct.unpack('>L', packet[:4])[0] - channel = self.channels[localChannel] - log.callWithLogger(channel, channel.eofReceived) - - def ssh_CHANNEL_CLOSE(self, packet): - """ - The other side is closing its end; it does not want to receive any - more data. Payload:: - uint32 local channel number - - Notify the channnel by calling its closeReceived() method. If - the channel has also sent a close message, call self.channelClosed(). - """ - localChannel = struct.unpack('>L', packet[:4])[0] - channel = self.channels[localChannel] - log.callWithLogger(channel, channel.closeReceived) - channel.remoteClosed = True - if channel.localClosed and channel.remoteClosed: - self.channelClosed(channel) - - def ssh_CHANNEL_REQUEST(self, packet): - """ - The other side is sending a request to a channel. Payload:: - uint32 local channel number - string request name - bool want reply - - - Pass the message to the channel's requestReceived method. If the - other side wants a reply, add callbacks which will send the - reply. - """ - localChannel = struct.unpack('>L', packet[: 4])[0] - requestType, rest = common.getNS(packet[4:]) - wantReply = ord(rest[0]) - channel = self.channels[localChannel] - d = defer.maybeDeferred(log.callWithLogger, channel, - channel.requestReceived, requestType, rest[1:]) - if wantReply: - d.addCallback(self._cbChannelRequest, localChannel) - d.addErrback(self._ebChannelRequest, localChannel) - return d - - def _cbChannelRequest(self, result, localChannel): - """ - Called back if the other side wanted a reply to a channel request. If - the result is true, send a MSG_CHANNEL_SUCCESS. Otherwise, raise - a C{error.ConchError} - - @param result: the value returned from the channel's requestReceived() - method. If it's False, the request failed. - @type result: C{bool} - @param localChannel: the local channel ID of the channel to which the - request was made. - @type localChannel: C{int} - @raises ConchError: if the result is False. - """ - if not result: - raise error.ConchError('failed request') - self.transport.sendPacket(MSG_CHANNEL_SUCCESS, struct.pack('>L', - self.localToRemoteChannel[localChannel])) - - def _ebChannelRequest(self, result, localChannel): - """ - Called if the other wisde wanted a reply to the channel requeset and - the channel request failed. - - @param result: a Failure, but it's not used. - @param localChannel: the local channel ID of the channel to which the - request was made. - @type localChannel: C{int} - """ - self.transport.sendPacket(MSG_CHANNEL_FAILURE, struct.pack('>L', - self.localToRemoteChannel[localChannel])) - - def ssh_CHANNEL_SUCCESS(self, packet): - """ - Our channel request to the other other side succeeded. Payload:: - uint32 local channel number - - Get the C{Deferred} out of self.deferreds and call it back. - """ - localChannel = struct.unpack('>L', packet[:4])[0] - if self.deferreds.get(localChannel): - d = self.deferreds[localChannel].pop(0) - log.callWithLogger(self.channels[localChannel], - d.callback, '') - - def ssh_CHANNEL_FAILURE(self, packet): - """ - Our channel request to the other side failed. Payload:: - uint32 local channel number - - Get the C{Deferred} out of self.deferreds and errback it with a - C{error.ConchError}. - """ - localChannel = struct.unpack('>L', packet[:4])[0] - if self.deferreds.get(localChannel): - d = self.deferreds[localChannel].pop(0) - log.callWithLogger(self.channels[localChannel], - d.errback, - error.ConchError('channel request failed')) - - # methods for users of the connection to call - - def sendGlobalRequest(self, request, data, wantReply=0): - """ - Send a global request for this connection. Current this is only used - for remote->local TCP forwarding. - - @type request: C{str} - @type data: C{str} - @type wantReply: C{bool} - @rtype C{Deferred}/C{None} - """ - self.transport.sendPacket(MSG_GLOBAL_REQUEST, - common.NS(request) - + (wantReply and '\xff' or '\x00') - + data) - if wantReply: - d = defer.Deferred() - self.deferreds.setdefault('global', []).append(d) - return d - - def openChannel(self, channel, extra=''): - """ - Open a new channel on this connection. - - @type channel: subclass of C{SSHChannel} - @type extra: C{str} - """ - log.msg('opening channel %s with %s %s'%(self.localChannelID, - channel.localWindowSize, channel.localMaxPacket)) - self.transport.sendPacket(MSG_CHANNEL_OPEN, common.NS(channel.name) - + struct.pack('>3L', self.localChannelID, - channel.localWindowSize, channel.localMaxPacket) - + extra) - channel.id = self.localChannelID - self.channels[self.localChannelID] = channel - self.localChannelID += 1 - - def sendRequest(self, channel, requestType, data, wantReply=0): - """ - Send a request to a channel. - - @type channel: subclass of C{SSHChannel} - @type requestType: C{str} - @type data: C{str} - @type wantReply: C{bool} - @rtype C{Deferred}/C{None} - """ - if channel.localClosed: - return - log.msg('sending request %s' % requestType) - self.transport.sendPacket(MSG_CHANNEL_REQUEST, struct.pack('>L', - self.channelsToRemoteChannel[channel]) - + common.NS(requestType)+chr(wantReply) - + data) - if wantReply: - d = defer.Deferred() - self.deferreds.setdefault(channel.id, []).append(d) - return d - - def adjustWindow(self, channel, bytesToAdd): - """ - Tell the other side that we will receive more data. This should not - normally need to be called as it is managed automatically. - - @type channel: subclass of L{SSHChannel} - @type bytesToAdd: C{int} - """ - if channel.localClosed: - return # we're already closed - self.transport.sendPacket(MSG_CHANNEL_WINDOW_ADJUST, struct.pack('>2L', - self.channelsToRemoteChannel[channel], - bytesToAdd)) - log.msg('adding %i to %i in channel %i' % (bytesToAdd, - channel.localWindowLeft, channel.id)) - channel.localWindowLeft += bytesToAdd - - def sendData(self, channel, data): - """ - Send data to a channel. This should not normally be used: instead use - channel.write(data) as it manages the window automatically. - - @type channel: subclass of L{SSHChannel} - @type data: C{str} - """ - if channel.localClosed: - return # we're already closed - self.transport.sendPacket(MSG_CHANNEL_DATA, struct.pack('>L', - self.channelsToRemoteChannel[channel]) + - common.NS(data)) - - def sendExtendedData(self, channel, dataType, data): - """ - Send extended data to a channel. This should not normally be used: - instead use channel.writeExtendedData(data, dataType) as it manages - the window automatically. - - @type channel: subclass of L{SSHChannel} - @type dataType: C{int} - @type data: C{str} - """ - if channel.localClosed: - return # we're already closed - self.transport.sendPacket(MSG_CHANNEL_EXTENDED_DATA, struct.pack('>2L', - self.channelsToRemoteChannel[channel],dataType) \ - + common.NS(data)) - - def sendEOF(self, channel): - """ - Send an EOF (End of File) for a channel. - - @type channel: subclass of L{SSHChannel} - """ - if channel.localClosed: - return # we're already closed - log.msg('sending eof') - self.transport.sendPacket(MSG_CHANNEL_EOF, struct.pack('>L', - self.channelsToRemoteChannel[channel])) - - def sendClose(self, channel): - """ - Close a channel. - - @type channel: subclass of L{SSHChannel} - """ - if channel.localClosed: - return # we're already closed - log.msg('sending close %i' % channel.id) - self.transport.sendPacket(MSG_CHANNEL_CLOSE, struct.pack('>L', - self.channelsToRemoteChannel[channel])) - channel.localClosed = True - if channel.localClosed and channel.remoteClosed: - self.channelClosed(channel) - - # methods to override - def getChannel(self, channelType, windowSize, maxPacket, data): - """ - The other side requested a channel of some sort. - channelType is the type of channel being requested, - windowSize is the initial size of the remote window, - maxPacket is the largest packet we should send, - data is any other packet data (often nothing). - - We return a subclass of L{SSHChannel}. - - By default, this dispatches to a method 'channel_channelType' with any - non-alphanumerics in the channelType replace with _'s. If it cannot - find a suitable method, it returns an OPEN_UNKNOWN_CHANNEL_TYPE error. - The method is called with arguments of windowSize, maxPacket, data. - - @type channelType: C{str} - @type windowSize: C{int} - @type maxPacket: C{int} - @type data: C{str} - @rtype: subclass of L{SSHChannel}/C{tuple} - """ - log.msg('got channel %s request' % channelType) - if hasattr(self.transport, "avatar"): # this is a server! - chan = self.transport.avatar.lookupChannel(channelType, - windowSize, - maxPacket, - data) - else: - channelType = channelType.translate(TRANSLATE_TABLE) - f = getattr(self, 'channel_%s' % channelType, None) - if f is not None: - chan = f(windowSize, maxPacket, data) - else: - chan = None - if chan is None: - raise error.ConchError('unknown channel', - OPEN_UNKNOWN_CHANNEL_TYPE) - else: - chan.conn = self - return chan - - def gotGlobalRequest(self, requestType, data): - """ - We got a global request. pretty much, this is just used by the client - to request that we forward a port from the server to the client. - Returns either: - - 1: request accepted - - 1, : request accepted with request specific data - - 0: request denied - - By default, this dispatches to a method 'global_requestType' with - -'s in requestType replaced with _'s. The found method is passed data. - If this method cannot be found, this method returns 0. Otherwise, it - returns the return value of that method. - - @type requestType: C{str} - @type data: C{str} - @rtype: C{int}/C{tuple} - """ - log.msg('got global %s request' % requestType) - if hasattr(self.transport, 'avatar'): # this is a server! - return self.transport.avatar.gotGlobalRequest(requestType, data) - - requestType = requestType.replace('-','_') - f = getattr(self, 'global_%s' % requestType, None) - if not f: - return 0 - return f(data) - - def channelClosed(self, channel): - """ - Called when a channel is closed. - It clears the local state related to the channel, and calls - channel.closed(). - MAKE SURE YOU CALL THIS METHOD, even if you subclass L{SSHConnection}. - If you don't, things will break mysteriously. - """ - if channel in self.channelsToRemoteChannel: # actually open - channel.localClosed = channel.remoteClosed = True - del self.localToRemoteChannel[channel.id] - del self.channels[channel.id] - del self.channelsToRemoteChannel[channel] - self.deferreds[channel.id] = [] - log.callWithLogger(channel, channel.closed) - -MSG_GLOBAL_REQUEST = 80 -MSG_REQUEST_SUCCESS = 81 -MSG_REQUEST_FAILURE = 82 -MSG_CHANNEL_OPEN = 90 -MSG_CHANNEL_OPEN_CONFIRMATION = 91 -MSG_CHANNEL_OPEN_FAILURE = 92 -MSG_CHANNEL_WINDOW_ADJUST = 93 -MSG_CHANNEL_DATA = 94 -MSG_CHANNEL_EXTENDED_DATA = 95 -MSG_CHANNEL_EOF = 96 -MSG_CHANNEL_CLOSE = 97 -MSG_CHANNEL_REQUEST = 98 -MSG_CHANNEL_SUCCESS = 99 -MSG_CHANNEL_FAILURE = 100 - -OPEN_ADMINISTRATIVELY_PROHIBITED = 1 -OPEN_CONNECT_FAILED = 2 -OPEN_UNKNOWN_CHANNEL_TYPE = 3 -OPEN_RESOURCE_SHORTAGE = 4 - -EXTENDED_DATA_STDERR = 1 - -messages = {} -for name, value in locals().copy().items(): - if name[:4] == 'MSG_': - messages[value] = name # doesn't handle doubles - -import string -alphanums = string.letters + string.digits -TRANSLATE_TABLE = ''.join([chr(i) in alphanums and chr(i) or '_' - for i in range(256)]) -SSHConnection.protocolMessages = messages diff --git a/tools/buildbot/pylibs/twisted/conch/ssh/factory.py b/tools/buildbot/pylibs/twisted/conch/ssh/factory.py deleted file mode 100644 index 0e49735..0000000 --- a/tools/buildbot/pylibs/twisted/conch/ssh/factory.py +++ /dev/null @@ -1,129 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -A Factory for SSH servers, along with an OpenSSHFactory to use the same -data sources as OpenSSH. - -Maintainer: U{Paul Swartz} -""" - -try: - import resource -except ImportError: - resource = None - -from twisted.internet import protocol -from twisted.python import log -from twisted.python.reflect import qual - -from twisted.conch import error -from twisted.conch.ssh import keys -import transport, userauth, connection - -import random -import warnings - -class SSHFactory(protocol.Factory): - services = { - 'ssh-userauth':userauth.SSHUserAuthServer, - 'ssh-connection':connection.SSHConnection - } - def startFactory(self): - # disable coredumps - if resource: - resource.setrlimit(resource.RLIMIT_CORE, (0,0)) - else: - log.msg('INSECURE: unable to disable core dumps.') - if not hasattr(self,'publicKeys'): - self.publicKeys = self.getPublicKeys() - for keyType, value in self.publicKeys.items(): - if isinstance(value, str): - warnings.warn("Returning a mapping from strings to " - "strings from getPublicKeys()/publicKeys (in %s) " - "is deprecated. Return a mapping from " - "strings to Key objects instead." % - (qual(self.__class__)), - DeprecationWarning, stacklevel=1) - self.publicKeys[keyType] = keys.Key.fromString(value) - if not hasattr(self,'privateKeys'): - self.privateKeys = self.getPrivateKeys() - for keyType, value in self.privateKeys.items(): - if not isinstance(value, keys.Key): - warnings.warn("Returning a mapping from strings to " - "PyCrypto key objects from " - "getPrivateKeys()/privateKeys (in %s) " - "is deprecated. Return a mapping from " - "strings to Key objects instead." % - (qual(self.__class__),), - DeprecationWarning, stacklevel=1) - self.privateKeys[keyType] = keys.Key(value) - if not self.publicKeys or not self.privateKeys: - raise error.ConchError('no host keys, failing') - if not hasattr(self,'primes'): - self.primes = self.getPrimes() - - def buildProtocol(self, addr): - t = transport.SSHServerTransport() - t.supportedPublicKeys = self.privateKeys.keys() - if not self.primes: - log.msg('disabling diffie-hellman-group-exchange because we ' - 'cannot find moduli file') - ske = t.supportedKeyExchanges[:] - ske.remove('diffie-hellman-group-exchange-sha1') - t.supportedKeyExchanges = ske - t.factory = self - return t - - def getPublicKeys(self): - """ - Called when the factory is started to get the public portions of the - servers host keys. Returns a dictionary mapping SSH key types to - public key strings. - - @rtype: C{dict} - """ - raise NotImplementedError('getPublicKeys unimplemented') - - def getPrivateKeys(self): - """ - Called when the factory is started to get the private portions of the - servers host keys. Returns a dictionary mapping SSH key types to - C{Crypto.PublicKey.pubkey.pubkey} objects. - - @rtype: C{dict} - """ - raise NotImplementedError('getPrivateKeys unimplemented') - - def getPrimes(self): - """ - Called when the factory is started to get Diffie-Hellman generators and - primes to use. Returns a dictionary mapping number of bits to lists - of tuple of (generator, prime). - - @rtype: C{dict} - """ - - def getDHPrime(self, bits): - """ - Return a tuple of (g, p) for a Diffe-Hellman process, with p being as - close to bits bits as possible. - - @type bits: C{int} - @rtype: C{tuple} - """ - primesKeys = self.primes.keys() - primesKeys.sort(lambda x, y: cmp(abs(x - bits), abs(y - bits))) - realBits = primesKeys[0] - return random.choice(self.primes[realBits]) - - def getService(self, transport, service): - """ - Return a class to use as a service for the given transport. - - @type transport: L{transport.SSHServerTransport} - @type service: C{str} - @rtype: subclass of L{service.SSHService} - """ - if service == 'ssh-userauth' or hasattr(transport, 'avatar'): - return self.services[service] diff --git a/tools/buildbot/pylibs/twisted/conch/ssh/filetransfer.py b/tools/buildbot/pylibs/twisted/conch/ssh/filetransfer.py deleted file mode 100644 index 748f2b6..0000000 --- a/tools/buildbot/pylibs/twisted/conch/ssh/filetransfer.py +++ /dev/null @@ -1,896 +0,0 @@ -# -*- test-case-name: twisted.conch.test.test_filetransfer -*- -# -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -import struct, errno - -from twisted.internet import defer, protocol -from twisted.python import failure, log - -from common import NS, getNS -from twisted.conch.interfaces import ISFTPServer, ISFTPFile - -from zope import interface - - - -class FileTransferBase(protocol.Protocol): - - versions = (3, ) - - packetTypes = {} - - def __init__(self): - self.buf = '' - self.otherVersion = None # this gets set - - def sendPacket(self, kind, data): - self.transport.write(struct.pack('!LB', len(data)+1, kind) + data) - - def dataReceived(self, data): - self.buf += data - while len(self.buf) > 5: - length, kind = struct.unpack('!LB', self.buf[:5]) - if len(self.buf) < 4 + length: - return - data, self.buf = self.buf[5:4+length], self.buf[4+length:] - packetType = self.packetTypes.get(kind, None) - if not packetType: - log.msg('no packet type for', kind) - continue - f = getattr(self, 'packet_%s' % packetType, None) - if not f: - log.msg('not implemented: %s' % packetType) - log.msg(repr(data[4:])) - reqId, = struct.unpack('!L', data[:4]) - self._sendStatus(reqId, FX_OP_UNSUPPORTED, - "don't understand %s" % packetType) - #XXX not implemented - continue - try: - f(data) - except: - log.err() - continue - reqId ,= struct.unpack('!L', data[:4]) - self._ebStatus(failure.Failure(e), reqId) - - def _parseAttributes(self, data): - flags ,= struct.unpack('!L', data[:4]) - attrs = {} - data = data[4:] - if flags & FILEXFER_ATTR_SIZE == FILEXFER_ATTR_SIZE: - size ,= struct.unpack('!Q', data[:8]) - attrs['size'] = size - data = data[8:] - if flags & FILEXFER_ATTR_OWNERGROUP == FILEXFER_ATTR_OWNERGROUP: - uid, gid = struct.unpack('!2L', data[:8]) - attrs['uid'] = uid - attrs['gid'] = gid - data = data[8:] - if flags & FILEXFER_ATTR_PERMISSIONS == FILEXFER_ATTR_PERMISSIONS: - perms ,= struct.unpack('!L', data[:4]) - attrs['permissions'] = perms - data = data[4:] - if flags & FILEXFER_ATTR_ACMODTIME == FILEXFER_ATTR_ACMODTIME: - atime, mtime = struct.unpack('!2L', data[:8]) - attrs['atime'] = atime - attrs['mtime'] = mtime - data = data[8:] - if flags & FILEXFER_ATTR_EXTENDED == FILEXFER_ATTR_EXTENDED: - extended_count ,= struct.unpack('!L', data[:4]) - data = data[4:] - for i in xrange(extended_count): - extended_type, data = getNS(data) - extended_data, data = getNS(data) - attrs['ext_%s' % extended_type] = extended_data - return attrs, data - - def _packAttributes(self, attrs): - flags = 0 - data = '' - if 'size' in attrs: - data += struct.pack('!Q', attrs['size']) - flags |= FILEXFER_ATTR_SIZE - if 'uid' in attrs and 'gid' in attrs: - data += struct.pack('!2L', attrs['uid'], attrs['gid']) - flags |= FILEXFER_ATTR_OWNERGROUP - if 'permissions' in attrs: - data += struct.pack('!L', attrs['permissions']) - flags |= FILEXFER_ATTR_PERMISSIONS - if 'atime' in attrs and 'mtime' in attrs: - data += struct.pack('!2L', attrs['atime'], attrs['mtime']) - flags |= FILEXFER_ATTR_ACMODTIME - extended = [] - for k in attrs: - if k.startswith('ext_'): - ext_type = NS(k[4:]) - ext_data = NS(attrs[k]) - extended.append(ext_type+ext_data) - if extended: - data += struct.pack('!L', len(extended)) - data += ''.join(extended) - flags |= FILEXFER_ATTR_EXTENDED - return struct.pack('!L', flags) + data - -class FileTransferServer(FileTransferBase): - - def __init__(self, data=None, avatar=None): - FileTransferBase.__init__(self) - self.client = ISFTPServer(avatar) # yay interfaces - self.openFiles = {} - self.openDirs = {} - - def packet_INIT(self, data): - version ,= struct.unpack('!L', data[:4]) - self.version = min(list(self.versions) + [version]) - data = data[4:] - ext = {} - while data: - ext_name, data = getNS(data) - ext_data, data = getNS(data) - ext[ext_name] = ext_data - our_ext = self.client.gotVersion(version, ext) - our_ext_data = "" - for (k,v) in our_ext.items(): - our_ext_data += NS(k) + NS(v) - self.sendPacket(FXP_VERSION, struct.pack('!L', self.version) + \ - our_ext_data) - - def packet_OPEN(self, data): - requestId = data[:4] - data = data[4:] - filename, data = getNS(data) - flags ,= struct.unpack('!L', data[:4]) - data = data[4:] - attrs, data = self._parseAttributes(data) - assert data == '', 'still have data in OPEN: %s' % repr(data) - d = defer.maybeDeferred(self.client.openFile, filename, flags, attrs) - d.addCallback(self._cbOpenFile, requestId) - d.addErrback(self._ebStatus, requestId, "open failed") - - def _cbOpenFile(self, fileObj, requestId): - fileId = str(hash(fileObj)) - if fileId in self.openFiles: - raise KeyError, 'id already open' - self.openFiles[fileId] = fileObj - self.sendPacket(FXP_HANDLE, requestId + NS(fileId)) - - def packet_CLOSE(self, data): - requestId = data[:4] - data = data[4:] - handle, data = getNS(data) - assert data == '', 'still have data in CLOSE: %s' % repr(data) - if handle in self.openFiles: - fileObj = self.openFiles[handle] - d = defer.maybeDeferred(fileObj.close) - d.addCallback(self._cbClose, handle, requestId) - d.addErrback(self._ebStatus, requestId, "close failed") - elif handle in self.openDirs: - dirObj = self.openDirs[handle][0] - d = defer.maybeDeferred(dirObj.close) - d.addCallback(self._cbClose, handle, requestId, 1) - d.addErrback(self._ebStatus, requestId, "close failed") - else: - self._ebClose(failure.Failure(KeyError()), requestId) - - def _cbClose(self, result, handle, requestId, isDir = 0): - if isDir: - del self.openDirs[handle] - else: - del self.openFiles[handle] - self._sendStatus(requestId, FX_OK, 'file closed') - - def packet_READ(self, data): - requestId = data[:4] - data = data[4:] - handle, data = getNS(data) - (offset, length), data = struct.unpack('!QL', data[:12]), data[12:] - assert data == '', 'still have data in READ: %s' % repr(data) - if handle not in self.openFiles: - self._ebRead(failure.Failure(KeyError()), requestId) - else: - fileObj = self.openFiles[handle] - d = defer.maybeDeferred(fileObj.readChunk, offset, length) - d.addCallback(self._cbRead, requestId) - d.addErrback(self._ebStatus, requestId, "read failed") - - def _cbRead(self, result, requestId): - if result == '': # python's read will return this for EOF - raise EOFError() - self.sendPacket(FXP_DATA, requestId + NS(result)) - - def packet_WRITE(self, data): - requestId = data[:4] - data = data[4:] - handle, data = getNS(data) - offset, = struct.unpack('!Q', data[:8]) - data = data[8:] - writeData, data = getNS(data) - assert data == '', 'still have data in WRITE: %s' % repr(data) - if handle not in self.openFiles: - self._ebWrite(failure.Failure(KeyError()), requestId) - else: - fileObj = self.openFiles[handle] - d = defer.maybeDeferred(fileObj.writeChunk, offset, writeData) - d.addCallback(self._cbStatus, requestId, "write succeeded") - d.addErrback(self._ebStatus, requestId, "write failed") - - def packet_REMOVE(self, data): - requestId = data[:4] - data = data[4:] - filename, data = getNS(data) - assert data == '', 'still have data in REMOVE: %s' % repr(data) - d = defer.maybeDeferred(self.client.removeFile, filename) - d.addCallback(self._cbStatus, requestId, "remove succeeded") - d.addErrback(self._ebStatus, requestId, "remove failed") - - def packet_RENAME(self, data): - requestId = data[:4] - data = data[4:] - oldPath, data = getNS(data) - newPath, data = getNS(data) - assert data == '', 'still have data in RENAME: %s' % repr(data) - d = defer.maybeDeferred(self.client.renameFile, oldPath, newPath) - d.addCallback(self._cbStatus, requestId, "rename succeeded") - d.addErrback(self._ebStatus, requestId, "rename failed") - - def packet_MKDIR(self, data): - requestId = data[:4] - data = data[4:] - path, data = getNS(data) - attrs, data = self._parseAttributes(data) - assert data == '', 'still have data in MKDIR: %s' % repr(data) - d = defer.maybeDeferred(self.client.makeDirectory, path, attrs) - d.addCallback(self._cbStatus, requestId, "mkdir succeeded") - d.addErrback(self._ebStatus, requestId, "mkdir failed") - - def packet_RMDIR(self, data): - requestId = data[:4] - data = data[4:] - path, data = getNS(data) - assert data == '', 'still have data in RMDIR: %s' % repr(data) - d = defer.maybeDeferred(self.client.removeDirectory, path) - d.addCallback(self._cbStatus, requestId, "rmdir succeeded") - d.addErrback(self._ebStatus, requestId, "rmdir failed") - - def packet_OPENDIR(self, data): - requestId = data[:4] - data = data[4:] - path, data = getNS(data) - assert data == '', 'still have data in OPENDIR: %s' % repr(data) - d = defer.maybeDeferred(self.client.openDirectory, path) - d.addCallback(self._cbOpenDirectory, requestId) - d.addErrback(self._ebStatus, requestId, "opendir failed") - - def _cbOpenDirectory(self, dirObj, requestId): - handle = str(hash(dirObj)) - if handle in self.openDirs: - raise KeyError, "already opened this directory" - self.openDirs[handle] = [dirObj, iter(dirObj)] - self.sendPacket(FXP_HANDLE, requestId + NS(handle)) - - def packet_READDIR(self, data): - requestId = data[:4] - data = data[4:] - handle, data = getNS(data) - assert data == '', 'still have data in READDIR: %s' % repr(data) - if handle not in self.openDirs: - self._ebStatus(failure.Failure(KeyError()), requestId) - else: - dirObj, dirIter = self.openDirs[handle] - d = defer.maybeDeferred(self._scanDirectory, dirIter, []) - d.addCallback(self._cbSendDirectory, requestId) - d.addErrback(self._ebStatus, requestId, "scan directory failed") - - def _scanDirectory(self, dirIter, f): - while len(f) < 250: - try: - info = dirIter.next() - except StopIteration: - if not f: - raise EOFError - return f - if isinstance(info, defer.Deferred): - info.addCallback(self._cbScanDirectory, dirIter, f) - return - else: - f.append(info) - return f - - def _cbScanDirectory(self, result, dirIter, f): - f.append(result) - return self._scanDirectory(dirIter, f) - - def _cbSendDirectory(self, result, requestId): - data = '' - for (filename, longname, attrs) in result: - data += NS(filename) - data += NS(longname) - data += self._packAttributes(attrs) - self.sendPacket(FXP_NAME, requestId + - struct.pack('!L', len(result))+data) - - def packet_STAT(self, data, followLinks = 1): - requestId = data[:4] - data = data[4:] - path, data = getNS(data) - assert data == '', 'still have data in STAT/LSTAT: %s' % repr(data) - d = defer.maybeDeferred(self.client.getAttrs, path, followLinks) - d.addCallback(self._cbStat, requestId) - d.addErrback(self._ebStatus, requestId, 'stat/lstat failed') - - def packet_LSTAT(self, data): - self.packet_STAT(data, 0) - - def packet_FSTAT(self, data): - requestId = data[:4] - data = data[4:] - handle, data = getNS(data) - assert data == '', 'still have data in FSTAT: %s' % repr(data) - if handle not in self.openFiles: - self._ebStatus(failure.Failure(KeyError('%s not in self.openFiles' - % handle)), requestId) - else: - fileObj = self.openFiles[handle] - d = defer.maybeDeferred(fileObj.getAttrs) - d.addCallback(self._cbStat, requestId) - d.addErrback(self._ebStatus, requestId, 'fstat failed') - - def _cbStat(self, result, requestId): - data = requestId + self._packAttributes(result) - self.sendPacket(FXP_ATTRS, data) - - def packet_SETSTAT(self, data): - requestId = data[:4] - data = data[4:] - path, data = getNS(data) - attrs, data = self._parseAttributes(data) - if data != '': - log.msg('WARN: still have data in SETSTAT: %s' % repr(data)) - d = defer.maybeDeferred(self.client.setAttrs, path, attrs) - d.addCallback(self._cbStatus, requestId, 'setstat succeeded') - d.addErrback(self._ebStatus, requestId, 'setstat failed') - - def packet_FSETSTAT(self, data): - requestId = data[:4] - data = data[4:] - handle, data = getNS(data) - attrs, data = self._parseAttributes(data) - assert data == '', 'still have data in FSETSTAT: %s' % repr(data) - if handle not in self.openFiles: - self._ebStatus(failure.Failure(KeyError()), requestId) - else: - fileObj = self.openFiles[handle] - d = defer.maybeDeferred(fileObj.setAttrs, attrs) - d.addCallback(self._cbStatus, requestId, 'fsetstat succeeded') - d.addErrback(self._ebStatus, requestId, 'fsetstat failed') - - def packet_READLINK(self, data): - requestId = data[:4] - data = data[4:] - path, data = getNS(data) - assert data == '', 'still have data in READLINK: %s' % repr(data) - d = defer.maybeDeferred(self.client.readLink, path) - d.addCallback(self._cbReadLink, requestId) - d.addErrback(self._ebStatus, requestId, 'readlink failed') - - def _cbReadLink(self, result, requestId): - self._cbSendDirectory([(result, '', {})], requestId) - - def packet_SYMLINK(self, data): - requestId = data[:4] - data = data[4:] - linkPath, data = getNS(data) - targetPath, data = getNS(data) - d = defer.maybeDeferred(self.client.makeLink, linkPath, targetPath) - d.addCallback(self._cbStatus, requestId, 'symlink succeeded') - d.addErrback(self._ebStatus, requestId, 'symlink failed') - - def packet_REALPATH(self, data): - requestId = data[:4] - data = data[4:] - path, data = getNS(data) - assert data == '', 'still have data in REALPATH: %s' % repr(data) - d = defer.maybeDeferred(self.client.realPath, path) - d.addCallback(self._cbReadLink, requestId) # same return format - d.addErrback(self._ebStatus, requestId, 'realpath failed') - - def packet_EXTENDED(self, data): - requestId = data[:4] - data = data[4:] - extName, extData = getNS(data) - d = defer.maybeDeferred(self.client.extendedRequest, extName, extData) - d.addCallback(self._cbExtended, requestId) - d.addErrback(self._ebStatus, requestId, 'extended %s failed' % extName) - - def _cbExtended(self, data, requestId): - self.sendPacket(FXP_EXTENDED_REPLY, requestId + data) - - def _cbStatus(self, result, requestId, msg = "request succeeded"): - self._sendStatus(requestId, FX_OK, msg) - - def _ebStatus(self, reason, requestId, msg = "request failed"): - code = FX_FAILURE - message = msg - if reason.type in (IOError, OSError): - if reason.value.errno == errno.ENOENT: # no such file - code = FX_NO_SUCH_FILE - message = reason.value.strerror - elif reason.value.errno == errno.EACCES: # permission denied - code = FX_PERMISSION_DENIED - message = reason.value.strerror - else: - log.err(reason) - elif reason.type == EOFError: # EOF - code = FX_EOF - if reason.value.args: - message = reason.value.args[0] - elif reason.type == NotImplementedError: - code = FX_OP_UNSUPPORTED - if reason.value.args: - message = reason.value.args[0] - elif reason.type == SFTPError: - code = reason.value.code - message = reason.value.message - else: - log.err(reason) - self._sendStatus(requestId, code, message) - - def _sendStatus(self, requestId, code, message, lang = ''): - """ - Helper method to send a FXP_STATUS message. - """ - data = requestId + struct.pack('!L', code) - data += NS(message) - data += NS(lang) - self.sendPacket(FXP_STATUS, data) - -class FileTransferClient(FileTransferBase): - - def __init__(self, extData = {}): - """ - @param extData: a dict of extended_name : extended_data items - to be sent to the server. - """ - FileTransferBase.__init__(self) - self.extData = {} - self.counter = 0 - self.openRequests = {} # id -> Deferred - self.wasAFile = {} # Deferred -> 1 TERRIBLE HACK - - def connectionMade(self): - data = struct.pack('!L', max(self.versions)) - for k,v in self.extData.itervalues(): - data += NS(k) + NS(v) - self.sendPacket(FXP_INIT, data) - - def _sendRequest(self, msg, data): - data = struct.pack('!L', self.counter) + data - d = defer.Deferred() - self.openRequests[self.counter] = d - self.counter += 1 - self.sendPacket(msg, data) - return d - - def _parseRequest(self, data): - (id,) = struct.unpack('!L', data[:4]) - d = self.openRequests[id] - del self.openRequests[id] - return d, data[4:] - - def openFile(self, filename, flags, attrs): - """ - Open a file. - - This method returns a L{Deferred} that is called back with an object - that provides the L{ISFTPFile} interface. - - @param filename: a string representing the file to open. - - @param flags: a integer of the flags to open the file with, ORed together. - The flags and their values are listed at the bottom of this file. - - @param attrs: a list of attributes to open the file with. It is a - dictionary, consisting of 0 or more keys. The possible keys are:: - - size: the size of the file in bytes - uid: the user ID of the file as an integer - gid: the group ID of the file as an integer - permissions: the permissions of the file with as an integer. - the bit representation of this field is defined by POSIX. - atime: the access time of the file as seconds since the epoch. - mtime: the modification time of the file as seconds since the epoch. - ext_*: extended attributes. The server is not required to - understand this, but it may. - - NOTE: there is no way to indicate text or binary files. it is up - to the SFTP client to deal with this. - """ - data = NS(filename) + struct.pack('!L', flags) + self._packAttributes(attrs) - d = self._sendRequest(FXP_OPEN, data) - self.wasAFile[d] = (1, filename) # HACK - return d - - def removeFile(self, filename): - """ - Remove the given file. - - This method returns a Deferred that is called back when it succeeds. - - @param filename: the name of the file as a string. - """ - return self._sendRequest(FXP_REMOVE, NS(filename)) - - def renameFile(self, oldpath, newpath): - """ - Rename the given file. - - This method returns a Deferred that is called back when it succeeds. - - @param oldpath: the current location of the file. - @param newpath: the new file name. - """ - return self._sendRequest(FXP_RENAME, NS(oldpath)+NS(newpath)) - - def makeDirectory(self, path, attrs): - """ - Make a directory. - - This method returns a Deferred that is called back when it is - created. - - @param path: the name of the directory to create as a string. - - @param attrs: a dictionary of attributes to create the directory - with. Its meaning is the same as the attrs in the openFile method. - """ - return self._sendRequest(FXP_MKDIR, NS(path)+self._packAttributes(attrs)) - - def removeDirectory(self, path): - """ - Remove a directory (non-recursively) - - It is an error to remove a directory that has files or directories in - it. - - This method returns a Deferred that is called back when it is removed. - - @param path: the directory to remove. - """ - return self._sendRequest(FXP_RMDIR, NS(path)) - - def openDirectory(self, path): - """ - Open a directory for scanning. - - This method returns a Deferred that is called back with an iterable - object that has a close() method. - - The close() method is called when the client is finished reading - from the directory. At this point, the iterable will no longer - be used. - - The iterable returns triples of the form (filename, longname, attrs) - or a Deferred that returns the same. The sequence must support - __getitem__, but otherwise may be any 'sequence-like' object. - - filename is the name of the file relative to the directory. - logname is an expanded format of the filename. The recommended format - is: - -rwxr-xr-x 1 mjos staff 348911 Mar 25 14:29 t-filexfer - 1234567890 123 12345678 12345678 12345678 123456789012 - - The first line is sample output, the second is the length of the field. - The fields are: permissions, link count, user owner, group owner, - size in bytes, modification time. - - attrs is a dictionary in the format of the attrs argument to openFile. - - @param path: the directory to open. - """ - d = self._sendRequest(FXP_OPENDIR, NS(path)) - self.wasAFile[d] = (0, path) - return d - - def getAttrs(self, path, followLinks=0): - """ - Return the attributes for the given path. - - This method returns a dictionary in the same format as the attrs - argument to openFile or a Deferred that is called back with same. - - @param path: the path to return attributes for as a string. - @param followLinks: a boolean. if it is True, follow symbolic links - and return attributes for the real path at the base. if it is False, - return attributes for the specified path. - """ - if followLinks: m = FXP_STAT - else: m = FXP_LSTAT - return self._sendRequest(m, NS(path)) - - def setAttrs(self, path, attrs): - """ - Set the attributes for the path. - - This method returns when the attributes are set or a Deferred that is - called back when they are. - - @param path: the path to set attributes for as a string. - @param attrs: a dictionary in the same format as the attrs argument to - openFile. - """ - data = NS(path) + self._packAttributes(attrs) - return self._sendRequest(FXP_SETSTAT, data) - - def readLink(self, path): - """ - Find the root of a set of symbolic links. - - This method returns the target of the link, or a Deferred that - returns the same. - - @param path: the path of the symlink to read. - """ - d = self._sendRequest(FXP_READLINK, NS(path)) - return d.addCallback(self._cbRealPath) - - def makeLink(self, linkPath, targetPath): - """ - Create a symbolic link. - - This method returns when the link is made, or a Deferred that - returns the same. - - @param linkPath: the pathname of the symlink as a string - @param targetPath: the path of the target of the link as a string. - """ - return self._sendRequest(FXP_SYMLINK, NS(linkPath)+NS(targetPath)) - - def realPath(self, path): - """ - Convert any path to an absolute path. - - This method returns the absolute path as a string, or a Deferred - that returns the same. - - @param path: the path to convert as a string. - """ - d = self._sendRequest(FXP_REALPATH, NS(path)) - return d.addCallback(self._cbRealPath) - - def _cbRealPath(self, result): - name, longname, attrs = result[0] - return name - - def extendedRequest(self, request, data): - """ - Make an extended request of the server. - - The method returns a Deferred that is called back with - the result of the extended request. - - @param request: the name of the extended request to make. - @param data: any other data that goes along with the request. - """ - return self._sendRequest(FXP_EXTENDED, NS(request) + data) - - def packet_VERSION(self, data): - version, = struct.unpack('!L', data[:4]) - data = data[4:] - d = {} - while data: - k, data = getNS(data) - v, data = getNS(data) - d[k]=v - self.version = version - self.gotServerVersion(version, d) - - def packet_STATUS(self, data): - d, data = self._parseRequest(data) - code, = struct.unpack('!L', data[:4]) - data = data[4:] - msg, data = getNS(data) - lang = getNS(data) - if code == FX_OK: - d.callback((msg, lang)) - elif code == FX_EOF: - d.errback(EOFError(msg)) - elif code == FX_OP_UNSUPPORTED: - d.errback(NotImplementedError(msg)) - else: - d.errback(SFTPError(code, msg, lang)) - - def packet_HANDLE(self, data): - d, data = self._parseRequest(data) - isFile, name = self.wasAFile.pop(d) - if isFile: - cb = ClientFile(self, getNS(data)[0]) - else: - cb = ClientDirectory(self, getNS(data)[0]) - cb.name = name - d.callback(cb) - - def packet_DATA(self, data): - d, data = self._parseRequest(data) - d.callback(getNS(data)[0]) - - def packet_NAME(self, data): - d, data = self._parseRequest(data) - count, = struct.unpack('!L', data[:4]) - data = data[4:] - files = [] - for i in range(count): - filename, data = getNS(data) - longname, data = getNS(data) - attrs, data = self._parseAttributes(data) - files.append((filename, longname, attrs)) - d.callback(files) - - def packet_ATTRS(self, data): - d, data = self._parseRequest(data) - d.callback(self._parseAttributes(data)[0]) - - def packet_EXTENDED_REPLY(self, data): - d, data = self._parseRequest(data) - d.callback(data) - - def gotServerVersion(self, serverVersion, extData): - """ - Called when the client sends their version info. - - @param otherVersion: an integer representing the version of the SFTP - protocol they are claiming. - @param extData: a dictionary of extended_name : extended_data items. - These items are sent by the client to indicate additional features. - """ - -class ClientFile: - - interface.implements(ISFTPFile) - - def __init__(self, parent, handle): - self.parent = parent - self.handle = NS(handle) - - def close(self): - return self.parent._sendRequest(FXP_CLOSE, self.handle) - - def readChunk(self, offset, length): - data = self.handle + struct.pack("!QL", offset, length) - return self.parent._sendRequest(FXP_READ, data) - - def writeChunk(self, offset, chunk): - data = self.handle + struct.pack("!Q", offset) + NS(chunk) - return self.parent._sendRequest(FXP_WRITE, data) - - def getAttrs(self): - return self.parent._sendRequest(FXP_FSTAT, self.handle) - - def setAttrs(self, attrs): - data = self.handle + self.parent._packAttributes(attrs) - return self.parent._sendRequest(FXP_FSTAT, data) - -class ClientDirectory: - - def __init__(self, parent, handle): - self.parent = parent - self.handle = NS(handle) - self.filesCache = [] - - def read(self): - d = self.parent._sendRequest(FXP_READDIR, self.handle) - return d - - def close(self): - return self.parent._sendRequest(FXP_CLOSE, self.handle) - - def __iter__(self): - return self - - def next(self): - if self.filesCache: - return self.filesCache.pop(0) - d = self.read() - d.addCallback(self._cbReadDir) - d.addErrback(self._ebReadDir) - return d - - def _cbReadDir(self, names): - self.filesCache = names[1:] - return names[0] - - def _ebReadDir(self, reason): - reason.trap(EOFError) - def _(): - raise StopIteration - self.next = _ - return reason - - -class SFTPError(Exception): - - def __init__(self, errorCode, errorMessage, lang = ''): - Exception.__init__(self) - self.code = errorCode - self.message = errorMessage - self.lang = lang - - def __str__(self): - return 'SFTPError %s: %s' % (self.code, self.message) - -FXP_INIT = 1 -FXP_VERSION = 2 -FXP_OPEN = 3 -FXP_CLOSE = 4 -FXP_READ = 5 -FXP_WRITE = 6 -FXP_LSTAT = 7 -FXP_FSTAT = 8 -FXP_SETSTAT = 9 -FXP_FSETSTAT = 10 -FXP_OPENDIR = 11 -FXP_READDIR = 12 -FXP_REMOVE = 13 -FXP_MKDIR = 14 -FXP_RMDIR = 15 -FXP_REALPATH = 16 -FXP_STAT = 17 -FXP_RENAME = 18 -FXP_READLINK = 19 -FXP_SYMLINK = 20 -FXP_STATUS = 101 -FXP_HANDLE = 102 -FXP_DATA = 103 -FXP_NAME = 104 -FXP_ATTRS = 105 -FXP_EXTENDED = 200 -FXP_EXTENDED_REPLY = 201 - -FILEXFER_ATTR_SIZE = 0x00000001 -FILEXFER_ATTR_OWNERGROUP = 0x00000002 -FILEXFER_ATTR_PERMISSIONS = 0x00000004 -FILEXFER_ATTR_ACMODTIME = 0x00000009 -FILEXFER_ATTR_EXTENDED = 0x80000000L - -FILEXFER_TYPE_REGULAR = 1 -FILEXFER_TYPE_DIRECTORY = 2 -FILEXFER_TYPE_SYMLINK = 3 -FILEXFER_TYPE_SPECIAL = 4 -FILEXFER_TYPE_UNKNOWN = 5 - -FXF_READ = 0x00000001 -FXF_WRITE = 0x00000002 -FXF_APPEND = 0x00000004 -FXF_CREAT = 0x00000008 -FXF_TRUNC = 0x00000010 -FXF_EXCL = 0x00000020 -FXF_TEXT = 0x00000040 - -FX_OK = 0 -FX_EOF = 1 -FX_NO_SUCH_FILE = 2 -FX_PERMISSION_DENIED = 3 -FX_FAILURE = 4 -FX_BAD_MESSAGE = 5 -FX_NO_CONNECTION = 6 -FX_CONNECTION_LOST = 7 -FX_OP_UNSUPPORTED = 8 -# http://www.ietf.org/internet-drafts/draft-ietf-secsh-filexfer-12.txt defines -# more useful error codes, but so far OpenSSH doesn't implement them. We use -# them internally for clarity, but for now define them all as FX_FAILURE to be -# compatible with existing software. -FX_FILE_ALREADY_EXISTS = FX_FAILURE -FX_NOT_A_DIRECTORY = FX_FAILURE -FX_FILE_IS_A_DIRECTORY = FX_FAILURE - - -# initialize FileTransferBase.packetTypes: -g = globals() -for name in g.keys(): - if name.startswith('FXP_'): - value = g[name] - FileTransferBase.packetTypes[value] = name[4:] -del g, name, value diff --git a/tools/buildbot/pylibs/twisted/conch/ssh/forwarding.py b/tools/buildbot/pylibs/twisted/conch/ssh/forwarding.py deleted file mode 100644 index 25dcb5b..0000000 --- a/tools/buildbot/pylibs/twisted/conch/ssh/forwarding.py +++ /dev/null @@ -1,181 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -""" -This module contains the implementation of the TCP forwarding, which allows -clients and servers to forward arbitrary TCP data across the connection. - -Maintainer: U{Paul Swartz} -""" - -import struct - -from twisted.internet import protocol, reactor -from twisted.python import log - -import common, channel - -class SSHListenForwardingFactory(protocol.Factory): - def __init__(self, connection, hostport, klass): - self.conn = connection - self.hostport = hostport # tuple - self.klass = klass - - def buildProtocol(self, addr): - channel = self.klass(conn = self.conn) - client = SSHForwardingClient(channel) - channel.client = client - addrTuple = (addr.host, addr.port) - channelOpenData = packOpen_direct_tcpip(self.hostport, addrTuple) - self.conn.openChannel(channel, channelOpenData) - return client - -class SSHListenForwardingChannel(channel.SSHChannel): - - def channelOpen(self, specificData): - log.msg('opened forwarding channel %s' % self.id) - if len(self.client.buf)>1: - b = self.client.buf[1:] - self.write(b) - self.client.buf = '' - - def openFailed(self, reason): - self.closed() - - def dataReceived(self, data): - self.client.transport.write(data) - - def eofReceived(self): - self.client.transport.loseConnection() - - def closed(self): - if hasattr(self, 'client'): - log.msg('closing local forwarding channel %s' % self.id) - self.client.transport.loseConnection() - del self.client - -class SSHListenClientForwardingChannel(SSHListenForwardingChannel): - - name = 'direct-tcpip' - -class SSHListenServerForwardingChannel(SSHListenForwardingChannel): - - name = 'forwarded-tcpip' - -class SSHConnectForwardingChannel(channel.SSHChannel): - - def __init__(self, hostport, *args, **kw): - channel.SSHChannel.__init__(self, *args, **kw) - self.hostport = hostport - self.client = None - self.clientBuf = '' - - def channelOpen(self, specificData): - cc = protocol.ClientCreator(reactor, SSHForwardingClient, self) - log.msg("connecting to %s:%i" % self.hostport) - cc.connectTCP(*self.hostport).addCallbacks(self._setClient, self._close) - - def _setClient(self, client): - self.client = client - log.msg("connected to %s:%i" % self.hostport) - if self.clientBuf: - self.client.transport.write(self.clientBuf) - self.clientBuf = None - if self.client.buf[1:]: - self.write(self.client.buf[1:]) - self.client.buf = '' - - def _close(self, reason): - log.msg("failed to connect: %s" % reason) - self.loseConnection() - - def dataReceived(self, data): - if self.client: - self.client.transport.write(data) - else: - self.clientBuf += data - - def closed(self): - if self.client: - log.msg('closed remote forwarding channel %s' % self.id) - if self.client.channel: - self.loseConnection() - self.client.transport.loseConnection() - del self.client - -def openConnectForwardingClient(remoteWindow, remoteMaxPacket, data, avatar): - remoteHP, origHP = unpackOpen_direct_tcpip(data) - return SSHConnectForwardingChannel(remoteHP, - remoteWindow=remoteWindow, - remoteMaxPacket=remoteMaxPacket, - avatar=avatar) - -class SSHForwardingClient(protocol.Protocol): - - def __init__(self, channel): - self.channel = channel - self.buf = '\000' - - def dataReceived(self, data): - if self.buf: - self.buf += data - else: - self.channel.write(data) - - def connectionLost(self, reason): - if self.channel: - self.channel.loseConnection() - self.channel = None - - -def packOpen_direct_tcpip((connHost, connPort), (origHost, origPort)): - """Pack the data suitable for sending in a CHANNEL_OPEN packet. - """ - conn = common.NS(connHost) + struct.pack('>L', connPort) - orig = common.NS(origHost) + struct.pack('>L', origPort) - return conn + orig - -packOpen_forwarded_tcpip = packOpen_direct_tcpip - -def unpackOpen_direct_tcpip(data): - """Unpack the data to a usable format. - """ - connHost, rest = common.getNS(data) - connPort = int(struct.unpack('>L', rest[:4])[0]) - origHost, rest = common.getNS(rest[4:]) - origPort = int(struct.unpack('>L', rest[:4])[0]) - return (connHost, connPort), (origHost, origPort) - -unpackOpen_forwarded_tcpip = unpackOpen_direct_tcpip - -def packGlobal_tcpip_forward((host, port)): - return common.NS(host) + struct.pack('>L', port) - -def unpackGlobal_tcpip_forward(data): - host, rest = common.getNS(data) - port = int(struct.unpack('>L', rest[:4])[0]) - return host, port - -"""This is how the data -> eof -> close stuff /should/ work. - -debug3: channel 1: waiting for connection -debug1: channel 1: connected -debug1: channel 1: read<=0 rfd 7 len 0 -debug1: channel 1: read failed -debug1: channel 1: close_read -debug1: channel 1: input open -> drain -debug1: channel 1: ibuf empty -debug1: channel 1: send eof -debug1: channel 1: input drain -> closed -debug1: channel 1: rcvd eof -debug1: channel 1: output open -> drain -debug1: channel 1: obuf empty -debug1: channel 1: close_write -debug1: channel 1: output drain -> closed -debug1: channel 1: rcvd close -debug3: channel 1: will not send data after close -debug1: channel 1: send close -debug1: channel 1: is dead -""" diff --git a/tools/buildbot/pylibs/twisted/conch/ssh/keys.py b/tools/buildbot/pylibs/twisted/conch/ssh/keys.py deleted file mode 100644 index 6e6f77e..0000000 --- a/tools/buildbot/pylibs/twisted/conch/ssh/keys.py +++ /dev/null @@ -1,829 +0,0 @@ -# -*- test-case-name: twisted.conch.test.test_keys -*- -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -""" -Handling of RSA and DSA keys. - -Maintainer: U{Paul Swartz} -""" - -# base library imports -import base64 -import sha, md5 -import warnings - -# external library imports -from Crypto.Cipher import DES3 -from Crypto.PublicKey import RSA, DSA -from Crypto import Util - -# twisted -from twisted.python import randbytes - -# sibling imports -from twisted.conch.ssh import asn1, common, sexpy - - -class BadKeyError(Exception): - """ - Raised when a key isn't what we expected from it. - - XXX: we really need to check for bad keys - """ - -class EncryptedKeyError(Exception): - """ - Raised when an encrypted key is presented to fromString/fromFile without - a password. - """ - -class Key(object): - """ - An object representing a key. A key can be either a public or - private key. A public key can verify a signature; a private key can - create or verify a signature. To generate a string that can be stored - on disk, use the toString method. If you have a private key, but want - the string representation of the public key, use Key.public().toString(). - - @ivar keyObject: The C{Crypto.PublicKey.pubkey.pubkey} object that - operations are performed with. - """ - - def fromFile(Class, filename, type=None, passphrase=None): - """ - Return a Key object corresponding to the data in filename. type - and passphrase function as they do in fromString. - """ - return Class.fromString(file(filename, 'rb').read(), type, passphrase) - fromFile = classmethod(fromFile) - - def fromString(Class, data, type=None, passphrase=None): - """ - Return a Key object corresponding to the string data. - type is optionally the type of string, matching a _fromString_* - method. Otherwise, the _guessStringType() classmethod will be used - to guess a type. If the key is encrypted, passphrase is used as - the decryption key. - - @type data: C{str} - @type type: C{None}/C{str} - @type passphrase: C{None}/C{str} - @rtype: C{Key} - """ - if type is None: - type = Class._guessStringType(data) - if type is None: - raise BadKeyError('cannot guess the type of %r' % data) - method = getattr(Class, '_fromString_%s' % type.upper(), None) - if method is None: - raise BadKeyError('no _fromString method for %s' % type) - if method.func_code.co_argcount == 2: # no passphrase - if passphrase: - raise BadKeyError('key not encrypted') - return method(data) - else: - return method(data, passphrase) - fromString = classmethod(fromString) - - def _fromString_BLOB(Class, blob): - """ - Return a public key object corresponding to this public key blob. - The format of a RSA public key blob is:: - string 'ssh-rsa' - integer e - integer n - - The format of a DSA public key blob is:: - string 'ssh-dss' - integer p - integer q - integer g - integer y - - @type blob: C{str} - @return: a C{Crypto.PublicKey.pubkey.pubkey} object - @raises BadKeyError: if the key type (the first string) is unknown. - """ - keyType, rest = common.getNS(blob) - if keyType == 'ssh-rsa': - e, n, rest = common.getMP(rest, 2) - return Class(RSA.construct((n, e))) - elif keyType == 'ssh-dss': - p, q, g, y, rest = common.getMP(rest, 4) - return Class(DSA.construct((y, g, p, q))) - else: - raise BadKeyError('unknown blob type: %s' % keyType) - _fromString_BLOB = classmethod(_fromString_BLOB) - - def _fromString_PUBLIC_OPENSSH(Class, data): - """ - Return a public key object corresponding to this OpenSSH public key - string. The format of an OpenSSH public key string is:: - - - @type data: C{str} - @return: A {Crypto.PublicKey.pubkey.pubkey} object - @raises BadKeyError: if the blob type is unknown. - """ - blob = base64.decodestring(data.split()[1]) - return Class._fromString_BLOB(blob) - _fromString_PUBLIC_OPENSSH = classmethod(_fromString_PUBLIC_OPENSSH) - - def _fromString_PRIVATE_OPENSSH(Class, data, passphrase): - """ - Return a private key object corresponding to this OpenSSH private key - string. If the key is encrypted, passphrase MUST be provided. - Providing a passphrase for an unencrypted key is an error. - - The format of an OpenSSH private key string is:: - -----BEGIN PRIVATE KEY----- - [Proc-Type: 4,ENCRYPTED - DEK-Info: DES-EDE3-CBC,] - - ------END PRIVATE KEY------ - - The ASN.1 structure of a RSA key is:: - (0, n, e, d, p, q) - - The ASN.1 structure of a DSA key is:: - (0, p, q, g, y, x) - - @type data: C{str} - @type passphrase: C{str} - @return: a C{Crypto.PublicKey.pubkey.pubkey} object - @raises BadKeyError: if - * a passphrase is provided for an unencrypted key - * a passphrase is not provided for an encrypted key - * the ASN.1 encoding is incorrect - """ - lines = [x + '\n' for x in data.split('\n')] - kind = lines[0][11:14] - if lines[1].startswith('Proc-Type: 4,ENCRYPTED'): # encrypted key - ivdata = lines[2].split(',')[1][:-1] - iv = ''.join([chr(int(ivdata[i:i + 2], 16)) for i in range(0, - len(ivdata), 2)]) - if not passphrase: - raise EncryptedKeyError('encrypted key with no passphrase') - ba = md5.new(passphrase + iv).digest() - bb = md5.new(ba + passphrase + iv).digest() - decKey = (ba + bb)[:24] - b64Data = base64.decodestring(''.join(lines[3:-1])) - keyData = DES3.new(decKey, DES3.MODE_CBC, iv).decrypt(b64Data) - removeLen = ord(keyData[-1]) - keyData = keyData[:-removeLen] - else: - keyData = base64.decodestring(''.join(lines[1:-1])) - try: - decodedKey = asn1.parse(keyData) - except Exception, e: - raise BadKeyError, 'something wrong with decode' - if kind == 'RSA': - if len(decodedKey) == 2: # alternate RSA key - decodedKey = decodedKey[0] - n, e, d, p, q = decodedKey[1:6] - if p > q: # make p smaller than q - p, q = q, p - return Class(RSA.construct((n, e, d, p, q))) - elif kind == 'DSA': - p, q, g, y, x = decodedKey[1: 6] - return Class(DSA.construct((y, g, p, q, x))) - _fromString_PRIVATE_OPENSSH = classmethod(_fromString_PRIVATE_OPENSSH) - - def _fromString_PUBLIC_LSH(Class, data): - """ - Return a public key corresponding to this LSH public key string. - The LSH public key string format is:: - , ()+))> - - The names for a RSA (key type 'rsa-pkcs1-sha1') key are: n, e. - The names for a DSA (key type 'dsa') key are: y, g, p, q. - - @type data: C{str} - @return: a C{Crypto.PublicKey.pubkey.pubkey} object - @raises BadKeyError: if the key type is unknown - """ - sexp = sexpy.parse(base64.decodestring(data[1:-1])) - assert sexp[0] == 'public-key' - kd = {} - for name, data in sexp[1][1:]: - kd[name] = common.getMP(common.NS(data))[0] - if sexp[1][0] == 'dsa': - return Class(DSA.construct((kd['y'], kd['g'], kd['p'], kd['q']))) - elif sexp[1][0] == 'rsa-pkcs1-sha1': - return Class(RSA.construct((kd['n'], kd['e']))) - else: - raise BadKeyError('unknown lsh key type %s' % sexp[1][0]) - _fromString_PUBLIC_LSH = classmethod(_fromString_PUBLIC_LSH) - - def _fromString_PRIVATE_LSH(Class, data): - """ - Return a private key corresponding to this LSH private key string. - The LSH private key string format is:: - , (, )+))> - - The names for a RSA (key type 'rsa-pkcs1-sha1') key are: n, e, d, p, q. - The names for a DSA (key type 'dsa') key are: y, g, p, q, x. - - @type data: C{str} - @return: a {Crypto.PublicKey.pubkey.pubkey} object - @raises BadKeyError: if the key type is unknown - """ - sexp = sexpy.parse(data) - assert sexp[0] == 'private-key' - kd = {} - for name, data in sexp[1][1:]: - kd[name] = common.getMP(common.NS(data))[0] - if sexp[1][0] == 'dsa': - assert len(kd) == 5, len(kd) - return Class(DSA.construct((kd['y'], kd['g'], kd['p'], - kd['q'], kd['x']))) - elif sexp[1][0] == 'rsa-pkcs1': - assert len(kd) == 8, len(kd) - if kd['p'] > kd['q']: # make p smaller than q - kd['p'], kd['q'] = kd['q'], kd['p'] - return Class(RSA.construct((kd['n'], kd['e'], kd['d'], - kd['p'], kd['q']))) - else: - raise BadKeyError('unknown lsh key type %s' % sexp[1][0]) - _fromString_PRIVATE_LSH = classmethod(_fromString_PRIVATE_LSH) - - def _fromString_AGENTV3(Class, data): - """ - Return a private key object corresponsing to the Secure Shell Key - Agent v3 format. - - The SSH Key Agent v3 format for a RSA key is:: - string 'ssh-rsa' - integer e - integer d - integer n - integer u - integer p - integer q - - The SSH Key Agent v3 format for a DSA key is:: - string 'ssh-dss' - integer p - integer q - integer g - integer y - integer x - - @type data: C{str} - @return: a C{Crypto.PublicKey.pubkey.pubkey} object - @raises BadKeyError: if the key type (the first string) is unknown - """ - keyType, data = common.getNS(data) - if keyType == 'ssh-dss': - p, data = common.getMP(data) - q, data = common.getMP(data) - g, data = common.getMP(data) - y, data = common.getMP(data) - x, data = common.getMP(data) - return Class(DSA.construct((y,g,p,q,x))) - elif keyType == 'ssh-rsa': - e, data = common.getMP(data) - d, data = common.getMP(data) - n, data = common.getMP(data) - u, data = common.getMP(data) - p, data = common.getMP(data) - q, data = common.getMP(data) - return Class(RSA.construct((n,e,d,p,q,u))) - else: - raise BadKeyError("unknown key type %s" % keyType) - _fromString_AGENTV3 = classmethod(_fromString_AGENTV3) - - def _guessStringType(Class, data): - """ - Guess the type of key in data. The types map to _fromString_* - methods. - """ - if data.startswith('ssh-'): - return 'public_openssh' - elif data.startswith('-----BEGIN'): - return 'private_openssh' - elif data.startswith('{'): - return 'public_lsh' - elif data.startswith('('): - return 'private_lsh' - elif data.startswith('\x00\x00\x00\x07ssh-'): - ignored, rest = common.getNS(data) - count = 0 - while rest: - count += 1 - ignored, rest = common.getMP(rest) - if count > 4: - return 'agentv3' - else: - return 'blob' - _guessStringType = classmethod(_guessStringType) - - def __init__(self, keyObject): - """ - Initialize a PublicKey with a C{Crypto.PublicKey.pubkey.pubkey} - object. - - @type keyObject: C{Crypto.PublicKey.pubkey.pubkey} - """ - self.keyObject = keyObject - - def __eq__(self, other): - """ - Return True if other represents an object with the same key. - """ - if type(self) == type(other): - return self.type() == other.type() and self.data() == other.data() - else: - return NotImplemented - - def __ne__(self, other): - """ - Return True if other represents anything other than this key. - """ - result = self.__eq__(other) - if result == NotImplemented: - return result - return not result - - def __repr__(self): - """ - Return a pretty representation of this object. - """ - lines = ['<%s %s (%s bits)' % (self.type(), - self.isPublic() and 'Public Key' or 'Private Key', - self.keyObject.size())] - for k, v in self.data().items(): - lines.append('attr %s:' % k) - by = common.MP(v)[4:] - while by: - m = by[:15] - by = by[15:] - o = '' - for c in m: - o = o + '%02x:' % ord(c) - if len(m) < 15: - o = o[:-1] - lines.append('\t' + o) - lines[-1] = lines[-1] + '>' - return '\n'.join(lines) - - def isPublic(self): - """ - Returns True if this Key is a public key. - """ - return not self.keyObject.has_private() - - def public(self): - """ - Returns a version of this key containing only the public key data. - If this is a public key, this may or may not be the same object - as self. - """ - return Key(self.keyObject.publickey()) - - def type(self): - """ - Return the type of the object we wrap. Currently this can only be - 'RSA' or 'DSA'. - """ - # the class is Crypto.PublicKey.. - klass = str(self.keyObject.__class__) - if klass.startswith('Crypto.PublicKey'): - type = klass.split('.')[2] - else: - raise RuntimeError('unknown type of object: %r' % self.keyObject) - if type in ('RSA', 'DSA'): - return type - else: - raise RuntimeError('unknown type of key: %s' % type) - - def sshType(self): - """ - Return the type of the object we wrap as defined in the ssh protocol. - Currently this can only be 'ssh-rsa' or 'ssh-dss'. - """ - return {'RSA':'ssh-rsa', 'DSA':'ssh-dss'}[self.type()] - - def data(self): - """ - Return the values of the public key as a dictionary. - - @rtype: C{dict} - """ - keyData = {} - for name in self.keyObject.keydata: - value = getattr(self.keyObject, name, None) - if value is not None: - keyData[name] = value - return keyData - - def blob(self): - """ - Return the public key blob for this key. The blob is the - over-the-wire format for public keys: - - RSA keys:: - string 'ssh-rsa' - integer e - integer n - - DSA keys:: - string 'ssh-dss' - integer p - integer q - integer g - integer y - - @rtype: C{str} - """ - type = self.type() - data = self.data() - if type == 'RSA': - return (common.NS('ssh-rsa') + common.MP(data['e']) + - common.MP(data['n'])) - elif type == 'DSA': - return (common.NS('ssh-dss') + common.MP(data['p']) + - common.MP(data['q']) + common.MP(data['g']) + - common.MP(data['y'])) - - def toString(self, type, extra=None): - """ - Create a string representation of this key. If the key is a - private key and you want the represenation of its public key, - use .public().toString(). type maps to a _toString_* method. - The extra paramater allows passing data to some of the method. - For public OpenSSH keys, it represents a comment. - For private OpenSSH keys, it represents a passphrase. - - @type type: C{str} - @type extra: C{str} - @rtype: C{str} - """ - method = getattr(self, '_toString_%s' % type.upper(), None) - if method is None: - raise BadKeyError('unknown type: %s' % type) - if method.func_code.co_argcount == 2: - return method(extra) - else: - return method() - - def _toString_OPENSSH(self, extra): - """ - Return a public or private OpenSSH string. See - _fromString_PUBLIC_OPENSSH and _fromString_PRIVATE_OPENSSH for the - string formats. If extra is present, it represents a comment for a - public key, or a passphrase for a private key. - - @type extra: C{str} - @rtype: C{str} - """ - data = self.data() - if self.isPublic(): - b64Data = base64.encodestring(self.blob()).replace('\n', '') - if not extra: - extra = '' - return ('%s %s %s' % (self.sshType(), b64Data, extra)).strip() - else: - lines = ['-----BEGIN %s PRIVATE KEY-----' % self.type()] - if self.type() == 'RSA': - p, q = data['p'], data['q'] - objData = (0, data['n'], data['e'], data['d'], q, p, - data['d'] % (q - 1), data['d'] % (p - 1), - data['u']) - else: - objData = (0, data['p'], data['q'], data['g'], data['y'], - data['x']) - if extra: - iv = randbytes.secureRandom(8) - hexiv = ''.join(['%02X' % ord(x) for x in iv]) - lines.append('Proc-Type: 4,ENCRYPTED') - lines.append('DEK-Info: DES-EDE3-CBC,%s\n' % hexiv) - ba = md5.new(extra + iv).digest() - bb = md5.new(ba + extra + iv).digest() - encKey = (ba + bb)[:24] - asn1Data = asn1.pack([objData]) - if extra: - padLen = 8 - (len(asn1Data) % 8) - asn1Data += (chr(padLen) * padLen) - asn1Data = DES3.new(encKey, DES3.MODE_CBC, - iv).encrypt(asn1Data) - b64Data = base64.encodestring(asn1Data).replace('\n', '') - lines += [b64Data[i:i + 64] for i in range(0, len(b64Data), 64)] - lines.append('-----END %s PRIVATE KEY-----' % self.type()) - return '\n'.join(lines) - - def _toString_LSH(self): - """ - Return a public or private LSH key. See _fromString_PUBLIC_LSH and - _fromString_PRIVATE_LSH for the key formats. - - @rtype: C{str} - """ - data = self.data() - if self.isPublic(): - if self.type() == 'RSA': - keyData = sexpy.pack([['public-key', ['rsa-pkcs1-sha1', - ['n', common.MP(data['n'])[4:]], - ['e', common.MP(data['e'])[4:]]]]]) - elif self.type() == 'DSA': - keyData = sexpy.pack([['public-key', ['dsa', - ['p', common.MP(data['p'])[4:]], - ['q', common.MP(data['q'])[4:]], - ['g', common.MP(data['g'])[4:]], - ['y', common.MP(data['y'])[4:]]]]]) - return '{' + base64.encodestring(keyData).replace('\n', '') + '}' - else: - if self.type() == 'RSA': - p, q = data['p'], data['q'] - return sexpy.pack([['private-key', ['rsa-pkcs1', - ['n', common.MP(data['n'])[4:]], - ['e', common.MP(data['e'])[4:]], - ['d', common.MP(data['d'])[4:]], - ['p', common.MP(q)[4:]], - ['q', common.MP(p)[4:]], - ['a', common.MP(data['d'] % (q - 1))[4:]], - ['b', common.MP(data['d'] % (p - 1))[4:]], - ['c', common.MP(data['u'])[4:]]]]]) - elif self.type() == 'DSA': - return sexpy.pack([['private-key', ['dsa', - ['p', common.MP(data['p'])[4:]], - ['q', common.MP(data['q'])[4:]], - ['g', common.MP(data['g'])[4:]], - ['y', common.MP(data['y'])[4:]], - ['x', common.MP(data['x'])[4:]]]]]) - - def _toString_AGENTV3(self): - """ - Return a private Secure Shell Agent v3 key. See - _fromString_AGENTV3 for the key format. - - @rtype: C{str} - """ - data = self.data() - if not self.isPublic(): - if self.type() == 'RSA': - values = (data['e'], data['d'], data['n'], data['u'], - data['p'], data['q']) - elif self.type() == 'DSA': - values = (data['p'], data['q'], data['g'], data['y'], - data['x']) - return common.NS(self.sshType()) + ''.join(map(common.MP, values)) - - - def sign(self, data): - """ - Returns a signature with this Key. - - @type data: C{str} - @rtype: C{str} - """ - if self.type() == 'RSA': - digest = pkcs1Digest(data, self.keyObject.size()/8) - signature = self.keyObject.sign(digest, '')[0] - ret = common.NS(Util.number.long_to_bytes(signature)) - elif self.type() == 'DSA': - digest = sha.new(data).digest() - randomBytes = randbytes.secureRandom(19) - sig = self.keyObject.sign(digest, randomBytes) - # SSH insists that the DSS signature blob be two 160-bit integers - # concatenated together. The sig[0], [1] numbers from obj.sign - # are just numbers, and could be any length from 0 to 160 bits. - # Make sure they are padded out to 160 bits (20 bytes each) - ret = common.NS(Util.number.long_to_bytes(sig[0], 20) + - Util.number.long_to_bytes(sig[1], 20)) - return common.NS(self.sshType()) + ret - - def verify(self, signature, data): - """ - Returns true if the signature for data is valid for this Key. - - @type signature: C{str} - @type data: C{str} - @rtype: C{bool} - """ - signatureType, signature = common.getNS(signature) - if signatureType != self.sshType(): - return False - if self.type() == 'RSA': - numbers = common.getMP(signature) - digest = pkcs1Digest(data, self.keyObject.size() / 8) - elif self.type() == 'DSA': - signature = common.getNS(signature)[0] - numbers = [Util.number.bytes_to_long(n) for n in signature[:20], - signature[20:]] - digest = sha.new(data).digest() - return self.keyObject.verify(digest, numbers) - -def getPublicKeyString(filename=None, line=0, data=''): - """ - Return a public key string suitable for being sent over the wire. - Takes a filename or data of a public key. Currently handles OpenSSH - and LSH keys. - - This function has been deprecated since Twisted Conch 0.9. Use - Key.fromString() instead. - - @type filename: C{str} - @type line: C{int} - @type data: C{str} - @rtype: C{str} - """ - warnings.warn("getPublicKeyString is deprecated since Twisted Conch 0.9." - " Use Key.fromString().", - DeprecationWarning, stacklevel=2) - if filename and data: - raise BadKeyError("either filename or data, not both") - if filename: - lines = open(filename).readlines() - data = lines[line] - return Key.fromString(data).blob() - -def makePublicKeyString(obj, comment='', kind='openssh'): - """ - Return an public key given a C{Crypto.PublicKey.pubkey.pubkey} - object. - kind is one of ('openssh', 'lsh') - - This function is deprecated since Twisted Conch 0.9. Instead use - Key(obj).toString(). - - @type obj: C{Crypto.PublicKey.pubkey.pubkey} - @type comment: C{str} - @type kind: C{str} - @rtype: C{str} - """ - warnings.warn("makePublicKeyString is deprecated since Twisted Conch 0.9." - " Use Key(obj).toString().", - DeprecationWarning, stacklevel=2) - return Key(obj).public().toString(kind, comment) - -def getPublicKeyObject(data): - """ - Return a C{Crypto.PublicKey.pubkey.pubkey} corresponding to the SSHv2 - public key data. data is in the over-the-wire public key format. - - This function is deprecated since Twisted Conch 0.9. Instead, use - Key.fromString(). - - @type data: C{str} - @rtype: C{Crypto.PublicKey.pubkey.pubkey} - """ - warnings.warn("getPublicKeyObject is deprecated since Twisted Conch 0.9." - " Use Key.fromString().", - DeprecationWarning, stacklevel=2) - return Key.fromString(data).keyObject - -def getPrivateKeyObject(filename=None, data='', passphrase=''): - """ - Return a C{Crypto.PublicKey.pubkey.pubkey} object corresponding to the - private key file/data. If the private key is encrypted, passphrase B{must} - be specified, other wise a L{BadKeyError} will be raised. - - This method is deprecated since Twisted Conch 0.9. Instead, use - the fromString or fromFile classmethods of Key. - - @type filename: C{str} - @type data: C{str} - @type passphrase: C{str} - @rtype: C{Crypto.PublicKey.pubkey.pubkey} - @raises BadKeyError: if the key is invalid or a passphrase is not specified - """ - warnings.warn("getPrivateKeyObject is deprecated since Twisted Conch 0.9." - " Use Key.fromString().", - DeprecationWarning, stacklevel=2) - if filename and data: - raise BadKeyError("either filename or data, not both") - if filename: - return Key.fromFile(filename, passphrase=passphrase).keyObject - else: - return Key.fromString(data, passphrase=passphrase).keyObject - -def makePrivateKeyString(obj, passphrase=None, kind='openssh'): - """ - Return an OpenSSH-style private key for a - C{Crypto.PublicKey.pubkey.pubkey} object. If passphrase is given, encrypt - the private key with it. - kind is one of ('openssh', 'lsh', 'agentv3') - - This function is deprecated since Twisted Conch 0.9. Instead use - Key(obj).toString(). - - @type obj: C{Crypto.PublicKey.pubkey.pubkey} - @type passphrase: C{str}/C{None} - @type kind: C{str} - @rtype: C{str} - """ - warnings.warn("makePrivateKeyString is deprecated since Twisted Conch 0.9." - " Use Key(obj).toString().", - DeprecationWarning, stacklevel=2) - return Key(obj).toString(kind, passphrase) - -def makePublicKeyBlob(obj): - """ - Make a public key blob from a C{Crypto.PublicKey.pubkey.pubkey}. - - This function is deprecated since Twisted Conch 0.9. Use - Key().blob() instead. - """ - warnings.warn("makePublicKeyBlob is deprecated since Twisted Conch 0.9." - " Use Key(obj).blob().", - DeprecationWarning, stacklevel=2) - return Key(obj).blob() - -def objectType(obj): - """ - Return the SSH key type corresponding to a C{Crypto.PublicKey.pubkey.pubkey} - object. - - @type obj: C{Crypto.PublicKey.pubkey.pubkey} - @rtype: C{str} - """ - keyDataMapping = { - ('n', 'e', 'd', 'p', 'q'): 'ssh-rsa', - ('n', 'e', 'd', 'p', 'q', 'u'): 'ssh-rsa', - ('y', 'g', 'p', 'q', 'x'): 'ssh-dss' - } - try: - return keyDataMapping[tuple(obj.keydata)] - except (KeyError, AttributeError): - raise BadKeyError("invalid key object", obj) - -def pkcs1Pad(data, messageLength): - """ - Pad out data to messageLength according to the PKCS#1 standard. - @type data: C{str} - @type messageLength: C{int} - """ - lenPad = messageLength - 2 - len(data) - return '\x01' + ('\xff' * lenPad) + '\x00' + data - -def pkcs1Digest(data, messageLength): - """ - Create a message digest using the SHA1 hash algorithm according to the - PKCS#1 standard. - @type data: C{str} - @type messageLength: C{str} - """ - digest = sha.new(data).digest() - return pkcs1Pad(ID_SHA1+digest, messageLength) - -def lenSig(obj): - """ - Return the length of the signature in bytes for a key object. - - @type obj: C{Crypto.PublicKey.pubkey.pubkey} - @rtype: C{long} - """ - return obj.size()/8 - -def signData(obj, data): - """ - Sign the data with the given C{Crypto.PublicKey.pubkey.pubkey} object. - - This method is deprecated since Twisted Conch 0.9. Instead use - Key().sign(). - - @type obj: C{Crypto.PublicKey.pubkey.pubkey} - @type data: C{str} - @rtype: C{str} - """ - warnings.warn("signData is deprecated since Twisted Conch 0.9." - " Use Key(obj).sign(data).", - DeprecationWarning, stacklevel=2) - return Key(obj).sign(data) - -def verifySignature(obj, sig, data): - """ - Verify that the signature for the data is valid. - - This method is deprecated since Twisted Conch 0.9. Use - Key().verify(). - - @type obj: C{Crypto.PublicKey.pubkey.pubkey} - @type sig: C{str} - @type data: C{str} - @rtype: C{bool} - """ - warnings.warn("verifySignature is deprecated since Twisted Conch 0.9." - " Use Key(obj).verify(signature, data).", - DeprecationWarning, stacklevel=2) - return Key(obj).verify(sig, data) - -def printKey(obj): - """ - Pretty print a C{Crypto.PublicKey.pubkey.pubkey} object. - - This function is deprecated since Twisted Conch 0.9. Use - repr(Key()). - - @type obj: C{Crypto.PublicKey.pubkey.pubkey} - """ - warnings.warn("printKey is deprecated since Twisted Conch 0.9." - " Use repr(Key(obj)).", - DeprecationWarning, stacklevel=2) - return repr(Key(obj))[1:-1] - -ID_SHA1 = '\x30\x21\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x04\x14' diff --git a/tools/buildbot/pylibs/twisted/conch/ssh/service.py b/tools/buildbot/pylibs/twisted/conch/ssh/service.py deleted file mode 100644 index 4cd6281..0000000 --- a/tools/buildbot/pylibs/twisted/conch/ssh/service.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -The parent class for all the SSH services. Currently implemented services -are ssh-userauth and ssh-connection. - -Maintainer: U{Paul Swartz} -""" - - -from twisted.python import log - -class SSHService(log.Logger): - name = None # this is the ssh name for the service - protocolMessages = {} # these map #'s -> protocol names - transport = None # gets set later - - def serviceStarted(self): - """ - called when the service is active on the transport. - """ - - def serviceStopped(self): - """ - called when the service is stopped, either by the connection ending - or by another service being started - """ - - def logPrefix(self): - return "SSHService %s on %s" % (self.name, - self.transport.transport.logPrefix()) - - def packetReceived(self, messageNum, packet): - """ - called when we receive a packet on the transport - """ - #print self.protocolMessages - if messageNum in self.protocolMessages: - messageType = self.protocolMessages[messageNum] - f = getattr(self,'ssh_%s' % messageType[4:], - None) - if f is not None: - return f(packet) - log.msg("couldn't handle %r" % messageNum) - log.msg(repr(packet)) - self.transport.sendUnimplemented() - diff --git a/tools/buildbot/pylibs/twisted/conch/ssh/session.py b/tools/buildbot/pylibs/twisted/conch/ssh/session.py deleted file mode 100644 index bf92bc6..0000000 --- a/tools/buildbot/pylibs/twisted/conch/ssh/session.py +++ /dev/null @@ -1,255 +0,0 @@ -# -*- test-case-name: twisted.conch.test.test_conch -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -""" -This module contains the implementation of SSHSession, which (by default) -allows access to a shell and a python interpreter over SSH. - -Maintainer: U{Paul Swartz} -""" - -import struct - -from twisted.internet import protocol -from twisted.python import log -from twisted.conch.interfaces import ISession -from twisted.conch.ssh import common, channel - -class SSHSession(channel.SSHChannel): - - name = 'session' - def __init__(self, *args, **kw): - channel.SSHChannel.__init__(self, *args, **kw) - self.buf = '' - self.client = None - self.session = None - - def request_subsystem(self, data): - subsystem, ignored= common.getNS(data) - log.msg('asking for subsystem "%s"' % subsystem) - client = self.avatar.lookupSubsystem(subsystem, data) - if client: - pp = SSHSessionProcessProtocol(self) - proto = wrapProcessProtocol(pp) - client.makeConnection(proto) - pp.makeConnection(wrapProtocol(client)) - self.client = pp - return 1 - else: - log.msg('failed to get subsystem') - return 0 - - def request_shell(self, data): - log.msg('getting shell') - if not self.session: - self.session = ISession(self.avatar) - try: - pp = SSHSessionProcessProtocol(self) - self.session.openShell(pp) - except: - log.deferr() - return 0 - else: - self.client = pp - return 1 - - def request_exec(self, data): - if not self.session: - self.session = ISession(self.avatar) - f,data = common.getNS(data) - log.msg('executing command "%s"' % f) - try: - pp = SSHSessionProcessProtocol(self) - self.session.execCommand(pp, f) - except: - log.deferr() - return 0 - else: - self.client = pp - return 1 - - def request_pty_req(self, data): - if not self.session: - self.session = ISession(self.avatar) - term, windowSize, modes = parseRequest_pty_req(data) - log.msg('pty request: %s %s' % (term, windowSize)) - try: - self.session.getPty(term, windowSize, modes) - except: - log.err() - return 0 - else: - return 1 - - def request_window_change(self, data): - if not self.session: - self.session = ISession(self.avatar) - winSize = parseRequest_window_change(data) - try: - self.session.windowChanged(winSize) - except: - log.msg('error changing window size') - log.err() - return 0 - else: - return 1 - - def dataReceived(self, data): - if not self.client: - #self.conn.sendClose(self) - self.buf += data - return - self.client.transport.write(data) - - def extReceived(self, dataType, data): - if dataType == connection.EXTENDED_DATA_STDERR: - if self.client and hasattr(self.client.transport, 'writeErr'): - self.client.transport.writeErr(data) - else: - log.msg('weird extended data: %s'%dataType) - - def eofReceived(self): - if self.session: - self.session.eofReceived() - elif self.client: - self.conn.sendClose(self) - - def closed(self): - if self.session: - self.session.closed() - elif self.client: - self.client.transport.loseConnection() - - #def closeReceived(self): - # self.loseConnection() # don't know what to do with this - - def loseConnection(self): - if self.client: - self.client.transport.loseConnection() - channel.SSHChannel.loseConnection(self) - -class _ProtocolWrapper(protocol.ProcessProtocol): - """ - This class wraps a L{Protocol} instance in a L{ProcessProtocol} instance. - """ - def __init__(self, proto): - self.proto = proto - - def connectionMade(self): self.proto.connectionMade() - - def outReceived(self, data): self.proto.dataReceived(data) - - def processEnded(self, reason): self.proto.connectionLost(reason) - -class _DummyTransport: - - def __init__(self, proto): - self.proto = proto - - def dataReceived(self, data): - self.proto.transport.write(data) - - def write(self, data): - self.proto.dataReceived(data) - - def writeSequence(self, seq): - self.write(''.join(seq)) - - def loseConnection(self): - self.proto.connectionLost(protocol.connectionDone) - -def wrapProcessProtocol(inst): - if isinstance(inst, protocol.Protocol): - return _ProtocolWrapper(inst) - else: - return inst - -def wrapProtocol(proto): - return _DummyTransport(proto) - -class SSHSessionProcessProtocol(protocol.ProcessProtocol): - -# __implements__ = I - def __init__(self, session): - self.session = session - - def connectionMade(self): - if self.session.buf: - self.transport.write(self.session.buf) - self.session.buf = None - - def outReceived(self, data): - self.session.write(data) - - def errReceived(self, err): - self.session.writeExtended(connection.EXTENDED_DATA_STDERR, err) - - def inConnectionLost(self): - self.session.conn.sendEOF(self.session) - - def connectionLost(self, reason = None): - self.session.loseConnection() - - def processEnded(self, reason = None): - if reason and hasattr(reason.value, 'exitCode'): - log.msg('exitCode: %s' % repr(reason.value.exitCode)) - self.session.conn.sendRequest(self.session, 'exit-status', struct.pack('!L', reason.value.exitCode)) - self.session.loseConnection() - - # transport stuff (we are also a transport!) - - def write(self, data): - self.session.write(data) - - def writeSequence(self, seq): - self.session.write(''.join(seq)) - - def loseConnection(self): - self.session.loseConnection() - -class SSHSessionClient(protocol.Protocol): - - def dataReceived(self, data): - if self.transport: - self.transport.write(data) - -# methods factored out to make live easier on server writers -def parseRequest_pty_req(data): - """Parse the data from a pty-req request into usable data. - - @returns: a tuple of (terminal type, (rows, cols, xpixel, ypixel), modes) - """ - term, rest = common.getNS(data) - cols, rows, xpixel, ypixel = struct.unpack('>4L', rest[: 16]) - modes, ignored= common.getNS(rest[16:]) - winSize = (rows, cols, xpixel, ypixel) - modes = [(ord(modes[i]), struct.unpack('>L', modes[i+1: i+5])[0]) for i in range(0, len(modes)-1, 5)] - return term, winSize, modes - -def packRequest_pty_req(term, (rows, cols, xpixel, ypixel), modes): - """Pack a pty-req request so that it is suitable for sending. - - NOTE: modes must be packed before being sent here. - """ - termPacked = common.NS(term) - winSizePacked = struct.pack('>4L', cols, rows, xpixel, ypixel) - modesPacked = common.NS(modes) # depend on the client packing modes - return termPacked + winSizePacked + modesPacked - -def parseRequest_window_change(data): - """Parse the data from a window-change request into usuable data. - - @returns: a tuple of (rows, cols, xpixel, ypixel) - """ - cols, rows, xpixel, ypixel = struct.unpack('>4L', data) - return rows, cols, xpixel, ypixel - -def packRequest_window_change((rows, cols, xpixel, ypixel)): - """Pack a window-change request so that it is suitable for sending. - """ - return struct.pack('>4L', cols, rows, xpixel, ypixel) - -import connection diff --git a/tools/buildbot/pylibs/twisted/conch/ssh/sexpy.py b/tools/buildbot/pylibs/twisted/conch/ssh/sexpy.py deleted file mode 100644 index b7f19d9..0000000 --- a/tools/buildbot/pylibs/twisted/conch/ssh/sexpy.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -def parse(s): - s = s.strip() - expr = [] - while s: - if s[0] == '(': - newSexp = [] - if expr: - expr[-1].append(newSexp) - expr.append(newSexp) - s = s[1:] - continue - if s[0] == ')': - aList = expr.pop() - s=s[1:] - if not expr: - assert not s - return aList - continue - i = 0 - while s[i].isdigit(): i+=1 - assert i - length = int(s[:i]) - data = s[i+1:i+1+length] - expr[-1].append(data) - s=s[i+1+length:] - assert 0, "this should not happen" - -def pack(sexp): - s = "" - for o in sexp: - if type(o) in (type(()), type([])): - s+='(' - s+=pack(o) - s+=')' - else: - s+='%i:%s' % (len(o), o) - return s diff --git a/tools/buildbot/pylibs/twisted/conch/ssh/transport.py b/tools/buildbot/pylibs/twisted/conch/ssh/transport.py deleted file mode 100644 index d1e2ad6..0000000 --- a/tools/buildbot/pylibs/twisted/conch/ssh/transport.py +++ /dev/null @@ -1,1408 +0,0 @@ -# -*- test-case-name: twisted.conch.test.test_transport -*- -# -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -The lowest level SSH protocol. This handles the key negotiation, the -encryption and the compression. The transport layer is described in -RFC 4253. - -Maintainer: U{Paul Swartz} -""" - -# base library imports -import struct -import md5 -import sha -import zlib -import array - -# external library imports -from Crypto import Util -from Crypto.Cipher import XOR - -# twisted imports -from twisted.internet import protocol, defer -from twisted.conch import error -from twisted.python import log, randbytes - -# sibling imports -from twisted.conch.ssh import keys -from twisted.conch.ssh.common import NS, getNS, MP, getMP, _MPpow, ffs - - - -class SSHTransportBase(protocol.Protocol): - """ - Protocol supporting basic SSH functionality: sending/receiving packets - and message dispatch. To connect to or run a server, you must use - SSHClientTransport or SSHServerTransport. - - @ivar protocolVersion: A string representing the version of the SSH - protocol we support. Currently defaults to '2.0'. - - @ivar version: A string representing the version of the server or client. - Currently defaults to 'Twisted'. - - @ivar comment: An optional string giving more information about the - server or client. - - @ivar supportedCiphers: A list of strings representing the encryption - algorithms supported, in order from most-preferred to least. - - @ivar supportedMACs: A list of strings representing the message - authentication codes (hashes) supported, in order from most-preferred - to least. Both this and supportedCiphers can include 'none' to use - no encryption or authentication, but that must be done manually, - - @ivar supportedKeyExchanges: A list of strings representing the - key exchanges supported, in order from most-preferred to least. - - @ivar supportedPublicKeys: A list of strings representing the - public key types supported, in order from most-preferred to least. - - @ivar supportedCompressions: A list of strings representing compression - types supported, from most-preferred to least. - - @ivar supportedLanguages: A list of strings representing languages - supported, from most-preferred to least. - - @ivar isClient: A boolean indicating whether this is a client or server. - - @ivar gotVersion: A boolean indicating whether we have receieved the - version string from the other side. - - @ivar buf: Data we've received but hasn't been parsed into a packet. - - @ivar outgoingPacketSequence: the sequence number of the next packet we - will send. - - @ivar incomingPacketSequence: the sequence number of the next packet we - are expecting from the other side. - - @ivar outgoingCompression: an object supporting the .compress(str) and - .flush() methods, or None if there is no outgoing compression. Used to - compress outgoing data. - - @ivar outgoingCompressionType: A string representing the outgoing - compression type. - - @ivar incomingCompression: an object supporting the .decompress(str) - method, or None if there is no incoming compression. Used to - decompress incoming data. - - @ivar incomingCompressionType: A string representing the incoming - compression type. - - @ivar ourVersionString: the version string that we sent to the other side. - Used in the key exchange. - - @ivar otherVersionString: the version string sent by the other side. Used - in the key exchange. - - @ivar ourKexInitPayload: the MSG_KEXINIT payload we sent. Used in the key - exchange. - - @ivar otherKexInitPayload: the MSG_KEXINIT payload we received. Used in - the key exchange - - @ivar sessionID: a string that is unique to this SSH session. Created as - part of the key exchange, sessionID is used to generate the various - encryption and authentication keys. - - @ivar service: an SSHService instance, or None. If it's set to an object, - it's the currently running service. - - @ivar kexAlg: the agreed-upon key exchange algorithm. - - @ivar keyAlg: the agreed-upon public key type for the key exchange. - - @ivar currentEncryptions: an SSHCiphers instance. It represents the - current encryption and authentication options for the transport. - - @ivar nextEncryptions: an SSHCiphers instance. Held here until the - MSG_NEWKEYS messages are exchanged, when nextEncryptions is - transitioned to currentEncryptions. - - @ivar first: the first bytes of the next packet. In order to avoid - decrypting data twice, the first bytes are decrypted and stored until - the whole packet is available. - - """ - - - protocolVersion = '2.0' - version = 'Twisted' - comment = '' - ourVersionString = ('SSH-' + protocolVersion + '-' + version + ' ' - + comment).strip() - supportedCiphers = ['aes256-ctr', 'aes256-cbc', 'aes192-ctr', 'aes192-cbc', - 'aes128-ctr', 'aes128-cbc', 'cast128-ctr', - 'cast128-cbc', 'blowfish-ctr', 'blowfish-cbc', - '3des-ctr', '3des-cbc'] # ,'none'] - supportedMACs = ['hmac-sha1', 'hmac-md5'] # , 'none'] - # both of the above support 'none', but for security are disabled by - # default. to enable them, subclass this class and add it, or do: - # SSHTransportBase.supportedCiphers.append('none') - supportedKeyExchanges = ['diffie-hellman-group-exchange-sha1', - 'diffie-hellman-group1-sha1'] - supportedPublicKeys = ['ssh-rsa', 'ssh-dss'] - supportedCompressions = ['none', 'zlib'] - supportedLanguages = () - isClient = False - gotVersion = False - buf = '' - outgoingPacketSequence = 0 - incomingPacketSequence = 0 - outgoingCompression = None - incomingCompression = None - sessionID = None - service = None - - - def connectionLost(self, reason): - if self.service: - self.service.serviceStopped() - if hasattr(self, 'avatar'): - self.logoutFunction() - log.msg('connection lost') - - - def connectionMade(self): - """ - Called when the connection is made to the other side. We sent our - version and the MSG_KEXINIT packet. - """ - self.transport.write('%s\r\n' % (self.ourVersionString,)) - self.currentEncryptions = SSHCiphers('none', 'none', 'none', 'none') - self.currentEncryptions.setKeys('', '', '', '', '', '') - self.sendKexInit() - - - def sendKexInit(self): - self.ourKexInitPayload = (chr(MSG_KEXINIT) + - randbytes.secureRandom(16) + - NS(','.join(self.supportedKeyExchanges)) + - NS(','.join(self.supportedPublicKeys)) + - NS(','.join(self.supportedCiphers)) + - NS(','.join(self.supportedCiphers)) + - NS(','.join(self.supportedMACs)) + - NS(','.join(self.supportedMACs)) + - NS(','.join(self.supportedCompressions)) + - NS(','.join(self.supportedCompressions)) + - NS(','.join(self.supportedLanguages)) + - NS(','.join(self.supportedLanguages)) + - '\000' + '\000\000\000\000') - self.sendPacket(MSG_KEXINIT, self.ourKexInitPayload[1:]) - - - def sendPacket(self, messageType, payload): - """ - Sends a packet. If it's been set up, compress the data, encrypt it, - and authenticate it before sending. - - @param messageType: The type of the packet; generally one of the - MSG_* values. - @type messageType: C{int} - @param payload: The payload for the message. - @type payload: C{str} - """ - payload = chr(messageType) + payload - if self.outgoingCompression: - payload = (self.outgoingCompression.compress(payload) - + self.outgoingCompression.flush(2)) - bs = self.currentEncryptions.encBlockSize - # 4 for the packet length and 1 for the padding length - totalSize = 5 + len(payload) - lenPad = bs - (totalSize % bs) - if lenPad < 4: - lenPad = lenPad + bs - packet = (struct.pack('!LB', - totalSize + lenPad - 4, lenPad) + - payload + randbytes.secureRandom(lenPad)) - encPacket = ( - self.currentEncryptions.encrypt(packet) + - self.currentEncryptions.makeMAC( - self.outgoingPacketSequence, packet)) - self.transport.write(encPacket) - self.outgoingPacketSequence += 1 - - - def getPacket(self): - """ - Try to return a decrypted, authenticated, and decompressed packet - out of the buffer. If there is not enough data, return None. - - @rtype: C{str}/C{None} - """ - bs = self.currentEncryptions.decBlockSize - ms = self.currentEncryptions.verifyDigestSize - if len(self.buf) < bs: return # not enough data - if not hasattr(self, 'first'): - first = self.currentEncryptions.decrypt(self.buf[:bs]) - else: - first = self.first - del self.first - packetLen, paddingLen = struct.unpack('!LB', first[:5]) - if packetLen > 1048576: # 1024 ** 2 - self.sendDisconnect(DISCONNECT_PROTOCOL_ERROR, - 'bad packet length %s' % packetLen) - return - if len(self.buf) < packetLen + 4 + ms: - self.first = first - return # not enough packet - if(packetLen + 4) % bs != 0: - self.sendDisconnect( - DISCONNECT_PROTOCOL_ERROR, - 'bad packet mod (%i%%%i == %i)' % (packetLen + 4, bs, - (packetLen + 4) % bs)) - return - encData, self.buf = self.buf[:4 + packetLen], self.buf[4 + packetLen:] - packet = first + self.currentEncryptions.decrypt(encData[bs:]) - if len(packet) != 4 + packetLen: - self.sendDisconnect(DISCONNECT_PROTOCOL_ERROR, - 'bad decryption') - return - if ms: - macData, self.buf = self.buf[:ms], self.buf[ms:] - if not self.currentEncryptions.verify(self.incomingPacketSequence, - packet, macData): - self.sendDisconnect(DISCONNECT_MAC_ERROR, 'bad MAC') - return - payload = packet[5:-paddingLen] - if self.incomingCompression: - try: - payload = self.incomingCompression.decompress(payload) - except: # bare except, because who knows what kind of errors - # decompression can raise - log.err() - self.sendDisconnect(DISCONNECT_COMPRESSION_ERROR, - 'compression error') - return - self.incomingPacketSequence += 1 - return payload - - - def dataReceived(self, data): - """ - First, check for the version string (SSH-2.0-*). After that has been - received, this method adds data to the buffer, and pulls out any - packets. - - @type data: C{str} - """ - self.buf = self.buf + data - if not self.gotVersion: - if self.buf.find('\n', self.buf.find('SSH-')) == -1: - return - lines = self.buf.split('\n') - for p in lines: - if p.startswith('SSH-'): - self.gotVersion = True - self.otherVersionString = p.strip() - if p.split('-')[1] not in ('1.99', '2.0'): # bad version - self.sendDisconnect( - DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED, - 'bad version ' + p.split('-')[1]) - return - i = lines.index(p) - self.buf = '\n'.join(lines[i + 1:]) - packet = self.getPacket() - while packet: - messageNum = ord(packet[0]) - self.dispatchMessage(messageNum, packet[1:]) - packet = self.getPacket() - - - def dispatchMessage(self, messageNum, payload): - """ - Send a received message to the appropriate method. - - @type messageNum: C{int} - @type payload: c{str} - """ - if messageNum < 50 and messageNum in messages: - messageType = messages[messageNum][4:] - f = getattr(self, 'ssh_%s' % messageType, None) - if f is not None: - f(payload) - else: - log.msg("couldn't handle %s" % messageType) - log.msg(repr(payload)) - self.sendUnimplemented() - elif self.service: - log.callWithLogger(self.service, self.service.packetReceived, - messageNum, payload) - else: - log.msg("couldn't handle %s" % messageNum) - log.msg(repr(payload)) - self.sendUnimplemented() - - - def ssh_KEXINIT(self, packet): - """ - Called when we receive a MSG_KEXINIT message. Payload:: - bytes[16] cookie - string keyExchangeAlgorithms - string keyAlgorithms - string incomingEncryptions - string outgoingEncryptions - string incomingAuthentications - string outgoingAuthentications - string incomingCompressions - string outgoingCompressions - string incomingLanguages - string outgoingLanguages - bool firstPacketFollows - unit32 0 (reserved) - - Starts setting up the key exchange, keys, encryptions, and - authentications. Extended by ssh_KEXINIT in SSHServerTransport and - SSHClientTransport. - """ - self.otherKexInitPayload = chr(MSG_KEXINIT) + packet - #cookie = packet[: 16] # taking this is useless - k = getNS(packet[16:], 10) - strings, rest = k[:-1], k[-1] - (kexAlgs, keyAlgs, encCS, encSC, macCS, macSC, compCS, compSC, langCS, - langSC) = [s.split(',') for s in strings] - # these are the server directions - outs = [encSC, macSC, compSC] - ins = [encCS, macSC, compCS] - if self.isClient: - outs, ins = ins, outs # switch directions - server = (self.supportedKeyExchanges, self.supportedPublicKeys, - self.supportedCiphers, self.supportedCiphers, - self.supportedMACs, self.supportedMACs, - self.supportedCompressions, self.supportedCompressions) - client = (kexAlgs, keyAlgs, outs[0], ins[0], outs[1], ins[1], - outs[2], ins[2]) - if self.isClient: - server, client = client, server - self.kexAlg = ffs(client[0], server[0]) - self.keyAlg = ffs(client[1], server[1]) - self.nextEncryptions = SSHCiphers( - ffs(client[2], server[2]), - ffs(client[3], server[3]), - ffs(client[4], server[4]), - ffs(client[5], server[5])) - self.outgoingCompressionType = ffs(client[6], server[6]) - self.incomingCompressionType = ffs(client[7], server[7]) - if None in (self.kexAlg, self.keyAlg, self.outgoingCompressionType, - self.incomingCompressionType): - self.sendDisconnect(DISCONNECT_KEY_EXCHANGE_FAILED, - "couldn't match all kex parts") - return - if None in self.nextEncryptions.__dict__.values(): - self.sendDisconnect(DISCONNECT_KEY_EXCHANGE_FAILED, - "couldn't match all kex parts") - return - log.msg('kex alg, key alg: %s %s' % (self.kexAlg, self.keyAlg)) - log.msg('outgoing: %s %s %s' % (self.nextEncryptions.outCipType, - self.nextEncryptions.outMACType, - self.outgoingCompressionType)) - log.msg('incoming: %s %s %s' % (self.nextEncryptions.inCipType, - self.nextEncryptions.inMACType, - self.incomingCompressionType)) - return kexAlgs, keyAlgs, rest # for SSHServerTransport to use - - - def ssh_DISCONNECT(self, packet): - """ - Called when we receive a MSG_DISCONNECT message. Payload:: - long code - string description - - This means that the other side has disconnected. Pass the message up - and disconnect ourselves. - """ - reasonCode = struct.unpack('>L', packet[: 4])[0] - description, foo = getNS(packet[4:]) - self.receiveError(reasonCode, description) - self.transport.loseConnection() - - - def ssh_IGNORE(self, packet): - """ - Called when we receieve a MSG_IGNORE message. No payload. - This means nothing; we simply return. - """ - - - def ssh_UNIMPLEMENTED(self, packet): - """ - Called when we receieve a MSG_UNIMPLEMENTED message. Payload:: - long packet - - This means that the other side did not implement one of our packets. - """ - seqnum, = struct.unpack('>L', packet) - self.receiveUnimplemented(seqnum) - - - def ssh_DEBUG(self, packet): - """ - Called when we receieve a MSG_DEBUG message. Payload:: - bool alwaysDisplay - string message - string language - - This means the other side has passed along some debugging info. - """ - alwaysDisplay = bool(packet[0]) - message, lang, foo = getNS(packet[1:], 2) - self.receiveDebug(alwaysDisplay, message, lang) - - - def setService(self, service): - """ - Set our service to service and start it running. If we were - running a service previously, stop it first. - - @type service: C{SSHService} - """ - log.msg('starting service %s' % service.name) - if self.service: - self.service.serviceStopped() - self.service = service - service.transport = self - self.service.serviceStarted() - - - def sendDebug(self, message, alwaysDisplay=False, language=''): - """ - Send a debug message to the other side. - - @param message: the message to send. - @type message: C{str} - @param alwaysDisplay: if True, tell the other side to always - display this message. - @type alwaysDisplay: C{bool} - @param language: optionally, the language the message is in. - @type language: C{str} - """ - self.sendPacket(MSG_DEBUG, chr(alwaysDisplay) + NS(message) + - NS(language)) - - - def sendIgnore(self, message): - """ - Send a message that will be ignored by the other side. This is - useful to fool attacks based on guessing packet sizes in the - encrypted stream. - - @param message: data to send with the message - @type message: C{str} - """ - self.sendPacket(MSG_IGNORE, NS(message)) - - - def sendUnimplemented(self): - """ - Send a message to the other side that the last packet was not - understood. - """ - seqnum = self.incomingPacketSequence - self.sendPacket(MSG_UNIMPLEMENTED, struct.pack('!L', seqnum)) - - - def sendDisconnect(self, reason, desc): - """ - Send a disconnect message to the other side and then disconnect. - - @param reason: the reason for the disconnect. Should be one of the - DISCONNECT_* values. - @type reason: C{int} - @param desc: a descrption of the reason for the disconnection. - @type desc: C{str} - """ - self.sendPacket( - MSG_DISCONNECT, struct.pack('>L', reason) + NS(desc) + NS('')) - log.msg('Disconnecting with error, code %s\nreason: %s' % (reason, - desc)) - self.transport.loseConnection() - - - def _getKey(self, c, sharedSecret, exchangeHash): - """ - Get one of the keys for authentication/encryption. - - @type c: C{str} - @type sharedSecret: C{str} - @type exchangeHash: C{str} - """ - k1 = sha.new(sharedSecret + exchangeHash + c + self.sessionID) - k1 = k1.digest() - k2 = sha.new(sharedSecret + exchangeHash + k1).digest() - return k1 + k2 - - - def _keySetup(self, sharedSecret, exchangeHash): - """ - Set up the keys for the connection and sends MSG_NEWKEYS when - finished, - - @param sharedSecret: a secret string agreed upon using a Diffie- - Hellman exchange, so it is only shared between - the server and the client. - @type sharedSecret: C{str} - @param exchangeHash: A hash of various data known by both sides. - @type exchangeHash: C{str} - """ - if not self.sessionID: - self.sessionID = exchangeHash - initIVCS = self._getKey('A', sharedSecret, exchangeHash) - initIVSC = self._getKey('B', sharedSecret, exchangeHash) - encKeyCS = self._getKey('C', sharedSecret, exchangeHash) - encKeySC = self._getKey('D', sharedSecret, exchangeHash) - integKeyCS = self._getKey('E', sharedSecret, exchangeHash) - integKeySC = self._getKey('F', sharedSecret, exchangeHash) - outs = [initIVSC, encKeySC, integKeySC] - ins = [initIVCS, encKeyCS, integKeyCS] - if self.isClient: # reverse for the client - log.msg('REVERSE') - outs, ins = ins, outs - self.nextEncryptions.setKeys(outs[0], outs[1], ins[0], ins[1], - outs[2], ins[2]) - self.sendPacket(MSG_NEWKEYS, '') - - - def isEncrypted(self, direction="out"): - """ - Return True if the connection is encrypted in the given direction. - Direction must be one of ["out", "in", "both"]. - """ - if direction == "out": - return self.currentEncryptions.outCipType != 'none' - elif direction == "in": - return self.currentEncryptions.inCipType != 'none' - elif direction == "both": - return self.isEncrypted("in") and self.isEncrypted("out") - else: - raise TypeError('direction must be "out", "in", or "both"') - - - def isVerified(self, direction="out"): - """ - Return True if the connecction is verified/authenticated in the - given direction. Direction must be one of ["out", "in", "both"]. - """ - if direction == "out": - return self.currentEncryptions.outMACType != 'none' - elif direction == "in": - return self.currentEncryptions.inMACType != 'none' - elif direction == "both": - return self.isVerified("in")and self.isVerified("out") - else: - raise TypeError('direction must be "out", "in", or "both"') - - - def loseConnection(self): - """ - Lose the connection to the other side, sending a - DISCONNECT_CONNECTION_LOST message. - """ - self.sendDisconnect(DISCONNECT_CONNECTION_LOST, - "user closed connection") - - - # client methods - def receiveError(self, reasonCode, description): - """ - Called when we receive a disconnect error message from the other - side. - - @param reasonCode: the reason for the disconnect, one of the - DISCONNECT_ values. - @type reasonCode: C{int} - @param description: a human-readable description of the - disconnection. - @type description: C{str} - """ - log.msg('Got remote error, code %s\nreason: %s' % (reasonCode, - description)) - - - def receiveUnimplemented(self, seqnum): - """ - Called when we receive an unimplemented packet message from the other - side. - - @param seqnum: the sequence number that was not understood. - @type seqnum: C{int} - """ - log.msg('other side unimplemented packet #%s' % seqnum) - - - def receiveDebug(self, alwaysDisplay, message, lang): - """ - Called when we receive a debug message from the other side. - - @param alwaysDisplay: if True, this message should always be - displayed. - @type alwaysDisplay: C{bool} - @param message: the debug message - @type message: C{str} - @param lang: optionally the language the message is in. - @type lang: C{str} - """ - if alwaysDisplay: - log.msg('Remote Debug Message: %s' % message) - - - -class SSHServerTransport(SSHTransportBase): - """ - SSHServerTransport implements the server side of the SSH protocol. - - @ivar isClient: since we are never the client, this is always False. - - @ivar ignoreNextPacket: if True, ignore the next key exchange packet. This - is set when the client sends a guessed key exchange packet but with - an incorrect guess. - - @ivar dhGexRequest: the KEX_DH_GEX_REQUEST(_OLD) that the client sent. - The key generation needs this to be stored. - - @ivar g: the Diffie-Hellman group generator. - - @ivar p: the Diffie-Hellman group prime. - """ - isClient = False - ignoreNextPacket = 0 - - - def ssh_KEXINIT(self, packet): - """ - Called when we receive a MSG_KEXINIT message. For a description - of the packet, see SSHTransportBase.ssh_KEXINIT(). Additionally, - this method checks if a guessed key exchange packet was sent. If - it was sent, and it guessed incorrectly, the next key exchange - packet MUST be ignored. - """ - retval = SSHTransportBase.ssh_KEXINIT(self, packet) - if not retval: # disconnected - return - else: - kexAlgs, keyAlgs, rest = retval - if ord(rest[0]): # first_kex_packet_follows - if (kexAlgs[0] != self.supportedKeyExchanges[0] or - keyAlgs[0] != self.supportedPublicKeys[0]): - self.ignoreNextPacket = True # guess was wrong - - - def ssh_KEX_DH_GEX_REQUEST_OLD(self, packet): - """ - This represents two different key exchange methods that share the - same integer value. - - KEXDH_INIT (for diffie-hellman-group1-sha1 exchanges) payload:: - - integer e (the client's Diffie-Hellman public key) - - We send the KEXDH_REPLY with our host key and signature. - - KEX_DH_GEX_REQUEST_OLD (for diffie-hellman-group-exchange-sha1) - payload:: - - integer ideal (ideal size for the Diffie-Hellman prime) - - We send the KEX_DH_GEX_GROUP message with the group that is - closest in size to ideal. - - If we were told to ignore the next key exchange packet by - ssh_KEXINIT, drop it on the floor and return. - """ - if self.ignoreNextPacket: - self.ignoreNextPacket = 0 - return - if self.kexAlg == 'diffie-hellman-group1-sha1': - # this is really KEXDH_INIT - clientDHpublicKey, foo = getMP(packet) - y = Util.number.getRandomNumber(512, randbytes.secureRandom) - serverDHpublicKey = _MPpow(DH_GENERATOR, y, DH_PRIME) - sharedSecret = _MPpow(clientDHpublicKey, y, DH_PRIME) - h = sha.new() - h.update(NS(self.otherVersionString)) - h.update(NS(self.ourVersionString)) - h.update(NS(self.otherKexInitPayload)) - h.update(NS(self.ourKexInitPayload)) - h.update(NS(self.factory.publicKeys[self.keyAlg].blob())) - h.update(MP(clientDHpublicKey)) - h.update(serverDHpublicKey) - h.update(sharedSecret) - exchangeHash = h.digest() - self.sendPacket( - MSG_KEXDH_REPLY, - NS(self.factory.publicKeys[self.keyAlg].blob()) + - serverDHpublicKey + - NS(self.factory.privateKeys[self.keyAlg].sign(exchangeHash))) - self._keySetup(sharedSecret, exchangeHash) - elif self.kexAlg == 'diffie-hellman-group-exchange-sha1': - self.dhGexRequest = packet - ideal = struct.unpack('>L', packet)[0] - self.g, self.p = self.factory.getDHPrime(ideal) - self.sendPacket(MSG_KEX_DH_GEX_GROUP, MP(self.p) + MP(self.g)) - else: - raise error.ConchError('bad kexalg: %s' % self.kexAlg) - - - def ssh_KEX_DH_GEX_REQUEST(self, packet): - """ - Called when we receive a MSG_KEX_DH_GEX_REQUEST message. Payload:: - integer minimum - integer ideal - integer maximum - - The client is asking for a Diffie-Hellman group between minimum and - maximum size, and close to ideal if possible. We reply with a - MSG_KEX_DH_GEX_GROUP message. - - If we were told to ignore the next key exchange packekt by - ssh_KEXINIT, drop it on the floor and return. - """ - if self.ignoreNextPacket: - self.ignoreNextPacket = 0 - return - self.dhGexRequest = packet - min, ideal, max = struct.unpack('>3L', packet) - self.g, self.p = self.factory.getDHPrime(ideal) - self.sendPacket(MSG_KEX_DH_GEX_GROUP, MP(self.p) + MP(self.g)) - - - def ssh_KEX_DH_GEX_INIT(self, packet): - """ - Called when we get a MSG_KEX_DH_GEX_INIT message. Payload:: - integer e (client DH public key) - - We send the MSG_KEX_DH_GEX_REPLY message with our host key and - signature. - """ - clientDHpublicKey, foo = getMP(packet) - # TODO: we should also look at the value they send to us and reject - # insecure values of f (if g==2 and f has a single '1' bit while the - # rest are '0's, then they must have used a small y also). - - # TODO: This could be computed when self.p is set up - # or do as openssh does and scan f for a single '1' bit instead - - pSize = Util.number.size(self.p) - y = Util.number.getRandomNumber(pSize, randbytes.secureRandom) - - serverDHpublicKey = _MPpow(self.g, y, self.p) - sharedSecret = _MPpow(clientDHpublicKey, y, self.p) - h = sha.new() - h.update(NS(self.otherVersionString)) - h.update(NS(self.ourVersionString)) - h.update(NS(self.otherKexInitPayload)) - h.update(NS(self.ourKexInitPayload)) - h.update(NS(self.factory.publicKeys[self.keyAlg].blob())) - h.update(self.dhGexRequest) - h.update(MP(self.p)) - h.update(MP(self.g)) - h.update(MP(clientDHpublicKey)) - h.update(serverDHpublicKey) - h.update(sharedSecret) - exchangeHash = h.digest() - self.sendPacket( - MSG_KEX_DH_GEX_REPLY, - NS(self.factory.publicKeys[self.keyAlg].blob()) + - serverDHpublicKey + - NS(self.factory.privateKeys[self.keyAlg].sign(exchangeHash))) - self._keySetup(sharedSecret, exchangeHash) - - - def ssh_NEWKEYS(self, packet): - """ - Called when we get a MSG_NEWKEYS message. No payload. - When we get this, the keys have been set on both sides, and we - start using them to encrypt and authenticate the connection. - """ - log.msg('NEW KEYS') - if packet != '': - self.sendDisconnect(DISCONNECT_PROTOCOL_ERROR, - "NEWKEYS takes no data") - return - self.currentEncryptions = self.nextEncryptions - if self.outgoingCompressionType == 'zlib': - self.outgoingCompression = zlib.compressobj(6) - if self.incomingCompressionType == 'zlib': - self.incomingCompression = zlib.decompressobj() - - - def ssh_SERVICE_REQUEST(self, packet): - """ - Called when we get a MSG_SERVICE_REQUEST message. Payload:: - string serviceName - - The client has requested a service. If we can start the service, - start it; otherwise, disconnect with - DISCONNECT_SERVICE_NOT_AVAILABLE. - """ - service, rest = getNS(packet) - cls = self.factory.getService(self, service) - if not cls: - self.sendDisconnect(DISCONNECT_SERVICE_NOT_AVAILABLE, - "don't have service %s" % service) - return - else: - self.sendPacket(MSG_SERVICE_ACCEPT, NS(service)) - self.setService(cls()) - - - -class SSHClientTransport(SSHTransportBase): - """ - SSHClientTransport implements the client side of the SSH protocol. - - @ivar isClient: since we are always the client, this is always True. - - @ivar _gotNewKeys: if we receive a MSG_NEWKEYS message before we are - ready to transition to the new keys, this is set to True so we - can transition when the keys are ready locally. - - @ivar x: our Diffie-Hellman private key. - - @ivar e: our Diffie-Hellman public key. - - @ivar g: the Diffie-Hellman group generator. - - @ivar p: the Diffie-Hellman group prime - - @ivar instance: the SSHService object we are requesting. - """ - isClient = True - - - def connectionMade(self): - """ - Called when the connection is started with the server. Just sets - up a private instance variable. - """ - SSHTransportBase.connectionMade(self) - self._gotNewKeys = 0 - - - def ssh_KEXINIT(self, packet): - """ - Called when we receive a MSG_KEXINIT message. For a description - of the packet, see SSHTransportBase.ssh_KEXINIT(). Additionally, - this method sends the first key exchange packet. If the agreed-upon - exchange is diffie-hellman-group1-sha1, generate a public key - and send it in a MSG_KEXDH_INIT message. If the exchange is - diffie-hellman-group-exchange-sha1, ask for a 2048 bit group with a - MSG_KEX_DH_GEX_REQUEST_OLD message. - """ - if SSHTransportBase.ssh_KEXINIT(self, packet) is None: - return # we disconnected - if self.kexAlg == 'diffie-hellman-group1-sha1': - self.x = Util.number.getRandomNumber(512, randbytes.secureRandom) - self.e = _MPpow(DH_GENERATOR, self.x, DH_PRIME) - self.sendPacket(MSG_KEXDH_INIT, self.e) - elif self.kexAlg == 'diffie-hellman-group-exchange-sha1': - self.sendPacket(MSG_KEX_DH_GEX_REQUEST_OLD, '\x00\x00\x08\x00') - else: - raise error.ConchError("somehow, the kexAlg has been set " - "to something we don't support") - - - def ssh_KEX_DH_GEX_GROUP(self, packet): - """ - This handles two different message which share an integer value. - If the key exchange is diffie-hellman-group1-sha1, this is - MSG_KEXDH_REPLY. Payload:: - string serverHostKey - integer f (server Diffie-Hellman public key) - string signature - - We verify the host key by calling verifyHostKey, then continue in - _continueKEXDH_REPLY. - - If the key exchange is diffie-hellman-group-exchange-sha1, this is - MSG_KEX_DH_GEX_GROUP. Payload:: - string g (group generator) - string p (group prime) - - We generate a Diffie-Hellman public key and send it in a - MSG_KEX_DH_GEX_INIT message. - """ - if self.kexAlg == 'diffie-hellman-group1-sha1': - # actually MSG_KEXDH_REPLY - pubKey, packet = getNS(packet) - f, packet = getMP(packet) - signature, packet = getNS(packet) - fingerprint = ':'.join([ch.encode('hex') for ch in - md5.new(pubKey).digest()]) - d = self.verifyHostKey(pubKey, fingerprint) - d.addCallback(self._continueKEXDH_REPLY, pubKey, f, signature) - d.addErrback( - lambda unused: self.sendDisconnect( - DISCONNECT_HOST_KEY_NOT_VERIFIABLE, 'bad host key')) - return d - else: - self.p, rest = getMP(packet) - self.g, rest = getMP(rest) - self.x = Util.number.getRandomNumber(320, randbytes.secureRandom) - self.e = _MPpow(self.g, self.x, self.p) - self.sendPacket(MSG_KEX_DH_GEX_INIT, self.e) - - - def _continueKEXDH_REPLY(self, ignored, pubKey, f, signature): - """ - The host key has been verified, so we generate the keys. - - @param pubKey: the public key blob for the server's public key. - @type pubKey: C{str} - @param f: the server's Diffie-Hellman public key. - @type f: C{long} - @param signature: the server's signature, verifying that it has the - correct private key. - @type signature: C{str} - """ - serverKey = keys.Key.fromString(pubKey) - sharedSecret = _MPpow(f, self.x, DH_PRIME) - h = sha.new() - h.update(NS(self.ourVersionString)) - h.update(NS(self.otherVersionString)) - h.update(NS(self.ourKexInitPayload)) - h.update(NS(self.otherKexInitPayload)) - h.update(NS(pubKey)) - h.update(self.e) - h.update(MP(f)) - h.update(sharedSecret) - exchangeHash = h.digest() - if not serverKey.verify(signature, exchangeHash): - self.sendDisconnect(DISCONNECT_KEY_EXCHANGE_FAILED, - 'bad signature') - return - self._keySetup(sharedSecret, exchangeHash) - - - def ssh_KEX_DH_GEX_REPLY(self, packet): - """ - Called when we receieve a MSG_KEX_DH_GEX_REPLY message. Payload:: - string server host key - integer f (server DH public key) - - We verify the host key by calling verifyHostKey, then continue in - _continueGEX_REPLY. - """ - pubKey, packet = getNS(packet) - f, packet = getMP(packet) - signature, packet = getNS(packet) - fingerprint = ':'.join(map(lambda c: '%02x'%ord(c), - md5.new(pubKey).digest())) - d = self.verifyHostKey(pubKey, fingerprint) - d.addCallback(self._continueGEX_REPLY, pubKey, f, signature) - d.addErrback( - lambda unused: self.sendDisconnect( - DISCONNECT_HOST_KEY_NOT_VERIFIABLE, 'bad host key')) - return d - - - def _continueGEX_REPLY(self, ignored, pubKey, f, signature): - """ - The host key has been verified, so we generate the keys. - - @param pubKey: the public key blob for the server's public key. - @type pubKey: C{str} - @param f: the server's Diffie-Hellman public key. - @type f: C{long} - @param signature: the server's signature, verifying that it has the - correct private key. - @type signature: C{str} - """ - serverKey = keys.Key.fromString(pubKey) - sharedSecret = _MPpow(f, self.x, self.p) - h = sha.new() - h.update(NS(self.ourVersionString)) - h.update(NS(self.otherVersionString)) - h.update(NS(self.ourKexInitPayload)) - h.update(NS(self.otherKexInitPayload)) - h.update(NS(pubKey)) - h.update('\x00\x00\x08\x00') - h.update(MP(self.p)) - h.update(MP(self.g)) - h.update(self.e) - h.update(MP(f)) - h.update(sharedSecret) - exchangeHash = h.digest() - if not serverKey.verify(signature, exchangeHash): - self.sendDisconnect(DISCONNECT_KEY_EXCHANGE_FAILED, - 'bad signature') - return - self._keySetup(sharedSecret, exchangeHash) - - - def _keySetup(self, sharedSecret, exchangeHash): - """ - See SSHTransportBase._keySetup(). - """ - SSHTransportBase._keySetup(self, sharedSecret, exchangeHash) - if self._gotNewKeys: - self.ssh_NEWKEYS('') - - - def ssh_NEWKEYS(self, packet): - """ - Called when we receieve a MSG_NEWKEYS message. No payload. - If we've finished setting up our own keys, start using them. - Otherwise, remeber that we've receieved this message. - """ - if packet != '': - self.sendDisconnect(DISCONNECT_PROTOCOL_ERROR, - "NEWKEYS takes no data") - return - if not self.nextEncryptions.encBlockSize: - self._gotNewKeys = 1 - return - log.msg('NEW KEYS') - self.currentEncryptions = self.nextEncryptions - if self.outgoingCompressionType == 'zlib': - self.outgoingCompression = zlib.compressobj(6) - if self.incomingCompressionType == 'zlib': - self.incomingCompression = zlib.decompressobj() - self.connectionSecure() - - - def ssh_SERVICE_ACCEPT(self, packet): - """ - Called when we receieve a MSG_SERVICE_ACCEPT message. Payload:: - string service name - - Start the service we requested. - """ - name = getNS(packet)[0] - if name != self.instance.name: - self.sendDisconnect( - DISCONNECT_PROTOCOL_ERROR, - "received accept for service we did not request") - self.setService(self.instance) - - - def requestService(self, instance): - """ - Request that a service be run over this transport. - - @type instance: subclass of L{twisted.conch.ssh.service.SSHService} - """ - self.sendPacket(MSG_SERVICE_REQUEST, NS(instance.name)) - self.instance = instance - - - # client methods - def verifyHostKey(self, hostKey, fingerprint): - """ - Returns a Deferred that gets a callback if it is a valid key, or - an errback if not. - - @type hostKey: C{str} - @type fingerprint: C{str} - @rtype: L{twisted.internet.defer.Deferred} - """ - # return if it's good - return defer.fail(NotImplementedError()) - - - def connectionSecure(self): - """ - Called when the encryption has been set up. Generally, - requestService() is called to run another service over the transport. - """ - raise NotImplementedError() - - - -class _DummyCipher: - """ - A cipher for the none encryption method. - - @ivar block_size: the block size of the encryption. In the case of the - none cipher, this is 8 bytes. - """ - block_size = 8 - - - def encrypt(self, x): - return x - - - decrypt = encrypt - - -class SSHCiphers: - """ - SSHCiphers represents all the encryption operations that need to occur - to encrypt and authenticate the SSH connection. - - @cvar cipherMap: A dictionary mapping SSH encryption names to 3-tuples of - (, , ) - @cvar macMap: A dictionary mapping SSH MAC names to hash modules. - - @ivar outCipType: the string type of the outgoing cipher. - @ivar inCipType: the string type of the incoming cipher. - @ivar outMACType: the string type of the incoming MAC. - @ivar inMACType: the string type of the incoming MAC. - @ivar encBlockSize: the block size of the outgoing cipher. - @ivar decBlockSize: the block size of the incoming cipher. - @ivar verifyDigestSize: the size of the incoming MAC. - @ivar outMAC: a tuple of (, , , - ) representing the outgoing MAC. - @ivar inMAc: see outMAC, but for the incoming MAC. - """ - - - cipherMap = { - '3des-cbc':('DES3', 24, 0), - 'blowfish-cbc':('Blowfish', 16,0 ), - 'aes256-cbc':('AES', 32, 0), - 'aes192-cbc':('AES', 24, 0), - 'aes128-cbc':('AES', 16, 0), - 'cast128-cbc':('CAST', 16, 0), - 'aes128-ctr':('AES', 16, 1), - 'aes192-ctr':('AES', 24, 1), - 'aes256-ctr':('AES', 32, 1), - '3des-ctr':('DES3', 24, 1), - 'blowfish-ctr':('Blowfish', 16, 1), - 'cast128-ctr':('CAST', 16, 1), - 'none':(None, 0, 0), - } - macMap = { - 'hmac-sha1': sha, - 'hmac-md5': md5, - 'none':None - } - - - def __init__(self, outCip, inCip, outMac, inMac): - self.outCipType = outCip - self.inCipType = inCip - self.outMACType = outMac - self.inMACType = inMac - self.encBlockSize = 0 - self.decBlockSize = 0 - self.verifyDigestSize = 0 - self.outMAC = (None, '', '', 0) - self.inMAC = (None, '', '', 0) - - - def setKeys(self, outIV, outKey, inIV, inKey, outInteg, inInteg): - """ - Set up the ciphers and hashes using the given keys, - - @param outIV: the outgoing initialization vector - @param outKey: the outgoing encryption key - @param inIV: the incoming initialization vector - @param inKey: the incoming encryption key - @param outInteg: the outgoing integrity key - @param inInteg: the incoming integrity key. - """ - o = self._getCipher(self.outCipType, outIV, outKey) - self.encrypt = o.encrypt - self.encBlockSize = o.block_size - o = self._getCipher(self.inCipType, inIV, inKey) - self.decrypt = o.decrypt - self.decBlockSize = o.block_size - self.outMAC = self._getMAC(self.outMACType, outInteg) - self.inMAC = self._getMAC(self.inMACType, inInteg) - if self.inMAC: - self.verifyDigestSize = self.inMAC[3] - - - def _getCipher(self, cip, iv, key): - """ - Creates an initialized cipher object. - - @param cip: the name of the cipher: maps into Crypto.Cipher.* - @param iv: the initialzation vector - @param key: the encryption key - """ - modName, keySize, counterMode = self.cipherMap[cip] - if not modName: # no cipher - return _DummyCipher() - mod = __import__('Crypto.Cipher.%s'%modName, {}, {}, 'x') - if counterMode: - return mod.new(key[:keySize], mod.MODE_CTR, iv[:mod.block_size], - counter=_Counter(iv, mod.block_size)) - else: - return mod.new(key[:keySize], mod.MODE_CBC, iv[:mod.block_size]) - - - def _getMAC(self, mac, key): - """ - Gets a 4-tuple representing the message authentication code. - (, , , - ) - - @param mac: a key mapping into macMap - @type mac: C{str} - @param key: the MAC key. - @type key: C{str} - """ - mod = self.macMap[mac] - if not mod: - return (None, '', '', 0) - #if not hasattr(mod, 'digest_size'): - # ds = len(mod.new().digest()) - #else: - ds = mod.digest_size - key = key[:ds] + '\x00' * (64 - ds) - i = XOR.new('\x36').encrypt(key) - o = XOR.new('\x5c').encrypt(key) - return mod, i, o, ds - - - def encrypt(self, blocks): - """ - Encrypt blocks. Overridden by the encrypt method of a - Crypto.Cipher.* object in setKeys(). - - @type blocks: C{str} - """ - raise NotImplementedError() - - - def decrypt(self, blocks): - """ - Decrypt blocks. See encrypt(). - - @type blocks: C{str} - """ - raise NotImplementedError() - - - def makeMAC(self, seqid, data): - """ - Create a message authentication code (MAC) for the given packet using - the outgoing MAC values. - - @param seqid: the sequence ID of the outgoing packet - @type seqid: C{int} - @param data: the data to create a MAC for - @type data: C{str} - @rtype: C{str} - """ - if not self.outMAC[0]: - return '' - data = struct.pack('>L', seqid) + data - mod, i, o, ds = self.outMAC - inner = mod.new(i + data) - outer = mod.new(o + inner.digest()) - return outer.digest() - - - def verify(self, seqid, data, mac): - """ - Verify an incoming MAC using the incoming MAC values. Return True - if the MAC is valid. - - @param seqid: the sequence ID of the incoming packet - @type seqid: C{int} - @param data: the packet data to verify - @type data: C{str} - @param mac: the MAC sent with the packet - @type mac: C{str} - @rtype: C{bool} - """ - if not self.inMAC[0]: - return mac == '' - data = struct.pack('>L', seqid) + data - mod, i, o, ds = self.inMAC - inner = mod.new(i + data) - outer = mod.new(o + inner.digest()) - return mac == outer.digest() - - - -class _Counter: - """ - Stateful counter which returns results packed in a byte string - """ - - - def __init__(self, initialVector, blockSize): - """ - @type initialVector: C{str} - @param initialVector: A byte string representing the initial counter - value. - @type blockSize: C{int} - @param blockSize: The length of the output buffer, as well as the - number of bytes at the beginning of C{initialVector} to consider. - """ - initialVector = initialVector[:blockSize] - self.count = getMP('\xff\xff\xff\xff' + initialVector)[0] - self.blockSize = blockSize - self.count = Util.number.long_to_bytes(self.count - 1) - self.count = '\x00' * (self.blockSize - len(self.count)) + self.count - self.count = array.array('c', self.count) - self.len = len(self.count) - 1 - - - def __call__(self): - """ - Increment the counter and return the new value. - """ - i = self.len - while i > -1: - self.count[i] = n = chr((ord(self.count[i]) + 1) % 256) - if n == '\x00': - i -= 1 - else: - return self.count.tostring() - - self.count = array.array('c', '\x00' * self.blockSize) - return self.count.tostring() - - - -# Diffie-Hellman primes from Oakley Group 2 [RFC 2409] -DH_PRIME = long('17976931348623159077083915679378745319786029604875601170644' -'442368419718021615851936894783379586492554150218056548598050364644054819923' -'910005079287700335581663922955313623907650873575991482257486257500742530207' -'744771258955095793777842444242661733472762929938766870920560605027081084290' -'7692932019128194467627007L') -DH_GENERATOR = 2L - - - -MSG_DISCONNECT = 1 -MSG_IGNORE = 2 -MSG_UNIMPLEMENTED = 3 -MSG_DEBUG = 4 -MSG_SERVICE_REQUEST = 5 -MSG_SERVICE_ACCEPT = 6 -MSG_KEXINIT = 20 -MSG_NEWKEYS = 21 -MSG_KEXDH_INIT = 30 -MSG_KEXDH_REPLY = 31 -MSG_KEX_DH_GEX_REQUEST_OLD = 30 -MSG_KEX_DH_GEX_REQUEST = 34 -MSG_KEX_DH_GEX_GROUP = 31 -MSG_KEX_DH_GEX_INIT = 32 -MSG_KEX_DH_GEX_REPLY = 33 - - - -DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT = 1 -DISCONNECT_PROTOCOL_ERROR = 2 -DISCONNECT_KEY_EXCHANGE_FAILED = 3 -DISCONNECT_RESERVED = 4 -DISCONNECT_MAC_ERROR = 5 -DISCONNECT_COMPRESSION_ERROR = 6 -DISCONNECT_SERVICE_NOT_AVAILABLE = 7 -DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED = 8 -DISCONNECT_HOST_KEY_NOT_VERIFIABLE = 9 -DISCONNECT_CONNECTION_LOST = 10 -DISCONNECT_BY_APPLICATION = 11 -DISCONNECT_TOO_MANY_CONNECTIONS = 12 -DISCONNECT_AUTH_CANCELLED_BY_USER = 13 -DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE = 14 -DISCONNECT_ILLEGAL_USER_NAME = 15 - - - -messages = {} -for name, value in globals().items(): - if name.startswith('MSG_'): - messages[value] = name diff --git a/tools/buildbot/pylibs/twisted/conch/ssh/userauth.py b/tools/buildbot/pylibs/twisted/conch/ssh/userauth.py deleted file mode 100644 index 4e40201..0000000 --- a/tools/buildbot/pylibs/twisted/conch/ssh/userauth.py +++ /dev/null @@ -1,438 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -""" -Implementation of the ssh-userauth service. -Currently implemented authentication types are public-key and password. - -Maintainer: U{Paul Swartz} -""" - -import struct -from twisted.conch import error, interfaces -from twisted.cred import credentials -from twisted.internet import defer, reactor -from twisted.python import failure, log -from common import NS, getNS, MP -import keys, transport, service - -class SSHUserAuthServer(service.SSHService): - name = 'ssh-userauth' - loginTimeout = 10 * 60 * 60 # 10 minutes before we disconnect them - attemptsBeforeDisconnect = 20 # number of attempts to allow before a disconnect - passwordDelay = 1 # number of seconds to delay on a failed password - protocolMessages = None # set later - interfaceToMethod = { - credentials.ISSHPrivateKey : 'publickey', - credentials.IUsernamePassword : 'password', - credentials.IPluggableAuthenticationModules : 'keyboard-interactive', - } - - def serviceStarted(self): - self.authenticatedWith = [] - self.loginAttempts = 0 - self.user = None - self.nextService = None - self.portal = self.transport.factory.portal - - self.supportedAuthentications = [] - for i in self.portal.listCredentialsInterfaces(): - if i in self.interfaceToMethod: - self.supportedAuthentications.append(self.interfaceToMethod[i]) - - if not self.transport.isEncrypted('out'): - if 'password' in self.supportedAuthentications: - self.supportedAuthentications.remove('password') - if 'keyboard-interactive' in self.supportedAuthentications: - self.supportedAuthentications.remove('keyboard-interactive') - # don't let us transport password in plaintext - self.cancelLoginTimeout = reactor.callLater(self.loginTimeout, - self.timeoutAuthentication) - - def serviceStopped(self): - if self.cancelLoginTimeout: - self.cancelLoginTimeout.cancel() - self.cancelLoginTimeout = None - - def timeoutAuthentication(self): - self.cancelLoginTimeout = None - self.transport.sendDisconnect( - transport.DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE, - 'you took too long') - - - def tryAuth(self, kind, user, data): - log.msg('%s trying auth %s' % (user, kind)) - if kind not in self.supportedAuthentications: - return defer.fail(error.ConchError('unsupported authentication, failing')) - kind = kind.replace('-', '_') - f = getattr(self,'auth_%s'%kind, None) - if f: - ret = f(data) - if not ret: - return defer.fail(error.ConchError('%s return None instead of a Deferred' % kind)) - else: - return ret - return defer.fail(error.ConchError('bad auth type: %s' % kind)) - - def ssh_USERAUTH_REQUEST(self, packet): - user, nextService, method, rest = getNS(packet, 3) - if user != self.user or nextService != self.nextService: - self.authenticatedWith = [] # clear auth state - self.user = user - self.nextService = nextService - self.method = method - d = self.tryAuth(method, user, rest) - if not d: - self._ebBadAuth( - failure.Failure(error.ConchError('auth returned none'))) - return - d.addCallbacks(self._cbFinishedAuth) - d.addErrback(self._ebMaybeBadAuth) - d.addErrback(self._ebBadAuth) - return d - - def _cbFinishedAuth(self, (interface, avatar, logout)): - self.transport.avatar = avatar - self.transport.logoutFunction = logout - service = self.transport.factory.getService(self.transport, - self.nextService) - if not service: - raise error.ConchError('could not get next service: %s' - % self.nextService) - log.msg('%s authenticated with %s' % (self.user, self.method)) - if self.cancelLoginTimeout: - self.cancelLoginTimeout.cancel() - self.cancelLoginTimeout = None - self.transport.sendPacket(MSG_USERAUTH_SUCCESS, '') - self.transport.setService(service()) - - def _ebMaybeBadAuth(self, reason): - reason.trap(error.NotEnoughAuthentication) - self.transport.sendPacket(MSG_USERAUTH_FAILURE, NS(','.join(self.supportedAuthentications))+'\xff') - - def _ebBadAuth(self, reason): - if reason.type == error.IgnoreAuthentication: - return - if self.method != 'none': - log.msg('%s failed auth %s' % (self.user, self.method)) - log.msg('reason:') - if reason.type == error.ConchError: - log.msg(str(reason)) - else: - log.msg(reason.getTraceback()) - self.loginAttempts += 1 - if self.loginAttempts > self.attemptsBeforeDisconnect: - self.transport.sendDisconnect(transport.DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE, - 'too many bad auths') - self.transport.sendPacket(MSG_USERAUTH_FAILURE, NS(','.join(self.supportedAuthentications))+'\x00') - - def auth_publickey(self, packet): - hasSig = ord(packet[0]) - algName, blob, rest = getNS(packet[1:], 2) - pubKey = keys.getPublicKeyObject(data = blob) - signature = hasSig and getNS(rest)[0] or None - if hasSig: - b = NS(self.transport.sessionID) + chr(MSG_USERAUTH_REQUEST) + \ - NS(self.user) + NS(self.nextService) + NS('publickey') + \ - chr(hasSig) + NS(keys.objectType(pubKey)) + NS(blob) - c = credentials.SSHPrivateKey(self.user, algName, blob, b, signature) - return self.portal.login(c, None, interfaces.IConchUser) - else: - c = credentials.SSHPrivateKey(self.user, algName, blob, None, None) - return self.portal.login(c, None, interfaces.IConchUser).addErrback( - self._ebCheckKey, - packet[1:]) - - def _ebCheckKey(self, reason, packet): - reason.trap(error.ValidPublicKey) - # if we make it here, it means that the publickey is valid - self.transport.sendPacket(MSG_USERAUTH_PK_OK, packet) - return failure.Failure(error.IgnoreAuthentication()) - - def auth_password(self, packet): - password = getNS(packet[1:])[0] - c = credentials.UsernamePassword(self.user, password) - return self.portal.login(c, None, interfaces.IConchUser).addErrback( - self._ebPassword) - - def _ebPassword(self, f): - d = defer.Deferred() - reactor.callLater(self.passwordDelay, lambda d,f:d.callback(f), d, f) - return d - - def auth_keyboard_interactive(self, packet): - if hasattr(self, '_pamDeferred'): - self.transport.sendDisconnect(transport.DISCONNECT_PROTOCOL_ERROR, "only one keyboard interactive attempt at a time") - return failure.Failure(error.IgnoreAuthentication()) - c = credentials.PluggableAuthenticationModules(self.user, self._pamConv) - return self.portal.login(c, None, interfaces.IConchUser) - - def _pamConv(self, items): - resp = [] - for message, kind in items: - if kind == 1: # password - resp.append((message, 0)) - elif kind == 2: # text - resp.append((message, 1)) - elif kind in (3, 4): - return defer.fail(error.ConchError('cannot handle PAM 3 or 4 messages')) - else: - return defer.fail(error.ConchError('bad PAM auth kind %i' % kind)) - packet = NS('')+NS('')+NS('') - packet += struct.pack('>L', len(resp)) - for prompt, echo in resp: - packet += NS(prompt) - packet += chr(echo) - self.transport.sendPacket(MSG_USERAUTH_INFO_REQUEST, packet) - self._pamDeferred = defer.Deferred() - return self._pamDeferred - - def ssh_USERAUTH_INFO_RESPONSE(self, packet): - d = self._pamDeferred - del self._pamDeferred - try: - resp = [] - numResps = struct.unpack('>L', packet[:4])[0] - packet = packet[4:] - while packet: - response, packet = getNS(packet) - resp.append((response, 0)) - assert len(resp) == numResps - except: - d.errback(failure.Failure()) - else: - d.callback(resp) - -class SSHUserAuthClient(service.SSHService): - name = 'ssh-userauth' - protocolMessages = None # set later - - preferredOrder = ['publickey', 'password', 'keyboard-interactive'] - - def __init__(self, user, instance): - self.user = user - self.instance = instance - - def serviceStarted(self): - self.authenticatedWith = [] - self.triedPublicKeys = [] - self.lastPublicKey = None - self.askForAuth('none', '') - - def askForAuth(self, kind, extraData): - self.lastAuth = kind - self.transport.sendPacket(MSG_USERAUTH_REQUEST, NS(self.user) + \ - NS(self.instance.name) + NS(kind) + extraData) - def tryAuth(self, kind): - kind = kind.replace('-', '_') - log.msg('trying to auth with %s' % kind) - f= getattr(self,'auth_%s'%kind, None) - if f: - return f() - - def _ebAuth(self, ignored, *args): - self.tryAuth('none') - - def ssh_USERAUTH_SUCCESS(self, packet): - self.transport.setService(self.instance) - #self.ssh_USERAUTH_SUCCESS = lambda *a: None # ignore these - - def ssh_USERAUTH_FAILURE(self, packet): - canContinue, partial = getNS(packet) - canContinue = canContinue.split(',') - partial = ord(partial) - if partial: - self.authenticatedWith.append(self.lastAuth) - def _(x, y): - try: - i1 = self.preferredOrder.index(x) - except ValueError: - return 1 - try: - i2 = self.preferredOrder.index(y) - except ValueError: - return -1 - return cmp(i1, i2) - canContinue.sort(_) - log.msg('can continue with: %s' % canContinue) - for method in canContinue: - if method not in self.authenticatedWith and self.tryAuth(method): - return - self.transport.sendDisconnect(transport.DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE, 'no more authentication methods available') - - def ssh_USERAUTH_PK_OK(self, packet): - if self.lastAuth == 'publickey': - # this is ok - publicKey = self.lastPublicKey - keyType = getNS(publicKey)[0] - b = NS(self.transport.sessionID) + chr(MSG_USERAUTH_REQUEST) + \ - NS(self.user) + NS(self.instance.name) + NS('publickey') + '\xff' +\ - NS(keyType) + NS(publicKey) - d = self.signData(publicKey, b) - if not d: - self.askForAuth('none', '') - # this will fail, we'll move on - return - d.addCallback(self._cbSignedData) - d.addErrback(self._ebAuth) - elif self.lastAuth == 'password': - prompt, language, rest = getNS(packet, 2) - self._oldPass = self._newPass = None - self.getPassword('Old Password: ').addCallbacks(self._setOldPass, self._ebAuth) - self.getPassword(prompt).addCallbacks(self._setNewPass, self._ebAuth) - elif self.lastAuth == 'keyboard-interactive': - name, instruction, lang, data = getNS(packet, 3) - numPrompts = struct.unpack('!L', data[:4])[0] - data = data[4:] - prompts = [] - for i in range(numPrompts): - prompt, data = getNS(data) - echo = bool(ord(data[0])) - data = data[1:] - prompts.append((prompt, echo)) - d = self.getGenericAnswers(name, instruction, prompts) - d.addCallback(self._cbGenericAnswers) - d.addErrback(self._ebAuth) - - def _cbSignedData(self, signedData): - publicKey = self.lastPublicKey - keyType = getNS(publicKey)[0] - self.askForAuth('publickey', '\xff' + NS(keyType) + NS(publicKey) + \ - NS(signedData)) - - - - - - - def _setOldPass(self, op): - if self._newPass: - np = self._newPass - self._newPass = None - self.askForAuth('password', '\xff'+NS(op)+NS(np)) - else: - self._oldPass = op - - def _setNewPass(self, np): - if self._oldPass: - op = self._oldPass - self._oldPass = None - self.askForAuth('password', '\xff'+NS(op)+NS(np)) - else: - self._newPass = np - - def _cbGenericAnswers(self, responses): - data = struct.pack('!L', len(responses)) - for r in responses: - data += NS(r.encode('UTF8')) - self.transport.sendPacket(MSG_USERAUTH_INFO_RESPONSE, data) - - def auth_publickey(self): - publicKey = self.getPublicKey() - if publicKey: - self.lastPublicKey = publicKey - self.triedPublicKeys.append(publicKey) - keyType = getNS(publicKey)[0] - log.msg('using key of type %s' % keyType) - self.askForAuth('publickey', '\x00' + NS(keyType) + \ - NS(publicKey)) - return 1 - else: - return 0 - - def auth_password(self): - d = self.getPassword() - if d: - d.addCallbacks(self._cbPassword, self._ebAuth) - return 1 - else: # returned None, don't do password auth - return 0 - - def auth_keyboard_interactive(self): - log.msg('authing with keyboard-interactive') - self.askForAuth('keyboard-interactive', NS('') + NS('')) - return 1 - - def _cbPassword(self, password): - self.askForAuth('password', '\x00'+NS(password)) - - def signData(self, publicKey, signData): - """ - Sign the given data with the given public key blob. - By default, this will call getPrivateKey to get the private key, - the sign the data using keys.signData. - However, this is factored out so that it can use alternate methods, - such as a key agent. - """ - key = self.getPrivateKey() - if not key: - return - return key.addCallback(self._cbSignData, signData) - - def _cbSignData(self, privateKey, signData): - return keys.signData(privateKey, signData) - - def getPublicKey(self): - """ - Return a public key for the user. If no more public keys are - available, return None. - - @rtype: C{str}/C{None} - """ - return None - #raise NotImplementedError - - - def getPrivateKey(self): - """ - Return a L{Deferred} that will be called back with the private key - corresponding to the last public key from getPublicKey(). - If the private key is not available, errback on the Deferred. - - @rtype: L{Deferred} - """ - return defer.fail(NotImplementedError()) - - def getPassword(self, prompt = None): - """ - Return a L{Deferred} that will be called back with a password. - prompt is a string to display for the password, or None for a generic - 'user@hostname's password: '. - - @type prompt: C{str}/C{None} - @rtype: L{Deferred} - """ - return defer.fail(NotImplementedError()) - - def getGenericAnswers(self, name, instruction, prompts): - """ - Returns a L{Deferred} with the responses to the promopts. - - @param name: The name of the authentication currently in progress. - @param instruction: Describes what the authentication wants. - @param prompts: A list of (prompt, echo) pairs, where prompt is a - string to display and echo is a boolean indicating whether the - user's response should be echoed as they type it. - """ - return defer.fail(NotImplementedError()) - -MSG_USERAUTH_REQUEST = 50 -MSG_USERAUTH_FAILURE = 51 -MSG_USERAUTH_SUCCESS = 52 -MSG_USERAUTH_BANNER = 53 -MSG_USERAUTH_PASSWD_CHANGEREQ = 60 -MSG_USERAUTH_INFO_REQUEST = 60 -MSG_USERAUTH_INFO_RESPONSE = 61 -MSG_USERAUTH_PK_OK = 60 - -messages = {} -import userauth -for v in dir(userauth): - if v[:4]=='MSG_': - messages[getattr(userauth,v)] = v # doesn't handle doubles - -SSHUserAuthServer.protocolMessages = messages -SSHUserAuthClient.protocolMessages = messages diff --git a/tools/buildbot/pylibs/twisted/conch/stdio.py b/tools/buildbot/pylibs/twisted/conch/stdio.py deleted file mode 100644 index b80c9b5..0000000 --- a/tools/buildbot/pylibs/twisted/conch/stdio.py +++ /dev/null @@ -1,95 +0,0 @@ -# -*- test-case-name: twisted.conch.test.test_manhole -*- -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Asynchronous local terminal input handling - -@author: U{Jp Calderone} -""" - -import os, tty, sys, termios - -from twisted.internet import reactor, stdio, protocol, defer -from twisted.python import failure, reflect, log - -from twisted.conch.insults.insults import ServerProtocol -from twisted.conch.manhole import ColoredManhole - -class UnexpectedOutputError(Exception): - pass - -class TerminalProcessProtocol(protocol.ProcessProtocol): - def __init__(self, proto): - self.proto = proto - self.onConnection = defer.Deferred() - - def connectionMade(self): - self.proto.makeConnection(self) - self.onConnection.callback(None) - self.onConnection = None - - def write(self, bytes): - self.transport.write(bytes) - - def outReceived(self, bytes): - self.proto.dataReceived(bytes) - - def errReceived(self, bytes): - self.transport.loseConnection() - if self.proto is not None: - self.proto.connectionLost(failure.Failure(UnexpectedOutputError(bytes))) - self.proto = None - - def childConnectionLost(self, childFD): - if self.proto is not None: - self.proto.childConnectionLost(childFD) - - def processEnded(self, reason): - if self.proto is not None: - self.proto.connectionLost(reason) - self.proto = None - - - -class ConsoleManhole(ColoredManhole): - """ - A manhole protocol specifically for use with L{stdio.StandardIO}. - """ - def connectionLost(self, reason): - """ - When the connection is lost, there is nothing more to do. Stop the - reactor so that the process can exit. - """ - reactor.stop() - - - -def runWithProtocol(klass): - fd = sys.__stdin__.fileno() - oldSettings = termios.tcgetattr(fd) - tty.setraw(fd) - try: - p = ServerProtocol(klass) - stdio.StandardIO(p) - reactor.run() - finally: - termios.tcsetattr(fd, termios.TCSANOW, oldSettings) - os.write(fd, "\r\x1bc\r") - - - -def main(argv=None): - log.startLogging(file('child.log', 'w')) - - if argv is None: - argv = sys.argv[1:] - if argv: - klass = reflect.namedClass(argv[0]) - else: - klass = ConsoleManhole - runWithProtocol(klass) - - -if __name__ == '__main__': - main() diff --git a/tools/buildbot/pylibs/twisted/conch/tap.py b/tools/buildbot/pylibs/twisted/conch/tap.py deleted file mode 100644 index 2fb5a8d..0000000 --- a/tools/buildbot/pylibs/twisted/conch/tap.py +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -# Twisted, the Framework of Your Internet -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -I am a support module for making SSH servers with mktap. -""" - -from twisted.conch import checkers, unix -from twisted.conch.openssh_compat import factory -from twisted.cred import portal -from twisted.python import usage -from twisted.application import strports - - -class Options(usage.Options): - synopsis = "Usage: mktap conch [-i ] [-p ] [-d

] " - longdesc = "Makes a Conch SSH server.." - optParameters = [ - ["interface", "i", "", "local interface to which we listen"], - ["port", "p", "22", "Port on which to listen"], - ["data", "d", "/etc", "directory to look for host keys in"], - ["moduli", "", None, "directory to look for moduli in " - "(if different from --data)"] - ] - zsh_actions = {"data" : "_dirs", "moduli" : "_dirs"} - - -def makeService(config): - t = factory.OpenSSHFactory() - t.portal = portal.Portal(unix.UnixSSHRealm()) - t.portal.registerChecker(checkers.UNIXPasswordDatabase()) - t.portal.registerChecker(checkers.SSHPublicKeyDatabase()) - if checkers.pamauth: - t.portal.registerChecker(checkers.PluggableAuthenticationModulesChecker()) - t.dataRoot = config['data'] - t.moduliRoot = config['moduli'] or config['data'] - port = config['port'] - if config['interface']: - # Add warning here - port += ':interface='+config['interface'] - return strports.service(port, t) diff --git a/tools/buildbot/pylibs/twisted/conch/telnet.py b/tools/buildbot/pylibs/twisted/conch/telnet.py deleted file mode 100644 index 8cdce94..0000000 --- a/tools/buildbot/pylibs/twisted/conch/telnet.py +++ /dev/null @@ -1,996 +0,0 @@ -# -*- test-case-name: twisted.conch.test.test_telnet -*- -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Telnet protocol implementation. - -@author: U{Jp Calderone} -""" - -import struct - -from zope.interface import implements - -from twisted.internet import protocol, interfaces as iinternet, defer -from twisted.python import log - -MODE = chr(1) -EDIT = 1 -TRAPSIG = 2 -MODE_ACK = 4 -SOFT_TAB = 8 -LIT_ECHO = 16 - -# Characters gleaned from the various (and conflicting) RFCs. Not all of these are correct. - -NULL = chr(0) # No operation. -BEL = chr(7) # Produces an audible or - # visible signal (which does - # NOT move the print head). -BS = chr(8) # Moves the print head one - # character position towards - # the left margin. -HT = chr(9) # Moves the printer to the - # next horizontal tab stop. - # It remains unspecified how - # either party determines or - # establishes where such tab - # stops are located. -LF = chr(10) # Moves the printer to the - # next print line, keeping the - # same horizontal position. -VT = chr(11) # Moves the printer to the - # next vertical tab stop. It - # remains unspecified how - # either party determines or - # establishes where such tab - # stops are located. -FF = chr(12) # Moves the printer to the top - # of the next page, keeping - # the same horizontal position. -CR = chr(13) # Moves the printer to the left - # margin of the current line. - -ECHO = chr(1) # User-to-Server: Asks the server to send - # Echos of the transmitted data. -SGA = chr(3) # Suppress Go Ahead. Go Ahead is silly - # and most modern servers should suppress - # it. -NAWS = chr(31) # Negotiate About Window Size. Indicate that - # information about the size of the terminal - # can be communicated. -LINEMODE = chr(34) # Allow line buffering to be - # negotiated about. - -SE = chr(240) # End of subnegotiation parameters. -NOP = chr(241) # No operation. -DM = chr(242) # "Data Mark": The data stream portion - # of a Synch. This should always be - # accompanied by a TCP Urgent - # notification. -BRK = chr(243) # NVT character Break. -IP = chr(244) # The function Interrupt Process. -AO = chr(245) # The function Abort Output -AYT = chr(246) # The function Are You There. -EC = chr(247) # The function Erase Character. -EL = chr(248) # The function Erase Line -GA = chr(249) # The Go Ahead signal. -SB = chr(250) # Indicates that what follows is - # subnegotiation of the indicated - # option. -WILL = chr(251) # Indicates the desire to begin - # performing, or confirmation that - # you are now performing, the - # indicated option. -WONT = chr(252) # Indicates the refusal to perform, - # or continue performing, the - # indicated option. -DO = chr(253) # Indicates the request that the - # other party perform, or - # confirmation that you are expecting - # the other party to perform, the - # indicated option. -DONT = chr(254) # Indicates the demand that the - # other party stop performing, - # or confirmation that you are no - # longer expecting the other party - # to perform, the indicated option. -IAC = chr(255) # Data Byte 255. Introduces a - # telnet command. - -LINEMODE_MODE = chr(1) -LINEMODE_EDIT = chr(1) -LINEMODE_TRAPSIG = chr(2) -LINEMODE_MODE_ACK = chr(4) -LINEMODE_SOFT_TAB = chr(8) -LINEMODE_LIT_ECHO = chr(16) -LINEMODE_FORWARDMASK = chr(2) -LINEMODE_SLC = chr(3) -LINEMODE_SLC_SYNCH = chr(1) -LINEMODE_SLC_BRK = chr(2) -LINEMODE_SLC_IP = chr(3) -LINEMODE_SLC_AO = chr(4) -LINEMODE_SLC_AYT = chr(5) -LINEMODE_SLC_EOR = chr(6) -LINEMODE_SLC_ABORT = chr(7) -LINEMODE_SLC_EOF = chr(8) -LINEMODE_SLC_SUSP = chr(9) -LINEMODE_SLC_EC = chr(10) -LINEMODE_SLC_EL = chr(11) - -LINEMODE_SLC_EW = chr(12) -LINEMODE_SLC_RP = chr(13) -LINEMODE_SLC_LNEXT = chr(14) -LINEMODE_SLC_XON = chr(15) -LINEMODE_SLC_XOFF = chr(16) -LINEMODE_SLC_FORW1 = chr(17) -LINEMODE_SLC_FORW2 = chr(18) -LINEMODE_SLC_MCL = chr(19) -LINEMODE_SLC_MCR = chr(20) -LINEMODE_SLC_MCWL = chr(21) -LINEMODE_SLC_MCWR = chr(22) -LINEMODE_SLC_MCBOL = chr(23) -LINEMODE_SLC_MCEOL = chr(24) -LINEMODE_SLC_INSRT = chr(25) -LINEMODE_SLC_OVER = chr(26) -LINEMODE_SLC_ECR = chr(27) -LINEMODE_SLC_EWR = chr(28) -LINEMODE_SLC_EBOL = chr(29) -LINEMODE_SLC_EEOL = chr(30) - -LINEMODE_SLC_DEFAULT = chr(3) -LINEMODE_SLC_VALUE = chr(2) -LINEMODE_SLC_CANTCHANGE = chr(1) -LINEMODE_SLC_NOSUPPORT = chr(0) -LINEMODE_SLC_LEVELBITS = chr(3) - -LINEMODE_SLC_ACK = chr(128) -LINEMODE_SLC_FLUSHIN = chr(64) -LINEMODE_SLC_FLUSHOUT = chr(32) -LINEMODE_EOF = chr(236) -LINEMODE_SUSP = chr(237) -LINEMODE_ABORT = chr(238) - -class ITelnetProtocol(iinternet.IProtocol): - def unhandledCommand(command, argument): - """A command was received but not understood. - """ - - def unhandledSubnegotiation(bytes): - """A subnegotiation command was received but not understood. - """ - - def enableLocal(option): - """Enable the given option locally. - - This should enable the given option on this side of the - telnet connection and return True. If False is returned, - the option will be treated as still disabled and the peer - will be notified. - """ - - def enableRemote(option): - """Indicate whether the peer should be allowed to enable this option. - - Returns True if the peer should be allowed to enable this option, - False otherwise. - """ - - def disableLocal(option): - """Disable the given option locally. - - Unlike enableLocal, this method cannot fail. The option must be - disabled. - """ - - def disableRemote(option): - """Indicate that the peer has disabled this option. - """ - -class ITelnetTransport(iinternet.ITransport): - def do(option): - """Indicate a desire for the peer to begin performing the given option. - - Returns a Deferred that fires with True when the peer begins performing - the option, or False when the peer refuses to perform it. If the peer - is already performing the given option, the Deferred will fail with - L{AlreadyEnabled}. If a negotiation regarding this option is already - in progress, the Deferred will fail with L{AlreadyNegotiating}. - - Note: It is currently possible that this Deferred will never fire, - if the peer never responds, or if the peer believes the option to - already be enabled. - """ - - def dont(option): - """Indicate a desire for the peer to cease performing the given option. - - Returns a Deferred that fires with True when the peer ceases performing - the option. If the peer is not performing the given option, the - Deferred will fail with L{AlreadyDisabled}. If negotiation regarding - this option is already in progress, the Deferred will fail with - L{AlreadyNegotiating}. - - Note: It is currently possible that this Deferred will never fire, - if the peer never responds, or if the peer believes the option to - already be disabled. - """ - - def will(option): - """Indicate our willingness to begin performing this option locally. - - Returns a Deferred that fires with True when the peer agrees to allow - us to begin performing this option, or False if the peer refuses to - allow us to begin performing it. If the option is already enabled - locally, the Deferred will fail with L{AlreadyEnabled}. If negotiation - regarding this option is already in progress, the Deferred will fail with - L{AlreadyNegotiating}. - - Note: It is currently possible that this Deferred will never fire, - if the peer never responds, or if the peer believes the option to - already be enabled. - """ - - def wont(option): - """Indicate that we will stop performing the given option. - - Returns a Deferred that fires with True when the peer acknowledges - we have stopped performing this option. If the option is already - disabled locally, the Deferred will fail with L{AlreadyDisabled}. - If negotiation regarding this option is already in progress, - the Deferred will fail with L{AlreadyNegotiating}. - - Note: It is currently possible that this Deferred will never fire, - if the peer never responds, or if the peer believes the option to - already be disabled. - """ - - def requestNegotiation(about, bytes): - """Send a subnegotiation request. - - @param about: A byte indicating the feature being negotiated. - @param bytes: Any number of bytes containing specific information - about the negotiation being requested. No values in this string - need to be escaped, as this function will escape any value which - requires it. - """ - -class TelnetError(Exception): - pass - -class NegotiationError(TelnetError): - def __str__(self): - return self.__class__.__module__ + '.' + self.__class__.__name__ + ':' + repr(self.args[0]) - -class OptionRefused(NegotiationError): - pass - -class AlreadyEnabled(NegotiationError): - pass - -class AlreadyDisabled(NegotiationError): - pass - -class AlreadyNegotiating(NegotiationError): - pass - -class TelnetProtocol(protocol.Protocol): - implements(ITelnetProtocol) - - def unhandledCommand(self, command, argument): - pass - - def unhandledSubnegotiation(self, command, bytes): - pass - - def enableLocal(self, option): - pass - - def enableRemote(self, option): - pass - - def disableLocal(self, option): - pass - - def disableRemote(self, option): - pass - - -class Telnet(protocol.Protocol): - """ - @ivar commandMap: A mapping of bytes to callables. When a - telnet command is received, the command byte (the first byte - after IAC) is looked up in this dictionary. If a callable is - found, it is invoked with the argument of the command, or None - if the command takes no argument. Values should be added to - this dictionary if commands wish to be handled. By default, - only WILL, WONT, DO, and DONT are handled. These should not - be overridden, as this class handles them correctly and - provides an API for interacting with them. - - @ivar negotiationMap: A mapping of bytes to callables. When - a subnegotiation command is received, the command byte (the - first byte after SB) is looked up in this dictionary. If - a callable is found, it is invoked with the argument of the - subnegotiation. Values should be added to this dictionary if - subnegotiations are to be handled. By default, no values are - handled. - - @ivar options: A mapping of option bytes to their current - state. This state is likely of little use to user code. - Changes should not be made to it. - - @ivar state: A string indicating the current parse state. It - can take on the values "data", "escaped", "command", "newline", - "subnegotiation", and "subnegotiation-escaped". Changes - should not be made to it. - - @ivar transport: This protocol's transport object. - """ - - # One of a lot of things - state = 'data' - - def __init__(self): - self.options = {} - self.negotiationMap = {} - self.commandMap = { - WILL: self.telnet_WILL, - WONT: self.telnet_WONT, - DO: self.telnet_DO, - DONT: self.telnet_DONT} - - def _write(self, bytes): - self.transport.write(bytes) - - class _OptionState: - class _Perspective: - state = 'no' - negotiating = False - onResult = None - - def __str__(self): - return self.state + ('*' * self.negotiating) - - def __init__(self): - self.us = self._Perspective() - self.him = self._Perspective() - - def __repr__(self): - return '<_OptionState us=%s him=%s>' % (self.us, self.him) - - def getOptionState(self, opt): - return self.options.setdefault(opt, self._OptionState()) - - def _do(self, option): - self._write(IAC + DO + option) - - def _dont(self, option): - self._write(IAC + DONT + option) - - def _will(self, option): - self._write(IAC + WILL + option) - - def _wont(self, option): - self._write(IAC + WONT + option) - - def will(self, option): - """Indicate our willingness to enable an option. - """ - s = self.getOptionState(option) - if s.us.negotiating or s.him.negotiating: - return defer.fail(AlreadyNegotiating(option)) - elif s.us.state == 'yes': - return defer.fail(AlreadyEnabled(option)) - else: - s.us.negotiating = True - s.us.onResult = d = defer.Deferred() - self._will(option) - return d - - def wont(self, option): - """Indicate we are not willing to enable an option. - """ - s = self.getOptionState(option) - if s.us.negotiating or s.him.negotiating: - return defer.fail(AlreadyNegotiating(option)) - elif s.us.state == 'no': - return defer.fail(AlreadyDisabled(option)) - else: - s.us.negotiating = True - s.us.onResult = d = defer.Deferred() - self._wont(option) - return d - - def do(self, option): - s = self.getOptionState(option) - if s.us.negotiating or s.him.negotiating: - return defer.fail(AlreadyNegotiating(option)) - elif s.him.state == 'yes': - return defer.fail(AlreadyEnabled(option)) - else: - s.him.negotiating = True - s.him.onResult = d = defer.Deferred() - self._do(option) - return d - - def dont(self, option): - s = self.getOptionState(option) - if s.us.negotiating or s.him.negotiating: - return defer.fail(AlreadyNegotiating(option)) - elif s.him.state == 'no': - return defer.fail(AlreadyDisabled(option)) - else: - s.him.negotiating = True - s.him.onResult = d = defer.Deferred() - self._dont(option) - return d - - def requestNegotiation(self, about, bytes): - bytes = bytes.replace(IAC, IAC * 2) - self._write(IAC + SB + bytes + IAC + SE) - - def dataReceived(self, data): - appDataBuffer = [] - - for b in data: - if self.state == 'data': - if b == IAC: - self.state = 'escaped' - elif b == '\r': - self.state = 'newline' - else: - appDataBuffer.append(b) - elif self.state == 'escaped': - if b == IAC: - appDataBuffer.append(b) - self.state = 'data' - elif b == SB: - self.state = 'subnegotiation' - self.commands = [] - elif b in (NOP, DM, BRK, IP, AO, AYT, EC, EL, GA): - self.state = 'data' - if appDataBuffer: - self.applicationDataReceived(''.join(appDataBuffer)) - del appDataBuffer[:] - self.commandReceived(b, None) - elif b in (WILL, WONT, DO, DONT): - self.state = 'command' - self.command = b - else: - raise ValueError("Stumped", b) - elif self.state == 'command': - self.state = 'data' - command = self.command - del self.command - if appDataBuffer: - self.applicationDataReceived(''.join(appDataBuffer)) - del appDataBuffer[:] - self.commandReceived(command, b) - elif self.state == 'newline': - if b == '\n': - appDataBuffer.append('\n') - elif b == '\0': - appDataBuffer.append('\r') - else: - appDataBuffer.append('\r' + b) - self.state = 'data' - elif self.state == 'subnegotiation': - if b == IAC: - self.state = 'subnegotiation-escaped' - else: - self.commands.append(b) - elif self.state == 'subnegotiation-escaped': - if b == SE: - self.state = 'data' - commands = self.commands - del self.commands - if appDataBuffer: - self.applicationDataReceived(''.join(appDataBuffer)) - del appDataBuffer[:] - self.negotiate(commands) - else: - self.state = 'subnegotiation' - self.commands.append(b) - else: - raise ValueError("How'd you do this?") - - if appDataBuffer: - self.applicationDataReceived(''.join(appDataBuffer)) - - - def connectionLost(self, reason): - for state in self.options.values(): - if state.us.onResult is not None: - d = state.us.onResult - state.us.onResult = None - d.errback(reason) - if state.him.onResult is not None: - d = state.him.onResult - state.him.onResult = None - d.errback(reason) - - def applicationDataReceived(self, bytes): - """Called with application-level data. - """ - - def unhandledCommand(self, command, argument): - """Called for commands for which no handler is installed. - """ - - def commandReceived(self, command, argument): - cmdFunc = self.commandMap.get(command) - if cmdFunc is None: - self.unhandledCommand(command, argument) - else: - cmdFunc(argument) - - def unhandledSubnegotiation(self, command, bytes): - """Called for subnegotiations for which no handler is installed. - """ - - def negotiate(self, bytes): - command, bytes = bytes[0], bytes[1:] - cmdFunc = self.negotiationMap.get(command) - if cmdFunc is None: - self.unhandledSubnegotiation(command, bytes) - else: - cmdFunc(bytes) - - def telnet_WILL(self, option): - s = self.getOptionState(option) - self.willMap[s.him.state, s.him.negotiating](self, s, option) - - def will_no_false(self, state, option): - # He is unilaterally offering to enable an option. - if self.enableRemote(option): - state.him.state = 'yes' - self._do(option) - else: - self._dont(option) - - def will_no_true(self, state, option): - # Peer agreed to enable an option in response to our request. - state.him.state = 'yes' - state.him.negotiating = False - d = state.him.onResult - state.him.onResult = None - d.callback(True) - assert self.enableRemote(option), "enableRemote must return True in this context (for option %r)" % (option,) - - def will_yes_false(self, state, option): - # He is unilaterally offering to enable an already-enabled option. - # Ignore this. - pass - - def will_yes_true(self, state, option): - # This is a bogus state. It is here for completeness. It will - # never be entered. - assert False, "will_yes_true can never be entered, but was called with %r, %r" % (state, option) - - willMap = {('no', False): will_no_false, ('no', True): will_no_true, - ('yes', False): will_yes_false, ('yes', True): will_yes_true} - - def telnet_WONT(self, option): - s = self.getOptionState(option) - self.wontMap[s.him.state, s.him.negotiating](self, s, option) - - def wont_no_false(self, state, option): - # He is unilaterally demanding that an already-disabled option be/remain disabled. - # Ignore this (although we could record it and refuse subsequent enable attempts - # from our side - he can always refuse them again though, so we won't) - pass - - def wont_no_true(self, state, option): - # Peer refused to enable an option in response to our request. - state.him.negotiating = False - d = state.him.onResult - state.him.onResult = None - d.errback(OptionRefused(option)) - - def wont_yes_false(self, state, option): - # Peer is unilaterally demanding that an option be disabled. - state.him.state = 'no' - self.disableRemote(option) - self._dont(option) - - def wont_yes_true(self, state, option): - # Peer agreed to disable an option at our request. - state.him.state = 'no' - state.him.negotiating = False - d = state.him.onResult - state.him.onResult = None - d.callback(True) - self.disableRemote(option) - - wontMap = {('no', False): wont_no_false, ('no', True): wont_no_true, - ('yes', False): wont_yes_false, ('yes', True): wont_yes_true} - - def telnet_DO(self, option): - s = self.getOptionState(option) - self.doMap[s.us.state, s.us.negotiating](self, s, option) - - def do_no_false(self, state, option): - # Peer is unilaterally requesting that we enable an option. - if self.enableLocal(option): - state.us.state = 'yes' - self._will(option) - else: - self._wont(option) - - def do_no_true(self, state, option): - # Peer agreed to allow us to enable an option at our request. - state.us.state = 'yes' - state.us.negotiating = False - d = state.us.onResult - state.us.onResult = None - d.callback(True) - self.enableLocal(option) - - def do_yes_false(self, state, option): - # Peer is unilaterally requesting us to enable an already-enabled option. - # Ignore this. - pass - - def do_yes_true(self, state, option): - # This is a bogus state. It is here for completeness. It will never be - # entered. - assert False, "do_yes_true can never be entered, but was called with %r, %r" % (state, option) - - doMap = {('no', False): do_no_false, ('no', True): do_no_true, - ('yes', False): do_yes_false, ('yes', True): do_yes_true} - - def telnet_DONT(self, option): - s = self.getOptionState(option) - self.dontMap[s.us.state, s.us.negotiating](self, s, option) - - def dont_no_false(self, state, option): - # Peer is unilaterally demanding us to disable an already-disabled option. - # Ignore this. - pass - - def dont_no_true(self, state, option): - # This is a bogus state. It is here for completeness. It will never be - # entered. - assert False, "dont_no_true can never be entered, but was called with %r, %r" % (state, option) - - - def dont_yes_false(self, state, option): - # Peer is unilaterally demanding we disable an option. - state.us.state = 'no' - self.disableLocal(option) - self._wont(option) - - def dont_yes_true(self, state, option): - # Peer acknowledged our notice that we will disable an option. - state.us.state = 'no' - state.us.negotiating = False - d = state.us.onResult - state.us.onResult = None - d.callback(True) - self.disableLocal(option) - - dontMap = {('no', False): dont_no_false, ('no', True): dont_no_true, - ('yes', False): dont_yes_false, ('yes', True): dont_yes_true} - - def enableLocal(self, option): - """ - Reject all attempts to enable options. - """ - return False - - - def enableRemote(self, option): - """ - Reject all attempts to enable options. - """ - return False - - - def disableLocal(self, option): - """ - Signal a programming error by raising an exception. - - L{enableLocal} must return true for the given value of C{option} in - order for this method to be called. If a subclass of L{Telnet} - overrides enableLocal to allow certain options to be enabled, it must - also override disableLocal to disable those options. - - @raise NotImplementedError: Always raised. - """ - raise NotImplementedError( - "Don't know how to disable local telnet option %r" % (option,)) - - - def disableRemote(self, option): - """ - Signal a programming error by raising an exception. - - L{enableRemote} must return true for the given value of C{option} in - order for this method to be called. If a subclass of L{Telnet} - overrides enableRemote to allow certain options to be enabled, it must - also override disableRemote tto disable those options. - - @raise NotImplementedError: Always raised. - """ - raise NotImplementedError( - "Don't know how to disable remote telnet option %r" % (option,)) - - - -class ProtocolTransportMixin: - def write(self, bytes): - self.transport.write(bytes.replace('\n', '\r\n')) - - def writeSequence(self, seq): - self.transport.writeSequence(seq) - - def loseConnection(self): - self.transport.loseConnection() - - def getHost(self): - return self.transport.getHost() - - def getPeer(self): - return self.transport.getPeer() - -class TelnetTransport(Telnet, ProtocolTransportMixin): - """ - @ivar protocol: An instance of the protocol to which this - transport is connected, or None before the connection is - established and after it is lost. - - @ivar protocolFactory: A callable which returns protocol instances - which provide L{ITelnetProtocol}. This will be invoked when a - connection is established. It is passed *protocolArgs and - **protocolKwArgs. - - @ivar protocolArgs: A tuple of additional arguments to - pass to protocolFactory. - - @ivar protocolKwArgs: A dictionary of additional arguments - to pass to protocolFactory. - """ - - disconnecting = False - - protocolFactory = None - protocol = None - - def __init__(self, protocolFactory=None, *a, **kw): - Telnet.__init__(self) - if protocolFactory is not None: - self.protocolFactory = protocolFactory - self.protocolArgs = a - self.protocolKwArgs = kw - - def connectionMade(self): - if self.protocolFactory is not None: - self.protocol = self.protocolFactory(*self.protocolArgs, **self.protocolKwArgs) - assert ITelnetProtocol.providedBy(self.protocol) - try: - factory = self.factory - except AttributeError: - pass - else: - self.protocol.factory = factory - self.protocol.makeConnection(self) - - def connectionLost(self, reason): - Telnet.connectionLost(self, reason) - if self.protocol is not None: - try: - self.protocol.connectionLost(reason) - finally: - del self.protocol - - def enableLocal(self, option): - return self.protocol.enableLocal(option) - - def enableRemote(self, option): - return self.protocol.enableRemote(option) - - def disableLocal(self, option): - return self.protocol.disableLocal(option) - - def disableRemote(self, option): - return self.protocol.disableRemote(option) - - def unhandledSubnegotiation(self, command, bytes): - self.protocol.unhandledSubnegotiation(command, bytes) - - def unhandledCommand(self, command, argument): - self.protocol.unhandledCommand(command, argument) - - def applicationDataReceived(self, bytes): - self.protocol.dataReceived(bytes) - - def write(self, data): - ProtocolTransportMixin.write(self, data.replace('\xff','\xff\xff')) - - -class TelnetBootstrapProtocol(TelnetProtocol, ProtocolTransportMixin): - implements() - - protocol = None - - def __init__(self, protocolFactory, *args, **kw): - self.protocolFactory = protocolFactory - self.protocolArgs = args - self.protocolKwArgs = kw - - def connectionMade(self): - self.transport.negotiationMap[NAWS] = self.telnet_NAWS - self.transport.negotiationMap[LINEMODE] = self.telnet_LINEMODE - - for opt in (LINEMODE, NAWS, SGA): - self.transport.do(opt).addErrback(log.err) - for opt in (ECHO,): - self.transport.will(opt).addErrback(log.err) - - self.protocol = self.protocolFactory(*self.protocolArgs, **self.protocolKwArgs) - - try: - factory = self.factory - except AttributeError: - pass - else: - self.protocol.factory = factory - - self.protocol.makeConnection(self) - - def connectionLost(self, reason): - if self.protocol is not None: - try: - self.protocol.connectionLost(reason) - finally: - del self.protocol - - def dataReceived(self, data): - self.protocol.dataReceived(data) - - def enableLocal(self, opt): - if opt == ECHO: - return True - elif opt == SGA: - return True - else: - return False - - def enableRemote(self, opt): - if opt == LINEMODE: - self.transport.requestNegotiation(LINEMODE, MODE + chr(TRAPSIG)) - return True - elif opt == NAWS: - return True - elif opt == SGA: - return True - else: - return False - - def telnet_NAWS(self, bytes): - # NAWS is client -> server *only*. self.protocol will - # therefore be an ITerminalTransport, the `.protocol' - # attribute of which will be an ITerminalProtocol. Maybe. - # You know what, XXX TODO clean this up. - if len(bytes) == 4: - width, height = struct.unpack('!HH', ''.join(bytes)) - self.protocol.terminalProtocol.terminalSize(width, height) - else: - log.msg("Wrong number of NAWS bytes") - - - linemodeSubcommands = { - LINEMODE_SLC: 'SLC'} - def telnet_LINEMODE(self, bytes): - revmap = {} - linemodeSubcommand = bytes[0] - if 0: - # XXX TODO: This should be enabled to parse linemode subnegotiation. - getattr(self, 'linemode_' + self.linemodeSubcommands[linemodeSubcommand])(bytes[1:]) - - def linemode_SLC(self, bytes): - chunks = zip(*[iter(bytes)]*3) - for slcFunction, slcValue, slcWhat in chunks: - # Later, we should parse stuff. - 'SLC', ord(slcFunction), ord(slcValue), ord(slcWhat) - -from twisted.protocols import basic - -class StatefulTelnetProtocol(basic.LineReceiver, TelnetProtocol): - delimiter = '\n' - - state = 'Discard' - - def connectionLost(self, reason): - basic.LineReceiver.connectionLost(self, reason) - TelnetProtocol.connectionLost(self, reason) - - def lineReceived(self, line): - oldState = self.state - newState = getattr(self, "telnet_" + oldState)(line) - if newState is not None: - if self.state == oldState: - self.state = newState - else: - log.msg("Warning: state changed and new state returned") - - def telnet_Discard(self, line): - pass - -from twisted.cred import credentials - -class AuthenticatingTelnetProtocol(StatefulTelnetProtocol): - """A protocol which prompts for credentials and attempts to authenticate them. - - Username and password prompts are given (the password is obscured). When the - information is collected, it is passed to a portal and an avatar implementing - L{ITelnetProtocol} is requested. If an avatar is returned, it connected to this - protocol's transport, and this protocol's transport is connected to it. - Otherwise, the user is re-prompted for credentials. - """ - - state = "User" - protocol = None - - def __init__(self, portal): - self.portal = portal - - def connectionMade(self): - self.transport.write("Username: ") - - def connectionLost(self, reason): - StatefulTelnetProtocol.connectionLost(self, reason) - if self.protocol is not None: - try: - self.protocol.connectionLost(reason) - self.logout() - finally: - del self.protocol, self.logout - - def telnet_User(self, line): - self.username = line - self.transport.will(ECHO) - self.transport.write("Password: ") - return 'Password' - - def telnet_Password(self, line): - username, password = self.username, line - del self.username - def login(ignored): - creds = credentials.UsernamePassword(username, password) - d = self.portal.login(creds, None, ITelnetProtocol) - d.addCallback(self._cbLogin) - d.addErrback(self._ebLogin) - self.transport.wont(ECHO).addCallback(login) - return 'Discard' - - def _cbLogin(self, ial): - interface, protocol, logout = ial - assert interface is ITelnetProtocol - self.protocol = protocol - self.logout = logout - self.state = 'Command' - - protocol.makeConnection(self.transport) - self.transport.protocol = protocol - - def _ebLogin(self, failure): - self.transport.write("\nAuthentication failed\n") - self.transport.write("Username: ") - self.state = "User" - -__all__ = [ - # Exceptions - 'TelnetError', 'NegotiationError', 'OptionRefused', - 'AlreadyNegotiating', 'AlreadyEnabled', 'AlreadyDisabled', - - # Interfaces - 'ITelnetProtocol', 'ITelnetTransport', - - # Other stuff, protocols, etc. - 'Telnet', 'TelnetProtocol', 'TelnetTransport', - 'TelnetBootstrapProtocol', - - ] diff --git a/tools/buildbot/pylibs/twisted/conch/test/__init__.py b/tools/buildbot/pylibs/twisted/conch/test/__init__.py deleted file mode 100644 index d09b412..0000000 --- a/tools/buildbot/pylibs/twisted/conch/test/__init__.py +++ /dev/null @@ -1 +0,0 @@ -'conch tests' diff --git a/tools/buildbot/pylibs/twisted/conch/test/keydata.py b/tools/buildbot/pylibs/twisted/conch/test/keydata.py deleted file mode 100644 index 33879459..0000000 --- a/tools/buildbot/pylibs/twisted/conch/test/keydata.py +++ /dev/null @@ -1,174 +0,0 @@ -# -*- test-case-name: twisted.conch.test.test_keys -*- -# Copyright (c) 2007-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Data used by test_keys as well as others. -""" -RSAData = { - 'n':long('1062486685755247411169438309495398947372127791189432809481' - '382072971106157632182084539383569281493520117634129557550415277' - '516685881326038852354459895734875625093273594925884531272867425' - '864910490065695876046999646807138717162833156501L'), - 'e':35L, - 'd':long('6678487739032983727350755088256793383481946116047863373882' - '973030104095847973715959961839578340816412167985957218887914482' - '713602371850869127033494910375212470664166001439410214474266799' - '85974425203903884190893469297150446322896587555L'), - 'q':long('3395694744258061291019136154000709371890447462086362702627' - '9704149412726577280741108645721676968699696898960891593323L'), - 'p':long('3128922844292337321766351031842562691837301298995834258844' - '4720539204069737532863831050930719431498338835415515173887L')} - -DSAData = { - 'y':long('2300663509295750360093768159135720439490120577534296730713' - '348508834878775464483169644934425336771277908527130096489120714' - '610188630979820723924744291603865L'), - 'g':long('4451569990409370769930903934104221766858515498655655091803' - '866645719060300558655677517139568505649468378587802312867198352' - '1161998270001677664063945776405L'), - 'p':long('7067311773048598659694590252855127633397024017439939353776' - '608320410518694001356789646664502838652272205440894335303988504' - '978724817717069039110940675621677L'), - 'q':1184501645189849666738820838619601267690550087703L, - 'x':863951293559205482820041244219051653999559962819L} - -publicRSA_openssh = ("ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAGEArzJx8OYOnJmzf4tfBE" -"vLi8DVPrJ3/c9k2I/Az64fxjHf9imyRJbixtQhlH9lfNjUIx+4LmrJH5QNRsFporcHDKOTwTTYL" -"h5KmRpslkYHRivcJSkbh/C+BR3utDS555mV comment") - -privateRSA_openssh = """-----BEGIN RSA PRIVATE KEY----- -MIIByAIBAAJhAK8ycfDmDpyZs3+LXwRLy4vA1T6yd/3PZNiPwM+uH8Yx3/YpskSW -4sbUIZR/ZXzY1CMfuC5qyR+UDUbBaaK3Bwyjk8E02C4eSpkabJZGB0Yr3CUpG4fw -vgUd7rQ0ueeZlQIBIwJgbh+1VZfr7WftK5lu7MHtqE1S1vPWZQYE3+VUn8yJADyb -Z4fsZaCrzW9lkIqXkE3GIY+ojdhZhkO1gbG0118sIgphwSWKRxK0mvh6ERxKqIt1 -xJEJO74EykXZV4oNJ8sjAjEA3J9r2ZghVhGN6V8DnQrTk24Td0E8hU8AcP0FVP+8 -PQm/g/aXf2QQkQT+omdHVEJrAjEAy0pL0EBH6EVS98evDCBtQw22OZT52qXlAwZ2 -gyTriKFVoqjeEjt3SZKKqXHSApP/AjBLpF99zcJJZRq2abgYlf9lv1chkrWqDHUu -DZttmYJeEfiFBBavVYIF1dOlZT0G8jMCMBc7sOSZodFnAiryP+Qg9otSBjJ3bQML -pSTqy7c3a2AScC/YyOwkDaICHnnD3XyjMwIxALRzl0tQEKMXs6hH8ToUdlLROCrP -EhQ0wahUTCk1gKA4uPD6TMTChavbh4K63OvbKg== ------END RSA PRIVATE KEY-----""" - -# some versions of OpenSSH generate these (slightly different keys) -privateRSA_openssh_alternate = """-----BEGIN RSA PRIVATE KEY----- -MIIBzjCCAcgCAQACYQCvMnHw5g6cmbN/i18ES8uLwNU+snf9z2TYj8DPrh/GMd/2 -KbJEluLG1CGUf2V82NQjH7guaskflA1GwWmitwcMo5PBNNguHkqZGmyWRgdGK9wl -KRuH8L4FHe60NLnnmZUCASMCYG4ftVWX6+1n7SuZbuzB7ahNUtbz1mUGBN/lVJ/M -iQA8m2eH7GWgq81vZZCKl5BNxiGPqI3YWYZDtYGxtNdfLCIKYcElikcStJr4ehEc -SqiLdcSRCTu+BMpF2VeKDSfLIwIxANyfa9mYIVYRjelfA50K05NuE3dBPIVPAHD9 -BVT/vD0Jv4P2l39kEJEE/qJnR1RCawIxAMtKS9BAR+hFUvfHrwwgbUMNtjmU+dql -5QMGdoMk64ihVaKo3hI7d0mSiqlx0gKT/wIwS6Rffc3CSWUatmm4GJX/Zb9XIZK1 -qgx1Lg2bbZmCXhH4hQQWr1WCBdXTpWU9BvIzAjAXO7DkmaHRZwIq8j/kIPaLUgYy -d20DC6Uk6su3N2tgEnAv2MjsJA2iAh55w918ozMCMQC0c5dLUBCjF7OoR/E6FHZS -0TgqzxIUNMGoVEwpNYCgOLjw+kzEwoWr24eCutzr2yowAA== -------END RSA PRIVATE KEY------""" - -privateRSA_openssh_encrypted = """-----BEGIN RSA PRIVATE KEY----- -Proc-Type: 4,ENCRYPTED -DEK-Info: DES-EDE3-CBC,FFFFFFFFFFFFFFFF - -30qUR7DYY/rpVJu159paRM1mUqt/IMibfEMTKWSjNhCVD21hskftZCJROw/WgIFt -ncusHpJMkjgwEpho0KyKilcC7zxjpunTex24Meb5pCdXCrYft8AyUkRdq3dugMqT -4nuWuWxziluBhKQ2M9tPGcEOeulU4vVjceZt2pZhZQVBf08o3XUv5/7RYd24M9md -WIo+5zdj2YQkI6xMFTP954O/X32ME1KQt98wgNEy6mxhItbvf00mH3woALwEKP3v -PSMxxtx3VKeDKd9YTOm1giKkXZUf91vZWs0378tUBrU4U5qJxgryTjvvVKOtofj6 -4qQy6+r6M6wtwVlXBgeRm2gBPvL3nv6MsROp3E6ztBd/e7A8fSec+UTq3ko/EbGP -0QG+IG5tg8FsdITxQ9WAIITZL3Rc6hA5Ymx1VNhySp3iSiso8Jof27lku4pyuvRV -ko/B3N2H7LnQrGV0GyrjeYocW/qZh/PCsY48JBFhlNQexn2mn44AJW3y5xgbhvKA -3mrmMD1hD17ZvZxi4fPHjbuAyM1vFqhQx63eT9ijbwJ91svKJl5O5MIv41mCRonm -hxvOXw8S0mjSasyofptzzQCtXxFLQigXbpQBltII+Ys= ------END RSA PRIVATE KEY-----""" - -publicRSA_lsh = ("{KDEwOnB1YmxpYy1rZXkoMTQ6cnNhLXBrY3MxLXNoYTEoMTpuOTc6AK8yc" -"fDmDpyZs3+LXwRLy4vA1T6yd/3PZNiPwM+uH8Yx3/YpskSW4sbUIZR/ZXzY1CMfuC5qyR+UDUbB" -"aaK3Bwyjk8E02C4eSpkabJZGB0Yr3CUpG4fwvgUd7rQ0ueeZlSkoMTplMTojKSkp}") - -privateRSA_lsh = ("(11:private-key(9:rsa-pkcs1(1:n97:\x00\xaf2q\xf0\xe6\x0e" -"\x9c\x99\xb3\x7f\x8b_\x04K\xcb\x8b\xc0\xd5>\xb2w\xfd\xcfd\xd8\x8f\xc0\xcf" -"\xae\x1f\xc61\xdf\xf6)\xb2D\x96\xe2\xc6\xd4!\x94\x7fe|\xd8\xd4#\x1f\xb8.j" -"\xc9\x1f\x94\rF\xc1i\xa2\xb7\x07\x0c\xa3\x93\xc14\xd8.\x1eJ\x99\x1al\x96F" -"\x07F+\xdc%)\x1b\x87\xf0\xbe\x05\x1d\xee\xb44\xb9\xe7\x99\x95)(1:e1:#)(1:d9" -"6:n\x1f\xb5U\x97\xeb\xedg\xed+\x99n\xec\xc1\xed\xa8MR\xd6\xf3\xd6e\x06\x04" -"\xdf\xe5T\x9f\xcc\x89\x00<\x9bg\x87\xece\xa0\xab\xcdoe\x90\x8a\x97\x90M\xc6" -'!\x8f\xa8\x8d\xd8Y\x86C\xb5\x81\xb1\xb4\xd7_,"\na\xc1%\x8aG\x12\xb4\x9a\xf8' -"z\x11\x1cJ\xa8\x8bu\xc4\x91\t;\xbe\x04\xcaE\xd9W\x8a\r\'\xcb#)(1:p49:\x00" -"\xdc\x9fk\xd9\x98!V\x11\x8d\xe9_\x03\x9d\n\xd3\x93n\x13wA<\x85O\x00p\xfd" -"\x05T\xff\xbc=\t\xbf\x83\xf6\x97\x7fd\x10\x91\x04\xfe\xa2gGTBk)(1:q49:\x00" -"\xcbJK\xd0@G\xe8ER\xf7\xc7\xaf\x0c mC\r\xb69\x94\xf9\xda\xa5\xe5\x03\x06v" -"\x83$\xeb\x88\xa1U\xa2\xa8\xde\x12;wI\x92\x8a\xa9q\xd2\x02\x93\xff)(1:a48:K" -"\xa4_}\xcd\xc2Ie\x1a\xb6i\xb8\x18\x95\xffe\xbfW!\x92\xb5\xaa\x0cu.\r\x9bm" -"\x99\x82^\x11\xf8\x85\x04\x16\xafU\x82\x05\xd5\xd3\xa5e=\x06\xf23)(1:b48:" -"\x17;\xb0\xe4\x99\xa1\xd1g\x02*\xf2?\xe4 \xf6\x8bR\x062wm\x03\x0b\xa5$\xea" -"\xcb\xb77k`\x12p/\xd8\xc8\xec$\r\xa2\x02\x1ey\xc3\xdd|\xa33)(1:c49:\x00\xb4" -"s\x97KP\x10\xa3\x17\xb3\xa8G\xf1:\x14vR\xd18*\xcf\x12\x144\xc1\xa8TL)5\x80" -"\xa08\xb8\xf0\xfaL\xc4\xc2\x85\xab\xdb\x87\x82\xba\xdc\xeb\xdb*)))") - -privateRSA_agentv3 = ("\x00\x00\x00\x07ssh-rsa\x00\x00\x00\x01#\x00\x00\x00`" -"n\x1f\xb5U\x97\xeb\xedg\xed+\x99n\xec\xc1\xed\xa8MR\xd6\xf3\xd6e\x06\x04" -"\xdf\xe5T\x9f\xcc\x89\x00<\x9bg\x87\xece\xa0\xab\xcdoe\x90\x8a\x97\x90M\xc6" -'!\x8f\xa8\x8d\xd8Y\x86C\xb5\x81\xb1\xb4\xd7_,"\na\xc1%\x8aG\x12\xb4\x9a\xf8' -"z\x11\x1cJ\xa8\x8bu\xc4\x91\t;\xbe\x04\xcaE\xd9W\x8a\r\'\xcb#\x00\x00\x00a" -"\x00\xaf2q\xf0\xe6\x0e\x9c\x99\xb3\x7f\x8b_\x04K\xcb\x8b\xc0\xd5>\xb2w\xfd" -"\xcfd\xd8\x8f\xc0\xcf\xae\x1f\xc61\xdf\xf6)\xb2D\x96\xe2\xc6\xd4!\x94\x7fe|" -"\xd8\xd4#\x1f\xb8.j\xc9\x1f\x94\rF\xc1i\xa2\xb7\x07\x0c\xa3\x93\xc14\xd8." -"\x1eJ\x99\x1al\x96F\x07F+\xdc%)\x1b\x87\xf0\xbe\x05\x1d\xee\xb44\xb9\xe7" -"\x99\x95\x00\x00\x001\x00\xb4s\x97KP\x10\xa3\x17\xb3\xa8G\xf1:\x14vR\xd18*" -"\xcf\x12\x144\xc1\xa8TL)5\x80\xa08\xb8\xf0\xfaL\xc4\xc2\x85\xab\xdb\x87\x82" -"\xba\xdc\xeb\xdb*\x00\x00\x001\x00\xcbJK\xd0@G\xe8ER\xf7\xc7\xaf\x0c mC\r" -"\xb69\x94\xf9\xda\xa5\xe5\x03\x06v\x83$\xeb\x88\xa1U\xa2\xa8\xde\x12;wI\x92" -"\x8a\xa9q\xd2\x02\x93\xff\x00\x00\x001\x00\xdc\x9fk\xd9\x98!V\x11\x8d\xe9_" -"\x03\x9d\n\xd3\x93n\x13wA<\x85O\x00p\xfd\x05T\xff\xbc=\t\xbf\x83\xf6\x97" -"\x7fd\x10\x91\x04\xfe\xa2gGTBk") - -publicDSA_openssh = ("ssh-dss AAAAB3NzaC1kc3MAAABBAIbwTOSsZ7Bl7U1KyMNqV13Tu7" -"yRAtTr70PVI3QnfrPumf2UzCgpL1ljbKxSfAi05XvrE/1vfCFAsFYXRZLhQy0AAAAVAM965Akmo" -"6eAi7K+k9qDR4TotFAXAAAAQADZlpTW964haQWS4vC063NGdldT6xpUGDcDRqbm90CoPEa2RmNO" -"uOqi8lnbhYraEzypYH3K4Gzv/bxCBnKtHRUAAABAK+1osyWBS0+P90u/rAuko6chZ98thUSY2kL" -"SHp6hLKyy2bjnT29h7haELE+XHfq2bM9fckDx2FLOSIJzy83VmQ== comment") - -privateDSA_openssh = """-----BEGIN DSA PRIVATE KEY----- -MIH4AgEAAkEAhvBM5KxnsGXtTUrIw2pXXdO7vJEC1OvvQ9UjdCd+s+6Z/ZTMKCkv -WWNsrFJ8CLTle+sT/W98IUCwVhdFkuFDLQIVAM965Akmo6eAi7K+k9qDR4TotFAX -AkAA2ZaU1veuIWkFkuLwtOtzRnZXU+saVBg3A0am5vdAqDxGtkZjTrjqovJZ24WK -2hM8qWB9yuBs7/28QgZyrR0VAkAr7WizJYFLT4/3S7+sC6SjpyFn3y2FRJjaQtIe -nqEsrLLZuOdPb2HuFoQsT5cd+rZsz19yQPHYUs5IgnPLzdWZAhUAl1TqdmlAG/b4 -nnVchGiO9sML8MM= ------END DSA PRIVATE KEY-----""" - -publicDSA_lsh = ("{KDEwOnB1YmxpYy1rZXkoMzpkc2EoMTpwNjU6AIbwTOSsZ7Bl7U1KyMNqV" -"13Tu7yRAtTr70PVI3QnfrPumf2UzCgpL1ljbKxSfAi05XvrE/1vfCFAsFYXRZLhQy0pKDE6cTIx" -"OgDPeuQJJqOngIuyvpPag0eE6LRQFykoMTpnNjQ6ANmWlNb3riFpBZLi8LTrc0Z2V1PrGlQYNwN" -"Gpub3QKg8RrZGY0646qLyWduFitoTPKlgfcrgbO/9vEIGcq0dFSkoMTp5NjQ6K+1osyWBS0+P90" -"u/rAuko6chZ98thUSY2kLSHp6hLKyy2bjnT29h7haELE+XHfq2bM9fckDx2FLOSIJzy83VmSkpK" -"Q==}") - -privateDSA_lsh = ("(11:private-key(3:dsa(1:p65:\x00\x86\xf0L\xe4\xacg\xb0e" -"\xedMJ\xc8\xc3jW]\xd3\xbb\xbc\x91\x02\xd4\xeb\xefC\xd5#t'~\xb3\xee\x99\xfd" -"\x94\xcc()/Ycl\xacR|\x08\xb4\xe5{\xeb\x13\xfdo|!@\xb0V\x17E\x92\xe1C-)(1:q2" -"1:\x00\xcfz\xe4\t&\xa3\xa7\x80\x8b\xb2\xbe\x93\xda\x83G\x84\xe8\xb4P\x17)(1" -":g64:\x00\xd9\x96\x94\xd6\xf7\xae!i\x05\x92\xe2\xf0\xb4\xebsFvWS\xeb\x1aT" -"\x187\x03F\xa6\xe6\xf7@\xa8' prompt - # has been received. (See use in TestOurServerCmdLineClient.setUp) - if self.onOutReceived is not None: - d, self.onOutReceived = self.onOutReceived, None - d.callback(data) - self.buffer += data - self._checkForCommand() - - def _checkForCommand(self): - prompt = 'cftp> ' - if self._expectingCommand and self._lineBuffer == prompt: - buf = '\n'.join(self._linesReceived) - if buf.startswith(prompt): - buf = buf[len(prompt):] - self.clearBuffer() - d, self._expectingCommand = self._expectingCommand, None - d.callback(buf) - - def errReceived(self, data): - """ - Called by Twisted when the cftp client prints data to stderr. - """ - log.msg('err: %s' % data) - - def getBuffer(self): - """ - Return the contents of the buffer of data received from stdout. - """ - return self.buffer - - def runCommand(self, command): - """ - Issue the given command via the cftp client. Return a C{Deferred} that - fires when the server returns a result. Note that the C{Deferred} will - callback even if the server returns some kind of error. - - @param command: A string containing an sftp command. - - @return: A C{Deferred} that fires when the sftp server returns a - result. The payload is the server's response string. - """ - self._expectingCommand = defer.Deferred() - self.clearBuffer() - self.transport.write(command + '\n') - return self._expectingCommand - - def runScript(self, commands): - """ - Run each command in sequence and return a Deferred that fires when all - commands are completed. - - @param commands: A list of strings containing sftp commands. - - @return: A C{Deferred} that fires when all commands are completed. The - payload is a list of response strings from the server, in the same - order as the commands. - """ - sem = defer.DeferredSemaphore(1) - dl = [sem.run(self.runCommand, command) for command in commands] - return defer.gatherResults(dl) - - def killProcess(self): - """ - Kill the process if it is still running. - - If the process is still running, sends a KILL signal to the transport - and returns a C{Deferred} which fires when L{processEnded} is called. - - @return: a C{Deferred}. - """ - if self._processEnded: - return defer.succeed(None) - self.onProcessEnd = defer.Deferred() - self.transport.signalProcess('KILL') - return self.onProcessEnd - - def processEnded(self, reason): - """ - Called by Twisted when the cftp client process ends. - """ - self._processEnded = True - if self.onProcessEnd: - d, self.onProcessEnd = self.onProcessEnd, None - d.callback(None) - - -class CFTPClientTestBase(SFTPTestBase): - def setUp(self): - f = open('dsa_test.pub','w') - f.write(test_ssh.publicDSA_openssh) - f.close() - f = open('dsa_test','w') - f.write(test_ssh.privateDSA_openssh) - f.close() - os.chmod('dsa_test', 33152) - f = open('kh_test','w') - f.write('127.0.0.1 ' + test_ssh.publicRSA_openssh) - f.close() - return SFTPTestBase.setUp(self) - - def startServer(self): - realm = FileTransferTestRealm(self.testDir) - p = portal.Portal(realm) - p.registerChecker(test_ssh.ConchTestPublicKeyChecker()) - fac = test_ssh.ConchTestServerFactory() - fac.portal = p - self.server = reactor.listenTCP(0, fac, interface="127.0.0.1") - - def stopServer(self): - if not hasattr(self.server.factory, 'proto'): - return self._cbStopServer(None) - self.server.factory.proto.expectedLoseConnection = 1 - d = defer.maybeDeferred( - self.server.factory.proto.transport.loseConnection) - d.addCallback(self._cbStopServer) - return d - - def _cbStopServer(self, ignored): - return defer.maybeDeferred(self.server.stopListening) - - def tearDown(self): - for f in ['dsa_test.pub', 'dsa_test', 'kh_test']: - try: - os.remove(f) - except: - pass - return SFTPTestBase.tearDown(self) - - - -class TestOurServerCmdLineClient(CFTPClientTestBase): - - def setUp(self): - CFTPClientTestBase.setUp(self) - - self.startServer() - cmds = ('-p %i -l testuser ' - '--known-hosts kh_test ' - '--user-authentications publickey ' - '--host-key-algorithms ssh-rsa ' - '-K direct ' - '-i dsa_test ' - '-a --nocache ' - '-v ' - '127.0.0.1') - port = self.server.getHost().port - cmds = test_conch._makeArgs((cmds % port).split(), mod='cftp') - log.msg('running %s %s' % (sys.executable, cmds)) - d = defer.Deferred() - self.processProtocol = SFTPTestProcess(d) - d.addCallback(lambda _: self.processProtocol.clearBuffer()) - env = os.environ.copy() - env['PYTHONPATH'] = os.pathsep.join(sys.path) - reactor.spawnProcess(self.processProtocol, sys.executable, cmds, - env=env) - return d - - def tearDown(self): - d = self.stopServer() - d.addCallback(lambda _: self.processProtocol.killProcess()) - return d - - def _killProcess(self, ignored): - try: - self.processProtocol.transport.signalProcess('KILL') - except error.ProcessExitedAlready: - pass - - def runCommand(self, command): - """ - Run the given command with the cftp client. Return a C{Deferred} that - fires when the command is complete. Payload is the server's output for - that command. - """ - return self.processProtocol.runCommand(command) - - def runScript(self, *commands): - """ - Run the given commands with the cftp client. Returns a C{Deferred} - that fires when the commands are all complete. The C{Deferred}'s - payload is a list of output for each command. - """ - return self.processProtocol.runScript(commands) - - def testCdPwd(self): - """ - Test that 'pwd' reports the current remote directory, that 'lpwd' - reports the current local directory, and that changing to a - subdirectory then changing to its parent leaves you in the original - remote directory. - """ - # XXX - not actually a unit test, see docstring. - homeDir = os.path.join(os.getcwd(), self.testDir) - d = self.runScript('pwd', 'lpwd', 'cd testDirectory', 'cd ..', 'pwd') - d.addCallback(lambda xs: xs[:3] + xs[4:]) - d.addCallback(self.assertEqual, - [homeDir, os.getcwd(), '', homeDir]) - return d - - def testChAttrs(self): - """ - Check that 'ls -l' output includes the access permissions and that - this output changes appropriately with 'chmod'. - """ - def _check(results): - self.flushLoggedErrors() - self.assertTrue(results[0].startswith('-rw-r--r--')) - self.assertEqual(results[1], '') - self.assertTrue(results[2].startswith('----------'), results[2]) - self.assertEqual(results[3], '') - - d = self.runScript('ls -l testfile1', 'chmod 0 testfile1', - 'ls -l testfile1', 'chmod 644 testfile1') - return d.addCallback(_check) - # XXX test chgrp/own - - - def testList(self): - """ - Check 'ls' works as expected. Checks for wildcards, hidden files, - listing directories and listing empty directories. - """ - def _check(results): - self.assertEqual(results[0], ['testDirectory', 'testRemoveFile', - 'testRenameFile', 'testfile1']) - self.assertEqual(results[1], ['testDirectory', 'testRemoveFile', - 'testRenameFile', 'testfile1']) - self.assertEqual(results[2], ['testRemoveFile', 'testRenameFile']) - self.assertEqual(results[3], ['.testHiddenFile', 'testRemoveFile', - 'testRenameFile']) - self.assertEqual(results[4], ['']) - d = self.runScript('ls', 'ls ../' + os.path.basename(self.testDir), - 'ls *File', 'ls -a *File', 'ls -l testDirectory') - d.addCallback(lambda xs: [x.split('\n') for x in xs]) - return d.addCallback(_check) - - def testHelp(self): - """ - Check that running the '?' command returns help. - """ - d = self.runCommand('?') - d.addCallback(self.assertEqual, - cftp.StdioClient(None).cmd_HELP('').strip()) - return d - - def assertFilesEqual(self, name1, name2, msg=None): - """ - Assert that the files at C{name1} and C{name2} contain exactly the - same data. - """ - f1 = file(name1).read() - f2 = file(name2).read() - self.failUnlessEqual(f1, f2, msg) - - - def testGet(self): - """ - Test that 'get' saves the remote file to the correct local location, - that the output of 'get' is correct and that 'rm' actually removes - the file. - """ - # XXX - not actually a unit test - expectedOutput = ("Transferred %s/%s/testfile1 to %s/test file2" - % (os.getcwd(), self.testDir, self.testDir)) - def _checkGet(result): - self.assertTrue(result.endswith(expectedOutput)) - self.assertFilesEqual(self.testDir + '/testfile1', - self.testDir + '/test file2', - "get failed") - return self.runCommand('rm "test file2"') - - d = self.runCommand('get testfile1 "%s/test file2"' % (self.testDir,)) - d.addCallback(_checkGet) - d.addCallback(lambda _: self.failIf( - os.path.exists(self.testDir + '/test file2'))) - return d - - - def testWildcardGet(self): - """ - Test that 'get' works correctly when given wildcard parameters. - """ - def _check(ignored): - self.assertFilesEqual(self.testDir + '/testRemoveFile', - 'testRemoveFile', - 'testRemoveFile get failed') - self.assertFilesEqual(self.testDir + '/testRenameFile', - 'testRenameFile', - 'testRenameFile get failed') - - d = self.runCommand('get testR*') - return d.addCallback(_check) - - - def testPut(self): - """ - Check that 'put' uploads files correctly and that they can be - successfully removed. Also check the output of the put command. - """ - # XXX - not actually a unit test - expectedOutput = ('Transferred %s/testfile1 to %s/%s/test"file2' - % (self.testDir, os.getcwd(), self.testDir)) - def _checkPut(result): - self.assertFilesEqual(self.testDir + '/testfile1', - self.testDir + '/test"file2') - self.failUnless(result.endswith(expectedOutput)) - return self.runCommand('rm "test\\"file2"') - - d = self.runCommand('put %s/testfile1 "test\\"file2"' - % (self.testDir,)) - d.addCallback(_checkPut) - d.addCallback(lambda _: self.failIf( - os.path.exists(self.testDir + '/test"file2'))) - return d - - - def testWildcardPut(self): - """ - What happens if you issue a 'put' command and include a wildcard (i.e. - '*') in parameter? Check that all files matching the wildcard are - uploaded to the correct directory. - """ - def check(results): - self.assertEqual(results[0], '') - self.assertEqual(results[2], '') - self.assertFilesEqual(self.testDir + '/testRemoveFile', - self.testDir + '/../testRemoveFile', - 'testRemoveFile get failed') - self.assertFilesEqual(self.testDir + '/testRenameFile', - self.testDir + '/../testRenameFile', - 'testRenameFile get failed') - - d = self.runScript('cd ..', - 'put %s/testR*' % (self.testDir,), - 'cd %s' % os.path.basename(self.testDir)) - d.addCallback(check) - return d - - - def testLink(self): - """ - Test that 'ln' creates a file which appears as a link in the output of - 'ls'. Check that removing the new file succeeds without output. - """ - def _check(results): - self.flushLoggedErrors() - self.assertEqual(results[0], '') - self.assertTrue(results[1].startswith('l'), 'link failed') - return self.runCommand('rm testLink') - - d = self.runScript('ln testLink testfile1', 'ls -l testLink') - d.addCallback(_check) - d.addCallback(self.assertEqual, '') - return d - - - def testRemoteDirectory(self): - """ - Test that we can create and remove directories with the cftp client. - """ - def _check(results): - self.assertEqual(results[0], '') - self.assertTrue(results[1].startswith('d')) - return self.runCommand('rmdir testMakeDirectory') - - d = self.runScript('mkdir testMakeDirectory', - 'ls -l testMakeDirector?') - d.addCallback(_check) - d.addCallback(self.assertEqual, '') - return d - - - def testLocalDirectory(self): - """ - Test that we can create a directory locally and remove it with the - cftp client. This test works because the 'remote' server is running - out of a local directory. - """ - d = self.runCommand('lmkdir %s/testLocalDirectory' % (self.testDir,)) - d.addCallback(self.assertEqual, '') - d.addCallback(lambda _: self.runCommand('rmdir testLocalDirectory')) - d.addCallback(self.assertEqual, '') - return d - - - def testRename(self): - """ - Test that we can rename a file. - """ - def _check(results): - self.assertEqual(results[0], '') - self.assertEqual(results[1], 'testfile2') - return self.runCommand('rename testfile2 testfile1') - - d = self.runScript('rename testfile1 testfile2', 'ls testfile?') - d.addCallback(_check) - d.addCallback(self.assertEqual, '') - return d - - - def testCommand(self): - d = self.runCommand('!echo hello') - return d.addCallback(self.assertEqual, 'hello') - - -class TestOurServerBatchFile(CFTPClientTestBase): - def setUp(self): - CFTPClientTestBase.setUp(self) - self.startServer() - - def tearDown(self): - CFTPClientTestBase.tearDown(self) - return self.stopServer() - - def _getBatchOutput(self, f): - fn = self.mktemp() - open(fn, 'w').write(f) - l = [] - port = self.server.getHost().port - cmds = ('-p %i -l testuser ' - '--known-hosts kh_test ' - '--user-authentications publickey ' - '--host-key-algorithms ssh-rsa ' - '-K direct ' - '-i dsa_test ' - '-a --nocache ' - '-v -b %s 127.0.0.1') % (port, fn) - cmds = test_conch._makeArgs(cmds.split(), mod='cftp')[1:] - log.msg('running %s %s' % (sys.executable, cmds)) - env = os.environ.copy() - env['PYTHONPATH'] = os.pathsep.join(sys.path) - - self.server.factory.expectedLoseConnection = 1 - - d = getProcessOutputAndValue(sys.executable, cmds, env=env) - - def _cleanup(res): - os.remove(fn) - return res - - d.addCallback(lambda res: res[0]) - d.addBoth(_cleanup) - - return d - - def testBatchFile(self): - """Test whether batch file function of cftp ('cftp -b batchfile'). - This works by treating the file as a list of commands to be run. - """ - cmds = """pwd -ls -exit -""" - def _cbCheckResult(res): - res = res.split('\n') - log.msg('RES %s' % str(res)) - self.failUnless(res[1].find(self.testDir) != -1, repr(res)) - self.failUnlessEqual(res[3:-2], ['testDirectory', 'testRemoveFile', - 'testRenameFile', 'testfile1']) - - d = self._getBatchOutput(cmds) - d.addCallback(_cbCheckResult) - return d - - def testError(self): - """Test that an error in the batch file stops running the batch. - """ - cmds = """chown 0 missingFile -pwd -exit -""" - def _cbCheckResult(res): - self.failIf(res.find(self.testDir) != -1) - - d = self._getBatchOutput(cmds) - d.addCallback(_cbCheckResult) - return d - - def testIgnoredError(self): - """Test that a minus sign '-' at the front of a line ignores - any errors. - """ - cmds = """-chown 0 missingFile -pwd -exit -""" - def _cbCheckResult(res): - self.failIf(res.find(self.testDir) == -1) - - d = self._getBatchOutput(cmds) - d.addCallback(_cbCheckResult) - return d - - -class TestOurServerUnixClient(test_conch._UnixFixHome, CFTPClientTestBase): - - def setUp(self): - test_conch._UnixFixHome.setUp(self) - CFTPClientTestBase.setUp(self) - self.startServer() - cmd1 = ('-p %i -l testuser ' - '--known-hosts kh_test ' - '--host-key-algorithms ssh-rsa ' - '-a ' - '-K direct ' - '-i dsa_test ' - '127.0.0.1' - ) - port = self.server.getHost().port - cmds1 = (cmd1 % port).split() - o = options.ConchOptions() - def _(host, *args): - o['host'] = host - o.parseArgs = _ - o.parseOptions(cmds1) - vhk = default.verifyHostKey - self.conn = conn = test_conch.SSHTestConnectionForUnix(None) - uao = default.SSHUserAuthClient(o['user'], o, conn) - return connect.connect(o['host'], int(o['port']), o, vhk, uao) - - def tearDown(self): - CFTPClientTestBase.tearDown(self) - d = defer.maybeDeferred(self.conn.transport.loseConnection) - d.addCallback(lambda x : self.stopServer()) - def clean(ign): - test_conch._UnixFixHome.tearDown(self) - return ign - return defer.gatherResults([d, self.conn.stopDeferred]).addBoth(clean) - - def _getBatchOutput(self, f): - fn = self.mktemp() - open(fn, 'w').write(f) - port = self.server.getHost().port - cmds = ('-p %i -l testuser ' - '-K unix ' - '-a ' - '-v -b %s 127.0.0.1') % (port, fn) - cmds = test_conch._makeArgs(cmds.split(), mod='cftp')[1:] - log.msg('running %s %s' % (sys.executable, cmds)) - env = os.environ.copy() - env['PYTHONPATH'] = os.pathsep.join(sys.path) - - self.server.factory.expectedLoseConnection = 1 - - d = getProcessOutputAndValue(sys.executable, cmds, env=env) - - def _cleanup(res): - os.remove(fn) - return res - - d.addCallback(lambda res: res[0]) - d.addBoth(_cleanup) - - return d - - def testBatchFile(self): - """Test that the client works even over a UNIX connection. - """ - cmds = """pwd -exit -""" - d = self._getBatchOutput(cmds) - d.addCallback( - lambda res : self.failIf(res.find(self.testDir) == -1, - "%s not in %r" % (self.testDir, res))) - return d - - - -class TestOurServerSftpClient(CFTPClientTestBase): - """ - Test the sftp server against sftp command line client. - """ - - def setUp(self): - CFTPClientTestBase.setUp(self) - return self.startServer() - - - def tearDown(self): - return self.stopServer() - - - def test_extendedAttributes(self): - """ - Test the return of extended attributes by the server: the sftp client - should ignore them, but still be able to parse the response correctly. - - This test is mainly here to check that - L{filetransfer.FILEXFER_ATTR_EXTENDED} has the correct value. - """ - fn = self.mktemp() - open(fn, 'w').write("ls .\nexit") - port = self.server.getHost().port - - oldGetAttr = FileTransferForTestAvatar._getAttrs - def _getAttrs(self, s): - attrs = oldGetAttr(self, s) - attrs["ext_foo"] = "bar" - return attrs - - self.patch(FileTransferForTestAvatar, "_getAttrs", _getAttrs) - - self.server.factory.expectedLoseConnection = True - cmds = ('-o', 'IdentityFile=dsa_test', - '-o', 'UserKnownHostsFile=kh_test', - '-o', 'HostKeyAlgorithms=ssh-rsa', - '-o', 'Port=%i' % (port,), '-b', fn, 'testuser@127.0.0.1') - d = getProcessOutputAndValue("sftp", cmds) - def check(result): - self.assertEquals(result[2], 0) - for i in ['testDirectory', 'testRemoveFile', - 'testRenameFile', 'testfile1']: - self.assertIn(i, result[0]) - return d.addCallback(check) - - - -if not unix or not Crypto or not interfaces.IReactorProcess(reactor, None): - TestOurServerCmdLineClient.skip = "don't run w/o spawnprocess or PyCrypto" - TestOurServerBatchFile.skip = "don't run w/o spawnProcess or PyCrypto" - TestOurServerUnixClient.skip = "don't run w/o spawnProcess or PyCrypto" - TestOurServerSftpClient.skip = "don't run w/o spawnProcess or PyCrypto" -else: - from twisted.python.procutils import which - if not which('sftp'): - TestOurServerSftpClient.skip = "no sftp command-line client available" diff --git a/tools/buildbot/pylibs/twisted/conch/test/test_channel.py b/tools/buildbot/pylibs/twisted/conch/test/test_channel.py deleted file mode 100644 index ac3057d..0000000 --- a/tools/buildbot/pylibs/twisted/conch/test/test_channel.py +++ /dev/null @@ -1,279 +0,0 @@ -# Copyright (C) 2007-2008 Twisted Matrix Laboratories -# See LICENSE for details - -""" -Test ssh/channel.py. -""" -from twisted.conch.ssh import channel -from twisted.trial import unittest - - -class MockTransport(object): - """ - A mock Transport. All we use is the getPeer() and getHost() methods. - Channels implement the ITransport interface, and their getPeer() and - getHost() methods return ('SSH', ) so - we need to implement these methods so they have something to draw - from. - """ - def getPeer(self): - return ('MockPeer',) - - def getHost(self): - return ('MockHost',) - - -class MockConnection(object): - """ - A mock for twisted.conch.ssh.connection.SSHConnection. Record the data - that channels send, and when they try to close the connection. - - @ivar data: a C{dict} mapping channel id #s to lists of data sent by that - channel. - @ivar extData: a C{dict} mapping channel id #s to lists of 2-tuples - (extended data type, data) sent by that channel. - @ivar closes: a C{dict} mapping channel id #s to True if that channel sent - a close message. - """ - transport = MockTransport() - - def __init__(self): - self.data = {} - self.extData = {} - self.closes = {} - - def logPrefix(self): - """ - Return our logging prefix. - """ - return "MockConnection" - - def sendData(self, channel, data): - """ - Record the sent data. - """ - self.data.setdefault(channel, []).append(data) - - def sendExtendedData(self, channel, type, data): - """ - Record the sent extended data. - """ - self.extData.setdefault(channel, []).append((type, data)) - - def sendClose(self, channel): - """ - Record that the channel sent a close message. - """ - self.closes[channel] = True - - -class ChannelTestCase(unittest.TestCase): - - def setUp(self): - """ - Initialize the channel. remoteMaxPacket is 10 so that data is able - to be sent (the default of 0 means no data is sent because no packets - are made). - """ - self.conn = MockConnection() - self.channel = channel.SSHChannel(conn=self.conn, - remoteMaxPacket=10) - self.channel.name = 'channel' - - def test_init(self): - """ - Test that SSHChannel initializes correctly. localWindowSize defaults - to 131072 (2**17) and localMaxPacket to 32768 (2**15) as reasonable - defaults (what OpenSSH uses for those variables). - - The values in the second set of assertions are meaningless; they serve - only to verify that the instance variables are assigned in the correct - order. - """ - c = channel.SSHChannel(conn=self.conn) - self.assertEquals(c.localWindowSize, 131072) - self.assertEquals(c.localWindowLeft, 131072) - self.assertEquals(c.localMaxPacket, 32768) - self.assertEquals(c.remoteWindowLeft, 0) - self.assertEquals(c.remoteMaxPacket, 0) - self.assertEquals(c.conn, self.conn) - self.assertEquals(c.data, None) - self.assertEquals(c.avatar, None) - - c2 = channel.SSHChannel(1, 2, 3, 4, 5, 6, 7) - self.assertEquals(c2.localWindowSize, 1) - self.assertEquals(c2.localWindowLeft, 1) - self.assertEquals(c2.localMaxPacket, 2) - self.assertEquals(c2.remoteWindowLeft, 3) - self.assertEquals(c2.remoteMaxPacket, 4) - self.assertEquals(c2.conn, 5) - self.assertEquals(c2.data, 6) - self.assertEquals(c2.avatar, 7) - - def test_str(self): - """ - Test that str(SSHChannel) works gives the channel name and local and - remote windows at a glance.. - """ - self.assertEquals(str(self.channel), '') - - def test_logPrefix(self): - """ - Test that SSHChannel.logPrefix gives the name of the channel, the - local channel ID and the underlying connection. - """ - self.assertEquals(self.channel.logPrefix(), 'SSHChannel channel ' - '(unknown) on MockConnection') - - def test_addWindowBytes(self): - """ - Test that addWindowBytes adds bytes to the window and resumes writing - if it was paused. - """ - cb = [False] - def stubStartWriting(): - cb[0] = True - self.channel.startWriting = stubStartWriting - self.channel.write('test') - self.channel.writeExtended(1, 'test') - self.channel.addWindowBytes(50) - self.assertEquals(self.channel.remoteWindowLeft, 50 - 4 - 4) - self.assertTrue(self.channel.areWriting) - self.assertTrue(cb[0]) - self.assertEquals(self.channel.buf, '') - self.assertEquals(self.conn.data[self.channel], ['test']) - self.assertEquals(self.channel.extBuf, []) - self.assertEquals(self.conn.extData[self.channel], [(1, 'test')]) - - cb[0] = False - self.channel.addWindowBytes(20) - self.assertFalse(cb[0]) - - self.channel.write('a'*80) - self.channel.loseConnection() - self.channel.addWindowBytes(20) - self.assertFalse(cb[0]) - - def test_requestReceived(self): - """ - Test that requestReceived handles requests by dispatching them to - request_* methods. - """ - self.channel.request_test_method = lambda data: data == '' - self.assertTrue(self.channel.requestReceived('test-method', '')) - self.assertFalse(self.channel.requestReceived('test-method', 'a')) - self.assertFalse(self.channel.requestReceived('bad-method', '')) - - def test_closeReceieved(self): - """ - Test that the default closeReceieved closes the connection. - """ - self.assertFalse(self.channel.closing) - self.channel.closeReceived() - self.assertTrue(self.channel.closing) - - def test_write(self): - """ - Test that write handles data correctly. Send data up to the size - of the remote window, splitting the data into packets of length - remoteMaxPacket. - """ - cb = [False] - def stubStopWriting(): - cb[0] = True - # no window to start with - self.channel.stopWriting = stubStopWriting - self.channel.write('d') - self.channel.write('a') - self.assertFalse(self.channel.areWriting) - self.assertTrue(cb[0]) - # regular write - self.channel.addWindowBytes(20) - self.channel.write('ta') - data = self.conn.data[self.channel] - self.assertEquals(data, ['da', 'ta']) - self.assertEquals(self.channel.remoteWindowLeft, 16) - # larger than max packet - self.channel.write('12345678901') - self.assertEquals(data, ['da', 'ta', '1234567890', '1']) - self.assertEquals(self.channel.remoteWindowLeft, 5) - # running out of window - cb[0] = False - self.channel.write('123456') - self.assertFalse(self.channel.areWriting) - self.assertTrue(cb[0]) - self.assertEquals(data, ['da', 'ta', '1234567890', '1', '12345']) - self.assertEquals(self.channel.buf, '6') - self.assertEquals(self.channel.remoteWindowLeft, 0) - - def test_writeExtended(self): - """ - Test that writeExtended handles data correctly. Send extended data - up to the size of the window, splitting the extended data into packets - of length remoteMaxPacket. - """ - cb = [False] - def stubStopWriting(): - cb[0] = True - # no window to start with - self.channel.stopWriting = stubStopWriting - self.channel.writeExtended(1, 'd') - self.channel.writeExtended(1, 'a') - self.channel.writeExtended(2, 't') - self.assertFalse(self.channel.areWriting) - self.assertTrue(cb[0]) - # regular write - self.channel.addWindowBytes(20) - self.channel.writeExtended(2, 'a') - data = self.conn.extData[self.channel] - self.assertEquals(data, [(1, 'da'), (2, 't'), (2, 'a')]) - self.assertEquals(self.channel.remoteWindowLeft, 16) - # larger than max packet - self.channel.writeExtended(3, '12345678901') - self.assertEquals(data, [(1, 'da'), (2, 't'), (2, 'a'), - (3, '1234567890'), (3, '1')]) - self.assertEquals(self.channel.remoteWindowLeft, 5) - # running out of window - cb[0] = False - self.channel.writeExtended(4, '123456') - self.assertFalse(self.channel.areWriting) - self.assertTrue(cb[0]) - self.assertEquals(data, [(1, 'da'), (2, 't'), (2, 'a'), - (3, '1234567890'), (3, '1'), (4, '12345')]) - self.assertEquals(self.channel.extBuf, [[4, '6']]) - self.assertEquals(self.channel.remoteWindowLeft, 0) - - def test_writeSequence(self): - """ - Test that writeSequence is equivalent to write(''.join(sequece)). - """ - self.channel.addWindowBytes(20) - self.channel.writeSequence(map(str, range(10))) - self.assertEquals(self.conn.data[self.channel], ['0123456789']) - - def test_loseConnection(self): - """ - Tesyt that loseConnection() doesn't close the channel until all - the data is sent. - """ - self.channel.write('data') - self.channel.writeExtended(1, 'datadata') - self.channel.loseConnection() - self.assertEquals(self.conn.closes.get(self.channel), None) - self.channel.addWindowBytes(4) # send regular data - self.assertEquals(self.conn.closes.get(self.channel), None) - self.channel.addWindowBytes(8) # send extended data - self.assertTrue(self.conn.closes.get(self.channel)) - - def test_getPeer(self): - """ - Test that getPeer() returns ('SSH', ). - """ - self.assertEquals(self.channel.getPeer(), ('SSH', 'MockPeer')) - - def test_getHost(self): - """ - Test that getHost() returns ('SSH', ). - """ - self.assertEquals(self.channel.getHost(), ('SSH', 'MockHost')) diff --git a/tools/buildbot/pylibs/twisted/conch/test/test_conch.py b/tools/buildbot/pylibs/twisted/conch/test/test_conch.py deleted file mode 100644 index 308b1d9..0000000 --- a/tools/buildbot/pylibs/twisted/conch/test/test_conch.py +++ /dev/null @@ -1,594 +0,0 @@ -# -*- test-case-name: twisted.conch.test.test_conch -*- -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -import os, sys - -try: - import Crypto -except: - Crypto = None - -from twisted.cred import portal -from twisted.internet import reactor, defer, protocol -from twisted.internet.error import ProcessExitedAlready -from twisted.python import log, runtime -from twisted.python.filepath import FilePath -from twisted.trial import unittest -from twisted.conch.error import ConchError -from twisted.conch.test.test_ssh import ConchTestRealm -from twisted.python.procutils import which - -from twisted.conch.test.keydata import publicRSA_openssh, privateRSA_openssh -from twisted.conch.test.keydata import publicDSA_openssh, privateDSA_openssh - - - -class Echo(protocol.Protocol): - def connectionMade(self): - log.msg('ECHO CONNECTION MADE') - - - def connectionLost(self, reason): - log.msg('ECHO CONNECTION DONE') - - - def dataReceived(self, data): - self.transport.write(data) - if '\n' in data: - self.transport.loseConnection() - - - -class EchoFactory(protocol.Factory): - protocol = Echo - - - -class ConchTestOpenSSHProcess(protocol.ProcessProtocol): - """ - Test protocol for launching an OpenSSH client process. - - @ivar deferred: Set by whatever uses this object. Accessed using - L{_getDeferred}, which destroys the value so the Deferred is not - fired twice. Fires when the process is terminated. - """ - - deferred = None - buf = '' - - def _getDeferred(self): - d, self.deferred = self.deferred, None - return d - - - def outReceived(self, data): - self.buf += data - - - def processEnded(self, reason): - """ - Called when the process has ended. - - @param reason: a Failure giving the reason for the process' end. - """ - if reason.value.exitCode != 0: - self._getDeferred().errback( - ConchError("exit code was not 0: %s" % - reason.value.exitCode)) - else: - buf = self.buf.replace('\r\n', '\n') - self._getDeferred().callback(buf) - - - -class ConchTestForwardingProcess(protocol.ProcessProtocol): - """ - Manages a third-party process which launches a server. - - Uses L{ConchTestForwardingPort} to connect to the third-party server. - Once L{ConchTestForwardingPort} has disconnected, kill the process and fire - a Deferred with the data received by the L{ConchTestForwardingPort}. - - @ivar deferred: Set by whatever uses this object. Accessed using - L{_getDeferred}, which destroys the value so the Deferred is not - fired twice. Fires when the process is terminated. - """ - - deferred = None - - def __init__(self, port, data): - """ - @type port: C{int} - @param port: The port on which the third-party server is listening. - (it is assumed that the server is running on localhost). - - @type data: C{str} - @param data: This is sent to the third-party server. Must end with '\n' - in order to trigger a disconnect. - """ - self.port = port - self.buffer = None - self.data = data - - - def _getDeferred(self): - d, self.deferred = self.deferred, None - return d - - - def connectionMade(self): - self._connect() - - - def _connect(self): - """ - Connect to the server, which is often a third-party process. - Tries to reconnect if it fails because we have no way of determining - exactly when the port becomes available for listening -- we can only - know when the process starts. - """ - cc = protocol.ClientCreator(reactor, ConchTestForwardingPort, self, - self.data) - d = cc.connectTCP('127.0.0.1', self.port) - d.addErrback(self._ebConnect) - return d - - - def _ebConnect(self, f): - reactor.callLater(1, self._connect) - - - def forwardingPortDisconnected(self, buffer): - """ - The network connection has died; save the buffer of output - from the network and attempt to quit the process gracefully, - and then (after the reactor has spun) send it a KILL signal. - """ - self.buffer = buffer - self.transport.write('\x03') - self.transport.loseConnection() - reactor.callLater(0, self._reallyDie) - - - def _reallyDie(self): - try: - self.transport.signalProcess('KILL') - except ProcessExitedAlready: - pass - - - def processEnded(self, reason): - """ - Fire the Deferred at self.deferred with the data collected - from the L{ConchTestForwardingPort} connection, if any. - """ - self._getDeferred().callback(self.buffer) - - - -class ConchTestForwardingPort(protocol.Protocol): - """ - Connects to server launched by a third-party process (managed by - L{ConchTestForwardingProcess}) sends data, then reports whatever it - received back to the L{ConchTestForwardingProcess} once the connection - is ended. - """ - - - def __init__(self, protocol, data): - """ - @type protocol: L{ConchTestForwardingProcess} - @param protocol: The L{ProcessProtocol} which made this connection. - - @type data: str - @param data: The data to be sent to the third-party server. - """ - self.protocol = protocol - self.data = data - - - def connectionMade(self): - self.buffer = '' - self.transport.write(self.data) - - - def dataReceived(self, data): - self.buffer += data - - - def connectionLost(self, reason): - self.protocol.forwardingPortDisconnected(self.buffer) - - - -if Crypto: - from twisted.conch.client import options, default, connect - from twisted.conch.ssh import forwarding - from twisted.conch.ssh import connection - - from twisted.conch.test.test_ssh import ConchTestServerFactory - from twisted.conch.test.test_ssh import ConchTestPublicKeyChecker - - - class SSHTestConnectionForUnix(connection.SSHConnection): - """ - @ivar stopDeferred: Deferred that will be fired when C{serviceStopped} - is called. - @type stopDeferred: C{defer.Deferred} - """ - - def __init__(self, p, exe=None, cmds=None): - connection.SSHConnection.__init__(self) - if p: - self.spawn = (p, exe, cmds) - else: - self.spawn = None - self.connected = 0 - self.remoteForwards = {} - self.stopDeferred = defer.Deferred() - - def serviceStopped(self): - self.stopDeferred.callback(None) - - def serviceStarted(self): - if self.spawn: - env = os.environ.copy() - env['PYTHONPATH'] = os.pathsep.join(sys.path) - reactor.callLater(0,reactor.spawnProcess, env=env, *self.spawn) - self.connected = 1 - - def requestRemoteForwarding(self, remotePort, hostport): - data = forwarding.packGlobal_tcpip_forward(('0.0.0.0', remotePort)) - d = self.sendGlobalRequest('tcpip-forward', data, - wantReply=1) - log.msg('requesting remote forwarding %s:%s' %(remotePort, hostport)) - d.addCallback(self._cbRemoteForwarding, remotePort, hostport) - d.addErrback(self._ebRemoteForwarding, remotePort, hostport) - - def _cbRemoteForwarding(self, result, remotePort, hostport): - log.msg('accepted remote forwarding %s:%s' % (remotePort, hostport)) - self.remoteForwards[remotePort] = hostport - log.msg(repr(self.remoteForwards)) - - def _ebRemoteForwarding(self, f, remotePort, hostport): - log.msg('remote forwarding %s:%s failed' % (remotePort, hostport)) - log.msg(f) - - def cancelRemoteForwarding(self, remotePort): - data = forwarding.packGlobal_tcpip_forward(('0.0.0.0', remotePort)) - self.sendGlobalRequest('cancel-tcpip-forward', data) - log.msg('cancelling remote forwarding %s' % remotePort) - try: - del self.remoteForwards[remotePort] - except: - pass - log.msg(repr(self.remoteForwards)) - - def channel_forwarded_tcpip(self, windowSize, maxPacket, data): - log.msg('%s %s' % ('FTCP', repr(data))) - remoteHP, origHP = forwarding.unpackOpen_forwarded_tcpip(data) - log.msg(self.remoteForwards) - log.msg(remoteHP) - if self.remoteForwards.has_key(remoteHP[1]): - connectHP = self.remoteForwards[remoteHP[1]] - log.msg('connect forwarding %s' % (connectHP,)) - return forwarding.SSHConnectForwardingChannel(connectHP, - remoteWindow = windowSize, - remoteMaxPacket = maxPacket, - conn = self) - else: - raise ConchError(connection.OPEN_CONNECT_FAILED, "don't know about that port") - - - -def _makeArgs(args, mod="conch"): - start = [sys.executable, '-c' -""" -### Twisted Preamble -import sys, os -path = os.path.abspath(sys.argv[0]) -while os.path.dirname(path) != path: - if os.path.basename(path).startswith('Twisted'): - sys.path.insert(0, path) - break - path = os.path.dirname(path) - -from twisted.conch.scripts.%s import run -run()""" % mod] - return start + list(args) - - - -class ForwardingTestBase: - """ - Template class for tests of the Conch server's ability to forward arbitrary - protocols over SSH. - - These tests are integration tests, not unit tests. They launch a Conch - server, a custom TCP server (just an L{EchoProtocol}) and then call - L{execute}. - - L{execute} is implemented by subclasses of L{ForwardingTestBase}. It should - cause an SSH client to connect to the Conch server, asking it to forward - data to the custom TCP server. - """ - - if not Crypto: - skip = "can't run w/o PyCrypto" - - def _createFiles(self): - for f in ['rsa_test','rsa_test.pub','dsa_test','dsa_test.pub', - 'kh_test']: - if os.path.exists(f): - os.remove(f) - open('rsa_test','w').write(privateRSA_openssh) - open('rsa_test.pub','w').write(publicRSA_openssh) - open('dsa_test.pub','w').write(publicDSA_openssh) - open('dsa_test','w').write(privateDSA_openssh) - os.chmod('dsa_test', 33152) - os.chmod('rsa_test', 33152) - open('kh_test','w').write('127.0.0.1 '+publicRSA_openssh) - - - def _getFreePort(self): - f = EchoFactory() - serv = reactor.listenTCP(0, f) - port = serv.getHost().port - serv.stopListening() - return port - - - def _makeConchFactory(self): - """ - Make a L{ConchTestServerFactory}, which allows us to start a - L{ConchTestServer} -- i.e. an actually listening conch. - """ - realm = ConchTestRealm() - p = portal.Portal(realm) - p.registerChecker(ConchTestPublicKeyChecker()) - factory = ConchTestServerFactory() - factory.portal = p - return factory - - - def setUp(self): - self._createFiles() - self.conchFactory = self._makeConchFactory() - self.conchFactory.expectedLoseConnection = 1 - self.conchServer = reactor.listenTCP(0, self.conchFactory, - interface="127.0.0.1") - self.echoServer = reactor.listenTCP(0, EchoFactory()) - self.echoPort = self.echoServer.getHost().port - - - def tearDown(self): - try: - self.conchFactory.proto.done = 1 - except AttributeError: - pass - else: - self.conchFactory.proto.transport.loseConnection() - return defer.gatherResults([ - defer.maybeDeferred(self.conchServer.stopListening), - defer.maybeDeferred(self.echoServer.stopListening)]) - - - def test_exec(self): - """ - Test that we can use whatever client to send the command "echo goodbye" - to the Conch server. Make sure we receive "goodbye" back from the - server. - """ - d = self.execute('echo goodbye', ConchTestOpenSSHProcess()) - return d.addCallback(self.assertEquals, 'goodbye\n') - - - def test_localToRemoteForwarding(self): - """ - Test that we can use whatever client to forward a local port to a - specified port on the server. - """ - lport = self._getFreePort() - process = ConchTestForwardingProcess(lport, 'test\n') - d = self.execute('', process, - sshArgs='-N -L%i:127.0.0.1:%i' - % (lport, self.echoPort)) - d.addCallback(self.assertEqual, 'test\n') - return d - - - def test_remoteToLocalForwarding(self): - """ - Test that we can use whatever client to forward a port from the server - to a port locally. - """ - localPort = self._getFreePort() - process = ConchTestForwardingProcess(localPort, 'test\n') - d = self.execute('', process, - sshArgs='-N -R %i:127.0.0.1:%i' - % (localPort, self.echoPort)) - d.addCallback(self.assertEqual, 'test\n') - return d - - - -class OpenSSHClientTestCase(ForwardingTestBase, unittest.TestCase): - - def execute(self, remoteCommand, process, sshArgs=''): - """ - Connects to the SSH server started in L{ForwardingTestBase.setUp} by - running the 'ssh' command line tool. - - @type remoteCommand: str - @param remoteCommand: The command (with arguments) to run on the - remote end. - - @type process: L{ConchTestOpenSSHProcess} - - @type sshArgs: str - @param sshArgs: Arguments to pass to the 'ssh' process. - - @return: L{defer.Deferred} - """ - process.deferred = defer.Deferred() - cmdline = ('ssh -2 -l testuser -p %i ' - '-oUserKnownHostsFile=kh_test ' - '-oPasswordAuthentication=no ' - # Always use the RSA key, since that's the one in kh_test. - '-oHostKeyAlgorithms=ssh-rsa ' - '-a ' - '-i dsa_test ') + sshArgs + \ - ' 127.0.0.1 ' + remoteCommand - port = self.conchServer.getHost().port - cmds = (cmdline % port).split() - reactor.spawnProcess(process, "ssh", cmds) - return process.deferred - - - -class CmdLineClientTestCase(ForwardingTestBase, unittest.TestCase): - def setUp(self): - if runtime.platformType == 'win32': - raise unittest.SkipTest("can't run cmdline client on win32") - ForwardingTestBase.setUp(self) - - - def execute(self, remoteCommand, process, sshArgs=''): - """ - As for L{OpenSSHClientTestCase.execute}, except it runs the 'conch' - command line tool, not 'ssh'. - """ - process.deferred = defer.Deferred() - port = self.conchServer.getHost().port - cmd = ('-p %i -l testuser ' - '--known-hosts kh_test ' - '--user-authentications publickey ' - '--host-key-algorithms ssh-rsa ' - '-a -I ' - '-K direct ' - '-i dsa_test ' - '-v ') % port + sshArgs + \ - ' 127.0.0.1 ' + remoteCommand - cmds = _makeArgs(cmd.split()) - log.msg(str(cmds)) - env = os.environ.copy() - env['PYTHONPATH'] = os.pathsep.join(sys.path) - reactor.spawnProcess(process, sys.executable, cmds, env=env) - return process.deferred - - - -class _UnixFixHome(object): - """ - Mixin class to fix the HOME environment variable to something usable. - - @ivar home: FilePath pointing at C{homePath}. - @type home: L{FilePath} - - @ivar homePath: relative path to the directory used as HOME during the - tests. - @type homePath: C{str} - """ - - def setUp(self): - path = self.mktemp() - self.home = FilePath(path) - self.homePath = os.path.join(*self.home.segmentsFrom(FilePath("."))) - if len(self.home.path) >= 70: - # UNIX_MAX_PATH is 108, and the socket file is generally of length - # 30, so we can't rely on mktemp... - self.homePath = "_tmp" - self.home = FilePath(self.homePath) - self.home.makedirs() - self.savedEnviron = os.environ.copy() - os.environ["HOME"] = self.homePath - - - def tearDown(self): - os.environ.clear() - os.environ.update(self.savedEnviron) - self.home.remove() - - - -class UnixClientTestCase(_UnixFixHome, ForwardingTestBase, unittest.TestCase): - def setUp(self): - if runtime.platformType == 'win32': - raise unittest.SkipTest("can't run cmdline client on win32") - ForwardingTestBase.setUp(self) - _UnixFixHome.setUp(self) - - - def tearDown(self): - d1 = ForwardingTestBase.tearDown(self) - d2 = defer.maybeDeferred(self.conn.transport.transport.loseConnection) - d3 = self.conn.stopDeferred - def clean(ign): - _UnixFixHome.tearDown(self) - return ign - return defer.gatherResults([d1, d2, d3]).addBoth(clean) - - - def makeOptions(self): - o = options.ConchOptions() - def parseArgs(host, *args): - o['host'] = host - o.parseArgs = parseArgs - return o - - - def makeAuthClient(self, port, options): - cmds = (('-p %i -l testuser ' - '--known-hosts kh_test ' - '--user-authentications publickey ' - '--host-key-algorithms ssh-rsa ' - '-a ' - '-K direct ' - '-i dsa_test ' - '127.0.0.1') % port).split() - options.parseOptions(cmds) - return default.SSHUserAuthClient(options['user'], options, self.conn) - - - def execute(self, remoteCommand, process, sshArgs=''): - """ - Connect to the forwarding process using the 'unix' client found in - L{twisted.conch.client.unix.connect}. See - L{OpenSSHClientTestCase.execute}. - """ - process.deferred = defer.Deferred() - port = self.conchServer.getHost().port - cmd = ('-p %i -l testuser ' - '-K unix ' - '-v ') % port + sshArgs + \ - ' 127.0.0.1 ' + remoteCommand - cmds = _makeArgs(cmd.split()) - options = self.makeOptions() - self.conn = SSHTestConnectionForUnix(process, sys.executable, cmds) - authClient = self.makeAuthClient(port, options) - d = connect.connect(options['host'], port, options, - default.verifyHostKey, authClient) - return d.addCallback(lambda x : process.deferred) - - - def test_noHome(self): - """ - When setting the HOME environment variable to a path that doesn't - exist, L{connect.connect} should forward the failure, and the created - process should fail with a L{ConchError}. - """ - path = self.mktemp() - # We override the HOME variable, and let tearDown restore the initial - # value - os.environ['HOME'] = path - process = ConchTestOpenSSHProcess() - d = self.execute('echo goodbye', process) - def cb(ign): - return self.assertFailure(process.deferred, ConchError) - return self.assertFailure(d, OSError).addCallback(cb) - - - -if not which('ssh'): - OpenSSHClientTestCase.skip = "no ssh command-line client available" diff --git a/tools/buildbot/pylibs/twisted/conch/test/test_connection.py b/tools/buildbot/pylibs/twisted/conch/test/test_connection.py deleted file mode 100644 index b055188..0000000 --- a/tools/buildbot/pylibs/twisted/conch/test/test_connection.py +++ /dev/null @@ -1,615 +0,0 @@ -# Copyright (c) 2007 Twisted Matrix Laboratories. -# See LICENSE for details - -""" -This module tests twisted.conch.ssh.connection. -""" -import struct -from twisted.conch import error -from twisted.conch.ssh import channel, common, connection -from twisted.trial import unittest -from twisted.conch.test import test_userauth - -class TestChannel(channel.SSHChannel): - """ - A mocked-up version of twisted.conch.ssh.channel.SSHChannel. - - @ivar gotOpen: True if channelOpen has been called. - @type gotOpen: C{bool} - @ivar specificData: the specific channel open data passed to channelOpen. - @type specificData: C{str} - @ivar openFailureReason: the reason passed to openFailed. - @type openFailed: C{error.ConchError} - @ivar inBuffer: a C{list} of strings received by the channel. - @type inBuffer: C{list} - @ivar extBuffer: a C{list} of 2-tuples (type, extended data) of received by - the channel. - @type extBuffer: C{list} - @ivar numberRequests: the number of requests that have been made to this - channel. - @type numberRequests: C{int} - @ivar gotEOF: True if the other side sent EOF. - @type gotEOF: C{bool} - @ivar gotOneClose: True if the other side closed the connection. - @type gotOneClose: C{bool} - @ivar gotClosed: True if the channel is closed. - @type gotClosed: C{bool} - """ - name = "TestChannel" - gotOpen = False - - def logPrefix(self): - return "TestChannel %i" % self.id - - def channelOpen(self, specificData): - """ - The channel is open. Set up the instance variables. - """ - self.gotOpen = True - self.specificData = specificData - self.inBuffer = [] - self.extBuffer = [] - self.numberRequests = 0 - self.gotEOF = False - self.gotOneClose = False - self.gotClosed = False - - def openFailed(self, reason): - """ - Opening the channel failed. Store the reason why. - """ - self.openFailureReason = reason - - def request_test(self, data): - """ - A test request. Return True if data is 'data'. - - @type data: C{str} - """ - self.numberRequests += 1 - return data == 'data' - - def dataReceived(self, data): - """ - Data was received. Store it in the buffer. - """ - self.inBuffer.append(data) - - def extReceived(self, code, data): - """ - Extended data was received. Store it in the buffer. - """ - self.extBuffer.append((code, data)) - - def eofReceived(self): - """ - EOF was received. Remember it. - """ - self.gotEOF = True - - def closeReceived(self): - """ - Close was received. Remember it. - """ - self.gotOneClose = True - - def closed(self): - """ - The channel is closed. Rembember it. - """ - self.gotClosed = True - -class TestAvatar: - """ - A mocked-up version of twisted.conch.avatar.ConchUser - """ - - def lookupChannel(self, channelType, windowSize, maxPacket, data): - """ - The server wants us to return a channel. If the requested channel is - our TestChannel, return it, otherwise return None. - """ - if channelType == TestChannel.name: - return TestChannel(remoteWindow=windowSize, - remoteMaxPacket=maxPacket, - data=data, avatar=self) - - def gotGlobalRequest(self, requestType, data): - """ - The client has made a global request. If the global request is - 'TestGlobal', return True. If the global request is 'TestData', - return True and the request-specific data we received. Otherwise, - return False. - """ - if requestType == 'TestGlobal': - return True - elif requestType == 'TestData': - return True, data - else: - return False - -class TestConnection(connection.SSHConnection): - """ - A subclass of SSHConnection for testing. - - @ivar channel: the current channel. - @type channel. C{TestChannel} - """ - - def logPrefix(self): - return "TestConnection" - - def global_TestGlobal(self, data): - """ - The other side made the 'TestGlobal' global request. Return True. - """ - return True - - def global_Test_Data(self, data): - """ - The other side made the 'Test-Data' global request. Return True and - the data we received. - """ - return True, data - - def channel_TestChannel(self, windowSize, maxPacket, data): - """ - The other side is requesting the TestChannel. Create a C{TestChannel} - instance, store it, and return it. - """ - self.channel = TestChannel(remoteWindow=windowSize, - remoteMaxPacket=maxPacket, data=data) - return self.channel - - def channel_ErrorChannel(self, windowSize, maxPacket, data): - """ - The other side is requesting the ErrorChannel. Raise an exception. - """ - raise AssertionError('no such thing') - -class ConnectionTestCase(unittest.TestCase): - - def setUp(self): - self.transport = test_userauth.FakeTransport(None) - self.transport.avatar = TestAvatar() - self.conn = TestConnection() - self.conn.transport = self.transport - self.conn.serviceStarted() - - def _openChannel(self, channel): - """ - Open the channel with the default connection. - """ - self.conn.openChannel(channel) - self.transport.packets = self.transport.packets[:-1] - self.conn.ssh_CHANNEL_OPEN_CONFIRMATION(struct.pack('>2L', - channel.id, 255) + '\x00\x02\x00\x00\x00\x00\x80\x00') - - def tearDown(self): - self.conn.serviceStopped() - - def test_linkAvatar(self): - """ - Test that the connection links itself to the avatar in the - transport. - """ - self.assertIdentical(self.transport.avatar.conn, self.conn) - - def test_serviceStopped(self): - """ - Test that serviceStopped() closes any open channels. - """ - channel1 = TestChannel() - channel2 = TestChannel() - self.conn.openChannel(channel1) - self.conn.openChannel(channel2) - self.conn.ssh_CHANNEL_OPEN_CONFIRMATION('\x00\x00\x00\x00' * 4) - self.assertTrue(channel1.gotOpen) - self.assertFalse(channel2.gotOpen) - self.conn.serviceStopped() - self.assertTrue(channel1.gotClosed) - - def test_GLOBAL_REQUEST(self): - """ - Test that global request packets are dispatched to the global_* - methods and the return values are translated into success or failure - messages. - """ - self.conn.ssh_GLOBAL_REQUEST(common.NS('TestGlobal') + '\xff') - self.assertEquals(self.transport.packets, - [(connection.MSG_REQUEST_SUCCESS, '')]) - self.transport.packets = [] - self.conn.ssh_GLOBAL_REQUEST(common.NS('TestData') + '\xff' + - 'test data') - self.assertEquals(self.transport.packets, - [(connection.MSG_REQUEST_SUCCESS, 'test data')]) - self.transport.packets = [] - self.conn.ssh_GLOBAL_REQUEST(common.NS('TestBad') + '\xff') - self.assertEquals(self.transport.packets, - [(connection.MSG_REQUEST_FAILURE, '')]) - self.transport.packets = [] - self.conn.ssh_GLOBAL_REQUEST(common.NS('TestGlobal') + '\x00') - self.assertEquals(self.transport.packets, []) - - def test_REQUEST_SUCCESS(self): - """ - Test that global request success packets cause the Deferred to be - called back. - """ - d = self.conn.sendGlobalRequest('request', 'data', True) - self.conn.ssh_REQUEST_SUCCESS('data') - def check(data): - self.assertEquals(data, 'data') - d.addCallback(check) - d.addErrback(self.fail) - return d - - def test_REQUEST_FAILURE(self): - """ - Test that global request failure packets cause the Deferred to be - erred back. - """ - d = self.conn.sendGlobalRequest('request', 'data', True) - self.conn.ssh_REQUEST_FAILURE('data') - def check(f): - self.assertEquals(f.value.data, 'data') - d.addCallback(self.fail) - d.addErrback(check) - return d - - def test_CHANNEL_OPEN(self): - """ - Test that open channel packets cause a channel to be created and - opened or a failure message to be returned. - """ - del self.transport.avatar - self.conn.ssh_CHANNEL_OPEN(common.NS('TestChannel') + - '\x00\x00\x00\x01' * 4) - self.assertTrue(self.conn.channel.gotOpen) - self.assertEquals(self.conn.channel.conn, self.conn) - self.assertEquals(self.conn.channel.data, '\x00\x00\x00\x01') - self.assertEquals(self.conn.channel.specificData, '\x00\x00\x00\x01') - self.assertEquals(self.conn.channel.remoteWindowLeft, 1) - self.assertEquals(self.conn.channel.remoteMaxPacket, 1) - self.assertEquals(self.transport.packets, - [(connection.MSG_CHANNEL_OPEN_CONFIRMATION, - '\x00\x00\x00\x01\x00\x00\x00\x00\x00\x02\x00\x00' - '\x00\x00\x80\x00')]) - self.transport.packets = [] - self.conn.ssh_CHANNEL_OPEN(common.NS('BadChannel') + - '\x00\x00\x00\x02' * 4) - self.flushLoggedErrors() - self.assertEquals(self.transport.packets, - [(connection.MSG_CHANNEL_OPEN_FAILURE, - '\x00\x00\x00\x02\x00\x00\x00\x03' + common.NS( - 'unknown channel') + common.NS(''))]) - self.transport.packets = [] - self.conn.ssh_CHANNEL_OPEN(common.NS('ErrorChannel') + - '\x00\x00\x00\x02' * 4) - self.flushLoggedErrors() - self.assertEquals(self.transport.packets, - [(connection.MSG_CHANNEL_OPEN_FAILURE, - '\x00\x00\x00\x02\x00\x00\x00\x02' + common.NS( - 'unknown failure') + common.NS(''))]) - - def test_CHANNEL_OPEN_CONFIRMATION(self): - """ - Test that channel open confirmation packets cause the channel to be - notified that it's open. - """ - channel = TestChannel() - self.conn.openChannel(channel) - self.conn.ssh_CHANNEL_OPEN_CONFIRMATION('\x00\x00\x00\x00'*5) - self.assertEquals(channel.remoteWindowLeft, 0) - self.assertEquals(channel.remoteMaxPacket, 0) - self.assertEquals(channel.specificData, '\x00\x00\x00\x00') - self.assertEquals(self.conn.channelsToRemoteChannel[channel], - 0) - self.assertEquals(self.conn.localToRemoteChannel[0], 0) - - def test_CHANNEL_OPEN_FAILURE(self): - """ - Test that channel open failure packets cause the channel to be - notified that its opening failed. - """ - channel = TestChannel() - self.conn.openChannel(channel) - self.conn.ssh_CHANNEL_OPEN_FAILURE('\x00\x00\x00\x00\x00\x00\x00' - '\x01' + common.NS('failure!')) - self.assertEquals(channel.openFailureReason.args, ('failure!', 1)) - self.assertEquals(self.conn.channels.get(channel), None) - - - def test_CHANNEL_WINDOW_ADJUST(self): - """ - Test that channel window adjust messages add bytes to the channel - window. - """ - channel = TestChannel() - self._openChannel(channel) - oldWindowSize = channel.remoteWindowLeft - self.conn.ssh_CHANNEL_WINDOW_ADJUST('\x00\x00\x00\x00\x00\x00\x00' - '\x01') - self.assertEquals(channel.remoteWindowLeft, oldWindowSize + 1) - - def test_CHANNEL_DATA(self): - """ - Test that channel data messages are passed up to the channel, or - cause the channel to be closed if the data is too large. - """ - channel = TestChannel(localWindow=6, localMaxPacket=5) - self._openChannel(channel) - self.conn.ssh_CHANNEL_DATA('\x00\x00\x00\x00' + common.NS('data')) - self.assertEquals(channel.inBuffer, ['data']) - self.assertEquals(self.transport.packets, - [(connection.MSG_CHANNEL_WINDOW_ADJUST, '\x00\x00\x00\xff' - '\x00\x00\x00\x04')]) - self.transport.packets = [] - longData = 'a' * (channel.localWindowLeft + 1) - self.conn.ssh_CHANNEL_DATA('\x00\x00\x00\x00' + common.NS(longData)) - self.assertEquals(channel.inBuffer, ['data']) - self.assertEquals(self.transport.packets, - [(connection.MSG_CHANNEL_CLOSE, '\x00\x00\x00\xff')]) - channel = TestChannel() - self._openChannel(channel) - bigData = 'a' * (channel.localMaxPacket + 1) - self.transport.packets = [] - self.conn.ssh_CHANNEL_DATA('\x00\x00\x00\x01' + common.NS(bigData)) - self.assertEquals(channel.inBuffer, []) - self.assertEquals(self.transport.packets, - [(connection.MSG_CHANNEL_CLOSE, '\x00\x00\x00\xff')]) - - def test_CHANNEL_EXTENDED_DATA(self): - """ - Test that channel extended data messages are passed up to the channel, - or cause the channel to be closed if they're too big. - """ - channel = TestChannel(localWindow=6, localMaxPacket=5) - self._openChannel(channel) - self.conn.ssh_CHANNEL_EXTENDED_DATA('\x00\x00\x00\x00\x00\x00\x00' - '\x00' + common.NS('data')) - self.assertEquals(channel.extBuffer, [(0, 'data')]) - self.assertEquals(self.transport.packets, - [(connection.MSG_CHANNEL_WINDOW_ADJUST, '\x00\x00\x00\xff' - '\x00\x00\x00\x04')]) - self.transport.packets = [] - longData = 'a' * (channel.localWindowLeft + 1) - self.conn.ssh_CHANNEL_EXTENDED_DATA('\x00\x00\x00\x00\x00\x00\x00' - '\x00' + common.NS(longData)) - self.assertEquals(channel.extBuffer, [(0, 'data')]) - self.assertEquals(self.transport.packets, - [(connection.MSG_CHANNEL_CLOSE, '\x00\x00\x00\xff')]) - channel = TestChannel() - self._openChannel(channel) - bigData = 'a' * (channel.localMaxPacket + 1) - self.transport.packets = [] - self.conn.ssh_CHANNEL_EXTENDED_DATA('\x00\x00\x00\x01\x00\x00\x00' - '\x00' + common.NS(bigData)) - self.assertEquals(channel.extBuffer, []) - self.assertEquals(self.transport.packets, - [(connection.MSG_CHANNEL_CLOSE, '\x00\x00\x00\xff')]) - - def test_CHANNEL_EOF(self): - """ - Test that channel eof messages are passed up to the channel. - """ - channel = TestChannel() - self._openChannel(channel) - self.conn.ssh_CHANNEL_EOF('\x00\x00\x00\x00') - self.assertTrue(channel.gotEOF) - - def test_CHANNEL_CLOSE(self): - """ - Test that channel close messages are passed up to the channel. Also, - test that channel.close() is called if both sides are closed when this - message is received. - """ - channel = TestChannel() - self._openChannel(channel) - self.conn.sendClose(channel) - self.conn.ssh_CHANNEL_CLOSE('\x00\x00\x00\x00') - self.assertTrue(channel.gotOneClose) - self.assertTrue(channel.gotClosed) - - def test_CHANNEL_REQUEST_success(self): - """ - Test that channel requests that succeed send MSG_CHANNEL_SUCCESS. - """ - channel = TestChannel() - self._openChannel(channel) - self.conn.ssh_CHANNEL_REQUEST('\x00\x00\x00\x00' + common.NS('test') - + '\x00') - self.assertEquals(channel.numberRequests, 1) - d = self.conn.ssh_CHANNEL_REQUEST('\x00\x00\x00\x00' + common.NS( - 'test') + '\xff' + 'data') - def check(result): - self.assertEquals(self.transport.packets, - [(connection.MSG_CHANNEL_SUCCESS, '\x00\x00\x00\xff')]) - d.addCallback(check) - return d - - def test_CHANNEL_REQUEST_failure(self): - """ - Test that channel requests that fail send MSG_CHANNEL_FAILURE. - """ - channel = TestChannel() - self._openChannel(channel) - d = self.conn.ssh_CHANNEL_REQUEST('\x00\x00\x00\x00' + common.NS( - 'test') + '\xff') - def check(result): - self.assertEquals(self.transport.packets, - [(connection.MSG_CHANNEL_FAILURE, '\x00\x00\x00\xff' - )]) - d.addCallback(self.fail) - d.addErrback(check) - return d - - def test_CHANNEL_REQUEST_SUCCESS(self): - """ - Test that channel request success messages cause the Deferred to be - called back. - """ - channel = TestChannel() - self._openChannel(channel) - d = self.conn.sendRequest(channel, 'test', 'data', True) - self.conn.ssh_CHANNEL_SUCCESS('\x00\x00\x00\x00') - def check(result): - self.assertTrue(result) - return d - - def test_CHANNEL_REQUEST_FAILURE(self): - """ - Test that channel request failure messages cause the Deferred to be - erred back. - """ - channel = TestChannel() - self._openChannel(channel) - d = self.conn.sendRequest(channel, 'test', '', True) - self.conn.ssh_CHANNEL_FAILURE('\x00\x00\x00\x00') - def check(result): - self.assertEquals(result.value.value, 'channel request failed') - d.addCallback(self.fail) - d.addErrback(check) - return d - - def test_sendGlobalRequest(self): - """ - Test that global request messages are sent in the right format. - """ - d = self.conn.sendGlobalRequest('wantReply', 'data', True) - self.conn.sendGlobalRequest('noReply', '', False) - self.assertEquals(self.transport.packets, - [(connection.MSG_GLOBAL_REQUEST, common.NS('wantReply') + - '\xffdata'), - (connection.MSG_GLOBAL_REQUEST, common.NS('noReply') + - '\x00')]) - self.assertEquals(self.conn.deferreds, {'global':[d]}) - - def test_openChannel(self): - """ - Test that open channel messages are sent in the right format. - """ - channel = TestChannel() - self.conn.openChannel(channel, 'aaaa') - self.assertEquals(self.transport.packets, - [(connection.MSG_CHANNEL_OPEN, common.NS('TestChannel') + - '\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x80\x00aaaa')]) - self.assertEquals(channel.id, 0) - self.assertEquals(self.conn.localChannelID, 1) - - def test_sendRequest(self): - """ - Test that channel request messages are sent in the right format. - """ - channel = TestChannel() - self._openChannel(channel) - d = self.conn.sendRequest(channel, 'test', 'test', True) - self.conn.sendRequest(channel, 'test2', '', False) - channel.localClosed = True # emulate sending a close message - self.conn.sendRequest(channel, 'test3', '', True) - self.assertEquals(self.transport.packets, - [(connection.MSG_CHANNEL_REQUEST, '\x00\x00\x00\xff' + - common.NS('test') + '\x01test'), - (connection.MSG_CHANNEL_REQUEST, '\x00\x00\x00\xff' + - common.NS('test2') + '\x00')]) - self.assertEquals(self.conn.deferreds, {0:[d]}) - - def test_adjustWindow(self): - """ - Test that channel window adjust messages cause bytes to be added - to the window. - """ - channel = TestChannel(localWindow=5) - self._openChannel(channel) - channel.localWindowLeft = 0 - self.conn.adjustWindow(channel, 1) - self.assertEquals(channel.localWindowLeft, 1) - channel.localClosed = True - self.conn.adjustWindow(channel, 2) - self.assertEquals(channel.localWindowLeft, 1) - self.assertEquals(self.transport.packets, - [(connection.MSG_CHANNEL_WINDOW_ADJUST, '\x00\x00\x00\xff' - '\x00\x00\x00\x01')]) - - def test_sendData(self): - """ - Test that channel data messages are sent in the right format. - """ - channel = TestChannel() - self._openChannel(channel) - self.conn.sendData(channel, 'a') - channel.localClosed = True - self.conn.sendData(channel, 'b') - self.assertEquals(self.transport.packets, - [(connection.MSG_CHANNEL_DATA, '\x00\x00\x00\xff' + - common.NS('a'))]) - - def test_sendExtendedData(self): - """ - Test that channel extended data messages are sent in the right format. - """ - channel = TestChannel() - self._openChannel(channel) - self.conn.sendExtendedData(channel, 1, 'test') - channel.localClosed = True - self.conn.sendExtendedData(channel, 2, 'test2') - self.assertEquals(self.transport.packets, - [(connection.MSG_CHANNEL_EXTENDED_DATA, '\x00\x00\x00\xff' + - '\x00\x00\x00\x01' + common.NS('test'))]) - - def test_sendEOF(self): - """ - Test that channel EOF messages are sent in the right format. - """ - channel = TestChannel() - self._openChannel(channel) - self.conn.sendEOF(channel) - self.assertEquals(self.transport.packets, - [(connection.MSG_CHANNEL_EOF, '\x00\x00\x00\xff')]) - channel.localClosed = True - self.conn.sendEOF(channel) - self.assertEquals(self.transport.packets, - [(connection.MSG_CHANNEL_EOF, '\x00\x00\x00\xff')]) - - def test_sendClose(self): - """ - Test that channel close messages are sent in the right format. - """ - channel = TestChannel() - self._openChannel(channel) - self.conn.sendClose(channel) - self.assertTrue(channel.localClosed) - self.assertEquals(self.transport.packets, - [(connection.MSG_CHANNEL_CLOSE, '\x00\x00\x00\xff')]) - self.conn.sendClose(channel) - self.assertEquals(self.transport.packets, - [(connection.MSG_CHANNEL_CLOSE, '\x00\x00\x00\xff')]) - - channel2 = TestChannel() - self._openChannel(channel2) - channel2.remoteClosed = True - self.conn.sendClose(channel2) - self.assertTrue(channel2.gotClosed) - - def test_getChannelWithAvatar(self): - """ - Test that getChannel dispatches to the avatar when an avatar is - present. Correct functioning without the avatar is verified in - test_CHANNEL_OPEN. - """ - channel = self.conn.getChannel('TestChannel', 50, 30, 'data') - self.assertEquals(channel.data, 'data') - self.assertEquals(channel.remoteWindowLeft, 50) - self.assertEquals(channel.remoteMaxPacket, 30) - self.assertRaises(error.ConchError, self.conn.getChannel, - 'BadChannel', 50, 30, 'data') - - def test_gotGlobalRequestWithoutAvatar(self): - """ - Test that gotGlobalRequests dispatches to global_* without an avatar. - """ - del self.transport.avatar - self.assertTrue(self.conn.gotGlobalRequest('TestGlobal', 'data')) - self.assertEquals(self.conn.gotGlobalRequest('Test-Data', 'data'), - (True, 'data')) - self.assertFalse(self.conn.gotGlobalRequest('BadGlobal', 'data')) diff --git a/tools/buildbot/pylibs/twisted/conch/test/test_filetransfer.py b/tools/buildbot/pylibs/twisted/conch/test/test_filetransfer.py deleted file mode 100644 index a779169..0000000 --- a/tools/buildbot/pylibs/twisted/conch/test/test_filetransfer.py +++ /dev/null @@ -1,513 +0,0 @@ -# -*- test-case-name: twisted.conch.test.test_filetransfer -*- -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE file for details. - - -import os -import struct -import sys - -from twisted.trial import unittest -try: - from twisted.conch import unix - unix # shut up pyflakes -except ImportError: - unix = None - try: - del sys.modules['twisted.conch.unix'] # remove the bad import - except KeyError: - # In Python 2.4, the bad import has already been cleaned up for us. - # Hooray. - pass - -from twisted.conch import avatar -from twisted.conch.ssh import common, connection, filetransfer, session -from twisted.internet import defer -from twisted.protocols import loopback -from twisted.python import components - - -class TestAvatar(avatar.ConchUser): - def __init__(self): - avatar.ConchUser.__init__(self) - self.channelLookup['session'] = session.SSHSession - self.subsystemLookup['sftp'] = filetransfer.FileTransferServer - - def _runAsUser(self, f, *args, **kw): - try: - f = iter(f) - except TypeError: - f = [(f, args, kw)] - for i in f: - func = i[0] - args = len(i)>1 and i[1] or () - kw = len(i)>2 and i[2] or {} - r = func(*args, **kw) - return r - - -class FileTransferTestAvatar(TestAvatar): - - def __init__(self, homeDir): - TestAvatar.__init__(self) - self.homeDir = homeDir - - def getHomeDir(self): - return os.path.join(os.getcwd(), self.homeDir) - - -class ConchSessionForTestAvatar: - - def __init__(self, avatar): - self.avatar = avatar - -if unix: - if not hasattr(unix, 'SFTPServerForUnixConchUser'): - # unix should either be a fully working module, or None. I'm not sure - # how this happens, but on win32 it does. Try to cope. --spiv. - import warnings - warnings.warn(("twisted.conch.unix imported %r, " - "but doesn't define SFTPServerForUnixConchUser'") - % (unix,)) - unix = None - else: - class FileTransferForTestAvatar(unix.SFTPServerForUnixConchUser): - - def gotVersion(self, version, otherExt): - return {'conchTest' : 'ext data'} - - def extendedRequest(self, extName, extData): - if extName == 'testExtendedRequest': - return 'bar' - raise NotImplementedError - - components.registerAdapter(FileTransferForTestAvatar, - TestAvatar, - filetransfer.ISFTPServer) - -class SFTPTestBase(unittest.TestCase): - - def setUp(self): - self.testDir = self.mktemp() - # Give the testDir another level so we can safely "cd .." from it in - # tests. - self.testDir = os.path.join(self.testDir, 'extra') - os.makedirs(os.path.join(self.testDir, 'testDirectory')) - - f = file(os.path.join(self.testDir, 'testfile1'),'w') - f.write('a'*10+'b'*10) - f.write(file('/dev/urandom').read(1024*64)) # random data - os.chmod(os.path.join(self.testDir, 'testfile1'), 0644) - file(os.path.join(self.testDir, 'testRemoveFile'), 'w').write('a') - file(os.path.join(self.testDir, 'testRenameFile'), 'w').write('a') - file(os.path.join(self.testDir, '.testHiddenFile'), 'w').write('a') - - -class TestOurServerOurClient(SFTPTestBase): - - if not unix: - skip = "can't run on non-posix computers" - - def setUp(self): - SFTPTestBase.setUp(self) - - self.avatar = FileTransferTestAvatar(self.testDir) - self.server = filetransfer.FileTransferServer(avatar=self.avatar) - clientTransport = loopback.LoopbackRelay(self.server) - - self.client = filetransfer.FileTransferClient() - self._serverVersion = None - self._extData = None - def _(serverVersion, extData): - self._serverVersion = serverVersion - self._extData = extData - self.client.gotServerVersion = _ - serverTransport = loopback.LoopbackRelay(self.client) - self.client.makeConnection(clientTransport) - self.server.makeConnection(serverTransport) - - self.clientTransport = clientTransport - self.serverTransport = serverTransport - - self._emptyBuffers() - - - def _emptyBuffers(self): - while self.serverTransport.buffer or self.clientTransport.buffer: - self.serverTransport.clearBuffer() - self.clientTransport.clearBuffer() - - - def testServerVersion(self): - self.failUnlessEqual(self._serverVersion, 3) - self.failUnlessEqual(self._extData, {'conchTest' : 'ext data'}) - - def testOpenFileIO(self): - d = self.client.openFile("testfile1", filetransfer.FXF_READ | - filetransfer.FXF_WRITE, {}) - self._emptyBuffers() - - def _fileOpened(openFile): - self.failUnlessEqual(openFile, filetransfer.ISFTPFile(openFile)) - d = _readChunk(openFile) - d.addCallback(_writeChunk, openFile) - return d - - def _readChunk(openFile): - d = openFile.readChunk(0, 20) - self._emptyBuffers() - d.addCallback(self.failUnlessEqual, 'a'*10 + 'b'*10) - return d - - def _writeChunk(_, openFile): - d = openFile.writeChunk(20, 'c'*10) - self._emptyBuffers() - d.addCallback(_readChunk2, openFile) - return d - - def _readChunk2(_, openFile): - d = openFile.readChunk(0, 30) - self._emptyBuffers() - d.addCallback(self.failUnlessEqual, 'a'*10 + 'b'*10 + 'c'*10) - return d - - d.addCallback(_fileOpened) - return d - - def testClosedFileGetAttrs(self): - d = self.client.openFile("testfile1", filetransfer.FXF_READ | - filetransfer.FXF_WRITE, {}) - self._emptyBuffers() - - def _getAttrs(_, openFile): - d = openFile.getAttrs() - self._emptyBuffers() - return d - - def _err(f): - self.flushLoggedErrors() - return f - - def _close(openFile): - d = openFile.close() - self._emptyBuffers() - d.addCallback(_getAttrs, openFile) - d.addErrback(_err) - return self.assertFailure(d, filetransfer.SFTPError) - - d.addCallback(_close) - return d - - def testOpenFileAttributes(self): - d = self.client.openFile("testfile1", filetransfer.FXF_READ | - filetransfer.FXF_WRITE, {}) - self._emptyBuffers() - - def _getAttrs(openFile): - d = openFile.getAttrs() - self._emptyBuffers() - d.addCallback(_getAttrs2) - return d - - def _getAttrs2(attrs1): - d = self.client.getAttrs('testfile1') - self._emptyBuffers() - d.addCallback(self.failUnlessEqual, attrs1) - return d - - return d.addCallback(_getAttrs) - - - def testOpenFileSetAttrs(self): - # XXX test setAttrs - # Ok, how about this for a start? It caught a bug :) -- spiv. - d = self.client.openFile("testfile1", filetransfer.FXF_READ | - filetransfer.FXF_WRITE, {}) - self._emptyBuffers() - - def _getAttrs(openFile): - d = openFile.getAttrs() - self._emptyBuffers() - d.addCallback(_setAttrs) - return d - - def _setAttrs(attrs): - attrs['atime'] = 0 - d = self.client.setAttrs('testfile1', attrs) - self._emptyBuffers() - d.addCallback(_getAttrs2) - d.addCallback(self.failUnlessEqual, attrs) - return d - - def _getAttrs2(_): - d = self.client.getAttrs('testfile1') - self._emptyBuffers() - return d - - d.addCallback(_getAttrs) - return d - - - def test_openFileExtendedAttributes(self): - """ - Check that L{filetransfer.FileTransferClient.openFile} can send - extended attributes, that should be extracted server side. By default, - they are ignored, so we just verify they are correctly parsed. - """ - savedAttributes = {} - def openFile(filename, flags, attrs): - savedAttributes.update(attrs) - self.server.client.openFile = openFile - - d = self.client.openFile("testfile1", filetransfer.FXF_READ | - filetransfer.FXF_WRITE, {"ext_foo": "bar"}) - self._emptyBuffers() - - def check(ign): - self.assertEquals(savedAttributes, {"ext_foo": "bar"}) - - return d.addCallback(check) - - - def testRemoveFile(self): - d = self.client.getAttrs("testRemoveFile") - self._emptyBuffers() - def _removeFile(ignored): - d = self.client.removeFile("testRemoveFile") - self._emptyBuffers() - return d - d.addCallback(_removeFile) - d.addCallback(_removeFile) - return self.assertFailure(d, filetransfer.SFTPError) - - def testRenameFile(self): - d = self.client.getAttrs("testRenameFile") - self._emptyBuffers() - def _rename(attrs): - d = self.client.renameFile("testRenameFile", "testRenamedFile") - self._emptyBuffers() - d.addCallback(_testRenamed, attrs) - return d - def _testRenamed(_, attrs): - d = self.client.getAttrs("testRenamedFile") - self._emptyBuffers() - d.addCallback(self.failUnlessEqual, attrs) - return d.addCallback(_rename) - - def testDirectoryBad(self): - d = self.client.getAttrs("testMakeDirectory") - self._emptyBuffers() - return self.assertFailure(d, filetransfer.SFTPError) - - def testDirectoryCreation(self): - d = self.client.makeDirectory("testMakeDirectory", {}) - self._emptyBuffers() - - def _getAttrs(_): - d = self.client.getAttrs("testMakeDirectory") - self._emptyBuffers() - return d - - # XXX not until version 4/5 - # self.failUnlessEqual(filetransfer.FILEXFER_TYPE_DIRECTORY&attrs['type'], - # filetransfer.FILEXFER_TYPE_DIRECTORY) - - def _removeDirectory(_): - d = self.client.removeDirectory("testMakeDirectory") - self._emptyBuffers() - return d - - d.addCallback(_getAttrs) - d.addCallback(_removeDirectory) - d.addCallback(_getAttrs) - return self.assertFailure(d, filetransfer.SFTPError) - - def testOpenDirectory(self): - d = self.client.openDirectory('') - self._emptyBuffers() - files = [] - - def _getFiles(openDir): - def append(f): - files.append(f) - return openDir - d = defer.maybeDeferred(openDir.next) - self._emptyBuffers() - d.addCallback(append) - d.addCallback(_getFiles) - d.addErrback(_close, openDir) - return d - - def _checkFiles(ignored): - fs = list(zip(*files)[0]) - fs.sort() - self.failUnlessEqual(fs, - ['.testHiddenFile', 'testDirectory', - 'testRemoveFile', 'testRenameFile', - 'testfile1']) - - def _close(_, openDir): - d = openDir.close() - self._emptyBuffers() - return d - - d.addCallback(_getFiles) - d.addCallback(_checkFiles) - return d - - def testLinkDoesntExist(self): - d = self.client.getAttrs('testLink') - self._emptyBuffers() - return self.assertFailure(d, filetransfer.SFTPError) - - def testLinkSharesAttrs(self): - d = self.client.makeLink('testLink', 'testfile1') - self._emptyBuffers() - def _getFirstAttrs(_): - d = self.client.getAttrs('testLink', 1) - self._emptyBuffers() - return d - def _getSecondAttrs(firstAttrs): - d = self.client.getAttrs('testfile1') - self._emptyBuffers() - d.addCallback(self.assertEqual, firstAttrs) - return d - d.addCallback(_getFirstAttrs) - return d.addCallback(_getSecondAttrs) - - def testLinkPath(self): - d = self.client.makeLink('testLink', 'testfile1') - self._emptyBuffers() - def _readLink(_): - d = self.client.readLink('testLink') - self._emptyBuffers() - d.addCallback(self.failUnlessEqual, - os.path.join(os.getcwd(), self.testDir, 'testfile1')) - return d - def _realPath(_): - d = self.client.realPath('testLink') - self._emptyBuffers() - d.addCallback(self.failUnlessEqual, - os.path.join(os.getcwd(), self.testDir, 'testfile1')) - return d - d.addCallback(_readLink) - d.addCallback(_realPath) - return d - - def testExtendedRequest(self): - d = self.client.extendedRequest('testExtendedRequest', 'foo') - self._emptyBuffers() - d.addCallback(self.failUnlessEqual, 'bar') - d.addCallback(self._cbTestExtendedRequest) - return d - - def _cbTestExtendedRequest(self, ignored): - d = self.client.extendedRequest('testBadRequest', '') - self._emptyBuffers() - return self.assertFailure(d, NotImplementedError) - - -class FakeConn: - def sendClose(self, channel): - pass - - -class TestFileTransferClose(unittest.TestCase): - - if not unix: - skip = "can't run on non-posix computers" - - def setUp(self): - self.avatar = TestAvatar() - - def buildServerConnection(self): - # make a server connection - conn = connection.SSHConnection() - # server connections have a 'self.transport.avatar'. - class DummyTransport: - def __init__(self): - self.transport = self - def sendPacket(self, kind, data): - pass - def logPrefix(self): - return 'dummy transport' - conn.transport = DummyTransport() - conn.transport.avatar = self.avatar - return conn - - def interceptConnectionLost(self, sftpServer): - self.connectionLostFired = False - origConnectionLost = sftpServer.connectionLost - def connectionLost(reason): - self.connectionLostFired = True - origConnectionLost(reason) - sftpServer.connectionLost = connectionLost - - def assertSFTPConnectionLost(self): - self.assertTrue(self.connectionLostFired, - "sftpServer's connectionLost was not called") - - def test_sessionClose(self): - """ - Closing a session should notify an SFTP subsystem launched by that - session. - """ - # make a session - testSession = session.SSHSession(conn=FakeConn(), avatar=self.avatar) - - # start an SFTP subsystem on the session - testSession.request_subsystem(common.NS('sftp')) - sftpServer = testSession.client.transport.proto - - # intercept connectionLost so we can check that it's called - self.interceptConnectionLost(sftpServer) - - # close session - testSession.closeReceived() - - self.assertSFTPConnectionLost() - - def test_clientClosesChannelOnConnnection(self): - """ - A client sending CHANNEL_CLOSE should trigger closeReceived on the - associated channel instance. - """ - conn = self.buildServerConnection() - - # somehow get a session - packet = common.NS('session') + struct.pack('>L', 0) * 3 - conn.ssh_CHANNEL_OPEN(packet) - sessionChannel = conn.channels[0] - - sessionChannel.request_subsystem(common.NS('sftp')) - sftpServer = sessionChannel.client.transport.proto - self.interceptConnectionLost(sftpServer) - - # intercept closeReceived - self.interceptConnectionLost(sftpServer) - - # close the connection - conn.ssh_CHANNEL_CLOSE(struct.pack('>L', 0)) - - self.assertSFTPConnectionLost() - - - def test_stopConnectionServiceClosesChannel(self): - """ - Closing an SSH connection should close all sessions within it. - """ - conn = self.buildServerConnection() - - # somehow get a session - packet = common.NS('session') + struct.pack('>L', 0) * 3 - conn.ssh_CHANNEL_OPEN(packet) - sessionChannel = conn.channels[0] - - sessionChannel.request_subsystem(common.NS('sftp')) - sftpServer = sessionChannel.client.transport.proto - self.interceptConnectionLost(sftpServer) - - # close the connection - conn.serviceStopped() - - self.assertSFTPConnectionLost() diff --git a/tools/buildbot/pylibs/twisted/conch/test/test_helper.py b/tools/buildbot/pylibs/twisted/conch/test/test_helper.py deleted file mode 100644 index 95db6ab..0000000 --- a/tools/buildbot/pylibs/twisted/conch/test/test_helper.py +++ /dev/null @@ -1,560 +0,0 @@ -# -*- test-case-name: twisted.conch.test.test_helper -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.conch.insults import helper -from twisted.conch.insults.insults import G0, G1, G2, G3 -from twisted.conch.insults.insults import modes, privateModes -from twisted.conch.insults.insults import NORMAL, BOLD, UNDERLINE, BLINK, REVERSE_VIDEO - -from twisted.trial import unittest - -WIDTH = 80 -HEIGHT = 24 - -class BufferTestCase(unittest.TestCase): - def setUp(self): - self.term = helper.TerminalBuffer() - self.term.connectionMade() - - def testInitialState(self): - self.assertEquals(self.term.width, WIDTH) - self.assertEquals(self.term.height, HEIGHT) - self.assertEquals(str(self.term), - '\n' * (HEIGHT - 1)) - self.assertEquals(self.term.reportCursorPosition(), (0, 0)) - - - def test_initialPrivateModes(self): - """ - Verify that only DEC Auto Wrap Mode (DECAWM) and DEC Text Cursor Enable - Mode (DECTCEM) are initially in the Set Mode (SM) state. - """ - self.assertEqual( - {privateModes.AUTO_WRAP: True, - privateModes.CURSOR_MODE: True}, - self.term.privateModes) - - - def test_carriageReturn(self): - """ - C{"\r"} moves the cursor to the first column in the current row. - """ - self.term.cursorForward(5) - self.term.cursorDown(3) - self.assertEqual(self.term.reportCursorPosition(), (5, 3)) - self.term.insertAtCursor("\r") - self.assertEqual(self.term.reportCursorPosition(), (0, 3)) - - - def test_linefeed(self): - """ - C{"\n"} moves the cursor to the next row without changing the column. - """ - self.term.cursorForward(5) - self.assertEqual(self.term.reportCursorPosition(), (5, 0)) - self.term.insertAtCursor("\n") - self.assertEqual(self.term.reportCursorPosition(), (5, 1)) - - - def test_newline(self): - """ - C{write} transforms C{"\n"} into C{"\r\n"}. - """ - self.term.cursorForward(5) - self.term.cursorDown(3) - self.assertEqual(self.term.reportCursorPosition(), (5, 3)) - self.term.write("\n") - self.assertEqual(self.term.reportCursorPosition(), (0, 4)) - - - def test_setPrivateModes(self): - """ - Verify that L{helper.TerminalBuffer.setPrivateModes} changes the Set - Mode (SM) state to "set" for the private modes it is passed. - """ - expected = self.term.privateModes.copy() - self.term.setPrivateModes([privateModes.SCROLL, privateModes.SCREEN]) - expected[privateModes.SCROLL] = True - expected[privateModes.SCREEN] = True - self.assertEqual(expected, self.term.privateModes) - - - def test_resetPrivateModes(self): - """ - Verify that L{helper.TerminalBuffer.resetPrivateModes} changes the Set - Mode (SM) state to "reset" for the private modes it is passed. - """ - expected = self.term.privateModes.copy() - self.term.resetPrivateModes([privateModes.AUTO_WRAP, privateModes.CURSOR_MODE]) - del expected[privateModes.AUTO_WRAP] - del expected[privateModes.CURSOR_MODE] - self.assertEqual(expected, self.term.privateModes) - - - def testCursorDown(self): - self.term.cursorDown(3) - self.assertEquals(self.term.reportCursorPosition(), (0, 3)) - self.term.cursorDown() - self.assertEquals(self.term.reportCursorPosition(), (0, 4)) - self.term.cursorDown(HEIGHT) - self.assertEquals(self.term.reportCursorPosition(), (0, HEIGHT - 1)) - - def testCursorUp(self): - self.term.cursorUp(5) - self.assertEquals(self.term.reportCursorPosition(), (0, 0)) - - self.term.cursorDown(20) - self.term.cursorUp(1) - self.assertEquals(self.term.reportCursorPosition(), (0, 19)) - - self.term.cursorUp(19) - self.assertEquals(self.term.reportCursorPosition(), (0, 0)) - - def testCursorForward(self): - self.term.cursorForward(2) - self.assertEquals(self.term.reportCursorPosition(), (2, 0)) - self.term.cursorForward(2) - self.assertEquals(self.term.reportCursorPosition(), (4, 0)) - self.term.cursorForward(WIDTH) - self.assertEquals(self.term.reportCursorPosition(), (WIDTH, 0)) - - def testCursorBackward(self): - self.term.cursorForward(10) - self.term.cursorBackward(2) - self.assertEquals(self.term.reportCursorPosition(), (8, 0)) - self.term.cursorBackward(7) - self.assertEquals(self.term.reportCursorPosition(), (1, 0)) - self.term.cursorBackward(1) - self.assertEquals(self.term.reportCursorPosition(), (0, 0)) - self.term.cursorBackward(1) - self.assertEquals(self.term.reportCursorPosition(), (0, 0)) - - def testCursorPositioning(self): - self.term.cursorPosition(3, 9) - self.assertEquals(self.term.reportCursorPosition(), (3, 9)) - - def testSimpleWriting(self): - s = "Hello, world." - self.term.write(s) - self.assertEquals( - str(self.term), - s + '\n' + - '\n' * (HEIGHT - 2)) - - def testOvertype(self): - s = "hello, world." - self.term.write(s) - self.term.cursorBackward(len(s)) - self.term.resetModes([modes.IRM]) - self.term.write("H") - self.assertEquals( - str(self.term), - ("H" + s[1:]) + '\n' + - '\n' * (HEIGHT - 2)) - - def testInsert(self): - s = "ello, world." - self.term.write(s) - self.term.cursorBackward(len(s)) - self.term.setModes([modes.IRM]) - self.term.write("H") - self.assertEquals( - str(self.term), - ("H" + s) + '\n' + - '\n' * (HEIGHT - 2)) - - def testWritingInTheMiddle(self): - s = "Hello, world." - self.term.cursorDown(5) - self.term.cursorForward(5) - self.term.write(s) - self.assertEquals( - str(self.term), - '\n' * 5 + - (self.term.fill * 5) + s + '\n' + - '\n' * (HEIGHT - 7)) - - def testWritingWrappedAtEndOfLine(self): - s = "Hello, world." - self.term.cursorForward(WIDTH - 5) - self.term.write(s) - self.assertEquals( - str(self.term), - s[:5].rjust(WIDTH) + '\n' + - s[5:] + '\n' + - '\n' * (HEIGHT - 3)) - - def testIndex(self): - self.term.index() - self.assertEquals(self.term.reportCursorPosition(), (0, 1)) - self.term.cursorDown(HEIGHT) - self.assertEquals(self.term.reportCursorPosition(), (0, HEIGHT - 1)) - self.term.index() - self.assertEquals(self.term.reportCursorPosition(), (0, HEIGHT - 1)) - - def testReverseIndex(self): - self.term.reverseIndex() - self.assertEquals(self.term.reportCursorPosition(), (0, 0)) - self.term.cursorDown(2) - self.assertEquals(self.term.reportCursorPosition(), (0, 2)) - self.term.reverseIndex() - self.assertEquals(self.term.reportCursorPosition(), (0, 1)) - - def test_nextLine(self): - """ - C{nextLine} positions the cursor at the beginning of the row below the - current row. - """ - self.term.nextLine() - self.assertEquals(self.term.reportCursorPosition(), (0, 1)) - self.term.cursorForward(5) - self.assertEquals(self.term.reportCursorPosition(), (5, 1)) - self.term.nextLine() - self.assertEquals(self.term.reportCursorPosition(), (0, 2)) - - def testSaveCursor(self): - self.term.cursorDown(5) - self.term.cursorForward(7) - self.assertEquals(self.term.reportCursorPosition(), (7, 5)) - self.term.saveCursor() - self.term.cursorDown(7) - self.term.cursorBackward(3) - self.assertEquals(self.term.reportCursorPosition(), (4, 12)) - self.term.restoreCursor() - self.assertEquals(self.term.reportCursorPosition(), (7, 5)) - - def testSingleShifts(self): - self.term.singleShift2() - self.term.write('Hi') - - ch = self.term.getCharacter(0, 0) - self.assertEquals(ch[0], 'H') - self.assertEquals(ch[1].charset, G2) - - ch = self.term.getCharacter(1, 0) - self.assertEquals(ch[0], 'i') - self.assertEquals(ch[1].charset, G0) - - self.term.singleShift3() - self.term.write('!!') - - ch = self.term.getCharacter(2, 0) - self.assertEquals(ch[0], '!') - self.assertEquals(ch[1].charset, G3) - - ch = self.term.getCharacter(3, 0) - self.assertEquals(ch[0], '!') - self.assertEquals(ch[1].charset, G0) - - def testShifting(self): - s1 = "Hello" - s2 = "World" - s3 = "Bye!" - self.term.write("Hello\n") - self.term.shiftOut() - self.term.write("World\n") - self.term.shiftIn() - self.term.write("Bye!\n") - - g = G0 - h = 0 - for s in (s1, s2, s3): - for i in range(len(s)): - ch = self.term.getCharacter(i, h) - self.assertEquals(ch[0], s[i]) - self.assertEquals(ch[1].charset, g) - g = g == G0 and G1 or G0 - h += 1 - - def testGraphicRendition(self): - self.term.selectGraphicRendition(BOLD, UNDERLINE, BLINK, REVERSE_VIDEO) - self.term.write('W') - self.term.selectGraphicRendition(NORMAL) - self.term.write('X') - self.term.selectGraphicRendition(BLINK) - self.term.write('Y') - self.term.selectGraphicRendition(BOLD) - self.term.write('Z') - - ch = self.term.getCharacter(0, 0) - self.assertEquals(ch[0], 'W') - self.failUnless(ch[1].bold) - self.failUnless(ch[1].underline) - self.failUnless(ch[1].blink) - self.failUnless(ch[1].reverseVideo) - - ch = self.term.getCharacter(1, 0) - self.assertEquals(ch[0], 'X') - self.failIf(ch[1].bold) - self.failIf(ch[1].underline) - self.failIf(ch[1].blink) - self.failIf(ch[1].reverseVideo) - - ch = self.term.getCharacter(2, 0) - self.assertEquals(ch[0], 'Y') - self.failUnless(ch[1].blink) - self.failIf(ch[1].bold) - self.failIf(ch[1].underline) - self.failIf(ch[1].reverseVideo) - - ch = self.term.getCharacter(3, 0) - self.assertEquals(ch[0], 'Z') - self.failUnless(ch[1].blink) - self.failUnless(ch[1].bold) - self.failIf(ch[1].underline) - self.failIf(ch[1].reverseVideo) - - def testColorAttributes(self): - s1 = "Merry xmas" - s2 = "Just kidding" - self.term.selectGraphicRendition(helper.FOREGROUND + helper.RED, - helper.BACKGROUND + helper.GREEN) - self.term.write(s1 + "\n") - self.term.selectGraphicRendition(NORMAL) - self.term.write(s2 + "\n") - - for i in range(len(s1)): - ch = self.term.getCharacter(i, 0) - self.assertEquals(ch[0], s1[i]) - self.assertEquals(ch[1].charset, G0) - self.assertEquals(ch[1].bold, False) - self.assertEquals(ch[1].underline, False) - self.assertEquals(ch[1].blink, False) - self.assertEquals(ch[1].reverseVideo, False) - self.assertEquals(ch[1].foreground, helper.RED) - self.assertEquals(ch[1].background, helper.GREEN) - - for i in range(len(s2)): - ch = self.term.getCharacter(i, 1) - self.assertEquals(ch[0], s2[i]) - self.assertEquals(ch[1].charset, G0) - self.assertEquals(ch[1].bold, False) - self.assertEquals(ch[1].underline, False) - self.assertEquals(ch[1].blink, False) - self.assertEquals(ch[1].reverseVideo, False) - self.assertEquals(ch[1].foreground, helper.WHITE) - self.assertEquals(ch[1].background, helper.BLACK) - - def testEraseLine(self): - s1 = 'line 1' - s2 = 'line 2' - s3 = 'line 3' - self.term.write('\n'.join((s1, s2, s3)) + '\n') - self.term.cursorPosition(1, 1) - self.term.eraseLine() - - self.assertEquals( - str(self.term), - s1 + '\n' + - '\n' + - s3 + '\n' + - '\n' * (HEIGHT - 4)) - - def testEraseToLineEnd(self): - s = 'Hello, world.' - self.term.write(s) - self.term.cursorBackward(5) - self.term.eraseToLineEnd() - self.assertEquals( - str(self.term), - s[:-5] + '\n' + - '\n' * (HEIGHT - 2)) - - def testEraseToLineBeginning(self): - s = 'Hello, world.' - self.term.write(s) - self.term.cursorBackward(5) - self.term.eraseToLineBeginning() - self.assertEquals( - str(self.term), - s[-4:].rjust(len(s)) + '\n' + - '\n' * (HEIGHT - 2)) - - def testEraseDisplay(self): - self.term.write('Hello world\n') - self.term.write('Goodbye world\n') - self.term.eraseDisplay() - - self.assertEquals( - str(self.term), - '\n' * (HEIGHT - 1)) - - def testEraseToDisplayEnd(self): - s1 = "Hello world" - s2 = "Goodbye world" - self.term.write('\n'.join((s1, s2, ''))) - self.term.cursorPosition(5, 1) - self.term.eraseToDisplayEnd() - - self.assertEquals( - str(self.term), - s1 + '\n' + - s2[:5] + '\n' + - '\n' * (HEIGHT - 3)) - - def testEraseToDisplayBeginning(self): - s1 = "Hello world" - s2 = "Goodbye world" - self.term.write('\n'.join((s1, s2))) - self.term.cursorPosition(5, 1) - self.term.eraseToDisplayBeginning() - - self.assertEquals( - str(self.term), - '\n' + - s2[6:].rjust(len(s2)) + '\n' + - '\n' * (HEIGHT - 3)) - - def testLineInsertion(self): - s1 = "Hello world" - s2 = "Goodbye world" - self.term.write('\n'.join((s1, s2))) - self.term.cursorPosition(7, 1) - self.term.insertLine() - - self.assertEquals( - str(self.term), - s1 + '\n' + - '\n' + - s2 + '\n' + - '\n' * (HEIGHT - 4)) - - def testLineDeletion(self): - s1 = "Hello world" - s2 = "Middle words" - s3 = "Goodbye world" - self.term.write('\n'.join((s1, s2, s3))) - self.term.cursorPosition(9, 1) - self.term.deleteLine() - - self.assertEquals( - str(self.term), - s1 + '\n' + - s3 + '\n' + - '\n' * (HEIGHT - 3)) - -class FakeDelayedCall: - called = False - cancelled = False - def __init__(self, fs, timeout, f, a, kw): - self.fs = fs - self.timeout = timeout - self.f = f - self.a = a - self.kw = kw - - def active(self): - return not (self.cancelled or self.called) - - def cancel(self): - self.cancelled = True -# self.fs.calls.remove(self) - - def call(self): - self.called = True - self.f(*self.a, **self.kw) - -class FakeScheduler: - def __init__(self): - self.calls = [] - - def callLater(self, timeout, f, *a, **kw): - self.calls.append(FakeDelayedCall(self, timeout, f, a, kw)) - return self.calls[-1] - -class ExpectTestCase(unittest.TestCase): - def setUp(self): - self.term = helper.ExpectableBuffer() - self.term.connectionMade() - self.fs = FakeScheduler() - - def testSimpleString(self): - result = [] - d = self.term.expect("hello world", timeout=1, scheduler=self.fs) - d.addCallback(result.append) - - self.term.write("greeting puny earthlings\n") - self.failIf(result) - self.term.write("hello world\n") - self.failUnless(result) - self.assertEquals(result[0].group(), "hello world") - self.assertEquals(len(self.fs.calls), 1) - self.failIf(self.fs.calls[0].active()) - - def testBrokenUpString(self): - result = [] - d = self.term.expect("hello world") - d.addCallback(result.append) - - self.failIf(result) - self.term.write("hello ") - self.failIf(result) - self.term.write("worl") - self.failIf(result) - self.term.write("d") - self.failUnless(result) - self.assertEquals(result[0].group(), "hello world") - - - def testMultiple(self): - result = [] - d1 = self.term.expect("hello ") - d1.addCallback(result.append) - d2 = self.term.expect("world") - d2.addCallback(result.append) - - self.failIf(result) - self.term.write("hello") - self.failIf(result) - self.term.write(" ") - self.assertEquals(len(result), 1) - self.term.write("world") - self.assertEquals(len(result), 2) - self.assertEquals(result[0].group(), "hello ") - self.assertEquals(result[1].group(), "world") - - def testSynchronous(self): - self.term.write("hello world") - - result = [] - d = self.term.expect("hello world") - d.addCallback(result.append) - self.failUnless(result) - self.assertEquals(result[0].group(), "hello world") - - def testMultipleSynchronous(self): - self.term.write("goodbye world") - - result = [] - d1 = self.term.expect("bye") - d1.addCallback(result.append) - d2 = self.term.expect("world") - d2.addCallback(result.append) - - self.assertEquals(len(result), 2) - self.assertEquals(result[0].group(), "bye") - self.assertEquals(result[1].group(), "world") - - def _cbTestTimeoutFailure(self, res): - self.assert_(hasattr(res, 'type')) - self.assertEqual(res.type, helper.ExpectationTimeout) - - def testTimeoutFailure(self): - d = self.term.expect("hello world", timeout=1, scheduler=self.fs) - d.addBoth(self._cbTestTimeoutFailure) - self.fs.calls[0].call() - - def testOverlappingTimeout(self): - self.term.write("not zoomtastic") - - result = [] - d1 = self.term.expect("hello world", timeout=1, scheduler=self.fs) - d1.addBoth(self._cbTestTimeoutFailure) - d2 = self.term.expect("zoom") - d2.addCallback(result.append) - - self.fs.calls[0].call() - - self.assertEquals(len(result), 1) - self.assertEquals(result[0].group(), "zoom") diff --git a/tools/buildbot/pylibs/twisted/conch/test/test_insults.py b/tools/buildbot/pylibs/twisted/conch/test/test_insults.py deleted file mode 100644 index eec07e3..0000000 --- a/tools/buildbot/pylibs/twisted/conch/test/test_insults.py +++ /dev/null @@ -1,382 +0,0 @@ -# -*- test-case-name: twisted.conch.test.test_insults -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.trial import unittest -from twisted.test.proto_helpers import StringTransport - -from twisted.conch.insults.insults import ServerProtocol, ClientProtocol -from twisted.conch.insults.insults import CS_UK, CS_US, CS_DRAWING, CS_ALTERNATE, CS_ALTERNATE_SPECIAL -from twisted.conch.insults.insults import G0, G1 -from twisted.conch.insults.insults import modes - -def _getattr(mock, name): - return super(Mock, mock).__getattribute__(name) - -def occurrences(mock): - return _getattr(mock, 'occurrences') - -def methods(mock): - return _getattr(mock, 'methods') - -def _append(mock, obj): - occurrences(mock).append(obj) - -default = object() - -class Mock(object): - callReturnValue = default - - def __init__(self, methods=None, callReturnValue=default): - """ - @param methods: Mapping of names to return values - @param callReturnValue: object __call__ should return - """ - self.occurrences = [] - if methods is None: - methods = {} - self.methods = methods - if callReturnValue is not default: - self.callReturnValue = callReturnValue - - def __call__(self, *a, **kw): - returnValue = _getattr(self, 'callReturnValue') - if returnValue is default: - returnValue = Mock() - # _getattr(self, 'occurrences').append(('__call__', returnValue, a, kw)) - _append(self, ('__call__', returnValue, a, kw)) - return returnValue - - def __getattribute__(self, name): - methods = _getattr(self, 'methods') - if name in methods: - attrValue = Mock(callReturnValue=methods[name]) - else: - attrValue = Mock() - # _getattr(self, 'occurrences').append((name, attrValue)) - _append(self, (name, attrValue)) - return attrValue - -class MockMixin: - def assertCall(self, occurrence, methodName, args=(), kw={}): - attr, mock = occurrence - self.assertEquals(attr, methodName) - self.assertEquals(len(occurrences(mock)), 1) - [(call, result, args, kw)] = occurrences(mock) - self.assertEquals(call, "__call__") - self.assertEquals(args, args) - self.assertEquals(kw, kw) - return result - - -_byteGroupingTestTemplate = """\ -def testByte%(groupName)s(self): - transport = StringTransport() - proto = Mock() - parser = self.protocolFactory(lambda: proto) - parser.factory = self - parser.makeConnection(transport) - - bytes = self.TEST_BYTES - while bytes: - chunk = bytes[:%(bytesPer)d] - bytes = bytes[%(bytesPer)d:] - parser.dataReceived(chunk) - - self.verifyResults(transport, proto, parser) -""" -class ByteGroupingsMixin(MockMixin): - protocolFactory = None - - for word, n in [('Pairs', 2), ('Triples', 3), ('Quads', 4), ('Quints', 5), ('Sexes', 6)]: - exec _byteGroupingTestTemplate % {'groupName': word, 'bytesPer': n} - del word, n - - def verifyResults(self, transport, proto, parser): - result = self.assertCall(occurrences(proto).pop(0), "makeConnection", (parser,)) - self.assertEquals(occurrences(result), []) - -del _byteGroupingTestTemplate - -class ServerArrowKeys(ByteGroupingsMixin, unittest.TestCase): - protocolFactory = ServerProtocol - - # All the arrow keys once - TEST_BYTES = '\x1b[A\x1b[B\x1b[C\x1b[D' - - def verifyResults(self, transport, proto, parser): - ByteGroupingsMixin.verifyResults(self, transport, proto, parser) - - for arrow in (parser.UP_ARROW, parser.DOWN_ARROW, - parser.RIGHT_ARROW, parser.LEFT_ARROW): - result = self.assertCall(occurrences(proto).pop(0), "keystrokeReceived", (arrow, None)) - self.assertEquals(occurrences(result), []) - self.failIf(occurrences(proto)) - - -class PrintableCharacters(ByteGroupingsMixin, unittest.TestCase): - protocolFactory = ServerProtocol - - # Some letters and digits, first on their own, then capitalized, - # then modified with alt - - TEST_BYTES = 'abc123ABC!@#\x1ba\x1bb\x1bc\x1b1\x1b2\x1b3' - - def verifyResults(self, transport, proto, parser): - ByteGroupingsMixin.verifyResults(self, transport, proto, parser) - - for char in 'abc123ABC!@#': - result = self.assertCall(occurrences(proto).pop(0), "keystrokeReceived", (char, None)) - self.assertEquals(occurrences(result), []) - - for char in 'abc123': - result = self.assertCall(occurrences(proto).pop(0), "keystrokeReceived", (char, parser.ALT)) - self.assertEquals(occurrences(result), []) - - occs = occurrences(proto) - self.failIf(occs, "%r should have been []" % (occs,)) - -class ServerFunctionKeys(ByteGroupingsMixin, unittest.TestCase): - """Test for parsing and dispatching function keys (F1 - F12) - """ - protocolFactory = ServerProtocol - - byteList = [] - for bytes in ('OP', 'OQ', 'OR', 'OS', # F1 - F4 - '15~', '17~', '18~', '19~', # F5 - F8 - '20~', '21~', '23~', '24~'): # F9 - F12 - byteList.append('\x1b[' + bytes) - TEST_BYTES = ''.join(byteList) - del byteList, bytes - - def verifyResults(self, transport, proto, parser): - ByteGroupingsMixin.verifyResults(self, transport, proto, parser) - for funcNum in range(1, 13): - funcArg = getattr(parser, 'F%d' % (funcNum,)) - result = self.assertCall(occurrences(proto).pop(0), "keystrokeReceived", (funcArg, None)) - self.assertEquals(occurrences(result), []) - self.failIf(occurrences(proto)) - -class ClientCursorMovement(ByteGroupingsMixin, unittest.TestCase): - protocolFactory = ClientProtocol - - d2 = "\x1b[2B" - r4 = "\x1b[4C" - u1 = "\x1b[A" - l2 = "\x1b[2D" - # Move the cursor down two, right four, up one, left two, up one, left two - TEST_BYTES = d2 + r4 + u1 + l2 + u1 + l2 - del d2, r4, u1, l2 - - def verifyResults(self, transport, proto, parser): - ByteGroupingsMixin.verifyResults(self, transport, proto, parser) - - for (method, count) in [('Down', 2), ('Forward', 4), ('Up', 1), - ('Backward', 2), ('Up', 1), ('Backward', 2)]: - result = self.assertCall(occurrences(proto).pop(0), "cursor" + method, (count,)) - self.assertEquals(occurrences(result), []) - self.failIf(occurrences(proto)) - -class ClientControlSequences(unittest.TestCase, MockMixin): - def setUp(self): - self.transport = StringTransport() - self.proto = Mock() - self.parser = ClientProtocol(lambda: self.proto) - self.parser.factory = self - self.parser.makeConnection(self.transport) - result = self.assertCall(occurrences(self.proto).pop(0), "makeConnection", (self.parser,)) - self.failIf(occurrences(result)) - - def testSimpleCardinals(self): - self.parser.dataReceived( - ''.join([''.join(['\x1b[' + str(n) + ch for n in ('', 2, 20, 200)]) for ch in 'BACD'])) - occs = occurrences(self.proto) - - for meth in ("Down", "Up", "Forward", "Backward"): - for count in (1, 2, 20, 200): - result = self.assertCall(occs.pop(0), "cursor" + meth, (count,)) - self.failIf(occurrences(result)) - self.failIf(occs) - - def testScrollRegion(self): - self.parser.dataReceived('\x1b[5;22r\x1b[r') - occs = occurrences(self.proto) - - result = self.assertCall(occs.pop(0), "setScrollRegion", (5, 22)) - self.failIf(occurrences(result)) - - result = self.assertCall(occs.pop(0), "setScrollRegion", (None, None)) - self.failIf(occurrences(result)) - self.failIf(occs) - - def testHeightAndWidth(self): - self.parser.dataReceived("\x1b#3\x1b#4\x1b#5\x1b#6") - occs = occurrences(self.proto) - - result = self.assertCall(occs.pop(0), "doubleHeightLine", (True,)) - self.failIf(occurrences(result)) - - result = self.assertCall(occs.pop(0), "doubleHeightLine", (False,)) - self.failIf(occurrences(result)) - - result = self.assertCall(occs.pop(0), "singleWidthLine") - self.failIf(occurrences(result)) - - result = self.assertCall(occs.pop(0), "doubleWidthLine") - self.failIf(occurrences(result)) - self.failIf(occs) - - def testCharacterSet(self): - self.parser.dataReceived( - ''.join([''.join(['\x1b' + g + n for n in 'AB012']) for g in '()'])) - occs = occurrences(self.proto) - - for which in (G0, G1): - for charset in (CS_UK, CS_US, CS_DRAWING, CS_ALTERNATE, CS_ALTERNATE_SPECIAL): - result = self.assertCall(occs.pop(0), "selectCharacterSet", (charset, which)) - self.failIf(occurrences(result)) - self.failIf(occs) - - def testShifting(self): - self.parser.dataReceived("\x15\x14") - occs = occurrences(self.proto) - - result = self.assertCall(occs.pop(0), "shiftIn") - self.failIf(occurrences(result)) - - result = self.assertCall(occs.pop(0), "shiftOut") - self.failIf(occurrences(result)) - self.failIf(occs) - - def testSingleShifts(self): - self.parser.dataReceived("\x1bN\x1bO") - occs = occurrences(self.proto) - - result = self.assertCall(occs.pop(0), "singleShift2") - self.failIf(occurrences(result)) - - result = self.assertCall(occs.pop(0), "singleShift3") - self.failIf(occurrences(result)) - self.failIf(occs) - - def testKeypadMode(self): - self.parser.dataReceived("\x1b=\x1b>") - occs = occurrences(self.proto) - - result = self.assertCall(occs.pop(0), "applicationKeypadMode") - self.failIf(occurrences(result)) - - result = self.assertCall(occs.pop(0), "numericKeypadMode") - self.failIf(occurrences(result)) - self.failIf(occs) - - def testCursor(self): - self.parser.dataReceived("\x1b7\x1b8") - occs = occurrences(self.proto) - - result = self.assertCall(occs.pop(0), "saveCursor") - self.failIf(occurrences(result)) - - result = self.assertCall(occs.pop(0), "restoreCursor") - self.failIf(occurrences(result)) - self.failIf(occs) - - def testReset(self): - self.parser.dataReceived("\x1bc") - occs = occurrences(self.proto) - - result = self.assertCall(occs.pop(0), "reset") - self.failIf(occurrences(result)) - self.failIf(occs) - - def testIndex(self): - self.parser.dataReceived("\x1bD\x1bM\x1bE") - occs = occurrences(self.proto) - - result = self.assertCall(occs.pop(0), "index") - self.failIf(occurrences(result)) - - result = self.assertCall(occs.pop(0), "reverseIndex") - self.failIf(occurrences(result)) - - result = self.assertCall(occs.pop(0), "nextLine") - self.failIf(occurrences(result)) - self.failIf(occs) - - def testModes(self): - self.parser.dataReceived( - "\x1b[" + ';'.join(map(str, [modes.KAM, modes.IRM, modes.LNM])) + "h") - self.parser.dataReceived( - "\x1b[" + ';'.join(map(str, [modes.KAM, modes.IRM, modes.LNM])) + "l") - occs = occurrences(self.proto) - - result = self.assertCall(occs.pop(0), "setModes", ([modes.KAM, modes.IRM, modes.LNM],)) - self.failIf(occurrences(result)) - - result = self.assertCall(occs.pop(0), "resetModes", ([modes.KAM, modes.IRM, modes.LNM],)) - self.failIf(occurrences(result)) - self.failIf(occs) - - def testErasure(self): - self.parser.dataReceived( - "\x1b[K\x1b[1K\x1b[2K\x1b[J\x1b[1J\x1b[2J\x1b[3P") - occs = occurrences(self.proto) - - for meth in ("eraseToLineEnd", "eraseToLineBeginning", "eraseLine", - "eraseToDisplayEnd", "eraseToDisplayBeginning", - "eraseDisplay"): - result = self.assertCall(occs.pop(0), meth) - self.failIf(occurrences(result)) - - result = self.assertCall(occs.pop(0), "deleteCharacter", (3,)) - self.failIf(occurrences(result)) - self.failIf(occs) - - def testLineDeletion(self): - self.parser.dataReceived("\x1b[M\x1b[3M") - occs = occurrences(self.proto) - - for arg in (1, 3): - result = self.assertCall(occs.pop(0), "deleteLine", (arg,)) - self.failIf(occurrences(result)) - self.failIf(occs) - - def testLineInsertion(self): - self.parser.dataReceived("\x1b[L\x1b[3L") - occs = occurrences(self.proto) - - for arg in (1, 3): - result = self.assertCall(occs.pop(0), "insertLine", (arg,)) - self.failIf(occurrences(result)) - self.failIf(occs) - - def testCursorPosition(self): - methods(self.proto)['reportCursorPosition'] = (6, 7) - self.parser.dataReceived("\x1b[6n") - self.assertEquals(self.transport.value(), "\x1b[7;8R") - occs = occurrences(self.proto) - - result = self.assertCall(occs.pop(0), "reportCursorPosition") - # This isn't really an interesting assert, since it only tests that - # our mock setup is working right, but I'll include it anyway. - self.assertEquals(result, (6, 7)) - - - -class ServerProtocolOutputTests(unittest.TestCase): - """ - Tests for the bytes L{ServerProtocol} writes to its transport when its - methods are called. - """ - def test_nextLine(self): - """ - L{ServerProtocol.nextLine} writes C{"\r\n"} to its transport. - """ - # Why doesn't it write ESC E? Because ESC E is poorly supported. For - # example, gnome-terminal (many different versions) fails to scroll if - # it receives ESC E and the cursor is already on the last row. - protocol = ServerProtocol() - transport = StringTransport() - protocol.makeConnection(transport) - protocol.nextLine() - self.assertEqual(transport.value(), "\r\n") diff --git a/tools/buildbot/pylibs/twisted/conch/test/test_keys.py b/tools/buildbot/pylibs/twisted/conch/test/test_keys.py deleted file mode 100644 index 5431af4..0000000 --- a/tools/buildbot/pylibs/twisted/conch/test/test_keys.py +++ /dev/null @@ -1,846 +0,0 @@ -# -*- test-case-name: twisted.conch.test.test_keys -*- -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -try: - import Crypto -except ImportError: - Crypto = None -else: - from twisted.conch.ssh import keys, common, sexpy, asn1 - -from twisted.conch.test import keydata -from twisted.python import randbytes -from twisted.trial import unittest -import sha, os, base64 - -class SSHKeysHandlingTestCase(unittest.TestCase): - """ - test the handling of reading/signing/verifying with RSA and DSA keys - assumed test keys are in test/ - """ - - if not Crypto: - skip = "cannot run w/o PyCrypto" - - def setUp(self): - self.tmpdir = self.mktemp() - os.mkdir(self.tmpdir) - self.privateKeyFile = os.path.join(self.tmpdir, 'private') - self.publicKeyFile = os.path.join(self.tmpdir, 'public') - file(self.privateKeyFile, 'wb').write(keydata.privateRSA_openssh) - file(self.publicKeyFile, 'wb').write('first line\n' + - keydata.publicRSA_openssh) - - def test_readFile(self): - """ - Test that reading a key from a file works as expected. - """ - self.assertEquals(self.assertWarns(DeprecationWarning, - "getPublicKeyString is deprecated since Twisted Conch 0.9. " - "Use Key.fromString().", unittest.__file__, - keys.getPublicKeyString, self.publicKeyFile, 1), - keys.Key.fromString(keydata.publicRSA_openssh).blob()) - self.assertEquals(self.assertWarns(DeprecationWarning, - "getPrivateKeyObject is deprecated since Twisted Conch 0.9. " - "Use Key.fromString().", unittest.__file__, - keys.getPrivateKeyObject, self.privateKeyFile), - keys.Key.fromString(keydata.privateRSA_openssh).keyObject) - - def test_DSA(self): - """ - Test DSA keys using both OpenSSH and LSH formats. - """ - self._testKey(keydata.publicDSA_openssh, keydata.privateDSA_openssh, - keydata.DSAData, 'openssh') - self._testKey(keydata.publicDSA_lsh, keydata.privateDSA_lsh, - keydata.DSAData,'lsh') - obj = self.assertWarns(DeprecationWarning, "getPrivateKeyObject is " - "deprecated since Twisted Conch 0.9. Use Key.fromString().", - unittest.__file__, keys.getPrivateKeyObject, - data=keydata.privateDSA_agentv3) - self._testGeneratePrivateKey(obj, keydata.privateDSA_agentv3, - 'agentv3') - - def test_RSA(self): - """ - Same as test_DSA but for RSA keys. - """ - self._testKey(keydata.publicRSA_openssh, keydata.privateRSA_openssh, - keydata.RSAData, 'openssh') - self._testKey(keydata.publicRSA_lsh, keydata.privateRSA_lsh, - keydata.RSAData, 'lsh') - obj = self.assertWarns(DeprecationWarning, "getPrivateKeyObject is " - "deprecated since Twisted Conch 0.9. Use Key.fromString().", - unittest.__file__, keys.getPrivateKeyObject, - data=keydata.privateRSA_agentv3) - self._testGeneratePrivateKey(obj, keydata.privateRSA_agentv3, - 'agentv3') - - def _testKey(self, pubStr, privStr, data, keyType): - """ - Run each of the key tests with the public/private keypairs. - - @param pubStr: The data for a public key in the format defined by - keyType. - @param privStr: The data for a private key in the format defined by - keyType. - @param data: The numerical values encoded in the key. - @param keyType: the type of the public and private key data: either - "openssh" or "lsh". - """ - pubBlob = self.assertWarns(DeprecationWarning, "getPublicKeyString is " - "deprecated since Twisted Conch 0.9. Use Key.fromString().", - unittest.__file__, keys.getPublicKeyString, data=pubStr) - pubObj = self.assertWarns(DeprecationWarning, "getPublicKeyObject is " - "deprecated since Twisted Conch 0.9. Use Key.fromString().", - unittest.__file__, keys.getPublicKeyObject, pubBlob) - privObj = self.assertWarns(DeprecationWarning, "getPrivateKeyObject is " - "deprecated since Twisted Conch 0.9. Use Key.fromString().", - unittest.__file__, keys.getPrivateKeyObject, data=privStr) - - self._testKeySignVerify(privObj, pubObj) - self._testKeyFromString(privObj, pubObj, data, keyType) - self._testGeneratePublicKey(privObj, pubObj, pubStr, keyType) - self._testGeneratePrivateKey(privObj, privStr, keyType) - self._testGenerateBlob(privObj, pubObj, pubBlob) - - def _testKeySignVerify(self, privObj, pubObj): - """ - Test that signing and verifying works correctly. - @param privObj: a private key object. - @type privObj: C{Crypto.PublicKey.pubkey.pubkey} - @param pubObj: a public key object. - @type pubObj: C{Crypto.PublicKey.pubkey.pubkey} - """ - - testData = 'this is the test data' - sig = self.assertWarns(DeprecationWarning, - "signData is deprecated since Twisted Conch 0.9. " - "Use Key(obj).sign(data).", unittest.__file__, keys.signData, - privObj, testData) - self.assertTrue(self.assertWarns(DeprecationWarning, - "verifySignature is deprecated since Twisted Conch 0.9. " - "Use Key(obj).verify(signature, data).", unittest.__file__, - keys.verifySignature, privObj, sig, testData), - 'verifying with private %s failed' % - keys.objectType(privObj)) - - self.assertTrue(self.assertWarns(DeprecationWarning, - "verifySignature is deprecated since Twisted Conch 0.9. " - "Use Key(obj).verify(signature, data).", unittest.__file__, - keys.verifySignature, pubObj, sig, testData), - 'verifying with public %s failed' % - keys.objectType(pubObj)) - - self.failIf(self.assertWarns(DeprecationWarning, - "verifySignature is deprecated since Twisted Conch 0.9. " - "Use Key(obj).verify(signature, data).", unittest.__file__, - keys.verifySignature,privObj, sig, 'other data'), - 'verified bad data with %s' % - keys.objectType(privObj)) - - self.failIf(self.assertWarns(DeprecationWarning, - "verifySignature is deprecated since Twisted Conch 0.9. " - "Use Key(obj).verify(signature, data).", unittest.__file__, - keys.verifySignature, privObj, 'bad sig', testData), - 'verified badsign with %s' % - keys.objectType(privObj)) - - def _testKeyFromString(self, privObj, pubObj, data, keyType): - """ - Test key object generation from a string. The public key objects - were generated in _testKey; just check that they were created - correctly. - """ - for k in data.keys(): - self.assertEquals(getattr(privObj, k), data[k]) - for k in pubObj.keydata: - if hasattr(pubObj, k): # public key objects don't have all the - # attributes - self.assertEquals(getattr(pubObj, k), data[k]) - - def _testGeneratePublicKey(self, privObj, pubObj, pubStr, keyType): - """ - Test public key string generation from an object. - """ - self.assertEquals(self.assertWarns(DeprecationWarning, - "makePublicKeyString is deprecated since Twisted Conch 0.9. " - "Use Key(obj).toString().", unittest.__file__, - keys.makePublicKeyString, pubObj, 'comment', - keyType), pubStr) - self.assertEquals(self.assertWarns(DeprecationWarning, - "makePublicKeyString is deprecated since Twisted Conch 0.9. " - "Use Key(obj).toString().", unittest.__file__, - keys.makePublicKeyString, privObj, 'comment', - keyType), pubStr) - - def _testGeneratePrivateKey(self, privObj, privStr, keyType): - """ - Test private key string generation from an object. - """ - self.assertEquals(self.assertWarns(DeprecationWarning, - "makePrivateKeyString is deprecated since Twisted Conch 0.9. " - "Use Key(obj).toString().", unittest.__file__, - keys.makePrivateKeyString, privObj, kind=keyType), - privStr) - if keyType == 'openssh': - encData = self.assertWarns(DeprecationWarning, - "makePrivateKeyString is deprecated since Twisted Conch " - "0.9. Use Key(obj).toString().", unittest.__file__, - keys.makePrivateKeyString, privObj, passphrase='test', - kind=keyType) - self.assertEquals(self.assertWarns(DeprecationWarning, - "getPrivateKeyObject is deprecated since Twisted Conch 0.9. " - "Use Key.fromString().", unittest.__file__, - keys.getPrivateKeyObject, data = encData, passphrase='test'), - privObj) - - def _testGenerateBlob(self, privObj, pubObj, pubBlob): - """ - Test wire-format blob generation. - """ - self.assertEquals(self.assertWarns(DeprecationWarning, - "makePublicKeyBlob is deprecated since Twisted Conch 0.9. " - "Use Key(obj).blob().", unittest.__file__, - keys.makePublicKeyBlob, pubObj), pubBlob) - self.assertEquals(self.assertWarns(DeprecationWarning, - "makePublicKeyBlob is deprecated since Twisted Conch 0.9. " - "Use Key(obj).blob().", unittest.__file__, - keys.makePublicKeyBlob, privObj), pubBlob) - - def test_getPublicKeyStringErrors(self): - """ - Test that getPublicKeyString raises errors in appropriate cases. - """ - self.assertWarns(DeprecationWarning, "getPublicKeyString is deprecated" - " since Twisted Conch 0.9. Use Key.fromString().", - unittest.__file__, self.assertRaises, keys.BadKeyError, - keys.getPublicKeyString, self.publicKeyFile, 1, - data=keydata.publicRSA_openssh) - self.assertWarns(DeprecationWarning, "getPublicKeyString is deprecated" - " since Twisted Conch 0.9. Use Key.fromString().", - unittest.__file__, self.assertRaises, keys.BadKeyError, - keys.getPublicKeyString, data = 'invalid key') - sexp = sexpy.pack([['public-key', ['bad-key', ['p', '2']]]]) - self.assertWarns(DeprecationWarning, "getPublicKeyString is deprecated" - " since Twisted Conch 0.9. Use Key.fromString().", - unittest.__file__, self.assertRaises, keys.BadKeyError, - keys.getPublicKeyString, data='{'+base64.encodestring(sexp)+'}') - - def test_getPrivateKeyObjectErrors(self): - """ - Test that getPrivateKeyObject raises errors in appropriate cases. - """ - self.assertWarns(DeprecationWarning, "getPrivateKeyObject is deprecated" - " since Twisted Conch 0.9. Use Key.fromString().", - unittest.__file__, self.assertRaises, keys.BadKeyError, - keys.getPrivateKeyObject, self.privateKeyFile, - keydata.privateRSA_openssh) - self.assertWarns(DeprecationWarning, "getPrivateKeyObject is deprecated" - " since Twisted Conch 0.9. Use Key.fromString().", - unittest.__file__, self.assertRaises, keys.BadKeyError, - keys.getPrivateKeyObject, data = 'invalid key') - sexp = sexpy.pack([['private-key', ['bad-key', ['p', '2']]]]) - self.assertWarns(DeprecationWarning, "getPrivateKeyObject is deprecated" - " since Twisted Conch 0.9. Use Key.fromString().", - unittest.__file__, self.assertRaises, keys.BadKeyError, - keys.getPrivateKeyObject, data=sexp) - self.assertWarns(DeprecationWarning, "getPrivateKeyObject is deprecated" - " since Twisted Conch 0.9. Use Key.fromString().", - unittest.__file__, self.assertRaises, keys.BadKeyError, - keys.getPrivateKeyObject, - data='\x00\x00\x00\x07ssh-foo'+'\x00\x00\x00\x01\x01'*5) - - def test_makePublicKeyStringErrors(self): - """ - Test that makePublicKeyString raises errors in appropriate cases. - """ - self.assertWarns(DeprecationWarning, "makePublicKeyString is deprecated" - " since Twisted Conch 0.9. Use Key(obj).toString().", - unittest.__file__, self.assertRaises, Exception, - keys.makePublicKeyString, None, kind='bad type') - self.assertWarns(DeprecationWarning, "makePublicKeyString is deprecated" - " since Twisted Conch 0.9. Use Key(obj).toString().", - unittest.__file__, self.assertRaises, Exception, - keys.makePublicKeyString, None) - self.assertWarns(DeprecationWarning, "makePublicKeyString is deprecated" - " since Twisted Conch 0.9. Use Key(obj).toString().", - unittest.__file__, self.assertRaises, Exception, - keys.makePublicKeyString, None, kind='lsh') - - def test_getPublicKeyObjectErrors(self): - """ - Test that getPublicKeyObject raises errors in appropriate cases. - """ - self.assertWarns(DeprecationWarning, "getPublicKeyObject is deprecated" - " since Twisted Conch 0.9. Use Key.fromString().", - unittest.__file__, self.assertRaises, keys.BadKeyError, - keys.getPublicKeyObject, '\x00\x00\x00\x01A') - - def test_makePrivateKeyStringErrors(self): - """ - Test that makePrivateKeyString raises errors in appropriate cases. - """ - self.assertWarns(DeprecationWarning, "makePrivateKeyString is " - "deprecated since Twisted Conch 0.9. Use Key(obj).toString().", - unittest.__file__, self.assertRaises, Exception, - keys.makePrivateKeyString, None, kind='bad type') - self.assertWarns(DeprecationWarning, "makePrivateKeyString is " - "deprecated since Twisted Conch 0.9. Use Key(obj).toString().", - unittest.__file__, self.assertRaises, Exception, - keys.makePrivateKeyString, None) - self.assertWarns(DeprecationWarning, "makePrivateKeyString is " - "deprecated since Twisted Conch 0.9. Use Key(obj).toString().", - unittest.__file__, self.assertRaises, Exception, - keys.makePrivateKeyString, None, kind='lsh') - -class HelpersTestCase(unittest.TestCase): - - if not Crypto: - skip = "cannot run w/o PyCrypto" - - def setUp(self): - self._secureRandom = randbytes.secureRandom - randbytes.secureRandom = lambda x: '\x55' * x - - def tearDown(self): - randbytes.secureRandom = self._secureRandom - self._secureRandom = None - - def test_pkcs1(self): - """ - Test Public Key Cryptographic Standard #1 functions. - """ - data = 'ABC' - messageSize = 6 - self.assertEquals(keys.pkcs1Pad(data, messageSize), - '\x01\xff\x00ABC') - hash = sha.new().digest() - messageSize = 40 - self.assertEquals(keys.pkcs1Digest('', messageSize), - '\x01\xff\xff\xff\x00' + keys.ID_SHA1 + hash) - - def _signRSA(self, data): - key = keys.Key.fromString(keydata.privateRSA_openssh) - sig = key.sign(data) - return key.keyObject, sig - - def _signDSA(self, data): - key = keys.Key.fromString(keydata.privateDSA_openssh) - sig = key.sign(data) - return key.keyObject, sig - - def test_signRSA(self): - """ - Test that RSA keys return appropriate signatures. - """ - data = 'data' - key, sig = self._signRSA(data) - sigData = keys.pkcs1Digest(data, keys.lenSig(key)) - v = key.sign(sigData, '')[0] - self.assertEquals(sig, common.NS('ssh-rsa') + common.MP(v)) - return key, sig - - def test_signDSA(self): - """ - Test that DSA keys return appropriate signatures. - """ - data = 'data' - key, sig = self._signDSA(data) - sigData = sha.new(data).digest() - v = key.sign(sigData, '\x55' * 19) - self.assertEquals(sig, common.NS('ssh-dss') + common.NS( - Crypto.Util.number.long_to_bytes(v[0], 20) + - Crypto.Util.number.long_to_bytes(v[1], 20))) - return key, sig - - def test_verifyRSA(self): - """ - Test that RSA signatures are verified appropriately. - """ - data = 'data' - key, sig = self._signRSA(data) - self.assertTrue(self.assertWarns(DeprecationWarning, "verifySignature " - "is deprecated since Twisted Conch 0.9. Use " - "Key(obj).verify(signature, data).", unittest.__file__, - keys.verifySignature, key, sig, data)) - - def test_verifyDSA(self): - """ - Test that RSA signatures are verified appropriately. - """ - data = 'data' - key, sig = self._signDSA(data) - self.assertTrue(self.assertWarns(DeprecationWarning, "verifySignature " - "is deprecated since Twisted Conch 0.9. Use " - "Key(obj).verify(signature, data).", unittest.__file__, - keys.verifySignature, key, sig, data)) - - def test_objectType(self): - """ - Test that objectType, returns the correct type for objects. - """ - self.assertEquals(keys.objectType(keys.Key.fromString( - keydata.privateRSA_openssh).keyObject), 'ssh-rsa') - self.assertEquals(keys.objectType(keys.Key.fromString( - keydata.privateDSA_openssh).keyObject), 'ssh-dss') - self.assertRaises(keys.BadKeyError, keys.objectType, None) - - def test_asn1PackError(self): - """ - L{asn1.pack} should raise a C{ValueError} when given a type not - handled. - """ - self.assertRaises(ValueError, asn1.pack, [object()]) - - def test_printKey(self): - """ - Test that the printKey function prints correctly. - """ - obj = keys.Key.fromString(keydata.privateRSA_openssh).keyObject - self.assertEquals(self.assertWarns(DeprecationWarning, "printKey is " - "deprecated since Twisted Conch 0.9. Use repr(Key(obj)).", - unittest.__file__, keys.printKey, obj), - """RSA Private Key (767 bits) -attr e: -\t23 -attr d: -\t6e:1f:b5:55:97:eb:ed:67:ed:2b:99:6e:ec:c1:ed: -\ta8:4d:52:d6:f3:d6:65:06:04:df:e5:54:9f:cc:89: -\t00:3c:9b:67:87:ec:65:a0:ab:cd:6f:65:90:8a:97: -\t90:4d:c6:21:8f:a8:8d:d8:59:86:43:b5:81:b1:b4: -\td7:5f:2c:22:0a:61:c1:25:8a:47:12:b4:9a:f8:7a: -\t11:1c:4a:a8:8b:75:c4:91:09:3b:be:04:ca:45:d9: -\t57:8a:0d:27:cb:23 -attr n: -\t00:af:32:71:f0:e6:0e:9c:99:b3:7f:8b:5f:04:4b: -\tcb:8b:c0:d5:3e:b2:77:fd:cf:64:d8:8f:c0:cf:ae: -\t1f:c6:31:df:f6:29:b2:44:96:e2:c6:d4:21:94:7f: -\t65:7c:d8:d4:23:1f:b8:2e:6a:c9:1f:94:0d:46:c1: -\t69:a2:b7:07:0c:a3:93:c1:34:d8:2e:1e:4a:99:1a: -\t6c:96:46:07:46:2b:dc:25:29:1b:87:f0:be:05:1d: -\tee:b4:34:b9:e7:99:95 -attr q: -\t00:dc:9f:6b:d9:98:21:56:11:8d:e9:5f:03:9d:0a: -\td3:93:6e:13:77:41:3c:85:4f:00:70:fd:05:54:ff: -\tbc:3d:09:bf:83:f6:97:7f:64:10:91:04:fe:a2:67: -\t47:54:42:6b -attr p: -\t00:cb:4a:4b:d0:40:47:e8:45:52:f7:c7:af:0c:20: -\t6d:43:0d:b6:39:94:f9:da:a5:e5:03:06:76:83:24: -\teb:88:a1:55:a2:a8:de:12:3b:77:49:92:8a:a9:71: -\td2:02:93:ff -attr u: -\t00:b4:73:97:4b:50:10:a3:17:b3:a8:47:f1:3a:14: -\t76:52:d1:38:2a:cf:12:14:34:c1:a8:54:4c:29:35: -\t80:a0:38:b8:f0:fa:4c:c4:c2:85:ab:db:87:82:ba: -\tdc:eb:db:2a""") - -class KeyTestCase(unittest.TestCase): - - def setUp(self): - self.rsaObj = Crypto.PublicKey.RSA.construct((1L, 2L, 3L, 4L, 5L)) - self.dsaObj = Crypto.PublicKey.DSA.construct((1L, 2L, 3L, 4L, 5L)) - self.rsaSignature = ('\x00\x00\x00\x07ssh-rsa\x00' - '\x00\x00`N\xac\xb4@qK\xa0(\xc3\xf2h \xd3\xdd\xee6Np\x9d_' - '\xb0>\xe3\x0c(L\x9d{\txUd|!\xf6m\x9c\xd3\x93\x842\x7fU' - '\x05\xf4\xf7\xfaD\xda\xce\x81\x8ea\x7f=Y\xed*\xb7\xba\x81' - '\xf2\xad\xda\xeb(\x97\x03S\x08\x81\xc7\xb1\xb7\xe6\xe3' - '\xcd*\xd4\xbd\xc0wt\xf7y\xcd\xf0\xb7\x7f\xfb\x1e>\xf9r' - '\x8c\xba') - self.dsaSignature = ('\x00\x00\x00\x07ssh-dss\x00\x00' - '\x00(\x18z)H\x8a\x1b\xc6\r\xbbq\xa2\xd7f\x7f$\xa7\xbf' - '\xe8\x87\x8c\x88\xef\xd9k\x1a\x98\xdd{=\xdec\x18\t\xe3' - '\x87\xa9\xc72h\x95') - self.oldSecureRandom = randbytes.secureRandom - randbytes.secureRandom = lambda x: '\xff' * x - self.keyFile = self.mktemp() - file(self.keyFile, 'wb').write(keydata.privateRSA_lsh) - - def tearDown(self): - randbytes.secureRandom = self.oldSecureRandom - del self.oldSecureRandom - os.unlink(self.keyFile) - - def test__guessStringType(self): - """ - Test that the _guessStringType method guesses string types - correctly. - """ - self.assertEquals(keys.Key._guessStringType(keydata.publicRSA_openssh), - 'public_openssh') - self.assertEquals(keys.Key._guessStringType(keydata.publicDSA_openssh), - 'public_openssh') - self.assertEquals(keys.Key._guessStringType( - keydata.privateRSA_openssh), 'private_openssh') - self.assertEquals(keys.Key._guessStringType( - keydata.privateDSA_openssh), 'private_openssh') - self.assertEquals(keys.Key._guessStringType(keydata.publicRSA_lsh), - 'public_lsh') - self.assertEquals(keys.Key._guessStringType(keydata.publicDSA_lsh), - 'public_lsh') - self.assertEquals(keys.Key._guessStringType(keydata.privateRSA_lsh), - 'private_lsh') - self.assertEquals(keys.Key._guessStringType(keydata.privateDSA_lsh), - 'private_lsh') - self.assertEquals(keys.Key._guessStringType( - keydata.privateRSA_agentv3), 'agentv3') - self.assertEquals(keys.Key._guessStringType( - keydata.privateDSA_agentv3), 'agentv3') - self.assertEquals(keys.Key._guessStringType( - '\x00\x00\x00\x07ssh-rsa\x00\x00\x00\x01\x01'), - 'blob') - self.assertEquals(keys.Key._guessStringType( - '\x00\x00\x00\x07ssh-dss\x00\x00\x00\x01\x01'), - 'blob') - self.assertEquals(keys.Key._guessStringType('not a key'), - None) - - def _testPublicPrivateFromString(self, public, private, type, data): - self._testPublicFromString(public, type, data) - self._testPrivateFromString(private, type, data) - - def _testPublicFromString(self, public, type, data): - publicKey = keys.Key.fromString(public) - self.assertTrue(publicKey.isPublic()) - self.assertEquals(publicKey.type(), type) - for k, v in publicKey.data().items(): - self.assertEquals(data[k], v) - - def _testPrivateFromString(self, private, type, data): - privateKey = keys.Key.fromString(private) - self.assertFalse(privateKey.isPublic()) - self.assertEquals(privateKey.type(), type) - for k, v in data.items(): - self.assertEquals(privateKey.data()[k], v) - - def test_fromOpenSSH(self): - """ - Test that keys are correctly generated from OpenSSH strings. - """ - self._testPublicPrivateFromString(keydata.publicRSA_openssh, - keydata.privateRSA_openssh, 'RSA', keydata.RSAData) - self.assertEquals(keys.Key.fromString( - keydata.privateRSA_openssh_encrypted, - passphrase='encrypted'), - keys.Key.fromString(keydata.privateRSA_openssh)) - self.assertEquals(keys.Key.fromString( - keydata.privateRSA_openssh_alternate), - keys.Key.fromString(keydata.privateRSA_openssh)) - self._testPublicPrivateFromString(keydata.publicDSA_openssh, - keydata.privateDSA_openssh, 'DSA', keydata.DSAData) - - def test_fromLSH(self): - """ - Test that keys are correctly generated from LSH strings. - """ - self._testPublicPrivateFromString(keydata.publicRSA_lsh, - keydata.privateRSA_lsh, 'RSA', keydata.RSAData) - self._testPublicPrivateFromString(keydata.publicDSA_lsh, - keydata.privateDSA_lsh, 'DSA', keydata.DSAData) - sexp = sexpy.pack([['public-key', ['bad-key', ['p', '2']]]]) - self.assertRaises(keys.BadKeyError, keys.Key.fromString, - data='{'+base64.encodestring(sexp)+'}') - sexp = sexpy.pack([['private-key', ['bad-key', ['p', '2']]]]) - self.assertRaises(keys.BadKeyError, keys.Key.fromString, - sexp) - - def test_fromAgentv3(self): - """ - Test that keys are correctly generated from Agent v3 strings. - """ - self._testPrivateFromString(keydata.privateRSA_agentv3, 'RSA', - keydata.RSAData) - self._testPrivateFromString(keydata.privateDSA_agentv3, 'DSA', - keydata.DSAData) - self.assertRaises(keys.BadKeyError, keys.Key.fromString, - '\x00\x00\x00\x07ssh-foo'+'\x00\x00\x00\x01\x01'*5) - - def test_fromStringErrors(self): - """ - Test that fromString raises errors appropriately. - """ - self.assertRaises(keys.BadKeyError, keys.Key.fromString, '') - self.assertRaises(keys.BadKeyError, keys.Key.fromString, '', - 'bad_type') - self.assertRaises(keys.BadKeyError, keys.Key.fromString, - keydata.publicRSA_lsh, passphrase = 'unencrypted') - self.assertRaises(keys.EncryptedKeyError, keys.Key.fromString, - keys.Key(self.rsaObj).toString('openssh', 'encrypted')) - self.assertRaises(keys.BadKeyError, keys.Key.fromString, - '-----BEGIN RSA KEY-----\nwA==\n') - - def test_fromFile(self): - """ - Test that fromFile works correctly. - """ - self.assertEquals(keys.Key.fromFile(self.keyFile), - keys.Key.fromString(keydata.privateRSA_lsh)) - self.assertRaises(keys.BadKeyError, keys.Key.fromFile, - self.keyFile, 'bad_type') - self.assertRaises(keys.BadKeyError, keys.Key.fromFile, - self.keyFile, passphrase='unencrypted') - - def test_init(self): - """ - Test that the PublicKey object is initialized correctly. - """ - obj = Crypto.PublicKey.RSA.construct((1L, 2L)) - key = keys.Key(obj) - self.assertEquals(key.keyObject, obj) - - def test_equal(self): - """ - Test that Key objects are compared correctly. - """ - rsa1 = keys.Key(self.rsaObj) - rsa2 = keys.Key(self.rsaObj) - rsa3 = keys.Key(Crypto.PublicKey.RSA.construct((1L, 2L))) - dsa = keys.Key(self.dsaObj) - self.assertTrue(rsa1 == rsa2) - self.assertFalse(rsa1 == rsa3) - self.assertFalse(rsa1 == dsa) - self.assertFalse(rsa1 == object) - self.assertFalse(rsa1 == None) - - def test_notEqual(self): - """ - Test that Key objects are not-compared correctly. - """ - rsa1 = keys.Key(self.rsaObj) - rsa2 = keys.Key(self.rsaObj) - rsa3 = keys.Key(Crypto.PublicKey.RSA.construct((1L, 2L))) - dsa = keys.Key(self.dsaObj) - self.assertFalse(rsa1 != rsa2) - self.assertTrue(rsa1 != rsa3) - self.assertTrue(rsa1 != dsa) - self.assertTrue(rsa1 != object) - self.assertTrue(rsa1 != None) - - def test_type(self): - """ - Test that the type method returns the correct type for an object. - """ - self.assertEquals(keys.Key(self.rsaObj).type(), 'RSA') - self.assertEquals(keys.Key(self.rsaObj).sshType(), 'ssh-rsa') - self.assertEquals(keys.Key(self.dsaObj).type(), 'DSA') - self.assertEquals(keys.Key(self.dsaObj).sshType(), 'ssh-dss') - self.assertRaises(RuntimeError, keys.Key(None).type) - self.assertRaises(RuntimeError, keys.Key(None).sshType) - self.assertRaises(RuntimeError, keys.Key(self).type) - self.assertRaises(RuntimeError, keys.Key(self).sshType) - - def test_fromBlob(self): - """ - Test that a public key is correctly generated from a public key blob. - """ - rsaBlob = common.NS('ssh-rsa') + common.MP(2) + common.MP(3) - rsaKey = keys.Key.fromString(rsaBlob) - dsaBlob = (common.NS('ssh-dss') + common.MP(2) + common.MP(3) + - common.MP(4) + common.MP(5)) - dsaKey = keys.Key.fromString(dsaBlob) - badBlob = common.NS('ssh-bad') - self.assertTrue(rsaKey.isPublic()) - self.assertEquals(rsaKey.data(), {'e':2L, 'n':3L}) - self.assertTrue(dsaKey.isPublic()) - self.assertEquals(dsaKey.data(), {'p':2L, 'q':3L, 'g':4L, 'y':5L}) - self.assertRaises(keys.BadKeyError, - keys.Key.fromString, badBlob) - - - def test_blob(self): - """ - Test that the Key object generates blobs correctly. - """ - self.assertEquals(keys.Key(self.rsaObj).blob(), - '\x00\x00\x00\x07ssh-rsa\x00\x00\x00\x01\x02' - '\x00\x00\x00\x01\x01') - self.assertEquals(keys.Key(self.dsaObj).blob(), - '\x00\x00\x00\x07ssh-dss\x00\x00\x00\x01\x03' - '\x00\x00\x00\x01\x04\x00\x00\x00\x01\x02' - '\x00\x00\x00\x01\x01') - - badKey = keys.Key(None) - self.assertRaises(RuntimeError, badKey.blob) - - def test_toOpenSSH(self): - """ - Test that the Key object generates OpenSSH keys correctly. - """ - key = keys.Key.fromString(keydata.privateRSA_lsh) - self.assertEquals(key.toString('openssh'), keydata.privateRSA_openssh) - self.assertEquals(key.toString('openssh', 'encrypted'), - keydata.privateRSA_openssh_encrypted) - self.assertEquals(key.public().toString('openssh'), - keydata.publicRSA_openssh[:-8]) # no comment - self.assertEquals(key.public().toString('openssh', 'comment'), - keydata.publicRSA_openssh) - key = keys.Key.fromString(keydata.privateDSA_lsh) - self.assertEquals(key.toString('openssh'), keydata.privateDSA_openssh) - self.assertEquals(key.public().toString('openssh', 'comment'), - keydata.publicDSA_openssh) - self.assertEquals(key.public().toString('openssh'), - keydata.publicDSA_openssh[:-8]) # no comment - - def test_toLSH(self): - """ - Test that the Key object generates LSH keys correctly. - """ - key = keys.Key.fromString(keydata.privateRSA_openssh) - self.assertEquals(key.toString('lsh'), keydata.privateRSA_lsh) - self.assertEquals(key.public().toString('lsh'), - keydata.publicRSA_lsh) - key = keys.Key.fromString(keydata.privateDSA_openssh) - self.assertEquals(key.toString('lsh'), keydata.privateDSA_lsh) - self.assertEquals(key.public().toString('lsh'), - keydata.publicDSA_lsh) - - def test_toAgentv3(self): - """ - Test that the Key object generates Agent v3 keys correctly. - """ - key = keys.Key.fromString(keydata.privateRSA_openssh) - self.assertEquals(key.toString('agentv3'), keydata.privateRSA_agentv3) - key = keys.Key.fromString(keydata.privateDSA_openssh) - self.assertEquals(key.toString('agentv3'), keydata.privateDSA_agentv3) - - def test_toStringErrors(self): - """ - Test that toString raises errors appropriately. - """ - self.assertRaises(keys.BadKeyError, keys.Key(self.rsaObj).toString, - 'bad_type') - - def test_sign(self): - """ - Test that the Key object generates correct signatures. - """ - key = keys.Key.fromString(keydata.privateRSA_openssh) - self.assertEquals(key.sign(''), self.rsaSignature) - key = keys.Key.fromString(keydata.privateDSA_openssh) - self.assertEquals(key.sign(''), self.dsaSignature) - - - def test_verify(self): - """ - Test that the Key object correctly verifies signatures. - """ - key = keys.Key.fromString(keydata.publicRSA_openssh) - self.assertTrue(key.verify(self.rsaSignature, '')) - self.assertFalse(key.verify(self.rsaSignature, 'a')) - self.assertFalse(key.verify(self.dsaSignature, '')) - key = keys.Key.fromString(keydata.publicDSA_openssh) - self.assertTrue(key.verify(self.dsaSignature, '')) - self.assertFalse(key.verify(self.dsaSignature, 'a')) - self.assertFalse(key.verify(self.rsaSignature, '')) - - def test_repr(self): - """ - Test the pretty representation of Key. - """ - self.assertEquals(repr(keys.Key(self.rsaObj)), -"""""") - -class WarningsTestCase(unittest.TestCase): - """ - Test that deprecated functions warn the user of their deprecation. - """ - - def setUp(self): - self.keyObject = keys.Key.fromString(keydata.privateRSA_lsh).keyObject - - def test_getPublicKeyString(self): - """ - Test that getPublicKeyString warns with a DeprecationWarning. - """ - self.assertWarns(DeprecationWarning, - "getPublicKeyString is deprecated since Twisted Conch 0.9." - " Use Key.fromString().", - unittest.__file__, keys.getPublicKeyString, - data=keydata.publicRSA_openssh) - - def test_makePublicKeyString(self): - """ - Test that makePublicKeyString warns with a DeprecationWarning. - """ - self.assertWarns(DeprecationWarning, - "makePublicKeyString is deprecated since Twisted Conch 0.9." - " Use Key(obj).toString().", unittest.__file__, - keys.makePublicKeyString, self.keyObject) - - def test_getPublicKeyObject(self): - """ - Test that getPublicKeyObject warns with a DeprecationWarning. - """ - self.assertWarns(DeprecationWarning, - "getPublicKeyObject is deprecated since Twisted Conch 0.9." - " Use Key.fromString().", unittest.__file__, - keys.getPublicKeyObject, keydata.publicRSA_lsh) - - def test_getPrivateKeyObject(self): - """ - Test that getPrivateKeyObject warns with a DeprecationWarning. - """ - self.assertWarns(DeprecationWarning, - "getPrivateKeyObject is deprecated since Twisted Conch 0.9." - " Use Key.fromString().", unittest.__file__, - keys.getPrivateKeyObject, data=keydata.privateRSA_lsh) - - def test_makePrivateKeyString(self): - """ - Test that makePrivateKeyString warns with a DeprecationWarning. - """ - self.assertWarns(DeprecationWarning, - "makePrivateKeyString is deprecated since Twisted Conch 0.9." - " Use Key(obj).toString().", unittest.__file__, - keys.makePrivateKeyString, self.keyObject) - - def test_makePublicKeyBlob(self): - """ - Test that makePublicKeyBlob warns with a DeprecationWarning. - """ - self.assertWarns(DeprecationWarning, - "makePublicKeyBlob is deprecated since Twisted Conch 0.9." - " Use Key(obj).blob().", unittest.__file__, - keys.makePublicKeyBlob, self.keyObject) - - def test_signData(self): - """ - Test that signData warns with a DeprecationWarning. - """ - self.assertWarns(DeprecationWarning, - "signData is deprecated since Twisted Conch 0.9." - " Use Key(obj).sign(data).", unittest.__file__, - keys.signData, self.keyObject, '') - - def test_verifySignature(self): - """ - Test that signData warns with a DeprecationWarning. - """ - self.assertWarns(DeprecationWarning, - "verifySignature is deprecated since Twisted Conch 0.9." - " Use Key(obj).verify(signature, data).", unittest.__file__, - keys.verifySignature, self.keyObject, '\x00\x00\x00\x00', '') - - def test_printKey(self): - """ - Test that signData warns with a DeprecationWarning. - """ - self.assertWarns(DeprecationWarning, - "printKey is deprecated since Twisted Conch 0.9." - " Use repr(Key(obj)).", unittest.__file__, - keys.printKey, self.keyObject) - diff --git a/tools/buildbot/pylibs/twisted/conch/test/test_manhole.py b/tools/buildbot/pylibs/twisted/conch/test/test_manhole.py deleted file mode 100644 index 9d70d2d..0000000 --- a/tools/buildbot/pylibs/twisted/conch/test/test_manhole.py +++ /dev/null @@ -1,345 +0,0 @@ -# -*- test-case-name: twisted.conch.test.test_manhole -*- -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.conch.manhole}. -""" - -import traceback - -from twisted.trial import unittest -from twisted.internet import error, defer -from twisted.test.proto_helpers import StringTransport -from twisted.conch.test.test_recvline import _TelnetMixin, _SSHMixin, _StdioMixin, stdio, ssh -from twisted.conch import manhole -from twisted.conch.insults import insults - - -def determineDefaultFunctionName(): - """ - Return the string used by Python as the name for code objects which are - compiled from interactive input or at the top-level of modules. - """ - try: - 1 / 0 - except: - return traceback.extract_stack()[0][2] -defaultFunctionName = determineDefaultFunctionName() - - - -class ManholeInterpreterTests(unittest.TestCase): - """ - Tests for L{manhole.ManholeInterpreter}. - """ - def test_resetBuffer(self): - """ - L{ManholeInterpreter.resetBuffer} should empty the input buffer. - """ - interpreter = manhole.ManholeInterpreter(None) - interpreter.buffer.extend(["1", "2"]) - interpreter.resetBuffer() - self.assertFalse(interpreter.buffer) - - - -class ManholeProtocolTests(unittest.TestCase): - """ - Tests for L{manhole.Manhole}. - """ - def test_interruptResetsInterpreterBuffer(self): - """ - L{manhole.Manhole.handle_INT} should cause the interpreter input buffer - to be reset. - """ - transport = StringTransport() - terminal = insults.ServerProtocol(manhole.Manhole) - terminal.makeConnection(transport) - protocol = terminal.terminalProtocol - interpreter = protocol.interpreter - interpreter.buffer.extend(["1", "2"]) - protocol.handle_INT() - self.assertFalse(interpreter.buffer) - - - -class WriterTestCase(unittest.TestCase): - def testInteger(self): - manhole.lastColorizedLine("1") - - - def testDoubleQuoteString(self): - manhole.lastColorizedLine('"1"') - - - def testSingleQuoteString(self): - manhole.lastColorizedLine("'1'") - - - def testTripleSingleQuotedString(self): - manhole.lastColorizedLine("'''1'''") - - - def testTripleDoubleQuotedString(self): - manhole.lastColorizedLine('"""1"""') - - - def testFunctionDefinition(self): - manhole.lastColorizedLine("def foo():") - - - def testClassDefinition(self): - manhole.lastColorizedLine("class foo:") - - -class ManholeLoopbackMixin: - serverProtocol = manhole.ColoredManhole - - def wfd(self, d): - return defer.waitForDeferred(d) - - def testSimpleExpression(self): - done = self.recvlineClient.expect("done") - - self._testwrite( - "1 + 1\n" - "done") - - def finished(ign): - self._assertBuffer( - [">>> 1 + 1", - "2", - ">>> done"]) - - return done.addCallback(finished) - - def testTripleQuoteLineContinuation(self): - done = self.recvlineClient.expect("done") - - self._testwrite( - "'''\n'''\n" - "done") - - def finished(ign): - self._assertBuffer( - [">>> '''", - "... '''", - "'\\n'", - ">>> done"]) - - return done.addCallback(finished) - - def testFunctionDefinition(self): - done = self.recvlineClient.expect("done") - - self._testwrite( - "def foo(bar):\n" - "\tprint bar\n\n" - "foo(42)\n" - "done") - - def finished(ign): - self._assertBuffer( - [">>> def foo(bar):", - "... print bar", - "... ", - ">>> foo(42)", - "42", - ">>> done"]) - - return done.addCallback(finished) - - def testClassDefinition(self): - done = self.recvlineClient.expect("done") - - self._testwrite( - "class Foo:\n" - "\tdef bar(self):\n" - "\t\tprint 'Hello, world!'\n\n" - "Foo().bar()\n" - "done") - - def finished(ign): - self._assertBuffer( - [">>> class Foo:", - "... def bar(self):", - "... print 'Hello, world!'", - "... ", - ">>> Foo().bar()", - "Hello, world!", - ">>> done"]) - - return done.addCallback(finished) - - def testException(self): - done = self.recvlineClient.expect("done") - - self._testwrite( - "1 / 0\n" - "done") - - def finished(ign): - self._assertBuffer( - [">>> 1 / 0", - "Traceback (most recent call last):", - ' File "", line 1, in ' + defaultFunctionName, - "ZeroDivisionError: integer division or modulo by zero", - ">>> done"]) - - return done.addCallback(finished) - - def testControlC(self): - done = self.recvlineClient.expect("done") - - self._testwrite( - "cancelled line" + manhole.CTRL_C + - "done") - - def finished(ign): - self._assertBuffer( - [">>> cancelled line", - "KeyboardInterrupt", - ">>> done"]) - - return done.addCallback(finished) - - - def test_interruptDuringContinuation(self): - """ - Sending ^C to Manhole while in a state where more input is required to - complete a statement should discard the entire ongoing statement and - reset the input prompt to the non-continuation prompt. - """ - continuing = self.recvlineClient.expect("things") - - self._testwrite("(\nthings") - - def gotContinuation(ignored): - self._assertBuffer( - [">>> (", - "... things"]) - interrupted = self.recvlineClient.expect(">>> ") - self._testwrite(manhole.CTRL_C) - return interrupted - continuing.addCallback(gotContinuation) - - def gotInterruption(ignored): - self._assertBuffer( - [">>> (", - "... things", - "KeyboardInterrupt", - ">>> "]) - continuing.addCallback(gotInterruption) - return continuing - - - def testControlBackslash(self): - self._testwrite("cancelled line") - partialLine = self.recvlineClient.expect("cancelled line") - - def gotPartialLine(ign): - self._assertBuffer( - [">>> cancelled line"]) - self._testwrite(manhole.CTRL_BACKSLASH) - - d = self.recvlineClient.onDisconnection - return self.assertFailure(d, error.ConnectionDone) - - def gotClearedLine(ign): - self._assertBuffer( - [""]) - - return partialLine.addCallback(gotPartialLine).addCallback(gotClearedLine) - - def testControlD(self): - self._testwrite("1 + 1") - helloWorld = self.wfd(self.recvlineClient.expect(r"\+ 1")) - yield helloWorld - helloWorld.getResult() - self._assertBuffer([">>> 1 + 1"]) - - self._testwrite(manhole.CTRL_D + " + 1") - cleared = self.wfd(self.recvlineClient.expect(r"\+ 1")) - yield cleared - cleared.getResult() - self._assertBuffer([">>> 1 + 1 + 1"]) - - self._testwrite("\n") - printed = self.wfd(self.recvlineClient.expect("3\n>>> ")) - yield printed - printed.getResult() - - self._testwrite(manhole.CTRL_D) - d = self.recvlineClient.onDisconnection - disconnected = self.wfd(self.assertFailure(d, error.ConnectionDone)) - yield disconnected - disconnected.getResult() - testControlD = defer.deferredGenerator(testControlD) - - - def testControlL(self): - """ - CTRL+L is generally used as a redraw-screen command in terminal - applications. Manhole doesn't currently respect this usage of it, - but it should at least do something reasonable in response to this - event (rather than, say, eating your face). - """ - # Start off with a newline so that when we clear the display we can - # tell by looking for the missing first empty prompt line. - self._testwrite("\n1 + 1") - helloWorld = self.wfd(self.recvlineClient.expect(r"\+ 1")) - yield helloWorld - helloWorld.getResult() - self._assertBuffer([">>> ", ">>> 1 + 1"]) - - self._testwrite(manhole.CTRL_L + " + 1") - redrew = self.wfd(self.recvlineClient.expect(r"1 \+ 1 \+ 1")) - yield redrew - redrew.getResult() - self._assertBuffer([">>> 1 + 1 + 1"]) - testControlL = defer.deferredGenerator(testControlL) - - - def testDeferred(self): - self._testwrite( - "from twisted.internet import defer, reactor\n" - "d = defer.Deferred()\n" - "d\n") - - deferred = self.wfd(self.recvlineClient.expect("")) - yield deferred - deferred.getResult() - - self._testwrite( - "c = reactor.callLater(0.1, d.callback, 'Hi!')\n") - delayed = self.wfd(self.recvlineClient.expect(">>> ")) - yield delayed - delayed.getResult() - - called = self.wfd(self.recvlineClient.expect("Deferred #0 called back: 'Hi!'\n>>> ")) - yield called - called.getResult() - self._assertBuffer( - [">>> from twisted.internet import defer, reactor", - ">>> d = defer.Deferred()", - ">>> d", - "", - ">>> c = reactor.callLater(0.1, d.callback, 'Hi!')", - "Deferred #0 called back: 'Hi!'", - ">>> "]) - - testDeferred = defer.deferredGenerator(testDeferred) - -class ManholeLoopbackTelnet(_TelnetMixin, unittest.TestCase, ManholeLoopbackMixin): - pass - -class ManholeLoopbackSSH(_SSHMixin, unittest.TestCase, ManholeLoopbackMixin): - if ssh is None: - skip = "Crypto requirements missing, can't run manhole tests over ssh" - -class ManholeLoopbackStdio(_StdioMixin, unittest.TestCase, ManholeLoopbackMixin): - if stdio is None: - skip = "Terminal requirements missing, can't run manhole tests over stdio" - else: - serverProtocol = stdio.ConsoleManhole diff --git a/tools/buildbot/pylibs/twisted/conch/test/test_mixin.py b/tools/buildbot/pylibs/twisted/conch/test/test_mixin.py deleted file mode 100644 index b35a89f..0000000 --- a/tools/buildbot/pylibs/twisted/conch/test/test_mixin.py +++ /dev/null @@ -1,47 +0,0 @@ -# -*- twisted.conch.test.test_mixin -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -import time - -from twisted.internet import reactor, protocol - -from twisted.trial import unittest -from twisted.test.proto_helpers import StringTransport - -from twisted.conch import mixin - - -class TestBufferingProto(mixin.BufferingMixin): - scheduled = False - rescheduled = 0 - def schedule(self): - self.scheduled = True - return object() - - def reschedule(self, token): - self.rescheduled += 1 - - - -class BufferingTest(unittest.TestCase): - def testBuffering(self): - p = TestBufferingProto() - t = p.transport = StringTransport() - - self.failIf(p.scheduled) - - L = ['foo', 'bar', 'baz', 'quux'] - - p.write('foo') - self.failUnless(p.scheduled) - self.failIf(p.rescheduled) - - for s in L: - n = p.rescheduled - p.write(s) - self.assertEquals(p.rescheduled, n + 1) - self.assertEquals(t.value(), '') - - p.flush() - self.assertEquals(t.value(), 'foo' + ''.join(L)) diff --git a/tools/buildbot/pylibs/twisted/conch/test/test_recvline.py b/tools/buildbot/pylibs/twisted/conch/test/test_recvline.py deleted file mode 100644 index a01d15a..0000000 --- a/tools/buildbot/pylibs/twisted/conch/test/test_recvline.py +++ /dev/null @@ -1,648 +0,0 @@ -# -*- test-case-name: twisted.conch.test.test_recvline -*- -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.conch.recvline} and fixtures for testing related -functionality. -""" - -import sys, os - -from twisted.conch.insults import insults -from twisted.conch import recvline - -from twisted.python import reflect, components -from twisted.internet import defer, error -from twisted.trial import unittest -from twisted.cred import portal -from twisted.test.proto_helpers import StringTransport - -class Arrows(unittest.TestCase): - def setUp(self): - self.underlyingTransport = StringTransport() - self.pt = insults.ServerProtocol() - self.p = recvline.HistoricRecvLine() - self.pt.protocolFactory = lambda: self.p - self.pt.factory = self - self.pt.makeConnection(self.underlyingTransport) - # self.p.makeConnection(self.pt) - - def testPrintableCharacters(self): - self.p.keystrokeReceived('x', None) - self.p.keystrokeReceived('y', None) - self.p.keystrokeReceived('z', None) - - self.assertEquals(self.p.currentLineBuffer(), ('xyz', '')) - - def testHorizontalArrows(self): - kR = lambda ch: self.p.keystrokeReceived(ch, None) - for ch in 'xyz': - kR(ch) - - self.assertEquals(self.p.currentLineBuffer(), ('xyz', '')) - - kR(self.pt.RIGHT_ARROW) - self.assertEquals(self.p.currentLineBuffer(), ('xyz', '')) - - kR(self.pt.LEFT_ARROW) - self.assertEquals(self.p.currentLineBuffer(), ('xy', 'z')) - - kR(self.pt.LEFT_ARROW) - self.assertEquals(self.p.currentLineBuffer(), ('x', 'yz')) - - kR(self.pt.LEFT_ARROW) - self.assertEquals(self.p.currentLineBuffer(), ('', 'xyz')) - - kR(self.pt.LEFT_ARROW) - self.assertEquals(self.p.currentLineBuffer(), ('', 'xyz')) - - kR(self.pt.RIGHT_ARROW) - self.assertEquals(self.p.currentLineBuffer(), ('x', 'yz')) - - kR(self.pt.RIGHT_ARROW) - self.assertEquals(self.p.currentLineBuffer(), ('xy', 'z')) - - kR(self.pt.RIGHT_ARROW) - self.assertEquals(self.p.currentLineBuffer(), ('xyz', '')) - - kR(self.pt.RIGHT_ARROW) - self.assertEquals(self.p.currentLineBuffer(), ('xyz', '')) - - def testNewline(self): - kR = lambda ch: self.p.keystrokeReceived(ch, None) - - for ch in 'xyz\nabc\n123\n': - kR(ch) - - self.assertEquals(self.p.currentHistoryBuffer(), - (('xyz', 'abc', '123'), ())) - - kR('c') - kR('b') - kR('a') - self.assertEquals(self.p.currentHistoryBuffer(), - (('xyz', 'abc', '123'), ())) - - kR('\n') - self.assertEquals(self.p.currentHistoryBuffer(), - (('xyz', 'abc', '123', 'cba'), ())) - - def testVerticalArrows(self): - kR = lambda ch: self.p.keystrokeReceived(ch, None) - - for ch in 'xyz\nabc\n123\n': - kR(ch) - - self.assertEquals(self.p.currentHistoryBuffer(), - (('xyz', 'abc', '123'), ())) - self.assertEquals(self.p.currentLineBuffer(), ('', '')) - - kR(self.pt.UP_ARROW) - self.assertEquals(self.p.currentHistoryBuffer(), - (('xyz', 'abc'), ('123',))) - self.assertEquals(self.p.currentLineBuffer(), ('123', '')) - - kR(self.pt.UP_ARROW) - self.assertEquals(self.p.currentHistoryBuffer(), - (('xyz',), ('abc', '123'))) - self.assertEquals(self.p.currentLineBuffer(), ('abc', '')) - - kR(self.pt.UP_ARROW) - self.assertEquals(self.p.currentHistoryBuffer(), - ((), ('xyz', 'abc', '123'))) - self.assertEquals(self.p.currentLineBuffer(), ('xyz', '')) - - kR(self.pt.UP_ARROW) - self.assertEquals(self.p.currentHistoryBuffer(), - ((), ('xyz', 'abc', '123'))) - self.assertEquals(self.p.currentLineBuffer(), ('xyz', '')) - - for i in range(4): - kR(self.pt.DOWN_ARROW) - self.assertEquals(self.p.currentHistoryBuffer(), - (('xyz', 'abc', '123'), ())) - - def testHome(self): - kR = lambda ch: self.p.keystrokeReceived(ch, None) - - for ch in 'hello, world': - kR(ch) - self.assertEquals(self.p.currentLineBuffer(), ('hello, world', '')) - - kR(self.pt.HOME) - self.assertEquals(self.p.currentLineBuffer(), ('', 'hello, world')) - - def testEnd(self): - kR = lambda ch: self.p.keystrokeReceived(ch, None) - - for ch in 'hello, world': - kR(ch) - self.assertEquals(self.p.currentLineBuffer(), ('hello, world', '')) - - kR(self.pt.HOME) - kR(self.pt.END) - self.assertEquals(self.p.currentLineBuffer(), ('hello, world', '')) - - def testBackspace(self): - kR = lambda ch: self.p.keystrokeReceived(ch, None) - - for ch in 'xyz': - kR(ch) - self.assertEquals(self.p.currentLineBuffer(), ('xyz', '')) - - kR(self.pt.BACKSPACE) - self.assertEquals(self.p.currentLineBuffer(), ('xy', '')) - - kR(self.pt.LEFT_ARROW) - kR(self.pt.BACKSPACE) - self.assertEquals(self.p.currentLineBuffer(), ('', 'y')) - - kR(self.pt.BACKSPACE) - self.assertEquals(self.p.currentLineBuffer(), ('', 'y')) - - def testDelete(self): - kR = lambda ch: self.p.keystrokeReceived(ch, None) - - for ch in 'xyz': - kR(ch) - self.assertEquals(self.p.currentLineBuffer(), ('xyz', '')) - - kR(self.pt.DELETE) - self.assertEquals(self.p.currentLineBuffer(), ('xyz', '')) - - kR(self.pt.LEFT_ARROW) - kR(self.pt.DELETE) - self.assertEquals(self.p.currentLineBuffer(), ('xy', '')) - - kR(self.pt.LEFT_ARROW) - kR(self.pt.DELETE) - self.assertEquals(self.p.currentLineBuffer(), ('x', '')) - - kR(self.pt.LEFT_ARROW) - kR(self.pt.DELETE) - self.assertEquals(self.p.currentLineBuffer(), ('', '')) - - kR(self.pt.DELETE) - self.assertEquals(self.p.currentLineBuffer(), ('', '')) - - def testInsert(self): - kR = lambda ch: self.p.keystrokeReceived(ch, None) - - for ch in 'xyz': - kR(ch) - - # kR(self.pt.INSERT) - - kR(self.pt.LEFT_ARROW) - kR('A') - self.assertEquals(self.p.currentLineBuffer(), ('xyA', 'z')) - - kR(self.pt.LEFT_ARROW) - kR('B') - self.assertEquals(self.p.currentLineBuffer(), ('xyB', 'Az')) - - def testTypeover(self): - kR = lambda ch: self.p.keystrokeReceived(ch, None) - - for ch in 'xyz': - kR(ch) - - kR(self.pt.INSERT) - - kR(self.pt.LEFT_ARROW) - kR('A') - self.assertEquals(self.p.currentLineBuffer(), ('xyA', '')) - - kR(self.pt.LEFT_ARROW) - kR('B') - self.assertEquals(self.p.currentLineBuffer(), ('xyB', '')) - - -from twisted.conch import telnet -from twisted.conch.insults import helper -from twisted.protocols import loopback - -class EchoServer(recvline.HistoricRecvLine): - def lineReceived(self, line): - self.terminal.write(line + '\n' + self.ps[self.pn]) - -# An insults API for this would be nice. -left = "\x1b[D" -right = "\x1b[C" -up = "\x1b[A" -down = "\x1b[B" -insert = "\x1b[2~" -home = "\x1b[1~" -delete = "\x1b[3~" -end = "\x1b[4~" -backspace = "\x7f" - -from twisted.cred import checkers - -try: - from twisted.conch.ssh import userauth, transport, channel, connection, session - from twisted.conch.manhole_ssh import TerminalUser, TerminalSession, TerminalRealm, TerminalSessionTransport, ConchFactory -except ImportError: - ssh = False -else: - ssh = True - class SessionChannel(channel.SSHChannel): - name = 'session' - - def __init__(self, protocolFactory, protocolArgs, protocolKwArgs, width, height, *a, **kw): - channel.SSHChannel.__init__(self, *a, **kw) - - self.protocolFactory = protocolFactory - self.protocolArgs = protocolArgs - self.protocolKwArgs = protocolKwArgs - - self.width = width - self.height = height - - def channelOpen(self, data): - term = session.packRequest_pty_req("vt102", (self.height, self.width, 0, 0), '') - self.conn.sendRequest(self, 'pty-req', term) - self.conn.sendRequest(self, 'shell', '') - - self._protocolInstance = self.protocolFactory(*self.protocolArgs, **self.protocolKwArgs) - self._protocolInstance.factory = self - self._protocolInstance.makeConnection(self) - - def closed(self): - self._protocolInstance.connectionLost(error.ConnectionDone()) - - def dataReceived(self, data): - self._protocolInstance.dataReceived(data) - - class TestConnection(connection.SSHConnection): - def __init__(self, protocolFactory, protocolArgs, protocolKwArgs, width, height, *a, **kw): - connection.SSHConnection.__init__(self, *a, **kw) - - self.protocolFactory = protocolFactory - self.protocolArgs = protocolArgs - self.protocolKwArgs = protocolKwArgs - - self.width = width - self.height = height - - def serviceStarted(self): - self.__channel = SessionChannel(self.protocolFactory, self.protocolArgs, self.protocolKwArgs, self.width, self.height) - self.openChannel(self.__channel) - - def write(self, bytes): - return self.__channel.write(bytes) - - class TestAuth(userauth.SSHUserAuthClient): - def __init__(self, username, password, *a, **kw): - userauth.SSHUserAuthClient.__init__(self, username, *a, **kw) - self.password = password - - def getPassword(self): - return defer.succeed(self.password) - - class TestTransport(transport.SSHClientTransport): - def __init__(self, protocolFactory, protocolArgs, protocolKwArgs, username, password, width, height, *a, **kw): - # transport.SSHClientTransport.__init__(self, *a, **kw) - self.protocolFactory = protocolFactory - self.protocolArgs = protocolArgs - self.protocolKwArgs = protocolKwArgs - self.username = username - self.password = password - self.width = width - self.height = height - - def verifyHostKey(self, hostKey, fingerprint): - return defer.succeed(True) - - def connectionSecure(self): - self.__connection = TestConnection(self.protocolFactory, self.protocolArgs, self.protocolKwArgs, self.width, self.height) - self.requestService( - TestAuth(self.username, self.password, self.__connection)) - - def write(self, bytes): - return self.__connection.write(bytes) - - class TestSessionTransport(TerminalSessionTransport): - def protocolFactory(self): - return self.avatar.conn.transport.factory.serverProtocol() - - class TestSession(TerminalSession): - transportFactory = TestSessionTransport - - class TestUser(TerminalUser): - pass - - components.registerAdapter(TestSession, TestUser, session.ISession) - - -class LoopbackRelay(loopback.LoopbackRelay): - clearCall = None - - def logPrefix(self): - return "LoopbackRelay(%r)" % (self.target.__class__.__name__,) - - def write(self, bytes): - loopback.LoopbackRelay.write(self, bytes) - if self.clearCall is not None: - self.clearCall.cancel() - - from twisted.internet import reactor - self.clearCall = reactor.callLater(0, self._clearBuffer) - - def _clearBuffer(self): - self.clearCall = None - loopback.LoopbackRelay.clearBuffer(self) - - -class NotifyingExpectableBuffer(helper.ExpectableBuffer): - def __init__(self): - self.onConnection = defer.Deferred() - self.onDisconnection = defer.Deferred() - - def connectionMade(self): - helper.ExpectableBuffer.connectionMade(self) - self.onConnection.callback(self) - - def connectionLost(self, reason): - self.onDisconnection.errback(reason) - - -class _BaseMixin: - WIDTH = 80 - HEIGHT = 24 - - def _assertBuffer(self, lines): - receivedLines = str(self.recvlineClient).splitlines() - expectedLines = lines + ([''] * (self.HEIGHT - len(lines) - 1)) - self.assertEquals(len(receivedLines), len(expectedLines)) - for i in range(len(receivedLines)): - self.assertEquals( - receivedLines[i], expectedLines[i], - str(receivedLines[max(0, i-1):i+1]) + - " != " + - str(expectedLines[max(0, i-1):i+1])) - - def _trivialTest(self, input, output): - done = self.recvlineClient.expect("done") - - self._testwrite(input) - - def finished(ign): - self._assertBuffer(output) - - return done.addCallback(finished) - - -class _SSHMixin(_BaseMixin): - def setUp(self): - if not ssh: - raise unittest.SkipTest("Crypto requirements missing, can't run historic recvline tests over ssh") - - u, p = 'testuser', 'testpass' - rlm = TerminalRealm() - rlm.userFactory = TestUser - rlm.chainedProtocolFactory = lambda: insultsServer - - ptl = portal.Portal( - rlm, - [checkers.InMemoryUsernamePasswordDatabaseDontUse(**{u: p})]) - sshFactory = ConchFactory(ptl) - sshFactory.serverProtocol = self.serverProtocol - sshFactory.startFactory() - - recvlineServer = self.serverProtocol() - insultsServer = insults.ServerProtocol(lambda: recvlineServer) - sshServer = sshFactory.buildProtocol(None) - clientTransport = LoopbackRelay(sshServer) - - recvlineClient = NotifyingExpectableBuffer() - insultsClient = insults.ClientProtocol(lambda: recvlineClient) - sshClient = TestTransport(lambda: insultsClient, (), {}, u, p, self.WIDTH, self.HEIGHT) - serverTransport = LoopbackRelay(sshClient) - - sshClient.makeConnection(clientTransport) - sshServer.makeConnection(serverTransport) - - self.recvlineClient = recvlineClient - self.sshClient = sshClient - self.sshServer = sshServer - self.clientTransport = clientTransport - self.serverTransport = serverTransport - - return recvlineClient.onConnection - - def _testwrite(self, bytes): - self.sshClient.write(bytes) - -from twisted.conch.test import test_telnet - -class TestInsultsClientProtocol(insults.ClientProtocol, - test_telnet.TestProtocol): - pass - - -class TestInsultsServerProtocol(insults.ServerProtocol, - test_telnet.TestProtocol): - pass - -class _TelnetMixin(_BaseMixin): - def setUp(self): - recvlineServer = self.serverProtocol() - insultsServer = TestInsultsServerProtocol(lambda: recvlineServer) - telnetServer = telnet.TelnetTransport(lambda: insultsServer) - clientTransport = LoopbackRelay(telnetServer) - - recvlineClient = NotifyingExpectableBuffer() - insultsClient = TestInsultsClientProtocol(lambda: recvlineClient) - telnetClient = telnet.TelnetTransport(lambda: insultsClient) - serverTransport = LoopbackRelay(telnetClient) - - telnetClient.makeConnection(clientTransport) - telnetServer.makeConnection(serverTransport) - - serverTransport.clearBuffer() - clientTransport.clearBuffer() - - self.recvlineClient = recvlineClient - self.telnetClient = telnetClient - self.clientTransport = clientTransport - self.serverTransport = serverTransport - - return recvlineClient.onConnection - - def _testwrite(self, bytes): - self.telnetClient.write(bytes) - -try: - from twisted.conch import stdio -except ImportError: - stdio = None - -class _StdioMixin(_BaseMixin): - def setUp(self): - # A memory-only terminal emulator, into which the server will - # write things and make other state changes. What ends up - # here is basically what a user would have seen on their - # screen. - testTerminal = NotifyingExpectableBuffer() - - # An insults client protocol which will translate bytes - # received from the child process into keystroke commands for - # an ITerminalProtocol. - insultsClient = insults.ClientProtocol(lambda: testTerminal) - - # A process protocol which will translate stdout and stderr - # received from the child process to dataReceived calls and - # error reporting on an insults client protocol. - processClient = stdio.TerminalProcessProtocol(insultsClient) - - # Run twisted/conch/stdio.py with the name of a class - # implementing ITerminalProtocol. This class will be used to - # handle bytes we send to the child process. - exe = sys.executable - module = stdio.__file__ - if module.endswith('.pyc') or module.endswith('.pyo'): - module = module[:-1] - args = [exe, module, reflect.qual(self.serverProtocol)] - env = {"PYTHONPATH": os.pathsep.join(sys.path)} - - from twisted.internet import reactor - clientTransport = reactor.spawnProcess(processClient, exe, args, - env=env, usePTY=True) - - self.recvlineClient = self.testTerminal = testTerminal - self.processClient = processClient - self.clientTransport = clientTransport - - # Wait for the process protocol and test terminal to become - # connected before proceeding. The former should always - # happen first, but it doesn't hurt to be safe. - return defer.gatherResults(filter(None, [ - processClient.onConnection, - testTerminal.expect(">>> ")])) - - def tearDown(self): - # Kill the child process. We're done with it. - try: - self.clientTransport.signalProcess("KILL") - except (error.ProcessExitedAlready, OSError): - pass - def trap(failure): - failure.trap(error.ProcessTerminated) - self.assertEquals(failure.value.exitCode, None) - self.assertEquals(failure.value.status, 9) - return self.testTerminal.onDisconnection.addErrback(trap) - - def _testwrite(self, bytes): - self.clientTransport.write(bytes) - -class RecvlineLoopbackMixin: - serverProtocol = EchoServer - - def testSimple(self): - return self._trivialTest( - "first line\ndone", - [">>> first line", - "first line", - ">>> done"]) - - def testLeftArrow(self): - return self._trivialTest( - insert + 'first line' + left * 4 + "xxxx\ndone", - [">>> first xxxx", - "first xxxx", - ">>> done"]) - - def testRightArrow(self): - return self._trivialTest( - insert + 'right line' + left * 4 + right * 2 + "xx\ndone", - [">>> right lixx", - "right lixx", - ">>> done"]) - - def testBackspace(self): - return self._trivialTest( - "second line" + backspace * 4 + "xxxx\ndone", - [">>> second xxxx", - "second xxxx", - ">>> done"]) - - def testDelete(self): - return self._trivialTest( - "delete xxxx" + left * 4 + delete * 4 + "line\ndone", - [">>> delete line", - "delete line", - ">>> done"]) - - def testInsert(self): - return self._trivialTest( - "third ine" + left * 3 + "l\ndone", - [">>> third line", - "third line", - ">>> done"]) - - def testTypeover(self): - return self._trivialTest( - "fourth xine" + left * 4 + insert + "l\ndone", - [">>> fourth line", - "fourth line", - ">>> done"]) - - def testHome(self): - return self._trivialTest( - insert + "blah line" + home + "home\ndone", - [">>> home line", - "home line", - ">>> done"]) - - def testEnd(self): - return self._trivialTest( - "end " + left * 4 + end + "line\ndone", - [">>> end line", - "end line", - ">>> done"]) - -class RecvlineLoopbackTelnet(_TelnetMixin, unittest.TestCase, RecvlineLoopbackMixin): - pass - -class RecvlineLoopbackSSH(_SSHMixin, unittest.TestCase, RecvlineLoopbackMixin): - pass - -class RecvlineLoopbackStdio(_StdioMixin, unittest.TestCase, RecvlineLoopbackMixin): - if stdio is None: - skip = "Terminal requirements missing, can't run recvline tests over stdio" - - -class HistoricRecvlineLoopbackMixin: - serverProtocol = EchoServer - - def testUpArrow(self): - return self._trivialTest( - "first line\n" + up + "\ndone", - [">>> first line", - "first line", - ">>> first line", - "first line", - ">>> done"]) - - def testDownArrow(self): - return self._trivialTest( - "first line\nsecond line\n" + up * 2 + down + "\ndone", - [">>> first line", - "first line", - ">>> second line", - "second line", - ">>> second line", - "second line", - ">>> done"]) - -class HistoricRecvlineLoopbackTelnet(_TelnetMixin, unittest.TestCase, HistoricRecvlineLoopbackMixin): - pass - -class HistoricRecvlineLoopbackSSH(_SSHMixin, unittest.TestCase, HistoricRecvlineLoopbackMixin): - pass - -class HistoricRecvlineLoopbackStdio(_StdioMixin, unittest.TestCase, HistoricRecvlineLoopbackMixin): - if stdio is None: - skip = "Terminal requirements missing, can't run historic recvline tests over stdio" diff --git a/tools/buildbot/pylibs/twisted/conch/test/test_ssh.py b/tools/buildbot/pylibs/twisted/conch/test/test_ssh.py deleted file mode 100644 index 7443e8e..0000000 --- a/tools/buildbot/pylibs/twisted/conch/test/test_ssh.py +++ /dev/null @@ -1,844 +0,0 @@ -# -*- test-case-name: twisted.conch.test.test_ssh -*- -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -try: - import Crypto -except ImportError: - Crypto = None - -from twisted.conch.ssh import common, session, forwarding -from twisted.conch import avatar, error -from twisted.conch.test.keydata import publicRSA_openssh, privateRSA_openssh -from twisted.conch.test.keydata import publicDSA_openssh, privateDSA_openssh -from twisted.cred import portal -from twisted.internet import defer, protocol, reactor -from twisted.internet.error import ProcessTerminated -from twisted.python import failure, log -from twisted.trial import unittest - -from test_recvline import LoopbackRelay - -import struct - - -class ConchTestRealm: - - def requestAvatar(self, avatarID, mind, *interfaces): - unittest.assertEquals(avatarID, 'testuser') - a = ConchTestAvatar() - return interfaces[0], a, a.logout - -class ConchTestAvatar(avatar.ConchUser): - loggedOut = False - - def __init__(self): - avatar.ConchUser.__init__(self) - self.listeners = {} - self.channelLookup.update({'session': session.SSHSession, - 'direct-tcpip':forwarding.openConnectForwardingClient}) - self.subsystemLookup.update({'crazy': CrazySubsystem}) - - def global_foo(self, data): - unittest.assertEquals(data, 'bar') - return 1 - - def global_foo_2(self, data): - unittest.assertEquals(data, 'bar2') - return 1, 'data' - - def global_tcpip_forward(self, data): - host, port = forwarding.unpackGlobal_tcpip_forward(data) - try: listener = reactor.listenTCP(port, - forwarding.SSHListenForwardingFactory(self.conn, - (host, port), - forwarding.SSHListenServerForwardingChannel), - interface = host) - except: - log.err() - unittest.fail("something went wrong with remote->local forwarding") - return 0 - else: - self.listeners[(host, port)] = listener - return 1 - - def global_cancel_tcpip_forward(self, data): - host, port = forwarding.unpackGlobal_tcpip_forward(data) - listener = self.listeners.get((host, port), None) - if not listener: - return 0 - del self.listeners[(host, port)] - listener.stopListening() - return 1 - - def logout(self): - loggedOut = True - for listener in self.listeners.values(): - log.msg('stopListening %s' % listener) - listener.stopListening() - -class ConchSessionForTestAvatar: - - def __init__(self, avatar): - unittest.assert_(isinstance(avatar, ConchTestAvatar)) - self.avatar = avatar - self.cmd = None - self.proto = None - self.ptyReq = False - self.eof = 0 - - def getPty(self, term, windowSize, attrs): - log.msg('pty req') - unittest.assertEquals(term, 'conch-test-term') - unittest.assertEquals(windowSize, (24, 80, 0, 0)) - self.ptyReq = True - - def openShell(self, proto): - log.msg('openning shell') - unittest.assertEquals(self.ptyReq, True) - self.proto = proto - EchoTransport(proto) - self.cmd = 'shell' - - def execCommand(self, proto, cmd): - self.cmd = cmd - unittest.assert_(cmd.split()[0] in ['false', 'echo', 'secho', 'eecho','jumboliah'], - 'invalid command: %s' % cmd.split()[0]) - if cmd == 'jumboliah': - raise error.ConchError('bad exec') - self.proto = proto - f = cmd.split()[0] - if f == 'false': - FalseTransport(proto) - elif f == 'echo': - t = EchoTransport(proto) - t.write(cmd[5:]) - t.loseConnection() - elif f == 'secho': - t = SuperEchoTransport(proto) - t.write(cmd[6:]) - t.loseConnection() - elif f == 'eecho': - t = ErrEchoTransport(proto) - t.write(cmd[6:]) - t.loseConnection() - self.avatar.conn.transport.expectedLoseConnection = 1 - -# def closeReceived(self): -# #if self.proto: -# # self.proto.transport.loseConnection() -# self.loseConnection() - - def eofReceived(self): - self.eof = 1 - - def closed(self): - log.msg('closed cmd "%s"' % self.cmd) - if self.cmd == 'echo hello': - rwl = self.proto.session.remoteWindowLeft - unittest.assertEquals(rwl, 4) - elif self.cmd == 'eecho hello': - rwl = self.proto.session.remoteWindowLeft - unittest.assertEquals(rwl, 4) - elif self.cmd == 'shell': - unittest.assert_(self.eof) - -from twisted.python import components -components.registerAdapter(ConchSessionForTestAvatar, ConchTestAvatar, session.ISession) - -class CrazySubsystem(protocol.Protocol): - - def __init__(self, *args, **kw): - pass - - def connectionMade(self): - """ - good ... good - """ - -class FalseTransport: - - def __init__(self, p): - p.makeConnection(self) - p.processEnded(failure.Failure(ProcessTerminated(255, None, None))) - - def loseConnection(self): - pass - -class EchoTransport: - - def __init__(self, p): - self.proto = p - p.makeConnection(self) - self.closed = 0 - - def write(self, data): - log.msg(repr(data)) - self.proto.outReceived(data) - self.proto.outReceived('\r\n') - if '\x00' in data: # mimic 'exit' for the shell test - self.loseConnection() - - def loseConnection(self): - if self.closed: return - self.closed = 1 - self.proto.inConnectionLost() - self.proto.outConnectionLost() - self.proto.errConnectionLost() - self.proto.processEnded(failure.Failure(ProcessTerminated(0, None, None))) - -class ErrEchoTransport: - - def __init__(self, p): - self.proto = p - p.makeConnection(self) - self.closed = 0 - - def write(self, data): - self.proto.errReceived(data) - self.proto.errReceived('\r\n') - - def loseConnection(self): - if self.closed: return - self.closed = 1 - self.proto.inConnectionLost() - self.proto.outConnectionLost() - self.proto.errConnectionLost() - self.proto.processEnded(failure.Failure(ProcessTerminated(0, None, None))) - -class SuperEchoTransport: - - def __init__(self, p): - self.proto = p - p.makeConnection(self) - self.closed = 0 - - def write(self, data): - self.proto.outReceived(data) - self.proto.outReceived('\r\n') - self.proto.errReceived(data) - self.proto.errReceived('\r\n') - - def loseConnection(self): - if self.closed: return - self.closed = 1 - self.proto.inConnectionLost() - self.proto.outConnectionLost() - self.proto.errConnectionLost() - self.proto.processEnded(failure.Failure(ProcessTerminated(0, None, None))) - - -if Crypto: # stuff that needs PyCrypto to even import - from twisted.conch import checkers - from twisted.conch.ssh import channel, connection, factory, keys - from twisted.conch.ssh import transport, userauth - - class UtilityTestCase(unittest.TestCase): - def testCounter(self): - c = transport._Counter('\x00\x00', 2) - for i in xrange(256 * 256): - self.assertEquals(c(), struct.pack('!H', (i + 1) % (2 ** 16))) - # It should wrap around, too. - for i in xrange(256 * 256): - self.assertEquals(c(), struct.pack('!H', (i + 1) % (2 ** 16))) - - - class ConchTestPublicKeyChecker(checkers.SSHPublicKeyDatabase): - def checkKey(self, credentials): - unittest.assertEquals(credentials.username, 'testuser', 'bad username') - unittest.assertEquals(credentials.blob, keys.getPublicKeyString(data=publicDSA_openssh)) - return 1 - - class ConchTestPasswordChecker: - credentialInterfaces = checkers.IUsernamePassword, - - def requestAvatarId(self, credentials): - unittest.assertEquals(credentials.username, 'testuser', 'bad username') - unittest.assertEquals(credentials.password, 'testpass', 'bad password') - return defer.succeed(credentials.username) - - class ConchTestSSHChecker(checkers.SSHProtocolChecker): - - def areDone(self, avatarId): - unittest.assertEquals(avatarId, 'testuser') - if len(self.successfulCredentials[avatarId]) < 2: - return 0 - else: - return 1 - - class ConchTestServerFactory(factory.SSHFactory): - noisy = 0 - - services = { - 'ssh-userauth':userauth.SSHUserAuthServer, - 'ssh-connection':connection.SSHConnection - } - - def buildProtocol(self, addr): - proto = ConchTestServer() - proto.supportedPublicKeys = self.privateKeys.keys() - proto.factory = self - - if hasattr(self, 'expectedLoseConnection'): - proto.expectedLoseConnection = self.expectedLoseConnection - - self.proto = proto - return proto - - def getPublicKeys(self): - return { - 'ssh-rsa':keys.getPublicKeyString(data=publicRSA_openssh), - 'ssh-dss':keys.getPublicKeyString(data=publicDSA_openssh) - } - - def getPrivateKeys(self): - return { - 'ssh-rsa':keys.getPrivateKeyObject(data=privateRSA_openssh), - 'ssh-dss':keys.getPrivateKeyObject(data=privateDSA_openssh) - } - - def getPrimes(self): - return { - 2048:[(transport.DH_GENERATOR, transport.DH_PRIME)] - } - - def getService(self, trans, name): - return factory.SSHFactory.getService(self, trans, name) - - class ConchTestBase: - - done = 0 - allowedToError = 0 - - def connectionLost(self, reason): - if self.done: - return - if not hasattr(self,'expectedLoseConnection'): - unittest.fail('unexpectedly lost connection %s\n%s' % (self, reason)) - self.done = 1 - - def receiveError(self, reasonCode, desc): - self.expectedLoseConnection = 1 - if not self.allowedToError: - unittest.fail('got disconnect for %s: reason %s, desc: %s' % - (self, reasonCode, desc)) - self.loseConnection() - - def receiveUnimplemented(self, seqID): - unittest.fail('got unimplemented: seqid %s' % seqID) - self.expectedLoseConnection = 1 - self.loseConnection() - - class ConchTestServer(ConchTestBase, transport.SSHServerTransport): - - def connectionLost(self, reason): - ConchTestBase.connectionLost(self, reason) - transport.SSHServerTransport.connectionLost(self, reason) - - class ConchTestClient(ConchTestBase, transport.SSHClientTransport): - - def connectionLost(self, reason): - ConchTestBase.connectionLost(self, reason) - transport.SSHClientTransport.connectionLost(self, reason) - - def verifyHostKey(self, key, fp): - unittest.assertEquals(key, keys.getPublicKeyString(data = publicRSA_openssh)) - unittest.assertEquals(fp,'3d:13:5f:cb:c9:79:8a:93:06:27:65:bc:3d:0b:8f:af') - return defer.succeed(1) - - def connectionSecure(self): - self.requestService(ConchTestClientAuth('testuser', - ConchTestClientConnection())) - - class ConchTestClientAuth(userauth.SSHUserAuthClient): - - hasTriedNone = 0 # have we tried the 'none' auth yet? - canSucceedPublicKey = 0 # can we succed with this yet? - canSucceedPassword = 0 - - def ssh_USERAUTH_SUCCESS(self, packet): - if not self.canSucceedPassword and self.canSucceedPublicKey: - unittest.fail('got USERAUTH_SUCESS before password and publickey') - userauth.SSHUserAuthClient.ssh_USERAUTH_SUCCESS(self, packet) - - def getPassword(self): - self.canSucceedPassword = 1 - return defer.succeed('testpass') - - def getPrivateKey(self): - self.canSucceedPublicKey = 1 - return defer.succeed(keys.getPrivateKeyObject(data=privateDSA_openssh)) - - def getPublicKey(self): - return keys.getPublicKeyString(data=publicDSA_openssh) - - class ConchTestClientConnection(connection.SSHConnection): - - name = 'ssh-connection' - results = 0 - totalResults = 8 - - def serviceStarted(self): - self.openChannel(SSHTestFailExecChannel(conn = self)) - self.openChannel(SSHTestFalseChannel(conn = self)) - self.openChannel(SSHTestEchoChannel(localWindow=4, localMaxPacket=5, conn = self)) - self.openChannel(SSHTestErrChannel(localWindow=4, localMaxPacket=5, conn = self)) - self.openChannel(SSHTestMaxPacketChannel(localWindow=12, localMaxPacket=1, conn = self)) - self.openChannel(SSHTestShellChannel(conn = self)) - self.openChannel(SSHTestSubsystemChannel(conn = self)) - self.openChannel(SSHUnknownChannel(conn = self)) - - def addResult(self): - self.results += 1 - log.msg('got %s of %s results' % (self.results, self.totalResults)) - if self.results == self.totalResults: - self.transport.expectedLoseConnection = 1 - self.serviceStopped() - - class SSHUnknownChannel(channel.SSHChannel): - - name = 'crazy-unknown-channel' - - def openFailed(self, reason): - """ - good .... good - """ - log.msg('unknown open failed') - log.flushErrors() - self.conn.addResult() - - def channelOpen(self, ignored): - unittest.fail("opened unknown channel") - - class SSHTestFailExecChannel(channel.SSHChannel): - - name = 'session' - - def openFailed(self, reason): - unittest.fail('fail exec open failed: %s' % reason) - - def channelOpen(self, ignore): - d = self.conn.sendRequest(self, 'exec', common.NS('jumboliah'), 1) - d.addCallback(self._cbRequestWorked) - d.addErrback(self._ebRequestWorked) - log.msg('opened fail exec') - - def _cbRequestWorked(self, ignored): - unittest.fail('fail exec succeeded') - - def _ebRequestWorked(self, ignored): - log.msg('fail exec finished') - log.flushErrors() - self.conn.addResult() - self.loseConnection() - - class SSHTestFalseChannel(channel.SSHChannel): - - name = 'session' - - def openFailed(self, reason): - unittest.fail('false open failed: %s' % reason) - - def channelOpen(self, ignored): - d = self.conn.sendRequest(self, 'exec', common.NS('false'), 1) - d.addCallback(self._cbRequestWorked) - d.addErrback(self._ebRequestFailed) - log.msg('opened false') - - def _cbRequestWorked(self, ignored): - pass - - def _ebRequestFailed(self, reason): - unittest.fail('false exec failed: %s' % reason) - - def dataReceived(self, data): - unittest.fail('got data when using false') - - def request_exit_status(self, status): - status, = struct.unpack('>L', status) - if status == 0: - unittest.fail('false exit status was 0') - log.msg('finished false') - self.conn.addResult() - return 1 - - class SSHTestEchoChannel(channel.SSHChannel): - - name = 'session' - testBuf = '' - eofCalled = 0 - - def openFailed(self, reason): - unittest.fail('echo open failed: %s' % reason) - - def channelOpen(self, ignore): - d = self.conn.sendRequest(self, 'exec', common.NS('echo hello'), 1) - d.addErrback(self._ebRequestFailed) - log.msg('opened echo') - - def _ebRequestFailed(self, reason): - unittest.fail('echo exec failed: %s' % reason) - - def dataReceived(self, data): - self.testBuf += data - - def errReceived(self, dataType, data): - unittest.fail('echo channel got extended data') - - def request_exit_status(self, status): - self.status ,= struct.unpack('>L', status) - - def eofReceived(self): - log.msg('eof received') - self.eofCalled = 1 - - def closed(self): - if self.status != 0: - unittest.fail('echo exit status was not 0: %i' % self.status) - if self.testBuf != "hello\r\n": - unittest.fail('echo did not return hello: %s' % repr(self.testBuf)) - unittest.assertEquals(self.localWindowLeft, 4) - unittest.assert_(self.eofCalled) - log.msg('finished echo') - self.conn.addResult() - return 1 - - class SSHTestErrChannel(channel.SSHChannel): - - name = 'session' - testBuf = '' - eofCalled = 0 - - def openFailed(self, reason): - unittest.fail('err open failed: %s' % reason) - - def channelOpen(self, ignore): - d = self.conn.sendRequest(self, 'exec', common.NS('eecho hello'), 1) - d.addErrback(self._ebRequestFailed) - log.msg('opened err') - - def _ebRequestFailed(self, reason): - unittest.fail('err exec failed: %s' % reason) - - def dataReceived(self, data): - unittest.fail('err channel got regular data: %s' % repr(data)) - - def extReceived(self, dataType, data): - unittest.assertEquals(dataType, connection.EXTENDED_DATA_STDERR) - self.testBuf += data - - def request_exit_status(self, status): - self.status ,= struct.unpack('>L', status) - - def eofReceived(self): - log.msg('eof received') - self.eofCalled = 1 - - def closed(self): - if self.status != 0: - unittest.fail('err exit status was not 0: %i' % self.status) - if self.testBuf != "hello\r\n": - unittest.fail('err did not return hello: %s' % repr(self.testBuf)) - unittest.assertEquals(self.localWindowLeft, 4) - unittest.assert_(self.eofCalled) - log.msg('finished err') - self.conn.addResult() - return 1 - - class SSHTestMaxPacketChannel(channel.SSHChannel): - - name = 'session' - testBuf = '' - testExtBuf = '' - eofCalled = 0 - - def openFailed(self, reason): - unittest.fail('max packet open failed: %s' % reason) - - def channelOpen(self, ignore): - d = self.conn.sendRequest(self, 'exec', common.NS('secho hello'), 1) - d.addErrback(self._ebRequestFailed) - log.msg('opened max packet') - - def _ebRequestFailed(self, reason): - unittest.fail('max packet exec failed: %s' % reason) - - def dataReceived(self, data): - self.testBuf += data - - def extReceived(self, dataType, data): - unittest.assertEquals(dataType, connection.EXTENDED_DATA_STDERR) - self.testExtBuf += data - - def request_exit_status(self, status): - self.status ,= struct.unpack('>L', status) - - def eofReceived(self): - log.msg('eof received') - self.eofCalled = 1 - - def closed(self): - if self.status != 0: - unittest.fail('echo exit status was not 0: %i' % self.status) - unittest.assertEquals(self.testBuf, 'hello\r\n') - unittest.assertEquals(self.testExtBuf, 'hello\r\n') - unittest.assertEquals(self.localWindowLeft, 12) - unittest.assert_(self.eofCalled) - log.msg('finished max packet') - self.conn.addResult() - return 1 - - class SSHTestShellChannel(channel.SSHChannel): - - name = 'session' - testBuf = '' - eofCalled = 0 - closeCalled = 0 - - def openFailed(self, reason): - unittest.fail('shell open failed: %s' % reason) - - def channelOpen(self, ignored): - data = session.packRequest_pty_req('conch-test-term', (24, 80, 0, 0), '') - d = self.conn.sendRequest(self, 'pty-req', data, 1) - d.addCallback(self._cbPtyReq) - d.addErrback(self._ebPtyReq) - log.msg('opened shell') - - def _cbPtyReq(self, ignored): - d = self.conn.sendRequest(self, 'shell', '', 1) - d.addCallback(self._cbShellOpen) - d.addErrback(self._ebShellOpen) - - def _ebPtyReq(self, reason): - unittest.fail('pty request failed: %s' % reason) - - def _cbShellOpen(self, ignored): - self.write('testing the shell!\x00') - self.conn.sendEOF(self) - - def _ebShellOpen(self, reason): - unittest.fail('shell request failed: %s' % reason) - - def dataReceived(self, data): - self.testBuf += data - - def request_exit_status(self, status): - self.status ,= struct.unpack('>L', status) - - def eofReceived(self): - self.eofCalled = 1 - - def closed(self): - log.msg('calling shell closed') - if self.status != 0: - log.msg('shell exit status was not 0: %i' % self.status) - unittest.assertEquals(self.testBuf, 'testing the shell!\x00\r\n') - unittest.assert_(self.eofCalled) - log.msg('finished shell') - self.conn.addResult() - - class SSHTestSubsystemChannel(channel.SSHChannel): - - name = 'session' - - def openFailed(self, reason): - unittest.fail('subsystem open failed: %s' % reason) - - def channelOpen(self, ignore): - d = self.conn.sendRequest(self, 'subsystem', common.NS('not-crazy'), 1) - d.addCallback(self._cbRequestWorked) - d.addErrback(self._ebRequestFailed) - - - def _cbRequestWorked(self, ignored): - unittest.fail('opened non-crazy subsystem') - - def _ebRequestFailed(self, ignored): - d = self.conn.sendRequest(self, 'subsystem', common.NS('crazy'), 1) - d.addCallback(self._cbRealRequestWorked) - d.addErrback(self._ebRealRequestFailed) - - def _cbRealRequestWorked(self, ignored): - d1 = self.conn.sendGlobalRequest('foo', 'bar', 1) - d1.addErrback(self._ebFirstGlobal) - - d2 = self.conn.sendGlobalRequest('foo-2', 'bar2', 1) - d2.addCallback(lambda x: unittest.assertEquals(x, 'data')) - d2.addErrback(self._ebSecondGlobal) - - d3 = self.conn.sendGlobalRequest('bar', 'foo', 1) - d3.addCallback(self._cbThirdGlobal) - d3.addErrback(lambda x,s=self: log.msg('subsystem finished') or s.conn.addResult() or s.loseConnection()) - - def _ebRealRequestFailed(self, reason): - unittest.fail('opening crazy subsystem failed: %s' % reason) - - def _ebFirstGlobal(self, reason): - unittest.fail('first global request failed: %s' % reason) - - def _ebSecondGlobal(self, reason): - unittest.fail('second global request failed: %s' % reason) - - def _cbThirdGlobal(self, ignored): - unittest.fail('second global request succeeded') - - - -class SSHProtocolTestCase(unittest.TestCase): - - if not Crypto: - skip = "can't run w/o PyCrypto" - - def testOurServerOurClient(self): - """test the Conch server against the Conch client - """ - realm = ConchTestRealm() - p = portal.Portal(realm) - sshpc = ConchTestSSHChecker() - sshpc.registerChecker(ConchTestPasswordChecker()) - sshpc.registerChecker(ConchTestPublicKeyChecker()) - p.registerChecker(sshpc) - fac = ConchTestServerFactory() - fac.portal = p - fac.startFactory() - self.server = fac.buildProtocol(None) - self.clientTransport = LoopbackRelay(self.server) - self.client = ConchTestClient() - self.serverTransport = LoopbackRelay(self.client) - - self.server.makeConnection(self.serverTransport) - self.client.makeConnection(self.clientTransport) - - while self.serverTransport.buffer or self.clientTransport.buffer: - log.callWithContext({'system': 'serverTransport'}, - self.serverTransport.clearBuffer) - log.callWithContext({'system': 'clientTransport'}, - self.clientTransport.clearBuffer) - self.failIf(self.server.done and self.client.done) - - -class TestSSHFactory(unittest.TestCase): - - if not Crypto: - skip = "can't run w/o PyCrypto" - - def testMultipleFactories(self): - f1 = factory.SSHFactory() - f2 = factory.SSHFactory() - gpk = lambda: {'ssh-rsa' : keys.Key(None)} - f1.getPrimes = lambda: None - f2.getPrimes = lambda: {1:(2,3)} - f1.getPublicKeys = f2.getPublicKeys = gpk - f1.getPrivateKeys = f2.getPrivateKeys = gpk - f1.startFactory() - f2.startFactory() - p1 = f1.buildProtocol(None) - p2 = f2.buildProtocol(None) - self.failIf('diffie-hellman-group-exchange-sha1' in p1.supportedKeyExchanges, - p1.supportedKeyExchanges) - self.failUnless('diffie-hellman-group-exchange-sha1' in p2.supportedKeyExchanges, - p2.supportedKeyExchanges) - - -class EntropyTestCase(unittest.TestCase): - """ - Tests for L{common.entropy}. - """ - - def test_deprecation(self): - """ - Test the deprecation of L{common.entropy.get_bytes}. - """ - def wrapper(): - return common.entropy.get_bytes(10) - self.assertWarns(DeprecationWarning, - "entropy.get_bytes is deprecated, please use " - "twisted.python.randbytes.secureRandom instead.", - __file__, wrapper) - - - -class MPTestCase(unittest.TestCase): - """ - Tests for L{common.getMP}. - - @cvar getMP: a method providing a MP parser. - @type getMP: C{callable} - """ - getMP = staticmethod(common.getMP) - - if not Crypto: - skip = "can't run w/o PyCrypto" - - - def test_getMP(self): - """ - L{common.getMP} should parse the a multiple precision integer from a - string: a 4-byte length followed by length bytes of the integer. - """ - self.assertEquals( - self.getMP('\x00\x00\x00\x04\x00\x00\x00\x01'), - (1, '')) - - - def test_getMPBigInteger(self): - """ - L{common.getMP} should be able to parse a big enough integer - (that doesn't fit on one byte). - """ - self.assertEquals( - self.getMP('\x00\x00\x00\x04\x01\x02\x03\x04'), - (16909060, '')) - - - def test_multipleGetMP(self): - """ - L{common.getMP} has the ability to parse multiple integer in the same - string. - """ - self.assertEquals( - self.getMP('\x00\x00\x00\x04\x00\x00\x00\x01' - '\x00\x00\x00\x04\x00\x00\x00\x02', 2), - (1, 2, '')) - - - def test_getMPRemainingData(self): - """ - When more data than needed is sent to L{common.getMP}, it should return - the remaining data. - """ - self.assertEquals( - self.getMP('\x00\x00\x00\x04\x00\x00\x00\x01foo'), - (1, 'foo')) - - - def test_notEnoughData(self): - """ - When the string passed to L{common.getMP} doesn't even make 5 bytes, - it should raise a L{struct.error}. - """ - self.assertRaises(struct.error, self.getMP, '\x02\x00') - - - -class PyMPTestCase(MPTestCase): - """ - Tests for the python implementation of L{common.getMP}. - """ - getMP = staticmethod(common.getMP_py) - - - -class GMPYMPTestCase(MPTestCase): - """ - Tests for the gmpy implementation of L{common.getMP}. - """ - getMP = staticmethod(common._fastgetMP) - - - -try: - import gmpy -except ImportError: - GMPYMPTestCase.skip = "gmpy not available" diff --git a/tools/buildbot/pylibs/twisted/conch/test/test_telnet.py b/tools/buildbot/pylibs/twisted/conch/test/test_telnet.py deleted file mode 100644 index a2fc4e7..0000000 --- a/tools/buildbot/pylibs/twisted/conch/test/test_telnet.py +++ /dev/null @@ -1,672 +0,0 @@ -# -*- test-case-name: twisted.conch.test.test_telnet -*- -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.conch.telnet}. -""" - -from zope.interface import implements - -from twisted.internet import defer - -from twisted.conch import telnet - -from twisted.trial import unittest -from twisted.test import proto_helpers - -class TestProtocol: - implements(telnet.ITelnetProtocol) - - localEnableable = () - remoteEnableable = () - - def __init__(self): - self.bytes = '' - self.subcmd = '' - self.calls = [] - - self.enabledLocal = [] - self.enabledRemote = [] - self.disabledLocal = [] - self.disabledRemote = [] - - def makeConnection(self, transport): - d = transport.negotiationMap = {} - d['\x12'] = self.neg_TEST_COMMAND - - d = transport.commandMap = transport.commandMap.copy() - for cmd in ('NOP', 'DM', 'BRK', 'IP', 'AO', 'AYT', 'EC', 'EL', 'GA'): - d[getattr(telnet, cmd)] = lambda arg, cmd=cmd: self.calls.append(cmd) - - def dataReceived(self, bytes): - self.bytes += bytes - - def connectionLost(self, reason): - pass - - def neg_TEST_COMMAND(self, payload): - self.subcmd = payload - - def enableLocal(self, option): - if option in self.localEnableable: - self.enabledLocal.append(option) - return True - return False - - def disableLocal(self, option): - self.disabledLocal.append(option) - - def enableRemote(self, option): - if option in self.remoteEnableable: - self.enabledRemote.append(option) - return True - return False - - def disableRemote(self, option): - self.disabledRemote.append(option) - - - -class TelnetTransportTestCase(unittest.TestCase): - """ - Tests for L{telnet.TelnetTransport}. - """ - def setUp(self): - self.p = telnet.TelnetTransport(TestProtocol) - self.t = proto_helpers.StringTransport() - self.p.makeConnection(self.t) - - def testRegularBytes(self): - # Just send a bunch of bytes. None of these do anything - # with telnet. They should pass right through to the - # application layer. - h = self.p.protocol - - L = ["here are some bytes la la la", - "some more arrive here", - "lots of bytes to play with", - "la la la", - "ta de da", - "dum"] - for b in L: - self.p.dataReceived(b) - - self.assertEquals(h.bytes, ''.join(L)) - - def testNewlineHandling(self): - # Send various kinds of newlines and make sure they get translated - # into \n. - h = self.p.protocol - - L = ["here is the first line\r\n", - "here is the second line\r\0", - "here is the third line\r\n", - "here is the last line\r\0"] - - for b in L: - self.p.dataReceived(b) - - self.assertEquals(h.bytes, L[0][:-2] + '\n' + - L[1][:-2] + '\r' + - L[2][:-2] + '\n' + - L[3][:-2] + '\r') - - def testIACEscape(self): - # Send a bunch of bytes and a couple quoted \xFFs. Unquoted, - # \xFF is a telnet command. Quoted, one of them from each pair - # should be passed through to the application layer. - h = self.p.protocol - - L = ["here are some bytes\xff\xff with an embedded IAC", - "and here is a test of a border escape\xff", - "\xff did you get that IAC?"] - - for b in L: - self.p.dataReceived(b) - - self.assertEquals(h.bytes, ''.join(L).replace('\xff\xff', '\xff')) - - def _simpleCommandTest(self, cmdName): - # Send a single simple telnet command and make sure - # it gets noticed and the appropriate method gets - # called. - h = self.p.protocol - - cmd = telnet.IAC + getattr(telnet, cmdName) - L = ["Here's some bytes, tra la la", - "But ono!" + cmd + " an interrupt"] - - for b in L: - self.p.dataReceived(b) - - self.assertEquals(h.calls, [cmdName]) - self.assertEquals(h.bytes, ''.join(L).replace(cmd, '')) - - def testInterrupt(self): - self._simpleCommandTest("IP") - - def testNoOperation(self): - self._simpleCommandTest("NOP") - - def testDataMark(self): - self._simpleCommandTest("DM") - - def testBreak(self): - self._simpleCommandTest("BRK") - - def testAbortOutput(self): - self._simpleCommandTest("AO") - - def testAreYouThere(self): - self._simpleCommandTest("AYT") - - def testEraseCharacter(self): - self._simpleCommandTest("EC") - - def testEraseLine(self): - self._simpleCommandTest("EL") - - def testGoAhead(self): - self._simpleCommandTest("GA") - - def testSubnegotiation(self): - # Send a subnegotiation command and make sure it gets - # parsed and that the correct method is called. - h = self.p.protocol - - cmd = telnet.IAC + telnet.SB + '\x12hello world' + telnet.IAC + telnet.SE - L = ["These are some bytes but soon" + cmd, - "there will be some more"] - - for b in L: - self.p.dataReceived(b) - - self.assertEquals(h.bytes, ''.join(L).replace(cmd, '')) - self.assertEquals(h.subcmd, list("hello world")) - - def testSubnegotiationWithEmbeddedSE(self): - # Send a subnegotiation command with an embedded SE. Make sure - # that SE gets passed to the correct method. - h = self.p.protocol - - cmd = (telnet.IAC + telnet.SB + - '\x12' + telnet.SE + - telnet.IAC + telnet.SE) - - L = ["Some bytes are here" + cmd + "and here", - "and here"] - - for b in L: - self.p.dataReceived(b) - - self.assertEquals(h.bytes, ''.join(L).replace(cmd, '')) - self.assertEquals(h.subcmd, [telnet.SE]) - - def testBoundarySubnegotiation(self): - # Send a subnegotiation command. Split it at every possible byte boundary - # and make sure it always gets parsed and that it is passed to the correct - # method. - cmd = (telnet.IAC + telnet.SB + - '\x12' + telnet.SE + 'hello' + - telnet.IAC + telnet.SE) - - for i in range(len(cmd)): - h = self.p.protocol = TestProtocol() - h.makeConnection(self.p) - - a, b = cmd[:i], cmd[i:] - L = ["first part" + a, - b + "last part"] - - for bytes in L: - self.p.dataReceived(bytes) - - self.assertEquals(h.bytes, ''.join(L).replace(cmd, '')) - self.assertEquals(h.subcmd, [telnet.SE] + list('hello')) - - def _enabledHelper(self, o, eL=[], eR=[], dL=[], dR=[]): - self.assertEquals(o.enabledLocal, eL) - self.assertEquals(o.enabledRemote, eR) - self.assertEquals(o.disabledLocal, dL) - self.assertEquals(o.disabledRemote, dR) - - def testRefuseWill(self): - # Try to enable an option. The server should refuse to enable it. - cmd = telnet.IAC + telnet.WILL + '\x12' - - bytes = "surrounding bytes" + cmd + "to spice things up" - self.p.dataReceived(bytes) - - self.assertEquals(self.p.protocol.bytes, bytes.replace(cmd, '')) - self.assertEquals(self.t.value(), telnet.IAC + telnet.DONT + '\x12') - self._enabledHelper(self.p.protocol) - - def testRefuseDo(self): - # Try to enable an option. The server should refuse to enable it. - cmd = telnet.IAC + telnet.DO + '\x12' - - bytes = "surrounding bytes" + cmd + "to spice things up" - self.p.dataReceived(bytes) - - self.assertEquals(self.p.protocol.bytes, bytes.replace(cmd, '')) - self.assertEquals(self.t.value(), telnet.IAC + telnet.WONT + '\x12') - self._enabledHelper(self.p.protocol) - - def testAcceptDo(self): - # Try to enable an option. The option is in our allowEnable - # list, so we will allow it to be enabled. - cmd = telnet.IAC + telnet.DO + '\x19' - bytes = 'padding' + cmd + 'trailer' - - h = self.p.protocol - h.localEnableable = ('\x19',) - self.p.dataReceived(bytes) - - self.assertEquals(self.t.value(), telnet.IAC + telnet.WILL + '\x19') - self._enabledHelper(h, eL=['\x19']) - - def testAcceptWill(self): - # Same as testAcceptDo, but reversed. - cmd = telnet.IAC + telnet.WILL + '\x91' - bytes = 'header' + cmd + 'padding' - - h = self.p.protocol - h.remoteEnableable = ('\x91',) - self.p.dataReceived(bytes) - - self.assertEquals(self.t.value(), telnet.IAC + telnet.DO + '\x91') - self._enabledHelper(h, eR=['\x91']) - - def testAcceptWont(self): - # Try to disable an option. The server must allow any option to - # be disabled at any time. Make sure it disables it and sends - # back an acknowledgement of this. - cmd = telnet.IAC + telnet.WONT + '\x29' - - # Jimmy it - after these two lines, the server will be in a state - # such that it believes the option to have been previously enabled - # via normal negotiation. - s = self.p.getOptionState('\x29') - s.him.state = 'yes' - - bytes = "fiddle dee" + cmd - self.p.dataReceived(bytes) - - self.assertEquals(self.p.protocol.bytes, bytes.replace(cmd, '')) - self.assertEquals(self.t.value(), telnet.IAC + telnet.DONT + '\x29') - self.assertEquals(s.him.state, 'no') - self._enabledHelper(self.p.protocol, dR=['\x29']) - - def testAcceptDont(self): - # Try to disable an option. The server must allow any option to - # be disabled at any time. Make sure it disables it and sends - # back an acknowledgement of this. - cmd = telnet.IAC + telnet.DONT + '\x29' - - # Jimmy it - after these two lines, the server will be in a state - # such that it believes the option to have beenp previously enabled - # via normal negotiation. - s = self.p.getOptionState('\x29') - s.us.state = 'yes' - - bytes = "fiddle dum " + cmd - self.p.dataReceived(bytes) - - self.assertEquals(self.p.protocol.bytes, bytes.replace(cmd, '')) - self.assertEquals(self.t.value(), telnet.IAC + telnet.WONT + '\x29') - self.assertEquals(s.us.state, 'no') - self._enabledHelper(self.p.protocol, dL=['\x29']) - - def testIgnoreWont(self): - # Try to disable an option. The option is already disabled. The - # server should send nothing in response to this. - cmd = telnet.IAC + telnet.WONT + '\x47' - - bytes = "dum de dum" + cmd + "tra la la" - self.p.dataReceived(bytes) - - self.assertEquals(self.p.protocol.bytes, bytes.replace(cmd, '')) - self.assertEquals(self.t.value(), '') - self._enabledHelper(self.p.protocol) - - def testIgnoreDont(self): - # Try to disable an option. The option is already disabled. The - # server should send nothing in response to this. Doing so could - # lead to a negotiation loop. - cmd = telnet.IAC + telnet.DONT + '\x47' - - bytes = "dum de dum" + cmd + "tra la la" - self.p.dataReceived(bytes) - - self.assertEquals(self.p.protocol.bytes, bytes.replace(cmd, '')) - self.assertEquals(self.t.value(), '') - self._enabledHelper(self.p.protocol) - - def testIgnoreWill(self): - # Try to enable an option. The option is already enabled. The - # server should send nothing in response to this. Doing so could - # lead to a negotiation loop. - cmd = telnet.IAC + telnet.WILL + '\x56' - - # Jimmy it - after these two lines, the server will be in a state - # such that it believes the option to have been previously enabled - # via normal negotiation. - s = self.p.getOptionState('\x56') - s.him.state = 'yes' - - bytes = "tra la la" + cmd + "dum de dum" - self.p.dataReceived(bytes) - - self.assertEquals(self.p.protocol.bytes, bytes.replace(cmd, '')) - self.assertEquals(self.t.value(), '') - self._enabledHelper(self.p.protocol) - - def testIgnoreDo(self): - # Try to enable an option. The option is already enabled. The - # server should send nothing in response to this. Doing so could - # lead to a negotiation loop. - cmd = telnet.IAC + telnet.DO + '\x56' - - # Jimmy it - after these two lines, the server will be in a state - # such that it believes the option to have been previously enabled - # via normal negotiation. - s = self.p.getOptionState('\x56') - s.us.state = 'yes' - - bytes = "tra la la" + cmd + "dum de dum" - self.p.dataReceived(bytes) - - self.assertEquals(self.p.protocol.bytes, bytes.replace(cmd, '')) - self.assertEquals(self.t.value(), '') - self._enabledHelper(self.p.protocol) - - def testAcceptedEnableRequest(self): - # Try to enable an option through the user-level API. This - # returns a Deferred that fires when negotiation about the option - # finishes. Make sure it fires, make sure state gets updated - # properly, make sure the result indicates the option was enabled. - d = self.p.do('\x42') - - h = self.p.protocol - h.remoteEnableable = ('\x42',) - - self.assertEquals(self.t.value(), telnet.IAC + telnet.DO + '\x42') - - self.p.dataReceived(telnet.IAC + telnet.WILL + '\x42') - - d.addCallback(self.assertEquals, True) - d.addCallback(lambda _: self._enabledHelper(h, eR=['\x42'])) - return d - - def testRefusedEnableRequest(self): - # Try to enable an option through the user-level API. This - # returns a Deferred that fires when negotiation about the option - # finishes. Make sure it fires, make sure state gets updated - # properly, make sure the result indicates the option was enabled. - d = self.p.do('\x42') - - self.assertEquals(self.t.value(), telnet.IAC + telnet.DO + '\x42') - - self.p.dataReceived(telnet.IAC + telnet.WONT + '\x42') - - d = self.assertFailure(d, telnet.OptionRefused) - d.addCallback(lambda _: self._enabledHelper(self.p.protocol)) - return d - - def testAcceptedDisableRequest(self): - # Try to disable an option through the user-level API. This - # returns a Deferred that fires when negotiation about the option - # finishes. Make sure it fires, make sure state gets updated - # properly, make sure the result indicates the option was enabled. - s = self.p.getOptionState('\x42') - s.him.state = 'yes' - - d = self.p.dont('\x42') - - self.assertEquals(self.t.value(), telnet.IAC + telnet.DONT + '\x42') - - self.p.dataReceived(telnet.IAC + telnet.WONT + '\x42') - - d.addCallback(self.assertEquals, True) - d.addCallback(lambda _: self._enabledHelper(self.p.protocol, - dR=['\x42'])) - return d - - def testNegotiationBlocksFurtherNegotiation(self): - # Try to disable an option, then immediately try to enable it, then - # immediately try to disable it. Ensure that the 2nd and 3rd calls - # fail quickly with the right exception. - s = self.p.getOptionState('\x24') - s.him.state = 'yes' - d2 = self.p.dont('\x24') # fires after the first line of _final - - def _do(x): - d = self.p.do('\x24') - return self.assertFailure(d, telnet.AlreadyNegotiating) - - def _dont(x): - d = self.p.dont('\x24') - return self.assertFailure(d, telnet.AlreadyNegotiating) - - def _final(x): - self.p.dataReceived(telnet.IAC + telnet.WONT + '\x24') - # an assertion that only passes if d2 has fired - self._enabledHelper(self.p.protocol, dR=['\x24']) - # Make sure we allow this - self.p.protocol.remoteEnableable = ('\x24',) - d = self.p.do('\x24') - self.p.dataReceived(telnet.IAC + telnet.WILL + '\x24') - d.addCallback(self.assertEquals, True) - d.addCallback(lambda _: self._enabledHelper(self.p.protocol, - eR=['\x24'], - dR=['\x24'])) - return d - - d = _do(None) - d.addCallback(_dont) - d.addCallback(_final) - return d - - def testSuperfluousDisableRequestRaises(self): - # Try to disable a disabled option. Make sure it fails properly. - d = self.p.dont('\xab') - return self.assertFailure(d, telnet.AlreadyDisabled) - - def testSuperfluousEnableRequestRaises(self): - # Try to disable a disabled option. Make sure it fails properly. - s = self.p.getOptionState('\xab') - s.him.state = 'yes' - d = self.p.do('\xab') - return self.assertFailure(d, telnet.AlreadyEnabled) - - def testLostConnectionFailsDeferreds(self): - d1 = self.p.do('\x12') - d2 = self.p.do('\x23') - d3 = self.p.do('\x34') - - class TestException(Exception): - pass - - self.p.connectionLost(TestException("Total failure!")) - - d1 = self.assertFailure(d1, TestException) - d2 = self.assertFailure(d2, TestException) - d3 = self.assertFailure(d3, TestException) - return defer.gatherResults([d1, d2, d3]) - - -class TestTelnet(telnet.Telnet): - """ - A trivial extension of the telnet protocol class useful to unit tests. - """ - def __init__(self): - telnet.Telnet.__init__(self) - self.events = [] - - - def applicationDataReceived(self, bytes): - """ - Record the given data in C{self.events}. - """ - self.events.append(('bytes', bytes)) - - - def unhandledCommand(self, command, bytes): - """ - Record the given command in C{self.events}. - """ - self.events.append(('command', command, bytes)) - - - def unhandledSubnegotiation(self, command, bytes): - """ - Record the given subnegotiation command in C{self.events}. - """ - self.events.append(('negotiate', command, bytes)) - - - -class TelnetTests(unittest.TestCase): - """ - Tests for L{telnet.Telnet}. - - L{telnet.Telnet} implements the TELNET protocol (RFC 854), including option - and suboption negotiation, and option state tracking. - """ - def setUp(self): - """ - Create an unconnected L{telnet.Telnet} to be used by tests. - """ - self.protocol = TestTelnet() - - - def test_enableLocal(self): - """ - L{telnet.Telnet.enableLocal} should reject all options, since - L{telnet.Telnet} does not know how to implement any options. - """ - self.assertFalse(self.protocol.enableLocal('\0')) - - - def test_enableRemote(self): - """ - L{telnet.Telnet.enableRemote} should reject all options, since - L{telnet.Telnet} does not know how to implement any options. - """ - self.assertFalse(self.protocol.enableRemote('\0')) - - - def test_disableLocal(self): - """ - It is an error for L{telnet.Telnet.disableLocal} to be called, since - L{telnet.Telnet.enableLocal} will never allow any options to be enabled - locally. If a subclass overrides enableLocal, it must also override - disableLocal. - """ - self.assertRaises(NotImplementedError, self.protocol.disableLocal, '\0') - - - def test_disableRemote(self): - """ - It is an error for L{telnet.Telnet.disableRemote} to be called, since - L{telnet.Telnet.enableRemote} will never allow any options to be - enabled remotely. If a subclass overrides enableRemote, it must also - override disableRemote. - """ - self.assertRaises(NotImplementedError, self.protocol.disableRemote, '\0') - - - def _deliver(self, bytes, *expected): - """ - Pass the given bytes to the protocol's C{dataReceived} method and - assert that the given events occur. - """ - received = self.protocol.events = [] - self.protocol.dataReceived(bytes) - self.assertEqual(received, list(expected)) - - - def test_oneApplicationDataByte(self): - """ - One application-data byte in the default state gets delivered right - away. - """ - self._deliver('a', ('bytes', 'a')) - - - def test_twoApplicationDataBytes(self): - """ - Two application-data bytes in the default state get delivered - together. - """ - self._deliver('bc', ('bytes', 'bc')) - - - def test_threeApplicationDataBytes(self): - """ - Three application-data bytes followed by a control byte get - delivered, but the control byte doesn't. - """ - self._deliver('def' + telnet.IAC, ('bytes', 'def')) - - - def test_escapedControl(self): - """ - IAC in the escaped state gets delivered and so does another - application-data byte following it. - """ - self._deliver(telnet.IAC) - self._deliver(telnet.IAC + 'g', ('bytes', telnet.IAC + 'g')) - - - def test_carriageReturn(self): - """ - A carriage return only puts the protocol into the newline state. A - linefeed in the newline state causes just the newline to be - delivered. A nul in the newline state causes a carriage return to - be delivered. Anything else causes a carriage return and that thing - to be delivered. - """ - self._deliver('\r') - self._deliver('\n', ('bytes', '\n')) - self._deliver('\r\n', ('bytes', '\n')) - - self._deliver('\r') - self._deliver('\0', ('bytes', '\r')) - self._deliver('\r\0', ('bytes', '\r')) - - self._deliver('\r') - self._deliver('a', ('bytes', '\ra')) - self._deliver('\ra', ('bytes', '\ra')) - - - def test_applicationDataBeforeSimpleCommand(self): - """ - Application bytes received before a command are delivered before the - command is processed. - """ - self._deliver( - 'x' + telnet.IAC + telnet.NOP, - ('bytes', 'x'), ('command', telnet.NOP, None)) - - - def test_applicationDataBeforeCommand(self): - """ - Application bytes received before a WILL/WONT/DO/DONT are delivered - before the command is processed. - """ - self.protocol.commandMap = {} - self._deliver( - 'y' + telnet.IAC + telnet.WILL + '\x00', - ('bytes', 'y'), ('command', telnet.WILL, '\x00')) - - - def test_applicationDataBeforeSubnegotiation(self): - """ - Application bytes received before a subnegotiation command are - delivered before the negotiation is processed. - """ - self._deliver( - 'z' + telnet.IAC + telnet.SB + 'Qx' + telnet.IAC + telnet.SE, - ('bytes', 'z'), ('negotiate', 'Q', ['x'])) diff --git a/tools/buildbot/pylibs/twisted/conch/test/test_text.py b/tools/buildbot/pylibs/twisted/conch/test/test_text.py deleted file mode 100644 index bfc5545..0000000 --- a/tools/buildbot/pylibs/twisted/conch/test/test_text.py +++ /dev/null @@ -1,101 +0,0 @@ -# -*- test-case-name: twisted.conch.test.test_text -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.trial import unittest - -from twisted.conch.insults import helper, text - -A = text.attributes - -class Serialization(unittest.TestCase): - def setUp(self): - self.attrs = helper.CharacterAttribute() - - def testTrivial(self): - self.assertEquals( - text.flatten(A.normal['Hello, world.'], self.attrs), - 'Hello, world.') - - def testBold(self): - self.assertEquals( - text.flatten(A.bold['Hello, world.'], self.attrs), - '\x1b[1mHello, world.') - - def testUnderline(self): - self.assertEquals( - text.flatten(A.underline['Hello, world.'], self.attrs), - '\x1b[4mHello, world.') - - def testBlink(self): - self.assertEquals( - text.flatten(A.blink['Hello, world.'], self.attrs), - '\x1b[5mHello, world.') - - def testReverseVideo(self): - self.assertEquals( - text.flatten(A.reverseVideo['Hello, world.'], self.attrs), - '\x1b[7mHello, world.') - - def testMinus(self): - self.assertEquals( - text.flatten( - A.bold[A.blink['Hello', -A.bold[' world'], '.']], - self.attrs), - '\x1b[1;5mHello\x1b[0;5m world\x1b[1;5m.') - - def testForeground(self): - self.assertEquals( - text.flatten( - A.normal[A.fg.red['Hello, '], A.fg.green['world!']], - self.attrs), - '\x1b[31mHello, \x1b[32mworld!') - - def testBackground(self): - self.assertEquals( - text.flatten( - A.normal[A.bg.red['Hello, '], A.bg.green['world!']], - self.attrs), - '\x1b[41mHello, \x1b[42mworld!') - - -class EfficiencyTestCase(unittest.TestCase): - todo = ("flatten() isn't quite stateful enough to avoid emitting a few extra bytes in " - "certain circumstances, so these tests fail. The failures take the form of " - "additional elements in the ;-delimited character attribute lists. For example, " - "\\x1b[0;31;46m might be emitted instead of \\x[46m, even if 31 has already been " - "activated and no conflicting attributes are set which need to be cleared.") - - def setUp(self): - self.attrs = helper.CharacterAttribute() - - def testComplexStructure(self): - output = A.normal[ - A.bold[ - A.bg.cyan[ - A.fg.red[ - "Foreground Red, Background Cyan, Bold", - A.blink[ - "Blinking"], - -A.bold[ - "Foreground Red, Background Cyan, normal"]], - A.fg.green[ - "Foreground Green, Background Cyan, Bold"]]]] - - self.assertEquals( - text.flatten(output, self.attrs), - "\x1b[1;31;46mForeground Red, Background Cyan, Bold" - "\x1b[5mBlinking" - "\x1b[0;31;46mForeground Red, Background Cyan, normal" - "\x1b[1;32;46mForeground Green, Background Cyan, Bold") - - def testNesting(self): - self.assertEquals( - text.flatten(A.bold['Hello, ', A.underline['world.']], self.attrs), - '\x1b[1mHello, \x1b[4mworld.') - - self.assertEquals( - text.flatten( - A.bold[A.reverseVideo['Hello, ', A.normal['world'], '.']], - self.attrs), - '\x1b[1;7mHello, \x1b[0mworld\x1b[1;7m.') diff --git a/tools/buildbot/pylibs/twisted/conch/test/test_transport.py b/tools/buildbot/pylibs/twisted/conch/test/test_transport.py deleted file mode 100644 index 2749adf..0000000 --- a/tools/buildbot/pylibs/twisted/conch/test/test_transport.py +++ /dev/null @@ -1,1930 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for ssh/transport.py and the classes therein. -""" - -import md5, sha - -try: - import Crypto -except ImportError: - Crypto = None - class transport: # fictional modules to make classes work - class SSHTransportBase: pass - class SSHServerTransport: pass - class SSHClientTransport: pass - class factory: - class SSHFactory: - pass -else: - from twisted.conch.ssh import transport, common, keys, factory - from twisted.conch.test import keydata - -from twisted.trial import unittest -from twisted.internet import defer -from twisted.protocols import loopback -from twisted.python import randbytes -from twisted.python.reflect import qual -from twisted.conch.ssh import service -from twisted.test import proto_helpers - -from twisted.conch.error import ConchError - - - -class MockTransportBase(transport.SSHTransportBase): - """ - A base class for the client and server protocols. Stores the messages - it receieves instead of ignoring them. - - @ivar errors: a list of tuples: (reasonCode, description) - @ivar unimplementeds: a list of integers: sequence number - @ivar debugs: a list of tuples: (alwaysDisplay, message, lang) - @ivar ignoreds: a list of strings: ignored data - """ - - - def connectionMade(self): - """ - Set up instance variables. - """ - transport.SSHTransportBase.connectionMade(self) - self.errors = [] - self.unimplementeds = [] - self.debugs = [] - self.ignoreds = [] - - - def receiveError(self, reasonCode, description): - """ - Store any errors received. - - @type reasonCode: C{int} - @type description: C{str} - """ - self.errors.append((reasonCode, description)) - - - def receiveUnimplemented(self, seqnum): - """ - Store any unimplemented packet messages. - - @type seqnum: C{int} - """ - self.unimplementeds.append(seqnum) - - - def receiveDebug(self, alwaysDisplay, message, lang): - """ - Store any debug messages. - - @type alwaysDisplay: C{bool} - @type message: C{str} - @type lang: C{str} - """ - self.debugs.append((alwaysDisplay, message, lang)) - - - def ssh_IGNORE(self, packet): - """ - Store any ignored data. - - @type packet: C{str} - """ - self.ignoreds.append(packet) - - -class MockCipher(object): - """ - A mocked-up version of twisted.conch.ssh.transport.SSHCiphers. - """ - outCipType = 'test' - encBlockSize = 6 - inCipType = 'test' - decBlockSize = 6 - inMACType = 'test' - outMACType = 'test' - verifyDigestSize = 1 - usedEncrypt = False - usedDecrypt = False - outMAC = (None, '', '', 1) - inMAC = (None, '', '', 1) - keys = () - - - def encrypt(self, x): - """ - Called to encrypt the packet. Simply record that encryption was used - and return the data unchanged. - """ - self.usedEncrypt = True - if (len(x) % self.encBlockSize) != 0: - raise RuntimeError("length %i modulo blocksize %i is not 0: %i" % - (len(x), self.encBlockSize, len(x) % self.encBlockSize)) - return x - - - def decrypt(self, x): - """ - Called to decrypt the packet. Simply record that decryption was used - and return the data unchanged. - """ - self.usedDecrypt = True - if (len(x) % self.encBlockSize) != 0: - raise RuntimeError("length %i modulo blocksize %i is not 0: %i" % - (len(x), self.decBlockSize, len(x) % self.decBlockSize)) - return x - - - def makeMAC(self, outgoingPacketSequence, payload): - """ - Make a Message Authentication Code by sending the character value of - the outgoing packet. - """ - return chr(outgoingPacketSequence) - - - def verify(self, incomingPacketSequence, packet, macData): - """ - Verify the Message Authentication Code by checking that the packet - sequence number is the same. - """ - return chr(incomingPacketSequence) == macData - - - def setKeys(self, ivOut, keyOut, ivIn, keyIn, macIn, macOut): - """ - Record the keys. - """ - self.keys = (ivOut, keyOut, ivIn, keyIn, macIn, macOut) - - - -class MockCompression: - """ - A mocked-up compression, based on the zlib interface. Instead of - compressing, it reverses the data and adds a 0x66 byte to the end. - """ - - - def compress(self, payload): - return payload[::-1] # reversed - - - def decompress(self, payload): - return payload[:-1][::-1] - - - def flush(self, kind): - return '\x66' - - - -class MockService(service.SSHService): - """ - A mocked-up service, based on twisted.conch.ssh.service.SSHService. - - @ivar started: True if this service has been started. - @ivar stopped: True if this service has been stopped. - """ - name = "MockService" - started = False - stopped = False - protocolMessages = {0xff: "MSG_TEST", 71: "MSG_fiction"} - - - def logPrefix(self): - return "MockService" - - - def serviceStarted(self): - """ - Record that the service was started. - """ - self.started = True - - - def serviceStopped(self): - """ - Record that the service was stopped. - """ - self.stopped = True - - - def ssh_TEST(self, packet): - """ - A message that this service responds to. - """ - self.transport.sendPacket(0xff, packet) - - -class MockFactory(factory.SSHFactory): - """ - A mocked-up factory based on twisted.conch.ssh.factory.SSHFactory. - """ - services = { - 'ssh-userauth': MockService} - - - def getPublicKeys(self): - """ - Return the public keys that authenticate this server. - """ - return { - 'ssh-rsa': keys.Key.fromString(keydata.publicRSA_openssh), - 'ssh-dsa': keys.Key.fromString(keydata.publicDSA_openssh)} - - - def getPrivateKeys(self): - """ - Return the private keys that authenticate this server. - """ - return { - 'ssh-rsa': keys.Key.fromString(keydata.privateRSA_openssh), - 'ssh-dsa': keys.Key.fromString(keydata.privateDSA_openssh)} - - - def getPrimes(self): - """ - Return the Diffie-Hellman primes that can be used for the - diffie-hellman-group-exchange-sha1 key exchange. - """ - return { - 1024: ((2, transport.DH_PRIME),), - 2048: ((3, transport.DH_PRIME),), - 4096: ((5, 7),)} - - - -class MockOldFactoryPublicKeys(MockFactory): - """ - The old SSHFactory returned mappings from key names to strings from - getPublicKeys(). We return those here for testing. - """ - - - def getPublicKeys(self): - """ - We used to map key types to public key blobs as strings. - """ - keys = MockFactory.getPublicKeys(self) - for name, key in keys.items()[:]: - keys[name] = key.blob() - return keys - - - -class MockOldFactoryPrivateKeys(MockFactory): - """ - The old SSHFactory returned mappings from key names to PyCrypto key - objects from getPrivateKeys(). We return those here for testing. - """ - - - def getPrivateKeys(self): - """ - We used to map key types to PyCrypto key objects. - """ - keys = MockFactory.getPrivateKeys(self) - for name, key in keys.items()[:]: - keys[name] = key.keyObject - return keys - - - -class TransportTestCase(unittest.TestCase): - """ - Base class for transport test cases. - """ - klass = None - - if Crypto is None: - skip = "cannot run w/o PyCrypto" - - - def setUp(self): - self.transport = proto_helpers.StringTransport() - self.proto = self.klass() - self.packets = [] - def secureRandom(len): - """ - Return a consistent entropy value - """ - return '\x99' * len - self.oldSecureRandom = randbytes.secureRandom - randbytes.secureRandom = secureRandom - def stubSendPacket(messageType, payload): - self.packets.append((messageType, payload)) - self.proto.makeConnection(self.transport) - # we just let the kex packet go into the transport - self.proto.sendPacket = stubSendPacket - - - def tearDown(self): - randbytes.secureRandom = self.oldSecureRandom - self.oldSecureRandom = None - - - -class BaseSSHTransportTestCase(TransportTestCase): - """ - Test TransportBase. It implements the non-server/client specific - parts of the SSH transport protocol. - """ - - klass = MockTransportBase - - - def test_sendVersion(self): - """ - Test that the first thing sent over the connection is the version - string. - """ - # the other setup was done in the setup method - self.assertEquals(self.transport.value().split('\r\n', 1)[0], - "SSH-2.0-Twisted") - - - def test_sendPacketPlain(self): - """ - Test that plain (unencrypted, uncompressed) packets are sent - correctly. The format is:: - uint32 length (including type and padding length) - byte padding length - byte type - bytes[length-padding length-2] data - bytes[padding length] padding - """ - proto = MockTransportBase() - proto.makeConnection(self.transport) - self.transport.clear() - message = ord('A') - payload = 'BCDEFG' - proto.sendPacket(message, payload) - value = self.transport.value() - self.assertEquals(value, '\x00\x00\x00\x0c\x04ABCDEFG\x99\x99\x99\x99') - - - def test_sendPacketEncrypted(self): - """ - Test that packets sent while encryption is enabled are sent - correctly. The whole packet should be encrypted. - """ - proto = MockTransportBase() - proto.makeConnection(self.transport) - proto.currentEncryptions = testCipher = MockCipher() - message = ord('A') - payload = 'BC' - self.transport.clear() - proto.sendPacket(message, payload) - self.assertTrue(testCipher.usedEncrypt) - value = self.transport.value() - self.assertEquals(value, '\x00\x00\x00\x08\x04ABC\x99\x99\x99\x99\x01') - - - def test_sendPacketCompressed(self): - """ - Test that packets sent while compression is enabled are sent - correctly. The packet type and data should be encrypted. - """ - proto = MockTransportBase() - proto.makeConnection(self.transport) - proto.outgoingCompression = MockCompression() - self.transport.clear() - proto.sendPacket(ord('A'), 'B') - value = self.transport.value() - self.assertEquals( - value, - '\x00\x00\x00\x0c\x08BA\x66\x99\x99\x99\x99\x99\x99\x99\x99') - - - def test_sendPacketBoth(self): - """ - Test that packets sent while compression and encryption are - enabled are sent correctly. The packet type and data should be - compressed and then the whole packet should be encrypted. - """ - proto = MockTransportBase() - proto.makeConnection(self.transport) - proto.currentEncryptions = testCipher = MockCipher() - proto.outgoingCompression = MockCompression() - message = ord('A') - payload = 'BC' - self.transport.clear() - proto.sendPacket(message, payload) - value = self.transport.value() - self.assertEquals( - value, - '\x00\x00\x00\x0e\x09CBA\x66\x99\x99\x99\x99\x99\x99\x99\x99\x99' - '\x01') - - - def test_getPacketPlain(self): - """ - Test that packets are retrieved correctly out of the buffer when - no encryption is enabled. - """ - proto = MockTransportBase() - proto.makeConnection(self.transport) - self.transport.clear() - proto.sendPacket(ord('A'), 'BC') - proto.buf = self.transport.value() + 'extra' - self.assertEquals(proto.getPacket(), 'ABC') - self.assertEquals(proto.buf, 'extra') - - - def test_getPacketEncrypted(self): - """ - Test that encrypted packets are retrieved correctly. - See test_sendPacketEncrypted. - """ - proto = MockTransportBase() - proto.sendKexInit = lambda: None # don't send packets - proto.makeConnection(self.transport) - self.transport.clear() - proto.currentEncryptions = testCipher = MockCipher() - proto.sendPacket(ord('A'), 'BCD') - value = self.transport.value() - proto.buf = value[:MockCipher.decBlockSize] - self.assertEquals(proto.getPacket(), None) - self.assertTrue(testCipher.usedDecrypt) - self.assertEquals(proto.first, '\x00\x00\x00\x0e\x09A') - proto.buf += value[MockCipher.decBlockSize:] - self.assertEquals(proto.getPacket(), 'ABCD') - self.assertEquals(proto.buf, '') - - - def test_getPacketCompressed(self): - """ - Test that compressed packets are retrieved correctly. See - test_sendPacketCompressed. - """ - proto = MockTransportBase() - proto.makeConnection(self.transport) - self.transport.clear() - proto.outgoingCompression = MockCompression() - proto.incomingCompression = proto.outgoingCompression - proto.sendPacket(ord('A'), 'BCD') - proto.buf = self.transport.value() - self.assertEquals(proto.getPacket(), 'ABCD') - - - def test_getPacketBoth(self): - """ - Test that compressed and encrypted packets are retrieved correctly. - See test_sendPacketBoth. - """ - proto = MockTransportBase() - proto.sendKexInit = lambda: None - proto.makeConnection(self.transport) - self.transport.clear() - proto.currentEncryptions = testCipher = MockCipher() - proto.outgoingCompression = MockCompression() - proto.incomingCompression = proto.outgoingCompression - proto.sendPacket(ord('A'), 'BCDEFG') - proto.buf = self.transport.value() - self.assertEquals(proto.getPacket(), 'ABCDEFG') - - - def test_ciphersAreValid(self): - """ - Test that all the supportedCiphers are valid. - """ - ciphers = transport.SSHCiphers('A', 'B', 'C', 'D') - iv = key = '\x00' * 16 - for cipName in self.proto.supportedCiphers: - self.assertTrue(ciphers._getCipher(cipName, iv, key)) - - - def test_sendKexInit(self): - """ - Test that the KEXINIT (key exchange initiation) message is sent - correctly. Payload:: - bytes[16] cookie - string key exchange algorithms - string public key algorithms - string outgoing ciphers - string incoming ciphers - string outgoing MACs - string incoming MACs - string outgoing compressions - string incoming compressions - bool first packet follows - uint32 0 - """ - value = self.transport.value().split('\r\n', 1)[1] - self.proto.buf = value - packet = self.proto.getPacket() - self.assertEquals(packet[0], chr(transport.MSG_KEXINIT)) - self.assertEquals(packet[1:17], '\x99' * 16) - (kex, pubkeys, ciphers1, ciphers2, macs1, macs2, compressions1, - compressions2, languages1, languages2, - buf) = common.getNS(packet[17:], 10) - - self.assertEquals(kex, ','.join(self.proto.supportedKeyExchanges)) - self.assertEquals(pubkeys, ','.join(self.proto.supportedPublicKeys)) - self.assertEquals(ciphers1, ','.join(self.proto.supportedCiphers)) - self.assertEquals(ciphers2, ','.join(self.proto.supportedCiphers)) - self.assertEquals(macs1, ','.join(self.proto.supportedMACs)) - self.assertEquals(macs2, ','.join(self.proto.supportedMACs)) - self.assertEquals(compressions1, - ','.join(self.proto.supportedCompressions)) - self.assertEquals(compressions2, - ','.join(self.proto.supportedCompressions)) - self.assertEquals(languages1, ','.join(self.proto.supportedLanguages)) - self.assertEquals(languages2, ','.join(self.proto.supportedLanguages)) - self.assertEquals(buf, '\x00' * 5) - - - def test_sendDebug(self): - """ - Test that debug messages are sent correctly. Payload:: - bool always display - string debug message - string language - """ - self.proto.sendDebug("test", True, 'en') - self.assertEquals( - self.packets, - [(transport.MSG_DEBUG, - "\x01\x00\x00\x00\x04test\x00\x00\x00\x02en")]) - - - def test_receiveDebug(self): - """ - Test that debug messages are received correctly. See test_sendDebug. - """ - self.proto.dispatchMessage( - transport.MSG_DEBUG, - '\x01\x00\x00\x00\x04test\x00\x00\x00\x02en') - self.assertEquals(self.proto.debugs, [(True, 'test', 'en')]) - - - def test_sendIgnore(self): - """ - Test that ignored messages are sent correctly. Payload:: - string ignored data - """ - self.proto.sendIgnore("test") - self.assertEquals( - self.packets, [(transport.MSG_IGNORE, - '\x00\x00\x00\x04test')]) - - - def test_receiveIgnore(self): - """ - Test that ignored messages are received correctly. See - test_sendIgnore. - """ - self.proto.dispatchMessage(transport.MSG_IGNORE, 'test') - self.assertEquals(self.proto.ignoreds, ['test']) - - - def test_sendUnimplemented(self): - """ - Test that unimplemented messages are sent correctly. Payload:: - uint32 sequence number - """ - self.proto.sendUnimplemented() - self.assertEquals( - self.packets, [(transport.MSG_UNIMPLEMENTED, - '\x00\x00\x00\x00')]) - - - def test_receiveUnimplemented(self): - """ - Test that unimplemented messages are received correctly. See - test_sendUnimplemented. - """ - self.proto.dispatchMessage(transport.MSG_UNIMPLEMENTED, - '\x00\x00\x00\xff') - self.assertEquals(self.proto.unimplementeds, [255]) - - - def test_sendDisconnect(self): - """ - Test that disconnection messages are sent correctly. Payload:: - uint32 reason code - string reason description - string language - """ - disconnected = [False] - def stubLoseConnection(): - disconnected[0] = True - self.transport.loseConnection = stubLoseConnection - self.proto.sendDisconnect(0xff, "test") - self.assertEquals( - self.packets, - [(transport.MSG_DISCONNECT, - "\x00\x00\x00\xff\x00\x00\x00\x04test\x00\x00\x00\x00")]) - self.assertTrue(disconnected[0]) - - - def test_receiveDisconnect(self): - """ - Test that disconnection messages are received correctly. See - test_sendDisconnect. - """ - disconnected = [False] - def stubLoseConnection(): - disconnected[0] = True - self.transport.loseConnection = stubLoseConnection - self.proto.dispatchMessage(transport.MSG_DISCONNECT, - '\x00\x00\x00\xff\x00\x00\x00\x04test') - self.assertEquals(self.proto.errors, [(255, 'test')]) - self.assertTrue(disconnected[0]) - - - def test_dataReceived(self): - """ - Test that dataReceived parses packets and dispatches them to - ssh_* methods. - """ - kexInit = [False] - def stubKEXINIT(packet): - kexInit[0] = True - self.proto.ssh_KEXINIT = stubKEXINIT - self.proto.dataReceived(self.transport.value()) - self.assertTrue(self.proto.gotVersion) - self.assertEquals(self.proto.ourVersionString, - self.proto.otherVersionString) - self.assertTrue(kexInit[0]) - - - def test_service(self): - """ - Test that the transport can set the running service and dispatches - packets to the service's packetReceived method. - """ - service = MockService() - self.proto.setService(service) - self.assertEquals(self.proto.service, service) - self.assertTrue(service.started) - self.proto.dispatchMessage(0xff, "test") - self.assertEquals(self.packets, [(0xff, "test")]) - - service2 = MockService() - self.proto.setService(service2) - self.assertTrue(service2.started) - self.assertTrue(service.stopped) - - self.proto.connectionLost(None) - self.assertTrue(service2.stopped) - - - def test_avatar(self): - """ - Test that the transport notifies the avatar of disconnections. - """ - disconnected = [False] - def logout(): - disconnected[0] = True - self.proto.logoutFunction = logout - self.proto.avatar = True - - self.proto.connectionLost(None) - self.assertTrue(disconnected[0]) - - - def test_isEncrypted(self): - """ - Test that the transport accurately reflects its encrypted status. - """ - self.assertFalse(self.proto.isEncrypted('in')) - self.assertFalse(self.proto.isEncrypted('out')) - self.assertFalse(self.proto.isEncrypted('both')) - self.proto.currentEncryptions = MockCipher() - self.assertTrue(self.proto.isEncrypted('in')) - self.assertTrue(self.proto.isEncrypted('out')) - self.assertTrue(self.proto.isEncrypted('both')) - self.proto.currentEncryptions = transport.SSHCiphers('none', 'none', - 'none', 'none') - self.assertFalse(self.proto.isEncrypted('in')) - self.assertFalse(self.proto.isEncrypted('out')) - self.assertFalse(self.proto.isEncrypted('both')) - - self.assertRaises(TypeError, self.proto.isEncrypted, 'bad') - - - def test_isVerified(self): - """ - Test that the transport accurately reflects its verified status. - """ - self.assertFalse(self.proto.isVerified('in')) - self.assertFalse(self.proto.isVerified('out')) - self.assertFalse(self.proto.isVerified('both')) - self.proto.currentEncryptions = MockCipher() - self.assertTrue(self.proto.isVerified('in')) - self.assertTrue(self.proto.isVerified('out')) - self.assertTrue(self.proto.isVerified('both')) - self.proto.currentEncryptions = transport.SSHCiphers('none', 'none', - 'none', 'none') - self.assertFalse(self.proto.isVerified('in')) - self.assertFalse(self.proto.isVerified('out')) - self.assertFalse(self.proto.isVerified('both')) - - self.assertRaises(TypeError, self.proto.isVerified, 'bad') - - - def test_loseConnection(self): - """ - Test that loseConnection sends a disconnect message and closes the - connection. - """ - disconnected = [False] - def stubLoseConnection(): - disconnected[0] = True - self.transport.loseConnection = stubLoseConnection - self.proto.loseConnection() - self.assertEquals(self.packets[0][0], transport.MSG_DISCONNECT) - self.assertEquals(self.packets[0][1][3], - chr(transport.DISCONNECT_CONNECTION_LOST)) - - - def test_badVersion(self): - """ - Test that the transport disconnects when it receives a bad version. - """ - def testBad(version): - self.packets = [] - self.proto.gotVersion = False - disconnected = [False] - def stubLoseConnection(): - disconnected[0] = True - self.transport.loseConnection = stubLoseConnection - for c in version + '\r\n': - self.proto.dataReceived(c) - self.assertTrue(disconnected[0]) - self.assertEquals(self.packets[0][0], transport.MSG_DISCONNECT) - self.assertEquals( - self.packets[0][1][3], - chr(transport.DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED)) - testBad('SSH-1.5-OpenSSH') - testBad('SSH-3.0-Twisted') - testBad('GET / HTTP/1.1') - - - def test_dataBeforeVersion(self): - """ - Test that the transport ignores data sent before the version string. - """ - proto = MockTransportBase() - proto.makeConnection(proto_helpers.StringTransport()) - data = ("""here's some stuff beforehand -here's some other stuff -""" + proto.ourVersionString + "\r\n") - [proto.dataReceived(c) for c in data] - self.assertTrue(proto.gotVersion) - self.assertEquals(proto.otherVersionString, proto.ourVersionString) - - - def test_compatabilityVersion(self): - """ - Test that the transport treats the compatbility version (1.99) - as equivalent to version 2.0. - """ - proto = MockTransportBase() - proto.makeConnection(proto_helpers.StringTransport()) - proto.dataReceived("SSH-1.99-OpenSSH\n") - self.assertTrue(proto.gotVersion) - self.assertEquals(proto.otherVersionString, "SSH-1.99-OpenSSH") - - - def test_badPackets(self): - """ - Test that the transport disconnects with an error when it receives - bad packets. - """ - def testBad(packet, error=transport.DISCONNECT_PROTOCOL_ERROR): - self.packets = [] - self.proto.buf = packet - self.assertEquals(self.proto.getPacket(), None) - self.assertEquals(len(self.packets), 1) - self.assertEquals(self.packets[0][0], transport.MSG_DISCONNECT) - self.assertEquals(self.packets[0][1][3], chr(error)) - - testBad('\xff' * 8) # big packet - testBad('\x00\x00\x00\x05\x00BCDE') # length not modulo blocksize - oldEncryptions = self.proto.currentEncryptions - self.proto.currentEncryptions = MockCipher() - testBad('\x00\x00\x00\x08\x06AB123456', # bad MAC - transport.DISCONNECT_MAC_ERROR) - self.proto.currentEncryptions.decrypt = lambda x: x[:-1] - testBad('\x00\x00\x00\x08\x06BCDEFGHIJK') # bad decryption - self.proto.currentEncryptions = oldEncryptions - self.proto.incomingCompression = MockCompression() - def stubDecompress(payload): - raise Exception('bad compression') - self.proto.incomingCompression.decompress = stubDecompress - testBad('\x00\x00\x00\x04\x00BCDE', # bad decompression - transport.DISCONNECT_COMPRESSION_ERROR) - self.flushLoggedErrors() - - - def test_unimplementedPackets(self): - """ - Test that unimplemented packet types cause MSG_UNIMPLEMENTED packets - to be sent. - """ - seqnum = self.proto.incomingPacketSequence - def checkUnimplemented(seqnum=seqnum): - self.assertEquals(self.packets[0][0], - transport.MSG_UNIMPLEMENTED) - self.assertEquals(self.packets[0][1][3], chr(seqnum)) - self.proto.packets = [] - seqnum += 1 - - self.proto.dispatchMessage(40, '') - checkUnimplemented() - transport.messages[41] = 'MSG_fiction' - self.proto.dispatchMessage(41, '') - checkUnimplemented() - self.proto.dispatchMessage(60, '') - checkUnimplemented() - self.proto.setService(MockService()) - self.proto.dispatchMessage(70, '') - checkUnimplemented() - self.proto.dispatchMessage(71, '') - checkUnimplemented() - - - def test_getKey(self): - """ - Test that _getKey generates the correct keys. - """ - self.proto.sessionID = 'EF' - - k1 = sha.new('AB' + 'CD' - + 'K' + self.proto.sessionID).digest() - k2 = sha.new('ABCD' + k1).digest() - self.assertEquals(self.proto._getKey('K', 'AB', 'CD'), k1 + k2) - - - def test_multipleClasses(self): - """ - Test that multiple instances have distinct states. - """ - proto = self.proto - proto.dataReceived(self.transport.value()) - proto.currentEncryptions = MockCipher() - proto.outgoingCompression = MockCompression() - proto.incomingCompression = MockCompression() - proto.setService(MockService()) - proto2 = MockTransportBase() - proto2.makeConnection(proto_helpers.StringTransport()) - proto2.sendIgnore('') - self.failIfEquals(proto.gotVersion, proto2.gotVersion) - self.failIfEquals(proto.transport, proto2.transport) - self.failIfEquals(proto.outgoingPacketSequence, - proto2.outgoingPacketSequence) - self.failIfEquals(proto.incomingPacketSequence, - proto2.incomingPacketSequence) - self.failIfEquals(proto.currentEncryptions, - proto2.currentEncryptions) - self.failIfEquals(proto.service, proto2.service) - - - -class ServerAndClientSSHTransportBaseCase: - """ - Tests that need to be run on both the server and the client. - """ - - - def checkDisconnected(self, kind=None): - """ - Helper function to check if the transport disconnected. - """ - if kind is None: - kind = transport.DISCONNECT_PROTOCOL_ERROR - self.assertEquals(self.packets[-1][0], transport.MSG_DISCONNECT) - self.assertEquals(self.packets[-1][1][3], chr(kind)) - - - def connectModifiedProtocol(self, protoModification, - kind=None): - """ - Helper function to connect a modified protocol to the test protocol - and test for disconnection. - """ - if kind is None: - kind = transport.DISCONNECT_KEY_EXCHANGE_FAILED - proto2 = self.klass() - protoModification(proto2) - proto2.makeConnection(proto_helpers.StringTransport()) - self.proto.dataReceived(proto2.transport.value()) - if kind: - self.checkDisconnected(kind) - return proto2 - - - def test_disconnectIfCantMatchKex(self): - """ - Test that the transport disconnects if it can't match the key - exchange - """ - def blankKeyExchanges(proto2): - proto2.supportedKeyExchanges = [] - self.connectModifiedProtocol(blankKeyExchanges) - - - def test_disconnectIfCantMatchKeyAlg(self): - """ - Like test_disconnectIfCantMatchKex, but for the key algorithm. - """ - def blankPublicKeys(proto2): - proto2.supportedPublicKeys = [] - self.connectModifiedProtocol(blankPublicKeys) - - - def test_disconnectIfCantMatchCompression(self): - """ - Like test_disconnectIfCantMatchKex, but for the compression. - """ - def blankCompressions(proto2): - proto2.supportedCompressions = [] - self.connectModifiedProtocol(blankCompressions) - - - def test_disconnectIfCantMatchCipher(self): - """ - Like test_disconnectIfCantMatchKex, but for the encryption. - """ - def blankCiphers(proto2): - proto2.supportedCiphers = [] - self.connectModifiedProtocol(blankCiphers) - - - def test_disconnectIfCantMatchMAC(self): - """ - Like test_disconnectIfCantMatchKex, but for the MAC. - """ - def blankMACs(proto2): - proto2.supportedMACs = [] - self.connectModifiedProtocol(blankMACs) - - - -class ServerSSHTransportTestCase(ServerAndClientSSHTransportBaseCase, - TransportTestCase): - """ - Tests for the SSHServerTransport. - """ - - klass = transport.SSHServerTransport - - - def setUp(self): - TransportTestCase.setUp(self) - self.proto.factory = MockFactory() - self.proto.factory.startFactory() - - - def tearDown(self): - TransportTestCase.tearDown(self) - self.proto.factory.stopFactory() - del self.proto.factory - - - def test_KEXINIT(self): - """ - Test that receiving a KEXINIT packet sets up the correct values on the - server. - """ - self.proto.dataReceived( 'SSH-2.0-Twisted\r\n\x00\x00\x01\xd4\t\x14' - '\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99' - '\x99\x00\x00\x00=diffie-hellman-group1-sha1,diffie-hellman-g' - 'roup-exchange-sha1\x00\x00\x00\x0fssh-dss,ssh-rsa\x00\x00\x00' - '\x85aes128-ctr,aes128-cbc,aes192-ctr,aes192-cbc,aes256-ctr,ae' - 's256-cbc,cast128-ctr,cast128-cbc,blowfish-ctr,blowfish-cbc,3d' - 'es-ctr,3des-cbc\x00\x00\x00\x85aes128-ctr,aes128-cbc,aes192-c' - 'tr,aes192-cbc,aes256-ctr,aes256-cbc,cast128-ctr,cast128-cbc,b' - 'lowfish-ctr,blowfish-cbc,3des-ctr,3des-cbc\x00\x00\x00\x12hma' - 'c-md5,hmac-sha1\x00\x00\x00\x12hmac-md5,hmac-sha1\x00\x00\x00' - '\tnone,zlib\x00\x00\x00\tnone,zlib\x00\x00\x00\x00\x00\x00' - '\x00\x00\x00\x00\x00\x00\x00\x99\x99\x99\x99\x99\x99\x99\x99' - '\x99') - self.assertEquals(self.proto.kexAlg, - 'diffie-hellman-group1-sha1') - self.assertEquals(self.proto.keyAlg, - 'ssh-dss') - self.assertEquals(self.proto.outgoingCompressionType, - 'none') - self.assertEquals(self.proto.incomingCompressionType, - 'none') - ne = self.proto.nextEncryptions - self.assertEquals(ne.outCipType, 'aes128-ctr') - self.assertEquals(ne.inCipType, 'aes128-ctr') - self.assertEquals(ne.outMACType, 'hmac-md5') - self.assertEquals(ne.inMACType, 'hmac-md5') - - - def test_ignoreGuessPacketKex(self): - """ - The client is allowed to send a guessed key exchange packet - after it sends the KEXINIT packet. However, if the key exchanges - do not match, that guess packet must be ignored. This tests that - the packet is ignored in the case of the key exchange method not - matching. - """ - kexInitPacket = '\x00' * 16 + ( - ''.join([common.NS(x) for x in - [','.join(y) for y in - [self.proto.supportedKeyExchanges[::-1], - self.proto.supportedPublicKeys, - self.proto.supportedCiphers, - self.proto.supportedCiphers, - self.proto.supportedMACs, - self.proto.supportedMACs, - self.proto.supportedCompressions, - self.proto.supportedCompressions, - self.proto.supportedLanguages, - self.proto.supportedLanguages]]])) + ( - '\xff\x00\x00\x00\x00') - self.proto.ssh_KEXINIT(kexInitPacket) - self.assertTrue(self.proto.ignoreNextPacket) - self.proto.ssh_DEBUG("\x01\x00\x00\x00\x04test\x00\x00\x00\x00") - self.assertTrue(self.proto.ignoreNextPacket) - - - self.proto.ssh_KEX_DH_GEX_REQUEST_OLD('\x00\x00\x08\x00') - self.assertFalse(self.proto.ignoreNextPacket) - self.assertEquals(self.packets, []) - self.proto.ignoreNextPacket = True - - self.proto.ssh_KEX_DH_GEX_REQUEST('\x00\x00\x08\x00' * 3) - self.assertFalse(self.proto.ignoreNextPacket) - self.assertEquals(self.packets, []) - - - def test_ignoreGuessPacketKey(self): - """ - Like test_ignoreGuessPacketKex, but for an incorrectly guessed - public key format. - """ - kexInitPacket = '\x00' * 16 + ( - ''.join([common.NS(x) for x in - [','.join(y) for y in - [self.proto.supportedKeyExchanges, - self.proto.supportedPublicKeys[::-1], - self.proto.supportedCiphers, - self.proto.supportedCiphers, - self.proto.supportedMACs, - self.proto.supportedMACs, - self.proto.supportedCompressions, - self.proto.supportedCompressions, - self.proto.supportedLanguages, - self.proto.supportedLanguages]]])) + ( - '\xff\x00\x00\x00\x00') - self.proto.ssh_KEXINIT(kexInitPacket) - self.assertTrue(self.proto.ignoreNextPacket) - self.proto.ssh_DEBUG("\x01\x00\x00\x00\x04test\x00\x00\x00\x00") - self.assertTrue(self.proto.ignoreNextPacket) - - self.proto.ssh_KEX_DH_GEX_REQUEST_OLD('\x00\x00\x08\x00') - self.assertFalse(self.proto.ignoreNextPacket) - self.assertEquals(self.packets, []) - self.proto.ignoreNextPacket = True - - self.proto.ssh_KEX_DH_GEX_REQUEST('\x00\x00\x08\x00' * 3) - self.assertFalse(self.proto.ignoreNextPacket) - self.assertEquals(self.packets, []) - - - def test_KEXDH_INIT(self): - """ - Test that the KEXDH_INIT packet causes the server to send a - KEXDH_REPLY with the server's public key and a signature. - """ - self.proto.supportedKeyExchanges = ['diffie-hellman-group1-sha1'] - self.proto.supportedPublicKeys = ['ssh-rsa'] - self.proto.dataReceived(self.transport.value()) - e = pow(transport.DH_GENERATOR, 5000, - transport.DH_PRIME) - - self.proto.ssh_KEX_DH_GEX_REQUEST_OLD(common.MP(e)) - y = common.getMP('\x00\x00\x00\x40' + '\x99' * 64)[0] - f = common._MPpow(transport.DH_GENERATOR, y, transport.DH_PRIME) - sharedSecret = common._MPpow(e, y, transport.DH_PRIME) - - h = sha.new() - h.update(common.NS(self.proto.ourVersionString) * 2) - h.update(common.NS(self.proto.ourKexInitPayload) * 2) - h.update(common.NS(self.proto.factory.publicKeys['ssh-rsa'].blob())) - h.update(common.MP(e)) - h.update(f) - h.update(sharedSecret) - exchangeHash = h.digest() - - signature = self.proto.factory.privateKeys['ssh-rsa'].sign( - exchangeHash) - - self.assertEquals( - self.packets, - [(transport.MSG_KEXDH_REPLY, - common.NS(self.proto.factory.publicKeys['ssh-rsa'].blob()) - + f + common.NS(signature)), - (transport.MSG_NEWKEYS, '')]) - - - def test_KEX_DH_GEX_REQUEST_OLD(self): - """ - Test that the KEX_DH_GEX_REQUEST_OLD message causes the server - to reply with a KEX_DH_GEX_GROUP message with the correct - Diffie-Hellman group. - """ - self.proto.supportedKeyExchanges = [ - 'diffie-hellman-group-exchange-sha1'] - self.proto.supportedPublicKeys = ['ssh-rsa'] - self.proto.dataReceived(self.transport.value()) - self.proto.ssh_KEX_DH_GEX_REQUEST_OLD('\x00\x00\x04\x00') - self.assertEquals( - self.packets, - [(transport.MSG_KEX_DH_GEX_GROUP, - common.MP(transport.DH_PRIME) + '\x00\x00\x00\x01\x02')]) - self.assertEquals(self.proto.g, 2) - self.assertEquals(self.proto.p, transport.DH_PRIME) - - - def test_KEX_DH_GEX_REQUEST_OLD_badKexAlg(self): - """ - Test that if the server recieves a KEX_DH_GEX_REQUEST_OLD message - and the key exchange algorithm is not 'diffie-hellman-group1-sha1' or - 'diffie-hellman-group-exchange-sha1', we raise a ConchError. - """ - self.proto.kexAlg = None - self.assertRaises(ConchError, self.proto.ssh_KEX_DH_GEX_REQUEST_OLD, - None) - - - def test_KEX_DH_GEX_REQUEST(self): - """ - Test that the KEX_DH_GEX_REQUEST message causes the server to reply - with a KEX_DH_GEX_GROUP message with the correct Diffie-Hellman - group. - """ - self.proto.supportedKeyExchanges = [ - 'diffie-hellman-group-exchange-sha1'] - self.proto.supportedPublicKeys = ['ssh-rsa'] - self.proto.dataReceived(self.transport.value()) - self.proto.ssh_KEX_DH_GEX_REQUEST('\x00\x00\x04\x00\x00\x00\x08\x00' + - '\x00\x00\x0c\x00') - self.assertEquals( - self.packets, - [(transport.MSG_KEX_DH_GEX_GROUP, - common.MP(transport.DH_PRIME) + '\x00\x00\x00\x01\x03')]) - self.assertEquals(self.proto.g, 3) - self.assertEquals(self.proto.p, transport.DH_PRIME) - - - def test_KEX_DH_GEX_INIT_after_REQUEST(self): - """ - Test that the KEX_DH_GEX_INIT message after the client sends - KEX_DH_GEX_REQUEST causes the server to send a KEX_DH_GEX_INIT message - with a public key and signature. - """ - self.test_KEX_DH_GEX_REQUEST() - e = pow(self.proto.g, 3, self.proto.p) - y = common.getMP('\x00\x00\x00\x80' + '\x99' * 128)[0] - f = common._MPpow(self.proto.g, y, self.proto.p) - sharedSecret = common._MPpow(e, y, self.proto.p) - h = sha.new() - h.update(common.NS(self.proto.ourVersionString) * 2) - h.update(common.NS(self.proto.ourKexInitPayload) * 2) - h.update(common.NS(self.proto.factory.publicKeys['ssh-rsa'].blob())) - h.update('\x00\x00\x04\x00\x00\x00\x08\x00\x00\x00\x0c\x00') - h.update(common.MP(self.proto.p)) - h.update(common.MP(self.proto.g)) - h.update(common.MP(e)) - h.update(f) - h.update(sharedSecret) - exchangeHash = h.digest() - self.proto.ssh_KEX_DH_GEX_INIT(common.MP(e)) - self.assertEquals( - self.packets[1], - (transport.MSG_KEX_DH_GEX_REPLY, - common.NS(self.proto.factory.publicKeys['ssh-rsa'].blob()) + - f + common.NS(self.proto.factory.privateKeys['ssh-rsa'].sign( - exchangeHash)))) - - - def test_KEX_DH_GEX_INIT_after_REQUEST_OLD(self): - """ - Test that the KEX_DH_GEX_INIT message after the client sends - KEX_DH_GEX_REQUEST_OLD causes the server to sent a KEX_DH_GEX_INIT - message with a public key and signature. - """ - self.test_KEX_DH_GEX_REQUEST_OLD() - e = pow(self.proto.g, 3, self.proto.p) - y = common.getMP('\x00\x00\x00\x80' + '\x99' * 128)[0] - f = common._MPpow(self.proto.g, y, self.proto.p) - sharedSecret = common._MPpow(e, y, self.proto.p) - h = sha.new() - h.update(common.NS(self.proto.ourVersionString) * 2) - h.update(common.NS(self.proto.ourKexInitPayload) * 2) - h.update(common.NS(self.proto.factory.publicKeys['ssh-rsa'].blob())) - h.update('\x00\x00\x04\x00') - h.update(common.MP(self.proto.p)) - h.update(common.MP(self.proto.g)) - h.update(common.MP(e)) - h.update(f) - h.update(sharedSecret) - exchangeHash = h.digest() - self.proto.ssh_KEX_DH_GEX_INIT(common.MP(e)) - self.assertEquals( - self.packets[1:], - [(transport.MSG_KEX_DH_GEX_REPLY, - common.NS(self.proto.factory.publicKeys['ssh-rsa'].blob()) + - f + common.NS(self.proto.factory.privateKeys['ssh-rsa'].sign( - exchangeHash))), - (transport.MSG_NEWKEYS, '')]) - - - def test_keySetup(self): - """ - Test that _keySetup sets up the next encryption keys. - """ - self.proto.nextEncryptions = MockCipher() - self.proto._keySetup('AB', 'CD') - self.assertEquals(self.proto.sessionID, 'CD') - self.proto._keySetup('AB', 'EF') - self.assertEquals(self.proto.sessionID, 'CD') - self.assertEquals(self.packets[-1], (transport.MSG_NEWKEYS, '')) - newKeys = [self.proto._getKey(c, 'AB', 'EF') for c in 'ABCDEF'] - self.assertEquals( - self.proto.nextEncryptions.keys, - (newKeys[1], newKeys[3], newKeys[0], newKeys[2], newKeys[5], - newKeys[4])) - - - def test_NEWKEYS(self): - """ - Test that NEWKEYS transitions the keys in nextEncryptions to - currentEncryptions. - """ - self.test_KEXINIT() - - self.proto.nextEncryptions = transport.SSHCiphers('none', 'none', - 'none', 'none') - self.proto.ssh_NEWKEYS('') - self.assertIdentical(self.proto.currentEncryptions, - self.proto.nextEncryptions) - self.assertIdentical(self.proto.outgoingCompression, None) - self.assertIdentical(self.proto.incomingCompression, None) - self.proto.outgoingCompressionType = 'zlib' - self.proto.ssh_NEWKEYS('') - self.failIfIdentical(self.proto.outgoingCompression, None) - self.proto.incomingCompressionType = 'zlib' - self.proto.ssh_NEWKEYS('') - self.failIfIdentical(self.proto.incomingCompression, None) - - - def test_SERVICE_REQUEST(self): - """ - Test that the SERVICE_REQUEST message requests and starts a - service. - """ - self.proto.ssh_SERVICE_REQUEST(common.NS('ssh-userauth')) - self.assertEquals(self.packets, [(transport.MSG_SERVICE_ACCEPT, - common.NS('ssh-userauth'))]) - self.assertEquals(self.proto.service.name, 'MockService') - - - def test_disconnectNEWKEYSData(self): - """ - Test that NEWKEYS disconnects if it receives data. - """ - self.proto.ssh_NEWKEYS("bad packet") - self.checkDisconnected() - - - def test_disconnectSERVICE_REQUESTBadService(self): - """ - Test that SERVICE_REQUESTS disconnects if an unknown service is - requested. - """ - self.proto.ssh_SERVICE_REQUEST(common.NS('no service')) - self.checkDisconnected(transport.DISCONNECT_SERVICE_NOT_AVAILABLE) - - - -class ClientSSHTransportTestCase(ServerAndClientSSHTransportBaseCase, - TransportTestCase): - """ - Tests for SSHClientTransport. - """ - - klass = transport.SSHClientTransport - - - def test_KEXINIT(self): - """ - Test that receiving a KEXINIT packet sets up the correct values on the - client. The way algorithms are picks is that the first item in the - client's list that is also in the server's list is chosen. - """ - self.proto.dataReceived( 'SSH-2.0-Twisted\r\n\x00\x00\x01\xd4\t\x14' - '\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99' - '\x99\x00\x00\x00=diffie-hellman-group1-sha1,diffie-hellman-g' - 'roup-exchange-sha1\x00\x00\x00\x0fssh-dss,ssh-rsa\x00\x00\x00' - '\x85aes128-ctr,aes128-cbc,aes192-ctr,aes192-cbc,aes256-ctr,ae' - 's256-cbc,cast128-ctr,cast128-cbc,blowfish-ctr,blowfish-cbc,3d' - 'es-ctr,3des-cbc\x00\x00\x00\x85aes128-ctr,aes128-cbc,aes192-c' - 'tr,aes192-cbc,aes256-ctr,aes256-cbc,cast128-ctr,cast128-cbc,b' - 'lowfish-ctr,blowfish-cbc,3des-ctr,3des-cbc\x00\x00\x00\x12hma' - 'c-md5,hmac-sha1\x00\x00\x00\x12hmac-md5,hmac-sha1\x00\x00\x00' - '\tzlib,none\x00\x00\x00\tzlib,none\x00\x00\x00\x00\x00\x00' - '\x00\x00\x00\x00\x00\x00\x00\x99\x99\x99\x99\x99\x99\x99\x99' - '\x99') - self.assertEquals(self.proto.kexAlg, - 'diffie-hellman-group-exchange-sha1') - self.assertEquals(self.proto.keyAlg, - 'ssh-rsa') - self.assertEquals(self.proto.outgoingCompressionType, - 'none') - self.assertEquals(self.proto.incomingCompressionType, - 'none') - ne = self.proto.nextEncryptions - self.assertEquals(ne.outCipType, 'aes256-ctr') - self.assertEquals(ne.inCipType, 'aes256-ctr') - self.assertEquals(ne.outMACType, 'hmac-sha1') - self.assertEquals(ne.inMACType, 'hmac-sha1') - - - def verifyHostKey(self, pubKey, fingerprint): - """ - Mock version of SSHClientTransport.verifyHostKey. - """ - self.calledVerifyHostKey = True - self.assertEquals(pubKey, self.blob) - self.assertEquals(fingerprint.replace(':', ''), - md5.new(pubKey).hexdigest()) - return defer.succeed(True) - - - def setUp(self): - TransportTestCase.setUp(self) - self.blob = keys.Key.fromString(keydata.publicRSA_openssh).blob() - self.privObj = keys.Key.fromString(keydata.privateRSA_openssh) - self.calledVerifyHostKey = False - self.proto.verifyHostKey = self.verifyHostKey - - - def test_notImplementedClientMethods(self): - """ - verifyHostKey() should return a Deferred which fails with a - NotImplementedError exception. connectionSecure() should raise - NotImplementedError(). - """ - self.assertRaises(NotImplementedError, self.klass().connectionSecure) - def _checkRaises(f): - f.trap(NotImplementedError) - d = self.klass().verifyHostKey(None, None) - return d.addCallback(self.fail).addErrback(_checkRaises) - - - def test_KEXINIT_groupexchange(self): - """ - Test that a KEXINIT packet with a group-exchange key exchange results - in a KEX_DH_GEX_REQUEST_OLD message.. - """ - self.proto.supportedKeyExchanges = [ - 'diffie-hellman-group-exchange-sha1'] - self.proto.dataReceived(self.transport.value()) - self.assertEquals(self.packets, [(transport.MSG_KEX_DH_GEX_REQUEST_OLD, - '\x00\x00\x08\x00')]) - - - def test_KEXINIT_group1(self): - """ - Like test_KEXINIT_groupexchange, but for the group-1 key exchange. - """ - self.proto.supportedKeyExchanges = ['diffie-hellman-group1-sha1'] - self.proto.dataReceived(self.transport.value()) - self.assertEquals(common.MP(self.proto.x)[5:], '\x99' * 64) - self.assertEquals(self.packets, - [(transport.MSG_KEXDH_INIT, self.proto.e)]) - - - def test_KEXINIT_badKexAlg(self): - """ - Test that the client raises a ConchError if it receives a - KEXINIT message bug doesn't have a key exchange algorithm that we - understand. - """ - self.proto.supportedKeyExchanges = ['diffie-hellman-group2-sha1'] - data = self.transport.value().replace('group1', 'group2') - self.assertRaises(ConchError, self.proto.dataReceived, data) - - - def test_KEXDH_REPLY(self): - """ - Test that the KEXDH_REPLY message verifies the server. - """ - self.test_KEXINIT_group1() - - sharedSecret = common._MPpow(transport.DH_GENERATOR, - self.proto.x, transport.DH_PRIME) - h = sha.new() - h.update(common.NS(self.proto.ourVersionString) * 2) - h.update(common.NS(self.proto.ourKexInitPayload) * 2) - h.update(common.NS(self.blob)) - h.update(self.proto.e) - h.update('\x00\x00\x00\x01\x02') # f - h.update(sharedSecret) - exchangeHash = h.digest() - - def _cbTestKEXDH_REPLY(value): - self.assertIdentical(value, None) - self.assertEquals(self.calledVerifyHostKey, True) - self.assertEquals(self.proto.sessionID, exchangeHash) - - signature = self.privObj.sign(exchangeHash) - - d = self.proto.ssh_KEX_DH_GEX_GROUP( - (common.NS(self.blob) + '\x00\x00\x00\x01\x02' + - common.NS(signature))) - d.addCallback(_cbTestKEXDH_REPLY) - - return d - - - def test_KEX_DH_GEX_GROUP(self): - """ - Test that the KEX_DH_GEX_GROUP message results in a - KEX_DH_GEX_INIT message with the client's Diffie-Hellman public key. - """ - self.test_KEXINIT_groupexchange() - self.proto.ssh_KEX_DH_GEX_GROUP( - '\x00\x00\x00\x01\x0f\x00\x00\x00\x01\x02') - self.assertEquals(self.proto.p, 15) - self.assertEquals(self.proto.g, 2) - self.assertEquals(common.MP(self.proto.x)[5:], '\x99' * 40) - self.assertEquals(self.proto.e, - common.MP(pow(2, self.proto.x, 15))) - self.assertEquals(self.packets[1:], [(transport.MSG_KEX_DH_GEX_INIT, - self.proto.e)]) - - - def test_KEX_DH_GEX_REPLY(self): - """ - Test that the KEX_DH_GEX_REPLY message results in a verified - server. - """ - - self.test_KEX_DH_GEX_GROUP() - sharedSecret = common._MPpow(3, self.proto.x, self.proto.p) - h = sha.new() - h.update(common.NS(self.proto.ourVersionString) * 2) - h.update(common.NS(self.proto.ourKexInitPayload) * 2) - h.update(common.NS(self.blob)) - h.update('\x00\x00\x08\x00\x00\x00\x00\x01\x0f\x00\x00\x00\x01\x02') - h.update(self.proto.e) - h.update('\x00\x00\x00\x01\x03') # f - h.update(sharedSecret) - exchangeHash = h.digest() - - def _cbTestKEX_DH_GEX_REPLY(value): - self.assertIdentical(value, None) - self.assertEquals(self.calledVerifyHostKey, True) - self.assertEquals(self.proto.sessionID, exchangeHash) - - signature = self.privObj.sign(exchangeHash) - - d = self.proto.ssh_KEX_DH_GEX_REPLY( - common.NS(self.blob) + - '\x00\x00\x00\x01\x03' + - common.NS(signature)) - d.addCallback(_cbTestKEX_DH_GEX_REPLY) - return d - - - def test_keySetup(self): - """ - Test that _keySetup sets up the next encryption keys. - """ - self.proto.nextEncryptions = MockCipher() - self.proto._keySetup('AB', 'CD') - self.assertEquals(self.proto.sessionID, 'CD') - self.proto._keySetup('AB', 'EF') - self.assertEquals(self.proto.sessionID, 'CD') - self.assertEquals(self.packets[-1], (transport.MSG_NEWKEYS, '')) - newKeys = [self.proto._getKey(c, 'AB', 'EF') for c in 'ABCDEF'] - self.assertEquals(self.proto.nextEncryptions.keys, - (newKeys[0], newKeys[2], newKeys[1], newKeys[3], - newKeys[4], newKeys[5])) - - - def test_NEWKEYS(self): - """ - Test that NEWKEYS transitions the keys from nextEncryptions to - currentEncryptions. - """ - self.test_KEXINIT() - secure = [False] - def stubConnectionSecure(): - secure[0] = True - self.proto.connectionSecure = stubConnectionSecure - - self.proto.nextEncryptions = transport.SSHCiphers('none', 'none', - 'none', 'none') - self.proto.ssh_NEWKEYS('') - - self.failIfIdentical(self.proto.currentEncryptions, - self.proto.nextEncryptions) - - self.proto.nextEncryptions = MockCipher() - self.proto._keySetup('AB', 'EF') - self.assertIdentical(self.proto.outgoingCompression, None) - self.assertIdentical(self.proto.incomingCompression, None) - self.assertIdentical(self.proto.currentEncryptions, - self.proto.nextEncryptions) - self.assertTrue(secure[0]) - self.proto.outgoingCompressionType = 'zlib' - self.proto.ssh_NEWKEYS('') - self.failIfIdentical(self.proto.outgoingCompression, None) - self.proto.incomingCompressionType = 'zlib' - self.proto.ssh_NEWKEYS('') - self.failIfIdentical(self.proto.incomingCompression, None) - - - def test_SERVICE_ACCEPT(self): - """ - Test that the SERVICE_ACCEPT packet starts the requested service. - """ - self.proto.instance = MockService() - self.proto.ssh_SERVICE_ACCEPT('\x00\x00\x00\x0bMockService') - self.assertTrue(self.proto.instance.started) - - - def test_requestService(self): - """ - Test that requesting a service sends a SERVICE_REQUEST packet. - """ - self.proto.requestService(MockService()) - self.assertEquals(self.packets, [(transport.MSG_SERVICE_REQUEST, - '\x00\x00\x00\x0bMockService')]) - - - def test_disconnectKEXDH_REPLYBadSignature(self): - """ - Test that KEXDH_REPLY disconnects if the signature is bad. - """ - self.test_KEXDH_REPLY() - self.proto._continueKEXDH_REPLY(None, self.blob, 3, "bad signature") - self.checkDisconnected(transport.DISCONNECT_KEY_EXCHANGE_FAILED) - - - def test_disconnectGEX_REPLYBadSignature(self): - """ - Like test_disconnectKEXDH_REPLYBadSignature, but for DH_GEX_REPLY. - """ - self.test_KEX_DH_GEX_REPLY() - self.proto._continueGEX_REPLY(None, self.blob, 3, "bad signature") - self.checkDisconnected(transport.DISCONNECT_KEY_EXCHANGE_FAILED) - - - def test_disconnectNEWKEYSData(self): - """ - Test that NEWKEYS disconnects if it receives data. - """ - self.proto.ssh_NEWKEYS("bad packet") - self.checkDisconnected() - - - def test_disconnectSERVICE_ACCEPT(self): - """ - Test that SERVICE_ACCEPT disconnects if the accepted protocol is - differet from the asked-for protocol. - """ - self.proto.instance = MockService() - self.proto.ssh_SERVICE_ACCEPT('\x00\x00\x00\x03bad') - self.checkDisconnected() - - - -class SSHCiphersTestCase(unittest.TestCase): - """ - Tests for the SSHCiphers helper class. - """ - if Crypto is None: - skip = "cannot run w/o PyCrypto" - - - def test_init(self): - """ - Test that the initializer sets up the SSHCiphers object. - """ - ciphers = transport.SSHCiphers('A', 'B', 'C', 'D') - self.assertEquals(ciphers.outCipType, 'A') - self.assertEquals(ciphers.inCipType, 'B') - self.assertEquals(ciphers.outMACType, 'C') - self.assertEquals(ciphers.inMACType, 'D') - - - def test_getCipher(self): - """ - Test that the _getCipher method returns the correct cipher. - """ - ciphers = transport.SSHCiphers('A', 'B', 'C', 'D') - iv = key = '\x00' * 16 - for cipName, (modName, keySize, counter) in ciphers.cipherMap.items(): - cip = ciphers._getCipher(cipName, iv, key) - if cipName == 'none': - self.assertIsInstance(cip, transport._DummyCipher) - else: - self.assertTrue(str(cip).startswith('<' + modName)) - - - def test_getMAC(self): - """ - Test that the _getMAC method returns the correct MAC. - """ - ciphers = transport.SSHCiphers('A', 'B', 'C', 'D') - key = '\x00' * 64 - for macName, mac in ciphers.macMap.items(): - mod = ciphers._getMAC(macName, key) - if macName == 'none': - self.assertIdentical(mac, None) - else: - self.assertEquals(mod[0], mac) - self.assertEquals(mod[1], - Crypto.Cipher.XOR.new('\x36').encrypt(key)) - self.assertEquals(mod[2], - Crypto.Cipher.XOR.new('\x5c').encrypt(key)) - self.assertEquals(mod[3], len(mod[0].new().digest())) - - - def test_setKeysCiphers(self): - """ - Test that setKeys sets up the ciphers. - """ - key = '\x00' * 64 - cipherItems = transport.SSHCiphers.cipherMap.items() - for cipName, (modName, keySize, counter) in cipherItems: - encCipher = transport.SSHCiphers(cipName, 'none', 'none', 'none') - decCipher = transport.SSHCiphers('none', cipName, 'none', 'none') - cip = encCipher._getCipher(cipName, key, key) - bs = cip.block_size - encCipher.setKeys(key, key, '', '', '', '') - decCipher.setKeys('', '', key, key, '', '') - self.assertEquals(encCipher.encBlockSize, bs) - self.assertEquals(decCipher.decBlockSize, bs) - enc = cip.encrypt(key[:bs]) - enc2 = cip.encrypt(key[:bs]) - if counter: - self.failIfEquals(enc, enc2) - self.assertEquals(encCipher.encrypt(key[:bs]), enc) - self.assertEquals(encCipher.encrypt(key[:bs]), enc2) - self.assertEquals(decCipher.decrypt(enc), key[:bs]) - self.assertEquals(decCipher.decrypt(enc2), key[:bs]) - - - def test_setKeysMACs(self): - """ - Test that setKeys sets up the MACs. - """ - key = '\x00' * 64 - for macName, mod in transport.SSHCiphers.macMap.items(): - outMac = transport.SSHCiphers('none', 'none', macName, 'none') - inMac = transport.SSHCiphers('none', 'none', 'none', macName) - outMac.setKeys('', '', '', '', key, '') - inMac.setKeys('', '', '', '', '', key) - if mod: - ds = mod.digest_size - else: - ds = 0 - self.assertEquals(inMac.verifyDigestSize, ds) - if mod: - mod, i, o, ds = outMac._getMAC(macName, key) - seqid = 0 - data = key - packet = '\x00' * 4 + key - if mod: - mac = mod.new(o + mod.new(i + packet).digest()).digest() - else: - mac = '' - self.assertEquals(outMac.makeMAC(seqid, data), mac) - self.assertTrue(inMac.verify(seqid, data, mac)) - - - -class CounterTestCase(unittest.TestCase): - """ - Tests for the _Counter helper class. - """ - if Crypto is None: - skip = "cannot run w/o PyCrypto" - - - def test_init(self): - """ - Test that the counter is initialized correctly. - """ - counter = transport._Counter('\x00' * 8 + '\xff' * 8, 8) - self.assertEquals(counter.blockSize, 8) - self.assertEquals(counter.count.tostring(), '\x00' * 8) - - - def test_count(self): - """ - Test that the counter counts incrementally and wraps at the top. - """ - counter = transport._Counter('\x00', 1) - self.assertEquals(counter(), '\x01') - self.assertEquals(counter(), '\x02') - [counter() for i in range(252)] - self.assertEquals(counter(), '\xff') - self.assertEquals(counter(), '\x00') - - - -class TransportLoopbackTestCase(unittest.TestCase): - """ - Test the server transport and client transport against each other, - """ - if Crypto is None: - skip = "cannot run w/o PyCrypto" - - - def _runClientServer(self, mod): - """ - Run an async client and server, modifying each using the mod function - provided. Returns a Deferred called back when both Protocols have - disconnected. - - @type mod: C{func} - @rtype: C{defer.Deferred} - """ - factory = MockFactory() - server = transport.SSHServerTransport() - server.factory = factory - factory.startFactory() - server.errors = [] - server.receiveError = lambda code, desc: server.errors.append(( - code, desc)) - client = transport.SSHClientTransport() - client.verifyHostKey = lambda x, y: defer.succeed(None) - client.errors = [] - client.receiveError = lambda code, desc: client.errors.append(( - code, desc)) - client.connectionSecure = lambda: client.loseConnection() - server = mod(server) - client = mod(client) - def check(ignored, server, client): - name = repr([server.supportedCiphers[0], - server.supportedMACs[0], - server.supportedKeyExchanges[0], - server.supportedCompressions[0]]) - self.assertEquals(client.errors, []) - self.assertEquals(server.errors, [( - transport.DISCONNECT_CONNECTION_LOST, - "user closed connection")]) - if server.supportedCiphers[0] == 'none': - self.assertFalse(server.isEncrypted(), name) - self.assertFalse(client.isEncrypted(), name) - else: - self.assertTrue(server.isEncrypted(), name) - self.assertTrue(client.isEncrypted(), name) - if server.supportedMACs[0] == 'none': - self.assertFalse(server.isVerified(), name) - self.assertFalse(client.isVerified(), name) - else: - self.assertTrue(server.isVerified(), name) - self.assertTrue(client.isVerified(), name) - - d = loopback.loopbackAsync(server, client) - d.addCallback(check, server, client) - return d - - - def test_ciphers(self): - """ - Test that the client and server play nicely together, in all - the various combinations of ciphers. - """ - deferreds = [] - for cipher in transport.SSHTransportBase.supportedCiphers + ['none']: - def setCipher(proto): - proto.supportedCiphers = [cipher] - return proto - deferreds.append(self._runClientServer(setCipher)) - return defer.DeferredList(deferreds, fireOnOneErrback=True) - - - def test_macs(self): - """ - Like test_ciphers, but for the various MACs. - """ - deferreds = [] - for mac in transport.SSHTransportBase.supportedMACs + ['none']: - def setMAC(proto): - proto.supportedMACs = [mac] - return proto - deferreds.append(self._runClientServer(setMAC)) - return defer.DeferredList(deferreds, fireOnOneErrback=True) - - - def test_keyexchanges(self): - """ - Like test_ciphers, but for the various key exchanges. - """ - deferreds = [] - for kex in transport.SSHTransportBase.supportedKeyExchanges: - def setKeyExchange(proto): - proto.supportedKeyExchanges = [kex] - return proto - deferreds.append(self._runClientServer(setKeyExchange)) - return defer.DeferredList(deferreds, fireOnOneErrback=True) - - - def test_compressions(self): - """ - Like test_ciphers, but for the various compressions. - """ - deferreds = [] - for compression in transport.SSHTransportBase.supportedCompressions: - def setCompression(proto): - proto.supportedCompressions = [compression] - return proto - deferreds.append(self._runClientServer(setCompression)) - return defer.DeferredList(deferreds, fireOnOneErrback=True) - - - -class OldFactoryTestCase(unittest.TestCase): - """ - The old C{SSHFactory.getPublicKeys}() returned mappings of key names to - strings of key blobs and mappings of key names to PyCrypto key objects from - C{SSHFactory.getPrivateKeys}() (they could also be specified with the - C{publicKeys} and C{privateKeys} attributes). This is no longer supported - by the C{SSHServerTransport}, so we warn the user if they create an old - factory. - """ - - - def test_getPublicKeysWarning(self): - """ - If the return value of C{getPublicKeys}() isn't a mapping from key - names to C{Key} objects, then warn the user and convert the mapping. - """ - sshFactory = MockOldFactoryPublicKeys() - self.assertWarns(DeprecationWarning, - "Returning a mapping from strings to strings from" - " getPublicKeys()/publicKeys (in %s) is deprecated. Return " - "a mapping from strings to Key objects instead." % - (qual(MockOldFactoryPublicKeys),), - factory.__file__, sshFactory.startFactory) - self.assertEquals(sshFactory.publicKeys, MockFactory().getPublicKeys()) - - - def test_getPrivateKeysWarning(self): - """ - If the return value of C{getPrivateKeys}() isn't a mapping from key - names to C{Key} objects, then warn the user and convert the mapping. - """ - sshFactory = MockOldFactoryPrivateKeys() - self.assertWarns(DeprecationWarning, - "Returning a mapping from strings to PyCrypto key objects from" - " getPrivateKeys()/privateKeys (in %s) is deprecated. Return" - " a mapping from strings to Key objects instead." % - (qual(MockOldFactoryPrivateKeys),), - factory.__file__, sshFactory.startFactory) - self.assertEquals(sshFactory.privateKeys, - MockFactory().getPrivateKeys()) - - - def test_publicKeysWarning(self): - """ - If the value of the C{publicKeys} attribute isn't a mapping from key - names to C{Key} objects, then warn the user and convert the mapping. - """ - sshFactory = MockOldFactoryPublicKeys() - sshFactory.publicKeys = sshFactory.getPublicKeys() - self.assertWarns(DeprecationWarning, - "Returning a mapping from strings to strings from" - " getPublicKeys()/publicKeys (in %s) is deprecated. Return " - "a mapping from strings to Key objects instead." % - (qual(MockOldFactoryPublicKeys),), - factory.__file__, sshFactory.startFactory) - self.assertEquals(sshFactory.publicKeys, MockFactory().getPublicKeys()) - - - def test_privateKeysWarning(self): - """ - If the return value of C{privateKeys} attribute isn't a mapping from - key names to C{Key} objects, then warn the user and convert the - mapping. - """ - sshFactory = MockOldFactoryPrivateKeys() - sshFactory.privateKeys = sshFactory.getPrivateKeys() - self.assertWarns(DeprecationWarning, - "Returning a mapping from strings to PyCrypto key objects from" - " getPrivateKeys()/privateKeys (in %s) is deprecated. Return" - " a mapping from strings to Key objects instead." % - (qual(MockOldFactoryPrivateKeys),), - factory.__file__, sshFactory.startFactory) - self.assertEquals(sshFactory.privateKeys, - MockFactory().getPrivateKeys()) diff --git a/tools/buildbot/pylibs/twisted/conch/test/test_userauth.py b/tools/buildbot/pylibs/twisted/conch/test/test_userauth.py deleted file mode 100644 index b0b601f..0000000 --- a/tools/buildbot/pylibs/twisted/conch/test/test_userauth.py +++ /dev/null @@ -1,176 +0,0 @@ -from zope.interface import implements - -from twisted.cred.checkers import ICredentialsChecker -from twisted.cred.credentials import IUsernamePassword -from twisted.cred.error import UnauthorizedLogin -from twisted.cred.portal import IRealm, Portal - -from twisted.conch.error import ConchError -from twisted.conch.ssh import userauth -from twisted.conch.ssh.common import NS -from twisted.conch.ssh.transport import SSHServerTransport - -from twisted.internet import defer - -from twisted.trial import unittest - - - -class FakeTransport(SSHServerTransport): - """ - L{userauth.SSHUserAuthServer} expects an SSH transport which has a factory - attribute which has a portal attribute. Because the portal is important for - testing authentication, we need to be able to provide an interesting portal - object to the C{SSHUserAuthServer}. - - In addition, we want to be able to capture any packets sent over the - transport. - """ - - - class Service(object): - name = 'nancy' - - def serviceStarted(self): - pass - - - class Factory(object): - def _makeService(self): - return FakeTransport.Service() - - def getService(self, transport, nextService): - # This has to return a callable. - return self._makeService - - - def __init__(self, portal): - self.factory = self.Factory() - self.factory.portal = portal - self.packets = [] - - - def sendPacket(self, messageType, message): - self.packets.append((messageType, message)) - - - def isEncrypted(self, direction): - """ - Pretend that this transport encrypts traffic in both directions. The - SSHUserAuthServer disables password authentication if the transport - isn't encrypted. - """ - return True - - - -class Realm(object): - """ - A mock realm for testing L{userauth.SSHUserAuthServer}. - - This realm is not actually used in the course of testing, so it returns the - simplest thing that could possibly work. - """ - - implements(IRealm) - - def requestAvatar(self, avatarId, mind, *interfaces): - return defer.succeed((interfaces[0], None, lambda: None)) - - - -class MockChecker(object): - """ - A very simple username/password checker which authenticates anyone whose - password matches their username and rejects all others. - """ - - credentialInterfaces = (IUsernamePassword,) - implements(ICredentialsChecker) - - - def requestAvatarId(self, creds): - if creds.username == creds.password: - return defer.succeed(creds.username) - return defer.fail(UnauthorizedLogin("Invalid username/password pair")) - - - -class TestSSHUserAuthServer(unittest.TestCase): - """Tests for SSHUserAuthServer.""" - - def setUp(self): - self.realm = Realm() - portal = Portal(self.realm) - portal.registerChecker(MockChecker()) - self.authServer = userauth.SSHUserAuthServer() - self.authServer.transport = FakeTransport(portal) - self.authServer.serviceStarted() - - - def tearDown(self): - self.authServer.serviceStopped() - self.authServer = None - - - def test_successfulAuthentication(self): - """ - When provided with correct authentication information, the server - should respond by sending a MSG_USERAUTH_SUCCESS message with no other - data. - - See RFC 4252, Section 5.1. - """ - packet = NS('foo') + NS('none') + NS('password') + chr(0) + NS('foo') - d = self.authServer.ssh_USERAUTH_REQUEST(packet) - - def check(ignored): - # Check that the server reports the failure, including 'password' - # as a valid authentication type. - self.assertEqual( - self.authServer.transport.packets, - [(userauth.MSG_USERAUTH_SUCCESS, '')]) - return d.addCallback(check) - - - def test_failedAuthentication(self): - """ - When provided with invalid authentication details, the server should - respond by sending a MSG_USERAUTH_FAILURE message which states whether - the authentication was partially successful, and provides other, open - options for authentication. - - See RFC 4252, Section 5.1. - """ - # packet = username, next_service, authentication type, FALSE, password - packet = NS('foo') + NS('none') + NS('password') + chr(0) + NS('bar') - d = self.authServer.ssh_USERAUTH_REQUEST(packet) - - def check(ignored): - # Check that the server reports the failure, including 'password' - # as a valid authentication type. - self.assertEqual( - self.authServer.transport.packets, - [(userauth.MSG_USERAUTH_FAILURE, NS('password') + chr(0))]) - return d.addCallback(check) - - - def test_requestRaisesConchError(self): - """ - ssh_USERAUTH_REQUEST should raise a ConchError if tryAuth returns - None. Added to catch a bug noticed by pyflakes. This is a whitebox - test. - """ - def mockTryAuth(kind, user, data): - return None - - def mockEbBadAuth(reason): - reason.trap(ConchError) - - self.patch(self.authServer, 'tryAuth', mockTryAuth) - self.patch(self.authServer, '_ebBadAuth', mockEbBadAuth) - - packet = NS('user') + NS('none') + NS('public-key') + NS('data') - # If an error other than ConchError is raised, this will trigger an - # exception. - return self.authServer.ssh_USERAUTH_REQUEST(packet) diff --git a/tools/buildbot/pylibs/twisted/conch/test/test_window.py b/tools/buildbot/pylibs/twisted/conch/test/test_window.py deleted file mode 100644 index 29b5898..0000000 --- a/tools/buildbot/pylibs/twisted/conch/test/test_window.py +++ /dev/null @@ -1,49 +0,0 @@ - -""" -Tests for the insults windowing module, L{twisted.conch.insults.window}. -""" - -from twisted.trial.unittest import TestCase - -from twisted.conch.insults.window import TopWindow - - -class TopWindowTests(TestCase): - """ - Tests for L{TopWindow}, the root window container class. - """ - - def test_paintScheduling(self): - """ - Verify that L{TopWindow.repaint} schedules an actual paint to occur - using the scheduling object passed to its initializer. - """ - paints = [] - scheduled = [] - root = TopWindow(lambda: paints.append(None), scheduled.append) - - # Nothing should have happened yet. - self.assertEqual(paints, []) - self.assertEqual(scheduled, []) - - # Cause a paint to be scheduled. - root.repaint() - self.assertEqual(paints, []) - self.assertEqual(len(scheduled), 1) - - # Do another one to verify nothing else happens as long as the previous - # one is still pending. - root.repaint() - self.assertEqual(paints, []) - self.assertEqual(len(scheduled), 1) - - # Run the actual paint call. - scheduled.pop()() - self.assertEqual(len(paints), 1) - self.assertEqual(scheduled, []) - - # Do one more to verify that now that the previous one is finished - # future paints will succeed. - root.repaint() - self.assertEqual(len(paints), 1) - self.assertEqual(len(scheduled), 1) diff --git a/tools/buildbot/pylibs/twisted/conch/topfiles/NEWS b/tools/buildbot/pylibs/twisted/conch/topfiles/NEWS deleted file mode 100644 index d184748..0000000 --- a/tools/buildbot/pylibs/twisted/conch/topfiles/NEWS +++ /dev/null @@ -1,127 +0,0 @@ -8.1.0 (2008-05-18) -================== - -Fixes ------ - - A regression was fixed whereby the publicKeys and privateKeys attributes of - SSHFactory would not be interpreted as strings (#3141) - - The sshsimpleserver.py example had a minor bug fix (#3135) - - The deprecated mktap API is no longer used (#3127) - - An infelicity was fixed whereby a NameError would be raised in certain - circumstances during authentication when a ConchError should have been - (#3154) - - A workaround was added to conch.insults for a bug in gnome-terminal whereby - it would not scroll correctly (#3189) - - -8.0.0 (2008-03-17) -================== - -Features --------- - - Add DEC private mode manipulation methods to ITerminalTransport. (#2403) - -Fixes ------ - - Parameterize the scheduler function used by the insults TopWindow widget. - This change breaks backwards compatibility in the TopWindow initializer. - (#2413) - - Notify subsystems, like SFTP, of connection close. (#2421) - - Change the process file descriptor "connection lost" code to reverse the - setNonBlocking operation done during initialization. (#2371) - - Change ConsoleManhole to wait for connectionLost notification before - stopping the reactor. (#2123, #2371) - - Make SSHUserAuthServer.ssh_USERAUTH_REQUEST return a Deferred. (#2528) - - Manhole's initializer calls its parent class's initializer with its - namespace argument. (#2587) - - Handle ^C during input line continuation in manhole by updating the prompt - and line buffer correctly. (#2663) - - Make twisted.conch.telnet.Telnet by default reject all attempts to enable - options. (#1967) - - Reduce the number of calls into application code to deliver application-level - data in twisted.conch.telnet.Telnet.dataReceived (#2107) - - Fix definition and management of extended attributes in conch file transfer. - (#3010) - - Fix parsing of OpenSSH-generated RSA keys with differing ASN.1 packing style. - (#3008) - - Fix handling of missing $HOME in twisted.conch.client.unix. (#3061) - -Misc ----- - - #2267, #2378, #2604, #2707, #2341, #2685, #2679, #2912, #2977, #2678, #2709 - #2063, #2847 - - -0.8.0 (2007-01-06) -================== - -Features --------- - - Manhole now supports Ctrl-l to emulate the same behavior in the - Python interactive interpreter (#1565) - - Python 2.5 is now supported (#1867) - -Misc ----- - - #1673, #1636, #1892, #1943, #2057, #1180, #1185, #2148, #2159, #2291, - -Deprecations and Removals -------------------------- - - - The old twisted.cred API (Identities, Authorizers, etc) is no - longer supported (#1440) - - -0.7.0 (2006-05-21) -================== - -Features --------- - - Timeout support for ExpectableBuffer.expect() - -Fixes ------ - - ~5x speedup for bulk data transfer (#1325) - - Misc: #1428 - -0.6.0: - - Bugfixes and improvements in SSH support and Insults: - - PAM authenticator support factored out into twisted.cred - - Poorly supported next-line terminal operation replaced with simple \r\n - - New functionality: - - An ITerminalTransport implementation with expect-like features - - Support for the "none" SSH cipher - - Insults support for handling more keystrokes and more methods for - terminal manipulation - - New, simple insults-based widget library added - - Better test coverage: - - Dependence on `localhost' name removed - - Some timing-sensitive tests changed to be more reliable - - Process spawning tests initialize environment more robustly - -0.5.0: - - Many improvements to SSH support. Here's some in particular: - - Add --reconnect option to conch binary - - utmp/wtmp logging - - Unix login improvements, PAM support - - Add "cftp" -- Conch SFTP. - - Deferred retrieval of public keys is supported - - PAM support for client and server - - Bugfixes: - - fix conch failing to exit, and hangs. - - Remote->Local forwarding - - Channel closing - - Invalid known_host writing - - Many others - - New functionality: - - twisted.conch.telnet: new, much improved telnet implementation. - - twisted.conch.insults: Basic curses-like terminal support (server-side). - - twisted.conch.manhole: new interactive python interactive interpreter, - can be used with conch's telnet, ssh, or on the console. - - Main features: Syntax coloring, line editing, and useful interactive - handling of Deferreds. diff --git a/tools/buildbot/pylibs/twisted/conch/topfiles/README b/tools/buildbot/pylibs/twisted/conch/topfiles/README deleted file mode 100644 index ee95c8c..0000000 --- a/tools/buildbot/pylibs/twisted/conch/topfiles/README +++ /dev/null @@ -1,3 +0,0 @@ -Twisted Conch 8.1.0 - -Conch depends on Python Crypto extensions. diff --git a/tools/buildbot/pylibs/twisted/conch/topfiles/setup.py b/tools/buildbot/pylibs/twisted/conch/topfiles/setup.py deleted file mode 100644 index 8e30ac5..0000000 --- a/tools/buildbot/pylibs/twisted/conch/topfiles/setup.py +++ /dev/null @@ -1,46 +0,0 @@ -import sys - -try: - from twisted.python import dist -except ImportError: - raise SystemExit("twisted.python.dist module not found. Make sure you " - "have installed the Twisted core package before " - "attempting to install any other Twisted projects.") - -if __name__ == '__main__': - if sys.version_info[:2] >= (2, 4): - extraMeta = dict( - classifiers=[ - "Development Status :: 4 - Beta", - "Environment :: Console", - "Environment :: No Input/Output (Daemon)", - "Intended Audience :: Developers", - "Intended Audience :: End Users/Desktop", - "Intended Audience :: System Administrators", - "License :: OSI Approved :: MIT License", - "Programming Language :: Python", - "Topic :: Internet", - "Topic :: Security", - "Topic :: Software Development :: Libraries :: Python Modules", - "Topic :: Terminals", - ]) - else: - extraMeta = {} - - dist.setup( - twisted_subproject="conch", - scripts=dist.getScripts("conch"), - # metadata - name="Conch", - description="Twisted SSHv2 implementation.", - author="Twisted Matrix Laboratories", - author_email="twisted-python@twistedmatrix.com", - maintainer="Paul Swartz", - maintainer_email="z3p@twistedmatrix.com", - url="http://twistedmatrix.com/trac/wiki/TwistedConch", - license="MIT", - long_description="""\ -Conch is an SSHv2 implementation using the Twisted framework. It -includes a server, client, a SFTP client, and a key generator. -""", - **extraMeta) diff --git a/tools/buildbot/pylibs/twisted/conch/ttymodes.py b/tools/buildbot/pylibs/twisted/conch/ttymodes.py deleted file mode 100644 index 020c104..0000000 --- a/tools/buildbot/pylibs/twisted/conch/ttymodes.py +++ /dev/null @@ -1,121 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -import tty -# this module was autogenerated. - -VINTR = 1 -VQUIT = 2 -VERASE = 3 -VKILL = 4 -VEOF = 5 -VEOL = 6 -VEOL2 = 7 -VSTART = 8 -VSTOP = 9 -VSUSP = 10 -VDSUSP = 11 -VREPRINT = 12 -VWERASE = 13 -VLNEXT = 14 -VFLUSH = 15 -VSWTCH = 16 -VSTATUS = 17 -VDISCARD = 18 -IGNPAR = 30 -PARMRK = 31 -INPCK = 32 -ISTRIP = 33 -INLCR = 34 -IGNCR = 35 -ICRNL = 36 -IUCLC = 37 -IXON = 38 -IXANY = 39 -IXOFF = 40 -IMAXBEL = 41 -ISIG = 50 -ICANON = 51 -XCASE = 52 -ECHO = 53 -ECHOE = 54 -ECHOK = 55 -ECHONL = 56 -NOFLSH = 57 -TOSTOP = 58 -IEXTEN = 59 -ECHOCTL = 60 -ECHOKE = 61 -PENDIN = 62 -OPOST = 70 -OLCUC = 71 -ONLCR = 72 -OCRNL = 73 -ONOCR = 74 -ONLRET = 75 -CS7 = 90 -CS8 = 91 -PARENB = 92 -PARODD = 93 -TTY_OP_ISPEED = 128 -TTY_OP_OSPEED = 129 - -TTYMODES = { - 1 : 'VINTR', - 2 : 'VQUIT', - 3 : 'VERASE', - 4 : 'VKILL', - 5 : 'VEOF', - 6 : 'VEOL', - 7 : 'VEOL2', - 8 : 'VSTART', - 9 : 'VSTOP', - 10 : 'VSUSP', - 11 : 'VDSUSP', - 12 : 'VREPRINT', - 13 : 'VWERASE', - 14 : 'VLNEXT', - 15 : 'VFLUSH', - 16 : 'VSWTCH', - 17 : 'VSTATUS', - 18 : 'VDISCARD', - 30 : (tty.IFLAG, 'IGNPAR'), - 31 : (tty.IFLAG, 'PARMRK'), - 32 : (tty.IFLAG, 'INPCK'), - 33 : (tty.IFLAG, 'ISTRIP'), - 34 : (tty.IFLAG, 'INLCR'), - 35 : (tty.IFLAG, 'IGNCR'), - 36 : (tty.IFLAG, 'ICRNL'), - 37 : (tty.IFLAG, 'IUCLC'), - 38 : (tty.IFLAG, 'IXON'), - 39 : (tty.IFLAG, 'IXANY'), - 40 : (tty.IFLAG, 'IXOFF'), - 41 : (tty.IFLAG, 'IMAXBEL'), - 50 : (tty.LFLAG, 'ISIG'), - 51 : (tty.LFLAG, 'ICANON'), - 52 : (tty.LFLAG, 'XCASE'), - 53 : (tty.LFLAG, 'ECHO'), - 54 : (tty.LFLAG, 'ECHOE'), - 55 : (tty.LFLAG, 'ECHOK'), - 56 : (tty.LFLAG, 'ECHONL'), - 57 : (tty.LFLAG, 'NOFLSH'), - 58 : (tty.LFLAG, 'TOSTOP'), - 59 : (tty.LFLAG, 'IEXTEN'), - 60 : (tty.LFLAG, 'ECHOCTL'), - 61 : (tty.LFLAG, 'ECHOKE'), - 62 : (tty.LFLAG, 'PENDIN'), - 70 : (tty.OFLAG, 'OPOST'), - 71 : (tty.OFLAG, 'OLCUC'), - 72 : (tty.OFLAG, 'ONLCR'), - 73 : (tty.OFLAG, 'OCRNL'), - 74 : (tty.OFLAG, 'ONOCR'), - 75 : (tty.OFLAG, 'ONLRET'), -# 90 : (tty.CFLAG, 'CS7'), -# 91 : (tty.CFLAG, 'CS8'), - 92 : (tty.CFLAG, 'PARENB'), - 93 : (tty.CFLAG, 'PARODD'), - 128 : 'ISPEED', - 129 : 'OSPEED' -} diff --git a/tools/buildbot/pylibs/twisted/conch/ui/__init__.py b/tools/buildbot/pylibs/twisted/conch/ui/__init__.py deleted file mode 100644 index f7d7a17..0000000 --- a/tools/buildbot/pylibs/twisted/conch/ui/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - - -""" -twisted.conch.ui is home to the UI elements for tkconch. - -Maintainer: U{Paul Swartz} -""" diff --git a/tools/buildbot/pylibs/twisted/conch/ui/ansi.py b/tools/buildbot/pylibs/twisted/conch/ui/ansi.py deleted file mode 100644 index d718641..0000000 --- a/tools/buildbot/pylibs/twisted/conch/ui/ansi.py +++ /dev/null @@ -1,240 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -"""Module to parse ANSI escape sequences - -Maintainer: U{Jean-Paul Calderone } -""" - -import string - -# Twisted imports -from twisted.python import log - -class ColorText: - """ - Represents an element of text along with the texts colors and - additional attributes. - """ - - # The colors to use - COLORS = ('b', 'r', 'g', 'y', 'l', 'm', 'c', 'w') - BOLD_COLORS = tuple([x.upper() for x in COLORS]) - BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(len(COLORS)) - - # Color names - COLOR_NAMES = ( - 'Black', 'Red', 'Green', 'Yellow', 'Blue', 'Magenta', 'Cyan', 'White' - ) - - def __init__(self, text, fg, bg, display, bold, underline, flash, reverse): - self.text, self.fg, self.bg = text, fg, bg - self.display = display - self.bold = bold - self.underline = underline - self.flash = flash - self.reverse = reverse - if self.reverse: - self.fg, self.bg = self.bg, self.fg - - -class AnsiParser: - """ - Parser class for ANSI codes. - """ - - # Terminators for cursor movement ansi controls - unsupported - CURSOR_SET = ('H', 'f', 'A', 'B', 'C', 'D', 'R', 's', 'u', 'd','G') - - # Terminators for erasure ansi controls - unsupported - ERASE_SET = ('J', 'K', 'P') - - # Terminators for mode change ansi controls - unsupported - MODE_SET = ('h', 'l') - - # Terminators for keyboard assignment ansi controls - unsupported - ASSIGN_SET = ('p',) - - # Terminators for color change ansi controls - supported - COLOR_SET = ('m',) - - SETS = (CURSOR_SET, ERASE_SET, MODE_SET, ASSIGN_SET, COLOR_SET) - - def __init__(self, defaultFG, defaultBG): - self.defaultFG, self.defaultBG = defaultFG, defaultBG - self.currentFG, self.currentBG = self.defaultFG, self.defaultBG - self.bold, self.flash, self.underline, self.reverse = 0, 0, 0, 0 - self.display = 1 - self.prepend = '' - - - def stripEscapes(self, string): - """ - Remove all ANSI color escapes from the given string. - """ - result = '' - show = 1 - i = 0 - L = len(string) - while i < L: - if show == 0 and string[i] in _sets: - show = 1 - elif show: - n = string.find('\x1B', i) - if n == -1: - return result + string[i:] - else: - result = result + string[i:n] - i = n - show = 0 - i = i + 1 - return result - - def writeString(self, colorstr): - pass - - def parseString(self, str): - """ - Turn a string input into a list of L{ColorText} elements. - """ - - if self.prepend: - str = self.prepend + str - self.prepend = '' - parts = str.split('\x1B') - - if len(parts) == 1: - self.writeString(self.formatText(parts[0])) - else: - self.writeString(self.formatText(parts[0])) - for s in parts[1:]: - L = len(s) - i = 0 - type = None - while i < L: - if s[i] not in string.digits+'[;?': - break - i+=1 - if not s: - self.prepend = '\x1b' - return - if s[0]!='[': - self.writeString(self.formatText(s[i+1:])) - continue - else: - s=s[1:] - i-=1 - if i==L-1: - self.prepend = '\x1b[' - return - type = _setmap.get(s[i], None) - if type is None: - continue - - if type == AnsiParser.COLOR_SET: - self.parseColor(s[:i + 1]) - s = s[i + 1:] - self.writeString(self.formatText(s)) - elif type == AnsiParser.CURSOR_SET: - cursor, s = s[:i+1], s[i+1:] - self.parseCursor(cursor) - self.writeString(self.formatText(s)) - elif type == AnsiParser.ERASE_SET: - erase, s = s[:i+1], s[i+1:] - self.parseErase(erase) - self.writeString(self.formatText(s)) - elif type == AnsiParser.MODE_SET: - mode, s = s[:i+1], s[i+1:] - #self.parseErase('2J') - self.writeString(self.formatText(s)) - elif i == L: - self.prepend = '\x1B[' + s - else: - log.msg('Unhandled ANSI control type: %c' % (s[i],)) - s = s[i + 1:] - self.writeString(self.formatText(s)) - - def parseColor(self, str): - """ - Handle a single ANSI color sequence - """ - # Drop the trailing 'm' - str = str[:-1] - - if not str: - str = '0' - - try: - parts = map(int, str.split(';')) - except ValueError: - log.msg('Invalid ANSI color sequence (%d): %s' % (len(str), str)) - self.currentFG, self.currentBG = self.defaultFG, self.defaultBG - return - - for x in parts: - if x == 0: - self.currentFG, self.currentBG = self.defaultFG, self.defaultBG - self.bold, self.flash, self.underline, self.reverse = 0, 0, 0, 0 - self.display = 1 - elif x == 1: - self.bold = 1 - elif 30 <= x <= 37: - self.currentFG = x - 30 - elif 40 <= x <= 47: - self.currentBG = x - 40 - elif x == 39: - self.currentFG = self.defaultFG - elif x == 49: - self.currentBG = self.defaultBG - elif x == 4: - self.underline = 1 - elif x == 5: - self.flash = 1 - elif x == 7: - self.reverse = 1 - elif x == 8: - self.display = 0 - elif x == 22: - self.bold = 0 - elif x == 24: - self.underline = 0 - elif x == 25: - self.blink = 0 - elif x == 27: - self.reverse = 0 - elif x == 28: - self.display = 1 - else: - log.msg('Unrecognised ANSI color command: %d' % (x,)) - - def parseCursor(self, cursor): - pass - - def parseErase(self, erase): - pass - - - def pickColor(self, value, mode, BOLD = ColorText.BOLD_COLORS): - if mode: - return ColorText.COLORS[value] - else: - return self.bold and BOLD[value] or ColorText.COLORS[value] - - - def formatText(self, text): - return ColorText( - text, - self.pickColor(self.currentFG, 0), - self.pickColor(self.currentBG, 1), - self.display, self.bold, self.underline, self.flash, self.reverse - ) - - -_sets = ''.join(map(''.join, AnsiParser.SETS)) - -_setmap = {} -for s in AnsiParser.SETS: - for r in s: - _setmap[r] = s -del s diff --git a/tools/buildbot/pylibs/twisted/conch/ui/tkvt100.py b/tools/buildbot/pylibs/twisted/conch/ui/tkvt100.py deleted file mode 100644 index 88e4120..0000000 --- a/tools/buildbot/pylibs/twisted/conch/ui/tkvt100.py +++ /dev/null @@ -1,197 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -"""Module to emulate a VT100 terminal in Tkinter. - -Maintainer: U{Paul Swartz } -""" - -import Tkinter, tkFont -import ansi -import string - -ttyFont = None#tkFont.Font(family = 'Courier', size = 10) -fontWidth, fontHeight = None,None#max(map(ttyFont.measure, string.letters+string.digits)), int(ttyFont.metrics()['linespace']) - -colorKeys = ( - 'b', 'r', 'g', 'y', 'l', 'm', 'c', 'w', - 'B', 'R', 'G', 'Y', 'L', 'M', 'C', 'W' -) - -colorMap = { - 'b': '#000000', 'r': '#c40000', 'g': '#00c400', 'y': '#c4c400', - 'l': '#000080', 'm': '#c400c4', 'c': '#00c4c4', 'w': '#c4c4c4', - 'B': '#626262', 'R': '#ff0000', 'G': '#00ff00', 'Y': '#ffff00', - 'L': '#0000ff', 'M': '#ff00ff', 'C': '#00ffff', 'W': '#ffffff', -} - -class VT100Frame(Tkinter.Frame): - def __init__(self, *args, **kw): - global ttyFont, fontHeight, fontWidth - ttyFont = tkFont.Font(family = 'Courier', size = 10) - fontWidth, fontHeight = max(map(ttyFont.measure, string.letters+string.digits)), int(ttyFont.metrics()['linespace']) - self.width = kw.get('width', 80) - self.height = kw.get('height', 25) - self.callback = kw['callback'] - del kw['callback'] - kw['width'] = w = fontWidth * self.width - kw['height'] = h = fontHeight * self.height - Tkinter.Frame.__init__(self, *args, **kw) - self.canvas = Tkinter.Canvas(bg='#000000', width=w, height=h) - self.canvas.pack(side=Tkinter.TOP, fill=Tkinter.BOTH, expand=1) - self.canvas.bind('', self.keyPressed) - self.canvas.bind('<1>', lambda x: 'break') - self.canvas.bind('', self.upPressed) - self.canvas.bind('', self.downPressed) - self.canvas.bind('', self.leftPressed) - self.canvas.bind('', self.rightPressed) - self.canvas.focus() - - self.ansiParser = ansi.AnsiParser(ansi.ColorText.WHITE, ansi.ColorText.BLACK) - self.ansiParser.writeString = self.writeString - self.ansiParser.parseCursor = self.parseCursor - self.ansiParser.parseErase = self.parseErase - #for (a, b) in colorMap.items(): - # self.canvas.tag_config(a, foreground=b) - # self.canvas.tag_config('b'+a, background=b) - #self.canvas.tag_config('underline', underline=1) - - self.x = 0 - self.y = 0 - self.cursor = self.canvas.create_rectangle(0,0,fontWidth-1,fontHeight-1,fill='green',outline='green') - - def _delete(self, sx, sy, ex, ey): - csx = sx*fontWidth + 1 - csy = sy*fontHeight + 1 - cex = ex*fontWidth + 3 - cey = ey*fontHeight + 3 - items = self.canvas.find_overlapping(csx,csy, cex,cey) - for item in items: - self.canvas.delete(item) - - def _write(self, ch, fg, bg): - if self.x == self.width: - self.x = 0 - self.y+=1 - if self.y == self.height: - [self.canvas.move(x,0,-fontHeight) for x in self.canvas.find_all()] - self.y-=1 - canvasX = self.x*fontWidth + 1 - canvasY = self.y*fontHeight + 1 - items = self.canvas.find_overlapping(canvasX, canvasY, canvasX+2, canvasY+2) - if items: - [self.canvas.delete(item) for item in items] - if bg: - self.canvas.create_rectangle(canvasX, canvasY, canvasX+fontWidth-1, canvasY+fontHeight-1, fill=bg, outline=bg) - self.canvas.create_text(canvasX, canvasY, anchor=Tkinter.NW, font=ttyFont, text=ch, fill=fg) - self.x+=1 - - def write(self, data): - #print self.x,self.y,repr(data) - #if len(data)>5: raw_input() - self.ansiParser.parseString(data) - self.canvas.delete(self.cursor) - canvasX = self.x*fontWidth + 1 - canvasY = self.y*fontHeight + 1 - self.cursor = self.canvas.create_rectangle(canvasX,canvasY,canvasX+fontWidth-1,canvasY+fontHeight-1, fill='green', outline='green') - self.canvas.lower(self.cursor) - - def writeString(self, i): - if not i.display: - return - fg = colorMap[i.fg] - bg = i.bg != 'b' and colorMap[i.bg] - for ch in i.text: - b = ord(ch) - if b == 7: # bell - self.bell() - elif b == 8: # BS - if self.x: - self.x-=1 - elif b == 9: # TAB - [self._write(' ',fg,bg) for i in range(8)] - elif b == 10: - if self.y == self.height-1: - self._delete(0,0,self.width,0) - [self.canvas.move(x,0,-fontHeight) for x in self.canvas.find_all()] - else: - self.y+=1 - elif b == 13: - self.x = 0 - elif 32 <= b < 127: - self._write(ch, fg, bg) - - def parseErase(self, erase): - if ';' in erase: - end = erase[-1] - parts = erase[:-1].split(';') - [self.parseErase(x+end) for x in parts] - return - start = 0 - x,y = self.x, self.y - if len(erase) > 1: - start = int(erase[:-1]) - if erase[-1] == 'J': - if start == 0: - self._delete(x,y,self.width,self.height) - else: - self._delete(0,0,self.width,self.height) - self.x = 0 - self.y = 0 - elif erase[-1] == 'K': - if start == 0: - self._delete(x,y,self.width,y) - elif start == 1: - self._delete(0,y,x,y) - self.x = 0 - else: - self._delete(0,y,self.width,y) - self.x = 0 - elif erase[-1] == 'P': - self._delete(x,y,x+start,y) - - def parseCursor(self, cursor): - #if ';' in cursor and cursor[-1]!='H': - # end = cursor[-1] - # parts = cursor[:-1].split(';') - # [self.parseCursor(x+end) for x in parts] - # return - start = 1 - if len(cursor) > 1 and cursor[-1]!='H': - start = int(cursor[:-1]) - if cursor[-1] == 'C': - self.x+=start - elif cursor[-1] == 'D': - self.x-=start - elif cursor[-1]=='d': - self.y=start-1 - elif cursor[-1]=='G': - self.x=start-1 - elif cursor[-1]=='H': - if len(cursor)>1: - y,x = map(int, cursor[:-1].split(';')) - y-=1 - x-=1 - else: - x,y=0,0 - self.x = x - self.y = y - - def keyPressed(self, event): - if self.callback and event.char: - self.callback(event.char) - return 'break' - - def upPressed(self, event): - self.callback('\x1bOA') - - def downPressed(self, event): - self.callback('\x1bOB') - - def rightPressed(self, event): - self.callback('\x1bOC') - - def leftPressed(self, event): - self.callback('\x1bOD') diff --git a/tools/buildbot/pylibs/twisted/conch/unix.py b/tools/buildbot/pylibs/twisted/conch/unix.py deleted file mode 100644 index c1e0675..0000000 --- a/tools/buildbot/pylibs/twisted/conch/unix.py +++ /dev/null @@ -1,457 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.cred import portal -from twisted.python import components, log -from twisted.internet.error import ProcessExitedAlready -from zope import interface -from ssh import session, forwarding, filetransfer -from ssh.filetransfer import FXF_READ, FXF_WRITE, FXF_APPEND, FXF_CREAT, FXF_TRUNC, FXF_EXCL -from twisted.conch.ls import lsLine - -from avatar import ConchUser -from error import ConchError -from interfaces import ISession, ISFTPServer, ISFTPFile - -import struct, os, time, socket -import fcntl, tty -import pwd, grp -import pty -import ttymodes - -try: - import utmp -except ImportError: - utmp = None - -class UnixSSHRealm: - interface.implements(portal.IRealm) - - def requestAvatar(self, username, mind, *interfaces): - user = UnixConchUser(username) - return interfaces[0], user, user.logout - - -class UnixConchUser(ConchUser): - - def __init__(self, username): - ConchUser.__init__(self) - self.username = username - self.pwdData = pwd.getpwnam(self.username) - l = [self.pwdData[3]] - for groupname, password, gid, userlist in grp.getgrall(): - if username in userlist: - l.append(gid) - self.otherGroups = l - self.listeners = {} # dict mapping (interface, port) -> listener - self.channelLookup.update( - {"session": session.SSHSession, - "direct-tcpip": forwarding.openConnectForwardingClient}) - - self.subsystemLookup.update( - {"sftp": filetransfer.FileTransferServer}) - - def getUserGroupId(self): - return self.pwdData[2:4] - - def getOtherGroups(self): - return self.otherGroups - - def getHomeDir(self): - return self.pwdData[5] - - def getShell(self): - return self.pwdData[6] - - def global_tcpip_forward(self, data): - hostToBind, portToBind = forwarding.unpackGlobal_tcpip_forward(data) - from twisted.internet import reactor - try: listener = self._runAsUser( - reactor.listenTCP, portToBind, - forwarding.SSHListenForwardingFactory(self.conn, - (hostToBind, portToBind), - forwarding.SSHListenServerForwardingChannel), - interface = hostToBind) - except: - return 0 - else: - self.listeners[(hostToBind, portToBind)] = listener - if portToBind == 0: - portToBind = listener.getHost()[2] # the port - return 1, struct.pack('>L', portToBind) - else: - return 1 - - def global_cancel_tcpip_forward(self, data): - hostToBind, portToBind = forwarding.unpackGlobal_tcpip_forward(data) - listener = self.listeners.get((hostToBind, portToBind), None) - if not listener: - return 0 - del self.listeners[(hostToBind, portToBind)] - self._runAsUser(listener.stopListening) - return 1 - - def logout(self): - # remove all listeners - for listener in self.listeners.itervalues(): - self._runAsUser(listener.stopListening) - log.msg('avatar %s logging out (%i)' % (self.username, len(self.listeners))) - - def _runAsUser(self, f, *args, **kw): - euid = os.geteuid() - egid = os.getegid() - groups = os.getgroups() - uid, gid = self.getUserGroupId() - os.setegid(0) - os.seteuid(0) - os.setgroups(self.getOtherGroups()) - os.setegid(gid) - os.seteuid(uid) - try: - f = iter(f) - except TypeError: - f = [(f, args, kw)] - try: - for i in f: - func = i[0] - args = len(i)>1 and i[1] or () - kw = len(i)>2 and i[2] or {} - r = func(*args, **kw) - finally: - os.setegid(0) - os.seteuid(0) - os.setgroups(groups) - os.setegid(egid) - os.seteuid(euid) - return r - -class SSHSessionForUnixConchUser: - - interface.implements(ISession) - - def __init__(self, avatar): - self.avatar = avatar - self. environ = {'PATH':'/bin:/usr/bin:/usr/local/bin'} - self.pty = None - self.ptyTuple = 0 - - def addUTMPEntry(self, loggedIn=1): - if not utmp: - return - ipAddress = self.avatar.conn.transport.transport.getPeer().host - packedIp ,= struct.unpack('L', socket.inet_aton(ipAddress)) - ttyName = self.ptyTuple[2][5:] - t = time.time() - t1 = int(t) - t2 = int((t-t1) * 1e6) - entry = utmp.UtmpEntry() - entry.ut_type = loggedIn and utmp.USER_PROCESS or utmp.DEAD_PROCESS - entry.ut_pid = self.pty.pid - entry.ut_line = ttyName - entry.ut_id = ttyName[-4:] - entry.ut_tv = (t1,t2) - if loggedIn: - entry.ut_user = self.avatar.username - entry.ut_host = socket.gethostbyaddr(ipAddress)[0] - entry.ut_addr_v6 = (packedIp, 0, 0, 0) - a = utmp.UtmpRecord(utmp.UTMP_FILE) - a.pututline(entry) - a.endutent() - b = utmp.UtmpRecord(utmp.WTMP_FILE) - b.pututline(entry) - b.endutent() - - - def getPty(self, term, windowSize, modes): - self.environ['TERM'] = term - self.winSize = windowSize - self.modes = modes - master, slave = pty.openpty() - ttyname = os.ttyname(slave) - self.environ['SSH_TTY'] = ttyname - self.ptyTuple = (master, slave, ttyname) - - def openShell(self, proto): - from twisted.internet import reactor - if not self.ptyTuple: # we didn't get a pty-req - log.msg('tried to get shell without pty, failing') - raise ConchError("no pty") - uid, gid = self.avatar.getUserGroupId() - homeDir = self.avatar.getHomeDir() - shell = self.avatar.getShell() - self.environ['USER'] = self.avatar.username - self.environ['HOME'] = homeDir - self.environ['SHELL'] = shell - shellExec = os.path.basename(shell) - peer = self.avatar.conn.transport.transport.getPeer() - host = self.avatar.conn.transport.transport.getHost() - self.environ['SSH_CLIENT'] = '%s %s %s' % (peer.host, peer.port, host.port) - self.getPtyOwnership() - self.pty = reactor.spawnProcess(proto, \ - shell, ['-%s' % shellExec], self.environ, homeDir, uid, gid, - usePTY = self.ptyTuple) - self.addUTMPEntry() - fcntl.ioctl(self.pty.fileno(), tty.TIOCSWINSZ, - struct.pack('4H', *self.winSize)) - if self.modes: - self.setModes() - self.oldWrite = proto.transport.write - proto.transport.write = self._writeHack - self.avatar.conn.transport.transport.setTcpNoDelay(1) - - def execCommand(self, proto, cmd): - from twisted.internet import reactor - uid, gid = self.avatar.getUserGroupId() - homeDir = self.avatar.getHomeDir() - shell = self.avatar.getShell() or '/bin/sh' - command = (shell, '-c', cmd) - peer = self.avatar.conn.transport.transport.getPeer() - host = self.avatar.conn.transport.transport.getHost() - self.environ['SSH_CLIENT'] = '%s %s %s' % (peer.host, peer.port, host.port) - if self.ptyTuple: - self.getPtyOwnership() - self.pty = reactor.spawnProcess(proto, \ - shell, command, self.environ, homeDir, - uid, gid, usePTY = self.ptyTuple or 0) - if self.ptyTuple: - self.addUTMPEntry() - if self.modes: - self.setModes() -# else: -# tty.setraw(self.pty.pipes[0].fileno(), tty.TCSANOW) - self.avatar.conn.transport.transport.setTcpNoDelay(1) - - def getPtyOwnership(self): - ttyGid = os.stat(self.ptyTuple[2])[5] - uid, gid = self.avatar.getUserGroupId() - euid, egid = os.geteuid(), os.getegid() - os.setegid(0) - os.seteuid(0) - try: - os.chown(self.ptyTuple[2], uid, ttyGid) - finally: - os.setegid(egid) - os.seteuid(euid) - - def setModes(self): - pty = self.pty - attr = tty.tcgetattr(pty.fileno()) - for mode, modeValue in self.modes: - if not ttymodes.TTYMODES.has_key(mode): continue - ttyMode = ttymodes.TTYMODES[mode] - if len(ttyMode) == 2: # flag - flag, ttyAttr = ttyMode - if not hasattr(tty, ttyAttr): continue - ttyval = getattr(tty, ttyAttr) - if modeValue: - attr[flag] = attr[flag]|ttyval - else: - attr[flag] = attr[flag]&~ttyval - elif ttyMode == 'OSPEED': - attr[tty.OSPEED] = getattr(tty, 'B%s'%modeValue) - elif ttyMode == 'ISPEED': - attr[tty.ISPEED] = getattr(tty, 'B%s'%modeValue) - else: - if not hasattr(tty, ttyMode): continue - ttyval = getattr(tty, ttyMode) - attr[tty.CC][ttyval] = chr(modeValue) - tty.tcsetattr(pty.fileno(), tty.TCSANOW, attr) - - def eofReceived(self): - if self.pty: - self.pty.closeStdin() - - def closed(self): - if self.ptyTuple and os.path.exists(self.ptyTuple[2]): - ttyGID = os.stat(self.ptyTuple[2])[5] - os.chown(self.ptyTuple[2], 0, ttyGID) - if self.pty: - try: - self.pty.signalProcess('HUP') - except (OSError,ProcessExitedAlready): - pass - self.pty.loseConnection() - self.addUTMPEntry(0) - log.msg('shell closed') - - def windowChanged(self, winSize): - self.winSize = winSize - fcntl.ioctl(self.pty.fileno(), tty.TIOCSWINSZ, - struct.pack('4H', *self.winSize)) - - def _writeHack(self, data): - """ - Hack to send ignore messages when we aren't echoing. - """ - if self.pty is not None: - attr = tty.tcgetattr(self.pty.fileno())[3] - if not attr & tty.ECHO and attr & tty.ICANON: # no echo - self.avatar.conn.transport.sendIgnore('\x00'*(8+len(data))) - self.oldWrite(data) - - -class SFTPServerForUnixConchUser: - - interface.implements(ISFTPServer) - - def __init__(self, avatar): - self.avatar = avatar - - - def _setAttrs(self, path, attrs): - """ - NOTE: this function assumes it runs as the logged-in user: - i.e. under _runAsUser() - """ - if attrs.has_key("uid") and attrs.has_key("gid"): - os.chown(path, attrs["uid"], attrs["gid"]) - if attrs.has_key("permissions"): - os.chmod(path, attrs["permissions"]) - if attrs.has_key("atime") and attrs.has_key("mtime"): - os.utime(path, (attrs["atime"], attrs["mtime"])) - - def _getAttrs(self, s): - return { - "size" : s.st_size, - "uid" : s.st_uid, - "gid" : s.st_gid, - "permissions" : s.st_mode, - "atime" : int(s.st_atime), - "mtime" : int(s.st_mtime) - } - - def _absPath(self, path): - home = self.avatar.getHomeDir() - return os.path.abspath(os.path.join(home, path)) - - def gotVersion(self, otherVersion, extData): - return {} - - def openFile(self, filename, flags, attrs): - return UnixSFTPFile(self, self._absPath(filename), flags, attrs) - - def removeFile(self, filename): - filename = self._absPath(filename) - return self.avatar._runAsUser(os.remove, filename) - - def renameFile(self, oldpath, newpath): - oldpath = self._absPath(oldpath) - newpath = self._absPath(newpath) - return self.avatar._runAsUser(os.rename, oldpath, newpath) - - def makeDirectory(self, path, attrs): - path = self._absPath(path) - return self.avatar._runAsUser([(os.mkdir, (path,)), - (self._setAttrs, (path, attrs))]) - - def removeDirectory(self, path): - path = self._absPath(path) - self.avatar._runAsUser(os.rmdir, path) - - def openDirectory(self, path): - return UnixSFTPDirectory(self, self._absPath(path)) - - def getAttrs(self, path, followLinks): - path = self._absPath(path) - if followLinks: - s = self.avatar._runAsUser(os.stat, path) - else: - s = self.avatar._runAsUser(os.lstat, path) - return self._getAttrs(s) - - def setAttrs(self, path, attrs): - path = self._absPath(path) - self.avatar._runAsUser(self._setAttrs, path, attrs) - - def readLink(self, path): - path = self._absPath(path) - return self.avatar._runAsUser(os.readlink, path) - - def makeLink(self, linkPath, targetPath): - linkPath = self._absPath(linkPath) - targetPath = self._absPath(targetPath) - return self.avatar._runAsUser(os.symlink, targetPath, linkPath) - - def realPath(self, path): - return os.path.realpath(self._absPath(path)) - - def extendedRequest(self, extName, extData): - raise NotImplementedError - -class UnixSFTPFile: - - interface.implements(ISFTPFile) - - def __init__(self, server, filename, flags, attrs): - self.server = server - openFlags = 0 - if flags & FXF_READ == FXF_READ and flags & FXF_WRITE == 0: - openFlags = os.O_RDONLY - if flags & FXF_WRITE == FXF_WRITE and flags & FXF_READ == 0: - openFlags = os.O_WRONLY - if flags & FXF_WRITE == FXF_WRITE and flags & FXF_READ == FXF_READ: - openFlags = os.O_RDWR - if flags & FXF_APPEND == FXF_APPEND: - openFlags |= os.O_APPEND - if flags & FXF_CREAT == FXF_CREAT: - openFlags |= os.O_CREAT - if flags & FXF_TRUNC == FXF_TRUNC: - openFlags |= os.O_TRUNC - if flags & FXF_EXCL == FXF_EXCL: - openFlags |= os.O_EXCL - if attrs.has_key("permissions"): - mode = attrs["permissions"] - del attrs["permissions"] - else: - mode = 0777 - fd = server.avatar._runAsUser(os.open, filename, openFlags, mode) - if attrs: - server.avatar._runAsUser(server._setAttrs, filename, attrs) - self.fd = fd - - def close(self): - return self.server.avatar._runAsUser(os.close, self.fd) - - def readChunk(self, offset, length): - return self.server.avatar._runAsUser([ (os.lseek, (self.fd, offset, 0)), - (os.read, (self.fd, length)) ]) - - def writeChunk(self, offset, data): - return self.server.avatar._runAsUser([(os.lseek, (self.fd, offset, 0)), - (os.write, (self.fd, data))]) - - def getAttrs(self): - s = self.server.avatar._runAsUser(os.fstat, self.fd) - return self.server._getAttrs(s) - - def setAttrs(self, attrs): - raise NotImplementedError - - -class UnixSFTPDirectory: - - def __init__(self, server, directory): - self.server = server - self.files = server.avatar._runAsUser(os.listdir, directory) - self.dir = directory - - def __iter__(self): - return self - - def next(self): - try: - f = self.files.pop(0) - except IndexError: - raise StopIteration - else: - s = self.server.avatar._runAsUser(os.lstat, os.path.join(self.dir, f)) - longname = lsLine(f, s) - attrs = self.server._getAttrs(s) - return (f, longname, attrs) - - def close(self): - self.files = [] - - -components.registerAdapter(SFTPServerForUnixConchUser, UnixConchUser, filetransfer.ISFTPServer) -components.registerAdapter(SSHSessionForUnixConchUser, UnixConchUser, session.ISession) diff --git a/tools/buildbot/pylibs/twisted/copyright.py b/tools/buildbot/pylibs/twisted/copyright.py deleted file mode 100644 index df2da3e..0000000 --- a/tools/buildbot/pylibs/twisted/copyright.py +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright (c) 2001-2006 Twisted Matrix Laboratories. -# See LICENSE for details. - - - -""" -Copyright information for Twisted. -""" - -from twisted import __version__ as version, version as longversion - -longversion = str(longversion) - -copyright="""\ -Copyright (c) 2001-2006 Twisted Matrix Laboratories. -See LICENSE for details.""" - -disclaimer=''' -Twisted, the Framework of Your Internet -%s - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -''' % copyright diff --git a/tools/buildbot/pylibs/twisted/cred/__init__.py b/tools/buildbot/pylibs/twisted/cred/__init__.py deleted file mode 100644 index b8048fd..0000000 --- a/tools/buildbot/pylibs/twisted/cred/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Twisted Cred - -Support for verifying credentials, and providing services to users based on -those credentials. - -(This package was previously known as the module twisted.internet.passport.) -""" diff --git a/tools/buildbot/pylibs/twisted/cred/checkers.py b/tools/buildbot/pylibs/twisted/cred/checkers.py deleted file mode 100644 index 55af6f9..0000000 --- a/tools/buildbot/pylibs/twisted/cred/checkers.py +++ /dev/null @@ -1,266 +0,0 @@ -# -*- test-case-name: twisted.test.test_newcred -*- -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -import os - -from zope.interface import implements, Interface, Attribute - -from twisted.internet import defer -from twisted.python import failure, log -from twisted.cred import error, credentials - - - -class ICredentialsChecker(Interface): - """ - An object that can check sub-interfaces of ICredentials. - """ - - credentialInterfaces = Attribute( - 'A list of sub-interfaces of ICredentials which specifies which I may check.') - - - def requestAvatarId(credentials): - """ - @param credentials: something which implements one of the interfaces in - self.credentialInterfaces. - - @return: a Deferred which will fire a string which identifies an - avatar, an empty tuple to specify an authenticated anonymous user - (provided as checkers.ANONYMOUS) or fire a Failure(UnauthorizedLogin). - Alternatively, return the result itself. - """ - - - -# A note on anonymity - We do not want None as the value for anonymous -# because it is too easy to accidentally return it. We do not want the -# empty string, because it is too easy to mistype a password file. For -# example, an .htpasswd file may contain the lines: ['hello:asdf', -# 'world:asdf', 'goodbye', ':world']. This misconfiguration will have an -# ill effect in any case, but accidentally granting anonymous access is a -# worse failure mode than simply granting access to an untypeable -# username. We do not want an instance of 'object', because that would -# create potential problems with persistence. - -ANONYMOUS = () - - -class AllowAnonymousAccess: - implements(ICredentialsChecker) - credentialInterfaces = credentials.IAnonymous, - - def requestAvatarId(self, credentials): - return defer.succeed(ANONYMOUS) - - -class InMemoryUsernamePasswordDatabaseDontUse: - """ - An extremely simple credentials checker. - - This is only of use in one-off test programs or examples which don't - want to focus too much on how credentials are verified. - - You really don't want to use this for anything else. It is, at best, a - toy. If you need a simple credentials checker for a real application, - see L{FilePasswordDB}. - """ - - implements(ICredentialsChecker) - - credentialInterfaces = (credentials.IUsernamePassword, - credentials.IUsernameHashedPassword) - - def __init__(self, **users): - self.users = users - - def addUser(self, username, password): - self.users[username] = password - - def _cbPasswordMatch(self, matched, username): - if matched: - return username - else: - return failure.Failure(error.UnauthorizedLogin()) - - def requestAvatarId(self, credentials): - if credentials.username in self.users: - return defer.maybeDeferred( - credentials.checkPassword, - self.users[credentials.username]).addCallback( - self._cbPasswordMatch, str(credentials.username)) - else: - return defer.fail(error.UnauthorizedLogin()) - - -class FilePasswordDB: - """A file-based, text-based username/password database. - - Records in the datafile for this class are delimited by a particular - string. The username appears in a fixed field of the columns delimited - by this string, as does the password. Both fields are specifiable. If - the passwords are not stored plaintext, a hash function must be supplied - to convert plaintext passwords to the form stored on disk and this - CredentialsChecker will only be able to check IUsernamePassword - credentials. If the passwords are stored plaintext, - IUsernameHashedPassword credentials will be checkable as well. - """ - - implements(ICredentialsChecker) - - cache = False - _credCache = None - _cacheTimestamp = 0 - - def __init__(self, filename, delim=':', usernameField=0, passwordField=1, - caseSensitive=True, hash=None, cache=False): - """ - @type filename: C{str} - @param filename: The name of the file from which to read username and - password information. - - @type delim: C{str} - @param delim: The field delimiter used in the file. - - @type usernameField: C{int} - @param usernameField: The index of the username after splitting a - line on the delimiter. - - @type passwordField: C{int} - @param passwordField: The index of the password after splitting a - line on the delimiter. - - @type caseSensitive: C{bool} - @param caseSensitive: If true, consider the case of the username when - performing a lookup. Ignore it otherwise. - - @type hash: Three-argument callable or C{None} - @param hash: A function used to transform the plaintext password - received over the network to a format suitable for comparison - against the version stored on disk. The arguments to the callable - are the username, the network-supplied password, and the in-file - version of the password. If the return value compares equal to the - version stored on disk, the credentials are accepted. - - @type cache: C{bool} - @param cache: If true, maintain an in-memory cache of the - contents of the password file. On lookups, the mtime of the - file will be checked, and the file will only be re-parsed if - the mtime is newer than when the cache was generated. - """ - self.filename = filename - self.delim = delim - self.ufield = usernameField - self.pfield = passwordField - self.caseSensitive = caseSensitive - self.hash = hash - self.cache = cache - - if self.hash is None: - # The passwords are stored plaintext. We can support both - # plaintext and hashed passwords received over the network. - self.credentialInterfaces = ( - credentials.IUsernamePassword, - credentials.IUsernameHashedPassword - ) - else: - # The passwords are hashed on disk. We can support only - # plaintext passwords received over the network. - self.credentialInterfaces = ( - credentials.IUsernamePassword, - ) - - - def __getstate__(self): - d = dict(vars(self)) - for k in '_credCache', '_cacheTimestamp': - try: - del d[k] - except KeyError: - pass - return d - - - def _cbPasswordMatch(self, matched, username): - if matched: - return username - else: - return failure.Failure(error.UnauthorizedLogin()) - - - def _loadCredentials(self): - try: - f = file(self.filename) - except: - log.err() - raise error.UnauthorizedLogin() - else: - for line in f: - line = line.rstrip() - parts = line.split(self.delim) - - if self.ufield >= len(parts) or self.pfield >= len(parts): - continue - if self.caseSensitive: - yield parts[self.ufield], parts[self.pfield] - else: - yield parts[self.ufield].lower(), parts[self.pfield] - - - def getUser(self, username): - if not self.caseSensitive: - username = username.lower() - - if self.cache: - if self._credCache is None or os.path.getmtime(self.filename) > self._cacheTimestamp: - self._cacheTimestamp = os.path.getmtime(self.filename) - self._credCache = dict(self._loadCredentials()) - return username, self._credCache[username] - else: - for u, p in self._loadCredentials(): - if u == username: - return u, p - raise KeyError(username) - - - def requestAvatarId(self, c): - try: - u, p = self.getUser(c.username) - except KeyError: - return defer.fail(error.UnauthorizedLogin()) - else: - up = credentials.IUsernamePassword(c, None) - if self.hash: - if up is not None: - h = self.hash(up.username, up.password, p) - if h == p: - return defer.succeed(u) - return defer.fail(error.UnauthorizedLogin()) - else: - return defer.maybeDeferred(c.checkPassword, p - ).addCallback(self._cbPasswordMatch, u) - - - -class PluggableAuthenticationModulesChecker: - implements(ICredentialsChecker) - credentialInterfaces = credentials.IPluggableAuthenticationModules, - service = 'Twisted' - - def requestAvatarId(self, credentials): - try: - from twisted.cred import pamauth - except ImportError: # PyPAM is missing - return defer.fail(error.UnauthorizedLogin()) - else: - d = pamauth.pamAuthenticate(self.service, credentials.username, - credentials.pamConversion) - d.addCallback(lambda x: credentials.username) - return d - - - -# For backwards compatibility -# Allow access as the old name. -OnDiskUsernamePasswordDatabase = FilePasswordDB diff --git a/tools/buildbot/pylibs/twisted/cred/credentials.py b/tools/buildbot/pylibs/twisted/cred/credentials.py deleted file mode 100644 index 141ebc2..0000000 --- a/tools/buildbot/pylibs/twisted/cred/credentials.py +++ /dev/null @@ -1,198 +0,0 @@ -# -*- test-case-name: twisted.test.test_newcred-*- - -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -from zope.interface import implements, Interface - -import hmac -import time -import random - - - -class ICredentials(Interface): - """ - I check credentials. - - Implementors _must_ specify which sub-interfaces of ICredentials - to which it conforms, using zope.interface.implements(). - """ - - - -class IUsernameHashedPassword(ICredentials): - """ - I encapsulate a username and a hashed password. - - This credential is used when a hashed password is received from the - party requesting authentication. CredentialCheckers which check this - kind of credential must store the passwords in plaintext (or as - password-equivalent hashes) form so that they can be hashed in a manner - appropriate for the particular credentials class. - - @type username: C{str} - @ivar username: The username associated with these credentials. - """ - - def checkPassword(password): - """Validate these credentials against the correct password. - - @param password: The correct, plaintext password against which to - check. - - @return: a deferred which becomes, or a boolean indicating if the - password matches. - """ - - - -class IUsernamePassword(ICredentials): - """ - I encapsulate a username and a plaintext password. - - This encapsulates the case where the password received over the network - has been hashed with the identity function (That is, not at all). The - CredentialsChecker may store the password in whatever format it desires, - it need only transform the stored password in a similar way before - performing the comparison. - - @type username: C{str} - @ivar username: The username associated with these credentials. - - @type password: C{str} - @ivar password: The password associated with these credentials. - """ - - def checkPassword(password): - """Validate these credentials against the correct password. - - @param password: The correct, plaintext password against which to - check. - - @return: a deferred which becomes, or a boolean indicating if the - password matches. - """ - - - -class IAnonymous(ICredentials): - """ - I am an explicitly anonymous request for access. - """ - - - -class CramMD5Credentials: - implements(IUsernameHashedPassword) - - challenge = '' - response = '' - - def __init__(self, host=None): - self.host = host - - def getChallenge(self): - if self.challenge: - return self.challenge - # The data encoded in the first ready response contains an - # presumptively arbitrary string of random digits, a timestamp, and - # the fully-qualified primary host name of the server. The syntax of - # the unencoded form must correspond to that of an RFC 822 'msg-id' - # [RFC822] as described in [POP3]. - # -- RFC 2195 - r = random.randrange(0x7fffffff) - t = time.time() - self.challenge = '<%d.%d@%s>' % (r, t, self.host) - return self.challenge - - def setResponse(self, response): - self.username, self.response = response.split(None, 1) - - def moreChallenges(self): - return False - - def checkPassword(self, password): - verify = hmac.HMAC(password, self.challenge).hexdigest() - return verify == self.response - - -class UsernameHashedPassword: - implements(IUsernameHashedPassword) - - def __init__(self, username, hashed): - self.username = username - self.hashed = hashed - - def checkPassword(self, password): - return self.hashed == password - - -class UsernamePassword: - implements(IUsernamePassword) - - def __init__(self, username, password): - self.username = username - self.password = password - - def checkPassword(self, password): - return self.password == password - - -class Anonymous: - implements(IAnonymous) - - - -class ISSHPrivateKey(ICredentials): - """ - I encapsulate an SSH public key to be checked against a users private - key. - - @ivar username: Duh? - - @ivar algName: The algorithm name for the blob. - - @ivar blob: The public key blob as sent by the client. - - @ivar sigData: The data the signature was made from. - - @ivar signature: The signed data. This is checked to verify that the user - owns the private key. - """ - - - -class SSHPrivateKey: - implements(ISSHPrivateKey) - def __init__(self, username, algName, blob, sigData, signature): - self.username = username - self.algName = algName - self.blob = blob - self.sigData = sigData - self.signature = signature - - -class IPluggableAuthenticationModules(ICredentials): - """I encapsulate the authentication of a user via PAM (Pluggable - Authentication Modules. I use PyPAM (available from - http://www.tummy.com/Software/PyPam/index.html). - - @ivar username: The username for the user being logged in. - - @ivar pamConversion: A function that is called with a list of tuples - (message, messageType). See the PAM documentation - for the meaning of messageType. The function - returns a Deferred which will fire with a list - of (response, 0), one for each message. The 0 is - currently unused, but is required by the PAM library. - """ - -class PluggableAuthenticationModules: - implements(IPluggableAuthenticationModules) - - def __init__(self, username, pamConversion): - self.username = username - self.pamConversion = pamConversion - diff --git a/tools/buildbot/pylibs/twisted/cred/error.py b/tools/buildbot/pylibs/twisted/cred/error.py deleted file mode 100644 index ec7b3e3..0000000 --- a/tools/buildbot/pylibs/twisted/cred/error.py +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Cred errors.""" - -class Unauthorized(Exception): - """Standard unauthorized error.""" - - - -class LoginFailed(Exception): - """ - The user's request to log in failed for some reason. - """ - - - -class UnauthorizedLogin(LoginFailed, Unauthorized): - """The user was not authorized to log in. - """ - - - -class UnhandledCredentials(LoginFailed): - """A type of credentials were passed in with no knowledge of how to check - them. This is a server configuration error - it means that a protocol was - connected to a Portal without a CredentialChecker that can check all of its - potential authentication strategies. - """ - - - -class LoginDenied(LoginFailed): - """ - The realm rejected this login for some reason. - - Examples of reasons this might be raised include an avatar logging in - too frequently, a quota having been fully used, or the overall server - load being too high. - """ diff --git a/tools/buildbot/pylibs/twisted/cred/pamauth.py b/tools/buildbot/pylibs/twisted/cred/pamauth.py deleted file mode 100644 index 1537a5f..0000000 --- a/tools/buildbot/pylibs/twisted/cred/pamauth.py +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Support for asynchronously authenticating using PAM. -""" - - -import PAM - -import getpass, threading, os - -from twisted.internet import threads, defer - -def pamAuthenticateThread(service, user, conv): - def _conv(items): - from twisted.internet import reactor - try: - d = conv(items) - except: - import traceback - traceback.print_exc() - return - ev = threading.Event() - def cb(r): - ev.r = (1, r) - ev.set() - def eb(e): - ev.r = (0, e) - ev.set() - reactor.callFromThread(d.addCallbacks, cb, eb) - ev.wait() - done = ev.r - if done[0]: - return done[1] - else: - raise done[1].type, done[1].value - - return callIntoPAM(service, user, _conv) - -def callIntoPAM(service, user, conv): - """A testing hook. - """ - pam = PAM.pam() - pam.start(service) - pam.set_item(PAM.PAM_USER, user) - pam.set_item(PAM.PAM_CONV, conv) - gid = os.getegid() - uid = os.geteuid() - os.setegid(0) - os.seteuid(0) - try: - pam.authenticate() # these will raise - pam.acct_mgmt() - return 1 - finally: - os.setegid(gid) - os.seteuid(uid) - -def defConv(items): - resp = [] - for i in range(len(items)): - message, kind = items[i] - if kind == 1: # password - p = getpass.getpass(message) - resp.append((p, 0)) - elif kind == 2: # text - p = raw_input(message) - resp.append((p, 0)) - elif kind in (3,4): - print message - resp.append(("", 0)) - else: - return defer.fail('foo') - d = defer.succeed(resp) - return d - -def pamAuthenticate(service, user, conv): - return threads.deferToThread(pamAuthenticateThread, service, user, conv) diff --git a/tools/buildbot/pylibs/twisted/cred/portal.py b/tools/buildbot/pylibs/twisted/cred/portal.py deleted file mode 100644 index 67c0f90..0000000 --- a/tools/buildbot/pylibs/twisted/cred/portal.py +++ /dev/null @@ -1,120 +0,0 @@ -# -*- test-case-name: twisted.test.test_newcred -*- - -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -The point of integration of application and authentication. -""" - - -from twisted.internet import defer -from twisted.internet.defer import maybeDeferred -from twisted.python import failure, reflect -from twisted.cred import error -from zope.interface import providedBy, Interface - - -class IRealm(Interface): - """ - The realm connects application-specific objects to the - authentication system. - """ - def requestAvatar(avatarId, mind, *interfaces): - """ - Return avatar which provides one of the given interfaces. - - @param avatarId: a string that identifies an avatar, as returned by - L{ICredentialsChecker.requestAvatarId} - (via a Deferred). Alternatively, it may be - C{twisted.cred.checkers.ANONYMOUS}. - @param mind: usually None. See the description of mind in - L{Portal.login}. - @param interfaces: the interface(s) the returned avatar should - implement, e.g. C{IMailAccount}. See the description of - L{Portal.login}. - - @returns: a deferred which will fire a tuple of (interface, - avatarAspect, logout), or the tuple itself. The interface will be - one of the interfaces passed in the 'interfaces' argument. The - 'avatarAspect' will implement that interface. The 'logout' object - is a callable which will detach the mind from the avatar. - """ - - -class Portal: - """ - A mediator between clients and a realm. - - A portal is associated with one Realm and zero or more credentials checkers. - When a login is attempted, the portal finds the appropriate credentials - checker for the credentials given, invokes it, and if the credentials are - valid, retrieves the appropriate avatar from the Realm. - - This class is not intended to be subclassed. Customization should be done - in the realm object and in the credentials checker objects. - """ - def __init__(self, realm, checkers=()): - """ - Create a Portal to a L{IRealm}. - """ - self.realm = realm - self.checkers = {} - for checker in checkers: - self.registerChecker(checker) - - def listCredentialsInterfaces(self): - """ - Return list of credentials interfaces that can be used to login. - """ - return self.checkers.keys() - - def registerChecker(self, checker, *credentialInterfaces): - if not credentialInterfaces: - credentialInterfaces = checker.credentialInterfaces - for credentialInterface in credentialInterfaces: - self.checkers[credentialInterface] = checker - - def login(self, credentials, mind, *interfaces): - """ - @param credentials: an implementor of - L{twisted.cred.credentials.ICredentials} - - @param mind: an object which implements a client-side interface for - your particular realm. In many cases, this may be None, so if the - word 'mind' confuses you, just ignore it. - - @param interfaces: list of interfaces for the perspective that the mind - wishes to attach to. Usually, this will be only one interface, for - example IMailAccount. For highly dynamic protocols, however, this - may be a list like (IMailAccount, IUserChooser, IServiceInfo). To - expand: if we are speaking to the system over IMAP, any information - that will be relayed to the user MUST be returned as an - IMailAccount implementor; IMAP clients would not be able to - understand anything else. Any information about unusual status - would have to be relayed as a single mail message in an - otherwise-empty mailbox. However, in a web-based mail system, or a - PB-based client, the ``mind'' object inside the web server - (implemented with a dynamic page-viewing mechanism such as woven) - or on the user's client program may be intelligent enough to - respond to several ``server''-side interfaces. - - @return: A deferred which will fire a tuple of (interface, - avatarAspect, logout). The interface will be one of the interfaces - passed in the 'interfaces' argument. The 'avatarAspect' will - implement that interface. The 'logout' object is a callable which - will detach the mind from the avatar. It must be called when the - user has conceptually disconnected from the service. Although in - some cases this will not be in connectionLost (such as in a - web-based session), it will always be at the end of a user's - interactive session. - """ - for i in self.checkers: - if i.providedBy(credentials): - return maybeDeferred(self.checkers[i].requestAvatarId, credentials - ).addCallback(self.realm.requestAvatar, mind, *interfaces - ) - ifac = providedBy(credentials) - return defer.fail(failure.Failure(error.UnhandledCredentials( - "No checker for %s" % ', '.join(map(reflect.qual, ifac))))) - diff --git a/tools/buildbot/pylibs/twisted/cred/strcred.py b/tools/buildbot/pylibs/twisted/cred/strcred.py deleted file mode 100644 index a436edc..0000000 --- a/tools/buildbot/pylibs/twisted/cred/strcred.py +++ /dev/null @@ -1,270 +0,0 @@ -# -*- test-case-name: twisted.test.test_strcred -*- -# -# Copyright (c) 2007-2008 Twisted Matrix Laboratories. -# See LICENSE for details. -# - -""" -Support for resolving command-line strings that represent different -checkers available to cred. - -Examples: - - passwd:/etc/passwd - - memory:admin:asdf:user:lkj - - unix -""" - -import sys - -from zope.interface import Interface, Attribute - -from twisted.plugin import getPlugins -from twisted.python import usage - - - -class ICheckerFactory(Interface): - """ - A factory for objects which provide - L{twisted.cred.checkers.ICredentialsChecker}. - - It's implemented by twistd plugins creating checkers. - """ - - authType = Attribute( - 'A tag that identifies the authentication method.') - - - authHelp = Attribute( - 'A detailed (potentially multi-line) description of precisely ' - 'what functionality this CheckerFactory provides.') - - - argStringFormat = Attribute( - 'A short (one-line) description of the argument string format.') - - - credentialInterfaces = Attribute( - 'A list of credentials interfaces that this factory will support.') - - - def generateChecker(argstring): - """ - Return an L{ICredentialChecker} provider using the supplied - argument string. - """ - - - -class StrcredException(Exception): - """ - Base exception class for strcred. - """ - - - -class InvalidAuthType(StrcredException): - """ - Raised when a user provides an invalid identifier for the - authentication plugin (known as the authType). - """ - - - -class InvalidAuthArgumentString(StrcredException): - """ - Raised by an authentication plugin when the argument string - provided is formatted incorrectly. - """ - - - -class UnsupportedInterfaces(StrcredException): - """ - Raised when an application is given a checker to use that does not - provide any of the application's supported credentials interfaces. - """ - - - -# This will be used to warn the users whenever they view help for an -# authType that is not supported by the application. -notSupportedWarning = ("WARNING: This authType is not supported by " - "this application.") - - - -def findCheckerFactories(): - """ - Find all objects that implement L{ICheckerFactory}. - """ - return getPlugins(ICheckerFactory) - - - -def findCheckerFactory(authType): - """ - Find the first checker factory that supports the given authType. - """ - for factory in findCheckerFactories(): - if factory.authType == authType: - return factory - raise InvalidAuthType(authType) - - - -def makeChecker(description): - """ - Returns an L{twisted.cred.checkers.ICredentialsChecker} based on the - contents of a descriptive string. Similar to - L{twisted.application.strports}. - """ - if ':' in description: - authType, argstring = description.split(':', 1) - else: - authType = description - argstring = '' - return findCheckerFactory(authType).generateChecker(argstring) - - - -class AuthOptionMixin: - """ - Defines helper methods that can be added on to any - L{usage.Options} subclass that needs authentication. - - This mixin implements three new options methods: - - The opt_auth method (--auth) will write two new values to the - 'self' dictionary: C{credInterfaces} (a dict of lists) and - C{credCheckers} (a list). - - The opt_help_auth method (--help-auth) will search for all - available checker plugins and list them for the user; it will exit - when finished. - - The opt_help_auth_type method (--help-auth-type) will display - detailed help for a particular checker plugin. - - @cvar supportedInterfaces: An iterable object that returns - credential interfaces which this application is able to support. - - @cvar authOutput: A writeable object to which this options class - will send all help-related output. Default: L{sys.stdout} - """ - - supportedInterfaces = None - authOutput = sys.stdout - - - def supportsInterface(self, interface): - """ - Returns whether a particular credentials interface is supported. - """ - return (self.supportedInterfaces is None - or interface in self.supportedInterfaces) - - - def supportsCheckerFactory(self, factory): - """ - Returns whether a checker factory will provide at least one of - the credentials interfaces that we care about. - """ - for interface in factory.credentialInterfaces: - if self.supportsInterface(interface): - return True - return False - - - def addChecker(self, checker): - """ - Supply a supplied credentials checker to the Options class. - """ - # First figure out which interfaces we're willing to support. - supported = [] - if self.supportedInterfaces is None: - supported = checker.credentialInterfaces - else: - for interface in checker.credentialInterfaces: - if self.supportsInterface(interface): - supported.append(interface) - if not supported: - raise UnsupportedInterfaces(checker.credentialInterfaces) - # If we get this far, then we know we can use this checker. - if 'credInterfaces' not in self: - self['credInterfaces'] = {} - if 'credCheckers' not in self: - self['credCheckers'] = [] - self['credCheckers'].append(checker) - for interface in supported: - self['credInterfaces'].setdefault(interface, []).append(checker) - - - def opt_auth(self, description): - """ - Specify an authentication method for the server. - """ - try: - self.addChecker(makeChecker(description)) - except UnsupportedInterfaces, e: - raise usage.UsageError( - 'Auth plugin not supported: %s' % e.args[0]) - except InvalidAuthType, e: - raise usage.UsageError( - 'Auth plugin not recognized: %s' % e.args[0]) - except Exception, e: - raise usage.UsageError('Unexpected error: %s' % e) - - - def _checkerFactoriesForOptHelpAuth(self): - """ - Return a list of which authTypes will be displayed by --help-auth. - This makes it a lot easier to test this module. - """ - for factory in findCheckerFactories(): - for interface in factory.credentialInterfaces: - if self.supportsInterface(interface): - yield factory - break - - - def opt_help_auth(self): - """ - Show all authentication methods available. - """ - self.authOutput.write("Usage: --auth AuthType[:ArgString]\n") - self.authOutput.write("For detailed help: --help-auth-type AuthType\n") - self.authOutput.write('\n') - # Figure out the right width for our columns - firstLength = 0 - for factory in self._checkerFactoriesForOptHelpAuth(): - if len(factory.authType) > firstLength: - firstLength = len(factory.authType) - formatString = ' %%-%is\t%%s\n' % firstLength - self.authOutput.write(formatString % ('AuthType', 'ArgString format')) - self.authOutput.write(formatString % ('========', '================')) - for factory in self._checkerFactoriesForOptHelpAuth(): - self.authOutput.write( - formatString % (factory.authType, factory.argStringFormat)) - self.authOutput.write('\n') - raise SystemExit(0) - - - def opt_help_auth_type(self, authType): - """ - Show help for a particular authentication type. - """ - try: - cf = findCheckerFactory(authType) - except InvalidAuthType: - raise usage.UsageError("Invalid auth type: %s" % authType) - self.authOutput.write("Usage: --auth %s[:ArgString]\n" % authType) - self.authOutput.write("ArgString format: %s\n" % cf.argStringFormat) - self.authOutput.write('\n') - for line in cf.authHelp.strip().splitlines(): - self.authOutput.write(' %s\n' % line.rstrip()) - self.authOutput.write('\n') - if not self.supportsCheckerFactory(cf): - self.authOutput.write(' %s\n' % notSupportedWarning) - self.authOutput.write('\n') - raise SystemExit(0) diff --git a/tools/buildbot/pylibs/twisted/cred/util.py b/tools/buildbot/pylibs/twisted/cred/util.py deleted file mode 100644 index fbd6750..0000000 --- a/tools/buildbot/pylibs/twisted/cred/util.py +++ /dev/null @@ -1,40 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Utility functions for authorization. - -These are currently for challenge-response shared secret authentication. - -Maintainer: U{Glyph Lefkowitz} -""" - -# System Imports -import md5 -import random - -from twisted.cred.error import Unauthorized - -def respond(challenge, password): - """Respond to a challenge. - This is useful for challenge/response authentication. - """ - m = md5.new() - m.update(password) - hashedPassword = m.digest() - m = md5.new() - m.update(hashedPassword) - m.update(challenge) - doubleHashedPassword = m.digest() - return doubleHashedPassword - -def challenge(): - """I return some random data. - """ - crap = '' - for x in range(random.randrange(15,25)): - crap = crap + chr(random.randint(65,90)) - crap = md5.new(crap).digest() - return crap diff --git a/tools/buildbot/pylibs/twisted/enterprise/__init__.py b/tools/buildbot/pylibs/twisted/enterprise/__init__.py deleted file mode 100644 index 5364bed..0000000 --- a/tools/buildbot/pylibs/twisted/enterprise/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Twisted Enterprise: database support for Twisted services. -""" - -__all__ = ['adbapi', 'reflector', 'row', 'sqlreflector', 'util'] diff --git a/tools/buildbot/pylibs/twisted/enterprise/adbapi.py b/tools/buildbot/pylibs/twisted/enterprise/adbapi.py deleted file mode 100644 index 9bfc9bd..0000000 --- a/tools/buildbot/pylibs/twisted/enterprise/adbapi.py +++ /dev/null @@ -1,440 +0,0 @@ -# -*- test-case-name: twisted.test.test_adbapi -*- -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -An asynchronous mapping to U{DB-API 2.0}. -""" - -from twisted.internet import defer, threads -from twisted.python import reflect, log -from twisted.python.deprecate import deprecated -from twisted.python.versions import Version - - -class ConnectionLost(Exception): - """This exception means that a db connection has been lost. - Client code may try again.""" - pass - - -class Connection(object): - """A wrapper for a DB-API connection instance. - - The wrapper passes almost everything to the wrapped connection and so has - the same API. However, the Connection knows about its pool and also - handle reconnecting should when the real connection dies. - """ - - def __init__(self, pool): - self._pool = pool - self._connection = None - self.reconnect() - - def close(self): - # The way adbapi works right now means that closing a connection is - # a really bad thing as it leaves a dead connection associated with - # a thread in the thread pool. - # Really, I think closing a pooled connection should return it to the - # pool but that's handled by the runWithConnection method already so, - # rather than upsetting anyone by raising an exception, let's ignore - # the request - pass - - def rollback(self): - if not self._pool.reconnect: - self._connection.rollback() - return - - try: - self._connection.rollback() - curs = self._connection.cursor() - curs.execute(self._pool.good_sql) - curs.close() - self._connection.commit() - return - except: - pass - - self._pool.disconnect(self._connection) - - if self._pool.noisy: - log.msg('Connection lost.') - - raise ConnectionLost() - - def reconnect(self): - if self._connection is not None: - self._pool.disconnect(self._connection) - self._connection = self._pool.connect() - - def __getattr__(self, name): - return getattr(self._connection, name) - - -class Transaction: - """A lightweight wrapper for a DB-API 'cursor' object. - - Relays attribute access to the DB cursor. That is, you can call - execute(), fetchall(), etc., and they will be called on the - underlying DB-API cursor object. Attributes will also be - retrieved from there. - """ - _cursor = None - - def __init__(self, pool, connection): - self._pool = pool - self._connection = connection - self.reopen() - - def close(self): - _cursor = self._cursor - self._cursor = None - _cursor.close() - - def reopen(self): - if self._cursor is not None: - self.close() - - try: - self._cursor = self._connection.cursor() - return - except: - if not self._pool.reconnect: - raise - - if self._pool.noisy: - log.msg('Connection lost, reconnecting') - - self.reconnect() - self._cursor = self._connection.cursor() - - def reconnect(self): - self._connection.reconnect() - self._cursor = None - - def __getattr__(self, name): - return getattr(self._cursor, name) - - -class ConnectionPool: - """I represent a pool of connections to a DB-API 2.0 compliant database. - """ - - CP_ARGS = "min max name noisy openfun reconnect good_sql".split() - - noisy = True # if true, generate informational log messages - min = 3 # minimum number of connections in pool - max = 5 # maximum number of connections in pool - name = None # Name to assign to thread pool for debugging - openfun = None # A function to call on new connections - reconnect = False # reconnect when connections fail - good_sql = 'select 1' # a query which should always succeed - - running = False # true when the pool is operating - - def __init__(self, dbapiName, *connargs, **connkw): - """Create a new ConnectionPool. - - Any positional or keyword arguments other than those documented here - are passed to the DB-API object when connecting. Use these arguments to - pass database names, usernames, passwords, etc. - - @param dbapiName: an import string to use to obtain a DB-API compatible - module (e.g. 'pyPgSQL.PgSQL') - - @param cp_min: the minimum number of connections in pool (default 3) - - @param cp_max: the maximum number of connections in pool (default 5) - - @param cp_noisy: generate informational log messages during operation - (default False) - - @param cp_openfun: a callback invoked after every connect() on the - underlying DB-API object. The callback is passed a - new DB-API connection object. This callback can - setup per-connection state such as charset, - timezone, etc. - - @param cp_reconnect: detect connections which have failed and reconnect - (default False). Failed connections may result in - ConnectionLost exceptions, which indicate the - query may need to be re-sent. - - @param cp_good_sql: an sql query which should always succeed and change - no state (default 'select 1') - """ - - self.dbapiName = dbapiName - self.dbapi = reflect.namedModule(dbapiName) - - if getattr(self.dbapi, 'apilevel', None) != '2.0': - log.msg('DB API module not DB API 2.0 compliant.') - - if getattr(self.dbapi, 'threadsafety', 0) < 1: - log.msg('DB API module not sufficiently thread-safe.') - - self.connargs = connargs - self.connkw = connkw - - for arg in self.CP_ARGS: - cp_arg = 'cp_%s' % arg - if connkw.has_key(cp_arg): - setattr(self, arg, connkw[cp_arg]) - del connkw[cp_arg] - - self.min = min(self.min, self.max) - self.max = max(self.min, self.max) - - self.connections = {} # all connections, hashed on thread id - - # these are optional so import them here - from twisted.python import threadpool - import thread - - self.threadID = thread.get_ident - self.threadpool = threadpool.ThreadPool(self.min, self.max) - - from twisted.internet import reactor - self.startID = reactor.callWhenRunning(self._start) - - def _start(self): - self.startID = None - return self.start() - - def start(self): - """Start the connection pool. - - If you are using the reactor normally, this function does *not* - need to be called. - """ - - if not self.running: - from twisted.internet import reactor - self.threadpool.start() - self.shutdownID = reactor.addSystemEventTrigger('during', - 'shutdown', - self.finalClose) - self.running = True - - def runWithConnection(self, func, *args, **kw): - return self._deferToThread(self._runWithConnection, - func, *args, **kw) - - def _runWithConnection(self, func, *args, **kw): - conn = Connection(self) - try: - result = func(conn, *args, **kw) - conn.commit() - return result - except: - conn.rollback() - raise - - def runInteraction(self, interaction, *args, **kw): - """Interact with the database and return the result. - - The 'interaction' is a callable object which will be executed - in a thread using a pooled connection. It will be passed an - L{Transaction} object as an argument (whose interface is - identical to that of the database cursor for your DB-API - module of choice), and its results will be returned as a - Deferred. If running the method raises an exception, the - transaction will be rolled back. If the method returns a - value, the transaction will be committed. - - NOTE that the function you pass is *not* run in the main - thread: you may have to worry about thread-safety in the - function you pass to this if it tries to use non-local - objects. - - @param interaction: a callable object whose first argument is - L{adbapi.Transaction}. *args,**kw will be passed as - additional arguments. - - @return: a Deferred which will fire the return value of - 'interaction(Transaction(...))', or a Failure. - """ - - return self._deferToThread(self._runInteraction, - interaction, *args, **kw) - - def runQuery(self, *args, **kw): - """Execute an SQL query and return the result. - - A DB-API cursor will will be invoked with cursor.execute(*args, **kw). - The exact nature of the arguments will depend on the specific flavor - of DB-API being used, but the first argument in *args be an SQL - statement. The result of a subsequent cursor.fetchall() will be - fired to the Deferred which is returned. If either the 'execute' or - 'fetchall' methods raise an exception, the transaction will be rolled - back and a Failure returned. - - The *args and **kw arguments will be passed to the DB-API cursor's - 'execute' method. - - @return: a Deferred which will fire the return value of a DB-API - cursor's 'fetchall' method, or a Failure. - """ - - return self.runInteraction(self._runQuery, *args, **kw) - - def runOperation(self, *args, **kw): - """Execute an SQL query and return None. - - A DB-API cursor will will be invoked with cursor.execute(*args, **kw). - The exact nature of the arguments will depend on the specific flavor - of DB-API being used, but the first argument in *args will be an SQL - statement. This method will not attempt to fetch any results from the - query and is thus suitable for INSERT, DELETE, and other SQL statements - which do not return values. If the 'execute' method raises an - exception, the transaction will be rolled back and a Failure returned. - - The args and kw arguments will be passed to the DB-API cursor's - 'execute' method. - - return: a Deferred which will fire None or a Failure. - """ - - return self.runInteraction(self._runOperation, *args, **kw) - - def close(self): - """Close all pool connections and shutdown the pool.""" - - from twisted.internet import reactor - if self.shutdownID: - reactor.removeSystemEventTrigger(self.shutdownID) - self.shutdownID = None - if self.startID: - reactor.removeSystemEventTrigger(self.startID) - self.startID = None - self.finalClose() - - def finalClose(self): - """This should only be called by the shutdown trigger.""" - - self.shutdownID = None - self.threadpool.stop() - self.running = False - for conn in self.connections.values(): - self._close(conn) - self.connections.clear() - - def connect(self): - """Return a database connection when one becomes available. - - This method blocks and should be run in a thread from the internal - threadpool. Don't call this method directly from non-threaded code. - Using this method outside the external threadpool may exceed the - maximum number of connections in the pool. - - @return: a database connection from the pool. - """ - - tid = self.threadID() - conn = self.connections.get(tid) - if conn is None: - if self.noisy: - log.msg('adbapi connecting: %s %s%s' % (self.dbapiName, - self.connargs or '', - self.connkw or '')) - conn = self.dbapi.connect(*self.connargs, **self.connkw) - if self.openfun != None: - self.openfun(conn) - self.connections[tid] = conn - return conn - - def disconnect(self, conn): - """Disconnect a database connection associated with this pool. - - Note: This function should only be used by the same thread which - called connect(). As with connect(), this function is not used - in normal non-threaded twisted code. - """ - - tid = self.threadID() - if conn is not self.connections.get(tid): - raise Exception("wrong connection for thread") - if conn is not None: - self._close(conn) - del self.connections[tid] - - def _close(self, conn): - if self.noisy: - log.msg('adbapi closing: %s' % (self.dbapiName,)) - try: - conn.close() - except: - pass - - def _runInteraction(self, interaction, *args, **kw): - conn = Connection(self) - trans = Transaction(self, conn) - try: - result = interaction(trans, *args, **kw) - trans.close() - conn.commit() - return result - except: - conn.rollback() - raise - - def _runQuery(self, trans, *args, **kw): - trans.execute(*args, **kw) - return trans.fetchall() - - def _runOperation(self, trans, *args, **kw): - trans.execute(*args, **kw) - - def __getstate__(self): - return {'dbapiName': self.dbapiName, - 'min': self.min, - 'max': self.max, - 'noisy': self.noisy, - 'reconnect': self.reconnect, - 'good_sql': self.good_sql, - 'connargs': self.connargs, - 'connkw': self.connkw} - - def __setstate__(self, state): - self.__dict__ = state - self.__init__(self.dbapiName, *self.connargs, **self.connkw) - - def _deferToThread(self, f, *args, **kwargs): - """Internal function. - - Call f in one of the connection pool's threads. - """ - - d = defer.Deferred() - self.threadpool.callInThread(threads._putResultInDeferred, - d, f, args, kwargs) - return d - - - -# Common deprecation decorator used for all deprecations. -_unreleasedVersion = Version("Twisted", 2, 6, 0) -_unreleasedDeprecation = deprecated(_unreleasedVersion) - - - -def _safe(text): - """ - Something really stupid that replaces quotes with escaped quotes. - """ - return text.replace("'", "''").replace("\\", "\\\\") - - - -def safe(text): - """ - Make a string safe to include in an SQL statement. - """ - return _safe(text) - -safe = _unreleasedDeprecation(safe) - - -__all__ = ['Transaction', 'ConnectionPool', 'safe'] diff --git a/tools/buildbot/pylibs/twisted/enterprise/reflector.py b/tools/buildbot/pylibs/twisted/enterprise/reflector.py deleted file mode 100644 index cc15a37..0000000 --- a/tools/buildbot/pylibs/twisted/enterprise/reflector.py +++ /dev/null @@ -1,167 +0,0 @@ -# -*- test-case-name: twisted.test.test_reflector -*- -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -import weakref, warnings - -from twisted.enterprise.util import DBError - -class Reflector: - """ - DEPRECATED. - - Base class for enterprise reflectors. This implements row caching. - """ - populated = 0 - - def __init__(self, rowClasses): - """ - Initialize me against a database. - - @param rowClasses: a list of row class objects that describe the - database schema. - """ - warnings.warn("twisted.enterprise.reflector is deprecated since " - "Twisted 8.0", category=DeprecationWarning, stacklevel=2) - # does not hold references to cached rows. - self.rowCache = weakref.WeakValueDictionary() - self.rowClasses = rowClasses - self.schema = {} - self._populate() - - def __getstate__(self): - d = self.__dict__.copy() - del d['rowCache'] - return d - - def __setstate__(self, state): - self.__dict__ = state - self.rowCache = weakref.WeakValueDictionary() - self._populate() - - def _populate(self): - """Implement me to populate schema information for the reflector. - """ - raise DBError("not implemented") - - def populateSchemaFor(self, tableInfo): - """This is called once for each registered rowClass to add it - and its foreign key relationships for that rowClass to the - schema.""" - - self.schema[ tableInfo.rowTableName ] = tableInfo - - # add the foreign key to the foreign table. - for foreignTableName, childColumns, parentColumns, containerMethod, autoLoad in tableInfo.rowForeignKeys: - self.schema[foreignTableName].addForeignKey(childColumns, - parentColumns, tableInfo.rowClass, - containerMethod, autoLoad) - - def getTableInfo(self, rowObject): - """Get a TableInfo record about a particular instance. - - This record contains various information about the instance's - class as registered with this reflector. - - @param rowObject: a L{RowObject} instance of a class previously - registered with me. - @raises twisted.enterprise.row.DBError: raised if this class was not - previously registered. - """ - try: - return self.schema[rowObject.rowTableName] - except KeyError: - raise DBError("class %s was not registered with %s" % ( - rowObject.__class__, self)) - - def buildWhereClause(self, relationship, row): - """util method used by reflectors. builds a where clause to link a row to another table. - """ - whereClause = [] - for i in range(0,len(relationship.childColumns)): - value = getattr(row, relationship.parentColumns[i][0]) - whereClause.append( [relationship.childColumns[i][0], EQUAL, value] ) - return whereClause - - def addToParent(self, parentRow, rows, tableName): - """util method used by reflectors. adds these rows to the parent row object. - If a rowClass does not have a containerMethod, then a list attribute "childRows" - will be used. - """ - parentInfo = self.getTableInfo(parentRow) - relationship = parentInfo.getRelationshipFor(tableName) - if not relationship: - raise DBError("no relationship from %s to %s" % ( parentRow.rowTableName, tableName) ) - - if not relationship.containerMethod: - if hasattr(parentRow, "childRows"): - for row in rows: - if row not in parentRow.childRows: - parentRow.childRows.append(row) - else: - parentRow.childRows = rows - return - - if not hasattr(parentRow, relationship.containerMethod): - raise DBError("parent row (%s) doesnt have container method <%s>!" % (parentRow, relationship.containerMethod)) - - meth = getattr(parentRow, relationship.containerMethod) - for row in rows: - meth(row) - - ####### Row Cache ######## - - def addToCache(self, rowObject): - """NOTE: Should this be recursive?! requires better container knowledge...""" - self.rowCache[ rowObject.getKeyTuple() ] = rowObject - - def findInCache(self, rowClass, kw): - keys = [] - keys.append(rowClass.rowTableName) - for keyName, keyType in rowClass.rowKeyColumns: - keys.append( kw[keyName] ) - keyTuple = tuple(keys) - return self.rowCache.get(keyTuple) - - def removeFromCache(self, rowObject): - """NOTE: should this be recursive!??""" - key = rowObject.getKeyTuple() - if self.rowCache.has_key(key): - del self.rowCache[key] - - ####### Row Operations ######## - - def loadObjectsFrom(self, tableName, parent=None, data=None, - whereClause=[], loadChildren=1): - """Implement me to load objects from the database. - - @param whereClause: a list of tuples of (columnName, conditional, value) - so it can be parsed by all types of reflectors. eg.:: - whereClause = [("name", EQUALS, "fred"), ("age", GREATERTHAN, 18)] - """ - raise DBError("not implemented") - - def updateRow(self, rowObject): - """update this rowObject to the database. - """ - raise DBError("not implemented") - - def insertRow(self, rowObject): - """insert a new row for this object instance. - """ - raise DBError("not implemented") - - def deleteRow(self, rowObject): - """delete the row for this object from the database. - """ - raise DBError("not implemented") - -# conditionals -EQUAL = 0 -LESSTHAN = 1 -GREATERTHAN = 2 -LIKE = 3 - - -__all__ = ['Reflector', 'EQUAL', 'LESSTHAN', 'GREATERTHAN', 'LIKE'] diff --git a/tools/buildbot/pylibs/twisted/enterprise/row.py b/tools/buildbot/pylibs/twisted/enterprise/row.py deleted file mode 100644 index 36d0fa4..0000000 --- a/tools/buildbot/pylibs/twisted/enterprise/row.py +++ /dev/null @@ -1,127 +0,0 @@ -# -*- test-case-name: twisted.test.test_reflector -*- -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -DEPRECATED. - -A (R)elational (O)bject (W)rapper. - -This is an extremely thin wrapper. - -Maintainer: U{Dave Peticolas} -""" - -import warnings - -from twisted.enterprise.util import DBError, NOQUOTE, getKeyColumn, dbTypeMap - - -class RowObject: - """ - I represent a row in a table in a relational database. - - My class is "populated" by a Reflector object. After I am - populated, instances of me are able to interact with a particular - database table. - - You should use a class derived from this class for each database - table. - - reflector.loadObjectsFrom() is used to create sets of - instance of objects of this class from database tables. - - Once created, the "key column" attributes cannot be changed. - - - Class Attributes that users must supply:: - - rowKeyColumns # list of key columns in form: [(columnName, typeName)] - rowTableName # name of database table - rowColumns # list of the columns in the table with the correct - # case.this will be used to create member variables. - rowFactoryMethod # method to create an instance of this class. - # HACK: must be in a list!!! [factoryMethod] (optional) - rowForeignKeys # keys to other tables (optional) - """ - - populated = 0 # set on the class when the class is "populated" with SQL - dirty = 0 # set on an instance when the instance is out-of-sync with the database - - def __init__(self): - """ - DEPRECATED. - """ - warnings.warn("twisted.enterprise.row is deprecated since Twisted 8.0", - category=DeprecationWarning, stacklevel=2) - - def assignKeyAttr(self, attrName, value): - """Assign to a key attribute. - - This cannot be done through normal means to protect changing - keys of db objects. - """ - found = 0 - for keyColumn, type in self.rowKeyColumns: - if keyColumn == attrName: - found = 1 - if not found: - raise DBError("%s is not a key columns." % attrName) - self.__dict__[attrName] = value - - def findAttribute(self, attrName): - """Find an attribute by caseless name. - """ - for attr, type in self.rowColumns: - if attr.lower() == attrName.lower(): - return getattr(self, attr) - raise DBError("Unable to find attribute %s" % attrName) - - def __setattr__(self, name, value): - """Special setattr to prevent changing of key values. - """ - # build where clause - if getKeyColumn(self.__class__, name): - raise DBError("cannot assign value <%s> to key column attribute <%s> of RowObject class" % (value,name)) - - if name in self.rowColumns: - if value != self.__dict__.get(name,None) and not self.dirty: - self.setDirty(1) - - self.__dict__[name] = value - - def createDefaultAttributes(self): - """Populate instance with default attributes. - - This is used when creating a new instance NOT from the - database. - """ - for attr in self.rowColumns: - if getKeyColumn(self.__class__, attr): - continue - for column, ctype, typeid in self.dbColumns: - if column.lower(column) == attr.lower(): - q = dbTypeMap.get(ctype, None) - if q == NOQUOTE: - setattr(self, attr, 0) - else: - setattr(self, attr, "") - - def setDirty(self, flag): - """Use this to set the 'dirty' flag. - - (note: this avoids infinite recursion in __setattr__, and - prevents the 'dirty' flag ) - """ - self.__dict__["dirty"] = flag - - def getKeyTuple(self): - keys = [] - keys.append(self.rowTableName) - for keyName, keyType in self.rowKeyColumns: - keys.append( getattr(self, keyName) ) - return tuple(keys) - - -__all__ = ['RowObject'] diff --git a/tools/buildbot/pylibs/twisted/enterprise/sqlreflector.py b/tools/buildbot/pylibs/twisted/enterprise/sqlreflector.py deleted file mode 100644 index d29d9fb..0000000 --- a/tools/buildbot/pylibs/twisted/enterprise/sqlreflector.py +++ /dev/null @@ -1,327 +0,0 @@ -# -*- test-case-name: twisted.test.test_reflector -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -from twisted.enterprise import reflector -from twisted.enterprise.util import DBError, getKeyColumn, quote, safe -from twisted.enterprise.util import _TableInfo -from twisted.enterprise.row import RowObject - -from twisted.python import reflect - -class SQLReflector(reflector.Reflector): - """ - DEPRECATED. - - I reflect on a database and load RowObjects from it. - - In order to do this, I interrogate a relational database to - extract schema information and interface with RowObject class - objects that can interact with specific tables. - """ - populated = 0 - conditionalLabels = { - reflector.EQUAL : "=", - reflector.LESSTHAN : "<", - reflector.GREATERTHAN : ">", - reflector.LIKE : "like" - } - - def __init__(self, dbpool, rowClasses): - """Initialize me against a database. - """ - reflector.Reflector.__init__(self, rowClasses) - self.dbpool = dbpool - - def _populate(self): - self._transPopulateSchema() - - def _transPopulateSchema(self): - """Used to construct the row classes in a single interaction. - """ - for rc in self.rowClasses: - if not issubclass(rc, RowObject): - raise DBError("Stub class (%s) is not derived from RowObject" % reflect.qual(rc.rowClass)) - - self._populateSchemaFor(rc) - self.populated = 1 - - def _populateSchemaFor(self, rc): - """Construct all the SQL templates for database operations on - and populate the class with that info. - """ - attributes = ("rowColumns", "rowKeyColumns", "rowTableName" ) - for att in attributes: - if not hasattr(rc, att): - raise DBError("RowClass %s must have class variable: %s" % (rc, att)) - - tableInfo = _TableInfo(rc) - tableInfo.updateSQL = self.buildUpdateSQL(tableInfo) - tableInfo.insertSQL = self.buildInsertSQL(tableInfo) - tableInfo.deleteSQL = self.buildDeleteSQL(tableInfo) - self.populateSchemaFor(tableInfo) - - def escape_string(self, text): - """Escape a string for use in an SQL statement. The default - implementation escapes ' with '' and \ with \\. Redefine this - function in a subclass if your database server uses different - escaping rules. - """ - return safe(text) - - def quote_value(self, value, type): - """Format a value for use in an SQL statement. - - @param value: a value to format as data in SQL. - @param type: a key in util.dbTypeMap. - """ - return quote(value, type, string_escaper=self.escape_string) - - def loadObjectsFrom(self, tableName, parentRow=None, data=None, - whereClause=None, forceChildren=0): - """Load a set of RowObjects from a database. - - Create a set of python objects of from the contents - of a table populated with appropriate data members. - Example:: - - | class EmployeeRow(row.RowObject): - | pass - | - | def gotEmployees(employees): - | for emp in employees: - | emp.manager = "fred smith" - | manager.updateRow(emp) - | - | reflector.loadObjectsFrom("employee", - | data = userData, - | whereClause = [("manager" , EQUAL, "fred smith")] - | ).addCallback(gotEmployees) - - NOTE: the objects and all children should be loaded in a single transaction. - NOTE: can specify a parentRow _OR_ a whereClause. - - """ - if parentRow and whereClause: - raise DBError("Must specify one of parentRow _OR_ whereClause") - if parentRow: - info = self.getTableInfo(parentRow) - relationship = info.getRelationshipFor(tableName) - whereClause = self.buildWhereClause(relationship, parentRow) - elif whereClause: - pass - else: - whereClause = [] - return self.dbpool.runInteraction(self._rowLoader, tableName, - parentRow, data, whereClause, - forceChildren) - - def _rowLoader(self, transaction, tableName, parentRow, data, - whereClause, forceChildren): - """immediate loading of rowobjects from the table with the whereClause. - """ - tableInfo = self.schema[tableName] - # Build the SQL for the query - sql = "SELECT " - first = 1 - for column, type in tableInfo.rowColumns: - if first: - first = 0 - else: - sql = sql + "," - sql = sql + " %s" % column - sql = sql + " FROM %s " % (tableName) - if whereClause: - sql += " WHERE " - first = 1 - for wItem in whereClause: - if first: - first = 0 - else: - sql += " AND " - (columnName, cond, value) = wItem - t = self.findTypeFor(tableName, columnName) - quotedValue = self.quote_value(value, t) - sql += "%s %s %s" % (columnName, self.conditionalLabels[cond], - quotedValue) - - # execute the query - transaction.execute(sql) - rows = transaction.fetchall() - - # construct the row objects - results = [] - newRows = [] - for args in rows: - kw = {} - for i in range(0,len(args)): - ColumnName = tableInfo.rowColumns[i][0].lower() - for attr, type in tableInfo.rowClass.rowColumns: - if attr.lower() == ColumnName: - kw[attr] = args[i] - break - # find the row in the cache or add it - resultObject = self.findInCache(tableInfo.rowClass, kw) - if not resultObject: - meth = tableInfo.rowFactoryMethod[0] - resultObject = meth(tableInfo.rowClass, data, kw) - self.addToCache(resultObject) - newRows.append(resultObject) - results.append(resultObject) - - # add these rows to the parentRow if required - if parentRow: - self.addToParent(parentRow, newRows, tableName) - - # load children or each of these rows if required - for relationship in tableInfo.relationships: - if not forceChildren and not relationship.autoLoad: - continue - for row in results: - # build where clause - childWhereClause = self.buildWhereClause(relationship, row) - # load the children immediately, but do nothing with them - self._rowLoader(transaction, - relationship.childRowClass.rowTableName, - row, data, childWhereClause, forceChildren) - - return results - - def findTypeFor(self, tableName, columnName): - tableInfo = self.schema[tableName] - columnName = columnName.lower() - for column, type in tableInfo.rowColumns: - if column.lower() == columnName: - return type - - def buildUpdateSQL(self, tableInfo): - """(Internal) Build SQL template to update a RowObject. - - Returns: SQL that is used to contruct a rowObject class. - """ - sql = "UPDATE %s SET" % tableInfo.rowTableName - # build update attributes - first = 1 - for column, type in tableInfo.rowColumns: - if getKeyColumn(tableInfo.rowClass, column): - continue - if not first: - sql = sql + ", " - sql = sql + " %s = %s" % (column, "%s") - first = 0 - - # build where clause - first = 1 - sql = sql + " WHERE " - for keyColumn, type in tableInfo.rowKeyColumns: - if not first: - sql = sql + " AND " - sql = sql + " %s = %s " % (keyColumn, "%s") - first = 0 - return sql - - def buildInsertSQL(self, tableInfo): - """(Internal) Build SQL template to insert a new row. - - Returns: SQL that is used to insert a new row for a rowObject - instance not created from the database. - """ - sql = "INSERT INTO %s (" % tableInfo.rowTableName - # build column list - first = 1 - for column, type in tableInfo.rowColumns: - if not first: - sql = sql + ", " - sql = sql + column - first = 0 - - sql = sql + " ) VALUES (" - - # build values list - first = 1 - for column, type in tableInfo.rowColumns: - if not first: - sql = sql + ", " - sql = sql + "%s" - first = 0 - - sql = sql + ")" - return sql - - def buildDeleteSQL(self, tableInfo): - """Build the SQL template to delete a row from the table. - """ - sql = "DELETE FROM %s " % tableInfo.rowTableName - # build where clause - first = 1 - sql = sql + " WHERE " - for keyColumn, type in tableInfo.rowKeyColumns: - if not first: - sql = sql + " AND " - sql = sql + " %s = %s " % (keyColumn, "%s") - first = 0 - return sql - - def updateRowSQL(self, rowObject): - """Build SQL to update the contents of rowObject. - """ - args = [] - tableInfo = self.schema[rowObject.rowTableName] - # build update attributes - for column, type in tableInfo.rowColumns: - if not getKeyColumn(rowObject.__class__, column): - args.append(self.quote_value(rowObject.findAttribute(column), - type)) - # build where clause - for keyColumn, type in tableInfo.rowKeyColumns: - args.append(self.quote_value(rowObject.findAttribute(keyColumn), - type)) - - return self.getTableInfo(rowObject).updateSQL % tuple(args) - - def updateRow(self, rowObject): - """Update the contents of rowObject to the database. - """ - sql = self.updateRowSQL(rowObject) - rowObject.setDirty(0) - return self.dbpool.runOperation(sql) - - def insertRowSQL(self, rowObject): - """Build SQL to insert the contents of rowObject. - """ - args = [] - tableInfo = self.schema[rowObject.rowTableName] - # build values - for column, type in tableInfo.rowColumns: - args.append(self.quote_value(rowObject.findAttribute(column),type)) - return self.getTableInfo(rowObject).insertSQL % tuple(args) - - def insertRow(self, rowObject): - """Insert a new row for rowObject. - """ - rowObject.setDirty(0) - sql = self.insertRowSQL(rowObject) - return self.dbpool.runOperation(sql) - - def deleteRowSQL(self, rowObject): - """Build SQL to delete rowObject from the database. - """ - args = [] - tableInfo = self.schema[rowObject.rowTableName] - # build where clause - for keyColumn, type in tableInfo.rowKeyColumns: - args.append(self.quote_value(rowObject.findAttribute(keyColumn), - type)) - - return self.getTableInfo(rowObject).deleteSQL % tuple(args) - - def deleteRow(self, rowObject): - """Delete the row for rowObject from the database. - """ - sql = self.deleteRowSQL(rowObject) - self.removeFromCache(rowObject) - return self.dbpool.runOperation(sql) - - -__all__ = ['SQLReflector'] diff --git a/tools/buildbot/pylibs/twisted/enterprise/util.py b/tools/buildbot/pylibs/twisted/enterprise/util.py deleted file mode 100644 index e75b92f..0000000 --- a/tools/buildbot/pylibs/twisted/enterprise/util.py +++ /dev/null @@ -1,200 +0,0 @@ -# -*- test-case-name: twisted.test.test_enterprise -*- -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -import warnings, types - -from twisted.python.versions import Version, getVersionString -from twisted.python.deprecate import deprecated -from twisted.enterprise.adbapi import _safe - -# Common deprecation decorator used for all deprecations. -_deprecatedVersion = Version("Twisted", 8, 0, 0) -_releasedDeprecation = deprecated(_deprecatedVersion) - -warnings.warn( - "twisted.enterprise.util is deprecated since %s." % ( - getVersionString(_deprecatedVersion),), - category=DeprecationWarning) - -NOQUOTE = 1 -USEQUOTE = 2 - -dbTypeMap = { - "bigint": NOQUOTE, - "bool": USEQUOTE, - "boolean": USEQUOTE, - "bytea": USEQUOTE, - "date": USEQUOTE, - "int2": NOQUOTE, - "int4": NOQUOTE, - "int8": NOQUOTE, - "int": NOQUOTE, - "integer": NOQUOTE, - "float4": NOQUOTE, - "float8": NOQUOTE, - "numeric": NOQUOTE, - "real": NOQUOTE, - "smallint": NOQUOTE, - "char": USEQUOTE, - "text": USEQUOTE, - "time": USEQUOTE, - "timestamp": USEQUOTE, - "varchar": USEQUOTE - } - -class DBError(Exception): - pass - - - -### Utility functions - -def getKeyColumn(rowClass, name): - lcname = name.lower() - for keyColumn, type in rowClass.rowKeyColumns: - if lcname == keyColumn.lower(): - return name - return None -getKeyColumn = _releasedDeprecation(getKeyColumn) - - - -def quote(value, typeCode, string_escaper=_safe): - """Add quotes for text types and no quotes for integer types. - NOTE: uses Postgresql type codes. - """ - q = dbTypeMap.get(typeCode, None) - if q is None: - raise DBError("Type %s not known" % typeCode) - if value is None: - return 'null' - if q == NOQUOTE: - return str(value) - elif q == USEQUOTE: - if typeCode.startswith('bool'): - if value: - value = '1' - else: - value = '0' - if typeCode == "bytea": - l = ["'"] - for c in value: - i = ord(c) - if i == 0: - l.append("\\\\000") - elif i == 92: - l.append(c * 4) - elif 32 <= i <= 126: - l.append(c) - else: - l.append("\\%03o" % i) - l.append("'") - return "".join(l) - if not isinstance(value, types.StringType) and \ - not isinstance(value, types.UnicodeType): - value = str(value) - return "'%s'" % string_escaper(value) -quote = _releasedDeprecation(quote) - - -def safe(text): - """ - Make a string safe to include in an SQL statement. - """ - return _safe(text) - -safe = _releasedDeprecation(safe) - - -def makeKW(rowClass, args): - """Utility method to construct a dictionary for the attributes - of an object from set of args. This also fixes the case of column names. - """ - kw = {} - for i in range(0,len(args)): - columnName = rowClass.dbColumns[i][0].lower() - for attr in rowClass.rowColumns: - if attr.lower() == columnName: - kw[attr] = args[i] - break - return kw -makeKW = _releasedDeprecation(makeKW) - - -def defaultFactoryMethod(rowClass, data, kw): - """Used by loadObjects to create rowObject instances. - """ - newObject = rowClass() - newObject.__dict__.update(kw) - return newObject -defaultFactoryMethod = _releasedDeprecation(defaultFactoryMethod) - -### utility classes - -class _TableInfo: - """(internal) - - Info about a table/class and it's relationships. Also serves as a container for - generated SQL. - """ - def __init__(self, rc): - self.rowClass = rc - self.rowTableName = rc.rowTableName - self.rowKeyColumns = rc.rowKeyColumns - self.rowColumns = rc.rowColumns - - if hasattr(rc, "rowForeignKeys"): - self.rowForeignKeys = rc.rowForeignKeys - else: - self.rowForeignKeys = [] - - if hasattr(rc, "rowFactoryMethod"): - if rc.rowFactoryMethod: - self.rowFactoryMethod = rc.rowFactoryMethod - else: - self.rowFactoryMethod = [defaultFactoryMethod] - else: - self.rowFactoryMethod = [defaultFactoryMethod] - - self.updateSQL = None - self.deleteSQL = None - self.insertSQL = None - self.relationships = [] - self.dbColumns = [] - - def addForeignKey(self, childColumns, parentColumns, childRowClass, containerMethod, autoLoad): - """This information is attached to the "parent" table - childColumns - columns of the "child" table - parentColumns - columns of the "parent" table, the one being joined to... the "foreign" table - """ - self.relationships.append( _TableRelationship(childColumns, parentColumns, - childRowClass, containerMethod, autoLoad) ) - - def getRelationshipFor(self, tableName): - for relationship in self.relationships: - if relationship.childRowClass.rowTableName == tableName: - return relationship - return None - -class _TableRelationship: - """(Internal) - - A foreign key relationship between two tables. - """ - def __init__(self, - childColumns, - parentColumns, - childRowClass, - containerMethod, - autoLoad): - self.childColumns = childColumns - self.parentColumns = parentColumns - self.childRowClass = childRowClass - self.containerMethod = containerMethod - self.autoLoad = autoLoad - - -__all__ = ['NOQUOTE', 'USEQUOTE', 'dbTypeMap', 'DBError', 'getKeyColumn', - 'safe', 'quote'] diff --git a/tools/buildbot/pylibs/twisted/flow/__init__.py b/tools/buildbot/pylibs/twisted/flow/__init__.py deleted file mode 100644 index 0b60907..0000000 --- a/tools/buildbot/pylibs/twisted/flow/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -# Author: Clark C. Evans - -""" -Twisted Flow: Generator support for data flows - -This package is unmaintained. It does not represent current best practices -for development with Twisted. Use it with this in mind. -""" - -__version__ = 'SVN-Trunk' - -import warnings -warnings.warn("twisted.flow is unmaintained.", DeprecationWarning, 2) diff --git a/tools/buildbot/pylibs/twisted/flow/_version.py b/tools/buildbot/pylibs/twisted/flow/_version.py deleted file mode 100644 index 2a88056..0000000 --- a/tools/buildbot/pylibs/twisted/flow/_version.py +++ /dev/null @@ -1,3 +0,0 @@ -# This is an auto-generated file. Do not edit it. -from twisted.python import versions -version = versions.Version('twisted.flow', 8, 0, 0) diff --git a/tools/buildbot/pylibs/twisted/flow/base.py b/tools/buildbot/pylibs/twisted/flow/base.py deleted file mode 100644 index aa8cc4c..0000000 --- a/tools/buildbot/pylibs/twisted/flow/base.py +++ /dev/null @@ -1,213 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -# Author: Clark Evans (cce@clarkevans.com) -# -""" -flow.base - -This module contains the core exceptions and base classes in the flow module. -See flow.flow for more detailed information -""" - -import twisted.python.compat -from twisted.internet import reactor -import time - -# -# Exceptions used within flow -# -class Unsupported(NotImplementedError): - """ Indicates that the given stage does not know what to do - with the flow instruction that was returned. - """ - def __init__(self, inst): - msg = "Unsupported flow instruction: %s " % repr(inst) - TypeError.__init__(self,msg) - -class NotReadyError(RuntimeError): - """ Raised when a stage has not been subject to a yield """ - pass - -# -# Abstract/Base Classes -# - -class Instruction: - """ Has special meaning when yielded in a flow """ - pass - -class Controller: - """ - Flow controller - - At the base of every flow, is a controller class which interprets the - instructions, especially the CallLater instructions. This is primarly just - a marker class to denote which classes consume Instruction events. If a - controller cannot handle a particular instruction, it raises the - Unsupported exception. - """ - pass - -class CallLater(Instruction): - """ - Instruction to support callbacks - - This is the instruction which is returned during the yield of the _Deferred - and Callback stage. The underlying flow driver should call the 'callLater' - function with the callable to be executed after each callback. - """ - def callLater(self, callable): - pass - -class Cooperate(CallLater): - """ - Requests that processing be paused so other tasks can resume - - Yield this object when the current chain would block or periodically during - an intensive processing task. The flow mechanism uses these objects to - signal that the current processing chain should be paused and resumed - later. This allows other delayed operations to be processed, etc. Usage - is quite simple:: - - # within some generator wrapped by a Controller - yield Cooperate(1) # yield for a second or more - - """ - def __init__(self, timeout = 0): - self.timeout = timeout - def callLater(self, callable): - reactor.callLater(self.timeout, callable) - -class Stage(Instruction): - """ - Abstract base defining protocol for iterator/generators in a flow - - This is the primary component in the flow system, it is an iterable object - which must be passed to a yield statement before each call to next(). - Usage:: - - iterable = DerivedStage( ... , SpamError, EggsError)) - yield iterable - for result in iterable: - # handle good result, or SpamError or EggsError - yield iterable - - Alternatively, when inside a generator, the next() method can be used - directly. In this case, if no results are available, StopIteration is - raised, and if left uncaught, will nicely end the generator. Of course, - unexpected failures are raised. This technique is especially useful when - pulling from more than one stage at a time. For example:: - - def someGenerator(): - iterable = SomeStage( ... , SpamError, EggsError) - while True: - yield iterable - result = iterable.next() - # handle good result or SpamError or EggsError - - For many generators, the results become available in chunks of rows. While - the default value is to get one row at a time, there is a 'chunked' - property which allows them to be returned via the next() method as many - rows rather than row by row. For example:: - - iterable = DerivedStage(...) - iterable.chunked = True - for results in iterable: - for result in results: - # handle good result - yield iterable - - For those wishing more control at the cost of a painful experience, the - following member variables can be used to great effect:: - - - results: This is a list of results produced by the generator, they - can be fetched one by one using next() or in a group - together. If no results were produced, then this is an - empty list. These results should be removed from the list - after they are read; or, after reading all of the results - set to an empty list - - - stop: This is true if the underlying generator has finished execution - (raised a StopIteration or returned). Note that several - results may exist, and stop may be true. - - - failure: If the generator produced an exception, then it is wrapped - as a Failure object and put here. Note that several results - may have been produced before the failure. To ensure that - the failure isn't accidently reported twice, it is - adviseable to set stop to True. - - The order in which these member variables is used is *critical* for - proper adherance to the flow protocol. First, all successful - results should be handled. Second, the iterable should be checked - to see if it is finished. Third, a failure should be checked; - while handling a failure, either the loop should be exited, or - the iterable's stop member should be set. For example:: - - iterable = SomeStage(...) - while True: - yield iterable - if iterable.results: - for result in iterable.results: - # handle good result - iterable.results = [] - if iterable.stop: - break - if iterable.failure: - iterable.stop = True - # handle iterable.failure - break - """ - def __init__(self, *trap): - self._trap = trap - self.stop = False - self.failure = None - self.results = [] - self.chunked = False - - def __iter__(self): - return self - - def next(self): - """ - return current result - - This is the primary function to be called to retrieve the current - result. It complies with the iterator protocol by raising - StopIteration when the stage is complete. It also raises an exception - if it is called before the stage is yielded. - """ - if self.results: - if self.chunked: - ret = self.results - self.results = [] - return ret - else: - return self.results.pop(0) - if self.stop: - raise StopIteration() - - if self.failure: - self.stop = True - - cr = self.failure.check(*self._trap) - - if cr: - return cr - - self.failure.raiseException() - - raise NotReadyError("Must 'yield' this object before calling next()") - - def _yield(self): - """ - executed during a yield statement by previous stage - - This method is private within the scope of the flow module, it is used - by one stage in the flow to ask a subsequent stage to produce its - value. The result of the yield is then stored in self.result and is an - instance of Failure if a problem occurred. - """ - raise NotImplementedError diff --git a/tools/buildbot/pylibs/twisted/flow/controller.py b/tools/buildbot/pylibs/twisted/flow/controller.py deleted file mode 100644 index 303d51d..0000000 --- a/tools/buildbot/pylibs/twisted/flow/controller.py +++ /dev/null @@ -1,101 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -# Author: Clark Evans (cce@clarkevans.com) -# - -""" -flow.controller - -This implements the various flow controllers, that is, those things which run -the flow stack. -""" - -from base import * -from wrap import wrap -from twisted.internet import defer - -class Block(Controller,Stage): - """ - A controller which blocks on Cooperate events - - This converts a Stage into an iterable which can be used directly in python - for loops and other iteratable constructs. It does this by eating any - Cooperate values and sleeping. This is largely helpful for testing or - within a threaded environment. It converts other stages into one which - does not emit cooperate events, ie:: - - [1,2, Cooperate(), 3] => [1,2,3] - """ - def __init__(self, stage, *trap): - Stage.__init__(self) - self._stage = wrap(stage,*trap) - self.block = time.sleep - - def next(self): - """ fetch the next value from the Stage flow """ - stage = self._stage - while True: - result = stage._yield() - if result: - if isinstance(result, Cooperate): - if result.__class__ == Cooperate: - self.block(result.timeout) - continue - raise Unsupported(result) - return stage.next() - -class Deferred(Controller, defer.Deferred): - """ - wraps up a Stage with a Deferred interface - - In this version, the results of the Stage are used to construct a list of - results and then sent to deferred. Further, in this version Cooperate is - implemented via reactor's callLater. - - For example:: - - from twisted.internet import reactor - from twisted.flow import flow - - def res(x): print x - d = flow.Deferred([1,2,3]) - d.addCallback(res) - reactor.iterate() - """ - def __init__(self, stage, *trap): - defer.Deferred.__init__(self) - self._results = [] - self._stage = wrap(stage, *trap) - self._execute() - - def results(self, results): - self._results.extend(results) - - def _execute(self, dummy = None): - cmd = self._stage - while True: - result = cmd._yield() - if cmd.results: - self.results(cmd.results) - cmd.results = [] - if cmd.stop: - if not self.called: - self.callback(self._results) - return - if cmd.failure: - cmd.stop = True - if cmd._trap: - error = cmd.failure.check(*cmd._trap) - if error: - self._results.append(error) - continue - self.errback(cmd.failure) - return - if result: - if isinstance(result, CallLater): - result.callLater(self._execute) - return - raise Unsupported(result) - diff --git a/tools/buildbot/pylibs/twisted/flow/flow.py b/tools/buildbot/pylibs/twisted/flow/flow.py deleted file mode 100644 index d750109..0000000 --- a/tools/buildbot/pylibs/twisted/flow/flow.py +++ /dev/null @@ -1,102 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -# Author: Clark Evans (cce@clarkevans.com) -# - -""" -flow -- asynchronous data flows using generators - -This module provides a mechanism for using async data flows through the use of -generators. The basic idea of flow is that when ever you require data from a -producer, you yield the producer. If the producer is ready, then you can call -producer.next() to fetch the incoming data. Otherwise, the underlying -controller will suspend the operation to try again later. - -For example, here is a simple 'printer' which consumes items from its source by -printing them. Note that to get a new item, it first yields the data source -and then calls source.next():: - - from __future__ import generators - from twisted.flow import flow - from twisted.internet import reactor, defer - - def printer(source): - source = flow.wrap(source) - while True: - yield source - print source.next() - - someFlowSource = [\"one\", flow.Cooperate(1), \"two\"] - - d = flow.Deferred(printer(someFlowSource)) - d.addCallback(lambda _: reactor.stop()) - reactor.run() - -In the example above, there are three objects imported from the flow module:: - - - flow.wrap converts many data sources such as lists, generators, and - deferreds, into a special instruction object, a Stage. In this case, a - simple list is wrapped. - - - flow.Deferred is a flow Controller which executes the stage passed to it, - aggregating all results into a list which is passed to the deferred's - callback. In this case, the result list is empty, but the callback is - used to stop the reactor after the printing has finished. - - - flow.Cooperate is a special instruction object which is used by the flow - Controller. In this case, the the flow pauses for one second between \"one\" - and \"two\". - - -Most classes in the flow module an Instruction, either a CallLater or a Stage. -A Stage instruction is used to wrap various sorts of producers, anything from a -simple string to Callback functions. Some stages can be constructed directly, -such as Zip, Concurrent, Merge, Callback, or Threaded. But in most cases, in -particular _String, _List, _Iterable, and _Deferred, state construction is -handled through the wrap function. Stages can yield other stages to build a -processing chain, results which are returned to the previous stage, or a -CallLater instruction which causes the whole operation to be suspended. - - -Typically, the CallLater instructions as passed up the call stack till the top -level, or Controller. The controller then typically returns control, but -registers itself to be called later. Once called again, the controller sets up -the call stack and resumes the top level generator. There is a special -CallLater, Cooperate, which simply resumes the chain of stages at a later time. -Some stages, Callback, _Deferred, and Threaded have their own special CallLater -which handles the process of resuming flow for their specific case. - -The inheritence hierarchy defined here looks like this:: - - Instruction - CallLater - Cooperate - Stage - # private stages (use flow.wrap) - _String - _List - _Iterable - _Deferred - # public stages - Map - Zip - Concurrent - Merge - Block - Callback* - Threaded* - Controller - Deferred - Block - Protocol - -""" - -from twisted.flow.base import * -from twisted.flow.stage import * -from twisted.flow.pipe import * -from twisted.flow.wrap import wrap -from twisted.flow.controller import Deferred, Block -from twisted.flow.protocol import makeProtocol, Protocol diff --git a/tools/buildbot/pylibs/twisted/flow/pipe.py b/tools/buildbot/pylibs/twisted/flow/pipe.py deleted file mode 100644 index 8b38e07..0000000 --- a/tools/buildbot/pylibs/twisted/flow/pipe.py +++ /dev/null @@ -1,112 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -# Author: Clark Evans (cce@clarkevans.com) - -""" -flow.pipe - -This contains various filter stages which have exactly one input stage. These -stages take a single input and modify its results, ie a rewrite stage. -""" - -from base import * -from wrap import wrap -from twisted.python.failure import Failure - -class Pipe(Stage): - """ abstract stage which takes a single input stage """ - def __init__(self, source, *trap): - Stage.__init__(self, *trap) - self._source = wrap(source) - - def _yield(self): - while not self.results \ - and not self.stop \ - and not self.failure: - source = self._source - instruction = source._yield() - if instruction: - return instruction - if source.failure: - self.failure = source.failure - return - results = source.results - stop = source.stop - if stop: - self.stop = True - source.results = [] - self.process(results, stop) - - def process(self, results): - """ process implemented by the pipe - - Take a set of possibly empty results and sets the member - variables: results, stop, or failure appropriately - """ - raise NotImplementedError - -class Filter(Pipe): - """ - flow equivalent to filter: Filter(function, source, ... ) - - Yield those elements from a source stage for which a function returns true. - If the function is None, the identity function is assumed, that is, all - items yielded that are false (zero or empty) are discarded. - - For example:: - - def odd(val): - if val % 2: - return True - - def range(): - yield 1 - yield 2 - yield 3 - yield 4 - - source = flow.Filter(odd,range) - printFlow(source) - """ - def __init__(self, func, source, *trap): - Pipe.__init__(self, source, *trap) - self._func = func - - def process(self, results, stop): - self.results.extend(filter(self._func,results)) - -class LineBreak(Pipe): - """ pipe stage which breaks its input into lines """ - def __init__(self, source, *trap, **kwargs): - Pipe.__init__(self, source, *trap) - self._delimiter = kwargs.get('delimiter','\r\n') - self._maxlen = int(kwargs.get('maxlength', 16384))+1 - self._trailer = int(kwargs.get('trailer',False)) - self._buffer = [] - self._currlen = 0 - - def process(self, results, stop): - for block in results: - lines = str(block).split(self._delimiter) - if len(lines) < 2: - tail = lines[0] - else: - tail = lines.pop() - if self._buffer: - self._buffer.append(lines.pop(0)) - self.results.append("".join(self._buffer)) - self._buffer = [] - self.results.extend(lines) - self._currlen = 0 - if tail: - self._currlen += len(tail) - self._buffer.append(tail) - if stop and self._buffer: - tail = "".join(self._buffer) - if self._trailer: - self.results.append(tail) - else: - raise RuntimeError, "trailing data remains: '%s'" % tail[:10] - diff --git a/tools/buildbot/pylibs/twisted/flow/protocol.py b/tools/buildbot/pylibs/twisted/flow/protocol.py deleted file mode 100644 index accad21..0000000 --- a/tools/buildbot/pylibs/twisted/flow/protocol.py +++ /dev/null @@ -1,151 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -# Author: Clark Evans (cce@clarkevans.com) -# - -""" -flow.protocol - -This allows one to use flow module to create protocols, a protocol is actually -a controller, but it is specialized enough to deserve its own module. -""" - -import types -from base import * -from wrap import wrap -from stage import Callback -from twisted.internet import protocol -from twisted.internet.error import ConnectionLost, ConnectionDone - -def makeProtocol(controller, baseClass = protocol.Protocol, - *callbacks, **kwargs): - """ - Construct a flow based protocol - - This takes a base protocol class, and a set of callbacks and creates a - connection flow based on the two. For example, the following would build a - simple 'echo' protocol:: - - from __future__ import generators - from twisted.internet import reactor, protocol - from twisted.flow import flow - PORT = 8392 - - def echoServer(conn): - yield conn - for data in conn: - conn.write(data) - yield conn - - def echoClient(conn): - conn.write("hello, world!") - yield conn - print "server said: ", conn.next() - reactor.callLater(0,reactor.stop) - - server = protocol.ServerFactory() - server.protocol = flow.makeProtocol(echoServer) - reactor.listenTCP(PORT,server) - client = protocol.ClientFactory() - client.protocol = flow.makeProtocol(echoClient) - reactor.connectTCP("localhost", PORT, client) - reactor.run() - - Of course, the best part about flow is that you can nest stages. Therefore - it is quite easy to make a lineBreaker generator which takes an input - connection and produces and output connection. Anyway, the code is almost - identical as far as the client/server is concerned:: - - # this is a filter generator, it consumes from the - # incoming connection, and yields results to - # the next stage, the echoServer below - def lineBreaker(conn, lineEnding = "\\n"): - lst = [] - yield conn - for chunk in conn: - pos = chunk.find(lineEnding) - if pos > -1: - lst.append(chunk[:pos]) - yield "".join(lst) - lst = [chunk[pos+1:]] - else: - lst.append(chunk) - yield conn - yield "".join(lst) - - # note that this class is only slightly modified, - # simply comment out the line breaker line to see - # how the server behaves without the filter... - def echoServer(conn): - lines = flow.wrap(lineBreaker(conn)) - yield lines - for data in lines: - conn.write(data) - yield lines - - # and the only thing that is changed is that we - # are sending data in strange chunks, and even - # putting the last chunk on hold for 2 seconds. - def echoClient(conn): - conn.write("Good Morning!\\nPlease ") - yield conn - print "server said: ", conn.next() - conn.write("do not disregard ") - reactor.callLater(2, conn.write, "this.\\n") - yield conn - print "server said: ", conn.next() - reactor.callLater(0,reactor.stop) - """ - if not callbacks: - callbacks = ('dataReceived',) - trap = kwargs.get("trap", tuple()) - class _Protocol(Controller, Callback, baseClass): - def __init__(self): - Callback.__init__(self, *trap) - setattr(self, callbacks[0], self) - # TODO: support more than one callback via Concurrent - def _execute(self, dummy = None): - cmd = self._controller - self.write = self.transport.write - while True: - instruction = cmd._yield() - if instruction: - if isinstance(instruction, CallLater): - instruction.callLater(self._execute) - return - raise Unsupported(instruction) - if cmd.stop: - self.transport.loseConnection() - return - if cmd.failure: - self.transport.loseConnection() - cmd.failure.trap() - return - if cmd.results: - self.transport.writeSequence(cmd.results) - cmd.results = [] - def connectionMade(self): - if types.ClassType == type(self.controller): - self._controller = wrap(self.controller(self)) - else: - self._controller = wrap(self.controller()) - self._execute() - def connectionLost(self, reason=protocol.connectionDone): - if isinstance(reason.value, ConnectionDone) or \ - (isinstance(reason.value, ConnectionLost) and \ - self.finishOnConnectionLost): - self.finish() - else: - self.errback(reason) - self._execute() - _Protocol.finishOnConnectionLost = kwargs.get("finishOnConnectionLost",True) - _Protocol.controller = controller - return _Protocol - -def _NotImplController(protocol): - raise NotImplementedError -Protocol = makeProtocol(_NotImplController) -Protocol.__doc__ = """ A concrete flow.Protocol for inheritance """ - diff --git a/tools/buildbot/pylibs/twisted/flow/stage.py b/tools/buildbot/pylibs/twisted/flow/stage.py deleted file mode 100644 index 86cf79f..0000000 --- a/tools/buildbot/pylibs/twisted/flow/stage.py +++ /dev/null @@ -1,239 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -# Author: Clark Evans (cce@clarkevans.com) -# - -""" -flow.stage - -Various stages for manipulating data flows, in particular, those stages which -take more than one input stages or alternative input, such as a callback. -""" - -from base import * -from wrap import wrap -from twisted.python.failure import Failure - -class Map(Stage): - """ - flow equivalent to map: Map(function, stage, ... ) - - Apply a function to every item yielded and yield the results. If - additional stages are passed, the function must take that many arguments - and is applied to the items of all lists in parallel. If a list is shorter - than another, it is assumed to be extended with None items. If the - function is None, the identity function is assumed; if there are multiple - list arguments, Map stage returns a sequence consisting of tuples - containing the corresponding items from all lists. - - For example:: - - def fn(val): - return val + 10 - - source = flow.Map(fn,range(4)) - printFlow(source) - """ - def __init__(self, func, stage, *stages): - Stage.__init__(self) - self.func = func - self._stage = [wrap(stage)] - for stage in stages: - self._stage.append(wrap(stage)) - self._index = 0 - - def _yield(self): - if self.results or self.stop or self.failure: - return - if not self._index: - self._curr = [] - self._done = True - while self._index < len(self._stage): - idx = self._index - curr = self._stage[idx] - instruction = curr._yield() - if instruction: - return instruction - if curr.results: - self._curr.append(curr.results.pop(0)) - self._index += 1 - self._done = False - continue - if curr.stop: - self._curr.append(None) - self._index += 1 - continue - if curr.failure: - self.failure = curr.failure - return - raise AssertionError("flow.Map ; no results, stop or failure?") - if self._done: - self.stop = 1 - return - curr = tuple(self._curr) - if self.func: - try: - curr = self.func(*curr) - except Failure, fail: - self.failure = fail - return - except: - self.failure = Failure() - return - self.results.append(curr) - self._index = 0 - -class Zip(Map): - """ - Zips two or more stages into a stream of N tuples - - For example:: - - source = flow.Zip([1,flow.Cooperate(),2,3],["one","two"]) - printFlow(source) - - """ - def __init__(self, *stages): - Map.__init__(self, None, stages[0], *stages[1:]) - -class Concurrent(Stage): - """ - Executes stages concurrently - - This stage allows two or more stages (branches) to be executed at the same - time. It returns each stage as it becomes available. This can be used if - you have N callbacks, and you want to yield and wait for the first - available one that produces results. Once a stage is retuned, its next() - method should be used to extract the value for the stage. - """ - - class Instruction(CallLater): - def __init__(self, inst): - self.inst = inst - def callLater(self, callable): - for inst in self.inst: - inst.callLater(callable) - - def __init__(self, *stages): - Stage.__init__(self) - self._stages = [] - for stage in stages: - self._stages.append(wrap(stage)) - - def _yield(self): - if self.results or self.stop or self.failure: - return - stages = self._stages - later = [] - exit = None - while stages: - if stages[0] is exit: - if self.results: - return - break - curr = stages.pop(0) - instruction = curr._yield() - if curr.results: - self.results.append(curr) - if curr.failure: - self.failure = curr.failure - return - if curr.stop: - exit = None - if self.results: - return - continue - stages.append(curr) - if not exit: - exit = curr - if instruction: - if isinstance(instruction, CallLater): - if instruction not in later: - later.append(instruction) - continue - raise Unsupported(instruction) - if later: - return Concurrent.Instruction(later) - self.stop = True - -class Merge(Stage): - """ - Merges two or more Stages results into a single stream - - For example:: - - source = flow.Zip([1,flow.Cooperate(),2,3],["one","two"]) - printFlow(source) - """ - def __init__(self, *stages): - Stage.__init__(self) - self.concurrent = Concurrent(*stages) - - def _yield(self): - if self.results or self.stop or self.failure: - return - instruction = self.concurrent._yield() - if instruction: - return instruction - for stage in self.concurrent.results: - self.results.extend(stage.results) - stage.results = [] - self.concurrent.results = [] - if self.concurrent.stop: - self.stop = True - self.failure = self.concurrent.failure - -class Callback(Stage): - """ - Converts a single-thread push interface into a pull interface. - - Once this stage is constructed, its result, errback, and finish member - variables may be called by a producer. The results of which can be - obtained by yielding the Callback and then calling next(). - - For example:: - - source = flow.Callback() - reactor.callLater(0, lambda: source.result("one")) - reactor.callLater(.5, lambda: source.result("two")) - reactor.callLater(1, lambda: source.finish()) - printFlow(source) - - """ - # TODO: Potentially rename this 'Consumer' and make it - # comply with protocols.IConsumer - # TODO: Make the inverse stage, which is an IProducer - class Instruction(CallLater): - def __init__(self): - self.flow = lambda: True - def callLater(self, callable): - self.flow = callable - def __init__(self, *trap): - Stage.__init__(self, *trap) - self._finished = False - self._cooperate = Callback.Instruction() - def result(self,result): - """ called by the producer to indicate a successful result """ - self.results.append(result) - self._cooperate.flow() - def finish(self): - """ called by producer to indicate successful stream completion """ - assert not self.failure, "failed streams should not be finished" - self._finished = True - self._cooperate.flow() - def errback(self, fail): - """ called by the producer in case of Failure """ - self.failure = fail - self._cooperate.flow() - def _yield(self): - if self.results or self.stop or self.failure: - return - if not self.results: - if self._finished: - self.stop = True - return - return self._cooperate - __call__ = result - diff --git a/tools/buildbot/pylibs/twisted/flow/test/__init__.py b/tools/buildbot/pylibs/twisted/flow/test/__init__.py deleted file mode 100644 index 24b6c6c..0000000 --- a/tools/buildbot/pylibs/twisted/flow/test/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"flow tests" diff --git a/tools/buildbot/pylibs/twisted/flow/test/test_flow.py b/tools/buildbot/pylibs/twisted/flow/test/test_flow.py deleted file mode 100644 index e364a93..0000000 --- a/tools/buildbot/pylibs/twisted/flow/test/test_flow.py +++ /dev/null @@ -1,491 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -# Author: Clark C. Evans -# - -from __future__ import nested_scopes -from __future__ import generators - -from twisted.flow import flow -from twisted.flow.threads import Threaded, QueryIterator -from twisted.trial import unittest -from twisted.python import failure -from twisted.internet import defer, reactor, protocol, interfaces -from time import sleep - -class slowlist: - """ this is a generator based list - - def slowlist(list): - list = list[:] - while list: - yield list.pop(0) - - It is primarly used to simulate generators by using - a list (for testing purposes) without being wrapped - as a flow.List, which has all kinds of shortcuts we - don't want for testing. - """ - def __init__(self, list): - self.list = list[:] - def __iter__(self): - return self - def next(self): - if self.list: - return self.list.pop(0) - raise StopIteration - -_onetwothree = ['one','two',flow.Cooperate(),'three'] - -class producer: - """ iterator version of the following generator... - - def producer(): - lst = flow.wrap(slowlist([1,2,3])) - nam = flow.wrap(slowlist(_onetwothree)) - while True: - yield lst - yield nam - yield (lst.next(),nam.next()) - - """ - def __iter__(self): - self.lst = flow.wrap(slowlist([1,2,3])) - self.nam = flow.wrap(slowlist(_onetwothree)) - self.next = self.yield_lst - return self - def yield_lst(self): - self.next = self.yield_nam - return self.lst - def yield_nam(self): - self.next = self.yield_results - return self.nam - def yield_results(self): - self.next = self.yield_lst - return (self.lst.next(), self.nam.next()) - -class consumer: - """ iterator version of the following generator... - - def consumer(): - title = flow.wrap(['Title']) - prod = flow.wrap(producer()) - yield title - yield title.next() - yield prod - for data in prod: - yield data - yield prod - """ - def __iter__(self): - self.title = flow.wrap(['Title']) - self.lst = flow.wrap(producer()) - self.next = self.yield_title - return self - def yield_title(self): - self.next = self.yield_title_result - return self.title - def yield_title_result(self): - self.next = self.yield_lst - return self.title.next() - def yield_lst(self): - self.next = self.yield_result - return self.lst - def yield_result(self): - self.next = self.yield_lst - return self.lst.next() - - -class badgen: - """ a bad generator... - - def badgen(): - yield 'x' - err = 3/ 0 - """ - def __iter__(self): - self.next = self.yield_x - return self - def yield_x(self): - self.next = self.yield_done - return 'x' - def yield_done(self): - err = 3 / 0 - raise StopIteration - -class buildlist: - """ building a list - - def buildlist(src): - out = [] - yield src - for itm in src: - out.append(itm) - yield src - yield out - """ - def __init__(self, src): - self.src = src - def __iter__(self): - self.out = [] - self.next = self.yield_src - return self - def yield_src(self): - self.next = self.yield_append - return self.src - def yield_append(self): - try: - self.out.append(self.src.next()) - except StopIteration: - self.next = self.yield_finish - return self.out - return self.src - def yield_finish(self): - raise StopIteration - -class testconcur: - """ interweving two concurrent stages - - def testconcur(*stages): - both = flow.Concurrent(*stages) - yield both - for stage in both: - yield (stage.name, stage.result) - yield both - """ - def __init__(self, *stages): - self.both = flow.Concurrent(*stages) - def __iter__(self): - self.next = self.yield_both - return self - def yield_both(self): - self.next = self.yield_result - return self.both - def yield_result(self): - self.next = self.yield_both - stage = self.both.next() - return (stage.name, stage.next()) - -class echoServer: - """ a simple echo protocol, server side - - def echoServer(conn): - yield conn - for data in conn: - yield data - yield conn - """ - def __init__(self, conn): - self.conn = conn - def __iter__(self): - self.next = self.yield_conn - return self - def yield_conn(self): - self.next = self.yield_data - return self.conn - def yield_data(self): - self.next = self.yield_conn - return self.conn.next() - -class echoClient: - """ a simple echo client tester - - def echoClient(conn): - yield "testing" - yield conn - # signal that we are done - conn.d.callback(conn.next()) - """ - def __init__(self, conn): - self.conn = conn - def __iter__(self): - self.next = self.yield_testing - return self - def yield_testing(self): - self.next = self.yield_conn - return "testing" - def yield_conn(self): - self.next = self.yield_stop - return self.conn - def yield_stop(self): - # signal that we are done - self.conn.factory.d.callback(self.conn.next()) - raise StopIteration() - -class CountIterator: - def __init__(self, count): - self.count = count - def __iter__(self): - return self - def next(self): # this is run in a separate thread - sleep(.1) - val = self.count - if not(val): - raise StopIteration - self.count -= 1 - return val - -class FlowTest(unittest.TestCase): - def testNotReady(self): - x = flow.wrap([1,2,3]) - self.assertRaises(flow.NotReadyError,x.next) - - def testBasic(self): - lhs = ['string'] - rhs = list(flow.Block('string')) - self.assertEqual(lhs,rhs) - - def testBasicList(self): - lhs = [1,2,3] - rhs = list(flow.Block([1,2,flow.Cooperate(),3])) - self.assertEqual(lhs,rhs) - - def testBasicIterator(self): - lhs = ['one','two','three'] - rhs = list(flow.Block(slowlist(_onetwothree))) - self.assertEqual(lhs,rhs) - - def testCallable(self): - lhs = ['one','two','three'] - rhs = list(flow.Block(slowlist(_onetwothree))) - self.assertEqual(lhs,rhs) - - def testProducer(self): - lhs = [(1,'one'),(2,'two'),(3,'three')] - rhs = list(flow.Block(producer())) - self.assertEqual(lhs,rhs) - - def testConsumer(self): - lhs = ['Title',(1,'one'),(2,'two'),(3,'three')] - rhs = list(flow.Block(consumer)) - self.assertEqual(lhs,rhs) - - def testFailure(self): - self.assertRaises(ZeroDivisionError, list, flow.Block(badgen())) - self.assertEqual(['x',ZeroDivisionError], - list(flow.Block(badgen(),ZeroDivisionError))) - self.assertEqual(['x',ZeroDivisionError], - list(flow.Block(flow.wrap(badgen()), - ZeroDivisionError))) - - def testZip(self): - lhs = [(1,'a'),(2,'b'),(3,None)] - mrg = flow.Zip([1,2,flow.Cooperate(),3],['a','b']) - rhs = list(flow.Block(mrg)) - self.assertEqual(lhs,rhs) - - def testMerge(self): - lhs = ['one', 1, 'two', 2, 3, 'three'] - mrg = flow.Merge(slowlist(_onetwothree),slowlist([1,2,3])) - rhs = list(flow.Block(mrg)) - self.assertEqual(lhs,rhs) - - def testFilter(self): - def odd(val): - if val % 2: - return True - lhs = [ 1, 3 ] - mrg = flow.Filter(odd,slowlist([1,2,flow.Cooperate(),3])) - rhs = list(flow.Block(mrg)) - self.assertEqual(lhs,rhs) - - def testLineBreak(self): - lhs = [ "Hello World", "Happy Days Are Here" ] - rhs = ["Hello ","World\nHappy", flow.Cooperate(), - " Days"," Are Here\n"] - mrg = flow.LineBreak(slowlist(rhs), delimiter='\n') - rhs = list(flow.Block(mrg)) - self.assertEqual(lhs,rhs) - - def testDeferred(self): - lhs = ['Title', (1,'one'),(2,'two'),(3,'three')] - d = flow.Deferred(consumer()) - d.addCallback(self.assertEquals, lhs) - return d - - def testBuildList(self): - src = flow.wrap([1,2,3]) - out = flow.Block(buildlist(src)).next() - self.assertEquals(out,[1,2,3]) - - def testDeferredFailure(self): - d = flow.Deferred(badgen()) - return self.assertFailure(d, ZeroDivisionError) - - def testDeferredTrap(self): - d = flow.Deferred(badgen(), ZeroDivisionError) - d.addCallback(self.assertEqual, ['x', ZeroDivisionError]) - return d - - def testZipFailure(self): - lhs = [(1,'a'),(2,'b'),(3,'c')] - mrg = flow.Zip([1,2,flow.Cooperate(),3],badgen()) - d = flow.Deferred(mrg) - return self.assertFailure(d, ZeroDivisionError) - - def testDeferredWrapper(self): - a = defer.Deferred() - reactor.callLater(0, lambda: a.callback("test")) - b = flow.Merge(a, slowlist([1,2,flow.Cooperate(),3])) - d = flow.Deferred(b) - d.addCallback(self.assertEqual, [1, 2, 'test', 3]) - return d - - def testDeferredWrapperImmediate(self): - from twisted.internet import defer - a = defer.Deferred() - a.callback("test") - self.assertEquals(["test"], list(flow.Block(a))) - - def testDeferredWrapperFail(self): - d = defer.Deferred() - f = lambda: d.errback(flow.Failure(IOError())) - reactor.callLater(0, f) - return self.assertFailure(d, IOError) - - def testCallback(self): - cb = flow.Callback() - d = flow.Deferred(buildlist(cb)) - for x in range(9): - cb.result(x) - cb.finish() - d.addCallback(self.assertEqual, [range(9)]) - return d - - def testCallbackFailure(self): - cb = flow.Callback() - d = flow.Deferred(buildlist(cb)) - for x in range(3): - cb.result(x) - cb.errback(flow.Failure(IOError())) - return self.assertFailure(d, IOError) - - def testConcurrentCallback(self): - ca = flow.Callback() - ca.name = 'a' - cb = flow.Callback() - cb.name = 'b' - d = flow.Deferred(testconcur(ca,cb)) - ca.result(1) - cb.result(2) - ca.result(3) - ca.result(4) - ca.finish() - cb.result(5) - cb.finish() - d.addCallback(self.assertEquals, - [('a',1),('b',2),('a',3),('a',4),('b',5)]) - return d - - def testProtocolLocalhost(self): - # this fails if parallel tests are run on the same box - server = protocol.ServerFactory() - server.protocol = flow.Protocol - server.protocol.controller = echoServer - port = reactor.listenTCP(0, server) - client = protocol.ClientFactory() - client.protocol = flow.makeProtocol(echoClient) - client.d = defer.Deferred() - reactor.connectTCP("127.0.0.1", port.getHost().port, client) - client.d.addCallback(self.assertEquals, 'testing') - client.d.addBoth(lambda x : - client.protocol.transport.loseConnection()) - client.d.addBoth(lambda x : - defer.maybeDeferred(port.stopListening)) - return client.d - #testProtocolLocalhost.skip = "XXX freezes, fixme" - - def testProtocol(self): - from twisted.protocols import loopback - server = flow.Protocol() - server.controller = echoServer - client = flow.makeProtocol(echoClient)() - client.factory = protocol.ClientFactory() - client.factory.d = defer.Deferred() - d2 = loopback.loopbackAsync(server, client) - client.factory.d.addCallback(self.assertEquals, 'testing') - return defer.gatherResults([client.factory.d, d2]) - - -class ThreadedFlowTest(unittest.TestCase): - if interfaces.IReactorThreads(reactor, None) is None: - skip = ("No thread support in reactor, " - "cannot test threaded flow constructs.") - - - def testThreaded(self): - expect = [5,4,3,2,1] - d = flow.Deferred(Threaded(CountIterator(5))) - d.addCallback(self.assertEquals, expect) - return d - - def testThreadedError(self): - # is this the expected behaviour? - def iterator(): - yield 1 - raise ValueError - d = flow.Deferred(Threaded(iterator())) - return self.assertFailure(d, ValueError) - - def testThreadedSleep(self): - expect = [5,4,3,2,1] - d = flow.Deferred(Threaded(CountIterator(5))) - sleep(.5) - d.addCallback(self.assertEquals, expect) - return d - - def testQueryIterator(self): - try: - from pyPgSQL import PgSQL - dbpool = PgSQL - c = dbpool.connect() - r = c.cursor() - r.execute("SELECT 'x'") - r.fetchone() - except: - # PostgreSQL is not installed or bad permissions - return - expect = [['one'],['two'],['three']] - sql = """ - (SELECT 'one') - UNION ALL - (SELECT 'two') - UNION ALL - (SELECT 'three') - """ - d = flow.Deferred(Threaded(QueryIterator(dbpool, sql))) - d.addCallback(self.assertEquals, expect) - return d - - def testThreadedImmediate(self): - """ - The goal of this test is to test the callback mechanism with - regard to threads, namely to assure that results can be - accumulated before they are needed; and that left-over results - are immediately made available on the next round (even though - the producing thread has shut down). This is a very tough thing - to test due to the timing issues. So it may fail on some - platforms, I'm not sure. - """ - expect = [5,4,3,2,1] - result = [] - f = Threaded(CountIterator(5)) - d = defer.Deferred() - def process(): - coop = f._yield() - if f.results: - result.extend(f.results) - del f.results[:len(result)] - reactor.callLater(0, process) - return - if coop: - sleep(.3) - reactor.callLater(0, coop.callLater, process) - return - if f.stop: - reactor.callLater(0, d.callback, result) - reactor.callLater(0, process) - d.addCallback(self.assertEquals, expect) - return d diff --git a/tools/buildbot/pylibs/twisted/flow/threads.py b/tools/buildbot/pylibs/twisted/flow/threads.py deleted file mode 100644 index b6a74fe..0000000 --- a/tools/buildbot/pylibs/twisted/flow/threads.py +++ /dev/null @@ -1,210 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -# Author: Clark Evans (cce@clarkevans.com) -# Stability: The API is stable, but the implementation may still -# have one or more bugs; threads are tough. -# - -""" flow.thread - - Support for threads within a flow -""" - -from __future__ import nested_scopes - -from base import * -from twisted.python.failure import Failure -from twisted.internet import reactor -from time import sleep - -class Threaded(Stage): - """ - A stage which runs a blocking iterable in a separate thread - - This stage tunnels output from an iterable executed in a separate thread to - the main thread. This process is carried out by a result buffer, and - returning Cooperate if the buffer is empty. The wrapped iterable's - __iter__ and next() methods will only be invoked in the spawned thread. - - This can be used in one of two ways, first, it can be extended via - inheritance; with the functionality of the inherited code implementing - next(), and using init() for initialization code to be run in the thread. - - If the iterable happens to have a chunked attribute, and that attribute is - true, then this wrapper will assume that data arrives in chunks via a - sequence instead of by values. - - For example:: - - from __future__ import generators - from twisted.internet import reactor, defer - from twisted.flow import flow - from twisted.flow.threads import Threaded - - def countSleep(index): - from time import sleep - for index in range(index): - sleep(.3) - print "sleep", index - yield index - - def countCooperate(index): - for index in range(index): - yield flow.Cooperate(.1) - print "cooperate", index - yield "coop %s" % index - - d = flow.Deferred( flow.Merge( - Threaded(countSleep(5)), - countCooperate(5))) - - def prn(x): - print x - reactor.stop() - d.addCallback(prn) - reactor.run() - """ - class Instruction(CallLater): - def __init__(self): - self.callable = None - self.immediate = False - def callLater(self, callable): - if self.immediate: - reactor.callLater(0,callable) - else: - self.callable = callable - def __call__(self): - callable = self.callable - if callable: - self.callable = None - callable() - - def __init__(self, iterable, *trap): - Stage.__init__(self, trap) - self._iterable = iterable - self._cooperate = Threaded.Instruction() - self.srcchunked = getattr(iterable, 'chunked', False) - reactor.callInThread(self._process) - - def _process_result(self, val): - if self.srcchunked: - self.results.extend(val) - else: - self.results.append(val) - self._cooperate() - - def _stopping(self): - self.stop = True - self._cooperate() - - def _process(self): - try: - self._iterable = iter(self._iterable) - except: - self.failure = Failure() - else: - try: - while True: - val = self._iterable.next() - reactor.callFromThread(self._process_result, val) - except StopIteration: - reactor.callFromThread(self._stopping) - except: - self.failure = Failure() - reactor.callFromThread(self._cooperate) - self._cooperate.immediate = True - - def _yield(self): - if self.results or self.stop or self.failure: - return - return self._cooperate - - -class QueryIterator: - """ - Converts a database query into a result iterator - - Example usage:: - - from __future__ import generators - from twisted.enterprise import adbapi - from twisted.internet import reactor - from twisted.flow import flow - from twisted.flow.threads import QueryIterator, Threaded - - dbpool = adbapi.ConnectionPool("SomeDriver",host='localhost', - db='Database',user='User',passwd='Password') - - # # I test with... - # from pyPgSQL import PgSQL - # dbpool = PgSQL - - sql = ''' - (SELECT 'one') - UNION ALL - (SELECT 'two') - UNION ALL - (SELECT 'three') - ''' - def consumer(): - print "executing" - query = Threaded(QueryIterator(dbpool, sql)) - print "yielding" - yield query - print "done yeilding" - for row in query: - print "Processed result : ", row - yield query - - from twisted.internet import reactor - def finish(result): - print "Deferred Complete : ", result - reactor.stop() - f = flow.Deferred(consumer()) - f.addBoth(finish) - reactor.run() - """ - - def __init__(self, pool, sql, fetchmany=False, fetchall=False): - self.curs = None - self.sql = sql - self.pool = pool - if fetchmany: - self.next = self.next_fetchmany - self.chunked = True - if fetchall: - self.next = self.next_fetchall - self.chunked = True - - def __iter__(self): - self.conn = self.pool.connect() - self.curs = self.conn.cursor() - self.curs.execute(self.sql) - return self - - def next_fetchall(self): - if self.curs: - ret = self.curs.fetchall() - self.curs = None - self.conn = None - return ret - raise StopIteration - - def next_fetchmany(self): - ret = self.curs.fetchmany() - if not ret: - self.curs = None - self.conn = None - raise StopIteration - return ret - - def next(self): - ret = self.curs.fetchone() - if not ret: - self.curs = None - self.conn = None - raise StopIteration - return ret - diff --git a/tools/buildbot/pylibs/twisted/flow/topfiles/README b/tools/buildbot/pylibs/twisted/flow/topfiles/README deleted file mode 100644 index de94edd..0000000 --- a/tools/buildbot/pylibs/twisted/flow/topfiles/README +++ /dev/null @@ -1,6 +0,0 @@ -Twisted Flow 8.0.0 - -Flow was recently split out of Twisted. - -Twisted Flow depends on twisted.web if you want to use the -twisted.flow.web module. diff --git a/tools/buildbot/pylibs/twisted/flow/topfiles/setup.py b/tools/buildbot/pylibs/twisted/flow/topfiles/setup.py deleted file mode 100644 index e319eab..0000000 --- a/tools/buildbot/pylibs/twisted/flow/topfiles/setup.py +++ /dev/null @@ -1,26 +0,0 @@ -import sys - -try: - from twisted.python import dist -except ImportError: - raise SystemExit("twisted.python.dist module not found. Make sure you " - "have installed the Twisted core package before " - "attempting to install any other Twisted projects.") - -if __name__ == '__main__': - dist.setup( - twisted_subproject="flow", - # metadata - name="Twisted Flow", - description="A Twisted concurrency programming library.", - author="Twisted Matrix Laboratories", - author_email="twisted-python@twistedmatrix.com", - maintainer="Clark Evans", - maintainer_email="cce@twistedmatrix.com", - url="http://twistedmatrix.com/trac/wiki/TwistedFlow", - license="MIT", - long_description="""\ -Twisted Flow aims to make asynchronous programming a easier, -using python generators. -""", - ) diff --git a/tools/buildbot/pylibs/twisted/flow/web.py b/tools/buildbot/pylibs/twisted/flow/web.py deleted file mode 100644 index d009cba..0000000 --- a/tools/buildbot/pylibs/twisted/flow/web.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -# Author: Clark Evans (cce@clarkevans.com) - -""" flow.web - - This contains wrappers to apply flow to components in twisted.web.* - -""" -from controller import Deferred -from twisted.web import resource, server -from twisted.python.failure import Failure - -class Resource(resource.Resource): - """ - A resource which uses flow in its page generation. - - Use it like this:: - - from __future__ import generators - from twisted.flow import flow - - def render(req): - req.write("Delayed") - req.write("

Delayed WebPage

") - yield flow.Cooperate(5) - req.write("

Delayed Content

") - - if __name__=='__main__': - from twisted.internet import reactor - from twisted.web.server import Site - from twisted.flow.web import Resource - print "visit http://localhost:8081/ to view" - reactor.listenTCP(8081,Site(Resource(render))) - reactor.run() - """ - def __init__(self, gen): - resource.Resource.__init__(self) - self.gen = gen - - def isLeaf(self): - return true - - def render(self, req): - self.d = Deferred(self.gen(req)) - self.d.addErrback(lambda fail: fail.printTraceback()) - self.d.addBoth(lambda ret: req.finish() or ret) - return server.NOT_DONE_YET diff --git a/tools/buildbot/pylibs/twisted/flow/wrap.py b/tools/buildbot/pylibs/twisted/flow/wrap.py deleted file mode 100644 index 3a55d41..0000000 --- a/tools/buildbot/pylibs/twisted/flow/wrap.py +++ /dev/null @@ -1,217 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -# Author: Clark Evans (cce@clarkevans.com) -# - -""" flow.wrap - - This module provides the wrap() function in the flow module and - the private classes used for its implementation. -""" - -from base import * -from twisted.python.failure import Failure -from twisted.internet.defer import Deferred - -class _String(Stage): - """ Wrapper for a string object; don't create directly use flow.wrap - - This is probably the simplest stage of all. It is a - constant list of one item. See wrap for an example. - - """ - def __init__(self, str): - Stage.__init__(self) - self.results.append(str) - self.stop = True - def _yield(self): - pass - -class _List(Stage): - """ Wrapper for lists and tuple objects; don't create directly - - A simple stage, which admits the usage of instructions, - such as Cooperate() within the list. This would be - much simpler without logic to handle instructions. - - """ - def __init__(self, seq): - Stage.__init__(self) - self._seq = list(seq) - def _yield(self): - seq = self._seq - while seq: - result = seq.pop(0) - if isinstance(result, Instruction): - return result - self.results.append(result) - self.stop = True - -class _DeferredInstruction(CallLater): - def __init__(self, deferred): - self.deferred = deferred - def callLater(self, callable): - self.deferred.addBoth(callable) - -class _Iterable(Stage): - """ Wrapper for iterable objects, pass in a next() function - - This wraps functions (or bound methods). Execution starts with - the initial function. If the return value is a Stage, then - control passes on to that stage for the next round of execution. - If the return value is Cooperate, then the chain of Stages is - put on hold, and this return value travels all the way up the - call stack so that the underlying mechanism can sleep, or - perform other tasks, etc. All other non-Instruction return - values, Failure objects included, are passed back to the - previous stage via self.result - - All exceptions signal the end of the Stage. StopIteration - means to stop without providing a result, while all other - exceptions provide a Failure self.result followed by stoppage. - - """ - def __init__(self, iterable, *trap): - Stage.__init__(self, *trap) - self._iterable = iter(iterable) - self._next = None - - def _yield(self): - """ executed during a yield statement """ - if self.results or self.stop or self.failure: - return - while True: - next = self._next - if next: - instruction = next._yield() - if instruction: - return instruction - self._next = None - try: - result = self._iterable.next() - if isinstance(result, Instruction): - if isinstance(result, Stage): - self._next = result - continue - return result - if isinstance(result, Deferred): - if result.called: - continue - return _DeferredInstruction(result) - self.results.append(result) - except StopIteration: - self.stop = True - except Failure, fail: - self.failure = fail - except: - self.failure = Failure() - return - -class _Deferred(Stage): - """ Wraps a Deferred object into a stage; create with flow.wrap - - This stage provides a callback 'catch' for errback and - callbacks. If not called, then this returns an Instruction - which will let the reactor execute other operations, such - as the producer for this deferred. - - """ - def __init__(self, deferred, *trap): - Stage.__init__(self, *trap) - self._called = False - deferred.addCallbacks(self._callback, self._errback) - self._cooperate = _DeferredInstruction(deferred) - - def _callback(self, res): - self._called = True - self.results = [res] - - def _errback(self, fail): - self._called = True - self.failure = fail - - def _yield(self): - if self.results or self.stop or self.failure: - return - if not self._called: - return self._cooperate - if self._called: - self.stop = True - return - -def wrap(obj, *trap): - """ - Wraps various objects for use within a flow - - The following example illustrates many different ways in which regular - objects can be wrapped by the flow module to behave in a cooperative - manner. - - For example:: - - # required imports - from __future__ import generators - from twisted.flow import flow - from twisted.internet import reactor, defer - - # save this function, it is used everwhere - def printFlow(source): - def printer(source): - source = flow.wrap(source) - while True: - yield source - print source.next() - d = flow.Deferred(printer(source)) - d.addCallback(lambda _: reactor.stop()) - reactor.run() - - source = "string" - printFlow(source) - - source = ["one",flow.Cooperate(1),"two"] - printFlow(source) - - def source(): - yield "aeye" - yield flow.Cooperate() - yield "capin" - printFlow(source) - - source = Deferred() - reactor.callLater(1, lambda: source.callback("howdy")) - printFlow(source) - - """ - if isinstance(obj, Stage): - if trap: - # merge trap list - trap = list(trap) - for ex in obj._trap: - if ex not in trap: - trap.append(ex) - obj._trap = tuple(trap) - return obj - - if callable(obj): - obj = obj() - - typ = type(obj) - - if typ is type([]) or typ is type(tuple()): - return _List(obj) - - if typ is type(''): - return _String(obj) - - if isinstance(obj, Deferred): - return _Deferred(obj, *trap) - - try: - return _Iterable(obj, *trap) - except TypeError: - pass - - raise ValueError, "A wrapper is not available for %r" % (obj,) - diff --git a/tools/buildbot/pylibs/twisted/im.py b/tools/buildbot/pylibs/twisted/im.py deleted file mode 100644 index 2db08cf..0000000 --- a/tools/buildbot/pylibs/twisted/im.py +++ /dev/null @@ -1,6 +0,0 @@ -from twisted.python import util - -util.moduleMovedForSplit('twisted.im', 'twisted.words.im', - 'Instance Messenger', 'Words', - 'http://projects.twistedmatrix.com/words', - globals()) diff --git a/tools/buildbot/pylibs/twisted/internet/__init__.py b/tools/buildbot/pylibs/twisted/internet/__init__.py deleted file mode 100644 index e87f846..0000000 --- a/tools/buildbot/pylibs/twisted/internet/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" - -Twisted Internet: Asynchronous I/O and Events. - -""" diff --git a/tools/buildbot/pylibs/twisted/internet/_dumbwin32proc.py b/tools/buildbot/pylibs/twisted/internet/_dumbwin32proc.py deleted file mode 100644 index 4334f77..0000000 --- a/tools/buildbot/pylibs/twisted/internet/_dumbwin32proc.py +++ /dev/null @@ -1,337 +0,0 @@ -# -*- test-case-name: twisted.test.test_process -*- -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -http://isometric.sixsided.org/_/gates_in_the_head/ -""" - -import os - -# Win32 imports -import win32api -import win32con -import win32event -import win32file -import win32pipe -import win32process -import win32security - -import pywintypes - -# security attributes for pipes -PIPE_ATTRS_INHERITABLE = win32security.SECURITY_ATTRIBUTES() -PIPE_ATTRS_INHERITABLE.bInheritHandle = 1 - -from zope.interface import implements -from twisted.internet.interfaces import IProcessTransport, IConsumer, IProducer - -from twisted.python.win32 import quoteArguments - -from twisted.internet import error -from twisted.python import failure - -from twisted.internet import _pollingfile - -def debug(msg): - import sys - print msg - sys.stdout.flush() - -class _Reaper(_pollingfile._PollableResource): - - def __init__(self, proc): - self.proc = proc - - def checkWork(self): - if win32event.WaitForSingleObject(self.proc.hProcess, 0) != win32event.WAIT_OBJECT_0: - return 0 - exitCode = win32process.GetExitCodeProcess(self.proc.hProcess) - self.deactivate() - self.proc.processEnded(exitCode) - return 0 - - -def _findShebang(filename): - """ - Look for a #! line, and return the value following the #! if one exists, or - None if this file is not a script. - - I don't know if there are any conventions for quoting in Windows shebang - lines, so this doesn't support any; therefore, you may not pass any - arguments to scripts invoked as filters. That's probably wrong, so if - somebody knows more about the cultural expectations on Windows, please feel - free to fix. - - This shebang line support was added in support of the CGI tests; - appropriately enough, I determined that shebang lines are culturally - accepted in the Windows world through this page: - - http://www.cgi101.com/learn/connect/winxp.html - - @param filename: str representing a filename - - @return: a str representing another filename. - """ - f = file(filename, 'ru') - if f.read(2) == '#!': - exe = f.readline(1024).strip('\n') - return exe - -def _invalidWin32App(pywinerr): - """ - Determine if a pywintypes.error is telling us that the given process is - 'not a valid win32 application', i.e. not a PE format executable. - - @param pywinerr: a pywintypes.error instance raised by CreateProcess - - @return: a boolean - """ - - # Let's do this better in the future, but I have no idea what this error - # is; MSDN doesn't mention it, and there is no symbolic constant in - # win32process module that represents 193. - - return pywinerr.args[0] == 193 - -class Process(_pollingfile._PollingTimer): - """A process that integrates with the Twisted event loop. - - If your subprocess is a python program, you need to: - - - Run python.exe with the '-u' command line option - this turns on - unbuffered I/O. Buffering stdout/err/in can cause problems, see e.g. - http://support.microsoft.com/default.aspx?scid=kb;EN-US;q1903 - - - If you don't want Windows messing with data passed over - stdin/out/err, set the pipes to be in binary mode:: - - import os, sys, mscvrt - msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY) - msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) - msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY) - - """ - implements(IProcessTransport, IConsumer, IProducer) - - buffer = '' - pid = None - - def __init__(self, reactor, protocol, command, args, environment, path): - _pollingfile._PollingTimer.__init__(self, reactor) - self.protocol = protocol - - # security attributes for pipes - sAttrs = win32security.SECURITY_ATTRIBUTES() - sAttrs.bInheritHandle = 1 - - # create the pipes which will connect to the secondary process - self.hStdoutR, hStdoutW = win32pipe.CreatePipe(sAttrs, 0) - self.hStderrR, hStderrW = win32pipe.CreatePipe(sAttrs, 0) - hStdinR, self.hStdinW = win32pipe.CreatePipe(sAttrs, 0) - - win32pipe.SetNamedPipeHandleState(self.hStdinW, - win32pipe.PIPE_NOWAIT, - None, - None) - - # set the info structure for the new process. - StartupInfo = win32process.STARTUPINFO() - StartupInfo.hStdOutput = hStdoutW - StartupInfo.hStdError = hStderrW - StartupInfo.hStdInput = hStdinR - StartupInfo.dwFlags = win32process.STARTF_USESTDHANDLES - - # Create new handles whose inheritance property is false - currentPid = win32api.GetCurrentProcess() - - tmp = win32api.DuplicateHandle(currentPid, self.hStdoutR, currentPid, 0, 0, - win32con.DUPLICATE_SAME_ACCESS) - win32file.CloseHandle(self.hStdoutR) - self.hStdoutR = tmp - - tmp = win32api.DuplicateHandle(currentPid, self.hStderrR, currentPid, 0, 0, - win32con.DUPLICATE_SAME_ACCESS) - win32file.CloseHandle(self.hStderrR) - self.hStderrR = tmp - - tmp = win32api.DuplicateHandle(currentPid, self.hStdinW, currentPid, 0, 0, - win32con.DUPLICATE_SAME_ACCESS) - win32file.CloseHandle(self.hStdinW) - self.hStdinW = tmp - - # Add the specified environment to the current environment - this is - # necessary because certain operations are only supported on Windows - # if certain environment variables are present. - - env = os.environ.copy() - env.update(environment or {}) - - cmdline = quoteArguments(args) - # TODO: error detection here. - def doCreate(): - self.hProcess, self.hThread, self.pid, dwTid = win32process.CreateProcess( - command, cmdline, None, None, 1, 0, env, path, StartupInfo) - try: - doCreate() - except pywintypes.error, pwte: - if not _invalidWin32App(pwte): - # This behavior isn't _really_ documented, but let's make it - # consistent with the behavior that is documented. - raise OSError(pwte) - else: - # look for a shebang line. Insert the original 'command' - # (actually a script) into the new arguments list. - sheb = _findShebang(command) - if sheb is None: - raise OSError( - "%r is neither a Windows executable, " - "nor a script with a shebang line" % command) - else: - args = list(args) - args.insert(0, command) - cmdline = quoteArguments(args) - origcmd = command - command = sheb - try: - # Let's try again. - doCreate() - except pywintypes.error, pwte2: - # d'oh, failed again! - if _invalidWin32App(pwte2): - raise OSError( - "%r has an invalid shebang line: " - "%r is not a valid executable" % ( - origcmd, sheb)) - raise OSError(pwte2) - - win32file.CloseHandle(self.hThread) - - # close handles which only the child will use - win32file.CloseHandle(hStderrW) - win32file.CloseHandle(hStdoutW) - win32file.CloseHandle(hStdinR) - - self.closed = 0 - self.closedNotifies = 0 - - # set up everything - self.stdout = _pollingfile._PollableReadPipe( - self.hStdoutR, - lambda data: self.protocol.childDataReceived(1, data), - self.outConnectionLost) - - self.stderr = _pollingfile._PollableReadPipe( - self.hStderrR, - lambda data: self.protocol.childDataReceived(2, data), - self.errConnectionLost) - - self.stdin = _pollingfile._PollableWritePipe( - self.hStdinW, self.inConnectionLost) - - for pipewatcher in self.stdout, self.stderr, self.stdin: - self._addPollableResource(pipewatcher) - - - # notify protocol - self.protocol.makeConnection(self) - - # (maybe?) a good idea in win32er, otherwise not - # self.reactor.addEvent(self.hProcess, self, 'inConnectionLost') - - - def signalProcess(self, signalID): - if self.pid is None: - raise error.ProcessExitedAlready() - if signalID in ("INT", "TERM", "KILL"): - os.popen('taskkill /T /F /PID %s' % self.pid) - - def processEnded(self, status): - """ - This is called when the child terminates. - """ - self.pid = None - if status == 0: - err = error.ProcessDone(status) - else: - err = error.ProcessTerminated(status) - self.protocol.processEnded(failure.Failure(err)) - - - def write(self, data): - """Write data to the process' stdin.""" - self.stdin.write(data) - - def writeSequence(self, seq): - """Write data to the process' stdin.""" - self.stdin.writeSequence(seq) - - def closeChildFD(self, fd): - if fd == 0: - self.closeStdin() - elif fd == 1: - self.closeStdout() - elif fd == 2: - self.closeStderr() - else: - raise NotImplementedError("Only standard-IO file descriptors available on win32") - - def closeStdin(self): - """Close the process' stdin. - """ - self.stdin.close() - - def closeStderr(self): - self.stderr.close() - - def closeStdout(self): - self.stdout.close() - - def loseConnection(self): - """Close the process' stdout, in and err.""" - self.closeStdin() - self.closeStdout() - self.closeStderr() - - def outConnectionLost(self): - self.protocol.childConnectionLost(1) - self.connectionLostNotify() - - def errConnectionLost(self): - self.protocol.childConnectionLost(2) - self.connectionLostNotify() - - def inConnectionLost(self): - self.protocol.childConnectionLost(0) - self.connectionLostNotify() - - def connectionLostNotify(self): - """Will be called 3 times, by stdout/err threads and process handle.""" - self.closedNotifies = self.closedNotifies + 1 - if self.closedNotifies == 3: - self.closed = 1 - self._addPollableResource(_Reaper(self)) - - # IConsumer - def registerProducer(self, producer, streaming): - self.stdin.registerProducer(producer, streaming) - - def unregisterProducer(self): - self.stdin.unregisterProducer() - - # IProducer - def pauseProducing(self): - self._pause() - - def resumeProducing(self): - self._unpause() - - def stopProducing(self): - self.loseConnection() - - - def __repr__(self): - """ - Return a string representation of the process. - """ - return "<%s pid=%s>" % (self.__class__.__name__, self.pid) diff --git a/tools/buildbot/pylibs/twisted/internet/_dumbwin32proc_orig.py b/tools/buildbot/pylibs/twisted/internet/_dumbwin32proc_orig.py deleted file mode 100644 index 44e3837..0000000 --- a/tools/buildbot/pylibs/twisted/internet/_dumbwin32proc_orig.py +++ /dev/null @@ -1,338 +0,0 @@ -# -*- test-case-name: twisted.test.test_process -*- -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -http://isometric.sixsided.org/_/gates_in_the_head/ -""" - -import os - -# Win32 imports -import win32api -import win32con -import win32event -import win32file -import win32pipe -import win32process -import win32security - -import pywintypes - -# security attributes for pipes -PIPE_ATTRS_INHERITABLE = win32security.SECURITY_ATTRIBUTES() -PIPE_ATTRS_INHERITABLE.bInheritHandle = 1 - -from zope.interface import implements -from twisted.internet.interfaces import IProcessTransport, IConsumer, IProducer - -from twisted.python.win32 import quoteArguments - -from twisted.internet import error -from twisted.python import failure - -from twisted.internet import _pollingfile - -def debug(msg): - import sys - print msg - sys.stdout.flush() - -class _Reaper(_pollingfile._PollableResource): - - def __init__(self, proc): - self.proc = proc - - def checkWork(self): - if win32event.WaitForSingleObject(self.proc.hProcess, 0) != win32event.WAIT_OBJECT_0: - return 0 - exitCode = win32process.GetExitCodeProcess(self.proc.hProcess) - self.deactivate() - self.proc.processEnded(exitCode) - return 0 - - -def _findShebang(filename): - """ - Look for a #! line, and return the value following the #! if one exists, or - None if this file is not a script. - - I don't know if there are any conventions for quoting in Windows shebang - lines, so this doesn't support any; therefore, you may not pass any - arguments to scripts invoked as filters. That's probably wrong, so if - somebody knows more about the cultural expectations on Windows, please feel - free to fix. - - This shebang line support was added in support of the CGI tests; - appropriately enough, I determined that shebang lines are culturally - accepted in the Windows world through this page: - - http://www.cgi101.com/learn/connect/winxp.html - - @param filename: str representing a filename - - @return: a str representing another filename. - """ - f = file(filename, 'ru') - if f.read(2) == '#!': - exe = f.readline(1024).strip('\n') - return exe - -def _invalidWin32App(pywinerr): - """ - Determine if a pywintypes.error is telling us that the given process is - 'not a valid win32 application', i.e. not a PE format executable. - - @param pywinerr: a pywintypes.error instance raised by CreateProcess - - @return: a boolean - """ - - # Let's do this better in the future, but I have no idea what this error - # is; MSDN doesn't mention it, and there is no symbolic constant in - # win32process module that represents 193. - - return pywinerr.args[0] == 193 - -class Process(_pollingfile._PollingTimer): - """A process that integrates with the Twisted event loop. - - If your subprocess is a python program, you need to: - - - Run python.exe with the '-u' command line option - this turns on - unbuffered I/O. Buffering stdout/err/in can cause problems, see e.g. - http://support.microsoft.com/default.aspx?scid=kb;EN-US;q1903 - - - If you don't want Windows messing with data passed over - stdin/out/err, set the pipes to be in binary mode:: - - import os, sys, mscvrt - msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY) - msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) - msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY) - - """ - implements(IProcessTransport, IConsumer, IProducer) - - buffer = '' - pid = None - - def __init__(self, reactor, protocol, command, args, environment, path): - _pollingfile._PollingTimer.__init__(self, reactor) - self.protocol = protocol - - # security attributes for pipes - sAttrs = win32security.SECURITY_ATTRIBUTES() - sAttrs.bInheritHandle = 1 - - # create the pipes which will connect to the secondary process - self.hStdoutR, hStdoutW = win32pipe.CreatePipe(sAttrs, 0) - self.hStderrR, hStderrW = win32pipe.CreatePipe(sAttrs, 0) - hStdinR, self.hStdinW = win32pipe.CreatePipe(sAttrs, 0) - - win32pipe.SetNamedPipeHandleState(self.hStdinW, - win32pipe.PIPE_NOWAIT, - None, - None) - - # set the info structure for the new process. - StartupInfo = win32process.STARTUPINFO() - StartupInfo.hStdOutput = hStdoutW - StartupInfo.hStdError = hStderrW - StartupInfo.hStdInput = hStdinR - StartupInfo.dwFlags = win32process.STARTF_USESTDHANDLES - - # Create new handles whose inheritance property is false - currentPid = win32api.GetCurrentProcess() - - tmp = win32api.DuplicateHandle(currentPid, self.hStdoutR, currentPid, 0, 0, - win32con.DUPLICATE_SAME_ACCESS) - win32file.CloseHandle(self.hStdoutR) - self.hStdoutR = tmp - - tmp = win32api.DuplicateHandle(currentPid, self.hStderrR, currentPid, 0, 0, - win32con.DUPLICATE_SAME_ACCESS) - win32file.CloseHandle(self.hStderrR) - self.hStderrR = tmp - - tmp = win32api.DuplicateHandle(currentPid, self.hStdinW, currentPid, 0, 0, - win32con.DUPLICATE_SAME_ACCESS) - win32file.CloseHandle(self.hStdinW) - self.hStdinW = tmp - - # Add the specified environment to the current environment - this is - # necessary because certain operations are only supported on Windows - # if certain environment variables are present. - - env = os.environ.copy() - env.update(environment or {}) - - cmdline = quoteArguments(args) - # TODO: error detection here. - def doCreate(): - self.hProcess, self.hThread, self.pid, dwTid = win32process.CreateProcess( - command, cmdline, None, None, 1, 0, env, path, StartupInfo) - try: - doCreate() - except pywintypes.error, pwte: - if not _invalidWin32App(pwte): - # This behavior isn't _really_ documented, but let's make it - # consistent with the behavior that is documented. - raise OSError(pwte) - else: - # look for a shebang line. Insert the original 'command' - # (actually a script) into the new arguments list. - sheb = _findShebang(command) - if sheb is None: - raise OSError( - "%r is neither a Windows executable, " - "nor a script with a shebang line" % command) - else: - args = list(args) - args.insert(0, command) - cmdline = quoteArguments(args) - origcmd = command - command = sheb - try: - # Let's try again. - doCreate() - except pywintypes.error, pwte2: - # d'oh, failed again! - if _invalidWin32App(pwte2): - raise OSError( - "%r has an invalid shebang line: " - "%r is not a valid executable" % ( - origcmd, sheb)) - raise OSError(pwte2) - - win32file.CloseHandle(self.hThread) - - # close handles which only the child will use - win32file.CloseHandle(hStderrW) - win32file.CloseHandle(hStdoutW) - win32file.CloseHandle(hStdinR) - - self.closed = 0 - self.closedNotifies = 0 - - # set up everything - self.stdout = _pollingfile._PollableReadPipe( - self.hStdoutR, - lambda data: self.protocol.childDataReceived(1, data), - self.outConnectionLost) - - self.stderr = _pollingfile._PollableReadPipe( - self.hStderrR, - lambda data: self.protocol.childDataReceived(2, data), - self.errConnectionLost) - - self.stdin = _pollingfile._PollableWritePipe( - self.hStdinW, self.inConnectionLost) - - for pipewatcher in self.stdout, self.stderr, self.stdin: - self._addPollableResource(pipewatcher) - - - # notify protocol - self.protocol.makeConnection(self) - - # (maybe?) a good idea in win32er, otherwise not - # self.reactor.addEvent(self.hProcess, self, 'inConnectionLost') - - - def signalProcess(self, signalID): - if self.pid is None: - raise error.ProcessExitedAlready() - if signalID in ("INT", "TERM", "KILL"): - win32process.TerminateProcess(self.hProcess, 1) - - - def processEnded(self, status): - """ - This is called when the child terminates. - """ - self.pid = None - if status == 0: - err = error.ProcessDone(status) - else: - err = error.ProcessTerminated(status) - self.protocol.processEnded(failure.Failure(err)) - - - def write(self, data): - """Write data to the process' stdin.""" - self.stdin.write(data) - - def writeSequence(self, seq): - """Write data to the process' stdin.""" - self.stdin.writeSequence(seq) - - def closeChildFD(self, fd): - if fd == 0: - self.closeStdin() - elif fd == 1: - self.closeStdout() - elif fd == 2: - self.closeStderr() - else: - raise NotImplementedError("Only standard-IO file descriptors available on win32") - - def closeStdin(self): - """Close the process' stdin. - """ - self.stdin.close() - - def closeStderr(self): - self.stderr.close() - - def closeStdout(self): - self.stdout.close() - - def loseConnection(self): - """Close the process' stdout, in and err.""" - self.closeStdin() - self.closeStdout() - self.closeStderr() - - def outConnectionLost(self): - self.protocol.childConnectionLost(1) - self.connectionLostNotify() - - def errConnectionLost(self): - self.protocol.childConnectionLost(2) - self.connectionLostNotify() - - def inConnectionLost(self): - self.protocol.childConnectionLost(0) - self.connectionLostNotify() - - def connectionLostNotify(self): - """Will be called 3 times, by stdout/err threads and process handle.""" - self.closedNotifies = self.closedNotifies + 1 - if self.closedNotifies == 3: - self.closed = 1 - self._addPollableResource(_Reaper(self)) - - # IConsumer - def registerProducer(self, producer, streaming): - self.stdin.registerProducer(producer, streaming) - - def unregisterProducer(self): - self.stdin.unregisterProducer() - - # IProducer - def pauseProducing(self): - self._pause() - - def resumeProducing(self): - self._unpause() - - def stopProducing(self): - self.loseConnection() - - - def __repr__(self): - """ - Return a string representation of the process. - """ - return "<%s pid=%s>" % (self.__class__.__name__, self.pid) diff --git a/tools/buildbot/pylibs/twisted/internet/_javaserialport.py b/tools/buildbot/pylibs/twisted/internet/_javaserialport.py deleted file mode 100644 index ee84695..0000000 --- a/tools/buildbot/pylibs/twisted/internet/_javaserialport.py +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Serial Port Protocol -""" - -# system imports -import os - -# dependent on pyserial ( http://pyserial.sf.net/ ) -# only tested w/ 1.18 (5 Dec 2002) -import serial -from serial import PARITY_NONE, PARITY_EVEN, PARITY_ODD -from serial import STOPBITS_ONE, STOPBITS_TWO -from serial import FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS -from serialport import BaseSerialPort - -# twisted imports -from twisted.internet import abstract, javareactor, main -from twisted.python import log - -class SerialPort(BaseSerialPort, javareactor.JConnection): - """A select()able serial device, acting as a transport.""" - connected = 1 - - def __init__(self, protocol, deviceNameOrPortNumber, reactor, - baudrate = 9600, bytesize = EIGHTBITS, parity = PARITY_NONE, - stopbits = STOPBITS_ONE, timeout = 3, xonxoff = 0, rtscts = 0): - # do NOT use timeout = 0 !! - self._serial = serial.Serial(deviceNameOrPortNumber, baudrate = baudrate, bytesize = bytesize, parity = parity, stopbits = stopbits, timeout = timeout, xonxoff = xonxoff, rtscts = rtscts) - javareactor.JConnection.__init__(self, self._serial.sPort, protocol, None) - self.flushInput() - self.flushOutput() - - self.reactor = reactor - self.protocol = protocol - self.protocol.makeConnection(self) - wb = javareactor.WriteBlocker(self, reactor.q) - wb.start() - self.writeBlocker = wb - javareactor.ReadBlocker(self, reactor.q).start() - - def writeSomeData(self, data): - try: - self._serial.write(data) - return len(data) - # should have something better here - except Exception, e: - return main.CONNECTION_LOST - - def doRead(self): - readBytes = '' - try: - readBytes = self._serial.read(min(8192, self.inWaiting())) - except Exception, e: - return main.CONNECTION_LOST - if not readBytes: - return main.CONNECTION_LOST - self.protocol.dataReceived(readBytes) - - def connectionLost(self, reason): - self._serial.close() - self.protocol.connectionLost(reason) - abstract.FileDescriptor.connectionLost(self, reason) - - def getHost(self): - raise NotImplementedError - - def getPeer(self): - raise NotImplementedError - - def getTcpNoDelay(self): - raise NotImplementedError - - def setTcpNoDelay(self, enabled): - raise NotImplementedError diff --git a/tools/buildbot/pylibs/twisted/internet/_pollingfile.py b/tools/buildbot/pylibs/twisted/internet/_pollingfile.py deleted file mode 100644 index cdf55ef..0000000 --- a/tools/buildbot/pylibs/twisted/internet/_pollingfile.py +++ /dev/null @@ -1,270 +0,0 @@ -# -*- test-case-name: twisted.web2.test -*- -""" - -Implements a simple polling interface for file descriptors that don't work with -select() - this is pretty much only useful on Windows. - -""" - -from zope.interface import implements - -from twisted.internet.interfaces import IConsumer, IPushProducer - -MIN_TIMEOUT = 0.000000001 -MAX_TIMEOUT = 0.1 - -class _PollableResource: - active = True - - def activate(self): - self.active = True - - def deactivate(self): - self.active = False - -class _PollingTimer: - # Everything is private here because it is really an implementation detail. - - def __init__(self, reactor): - self.reactor = reactor - self._resources = [] - self._pollTimer = None - self._currentTimeout = MAX_TIMEOUT - self._paused = False - - def _addPollableResource(self, res): - self._resources.append(res) - self._checkPollingState() - - def _checkPollingState(self): - for resource in self._resources: - if resource.active: - self._startPolling() - break - else: - self._stopPolling() - - def _startPolling(self): - if self._pollTimer is None: - self._pollTimer = self._reschedule() - - def _stopPolling(self): - if self._pollTimer is not None: - self._pollTimer.cancel() - self._pollTimer = None - - def _pause(self): - self._paused = True - - def _unpause(self): - self._paused = False - self._checkPollingState() - - def _reschedule(self): - if not self._paused: - return self.reactor.callLater(self._currentTimeout, self._pollEvent) - - def _pollEvent(self): - workUnits = 0. - anyActive = [] - for resource in self._resources: - if resource.active: - workUnits += resource.checkWork() - # Check AFTER work has been done - if resource.active: - anyActive.append(resource) - - newTimeout = self._currentTimeout - if workUnits: - newTimeout = self._currentTimeout / (workUnits + 1.) - if newTimeout < MIN_TIMEOUT: - newTimeout = MIN_TIMEOUT - else: - newTimeout = self._currentTimeout * 2. - if newTimeout > MAX_TIMEOUT: - newTimeout = MAX_TIMEOUT - self._currentTimeout = newTimeout - if anyActive: - self._pollTimer = self._reschedule() - - -# If we ever (let's hope not) need the above functionality on UNIX, this could -# be factored into a different module. - -import win32pipe -import win32file -import win32api -import pywintypes - -class _PollableReadPipe(_PollableResource): - - implements(IPushProducer) - - def __init__(self, pipe, receivedCallback, lostCallback): - # security attributes for pipes - self.pipe = pipe - self.receivedCallback = receivedCallback - self.lostCallback = lostCallback - - def checkWork(self): - finished = 0 - fullDataRead = [] - - while 1: - try: - buffer, bytesToRead, result = win32pipe.PeekNamedPipe(self.pipe, 1) - # finished = (result == -1) - if not bytesToRead: - break - hr, data = win32file.ReadFile(self.pipe, bytesToRead, None) - fullDataRead.append(data) - except win32api.error: - finished = 1 - break - - dataBuf = ''.join(fullDataRead) - if dataBuf: - self.receivedCallback(dataBuf) - if finished: - self.cleanup() - return len(dataBuf) - - def cleanup(self): - self.deactivate() - self.lostCallback() - - def close(self): - try: - win32api.CloseHandle(self.pipe) - except pywintypes.error: - # You can't close std handles...? - pass - - def stopProducing(self): - self.close() - - def pauseProducing(self): - self.deactivate() - - def resumeProducing(self): - self.activate() - - -FULL_BUFFER_SIZE = 64 * 1024 - -class _PollableWritePipe(_PollableResource): - - implements(IConsumer) - - def __init__(self, writePipe, lostCallback): - self.disconnecting = False - self.producer = None - self.producerPaused = 0 - self.streamingProducer = 0 - self.outQueue = [] - self.writePipe = writePipe - self.lostCallback = lostCallback - try: - win32pipe.SetNamedPipeHandleState(writePipe, - win32pipe.PIPE_NOWAIT, - None, - None) - except pywintypes.error: - # Maybe it's an invalid handle. Who knows. - pass - - def close(self): - self.disconnecting = True - - def bufferFull(self): - if self.producer is not None: - self.producerPaused = 1 - self.producer.pauseProducing() - - def bufferEmpty(self): - if self.producer is not None and ((not self.streamingProducer) or - self.producerPaused): - self.producer.producerPaused = 0 - self.producer.resumeProducing() - return True - return False - - # almost-but-not-quite-exact copy-paste from abstract.FileDescriptor... ugh - - def registerProducer(self, producer, streaming): - """Register to receive data from a producer. - - This sets this selectable to be a consumer for a producer. When this - selectable runs out of data on a write() call, it will ask the producer - to resumeProducing(). A producer should implement the IProducer - interface. - - FileDescriptor provides some infrastructure for producer methods. - """ - if self.producer is not None: - raise RuntimeError("Cannot register producer %s, because producer %s was never unregistered." % (producer, self.producer)) - if not self.active: - producer.stopProducing() - else: - self.producer = producer - self.streamingProducer = streaming - if not streaming: - producer.resumeProducing() - - def unregisterProducer(self): - """Stop consuming data from a producer, without disconnecting. - """ - self.producer = None - - def writeConnectionLost(self): - self.deactivate() - try: - win32api.CloseHandle(self.writePipe) - except pywintypes.error: - # OMG what - pass - self.lostCallback() - - def writeSequence(self, seq): - self.outQueue.extend(seq) - - def write(self, data): - if self.disconnecting: - return - self.outQueue.append(data) - if sum(map(len, self.outQueue)) > FULL_BUFFER_SIZE: - self.bufferFull() - - def checkWork(self): - numBytesWritten = 0 - if not self.outQueue: - if self.disconnecting: - self.writeConnectionLost() - return 0 - try: - win32file.WriteFile(self.writePipe, '', None) - except pywintypes.error: - self.writeConnectionLost() - return numBytesWritten - while self.outQueue: - data = self.outQueue.pop(0) - errCode = 0 - try: - errCode, nBytesWritten = win32file.WriteFile(self.writePipe, - data, None) - except win32api.error: - self.writeConnectionLost() - break - else: - # assert not errCode, "wtf an error code???" - numBytesWritten += nBytesWritten - if len(data) > nBytesWritten: - self.outQueue.insert(0, data[nBytesWritten:]) - break - else: - resumed = self.bufferEmpty() - if not resumed and self.disconnecting: - self.writeConnectionLost() - return numBytesWritten - - diff --git a/tools/buildbot/pylibs/twisted/internet/_posixserialport.py b/tools/buildbot/pylibs/twisted/internet/_posixserialport.py deleted file mode 100644 index c94ecee..0000000 --- a/tools/buildbot/pylibs/twisted/internet/_posixserialport.py +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Serial Port Protocol -""" - -# system imports -import os, errno - -# dependent on pyserial ( http://pyserial.sf.net/ ) -# only tested w/ 1.18 (5 Dec 2002) -import serial -from serial import PARITY_NONE, PARITY_EVEN, PARITY_ODD -from serial import STOPBITS_ONE, STOPBITS_TWO -from serial import FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS - -from serialport import BaseSerialPort - -# twisted imports -from twisted.internet import abstract, fdesc, main - -class SerialPort(BaseSerialPort, abstract.FileDescriptor): - """ - A select()able serial device, acting as a transport. - """ - - connected = 1 - - def __init__(self, protocol, deviceNameOrPortNumber, reactor, - baudrate = 9600, bytesize = EIGHTBITS, parity = PARITY_NONE, - stopbits = STOPBITS_ONE, timeout = 0, xonxoff = 0, rtscts = 0): - abstract.FileDescriptor.__init__(self, reactor) - self._serial = serial.Serial(deviceNameOrPortNumber, baudrate = baudrate, bytesize = bytesize, parity = parity, stopbits = stopbits, timeout = timeout, xonxoff = xonxoff, rtscts = rtscts) - self.reactor = reactor - self.flushInput() - self.flushOutput() - self.protocol = protocol - self.protocol.makeConnection(self) - self.startReading() - - def fileno(self): - return self._serial.fd - - def writeSomeData(self, data): - """ - Write some data to the serial device. - """ - return fdesc.writeToFD(self.fileno(), data) - - def doRead(self): - """ - Some data's readable from serial device. - """ - return fdesc.readFromFD(self.fileno(), self.protocol.dataReceived) - - def connectionLost(self, reason): - abstract.FileDescriptor.connectionLost(self, reason) - self._serial.close() diff --git a/tools/buildbot/pylibs/twisted/internet/_posixstdio.py b/tools/buildbot/pylibs/twisted/internet/_posixstdio.py deleted file mode 100644 index 56eb141..0000000 --- a/tools/buildbot/pylibs/twisted/internet/_posixstdio.py +++ /dev/null @@ -1,171 +0,0 @@ -# -*- test-case-name: twisted.test.test_stdio -*- - -"""Standard input/out/err support. - -Future Plans:: - - support for stderr, perhaps - Rewrite to use the reactor instead of an ad-hoc mechanism for connecting - protocols to transport. - -Maintainer: U{James Y Knight } -""" - -import warnings -from zope.interface import implements - -from twisted.internet import process, error, interfaces -from twisted.python import log, failure - - -class PipeAddress(object): - implements(interfaces.IAddress) - - -class StandardIO(object): - implements(interfaces.ITransport, interfaces.IProducer, interfaces.IConsumer, interfaces.IHalfCloseableDescriptor) - _reader = None - _writer = None - disconnected = False - disconnecting = False - - def __init__(self, proto, stdin=0, stdout=1): - from twisted.internet import reactor - self.protocol = proto - - self._reader=process.ProcessReader(reactor, self, 'read', stdin) - self._reader.startReading() - self._writer=process.ProcessWriter(reactor, self, 'write', stdout) - self._writer.startReading() - self.protocol.makeConnection(self) - - # ITransport - def loseWriteConnection(self): - if self._writer is not None: - self._writer.loseConnection() - - def write(self, data): - if self._writer is not None: - self._writer.write(data) - - def writeSequence(self, data): - if self._writer is not None: - self._writer.writeSequence(data) - - def loseConnection(self): - self.disconnecting = True - - if self._writer is not None: - self._writer.loseConnection() - if self._reader is not None: - # Don't loseConnection, because we don't want to SIGPIPE it. - self._reader.stopReading() - - def getPeer(self): - return PipeAddress() - - def getHost(self): - return PipeAddress() - - - # Callbacks from process.ProcessReader/ProcessWriter - def childDataReceived(self, fd, data): - self.protocol.dataReceived(data) - - def childConnectionLost(self, fd, reason): - if self.disconnected: - return - - if reason.value.__class__ == error.ConnectionDone: - # Normal close - if fd == 'read': - self._readConnectionLost(reason) - else: - self._writeConnectionLost(reason) - else: - self.connectionLost(reason) - - def connectionLost(self, reason): - self.disconnected = True - - # Make sure to cleanup the other half - _reader = self._reader - _writer = self._writer - protocol = self.protocol - self._reader = self._writer = None - self.protocol = None - - if _writer is not None and not _writer.disconnected: - _writer.connectionLost(reason) - - if _reader is not None and not _reader.disconnected: - _reader.connectionLost(reason) - - try: - protocol.connectionLost(reason) - except: - log.err() - - def _writeConnectionLost(self, reason): - self._writer=None - if self.disconnecting: - self.connectionLost(reason) - return - - p = interfaces.IHalfCloseableProtocol(self.protocol, None) - if p: - try: - p.writeConnectionLost() - except: - log.err() - self.connectionLost(failure.Failure()) - - def _readConnectionLost(self, reason): - self._reader=None - p = interfaces.IHalfCloseableProtocol(self.protocol, None) - if p: - try: - p.readConnectionLost() - except: - log.err() - self.connectionLost(failure.Failure()) - else: - self.connectionLost(reason) - - # IConsumer - def registerProducer(self, producer, streaming): - if self._writer is None: - producer.stopProducing() - else: - self._writer.registerProducer(producer, streaming) - - def unregisterProducer(self): - if self._writer is not None: - self._writer.unregisterProducer() - - # IProducer - def stopProducing(self): - self.loseConnection() - - def pauseProducing(self): - if self._reader is not None: - self._reader.pauseProducing() - - def resumeProducing(self): - if self._reader is not None: - self._reader.resumeProducing() - - # Stupid compatibility: - def closeStdin(self): - """Compatibility only, don't use. Same as loseWriteConnection.""" - warnings.warn("This function is deprecated, use loseWriteConnection instead.", - category=DeprecationWarning, stacklevel=2) - self.loseWriteConnection() - - def stopReading(self): - """Compatibility only, don't use. Call pauseProducing.""" - self.pauseProducing() - - def startReading(self): - """Compatibility only, don't use. Call resumeProducing.""" - self.resumeProducing() diff --git a/tools/buildbot/pylibs/twisted/internet/_sslverify.py b/tools/buildbot/pylibs/twisted/internet/_sslverify.py deleted file mode 100644 index 32c4173..0000000 --- a/tools/buildbot/pylibs/twisted/internet/_sslverify.py +++ /dev/null @@ -1,948 +0,0 @@ -# -*- test-case-name: twisted.test.test_sslverify -*- -# Copyright 2005 Divmod, Inc. See LICENSE file for details - -import itertools, md5 -from OpenSSL import SSL, crypto - -from twisted.python import reflect, util -from twisted.internet.defer import Deferred -from twisted.internet.error import VerifyError, CertificateError - -# Private - shared between all OpenSSLCertificateOptions, counts up to provide -# a unique session id for each context -_sessionCounter = itertools.count().next - -class _SSLApplicationData(object): - def __init__(self): - self.problems = [] - -class OpenSSLVerifyError(VerifyError): - - _errorCodes = {0: ('X509_V_OK', - 'ok', - 'the operation was successful. >'), - - 2: ('X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT', - 'unable to get issuer certificate', - "The issuer certificate could not be found. This " - "occurs if the issuer certificate of an untrusted " - "certificate cannot be found."), - - 3: ('X509_V_ERR_UNABLE_TO_GET_CRL', - 'unable to get certificate CRL', - "The CRL of a certificate could not be found. " - "Unused."), - - 4: ('X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE', - "unable to decrypt certificate's signature", - "The certificate signature could not be decrypted. " - "This means that the actual signature value could not " - "be determined rather than it not matching the " - "expected value, this is only meaningful for RSA " - "keys."), - - 5: ('X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE', - "unable to decrypt CRL's signature", - "The CRL signature could not be decrypted. This " - "means that the actual signature value could not be " - "determined rather than it not matching the expected " - "value. Unused."), - - 6: ('X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY', - 'unable to decode issuer', - "Public key the public key in the certificate " - "SubjectPublicKeyInfo could not be read."), - - 7: ('X509_V_ERR_CERT_SIGNATURE_FAILURE', - 'certificate signature failure', - 'The signature of the certificate is invalid.'), - - 8: ('X509_V_ERR_CRL_SIGNATURE_FAILURE', - 'CRL signature failure', - 'The signature of the certificate is invalid. Unused.'), - - 9: ('X509_V_ERR_CERT_NOT_YET_VALID', - 'certificate is not yet valid', - "The certificate is not yet valid. The notBefore " - "date is after the current time."), - - 10: ('X509_V_ERR_CERT_HAS_EXPIRED', - 'certificate has expired', - "The certificate has expired. The notAfter date " - "is before the current time."), - - 11: ('X509_V_ERR_CRL_NOT_YET_VALID', - 'CRL is not yet valid', - 'The CRL is not yet valid. Unused.'), - - 12: ('X509_V_ERR_CRL_HAS_EXPIRED', - 'CRL has expired', - 'The CRL has expired. Unused.'), - - 13: ('X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD', - "format error in certificate's notBefore field", - "The certificate's notBefore field contains an " - "invalid time."), - - 14: ('X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD', - "format error in certificate's notAfter field.", - "The certificate's notAfter field contains an " - "invalid time."), - - 15: ('X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD', - "format error in CRL's lastUpdate field", - "The CRL lastUpdate field contains an invalid " - "time. Unused."), - - 16: ('X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD', - "format error in CRL's nextUpdate field", - "The CRL nextUpdate field contains an invalid " - "time. Unused."), - - 17: ('X509_V_ERR_OUT_OF_MEM', - 'out of memory', - 'An error occurred trying to allocate memory. ' - 'This should never happen.'), - - 18: ('X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT', - 'self signed certificate', - 'The passed certificate is self signed and the same ' - 'certificate cannot be found in the list of trusted ' - 'certificates.'), - - 19: ('X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN', - 'self signed certificate in certificate chain', - 'The certificate chain could be built up using the ' - 'untrusted certificates but the root could not be ' - 'found locally.'), - - 20: ('X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY', - 'unable to get local issuer certificate', - 'The issuer certificate of a locally looked up ' - 'certificate could not be found. This normally ' - 'means the list of trusted certificates is not ' - 'complete.'), - - 21: ('X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE', - 'unable to verify the first certificate', - 'No signatures could be verified because the chain ' - 'contains only one certificate and it is not self ' - 'signed.'), - - 22: ('X509_V_ERR_CERT_CHAIN_TOO_LONG', - 'certificate chain too long', - 'The certificate chain length is greater than the ' - 'supplied maximum depth. Unused.'), - - 23: ('X509_V_ERR_CERT_REVOKED', - 'certificate revoked', - 'The certificate has been revoked. Unused.'), - - 24: ('X509_V_ERR_INVALID_CA', - 'invalid CA certificate', - 'A CA certificate is invalid. Either it is not a CA ' - 'or its extensions are not consistent with the ' - 'supplied purpose.'), - - 25: ('X509_V_ERR_PATH_LENGTH_EXCEEDED', - 'path length constraint exceeded', - 'The basicConstraints pathlength parameter has been ' - 'exceeded.'), - - 26: ('X509_V_ERR_INVALID_PURPOSE', - 'unsupported certificate purpose', - 'The supplied certificate cannot be used for the ' - 'specified purpose.'), - - 27: ('X509_V_ERR_CERT_UNTRUSTED', - 'certificate not trusted', - 'The root CA is not marked as trusted for the ' - 'specified purpose.'), - - 28: ('X509_V_ERR_CERT_REJECTED', - 'certificate rejected', - 'The root CA is marked to reject the specified ' - 'purpose.'), - - 29: ('X509_V_ERR_SUBJECT_ISSUER_MISMATCH', - 'subject issuer mismatch', - 'The current candidate issuer certificate was ' - 'rejected because its subject name did not match ' - 'the issuer name of the current certificate. Only ' - 'displayed when the issuer_checks option is set.'), - - 30: ('X509_V_ERR_AKID_SKID_MISMATCH', - 'authority and subject key identifier mismatch', - 'The current candidate issuer certificate was ' - 'rejected because its subject key identifier was ' - 'present and did not match the authority key ' - 'identifier current certificate. Only displayed ' - 'when the issuer_checks option is set.'), - - 31: ('X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH', - 'authority and issuer serial number mismatch', - 'The current candidate issuer certificate was ' - 'rejected because its issuer name and serial ' - 'number was present and did not match the ' - 'authority key identifier of the current ' - 'certificate. Only displayed when the issuer_checks ' - 'option is set.'), - - 32: ('X509_V_ERR_KEYUSAGE_NO_CERTSIGN', - 'key usage does not include certificate', - 'Signing the current candidate issuer certificate was ' - 'rejected because its keyUsage extension does not ' - 'permit certificate signing.'), - - 50: ('X509_V_ERR_APPLICATION_VERIFICATION', - 'application verification failure', - 'an application specific error. Unused.')} - - - def __init__(self, cert, errno, depth): - VerifyError.__init__(self, cert, errno, depth) - self.cert = cert - self.errno = errno - self.depth = depth - - def __repr__(self): - x = self._errorCodes.get(self.errno) - if x is not None: - name, short, long = x - return 'Peer Certificate Verification Failed: %s (error code: %d)' % ( - long, self.errno - ) - return "Peer Certificate Verification Failed for Unknown Reason" - - __str__ = __repr__ - - -_x509names = { - 'CN': 'commonName', - 'commonName': 'commonName', - - 'O': 'organizationName', - 'organizationName': 'organizationName', - - 'OU': 'organizationalUnitName', - 'organizationalUnitName': 'organizationalUnitName', - - 'L': 'localityName', - 'localityName': 'localityName', - - 'ST': 'stateOrProvinceName', - 'stateOrProvinceName': 'stateOrProvinceName', - - 'C': 'countryName', - 'countryName': 'countryName', - - 'emailAddress': 'emailAddress'} - - -class DistinguishedName(dict): - """ - Identify and describe an entity. - - Distinguished names are used to provide a minimal amount of identifying - information about a certificate issuer or subject. They are commonly - created with one or more of the following fields:: - - commonName (CN) - organizationName (O) - organizationalUnitName (OU) - localityName (L) - stateOrProvinceName (ST) - countryName (C) - emailAddress - """ - __slots__ = () - - def __init__(self, **kw): - for k, v in kw.iteritems(): - setattr(self, k, v) - - - def _copyFrom(self, x509name): - d = {} - for name in _x509names: - value = getattr(x509name, name, None) - if value is not None: - setattr(self, name, value) - - - def _copyInto(self, x509name): - for k, v in self.iteritems(): - setattr(x509name, k, v) - - - def __repr__(self): - return '' % (dict.__repr__(self)[1:-1]) - - - def __getattr__(self, attr): - try: - return self[_x509names[attr]] - except KeyError: - raise AttributeError(attr) - - - def __setattr__(self, attr, value): - assert type(attr) is str - if not attr in _x509names: - raise AttributeError("%s is not a valid OpenSSL X509 name field" % (attr,)) - realAttr = _x509names[attr] - value = value.encode('ascii') - assert type(value) is str - self[realAttr] = value - - - def inspect(self): - """ - Return a multi-line, human-readable representation of this DN. - """ - l = [] - lablen = 0 - def uniqueValues(mapping): - return dict.fromkeys(mapping.itervalues()).keys() - for k in uniqueValues(_x509names): - label = util.nameToLabel(k) - lablen = max(len(label), lablen) - v = getattr(self, k, None) - if v is not None: - l.append((label, v)) - lablen += 2 - for n, (label, attr) in enumerate(l): - l[n] = (label.rjust(lablen)+': '+ attr) - return '\n'.join(l) - -DN = DistinguishedName - - -class CertBase: - def __init__(self, original): - self.original = original - - def _copyName(self, suffix): - dn = DistinguishedName() - dn._copyFrom(getattr(self.original, 'get_'+suffix)()) - return dn - - def getSubject(self): - """ - Retrieve the subject of this certificate. - - @rtype: L{DistinguishedName} - @return: A copy of the subject of this certificate. - """ - return self._copyName('subject') - - - -def problemsFromTransport(tpt): - """ - Retrieve the SSL errors associated with the given transport. - - @type tpt: L{ISystemHandle} provider wrapper around an SSL connection. - @rtype: C{list} of L{OpenSSLVerifyError}. - """ - return tpt.getHandle().get_context().get_app_data().problems - - -def _handleattrhelper(Class, transport, methodName): - """ - (private) Helper for L{Certificate.peerFromTransport} and - L{Certificate.hostFromTransport} which checks for incompatible handle types - and null certificates and raises the appropriate exception or returns the - appropriate certificate object. - """ - method = getattr(transport.getHandle(), - "get_%s_certificate" % (methodName,), None) - if method is None: - raise CertificateError( - "non-TLS transport %r did not have %s certificate" % (transport, methodName)) - cert = method() - if cert is None: - raise CertificateError( - "TLS transport %r did not have %s certificate" % (transport, methodName)) - return Class(cert) - - -class Certificate(CertBase): - """ - An x509 certificate. - """ - def __repr__(self): - return '<%s Subject=%s Issuer=%s>' % (self.__class__.__name__, - self.getSubject().commonName, - self.getIssuer().commonName) - - def __eq__(self, other): - if isinstance(other, Certificate): - return self.dump() == other.dump() - return False - - - def __ne__(self, other): - return not self.__eq__(other) - - - def load(Class, requestData, format=crypto.FILETYPE_ASN1, args=()): - """ - Load a certificate from an ASN.1- or PEM-format string. - - @rtype: C{Class} - """ - return Class(crypto.load_certificate(format, requestData), *args) - load = classmethod(load) - _load = load - - - def dumpPEM(self): - """ - Dump this certificate to a PEM-format data string. - - @rtype: C{str} - """ - return self.dump(crypto.FILETYPE_PEM) - - - def loadPEM(Class, data): - """ - Load a certificate from a PEM-format data string. - - @rtype: C{Class} - """ - return Class.load(data, crypto.FILETYPE_PEM) - loadPEM = classmethod(loadPEM) - - - def peerFromTransport(Class, transport): - """ - Get the certificate for the remote end of the given transport. - - @type: L{ISystemHandle} - @rtype: C{Class} - - @raise: L{CertificateError}, if the given transport does not have a peer - certificate. - """ - return _handleattrhelper(Class, transport, 'peer') - peerFromTransport = classmethod(peerFromTransport) - - - def hostFromTransport(Class, transport): - """ - Get the certificate for the local end of the given transport. - - @param transport: an L{ISystemHandle} provider; the transport we will - - @rtype: C{Class} - - @raise: L{CertificateError}, if the given transport does not have a host - certificate. - """ - return _handleattrhelper(Class, transport, 'host') - hostFromTransport = classmethod(hostFromTransport) - - - def getPublicKey(self): - """ - Get the public key for this certificate. - - @rtype: L{PublicKey} - """ - return PublicKey(self.original.get_pubkey()) - - - def dump(self, format=crypto.FILETYPE_ASN1): - return crypto.dump_certificate(format, self.original) - - - def serialNumber(self): - """ - Retrieve the serial number of this certificate. - - @rtype: C{int} - """ - return self.original.get_serial_number() - - - def digest(self, method='md5'): - """ - Return a digest hash of this certificate using the specified hash - algorithm. - - @param method: One of C{'md5'} or C{'sha'}. - @rtype: C{str} - """ - return self.original.digest(method) - - - def _inspect(self): - return '\n'.join(['Certificate For Subject:', - self.getSubject().inspect(), - '\nIssuer:', - self.getIssuer().inspect(), - '\nSerial Number: %d' % self.serialNumber(), - 'Digest: %s' % self.digest()]) - - - def inspect(self): - """ - Return a multi-line, human-readable representation of this - Certificate, including information about the subject, issuer, and - public key. - """ - return '\n'.join((self._inspect(), self.getPublicKey().inspect())) - - - def getIssuer(self): - """ - Retrieve the issuer of this certificate. - - @rtype: L{DistinguishedName} - @return: A copy of the issuer of this certificate. - """ - return self._copyName('issuer') - - - def options(self, *authorities): - raise NotImplementedError('Possible, but doubtful we need this yet') - - - -class CertificateRequest(CertBase): - """ - An x509 certificate request. - - Certificate requests are given to certificate authorities to be signed and - returned resulting in an actual certificate. - """ - def load(Class, requestData, requestFormat=crypto.FILETYPE_ASN1): - req = crypto.load_certificate_request(requestFormat, requestData) - dn = DistinguishedName() - dn._copyFrom(req.get_subject()) - if not req.verify(req.get_pubkey()): - raise VerifyError("Can't verify that request for %r is self-signed." % (dn,)) - return Class(req) - load = classmethod(load) - - - def dump(self, format=crypto.FILETYPE_ASN1): - return crypto.dump_certificate_request(format, self.original) - - - -class PrivateCertificate(Certificate): - """ - An x509 certificate and private key. - """ - def __repr__(self): - return Certificate.__repr__(self) + ' with ' + repr(self.privateKey) - - - def _setPrivateKey(self, privateKey): - if not privateKey.matches(self.getPublicKey()): - raise VerifyError( - "Sanity check failed: Your certificate was not properly signed.") - self.privateKey = privateKey - return self - - - def newCertificate(self, newCertData, format=crypto.FILETYPE_ASN1): - """ - Create a new L{PrivateCertificate} from the given certificate data and - this instance's private key. - """ - return self.load(newCertData, self.privateKey, format) - - - def load(Class, data, privateKey, format=crypto.FILETYPE_ASN1): - return Class._load(data, format)._setPrivateKey(privateKey) - load = classmethod(load) - - - def inspect(self): - return '\n'.join([Certificate._inspect(self), - self.privateKey.inspect()]) - - - def dumpPEM(self): - """ - Dump both public and private parts of a private certificate to - PEM-format data. - """ - return self.dump(crypto.FILETYPE_PEM) + self.privateKey.dump(crypto.FILETYPE_PEM) - - - def loadPEM(Class, data): - """ - Load both private and public parts of a private certificate from a - chunk of PEM-format data. - """ - return Class.load(data, KeyPair.load(data, crypto.FILETYPE_PEM), - crypto.FILETYPE_PEM) - loadPEM = classmethod(loadPEM) - - - def fromCertificateAndKeyPair(Class, certificateInstance, privateKey): - privcert = Class(certificateInstance.original) - return privcert._setPrivateKey(privateKey) - fromCertificateAndKeyPair = classmethod(fromCertificateAndKeyPair) - - - def options(self, *authorities): - options = dict(privateKey=self.privateKey.original, - certificate=self.original) - if authorities: - options.update(dict(verify=True, - requireCertificate=True, - caCerts=[auth.original for auth in authorities])) - return OpenSSLCertificateOptions(**options) - - - def certificateRequest(self, format=crypto.FILETYPE_ASN1, - digestAlgorithm='md5'): - return self.privateKey.certificateRequest( - self.getSubject(), - format, - digestAlgorithm) - - - def signCertificateRequest(self, - requestData, - verifyDNCallback, - serialNumber, - requestFormat=crypto.FILETYPE_ASN1, - certificateFormat=crypto.FILETYPE_ASN1): - issuer = self.getSubject() - return self.privateKey.signCertificateRequest( - issuer, - requestData, - verifyDNCallback, - serialNumber, - requestFormat, - certificateFormat) - - - def signRequestObject(self, certificateRequest, serialNumber, - secondsToExpiry=60 * 60 * 24 * 365, # One year - digestAlgorithm='md5'): - return self.privateKey.signRequestObject(self.getSubject(), - certificateRequest, - serialNumber, - secondsToExpiry, - digestAlgorithm) - - -class PublicKey: - def __init__(self, osslpkey): - self.original = osslpkey - req1 = crypto.X509Req() - req1.set_pubkey(osslpkey) - self._emptyReq = crypto.dump_certificate_request(crypto.FILETYPE_ASN1, req1) - - - def matches(self, otherKey): - return self._emptyReq == otherKey._emptyReq - - - # XXX This could be a useful method, but sometimes it triggers a segfault, - # so we'll steer clear for now. -# def verifyCertificate(self, certificate): -# """ -# returns None, or raises a VerifyError exception if the certificate -# could not be verified. -# """ -# if not certificate.original.verify(self.original): -# raise VerifyError("We didn't sign that certificate.") - - def __repr__(self): - return '<%s %s>' % (self.__class__.__name__, self.keyHash()) - - - def keyHash(self): - """ - MD5 hex digest of signature on an empty certificate request with this - key. - """ - return md5.md5(self._emptyReq).hexdigest() - - - def inspect(self): - return 'Public Key with Hash: %s' % (self.keyHash(),) - - - -class KeyPair(PublicKey): - - def load(Class, data, format=crypto.FILETYPE_ASN1): - return Class(crypto.load_privatekey(format, data)) - load = classmethod(load) - - - def dump(self, format=crypto.FILETYPE_ASN1): - return crypto.dump_privatekey(format, self.original) - - - def __getstate__(self): - return self.dump() - - - def __setstate__(self, state): - self.__init__(crypto.load_privatekey(crypto.FILETYPE_ASN1, state)) - - - def inspect(self): - t = self.original.type() - if t == crypto.TYPE_RSA: - ts = 'RSA' - elif t == crypto.TYPE_DSA: - ts = 'DSA' - else: - ts = '(Unknown Type!)' - L = (self.original.bits(), ts, self.keyHash()) - return '%s-bit %s Key Pair with Hash: %s' % L - - - def generate(Class, kind=crypto.TYPE_RSA, size=1024): - pkey = crypto.PKey() - pkey.generate_key(kind, size) - return Class(pkey) - - - def newCertificate(self, newCertData, format=crypto.FILETYPE_ASN1): - return PrivateCertificate.load(newCertData, self, format) - generate = classmethod(generate) - - - def requestObject(self, distinguishedName, digestAlgorithm='md5'): - req = crypto.X509Req() - req.set_pubkey(self.original) - distinguishedName._copyInto(req.get_subject()) - req.sign(self.original, digestAlgorithm) - return CertificateRequest(req) - - - def certificateRequest(self, distinguishedName, - format=crypto.FILETYPE_ASN1, - digestAlgorithm='md5'): - """Create a certificate request signed with this key. - - @return: a string, formatted according to the 'format' argument. - """ - return self.requestObject(distinguishedName, digestAlgorithm).dump(format) - - - def signCertificateRequest(self, - issuerDistinguishedName, - requestData, - verifyDNCallback, - serialNumber, - requestFormat=crypto.FILETYPE_ASN1, - certificateFormat=crypto.FILETYPE_ASN1, - secondsToExpiry=60 * 60 * 24 * 365, # One year - digestAlgorithm='md5'): - """ - Given a blob of certificate request data and a certificate authority's - DistinguishedName, return a blob of signed certificate data. - - If verifyDNCallback returns a Deferred, I will return a Deferred which - fires the data when that Deferred has completed. - """ - hlreq = CertificateRequest.load(requestData, requestFormat) - - dn = hlreq.getSubject() - vval = verifyDNCallback(dn) - - def verified(value): - if not value: - raise VerifyError("DN callback %r rejected request DN %r" % (verifyDNCallback, dn)) - return self.signRequestObject(issuerDistinguishedName, hlreq, - serialNumber, secondsToExpiry, digestAlgorithm).dump(certificateFormat) - - if isinstance(vval, Deferred): - return vval.addCallback(verified) - else: - return verified(vval) - - - def signRequestObject(self, - issuerDistinguishedName, - requestObject, - serialNumber, - secondsToExpiry=60 * 60 * 24 * 365, # One year - digestAlgorithm='md5'): - """ - Sign a CertificateRequest instance, returning a Certificate instance. - """ - req = requestObject.original - dn = requestObject.getSubject() - cert = crypto.X509() - issuerDistinguishedName._copyInto(cert.get_issuer()) - cert.set_subject(req.get_subject()) - cert.set_pubkey(req.get_pubkey()) - cert.gmtime_adj_notBefore(0) - cert.gmtime_adj_notAfter(secondsToExpiry) - cert.set_serial_number(serialNumber) - cert.sign(self.original, digestAlgorithm) - return Certificate(cert) - - - def selfSignedCert(self, serialNumber, **kw): - dn = DN(**kw) - return PrivateCertificate.fromCertificateAndKeyPair( - self.signRequestObject(dn, self.requestObject(dn), serialNumber), - self) - - - -class OpenSSLCertificateOptions(object): - """ - A factory for SSL context objects for both SSL servers and clients. - """ - - _context = None - # Older versions of PyOpenSSL didn't provide OP_ALL. Fudge it here, just in case. - _OP_ALL = getattr(SSL, 'OP_ALL', 0x0000FFFF) - - method = SSL.TLSv1_METHOD - - def __init__(self, - privateKey=None, - certificate=None, - method=None, - verify=False, - caCerts=None, - verifyDepth=9, - requireCertificate=True, - verifyOnce=True, - enableSingleUseKeys=True, - enableSessions=True, - fixBrokenPeers=False): - """ - Create an OpenSSL context SSL connection context factory. - - @param privateKey: A PKey object holding the private key. - - @param certificate: An X509 object holding the certificate. - - @param method: The SSL protocol to use, one of SSLv23_METHOD, - SSLv2_METHOD, SSLv3_METHOD, TLSv1_METHOD. Defaults to TLSv1_METHOD. - - @param verify: If True, verify certificates received from the peer and - fail the handshake if verification fails. Otherwise, allow anonymous - sessions and sessions with certificates which fail validation. By - default this is False. - - @param caCerts: List of certificate authority certificates to - send to the client when requesting a certificate. Only used if verify - is True, and if verify is True, either this must be specified or - caCertsFile must be given. Since verify is False by default, - this is None by default. - - @param verifyDepth: Depth in certificate chain down to which to verify. - If unspecified, use the underlying default (9). - - @param requireCertificate: If True, do not allow anonymous sessions. - - @param verifyOnce: If True, do not re-verify the certificate - on session resumption. - - @param enableSingleUseKeys: If True, generate a new key whenever - ephemeral DH parameters are used to prevent small subgroup attacks. - - @param enableSessions: If True, set a session ID on each context. This - allows a shortened handshake to be used when a known client reconnects. - - @param fixBrokenPeers: If True, enable various non-spec protocol fixes - for broken SSL implementations. This should be entirely safe, - according to the OpenSSL documentation, but YMMV. This option is now - off by default, because it causes problems with connections between - peers using OpenSSL 0.9.8a. - """ - - assert (privateKey is None) == (certificate is None), "Specify neither or both of privateKey and certificate" - self.privateKey = privateKey - self.certificate = certificate - if method is not None: - self.method = method - - self.verify = verify - assert ((verify and caCerts) or - (not verify)), "Specify client CA certificate information if and only if enabling certificate verification" - - self.caCerts = caCerts - self.verifyDepth = verifyDepth - self.requireCertificate = requireCertificate - self.verifyOnce = verifyOnce - self.enableSingleUseKeys = enableSingleUseKeys - self.enableSessions = enableSessions - self.fixBrokenPeers = fixBrokenPeers - - - def __getstate__(self): - d = self.__dict__.copy() - try: - del d['_context'] - except KeyError: - pass - return d - - - def __setstate__(self, state): - self.__dict__ = state - - - def getContext(self): - """Return a SSL.Context object. - """ - if self._context is None: - self._context = self._makeContext() - return self._context - - - def _makeContext(self): - ctx = SSL.Context(self.method) - ctx.set_app_data(_SSLApplicationData()) - - if self.certificate is not None and self.privateKey is not None: - ctx.use_certificate(self.certificate) - ctx.use_privatekey(self.privateKey) - # Sanity check - ctx.check_privatekey() - - verifyFlags = SSL.VERIFY_NONE - if self.verify: - verifyFlags = SSL.VERIFY_PEER - if self.requireCertificate: - verifyFlags |= SSL.VERIFY_FAIL_IF_NO_PEER_CERT - if self.verifyOnce: - verifyFlags |= SSL.VERIFY_CLIENT_ONCE - if self.caCerts: - store = ctx.get_cert_store() - for cert in self.caCerts: - store.add_cert(cert) - - def _trackVerificationProblems(conn,cert,errno,depth,preverify_ok): - # retcode is the answer OpenSSL's default verifier would have - # given, had we allowed it to run. - if not preverify_ok: - ctx.get_app_data().problems.append(OpenSSLVerifyError(cert, errno, depth)) - return preverify_ok - ctx.set_verify(verifyFlags, _trackVerificationProblems) - - if self.verifyDepth is not None: - ctx.set_verify_depth(self.verifyDepth) - - if self.enableSingleUseKeys: - ctx.set_options(SSL.OP_SINGLE_DH_USE) - - if self.fixBrokenPeers: - ctx.set_options(self._OP_ALL) - - if self.enableSessions: - sessionName = md5.md5("%s-%d" % (reflect.qual(self.__class__), _sessionCounter())).hexdigest() - ctx.set_session_id(sessionName) - - return ctx diff --git a/tools/buildbot/pylibs/twisted/internet/_threadedselect.py b/tools/buildbot/pylibs/twisted/internet/_threadedselect.py deleted file mode 100644 index 9dc90a0..0000000 --- a/tools/buildbot/pylibs/twisted/internet/_threadedselect.py +++ /dev/null @@ -1,362 +0,0 @@ -# -*- test-case-name: twisted.test.test_internet -*- -# $Id: default.py,v 1.90 2004/01/06 22:35:22 warner Exp $ -# -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -from __future__ import generators - -""" -Threaded select reactor - -Maintainer: U{Bob Ippolito} - - -The threadedselectreactor is a specialized reactor for integrating with -arbitrary foreign event loop, such as those you find in GUI toolkits. - -There are three things you'll need to do to use this reactor. - -Install the reactor at the beginning of your program, before importing -the rest of Twisted:: - - | from twisted.internet import _threadedselect - | _threadedselect.install() - -Interleave this reactor with your foreign event loop, at some point after -your event loop is initialized:: - - | from twisted.internet import reactor - | reactor.interleave(foreignEventLoopWakerFunction) - | self.addSystemEventTrigger('after', 'shutdown', foreignEventLoopStop) - -Instead of shutting down the foreign event loop directly, shut down the -reactor:: - - | from twisted.internet import reactor - | reactor.stop() - -In order for Twisted to do its work in the main thread (the thread that -interleave is called from), a waker function is necessary. The waker function -will be called from a "background" thread with one argument: func. -The waker function's purpose is to call func() from the main thread. -Many GUI toolkits ship with appropriate waker functions. -Some examples of this are wxPython's wx.callAfter (may be wxCallAfter in -older versions of wxPython) or PyObjC's PyObjCTools.AppHelper.callAfter. -These would be used in place of "foreignEventLoopWakerFunction" in the above -example. - -The other integration point at which the foreign event loop and this reactor -must integrate is shutdown. In order to ensure clean shutdown of Twisted, -you must allow for Twisted to come to a complete stop before quitting the -application. Typically, you will do this by setting up an after shutdown -trigger to stop your foreign event loop, and call reactor.stop() where you -would normally have initiated the shutdown procedure for the foreign event -loop. Shutdown functions that could be used in place of -"foreignEventloopStop" would be the ExitMainLoop method of the wxApp instance -with wxPython, or the PyObjCTools.AppHelper.stopEventLoop function. -""" - -from threading import Thread -from Queue import Queue, Empty -from time import sleep -import sys - -from zope.interface import implements - -from twisted.internet.interfaces import IReactorFDSet -from twisted.internet import error -from twisted.internet import posixbase -from twisted.python import log, failure, threadable -from twisted.persisted import styles -from twisted.python.runtime import platformType - -import select -from errno import EINTR, EBADF - -from twisted.internet.selectreactor import _select - -# Exceptions that doSelect might return frequently -_NO_FILENO = error.ConnectionFdescWentAway('Handler has no fileno method') -_NO_FILEDESC = error.ConnectionFdescWentAway('Filedescriptor went away') - -def dictRemove(dct, value): - try: - del dct[value] - except KeyError: - pass - -def raiseException(e): - raise e - -class ThreadedSelectReactor(posixbase.PosixReactorBase): - """A threaded select() based reactor - runs on all POSIX platforms and on - Win32. - """ - implements(IReactorFDSet) - - def __init__(self): - threadable.init(1) - self.reads = {} - self.writes = {} - self.toThreadQueue = Queue() - self.toMainThread = Queue() - self.workerThread = None - self.mainWaker = None - posixbase.PosixReactorBase.__init__(self) - self.addSystemEventTrigger('after', 'shutdown', self._mainLoopShutdown) - - def wakeUp(self): - # we want to wake up from any thread - self.waker.wakeUp() - - def callLater(self, *args, **kw): - tple = posixbase.PosixReactorBase.callLater(self, *args, **kw) - self.wakeUp() - return tple - - def _sendToMain(self, msg, *args): - #print >>sys.stderr, 'sendToMain', msg, args - self.toMainThread.put((msg, args)) - if self.mainWaker is not None: - self.mainWaker() - - def _sendToThread(self, fn, *args): - #print >>sys.stderr, 'sendToThread', fn, args - self.toThreadQueue.put((fn, args)) - - def _preenDescriptorsInThread(self): - log.msg("Malformed file descriptor found. Preening lists.") - readers = self.reads.keys() - writers = self.writes.keys() - self.reads.clear() - self.writes.clear() - for selDict, selList in ((self.reads, readers), (self.writes, writers)): - for selectable in selList: - try: - select.select([selectable], [selectable], [selectable], 0) - except: - log.msg("bad descriptor %s" % selectable) - else: - selDict[selectable] = 1 - - def _workerInThread(self): - try: - while 1: - fn, args = self.toThreadQueue.get() - #print >>sys.stderr, "worker got", fn, args - fn(*args) - except SystemExit: - pass # exception indicates this thread should exit - except: - f = failure.Failure() - self._sendToMain('Failure', f) - #print >>sys.stderr, "worker finished" - - def _doSelectInThread(self, timeout): - """Run one iteration of the I/O monitor loop. - - This will run all selectables who had input or output readiness - waiting for them. - """ - reads = self.reads - writes = self.writes - while 1: - try: - r, w, ignored = _select(reads.keys(), - writes.keys(), - [], timeout) - break - except ValueError, ve: - # Possibly a file descriptor has gone negative? - log.err() - self._preenDescriptorsInThread() - except TypeError, te: - # Something *totally* invalid (object w/o fileno, non-integral - # result) was passed - log.err() - self._preenDescriptorsInThread() - except (select.error, IOError), se: - # select(2) encountered an error - if se.args[0] in (0, 2): - # windows does this if it got an empty list - if (not reads) and (not writes): - return - else: - raise - elif se.args[0] == EINTR: - return - elif se.args[0] == EBADF: - self._preenDescriptorsInThread() - else: - # OK, I really don't know what's going on. Blow up. - raise - self._sendToMain('Notify', r, w) - - def _process_Notify(self, r, w): - #print >>sys.stderr, "_process_Notify" - reads = self.reads - writes = self.writes - - _drdw = self._doReadOrWrite - _logrun = log.callWithLogger - for selectables, method, dct in ((r, "doRead", reads), (w, "doWrite", writes)): - for selectable in selectables: - # if this was disconnected in another thread, kill it. - if selectable not in dct: - continue - # This for pausing input when we're not ready for more. - _logrun(selectable, _drdw, selectable, method, dct) - #print >>sys.stderr, "done _process_Notify" - - def _process_Failure(self, f): - f.raiseException() - - _doIterationInThread = _doSelectInThread - - def ensureWorkerThread(self): - if self.workerThread is None or not self.workerThread.isAlive(): - self.workerThread = Thread(target=self._workerInThread) - self.workerThread.start() - - def doThreadIteration(self, timeout): - self._sendToThread(self._doIterationInThread, timeout) - self.ensureWorkerThread() - #print >>sys.stderr, 'getting...' - msg, args = self.toMainThread.get() - #print >>sys.stderr, 'got', msg, args - getattr(self, '_process_' + msg)(*args) - - doIteration = doThreadIteration - - def _interleave(self): - while self.running: - #print >>sys.stderr, "runUntilCurrent" - self.runUntilCurrent() - t2 = self.timeout() - t = self.running and t2 - self._sendToThread(self._doIterationInThread, t) - #print >>sys.stderr, "yielding" - yield None - #print >>sys.stderr, "fetching" - msg, args = self.toMainThread.get_nowait() - getattr(self, '_process_' + msg)(*args) - - def interleave(self, waker, *args, **kw): - """ - interleave(waker) interleaves this reactor with the - current application by moving the blocking parts of - the reactor (select() in this case) to a separate - thread. This is typically useful for integration with - GUI applications which have their own event loop - already running. - - See the module docstring for more information. - """ - self.startRunning(*args, **kw) - loop = self._interleave() - def mainWaker(waker=waker, loop=loop): - #print >>sys.stderr, "mainWaker()" - waker(loop.next) - self.mainWaker = mainWaker - loop.next() - self.ensureWorkerThread() - - def _mainLoopShutdown(self): - self.mainWaker = None - if self.workerThread is not None: - #print >>sys.stderr, 'getting...' - self._sendToThread(raiseException, SystemExit) - self.wakeUp() - try: - while 1: - msg, args = self.toMainThread.get_nowait() - #print >>sys.stderr, "ignored:", (msg, args) - except Empty: - pass - self.workerThread.join() - self.workerThread = None - try: - while 1: - fn, args = self.toThreadQueue.get_nowait() - if fn is self._doIterationInThread: - log.msg('Iteration is still in the thread queue!') - elif fn is raiseException and args[0] is SystemExit: - pass - else: - fn(*args) - except Empty: - pass - - def _doReadOrWrite(self, selectable, method, dict): - try: - why = getattr(selectable, method)() - handfn = getattr(selectable, 'fileno', None) - if not handfn: - why = _NO_FILENO - elif handfn() == -1: - why = _NO_FILEDESC - except: - why = sys.exc_info()[1] - log.err() - if why: - self._disconnectSelectable(selectable, why, method == "doRead") - - def addReader(self, reader): - """Add a FileDescriptor for notification of data available to read. - """ - self._sendToThread(self.reads.__setitem__, reader, 1) - self.wakeUp() - - def addWriter(self, writer): - """Add a FileDescriptor for notification of data available to write. - """ - self._sendToThread(self.writes.__setitem__, writer, 1) - self.wakeUp() - - def removeReader(self, reader): - """Remove a Selectable for notification of data available to read. - """ - self._sendToThread(dictRemove, self.reads, reader) - - def removeWriter(self, writer): - """Remove a Selectable for notification of data available to write. - """ - self._sendToThread(dictRemove, self.writes, writer) - - def removeAll(self): - return self._removeAll(self.reads, self.writes) - - - def getReaders(self): - return self.reads.keys() - - - def getWriters(self): - return self.writes.keys() - - - def run(self, installSignalHandlers=1): - self.startRunning(installSignalHandlers=installSignalHandlers) - self.mainLoop() - - def mainLoop(self): - q = Queue() - self.interleave(q.put) - while self.running: - try: - q.get()() - except StopIteration: - break - - - -def install(): - """Configure the twisted mainloop to be run using the select() reactor. - """ - reactor = ThreadedSelectReactor() - from twisted.internet.main import installReactor - installReactor(reactor) - return reactor - -__all__ = ['install'] diff --git a/tools/buildbot/pylibs/twisted/internet/_win32serialport.py b/tools/buildbot/pylibs/twisted/internet/_win32serialport.py deleted file mode 100644 index 576e7b4..0000000 --- a/tools/buildbot/pylibs/twisted/internet/_win32serialport.py +++ /dev/null @@ -1,112 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Serial port support for Windows. - -Requires PySerial and win32all, and needs to be used with win32event -reactor. -""" - -# system imports -import os -import serial -from serial import PARITY_NONE, PARITY_EVEN, PARITY_ODD -from serial import STOPBITS_ONE, STOPBITS_TWO -from serial import FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS -import win32file, win32event - -# twisted imports -from twisted.protocols import basic -from twisted.internet import abstract -from twisted.python import log - -# sibling imports -from serialport import BaseSerialPort - - -class SerialPort(BaseSerialPort, abstract.FileDescriptor): - """A select()able serial device, acting as a transport.""" - - connected = 1 - - def __init__(self, protocol, deviceNameOrPortNumber, reactor, - baudrate = 9600, bytesize = EIGHTBITS, parity = PARITY_NONE, - stopbits = STOPBITS_ONE, xonxoff = 0, rtscts = 0): - self._serial = serial.Serial(deviceNameOrPortNumber, baudrate=baudrate, - bytesize=bytesize, parity=parity, - stopbits=stopbits, timeout=None, - xonxoff=xonxoff, rtscts=rtscts) - self.flushInput() - self.flushOutput() - self.reactor = reactor - self.protocol = protocol - self.outQueue = [] - self.closed = 0 - self.closedNotifies = 0 - self.writeInProgress = 0 - - self.protocol = protocol - self._overlappedRead = win32file.OVERLAPPED() - self._overlappedRead.hEvent = win32event.CreateEvent(None, 1, 0, None) - self._overlappedWrite = win32file.OVERLAPPED() - self._overlappedWrite.hEvent = win32event.CreateEvent(None, 0, 0, None) - - self.reactor.addEvent(self._overlappedRead.hEvent, self, 'serialReadEvent') - self.reactor.addEvent(self._overlappedWrite.hEvent, self, 'serialWriteEvent') - - self.protocol.makeConnection(self) - - flags, comstat = win32file.ClearCommError(self._serial.hComPort) - rc, self.read_buf = win32file.ReadFile(self._serial.hComPort, - win32file.AllocateReadBuffer(1), - self._overlappedRead) - - def serialReadEvent(self): - #get that character we set up - n = win32file.GetOverlappedResult(self._serial.hComPort, self._overlappedRead, 0) - if n: - first = str(self.read_buf[:n]) - #now we should get everything that is already in the buffer - flags, comstat = win32file.ClearCommError(self._serial.hComPort) - if comstat.cbInQue: - win32event.ResetEvent(self._overlappedRead.hEvent) - rc, buf = win32file.ReadFile(self._serial.hComPort, - win32file.AllocateReadBuffer(comstat.cbInQue), - self._overlappedRead) - n = win32file.GetOverlappedResult(self._serial.hComPort, self._overlappedRead, 1) - #handle all the received data: - self.protocol.dataReceived(first + str(buf[:n])) - else: - #handle all the received data: - self.protocol.dataReceived(first) - - #set up next one - win32event.ResetEvent(self._overlappedRead.hEvent) - rc, self.read_buf = win32file.ReadFile(self._serial.hComPort, - win32file.AllocateReadBuffer(1), - self._overlappedRead) - - def write(self, data): - if data: - if self.writeInProgress: - self.outQueue.append(data) - else: - self.writeInProgress = 1 - win32file.WriteFile(self._serial.hComPort, data, self._overlappedWrite) - - def serialWriteEvent(self): - try: - dataToWrite = self.outQueue.pop(0) - except IndexError: - self.writeInProgress = 0 - return - else: - win32file.WriteFile(self._serial.hComPort, dataToWrite, self._overlappedWrite) - - def connectionLost(self, reason): - self.reactor.removeEvent(self._overlappedRead.hEvent) - self.reactor.removeEvent(self._overlappedWrite.hEvent) - abstract.FileDescriptor.connectionLost(self, reason) - self._serial.close() diff --git a/tools/buildbot/pylibs/twisted/internet/_win32stdio.py b/tools/buildbot/pylibs/twisted/internet/_win32stdio.py deleted file mode 100644 index b87f7a3..0000000 --- a/tools/buildbot/pylibs/twisted/internet/_win32stdio.py +++ /dev/null @@ -1,116 +0,0 @@ -# -*- test-case-name: twisted.test.test_process.ProcessTestCase.testStdio -*- - -import win32api -import os, msvcrt - -from zope.interface import implements - -from twisted.internet.interfaces import IHalfCloseableProtocol, ITransport, IAddress -from twisted.internet.interfaces import IConsumer, IPushProducer - -from twisted.internet import _pollingfile, main - -class Win32PipeAddress(object): - implements(IAddress) - -class StandardIO(_pollingfile._PollingTimer): - - implements(ITransport, - IConsumer, - IPushProducer) - - disconnecting = False - disconnected = False - - def __init__(self, proto): - """ - Start talking to standard IO with the given protocol. - - Also, put it stdin/stdout/stderr into binary mode. - """ - from twisted.internet import reactor - - for stdfd in range(0, 1, 2): - msvcrt.setmode(stdfd, os.O_BINARY) - - _pollingfile._PollingTimer.__init__(self, reactor) - self.proto = proto - - hstdin = win32api.GetStdHandle(win32api.STD_INPUT_HANDLE) - hstdout = win32api.GetStdHandle(win32api.STD_OUTPUT_HANDLE) - - self.stdin = _pollingfile._PollableReadPipe( - hstdin, self.dataReceived, self.readConnectionLost) - - self.stdout = _pollingfile._PollableWritePipe( - hstdout, self.writeConnectionLost) - - self._addPollableResource(self.stdin) - self._addPollableResource(self.stdout) - - self.proto.makeConnection(self) - - def dataReceived(self, data): - self.proto.dataReceived(data) - - def readConnectionLost(self): - if IHalfCloseableProtocol.providedBy(self.proto): - self.proto.readConnectionLost() - self.checkConnLost() - - def writeConnectionLost(self): - if IHalfCloseableProtocol.providedBy(self.proto): - self.proto.writeConnectionLost() - self.checkConnLost() - - connsLost = 0 - - def checkConnLost(self): - self.connsLost += 1 - if self.connsLost >= 2: - self.disconnecting = True - self.disconnected = True - self.proto.connectionLost(main.CONNECTION_DONE) - - # ITransport - - def write(self, data): - self.stdout.write(data) - - def writeSequence(self, seq): - self.stdout.write(''.join(seq)) - - def loseConnection(self): - self.disconnecting = True - self.stdin.close() - self.stdout.close() - - def getPeer(self): - return Win32PipeAddress() - - def getHost(self): - return Win32PipeAddress() - - # IConsumer - - def registerProducer(self, producer, streaming): - return self.stdout.registerProducer(producer, streaming) - - def unregisterProducer(self): - return self.stdout.unregisterProducer() - - # def write() above - - # IProducer - - def stopProducing(self): - self.stdin.stopProducing() - - # IPushProducer - - def pauseProducing(self): - self.stdin.pauseProducing() - - def resumeProducing(self): - self.stdin.resumeProducing() - diff --git a/tools/buildbot/pylibs/twisted/internet/abstract.py b/tools/buildbot/pylibs/twisted/internet/abstract.py deleted file mode 100644 index cc6db47..0000000 --- a/tools/buildbot/pylibs/twisted/internet/abstract.py +++ /dev/null @@ -1,368 +0,0 @@ -# -*- test-case-name: twisted.test.test_abstract -*- -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Support for generic select()able objects. - -Maintainer: U{Itamar Shtull-Trauring} -""" - -from zope.interface import implements - -# Twisted Imports -from twisted.python import log, reflect, failure -from twisted.persisted import styles -from twisted.internet import interfaces, main - - -class FileDescriptor(log.Logger, styles.Ephemeral, object): - """An object which can be operated on by select(). - - This is an abstract superclass of all objects which may be notified when - they are readable or writable; e.g. they have a file-descriptor that is - valid to be passed to select(2). - """ - connected = 0 - producerPaused = 0 - streamingProducer = 0 - producer = None - disconnected = 0 - disconnecting = 0 - _writeDisconnecting = False - _writeDisconnected = False - dataBuffer = "" - offset = 0 - - SEND_LIMIT = 128*1024 - - implements(interfaces.IProducer, interfaces.IReadWriteDescriptor, - interfaces.IConsumer, interfaces.ITransport, interfaces.IHalfCloseableDescriptor) - - def __init__(self, reactor=None): - if not reactor: - from twisted.internet import reactor - self.reactor = reactor - self._tempDataBuffer = [] # will be added to dataBuffer in doWrite - self._tempDataLen = 0 - - def connectionLost(self, reason): - """The connection was lost. - - This is called when the connection on a selectable object has been - lost. It will be called whether the connection was closed explicitly, - an exception occurred in an event handler, or the other end of the - connection closed it first. - - Clean up state here, but make sure to call back up to FileDescriptor. - """ - - self.disconnected = 1 - self.connected = 0 - if self.producer is not None: - self.producer.stopProducing() - self.producer = None - self.stopReading() - self.stopWriting() - - def writeSomeData(self, data): - """Write as much as possible of the given data, immediately. - - This is called to invoke the lower-level writing functionality, such as - a socket's send() method, or a file's write(); this method returns an - integer. If positive, it is the number of bytes written; if negative, - it indicates the connection was lost. - """ - - raise NotImplementedError("%s does not implement writeSomeData" % - reflect.qual(self.__class__)) - - def doRead(self): - """Called when data is avaliable for reading. - - Subclasses must override this method. The result will be interpreted - in the same way as a result of doWrite(). - """ - raise NotImplementedError("%s does not implement doRead" % - reflect.qual(self.__class__)) - - def doWrite(self): - """Called when data can be written. - - A result that is true (which will be a negative number) implies the - connection was lost. A false result implies the connection is still - there; a result of 0 implies no write was done, and a result of None - indicates that a write was done. - """ - if len(self.dataBuffer) - self.offset < self.SEND_LIMIT: - # If there is currently less than SEND_LIMIT bytes left to send - # in the string, extend it with the array data. - self.dataBuffer = buffer(self.dataBuffer, self.offset) + "".join(self._tempDataBuffer) - self.offset = 0 - self._tempDataBuffer = [] - self._tempDataLen = 0 - - # Send as much data as you can. - if self.offset: - l = self.writeSomeData(buffer(self.dataBuffer, self.offset)) - else: - l = self.writeSomeData(self.dataBuffer) - if l < 0 or isinstance(l, Exception): - return l - if l == 0 and self.dataBuffer: - result = 0 - else: - result = None - self.offset += l - # If there is nothing left to send, - if self.offset == len(self.dataBuffer) and not self._tempDataLen: - self.dataBuffer = "" - self.offset = 0 - # stop writing. - self.stopWriting() - # If I've got a producer who is supposed to supply me with data, - if self.producer is not None and ((not self.streamingProducer) - or self.producerPaused): - # tell them to supply some more. - self.producerPaused = 0 - self.producer.resumeProducing() - elif self.disconnecting: - # But if I was previously asked to let the connection die, do - # so. - return self._postLoseConnection() - elif self._writeDisconnecting: - # I was previously asked to to half-close the connection. - result = self._closeWriteConnection() - self._writeDisconnected = True - return result - return result - - def _postLoseConnection(self): - """Called after a loseConnection(), when all data has been written. - - Whatever this returns is then returned by doWrite. - """ - # default implementation, telling reactor we're finished - return main.CONNECTION_DONE - - def _closeWriteConnection(self): - # override in subclasses - pass - - def writeConnectionLost(self, reason): - # in current code should never be called - self.connectionLost(reason) - - def readConnectionLost(self, reason): - # override in subclasses - self.connectionLost(reason) - - def write(self, data): - """Reliably write some data. - - The data is buffered until the underlying file descriptor is ready - for writing. If there is more than C{self.bufferSize} data in the - buffer and this descriptor has a registered streaming producer, its - C{pauseProducing()} method will be called. - """ - if isinstance(data, unicode): # no, really, I mean it - raise TypeError("Data must not be unicode") - if not self.connected or self._writeDisconnected: - return - if data: - self._tempDataBuffer.append(data) - self._tempDataLen += len(data) - # If we are responsible for pausing our producer, - if self.producer is not None and self.streamingProducer: - # and our buffer is full, - if len(self.dataBuffer) + self._tempDataLen > self.bufferSize: - # pause it. - self.producerPaused = 1 - self.producer.pauseProducing() - self.startWriting() - - def writeSequence(self, iovec): - """Reliably write a sequence of data. - - Currently, this is a convenience method roughly equivalent to:: - - for chunk in iovec: - fd.write(chunk) - - It may have a more efficient implementation at a later time or in a - different reactor. - - As with the C{write()} method, if a buffer size limit is reached and a - streaming producer is registered, it will be paused until the buffered - data is written to the underlying file descriptor. - """ - if not self.connected or not iovec or self._writeDisconnected: - return - self._tempDataBuffer.extend(iovec) - for i in iovec: - self._tempDataLen += len(i) - # If we are responsible for pausing our producer, - if self.producer is not None and self.streamingProducer: - # and our buffer is full, - if len(self.dataBuffer) + self._tempDataLen > self.bufferSize: - # pause it. - self.producerPaused = 1 - self.producer.pauseProducing() - self.startWriting() - - def loseConnection(self, _connDone=failure.Failure(main.CONNECTION_DONE)): - """Close the connection at the next available opportunity. - - Call this to cause this FileDescriptor to lose its connection. It will - first write any data that it has buffered. - - If there is data buffered yet to be written, this method will cause the - transport to lose its connection as soon as it's done flushing its - write buffer. If you have a producer registered, the connection won't - be closed until the producer is finished. Therefore, make sure you - unregister your producer when it's finished, or the connection will - never close. - """ - - if self.connected and not self.disconnecting: - if self._writeDisconnected: - # doWrite won't trigger the connection close anymore - self.stopReading() - self.stopWriting() - self.connectionLost(_connDone) - else: - self.stopReading() - self.startWriting() - self.disconnecting = 1 - - def loseWriteConnection(self): - self._writeDisconnecting = True - self.startWriting() - - def stopReading(self): - """Stop waiting for read availability. - - Call this to remove this selectable from being notified when it is - ready for reading. - """ - self.reactor.removeReader(self) - - def stopWriting(self): - """Stop waiting for write availability. - - Call this to remove this selectable from being notified when it is ready - for writing. - """ - self.reactor.removeWriter(self) - - def startReading(self): - """Start waiting for read availability. - """ - self.reactor.addReader(self) - - def startWriting(self): - """Start waiting for write availability. - - Call this to have this FileDescriptor be notified whenever it is ready for - writing. - """ - self.reactor.addWriter(self) - - # Producer/consumer implementation - - # first, the consumer stuff. This requires no additional work, as - # any object you can write to can be a consumer, really. - - producer = None - bufferSize = 2**2**2**2 - - def registerProducer(self, producer, streaming): - """Register to receive data from a producer. - - This sets this selectable to be a consumer for a producer. When this - selectable runs out of data on a write() call, it will ask the producer - to resumeProducing(). When the FileDescriptor's internal data buffer is - filled, it will ask the producer to pauseProducing(). If the connection - is lost, FileDescriptor calls producer's stopProducing() method. - - If streaming is true, the producer should provide the IPushProducer - interface. Otherwise, it is assumed that producer provides the - IPullProducer interface. In this case, the producer won't be asked - to pauseProducing(), but it has to be careful to write() data only - when its resumeProducing() method is called. - """ - if self.producer is not None: - raise RuntimeError("Cannot register producer %s, because producer %s was never unregistered." % (producer, self.producer)) - if self.disconnected: - producer.stopProducing() - else: - self.producer = producer - self.streamingProducer = streaming - if not streaming: - producer.resumeProducing() - - def unregisterProducer(self): - """Stop consuming data from a producer, without disconnecting. - """ - self.producer = None - - def stopConsuming(self): - """Stop consuming data. - - This is called when a producer has lost its connection, to tell the - consumer to go lose its connection (and break potential circular - references). - """ - self.unregisterProducer() - self.loseConnection() - - # producer interface implementation - - def resumeProducing(self): - assert self.connected and not self.disconnecting - self.startReading() - - def pauseProducing(self): - self.stopReading() - - def stopProducing(self): - self.loseConnection() - - - def fileno(self): - """File Descriptor number for select(). - - This method must be overridden or assigned in subclasses to - indicate a valid file descriptor for the operating system. - """ - return -1 - - -def isIPAddress(addr): - """ - Determine whether the given string represents an IPv4 address. - - @type addr: C{str} - @param addr: A string which may or may not be the decimal dotted - representation of an IPv4 address. - - @rtype: C{bool} - @return: C{True} if C{addr} represents an IPv4 address, C{False} - otherwise. - """ - dottedParts = addr.split('.') - if len(dottedParts) == 4: - for octet in dottedParts: - try: - value = int(octet) - except ValueError: - return False - else: - if value < 0 or value > 255: - return False - return True - return False - - -__all__ = ["FileDescriptor"] diff --git a/tools/buildbot/pylibs/twisted/internet/address.py b/tools/buildbot/pylibs/twisted/internet/address.py deleted file mode 100644 index b349080..0000000 --- a/tools/buildbot/pylibs/twisted/internet/address.py +++ /dev/null @@ -1,113 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Address objects for network connections.""" - -import warnings, os -from zope.interface import implements -from twisted.internet.interfaces import IAddress - - -class IPv4Address(object): - """ - Object representing an IPv4 socket endpoint. - - @ivar type: A string describing the type of transport, either 'TCP' or 'UDP'. - @ivar host: A string containing the dotted-quad IP address. - @ivar port: An integer representing the port number. - """ - - # _bwHack is given to old users who think we are a tuple. They expected - # addr[0] to define the socket type rather than the address family, so - # the value comes from a different namespace than the new .type value: - - # type = map[_bwHack] - # map = { 'SSL': 'TCP', 'INET': 'TCP', 'INET_UDP': 'UDP' } - - implements(IAddress) - - def __init__(self, type, host, port, _bwHack = None): - assert type in ('TCP', 'UDP') - self.type = type - self.host = host - self.port = port - self._bwHack = _bwHack - - def __getitem__(self, index): - warnings.warn("IPv4Address.__getitem__ is deprecated. Use attributes instead.", - category=DeprecationWarning, stacklevel=2) - return (self._bwHack or self.type, self.host, self.port).__getitem__(index) - - def __getslice__(self, start, stop): - warnings.warn("IPv4Address.__getitem__ is deprecated. Use attributes instead.", - category=DeprecationWarning, stacklevel=2) - return (self._bwHack or self.type, self.host, self.port)[start:stop] - - def __eq__(self, other): - if isinstance(other, tuple): - return tuple(self) == other - elif isinstance(other, IPv4Address): - a = (self.type, self.host, self.port) - b = (other.type, other.host, other.port) - return a == b - return False - - def __str__(self): - return 'IPv4Address(%s, %r, %d)' % (self.type, self.host, self.port) - - -class UNIXAddress(object): - """ - Object representing a UNIX socket endpoint. - - @ivar name: The filename associated with this socket. - @type name: C{str} - """ - - implements(IAddress) - - def __init__(self, name, _bwHack='UNIX'): - self.name = name - self._bwHack = _bwHack - - def __getitem__(self, index): - warnings.warn("UNIXAddress.__getitem__ is deprecated. Use attributes instead.", - category=DeprecationWarning, stacklevel=2) - return (self._bwHack, self.name).__getitem__(index) - - def __getslice__(self, start, stop): - warnings.warn("UNIXAddress.__getitem__ is deprecated. Use attributes instead.", - category=DeprecationWarning, stacklevel=2) - return (self._bwHack, self.name)[start:stop] - - def __eq__(self, other): - if isinstance(other, tuple): - return tuple(self) == other - elif isinstance(other, UNIXAddress): - try: - return os.path.samefile(self.name, other.name) - except OSError: - pass - return False - - def __str__(self): - return 'UNIXSocket(%r)' % (self.name,) - - -# These are for buildFactory backwards compatability due to -# stupidity-induced inconsistency. - -class _ServerFactoryIPv4Address(IPv4Address): - """Backwards compatability hack. Just like IPv4Address in practice.""" - - def __eq__(self, other): - if isinstance(other, tuple): - warnings.warn("IPv4Address.__getitem__ is deprecated. Use attributes instead.", - category=DeprecationWarning, stacklevel=2) - return (self.host, self.port) == other - elif isinstance(other, IPv4Address): - a = (self.type, self.host, self.port) - b = (other.type, other.host, other.port) - return a == b - return False diff --git a/tools/buildbot/pylibs/twisted/internet/base.py b/tools/buildbot/pylibs/twisted/internet/base.py deleted file mode 100644 index 0d700f8..0000000 --- a/tools/buildbot/pylibs/twisted/internet/base.py +++ /dev/null @@ -1,1069 +0,0 @@ -# -*- test-case-name: twisted.test.test_internet -*- -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Very basic functionality for a Reactor implementation. - -Maintainer: U{Itamar Shtull-Trauring} -""" - -import socket # needed only for sync-dns -from zope.interface import implements, classImplements - -import sys -import warnings -import operator -from heapq import heappush, heappop, heapify - -try: - import fcntl -except ImportError: - fcntl = None -import traceback - -from twisted.internet.interfaces import IReactorCore, IReactorTime, IReactorThreads -from twisted.internet.interfaces import IResolverSimple, IReactorPluggableResolver -from twisted.internet.interfaces import IConnector, IDelayedCall -from twisted.internet import main, error, abstract, defer, threads -from twisted.python import log, failure, reflect -from twisted.python.runtime import seconds as runtimeSeconds, platform, platformType -from twisted.internet.defer import Deferred, DeferredList -from twisted.persisted import styles - -# This import is for side-effects! Even if you don't see any code using it -# in this module, don't delete it. -from twisted.python import threadable - - -class DelayedCall(styles.Ephemeral): - - implements(IDelayedCall) - # enable .debug to record creator call stack, and it will be logged if - # an exception occurs while the function is being run - debug = False - _str = None - - def __init__(self, time, func, args, kw, cancel, reset, - seconds=runtimeSeconds): - """ - @param time: Seconds from the epoch at which to call C{func}. - @param func: The callable to call. - @param args: The positional arguments to pass to the callable. - @param kw: The keyword arguments to pass to the callable. - @param cancel: A callable which will be called with this - DelayedCall before cancellation. - @param reset: A callable which will be called with this - DelayedCall after changing this DelayedCall's scheduled - execution time. The callable should adjust any necessary - scheduling details to ensure this DelayedCall is invoked - at the new appropriate time. - @param seconds: If provided, a no-argument callable which will be - used to determine the current time any time that information is - needed. - """ - self.time, self.func, self.args, self.kw = time, func, args, kw - self.resetter = reset - self.canceller = cancel - self.seconds = seconds - self.cancelled = self.called = 0 - self.delayed_time = 0 - if self.debug: - self.creator = traceback.format_stack()[:-2] - - def getTime(self): - """Return the time at which this call will fire - - @rtype: C{float} - @return: The number of seconds after the epoch at which this call is - scheduled to be made. - """ - return self.time + self.delayed_time - - def cancel(self): - """Unschedule this call - - @raise AlreadyCancelled: Raised if this call has already been - unscheduled. - - @raise AlreadyCalled: Raised if this call has already been made. - """ - if self.cancelled: - raise error.AlreadyCancelled - elif self.called: - raise error.AlreadyCalled - else: - self.canceller(self) - self.cancelled = 1 - if self.debug: - self._str = str(self) - del self.func, self.args, self.kw - - def reset(self, secondsFromNow): - """Reschedule this call for a different time - - @type secondsFromNow: C{float} - @param secondsFromNow: The number of seconds from the time of the - C{reset} call at which this call will be scheduled. - - @raise AlreadyCancelled: Raised if this call has been cancelled. - @raise AlreadyCalled: Raised if this call has already been made. - """ - if self.cancelled: - raise error.AlreadyCancelled - elif self.called: - raise error.AlreadyCalled - else: - newTime = self.seconds() + secondsFromNow - if newTime < self.time: - self.delayed_time = 0 - self.time = newTime - self.resetter(self) - else: - self.delayed_time = newTime - self.time - - def delay(self, secondsLater): - """Reschedule this call for a later time - - @type secondsLater: C{float} - @param secondsLater: The number of seconds after the originally - scheduled time for which to reschedule this call. - - @raise AlreadyCancelled: Raised if this call has been cancelled. - @raise AlreadyCalled: Raised if this call has already been made. - """ - if self.cancelled: - raise error.AlreadyCancelled - elif self.called: - raise error.AlreadyCalled - else: - self.delayed_time += secondsLater - if self.delayed_time < 0: - self.activate_delay() - self.resetter(self) - - def activate_delay(self): - self.time += self.delayed_time - self.delayed_time = 0 - - def active(self): - """Determine whether this call is still pending - - @rtype: C{bool} - @return: True if this call has not yet been made or cancelled, - False otherwise. - """ - return not (self.cancelled or self.called) - - def __le__(self, other): - return self.time <= other.time - - def __str__(self): - if self._str is not None: - return self._str - if hasattr(self, 'func'): - if hasattr(self.func, 'func_name'): - func = self.func.func_name - if hasattr(self.func, 'im_class'): - func = self.func.im_class.__name__ + '.' + func - else: - func = reflect.safe_repr(self.func) - else: - func = None - - now = self.seconds() - L = ["') - - return "".join(L) - - -class ThreadedResolver: - implements(IResolverSimple) - - def __init__(self, reactor): - self.reactor = reactor - self._runningQueries = {} - - def _fail(self, name, err): - err = error.DNSLookupError("address %r not found: %s" % (name, err)) - return failure.Failure(err) - - def _cleanup(self, name, lookupDeferred): - userDeferred, cancelCall = self._runningQueries[lookupDeferred] - del self._runningQueries[lookupDeferred] - userDeferred.errback(self._fail(name, "timeout error")) - - def _checkTimeout(self, result, name, lookupDeferred): - try: - userDeferred, cancelCall = self._runningQueries[lookupDeferred] - except KeyError: - pass - else: - del self._runningQueries[lookupDeferred] - cancelCall.cancel() - - if isinstance(result, failure.Failure): - userDeferred.errback(self._fail(name, result.getErrorMessage())) - else: - userDeferred.callback(result) - - def getHostByName(self, name, timeout = (1, 3, 11, 45)): - if timeout: - timeoutDelay = reduce(operator.add, timeout) - else: - timeoutDelay = 60 - userDeferred = defer.Deferred() - lookupDeferred = threads.deferToThread(socket.gethostbyname, name) - cancelCall = self.reactor.callLater( - timeoutDelay, self._cleanup, name, lookupDeferred) - self._runningQueries[lookupDeferred] = (userDeferred, cancelCall) - lookupDeferred.addBoth(self._checkTimeout, name, lookupDeferred) - return userDeferred - -class BlockingResolver: - implements(IResolverSimple) - - def getHostByName(self, name, timeout = (1, 3, 11, 45)): - try: - address = socket.gethostbyname(name) - except socket.error: - msg = "address %r not found" % (name,) - err = error.DNSLookupError(msg) - return defer.fail(err) - else: - return defer.succeed(address) - - -class _ThreePhaseEvent(object): - """ - Collection of callables (with arguments) which can be invoked as a group in - a particular order. - - This provides the underlying implementation for the reactor's system event - triggers. An instance of this class tracks triggers for all phases of a - single type of event. - - @ivar before: A list of the before-phase triggers containing three-tuples - of a callable, a tuple of positional arguments, and a dict of keyword - arguments - - @ivar finishedBefore: A list of the before-phase triggers which have - already been executed. This is only populated in the C{'BEFORE'} state. - - @ivar during: A list of the during-phase triggers containing three-tuples - of a callable, a tuple of positional arguments, and a dict of keyword - arguments - - @ivar after: A list of the after-phase triggers containing three-tuples - of a callable, a tuple of positional arguments, and a dict of keyword - arguments - - @ivar state: A string indicating what is currently going on with this - object. One of C{'BASE'} (for when nothing in particular is happening; - this is the initial value), C{'BEFORE'} (when the before-phase triggers - are in the process of being executed). - """ - def __init__(self): - self.before = [] - self.during = [] - self.after = [] - self.state = 'BASE' - - - def addTrigger(self, phase, callable, *args, **kwargs): - """ - Add a trigger to the indicate phase. - - @param phase: One of C{'before'}, C{'during'}, or C{'after'}. - - @param callable: An object to be called when this event is triggered. - @param *args: Positional arguments to pass to C{callable}. - @param **kwargs: Keyword arguments to pass to C{callable}. - - @return: An opaque handle which may be passed to L{removeTrigger} to - reverse the effects of calling this method. - """ - if phase not in ('before', 'during', 'after'): - raise KeyError("invalid phase") - getattr(self, phase).append((callable, args, kwargs)) - return phase, callable, args, kwargs - - - def removeTrigger(self, handle): - """ - Remove a previously added trigger callable. - - @param handle: An object previously returned by L{addTrigger}. The - trigger added by that call will be removed. - - @raise ValueError: If the trigger associated with C{handle} has already - been removed or if C{handle} is not a valid handle. - """ - return getattr(self, 'removeTrigger_' + self.state)(handle) - - - def removeTrigger_BASE(self, handle): - """ - Just try to remove the trigger. - - @see removeTrigger - """ - try: - phase, callable, args, kwargs = handle - except (TypeError, ValueError), e: - raise ValueError("invalid trigger handle") - else: - if phase not in ('before', 'during', 'after'): - raise KeyError("invalid phase") - getattr(self, phase).remove((callable, args, kwargs)) - - - def removeTrigger_BEFORE(self, handle): - """ - Remove the trigger if it has yet to be executed, otherwise emit a - warning that in the future an exception will be raised when removing an - already-executed trigger. - - @see removeTrigger - """ - phase, callable, args, kwargs = handle - if phase != 'before': - return self.removeTrigger_BASE(handle) - if (callable, args, kwargs) in self.finishedBefore: - warnings.warn( - "Removing already-fired system event triggers will raise an " - "exception in a future version of Twisted.", - category=DeprecationWarning, - stacklevel=3) - else: - self.removeTrigger_BASE(handle) - - - def fireEvent(self): - """ - Call the triggers added to this event. - """ - self.state = 'BEFORE' - self.finishedBefore = [] - beforeResults = [] - while self.before: - callable, args, kwargs = self.before.pop(0) - self.finishedBefore.append((callable, args, kwargs)) - try: - result = callable(*args, **kwargs) - except: - log.err() - else: - if isinstance(result, Deferred): - beforeResults.append(result) - DeferredList(beforeResults).addCallback(self._continueFiring) - - - def _continueFiring(self, ignored): - """ - Call the during and after phase triggers for this event. - """ - self.state = 'BASE' - self.finishedBefore = [] - for phase in self.during, self.after: - while phase: - callable, args, kwargs = phase.pop(0) - try: - callable(*args, **kwargs) - except: - log.err() - - - -class ReactorBase(object): - """ - Default base class for Reactors. - - @type _stopped: C{bool} - @ivar _stopped: A flag which is true between paired calls to C{reactor.run} - and C{reactor.stop}. - """ - - implements(IReactorCore, IReactorTime, IReactorPluggableResolver) - - _stopped = True - installed = False - usingThreads = False - resolver = BlockingResolver() - - __name__ = "twisted.internet.reactor" - - def __init__(self): - self.threadCallQueue = [] - self._eventTriggers = {} - self._pendingTimedCalls = [] - self._newTimedCalls = [] - self._cancellations = 0 - self.running = False - self.waker = None - - self.addSystemEventTrigger('during', 'shutdown', self.crash) - self.addSystemEventTrigger('during', 'shutdown', self.disconnectAll) - - if platform.supportsThreads(): - self._initThreads() - - # override in subclasses - - _lock = None - - def installWaker(self): - raise NotImplementedError() - - def installResolver(self, resolver): - assert IResolverSimple.providedBy(resolver) - oldResolver = self.resolver - self.resolver = resolver - return oldResolver - - def wakeUp(self): - """Wake up the event loop.""" - if not threadable.isInIOThread(): - if self.waker: - self.waker.wakeUp() - # if the waker isn't installed, the reactor isn't running, and - # therefore doesn't need to be woken up - - def doIteration(self, delay): - """Do one iteration over the readers and writers we know about.""" - raise NotImplementedError - - def addReader(self, reader): - raise NotImplementedError - - def addWriter(self, writer): - raise NotImplementedError - - def removeReader(self, reader): - raise NotImplementedError - - def removeWriter(self, writer): - raise NotImplementedError - - def removeAll(self): - raise NotImplementedError - - - def getReaders(self): - raise NotImplementedError() - - - def getWriters(self): - raise NotImplementedError() - - - def resolve(self, name, timeout = (1, 3, 11, 45)): - """Return a Deferred that will resolve a hostname. - """ - if not name: - # XXX - This is *less than* '::', and will screw up IPv6 servers - return defer.succeed('0.0.0.0') - if abstract.isIPAddress(name): - return defer.succeed(name) - return self.resolver.getHostByName(name, timeout) - - # Installation. - - # IReactorCore - - def stop(self): - """ - See twisted.internet.interfaces.IReactorCore.stop. - """ - if self._stopped: - raise error.ReactorNotRunning( - "Can't stop reactor that isn't running.") - self._stopped = True - self.callLater(0, self.fireSystemEvent, "shutdown") - - def crash(self): - """ - See twisted.internet.interfaces.IReactorCore.crash. - """ - self.running = False - - def sigInt(self, *args): - """Handle a SIGINT interrupt. - """ - log.msg("Received SIGINT, shutting down.") - self.callFromThread(self.stop) - - def sigBreak(self, *args): - """Handle a SIGBREAK interrupt. - """ - log.msg("Received SIGBREAK, shutting down.") - self.callFromThread(self.stop) - - def sigTerm(self, *args): - """Handle a SIGTERM interrupt. - """ - log.msg("Received SIGTERM, shutting down.") - self.callFromThread(self.stop) - - def disconnectAll(self): - """Disconnect every reader, and writer in the system. - """ - selectables = self.removeAll() - for reader in selectables: - log.callWithLogger(reader, - reader.connectionLost, - failure.Failure(main.CONNECTION_LOST)) - - - def iterate(self, delay=0): - """See twisted.internet.interfaces.IReactorCore.iterate. - """ - self.runUntilCurrent() - self.doIteration(delay) - - - def fireSystemEvent(self, eventType): - """See twisted.internet.interfaces.IReactorCore.fireSystemEvent. - """ - event = self._eventTriggers.get(eventType) - if event is not None: - event.fireEvent() - - - def addSystemEventTrigger(self, _phase, _eventType, _f, *args, **kw): - """See twisted.internet.interfaces.IReactorCore.addSystemEventTrigger. - """ - assert callable(_f), "%s is not callable" % _f - if _eventType not in self._eventTriggers: - self._eventTriggers[_eventType] = _ThreePhaseEvent() - return (_eventType, self._eventTriggers[_eventType].addTrigger( - _phase, _f, *args, **kw)) - - - def removeSystemEventTrigger(self, triggerID): - """See twisted.internet.interfaces.IReactorCore.removeSystemEventTrigger. - """ - eventType, handle = triggerID - self._eventTriggers[eventType].removeTrigger(handle) - - - def callWhenRunning(self, _callable, *args, **kw): - """See twisted.internet.interfaces.IReactorCore.callWhenRunning. - """ - if self.running: - _callable(*args, **kw) - else: - return self.addSystemEventTrigger('after', 'startup', - _callable, *args, **kw) - - def startRunning(self): - """ - Method called when reactor starts: do some initialization and fire - startup events. - - Don't call this directly, call reactor.run() instead: it should take - care of calling this. - """ - if self.running: - warnings.warn( - "Reactor already running! This behavior is deprecated " - "since Twisted 8.0", - category=DeprecationWarning, stacklevel=3) - self.running = True - self._stopped = False - threadable.registerAsIOThread() - self.fireSystemEvent('startup') - - # IReactorTime - - seconds = staticmethod(runtimeSeconds) - - def callLater(self, _seconds, _f, *args, **kw): - """See twisted.internet.interfaces.IReactorTime.callLater. - """ - assert callable(_f), "%s is not callable" % _f - assert sys.maxint >= _seconds >= 0, \ - "%s is not greater than or equal to 0 seconds" % (_seconds,) - tple = DelayedCall(self.seconds() + _seconds, _f, args, kw, - self._cancelCallLater, - self._moveCallLaterSooner, - seconds=self.seconds) - self._newTimedCalls.append(tple) - return tple - - def _moveCallLaterSooner(self, tple): - # Linear time find: slow. - heap = self._pendingTimedCalls - try: - pos = heap.index(tple) - - # Move elt up the heap until it rests at the right place. - elt = heap[pos] - while pos != 0: - parent = (pos-1) // 2 - if heap[parent] <= elt: - break - # move parent down - heap[pos] = heap[parent] - pos = parent - heap[pos] = elt - except ValueError: - # element was not found in heap - oh well... - pass - - def _cancelCallLater(self, tple): - self._cancellations+=1 - - def cancelCallLater(self, callID): - """See twisted.internet.interfaces.IReactorTime.cancelCallLater. - """ - # DO NOT DELETE THIS - this is documented in Python in a Nutshell, so we - # we can't get rid of it for a long time. - warnings.warn("reactor.cancelCallLater(callID) is deprecated - use callID.cancel() instead") - callID.cancel() - - def getDelayedCalls(self): - """Return all the outstanding delayed calls in the system. - They are returned in no particular order. - This method is not efficient -- it is really only meant for - test cases.""" - return [x for x in (self._pendingTimedCalls + self._newTimedCalls) if not x.cancelled] - - def _insertNewDelayedCalls(self): - for call in self._newTimedCalls: - if call.cancelled: - self._cancellations-=1 - else: - call.activate_delay() - heappush(self._pendingTimedCalls, call) - self._newTimedCalls = [] - - def timeout(self): - # insert new delayed calls to make sure to include them in timeout value - self._insertNewDelayedCalls() - - if not self._pendingTimedCalls: - return None - - return max(0, self._pendingTimedCalls[0].time - self.seconds()) - - - def runUntilCurrent(self): - """Run all pending timed calls. - """ - if self.threadCallQueue: - # Keep track of how many calls we actually make, as we're - # making them, in case another call is added to the queue - # while we're in this loop. - count = 0 - total = len(self.threadCallQueue) - for (f, a, kw) in self.threadCallQueue: - try: - f(*a, **kw) - except: - log.err() - count += 1 - if count == total: - break - del self.threadCallQueue[:count] - if self.threadCallQueue: - if self.waker: - self.waker.wakeUp() - - # insert new delayed calls now - self._insertNewDelayedCalls() - - now = self.seconds() - while self._pendingTimedCalls and (self._pendingTimedCalls[0].time <= now): - call = heappop(self._pendingTimedCalls) - if call.cancelled: - self._cancellations-=1 - continue - - if call.delayed_time > 0: - call.activate_delay() - heappush(self._pendingTimedCalls, call) - continue - - try: - call.called = 1 - call.func(*call.args, **call.kw) - except: - log.deferr() - if hasattr(call, "creator"): - e = "\n" - e += " C: previous exception occurred in " + \ - "a DelayedCall created here:\n" - e += " C:" - e += "".join(call.creator).rstrip().replace("\n","\n C:") - e += "\n" - log.msg(e) - - - if (self._cancellations > 50 and - self._cancellations > len(self._pendingTimedCalls) >> 1): - self._cancellations = 0 - self._pendingTimedCalls = [x for x in self._pendingTimedCalls - if not x.cancelled] - heapify(self._pendingTimedCalls) - - # IReactorProcess - - def _checkProcessArgs(self, args, env): - """ - Check for valid arguments and environment to spawnProcess. - - @return: A two element tuple giving values to use when creating the - process. The first element of the tuple is a C{list} of C{str} - giving the values for argv of the child process. The second element - of the tuple is either C{None} if C{env} was C{None} or a C{dict} - mapping C{str} environment keys to C{str} environment values. - """ - # Any unicode string which Python would successfully implicitly - # encode to a byte string would have worked before these explicit - # checks were added. Anything which would have failed with a - # UnicodeEncodeError during that implicit encoding step would have - # raised an exception in the child process and that would have been - # a pain in the butt to debug. - # - # So, we will explicitly attempt the same encoding which Python - # would implicitly do later. If it fails, we will report an error - # without ever spawning a child process. If it succeeds, we'll save - # the result so that Python doesn't need to do it implicitly later. - # - # For any unicode which we can actually encode, we'll also issue a - # deprecation warning, because no one should be passing unicode here - # anyway. - # - # -exarkun - defaultEncoding = sys.getdefaultencoding() - - # Common check function - def argChecker(arg): - """ - Return either a str or None. If the given value is not - allowable for some reason, None is returned. Otherwise, a - possibly different object which should be used in place of arg - is returned. This forces unicode encoding to happen now, rather - than implicitly later. - """ - if isinstance(arg, unicode): - try: - arg = arg.encode(defaultEncoding) - except UnicodeEncodeError: - return None - warnings.warn( - "Argument strings and environment keys/values passed to " - "reactor.spawnProcess should be str, not unicode.", - category=DeprecationWarning, - stacklevel=4) - if isinstance(arg, str) and '\0' not in arg: - return arg - return None - - # Make a few tests to check input validity - if not isinstance(args, (tuple, list)): - raise TypeError("Arguments must be a tuple or list") - - outputArgs = [] - for arg in args: - arg = argChecker(arg) - if arg is None: - raise TypeError("Arguments contain a non-string value") - else: - outputArgs.append(arg) - - outputEnv = None - if env is not None: - outputEnv = {} - for key, val in env.iteritems(): - key = argChecker(key) - if key is None: - raise TypeError("Environment contains a non-string key") - val = argChecker(val) - if val is None: - raise TypeError("Environment contains a non-string value") - outputEnv[key] = val - return outputArgs, outputEnv - - # IReactorThreads - if platform.supportsThreads(): - threadpool = None - # ID of the trigger stopping the threadpool - threadpoolShutdownID = None - - def _initThreads(self): - self.usingThreads = True - self.resolver = ThreadedResolver(self) - self.installWaker() - - def callFromThread(self, f, *args, **kw): - """ - See L{twisted.internet.interfaces.IReactorThreads.callFromThread}. - """ - assert callable(f), "%s is not callable" % (f,) - # lists are thread-safe in CPython, but not in Jython - # this is probably a bug in Jython, but until fixed this code - # won't work in Jython. - self.threadCallQueue.append((f, args, kw)) - self.wakeUp() - - def _initThreadPool(self): - """ - Create the threadpool accessible with callFromThread. - """ - from twisted.python import threadpool - self.threadpool = threadpool.ThreadPool(0, 10, 'twisted.internet.reactor') - self.callWhenRunning(self.threadpool.start) - self.threadpoolShutdownID = self.addSystemEventTrigger( - 'during', 'shutdown', self._stopThreadPool) - - def _stopThreadPool(self): - """ - Stop the reactor threadpool. - """ - self.threadpoolShutdownID = None - self.threadpool.stop() - self.threadpool = None - - def callInThread(self, _callable, *args, **kwargs): - """ - See L{twisted.internet.interfaces.IReactorThreads.callInThread}. - """ - if self.threadpool is None: - self._initThreadPool() - self.threadpool.callInThread(_callable, *args, **kwargs) - - def suggestThreadPoolSize(self, size): - """ - See L{twisted.internet.interfaces.IReactorThreads.suggestThreadPoolSize}. - """ - if size == 0 and self.threadpool is None: - return - if self.threadpool is None: - self._initThreadPool() - self.threadpool.adjustPoolsize(maxthreads=size) - else: - # This is for signal handlers. - def callFromThread(self, f, *args, **kw): - assert callable(f), "%s is not callable" % (f,) - # See comment in the other callFromThread implementation. - self.threadCallQueue.append((f, args, kw)) - -if platform.supportsThreads(): - classImplements(ReactorBase, IReactorThreads) - - -class BaseConnector(styles.Ephemeral): - """Basic implementation of connector. - - State can be: "connecting", "connected", "disconnected" - """ - - implements(IConnector) - - timeoutID = None - factoryStarted = 0 - - def __init__(self, factory, timeout, reactor): - self.state = "disconnected" - self.reactor = reactor - self.factory = factory - self.timeout = timeout - - def disconnect(self): - """Disconnect whatever our state is.""" - if self.state == 'connecting': - self.stopConnecting() - elif self.state == 'connected': - self.transport.loseConnection() - - def connect(self): - """Start connection to remote server.""" - if self.state != "disconnected": - raise RuntimeError, "can't connect in this state" - - self.state = "connecting" - if not self.factoryStarted: - self.factory.doStart() - self.factoryStarted = 1 - self.transport = transport = self._makeTransport() - if self.timeout is not None: - self.timeoutID = self.reactor.callLater(self.timeout, transport.failIfNotConnected, error.TimeoutError()) - self.factory.startedConnecting(self) - - def stopConnecting(self): - """Stop attempting to connect.""" - if self.state != "connecting": - raise error.NotConnectingError, "we're not trying to connect" - - self.state = "disconnected" - self.transport.failIfNotConnected(error.UserError()) - del self.transport - - def cancelTimeout(self): - if self.timeoutID is not None: - try: - self.timeoutID.cancel() - except ValueError: - pass - del self.timeoutID - - def buildProtocol(self, addr): - self.state = "connected" - self.cancelTimeout() - return self.factory.buildProtocol(addr) - - def connectionFailed(self, reason): - self.cancelTimeout() - self.transport = None - self.state = "disconnected" - self.factory.clientConnectionFailed(self, reason) - if self.state == "disconnected": - # factory hasn't called our connect() method - self.factory.doStop() - self.factoryStarted = 0 - - def connectionLost(self, reason): - self.state = "disconnected" - self.factory.clientConnectionLost(self, reason) - if self.state == "disconnected": - # factory hasn't called our connect() method - self.factory.doStop() - self.factoryStarted = 0 - - def getDestination(self): - raise NotImplementedError, "implement in subclasses" - - -class BasePort(abstract.FileDescriptor): - """Basic implementation of a ListeningPort. - - Note: This does not actually implement IListeningPort. - """ - - addressFamily = None - socketType = None - - def createInternetSocket(self): - s = socket.socket(self.addressFamily, self.socketType) - s.setblocking(0) - if fcntl and hasattr(fcntl, 'FD_CLOEXEC'): - old = fcntl.fcntl(s.fileno(), fcntl.F_GETFD) - fcntl.fcntl(s.fileno(), fcntl.F_SETFD, old | fcntl.FD_CLOEXEC) - return s - - - def doWrite(self): - """Raises a RuntimeError""" - raise RuntimeError, "doWrite called on a %s" % reflect.qual(self.__class__) - - - -class _SignalReactorMixin: - """ - Private mixin to manage signals: it installs signal handlers at start time, - and define run method. - - It can only be used mixed in with L{ReactorBase}, and has to be defined - first in the inheritance (so that method resolution order finds - startRunning first). - """ - - def _handleSignals(self): - """ - Install the signal handlers for the Twisted event loop. - """ - try: - import signal - except ImportError: - log.msg("Warning: signal module unavailable -- " - "not installing signal handlers.") - return - - if signal.getsignal(signal.SIGINT) == signal.default_int_handler: - # only handle if there isn't already a handler, e.g. for Pdb. - signal.signal(signal.SIGINT, self.sigInt) - signal.signal(signal.SIGTERM, self.sigTerm) - - # Catch Ctrl-Break in windows - if hasattr(signal, "SIGBREAK"): - signal.signal(signal.SIGBREAK, self.sigBreak) - - if platformType == 'posix': - signal.signal(signal.SIGCHLD, self._handleSigchld) - - - def _handleSigchld(self, signum, frame, _threadSupport=platform.supportsThreads()): - """ - Reap all processes on SIGCHLD. - - This gets called on SIGCHLD. We do no processing inside a signal - handler, as the calls we make here could occur between any two - python bytecode instructions. Deferring processing to the next - eventloop round prevents us from violating the state constraints - of arbitrary classes. - """ - from twisted.internet.process import reapAllProcesses - if _threadSupport: - self.callFromThread(reapAllProcesses) - else: - self.callLater(0, reapAllProcesses) - - - def startRunning(self, installSignalHandlers=True): - """ - Forward call to ReactorBase, arrange for signal handlers to be - installed if asked. - """ - if installSignalHandlers: - # Make sure this happens before after-startup events, since the - # expectation of after-startup is that the reactor is fully - # initialized. Don't do it right away for historical reasons - # (perhaps some before-startup triggers don't want there to be a - # custom SIGCHLD handler so that they can run child processes with - # some blocking api). - self.addSystemEventTrigger( - 'during', 'startup', self._handleSignals) - ReactorBase.startRunning(self) - - - def run(self, installSignalHandlers=True): - self.startRunning(installSignalHandlers=installSignalHandlers) - self.mainLoop() - - - def mainLoop(self): - while self.running: - try: - while self.running: - # Advance simulation time in delayed event - # processors. - self.runUntilCurrent() - t2 = self.timeout() - t = self.running and t2 - self.doIteration(t) - except: - log.msg("Unexpected error in main loop.") - log.err() - else: - log.msg('Main loop terminated.') - - - -__all__ = [] diff --git a/tools/buildbot/pylibs/twisted/internet/cfreactor.py b/tools/buildbot/pylibs/twisted/internet/cfreactor.py deleted file mode 100644 index 84ccaea..0000000 --- a/tools/buildbot/pylibs/twisted/internet/cfreactor.py +++ /dev/null @@ -1,342 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -This module provides support for Twisted to interact with CoreFoundation -CFRunLoops. This includes Cocoa's NSRunLoop. - -In order to use this support, simply do the following:: - - | from twisted.internet import cfreactor - | cfreactor.install() - -Then use the twisted.internet APIs as usual. The other methods here are not -intended to be called directly under normal use. However, install can take -a runLoop kwarg, and run will take a withRunLoop arg if you need to explicitly -pass a CFRunLoop for some reason. Otherwise it will make a pretty good guess -as to which runLoop you want (the current NSRunLoop if PyObjC is imported, -otherwise the current CFRunLoop. Either way, if one doesn't exist, it will -be created). - -Maintainer: U{Bob Ippolito} -""" - -__all__ = ['install'] - -import sys - -# hints for py2app -import Carbon.CF -import traceback - -import cfsupport as cf - -from zope.interface import implements - -from twisted.python import log, threadable, failure -from twisted.internet.interfaces import IReactorFDSet -from twisted.internet import posixbase, error -from weakref import WeakKeyDictionary -from Foundation import NSRunLoop -from AppKit import NSApp - -# cache two extremely common "failures" without traceback info -_faildict = { - error.ConnectionDone: failure.Failure(error.ConnectionDone()), - error.ConnectionLost: failure.Failure(error.ConnectionLost()), -} - -class SelectableSocketWrapper(object): - _objCache = WeakKeyDictionary() - - cf = None - def socketWrapperForReactorAndObject(klass, reactor, obj): - _objCache = klass._objCache - if obj in _objCache: - return _objCache[obj] - v = _objCache[obj] = klass(reactor, obj) - return v - socketWrapperForReactorAndObject = classmethod(socketWrapperForReactorAndObject) - - def __init__(self, reactor, obj): - if self.cf: - raise ValueError, "This socket wrapper is already initialized" - self.reactor = reactor - self.obj = obj - obj._orig_ssw_connectionLost = obj.connectionLost - obj.connectionLost = self.objConnectionLost - self.fd = obj.fileno() - self.writing = False - self.reading = False - self.wouldRead = False - self.wouldWrite = False - self.cf = cf.PyCFSocket(obj.fileno(), self.doRead, self.doWrite, self.doConnect) - self.cf.stopWriting() - reactor.getRunLoop().addSocket(self.cf) - - def __repr__(self): - return 'SSW(fd=%r r=%r w=%r x=%08x o=%08x)' % (self.fd, int(self.reading), int(self.writing), id(self), id(self.obj)) - - def objConnectionLost(self, *args, **kwargs): - obj = self.obj - self.reactor.removeReader(obj) - self.reactor.removeWriter(obj) - obj.connectionLost = obj._orig_ssw_connectionLost - obj.connectionLost(*args, **kwargs) - try: - del self._objCache[obj] - except: - pass - self.obj = None - self.cf = None - - def doConnect(self, why): - pass - - def startReading(self): - self.cf.startReading() - self.reading = True - if self.wouldRead: - if not self.reactor.running: - self.reactor.callLater(0, self.doRead) - else: - self.doRead() - self.wouldRead = False - return self - - def stopReading(self): - self.cf.stopReading() - self.reading = False - self.wouldRead = False - return self - - def startWriting(self): - self.cf.startWriting() - self.writing = True - if self.wouldWrite: - if not self.reactor.running: - self.reactor.callLater(0, self.doWrite) - else: - self.doWrite() - self.wouldWrite = False - return self - - def stopWriting(self): - self.cf.stopWriting() - self.writing = False - self.wouldWrite = False - - def _finishReadOrWrite(self, fn, faildict=_faildict): - try: - why = fn() - except: - why = sys.exc_info()[1] - log.err() - if why: - try: - f = faildict.get(why.__class__) or failure.Failure(why) - self.objConnectionLost(f) - except: - log.err() - if self.reactor.running: - self.reactor.simulate() - - def doRead(self): - obj = self.obj - if not obj: - return - if not self.reading: - self.wouldRead = True - if self.reactor.running: - self.reactor.simulate() - return - self._finishReadOrWrite(obj.doRead) - - def doWrite(self): - obj = self.obj - if not obj: - return - if not self.writing: - self.wouldWrite = True - if self.reactor.running: - self.reactor.simulate() - return - self._finishReadOrWrite(obj.doWrite) - - def __hash__(self): - return hash(self.fd) - -class CFReactor(posixbase.PosixReactorBase): - implements(IReactorFDSet) - # how long to poll if we're don't care about signals - longIntervalOfTime = 60.0 - - # how long we should poll if we do care about signals - shortIntervalOfTime = 1.0 - - # don't set this - pollInterval = longIntervalOfTime - - def __init__(self, runLoop=None): - self.readers = {} - self.writers = {} - self.running = 0 - self.crashing = False - self._doRunUntilCurrent = True - self.timer = None - self.runLoop = None - self.nsRunLoop = None - self.didStartRunLoop = False - if runLoop is not None: - self.getRunLoop(runLoop) - posixbase.PosixReactorBase.__init__(self) - - def getRunLoop(self, runLoop=None): - if self.runLoop is None: - self.nsRunLoop = runLoop or NSRunLoop.currentRunLoop() - self.runLoop = cf.PyCFRunLoop(self.nsRunLoop.getCFRunLoop()) - return self.runLoop - - def addReader(self, reader): - self.readers[reader] = SelectableSocketWrapper.socketWrapperForReactorAndObject(self, reader).startReading() - - def addWriter(self, writer): - self.writers[writer] = SelectableSocketWrapper.socketWrapperForReactorAndObject(self, writer).startWriting() - - def removeReader(self, reader): - wrapped = self.readers.get(reader, None) - if wrapped is not None: - del self.readers[reader] - wrapped.stopReading() - - def removeWriter(self, writer): - wrapped = self.writers.get(writer, None) - if wrapped is not None: - del self.writers[writer] - wrapped.stopWriting() - - - def getReaders(self): - return self.readers.keys() - - - def getWriters(self): - return self.writers.keys() - - - def removeAll(self): - r = self.readers.keys() - for s in self.readers.itervalues(): - s.stopReading() - for s in self.writers.itervalues(): - s.stopWriting() - self.readers.clear() - self.writers.clear() - return r - - def run(self, installSignalHandlers=1, withRunLoop=None): - if self.running: - raise ValueError, "Reactor already running" - if installSignalHandlers: - self.pollInterval = self.shortIntervalOfTime - runLoop = self.getRunLoop(withRunLoop) - self._startup() - - self.startRunning(installSignalHandlers=installSignalHandlers) - - self.running = True - if NSApp() is None and self.nsRunLoop.currentMode() is None: - # Most of the time the NSRunLoop will have already started, - # but in this case it wasn't. - runLoop.run() - self.crashing = False - self.didStartRunLoop = True - - def callLater(self, howlong, *args, **kwargs): - rval = posixbase.PosixReactorBase.callLater(self, howlong, *args, **kwargs) - if self.timer: - timeout = self.timeout() - if timeout is None: - timeout = howlong - sleepUntil = cf.now() + min(timeout, howlong) - if sleepUntil < self.timer.getNextFireDate(): - self.timer.setNextFireDate(sleepUntil) - else: - pass - return rval - - def iterate(self, howlong=0.0): - if self.running: - raise ValueError, "Can't iterate a running reactor" - self.runUntilCurrent() - self.doIteration(howlong) - - def doIteration(self, howlong): - if self.running: - raise ValueError, "Can't iterate a running reactor" - howlong = howlong or 0.01 - pi = self.pollInterval - self.pollInterval = howlong - self._doRunUntilCurrent = False - self.run() - self._doRunUntilCurrent = True - self.pollInterval = pi - - def simulate(self): - if self.crashing: - return - if not self.running: - raise ValueError, "You can't simulate a stopped reactor" - if self._doRunUntilCurrent: - self.runUntilCurrent() - if self.crashing: - return - if self.timer is None: - return - nap = self.timeout() - if nap is None: - nap = self.pollInterval - else: - nap = min(self.pollInterval, nap) - if self.running: - self.timer.setNextFireDate(cf.now() + nap) - if not self._doRunUntilCurrent: - self.crash() - - def _startup(self): - if self.running: - raise ValueError, "Can't bootstrap a running reactor" - self.timer = cf.PyCFRunLoopTimer(cf.now(), self.pollInterval, self.simulate) - self.runLoop.addTimer(self.timer) - - def cleanup(self): - pass - - def sigInt(self, *args): - self.callLater(0.0, self.stop) - - def crash(self): - if not self.running: - raise ValueError, "Can't crash a stopped reactor" - posixbase.PosixReactorBase.crash(self) - self.crashing = True - if self.timer is not None: - self.runLoop.removeTimer(self.timer) - self.timer = None - if self.didStartRunLoop: - self.runLoop.stop() - - def stop(self): - if not self.running: - raise ValueError, "Can't stop a stopped reactor" - posixbase.PosixReactorBase.stop(self) - -def install(runLoop=None): - """Configure the twisted mainloop to be run inside CFRunLoop. - """ - reactor = CFReactor(runLoop=runLoop) - reactor.addSystemEventTrigger('after', 'shutdown', reactor.cleanup) - from twisted.internet.main import installReactor - installReactor(reactor) - return reactor diff --git a/tools/buildbot/pylibs/twisted/internet/cfsupport/cfdate.pxi b/tools/buildbot/pylibs/twisted/internet/cfsupport/cfdate.pxi deleted file mode 100644 index 3a773d7..0000000 --- a/tools/buildbot/pylibs/twisted/internet/cfsupport/cfdate.pxi +++ /dev/null @@ -1,2 +0,0 @@ -def now(): - return CFAbsoluteTimeGetCurrent() diff --git a/tools/buildbot/pylibs/twisted/internet/cfsupport/cfdecl.pxi b/tools/buildbot/pylibs/twisted/internet/cfsupport/cfdecl.pxi deleted file mode 100644 index 7586001..0000000 --- a/tools/buildbot/pylibs/twisted/internet/cfsupport/cfdecl.pxi +++ /dev/null @@ -1,227 +0,0 @@ -cdef extern from "pymactoolbox.h": - # CFBase - ctypedef void *CFTypeRef - ctypedef CFTypeRef CFAllocatorRef - ctypedef CFTypeRef CFStringRef - ctypedef CFStringRef CFMutableStringRef - ctypedef CFTypeRef CFDataRef - ctypedef CFDataRef CFMutableDataRef - ctypedef CFTypeRef CFArrayRef - ctypedef CFArrayRef CFMutableArrayRef - ctypedef CFTypeRef CFDictionaryRef - ctypedef CFDictionaryRef CFMutableDictionaryRef - ctypedef CFTypeRef CFURLRef - - ctypedef unsigned short UniChar - ctypedef int CFIndex - ctypedef int CFOptionFlags - ctypedef int Boolean - - ctypedef struct CFRange: - CFIndex location - CFIndex length - - cdef extern CFAllocatorRef kCFAllocatorDefault - cdef extern CFAllocatorRef kCFAllocatorNull - - cdef CFTypeRef CFRetain(CFTypeRef cf) - cdef void CFRelease(CFTypeRef cf) - cdef CFIndex CFGetRetainCount(CFTypeRef cf) - cdef CFStringRef CFCopyDescription(CFTypeRef cf) - cdef CFRange CFRangeMake(CFIndex location, CFIndex length) - - # CFData - cdef CFDataRef CFDataCreate(CFAllocatorRef allocator, unsigned char *bytes, CFIndex length) - cdef CFDataRef CFDataCreateWithBytesNoCopy(CFAllocatorRef, unsigned char *bytes, CFIndexLength, CFAllocatorRef bytesDeallocator) - cdef CFMutableDataRef CFDataCreateMutable(CFAllocatorRef allocator, CFIndex capacity) - cdef CFMutableDataRef CFDataCreateMutableCopy(CFAllocatorRef allocator, CFIndex capacity, CFDataRef theData) - cdef CFIndex CFDataGetLength(CFDataRef theData) - cdef unsigned char *CFDataGetBytePtr(CFDataRef theData) - cdef unsigned char *CFDataGetMutableBytePtr(CFMutableDataRef theData) - cdef CFDataGetBytes(CFDataRef theData, CFRange range, unsigned char *buffer) - cdef CFDataSetLength(CFMutableDataRef theData, CFIndex length) - cdef CFDataIncreaseLength(CFMutableDataRef theData, CFIndex extraLength) - cdef CFDataAppendBytes(CFMutableDataRef theData, unsigned char *bytes, CFIndex length) - cdef CFDataReplaceBytes(CFMutableDataRef theData, CFRange range, unsigned char *newBytes, CFIndex newLength) - cdef CFDataDeleteBytes(CFMutableDataRef theData, CFRange range) - - - # CFString - - ctypedef enum CFStringBuiltInEncodings: - kCFStringEncodingMacRoman = 0 - kCFStringEncodingWindowsLatin1 = 0x0500 - kCFStringEncodingISOLatin1 = 0x0201 - kCFStringEncodingNextStepLatin = 0x0B01 - kCFStringEncodingASCII = 0x0600 - kCFStringEncodingUnicode = 0x0100 - kCFStringEncodingUTF8 = 0x08000100 - kCFStringEncodingNonLossyASCII = 0x0BFF - kCFStringEncodingInvalidId = 0xffffffff - ctypedef unsigned int CFStringEncoding - - cdef void CFStringGetCharacters(CFStringRef theString, CFRange range, UniChar *ubuffer) - cdef CFIndex CFStringGetLength(CFStringRef theString) - cdef CFStringRef CFStringCreateWithCString(CFAllocatorRef alloc, char *cStr, CFStringEncoding encoding) - cdef CFStringRef CFStringCreateWithCharacters(CFAllocatorRef alloc, UniChar *chars, CFIndex numChars) - - # CFArray - - cdef CFIndex CFArrayGetCount(CFArrayRef theArray) - cdef void *CFArrayGetValueAtIndex(CFArrayRef theArray, CFIndex idx) - cdef void CFArrayGetValues(CFArrayRef theArray, CFRange range, void **values) - - # CFDate - ctypedef double CFTimeInterval - ctypedef CFTimeInterval CFAbsoluteTime - - cdef CFAbsoluteTime CFAbsoluteTimeGetCurrent() - - # CFRunLoop - ctypedef struct CFRunLoopTimerContext: - CFIndex version - void* info - void *(*retain)(void *info) - void (*release)(void *info) - CFStringRef (*copyDescription)(void *info) - - ctypedef CFTypeRef CFRunLoopRef - ctypedef CFTypeRef CFRunLoopTimerRef - ctypedef CFTypeRef CFRunLoopSourceRef - ctypedef void (*CFRunLoopTimerCallBack)(CFRunLoopTimerRef timer, void *info) - - cdef extern CFStringRef kCFRunLoopCommonModes - - cdef CFRunLoopRef CFRunLoopGetCurrent() - cdef void CFRunLoopRun() - cdef void CFRunLoopStop(CFRunLoopRef rl) - cdef void CFRunLoopAddSource(CFRunLoopRef rl, CFRunLoopSourceRef source, CFStringRef mode) - cdef void CFRunLoopRemoveSource(CFRunLoopRef rl, CFRunLoopSourceRef source, CFStringRef mode) - cdef CFStringRef CFRunLoopCopyCurrentMode(CFRunLoopRef rl) - - cdef void CFRunLoopAddTimer(CFRunLoopRef rl, CFRunLoopTimerRef timer, CFStringRef mode) - cdef void CFRunLoopRemoveTimer(CFRunLoopRef rl, CFRunLoopTimerRef timer, CFStringRef mode) - - cdef CFRunLoopTimerRef CFRunLoopTimerCreate(CFAllocatorRef allocator, CFAbsoluteTime fireDate, CFTimeInterval interval, CFOptionFlags flags, CFIndex order, CFRunLoopTimerCallBack callout, CFRunLoopTimerContext *context) - cdef CFAbsoluteTime CFRunLoopTimerGetNextFireDate(CFRunLoopTimerRef timer) - cdef void CFRunLoopTimerSetNextFireDate(CFRunLoopTimerRef timer, CFAbsoluteTime fireDate) - cdef void CFRunLoopTimerInvalidate(CFRunLoopTimerRef timer) - - # CFSocket - enum kCFSocketFlags: - kCFSocketAutomaticallyReenableReadCallBack = 1 - kCFSocketAutomaticallyReenableAcceptCallBack = 2 - kCFSocketAutomaticallyReenableDataCallBack = 3 - kCFSocketAutomaticallyReenableWriteCallBack = 8 - kCFSocketCloseOnInvalidate = 128 - - ctypedef enum CFSocketCallBackType: - kCFSocketNoCallBack = 0 - kCFSocketReadCallBack = 1 - kCFSocketAcceptCallBack = 2 - kCFSocketDataCallBack = 3 - kCFSocketConnectCallBack = 4 - kCFSocketWriteCallBack = 8 - - ctypedef struct CFSocketContext: - CFIndex version - void *info - void *(*retain)(void *info) - void (*release)(void *info) - CFStringRef (*copyDescription)(void *info) - - ctypedef int CFSocketNativeHandle - ctypedef void *CFSocketRef - ctypedef void (*CFSocketCallBack)(CFSocketRef s, CFSocketCallBackType _type, CFDataRef address, void *data, void *info) - - cdef CFSocketRef CFSocketCreateWithNative(CFAllocatorRef allocator, CFSocketNativeHandle sock, CFOptionFlags callbackTypes, CFSocketCallBack callout, CFSocketContext* context) - cdef CFSocketNativeHandle CFSocketGetNative(CFSocketRef s) - cdef CFRunLoopSourceRef CFSocketCreateRunLoopSource(CFAllocatorRef allocator, CFSocketRef s, CFIndex order) - cdef void CFSocketEnableCallBacks(CFSocketRef s, CFOptionFlags callBackTypes) - cdef void CFSocketDisableCallBacks(CFSocketRef s, CFOptionFlags callBackTypes) - cdef CFOptionFlags CFSocketGetSocketFlags(CFSocketRef s) - cdef void CFSocketSetSocketFlags(CFSocketRef s, CFOptionFlags socketFlags) - cdef void CFSocketInvalidate(CFSocketRef s) - - # CFStream - ctypedef enum CFStreamErrorDomain: - kCFStreamErrorDomainCustom = -1 - kCFStreamErrorDomainPOSIX = 1 - kCFStreamErrorDomainMacOSStatus = 2 - - ctypedef struct CFStreamError: - CFStreamErrorDomain domain - int error - - cdef object CFObj_New(CFTypeRef) - cdef int CFObj_Convert(object, CFTypeRef *) - cdef object CFTypeRefObj_New(CFTypeRef) - cdef int CFTypeRefObj_Convert(object, CFTypeRef *) - cdef object CFStringRefObj_New(CFStringRef) - cdef int CFStringRefObj_Convert(object, CFStringRef *) - cdef object CFMutableStringRefObj_New(CFMutableStringRef) - cdef int CFMutableStringRefObj_Convert(object, CFMutableStringRef *) - cdef object CFArrayRefObj_New(CFArrayRef) - cdef int CFArrayRefObj_Convert(object, CFArrayRef *) - cdef object CFMutableArrayRefObj_New(CFMutableArrayRef) - cdef int CFMutableArrayRefObj_Convert(object, CFMutableArrayRef *) - cdef object CFDictionaryRefObj_New(CFDictionaryRef) - cdef int CFDictionaryRefObj_Convert(object, CFDictionaryRef *) - cdef object CFMutableDictionaryRefObj_New(CFMutableDictionaryRef) - cdef int CFMutableDictionaryRefObj_Convert(object, CFMutableDictionaryRef *) - cdef object CFURLRefObj_New(CFURLRef) - cdef int CFURLRefObj_Convert(object, CFURLRef *) - cdef int OptionalCFURLRefObj_Convert(object, CFURLRef *) - - # CFNetwork - ctypedef struct CFNetServiceClientContext: - CFIndex version - void *info - void *(*retain)(void *info) - void (*release)(void *info) - CFStringRef (*copyDescription)(void *info) - - ctypedef enum CFNetServiceBrowserClientCallBackFlags: - kCFNetServiceFlagMoreComing = 1 - kCFNetServiceFlagIsDomain = 2 - kCFNetServiceFlagIsRegistrationDomain = 4 - kCFNetServiceFlagRemove = 8 - - ctypedef CFTypeRef CFNetServiceBrowserRef - ctypedef CFTypeRef CFNetServiceRef - ctypedef void (*CFNetServiceBrowserClientCallBack)(CFNetServiceBrowserRef browser, CFOptionFlags flags, CFTypeRef domainOrService, CFStreamError* error, void* info) - ctypedef void (*CFNetServiceClientCallBack)(CFNetServiceRef theService, CFStreamError* error, void* info) - - cdef CFNetServiceBrowserRef CFNetServiceBrowserCreate(CFAllocatorRef alloc, CFNetServiceBrowserClientCallBack clientCB, CFNetServiceClientContext* clientContext) - cdef void CFNetworkServiceBrowserInvalidate(CFNetServiceBrowserRef browser) - cdef void CFNetServiceBrowserScheduleWithRunLoop(CFNetServiceBrowserRef browser, CFRunLoopRef runLoop, CFStringRef runLoopMode) - cdef Boolean CFNetServiceBrowserSearchForDomains(CFNetServiceBrowserRef browser, Boolean registrationDomain, CFStreamError* error) - cdef Boolean CFNetServiceBrowserSearchForServices(CFNetServiceBrowserRef browser, CFStringRef domain, CFStringRef type, CFStreamError* error) - cdef void CFNetServiceBrowserStopSearch(CFNetServiceBrowserRef browser, CFStreamError* error) - - # Call this function to shut down a browser that is running asynchronously. - # To complete the shutdown, call CFNetServiceBrowserInvalidate followed by CFNetServiceBrowserStopSearch. - cdef void CFNetServiceBrowserUnscheduleFromRunLoop(CFNetServiceBrowserRef browser, CFRunLoopRef runLoop, CFStringRef runLoopMode) - - cdef void CFNetServiceCancel(CFNetServiceRef theService) - cdef CFNetServiceRef CFNetServiceCreate(CFAllocatorRef alloc, CFStringRef domain, CFStringRef type, CFStringRef name, unsigned int port) - - cdef CFArrayRef CFNetServiceGetAddressing(CFNetServiceRef theService) - cdef CFStringRef CFNetServiceGetDomain(CFNetServiceRef theService) - cdef CFStringRef CFNetServiceGetName(CFNetServiceRef theService) - cdef CFStringRef CFNetServiceGetProtocolSpecificInformation(CFNetServiceRef theService) - cdef CFStringRef CFNetServiceGetType(CFNetServiceRef theService) - cdef Boolean CFNetServiceRegister(CFNetServiceRef theService, CFStreamError* error) - cdef Boolean CFNetServiceResolve(CFNetServiceRef theService, CFStreamError* error) - cdef void CFNetServiceScheduleWithRunLoop(CFNetServiceRef theService, CFRunLoopRef runLoop, CFStringRef runLoopMode) - - # For CFNetServices that will operate asynchronously, call this function and then call CFNetServiceScheduleWithRunLoop to schedule the service on a run loop. - # Then call CFNetServiceRegister or CFNetServiceResolve - cdef Boolean CFNetServiceSetClient(CFNetServiceRef theService, CFNetServiceClientCallBack clientCB, CFNetServiceClientContext* clientContext) - - cdef void CFNetServiceSetProtocolSpecificInformation(CFNetServiceRef theService, CFStringRef theInfo) - - # Unschedules the specified service from the specified run loop and mode. - # Call this function to shut down a service that is running asynchronously. - # To complete the shutdown, call CFNetServiceSetClient and set clientCB to NULL. Then call CFNetServiceCancel. - cdef void CFNetServiceUnscheduleFromRunLoop(CFNetServiceRef theService, CFRunLoopRef runLoop, CFStringRef runLoopMode) diff --git a/tools/buildbot/pylibs/twisted/internet/cfsupport/cfrunloop.pxi b/tools/buildbot/pylibs/twisted/internet/cfsupport/cfrunloop.pxi deleted file mode 100644 index 8cd40a8..0000000 --- a/tools/buildbot/pylibs/twisted/internet/cfsupport/cfrunloop.pxi +++ /dev/null @@ -1,104 +0,0 @@ -import traceback - -# possibly figure out how to subclass these or something - -cdef class PyCFRunLoopTimer: - cdef CFRunLoopTimerRef cf - cdef public object callout - cdef CFRunLoopTimerContext context - - def __new__(self, double fireDate, double interval, callout): - self.callout = callout - self.context.version = 0 - self.context.info = self - self.context.retain = NULL - self.context.release = NULL - self.context.copyDescription = NULL - self.cf = CFRunLoopTimerCreate(kCFAllocatorDefault, fireDate, interval, 0, 0, &gilRunLoopTimerCallBack, &self.context) - if self.cf == NULL: - raise ValueError("Invalid Socket") - - def getNextFireDate(self): - return CFRunLoopTimerGetNextFireDate(self.cf) - - def setNextFireDate(self, double fireDate): - CFRunLoopTimerSetNextFireDate(self.cf, fireDate) - - def invalidate(self): - CFRunLoopTimerInvalidate(self.cf) - - def __dealloc__(self): - if self.cf != NULL: - CFRelease(self.cf) - -cdef void runLoopTimerCallBack(CFRunLoopTimerRef timer, void *info): - cdef PyCFRunLoopTimer obj - obj = info - try: - if obj.callout: - obj.callout() - except: - traceback.print_exc() - -cdef void gilRunLoopTimerCallBack(CFRunLoopTimerRef timer, void *info): - cdef PyGILState_STATE gil - gil = PyGILState_Ensure() - runLoopTimerCallBack(timer, info) - PyGILState_Release(gil) - -cdef class PyCFRunLoop: - cdef public object cf - - def __new__(self, runLoop=None): - cdef CFTypeRef _runLoop - if runLoop is None: - _runLoop = CFRunLoopGetCurrent() - else: - if CFObj_Convert(runLoop, &_runLoop) == 0: - raise - #return -1 - # this is going to leak a reference - self.cf = CFObj_New(CFRetain(_runLoop)) - - def run(self): - CFRunLoopRun() - - def stop(self): - cdef CFTypeRef _runLoop - if CFObj_Convert(self.cf, &_runLoop) == 0: - raise ValueError, "CFRunLoopReference is invalid" - CFRunLoopStop(_runLoop) - - def currentMode(self): - cdef CFTypeRef _currentMode - cdef CFTypeRef _runLoop - if CFObj_Convert(self.cf, &_runLoop) == 0: - raise ValueError, "CFRunLoopReference is invalid" - _currentMode = CFRunLoopCopyCurrentMode(_runLoop) - if _currentMode == NULL: - return None - return CFObj_New(_currentMode) - - def addSocket(self, PyCFSocket socket not None): - cdef CFTypeRef _runLoop - if CFObj_Convert(self.cf, &_runLoop) == 0: - raise ValueError, "CFRunLoopReference is invalid" - CFRunLoopAddSource(_runLoop, socket.source, kCFRunLoopCommonModes) - - def removeSocket(self, PyCFSocket socket not None): - cdef CFTypeRef _runLoop - if CFObj_Convert(self.cf, &_runLoop) == 0: - raise ValueError, "CFRunLoopReference is invalid" - CFRunLoopRemoveSource(_runLoop, socket.source, kCFRunLoopCommonModes) - - def addTimer(self, PyCFRunLoopTimer timer not None): - cdef CFTypeRef _runLoop - if CFObj_Convert(self.cf, &_runLoop) == 0: - raise ValueError, "CFRunLoopReference is invalid" - CFRunLoopAddTimer(_runLoop, timer.cf, kCFRunLoopCommonModes) - - def removeTimer(self, PyCFRunLoopTimer timer not None): - cdef CFTypeRef _runLoop - if CFObj_Convert(self.cf, &_runLoop) == 0: - raise ValueError, "CFRunLoopReference is invalid" - CFRunLoopRemoveTimer(_runLoop, timer.cf, kCFRunLoopCommonModes) diff --git a/tools/buildbot/pylibs/twisted/internet/cfsupport/cfsocket.pxi b/tools/buildbot/pylibs/twisted/internet/cfsupport/cfsocket.pxi deleted file mode 100644 index b87cfb6..0000000 --- a/tools/buildbot/pylibs/twisted/internet/cfsupport/cfsocket.pxi +++ /dev/null @@ -1,111 +0,0 @@ -import traceback - -cdef class PyCFSocket - -cdef void socketCallBack(CFSocketRef s, CFSocketCallBackType _type, CFDataRef address, void *data, void *info): - cdef PyCFSocket socket - cdef int res - cdef int mask - socket = (info) - #print "fileno = %r" % (socket.fileno,) - try: - if _type == kCFSocketReadCallBack: - if socket.readcallback: - socket.readcallback() - elif _type == kCFSocketWriteCallBack: - if socket.writecallback: - socket.writecallback() - elif _type == kCFSocketConnectCallBack: - if data == NULL: - res = 0 - else: - res = (data)[0] - if socket.connectcallback: - socket.connectcallback(res) - except: - traceback.print_exc() - -cdef void gilSocketCallBack(CFSocketRef s, CFSocketCallBackType _type, CFDataRef address, void *data, void *info): - cdef PyGILState_STATE gil - gil = PyGILState_Ensure() - socketCallBack(s, _type, address, data, info) - PyGILState_Release(gil) - -cdef class PyCFSocket: - cdef public object readcallback - cdef public object writecallback - cdef public object connectcallback - cdef public object reading - cdef public object writing - cdef CFSocketRef cf - cdef CFRunLoopSourceRef source - cdef readonly CFSocketNativeHandle fileno - cdef CFSocketContext context - - def __new__(self, CFSocketNativeHandle fileno, readcallback=None, writecallback=None, connectcallback=None): - #print "new socket %r" % (fileno,) - self.fileno = fileno - self.readcallback = readcallback - self.writecallback = writecallback - self.connectcallback = connectcallback - self.context.version = 0 - self.context.info = self - self.context.retain = NULL - self.context.release = NULL - self.context.copyDescription = NULL - self.reading = False - self.writing = False - self.cf = CFSocketCreateWithNative(kCFAllocatorDefault, fileno, kCFSocketConnectCallBack | kCFSocketReadCallBack | kCFSocketWriteCallBack, &gilSocketCallBack, &self.context) - if self.cf == NULL: - raise ValueError("Invalid Socket") - self.source = CFSocketCreateRunLoopSource(kCFAllocatorDefault, self.cf, 10000) - if self.source == NULL: - raise ValueError("Couldn't create runloop source") - #print "made new socket" - - def update(self): - cdef int mask - cdef int offmask - cdef int automask - mask = kCFSocketConnectCallBack | kCFSocketAcceptCallBack - offmask = 0 - automask = kCFSocketAutomaticallyReenableAcceptCallBack - if self.reading: - mask = mask | kCFSocketReadCallBack - automask = automask | kCFSocketAutomaticallyReenableReadCallBack - else: - offmask = offmask | kCFSocketReadCallBack - if self.writing: - mask = mask | kCFSocketWriteCallBack - automask = automask | kCFSocketAutomaticallyReenableWriteCallBack - else: - offmask = offmask | kCFSocketWriteCallBack - CFSocketDisableCallBacks(self.cf, offmask) - CFSocketEnableCallBacks(self.cf, mask) - CFSocketSetSocketFlags(self.cf, automask) - - - def startReading(self): - self.reading = True - self.update() - - def stopReading(self): - self.reading = False - self.update() - - def startWriting(self): - self.writing = True - self.update() - - def stopWriting(self): - self.writing = False - self.update() - - def __dealloc__(self): - #print "PyCFSocket(%r).__dealloc__()" % (self.fileno,) - if self.source != NULL: - CFRelease(self.source) - if self.cf != NULL: - CFSocketInvalidate(self.cf) - CFRelease(self.cf) - #print "__dealloc__()" diff --git a/tools/buildbot/pylibs/twisted/internet/cfsupport/cfsupport.c b/tools/buildbot/pylibs/twisted/internet/cfsupport/cfsupport.c deleted file mode 100644 index eb1b371..0000000 --- a/tools/buildbot/pylibs/twisted/internet/cfsupport/cfsupport.c +++ /dev/null @@ -1,2136 +0,0 @@ -/* Generated by Pyrex 0.9.3 on Sat Mar 12 04:43:18 2005 */ - -#include "Python.h" -#include "structmember.h" -#ifndef PY_LONG_LONG - #define PY_LONG_LONG LONG_LONG -#endif -#include "pymactoolbox.h" - - -typedef struct {PyObject **p; char *s;} __Pyx_InternTabEntry; /*proto*/ -typedef struct {PyObject **p; char *s; long n;} __Pyx_StringTabEntry; /*proto*/ -static PyObject *__Pyx_UnpackItem(PyObject *, int); /*proto*/ -static int __Pyx_EndUnpack(PyObject *, int); /*proto*/ -static int __Pyx_PrintItem(PyObject *); /*proto*/ -static int __Pyx_PrintNewline(void); /*proto*/ -static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb); /*proto*/ -static void __Pyx_ReRaise(void); /*proto*/ -static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list); /*proto*/ -static PyObject *__Pyx_GetExcValue(void); /*proto*/ -static int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, int none_allowed, char *name); /*proto*/ -static int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); /*proto*/ -static int __Pyx_GetStarArgs(PyObject **args, PyObject **kwds, char *kwd_list[], int nargs, PyObject **args2, PyObject **kwds2); /*proto*/ -static void __Pyx_WriteUnraisable(char *name); /*proto*/ -static void __Pyx_AddTraceback(char *funcname); /*proto*/ -static PyTypeObject *__Pyx_ImportType(char *module_name, char *class_name, long size); /*proto*/ -static int __Pyx_SetVtable(PyObject *dict, void *vtable); /*proto*/ -static int __Pyx_GetVtable(PyObject *dict, void *vtabptr); /*proto*/ -static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name, char *modname); /*proto*/ -static int __Pyx_InternStrings(__Pyx_InternTabEntry *t); /*proto*/ -static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); /*proto*/ -static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name); /*proto*/ - -static PyObject *__pyx_m; -static PyObject *__pyx_b; -static int __pyx_lineno; -static char *__pyx_filename; -staticforward char **__pyx_f; - -/* Declarations from cfsupport */ - -staticforward PyTypeObject __pyx_type_9cfsupport_PyCFSocket; - -struct __pyx_obj_9cfsupport_PyCFSocket { - PyObject_HEAD - PyObject *readcallback; - PyObject *writecallback; - PyObject *connectcallback; - PyObject *reading; - PyObject *writing; - CFSocketRef cf; - CFRunLoopSourceRef source; - CFSocketNativeHandle fileno; - CFSocketContext context; -}; - -staticforward PyTypeObject __pyx_type_9cfsupport_PyCFRunLoopTimer; - -struct __pyx_obj_9cfsupport_PyCFRunLoopTimer { - PyObject_HEAD - CFRunLoopTimerRef cf; - PyObject *callout; - CFRunLoopTimerContext context; -}; - -staticforward PyTypeObject __pyx_type_9cfsupport_PyCFRunLoop; - -struct __pyx_obj_9cfsupport_PyCFRunLoop { - PyObject_HEAD - PyObject *cf; -}; - -static PyTypeObject *__pyx_ptype_9cfsupport_PyCFSocket = 0; -static PyTypeObject *__pyx_ptype_9cfsupport_PyCFRunLoopTimer = 0; -static PyTypeObject *__pyx_ptype_9cfsupport_PyCFRunLoop = 0; -static PyObject *__pyx_k2; -static PyObject *__pyx_k3; -static PyObject *__pyx_k4; -static PyObject *__pyx_k6; -static void (__pyx_f_9cfsupport_socketCallBack(CFSocketRef ,CFSocketCallBackType ,CFDataRef ,void (*),void (*))); /*proto*/ -static void (__pyx_f_9cfsupport_gilSocketCallBack(CFSocketRef ,CFSocketCallBackType ,CFDataRef ,void (*),void (*))); /*proto*/ -static void (__pyx_f_9cfsupport_runLoopTimerCallBack(CFRunLoopTimerRef ,void (*))); /*proto*/ -static void (__pyx_f_9cfsupport_gilRunLoopTimerCallBack(CFRunLoopTimerRef ,void (*))); /*proto*/ - -/* Implementation of cfsupport */ - -static char (__pyx_k7[]) = "0.4"; - -static PyObject *__pyx_n_now; -static PyObject *__pyx_n_traceback; -static PyObject *__pyx_n___version__; - -static PyObject *__pyx_k7p; - -static PyObject *__pyx_f_9cfsupport_now(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static PyObject *__pyx_f_9cfsupport_now(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_r; - PyObject *__pyx_1 = 0; - static char *__pyx_argnames[] = {0}; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "", __pyx_argnames)) return 0; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfdate.pxi":2 */ - __pyx_1 = PyFloat_FromDouble(CFAbsoluteTimeGetCurrent()); if (!__pyx_1) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 2; goto __pyx_L1;} - __pyx_r = __pyx_1; - __pyx_1 = 0; - goto __pyx_L0; - - __pyx_r = Py_None; Py_INCREF(__pyx_r); - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_1); - __Pyx_AddTraceback("cfsupport.now"); - __pyx_r = 0; - __pyx_L0:; - return __pyx_r; -} - -static PyObject *__pyx_n_print_exc; - -static void __pyx_f_9cfsupport_socketCallBack(CFSocketRef __pyx_v_s,CFSocketCallBackType __pyx_v__type,CFDataRef __pyx_v_address,void (*__pyx_v_data),void (*__pyx_v_info)) { - struct __pyx_obj_9cfsupport_PyCFSocket *__pyx_v_socket; - int __pyx_v_res; - int __pyx_v_mask; - PyObject *__pyx_1 = 0; - int __pyx_2; - PyObject *__pyx_3 = 0; - PyObject *__pyx_4 = 0; - ((PyObject*)__pyx_v_socket) = Py_None; Py_INCREF(((PyObject*)__pyx_v_socket)); - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":9 */ - __pyx_1 = (PyObject *)__pyx_v_info; - Py_INCREF(__pyx_1); - Py_DECREF(((PyObject *)__pyx_v_socket)); - ((PyObject *)__pyx_v_socket) = __pyx_1; - __pyx_1 = 0; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":11 */ - /*try:*/ { - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":12 */ - __pyx_2 = (__pyx_v__type == kCFSocketReadCallBack); - if (__pyx_2) { - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":13 */ - __pyx_2 = PyObject_IsTrue(__pyx_v_socket->readcallback); if (__pyx_2 < 0) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 13; goto __pyx_L2;} - if (__pyx_2) { - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":14 */ - __pyx_1 = PyTuple_New(0); if (!__pyx_1) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 14; goto __pyx_L2;} - __pyx_3 = PyObject_CallObject(__pyx_v_socket->readcallback, __pyx_1); if (!__pyx_3) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 14; goto __pyx_L2;} - Py_DECREF(__pyx_1); __pyx_1 = 0; - Py_DECREF(__pyx_3); __pyx_3 = 0; - goto __pyx_L5; - } - __pyx_L5:; - goto __pyx_L4; - } - __pyx_2 = (__pyx_v__type == kCFSocketWriteCallBack); - if (__pyx_2) { - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":16 */ - __pyx_2 = PyObject_IsTrue(__pyx_v_socket->writecallback); if (__pyx_2 < 0) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 16; goto __pyx_L2;} - if (__pyx_2) { - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":17 */ - __pyx_1 = PyTuple_New(0); if (!__pyx_1) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 17; goto __pyx_L2;} - __pyx_3 = PyObject_CallObject(__pyx_v_socket->writecallback, __pyx_1); if (!__pyx_3) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 17; goto __pyx_L2;} - Py_DECREF(__pyx_1); __pyx_1 = 0; - Py_DECREF(__pyx_3); __pyx_3 = 0; - goto __pyx_L6; - } - __pyx_L6:; - goto __pyx_L4; - } - __pyx_2 = (__pyx_v__type == kCFSocketConnectCallBack); - if (__pyx_2) { - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":19 */ - __pyx_2 = (__pyx_v_data == 0); - if (__pyx_2) { - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":20 */ - __pyx_v_res = 0; - goto __pyx_L7; - } - /*else*/ { - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":22 */ - __pyx_v_res = (((int (*))__pyx_v_data)[0]); - } - __pyx_L7:; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":23 */ - __pyx_2 = PyObject_IsTrue(__pyx_v_socket->connectcallback); if (__pyx_2 < 0) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 23; goto __pyx_L2;} - if (__pyx_2) { - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":24 */ - __pyx_1 = PyInt_FromLong(__pyx_v_res); if (!__pyx_1) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 24; goto __pyx_L2;} - __pyx_3 = PyTuple_New(1); if (!__pyx_3) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 24; goto __pyx_L2;} - PyTuple_SET_ITEM(__pyx_3, 0, __pyx_1); - __pyx_1 = 0; - __pyx_1 = PyObject_CallObject(__pyx_v_socket->connectcallback, __pyx_3); if (!__pyx_1) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 24; goto __pyx_L2;} - Py_DECREF(__pyx_3); __pyx_3 = 0; - Py_DECREF(__pyx_1); __pyx_1 = 0; - goto __pyx_L8; - } - __pyx_L8:; - goto __pyx_L4; - } - __pyx_L4:; - } - goto __pyx_L3; - __pyx_L2:; - Py_XDECREF(__pyx_3); __pyx_3 = 0; - Py_XDECREF(__pyx_1); __pyx_1 = 0; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":25 */ - /*except:*/ { - __Pyx_AddTraceback("cfsupport.socketCallBack"); - __pyx_3 = __Pyx_GetExcValue(); if (!__pyx_3) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 25; goto __pyx_L1;} - Py_DECREF(__pyx_3); __pyx_3 = 0; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":26 */ - __pyx_1 = __Pyx_GetName(__pyx_m, __pyx_n_traceback); if (!__pyx_1) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 26; goto __pyx_L1;} - __pyx_3 = PyObject_GetAttr(__pyx_1, __pyx_n_print_exc); if (!__pyx_3) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 26; goto __pyx_L1;} - Py_DECREF(__pyx_1); __pyx_1 = 0; - __pyx_1 = PyTuple_New(0); if (!__pyx_1) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 26; goto __pyx_L1;} - __pyx_4 = PyObject_CallObject(__pyx_3, __pyx_1); if (!__pyx_4) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 26; goto __pyx_L1;} - Py_DECREF(__pyx_3); __pyx_3 = 0; - Py_DECREF(__pyx_1); __pyx_1 = 0; - Py_DECREF(__pyx_4); __pyx_4 = 0; - goto __pyx_L3; - } - __pyx_L3:; - - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_1); - Py_XDECREF(__pyx_3); - Py_XDECREF(__pyx_4); - __Pyx_WriteUnraisable("cfsupport.socketCallBack"); - __pyx_L0:; - Py_DECREF(__pyx_v_socket); -} - -static void __pyx_f_9cfsupport_gilSocketCallBack(CFSocketRef __pyx_v_s,CFSocketCallBackType __pyx_v__type,CFDataRef __pyx_v_address,void (*__pyx_v_data),void (*__pyx_v_info)) { - PyGILState_STATE __pyx_v_gil; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":30 */ - __pyx_v_gil = PyGILState_Ensure(); - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":31 */ - __pyx_f_9cfsupport_socketCallBack(__pyx_v_s,__pyx_v__type,__pyx_v_address,__pyx_v_data,__pyx_v_info); - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":32 */ - PyGILState_Release(__pyx_v_gil); - - goto __pyx_L0; - __pyx_L1:; - __Pyx_WriteUnraisable("cfsupport.gilSocketCallBack"); - __pyx_L0:; -} - -static PyObject *__pyx_n_False; -static PyObject *__pyx_n_ValueError; - -static PyObject *__pyx_k8p; -static PyObject *__pyx_k9p; - -static char (__pyx_k8[]) = "Invalid Socket"; -static char (__pyx_k9[]) = "Couldn't create runloop source"; - -static int __pyx_f_9cfsupport_10PyCFSocket___new__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static int __pyx_f_9cfsupport_10PyCFSocket___new__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - int __pyx_v_fileno; - PyObject *__pyx_v_readcallback = 0; - PyObject *__pyx_v_writecallback = 0; - PyObject *__pyx_v_connectcallback = 0; - int __pyx_r; - PyObject *__pyx_1 = 0; - int __pyx_2; - PyObject *__pyx_3 = 0; - PyObject *__pyx_4 = 0; - static char *__pyx_argnames[] = {"fileno","readcallback","writecallback","connectcallback",0}; - __pyx_v_readcallback = __pyx_k2; - __pyx_v_writecallback = __pyx_k3; - __pyx_v_connectcallback = __pyx_k4; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "i|OOO", __pyx_argnames, &__pyx_v_fileno, &__pyx_v_readcallback, &__pyx_v_writecallback, &__pyx_v_connectcallback)) return -1; - Py_INCREF(__pyx_v_self); - Py_INCREF(__pyx_v_readcallback); - Py_INCREF(__pyx_v_writecallback); - Py_INCREF(__pyx_v_connectcallback); - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":47 */ - ((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->fileno = __pyx_v_fileno; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":48 */ - Py_INCREF(__pyx_v_readcallback); - Py_DECREF(((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->readcallback); - ((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->readcallback = __pyx_v_readcallback; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":49 */ - Py_INCREF(__pyx_v_writecallback); - Py_DECREF(((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->writecallback); - ((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->writecallback = __pyx_v_writecallback; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":50 */ - Py_INCREF(__pyx_v_connectcallback); - Py_DECREF(((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->connectcallback); - ((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->connectcallback = __pyx_v_connectcallback; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":51 */ - ((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->context.version = 0; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":52 */ - ((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->context.info = ((void (*))__pyx_v_self); - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":53 */ - ((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->context.retain = 0; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":54 */ - ((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->context.release = 0; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":55 */ - ((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->context.copyDescription = 0; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":56 */ - __pyx_1 = __Pyx_GetName(__pyx_b, __pyx_n_False); if (!__pyx_1) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 56; goto __pyx_L1;} - Py_DECREF(((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->reading); - ((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->reading = __pyx_1; - __pyx_1 = 0; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":57 */ - __pyx_1 = __Pyx_GetName(__pyx_b, __pyx_n_False); if (!__pyx_1) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 57; goto __pyx_L1;} - Py_DECREF(((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->writing); - ((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->writing = __pyx_1; - __pyx_1 = 0; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":58 */ - ((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->cf = CFSocketCreateWithNative(kCFAllocatorDefault,__pyx_v_fileno,((kCFSocketConnectCallBack | kCFSocketReadCallBack) | kCFSocketWriteCallBack),((CFSocketCallBack )(&__pyx_f_9cfsupport_gilSocketCallBack)),(&((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->context)); - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":59 */ - __pyx_2 = (((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->cf == 0); - if (__pyx_2) { - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":60 */ - __pyx_1 = __Pyx_GetName(__pyx_b, __pyx_n_ValueError); if (!__pyx_1) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 60; goto __pyx_L1;} - __pyx_3 = PyTuple_New(1); if (!__pyx_3) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 60; goto __pyx_L1;} - Py_INCREF(__pyx_k8p); - PyTuple_SET_ITEM(__pyx_3, 0, __pyx_k8p); - __pyx_4 = PyObject_CallObject(__pyx_1, __pyx_3); if (!__pyx_4) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 60; goto __pyx_L1;} - Py_DECREF(__pyx_1); __pyx_1 = 0; - Py_DECREF(__pyx_3); __pyx_3 = 0; - __Pyx_Raise(__pyx_4, 0, 0); - Py_DECREF(__pyx_4); __pyx_4 = 0; - {__pyx_filename = __pyx_f[1]; __pyx_lineno = 60; goto __pyx_L1;} - goto __pyx_L2; - } - __pyx_L2:; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":61 */ - ((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->source = CFSocketCreateRunLoopSource(kCFAllocatorDefault,((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->cf,10000); - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":62 */ - __pyx_2 = (((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->source == 0); - if (__pyx_2) { - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":63 */ - __pyx_1 = __Pyx_GetName(__pyx_b, __pyx_n_ValueError); if (!__pyx_1) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 63; goto __pyx_L1;} - __pyx_3 = PyTuple_New(1); if (!__pyx_3) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 63; goto __pyx_L1;} - Py_INCREF(__pyx_k9p); - PyTuple_SET_ITEM(__pyx_3, 0, __pyx_k9p); - __pyx_4 = PyObject_CallObject(__pyx_1, __pyx_3); if (!__pyx_4) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 63; goto __pyx_L1;} - Py_DECREF(__pyx_1); __pyx_1 = 0; - Py_DECREF(__pyx_3); __pyx_3 = 0; - __Pyx_Raise(__pyx_4, 0, 0); - Py_DECREF(__pyx_4); __pyx_4 = 0; - {__pyx_filename = __pyx_f[1]; __pyx_lineno = 63; goto __pyx_L1;} - goto __pyx_L3; - } - __pyx_L3:; - - __pyx_r = 0; - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_1); - Py_XDECREF(__pyx_3); - Py_XDECREF(__pyx_4); - __Pyx_AddTraceback("cfsupport.PyCFSocket.__new__"); - __pyx_r = -1; - __pyx_L0:; - Py_DECREF(__pyx_v_self); - Py_DECREF(__pyx_v_readcallback); - Py_DECREF(__pyx_v_writecallback); - Py_DECREF(__pyx_v_connectcallback); - return __pyx_r; -} - -static PyObject *__pyx_f_9cfsupport_10PyCFSocket_update(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static PyObject *__pyx_f_9cfsupport_10PyCFSocket_update(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - int __pyx_v_mask; - int __pyx_v_offmask; - int __pyx_v_automask; - PyObject *__pyx_r; - int __pyx_1; - static char *__pyx_argnames[] = {0}; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "", __pyx_argnames)) return 0; - Py_INCREF(__pyx_v_self); - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":70 */ - __pyx_v_mask = (kCFSocketConnectCallBack | kCFSocketAcceptCallBack); - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":71 */ - __pyx_v_offmask = 0; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":72 */ - __pyx_v_automask = kCFSocketAutomaticallyReenableAcceptCallBack; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":73 */ - __pyx_1 = PyObject_IsTrue(((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->reading); if (__pyx_1 < 0) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 73; goto __pyx_L1;} - if (__pyx_1) { - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":74 */ - __pyx_v_mask = (__pyx_v_mask | kCFSocketReadCallBack); - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":75 */ - __pyx_v_automask = (__pyx_v_automask | kCFSocketAutomaticallyReenableReadCallBack); - goto __pyx_L2; - } - /*else*/ { - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":77 */ - __pyx_v_offmask = (__pyx_v_offmask | kCFSocketReadCallBack); - } - __pyx_L2:; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":78 */ - __pyx_1 = PyObject_IsTrue(((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->writing); if (__pyx_1 < 0) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 78; goto __pyx_L1;} - if (__pyx_1) { - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":79 */ - __pyx_v_mask = (__pyx_v_mask | kCFSocketWriteCallBack); - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":80 */ - __pyx_v_automask = (__pyx_v_automask | kCFSocketAutomaticallyReenableWriteCallBack); - goto __pyx_L3; - } - /*else*/ { - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":82 */ - __pyx_v_offmask = (__pyx_v_offmask | kCFSocketWriteCallBack); - } - __pyx_L3:; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":83 */ - CFSocketDisableCallBacks(((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->cf,__pyx_v_offmask); - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":84 */ - CFSocketEnableCallBacks(((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->cf,__pyx_v_mask); - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":85 */ - CFSocketSetSocketFlags(((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->cf,__pyx_v_automask); - - __pyx_r = Py_None; Py_INCREF(__pyx_r); - goto __pyx_L0; - __pyx_L1:; - __Pyx_AddTraceback("cfsupport.PyCFSocket.update"); - __pyx_r = 0; - __pyx_L0:; - Py_DECREF(__pyx_v_self); - return __pyx_r; -} - -static PyObject *__pyx_n_True; -static PyObject *__pyx_n_update; - -static PyObject *__pyx_f_9cfsupport_10PyCFSocket_startReading(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static PyObject *__pyx_f_9cfsupport_10PyCFSocket_startReading(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_r; - PyObject *__pyx_1 = 0; - PyObject *__pyx_2 = 0; - PyObject *__pyx_3 = 0; - static char *__pyx_argnames[] = {0}; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "", __pyx_argnames)) return 0; - Py_INCREF(__pyx_v_self); - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":89 */ - __pyx_1 = __Pyx_GetName(__pyx_b, __pyx_n_True); if (!__pyx_1) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 89; goto __pyx_L1;} - Py_DECREF(((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->reading); - ((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->reading = __pyx_1; - __pyx_1 = 0; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":90 */ - __pyx_1 = PyObject_GetAttr(__pyx_v_self, __pyx_n_update); if (!__pyx_1) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 90; goto __pyx_L1;} - __pyx_2 = PyTuple_New(0); if (!__pyx_2) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 90; goto __pyx_L1;} - __pyx_3 = PyObject_CallObject(__pyx_1, __pyx_2); if (!__pyx_3) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 90; goto __pyx_L1;} - Py_DECREF(__pyx_1); __pyx_1 = 0; - Py_DECREF(__pyx_2); __pyx_2 = 0; - Py_DECREF(__pyx_3); __pyx_3 = 0; - - __pyx_r = Py_None; Py_INCREF(__pyx_r); - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_1); - Py_XDECREF(__pyx_2); - Py_XDECREF(__pyx_3); - __Pyx_AddTraceback("cfsupport.PyCFSocket.startReading"); - __pyx_r = 0; - __pyx_L0:; - Py_DECREF(__pyx_v_self); - return __pyx_r; -} - -static PyObject *__pyx_f_9cfsupport_10PyCFSocket_stopReading(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static PyObject *__pyx_f_9cfsupport_10PyCFSocket_stopReading(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_r; - PyObject *__pyx_1 = 0; - PyObject *__pyx_2 = 0; - PyObject *__pyx_3 = 0; - static char *__pyx_argnames[] = {0}; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "", __pyx_argnames)) return 0; - Py_INCREF(__pyx_v_self); - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":93 */ - __pyx_1 = __Pyx_GetName(__pyx_b, __pyx_n_False); if (!__pyx_1) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 93; goto __pyx_L1;} - Py_DECREF(((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->reading); - ((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->reading = __pyx_1; - __pyx_1 = 0; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":94 */ - __pyx_1 = PyObject_GetAttr(__pyx_v_self, __pyx_n_update); if (!__pyx_1) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 94; goto __pyx_L1;} - __pyx_2 = PyTuple_New(0); if (!__pyx_2) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 94; goto __pyx_L1;} - __pyx_3 = PyObject_CallObject(__pyx_1, __pyx_2); if (!__pyx_3) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 94; goto __pyx_L1;} - Py_DECREF(__pyx_1); __pyx_1 = 0; - Py_DECREF(__pyx_2); __pyx_2 = 0; - Py_DECREF(__pyx_3); __pyx_3 = 0; - - __pyx_r = Py_None; Py_INCREF(__pyx_r); - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_1); - Py_XDECREF(__pyx_2); - Py_XDECREF(__pyx_3); - __Pyx_AddTraceback("cfsupport.PyCFSocket.stopReading"); - __pyx_r = 0; - __pyx_L0:; - Py_DECREF(__pyx_v_self); - return __pyx_r; -} - -static PyObject *__pyx_f_9cfsupport_10PyCFSocket_startWriting(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static PyObject *__pyx_f_9cfsupport_10PyCFSocket_startWriting(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_r; - PyObject *__pyx_1 = 0; - PyObject *__pyx_2 = 0; - PyObject *__pyx_3 = 0; - static char *__pyx_argnames[] = {0}; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "", __pyx_argnames)) return 0; - Py_INCREF(__pyx_v_self); - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":97 */ - __pyx_1 = __Pyx_GetName(__pyx_b, __pyx_n_True); if (!__pyx_1) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 97; goto __pyx_L1;} - Py_DECREF(((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->writing); - ((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->writing = __pyx_1; - __pyx_1 = 0; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":98 */ - __pyx_1 = PyObject_GetAttr(__pyx_v_self, __pyx_n_update); if (!__pyx_1) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 98; goto __pyx_L1;} - __pyx_2 = PyTuple_New(0); if (!__pyx_2) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 98; goto __pyx_L1;} - __pyx_3 = PyObject_CallObject(__pyx_1, __pyx_2); if (!__pyx_3) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 98; goto __pyx_L1;} - Py_DECREF(__pyx_1); __pyx_1 = 0; - Py_DECREF(__pyx_2); __pyx_2 = 0; - Py_DECREF(__pyx_3); __pyx_3 = 0; - - __pyx_r = Py_None; Py_INCREF(__pyx_r); - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_1); - Py_XDECREF(__pyx_2); - Py_XDECREF(__pyx_3); - __Pyx_AddTraceback("cfsupport.PyCFSocket.startWriting"); - __pyx_r = 0; - __pyx_L0:; - Py_DECREF(__pyx_v_self); - return __pyx_r; -} - -static PyObject *__pyx_f_9cfsupport_10PyCFSocket_stopWriting(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static PyObject *__pyx_f_9cfsupport_10PyCFSocket_stopWriting(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_r; - PyObject *__pyx_1 = 0; - PyObject *__pyx_2 = 0; - PyObject *__pyx_3 = 0; - static char *__pyx_argnames[] = {0}; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "", __pyx_argnames)) return 0; - Py_INCREF(__pyx_v_self); - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":101 */ - __pyx_1 = __Pyx_GetName(__pyx_b, __pyx_n_False); if (!__pyx_1) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 101; goto __pyx_L1;} - Py_DECREF(((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->writing); - ((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->writing = __pyx_1; - __pyx_1 = 0; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":102 */ - __pyx_1 = PyObject_GetAttr(__pyx_v_self, __pyx_n_update); if (!__pyx_1) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 102; goto __pyx_L1;} - __pyx_2 = PyTuple_New(0); if (!__pyx_2) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 102; goto __pyx_L1;} - __pyx_3 = PyObject_CallObject(__pyx_1, __pyx_2); if (!__pyx_3) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 102; goto __pyx_L1;} - Py_DECREF(__pyx_1); __pyx_1 = 0; - Py_DECREF(__pyx_2); __pyx_2 = 0; - Py_DECREF(__pyx_3); __pyx_3 = 0; - - __pyx_r = Py_None; Py_INCREF(__pyx_r); - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_1); - Py_XDECREF(__pyx_2); - Py_XDECREF(__pyx_3); - __Pyx_AddTraceback("cfsupport.PyCFSocket.stopWriting"); - __pyx_r = 0; - __pyx_L0:; - Py_DECREF(__pyx_v_self); - return __pyx_r; -} - -static void __pyx_f_9cfsupport_10PyCFSocket___dealloc__(PyObject *__pyx_v_self); /*proto*/ -static void __pyx_f_9cfsupport_10PyCFSocket___dealloc__(PyObject *__pyx_v_self) { - int __pyx_1; - Py_INCREF(__pyx_v_self); - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":106 */ - __pyx_1 = (((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->source != 0); - if (__pyx_1) { - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":107 */ - CFRelease(((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->source); - goto __pyx_L2; - } - __pyx_L2:; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":108 */ - __pyx_1 = (((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->cf != 0); - if (__pyx_1) { - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":109 */ - CFSocketInvalidate(((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->cf); - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":110 */ - CFRelease(((struct __pyx_obj_9cfsupport_PyCFSocket *)__pyx_v_self)->cf); - goto __pyx_L3; - } - __pyx_L3:; - - goto __pyx_L0; - __pyx_L1:; - __Pyx_AddTraceback("cfsupport.PyCFSocket.__dealloc__"); - __pyx_L0:; - Py_DECREF(__pyx_v_self); -} - -static PyObject *__pyx_k10p; - -static char (__pyx_k10[]) = "Invalid Socket"; - -static int __pyx_f_9cfsupport_16PyCFRunLoopTimer___new__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static int __pyx_f_9cfsupport_16PyCFRunLoopTimer___new__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - double __pyx_v_fireDate; - double __pyx_v_interval; - PyObject *__pyx_v_callout = 0; - int __pyx_r; - int __pyx_1; - PyObject *__pyx_2 = 0; - PyObject *__pyx_3 = 0; - PyObject *__pyx_4 = 0; - static char *__pyx_argnames[] = {"fireDate","interval","callout",0}; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "ddO", __pyx_argnames, &__pyx_v_fireDate, &__pyx_v_interval, &__pyx_v_callout)) return -1; - Py_INCREF(__pyx_v_self); - Py_INCREF(__pyx_v_callout); - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":11 */ - Py_INCREF(__pyx_v_callout); - Py_DECREF(((struct __pyx_obj_9cfsupport_PyCFRunLoopTimer *)__pyx_v_self)->callout); - ((struct __pyx_obj_9cfsupport_PyCFRunLoopTimer *)__pyx_v_self)->callout = __pyx_v_callout; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":12 */ - ((struct __pyx_obj_9cfsupport_PyCFRunLoopTimer *)__pyx_v_self)->context.version = 0; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":13 */ - ((struct __pyx_obj_9cfsupport_PyCFRunLoopTimer *)__pyx_v_self)->context.info = ((void (*))__pyx_v_self); - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":14 */ - ((struct __pyx_obj_9cfsupport_PyCFRunLoopTimer *)__pyx_v_self)->context.retain = 0; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":15 */ - ((struct __pyx_obj_9cfsupport_PyCFRunLoopTimer *)__pyx_v_self)->context.release = 0; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":16 */ - ((struct __pyx_obj_9cfsupport_PyCFRunLoopTimer *)__pyx_v_self)->context.copyDescription = 0; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":17 */ - ((struct __pyx_obj_9cfsupport_PyCFRunLoopTimer *)__pyx_v_self)->cf = CFRunLoopTimerCreate(kCFAllocatorDefault,__pyx_v_fireDate,__pyx_v_interval,0,0,((CFRunLoopTimerCallBack )(&__pyx_f_9cfsupport_gilRunLoopTimerCallBack)),(&((struct __pyx_obj_9cfsupport_PyCFRunLoopTimer *)__pyx_v_self)->context)); - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":18 */ - __pyx_1 = (((struct __pyx_obj_9cfsupport_PyCFRunLoopTimer *)__pyx_v_self)->cf == 0); - if (__pyx_1) { - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":19 */ - __pyx_2 = __Pyx_GetName(__pyx_b, __pyx_n_ValueError); if (!__pyx_2) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 19; goto __pyx_L1;} - __pyx_3 = PyTuple_New(1); if (!__pyx_3) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 19; goto __pyx_L1;} - Py_INCREF(__pyx_k10p); - PyTuple_SET_ITEM(__pyx_3, 0, __pyx_k10p); - __pyx_4 = PyObject_CallObject(__pyx_2, __pyx_3); if (!__pyx_4) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 19; goto __pyx_L1;} - Py_DECREF(__pyx_2); __pyx_2 = 0; - Py_DECREF(__pyx_3); __pyx_3 = 0; - __Pyx_Raise(__pyx_4, 0, 0); - Py_DECREF(__pyx_4); __pyx_4 = 0; - {__pyx_filename = __pyx_f[2]; __pyx_lineno = 19; goto __pyx_L1;} - goto __pyx_L2; - } - __pyx_L2:; - - __pyx_r = 0; - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_2); - Py_XDECREF(__pyx_3); - Py_XDECREF(__pyx_4); - __Pyx_AddTraceback("cfsupport.PyCFRunLoopTimer.__new__"); - __pyx_r = -1; - __pyx_L0:; - Py_DECREF(__pyx_v_self); - Py_DECREF(__pyx_v_callout); - return __pyx_r; -} - -static PyObject *__pyx_f_9cfsupport_16PyCFRunLoopTimer_getNextFireDate(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static PyObject *__pyx_f_9cfsupport_16PyCFRunLoopTimer_getNextFireDate(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_r; - PyObject *__pyx_1 = 0; - static char *__pyx_argnames[] = {0}; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "", __pyx_argnames)) return 0; - Py_INCREF(__pyx_v_self); - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":22 */ - __pyx_1 = PyFloat_FromDouble(CFRunLoopTimerGetNextFireDate(((struct __pyx_obj_9cfsupport_PyCFRunLoopTimer *)__pyx_v_self)->cf)); if (!__pyx_1) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 22; goto __pyx_L1;} - __pyx_r = __pyx_1; - __pyx_1 = 0; - goto __pyx_L0; - - __pyx_r = Py_None; Py_INCREF(__pyx_r); - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_1); - __Pyx_AddTraceback("cfsupport.PyCFRunLoopTimer.getNextFireDate"); - __pyx_r = 0; - __pyx_L0:; - Py_DECREF(__pyx_v_self); - return __pyx_r; -} - -static PyObject *__pyx_f_9cfsupport_16PyCFRunLoopTimer_setNextFireDate(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static PyObject *__pyx_f_9cfsupport_16PyCFRunLoopTimer_setNextFireDate(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - double __pyx_v_fireDate; - PyObject *__pyx_r; - static char *__pyx_argnames[] = {"fireDate",0}; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "d", __pyx_argnames, &__pyx_v_fireDate)) return 0; - Py_INCREF(__pyx_v_self); - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":25 */ - CFRunLoopTimerSetNextFireDate(((struct __pyx_obj_9cfsupport_PyCFRunLoopTimer *)__pyx_v_self)->cf,__pyx_v_fireDate); - - __pyx_r = Py_None; Py_INCREF(__pyx_r); - goto __pyx_L0; - __pyx_L1:; - __Pyx_AddTraceback("cfsupport.PyCFRunLoopTimer.setNextFireDate"); - __pyx_r = 0; - __pyx_L0:; - Py_DECREF(__pyx_v_self); - return __pyx_r; -} - -static PyObject *__pyx_f_9cfsupport_16PyCFRunLoopTimer_invalidate(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static PyObject *__pyx_f_9cfsupport_16PyCFRunLoopTimer_invalidate(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_r; - static char *__pyx_argnames[] = {0}; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "", __pyx_argnames)) return 0; - Py_INCREF(__pyx_v_self); - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":28 */ - CFRunLoopTimerInvalidate(((struct __pyx_obj_9cfsupport_PyCFRunLoopTimer *)__pyx_v_self)->cf); - - __pyx_r = Py_None; Py_INCREF(__pyx_r); - goto __pyx_L0; - __pyx_L1:; - __Pyx_AddTraceback("cfsupport.PyCFRunLoopTimer.invalidate"); - __pyx_r = 0; - __pyx_L0:; - Py_DECREF(__pyx_v_self); - return __pyx_r; -} - -static void __pyx_f_9cfsupport_16PyCFRunLoopTimer___dealloc__(PyObject *__pyx_v_self); /*proto*/ -static void __pyx_f_9cfsupport_16PyCFRunLoopTimer___dealloc__(PyObject *__pyx_v_self) { - int __pyx_1; - Py_INCREF(__pyx_v_self); - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":31 */ - __pyx_1 = (((struct __pyx_obj_9cfsupport_PyCFRunLoopTimer *)__pyx_v_self)->cf != 0); - if (__pyx_1) { - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":32 */ - CFRelease(((struct __pyx_obj_9cfsupport_PyCFRunLoopTimer *)__pyx_v_self)->cf); - goto __pyx_L2; - } - __pyx_L2:; - - goto __pyx_L0; - __pyx_L1:; - __Pyx_AddTraceback("cfsupport.PyCFRunLoopTimer.__dealloc__"); - __pyx_L0:; - Py_DECREF(__pyx_v_self); -} - -static void __pyx_f_9cfsupport_runLoopTimerCallBack(CFRunLoopTimerRef __pyx_v_timer,void (*__pyx_v_info)) { - struct __pyx_obj_9cfsupport_PyCFRunLoopTimer *__pyx_v_obj; - PyObject *__pyx_1 = 0; - int __pyx_2; - PyObject *__pyx_3 = 0; - PyObject *__pyx_4 = 0; - ((PyObject*)__pyx_v_obj) = Py_None; Py_INCREF(((PyObject*)__pyx_v_obj)); - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":36 */ - __pyx_1 = (PyObject *)__pyx_v_info; - Py_INCREF(__pyx_1); - Py_DECREF(((PyObject *)__pyx_v_obj)); - ((PyObject *)__pyx_v_obj) = __pyx_1; - __pyx_1 = 0; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":37 */ - /*try:*/ { - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":38 */ - __pyx_2 = PyObject_IsTrue(__pyx_v_obj->callout); if (__pyx_2 < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 38; goto __pyx_L2;} - if (__pyx_2) { - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":39 */ - __pyx_1 = PyTuple_New(0); if (!__pyx_1) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 39; goto __pyx_L2;} - __pyx_3 = PyObject_CallObject(__pyx_v_obj->callout, __pyx_1); if (!__pyx_3) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 39; goto __pyx_L2;} - Py_DECREF(__pyx_1); __pyx_1 = 0; - Py_DECREF(__pyx_3); __pyx_3 = 0; - goto __pyx_L4; - } - __pyx_L4:; - } - goto __pyx_L3; - __pyx_L2:; - Py_XDECREF(__pyx_1); __pyx_1 = 0; - Py_XDECREF(__pyx_3); __pyx_3 = 0; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":40 */ - /*except:*/ { - __Pyx_AddTraceback("cfsupport.runLoopTimerCallBack"); - __pyx_1 = __Pyx_GetExcValue(); if (!__pyx_1) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 40; goto __pyx_L1;} - Py_DECREF(__pyx_1); __pyx_1 = 0; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":41 */ - __pyx_3 = __Pyx_GetName(__pyx_m, __pyx_n_traceback); if (!__pyx_3) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 41; goto __pyx_L1;} - __pyx_1 = PyObject_GetAttr(__pyx_3, __pyx_n_print_exc); if (!__pyx_1) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 41; goto __pyx_L1;} - Py_DECREF(__pyx_3); __pyx_3 = 0; - __pyx_3 = PyTuple_New(0); if (!__pyx_3) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 41; goto __pyx_L1;} - __pyx_4 = PyObject_CallObject(__pyx_1, __pyx_3); if (!__pyx_4) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 41; goto __pyx_L1;} - Py_DECREF(__pyx_1); __pyx_1 = 0; - Py_DECREF(__pyx_3); __pyx_3 = 0; - Py_DECREF(__pyx_4); __pyx_4 = 0; - goto __pyx_L3; - } - __pyx_L3:; - - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_1); - Py_XDECREF(__pyx_3); - Py_XDECREF(__pyx_4); - __Pyx_WriteUnraisable("cfsupport.runLoopTimerCallBack"); - __pyx_L0:; - Py_DECREF(__pyx_v_obj); -} - -static void __pyx_f_9cfsupport_gilRunLoopTimerCallBack(CFRunLoopTimerRef __pyx_v_timer,void (*__pyx_v_info)) { - PyGILState_STATE __pyx_v_gil; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":45 */ - __pyx_v_gil = PyGILState_Ensure(); - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":46 */ - __pyx_f_9cfsupport_runLoopTimerCallBack(__pyx_v_timer,__pyx_v_info); - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":47 */ - PyGILState_Release(__pyx_v_gil); - - goto __pyx_L0; - __pyx_L1:; - __Pyx_WriteUnraisable("cfsupport.gilRunLoopTimerCallBack"); - __pyx_L0:; -} - -static int __pyx_f_9cfsupport_11PyCFRunLoop___new__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static int __pyx_f_9cfsupport_11PyCFRunLoop___new__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_v_runLoop = 0; - CFTypeRef __pyx_v__runLoop; - int __pyx_r; - int __pyx_1; - PyObject *__pyx_2 = 0; - static char *__pyx_argnames[] = {"runLoop",0}; - __pyx_v_runLoop = __pyx_k6; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "|O", __pyx_argnames, &__pyx_v_runLoop)) return -1; - Py_INCREF(__pyx_v_self); - Py_INCREF(__pyx_v_runLoop); - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":54 */ - __pyx_1 = __pyx_v_runLoop == Py_None; - if (__pyx_1) { - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":55 */ - __pyx_v__runLoop = CFRunLoopGetCurrent(); - goto __pyx_L2; - } - /*else*/ { - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":57 */ - __pyx_1 = (CFObj_Convert(__pyx_v_runLoop,(&__pyx_v__runLoop)) == 0); - if (__pyx_1) { - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":58 */ - __Pyx_ReRaise(); - {__pyx_filename = __pyx_f[2]; __pyx_lineno = 58; goto __pyx_L1;} - goto __pyx_L3; - } - __pyx_L3:; - } - __pyx_L2:; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":61 */ - __pyx_2 = CFObj_New(CFRetain(__pyx_v__runLoop)); if (!__pyx_2) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 61; goto __pyx_L1;} - Py_DECREF(((struct __pyx_obj_9cfsupport_PyCFRunLoop *)__pyx_v_self)->cf); - ((struct __pyx_obj_9cfsupport_PyCFRunLoop *)__pyx_v_self)->cf = __pyx_2; - __pyx_2 = 0; - - __pyx_r = 0; - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_2); - __Pyx_AddTraceback("cfsupport.PyCFRunLoop.__new__"); - __pyx_r = -1; - __pyx_L0:; - Py_DECREF(__pyx_v_self); - Py_DECREF(__pyx_v_runLoop); - return __pyx_r; -} - -static PyObject *__pyx_f_9cfsupport_11PyCFRunLoop_run(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static PyObject *__pyx_f_9cfsupport_11PyCFRunLoop_run(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_r; - static char *__pyx_argnames[] = {0}; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "", __pyx_argnames)) return 0; - Py_INCREF(__pyx_v_self); - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":64 */ - CFRunLoopRun(); - - __pyx_r = Py_None; Py_INCREF(__pyx_r); - goto __pyx_L0; - __pyx_L1:; - __Pyx_AddTraceback("cfsupport.PyCFRunLoop.run"); - __pyx_r = 0; - __pyx_L0:; - Py_DECREF(__pyx_v_self); - return __pyx_r; -} - -static PyObject *__pyx_k11p; - -static char (__pyx_k11[]) = "CFRunLoopReference is invalid"; - -static PyObject *__pyx_f_9cfsupport_11PyCFRunLoop_stop(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static PyObject *__pyx_f_9cfsupport_11PyCFRunLoop_stop(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - CFTypeRef __pyx_v__runLoop; - PyObject *__pyx_r; - int __pyx_1; - PyObject *__pyx_2 = 0; - static char *__pyx_argnames[] = {0}; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "", __pyx_argnames)) return 0; - Py_INCREF(__pyx_v_self); - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":68 */ - __pyx_1 = (CFObj_Convert(((struct __pyx_obj_9cfsupport_PyCFRunLoop *)__pyx_v_self)->cf,(&__pyx_v__runLoop)) == 0); - if (__pyx_1) { - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":69 */ - __pyx_2 = __Pyx_GetName(__pyx_b, __pyx_n_ValueError); if (!__pyx_2) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 69; goto __pyx_L1;} - __Pyx_Raise(__pyx_2, __pyx_k11p, 0); - Py_DECREF(__pyx_2); __pyx_2 = 0; - {__pyx_filename = __pyx_f[2]; __pyx_lineno = 69; goto __pyx_L1;} - goto __pyx_L2; - } - __pyx_L2:; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":70 */ - CFRunLoopStop(__pyx_v__runLoop); - - __pyx_r = Py_None; Py_INCREF(__pyx_r); - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_2); - __Pyx_AddTraceback("cfsupport.PyCFRunLoop.stop"); - __pyx_r = 0; - __pyx_L0:; - Py_DECREF(__pyx_v_self); - return __pyx_r; -} - -static PyObject *__pyx_k12p; - -static char (__pyx_k12[]) = "CFRunLoopReference is invalid"; - -static PyObject *__pyx_f_9cfsupport_11PyCFRunLoop_currentMode(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static PyObject *__pyx_f_9cfsupport_11PyCFRunLoop_currentMode(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - CFTypeRef __pyx_v__currentMode; - CFTypeRef __pyx_v__runLoop; - PyObject *__pyx_r; - int __pyx_1; - PyObject *__pyx_2 = 0; - static char *__pyx_argnames[] = {0}; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "", __pyx_argnames)) return 0; - Py_INCREF(__pyx_v_self); - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":75 */ - __pyx_1 = (CFObj_Convert(((struct __pyx_obj_9cfsupport_PyCFRunLoop *)__pyx_v_self)->cf,(&__pyx_v__runLoop)) == 0); - if (__pyx_1) { - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":76 */ - __pyx_2 = __Pyx_GetName(__pyx_b, __pyx_n_ValueError); if (!__pyx_2) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 76; goto __pyx_L1;} - __Pyx_Raise(__pyx_2, __pyx_k12p, 0); - Py_DECREF(__pyx_2); __pyx_2 = 0; - {__pyx_filename = __pyx_f[2]; __pyx_lineno = 76; goto __pyx_L1;} - goto __pyx_L2; - } - __pyx_L2:; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":77 */ - __pyx_v__currentMode = CFRunLoopCopyCurrentMode(__pyx_v__runLoop); - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":78 */ - __pyx_1 = (__pyx_v__currentMode == 0); - if (__pyx_1) { - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":79 */ - Py_INCREF(Py_None); - __pyx_r = Py_None; - goto __pyx_L0; - goto __pyx_L3; - } - __pyx_L3:; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":80 */ - __pyx_2 = CFObj_New(__pyx_v__currentMode); if (!__pyx_2) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 80; goto __pyx_L1;} - __pyx_r = __pyx_2; - __pyx_2 = 0; - goto __pyx_L0; - - __pyx_r = Py_None; Py_INCREF(__pyx_r); - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_2); - __Pyx_AddTraceback("cfsupport.PyCFRunLoop.currentMode"); - __pyx_r = 0; - __pyx_L0:; - Py_DECREF(__pyx_v_self); - return __pyx_r; -} - -static PyObject *__pyx_k13p; - -static char (__pyx_k13[]) = "CFRunLoopReference is invalid"; - -static PyObject *__pyx_f_9cfsupport_11PyCFRunLoop_addSocket(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static PyObject *__pyx_f_9cfsupport_11PyCFRunLoop_addSocket(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - struct __pyx_obj_9cfsupport_PyCFSocket *__pyx_v_socket = 0; - CFTypeRef __pyx_v__runLoop; - PyObject *__pyx_r; - int __pyx_1; - PyObject *__pyx_2 = 0; - static char *__pyx_argnames[] = {"socket",0}; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "O", __pyx_argnames, &__pyx_v_socket)) return 0; - Py_INCREF(__pyx_v_self); - Py_INCREF(__pyx_v_socket); - if (!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_socket), __pyx_ptype_9cfsupport_PyCFSocket, 0, "socket")) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 82; goto __pyx_L1;} - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":84 */ - __pyx_1 = (CFObj_Convert(((struct __pyx_obj_9cfsupport_PyCFRunLoop *)__pyx_v_self)->cf,(&__pyx_v__runLoop)) == 0); - if (__pyx_1) { - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":85 */ - __pyx_2 = __Pyx_GetName(__pyx_b, __pyx_n_ValueError); if (!__pyx_2) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 85; goto __pyx_L1;} - __Pyx_Raise(__pyx_2, __pyx_k13p, 0); - Py_DECREF(__pyx_2); __pyx_2 = 0; - {__pyx_filename = __pyx_f[2]; __pyx_lineno = 85; goto __pyx_L1;} - goto __pyx_L2; - } - __pyx_L2:; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":86 */ - CFRunLoopAddSource(__pyx_v__runLoop,__pyx_v_socket->source,kCFRunLoopCommonModes); - - __pyx_r = Py_None; Py_INCREF(__pyx_r); - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_2); - __Pyx_AddTraceback("cfsupport.PyCFRunLoop.addSocket"); - __pyx_r = 0; - __pyx_L0:; - Py_DECREF(__pyx_v_self); - Py_DECREF(__pyx_v_socket); - return __pyx_r; -} - -static PyObject *__pyx_k14p; - -static char (__pyx_k14[]) = "CFRunLoopReference is invalid"; - -static PyObject *__pyx_f_9cfsupport_11PyCFRunLoop_removeSocket(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static PyObject *__pyx_f_9cfsupport_11PyCFRunLoop_removeSocket(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - struct __pyx_obj_9cfsupport_PyCFSocket *__pyx_v_socket = 0; - CFTypeRef __pyx_v__runLoop; - PyObject *__pyx_r; - int __pyx_1; - PyObject *__pyx_2 = 0; - static char *__pyx_argnames[] = {"socket",0}; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "O", __pyx_argnames, &__pyx_v_socket)) return 0; - Py_INCREF(__pyx_v_self); - Py_INCREF(__pyx_v_socket); - if (!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_socket), __pyx_ptype_9cfsupport_PyCFSocket, 0, "socket")) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 88; goto __pyx_L1;} - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":90 */ - __pyx_1 = (CFObj_Convert(((struct __pyx_obj_9cfsupport_PyCFRunLoop *)__pyx_v_self)->cf,(&__pyx_v__runLoop)) == 0); - if (__pyx_1) { - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":91 */ - __pyx_2 = __Pyx_GetName(__pyx_b, __pyx_n_ValueError); if (!__pyx_2) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 91; goto __pyx_L1;} - __Pyx_Raise(__pyx_2, __pyx_k14p, 0); - Py_DECREF(__pyx_2); __pyx_2 = 0; - {__pyx_filename = __pyx_f[2]; __pyx_lineno = 91; goto __pyx_L1;} - goto __pyx_L2; - } - __pyx_L2:; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":92 */ - CFRunLoopRemoveSource(__pyx_v__runLoop,__pyx_v_socket->source,kCFRunLoopCommonModes); - - __pyx_r = Py_None; Py_INCREF(__pyx_r); - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_2); - __Pyx_AddTraceback("cfsupport.PyCFRunLoop.removeSocket"); - __pyx_r = 0; - __pyx_L0:; - Py_DECREF(__pyx_v_self); - Py_DECREF(__pyx_v_socket); - return __pyx_r; -} - -static PyObject *__pyx_k15p; - -static char (__pyx_k15[]) = "CFRunLoopReference is invalid"; - -static PyObject *__pyx_f_9cfsupport_11PyCFRunLoop_addTimer(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static PyObject *__pyx_f_9cfsupport_11PyCFRunLoop_addTimer(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - struct __pyx_obj_9cfsupport_PyCFRunLoopTimer *__pyx_v_timer = 0; - CFTypeRef __pyx_v__runLoop; - PyObject *__pyx_r; - int __pyx_1; - PyObject *__pyx_2 = 0; - static char *__pyx_argnames[] = {"timer",0}; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "O", __pyx_argnames, &__pyx_v_timer)) return 0; - Py_INCREF(__pyx_v_self); - Py_INCREF(__pyx_v_timer); - if (!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_timer), __pyx_ptype_9cfsupport_PyCFRunLoopTimer, 0, "timer")) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 94; goto __pyx_L1;} - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":96 */ - __pyx_1 = (CFObj_Convert(((struct __pyx_obj_9cfsupport_PyCFRunLoop *)__pyx_v_self)->cf,(&__pyx_v__runLoop)) == 0); - if (__pyx_1) { - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":97 */ - __pyx_2 = __Pyx_GetName(__pyx_b, __pyx_n_ValueError); if (!__pyx_2) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 97; goto __pyx_L1;} - __Pyx_Raise(__pyx_2, __pyx_k15p, 0); - Py_DECREF(__pyx_2); __pyx_2 = 0; - {__pyx_filename = __pyx_f[2]; __pyx_lineno = 97; goto __pyx_L1;} - goto __pyx_L2; - } - __pyx_L2:; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":98 */ - CFRunLoopAddTimer(__pyx_v__runLoop,__pyx_v_timer->cf,kCFRunLoopCommonModes); - - __pyx_r = Py_None; Py_INCREF(__pyx_r); - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_2); - __Pyx_AddTraceback("cfsupport.PyCFRunLoop.addTimer"); - __pyx_r = 0; - __pyx_L0:; - Py_DECREF(__pyx_v_self); - Py_DECREF(__pyx_v_timer); - return __pyx_r; -} - -static PyObject *__pyx_k16p; - -static char (__pyx_k16[]) = "CFRunLoopReference is invalid"; - -static PyObject *__pyx_f_9cfsupport_11PyCFRunLoop_removeTimer(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static PyObject *__pyx_f_9cfsupport_11PyCFRunLoop_removeTimer(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - struct __pyx_obj_9cfsupport_PyCFRunLoopTimer *__pyx_v_timer = 0; - CFTypeRef __pyx_v__runLoop; - PyObject *__pyx_r; - int __pyx_1; - PyObject *__pyx_2 = 0; - static char *__pyx_argnames[] = {"timer",0}; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "O", __pyx_argnames, &__pyx_v_timer)) return 0; - Py_INCREF(__pyx_v_self); - Py_INCREF(__pyx_v_timer); - if (!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_timer), __pyx_ptype_9cfsupport_PyCFRunLoopTimer, 0, "timer")) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 100; goto __pyx_L1;} - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":102 */ - __pyx_1 = (CFObj_Convert(((struct __pyx_obj_9cfsupport_PyCFRunLoop *)__pyx_v_self)->cf,(&__pyx_v__runLoop)) == 0); - if (__pyx_1) { - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":103 */ - __pyx_2 = __Pyx_GetName(__pyx_b, __pyx_n_ValueError); if (!__pyx_2) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 103; goto __pyx_L1;} - __Pyx_Raise(__pyx_2, __pyx_k16p, 0); - Py_DECREF(__pyx_2); __pyx_2 = 0; - {__pyx_filename = __pyx_f[2]; __pyx_lineno = 103; goto __pyx_L1;} - goto __pyx_L2; - } - __pyx_L2:; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":104 */ - CFRunLoopRemoveTimer(__pyx_v__runLoop,__pyx_v_timer->cf,kCFRunLoopCommonModes); - - __pyx_r = Py_None; Py_INCREF(__pyx_r); - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_2); - __Pyx_AddTraceback("cfsupport.PyCFRunLoop.removeTimer"); - __pyx_r = 0; - __pyx_L0:; - Py_DECREF(__pyx_v_self); - Py_DECREF(__pyx_v_timer); - return __pyx_r; -} - -static __Pyx_InternTabEntry __pyx_intern_tab[] = { - {&__pyx_n_False, "False"}, - {&__pyx_n_True, "True"}, - {&__pyx_n_ValueError, "ValueError"}, - {&__pyx_n___version__, "__version__"}, - {&__pyx_n_now, "now"}, - {&__pyx_n_print_exc, "print_exc"}, - {&__pyx_n_traceback, "traceback"}, - {&__pyx_n_update, "update"}, - {0, 0} -}; - -static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_k7p, __pyx_k7, sizeof(__pyx_k7)}, - {&__pyx_k8p, __pyx_k8, sizeof(__pyx_k8)}, - {&__pyx_k9p, __pyx_k9, sizeof(__pyx_k9)}, - {&__pyx_k10p, __pyx_k10, sizeof(__pyx_k10)}, - {&__pyx_k11p, __pyx_k11, sizeof(__pyx_k11)}, - {&__pyx_k12p, __pyx_k12, sizeof(__pyx_k12)}, - {&__pyx_k13p, __pyx_k13, sizeof(__pyx_k13)}, - {&__pyx_k14p, __pyx_k14, sizeof(__pyx_k14)}, - {&__pyx_k15p, __pyx_k15, sizeof(__pyx_k15)}, - {&__pyx_k16p, __pyx_k16, sizeof(__pyx_k16)}, - {0, 0, 0} -}; - -static PyObject *__pyx_tp_new_9cfsupport_PyCFSocket(PyTypeObject *t, PyObject *a, PyObject *k) { - PyObject *o = (*t->tp_alloc)(t, 0); - struct __pyx_obj_9cfsupport_PyCFSocket *p = (struct __pyx_obj_9cfsupport_PyCFSocket *)o; - p->readcallback = Py_None; Py_INCREF(p->readcallback); - p->writecallback = Py_None; Py_INCREF(p->writecallback); - p->connectcallback = Py_None; Py_INCREF(p->connectcallback); - p->reading = Py_None; Py_INCREF(p->reading); - p->writing = Py_None; Py_INCREF(p->writing); - if (__pyx_f_9cfsupport_10PyCFSocket___new__(o, a, k) < 0) { - Py_DECREF(o); o = 0; - } - return o; -} - -static void __pyx_tp_dealloc_9cfsupport_PyCFSocket(PyObject *o) { - struct __pyx_obj_9cfsupport_PyCFSocket *p = (struct __pyx_obj_9cfsupport_PyCFSocket *)o; - { - PyObject *etype, *eval, *etb; - PyErr_Fetch(&etype, &eval, &etb); - ++o->ob_refcnt; - __pyx_f_9cfsupport_10PyCFSocket___dealloc__(o); - if (PyErr_Occurred()) PyErr_WriteUnraisable(o); - --o->ob_refcnt; - PyErr_Restore(etype, eval, etb); - } - Py_XDECREF(p->readcallback); - Py_XDECREF(p->writecallback); - Py_XDECREF(p->connectcallback); - Py_XDECREF(p->reading); - Py_XDECREF(p->writing); - (*o->ob_type->tp_free)(o); -} - -static int __pyx_tp_traverse_9cfsupport_PyCFSocket(PyObject *o, visitproc v, void *a) { - int e; - struct __pyx_obj_9cfsupport_PyCFSocket *p = (struct __pyx_obj_9cfsupport_PyCFSocket *)o; - if (p->readcallback) { - e = (*v)(p->readcallback, a); if (e) return e; - } - if (p->writecallback) { - e = (*v)(p->writecallback, a); if (e) return e; - } - if (p->connectcallback) { - e = (*v)(p->connectcallback, a); if (e) return e; - } - if (p->reading) { - e = (*v)(p->reading, a); if (e) return e; - } - if (p->writing) { - e = (*v)(p->writing, a); if (e) return e; - } - return 0; -} - -static int __pyx_tp_clear_9cfsupport_PyCFSocket(PyObject *o) { - struct __pyx_obj_9cfsupport_PyCFSocket *p = (struct __pyx_obj_9cfsupport_PyCFSocket *)o; - Py_XDECREF(p->readcallback); - p->readcallback = Py_None; Py_INCREF(p->readcallback); - Py_XDECREF(p->writecallback); - p->writecallback = Py_None; Py_INCREF(p->writecallback); - Py_XDECREF(p->connectcallback); - p->connectcallback = Py_None; Py_INCREF(p->connectcallback); - Py_XDECREF(p->reading); - p->reading = Py_None; Py_INCREF(p->reading); - Py_XDECREF(p->writing); - p->writing = Py_None; Py_INCREF(p->writing); - return 0; -} - -static struct PyMethodDef __pyx_methods_9cfsupport_PyCFSocket[] = { - {"update", (PyCFunction)__pyx_f_9cfsupport_10PyCFSocket_update, METH_VARARGS|METH_KEYWORDS, 0}, - {"startReading", (PyCFunction)__pyx_f_9cfsupport_10PyCFSocket_startReading, METH_VARARGS|METH_KEYWORDS, 0}, - {"stopReading", (PyCFunction)__pyx_f_9cfsupport_10PyCFSocket_stopReading, METH_VARARGS|METH_KEYWORDS, 0}, - {"startWriting", (PyCFunction)__pyx_f_9cfsupport_10PyCFSocket_startWriting, METH_VARARGS|METH_KEYWORDS, 0}, - {"stopWriting", (PyCFunction)__pyx_f_9cfsupport_10PyCFSocket_stopWriting, METH_VARARGS|METH_KEYWORDS, 0}, - {0, 0, 0, 0} -}; - -static struct PyMemberDef __pyx_members_9cfsupport_PyCFSocket[] = { - {"readcallback", T_OBJECT, offsetof(struct __pyx_obj_9cfsupport_PyCFSocket, readcallback), 0, 0}, - {"writecallback", T_OBJECT, offsetof(struct __pyx_obj_9cfsupport_PyCFSocket, writecallback), 0, 0}, - {"connectcallback", T_OBJECT, offsetof(struct __pyx_obj_9cfsupport_PyCFSocket, connectcallback), 0, 0}, - {"reading", T_OBJECT, offsetof(struct __pyx_obj_9cfsupport_PyCFSocket, reading), 0, 0}, - {"writing", T_OBJECT, offsetof(struct __pyx_obj_9cfsupport_PyCFSocket, writing), 0, 0}, - {"fileno", T_INT, offsetof(struct __pyx_obj_9cfsupport_PyCFSocket, fileno), READONLY, 0}, - {0, 0, 0, 0, 0} -}; - -static PyNumberMethods __pyx_tp_as_number_PyCFSocket = { - 0, /*nb_add*/ - 0, /*nb_subtract*/ - 0, /*nb_multiply*/ - 0, /*nb_divide*/ - 0, /*nb_remainder*/ - 0, /*nb_divmod*/ - 0, /*nb_power*/ - 0, /*nb_negative*/ - 0, /*nb_positive*/ - 0, /*nb_absolute*/ - 0, /*nb_nonzero*/ - 0, /*nb_invert*/ - 0, /*nb_lshift*/ - 0, /*nb_rshift*/ - 0, /*nb_and*/ - 0, /*nb_xor*/ - 0, /*nb_or*/ - 0, /*nb_coerce*/ - 0, /*nb_int*/ - 0, /*nb_long*/ - 0, /*nb_float*/ - 0, /*nb_oct*/ - 0, /*nb_hex*/ - 0, /*nb_inplace_add*/ - 0, /*nb_inplace_subtract*/ - 0, /*nb_inplace_multiply*/ - 0, /*nb_inplace_divide*/ - 0, /*nb_inplace_remainder*/ - 0, /*nb_inplace_power*/ - 0, /*nb_inplace_lshift*/ - 0, /*nb_inplace_rshift*/ - 0, /*nb_inplace_and*/ - 0, /*nb_inplace_xor*/ - 0, /*nb_inplace_or*/ - 0, /*nb_floor_divide*/ - 0, /*nb_true_divide*/ - 0, /*nb_inplace_floor_divide*/ - 0, /*nb_inplace_true_divide*/ -}; - -static PySequenceMethods __pyx_tp_as_sequence_PyCFSocket = { - 0, /*sq_length*/ - 0, /*sq_concat*/ - 0, /*sq_repeat*/ - 0, /*sq_item*/ - 0, /*sq_slice*/ - 0, /*sq_ass_item*/ - 0, /*sq_ass_slice*/ - 0, /*sq_contains*/ - 0, /*sq_inplace_concat*/ - 0, /*sq_inplace_repeat*/ -}; - -static PyMappingMethods __pyx_tp_as_mapping_PyCFSocket = { - 0, /*mp_length*/ - 0, /*mp_subscript*/ - 0, /*mp_ass_subscript*/ -}; - -static PyBufferProcs __pyx_tp_as_buffer_PyCFSocket = { - 0, /*bf_getreadbuffer*/ - 0, /*bf_getwritebuffer*/ - 0, /*bf_getsegcount*/ - 0, /*bf_getcharbuffer*/ -}; - -statichere PyTypeObject __pyx_type_9cfsupport_PyCFSocket = { - PyObject_HEAD_INIT(0) - 0, /*ob_size*/ - "cfsupport.PyCFSocket", /*tp_name*/ - sizeof(struct __pyx_obj_9cfsupport_PyCFSocket), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_9cfsupport_PyCFSocket, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - &__pyx_tp_as_number_PyCFSocket, /*tp_as_number*/ - &__pyx_tp_as_sequence_PyCFSocket, /*tp_as_sequence*/ - &__pyx_tp_as_mapping_PyCFSocket, /*tp_as_mapping*/ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - &__pyx_tp_as_buffer_PyCFSocket, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/ - 0, /*tp_doc*/ - __pyx_tp_traverse_9cfsupport_PyCFSocket, /*tp_traverse*/ - __pyx_tp_clear_9cfsupport_PyCFSocket, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - __pyx_methods_9cfsupport_PyCFSocket, /*tp_methods*/ - __pyx_members_9cfsupport_PyCFSocket, /*tp_members*/ - 0, /*tp_getset*/ - 0, /*tp_base*/ - 0, /*tp_dict*/ - 0, /*tp_descr_get*/ - 0, /*tp_descr_set*/ - 0, /*tp_dictoffset*/ - 0, /*tp_init*/ - 0, /*tp_alloc*/ - __pyx_tp_new_9cfsupport_PyCFSocket, /*tp_new*/ - 0, /*tp_free*/ - 0, /*tp_is_gc*/ - 0, /*tp_bases*/ - 0, /*tp_mro*/ - 0, /*tp_cache*/ - 0, /*tp_subclasses*/ - 0, /*tp_weaklist*/ -}; - -static PyObject *__pyx_tp_new_9cfsupport_PyCFRunLoopTimer(PyTypeObject *t, PyObject *a, PyObject *k) { - PyObject *o = (*t->tp_alloc)(t, 0); - struct __pyx_obj_9cfsupport_PyCFRunLoopTimer *p = (struct __pyx_obj_9cfsupport_PyCFRunLoopTimer *)o; - p->callout = Py_None; Py_INCREF(p->callout); - if (__pyx_f_9cfsupport_16PyCFRunLoopTimer___new__(o, a, k) < 0) { - Py_DECREF(o); o = 0; - } - return o; -} - -static void __pyx_tp_dealloc_9cfsupport_PyCFRunLoopTimer(PyObject *o) { - struct __pyx_obj_9cfsupport_PyCFRunLoopTimer *p = (struct __pyx_obj_9cfsupport_PyCFRunLoopTimer *)o; - { - PyObject *etype, *eval, *etb; - PyErr_Fetch(&etype, &eval, &etb); - ++o->ob_refcnt; - __pyx_f_9cfsupport_16PyCFRunLoopTimer___dealloc__(o); - if (PyErr_Occurred()) PyErr_WriteUnraisable(o); - --o->ob_refcnt; - PyErr_Restore(etype, eval, etb); - } - Py_XDECREF(p->callout); - (*o->ob_type->tp_free)(o); -} - -static int __pyx_tp_traverse_9cfsupport_PyCFRunLoopTimer(PyObject *o, visitproc v, void *a) { - int e; - struct __pyx_obj_9cfsupport_PyCFRunLoopTimer *p = (struct __pyx_obj_9cfsupport_PyCFRunLoopTimer *)o; - if (p->callout) { - e = (*v)(p->callout, a); if (e) return e; - } - return 0; -} - -static int __pyx_tp_clear_9cfsupport_PyCFRunLoopTimer(PyObject *o) { - struct __pyx_obj_9cfsupport_PyCFRunLoopTimer *p = (struct __pyx_obj_9cfsupport_PyCFRunLoopTimer *)o; - Py_XDECREF(p->callout); - p->callout = Py_None; Py_INCREF(p->callout); - return 0; -} - -static struct PyMethodDef __pyx_methods_9cfsupport_PyCFRunLoopTimer[] = { - {"getNextFireDate", (PyCFunction)__pyx_f_9cfsupport_16PyCFRunLoopTimer_getNextFireDate, METH_VARARGS|METH_KEYWORDS, 0}, - {"setNextFireDate", (PyCFunction)__pyx_f_9cfsupport_16PyCFRunLoopTimer_setNextFireDate, METH_VARARGS|METH_KEYWORDS, 0}, - {"invalidate", (PyCFunction)__pyx_f_9cfsupport_16PyCFRunLoopTimer_invalidate, METH_VARARGS|METH_KEYWORDS, 0}, - {0, 0, 0, 0} -}; - -static struct PyMemberDef __pyx_members_9cfsupport_PyCFRunLoopTimer[] = { - {"callout", T_OBJECT, offsetof(struct __pyx_obj_9cfsupport_PyCFRunLoopTimer, callout), 0, 0}, - {0, 0, 0, 0, 0} -}; - -static PyNumberMethods __pyx_tp_as_number_PyCFRunLoopTimer = { - 0, /*nb_add*/ - 0, /*nb_subtract*/ - 0, /*nb_multiply*/ - 0, /*nb_divide*/ - 0, /*nb_remainder*/ - 0, /*nb_divmod*/ - 0, /*nb_power*/ - 0, /*nb_negative*/ - 0, /*nb_positive*/ - 0, /*nb_absolute*/ - 0, /*nb_nonzero*/ - 0, /*nb_invert*/ - 0, /*nb_lshift*/ - 0, /*nb_rshift*/ - 0, /*nb_and*/ - 0, /*nb_xor*/ - 0, /*nb_or*/ - 0, /*nb_coerce*/ - 0, /*nb_int*/ - 0, /*nb_long*/ - 0, /*nb_float*/ - 0, /*nb_oct*/ - 0, /*nb_hex*/ - 0, /*nb_inplace_add*/ - 0, /*nb_inplace_subtract*/ - 0, /*nb_inplace_multiply*/ - 0, /*nb_inplace_divide*/ - 0, /*nb_inplace_remainder*/ - 0, /*nb_inplace_power*/ - 0, /*nb_inplace_lshift*/ - 0, /*nb_inplace_rshift*/ - 0, /*nb_inplace_and*/ - 0, /*nb_inplace_xor*/ - 0, /*nb_inplace_or*/ - 0, /*nb_floor_divide*/ - 0, /*nb_true_divide*/ - 0, /*nb_inplace_floor_divide*/ - 0, /*nb_inplace_true_divide*/ -}; - -static PySequenceMethods __pyx_tp_as_sequence_PyCFRunLoopTimer = { - 0, /*sq_length*/ - 0, /*sq_concat*/ - 0, /*sq_repeat*/ - 0, /*sq_item*/ - 0, /*sq_slice*/ - 0, /*sq_ass_item*/ - 0, /*sq_ass_slice*/ - 0, /*sq_contains*/ - 0, /*sq_inplace_concat*/ - 0, /*sq_inplace_repeat*/ -}; - -static PyMappingMethods __pyx_tp_as_mapping_PyCFRunLoopTimer = { - 0, /*mp_length*/ - 0, /*mp_subscript*/ - 0, /*mp_ass_subscript*/ -}; - -static PyBufferProcs __pyx_tp_as_buffer_PyCFRunLoopTimer = { - 0, /*bf_getreadbuffer*/ - 0, /*bf_getwritebuffer*/ - 0, /*bf_getsegcount*/ - 0, /*bf_getcharbuffer*/ -}; - -statichere PyTypeObject __pyx_type_9cfsupport_PyCFRunLoopTimer = { - PyObject_HEAD_INIT(0) - 0, /*ob_size*/ - "cfsupport.PyCFRunLoopTimer", /*tp_name*/ - sizeof(struct __pyx_obj_9cfsupport_PyCFRunLoopTimer), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_9cfsupport_PyCFRunLoopTimer, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - &__pyx_tp_as_number_PyCFRunLoopTimer, /*tp_as_number*/ - &__pyx_tp_as_sequence_PyCFRunLoopTimer, /*tp_as_sequence*/ - &__pyx_tp_as_mapping_PyCFRunLoopTimer, /*tp_as_mapping*/ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - &__pyx_tp_as_buffer_PyCFRunLoopTimer, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/ - 0, /*tp_doc*/ - __pyx_tp_traverse_9cfsupport_PyCFRunLoopTimer, /*tp_traverse*/ - __pyx_tp_clear_9cfsupport_PyCFRunLoopTimer, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - __pyx_methods_9cfsupport_PyCFRunLoopTimer, /*tp_methods*/ - __pyx_members_9cfsupport_PyCFRunLoopTimer, /*tp_members*/ - 0, /*tp_getset*/ - 0, /*tp_base*/ - 0, /*tp_dict*/ - 0, /*tp_descr_get*/ - 0, /*tp_descr_set*/ - 0, /*tp_dictoffset*/ - 0, /*tp_init*/ - 0, /*tp_alloc*/ - __pyx_tp_new_9cfsupport_PyCFRunLoopTimer, /*tp_new*/ - 0, /*tp_free*/ - 0, /*tp_is_gc*/ - 0, /*tp_bases*/ - 0, /*tp_mro*/ - 0, /*tp_cache*/ - 0, /*tp_subclasses*/ - 0, /*tp_weaklist*/ -}; - -static PyObject *__pyx_tp_new_9cfsupport_PyCFRunLoop(PyTypeObject *t, PyObject *a, PyObject *k) { - PyObject *o = (*t->tp_alloc)(t, 0); - struct __pyx_obj_9cfsupport_PyCFRunLoop *p = (struct __pyx_obj_9cfsupport_PyCFRunLoop *)o; - p->cf = Py_None; Py_INCREF(p->cf); - if (__pyx_f_9cfsupport_11PyCFRunLoop___new__(o, a, k) < 0) { - Py_DECREF(o); o = 0; - } - return o; -} - -static void __pyx_tp_dealloc_9cfsupport_PyCFRunLoop(PyObject *o) { - struct __pyx_obj_9cfsupport_PyCFRunLoop *p = (struct __pyx_obj_9cfsupport_PyCFRunLoop *)o; - Py_XDECREF(p->cf); - (*o->ob_type->tp_free)(o); -} - -static int __pyx_tp_traverse_9cfsupport_PyCFRunLoop(PyObject *o, visitproc v, void *a) { - int e; - struct __pyx_obj_9cfsupport_PyCFRunLoop *p = (struct __pyx_obj_9cfsupport_PyCFRunLoop *)o; - if (p->cf) { - e = (*v)(p->cf, a); if (e) return e; - } - return 0; -} - -static int __pyx_tp_clear_9cfsupport_PyCFRunLoop(PyObject *o) { - struct __pyx_obj_9cfsupport_PyCFRunLoop *p = (struct __pyx_obj_9cfsupport_PyCFRunLoop *)o; - Py_XDECREF(p->cf); - p->cf = Py_None; Py_INCREF(p->cf); - return 0; -} - -static struct PyMethodDef __pyx_methods_9cfsupport_PyCFRunLoop[] = { - {"run", (PyCFunction)__pyx_f_9cfsupport_11PyCFRunLoop_run, METH_VARARGS|METH_KEYWORDS, 0}, - {"stop", (PyCFunction)__pyx_f_9cfsupport_11PyCFRunLoop_stop, METH_VARARGS|METH_KEYWORDS, 0}, - {"currentMode", (PyCFunction)__pyx_f_9cfsupport_11PyCFRunLoop_currentMode, METH_VARARGS|METH_KEYWORDS, 0}, - {"addSocket", (PyCFunction)__pyx_f_9cfsupport_11PyCFRunLoop_addSocket, METH_VARARGS|METH_KEYWORDS, 0}, - {"removeSocket", (PyCFunction)__pyx_f_9cfsupport_11PyCFRunLoop_removeSocket, METH_VARARGS|METH_KEYWORDS, 0}, - {"addTimer", (PyCFunction)__pyx_f_9cfsupport_11PyCFRunLoop_addTimer, METH_VARARGS|METH_KEYWORDS, 0}, - {"removeTimer", (PyCFunction)__pyx_f_9cfsupport_11PyCFRunLoop_removeTimer, METH_VARARGS|METH_KEYWORDS, 0}, - {0, 0, 0, 0} -}; - -static struct PyMemberDef __pyx_members_9cfsupport_PyCFRunLoop[] = { - {"cf", T_OBJECT, offsetof(struct __pyx_obj_9cfsupport_PyCFRunLoop, cf), 0, 0}, - {0, 0, 0, 0, 0} -}; - -static PyNumberMethods __pyx_tp_as_number_PyCFRunLoop = { - 0, /*nb_add*/ - 0, /*nb_subtract*/ - 0, /*nb_multiply*/ - 0, /*nb_divide*/ - 0, /*nb_remainder*/ - 0, /*nb_divmod*/ - 0, /*nb_power*/ - 0, /*nb_negative*/ - 0, /*nb_positive*/ - 0, /*nb_absolute*/ - 0, /*nb_nonzero*/ - 0, /*nb_invert*/ - 0, /*nb_lshift*/ - 0, /*nb_rshift*/ - 0, /*nb_and*/ - 0, /*nb_xor*/ - 0, /*nb_or*/ - 0, /*nb_coerce*/ - 0, /*nb_int*/ - 0, /*nb_long*/ - 0, /*nb_float*/ - 0, /*nb_oct*/ - 0, /*nb_hex*/ - 0, /*nb_inplace_add*/ - 0, /*nb_inplace_subtract*/ - 0, /*nb_inplace_multiply*/ - 0, /*nb_inplace_divide*/ - 0, /*nb_inplace_remainder*/ - 0, /*nb_inplace_power*/ - 0, /*nb_inplace_lshift*/ - 0, /*nb_inplace_rshift*/ - 0, /*nb_inplace_and*/ - 0, /*nb_inplace_xor*/ - 0, /*nb_inplace_or*/ - 0, /*nb_floor_divide*/ - 0, /*nb_true_divide*/ - 0, /*nb_inplace_floor_divide*/ - 0, /*nb_inplace_true_divide*/ -}; - -static PySequenceMethods __pyx_tp_as_sequence_PyCFRunLoop = { - 0, /*sq_length*/ - 0, /*sq_concat*/ - 0, /*sq_repeat*/ - 0, /*sq_item*/ - 0, /*sq_slice*/ - 0, /*sq_ass_item*/ - 0, /*sq_ass_slice*/ - 0, /*sq_contains*/ - 0, /*sq_inplace_concat*/ - 0, /*sq_inplace_repeat*/ -}; - -static PyMappingMethods __pyx_tp_as_mapping_PyCFRunLoop = { - 0, /*mp_length*/ - 0, /*mp_subscript*/ - 0, /*mp_ass_subscript*/ -}; - -static PyBufferProcs __pyx_tp_as_buffer_PyCFRunLoop = { - 0, /*bf_getreadbuffer*/ - 0, /*bf_getwritebuffer*/ - 0, /*bf_getsegcount*/ - 0, /*bf_getcharbuffer*/ -}; - -statichere PyTypeObject __pyx_type_9cfsupport_PyCFRunLoop = { - PyObject_HEAD_INIT(0) - 0, /*ob_size*/ - "cfsupport.PyCFRunLoop", /*tp_name*/ - sizeof(struct __pyx_obj_9cfsupport_PyCFRunLoop), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_9cfsupport_PyCFRunLoop, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - &__pyx_tp_as_number_PyCFRunLoop, /*tp_as_number*/ - &__pyx_tp_as_sequence_PyCFRunLoop, /*tp_as_sequence*/ - &__pyx_tp_as_mapping_PyCFRunLoop, /*tp_as_mapping*/ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - &__pyx_tp_as_buffer_PyCFRunLoop, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/ - 0, /*tp_doc*/ - __pyx_tp_traverse_9cfsupport_PyCFRunLoop, /*tp_traverse*/ - __pyx_tp_clear_9cfsupport_PyCFRunLoop, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - __pyx_methods_9cfsupport_PyCFRunLoop, /*tp_methods*/ - __pyx_members_9cfsupport_PyCFRunLoop, /*tp_members*/ - 0, /*tp_getset*/ - 0, /*tp_base*/ - 0, /*tp_dict*/ - 0, /*tp_descr_get*/ - 0, /*tp_descr_set*/ - 0, /*tp_dictoffset*/ - 0, /*tp_init*/ - 0, /*tp_alloc*/ - __pyx_tp_new_9cfsupport_PyCFRunLoop, /*tp_new*/ - 0, /*tp_free*/ - 0, /*tp_is_gc*/ - 0, /*tp_bases*/ - 0, /*tp_mro*/ - 0, /*tp_cache*/ - 0, /*tp_subclasses*/ - 0, /*tp_weaklist*/ -}; - -static struct PyMethodDef __pyx_methods[] = { - {"now", (PyCFunction)__pyx_f_9cfsupport_now, METH_VARARGS|METH_KEYWORDS, 0}, - {0, 0, 0, 0} -}; - -DL_EXPORT(void) initcfsupport(void); /*proto*/ -DL_EXPORT(void) initcfsupport(void) { - PyObject *__pyx_1 = 0; - __pyx_m = Py_InitModule4("cfsupport", __pyx_methods, 0, 0, PYTHON_API_VERSION); - if (!__pyx_m) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 1; goto __pyx_L1;}; - __pyx_b = PyImport_AddModule("__builtin__"); - if (!__pyx_b) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 1; goto __pyx_L1;}; - if (PyObject_SetAttrString(__pyx_m, "__builtins__", __pyx_b) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 1; goto __pyx_L1;}; - if (__Pyx_InternStrings(__pyx_intern_tab) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 1; goto __pyx_L1;}; - if (__Pyx_InitStrings(__pyx_string_tab) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 1; goto __pyx_L1;}; - __pyx_type_9cfsupport_PyCFSocket.tp_free = _PyObject_GC_Del; - if (PyType_Ready(&__pyx_type_9cfsupport_PyCFSocket) < 0) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 34; goto __pyx_L1;} - if (PyObject_SetAttrString(__pyx_m, "PyCFSocket", (PyObject *)&__pyx_type_9cfsupport_PyCFSocket) < 0) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 34; goto __pyx_L1;} - __pyx_ptype_9cfsupport_PyCFSocket = &__pyx_type_9cfsupport_PyCFSocket; - __pyx_type_9cfsupport_PyCFRunLoopTimer.tp_free = _PyObject_GC_Del; - if (PyType_Ready(&__pyx_type_9cfsupport_PyCFRunLoopTimer) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 5; goto __pyx_L1;} - if (PyObject_SetAttrString(__pyx_m, "PyCFRunLoopTimer", (PyObject *)&__pyx_type_9cfsupport_PyCFRunLoopTimer) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 5; goto __pyx_L1;} - __pyx_ptype_9cfsupport_PyCFRunLoopTimer = &__pyx_type_9cfsupport_PyCFRunLoopTimer; - __pyx_type_9cfsupport_PyCFRunLoop.tp_free = _PyObject_GC_Del; - if (PyType_Ready(&__pyx_type_9cfsupport_PyCFRunLoop) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 49; goto __pyx_L1;} - if (PyObject_SetAttrString(__pyx_m, "PyCFRunLoop", (PyObject *)&__pyx_type_9cfsupport_PyCFRunLoop) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 49; goto __pyx_L1;} - __pyx_ptype_9cfsupport_PyCFRunLoop = &__pyx_type_9cfsupport_PyCFRunLoop; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":1 */ - __pyx_1 = __Pyx_Import(__pyx_n_traceback, 0); if (!__pyx_1) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 1; goto __pyx_L1;} - if (PyObject_SetAttr(__pyx_m, __pyx_n_traceback, __pyx_1) < 0) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 1; goto __pyx_L1;} - Py_DECREF(__pyx_1); __pyx_1 = 0; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsocket.pxi":45 */ - Py_INCREF(Py_None); - __pyx_k2 = Py_None; - Py_INCREF(Py_None); - __pyx_k3 = Py_None; - Py_INCREF(Py_None); - __pyx_k4 = Py_None; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":1 */ - __pyx_1 = __Pyx_Import(__pyx_n_traceback, 0); if (!__pyx_1) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 1; goto __pyx_L1;} - if (PyObject_SetAttr(__pyx_m, __pyx_n_traceback, __pyx_1) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 1; goto __pyx_L1;} - Py_DECREF(__pyx_1); __pyx_1 = 0; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfrunloop.pxi":52 */ - Py_INCREF(Py_None); - __pyx_k6 = Py_None; - - /* "/Volumes/Crack/src/Twisted/twisted/internet/cfsupport/cfsupport.pyx":6 */ - if (PyObject_SetAttr(__pyx_m, __pyx_n___version__, __pyx_k7p) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 6; goto __pyx_L1;} - return; - __pyx_L1:; - Py_XDECREF(__pyx_1); - __Pyx_AddTraceback("cfsupport"); -} - -static char *__pyx_filenames[] = { - "cfdate.pxi", - "cfsocket.pxi", - "cfrunloop.pxi", - "cfsupport.pyx", -}; -statichere char **__pyx_f = __pyx_filenames; - -/* Runtime support code */ - -static int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, int none_allowed, char *name) { - if (!type) { - PyErr_Format(PyExc_SystemError, "Missing type object"); - return 0; - } - if ((none_allowed && obj == Py_None) || PyObject_TypeCheck(obj, type)) - return 1; - PyErr_Format(PyExc_TypeError, - "Argument '%s' has incorrect type (expected %s, got %s)", - name, type->tp_name, obj->ob_type->tp_name); - return 0; -} - -static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list) { - PyObject *__import__ = 0; - PyObject *empty_list = 0; - PyObject *module = 0; - PyObject *global_dict = 0; - PyObject *empty_dict = 0; - PyObject *list; - __import__ = PyObject_GetAttrString(__pyx_b, "__import__"); - if (!__import__) - goto bad; - if (from_list) - list = from_list; - else { - empty_list = PyList_New(0); - if (!empty_list) - goto bad; - list = empty_list; - } - global_dict = PyModule_GetDict(__pyx_m); - if (!global_dict) - goto bad; - empty_dict = PyDict_New(); - if (!empty_dict) - goto bad; - module = PyObject_CallFunction(__import__, "OOOO", - name, global_dict, empty_dict, list); -bad: - Py_XDECREF(empty_list); - Py_XDECREF(__import__); - Py_XDECREF(empty_dict); - return module; -} - -static PyObject *__Pyx_GetExcValue(void) { - PyObject *type = 0, *value = 0, *tb = 0; - PyObject *result = 0; - PyThreadState *tstate = PyThreadState_Get(); - PyErr_Fetch(&type, &value, &tb); - PyErr_NormalizeException(&type, &value, &tb); - if (PyErr_Occurred()) - goto bad; - if (!value) { - value = Py_None; - Py_INCREF(value); - } - Py_XDECREF(tstate->exc_type); - Py_XDECREF(tstate->exc_value); - Py_XDECREF(tstate->exc_traceback); - tstate->exc_type = type; - tstate->exc_value = value; - tstate->exc_traceback = tb; - result = value; - Py_XINCREF(result); - type = 0; - value = 0; - tb = 0; -bad: - Py_XDECREF(type); - Py_XDECREF(value); - Py_XDECREF(tb); - return result; -} - -static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name) { - PyObject *result; - result = PyObject_GetAttr(dict, name); - if (!result) - PyErr_SetObject(PyExc_NameError, name); - return result; -} - -static void __Pyx_WriteUnraisable(char *name) { - PyObject *old_exc, *old_val, *old_tb; - PyObject *ctx; - PyErr_Fetch(&old_exc, &old_val, &old_tb); - ctx = PyString_FromString(name); - PyErr_Restore(old_exc, old_val, old_tb); - if (!ctx) - ctx = Py_None; - PyErr_WriteUnraisable(ctx); -} - -static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb) { - Py_XINCREF(type); - Py_XINCREF(value); - Py_XINCREF(tb); - /* First, check the traceback argument, replacing None with NULL. */ - if (tb == Py_None) { - Py_DECREF(tb); - tb = 0; - } - else if (tb != NULL && !PyTraceBack_Check(tb)) { - PyErr_SetString(PyExc_TypeError, - "raise: arg 3 must be a traceback or None"); - goto raise_error; - } - /* Next, replace a missing value with None */ - if (value == NULL) { - value = Py_None; - Py_INCREF(value); - } - /* Next, repeatedly, replace a tuple exception with its first item */ - while (PyTuple_Check(type) && PyTuple_Size(type) > 0) { - PyObject *tmp = type; - type = PyTuple_GET_ITEM(type, 0); - Py_INCREF(type); - Py_DECREF(tmp); - } - if (PyString_Check(type)) - ; - else if (PyClass_Check(type)) - ; /*PyErr_NormalizeException(&type, &value, &tb);*/ - else if (PyInstance_Check(type)) { - /* Raising an instance. The value should be a dummy. */ - if (value != Py_None) { - PyErr_SetString(PyExc_TypeError, - "instance exception may not have a separate value"); - goto raise_error; - } - else { - /* Normalize to raise , */ - Py_DECREF(value); - value = type; - type = (PyObject*) ((PyInstanceObject*)type)->in_class; - Py_INCREF(type); - } - } - else { - /* Not something you can raise. You get an exception - anyway, just not what you specified :-) */ - PyErr_Format(PyExc_TypeError, - "exceptions must be strings, classes, or " - "instances, not %s", type->ob_type->tp_name); - goto raise_error; - } - PyErr_Restore(type, value, tb); - return; -raise_error: - Py_XDECREF(value); - Py_XDECREF(type); - Py_XDECREF(tb); - return; -} - -static void __Pyx_ReRaise(void) { - PyThreadState *tstate = PyThreadState_Get(); - PyObject *type = tstate->exc_type; - PyObject *value = tstate->exc_value; - PyObject *tb = tstate->exc_traceback; - Py_XINCREF(type); - Py_XINCREF(value); - Py_XINCREF(tb); - PyErr_Restore(type, value, tb); -} - -static int __Pyx_InternStrings(__Pyx_InternTabEntry *t) { - while (t->p) { - *t->p = PyString_InternFromString(t->s); - if (!*t->p) - return -1; - ++t; - } - return 0; -} - -static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) { - while (t->p) { - *t->p = PyString_FromStringAndSize(t->s, t->n - 1); - if (!*t->p) - return -1; - ++t; - } - return 0; -} - -#include "compile.h" -#include "frameobject.h" -#include "traceback.h" - -static void __Pyx_AddTraceback(char *funcname) { - PyObject *py_srcfile = 0; - PyObject *py_funcname = 0; - PyObject *py_globals = 0; - PyObject *empty_tuple = 0; - PyObject *empty_string = 0; - PyCodeObject *py_code = 0; - PyFrameObject *py_frame = 0; - - py_srcfile = PyString_FromString(__pyx_filename); - if (!py_srcfile) goto bad; - py_funcname = PyString_FromString(funcname); - if (!py_funcname) goto bad; - py_globals = PyModule_GetDict(__pyx_m); - if (!py_globals) goto bad; - empty_tuple = PyTuple_New(0); - if (!empty_tuple) goto bad; - empty_string = PyString_FromString(""); - if (!empty_string) goto bad; - py_code = PyCode_New( - 0, /*int argcount,*/ - 0, /*int nlocals,*/ - 0, /*int stacksize,*/ - 0, /*int flags,*/ - empty_string, /*PyObject *code,*/ - empty_tuple, /*PyObject *consts,*/ - empty_tuple, /*PyObject *names,*/ - empty_tuple, /*PyObject *varnames,*/ - empty_tuple, /*PyObject *freevars,*/ - empty_tuple, /*PyObject *cellvars,*/ - py_srcfile, /*PyObject *filename,*/ - py_funcname, /*PyObject *name,*/ - __pyx_lineno, /*int firstlineno,*/ - empty_string /*PyObject *lnotab*/ - ); - if (!py_code) goto bad; - py_frame = PyFrame_New( - PyThreadState_Get(), /*PyThreadState *tstate,*/ - py_code, /*PyCodeObject *code,*/ - py_globals, /*PyObject *globals,*/ - 0 /*PyObject *locals*/ - ); - if (!py_frame) goto bad; - py_frame->f_lineno = __pyx_lineno; - PyTraceBack_Here(py_frame); -bad: - Py_XDECREF(py_srcfile); - Py_XDECREF(py_funcname); - Py_XDECREF(empty_tuple); - Py_XDECREF(empty_string); - Py_XDECREF(py_code); - Py_XDECREF(py_frame); -} diff --git a/tools/buildbot/pylibs/twisted/internet/cfsupport/cfsupport.pyx b/tools/buildbot/pylibs/twisted/internet/cfsupport/cfsupport.pyx deleted file mode 100644 index 0b2afd5..0000000 --- a/tools/buildbot/pylibs/twisted/internet/cfsupport/cfsupport.pyx +++ /dev/null @@ -1,6 +0,0 @@ -include "python.pxi" -include "cfdecl.pxi" -include "cfdate.pxi" -include "cfsocket.pxi" -include "cfrunloop.pxi" -__version__ = '0.4' diff --git a/tools/buildbot/pylibs/twisted/internet/cfsupport/python.pxi b/tools/buildbot/pylibs/twisted/internet/cfsupport/python.pxi deleted file mode 100644 index 2f97458..0000000 --- a/tools/buildbot/pylibs/twisted/internet/cfsupport/python.pxi +++ /dev/null @@ -1,5 +0,0 @@ -cdef extern from "Python.h": - ctypedef void *PyGILState_STATE - void PyErr_Clear() - PyGILState_STATE PyGILState_Ensure() - void PyGILState_Release(PyGILState_STATE) diff --git a/tools/buildbot/pylibs/twisted/internet/cfsupport/setup.py b/tools/buildbot/pylibs/twisted/internet/cfsupport/setup.py deleted file mode 100644 index e5b3b2d..0000000 --- a/tools/buildbot/pylibs/twisted/internet/cfsupport/setup.py +++ /dev/null @@ -1,50 +0,0 @@ -from distutils.core import setup -from distutils.extension import Extension -try: - from Pyrex.Distutils import build_ext - # pyrex is available - setup( - name = 'cfsupport', - version = '0.4', - description = "Enough CoreFoundation wrappers to deal with CFRunLoop", - long_description = "Pythonic wrappers for pieces of Apple's CoreFoundation API's that are not otherwise wrapped by MacPython.\nPrimarily useful for dealing with CFRunLoop.", - maintainer = 'Bob Ippolito', - maintainer_email = 'bob@redivi.com', - license = 'Python', - platforms = ['Mac OSX'], - keywords = ['CoreFoundation', 'CFRunLoop', 'Cocoa', 'GUI'], - ext_modules=[ - Extension( - 'cfsupport', - ['cfsupport.pyx'], - extra_link_args=[ - '-framework','CoreFoundation', - '-framework','CoreServices', - ], - ), - ], - cmdclass = {'build_ext': build_ext} - ) -except ImportError: - # pyrex is not available, use existing .c - setup( - name = 'cfsupport', - version = '0.4', - description = "Enough CoreFoundation wrappers to deal with CFRunLoop", - long_description = "Pythonic wrappers for pieces of Apple's CoreFoundation API's that are not otherwise wrapped by MacPython.\nPrimarily useful for dealing with CFRunLoop.", - maintainer = 'Bob Ippolito', - maintainer_email = 'bob@redivi.com', - license = 'Python', - platforms = ['Mac OSX'], - keywords = ['CoreFoundation', 'CFRunLoop', 'Cocoa', 'GUI'], - ext_modules=[ - Extension( - 'cfsupport', - ['cfsupport.c'], - extra_link_args=[ - '-framework','CoreFoundation', - '-framework','CoreServices', - ], - ), - ], - ) diff --git a/tools/buildbot/pylibs/twisted/internet/default.py b/tools/buildbot/pylibs/twisted/internet/default.py deleted file mode 100644 index 6207525..0000000 --- a/tools/buildbot/pylibs/twisted/internet/default.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- test-case-name: twisted.test.test_internet -*- -# $Id: default.py,v 1.90 2004/01/06 22:35:22 warner Exp $ -# -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Deprecated module that used to contain SelectReactor and PosixReactorBase - -Maintainer: U{Itamar Shtull-Trauring} -""" - -import warnings -warnings.warn("twisted.internet.default is deprecated. Use posixbase or selectreactor instead.", category=DeprecationWarning) - -# Backwards compat -from posixbase import PosixReactorBase -from selectreactor import SelectReactor, install - -__all__ = ["install", "PosixReactorBase", "SelectReactor"] diff --git a/tools/buildbot/pylibs/twisted/internet/defer.py b/tools/buildbot/pylibs/twisted/internet/defer.py deleted file mode 100644 index 8980a13..0000000 --- a/tools/buildbot/pylibs/twisted/internet/defer.py +++ /dev/null @@ -1,1107 +0,0 @@ -# -*- test-case-name: twisted.test.test_defer -*- -# -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Support for results that aren't immediately available. - -Maintainer: U{Glyph Lefkowitz} -""" - -from __future__ import nested_scopes, generators -import traceback -import warnings - -# Twisted imports -from twisted.python import log, failure, lockfile -from twisted.python.util import unsignedID, mergeFunctionMetadata - -class AlreadyCalledError(Exception): - pass - -class TimeoutError(Exception): - pass - -def logError(err): - log.err(err) - return err - -def succeed(result): - """ - Return a Deferred that has already had '.callback(result)' called. - - This is useful when you're writing synchronous code to an - asynchronous interface: i.e., some code is calling you expecting a - Deferred result, but you don't actually need to do anything - asynchronous. Just return defer.succeed(theResult). - - See L{fail} for a version of this function that uses a failing - Deferred rather than a successful one. - - @param result: The result to give to the Deferred's 'callback' - method. - - @rtype: L{Deferred} - """ - d = Deferred() - d.callback(result) - return d - - -def fail(result=None): - """ - Return a Deferred that has already had '.errback(result)' called. - - See L{succeed}'s docstring for rationale. - - @param result: The same argument that L{Deferred.errback} takes. - - @raise NoCurrentExceptionError: If C{result} is C{None} but there is no - current exception state. - - @rtype: L{Deferred} - """ - d = Deferred() - d.errback(result) - return d - - -def execute(callable, *args, **kw): - """Create a deferred from a callable and arguments. - - Call the given function with the given arguments. Return a deferred which - has been fired with its callback as the result of that invocation or its - errback with a Failure for the exception thrown. - """ - try: - result = callable(*args, **kw) - except: - return fail() - else: - return succeed(result) - -def maybeDeferred(f, *args, **kw): - """Invoke a function that may or may not return a deferred. - - Call the given function with the given arguments. If the returned - object is a C{Deferred}, return it. If the returned object is a C{Failure}, - wrap it with C{fail} and return it. Otherwise, wrap it in C{succeed} and - return it. If an exception is raised, convert it to a C{Failure}, wrap it - in C{fail}, and then return it. - - @type f: Any callable - @param f: The callable to invoke - - @param args: The arguments to pass to C{f} - @param kw: The keyword arguments to pass to C{f} - - @rtype: C{Deferred} - @return: The result of the function call, wrapped in a C{Deferred} if - necessary. - """ - deferred = None - - try: - result = f(*args, **kw) - except: - return fail(failure.Failure()) - else: - if isinstance(result, Deferred): - return result - elif isinstance(result, failure.Failure): - return fail(result) - else: - return succeed(result) - return deferred - -def timeout(deferred): - deferred.errback(failure.Failure(TimeoutError("Callback timed out"))) - -def passthru(arg): - return arg - -def setDebugging(on): - """Enable or disable Deferred debugging. - - When debugging is on, the call stacks from creation and invocation are - recorded, and added to any AlreadyCalledErrors we raise. - """ - Deferred.debug=bool(on) - -def getDebugging(): - """Determine whether Deferred debugging is enabled. - """ - return Deferred.debug - -class Deferred: - """This is a callback which will be put off until later. - - Why do we want this? Well, in cases where a function in a threaded - program would block until it gets a result, for Twisted it should - not block. Instead, it should return a Deferred. - - This can be implemented for protocols that run over the network by - writing an asynchronous protocol for twisted.internet. For methods - that come from outside packages that are not under our control, we use - threads (see for example L{twisted.enterprise.adbapi}). - - For more information about Deferreds, see doc/howto/defer.html or - U{http://twistedmatrix.com/projects/core/documentation/howto/defer.html} - """ - called = 0 - paused = 0 - timeoutCall = None - _debugInfo = None - - # Are we currently running a user-installed callback? Meant to prevent - # recursive running of callbacks when a reentrant call to add a callback is - # used. - _runningCallbacks = False - - # Keep this class attribute for now, for compatibility with code that - # sets it directly. - debug = False - - def __init__(self): - self.callbacks = [] - if self.debug: - self._debugInfo = DebugInfo() - self._debugInfo.creator = traceback.format_stack()[:-1] - - def addCallbacks(self, callback, errback=None, - callbackArgs=None, callbackKeywords=None, - errbackArgs=None, errbackKeywords=None): - """Add a pair of callbacks (success and error) to this Deferred. - - These will be executed when the 'master' callback is run. - """ - assert callable(callback) - assert errback == None or callable(errback) - cbs = ((callback, callbackArgs, callbackKeywords), - (errback or (passthru), errbackArgs, errbackKeywords)) - self.callbacks.append(cbs) - - if self.called: - self._runCallbacks() - return self - - def addCallback(self, callback, *args, **kw): - """Convenience method for adding just a callback. - - See L{addCallbacks}. - """ - return self.addCallbacks(callback, callbackArgs=args, - callbackKeywords=kw) - - def addErrback(self, errback, *args, **kw): - """Convenience method for adding just an errback. - - See L{addCallbacks}. - """ - return self.addCallbacks(passthru, errback, - errbackArgs=args, - errbackKeywords=kw) - - def addBoth(self, callback, *args, **kw): - """Convenience method for adding a single callable as both a callback - and an errback. - - See L{addCallbacks}. - """ - return self.addCallbacks(callback, callback, - callbackArgs=args, errbackArgs=args, - callbackKeywords=kw, errbackKeywords=kw) - - def chainDeferred(self, d): - """Chain another Deferred to this Deferred. - - This method adds callbacks to this Deferred to call d's callback or - errback, as appropriate. It is merely a shorthand way of performing - the following:: - - self.addCallbacks(d.callback, d.errback) - - When you chain a deferred d2 to another deferred d1 with - d1.chainDeferred(d2), you are making d2 participate in the callback - chain of d1. Thus any event that fires d1 will also fire d2. - However, the converse is B{not} true; if d2 is fired d1 will not be - affected. - """ - return self.addCallbacks(d.callback, d.errback) - - def callback(self, result): - """Run all success callbacks that have been added to this Deferred. - - Each callback will have its result passed as the first - argument to the next; this way, the callbacks act as a - 'processing chain'. Also, if the success-callback returns a Failure - or raises an Exception, processing will continue on the *error*- - callback chain. - """ - assert not isinstance(result, Deferred) - self._startRunCallbacks(result) - - - def errback(self, fail=None): - """ - Run all error callbacks that have been added to this Deferred. - - Each callback will have its result passed as the first - argument to the next; this way, the callbacks act as a - 'processing chain'. Also, if the error-callback returns a non-Failure - or doesn't raise an Exception, processing will continue on the - *success*-callback chain. - - If the argument that's passed to me is not a failure.Failure instance, - it will be embedded in one. If no argument is passed, a failure.Failure - instance will be created based on the current traceback stack. - - Passing a string as `fail' is deprecated, and will be punished with - a warning message. - - @raise NoCurrentExceptionError: If C{fail} is C{None} but there is - no current exception state. - """ - if not isinstance(fail, failure.Failure): - fail = failure.Failure(fail) - - self._startRunCallbacks(fail) - - - def pause(self): - """Stop processing on a Deferred until L{unpause}() is called. - """ - self.paused = self.paused + 1 - - - def unpause(self): - """Process all callbacks made since L{pause}() was called. - """ - self.paused = self.paused - 1 - if self.paused: - return - if self.called: - self._runCallbacks() - - def _continue(self, result): - self.result = result - self.unpause() - - def _startRunCallbacks(self, result): - if self.called: - if self.debug: - if self._debugInfo is None: - self._debugInfo = DebugInfo() - extra = "\n" + self._debugInfo._getDebugTracebacks() - raise AlreadyCalledError(extra) - raise AlreadyCalledError - if self.debug: - if self._debugInfo is None: - self._debugInfo = DebugInfo() - self._debugInfo.invoker = traceback.format_stack()[:-2] - self.called = True - self.result = result - if self.timeoutCall: - try: - self.timeoutCall.cancel() - except: - pass - - del self.timeoutCall - self._runCallbacks() - - def _runCallbacks(self): - if self._runningCallbacks: - # Don't recursively run callbacks - return - if not self.paused: - while self.callbacks: - item = self.callbacks.pop(0) - callback, args, kw = item[ - isinstance(self.result, failure.Failure)] - args = args or () - kw = kw or {} - try: - self._runningCallbacks = True - try: - self.result = callback(self.result, *args, **kw) - finally: - self._runningCallbacks = False - if isinstance(self.result, Deferred): - # note: this will cause _runCallbacks to be called - # recursively if self.result already has a result. - # This shouldn't cause any problems, since there is no - # relevant state in this stack frame at this point. - # The recursive call will continue to process - # self.callbacks until it is empty, then return here, - # where there is no more work to be done, so this call - # will return as well. - self.pause() - self.result.addBoth(self._continue) - break - except: - self.result = failure.Failure() - - if isinstance(self.result, failure.Failure): - self.result.cleanFailure() - if self._debugInfo is None: - self._debugInfo = DebugInfo() - self._debugInfo.failResult = self.result - else: - if self._debugInfo is not None: - self._debugInfo.failResult = None - - def setTimeout(self, seconds, timeoutFunc=timeout, *args, **kw): - """Set a timeout function to be triggered if I am not called. - - @param seconds: How long to wait (from now) before firing the - timeoutFunc. - - @param timeoutFunc: will receive the Deferred and *args, **kw as its - arguments. The default timeoutFunc will call the errback with a - L{TimeoutError}. - """ - warnings.warn( - "Deferred.setTimeout is deprecated. Look for timeout " - "support specific to the API you are using instead.", - DeprecationWarning, stacklevel=2) - - if self.called: - return - assert not self.timeoutCall, "Don't call setTimeout twice on the same Deferred." - - from twisted.internet import reactor - self.timeoutCall = reactor.callLater( - seconds, - lambda: self.called or timeoutFunc(self, *args, **kw)) - return self.timeoutCall - - def __str__(self): - cname = self.__class__.__name__ - if hasattr(self, 'result'): - return "<%s at %s current result: %r>" % (cname, hex(unsignedID(self)), - self.result) - return "<%s at %s>" % (cname, hex(unsignedID(self))) - __repr__ = __str__ - -class DebugInfo: - """Deferred debug helper""" - failResult = None - - def _getDebugTracebacks(self): - info = '' - if hasattr(self, "creator"): - info += " C: Deferred was created:\n C:" - info += "".join(self.creator).rstrip().replace("\n","\n C:") - info += "\n" - if hasattr(self, "invoker"): - info += " I: First Invoker was:\n I:" - info += "".join(self.invoker).rstrip().replace("\n","\n I:") - info += "\n" - return info - - def __del__(self): - """Print tracebacks and die. - - If the *last* (and I do mean *last*) callback leaves me in an error - state, print a traceback (if said errback is a Failure). - """ - if self.failResult is not None: - log.msg("Unhandled error in Deferred:", isError=True) - debugInfo = self._getDebugTracebacks() - if debugInfo != '': - log.msg("(debug: " + debugInfo + ")", isError=True) - log.err(self.failResult) - -class FirstError(Exception): - """First error to occur in a DeferredList if fireOnOneErrback is set. - - @ivar subFailure: the L{Failure} that occurred. - @ivar index: the index of the Deferred in the DeferredList where it - happened. - """ - def __init__(self, failure, index): - self.subFailure = failure - self.index = index - - def __repr__(self): - return 'FirstError(%r, %d)' % (self.subFailure, self.index) - - def __str__(self): - return repr(self) - - def __getitem__(self, index): - warnings.warn("FirstError.__getitem__ is deprecated. " - "Use attributes instead.", - category=DeprecationWarning, stacklevel=2) - return [self.subFailure, self.index][index] - - def __getslice__(self, start, stop): - warnings.warn("FirstError.__getslice__ is deprecated. " - "Use attributes instead.", - category=DeprecationWarning, stacklevel=2) - return [self.subFailure, self.index][start:stop] - - def __eq__(self, other): - if isinstance(other, tuple): - return tuple(self) == other - elif isinstance(other, FirstError): - return (self.subFailure == other.subFailure and - self.index == other.index) - return False - -class DeferredList(Deferred): - """I combine a group of deferreds into one callback. - - I track a list of L{Deferred}s for their callbacks, and make a single - callback when they have all completed, a list of (success, result) - tuples, 'success' being a boolean. - - Note that you can still use a L{Deferred} after putting it in a - DeferredList. For example, you can suppress 'Unhandled error in Deferred' - messages by adding errbacks to the Deferreds *after* putting them in the - DeferredList, as a DeferredList won't swallow the errors. (Although a more - convenient way to do this is simply to set the consumeErrors flag) - """ - - fireOnOneCallback = 0 - fireOnOneErrback = 0 - - def __init__(self, deferredList, fireOnOneCallback=0, fireOnOneErrback=0, - consumeErrors=0): - """Initialize a DeferredList. - - @type deferredList: C{list} of L{Deferred}s - @param deferredList: The list of deferreds to track. - @param fireOnOneCallback: (keyword param) a flag indicating that - only one callback needs to be fired for me to call - my callback - @param fireOnOneErrback: (keyword param) a flag indicating that - only one errback needs to be fired for me to call - my errback - @param consumeErrors: (keyword param) a flag indicating that any errors - raised in the original deferreds should be - consumed by this DeferredList. This is useful to - prevent spurious warnings being logged. - """ - self.resultList = [None] * len(deferredList) - Deferred.__init__(self) - if len(deferredList) == 0 and not fireOnOneCallback: - self.callback(self.resultList) - - # These flags need to be set *before* attaching callbacks to the - # deferreds, because the callbacks use these flags, and will run - # synchronously if any of the deferreds are already fired. - self.fireOnOneCallback = fireOnOneCallback - self.fireOnOneErrback = fireOnOneErrback - self.consumeErrors = consumeErrors - self.finishedCount = 0 - - index = 0 - for deferred in deferredList: - deferred.addCallbacks(self._cbDeferred, self._cbDeferred, - callbackArgs=(index,SUCCESS), - errbackArgs=(index,FAILURE)) - index = index + 1 - - def _cbDeferred(self, result, index, succeeded): - """(internal) Callback for when one of my deferreds fires. - """ - self.resultList[index] = (succeeded, result) - - self.finishedCount += 1 - if not self.called: - if succeeded == SUCCESS and self.fireOnOneCallback: - self.callback((result, index)) - elif succeeded == FAILURE and self.fireOnOneErrback: - self.errback(failure.Failure(FirstError(result, index))) - elif self.finishedCount == len(self.resultList): - self.callback(self.resultList) - - if succeeded == FAILURE and self.consumeErrors: - result = None - - return result - - -def _parseDListResult(l, fireOnOneErrback=0): - if __debug__: - for success, value in l: - assert success - return [x[1] for x in l] - -def gatherResults(deferredList): - """Returns list with result of given Deferreds. - - This builds on C{DeferredList} but is useful since you don't - need to parse the result for success/failure. - - @type deferredList: C{list} of L{Deferred}s - """ - d = DeferredList(deferredList, fireOnOneErrback=1) - d.addCallback(_parseDListResult) - return d - -# Constants for use with DeferredList - -SUCCESS = True -FAILURE = False - - - -## deferredGenerator - -class waitForDeferred: - """ - See L{deferredGenerator}. - """ - - def __init__(self, d): - if not isinstance(d, Deferred): - raise TypeError("You must give waitForDeferred a Deferred. You gave it %r." % (d,)) - self.d = d - - - def getResult(self): - if isinstance(self.result, failure.Failure): - self.result.raiseException() - return self.result - - - -def _deferGenerator(g, deferred): - """ - See L{deferredGenerator}. - """ - result = None - - # This function is complicated by the need to prevent unbounded recursion - # arising from repeatedly yielding immediately ready deferreds. This while - # loop and the waiting variable solve that by manually unfolding the - # recursion. - - waiting = [True, # defgen is waiting for result? - None] # result - - while 1: - try: - result = g.next() - except StopIteration: - deferred.callback(result) - return deferred - except: - deferred.errback() - return deferred - - # Deferred.callback(Deferred) raises an error; we catch this case - # early here and give a nicer error message to the user in case - # they yield a Deferred. - if isinstance(result, Deferred): - return fail(TypeError("Yield waitForDeferred(d), not d!")) - - if isinstance(result, waitForDeferred): - # a waitForDeferred was yielded, get the result. - # Pass result in so it don't get changed going around the loop - # This isn't a problem for waiting, as it's only reused if - # gotResult has already been executed. - def gotResult(r, result=result): - result.result = r - if waiting[0]: - waiting[0] = False - waiting[1] = r - else: - _deferGenerator(g, deferred) - result.d.addBoth(gotResult) - if waiting[0]: - # Haven't called back yet, set flag so that we get reinvoked - # and return from the loop - waiting[0] = False - return deferred - # Reset waiting to initial values for next loop - waiting[0] = True - waiting[1] = None - - result = None - - - -def deferredGenerator(f): - """ - Maintainer: U{Christopher Armstrong} - - deferredGenerator and waitForDeferred help you write Deferred-using code - that looks like a regular sequential function. If your code has a minimum - requirement of Python 2.5, consider the use of L{inlineCallbacks} instead, - which can accomplish the same thing in a more concise manner. - - There are two important functions involved: waitForDeferred, and - deferredGenerator. They are used together, like this:: - - def thingummy(): - thing = waitForDeferred(makeSomeRequestResultingInDeferred()) - yield thing - thing = thing.getResult() - print thing #the result! hoorj! - thingummy = deferredGenerator(thingummy) - - waitForDeferred returns something that you should immediately yield; when - your generator is resumed, calling thing.getResult() will either give you - the result of the Deferred if it was a success, or raise an exception if it - was a failure. Calling C{getResult} is B{absolutely mandatory}. If you do - not call it, I{your program will not work}. - - deferredGenerator takes one of these waitForDeferred-using generator - functions and converts it into a function that returns a Deferred. The - result of the Deferred will be the last value that your generator yielded - unless the last value is a waitForDeferred instance, in which case the - result will be C{None}. If the function raises an unhandled exception, the - Deferred will errback instead. Remember that 'return result' won't work; - use 'yield result; return' in place of that. - - Note that not yielding anything from your generator will make the Deferred - result in None. Yielding a Deferred from your generator is also an error - condition; always yield waitForDeferred(d) instead. - - The Deferred returned from your deferred generator may also errback if your - generator raised an exception. For example:: - - def thingummy(): - thing = waitForDeferred(makeSomeRequestResultingInDeferred()) - yield thing - thing = thing.getResult() - if thing == 'I love Twisted': - # will become the result of the Deferred - yield 'TWISTED IS GREAT!' - return - else: - # will trigger an errback - raise Exception('DESTROY ALL LIFE') - thingummy = deferredGenerator(thingummy) - - Put succinctly, these functions connect deferred-using code with this 'fake - blocking' style in both directions: waitForDeferred converts from a - Deferred to the 'blocking' style, and deferredGenerator converts from the - 'blocking' style to a Deferred. - """ - def unwindGenerator(*args, **kwargs): - return _deferGenerator(f(*args, **kwargs), Deferred()) - return mergeFunctionMetadata(f, unwindGenerator) - - -## inlineCallbacks - -# BaseException is only in Py 2.5. -try: - BaseException -except NameError: - BaseException=Exception - -class _DefGen_Return(BaseException): - def __init__(self, value): - self.value = value - -def returnValue(val): - """ - Return val from a L{inlineCallbacks} generator. - - Note: this is currently implemented by raising an exception - derived from BaseException. You might want to change any - 'except:' clauses to an 'except Exception:' clause so as not to - catch this exception. - - Also: while this function currently will work when called from - within arbitrary functions called from within the generator, do - not rely upon this behavior. - """ - raise _DefGen_Return(val) - -def _inlineCallbacks(result, g, deferred): - """ - See L{inlineCallbacks}. - """ - # This function is complicated by the need to prevent unbounded recursion - # arising from repeatedly yielding immediately ready deferreds. This while - # loop and the waiting variable solve that by manually unfolding the - # recursion. - - waiting = [True, # waiting for result? - None] # result - - while 1: - try: - # Send the last result back as the result of the yield expression. - if isinstance(result, failure.Failure): - result = result.throwExceptionIntoGenerator(g) - else: - result = g.send(result) - except StopIteration: - # fell off the end, or "return" statement - deferred.callback(None) - return deferred - except _DefGen_Return, e: - # returnValue call - deferred.callback(e.value) - return deferred - except: - deferred.errback() - return deferred - - if isinstance(result, Deferred): - # a deferred was yielded, get the result. - def gotResult(r): - if waiting[0]: - waiting[0] = False - waiting[1] = r - else: - _inlineCallbacks(r, g, deferred) - - result.addBoth(gotResult) - if waiting[0]: - # Haven't called back yet, set flag so that we get reinvoked - # and return from the loop - waiting[0] = False - return deferred - - result = waiting[1] - # Reset waiting to initial values for next loop. gotResult uses - # waiting, but this isn't a problem because gotResult is only - # executed once, and if it hasn't been executed yet, the return - # branch above would have been taken. - - - waiting[0] = True - waiting[1] = None - - - return deferred - -def inlineCallbacks(f): - """ - Maintainer: U{Christopher Armstrong} - - WARNING: this function will not work in Python 2.4 and earlier! - - inlineCallbacks helps you write Deferred-using code that looks like a - regular sequential function. This function uses features of Python 2.5 - generators. If you need to be compatible with Python 2.4 or before, use - the L{deferredGenerator} function instead, which accomplishes the same - thing, but with somewhat more boilerplate. For example:: - - def thingummy(): - thing = yield makeSomeRequestResultingInDeferred() - print thing #the result! hoorj! - thingummy = inlineCallbacks(thingummy) - - When you call anything that results in a Deferred, you can simply yield it; - your generator will automatically be resumed when the Deferred's result is - available. The generator will be sent the result of the Deferred with the - 'send' method on generators, or if the result was a failure, 'throw'. - - Your inlineCallbacks-enabled generator will return a Deferred object, which - will result in the return value of the generator (or will fail with a - failure object if your generator raises an unhandled exception). Note that - you can't use 'return result' to return a value; use 'returnValue(result)' - instead. Falling off the end of the generator, or simply using 'return' - will cause the Deferred to have a result of None. - - The Deferred returned from your deferred generator may errback if your - generator raised an exception:: - - def thingummy(): - thing = yield makeSomeRequestResultingInDeferred() - if thing == 'I love Twisted': - # will become the result of the Deferred - returnValue('TWISTED IS GREAT!') - else: - # will trigger an errback - raise Exception('DESTROY ALL LIFE') - thingummy = inlineCallbacks(thingummy) - """ - def unwindGenerator(*args, **kwargs): - return _inlineCallbacks(None, f(*args, **kwargs), Deferred()) - return mergeFunctionMetadata(f, unwindGenerator) - - -## DeferredLock/DeferredQueue - -class _ConcurrencyPrimitive(object): - def __init__(self): - self.waiting = [] - - def _releaseAndReturn(self, r): - self.release() - return r - - def run(*args, **kwargs): - """Acquire, run, release. - - This function takes a callable as its first argument and any - number of other positional and keyword arguments. When the - lock or semaphore is acquired, the callable will be invoked - with those arguments. - - The callable may return a Deferred; if it does, the lock or - semaphore won't be released until that Deferred fires. - - @return: Deferred of function result. - """ - if len(args) < 2: - if not args: - raise TypeError("run() takes at least 2 arguments, none given.") - raise TypeError("%s.run() takes at least 2 arguments, 1 given" % ( - args[0].__class__.__name__,)) - self, f = args[:2] - args = args[2:] - - def execute(ignoredResult): - d = maybeDeferred(f, *args, **kwargs) - d.addBoth(self._releaseAndReturn) - return d - - d = self.acquire() - d.addCallback(execute) - return d - - -class DeferredLock(_ConcurrencyPrimitive): - """ - A lock for event driven systems. - - @ivar locked: True when this Lock has been acquired, false at all - other times. Do not change this value, but it is useful to - examine for the equivalent of a \"non-blocking\" acquisition. - """ - - locked = 0 - - def acquire(self): - """Attempt to acquire the lock. - - @return: a Deferred which fires on lock acquisition. - """ - d = Deferred() - if self.locked: - self.waiting.append(d) - else: - self.locked = 1 - d.callback(self) - return d - - def release(self): - """Release the lock. - - Should be called by whomever did the acquire() when the shared - resource is free. - """ - assert self.locked, "Tried to release an unlocked lock" - self.locked = 0 - if self.waiting: - # someone is waiting to acquire lock - self.locked = 1 - d = self.waiting.pop(0) - d.callback(self) - -class DeferredSemaphore(_ConcurrencyPrimitive): - """ - A semaphore for event driven systems. - """ - - def __init__(self, tokens): - _ConcurrencyPrimitive.__init__(self) - self.tokens = tokens - self.limit = tokens - - def acquire(self): - """Attempt to acquire the token. - - @return: a Deferred which fires on token acquisition. - """ - assert self.tokens >= 0, "Internal inconsistency?? tokens should never be negative" - d = Deferred() - if not self.tokens: - self.waiting.append(d) - else: - self.tokens = self.tokens - 1 - d.callback(self) - return d - - def release(self): - """Release the token. - - Should be called by whoever did the acquire() when the shared - resource is free. - """ - assert self.tokens < self.limit, "Someone released me too many times: too many tokens!" - self.tokens = self.tokens + 1 - if self.waiting: - # someone is waiting to acquire token - self.tokens = self.tokens - 1 - d = self.waiting.pop(0) - d.callback(self) - -class QueueOverflow(Exception): - pass - -class QueueUnderflow(Exception): - pass - - -class DeferredQueue(object): - """ - An event driven queue. - - Objects may be added as usual to this queue. When an attempt is - made to retrieve an object when the queue is empty, a Deferred is - returned which will fire when an object becomes available. - - @ivar size: The maximum number of objects to allow into the queue - at a time. When an attempt to add a new object would exceed this - limit, QueueOverflow is raised synchronously. None for no limit. - - @ivar backlog: The maximum number of Deferred gets to allow at - one time. When an attempt is made to get an object which would - exceed this limit, QueueUnderflow is raised synchronously. None - for no limit. - """ - - def __init__(self, size=None, backlog=None): - self.waiting = [] - self.pending = [] - self.size = size - self.backlog = backlog - - def put(self, obj): - """Add an object to this queue. - - @raise QueueOverflow: Too many objects are in this queue. - """ - if self.waiting: - self.waiting.pop(0).callback(obj) - elif self.size is None or len(self.pending) < self.size: - self.pending.append(obj) - else: - raise QueueOverflow() - - def get(self): - """Attempt to retrieve and remove an object from the queue. - - @return: a Deferred which fires with the next object available in the queue. - - @raise QueueUnderflow: Too many (more than C{backlog}) - Deferreds are already waiting for an object from this queue. - """ - if self.pending: - return succeed(self.pending.pop(0)) - elif self.backlog is None or len(self.waiting) < self.backlog: - d = Deferred() - self.waiting.append(d) - return d - else: - raise QueueUnderflow() - - -class AlreadyTryingToLockError(Exception): - """ - Raised when DeferredFilesystemLock.deferUntilLocked is called twice on a - single DeferredFilesystemLock. - """ - - -class DeferredFilesystemLock(lockfile.FilesystemLock): - """ - A FilesystemLock that allows for a deferred to be fired when the lock is - acquired. - - @ivar _scheduler: The object in charge of scheduling retries. In this - implementation this is parameterized for testing. - - @ivar _interval: The retry interval for an L{IReactorTime} based scheduler. - - @ivar _tryLockCall: A L{DelayedCall} based on _interval that will managex - the next retry for aquiring the lock. - - @ivar _timeoutCall: A L{DelayedCall} based on deferUntilLocked's timeout - argument. This is in charge of timing out our attempt to acquire the - lock. - """ - _interval = 1 - _tryLockCall = None - _timeoutCall = None - - def __init__(self, name, scheduler=None): - """ - @param name: The name of the lock to acquire - @param scheduler: An object which provides L{IReactorTime} - """ - lockfile.FilesystemLock.__init__(self, name) - - if scheduler is None: - from twisted.internet import reactor - scheduler = reactor - - self._scheduler = scheduler - - def deferUntilLocked(self, timeout=None): - """ - Wait until we acquire this lock. This method is not safe for - concurrent use. - - @type timeout: C{float} or C{int} - @param timeout: the number of seconds after which to time out if the - lock has not been acquired. - - @return: a deferred which will callback when the lock is acquired, or - errback with a L{TimeoutError} after timing out or an - L{AlreadyTryingToLockError} if the L{deferUntilLocked} has already - been called and not successfully locked the file. - """ - if self._tryLockCall is not None: - return fail( - AlreadyTryingToLockError( - "deferUntilLocked isn't safe for concurrent use.")) - - d = Deferred() - - def _cancelLock(): - self._tryLockCall.cancel() - self._tryLockCall = None - self._timeoutCall = None - - if self.lock(): - d.callback(None) - else: - d.errback(failure.Failure( - TimeoutError("Timed out aquiring lock: %s after %fs" % ( - self.name, - timeout)))) - - def _tryLock(): - if self.lock(): - if self._timeoutCall is not None: - self._timeoutCall.cancel() - self._timeoutCall = None - - self._tryLockCall = None - - d.callback(None) - else: - if timeout is not None and self._timeoutCall is None: - self._timeoutCall = self._scheduler.callLater( - timeout, _cancelLock) - - self._tryLockCall = self._scheduler.callLater( - self._interval, _tryLock) - - _tryLock() - - return d - - -__all__ = ["Deferred", "DeferredList", "succeed", "fail", "FAILURE", "SUCCESS", - "AlreadyCalledError", "TimeoutError", "gatherResults", - "maybeDeferred", - "waitForDeferred", "deferredGenerator", "inlineCallbacks", - "DeferredLock", "DeferredSemaphore", "DeferredQueue", - "DeferredFilesystemLock", "AlreadyTryingToLockError", - ] diff --git a/tools/buildbot/pylibs/twisted/internet/epollreactor.py b/tools/buildbot/pylibs/twisted/internet/epollreactor.py deleted file mode 100644 index 051bf71..0000000 --- a/tools/buildbot/pylibs/twisted/internet/epollreactor.py +++ /dev/null @@ -1,256 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -An epoll() based implementation of the twisted main loop. - -To install the event loop (and you should do this before any connections, -listeners or connectors are added):: - - from twisted.internet import epollreactor - epollreactor.install() - -Maintainer: U{Jp Calderone } -""" - -import sys, errno - -from zope.interface import implements - -from twisted.internet.interfaces import IReactorFDSet - -from twisted.python import _epoll -from twisted.python import log -from twisted.internet import posixbase, error -from twisted.internet.main import CONNECTION_LOST - - -_POLL_DISCONNECTED = (_epoll.HUP | _epoll.ERR) - -class EPollReactor(posixbase.PosixReactorBase): - """ - A reactor that uses epoll(4). - - @ivar _poller: A L{poll} which will be used to check for I/O - readiness. - - @ivar _selectables: A dictionary mapping integer file descriptors to - instances of L{FileDescriptor} which have been registered with the - reactor. All L{FileDescriptors} which are currently receiving read or - write readiness notifications will be present as values in this - dictionary. - - @ivar _reads: A dictionary mapping integer file descriptors to arbitrary - values (this is essentially a set). Keys in this dictionary will be - registered with C{_poller} for read readiness notifications which will - be dispatched to the corresponding L{FileDescriptor} instances in - C{_selectables}. - - @ivar _writes: A dictionary mapping integer file descriptors to arbitrary - values (this is essentially a set). Keys in this dictionary will be - registered with C{_poller} for write readiness notifications which will - be dispatched to the corresponding L{FileDescriptor} instances in - C{_selectables}. - """ - implements(IReactorFDSet) - - def __init__(self): - """ - Initialize epoll object, file descriptor tracking dictionaries, and the - base class. - """ - # Create the poller we're going to use. The 1024 here is just a hint - # to the kernel, it is not a hard maximum. - self._poller = _epoll.epoll(1024) - self._reads = {} - self._writes = {} - self._selectables = {} - posixbase.PosixReactorBase.__init__(self) - - - def _add(self, xer, primary, other, selectables, event, antievent): - """ - Private method for adding a descriptor from the event loop. - - It takes care of adding it if new or modifying it if already added - for another state (read -> read/write for example). - """ - fd = xer.fileno() - if fd not in primary: - cmd = _epoll.CTL_ADD - flags = event - if fd in other: - flags |= antievent - cmd = _epoll.CTL_MOD - primary[fd] = 1 - selectables[fd] = xer - # epoll_ctl can raise all kinds of IOErrors, and every one - # indicates a bug either in the reactor or application-code. - # Let them all through so someone sees a traceback and fixes - # something. We'll do the same thing for every other call to - # this method in this file. - self._poller._control(cmd, fd, flags) - - - def addReader(self, reader): - """ - Add a FileDescriptor for notification of data available to read. - """ - self._add(reader, self._reads, self._writes, self._selectables, _epoll.IN, _epoll.OUT) - - - def addWriter(self, writer): - """ - Add a FileDescriptor for notification of data available to write. - """ - self._add(writer, self._writes, self._reads, self._selectables, _epoll.OUT, _epoll.IN) - - - def _remove(self, xer, primary, other, selectables, event, antievent): - """ - Private method for removing a descriptor from the event loop. - - It does the inverse job of _add, and also add a check in case of the fd - has gone away. - """ - fd = xer.fileno() - if fd == -1: - for fd, fdes in selectables.items(): - if xer is fdes: - break - else: - return - if fd in primary: - cmd = _epoll.CTL_DEL - flags = event - if fd in other: - flags = antievent - cmd = _epoll.CTL_MOD - else: - del selectables[fd] - del primary[fd] - # See comment above _control call in _add. - self._poller._control(cmd, fd, flags) - - - def removeReader(self, reader): - """ - Remove a Selectable for notification of data available to read. - """ - self._remove(reader, self._reads, self._writes, self._selectables, _epoll.IN, _epoll.OUT) - - - def removeWriter(self, writer): - """ - Remove a Selectable for notification of data available to write. - """ - self._remove(writer, self._writes, self._reads, self._selectables, _epoll.OUT, _epoll.IN) - - def removeAll(self): - """ - Remove all selectables, and return a list of them. - """ - if self.waker is not None: - fd = self.waker.fileno() - if fd in self._reads: - del self._reads[fd] - del self._selectables[fd] - result = self._selectables.values() - fds = self._selectables.keys() - self._reads.clear() - self._writes.clear() - self._selectables.clear() - for fd in fds: - try: - # Actually, we'll ignore all errors from this, since it's - # just last-chance cleanup. - self._poller._control(_epoll.CTL_DEL, fd, 0) - except IOError: - pass - if self.waker is not None: - fd = self.waker.fileno() - self._reads[fd] = 1 - self._selectables[fd] = self.waker - return result - - - def getReaders(self): - return [self._selectables[fd] for fd in self._reads] - - - def getWriters(self): - return [self._selectables[fd] for fd in self._writes] - - - def doPoll(self, timeout): - """ - Poll the poller for new events. - """ - if timeout is None: - timeout = 1 - timeout = int(timeout * 1000) # convert seconds to milliseconds - - try: - # Limit the number of events to the number of io objects we're - # currently tracking (because that's maybe a good heuristic) and - # the amount of time we block to the value specified by our - # caller. - l = self._poller.wait(len(self._selectables), timeout) - except IOError, err: - if err.errno == errno.EINTR: - return - # See epoll_wait(2) for documentation on the other conditions - # under which this can fail. They can only be due to a serious - # programming error on our part, so let's just announce them - # loudly. - raise - - _drdw = self._doReadOrWrite - for fd, event in l: - try: - selectable = self._selectables[fd] - except KeyError: - pass - else: - log.callWithLogger(selectable, _drdw, selectable, fd, event) - - doIteration = doPoll - - def _doReadOrWrite(self, selectable, fd, event): - """ - fd is available for read or write, make the work and raise errors - if necessary. - """ - why = None - inRead = False - if event & _POLL_DISCONNECTED and not (event & _epoll.IN): - why = CONNECTION_LOST - else: - try: - if event & _epoll.IN: - why = selectable.doRead() - inRead = True - if not why and event & _epoll.OUT: - why = selectable.doWrite() - inRead = False - if selectable.fileno() != fd: - why = error.ConnectionFdescWentAway( - 'Filedescriptor went away') - inRead = False - except: - log.err() - why = sys.exc_info()[1] - if why: - self._disconnectSelectable(selectable, why, inRead) - -def install(): - """ - Install the epoll() reactor. - """ - p = EPollReactor() - from twisted.internet.main import installReactor - installReactor(p) - - -__all__ = ["EPollReactor", "install"] - diff --git a/tools/buildbot/pylibs/twisted/internet/error.py b/tools/buildbot/pylibs/twisted/internet/error.py deleted file mode 100644 index 7c043f6..0000000 --- a/tools/buildbot/pylibs/twisted/internet/error.py +++ /dev/null @@ -1,305 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Exceptions and errors for use in twisted.internet modules. - -Maintainer: U{Itamar Shtull-Trauring} -""" - -import socket - - -class BindError(Exception): - """An error occurred binding to an interface""" - - def __str__(self): - s = self.__doc__ - if self.args: - s = '%s: %s' % (s, ' '.join(self.args)) - s = '%s.' % s - return s - -class CannotListenError(BindError): - """This gets raised by a call to startListening, when the object cannot start listening. - - @ivar interface: the interface I tried to listen on - @ivar port: the port I tried to listen on - @ivar socketError: the exception I got when I tried to listen - @type socketError: L{socket.error} - """ - def __init__(self, interface, port, socketError): - BindError.__init__(self, interface, port, socketError) - self.interface = interface - self.port = port - self.socketError = socketError - - def __str__(self): - iface = self.interface or 'any' - return "Couldn't listen on %s:%s: %s." % (iface, self.port, - self.socketError) - - -class MulticastJoinError(Exception): - """ - An attempt to join a multicast group failed. - """ - - -class MessageLengthError(Exception): - """Message is too long to send""" - - def __str__(self): - s = self.__doc__ - if self.args: - s = '%s: %s' % (s, ' '.join(self.args)) - s = '%s.' % s - return s - - -class DNSLookupError(IOError): - """DNS lookup failed""" - - def __str__(self): - s = self.__doc__ - if self.args: - s = '%s: %s' % (s, ' '.join(self.args)) - s = '%s.' % s - return s - - -class ConnectInProgressError(Exception): - """A connect operation was started and isn't done yet.""" - - -# connection errors - -class ConnectError(Exception): - """An error occurred while connecting""" - - def __init__(self, osError=None, string=""): - self.osError = osError - Exception.__init__(self, string) - - def __str__(self): - s = self.__doc__ or self.__class__.__name__ - if self.osError: - s = '%s: %s' % (s, self.osError) - if self[0]: - s = '%s: %s' % (s, self[0]) - s = '%s.' % s - return s - - -class ConnectBindError(ConnectError): - """Couldn't bind""" - - -class UnknownHostError(ConnectError): - """Hostname couldn't be looked up""" - - -class NoRouteError(ConnectError): - """No route to host""" - - -class ConnectionRefusedError(ConnectError): - """Connection was refused by other side""" - - -class TCPTimedOutError(ConnectError): - """TCP connection timed out""" - - -class BadFileError(ConnectError): - """File used for UNIX socket is no good""" - - -class ServiceNameUnknownError(ConnectError): - """Service name given as port is unknown""" - - -class UserError(ConnectError): - """User aborted connection""" - - -class TimeoutError(UserError): - """User timeout caused connection failure""" - -class SSLError(ConnectError): - """An SSL error occurred""" - -class VerifyError(Exception): - """Could not verify something that was supposed to be signed. - """ - -class PeerVerifyError(VerifyError): - """The peer rejected our verify error. - """ - -class CertificateError(Exception): - """ - We did not find a certificate where we expected to find one. - """ - -try: - import errno - errnoMapping = { - errno.ENETUNREACH: NoRouteError, - errno.ECONNREFUSED: ConnectionRefusedError, - errno.ETIMEDOUT: TCPTimedOutError, - } - if hasattr(errno, "WSAECONNREFUSED"): - errnoMapping[errno.WSAECONNREFUSED] = ConnectionRefusedError - errnoMapping[errno.WSAENETUNREACH] = NoRouteError -except ImportError: - errnoMapping = {} - -def getConnectError(e): - """Given a socket exception, return connection error.""" - try: - number, string = e - except ValueError: - return ConnectError(string=e) - - if hasattr(socket, 'gaierror') and isinstance(e, socket.gaierror): - # only works in 2.2 - klass = UnknownHostError - else: - klass = errnoMapping.get(number, ConnectError) - return klass(number, string) - - - -class ConnectionClosed(Exception): - """ - Connection was closed, whether cleanly or non-cleanly. - """ - - - -class ConnectionLost(ConnectionClosed): - """Connection to the other side was lost in a non-clean fashion""" - - def __str__(self): - s = self.__doc__ - if self.args: - s = '%s: %s' % (s, ' '.join(self.args)) - s = '%s.' % s - return s - - - -class ConnectionDone(ConnectionClosed): - """Connection was closed cleanly""" - - def __str__(self): - s = self.__doc__ - if self.args: - s = '%s: %s' % (s, ' '.join(self.args)) - s = '%s.' % s - return s - - -class ConnectionFdescWentAway(ConnectionLost): - """Uh""" #TODO - - -class AlreadyCalled(ValueError): - """Tried to cancel an already-called event""" - - def __str__(self): - s = self.__doc__ - if self.args: - s = '%s: %s' % (s, ' '.join(self.args)) - s = '%s.' % s - return s - - -class AlreadyCancelled(ValueError): - """Tried to cancel an already-cancelled event""" - - def __str__(self): - s = self.__doc__ - if self.args: - s = '%s: %s' % (s, ' '.join(self.args)) - s = '%s.' % s - return s - - - -class PotentialZombieWarning(Warning): - """ - Emitted when L{IReactorProcess.spawnProcess} is called in a way which may - result in termination of the created child process not being reported. - """ - MESSAGE = ( - "spawnProcess called, but the SIGCHLD handler is not " - "installed. This probably means you have not yet " - "called reactor.run, or called " - "reactor.run(installSignalHandler=0). You will probably " - "never see this process finish, and it may become a " - "zombie process.") - - - -class ProcessDone(ConnectionDone): - """A process has ended without apparent errors""" - - def __init__(self, status): - Exception.__init__(self, "process finished with exit code 0") - self.exitCode = 0 - self.signal = None - self.status = status - - -class ProcessTerminated(ConnectionLost): - """A process has ended with a probable error condition""" - - def __init__(self, exitCode=None, signal=None, status=None): - self.exitCode = exitCode - self.signal = signal - self.status = status - s = "process ended" - if exitCode is not None: s = s + " with exit code %s" % exitCode - if signal is not None: s = s + " by signal %s" % signal - Exception.__init__(self, s) - - -class ProcessExitedAlready(Exception): - """The process has already excited, and the operation requested can no longer be performed.""" - - -class NotConnectingError(RuntimeError): - """The Connector was not connecting when it was asked to stop connecting""" - - def __str__(self): - s = self.__doc__ - if self.args: - s = '%s: %s' % (s, ' '.join(self.args)) - s = '%s.' % s - return s - -class NotListeningError(RuntimeError): - """The Port was not listening when it was asked to stop listening""" - - def __str__(self): - s = self.__doc__ - if self.args: - s = '%s: %s' % (s, ' '.join(self.args)) - s = '%s.' % s - return s - - -class ReactorNotRunning(RuntimeError): - """ - Error raised when trying to stop a reactor which is not running. - """ - - -class ReactorAlreadyRunning(RuntimeError): - """ - Error raised when trying to start the reactor multiple times. - """ - diff --git a/tools/buildbot/pylibs/twisted/internet/fdesc.py b/tools/buildbot/pylibs/twisted/internet/fdesc.py deleted file mode 100644 index 4d990bb..0000000 --- a/tools/buildbot/pylibs/twisted/internet/fdesc.py +++ /dev/null @@ -1,93 +0,0 @@ -# -*- test-case-name: twisted.test.test_fdesc -*- - -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Utility functions for dealing with POSIX file descriptors. -""" - -import sys -import os -import errno -import fcntl -if (sys.hexversion >> 16) >= 0x202: - FCNTL = fcntl -else: - import FCNTL - -# twisted imports -from twisted.internet.main import CONNECTION_LOST, CONNECTION_DONE - - -def setNonBlocking(fd): - """ - Make a file descriptor non-blocking. - """ - flags = fcntl.fcntl(fd, FCNTL.F_GETFL) - flags = flags | os.O_NONBLOCK - fcntl.fcntl(fd, FCNTL.F_SETFL, flags) - - -def setBlocking(fd): - """ - Make a file descriptor blocking. - """ - flags = fcntl.fcntl(fd, FCNTL.F_GETFL) - flags = flags & ~os.O_NONBLOCK - fcntl.fcntl(fd, FCNTL.F_SETFL, flags) - - -def readFromFD(fd, callback): - """ - Read from file descriptor, calling callback with resulting data. - - Returns same thing FileDescriptor.doRead would. - - @type fd: C{int} - @param fd: non-blocking file descriptor to be read from. - @param callback: a callable which accepts a single argument. If - data is read from the file descriptor it will be called with this - data. Handling exceptions from calling the callback is up to the - caller. - - Note that if the descriptor is still connected but no data is read, - None will be returned but callback will not be called. - - @return: CONNECTION_LOST on error, CONNECTION_DONE when fd is - closed, otherwise None. - """ - try: - output = os.read(fd, 8192) - except (OSError, IOError), ioe: - if ioe.args[0] in (errno.EAGAIN, errno.EINTR): - return - else: - return CONNECTION_LOST - if not output: - return CONNECTION_DONE - callback(output) - -def writeToFD(fd, data): - """ - Write data to file descriptor. - - Returns same thing FileDescriptor.writeSomeData would. - - @type fd: C{int} - @param fd: non-blocking file descriptor to be written to. - @type data: C{str} or C{buffer} - @param data: bytes to write to fd. - - @return: number of bytes written, or CONNECTION_LOST. - """ - try: - return os.write(fd, data) - except (OSError, IOError), io: - if io.errno in (errno.EAGAIN, errno.EINTR): - return 0 - return CONNECTION_LOST - - -__all__ = ["setNonBlocking", "setBlocking", "readFromFD", "writeToFD"] diff --git a/tools/buildbot/pylibs/twisted/internet/glib2reactor.py b/tools/buildbot/pylibs/twisted/internet/glib2reactor.py deleted file mode 100644 index a759107..0000000 --- a/tools/buildbot/pylibs/twisted/internet/glib2reactor.py +++ /dev/null @@ -1,49 +0,0 @@ - -""" -This module provides support for Twisted to interact with the glib mainloop. -This is like gtk2, but slightly faster and does not require a working -$DISPLAY. However, you cannot run GUIs under this reactor: for that you must -use the gtk2reactor instead. - -In order to use this support, simply do the following:: - - | from twisted.internet import glib2reactor - | glib2reactor.install() - -Then use twisted.internet APIs as usual. The other methods here are not -intended to be called directly. - -When installing the reactor, you can choose whether to use the glib -event loop or the GTK+ event loop which is based on it but adds GUI -integration. - -Maintainer: U{Itamar Shtull-Trauring} -""" - -from twisted.internet import gtk2reactor - - - -class Glib2Reactor(gtk2reactor.Gtk2Reactor): - """ - The reactor using the glib mainloop. - """ - - def __init__(self): - """ - Override init to set the C{useGtk} flag. - """ - gtk2reactor.Gtk2Reactor.__init__(self, useGtk=False) - - - -def install(): - """ - Configure the twisted mainloop to be run inside the glib mainloop. - """ - reactor = Glib2Reactor() - from twisted.internet.main import installReactor - installReactor(reactor) - -__all__ = ['install'] - diff --git a/tools/buildbot/pylibs/twisted/internet/gtk2reactor.py b/tools/buildbot/pylibs/twisted/internet/gtk2reactor.py deleted file mode 100644 index d2aaf03..0000000 --- a/tools/buildbot/pylibs/twisted/internet/gtk2reactor.py +++ /dev/null @@ -1,295 +0,0 @@ -# -*- test-case-name: twisted.internet.test.test_gtk2reactor -*- -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -This module provides support for Twisted to interact with the glib/gtk2 -mainloop. - -In order to use this support, simply do the following:: - - | from twisted.internet import gtk2reactor - | gtk2reactor.install() - -Then use twisted.internet APIs as usual. The other methods here are not -intended to be called directly. - -When installing the reactor, you can choose whether to use the glib -event loop or the GTK+ event loop which is based on it but adds GUI -integration. - -Maintainer: U{Itamar Shtull-Trauring} -""" - -# System Imports -import sys -from zope.interface import implements -try: - if not hasattr(sys, 'frozen'): - # Don't want to check this for py2exe - import pygtk - pygtk.require('2.0') -except (ImportError, AttributeError): - pass # maybe we're using pygtk before this hack existed. -import gobject -if hasattr(gobject, "threads_init"): - # recent versions of python-gtk expose this. python-gtk=2.4.1 - # (wrapping glib-2.4.7) does. python-gtk=2.0.0 (wrapping - # glib-2.2.3) does not. - gobject.threads_init() - -# Twisted Imports -from twisted.python import log, runtime, failure -from twisted.internet.interfaces import IReactorFDSet -from twisted.internet import main, posixbase, error, selectreactor - -POLL_DISCONNECTED = gobject.IO_HUP | gobject.IO_ERR | gobject.IO_NVAL - -# glib's iochannel sources won't tell us about any events that we haven't -# asked for, even if those events aren't sensible inputs to the poll() -# call. -INFLAGS = gobject.IO_IN | POLL_DISCONNECTED -OUTFLAGS = gobject.IO_OUT | POLL_DISCONNECTED - -def _our_mainquit(): - # XXX: gtk.main_quit() (which is used for crash()) raises an exception if - # gtk.main_level() == 0; however, all the tests freeze if we use this - # function to stop the reactor. what gives? (I believe this may have been - # a stupid mistake where I forgot to import gtk here... I will remove this - # comment if the tests pass) - import gtk - if gtk.main_level(): - gtk.main_quit() - -class Gtk2Reactor(posixbase.PosixReactorBase): - """ - GTK+-2 event loop reactor. - - @ivar _reads: A dictionary mapping L{FileDescriptor} instances to gtk - INPUT_READ watch handles. - - @ivar _writes: A dictionary mapping L{FileDescriptor} instances to gtk - INTPUT_WRITE watch handles. - - @ivar _simtag: A gtk timeout handle for the next L{simulate} call. - """ - implements(IReactorFDSet) - - def __init__(self, useGtk=True): - self.context = gobject.main_context_default() - self.loop = gobject.MainLoop() - self._simtag = None - self._reads = {} - self._writes = {} - posixbase.PosixReactorBase.__init__(self) - # pre 2.3.91 the glib iteration and mainloop functions didn't release - # global interpreter lock, thus breaking thread and signal support. - if (hasattr(gobject, "pygtk_version") and gobject.pygtk_version >= (2, 3, 91) - and not useGtk): - self.__pending = self.context.pending - self.__iteration = self.context.iteration - self.__crash = self.loop.quit - self.__run = self.loop.run - else: - import gtk - self.__pending = gtk.events_pending - self.__iteration = gtk.main_iteration - self.__crash = _our_mainquit - self.__run = gtk.main - - # The input_add function in pygtk1 checks for objects with a - # 'fileno' method and, if present, uses the result of that method - # as the input source. The pygtk2 input_add does not do this. The - # function below replicates the pygtk1 functionality. - - # In addition, pygtk maps gtk.input_add to _gobject.io_add_watch, and - # g_io_add_watch() takes different condition bitfields than - # gtk_input_add(). We use g_io_add_watch() here in case pygtk fixes this - # bug. - def input_add(self, source, condition, callback): - if hasattr(source, 'fileno'): - # handle python objects - def wrapper(source, condition, real_s=source, real_cb=callback): - return real_cb(real_s, condition) - return gobject.io_add_watch(source.fileno(), condition, wrapper) - else: - return gobject.io_add_watch(source, condition, callback) - - def addReader(self, reader): - if reader not in self._reads: - self._reads[reader] = self.input_add(reader, INFLAGS, self.callback) - - def addWriter(self, writer): - if writer not in self._writes: - self._writes[writer] = self.input_add(writer, OUTFLAGS, self.callback) - - - def getReaders(self): - return self._reads.keys() - - - def getWriters(self): - return self._writes.keys() - - - def removeAll(self): - return self._removeAll(self._reads, self._writes) - - def removeReader(self, reader): - if reader in self._reads: - gobject.source_remove(self._reads[reader]) - del self._reads[reader] - - def removeWriter(self, writer): - if writer in self._writes: - gobject.source_remove(self._writes[writer]) - del self._writes[writer] - - doIterationTimer = None - - def doIterationTimeout(self, *args): - self.doIterationTimer = None - return 0 # auto-remove - - def doIteration(self, delay): - # flush some pending events, return if there was something to do - # don't use the usual "while self.context.pending(): self.context.iteration()" - # idiom because lots of IO (in particular test_tcp's - # ProperlyCloseFilesTestCase) can keep us from ever exiting. - log.msg(channel='system', event='iteration', reactor=self) - if self.__pending(): - self.__iteration(0) - return - # nothing to do, must delay - if delay == 0: - return # shouldn't delay, so just return - self.doIterationTimer = gobject.timeout_add(int(delay * 1000), - self.doIterationTimeout) - # This will either wake up from IO or from a timeout. - self.__iteration(1) # block - # note: with the .simulate timer below, delays > 0.1 will always be - # woken up by the .simulate timer - if self.doIterationTimer: - # if woken by IO, need to cancel the timer - gobject.source_remove(self.doIterationTimer) - self.doIterationTimer = None - - def crash(self): - posixbase.PosixReactorBase.crash(self) - self.__crash() - - def run(self, installSignalHandlers=1): - self.startRunning(installSignalHandlers=installSignalHandlers) - gobject.timeout_add(0, self.simulate) - if not self._stopped: - self.__run() - - def _doReadOrWrite(self, source, condition, faildict={ - error.ConnectionDone: failure.Failure(error.ConnectionDone()), - error.ConnectionLost: failure.Failure(error.ConnectionLost()), - }): - why = None - didRead = None - if condition & POLL_DISCONNECTED and \ - not (condition & gobject.IO_IN): - why = main.CONNECTION_LOST - else: - try: - if condition & gobject.IO_IN: - why = source.doRead() - didRead = source.doRead - if not why and condition & gobject.IO_OUT: - # if doRead caused connectionLost, don't call doWrite - # if doRead is doWrite, don't call it again. - if not source.disconnected and source.doWrite != didRead: - why = source.doWrite() - didRead = source.doWrite # if failed it was in write - except: - why = sys.exc_info()[1] - log.msg('Error In %s' % source) - log.deferr() - - if why: - self._disconnectSelectable(source, why, didRead == source.doRead) - - def callback(self, source, condition): - log.callWithLogger(source, self._doReadOrWrite, source, condition) - self.simulate() # fire Twisted timers - return 1 # 1=don't auto-remove the source - - def simulate(self): - """Run simulation loops and reschedule callbacks. - """ - if self._simtag is not None: - gobject.source_remove(self._simtag) - self.runUntilCurrent() - timeout = min(self.timeout(), 0.1) - if timeout is None: - timeout = 0.1 - # grumble - self._simtag = gobject.timeout_add(int(timeout * 1010), self.simulate) - - -class PortableGtkReactor(selectreactor.SelectReactor): - """Reactor that works on Windows. - - input_add is not supported on GTK+ for Win32, apparently. - """ - - def crash(self): - selectreactor.SelectReactor.crash(self) - import gtk - # mainquit is deprecated in newer versions - if hasattr(gtk, 'main_quit'): - gtk.main_quit() - else: - gtk.mainquit() - - def run(self, installSignalHandlers=1): - import gtk - self.startRunning(installSignalHandlers=installSignalHandlers) - self.simulate() - # mainloop is deprecated in newer versions - if hasattr(gtk, 'main'): - gtk.main() - else: - gtk.mainloop() - - def simulate(self): - """Run simulation loops and reschedule callbacks. - """ - if self._simtag is not None: - gobject.source_remove(self._simtag) - self.iterate() - timeout = min(self.timeout(), 0.1) - if timeout is None: - timeout = 0.1 - # grumble - self._simtag = gobject.timeout_add(int(timeout * 1010), self.simulate) - - -def install(useGtk=True): - """Configure the twisted mainloop to be run inside the gtk mainloop. - - @param useGtk: should glib rather than GTK+ event loop be - used (this will be slightly faster but does not support GUI). - """ - reactor = Gtk2Reactor(useGtk) - from twisted.internet.main import installReactor - installReactor(reactor) - return reactor - -def portableInstall(useGtk=True): - """Configure the twisted mainloop to be run inside the gtk mainloop. - """ - reactor = PortableGtkReactor() - from twisted.internet.main import installReactor - installReactor(reactor) - return reactor - -if runtime.platform.getType() != 'posix': - install = portableInstall - - -__all__ = ['install'] diff --git a/tools/buildbot/pylibs/twisted/internet/gtkreactor.py b/tools/buildbot/pylibs/twisted/internet/gtkreactor.py deleted file mode 100644 index 6c19fe4..0000000 --- a/tools/buildbot/pylibs/twisted/internet/gtkreactor.py +++ /dev/null @@ -1,233 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -This module provides support for Twisted to interact with the PyGTK mainloop. - -In order to use this support, simply do the following:: - - | from twisted.internet import gtkreactor - | gtkreactor.install() - -Then use twisted.internet APIs as usual. The other methods here are not -intended to be called directly. - -Maintainer: U{Itamar Shtull-Trauring} -""" - -import sys - -# System Imports -try: - import pygtk - pygtk.require('1.2') -except ImportError, AttributeError: - pass # maybe we're using pygtk before this hack existed. -import gtk - -from zope.interface import implements - -# Twisted Imports -from twisted.python import log, runtime -from twisted.internet.interfaces import IReactorFDSet - -# Sibling Imports -from twisted.internet import posixbase, selectreactor - - -class GtkReactor(posixbase.PosixReactorBase): - """ - GTK+ event loop reactor. - - @ivar _reads: A dictionary mapping L{FileDescriptor} instances to gtk INPUT_READ - watch handles. - - @ivar _writes: A dictionary mapping L{FileDescriptor} instances to gtk - INTPUT_WRITE watch handles. - - @ivar _simtag: A gtk timeout handle for the next L{simulate} call. - """ - implements(IReactorFDSet) - - def __init__(self): - """ - Initialize the file descriptor tracking dictionaries and the base - class. - """ - self._simtag = None - self._reads = {} - self._writes = {} - posixbase.PosixReactorBase.__init__(self) - - - def addReader(self, reader): - if reader not in self._reads: - self._reads[reader] = gtk.input_add(reader, gtk.GDK.INPUT_READ, self.callback) - - def addWriter(self, writer): - if writer not in self._writes: - self._writes[writer] = gtk.input_add(writer, gtk.GDK.INPUT_WRITE, self.callback) - - - def getReaders(self): - return self._reads.keys() - - - def getWriters(self): - return self._writes.keys() - - - def removeAll(self): - return self._removeAll(self._reads, self._writes) - - def removeReader(self, reader): - if reader in self._reads: - gtk.input_remove(self._reads[reader]) - del self._reads[reader] - - def removeWriter(self, writer): - if writer in self._writes: - gtk.input_remove(self._writes[writer]) - del self._writes[writer] - - doIterationTimer = None - - def doIterationTimeout(self, *args): - self.doIterationTimer = None - return 0 # auto-remove - def doIteration(self, delay): - # flush some pending events, return if there was something to do - # don't use the usual "while gtk.events_pending(): mainiteration()" - # idiom because lots of IO (in particular test_tcp's - # ProperlyCloseFilesTestCase) can keep us from ever exiting. - log.msg(channel='system', event='iteration', reactor=self) - if gtk.events_pending(): - gtk.mainiteration(0) - return - # nothing to do, must delay - if delay == 0: - return # shouldn't delay, so just return - self.doIterationTimer = gtk.timeout_add(int(delay * 1000), - self.doIterationTimeout) - # This will either wake up from IO or from a timeout. - gtk.mainiteration(1) # block - # note: with the .simulate timer below, delays > 0.1 will always be - # woken up by the .simulate timer - if self.doIterationTimer: - # if woken by IO, need to cancel the timer - gtk.timeout_remove(self.doIterationTimer) - self.doIterationTimer = None - - def crash(self): - posixbase.PosixReactorBase.crash(self) - gtk.mainquit() - - def run(self, installSignalHandlers=1): - self.startRunning(installSignalHandlers=installSignalHandlers) - gtk.timeout_add(0, self.simulate) - gtk.mainloop() - - def _readAndWrite(self, source, condition): - # note: gtk-1.2's gtk_input_add presents an API in terms of gdk - # constants like INPUT_READ and INPUT_WRITE. Internally, it will add - # POLL_HUP and POLL_ERR to the poll() events, but if they happen it - # will turn them back into INPUT_READ and INPUT_WRITE. gdkevents.c - # maps IN/HUP/ERR to INPUT_READ, and OUT/ERR to INPUT_WRITE. This - # means there is no immediate way to detect a disconnected socket. - - # The g_io_add_watch() API is more suited to this task. I don't think - # pygtk exposes it, though. - why = None - didRead = None - try: - if condition & gtk.GDK.INPUT_READ: - why = source.doRead() - didRead = source.doRead - if not why and condition & gtk.GDK.INPUT_WRITE: - # if doRead caused connectionLost, don't call doWrite - # if doRead is doWrite, don't call it again. - if not source.disconnected and source.doWrite != didRead: - why = source.doWrite() - didRead = source.doWrite # if failed it was in write - except: - why = sys.exc_info()[1] - log.msg('Error In %s' % source) - log.deferr() - - if why: - self._disconnectSelectable(source, why, didRead == source.doRead) - - def callback(self, source, condition): - log.callWithLogger(source, self._readAndWrite, source, condition) - self.simulate() # fire Twisted timers - return 1 # 1=don't auto-remove the source - - def simulate(self): - """Run simulation loops and reschedule callbacks. - """ - if self._simtag is not None: - gtk.timeout_remove(self._simtag) - self.runUntilCurrent() - timeout = min(self.timeout(), 0.1) - if timeout is None: - timeout = 0.1 - # Quoth someone other than me, "grumble", yet I know not why. Try to be - # more specific in your complaints, guys. -exarkun - self._simtag = gtk.timeout_add(int(timeout * 1010), self.simulate) - - - -class PortableGtkReactor(selectreactor.SelectReactor): - """Reactor that works on Windows. - - input_add is not supported on GTK+ for Win32, apparently. - - @ivar _simtag: A gtk timeout handle for the next L{simulate} call. - """ - _simtag = None - - - def crash(self): - selectreactor.SelectReactor.crash(self) - gtk.mainquit() - - def run(self, installSignalHandlers=1): - self.startRunning(installSignalHandlers=installSignalHandlers) - self.simulate() - gtk.mainloop() - - def simulate(self): - """Run simulation loops and reschedule callbacks. - """ - if self._simtag is not None: - gtk.timeout_remove(self._simtag) - self.iterate() - timeout = min(self.timeout(), 0.1) - if timeout is None: - timeout = 0.1 - - # See comment for identical line in GtkReactor.simulate. - self._simtag = gtk.timeout_add((timeout * 1010), self.simulate) - - - -def install(): - """Configure the twisted mainloop to be run inside the gtk mainloop. - """ - reactor = GtkReactor() - from twisted.internet.main import installReactor - installReactor(reactor) - return reactor - -def portableInstall(): - """Configure the twisted mainloop to be run inside the gtk mainloop. - """ - reactor = PortableGtkReactor() - from twisted.internet.main import installReactor - installReactor(reactor) - return reactor - -if runtime.platform.getType() != 'posix': - install = portableInstall - -__all__ = ['install'] diff --git a/tools/buildbot/pylibs/twisted/internet/interfaces.py b/tools/buildbot/pylibs/twisted/internet/interfaces.py deleted file mode 100644 index d7a4521..0000000 --- a/tools/buildbot/pylibs/twisted/internet/interfaces.py +++ /dev/null @@ -1,1417 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Interface documentation. - -Maintainer: U{Itamar Shtull-Trauring} -""" - -from zope.interface import Interface - - -class IAddress(Interface): - """An address, e.g. a TCP (host, port). - - Default implementations are in L{twisted.internet.address}. - """ - - -### Reactor Interfaces - -class IConnector(Interface): - """Object used to interface between connections and protocols. - - Each IConnector manages one connection. - """ - - def stopConnecting(): - """Stop attempting to connect.""" - - def disconnect(): - """Disconnect regardless of the connection state. - - If we are connected, disconnect, if we are trying to connect, - stop trying. - """ - - def connect(): - """Try to connect to remote address.""" - - def getDestination(): - """Return destination this will try to connect to. - - @return: An object which provides L{IAddress}. - """ - - -class IResolverSimple(Interface): - def getHostByName(name, timeout = (1, 3, 11, 45)): - """Resolve the domain name C{name} into an IP address. - - @type name: C{str} - @type timeout: C{tuple} - @rtype: L{twisted.internet.defer.Deferred} - @return: The callback of the Deferred that is returned will be - passed a string that represents the IP address of the specified - name, or the errback will be called if the lookup times out. If - multiple types of address records are associated with the name, - A6 records will be returned in preference to AAAA records, which - will be returned in preference to A records. If there are multiple - records of the type to be returned, one will be selected at random. - - @raise twisted.internet.defer.TimeoutError: Raised (asynchronously) - if the name cannot be resolved within the specified timeout period. - """ - -class IResolver(IResolverSimple): - def lookupRecord(name, cls, type, timeout = 10): - """Lookup the records associated with the given name - that are of the given type and in the given class. - """ - - def query(query, timeout = 10): - """Interpret and dispatch a query object to the appropriate - lookup* method. - """ - - def lookupAddress(name, timeout = 10): - """Lookup the A records associated with C{name}.""" - - def lookupAddress6(name, timeout = 10): - """Lookup all the A6 records associated with C{name}.""" - - def lookupIPV6Address(name, timeout = 10): - """Lookup all the AAAA records associated with C{name}.""" - - def lookupMailExchange(name, timeout = 10): - """Lookup the MX records associated with C{name}.""" - - def lookupNameservers(name, timeout = 10): - """Lookup the the NS records associated with C{name}.""" - - def lookupCanonicalName(name, timeout = 10): - """Lookup the CNAME records associated with C{name}.""" - - def lookupMailBox(name, timeout = 10): - """Lookup the MB records associated with C{name}.""" - - def lookupMailGroup(name, timeout = 10): - """Lookup the MG records associated with C{name}.""" - - def lookupMailRename(name, timeout = 10): - """Lookup the MR records associated with C{name}.""" - - def lookupPointer(name, timeout = 10): - """Lookup the PTR records associated with C{name}.""" - - def lookupAuthority(name, timeout = 10): - """Lookup the SOA records associated with C{name}.""" - - def lookupNull(name, timeout = 10): - """Lookup the NULL records associated with C{name}.""" - - def lookupWellKnownServices(name, timeout = 10): - """Lookup the WKS records associated with C{name}.""" - - def lookupHostInfo(name, timeout = 10): - """Lookup the HINFO records associated with C{name}.""" - - def lookupMailboxInfo(name, timeout = 10): - """Lookup the MINFO records associated with C{name}.""" - - def lookupText(name, timeout = 10): - """Lookup the TXT records associated with C{name}.""" - - def lookupResponsibility(name, timeout = 10): - """Lookup the RP records associated with C{name}.""" - - def lookupAFSDatabase(name, timeout = 10): - """Lookup the AFSDB records associated with C{name}.""" - - def lookupService(name, timeout = 10): - """Lookup the SRV records associated with C{name}.""" - - def lookupAllRecords(name, timeout = 10): - """Lookup all records associated with C{name}.""" - - def lookupZone(name, timeout = 10): - """Perform a zone transfer for the given C{name}.""" - - -class IReactorArbitrary(Interface): - def listenWith(portType, *args, **kw): - """Start an instance of the given C{portType} listening. - - @type portType: type which implements L{IListeningPort} - - @param portType: The object given by C{portType(*args, **kw)} will be - started listening. - - @return: an object which provides L{IListeningPort}. - """ - - def connectWith(connectorType, *args, **kw): - """ - Start an instance of the given C{connectorType} connecting. - - @type connectorType: type which implements L{IConnector} - - @param connectorType: The object given by C{connectorType(*args, **kw)} - will be started connecting. - - @return: An object which provides L{IConnector}. - """ - -class IReactorTCP(Interface): - - def listenTCP(port, factory, backlog=50, interface=''): - """Connects a given protocol factory to the given numeric TCP/IP port. - - @param port: a port number on which to listen - - @param factory: a L{twisted.internet.protocol.ServerFactory} instance - - @param backlog: size of the listen queue - - @param interface: the hostname to bind to, defaults to '' (all) - - @return: an object that provides L{IListeningPort}. - - @raise CannotListenError: as defined here - L{twisted.internet.error.CannotListenError}, - if it cannot listen on this port (e.g., it - cannot bind to the required port number) - """ - - def connectTCP(host, port, factory, timeout=30, bindAddress=None): - """Connect a TCP client. - - @param host: a host name - - @param port: a port number - - @param factory: a L{twisted.internet.protocol.ClientFactory} instance - - @param timeout: number of seconds to wait before assuming the - connection has failed. - - @param bindAddress: a (host, port) tuple of local address to bind - to, or None. - - @return: An object which provides L{IConnector}. This connector will - call various callbacks on the factory when a connection is - made, failed, or lost - see - L{ClientFactory} - docs for details. - """ - -class IReactorSSL(Interface): - - def connectSSL(host, port, factory, contextFactory, timeout=30, bindAddress=None): - """Connect a client Protocol to a remote SSL socket. - - @param host: a host name - - @param port: a port number - - @param factory: a L{twisted.internet.protocol.ClientFactory} instance - - @param contextFactory: a L{twisted.internet.ssl.ClientContextFactory} object. - - @param timeout: number of seconds to wait before assuming the - connection has failed. - - @param bindAddress: a (host, port) tuple of local address to bind to, - or C{None}. - - @return: An object which provides L{IConnector}. - """ - - def listenSSL(port, factory, contextFactory, backlog=50, interface=''): - """ - Connects a given protocol factory to the given numeric TCP/IP port. - The connection is a SSL one, using contexts created by the context - factory. - - @param port: a port number on which to listen - - @param factory: a L{twisted.internet.protocol.ServerFactory} instance - - @param contextFactory: a L{twisted.internet.ssl.ContextFactory} instance - - @param backlog: size of the listen queue - - @param interface: the hostname to bind to, defaults to '' (all) - """ - - -class IReactorUNIX(Interface): - """UNIX socket methods.""" - - def connectUNIX(address, factory, timeout=30, checkPID=0): - """Connect a client protocol to a UNIX socket. - - @param address: a path to a unix socket on the filesystem. - - @param factory: a L{twisted.internet.protocol.ClientFactory} instance - - @param timeout: number of seconds to wait before assuming the connection - has failed. - - @param checkPID: if True, check for a pid file to verify that a server - is listening. - - @return: An object which provides L{IConnector}. - """ - - def listenUNIX(address, factory, backlog=50, mode=0666, wantPID=0): - """Listen on a UNIX socket. - - @param address: a path to a unix socket on the filesystem. - - @param factory: a L{twisted.internet.protocol.Factory} instance. - - @param backlog: number of connections to allow in backlog. - - @param mode: mode to set on the unix socket. - - @param wantPID: if True, create a pidfile for the socket. - - @return: An object which provides L{IListeningPort}. - """ - - -class IReactorUNIXDatagram(Interface): - """datagram UNIX socket methods.""" - - def connectUNIXDatagram(address, protocol, maxPacketSize=8192, mode=0666, bindAddress=None): - """Connect a client protocol to a datagram UNIX socket. - - @param address: a path to a unix socket on the filesystem. - - @param protocol: a L{twisted.internet.protocol.ConnectedDatagramProtocol} instance - - @param maxPacketSize: maximum packet size to accept - - @param mode: mode to set on the unix socket. - - @param bindAddress: address to bind to - - @return: An object which provides L{IConnector}. - """ - - def listenUNIXDatagram(address, protocol, maxPacketSize=8192, mode=0666): - """Listen on a datagram UNIX socket. - - @param address: a path to a unix socket on the filesystem. - - @param protocol: a L{twisted.internet.protocol.DatagramProtocol} instance. - - @param maxPacketSize: maximum packet size to accept - - @param mode: mode to set on the unix socket. - - @return: An object which provides L{IListeningPort}. - """ - - -class IReactorUDP(Interface): - """UDP socket methods. - - IMPORTANT: This is an experimental new interface. It may change - without backwards compatability. Suggestions are welcome. - """ - - def listenUDP(port, protocol, interface='', maxPacketSize=8192): - """Connects a given DatagramProtocol to the given numeric UDP port. - - @return: object which provides L{IListeningPort}. - """ - - def connectUDP(remotehost, remoteport, protocol, localport=0, - interface='', maxPacketSize=8192): - """DEPRECATED. - - Connects a L{twisted.internet.protocol.ConnectedDatagramProtocol} - instance to a UDP port. - """ - - -class IReactorMulticast(Interface): - """UDP socket methods that support multicast. - - IMPORTANT: This is an experimental new interface. It may change - without backwards compatability. Suggestions are welcome. - """ - - def listenMulticast(port, protocol, interface='', maxPacketSize=8192, - listenMultiple=False): - """ - Connects a given - L{DatagramProtocol} to the - given numeric UDP port. - - @param listenMultiple: boolean indicating whether multiple sockets can - bind to same UDP port. - - @returns: An object which provides L{IListeningPort}. - """ - - -class IReactorProcess(Interface): - - def spawnProcess(processProtocol, executable, args=(), env={}, path=None, - uid=None, gid=None, usePTY=0, childFDs=None): - """ - Spawn a process, with a process protocol. - - @type processProtocol: L{IProcessProtocol} provider - @param processProtocol: An object which will be notified of all - events related to the created process. - - @param executable: the file name to spawn - the full path should be - used. - - @param args: the command line arguments to pass to the process; a - sequence of strings. The first string should be the - executable's name. - - @param env: the environment variables to pass to the processs; a - dictionary of strings. If 'None', use os.environ. - - @param path: the path to run the subprocess in - defaults to the - current directory. - - @param uid: user ID to run the subprocess as. (Only available on - POSIX systems.) - - @param gid: group ID to run the subprocess as. (Only available on - POSIX systems.) - - @param usePTY: if true, run this process in a pseudo-terminal. - optionally a tuple of (masterfd, slavefd, ttyname), - in which case use those file descriptors. - (Not available on all systems.) - - @param childFDs: A dictionary mapping file descriptors in the new child - process to an integer or to the string 'r' or 'w'. - - If the value is an integer, it specifies a file - descriptor in the parent process which will be mapped - to a file descriptor (specified by the key) in the - child process. This is useful for things like inetd - and shell-like file redirection. - - If it is the string 'r', a pipe will be created and - attached to the child at that file descriptor: the - child will be able to write to that file descriptor - and the parent will receive read notification via the - L{IProcessProtocol.childDataReceived} callback. This - is useful for the child's stdout and stderr. - - If it is the string 'w', similar setup to the previous - case will occur, with the pipe being readable by the - child instead of writeable. The parent process can - write to that file descriptor using - L{IProcessTransport.writeToChild}. This is useful for - the child's stdin. - - If childFDs is not passed, the default behaviour is to - use a mapping that opens the usual stdin/stdout/stderr - pipes. - - @see: L{twisted.internet.protocol.ProcessProtocol} - - @return: An object which provides L{IProcessTransport}. - - @raise OSError: Raised with errno EAGAIN or ENOMEM if there are - insufficient system resources to create a new process. - """ - -class IReactorTime(Interface): - """ - Time methods that a Reactor should implement. - """ - - def seconds(): - """ - Get the current time in seconds. - - @return: A number-like object of some sort. - """ - - - def callLater(delay, callable, *args, **kw): - """ - Call a function later. - - @type delay: C{float} - @param delay: the number of seconds to wait. - - @param callable: the callable object to call later. - - @param args: the arguments to call it with. - - @param kw: the keyword arguments to call it with. - - @return: An object which provides L{IDelayedCall} and can be used to - cancel the scheduled call, by calling its C{cancel()} method. - It also may be rescheduled by calling its C{delay()} or - C{reset()} methods. - """ - - def cancelCallLater(callID): - """ - This method is deprecated. - - Cancel a call that would happen later. - - @param callID: this is an opaque identifier returned from C{callLater} - that will be used to cancel a specific call. - - @raise ValueError: if the callID is not recognized. - """ - - def getDelayedCalls(): - """ - Retrieve all currently scheduled delayed calls. - - @return: A tuple of all L{IDelayedCall} providers representing all - currently scheduled calls. This is everything that has been - returned by C{callLater} but not yet called or canceled. - """ - - -class IDelayedCall(Interface): - """ - A scheduled call. - - There are probably other useful methods we can add to this interface; - suggestions are welcome. - """ - - def getTime(): - """ - Get time when delayed call will happen. - - @return: time in seconds since epoch (a float). - """ - - def cancel(): - """ - Cancel the scheduled call. - - @raises twisted.internet.error.AlreadyCalled: if the call has already - happened. - @raises twisted.internet.error.AlreadyCancelled: if the call has already - been cancelled. - """ - - def delay(secondsLater): - """ - Delay the scheduled call. - - @param secondsLater: how many seconds from its current firing time to delay - - @raises twisted.internet.error.AlreadyCalled: if the call has already - happened. - @raises twisted.internet.error.AlreadyCancelled: if the call has already - been cancelled. - """ - - def reset(secondsFromNow): - """ - Reset the scheduled call's timer. - - @param secondsFromNow: how many seconds from now it should fire, - equivalent to C{.cancel()} and then doing another - C{reactor.callLater(secondsLater, ...)} - - @raises twisted.internet.error.AlreadyCalled: if the call has already - happened. - @raises twisted.internet.error.AlreadyCancelled: if the call has already - been cancelled. - """ - - def active(): - """ - @return: True if this call is still active, False if it has been - called or cancelled. - """ - -class IReactorThreads(Interface): - """Dispatch methods to be run in threads. - - Internally, this should use a thread pool and dispatch methods to them. - """ - - def callInThread(callable, *args, **kwargs): - """Run the callable object in a separate thread. - """ - - def callFromThread(callable, *args, **kw): - """Cause a function to be executed by the reactor thread. - - Use this method when you want to run a function in the reactor's thread - from another thread. Calling callFromThread should wake up the main - thread (where reactor.run() is executing) and run the given callable in - that thread. - - Obviously, the callable must be thread safe. (If you want to call a - function in the next mainloop iteration, but you're in the same thread, - use callLater with a delay of 0.) - """ - - def suggestThreadPoolSize(size): - """ - Suggest the size of the internal threadpool used to dispatch functions - passed to L{callInThread}. - """ - - -class IReactorCore(Interface): - """Core methods that a Reactor must implement. - """ - - def resolve(name, timeout=10): - """Return a L{twisted.internet.defer.Deferred} that will resolve a hostname. - """ - - - def run(): - """Fire 'startup' System Events, move the reactor to the 'running' - state, then run the main loop until it is stopped with stop() or - crash(). - """ - - def stop(): - """Fire 'shutdown' System Events, which will move the reactor to the - 'stopped' state and cause reactor.run() to exit. """ - - def crash(): - """Stop the main loop *immediately*, without firing any system events. - - This is named as it is because this is an extremely "rude" thing to do; - it is possible to lose data and put your system in an inconsistent - state by calling this. However, it is necessary, as sometimes a system - can become wedged in a pre-shutdown call. - """ - - def iterate(delay=0): - """Run the main loop's I/O polling function for a period of time. - - This is most useful in applications where the UI is being drawn "as - fast as possible", such as games. All pending L{IDelayedCall}s will - be called. - - The reactor must have been started (via the run() method) prior to - any invocations of this method. It must also be stopped manually - after the last call to this method (via the stop() method). This - method is not re-entrant: you must not call it recursively; in - particular, you must not call it while the reactor is running. - """ - - def fireSystemEvent(eventType): - """Fire a system-wide event. - - System-wide events are things like 'startup', 'shutdown', and - 'persist'. - """ - - def addSystemEventTrigger(phase, eventType, callable, *args, **kw): - """Add a function to be called when a system event occurs. - - Each "system event" in Twisted, such as 'startup', 'shutdown', and - 'persist', has 3 phases: 'before', 'during', and 'after' (in that - order, of course). These events will be fired internally by the - Reactor. - - An implementor of this interface must only implement those events - described here. - - Callbacks registered for the "before" phase may return either None or a - Deferred. The "during" phase will not execute until all of the - Deferreds from the "before" phase have fired. - - Once the "during" phase is running, all of the remaining triggers must - execute; their return values must be ignored. - - @param phase: a time to call the event -- either the string 'before', - 'after', or 'during', describing when to call it - relative to the event's execution. - - @param eventType: this is a string describing the type of event. - - @param callable: the object to call before shutdown. - - @param args: the arguments to call it with. - - @param kw: the keyword arguments to call it with. - - @return: an ID that can be used to remove this call with - removeSystemEventTrigger. - """ - - def removeSystemEventTrigger(triggerID): - """Removes a trigger added with addSystemEventTrigger. - - @param triggerID: a value returned from addSystemEventTrigger. - - @raise KeyError: If there is no system event trigger for the given - C{triggerID}. - - @raise ValueError: If there is no system event trigger for the given - C{triggerID}. - - @raise TypeError: If there is no system event trigger for the given - C{triggerID}. - """ - - def callWhenRunning(callable, *args, **kw): - """Call a function when the reactor is running. - - If the reactor has not started, the callable will be scheduled - to run when it does start. Otherwise, the callable will be invoked - immediately. - - @param callable: the callable object to call later. - - @param args: the arguments to call it with. - - @param kw: the keyword arguments to call it with. - - @return: None if the callable was invoked, otherwise a system - event id for the scheduled call. - """ - - -class IReactorPluggableResolver(Interface): - """A reactor with a pluggable name resolver interface. - """ - def installResolver(resolver): - """Set the internal resolver to use to for name lookups. - - @type resolver: An object implementing the L{IResolverSimple} interface - @param resolver: The new resolver to use. - - @return: The previously installed resolver. - """ - - -class IReactorFDSet(Interface): - """ - Implement me to be able to use - L{FileDescriptor} type resources. - - This assumes that your main-loop uses UNIX-style numeric file descriptors - (or at least similarly opaque IDs returned from a .fileno() method) - """ - - def addReader(reader): - """I add reader to the set of file descriptors to get read events for. - - @param reader: An L{IReadDescriptor} provider that will be checked for - read events until it is removed from the reactor with - L{removeReader}. - - @return: C{None}. - """ - - def addWriter(writer): - """I add writer to the set of file descriptors to get write events for. - - @param writer: An L{IWriteDescriptor} provider that will be checked for - read events until it is removed from the reactor with - L{removeWriter}. - - @return: C{None}. - """ - - def removeReader(reader): - """Removes an object previously added with L{addReader}. - - @return: C{None}. - """ - - def removeWriter(writer): - """Removes an object previously added with L{addWriter}. - - @return: C{None}. - """ - - def removeAll(): - """Remove all readers and writers. - - Should not remove reactor internal reactor connections (like a waker). - - @return: A list of L{IReadDescriptor} and L{IWriteDescriptor} providers - which were removed. - """ - - - def getReaders(): - """ - Return the list of file descriptors currently monitored for input - events by the reactor. - - @return: the list of file descriptors monitored for input events. - @rtype: C{list} of C{IReadDescriptor} - """ - - - def getWriters(): - """ - Return the list file descriptors currently monitored for output events - by the reactor. - - @return: the list of file descriptors monitored for output events. - @rtype: C{list} of C{IWriteDescriptor} - """ - - - -class IListeningPort(Interface): - """A listening port. - """ - - def startListening(): - """Start listening on this port. - - @raise CannotListenError: If it cannot listen on this port (e.g., it is - a TCP port and it cannot bind to the required - port number). - """ - - def stopListening(): - """Stop listening on this port. - - If it does not complete immediately, will return Deferred that fires - upon completion. - """ - - def getHost(): - """Get the host that this port is listening for. - - @return: An L{IAddress} provider. - """ - - -class ILoggingContext(Interface): - """ - Give context information that will be used to log events generated by - this item. - """ - def logPrefix(): - """ - @return: Prefix used during log formatting to indicate context. - @rtype: C{str} - """ - - -class IFileDescriptor(ILoggingContext): - """ - A file descriptor. - """ - - def fileno(): - """ - @return: The platform-specified representation of a file-descriptor - number. - """ - - def connectionLost(reason): - """Called when the connection was lost. - - This is called when the connection on a selectable object has been - lost. It will be called whether the connection was closed explicitly, - an exception occurred in an event handler, or the other end of the - connection closed it first. - - See also L{IHalfCloseableDescriptor} if your descriptor wants to be - notified separately of the two halves of the connection being closed. - - @param reason: A failure instance indicating the reason why the - connection was lost. L{error.ConnectionLost} and - L{error.ConnectionDone} are of special note, but the - failure may be of other classes as well. - """ - -class IReadDescriptor(IFileDescriptor): - - def doRead(): - """Some data is available for reading on your descriptor. - """ - - -class IWriteDescriptor(IFileDescriptor): - - def doWrite(): - """Some data can be written to your descriptor. - """ - - -class IReadWriteDescriptor(IReadDescriptor, IWriteDescriptor): - """I am a L{FileDescriptor} that can both read and write. - """ - - -class IHalfCloseableDescriptor(Interface): - """A descriptor that can be half-closed.""" - - def writeConnectionLost(reason): - """Indicates write connection was lost.""" - - def readConnectionLost(reason): - """Indicates read connection was lost.""" - - -class ISystemHandle(Interface): - """An object that wraps a networking OS-specific handle.""" - - def getHandle(): - """Return a system- and reactor-specific handle. - - This might be a socket.socket() object, or some other type of - object, depending on which reactor is being used. Use and - manipulate at your own risk. - - This might be used in cases where you want to set specific - options not exposed by the Twisted APIs. - """ - - -class IConsumer(Interface): - """A consumer consumes data from a producer.""" - - def registerProducer(producer, streaming): - """ - Register to receive data from a producer. - - This sets self to be a consumer for a producer. When this object runs - out of data (as when a send(2) call on a socket succeeds in moving the - last data from a userspace buffer into a kernelspace buffer), it will - ask the producer to resumeProducing(). - - For L{IPullProducer} providers, C{resumeProducing} will be called once - each time data is required. - - For L{IPushProducer} providers, C{pauseProducing} will be called - whenever the write buffer fills up and C{resumeProducing} will only be - called when it empties. - - @type producer: L{IProducer} provider - - @type streaming: C{bool} - @param streaming: C{True} if C{producer} provides L{IPushProducer}, - C{False} if C{producer} provides L{IPullProducer}. - - @return: C{None} - """ - - def unregisterProducer(): - """Stop consuming data from a producer, without disconnecting. - """ - - def write(data): - """The producer will write data by calling this method.""" - -class IFinishableConsumer(IConsumer): - """A Consumer for producers that finish. - """ - def finish(): - """The producer has finished producing.""" - -class IProducer(Interface): - """A producer produces data for a consumer. - - Typically producing is done by calling the write method of an class - implementing L{IConsumer}. - """ - - def stopProducing(): - """Stop producing data. - - This tells a producer that its consumer has died, so it must stop - producing data for good. - """ - - -class IPushProducer(IProducer): - """ - A push producer, also known as a streaming producer is expected to - produce (write to this consumer) data on a continous basis, unless - it has been paused. A paused push producer will resume producing - after its resumeProducing() method is called. For a push producer - which is not pauseable, these functions may be noops. - """ - - def pauseProducing(): - """Pause producing data. - - Tells a producer that it has produced too much data to process for - the time being, and to stop until resumeProducing() is called. - """ - def resumeProducing(): - """Resume producing data. - - This tells a producer to re-add itself to the main loop and produce - more data for its consumer. - """ - -class IPullProducer(IProducer): - """ - A pull producer, also known as a non-streaming producer, is - expected to produce data each time resumeProducing() is called. - """ - - def resumeProducing(): - """Produce data for the consumer a single time. - - This tells a producer to produce data for the consumer once - (not repeatedly, once only). Typically this will be done - by calling the consumer's write() method a single time with - produced data. - """ - -class IProtocol(Interface): - - def dataReceived(data): - """Called whenever data is received. - - Use this method to translate to a higher-level message. Usually, some - callback will be made upon the receipt of each complete protocol - message. - - @param data: a string of indeterminate length. Please keep in mind - that you will probably need to buffer some data, as partial - (or multiple) protocol messages may be received! I recommend - that unit tests for protocols call through to this method with - differing chunk sizes, down to one byte at a time. - """ - - def connectionLost(reason): - """Called when the connection is shut down. - - Clear any circular references here, and any external references - to this Protocol. The connection has been closed. The C{reason} - Failure wraps a L{twisted.internet.error.ConnectionDone} or - L{twisted.internet.error.ConnectionLost} instance (or a subclass - of one of those). - - @type reason: L{twisted.python.failure.Failure} - """ - - def makeConnection(transport): - """Make a connection to a transport and a server. - """ - - def connectionMade(): - """Called when a connection is made. - - This may be considered the initializer of the protocol, because - it is called when the connection is completed. For clients, - this is called once the connection to the server has been - established; for servers, this is called after an accept() call - stops blocking and a socket has been received. If you need to - send any greeting or initial message, do it here. - """ - - -class IProcessProtocol(Interface): - """ - Interface for process-related event handlers. - """ - - def makeConnection(process): - """ - Called when the process has been created. - - @type process: L{IProcessTransport} provider - @param process: An object representing the process which has been - created and associated with this protocol. - """ - - - def childDataReceived(childFD, data): - """ - Called when data arrives from the child process. - - @type childFD: C{int} - @param childFD: The file descriptor from which the data was - received. - - @type data: C{str} - @param data: The data read from the child's file descriptor. - """ - - - def childConnectionLost(childFD): - """ - Called when a file descriptor associated with the child process is - closed. - - @type childFD: C{int} - @param childFD: The file descriptor which was closed. - """ - - - def processEnded(reason): - """ - Called when the child process exits. - - @type reason: L{twisted.python.failure.Failure} - @param reason: A failure giving the reason the child process - terminated. The type of exception for this failure is either - L{twisted.internet.error.ProcessDone} or - L{twisted.internet.error.ProcessTerminated}. - """ - - - -class IHalfCloseableProtocol(Interface): - """Implemented to indicate they want notification of half-closes. - - TCP supports the notion of half-closing the connection, e.g. - closing the write side but still not stopping reading. A protocol - that implements this interface will be notified of such events, - instead of having connectionLost called. - """ - - def readConnectionLost(): - """Notification of the read connection being closed. - - This indicates peer did half-close of write side. It is now - the responsiblity of the this protocol to call - loseConnection(). In addition, the protocol MUST make sure a - reference to it still exists (i.e. by doing a callLater with - one of its methods, etc.) as the reactor will only have a - reference to it if it is writing. - - If the protocol does not do so, it might get garbage collected - without the connectionLost method ever being called. - """ - - def writeConnectionLost(): - """Notification of the write connection being closed. - - This will never be called for TCP connections as TCP does not - support notification of this type of half-close. - """ - - -class IProtocolFactory(Interface): - """Interface for protocol factories. - """ - - def buildProtocol(addr): - """Called when a connection has been established to addr. - - If None is returned, the connection is assumed to have been refused, - and the Port will close the connection. - - @type addr: (host, port) - @param addr: The address of the newly-established connection - - @return: None if the connection was refused, otherwise an object - providing L{IProtocol}. - """ - - def doStart(): - """Called every time this is connected to a Port or Connector.""" - - def doStop(): - """Called every time this is unconnected from a Port or Connector.""" - - -class ITransport(Interface): - """I am a transport for bytes. - - I represent (and wrap) the physical connection and synchronicity - of the framework which is talking to the network. I make no - representations about whether calls to me will happen immediately - or require returning to a control loop, or whether they will happen - in the same or another thread. Consider methods of this class - (aside from getPeer) to be 'thrown over the wall', to happen at some - indeterminate time. - """ - - def write(data): - """Write some data to the physical connection, in sequence, in a - non-blocking fashion. - - If possible, make sure that it is all written. No data will - ever be lost, although (obviously) the connection may be closed - before it all gets through. - """ - - def writeSequence(data): - """Write a list of strings to the physical connection. - - If possible, make sure that all of the data is written to - the socket at once, without first copying it all into a - single string. - """ - - def loseConnection(): - """Close my connection, after writing all pending data. - - Note that if there is a registered producer on a transport it - will not be closed until the producer has been unregistered. - """ - - def getPeer(): - """Get the remote address of this connection. - - Treat this method with caution. It is the unfortunate result of the - CGI and Jabber standards, but should not be considered reliable for - the usual host of reasons; port forwarding, proxying, firewalls, IP - masquerading, etc. - - @return: An L{IAddress} provider. - """ - - def getHost(): - """ - Similar to getPeer, but returns an address describing this side of the - connection. - - @return: An L{IAddress} provider. - """ - - -class ITCPTransport(ITransport): - """A TCP based transport.""" - - def loseWriteConnection(): - """Half-close the write side of a TCP connection. - - If the protocol instance this is attached to provides - IHalfCloseableProtocol, it will get notified when the operation is - done. When closing write connection, as with loseConnection this will - only happen when buffer has emptied and there is no registered - producer. - """ - - def getTcpNoDelay(): - """Return if TCP_NODELAY is enabled.""" - - def setTcpNoDelay(enabled): - """Enable/disable TCP_NODELAY. - - Enabling TCP_NODELAY turns off Nagle's algorithm. Small packets are - sent sooner, possibly at the expense of overall throughput.""" - - def getTcpKeepAlive(): - """Return if SO_KEEPALIVE enabled.""" - - def setTcpKeepAlive(enabled): - """Enable/disable SO_KEEPALIVE. - - Enabling SO_KEEPALIVE sends packets periodically when the connection - is otherwise idle, usually once every two hours. They are intended - to allow detection of lost peers in a non-infinite amount of time.""" - - def getHost(): - """Returns L{IPv4Address}.""" - - def getPeer(): - """Returns L{IPv4Address}.""" - - -class ITLSTransport(ITCPTransport): - """A TCP transport that supports switching to TLS midstream. - - Once TLS mode is started the transport will implement L{ISSLTransport}. - """ - - def startTLS(contextFactory): - """Initiate TLS negotiation. - - @param contextFactory: A context factory (see L{ssl.py}) - """ - -class ISSLTransport(ITCPTransport): - """A SSL/TLS based transport.""" - - def getPeerCertificate(): - """Return an object with the peer's certificate info.""" - - -class IProcessTransport(ITransport): - """A process transport. - - @ivar pid: The Process-ID of this process. - """ - - def closeStdin(): - """Close stdin after all data has been written out.""" - - def closeStdout(): - """Close stdout.""" - - def closeStderr(): - """Close stderr.""" - - def closeChildFD(descriptor): - """ - Close a file descriptor which is connected to the child process, identified - by its FD in the child process. - """ - - def writeToChild(childFD, data): - """ - Similar to L{ITransport.write} but also allows the file descriptor in - the child process which will receive the bytes to be specified. - - This is not available on all platforms. - - @type childFD: C{int} - @param childFD: The file descriptor to which to write. - - @type data: C{str} - @param data: The bytes to write. - - @return: C{None} - """ - - def loseConnection(): - """Close stdin, stderr and stdout.""" - - def signalProcess(signalID): - """Send a signal to the process. - - @param signalID: can be - - one of C{\"HUP\"}, C{\"KILL\"}, C{\"STOP\"}, or C{\"INT\"}. - These will be implemented in a - cross-platform manner, and so should be used - if possible. - - an integer, where it represents a POSIX - signal ID. - - @raise twisted.internet.error.ProcessExitedAlready: The process has - already exited. - """ - - -class IServiceCollection(Interface): - """An object which provides access to a collection of services.""" - - def getServiceNamed(serviceName): - """Retrieve the named service from this application. - - Raise a KeyError if there is no such service name. - """ - - def addService(service): - """Add a service to this collection. - """ - - def removeService(service): - """Remove a service from this collection.""" - - -class IUDPTransport(Interface): - """Transport for UDP DatagramProtocols.""" - - def write(packet, addr=None): - """Write packet to given address. - - @param addr: a tuple of (ip, port). For connected transports must - be the address the transport is connected to, or None. - In non-connected mode this is mandatory. - - @raise twisted.internet.error.MessageLengthError: C{packet} was too - long. - """ - - def connect(host, port): - """Connect the transport to an address. - - This changes it to connected mode. Datagrams can only be sent to - this address, and will only be received from this address. In addition - the protocol's connectionRefused method might get called if destination - is not receiving datagrams. - - @param host: an IP address, not a domain name ('127.0.0.1', not 'localhost') - @param port: port to connect to. - """ - - def getHost(): - """Returns IPv4Address.""" - - def stopListening(): - """Stop listening on this port. - - If it does not complete immediately, will return Deferred that fires - upon completion. - """ - - -class IUDPConnectedTransport(Interface): - """DEPRECATED. Transport for UDP ConnectedPacketProtocols.""" - - def write(packet): - """Write packet to address we are connected to.""" - - def getHost(): - """Returns UNIXAddress.""" - - -class IUNIXDatagramTransport(Interface): - """Transport for UDP PacketProtocols.""" - - def write(packet, address): - """Write packet to given address.""" - - def getHost(): - """Returns UNIXAddress.""" - - -class IUNIXDatagramConnectedTransport(Interface): - """Transport for UDP ConnectedPacketProtocols.""" - - def write(packet): - """Write packet to address we are connected to.""" - - def getHost(): - """Returns UNIXAddress.""" - - def getPeer(): - """Returns UNIXAddress.""" - - -class IMulticastTransport(Interface): - """Additional functionality for multicast UDP.""" - - def getOutgoingInterface(): - """Return interface of outgoing multicast packets.""" - - def setOutgoingInterface(addr): - """Set interface for outgoing multicast packets. - - Returns Deferred of success. - """ - - def getLoopbackMode(): - """Return if loopback mode is enabled.""" - - def setLoopbackMode(mode): - """Set if loopback mode is enabled.""" - - def getTTL(): - """Get time to live for multicast packets.""" - - def setTTL(ttl): - """Set time to live on multicast packets.""" - - def joinGroup(addr, interface=""): - """Join a multicast group. Returns Deferred of success or failure. - - If an error occurs, the returned Deferred will fail with - L{error.MulticastJoinError}. - """ - - def leaveGroup(addr, interface=""): - """Leave multicast group, return Deferred of success.""" diff --git a/tools/buildbot/pylibs/twisted/internet/iocpreactor/__init__.py b/tools/buildbot/pylibs/twisted/internet/iocpreactor/__init__.py deleted file mode 100644 index d0c595d..0000000 --- a/tools/buildbot/pylibs/twisted/internet/iocpreactor/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from twisted.internet.iocpreactor.reactor import install - diff --git a/tools/buildbot/pylibs/twisted/internet/iocpreactor/abstract.py b/tools/buildbot/pylibs/twisted/internet/iocpreactor/abstract.py deleted file mode 100644 index c1838a5..0000000 --- a/tools/buildbot/pylibs/twisted/internet/iocpreactor/abstract.py +++ /dev/null @@ -1,456 +0,0 @@ -# Copyright (c) 2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Abstract file handle class -""" - -from twisted.internet import main, error, interfaces -from twisted.python import log, failure -from twisted.persisted import styles - -from zope.interface import implements -import errno - -from twisted.internet.iocpreactor.const import ERROR_HANDLE_EOF -from twisted.internet.iocpreactor.const import ERROR_IO_PENDING -from twisted.internet.iocpreactor import iocpsupport as _iocp - - - -class FileHandle(log.Logger, styles.Ephemeral, object): - """ - File handle that can read and write asynchronously - """ - implements(interfaces.IProducer, interfaces.IConsumer, - interfaces.ITransport, interfaces.IHalfCloseableDescriptor) - # read stuff - maxReadBuffers = 16 - readBufferSize = 4096 - reading = False - dynamicReadBuffers = True # set this to false if subclass doesn't do iovecs - _readNextBuffer = 0 - _readSize = 0 # how much data we have in the read buffer - _readScheduled = None - _readScheduledInOS = False - - - def startReading(self): - self.reactor.addActiveHandle(self) - if not self._readScheduled and not self.reading: - self.reading = True - self._readScheduled = self.reactor.callLater(0, - self._resumeReading) - - - def stopReading(self): - if self._readScheduled: - self._readScheduled.cancel() - self._readScheduled = None - self.reading = False - - - def _resumeReading(self): - self._readScheduled = None - if self._dispatchData() and not self._readScheduledInOS: - self.doRead() - - - def _dispatchData(self): - """ - Dispatch previously read data. Return True if self.reading and we don't - have any more data - """ - if not self._readSize: - return self.reading - size = self._readSize - full_buffers = size // self.readBufferSize - while self._readNextBuffer < full_buffers: - self.dataReceived(self._readBuffers[self._readNextBuffer]) - self._readNextBuffer += 1 - if not self.reading: - return False - remainder = size % self.readBufferSize - if remainder: - self.dataReceived(buffer(self._readBuffers[full_buffers], - 0, remainder)) - if self.dynamicReadBuffers: - total_buffer_size = self.readBufferSize * len(self._readBuffers) - # we have one buffer too many - if size < total_buffer_size - self.readBufferSize: - del self._readBuffers[-1] - # we filled all buffers, so allocate one more - elif (size == total_buffer_size and - len(self._readBuffers) < self.maxReadBuffers): - self._readBuffers.append(_iocp.AllocateReadBuffer( - self.readBufferSize)) - self._readNextBuffer = 0 - self._readSize = 0 - return self.reading - - - def _cbRead(self, rc, bytes, evt): - self._readScheduledInOS = False - if self._handleRead(rc, bytes, evt): - self.doRead() - - - def _handleRead(self, rc, bytes, evt): - """ - Returns False if we should stop reading for now - """ - if self.disconnected: - return False - # graceful disconnection - if (not (rc or bytes)) or rc in (errno.WSAEDISCON, ERROR_HANDLE_EOF): - self.reactor.removeActiveHandle(self) - self.readConnectionLost(failure.Failure(main.CONNECTION_DONE)) - return False - # XXX: not handling WSAEWOULDBLOCK - # ("too many outstanding overlapped I/O requests") - elif rc: - self.connectionLost(failure.Failure( - error.ConnectionLost("read error -- %s (%s)" % - (errno.errorcode.get(rc, 'unknown'), rc)))) - return False - else: - assert self._readSize == 0 - assert self._readNextBuffer == 0 - self._readSize = bytes - return self._dispatchData() - - - def doRead(self): - numReads = 0 - while 1: - evt = _iocp.Event(self._cbRead, self) - - evt.buff = buff = self._readBuffers - rc, bytes = self.readFromHandle(buff, evt) - - if (rc == ERROR_IO_PENDING - or (not rc and numReads >= self.maxReads)): - self._readScheduledInOS = True - break - else: - evt.ignore = True - if not self._handleRead(rc, bytes, evt): - break - numReads += 1 - - - def readFromHandle(self, bufflist, evt): - raise NotImplementedError() # TODO: this should default to ReadFile - - - def dataReceived(self, data): - raise NotImplementedError - - - def readConnectionLost(self, reason): - self.connectionLost(reason) - - - # write stuff - dataBuffer = '' - offset = 0 - writing = False - _writeScheduled = None - _writeDisconnecting = False - _writeDisconnected = False - writeBufferSize = 2**2**2**2 - maxWrites = 5 - - - def loseWriteConnection(self): - self._writeDisconnecting = True - self.startWriting() - - - def _closeWriteConnection(self): - # override in subclasses - pass - - - def writeConnectionLost(self, reason): - # in current code should never be called - self.connectionLost(reason) - - - def startWriting(self): - self.reactor.addActiveHandle(self) - self.writing = True - if not self._writeScheduled: - self._writeScheduled = self.reactor.callLater(0, - self._resumeWriting) - - - def stopWriting(self): - if self._writeScheduled: - self._writeScheduled.cancel() - self._writeScheduled = None - self.writing = False - - - def _resumeWriting(self): - self._writeScheduled = None - self.doWrite() - - - def _cbWrite(self, rc, bytes, evt): - if self._handleWrite(rc, bytes, evt): - self.doWrite() - - - def _handleWrite(self, rc, bytes, evt): - """ - Returns false if we should stop writing for now - """ - if self.disconnected or self._writeDisconnected: - return False - # XXX: not handling WSAEWOULDBLOCK - # ("too many outstanding overlapped I/O requests") - if rc: - self.connectionLost(failure.Failure( - error.ConnectionLost("write error -- %s (%s)" % - (errno.errorcode.get(rc, 'unknown'), rc)))) - return False - else: - self.offset += bytes - # If there is nothing left to send, - if self.offset == len(self.dataBuffer) and not self._tempDataLen: - self.dataBuffer = "" - self.offset = 0 - # stop writing - self.stopWriting() - # If I've got a producer who is supposed to supply me with data - if self.producer is not None and ((not self.streamingProducer) - or self.producerPaused): - # tell them to supply some more. - self.producerPaused = True - self.producer.resumeProducing() - elif self.disconnecting: - # But if I was previously asked to let the connection die, - # do so. - self.connectionLost(failure.Failure(main.CONNECTION_DONE)) - elif self._writeDisconnecting: - # I was previously asked to to half-close the connection. - self._closeWriteConnection() - self._writeDisconnected = True - return False - else: - return True - - - def doWrite(self): - numWrites = 0 - while 1: - if len(self.dataBuffer) - self.offset < self.SEND_LIMIT: - # If there is currently less than SEND_LIMIT bytes left to send - # in the string, extend it with the array data. - self.dataBuffer = (buffer(self.dataBuffer, self.offset) + - "".join(self._tempDataBuffer)) - self.offset = 0 - self._tempDataBuffer = [] - self._tempDataLen = 0 - - evt = _iocp.Event(self._cbWrite, self) - - # Send as much data as you can. - if self.offset: - evt.buff = buff = buffer(self.dataBuffer, self.offset) - else: - evt.buff = buff = self.dataBuffer - rc, bytes = self.writeToHandle(buff, evt) - if (rc == ERROR_IO_PENDING - or (not rc and numWrites >= self.maxWrites)): - break - else: - evt.ignore = True - if not self._handleWrite(rc, bytes, evt): - break - numWrites += 1 - - - def writeToHandle(self, buff, evt): - raise NotImplementedError() # TODO: this should default to WriteFile - - - def write(self, data): - """Reliably write some data. - - The data is buffered until his file descriptor is ready for writing. - """ - if isinstance(data, unicode): # no, really, I mean it - raise TypeError("Data must not be unicode") - if not self.connected or self._writeDisconnected: - return - if data: - self._tempDataBuffer.append(data) - self._tempDataLen += len(data) - if self.producer is not None: - if (len(self.dataBuffer) + self._tempDataLen - > self.writeBufferSize): - self.producerPaused = True - self.producer.pauseProducing() - self.startWriting() - - - def writeSequence(self, iovec): - if not self.connected or not iovec or self._writeDisconnected: - return - self._tempDataBuffer.extend(iovec) - for i in iovec: - self._tempDataLen += len(i) - if self.producer is not None: - if len(self.dataBuffer) + self._tempDataLen > self.writeBufferSize: - self.producerPaused = True - self.producer.pauseProducing() - self.startWriting() - - - # general stuff - connected = False - disconnected = False - disconnecting = False - logstr = "Uninitialized" - - SEND_LIMIT = 128*1024 - - maxReads = 5 - - - def __init__(self, reactor = None): - if not reactor: - from twisted.internet import reactor - self.reactor = reactor - self._tempDataBuffer = [] # will be added to dataBuffer in doWrite - self._tempDataLen = 0 - self._readBuffers = [_iocp.AllocateReadBuffer(self.readBufferSize)] - - - def connectionLost(self, reason): - """ - The connection was lost. - - This is called when the connection on a selectable object has been - lost. It will be called whether the connection was closed explicitly, - an exception occurred in an event handler, or the other end of the - connection closed it first. - - Clean up state here, but make sure to call back up to FileDescriptor. - """ - - self.disconnected = True - self.connected = False - if self.producer is not None: - self.producer.stopProducing() - self.producer = None - self.stopReading() - self.stopWriting() - self.reactor.removeActiveHandle(self) - - - def getFileHandle(self): - return -1 - - - def loseConnection(self, _connDone=failure.Failure(main.CONNECTION_DONE)): - """ - Close the connection at the next available opportunity. - - Call this to cause this FileDescriptor to lose its connection. It will - first write any data that it has buffered. - - If there is data buffered yet to be written, this method will cause the - transport to lose its connection as soon as it's done flushing its - write buffer. If you have a producer registered, the connection won't - be closed until the producer is finished. Therefore, make sure you - unregister your producer when it's finished, or the connection will - never close. - """ - - if self.connected and not self.disconnecting: - if self._writeDisconnected: - # doWrite won't trigger the connection close anymore - self.stopReading() - self.stopWriting - self.connectionLost(_connDone) - else: - self.stopReading() - self.startWriting() - self.disconnecting = 1 - - - # Producer/consumer implementation - - producerPaused = False - streamingProducer = False - - # first, the consumer stuff. This requires no additional work, as - # any object you can write to can be a consumer, really. - - producer = None - - - def registerProducer(self, producer, streaming): - """ - Register to receive data from a producer. - - This sets this selectable to be a consumer for a producer. When this - selectable runs out of data on a write() call, it will ask the producer - to resumeProducing(). A producer should implement the IProducer - interface. - - FileDescriptor provides some infrastructure for producer methods. - """ - if self.producer is not None: - raise RuntimeError( - "Cannot register producer %s, because producer " - "%s was never unregistered." % (producer, self.producer)) - if self.disconnected: - producer.stopProducing() - else: - self.producer = producer - self.streamingProducer = streaming - if not streaming: - producer.resumeProducing() - - - def unregisterProducer(self): - """ - Stop consuming data from a producer, without disconnecting. - """ - self.producer = None - - - def stopConsuming(self): - """ - Stop consuming data. - - This is called when a producer has lost its connection, to tell the - consumer to go lose its connection (and break potential circular - references). - """ - self.unregisterProducer() - self.loseConnection() - - - # producer interface implementation - - def resumeProducing(self): - assert self.connected and not self.disconnecting - self.startReading() - - - def pauseProducing(self): - self.stopReading() - - - def stopProducing(self): - self.loseConnection() - - -__all__ = ['FileHandle'] - diff --git a/tools/buildbot/pylibs/twisted/internet/iocpreactor/build.bat b/tools/buildbot/pylibs/twisted/internet/iocpreactor/build.bat deleted file mode 100644 index 25f361b..0000000 --- a/tools/buildbot/pylibs/twisted/internet/iocpreactor/build.bat +++ /dev/null @@ -1,4 +0,0 @@ -del iocpsupport\iocpsupport.c iocpsupport.pyd -del /f /s /q build -python setup.py build_ext -i -c mingw32 - diff --git a/tools/buildbot/pylibs/twisted/internet/iocpreactor/const.py b/tools/buildbot/pylibs/twisted/internet/iocpreactor/const.py deleted file mode 100644 index edc09f2..0000000 --- a/tools/buildbot/pylibs/twisted/internet/iocpreactor/const.py +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright (c) 2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Windows constants for IOCP -""" - - -# this stuff should really be gotten from Windows headers via pyrex, but it -# probably is not going to change - -ERROR_PORT_UNREACHABLE = 1234 -ERROR_NETWORK_UNREACHABLE = 1231 -ERROR_CONNECTION_REFUSED = 1225 -ERROR_IO_PENDING = 997 -ERROR_OPERATION_ABORTED = 995 -WAIT_TIMEOUT = 258 -ERROR_NETNAME_DELETED = 64 -ERROR_HANDLE_EOF = 38 - -INFINITE = -1 - -SO_UPDATE_CONNECT_CONTEXT = 0x7010 -SO_UPDATE_ACCEPT_CONTEXT = 0x700B - diff --git a/tools/buildbot/pylibs/twisted/internet/iocpreactor/interfaces.py b/tools/buildbot/pylibs/twisted/internet/iocpreactor/interfaces.py deleted file mode 100644 index 180f3cc..0000000 --- a/tools/buildbot/pylibs/twisted/internet/iocpreactor/interfaces.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (c) 2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Interfaces for iocpreactor -""" - - -from zope.interface import Interface - - - -class IReadHandle(Interface): - def readFromHandle(bufflist, evt): - """ - Read from this handle into the buffer list - """ - - - -class IWriteHandle(Interface): - def writeToHandle(buff, evt): - """ - Write the buffer to this handle - """ - - - -class IReadWriteHandle(IReadHandle, IWriteHandle): - pass - - diff --git a/tools/buildbot/pylibs/twisted/internet/iocpreactor/iocpsupport/acceptex.pxi b/tools/buildbot/pylibs/twisted/internet/iocpreactor/iocpsupport/acceptex.pxi deleted file mode 100644 index 8fd76ef..0000000 --- a/tools/buildbot/pylibs/twisted/internet/iocpreactor/iocpsupport/acceptex.pxi +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright (c) 2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -def accept(long listening, long accepting, object buff, object obj): - cdef unsigned long bytes - cdef int size, rc - cdef void *mem_buffer - cdef myOVERLAPPED *ov - - PyObject_AsWriteBuffer(buff, &mem_buffer, &size) - - ov = makeOV() - if obj is not None: - ov.obj = obj - - rc = lpAcceptEx(listening, accepting, mem_buffer, 0, size / 2, size / 2, - &bytes, ov) - if not rc: - rc = WSAGetLastError() - if rc != ERROR_IO_PENDING: - return rc - - # operation is in progress - Py_XINCREF(obj) - return rc - -def get_accept_addrs(long s, object buff): - cdef WSAPROTOCOL_INFO wsa_pi - cdef int size, locallen, remotelen - cdef void *mem_buffer - cdef sockaddr *localaddr, *remoteaddr - - PyObject_AsReadBuffer(buff, &mem_buffer, &size) - - lpGetAcceptExSockaddrs(mem_buffer, 0, size / 2, size / 2, &localaddr, &locallen, &remoteaddr, &remotelen) - return remoteaddr.sa_family, _makesockaddr(localaddr, locallen), _makesockaddr(remoteaddr, remotelen) - diff --git a/tools/buildbot/pylibs/twisted/internet/iocpreactor/iocpsupport/connectex.pxi b/tools/buildbot/pylibs/twisted/internet/iocpreactor/iocpsupport/connectex.pxi deleted file mode 100644 index 65f07434..0000000 --- a/tools/buildbot/pylibs/twisted/internet/iocpreactor/iocpsupport/connectex.pxi +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright (c) 2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -def connect(long s, object addr, object obj): - cdef int family, rc - cdef myOVERLAPPED *ov - cdef sockaddr name - - if not have_connectex: - raise ValueError, 'ConnectEx is not available on this system' - - family = getAddrFamily(s) - if family == AF_INET: - fillinetaddr(&name, addr) - else: - raise ValueError, 'unsupported address family' - name.sa_family = family - - ov = makeOV() - if obj is not None: - ov.obj = obj - - rc = lpConnectEx(s, &name, sizeof(name), NULL, 0, NULL, ov) - - if not rc: - rc = WSAGetLastError() - if rc != ERROR_IO_PENDING: - return rc - - # operation is in progress - Py_XINCREF(obj) - return rc - diff --git a/tools/buildbot/pylibs/twisted/internet/iocpreactor/iocpsupport/iocpsupport.c b/tools/buildbot/pylibs/twisted/internet/iocpreactor/iocpsupport/iocpsupport.c deleted file mode 100644 index f67e35c..0000000 --- a/tools/buildbot/pylibs/twisted/internet/iocpreactor/iocpsupport/iocpsupport.c +++ /dev/null @@ -1,2003 +0,0 @@ -/* Generated by Pyrex 0.9.6.4 on Tue Mar 18 10:18:51 2008 */ - -#define PY_SSIZE_T_CLEAN -#include "Python.h" -#include "structmember.h" -#ifndef PY_LONG_LONG - #define PY_LONG_LONG LONG_LONG -#endif -#if PY_VERSION_HEX < 0x02050000 - typedef int Py_ssize_t; - #define PY_SSIZE_T_MAX INT_MAX - #define PY_SSIZE_T_MIN INT_MIN - #define PyInt_FromSsize_t(z) PyInt_FromLong(z) - #define PyInt_AsSsize_t(o) PyInt_AsLong(o) -#endif -#ifndef WIN32 - #ifndef __stdcall - #define __stdcall - #endif - #ifndef __cdecl - #define __cdecl - #endif -#endif -#ifdef __cplusplus -#define __PYX_EXTERN_C extern "C" -#else -#define __PYX_EXTERN_C extern -#endif -#include -#include "io.h" -#include "errno.h" -#include "winsock2.h" -#include "windows.h" -#include "python.h" -#include "string.h" -#include "winsock_pointers.h" - - -typedef struct {PyObject **p; char *s;} __Pyx_InternTabEntry; /*proto*/ -typedef struct {PyObject **p; char *s; long n;} __Pyx_StringTabEntry; /*proto*/ - -static PyObject *__pyx_m; -static PyObject *__pyx_b; -static int __pyx_lineno; -static char *__pyx_filename; -static char **__pyx_f; - -static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name, char *modname); /*proto*/ - -static int __Pyx_GetStarArgs(PyObject **args, PyObject **kwds, char *kwd_list[], Py_ssize_t nargs, PyObject **args2, PyObject **kwds2, char rqd_kwds[]); /*proto*/ - -static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list); /*proto*/ - -static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name); /*proto*/ - -static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb); /*proto*/ - -static PyObject *__Pyx_UnpackItem(PyObject *); /*proto*/ -static int __Pyx_EndUnpack(PyObject *); /*proto*/ - -static int __Pyx_InternStrings(__Pyx_InternTabEntry *t); /*proto*/ - -static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); /*proto*/ - -static void __Pyx_AddTraceback(char *funcname); /*proto*/ - -/* Declarations from iocpsupport */ - -typedef int __pyx_t_11iocpsupport_size_t; - -typedef unsigned long __pyx_t_11iocpsupport_HANDLE; - -typedef unsigned long __pyx_t_11iocpsupport_SOCKET; - -typedef unsigned long __pyx_t_11iocpsupport_DWORD; - -typedef unsigned long __pyx_t_11iocpsupport_ULONG_PTR; - -typedef int __pyx_t_11iocpsupport_BOOL; - -struct __pyx_t_11iocpsupport_myOVERLAPPED { - OVERLAPPED ov; - struct PyObject *obj; -}; - -struct __pyx_obj_11iocpsupport_CompletionPort { - PyObject_HEAD - __pyx_t_11iocpsupport_HANDLE port; -}; - - -static PyTypeObject *__pyx_ptype_11iocpsupport_CompletionPort = 0; -static long __pyx_k2; -static unsigned long __pyx_k5; -static unsigned long __pyx_k6; -static unsigned long __pyx_k7; -static struct __pyx_t_11iocpsupport_myOVERLAPPED *__pyx_f_11iocpsupport_makeOV(void); /*proto*/ -static void __pyx_f_11iocpsupport_raise_error(int,PyObject *); /*proto*/ -static PyObject *__pyx_f_11iocpsupport__makesockaddr(struct sockaddr *,int); /*proto*/ -static PyObject *__pyx_f_11iocpsupport_fillinetaddr(struct sockaddr_in *,PyObject *); /*proto*/ -static int __pyx_f_11iocpsupport_getAddrFamily(__pyx_t_11iocpsupport_SOCKET); /*proto*/ - - -/* Implementation of iocpsupport */ - -static char __pyx_k4[] = "Failed to initialize Winsock function vectors"; - -static PyObject *__pyx_n_Event; -static PyObject *__pyx_n___init__; -static PyObject *__pyx_n_socket; -static PyObject *__pyx_n_ValueError; -static PyObject *__pyx_n_have_connectex; - -static PyObject *__pyx_k4p; - -static PyObject *__pyx_n_MemoryError; - -static struct __pyx_t_11iocpsupport_myOVERLAPPED *__pyx_f_11iocpsupport_makeOV(void) { - struct __pyx_t_11iocpsupport_myOVERLAPPED *__pyx_v_res; - struct __pyx_t_11iocpsupport_myOVERLAPPED *__pyx_r; - void *__pyx_1; - int __pyx_2; - PyObject *__pyx_3 = 0; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":110 */ - __pyx_1 = PyMem_Malloc((sizeof(struct __pyx_t_11iocpsupport_myOVERLAPPED))); if (__pyx_1 == NULL) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 110; goto __pyx_L1;} - __pyx_v_res = ((struct __pyx_t_11iocpsupport_myOVERLAPPED *)__pyx_1); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":111 */ - __pyx_2 = (!(__pyx_v_res != 0)); - if (__pyx_2) { - __pyx_3 = __Pyx_GetName(__pyx_b, __pyx_n_MemoryError); if (!__pyx_3) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 112; goto __pyx_L1;} - __Pyx_Raise(__pyx_3, 0, 0); - Py_DECREF(__pyx_3); __pyx_3 = 0; - {__pyx_filename = __pyx_f[0]; __pyx_lineno = 112; goto __pyx_L1;} - goto __pyx_L2; - } - __pyx_L2:; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":113 */ - memset(__pyx_v_res,0,(sizeof(struct __pyx_t_11iocpsupport_myOVERLAPPED))); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":114 */ - __pyx_r = __pyx_v_res; - goto __pyx_L0; - - __pyx_r = 0; - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_3); - __Pyx_AddTraceback("iocpsupport.makeOV"); - __pyx_r = NULL; - __pyx_L0:; - return __pyx_r; -} - -static PyObject *__pyx_n_WindowsError; - -static void __pyx_f_11iocpsupport_raise_error(int __pyx_v_err,PyObject *__pyx_v_message) { - int __pyx_1; - PyObject *__pyx_2 = 0; - PyObject *__pyx_3 = 0; - PyObject *__pyx_4 = 0; - Py_INCREF(__pyx_v_message); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":117 */ - __pyx_1 = (!__pyx_v_err); - if (__pyx_1) { - __pyx_v_err = GetLastError(); - goto __pyx_L2; - } - __pyx_L2:; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":119 */ - __pyx_2 = __Pyx_GetName(__pyx_b, __pyx_n_WindowsError); if (!__pyx_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 119; goto __pyx_L1;} - __pyx_3 = PyInt_FromLong(__pyx_v_err); if (!__pyx_3) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 119; goto __pyx_L1;} - __pyx_4 = PyTuple_New(2); if (!__pyx_4) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 119; goto __pyx_L1;} - Py_INCREF(__pyx_v_message); - PyTuple_SET_ITEM(__pyx_4, 0, __pyx_v_message); - PyTuple_SET_ITEM(__pyx_4, 1, __pyx_3); - __pyx_3 = 0; - __pyx_3 = PyObject_CallObject(__pyx_2, __pyx_4); if (!__pyx_3) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 119; goto __pyx_L1;} - Py_DECREF(__pyx_2); __pyx_2 = 0; - Py_DECREF(__pyx_4); __pyx_4 = 0; - __Pyx_Raise(__pyx_3, 0, 0); - Py_DECREF(__pyx_3); __pyx_3 = 0; - {__pyx_filename = __pyx_f[0]; __pyx_lineno = 119; goto __pyx_L1;} - - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_2); - Py_XDECREF(__pyx_3); - Py_XDECREF(__pyx_4); - __Pyx_AddTraceback("iocpsupport.raise_error"); - __pyx_L0:; - Py_DECREF(__pyx_v_message); -} - -static PyObject *__pyx_n_callback; -static PyObject *__pyx_n_owner; -static PyObject *__pyx_n_False; -static PyObject *__pyx_n_ignore; -static PyObject *__pyx_n_items; - -static PyObject *__pyx_f_11iocpsupport_5Event___init__(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static PyMethodDef __pyx_mdef_11iocpsupport_5Event___init__ = {"__init__", (PyCFunction)__pyx_f_11iocpsupport_5Event___init__, METH_VARARGS|METH_KEYWORDS, 0}; -static PyObject *__pyx_f_11iocpsupport_5Event___init__(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_v_self = 0; - PyObject *__pyx_v_callback = 0; - PyObject *__pyx_v_owner = 0; - PyObject *__pyx_v_kw = 0; - PyObject *__pyx_v_k; - PyObject *__pyx_v_v; - PyObject *__pyx_r; - PyObject *__pyx_1 = 0; - PyObject *__pyx_2 = 0; - PyObject *__pyx_3 = 0; - int __pyx_4; - static char *__pyx_argnames[] = {"self","callback","owner",0}; - if (__Pyx_GetStarArgs(&__pyx_args, &__pyx_kwds, __pyx_argnames, 3, 0, &__pyx_v_kw, 0) < 0) return 0; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "OOO", __pyx_argnames, &__pyx_v_self, &__pyx_v_callback, &__pyx_v_owner)) { - Py_XDECREF(__pyx_args); - Py_XDECREF(__pyx_kwds); - Py_XDECREF(__pyx_v_kw); - return 0; - } - Py_INCREF(__pyx_v_self); - Py_INCREF(__pyx_v_callback); - Py_INCREF(__pyx_v_owner); - __pyx_v_k = Py_None; Py_INCREF(Py_None); - __pyx_v_v = Py_None; Py_INCREF(Py_None); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":123 */ - if (PyObject_SetAttr(__pyx_v_self, __pyx_n_callback, __pyx_v_callback) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 123; goto __pyx_L1;} - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":124 */ - if (PyObject_SetAttr(__pyx_v_self, __pyx_n_owner, __pyx_v_owner) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 124; goto __pyx_L1;} - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":125 */ - __pyx_1 = __Pyx_GetName(__pyx_b, __pyx_n_False); if (!__pyx_1) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 125; goto __pyx_L1;} - if (PyObject_SetAttr(__pyx_v_self, __pyx_n_ignore, __pyx_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 125; goto __pyx_L1;} - Py_DECREF(__pyx_1); __pyx_1 = 0; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":126 */ - __pyx_1 = PyObject_GetAttr(__pyx_v_kw, __pyx_n_items); if (!__pyx_1) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 126; goto __pyx_L1;} - __pyx_2 = PyObject_CallObject(__pyx_1, 0); if (!__pyx_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 126; goto __pyx_L1;} - Py_DECREF(__pyx_1); __pyx_1 = 0; - __pyx_1 = PyObject_GetIter(__pyx_2); if (!__pyx_1) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 126; goto __pyx_L1;} - Py_DECREF(__pyx_2); __pyx_2 = 0; - for (;;) { - __pyx_2 = PyIter_Next(__pyx_1); - if (!__pyx_2) { - if (PyErr_Occurred()) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 126; goto __pyx_L1;} - break; - } - __pyx_3 = PyObject_GetIter(__pyx_2); if (!__pyx_3) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 126; goto __pyx_L1;} - Py_DECREF(__pyx_2); __pyx_2 = 0; - __pyx_2 = __Pyx_UnpackItem(__pyx_3); if (!__pyx_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 126; goto __pyx_L1;} - Py_DECREF(__pyx_v_k); - __pyx_v_k = __pyx_2; - __pyx_2 = 0; - __pyx_2 = __Pyx_UnpackItem(__pyx_3); if (!__pyx_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 126; goto __pyx_L1;} - Py_DECREF(__pyx_v_v); - __pyx_v_v = __pyx_2; - __pyx_2 = 0; - if (__Pyx_EndUnpack(__pyx_3) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 126; goto __pyx_L1;} - Py_DECREF(__pyx_3); __pyx_3 = 0; - __pyx_4 = PyObject_SetAttr(__pyx_v_self,__pyx_v_k,__pyx_v_v); if (__pyx_4 == -1) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 127; goto __pyx_L1;} - } - Py_DECREF(__pyx_1); __pyx_1 = 0; - - __pyx_r = Py_None; Py_INCREF(Py_None); - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_1); - Py_XDECREF(__pyx_2); - Py_XDECREF(__pyx_3); - __Pyx_AddTraceback("iocpsupport.Event.__init__"); - __pyx_r = 0; - __pyx_L0:; - Py_XDECREF(__pyx_v_kw); - Py_DECREF(__pyx_v_k); - Py_DECREF(__pyx_v_v); - Py_DECREF(__pyx_v_self); - Py_DECREF(__pyx_v_callback); - Py_DECREF(__pyx_v_owner); - Py_XDECREF(__pyx_args); - Py_XDECREF(__pyx_kwds); - return __pyx_r; -} - -static PyObject *__pyx_n_CreateIoCompletionPort; - - -static int __pyx_f_11iocpsupport_14CompletionPort___init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static int __pyx_f_11iocpsupport_14CompletionPort___init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - __pyx_t_11iocpsupport_HANDLE __pyx_v_res; - int __pyx_r; - int __pyx_1; - static char *__pyx_argnames[] = {0}; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "", __pyx_argnames)) return -1; - Py_INCREF(__pyx_v_self); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":133 */ - __pyx_v_res = CreateIoCompletionPort(INVALID_HANDLE_VALUE,0,0,0); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":134 */ - __pyx_1 = (!__pyx_v_res); - if (__pyx_1) { - __pyx_f_11iocpsupport_raise_error(0,__pyx_n_CreateIoCompletionPort); if (PyErr_Occurred()) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 135; goto __pyx_L1;} - goto __pyx_L2; - } - __pyx_L2:; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":136 */ - ((struct __pyx_obj_11iocpsupport_CompletionPort *)__pyx_v_self)->port = __pyx_v_res; - - __pyx_r = 0; - goto __pyx_L0; - __pyx_L1:; - __Pyx_AddTraceback("iocpsupport.CompletionPort.__init__"); - __pyx_r = -1; - __pyx_L0:; - Py_DECREF(__pyx_v_self); - return __pyx_r; -} - - -static PyObject *__pyx_f_11iocpsupport_14CompletionPort_addHandle(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static PyObject *__pyx_f_11iocpsupport_14CompletionPort_addHandle(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - long __pyx_v_handle; - long __pyx_v_key; - __pyx_t_11iocpsupport_HANDLE __pyx_v_res; - PyObject *__pyx_r; - int __pyx_1; - static char *__pyx_argnames[] = {"handle","key",0}; - __pyx_v_key = __pyx_k2; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "l|l", __pyx_argnames, &__pyx_v_handle, &__pyx_v_key)) return 0; - Py_INCREF(__pyx_v_self); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":140 */ - __pyx_v_res = CreateIoCompletionPort(__pyx_v_handle,((struct __pyx_obj_11iocpsupport_CompletionPort *)__pyx_v_self)->port,__pyx_v_key,0); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":141 */ - __pyx_1 = (!__pyx_v_res); - if (__pyx_1) { - __pyx_f_11iocpsupport_raise_error(0,__pyx_n_CreateIoCompletionPort); if (PyErr_Occurred()) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 142; goto __pyx_L1;} - goto __pyx_L2; - } - __pyx_L2:; - - __pyx_r = Py_None; Py_INCREF(Py_None); - goto __pyx_L0; - __pyx_L1:; - __Pyx_AddTraceback("iocpsupport.CompletionPort.addHandle"); - __pyx_r = 0; - __pyx_L0:; - Py_DECREF(__pyx_v_self); - return __pyx_r; -} - -static PyObject *__pyx_f_11iocpsupport_14CompletionPort_getEvent(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static PyObject *__pyx_f_11iocpsupport_14CompletionPort_getEvent(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - long __pyx_v_timeout; - struct PyThreadState *__pyx_v__save; - unsigned long __pyx_v_bytes; - unsigned long __pyx_v_key; - unsigned long __pyx_v_rc; - struct __pyx_t_11iocpsupport_myOVERLAPPED *__pyx_v_ov; - PyObject *__pyx_v_obj; - PyObject *__pyx_r; - int __pyx_1; - PyObject *__pyx_2 = 0; - PyObject *__pyx_3 = 0; - PyObject *__pyx_4 = 0; - PyObject *__pyx_5 = 0; - static char *__pyx_argnames[] = {"timeout",0}; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "l", __pyx_argnames, &__pyx_v_timeout)) return 0; - Py_INCREF(__pyx_v_self); - __pyx_v_obj = Py_None; Py_INCREF(Py_None); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":149 */ - __pyx_v__save = PyEval_SaveThread(); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":150 */ - __pyx_v_rc = GetQueuedCompletionStatus(((struct __pyx_obj_11iocpsupport_CompletionPort *)__pyx_v_self)->port,(&__pyx_v_bytes),(&__pyx_v_key),((OVERLAPPED **)(&__pyx_v_ov)),__pyx_v_timeout); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":151 */ - PyEval_RestoreThread(__pyx_v__save); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":153 */ - __pyx_1 = (!__pyx_v_rc); - if (__pyx_1) { - __pyx_v_rc = GetLastError(); - goto __pyx_L2; - } - /*else*/ { - __pyx_v_rc = 0; - } - __pyx_L2:; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":158 */ - Py_INCREF(Py_None); - Py_DECREF(__pyx_v_obj); - __pyx_v_obj = Py_None; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":159 */ - __pyx_1 = (__pyx_v_ov != 0); - if (__pyx_1) { - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":160 */ - __pyx_1 = (__pyx_v_ov->obj != 0); - if (__pyx_1) { - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":161 */ - __pyx_2 = (PyObject *)__pyx_v_ov->obj; - Py_INCREF(__pyx_2); - Py_DECREF(__pyx_v_obj); - __pyx_v_obj = __pyx_2; - __pyx_2 = 0; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":162 */ - Py_DECREF(__pyx_v_obj); - goto __pyx_L4; - } - __pyx_L4:; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":163 */ - PyMem_Free(__pyx_v_ov); - goto __pyx_L3; - } - __pyx_L3:; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":165 */ - __pyx_2 = PyLong_FromUnsignedLong(__pyx_v_rc); if (!__pyx_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 165; goto __pyx_L1;} - __pyx_3 = PyLong_FromUnsignedLong(__pyx_v_bytes); if (!__pyx_3) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 165; goto __pyx_L1;} - __pyx_4 = PyLong_FromUnsignedLong(__pyx_v_key); if (!__pyx_4) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 165; goto __pyx_L1;} - __pyx_5 = PyTuple_New(4); if (!__pyx_5) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 165; goto __pyx_L1;} - PyTuple_SET_ITEM(__pyx_5, 0, __pyx_2); - PyTuple_SET_ITEM(__pyx_5, 1, __pyx_3); - PyTuple_SET_ITEM(__pyx_5, 2, __pyx_4); - Py_INCREF(__pyx_v_obj); - PyTuple_SET_ITEM(__pyx_5, 3, __pyx_v_obj); - __pyx_2 = 0; - __pyx_3 = 0; - __pyx_4 = 0; - __pyx_r = __pyx_5; - __pyx_5 = 0; - goto __pyx_L0; - - __pyx_r = Py_None; Py_INCREF(Py_None); - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_2); - Py_XDECREF(__pyx_3); - Py_XDECREF(__pyx_4); - Py_XDECREF(__pyx_5); - __Pyx_AddTraceback("iocpsupport.CompletionPort.getEvent"); - __pyx_r = 0; - __pyx_L0:; - Py_DECREF(__pyx_v_obj); - Py_DECREF(__pyx_v_self); - return __pyx_r; -} - -static PyObject *__pyx_n_PostQueuedCompletionStatus; - - -static PyObject *__pyx_f_11iocpsupport_14CompletionPort_postEvent(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static PyObject *__pyx_f_11iocpsupport_14CompletionPort_postEvent(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - unsigned long __pyx_v_bytes; - unsigned long __pyx_v_key; - PyObject *__pyx_v_obj = 0; - struct __pyx_t_11iocpsupport_myOVERLAPPED *__pyx_v_ov; - unsigned long __pyx_v_rc; - PyObject *__pyx_r; - int __pyx_1; - struct __pyx_t_11iocpsupport_myOVERLAPPED *__pyx_2; - static char *__pyx_argnames[] = {"bytes","key","obj",0}; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "kkO", __pyx_argnames, &__pyx_v_bytes, &__pyx_v_key, &__pyx_v_obj)) return 0; - Py_INCREF(__pyx_v_self); - Py_INCREF(__pyx_v_obj); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":171 */ - __pyx_1 = __pyx_v_obj != Py_None; - if (__pyx_1) { - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":172 */ - __pyx_2 = __pyx_f_11iocpsupport_makeOV(); if (__pyx_2 == NULL) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 172; goto __pyx_L1;} - __pyx_v_ov = __pyx_2; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":173 */ - Py_INCREF(__pyx_v_obj); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":174 */ - __pyx_v_ov->obj = ((struct PyObject *)__pyx_v_obj); - goto __pyx_L2; - } - /*else*/ { - __pyx_v_ov = NULL; - } - __pyx_L2:; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":178 */ - __pyx_v_rc = PostQueuedCompletionStatus(((struct __pyx_obj_11iocpsupport_CompletionPort *)__pyx_v_self)->port,__pyx_v_bytes,__pyx_v_key,((OVERLAPPED *)__pyx_v_ov)); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":179 */ - __pyx_1 = (!__pyx_v_rc); - if (__pyx_1) { - __pyx_f_11iocpsupport_raise_error(0,__pyx_n_PostQueuedCompletionStatus); if (PyErr_Occurred()) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 180; goto __pyx_L1;} - goto __pyx_L3; - } - __pyx_L3:; - - __pyx_r = Py_None; Py_INCREF(Py_None); - goto __pyx_L0; - __pyx_L1:; - __Pyx_AddTraceback("iocpsupport.CompletionPort.postEvent"); - __pyx_r = 0; - __pyx_L0:; - Py_DECREF(__pyx_v_self); - Py_DECREF(__pyx_v_obj); - return __pyx_r; -} - -static PyObject *__pyx_f_11iocpsupport_14CompletionPort___del__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static PyObject *__pyx_f_11iocpsupport_14CompletionPort___del__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_r; - static char *__pyx_argnames[] = {0}; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "", __pyx_argnames)) return 0; - Py_INCREF(__pyx_v_self); - CloseHandle(((struct __pyx_obj_11iocpsupport_CompletionPort *)__pyx_v_self)->port); - - __pyx_r = Py_None; Py_INCREF(Py_None); - Py_DECREF(__pyx_v_self); - return __pyx_r; -} - -static PyObject *__pyx_f_11iocpsupport_makesockaddr(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static PyObject *__pyx_f_11iocpsupport_makesockaddr(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_v_buff = 0; - void *__pyx_v_mem_buffer; - int __pyx_v_size; - PyObject *__pyx_r; - int __pyx_1; - PyObject *__pyx_2 = 0; - static char *__pyx_argnames[] = {"buff",0}; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "O", __pyx_argnames, &__pyx_v_buff)) return 0; - Py_INCREF(__pyx_v_buff); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":189 */ - __pyx_1 = PyObject_AsReadBuffer(__pyx_v_buff,(&__pyx_v_mem_buffer),(&__pyx_v_size)); if (__pyx_1 == (-1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 189; goto __pyx_L1;} - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":191 */ - __pyx_2 = __pyx_f_11iocpsupport__makesockaddr(((struct sockaddr *)__pyx_v_mem_buffer),__pyx_v_size); if (!__pyx_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 191; goto __pyx_L1;} - __pyx_r = __pyx_2; - __pyx_2 = 0; - goto __pyx_L0; - - __pyx_r = Py_None; Py_INCREF(Py_None); - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_2); - __Pyx_AddTraceback("iocpsupport.makesockaddr"); - __pyx_r = 0; - __pyx_L0:; - Py_DECREF(__pyx_v_buff); - return __pyx_r; -} - -static PyObject *__pyx_f_11iocpsupport__makesockaddr(struct sockaddr *__pyx_v_addr,int __pyx_v_len) { - struct sockaddr_in *__pyx_v_sin; - PyObject *__pyx_r; - int __pyx_1; - PyObject *__pyx_2 = 0; - PyObject *__pyx_3 = 0; - PyObject *__pyx_4 = 0; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":195 */ - __pyx_1 = (!__pyx_v_len); - if (__pyx_1) { - Py_INCREF(Py_None); - __pyx_r = Py_None; - goto __pyx_L0; - goto __pyx_L2; - } - __pyx_L2:; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":197 */ - __pyx_1 = (__pyx_v_addr->sa_family == AF_INET); - if (__pyx_1) { - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":198 */ - __pyx_v_sin = ((struct sockaddr_in *)__pyx_v_addr); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":199 */ - __pyx_2 = PyString_FromString(inet_ntoa(__pyx_v_sin->sin_addr)); if (!__pyx_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 199; goto __pyx_L1;} - __pyx_3 = PyInt_FromLong(ntohs(__pyx_v_sin->sin_port)); if (!__pyx_3) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 199; goto __pyx_L1;} - __pyx_4 = PyTuple_New(2); if (!__pyx_4) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 199; goto __pyx_L1;} - PyTuple_SET_ITEM(__pyx_4, 0, __pyx_2); - PyTuple_SET_ITEM(__pyx_4, 1, __pyx_3); - __pyx_2 = 0; - __pyx_3 = 0; - __pyx_r = __pyx_4; - __pyx_4 = 0; - goto __pyx_L0; - goto __pyx_L3; - } - /*else*/ { - __pyx_2 = PyString_FromStringAndSize(__pyx_v_addr->sa_data,(sizeof(__pyx_v_addr->sa_data))); if (!__pyx_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 201; goto __pyx_L1;} - __pyx_r = __pyx_2; - __pyx_2 = 0; - goto __pyx_L0; - } - __pyx_L3:; - - __pyx_r = Py_None; Py_INCREF(Py_None); - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_2); - Py_XDECREF(__pyx_3); - Py_XDECREF(__pyx_4); - __Pyx_AddTraceback("iocpsupport._makesockaddr"); - __pyx_r = 0; - __pyx_L0:; - return __pyx_r; -} - -static PyObject *__pyx_k11p; - -static char __pyx_k11[] = "invalid IP address"; - -static PyObject *__pyx_f_11iocpsupport_fillinetaddr(struct sockaddr_in *__pyx_v_dest,PyObject *__pyx_v_addr) { - short __pyx_v_port; - unsigned long __pyx_v_res; - char *__pyx_v_hoststr; - PyObject *__pyx_v_host; - PyObject *__pyx_r; - PyObject *__pyx_1 = 0; - PyObject *__pyx_2 = 0; - short __pyx_3; - char *__pyx_4; - int __pyx_5; - Py_INCREF(__pyx_v_addr); - __pyx_v_host = Py_None; Py_INCREF(Py_None); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":207 */ - __pyx_1 = PyObject_GetIter(__pyx_v_addr); if (!__pyx_1) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 207; goto __pyx_L1;} - __pyx_2 = __Pyx_UnpackItem(__pyx_1); if (!__pyx_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 207; goto __pyx_L1;} - Py_DECREF(__pyx_v_host); - __pyx_v_host = __pyx_2; - __pyx_2 = 0; - __pyx_2 = __Pyx_UnpackItem(__pyx_1); if (!__pyx_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 207; goto __pyx_L1;} - __pyx_3 = PyInt_AsLong(__pyx_2); if (PyErr_Occurred()) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 207; goto __pyx_L1;} - Py_DECREF(__pyx_2); __pyx_2 = 0; - __pyx_v_port = __pyx_3; - if (__Pyx_EndUnpack(__pyx_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 207; goto __pyx_L1;} - Py_DECREF(__pyx_1); __pyx_1 = 0; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":209 */ - __pyx_4 = PyString_AsString(__pyx_v_host); if (__pyx_4 == NULL) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 209; goto __pyx_L1;} - __pyx_v_hoststr = __pyx_4; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":210 */ - __pyx_v_res = inet_addr(__pyx_v_hoststr); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":211 */ - __pyx_5 = (__pyx_v_res == INADDR_ANY); - if (__pyx_5) { - __pyx_2 = __Pyx_GetName(__pyx_b, __pyx_n_ValueError); if (!__pyx_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 212; goto __pyx_L1;} - __Pyx_Raise(__pyx_2, __pyx_k11p, 0); - Py_DECREF(__pyx_2); __pyx_2 = 0; - {__pyx_filename = __pyx_f[0]; __pyx_lineno = 212; goto __pyx_L1;} - goto __pyx_L2; - } - __pyx_L2:; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":213 */ - __pyx_v_dest->sin_addr.s_addr = __pyx_v_res; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":215 */ - __pyx_v_dest->sin_port = htons(__pyx_v_port); - - __pyx_r = Py_None; Py_INCREF(Py_None); - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_1); - Py_XDECREF(__pyx_2); - __Pyx_AddTraceback("iocpsupport.fillinetaddr"); - __pyx_r = 0; - __pyx_L0:; - Py_DECREF(__pyx_v_host); - Py_DECREF(__pyx_v_addr); - return __pyx_r; -} - -static PyObject *__pyx_f_11iocpsupport_AllocateReadBuffer(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static PyObject *__pyx_f_11iocpsupport_AllocateReadBuffer(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - int __pyx_v_size; - PyObject *__pyx_r; - PyObject *__pyx_1 = 0; - static char *__pyx_argnames[] = {"size",0}; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "i", __pyx_argnames, &__pyx_v_size)) return 0; - __pyx_1 = PyBuffer_New(__pyx_v_size); if (!__pyx_1) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 218; goto __pyx_L1;} - __pyx_r = __pyx_1; - __pyx_1 = 0; - goto __pyx_L0; - - __pyx_r = Py_None; Py_INCREF(Py_None); - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_1); - __Pyx_AddTraceback("iocpsupport.AllocateReadBuffer"); - __pyx_r = 0; - __pyx_L0:; - return __pyx_r; -} - -static PyObject *__pyx_n_getsockopt; - - -static PyObject *__pyx_f_11iocpsupport_maxAddrLen(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static PyObject *__pyx_f_11iocpsupport_maxAddrLen(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - long __pyx_v_s; - WSAPROTOCOL_INFO __pyx_v_wsa_pi; - int __pyx_v_size; - int __pyx_v_rc; - PyObject *__pyx_r; - int __pyx_1; - PyObject *__pyx_2 = 0; - static char *__pyx_argnames[] = {"s",0}; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "l", __pyx_argnames, &__pyx_v_s)) return 0; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":224 */ - __pyx_v_size = (sizeof(__pyx_v_wsa_pi)); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":225 */ - __pyx_v_rc = getsockopt(__pyx_v_s,SOL_SOCKET,SO_PROTOCOL_INFO,((char *)(&__pyx_v_wsa_pi)),(&__pyx_v_size)); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":226 */ - __pyx_1 = (__pyx_v_rc == SOCKET_ERROR); - if (__pyx_1) { - __pyx_f_11iocpsupport_raise_error(WSAGetLastError(),__pyx_n_getsockopt); if (PyErr_Occurred()) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 227; goto __pyx_L1;} - goto __pyx_L2; - } - __pyx_L2:; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":228 */ - __pyx_2 = PyInt_FromLong(__pyx_v_wsa_pi.iMaxSockAddr); if (!__pyx_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 228; goto __pyx_L1;} - __pyx_r = __pyx_2; - __pyx_2 = 0; - goto __pyx_L0; - - __pyx_r = Py_None; Py_INCREF(Py_None); - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_2); - __Pyx_AddTraceback("iocpsupport.maxAddrLen"); - __pyx_r = 0; - __pyx_L0:; - return __pyx_r; -} - - -static int __pyx_f_11iocpsupport_getAddrFamily(__pyx_t_11iocpsupport_SOCKET __pyx_v_s) { - WSAPROTOCOL_INFO __pyx_v_wsa_pi; - int __pyx_v_size; - int __pyx_v_rc; - int __pyx_r; - int __pyx_1; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":234 */ - __pyx_v_size = (sizeof(__pyx_v_wsa_pi)); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":235 */ - __pyx_v_rc = getsockopt(__pyx_v_s,SOL_SOCKET,SO_PROTOCOL_INFO,((char *)(&__pyx_v_wsa_pi)),(&__pyx_v_size)); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":236 */ - __pyx_1 = (__pyx_v_rc == SOCKET_ERROR); - if (__pyx_1) { - __pyx_f_11iocpsupport_raise_error(WSAGetLastError(),__pyx_n_getsockopt); if (PyErr_Occurred()) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 237; goto __pyx_L1;} - goto __pyx_L2; - } - __pyx_L2:; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":238 */ - __pyx_r = __pyx_v_wsa_pi.iAddressFamily; - goto __pyx_L0; - - __pyx_r = 0; - goto __pyx_L0; - __pyx_L1:; - __Pyx_AddTraceback("iocpsupport.getAddrFamily"); - __pyx_L0:; - return __pyx_r; -} - -static PyObject *__pyx_f_11iocpsupport_accept(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static PyObject *__pyx_f_11iocpsupport_accept(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - long __pyx_v_listening; - long __pyx_v_accepting; - PyObject *__pyx_v_buff = 0; - PyObject *__pyx_v_obj = 0; - unsigned long __pyx_v_bytes; - int __pyx_v_size; - int __pyx_v_rc; - void *__pyx_v_mem_buffer; - struct __pyx_t_11iocpsupport_myOVERLAPPED *__pyx_v_ov; - PyObject *__pyx_r; - int __pyx_1; - struct __pyx_t_11iocpsupport_myOVERLAPPED *__pyx_2; - PyObject *__pyx_3 = 0; - static char *__pyx_argnames[] = {"listening","accepting","buff","obj",0}; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "llOO", __pyx_argnames, &__pyx_v_listening, &__pyx_v_accepting, &__pyx_v_buff, &__pyx_v_obj)) return 0; - Py_INCREF(__pyx_v_buff); - Py_INCREF(__pyx_v_obj); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":11 */ - __pyx_1 = PyObject_AsWriteBuffer(__pyx_v_buff,(&__pyx_v_mem_buffer),(&__pyx_v_size)); if (__pyx_1 == (-1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 11; goto __pyx_L1;} - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":13 */ - __pyx_2 = __pyx_f_11iocpsupport_makeOV(); if (__pyx_2 == NULL) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 13; goto __pyx_L1;} - __pyx_v_ov = __pyx_2; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":14 */ - __pyx_1 = __pyx_v_obj != Py_None; - if (__pyx_1) { - __pyx_v_ov->obj = ((struct PyObject *)__pyx_v_obj); - goto __pyx_L2; - } - __pyx_L2:; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":17 */ - __pyx_v_rc = lpAcceptEx(__pyx_v_listening,__pyx_v_accepting,__pyx_v_mem_buffer,0,(__pyx_v_size / 2),(__pyx_v_size / 2),(&__pyx_v_bytes),((OVERLAPPED *)__pyx_v_ov)); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":19 */ - __pyx_1 = (!__pyx_v_rc); - if (__pyx_1) { - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":20 */ - __pyx_v_rc = WSAGetLastError(); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":21 */ - __pyx_1 = (__pyx_v_rc != ERROR_IO_PENDING); - if (__pyx_1) { - __pyx_3 = PyInt_FromLong(__pyx_v_rc); if (!__pyx_3) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 22; goto __pyx_L1;} - __pyx_r = __pyx_3; - __pyx_3 = 0; - goto __pyx_L0; - goto __pyx_L4; - } - __pyx_L4:; - goto __pyx_L3; - } - __pyx_L3:; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":25 */ - Py_XINCREF(__pyx_v_obj); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":26 */ - __pyx_3 = PyInt_FromLong(__pyx_v_rc); if (!__pyx_3) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 26; goto __pyx_L1;} - __pyx_r = __pyx_3; - __pyx_3 = 0; - goto __pyx_L0; - - __pyx_r = Py_None; Py_INCREF(Py_None); - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_3); - __Pyx_AddTraceback("iocpsupport.accept"); - __pyx_r = 0; - __pyx_L0:; - Py_DECREF(__pyx_v_buff); - Py_DECREF(__pyx_v_obj); - return __pyx_r; -} - -static PyObject *__pyx_f_11iocpsupport_get_accept_addrs(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static PyObject *__pyx_f_11iocpsupport_get_accept_addrs(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - long __pyx_v_s; - PyObject *__pyx_v_buff = 0; - int __pyx_v_size; - int __pyx_v_locallen; - int __pyx_v_remotelen; - void *__pyx_v_mem_buffer; - struct sockaddr *__pyx_v_localaddr; - struct sockaddr *__pyx_v_remoteaddr; - PyObject *__pyx_r; - int __pyx_1; - PyObject *__pyx_2 = 0; - PyObject *__pyx_3 = 0; - PyObject *__pyx_4 = 0; - PyObject *__pyx_5 = 0; - static char *__pyx_argnames[] = {"s","buff",0}; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "lO", __pyx_argnames, &__pyx_v_s, &__pyx_v_buff)) return 0; - Py_INCREF(__pyx_v_buff); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":34 */ - __pyx_1 = PyObject_AsReadBuffer(__pyx_v_buff,(&__pyx_v_mem_buffer),(&__pyx_v_size)); if (__pyx_1 == (-1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 34; goto __pyx_L1;} - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":36 */ - lpGetAcceptExSockaddrs(__pyx_v_mem_buffer,0,(__pyx_v_size / 2),(__pyx_v_size / 2),(&__pyx_v_localaddr),(&__pyx_v_locallen),(&__pyx_v_remoteaddr),(&__pyx_v_remotelen)); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":37 */ - __pyx_2 = PyInt_FromLong(__pyx_v_remoteaddr->sa_family); if (!__pyx_2) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 37; goto __pyx_L1;} - __pyx_3 = __pyx_f_11iocpsupport__makesockaddr(__pyx_v_localaddr,__pyx_v_locallen); if (!__pyx_3) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 37; goto __pyx_L1;} - __pyx_4 = __pyx_f_11iocpsupport__makesockaddr(__pyx_v_remoteaddr,__pyx_v_remotelen); if (!__pyx_4) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 37; goto __pyx_L1;} - __pyx_5 = PyTuple_New(3); if (!__pyx_5) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 37; goto __pyx_L1;} - PyTuple_SET_ITEM(__pyx_5, 0, __pyx_2); - PyTuple_SET_ITEM(__pyx_5, 1, __pyx_3); - PyTuple_SET_ITEM(__pyx_5, 2, __pyx_4); - __pyx_2 = 0; - __pyx_3 = 0; - __pyx_4 = 0; - __pyx_r = __pyx_5; - __pyx_5 = 0; - goto __pyx_L0; - - __pyx_r = Py_None; Py_INCREF(Py_None); - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_2); - Py_XDECREF(__pyx_3); - Py_XDECREF(__pyx_4); - Py_XDECREF(__pyx_5); - __Pyx_AddTraceback("iocpsupport.get_accept_addrs"); - __pyx_r = 0; - __pyx_L0:; - Py_DECREF(__pyx_v_buff); - return __pyx_r; -} - -static PyObject *__pyx_k14p; -static PyObject *__pyx_k15p; - -static char __pyx_k14[] = "ConnectEx is not available on this system"; -static char __pyx_k15[] = "unsupported address family"; - -static PyObject *__pyx_f_11iocpsupport_connect(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static PyObject *__pyx_f_11iocpsupport_connect(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - long __pyx_v_s; - PyObject *__pyx_v_addr = 0; - PyObject *__pyx_v_obj = 0; - int __pyx_v_family; - int __pyx_v_rc; - struct __pyx_t_11iocpsupport_myOVERLAPPED *__pyx_v_ov; - struct sockaddr __pyx_v_name; - PyObject *__pyx_r; - PyObject *__pyx_1 = 0; - int __pyx_2; - int __pyx_3; - struct __pyx_t_11iocpsupport_myOVERLAPPED *__pyx_4; - static char *__pyx_argnames[] = {"s","addr","obj",0}; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "lOO", __pyx_argnames, &__pyx_v_s, &__pyx_v_addr, &__pyx_v_obj)) return 0; - Py_INCREF(__pyx_v_addr); - Py_INCREF(__pyx_v_obj); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":10 */ - __pyx_1 = __Pyx_GetName(__pyx_m, __pyx_n_have_connectex); if (!__pyx_1) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 10; goto __pyx_L1;} - __pyx_2 = PyObject_IsTrue(__pyx_1); if (__pyx_2 < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 10; goto __pyx_L1;} - Py_DECREF(__pyx_1); __pyx_1 = 0; - __pyx_3 = (!__pyx_2); - if (__pyx_3) { - __pyx_1 = __Pyx_GetName(__pyx_b, __pyx_n_ValueError); if (!__pyx_1) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 11; goto __pyx_L1;} - __Pyx_Raise(__pyx_1, __pyx_k14p, 0); - Py_DECREF(__pyx_1); __pyx_1 = 0; - {__pyx_filename = __pyx_f[2]; __pyx_lineno = 11; goto __pyx_L1;} - goto __pyx_L2; - } - __pyx_L2:; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":13 */ - __pyx_2 = __pyx_f_11iocpsupport_getAddrFamily(__pyx_v_s); if (PyErr_Occurred()) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 13; goto __pyx_L1;} - __pyx_v_family = __pyx_2; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":14 */ - __pyx_3 = (__pyx_v_family == AF_INET); - if (__pyx_3) { - __pyx_1 = __pyx_f_11iocpsupport_fillinetaddr(((struct sockaddr_in *)(&__pyx_v_name)),__pyx_v_addr); if (!__pyx_1) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 15; goto __pyx_L1;} - Py_DECREF(__pyx_1); __pyx_1 = 0; - goto __pyx_L3; - } - /*else*/ { - __pyx_1 = __Pyx_GetName(__pyx_b, __pyx_n_ValueError); if (!__pyx_1) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 17; goto __pyx_L1;} - __Pyx_Raise(__pyx_1, __pyx_k15p, 0); - Py_DECREF(__pyx_1); __pyx_1 = 0; - {__pyx_filename = __pyx_f[2]; __pyx_lineno = 17; goto __pyx_L1;} - } - __pyx_L3:; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":18 */ - __pyx_v_name.sa_family = __pyx_v_family; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":20 */ - __pyx_4 = __pyx_f_11iocpsupport_makeOV(); if (__pyx_4 == NULL) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 20; goto __pyx_L1;} - __pyx_v_ov = __pyx_4; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":21 */ - __pyx_2 = __pyx_v_obj != Py_None; - if (__pyx_2) { - __pyx_v_ov->obj = ((struct PyObject *)__pyx_v_obj); - goto __pyx_L4; - } - __pyx_L4:; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":24 */ - __pyx_v_rc = lpConnectEx(__pyx_v_s,(&__pyx_v_name),(sizeof(__pyx_v_name)),NULL,0,NULL,((OVERLAPPED *)__pyx_v_ov)); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":26 */ - __pyx_3 = (!__pyx_v_rc); - if (__pyx_3) { - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":27 */ - __pyx_v_rc = WSAGetLastError(); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":28 */ - __pyx_2 = (__pyx_v_rc != ERROR_IO_PENDING); - if (__pyx_2) { - __pyx_1 = PyInt_FromLong(__pyx_v_rc); if (!__pyx_1) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 29; goto __pyx_L1;} - __pyx_r = __pyx_1; - __pyx_1 = 0; - goto __pyx_L0; - goto __pyx_L6; - } - __pyx_L6:; - goto __pyx_L5; - } - __pyx_L5:; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":32 */ - Py_XINCREF(__pyx_v_obj); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":33 */ - __pyx_1 = PyInt_FromLong(__pyx_v_rc); if (!__pyx_1) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 33; goto __pyx_L1;} - __pyx_r = __pyx_1; - __pyx_1 = 0; - goto __pyx_L0; - - __pyx_r = Py_None; Py_INCREF(Py_None); - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_1); - __Pyx_AddTraceback("iocpsupport.connect"); - __pyx_r = 0; - __pyx_L0:; - Py_DECREF(__pyx_v_addr); - Py_DECREF(__pyx_v_obj); - return __pyx_r; -} - -static char __pyx_k16[] = "second argument needs to be a list"; - -static PyObject *__pyx_f_11iocpsupport_recv(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static PyObject *__pyx_f_11iocpsupport_recv(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - long __pyx_v_s; - PyObject *__pyx_v_bufflist = 0; - PyObject *__pyx_v_obj = 0; - unsigned long __pyx_v_flags; - int __pyx_v_rc; - int __pyx_v_buffcount; - int __pyx_v_i; - struct __pyx_t_11iocpsupport_myOVERLAPPED *__pyx_v_ov; - WSABUF *__pyx_v_ws_buf; - unsigned long __pyx_v_bytes; - struct PyObject **__pyx_v_buffers; - PyObject *__pyx_r; - PyObject *__pyx_1 = 0; - void *__pyx_2; - int __pyx_3; - struct __pyx_t_11iocpsupport_myOVERLAPPED *__pyx_4; - PyObject *__pyx_5 = 0; - PyObject *__pyx_6 = 0; - static char *__pyx_argnames[] = {"s","bufflist","obj","flags",0}; - __pyx_v_flags = __pyx_k5; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "lOO|k", __pyx_argnames, &__pyx_v_s, &__pyx_v_bufflist, &__pyx_v_obj, &__pyx_v_flags)) return 0; - Py_INCREF(__pyx_v_bufflist); - Py_INCREF(__pyx_v_obj); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":12 */ - __pyx_1 = PySequence_Fast(__pyx_v_bufflist,__pyx_k16); if (!__pyx_1) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 12; goto __pyx_L1;} - Py_DECREF(__pyx_v_bufflist); - __pyx_v_bufflist = __pyx_1; - __pyx_1 = 0; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":13 */ - __pyx_v_buffcount = PySequence_Fast_GET_SIZE(__pyx_v_bufflist); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":14 */ - __pyx_v_buffers = PySequence_Fast_ITEMS(__pyx_v_bufflist); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":16 */ - __pyx_2 = PyMem_Malloc((__pyx_v_buffcount * (sizeof(WSABUF)))); if (__pyx_2 == NULL) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 16; goto __pyx_L1;} - __pyx_v_ws_buf = ((WSABUF *)__pyx_2); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":18 */ - /*try:*/ { - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":19 */ - for (__pyx_v_i = 0; __pyx_v_i < __pyx_v_buffcount; ++__pyx_v_i) { - __pyx_1 = (PyObject *)(__pyx_v_buffers[__pyx_v_i]); - Py_INCREF(__pyx_1); - __pyx_3 = PyObject_AsWriteBuffer(__pyx_1,((void **)(&(__pyx_v_ws_buf[__pyx_v_i]).buf)),((int *)(&(__pyx_v_ws_buf[__pyx_v_i]).len))); if (__pyx_3 == (-1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 20; goto __pyx_L3;} - Py_DECREF(__pyx_1); __pyx_1 = 0; - } - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":22 */ - __pyx_4 = __pyx_f_11iocpsupport_makeOV(); if (__pyx_4 == NULL) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 22; goto __pyx_L3;} - __pyx_v_ov = __pyx_4; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":23 */ - __pyx_3 = __pyx_v_obj != Py_None; - if (__pyx_3) { - __pyx_v_ov->obj = ((struct PyObject *)__pyx_v_obj); - goto __pyx_L7; - } - __pyx_L7:; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":26 */ - __pyx_v_rc = WSARecv(__pyx_v_s,__pyx_v_ws_buf,__pyx_v_buffcount,(&__pyx_v_bytes),(&__pyx_v_flags),((OVERLAPPED *)__pyx_v_ov),NULL); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":28 */ - __pyx_3 = (__pyx_v_rc == SOCKET_ERROR); - if (__pyx_3) { - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":29 */ - __pyx_v_rc = WSAGetLastError(); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":30 */ - __pyx_3 = (__pyx_v_rc != ERROR_IO_PENDING); - if (__pyx_3) { - __pyx_1 = PyInt_FromLong(__pyx_v_rc); if (!__pyx_1) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 31; goto __pyx_L3;} - __pyx_5 = PyInt_FromLong(0); if (!__pyx_5) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 31; goto __pyx_L3;} - __pyx_6 = PyTuple_New(2); if (!__pyx_6) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 31; goto __pyx_L3;} - PyTuple_SET_ITEM(__pyx_6, 0, __pyx_1); - PyTuple_SET_ITEM(__pyx_6, 1, __pyx_5); - __pyx_1 = 0; - __pyx_5 = 0; - __pyx_r = __pyx_6; - __pyx_6 = 0; - goto __pyx_L2; - goto __pyx_L9; - } - __pyx_L9:; - goto __pyx_L8; - } - __pyx_L8:; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":33 */ - Py_XINCREF(__pyx_v_obj); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":34 */ - __pyx_1 = PyInt_FromLong(__pyx_v_rc); if (!__pyx_1) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 34; goto __pyx_L3;} - __pyx_5 = PyLong_FromUnsignedLong(__pyx_v_bytes); if (!__pyx_5) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 34; goto __pyx_L3;} - __pyx_6 = PyTuple_New(2); if (!__pyx_6) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 34; goto __pyx_L3;} - PyTuple_SET_ITEM(__pyx_6, 0, __pyx_1); - PyTuple_SET_ITEM(__pyx_6, 1, __pyx_5); - __pyx_1 = 0; - __pyx_5 = 0; - __pyx_r = __pyx_6; - __pyx_6 = 0; - goto __pyx_L2; - } - /*finally:*/ { - int __pyx_why; - PyObject *__pyx_exc_type, *__pyx_exc_value, *__pyx_exc_tb; - int __pyx_exc_lineno; - __pyx_why = 0; goto __pyx_L4; - __pyx_L2: __pyx_why = 3; goto __pyx_L4; - __pyx_L3: { - __pyx_why = 4; - Py_XDECREF(__pyx_1); __pyx_1 = 0; - Py_XDECREF(__pyx_5); __pyx_5 = 0; - Py_XDECREF(__pyx_6); __pyx_6 = 0; - PyErr_Fetch(&__pyx_exc_type, &__pyx_exc_value, &__pyx_exc_tb); - __pyx_exc_lineno = __pyx_lineno; - goto __pyx_L4; - } - __pyx_L4:; - PyMem_Free(__pyx_v_ws_buf); - switch (__pyx_why) { - case 3: goto __pyx_L0; - case 4: { - PyErr_Restore(__pyx_exc_type, __pyx_exc_value, __pyx_exc_tb); - __pyx_lineno = __pyx_exc_lineno; - __pyx_exc_type = 0; - __pyx_exc_value = 0; - __pyx_exc_tb = 0; - goto __pyx_L1; - } - } - } - - __pyx_r = Py_None; Py_INCREF(Py_None); - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_1); - Py_XDECREF(__pyx_5); - Py_XDECREF(__pyx_6); - __Pyx_AddTraceback("iocpsupport.recv"); - __pyx_r = 0; - __pyx_L0:; - Py_DECREF(__pyx_v_bufflist); - Py_DECREF(__pyx_v_obj); - return __pyx_r; -} - -static PyObject *__pyx_f_11iocpsupport_recvfrom(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static PyObject *__pyx_f_11iocpsupport_recvfrom(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - long __pyx_v_s; - PyObject *__pyx_v_buff = 0; - PyObject *__pyx_v_addr_buff = 0; - PyObject *__pyx_v_obj = 0; - unsigned long __pyx_v_flags; - int __pyx_v_rc; - int __pyx_v_fromlen; - struct __pyx_t_11iocpsupport_myOVERLAPPED *__pyx_v_ov; - WSABUF __pyx_v_ws_buf; - unsigned long __pyx_v_bytes; - struct sockaddr *__pyx_v_fromaddr; - PyObject *__pyx_r; - int __pyx_1; - struct __pyx_t_11iocpsupport_myOVERLAPPED *__pyx_2; - PyObject *__pyx_3 = 0; - PyObject *__pyx_4 = 0; - PyObject *__pyx_5 = 0; - static char *__pyx_argnames[] = {"s","buff","addr_buff","obj","flags",0}; - __pyx_v_flags = __pyx_k6; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "lOOO|k", __pyx_argnames, &__pyx_v_s, &__pyx_v_buff, &__pyx_v_addr_buff, &__pyx_v_obj, &__pyx_v_flags)) return 0; - Py_INCREF(__pyx_v_buff); - Py_INCREF(__pyx_v_addr_buff); - Py_INCREF(__pyx_v_obj); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":45 */ - __pyx_1 = PyObject_AsWriteBuffer(__pyx_v_buff,((void **)(&__pyx_v_ws_buf.buf)),((int *)(&__pyx_v_ws_buf.len))); if (__pyx_1 == (-1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 45; goto __pyx_L1;} - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":46 */ - __pyx_1 = PyObject_AsWriteBuffer(__pyx_v_addr_buff,((void **)(&__pyx_v_fromaddr)),(&__pyx_v_fromlen)); if (__pyx_1 == (-1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 46; goto __pyx_L1;} - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":48 */ - __pyx_2 = __pyx_f_11iocpsupport_makeOV(); if (__pyx_2 == NULL) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 48; goto __pyx_L1;} - __pyx_v_ov = __pyx_2; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":49 */ - __pyx_1 = __pyx_v_obj != Py_None; - if (__pyx_1) { - __pyx_v_ov->obj = ((struct PyObject *)__pyx_v_obj); - goto __pyx_L2; - } - __pyx_L2:; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":52 */ - __pyx_v_rc = WSARecvFrom(__pyx_v_s,(&__pyx_v_ws_buf),1,(&__pyx_v_bytes),(&__pyx_v_flags),__pyx_v_fromaddr,(&__pyx_v_fromlen),((OVERLAPPED *)__pyx_v_ov),NULL); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":54 */ - __pyx_1 = (__pyx_v_rc == SOCKET_ERROR); - if (__pyx_1) { - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":55 */ - __pyx_v_rc = WSAGetLastError(); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":56 */ - __pyx_1 = (__pyx_v_rc != ERROR_IO_PENDING); - if (__pyx_1) { - __pyx_3 = PyInt_FromLong(__pyx_v_rc); if (!__pyx_3) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 57; goto __pyx_L1;} - __pyx_4 = PyInt_FromLong(0); if (!__pyx_4) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 57; goto __pyx_L1;} - __pyx_5 = PyTuple_New(2); if (!__pyx_5) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 57; goto __pyx_L1;} - PyTuple_SET_ITEM(__pyx_5, 0, __pyx_3); - PyTuple_SET_ITEM(__pyx_5, 1, __pyx_4); - __pyx_3 = 0; - __pyx_4 = 0; - __pyx_r = __pyx_5; - __pyx_5 = 0; - goto __pyx_L0; - goto __pyx_L4; - } - __pyx_L4:; - goto __pyx_L3; - } - __pyx_L3:; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":59 */ - Py_XINCREF(__pyx_v_obj); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":60 */ - __pyx_3 = PyInt_FromLong(__pyx_v_rc); if (!__pyx_3) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 60; goto __pyx_L1;} - __pyx_4 = PyLong_FromUnsignedLong(__pyx_v_bytes); if (!__pyx_4) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 60; goto __pyx_L1;} - __pyx_5 = PyTuple_New(2); if (!__pyx_5) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 60; goto __pyx_L1;} - PyTuple_SET_ITEM(__pyx_5, 0, __pyx_3); - PyTuple_SET_ITEM(__pyx_5, 1, __pyx_4); - __pyx_3 = 0; - __pyx_4 = 0; - __pyx_r = __pyx_5; - __pyx_5 = 0; - goto __pyx_L0; - - __pyx_r = Py_None; Py_INCREF(Py_None); - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_3); - Py_XDECREF(__pyx_4); - Py_XDECREF(__pyx_5); - __Pyx_AddTraceback("iocpsupport.recvfrom"); - __pyx_r = 0; - __pyx_L0:; - Py_DECREF(__pyx_v_buff); - Py_DECREF(__pyx_v_addr_buff); - Py_DECREF(__pyx_v_obj); - return __pyx_r; -} - -static PyObject *__pyx_f_11iocpsupport_send(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static PyObject *__pyx_f_11iocpsupport_send(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - long __pyx_v_s; - PyObject *__pyx_v_buff = 0; - PyObject *__pyx_v_obj = 0; - unsigned long __pyx_v_flags; - int __pyx_v_rc; - struct __pyx_t_11iocpsupport_myOVERLAPPED *__pyx_v_ov; - WSABUF __pyx_v_ws_buf; - unsigned long __pyx_v_bytes; - PyObject *__pyx_r; - int __pyx_1; - struct __pyx_t_11iocpsupport_myOVERLAPPED *__pyx_2; - PyObject *__pyx_3 = 0; - PyObject *__pyx_4 = 0; - PyObject *__pyx_5 = 0; - static char *__pyx_argnames[] = {"s","buff","obj","flags",0}; - __pyx_v_flags = __pyx_k7; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "lOO|k", __pyx_argnames, &__pyx_v_s, &__pyx_v_buff, &__pyx_v_obj, &__pyx_v_flags)) return 0; - Py_INCREF(__pyx_v_buff); - Py_INCREF(__pyx_v_obj); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":11 */ - __pyx_1 = PyObject_AsReadBuffer(__pyx_v_buff,((void **)(&__pyx_v_ws_buf.buf)),((int *)(&__pyx_v_ws_buf.len))); if (__pyx_1 == (-1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 11; goto __pyx_L1;} - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":13 */ - __pyx_2 = __pyx_f_11iocpsupport_makeOV(); if (__pyx_2 == NULL) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 13; goto __pyx_L1;} - __pyx_v_ov = __pyx_2; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":14 */ - __pyx_1 = __pyx_v_obj != Py_None; - if (__pyx_1) { - __pyx_v_ov->obj = ((struct PyObject *)__pyx_v_obj); - goto __pyx_L2; - } - __pyx_L2:; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":17 */ - __pyx_v_rc = WSASend(__pyx_v_s,(&__pyx_v_ws_buf),1,(&__pyx_v_bytes),__pyx_v_flags,((OVERLAPPED *)__pyx_v_ov),NULL); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":19 */ - __pyx_1 = (__pyx_v_rc == SOCKET_ERROR); - if (__pyx_1) { - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":20 */ - __pyx_v_rc = WSAGetLastError(); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":21 */ - __pyx_1 = (__pyx_v_rc != ERROR_IO_PENDING); - if (__pyx_1) { - __pyx_3 = PyInt_FromLong(__pyx_v_rc); if (!__pyx_3) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 22; goto __pyx_L1;} - __pyx_4 = PyLong_FromUnsignedLong(__pyx_v_bytes); if (!__pyx_4) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 22; goto __pyx_L1;} - __pyx_5 = PyTuple_New(2); if (!__pyx_5) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 22; goto __pyx_L1;} - PyTuple_SET_ITEM(__pyx_5, 0, __pyx_3); - PyTuple_SET_ITEM(__pyx_5, 1, __pyx_4); - __pyx_3 = 0; - __pyx_4 = 0; - __pyx_r = __pyx_5; - __pyx_5 = 0; - goto __pyx_L0; - goto __pyx_L4; - } - __pyx_L4:; - goto __pyx_L3; - } - __pyx_L3:; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":24 */ - Py_XINCREF(__pyx_v_obj); - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":25 */ - __pyx_3 = PyInt_FromLong(__pyx_v_rc); if (!__pyx_3) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 25; goto __pyx_L1;} - __pyx_4 = PyLong_FromUnsignedLong(__pyx_v_bytes); if (!__pyx_4) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 25; goto __pyx_L1;} - __pyx_5 = PyTuple_New(2); if (!__pyx_5) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 25; goto __pyx_L1;} - PyTuple_SET_ITEM(__pyx_5, 0, __pyx_3); - PyTuple_SET_ITEM(__pyx_5, 1, __pyx_4); - __pyx_3 = 0; - __pyx_4 = 0; - __pyx_r = __pyx_5; - __pyx_5 = 0; - goto __pyx_L0; - - __pyx_r = Py_None; Py_INCREF(Py_None); - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_3); - Py_XDECREF(__pyx_4); - Py_XDECREF(__pyx_5); - __Pyx_AddTraceback("iocpsupport.send"); - __pyx_r = 0; - __pyx_L0:; - Py_DECREF(__pyx_v_buff); - Py_DECREF(__pyx_v_obj); - return __pyx_r; -} - -static __Pyx_InternTabEntry __pyx_intern_tab[] = { - {&__pyx_n_CreateIoCompletionPort, "CreateIoCompletionPort"}, - {&__pyx_n_Event, "Event"}, - {&__pyx_n_False, "False"}, - {&__pyx_n_MemoryError, "MemoryError"}, - {&__pyx_n_PostQueuedCompletionStatus, "PostQueuedCompletionStatus"}, - {&__pyx_n_ValueError, "ValueError"}, - {&__pyx_n_WindowsError, "WindowsError"}, - {&__pyx_n___init__, "__init__"}, - {&__pyx_n_callback, "callback"}, - {&__pyx_n_getsockopt, "getsockopt"}, - {&__pyx_n_have_connectex, "have_connectex"}, - {&__pyx_n_ignore, "ignore"}, - {&__pyx_n_items, "items"}, - {&__pyx_n_owner, "owner"}, - {&__pyx_n_socket, "socket"}, - {0, 0} -}; - -static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_k4p, __pyx_k4, sizeof(__pyx_k4)}, - {&__pyx_k11p, __pyx_k11, sizeof(__pyx_k11)}, - {&__pyx_k14p, __pyx_k14, sizeof(__pyx_k14)}, - {&__pyx_k15p, __pyx_k15, sizeof(__pyx_k15)}, - {0, 0, 0} -}; - -static PyObject *__pyx_tp_new_11iocpsupport_CompletionPort(PyTypeObject *t, PyObject *a, PyObject *k) { - PyObject *o = (*t->tp_alloc)(t, 0); - if (!o) return 0; - return o; -} - -static void __pyx_tp_dealloc_11iocpsupport_CompletionPort(PyObject *o) { - (*o->ob_type->tp_free)(o); -} - -static int __pyx_tp_traverse_11iocpsupport_CompletionPort(PyObject *o, visitproc v, void *a) { - return 0; -} - -static int __pyx_tp_clear_11iocpsupport_CompletionPort(PyObject *o) { - return 0; -} - -static struct PyMethodDef __pyx_methods_11iocpsupport_CompletionPort[] = { - {"addHandle", (PyCFunction)__pyx_f_11iocpsupport_14CompletionPort_addHandle, METH_VARARGS|METH_KEYWORDS, 0}, - {"getEvent", (PyCFunction)__pyx_f_11iocpsupport_14CompletionPort_getEvent, METH_VARARGS|METH_KEYWORDS, 0}, - {"postEvent", (PyCFunction)__pyx_f_11iocpsupport_14CompletionPort_postEvent, METH_VARARGS|METH_KEYWORDS, 0}, - {"__del__", (PyCFunction)__pyx_f_11iocpsupport_14CompletionPort___del__, METH_VARARGS|METH_KEYWORDS, 0}, - {0, 0, 0, 0} -}; - -static PyNumberMethods __pyx_tp_as_number_CompletionPort = { - 0, /*nb_add*/ - 0, /*nb_subtract*/ - 0, /*nb_multiply*/ - 0, /*nb_divide*/ - 0, /*nb_remainder*/ - 0, /*nb_divmod*/ - 0, /*nb_power*/ - 0, /*nb_negative*/ - 0, /*nb_positive*/ - 0, /*nb_absolute*/ - 0, /*nb_nonzero*/ - 0, /*nb_invert*/ - 0, /*nb_lshift*/ - 0, /*nb_rshift*/ - 0, /*nb_and*/ - 0, /*nb_xor*/ - 0, /*nb_or*/ - 0, /*nb_coerce*/ - 0, /*nb_int*/ - 0, /*nb_long*/ - 0, /*nb_float*/ - 0, /*nb_oct*/ - 0, /*nb_hex*/ - 0, /*nb_inplace_add*/ - 0, /*nb_inplace_subtract*/ - 0, /*nb_inplace_multiply*/ - 0, /*nb_inplace_divide*/ - 0, /*nb_inplace_remainder*/ - 0, /*nb_inplace_power*/ - 0, /*nb_inplace_lshift*/ - 0, /*nb_inplace_rshift*/ - 0, /*nb_inplace_and*/ - 0, /*nb_inplace_xor*/ - 0, /*nb_inplace_or*/ - 0, /*nb_floor_divide*/ - 0, /*nb_true_divide*/ - 0, /*nb_inplace_floor_divide*/ - 0, /*nb_inplace_true_divide*/ - #if Py_TPFLAGS_DEFAULT & Py_TPFLAGS_HAVE_INDEX - 0, /*nb_index*/ - #endif -}; - -static PySequenceMethods __pyx_tp_as_sequence_CompletionPort = { - 0, /*sq_length*/ - 0, /*sq_concat*/ - 0, /*sq_repeat*/ - 0, /*sq_item*/ - 0, /*sq_slice*/ - 0, /*sq_ass_item*/ - 0, /*sq_ass_slice*/ - 0, /*sq_contains*/ - 0, /*sq_inplace_concat*/ - 0, /*sq_inplace_repeat*/ -}; - -static PyMappingMethods __pyx_tp_as_mapping_CompletionPort = { - 0, /*mp_length*/ - 0, /*mp_subscript*/ - 0, /*mp_ass_subscript*/ -}; - -static PyBufferProcs __pyx_tp_as_buffer_CompletionPort = { - 0, /*bf_getreadbuffer*/ - 0, /*bf_getwritebuffer*/ - 0, /*bf_getsegcount*/ - 0, /*bf_getcharbuffer*/ -}; - -PyTypeObject __pyx_type_11iocpsupport_CompletionPort = { - PyObject_HEAD_INIT(0) - 0, /*ob_size*/ - "iocpsupport.CompletionPort", /*tp_name*/ - sizeof(struct __pyx_obj_11iocpsupport_CompletionPort), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_11iocpsupport_CompletionPort, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - &__pyx_tp_as_number_CompletionPort, /*tp_as_number*/ - &__pyx_tp_as_sequence_CompletionPort, /*tp_as_sequence*/ - &__pyx_tp_as_mapping_CompletionPort, /*tp_as_mapping*/ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - &__pyx_tp_as_buffer_CompletionPort, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/ - 0, /*tp_doc*/ - __pyx_tp_traverse_11iocpsupport_CompletionPort, /*tp_traverse*/ - __pyx_tp_clear_11iocpsupport_CompletionPort, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - __pyx_methods_11iocpsupport_CompletionPort, /*tp_methods*/ - 0, /*tp_members*/ - 0, /*tp_getset*/ - 0, /*tp_base*/ - 0, /*tp_dict*/ - 0, /*tp_descr_get*/ - 0, /*tp_descr_set*/ - 0, /*tp_dictoffset*/ - __pyx_f_11iocpsupport_14CompletionPort___init__, /*tp_init*/ - 0, /*tp_alloc*/ - __pyx_tp_new_11iocpsupport_CompletionPort, /*tp_new*/ - 0, /*tp_free*/ - 0, /*tp_is_gc*/ - 0, /*tp_bases*/ - 0, /*tp_mro*/ - 0, /*tp_cache*/ - 0, /*tp_subclasses*/ - 0, /*tp_weaklist*/ -}; - -static struct PyMethodDef __pyx_methods[] = { - {"makesockaddr", (PyCFunction)__pyx_f_11iocpsupport_makesockaddr, METH_VARARGS|METH_KEYWORDS, 0}, - {"AllocateReadBuffer", (PyCFunction)__pyx_f_11iocpsupport_AllocateReadBuffer, METH_VARARGS|METH_KEYWORDS, 0}, - {"maxAddrLen", (PyCFunction)__pyx_f_11iocpsupport_maxAddrLen, METH_VARARGS|METH_KEYWORDS, 0}, - {"accept", (PyCFunction)__pyx_f_11iocpsupport_accept, METH_VARARGS|METH_KEYWORDS, 0}, - {"get_accept_addrs", (PyCFunction)__pyx_f_11iocpsupport_get_accept_addrs, METH_VARARGS|METH_KEYWORDS, 0}, - {"connect", (PyCFunction)__pyx_f_11iocpsupport_connect, METH_VARARGS|METH_KEYWORDS, 0}, - {"recv", (PyCFunction)__pyx_f_11iocpsupport_recv, METH_VARARGS|METH_KEYWORDS, 0}, - {"recvfrom", (PyCFunction)__pyx_f_11iocpsupport_recvfrom, METH_VARARGS|METH_KEYWORDS, 0}, - {"send", (PyCFunction)__pyx_f_11iocpsupport_send, METH_VARARGS|METH_KEYWORDS, 0}, - {0, 0, 0, 0} -}; - -static void __pyx_init_filenames(void); /*proto*/ - -PyMODINIT_FUNC initiocpsupport(void); /*proto*/ -PyMODINIT_FUNC initiocpsupport(void) { - PyObject *__pyx_1 = 0; - PyObject *__pyx_2 = 0; - PyObject *__pyx_3 = 0; - PyObject *__pyx_4 = 0; - int __pyx_5; - __pyx_init_filenames(); - __pyx_m = Py_InitModule4("iocpsupport", __pyx_methods, 0, 0, PYTHON_API_VERSION); - if (!__pyx_m) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 5; goto __pyx_L1;}; - Py_INCREF(__pyx_m); - __pyx_b = PyImport_AddModule("__builtin__"); - if (!__pyx_b) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 5; goto __pyx_L1;}; - if (PyObject_SetAttrString(__pyx_m, "__builtins__", __pyx_b) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 5; goto __pyx_L1;}; - if (__Pyx_InternStrings(__pyx_intern_tab) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 5; goto __pyx_L1;}; - if (__Pyx_InitStrings(__pyx_string_tab) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 5; goto __pyx_L1;}; - if (PyType_Ready(&__pyx_type_11iocpsupport_CompletionPort) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 129; goto __pyx_L1;} - if (PyObject_SetAttrString(__pyx_m, "CompletionPort", (PyObject *)&__pyx_type_11iocpsupport_CompletionPort) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 129; goto __pyx_L1;} - __pyx_ptype_11iocpsupport_CompletionPort = &__pyx_type_11iocpsupport_CompletionPort; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":121 */ - __pyx_1 = PyDict_New(); if (!__pyx_1) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 121; goto __pyx_L1;} - __pyx_2 = PyTuple_New(0); if (!__pyx_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 121; goto __pyx_L1;} - __pyx_3 = __Pyx_CreateClass(__pyx_2, __pyx_1, __pyx_n_Event, "iocpsupport"); if (!__pyx_3) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 121; goto __pyx_L1;} - Py_DECREF(__pyx_2); __pyx_2 = 0; - __pyx_2 = PyCFunction_New(&__pyx_mdef_11iocpsupport_5Event___init__, 0); if (!__pyx_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 122; goto __pyx_L1;} - __pyx_4 = PyMethod_New(__pyx_2, 0, __pyx_3); if (!__pyx_4) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 122; goto __pyx_L1;} - Py_DECREF(__pyx_2); __pyx_2 = 0; - if (PyObject_SetAttr(__pyx_3, __pyx_n___init__, __pyx_4) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 122; goto __pyx_L1;} - Py_DECREF(__pyx_4); __pyx_4 = 0; - if (PyObject_SetAttr(__pyx_m, __pyx_n_Event, __pyx_3) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 121; goto __pyx_L1;} - Py_DECREF(__pyx_3); __pyx_3 = 0; - Py_DECREF(__pyx_1); __pyx_1 = 0; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":138 */ - __pyx_k2 = 0; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":240 */ - __pyx_2 = __Pyx_Import(__pyx_n_socket, 0); if (!__pyx_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 240; goto __pyx_L1;} - if (PyObject_SetAttr(__pyx_m, __pyx_n_socket, __pyx_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 240; goto __pyx_L1;} - Py_DECREF(__pyx_2); __pyx_2 = 0; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":241 */ - __pyx_5 = (!initWinsockPointers()); - if (__pyx_5) { - __pyx_4 = __Pyx_GetName(__pyx_b, __pyx_n_ValueError); if (!__pyx_4) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 242; goto __pyx_L1;} - __Pyx_Raise(__pyx_4, __pyx_k4p, 0); - Py_DECREF(__pyx_4); __pyx_4 = 0; - {__pyx_filename = __pyx_f[0]; __pyx_lineno = 242; goto __pyx_L1;} - goto __pyx_L5; - } - __pyx_L5:; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport/iocpsupport.pyx":244 */ - __pyx_3 = PyInt_FromLong((lpConnectEx != NULL)); if (!__pyx_3) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 244; goto __pyx_L1;} - if (PyObject_SetAttr(__pyx_m, __pyx_n_have_connectex, __pyx_3) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 244; goto __pyx_L1;} - Py_DECREF(__pyx_3); __pyx_3 = 0; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":5 */ - __pyx_k5 = 0; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":38 */ - __pyx_k6 = 0; - - /* "X:\projects\Twisted\trunk\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":5 */ - __pyx_k7 = 0; - return; - __pyx_L1:; - Py_XDECREF(__pyx_1); - Py_XDECREF(__pyx_2); - Py_XDECREF(__pyx_3); - Py_XDECREF(__pyx_4); - __Pyx_AddTraceback("iocpsupport"); -} - -static char *__pyx_filenames[] = { - "iocpsupport.pyx", - "acceptex.pxi", - "connectex.pxi", - "wsarecv.pxi", - "wsasend.pxi", -}; - -/* Runtime support code */ - -static void __pyx_init_filenames(void) { - __pyx_f = __pyx_filenames; -} - -static PyObject *__Pyx_CreateClass( - PyObject *bases, PyObject *dict, PyObject *name, char *modname) -{ - PyObject *py_modname; - PyObject *result = 0; - - py_modname = PyString_FromString(modname); - if (!py_modname) - goto bad; - if (PyDict_SetItemString(dict, "__module__", py_modname) < 0) - goto bad; - result = PyClass_New(bases, dict, name); -bad: - Py_XDECREF(py_modname); - return result; -} - -static int __Pyx_GetStarArgs( - PyObject **args, - PyObject **kwds, - char *kwd_list[], - Py_ssize_t nargs, - PyObject **args2, - PyObject **kwds2, - char rqd_kwds[]) -{ - PyObject *x = 0, *args1 = 0, *kwds1 = 0; - int i; - char **p; - - if (args2) - *args2 = 0; - if (kwds2) - *kwds2 = 0; - - if (args2) { - args1 = PyTuple_GetSlice(*args, 0, nargs); - if (!args1) - goto bad; - *args2 = PyTuple_GetSlice(*args, nargs, PyTuple_GET_SIZE(*args)); - if (!*args2) - goto bad; - } - else if (PyTuple_GET_SIZE(*args) > nargs) { - int m = nargs; - int n = PyTuple_GET_SIZE(*args); - PyErr_Format(PyExc_TypeError, - "function takes at most %d positional arguments (%d given)", - m, n); - goto bad; - } - else { - args1 = *args; - Py_INCREF(args1); - } - - if (rqd_kwds && !*kwds) - for (i = 0, p = kwd_list; *p; i++, p++) - if (rqd_kwds[i]) - goto missing_kwarg; - - if (kwds2) { - if (*kwds) { - kwds1 = PyDict_New(); - if (!kwds1) - goto bad; - *kwds2 = PyDict_Copy(*kwds); - if (!*kwds2) - goto bad; - for (i = 0, p = kwd_list; *p; i++, p++) { - x = PyDict_GetItemString(*kwds, *p); - if (x) { - if (PyDict_SetItemString(kwds1, *p, x) < 0) - goto bad; - if (PyDict_DelItemString(*kwds2, *p) < 0) - goto bad; - } - else if (rqd_kwds && rqd_kwds[i]) - goto missing_kwarg; - } - } - else { - *kwds2 = PyDict_New(); - if (!*kwds2) - goto bad; - } - } - else { - kwds1 = *kwds; - Py_XINCREF(kwds1); - if (rqd_kwds && *kwds) - for (i = 0, p = kwd_list; *p; i++, p++) - if (rqd_kwds[i] && !PyDict_GetItemString(*kwds, *p)) - goto missing_kwarg; - } - - *args = args1; - *kwds = kwds1; - return 0; -missing_kwarg: - PyErr_Format(PyExc_TypeError, - "required keyword argument '%s' is missing", *p); -bad: - Py_XDECREF(args1); - Py_XDECREF(kwds1); - if (args2) { - Py_XDECREF(*args2); - } - if (kwds2) { - Py_XDECREF(*kwds2); - } - return -1; -} - -static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list) { - PyObject *__import__ = 0; - PyObject *empty_list = 0; - PyObject *module = 0; - PyObject *global_dict = 0; - PyObject *empty_dict = 0; - PyObject *list; - __import__ = PyObject_GetAttrString(__pyx_b, "__import__"); - if (!__import__) - goto bad; - if (from_list) - list = from_list; - else { - empty_list = PyList_New(0); - if (!empty_list) - goto bad; - list = empty_list; - } - global_dict = PyModule_GetDict(__pyx_m); - if (!global_dict) - goto bad; - empty_dict = PyDict_New(); - if (!empty_dict) - goto bad; - module = PyObject_CallFunction(__import__, "OOOO", - name, global_dict, empty_dict, list); -bad: - Py_XDECREF(empty_list); - Py_XDECREF(__import__); - Py_XDECREF(empty_dict); - return module; -} - -static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name) { - PyObject *result; - result = PyObject_GetAttr(dict, name); - if (!result) - PyErr_SetObject(PyExc_NameError, name); - return result; -} - -static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb) { - Py_XINCREF(type); - Py_XINCREF(value); - Py_XINCREF(tb); - /* First, check the traceback argument, replacing None with NULL. */ - if (tb == Py_None) { - Py_DECREF(tb); - tb = 0; - } - else if (tb != NULL && !PyTraceBack_Check(tb)) { - PyErr_SetString(PyExc_TypeError, - "raise: arg 3 must be a traceback or None"); - goto raise_error; - } - /* Next, replace a missing value with None */ - if (value == NULL) { - value = Py_None; - Py_INCREF(value); - } - #if PY_VERSION_HEX < 0x02050000 - if (!PyClass_Check(type)) - #else - if (!PyType_Check(type)) - #endif - { - /* Raising an instance. The value should be a dummy. */ - if (value != Py_None) { - PyErr_SetString(PyExc_TypeError, - "instance exception may not have a separate value"); - goto raise_error; - } - /* Normalize to raise , */ - Py_DECREF(value); - value = type; - #if PY_VERSION_HEX < 0x02050000 - if (PyInstance_Check(type)) { - type = (PyObject*) ((PyInstanceObject*)type)->in_class; - Py_INCREF(type); - } - else { - PyErr_SetString(PyExc_TypeError, - "raise: exception must be an old-style class or instance"); - goto raise_error; - } - #else - type = (PyObject*) type->ob_type; - Py_INCREF(type); - if (!PyType_IsSubtype((PyTypeObject *)type, (PyTypeObject *)PyExc_BaseException)) { - PyErr_SetString(PyExc_TypeError, - "raise: exception class must be a subclass of BaseException"); - goto raise_error; - } - #endif - } - PyErr_Restore(type, value, tb); - return; -raise_error: - Py_XDECREF(value); - Py_XDECREF(type); - Py_XDECREF(tb); - return; -} - -static void __Pyx_UnpackError(void) { - PyErr_SetString(PyExc_ValueError, "unpack sequence of wrong size"); -} - -static PyObject *__Pyx_UnpackItem(PyObject *iter) { - PyObject *item; - if (!(item = PyIter_Next(iter))) { - if (!PyErr_Occurred()) - __Pyx_UnpackError(); - } - return item; -} - -static int __Pyx_EndUnpack(PyObject *iter) { - PyObject *item; - if ((item = PyIter_Next(iter))) { - Py_DECREF(item); - __Pyx_UnpackError(); - return -1; - } - else if (!PyErr_Occurred()) - return 0; - else - return -1; -} - -static int __Pyx_InternStrings(__Pyx_InternTabEntry *t) { - while (t->p) { - *t->p = PyString_InternFromString(t->s); - if (!*t->p) - return -1; - ++t; - } - return 0; -} - -static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) { - while (t->p) { - *t->p = PyString_FromStringAndSize(t->s, t->n - 1); - if (!*t->p) - return -1; - ++t; - } - return 0; -} - -#include "compile.h" -#include "frameobject.h" -#include "traceback.h" - -static void __Pyx_AddTraceback(char *funcname) { - PyObject *py_srcfile = 0; - PyObject *py_funcname = 0; - PyObject *py_globals = 0; - PyObject *empty_tuple = 0; - PyObject *empty_string = 0; - PyCodeObject *py_code = 0; - PyFrameObject *py_frame = 0; - - py_srcfile = PyString_FromString(__pyx_filename); - if (!py_srcfile) goto bad; - py_funcname = PyString_FromString(funcname); - if (!py_funcname) goto bad; - py_globals = PyModule_GetDict(__pyx_m); - if (!py_globals) goto bad; - empty_tuple = PyTuple_New(0); - if (!empty_tuple) goto bad; - empty_string = PyString_FromString(""); - if (!empty_string) goto bad; - py_code = PyCode_New( - 0, /*int argcount,*/ - 0, /*int nlocals,*/ - 0, /*int stacksize,*/ - 0, /*int flags,*/ - empty_string, /*PyObject *code,*/ - empty_tuple, /*PyObject *consts,*/ - empty_tuple, /*PyObject *names,*/ - empty_tuple, /*PyObject *varnames,*/ - empty_tuple, /*PyObject *freevars,*/ - empty_tuple, /*PyObject *cellvars,*/ - py_srcfile, /*PyObject *filename,*/ - py_funcname, /*PyObject *name,*/ - __pyx_lineno, /*int firstlineno,*/ - empty_string /*PyObject *lnotab*/ - ); - if (!py_code) goto bad; - py_frame = PyFrame_New( - PyThreadState_Get(), /*PyThreadState *tstate,*/ - py_code, /*PyCodeObject *code,*/ - py_globals, /*PyObject *globals,*/ - 0 /*PyObject *locals*/ - ); - if (!py_frame) goto bad; - py_frame->f_lineno = __pyx_lineno; - PyTraceBack_Here(py_frame); -bad: - Py_XDECREF(py_srcfile); - Py_XDECREF(py_funcname); - Py_XDECREF(empty_tuple); - Py_XDECREF(empty_string); - Py_XDECREF(py_code); - Py_XDECREF(py_frame); -} diff --git a/tools/buildbot/pylibs/twisted/internet/iocpreactor/iocpsupport/iocpsupport.pyx b/tools/buildbot/pylibs/twisted/internet/iocpreactor/iocpsupport/iocpsupport.pyx deleted file mode 100644 index 85f8c47..0000000 --- a/tools/buildbot/pylibs/twisted/internet/iocpreactor/iocpsupport/iocpsupport.pyx +++ /dev/null @@ -1,250 +0,0 @@ -# Copyright (c) 2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -ctypedef int size_t -ctypedef unsigned long HANDLE -ctypedef unsigned long SOCKET -ctypedef unsigned long DWORD -ctypedef unsigned long ULONG_PTR -ctypedef int BOOL - -cdef extern from 'io.h': - long _get_osfhandle(int filehandle) - -cdef extern from 'errno.h': - int errno - enum: - EBADF - -cdef extern from 'winsock2.h': - pass - -cdef extern from 'windows.h': - ctypedef struct OVERLAPPED: - pass - HANDLE CreateIoCompletionPort(HANDLE fileHandle, HANDLE existing, ULONG_PTR key, DWORD numThreads) - BOOL GetQueuedCompletionStatus(HANDLE port, DWORD *bytes, ULONG_PTR *key, OVERLAPPED **ov, DWORD timeout) - BOOL PostQueuedCompletionStatus(HANDLE port, DWORD bytes, ULONG_PTR key, OVERLAPPED *ov) - DWORD GetLastError() - BOOL CloseHandle(HANDLE h) - enum: - INVALID_HANDLE_VALUE - void DebugBreak() - -cdef extern from 'python.h': - struct PyObject: - pass - void *PyMem_Malloc(size_t n) except NULL - void PyMem_Free(void *p) - struct PyThreadState: - pass - PyThreadState *PyEval_SaveThread() - void PyEval_RestoreThread(PyThreadState *tstate) - void Py_INCREF(object o) - void Py_XINCREF(object o) - void Py_DECREF(object o) - void Py_XDECREF(object o) - int PyObject_AsWriteBuffer(object obj, void **buffer, int *buffer_len) except -1 - int PyObject_AsReadBuffer(object obj, void **buffer, int *buffer_len) except -1 - object PyString_FromString(char *v) - object PyString_FromStringAndSize(char *v, int len) - object PyBuffer_New(int size) - char *PyString_AsString(object obj) except NULL - object PySequence_Fast(object o, char *m) -# object PySequence_Fast_GET_ITEM(object o, int i) - PyObject** PySequence_Fast_ITEMS(object o) - PyObject* PySequence_ITEM( PyObject *o, int i) - int PySequence_Fast_GET_SIZE(object o) - -cdef extern from '': - struct sockaddr: - int sa_family - char sa_data[0] - cdef struct in_addr: - unsigned long s_addr - struct sockaddr_in: - int sin_port - in_addr sin_addr - int getsockopt(SOCKET s, int level, int optname, char *optval, int *optlen) - enum: - SOL_SOCKET - SO_PROTOCOL_INFO - SOCKET_ERROR - ERROR_IO_PENDING - AF_INET - INADDR_ANY - ctypedef struct WSAPROTOCOL_INFO: - int iMaxSockAddr - int iAddressFamily - int WSAGetLastError() - char *inet_ntoa(in_addr ina) - unsigned long inet_addr(char *cp) - short ntohs(short netshort) - short htons(short hostshort) - ctypedef struct WSABUF: - long len - char *buf -# cdef struct TRANSMIT_FILE_BUFFERS: -# pass - int WSARecv(SOCKET s, WSABUF *buffs, DWORD buffcount, DWORD *bytes, DWORD *flags, OVERLAPPED *ov, void *crud) - int WSARecvFrom(SOCKET s, WSABUF *buffs, DWORD buffcount, DWORD *bytes, DWORD *flags, sockaddr *fromaddr, int *fromlen, OVERLAPPED *ov, void *crud) - int WSASend(SOCKET s, WSABUF *buffs, DWORD buffcount, DWORD *bytes, DWORD flags, OVERLAPPED *ov, void *crud) - -cdef extern from 'string.h': - void *memset(void *s, int c, size_t n) - -cdef extern from 'winsock_pointers.h': - int initWinsockPointers() - BOOL (*lpAcceptEx)(SOCKET listening, SOCKET accepting, void *buffer, DWORD recvlen, DWORD locallen, DWORD remotelen, DWORD *bytes, OVERLAPPED *ov) - void (*lpGetAcceptExSockaddrs)(void *buffer, DWORD recvlen, DWORD locallen, DWORD remotelen, sockaddr **localaddr, int *locallen, sockaddr **remoteaddr, int *remotelen) - BOOL (*lpConnectEx)(SOCKET s, sockaddr *name, int namelen, void *buff, DWORD sendlen, DWORD *sentlen, OVERLAPPED *ov) -# BOOL (*lpTransmitFile)(SOCKET s, HANDLE hFile, DWORD size, DWORD buffer_size, OVERLAPPED *ov, TRANSMIT_FILE_BUFFERS *buff, DWORD flags) - -cdef struct myOVERLAPPED: - OVERLAPPED ov - PyObject *obj - -cdef myOVERLAPPED *makeOV() except NULL: - cdef myOVERLAPPED *res - res = PyMem_Malloc(sizeof(myOVERLAPPED)) - if not res: - raise MemoryError - memset(res, 0, sizeof(myOVERLAPPED)) - return res - -cdef void raise_error(int err, object message) except *: - if not err: - err = GetLastError() - raise WindowsError(message, err) - -class Event: - def __init__(self, callback, owner, **kw): - self.callback = callback - self.owner = owner - self.ignore = False - for k, v in kw.items(): - setattr(self, k, v) - -cdef class CompletionPort: - cdef HANDLE port - def __init__(self): - cdef HANDLE res - res = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0) - if not res: - raise_error(0, 'CreateIoCompletionPort') - self.port = res - - def addHandle(self, long handle, long key=0): - cdef HANDLE res - res = CreateIoCompletionPort(handle, self.port, key, 0) - if not res: - raise_error(0, 'CreateIoCompletionPort') - - def getEvent(self, long timeout): - cdef PyThreadState *_save - cdef unsigned long bytes, key, rc - cdef myOVERLAPPED *ov - - _save = PyEval_SaveThread() - rc = GetQueuedCompletionStatus(self.port, &bytes, &key, &ov, timeout) - PyEval_RestoreThread(_save) - - if not rc: - rc = GetLastError() - else: - rc = 0 - - obj = None - if ov: - if ov.obj: - obj = ov.obj - Py_DECREF(obj) # we are stealing a reference here - PyMem_Free(ov) - - return (rc, bytes, key, obj) - - def postEvent(self, unsigned long bytes, unsigned long key, obj): - cdef myOVERLAPPED *ov - cdef unsigned long rc - - if obj is not None: - ov = makeOV() - Py_INCREF(obj) # give ov its own reference to obj - ov.obj = obj - else: - ov = NULL - - rc = PostQueuedCompletionStatus(self.port, bytes, key, ov) - if not rc: - raise_error(0, 'PostQueuedCompletionStatus') - - def __del__(self): - CloseHandle(self.port) - -def makesockaddr(object buff): - cdef void *mem_buffer - cdef int size - - PyObject_AsReadBuffer(buff, &mem_buffer, &size) - # XXX: this should really return the address family as well - return _makesockaddr(mem_buffer, size) - -cdef object _makesockaddr(sockaddr *addr, int len): - cdef sockaddr_in *sin - if not len: - return None - if addr.sa_family == AF_INET: - sin = addr - return PyString_FromString(inet_ntoa(sin.sin_addr)), ntohs(sin.sin_port) - else: - return PyString_FromStringAndSize(addr.sa_data, sizeof(addr.sa_data)) - -cdef object fillinetaddr(sockaddr_in *dest, object addr): - cdef short port - cdef unsigned long res - cdef char *hoststr - host, port = addr - - hoststr = PyString_AsString(host) - res = inet_addr(hoststr) - if res == INADDR_ANY: - raise ValueError, 'invalid IP address' - dest.sin_addr.s_addr = res - - dest.sin_port = htons(port) - -def AllocateReadBuffer(int size): - return PyBuffer_New(size) - -def maxAddrLen(long s): - cdef WSAPROTOCOL_INFO wsa_pi - cdef int size, rc - - size = sizeof(wsa_pi) - rc = getsockopt(s, SOL_SOCKET, SO_PROTOCOL_INFO, &wsa_pi, &size) - if rc == SOCKET_ERROR: - raise_error(WSAGetLastError(), 'getsockopt') - return wsa_pi.iMaxSockAddr - -cdef int getAddrFamily(SOCKET s) except *: - cdef WSAPROTOCOL_INFO wsa_pi - cdef int size, rc - - size = sizeof(wsa_pi) - rc = getsockopt(s, SOL_SOCKET, SO_PROTOCOL_INFO, &wsa_pi, &size) - if rc == SOCKET_ERROR: - raise_error(WSAGetLastError(), 'getsockopt') - return wsa_pi.iAddressFamily - -import socket # for WSAStartup -if not initWinsockPointers(): - raise ValueError, 'Failed to initialize Winsock function vectors' - -have_connectex = (lpConnectEx != NULL) - -include 'acceptex.pxi' -include 'connectex.pxi' -include 'wsarecv.pxi' -include 'wsasend.pxi' - diff --git a/tools/buildbot/pylibs/twisted/internet/iocpreactor/iocpsupport/winsock_pointers.c b/tools/buildbot/pylibs/twisted/internet/iocpreactor/iocpsupport/winsock_pointers.c deleted file mode 100644 index 9bd115a..0000000 --- a/tools/buildbot/pylibs/twisted/internet/iocpreactor/iocpsupport/winsock_pointers.c +++ /dev/null @@ -1,62 +0,0 @@ -/* Copyright (c) 2008 Twisted Matrix Laboratories. - * See LICENSE for details. - */ - - -#include -#include -#include -#include - -#ifndef WSAID_CONNECTEX -#define WSAID_CONNECTEX {0x25a207b9,0xddf3,0x4660,{0x8e,0xe9,0x76,0xe5,0x8c,0x74,0x06,0x3e}} -#endif -#ifndef WSAID_GETACCEPTEXSOCKADDRS -#define WSAID_GETACCEPTEXSOCKADDRS {0xb5367df2,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}} -#endif -#ifndef WSAID_ACCEPTEX -#define WSAID_ACCEPTEX {0xb5367df1,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}} -#endif -/*#ifndef WSAID_TRANSMITFILE -#define WSAID_TRANSMITFILE {0xb5367df0,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}} -#endif*/ - - -void *lpAcceptEx, *lpGetAcceptExSockaddrs, *lpConnectEx, *lpTransmitFile; - -int initPointer(SOCKET s, void **fun, GUID guid) { - int res; - DWORD bytes; - - *fun = NULL; - res = WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, - &guid, sizeof(guid), - fun, sizeof(fun), - &bytes, NULL, NULL); - return !res; -} - -int initWinsockPointers() { - SOCKET s = socket(AF_INET, SOCK_STREAM, 0); - /* I hate C */ - GUID guid1 = WSAID_ACCEPTEX; - GUID guid2 = WSAID_GETACCEPTEXSOCKADDRS; - GUID guid3 = WSAID_CONNECTEX; - /*GUID guid4 = WSAID_TRANSMITFILE;*/ - if (!s) { - return 0; - } - if (!initPointer(s, &lpAcceptEx, guid1)) - { - return 0; - } - if (!initPointer(s, &lpGetAcceptExSockaddrs, guid2)) { - return 0; - } - if (!initPointer(s, &lpConnectEx, guid3)) { - return 0; - }; - /*initPointer(s, &lpTransmitFile, guid4);*/ - return 1; -} - diff --git a/tools/buildbot/pylibs/twisted/internet/iocpreactor/iocpsupport/winsock_pointers.h b/tools/buildbot/pylibs/twisted/internet/iocpreactor/iocpsupport/winsock_pointers.h deleted file mode 100644 index 83e9ba8..0000000 --- a/tools/buildbot/pylibs/twisted/internet/iocpreactor/iocpsupport/winsock_pointers.h +++ /dev/null @@ -1,51 +0,0 @@ -/* Copyright (c) 2008 Twisted Matrix Laboratories. - * See LICENSE for details. - */ - - -#include - -int initWinsockPointers(); -BOOL -(PASCAL FAR * lpAcceptEx)( - IN SOCKET sListenSocket, - IN SOCKET sAcceptSocket, - IN PVOID lpOutputBuffer, - IN DWORD dwReceiveDataLength, - IN DWORD dwLocalAddressLength, - IN DWORD dwRemoteAddressLength, - OUT LPDWORD lpdwBytesReceived, - IN LPOVERLAPPED lpOverlapped - ); -VOID -(PASCAL FAR * lpGetAcceptExSockaddrs)( - IN PVOID lpOutputBuffer, - IN DWORD dwReceiveDataLength, - IN DWORD dwLocalAddressLength, - IN DWORD dwRemoteAddressLength, - OUT struct sockaddr **LocalSockaddr, - OUT LPINT LocalSockaddrLength, - OUT struct sockaddr **RemoteSockaddr, - OUT LPINT RemoteSockaddrLength - ); -BOOL -(PASCAL FAR * lpConnectEx) ( - IN SOCKET s, - IN const struct sockaddr FAR *name, - IN int namelen, - IN PVOID lpSendBuffer OPTIONAL, - IN DWORD dwSendDataLength, - OUT LPDWORD lpdwBytesSent, - IN LPOVERLAPPED lpOverlapped - ); -/*BOOL -(PASCAL FAR * lpTransmitFile)( - IN SOCKET hSocket, - IN HANDLE hFile, - IN DWORD nNumberOfBytesToWrite, - IN DWORD nNumberOfBytesPerSend, - IN LPOVERLAPPED lpOverlapped, - IN LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers, - IN DWORD dwReserved - );*/ - diff --git a/tools/buildbot/pylibs/twisted/internet/iocpreactor/iocpsupport/wsarecv.pxi b/tools/buildbot/pylibs/twisted/internet/iocpreactor/iocpsupport/wsarecv.pxi deleted file mode 100644 index afb1906..0000000 --- a/tools/buildbot/pylibs/twisted/internet/iocpreactor/iocpsupport/wsarecv.pxi +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright (c) 2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -def recv(long s, object bufflist, object obj, unsigned long flags = 0): - cdef int rc, buffcount, i, res - cdef myOVERLAPPED *ov - cdef WSABUF *ws_buf - cdef unsigned long bytes - cdef PyObject **buffers - - bufflist = PySequence_Fast(bufflist, 'second argument needs to be a list') - buffcount = PySequence_Fast_GET_SIZE(bufflist) - buffers = PySequence_Fast_ITEMS(bufflist) - - ws_buf = PyMem_Malloc(buffcount*sizeof(WSABUF)) - - try: - for i from 0 <= i < buffcount: - PyObject_AsWriteBuffer(buffers[i], &ws_buf[i].buf, &ws_buf[i].len) - - ov = makeOV() - if obj is not None: - ov.obj = obj - - rc = WSARecv(s, ws_buf, buffcount, &bytes, &flags, ov, NULL) - - if rc == SOCKET_ERROR: - rc = WSAGetLastError() - if rc != ERROR_IO_PENDING: - return rc, 0 - - Py_XINCREF(obj) - return rc, bytes - finally: - PyMem_Free(ws_buf) - -def recvfrom(long s, object buff, object addr_buff, object obj, unsigned long flags = 0): - cdef int rc, fromlen - cdef myOVERLAPPED *ov - cdef WSABUF ws_buf - cdef unsigned long bytes - cdef sockaddr *fromaddr - - PyObject_AsWriteBuffer(buff, &ws_buf.buf, &ws_buf.len) - PyObject_AsWriteBuffer(addr_buff, &fromaddr, &fromlen) - - ov = makeOV() - if obj is not None: - ov.obj = obj - - rc = WSARecvFrom(s, &ws_buf, 1, &bytes, &flags, fromaddr, &fromlen, ov, NULL) - - if rc == SOCKET_ERROR: - rc = WSAGetLastError() - if rc != ERROR_IO_PENDING: - return rc, 0 - - Py_XINCREF(obj) - return rc, bytes - diff --git a/tools/buildbot/pylibs/twisted/internet/iocpreactor/iocpsupport/wsasend.pxi b/tools/buildbot/pylibs/twisted/internet/iocpreactor/iocpsupport/wsasend.pxi deleted file mode 100644 index 03c44ad..0000000 --- a/tools/buildbot/pylibs/twisted/internet/iocpreactor/iocpsupport/wsasend.pxi +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright (c) 2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -def send(long s, object buff, object obj, unsigned long flags = 0): - cdef int rc - cdef myOVERLAPPED *ov - cdef WSABUF ws_buf - cdef unsigned long bytes - - PyObject_AsReadBuffer(buff, &ws_buf.buf, &ws_buf.len) - - ov = makeOV() - if obj is not None: - ov.obj = obj - - rc = WSASend(s, &ws_buf, 1, &bytes, flags, ov, NULL) - - if rc == SOCKET_ERROR: - rc = WSAGetLastError() - if rc != ERROR_IO_PENDING: - return rc, bytes - - Py_XINCREF(obj) - return rc, bytes - - diff --git a/tools/buildbot/pylibs/twisted/internet/iocpreactor/notes.txt b/tools/buildbot/pylibs/twisted/internet/iocpreactor/notes.txt deleted file mode 100644 index 4caffb8..0000000 --- a/tools/buildbot/pylibs/twisted/internet/iocpreactor/notes.txt +++ /dev/null @@ -1,24 +0,0 @@ -test specifically: -failed accept error message -- similar to test_tcp_internals -immediate success on accept/connect/recv, including Event.ignore -parametrize iocpsupport somehow -- via reactor? - -do: -break handling -- WaitForSingleObject on the IOCP handle? -iovecs for write buffer -do not wait for a mainloop iteration if resumeProducing (in _handleWrite) does startWriting -don't addActiveHandle in every call to startWriting/startReading -iocpified process support - win32er-in-a-thread (or run GQCS in a thread -- it can't receive SIGBREAK) -blocking in sendto() -- I think Windows can do that, especially with local UDP - -buildbot: -run in vmware -start from a persistent snapshot - -use a stub inside the vm to svnup/run tests/collect stdio -lift logs through SMB? or ship them via tcp beams to the VM host - -have a timeout on the test run -if we time out, take a screenshot, save it, kill the VM - diff --git a/tools/buildbot/pylibs/twisted/internet/iocpreactor/reactor.py b/tools/buildbot/pylibs/twisted/internet/iocpreactor/reactor.py deleted file mode 100644 index 08c4a36..0000000 --- a/tools/buildbot/pylibs/twisted/internet/iocpreactor/reactor.py +++ /dev/null @@ -1,211 +0,0 @@ -# -*- test-case-name: twisted.internet.test.test_iocp -*- - -# Copyright (c) 2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Reactor that uses IO completion ports -""" - - -from twisted.internet import base, interfaces, main, error -from twisted.python import log, failure -from twisted.internet._dumbwin32proc import Process - -from zope.interface import implements -import socket, sys - -from twisted.internet.iocpreactor import iocpsupport as _iocp -from twisted.internet.iocpreactor.const import WAIT_TIMEOUT -from twisted.internet.iocpreactor import tcp, udp - -from twisted.python.compat import set - -MAX_TIMEOUT = 2000 # 2 seconds, see doIteration for explanation - -EVENTS_PER_LOOP = 1000 # XXX: what's a good value here? - -# keys to associate with normal and waker events -KEY_NORMAL, KEY_WAKEUP = range(2) - -_NO_GETHANDLE = error.ConnectionFdescWentAway( - 'Handler has no getFileHandle method') -_NO_FILEDESC = error.ConnectionFdescWentAway('Filedescriptor went away') - - - -class IOCPReactor(base._SignalReactorMixin, base.ReactorBase): - implements(interfaces.IReactorTCP, interfaces.IReactorUDP, - interfaces.IReactorMulticast, interfaces.IReactorProcess) - - port = None - - def __init__(self): - base.ReactorBase.__init__(self) - self.port = _iocp.CompletionPort() - self.handles = set() - - - def addActiveHandle(self, handle): - self.handles.add(handle) - - - def removeActiveHandle(self, handle): - self.handles.discard(handle) - - - def doIteration(self, timeout): - # This function sits and waits for an IO completion event. - # - # There are two requirements: process IO events as soon as they arrive - # and process ctrl-break from the user in a reasonable amount of time. - # - # There are three kinds of waiting. - # 1) GetQueuedCompletionStatus (self.port.getEvent) to wait for IO - # events only. - # 2) Msg* family of wait functions that can stop waiting when - # ctrl-break is detected (then, I think, Python converts it into a - # KeyboardInterrupt) - # 3) *Ex family of wait functions that put the thread into an - # "alertable" wait state which is supposedly triggered by IO completion - # - # 2) and 3) can be combined. Trouble is, my IO completion is not - # causing 3) to trigger, possibly because I do not use an IO completion - # callback. Windows is weird. - # There are two ways to handle this. I could use MsgWaitForSingleObject - # here and GetQueuedCompletionStatus in a thread. Or I could poll with - # a reasonable interval. Guess what! Threads are hard. - - processed_events = 0 - if timeout is None: - timeout = MAX_TIMEOUT - else: - timeout = min(MAX_TIMEOUT, int(1000*timeout)) - rc, bytes, key, evt = self.port.getEvent(timeout) - while processed_events < EVENTS_PER_LOOP: - if rc == WAIT_TIMEOUT: - break - if key != KEY_WAKEUP: - assert key == KEY_NORMAL - if not evt.ignore: - log.callWithLogger(evt.owner, self._callEventCallback, - rc, bytes, evt) - processed_events += 1 - rc, bytes, key, evt = self.port.getEvent(0) - - - def _callEventCallback(self, rc, bytes, evt): - owner = evt.owner - why = None - try: - evt.callback(rc, bytes, evt) - handfn = getattr(owner, 'getFileHandle', None) - if not handfn: - why = _NO_GETHANDLE - elif handfn() == -1: - why = _NO_FILEDESC - if why: - return # ignore handles that were closed - except: - why = sys.exc_info()[1] - log.err() - if why: - owner.loseConnection(failure.Failure(why)) - - - def installWaker(self): - pass - - - def wakeUp(self): - self.port.postEvent(0, KEY_WAKEUP, None) - - - def registerHandle(self, handle): - self.port.addHandle(handle, KEY_NORMAL) - - - def createSocket(self, af, stype): - skt = socket.socket(af, stype) - self.registerHandle(skt.fileno()) - return skt - - - def listenTCP(self, port, factory, backlog=50, interface=''): - """ - @see: twisted.internet.interfaces.IReactorTCP.listenTCP - """ - p = tcp.Port(port, factory, backlog, interface, self) - p.startListening() - return p - - - def connectTCP(self, host, port, factory, timeout=30, bindAddress=None): - """ - @see: twisted.internet.interfaces.IReactorTCP.connectTCP - """ - c = tcp.Connector(host, port, factory, timeout, bindAddress, self) - c.connect() - return c - - - def listenUDP(self, port, protocol, interface='', maxPacketSize=8192): - """ - Connects a given L{DatagramProtocol} to the given numeric UDP port. - - @returns: object conforming to L{IListeningPort}. - """ - p = udp.Port(port, protocol, interface, maxPacketSize, self) - p.startListening() - return p - - - def listenMulticast(self, port, protocol, interface='', maxPacketSize=8192, - listenMultiple=False): - """ - Connects a given DatagramProtocol to the given numeric UDP port. - - EXPERIMENTAL. - - @returns: object conforming to IListeningPort. - """ - p = udp.MulticastPort(port, protocol, interface, maxPacketSize, self, - listenMultiple) - p.startListening() - return p - - - def spawnProcess(self, processProtocol, executable, args=(), env={}, - path=None, uid=None, gid=None, usePTY=0, childFDs=None): - """ - Spawn a process. - """ - if uid is not None: - raise ValueError("Setting UID is unsupported on this platform.") - if gid is not None: - raise ValueError("Setting GID is unsupported on this platform.") - if usePTY: - raise ValueError("PTYs are unsupported on this platform.") - if childFDs is not None: - raise ValueError( - "Custom child file descriptor mappings are unsupported on " - "this platform.") - args, env = self._checkProcessArgs(args, env) - return Process(self, processProtocol, executable, args, env, path) - - - def removeAll(self): - res = list(self.handles) - self.handles.clear() - return res - - - -def install(): - r = IOCPReactor() - main.installReactor(r) - - -__all__ = ['IOCPReactor', 'install'] - diff --git a/tools/buildbot/pylibs/twisted/internet/iocpreactor/setup.py b/tools/buildbot/pylibs/twisted/internet/iocpreactor/setup.py deleted file mode 100644 index 6a70d55..0000000 --- a/tools/buildbot/pylibs/twisted/internet/iocpreactor/setup.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (c) 2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Distutils file for building low-level IOCP bindings from their Pyrex source -""" - - -from distutils.core import setup -from distutils.extension import Extension -from Pyrex.Distutils import build_ext - -setup(name='iocpsupport', - ext_modules=[Extension('iocpsupport', - ['iocpsupport/iocpsupport.pyx', - 'iocpsupport/winsock_pointers.c'], - libraries = ['ws2_32'], - ) - ], - cmdclass = {'build_ext': build_ext}, - ) - diff --git a/tools/buildbot/pylibs/twisted/internet/iocpreactor/tcp.py b/tools/buildbot/pylibs/twisted/internet/iocpreactor/tcp.py deleted file mode 100644 index 2300bef..0000000 --- a/tools/buildbot/pylibs/twisted/internet/iocpreactor/tcp.py +++ /dev/null @@ -1,497 +0,0 @@ -# Copyright (c) 2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -TCP support for IOCP reactor -""" - -from twisted.internet import interfaces, error, address, main, defer -from twisted.internet.abstract import isIPAddress -from twisted.internet.tcp import _SocketCloser, Connector as TCPConnector -from twisted.persisted import styles -from twisted.python import log, failure, reflect, util - -from zope.interface import implements -import socket, operator, errno, struct - -from twisted.internet.iocpreactor import iocpsupport as _iocp, abstract -from twisted.internet.iocpreactor.interfaces import IReadWriteHandle -from twisted.internet.iocpreactor.const import ERROR_IO_PENDING -from twisted.internet.iocpreactor.const import SO_UPDATE_CONNECT_CONTEXT -from twisted.internet.iocpreactor.const import SO_UPDATE_ACCEPT_CONTEXT -from twisted.internet.iocpreactor.const import ERROR_CONNECTION_REFUSED -from twisted.internet.iocpreactor.const import ERROR_NETWORK_UNREACHABLE - -# ConnectEx returns these. XXX: find out what it does for timeout -connectExErrors = { - ERROR_CONNECTION_REFUSED: errno.WSAECONNREFUSED, - ERROR_NETWORK_UNREACHABLE: errno.WSAENETUNREACH, - } - - - -class Connection(abstract.FileHandle, _SocketCloser): - implements(IReadWriteHandle, interfaces.ITCPTransport, - interfaces.ISystemHandle) - - - def __init__(self, sock, proto, reactor=None): - abstract.FileHandle.__init__(self, reactor) - self.socket = sock - self.getFileHandle = sock.fileno - self.protocol = proto - - - def getHandle(self): - return self.socket - - - def dataReceived(self, rbuffer): - # XXX: some day, we'll have protocols that can handle raw buffers - self.protocol.dataReceived(str(rbuffer)) - - - def readFromHandle(self, bufflist, evt): - return _iocp.recv(self.getFileHandle(), bufflist, evt) - - - def writeToHandle(self, buff, evt): - return _iocp.send(self.getFileHandle(), buff, evt) - - - def _closeWriteConnection(self): - try: - getattr(self.socket, self._socketShutdownMethod)(1) - except socket.error: - pass - p = interfaces.IHalfCloseableProtocol(self.protocol, None) - if p: - try: - p.writeConnectionLost() - except: - f = failure.Failure() - log.err() - self.connectionLost(f) - - - def readConnectionLost(self, reason): - p = interfaces.IHalfCloseableProtocol(self.protocol, None) - if p: - try: - p.readConnectionLost() - except: - log.err() - self.connectionLost(failure.Failure()) - else: - self.connectionLost(reason) - - - def connectionLost(self, reason): - abstract.FileHandle.connectionLost(self, reason) - self._closeSocket() - protocol = self.protocol - del self.protocol - del self.socket - del self.getFileHandle - protocol.connectionLost(reason) - - - def logPrefix(self): - """ - Return the prefix to log with when I own the logging thread. - """ - return self.logstr - - - def getTcpNoDelay(self): - return operator.truth(self.socket.getsockopt(socket.IPPROTO_TCP, - socket.TCP_NODELAY)) - - - def setTcpNoDelay(self, enabled): - self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, enabled) - - - def getTcpKeepAlive(self): - return operator.truth(self.socket.getsockopt(socket.SOL_SOCKET, - socket.SO_KEEPALIVE)) - - - def setTcpKeepAlive(self, enabled): - self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, enabled) - - - -class Client(Connection): - addressFamily = socket.AF_INET - socketType = socket.SOCK_STREAM - - - def __init__(self, host, port, bindAddress, connector, reactor): - self.connector = connector - self.addr = (host, port) - self.reactor = reactor - # ConnectEx documentation says socket _has_ to be bound - if bindAddress is None: - bindAddress = ('', 0) - - try: - try: - skt = reactor.createSocket(self.addressFamily, self.socketType) - except socket.error, se: - raise error.ConnectBindError(se[0], se[1]) - else: - try: - skt.bind(bindAddress) - except socket.error, se: - raise error.ConnectBindError(se[0], se[1]) - self.socket = skt - Connection.__init__(self, skt, None) - reactor.callLater(0, self.resolveAddress) - except error.ConnectBindError, err: - reactor.callLater(0, self.failIfNotConnected, err) - - - def resolveAddress(self): - if isIPAddress(self.addr[0]): - self._setRealAddress(self.addr[0]) - else: - d = self.reactor.resolve(self.addr[0]) - d.addCallbacks(self._setRealAddress, self.failIfNotConnected) - - - def _setRealAddress(self, address): - self.realAddress = (address, self.addr[1]) - self.doConnect() - - - def failIfNotConnected(self, err): - if (self.connected or self.disconnected or - not hasattr(self, "connector")): - return - - try: - self._closeSocket() - except AttributeError: - pass - else: - del self.socket, self.getFileHandle - self.reactor.removeActiveHandle(self) - - self.connector.connectionFailed(failure.Failure(err)) - del self.connector - - - def stopConnecting(self): - """ - Stop attempt to connect. - """ - self.failIfNotConnected(error.UserError()) - - - def cbConnect(self, rc, bytes, evt): - if rc: - rc = connectExErrors.get(rc, rc) - self.failIfNotConnected(error.getConnectError((rc, - errno.errorcode.get(rc, 'Unknown error')))) - else: - self.socket.setsockopt(socket.SOL_SOCKET, - SO_UPDATE_CONNECT_CONTEXT, - struct.pack('I', self.socket.fileno())) - self.protocol = self.connector.buildProtocol(self.getPeer()) - self.connected = True - self.logstr = self.protocol.__class__.__name__+",client" - self.protocol.makeConnection(self) - self.startReading() - - - def doConnect(self): - if not hasattr(self, "connector"): - # this happens if we connector.stopConnecting in - # factory.startedConnecting - return - assert _iocp.have_connectex - self.reactor.addActiveHandle(self) - evt = _iocp.Event(self.cbConnect, self) - - rc = _iocp.connect(self.socket.fileno(), self.realAddress, evt) - if rc == ERROR_IO_PENDING: - return - else: - evt.ignore = True - self.cbConnect(rc, 0, 0, evt) - - - def getHost(self): - """ - Returns an IPv4Address. - - This indicates the address from which I am connecting. - """ - return address.IPv4Address('TCP', *(self.socket.getsockname() + - ('INET',))) - - - def getPeer(self): - """ - Returns an IPv4Address. - - This indicates the address that I am connected to. - """ - return address.IPv4Address('TCP', *(self.addr + ('INET',))) - - - def __repr__(self): - s = ('<%s to %s at %x>' % - (self.__class__, self.addr, util.unsignedID(self))) - return s - - - def connectionLost(self, reason): - if not self.connected: - self.failIfNotConnected(error.ConnectError(string=reason)) - else: - Connection.connectionLost(self, reason) - self.connector.connectionLost(reason) - - - -class Server(Connection): - """ - Serverside socket-stream connection class. - - I am a serverside network connection transport; a socket which came from an - accept() on a server. - """ - - - def __init__(self, sock, protocol, clientAddr, serverAddr, sessionno): - """ - Server(sock, protocol, client, server, sessionno) - - Initialize me with a socket, a protocol, a descriptor for my peer (a - tuple of host, port describing the other end of the connection), an - instance of Port, and a session number. - """ - Connection.__init__(self, sock, protocol) - self.serverAddr = serverAddr - self.clientAddr = clientAddr - self.sessionno = sessionno - self.logstr = "%s,%s,%s" % (self.protocol.__class__.__name__, - sessionno, self.clientAddr.host) - self.repstr = "<%s #%s on %s>" % (self.protocol.__class__.__name__, - self.sessionno, self.serverAddr.port) - self.connected = True - self.startReading() - - - def __repr__(self): - """ - A string representation of this connection. - """ - return self.repstr - - - def getHost(self): - """ - Returns an IPv4Address. - - This indicates the server's address. - """ - return self.serverAddr - - - def getPeer(self): - """ - Returns an IPv4Address. - - This indicates the client's address. - """ - return self.clientAddr - - - -class Connector(TCPConnector): - def _makeTransport(self): - return Client(self.host, self.port, self.bindAddress, self, - self.reactor) - - - -class Port(styles.Ephemeral, _SocketCloser): - implements(interfaces.IListeningPort) - - connected = False - disconnected = False - disconnecting = False - addressFamily = socket.AF_INET - socketType = socket.SOCK_STREAM - - sessionno = 0 - - maxAccepts = 100 - - # Actual port number being listened on, only set to a non-None - # value when we are actually listening. - _realPortNumber = None - - - def __init__(self, port, factory, backlog=50, interface='', reactor=None): - self.port = port - self.factory = factory - self.backlog = backlog - self.interface = interface - self.reactor = reactor - - skt = socket.socket(self.addressFamily, self.socketType) - self.addrLen = _iocp.maxAddrLen(skt.fileno()) - - - def __repr__(self): - if self._realPortNumber is not None: - return "<%s of %s on %s>" % (self.__class__, - self.factory.__class__, - self._realPortNumber) - else: - return "<%s of %s (not listening)>" % (self.__class__, - self.factory.__class__) - - - def startListening(self): - try: - skt = self.reactor.createSocket(self.addressFamily, - self.socketType) - # TODO: resolve self.interface if necessary - skt.bind((self.interface, self.port)) - except socket.error, le: - raise error.CannotListenError, (self.interface, self.port, le) - - # Make sure that if we listened on port 0, we update that to - # reflect what the OS actually assigned us. - self._realPortNumber = skt.getsockname()[1] - - log.msg("%s starting on %s" % (self.factory.__class__, - self._realPortNumber)) - - self.factory.doStart() - skt.listen(self.backlog) - self.connected = True - self.reactor.addActiveHandle(self) - self.socket = skt - self.getFileHandle = self.socket.fileno - self.doAccept() - - - def loseConnection(self, connDone=failure.Failure(main.CONNECTION_DONE)): - """ - Stop accepting connections on this port. - - This will shut down my socket and call self.connectionLost(). - It returns a deferred which will fire successfully when the - port is actually closed. - """ - self.disconnecting = True - if self.connected: - self.deferred = defer.Deferred() - self.reactor.callLater(0, self.connectionLost, connDone) - return self.deferred - - stopListening = loseConnection - - - def connectionLost(self, reason): - """ - Cleans up my socket. - """ - log.msg('(Port %s Closed)' % self._realPortNumber) - self._realPortNumber = None - self.disconnected = True - self.reactor.removeActiveHandle(self) - self.connected = False - self._closeSocket() - del self.socket - del self.getFileHandle - self.factory.doStop() - if hasattr(self, "deferred"): - self.deferred.callback(None) - del self.deferred - - - def logPrefix(self): - """ - Returns the name of my class, to prefix log entries with. - """ - return reflect.qual(self.factory.__class__) - - - def getHost(self): - """ - Returns an IPv4Address. - - This indicates the server's address. - """ - return address.IPv4Address('TCP', *(self.socket.getsockname() + - ('INET',))) - - - def cbAccept(self, rc, bytes, evt): - self.handleAccept(rc, evt) - if not (self.disconnecting or self.disconnected): - self.doAccept() - - - def handleAccept(self, rc, evt): - if self.disconnecting or self.disconnected: - return False - - # possible errors: - # (WSAEMFILE, WSAENOBUFS, WSAENFILE, WSAENOMEM, WSAECONNABORTED) - if rc: - log.msg("Could not accept new connection -- %s (%s)" % - (errno.errorcode.get(rc, 'unknown error'), rc)) - return False - else: - evt.newskt.setsockopt(socket.SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, - struct.pack('I', self.socket.fileno())) - family, lAddr, rAddr = _iocp.get_accept_addrs(evt.newskt.fileno(), - evt.buff) - assert family == self.addressFamily - - protocol = self.factory.buildProtocol( - address._ServerFactoryIPv4Address('TCP', rAddr[0], rAddr[1])) - if protocol is None: - evt.newskt.close() - else: - s = self.sessionno - self.sessionno = s+1 - transport = Server(evt.newskt, protocol, - address.IPv4Address('TCP', rAddr[0], rAddr[1], 'INET'), - address.IPv4Address('TCP', lAddr[0], lAddr[1], 'INET'), - s) - protocol.makeConnection(transport) - return True - - - def doAccept(self): - numAccepts = 0 - while 1: - evt = _iocp.Event(self.cbAccept, self) - - # see AcceptEx documentation - evt.buff = buff = _iocp.AllocateReadBuffer(2 * (self.addrLen + 16)) - - evt.newskt = newskt = self.reactor.createSocket(self.addressFamily, - self.socketType) - rc = _iocp.accept(self.socket.fileno(), newskt.fileno(), buff, evt) - - if (rc == ERROR_IO_PENDING - or (not rc and numAccepts >= self.maxAccepts)): - break - else: - evt.ignore = True - if not self.handleAccept(rc, evt): - break - numAccepts += 1 - - diff --git a/tools/buildbot/pylibs/twisted/internet/iocpreactor/udp.py b/tools/buildbot/pylibs/twisted/internet/iocpreactor/udp.py deleted file mode 100644 index c0e1a8e..0000000 --- a/tools/buildbot/pylibs/twisted/internet/iocpreactor/udp.py +++ /dev/null @@ -1,389 +0,0 @@ -# Copyright (c) 2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -UDP support for IOCP reactor -""" - -from twisted.internet import defer, address, error, interfaces -from twisted.internet.abstract import isIPAddress -from twisted.python import log, reflect, failure - -from zope.interface import implements -import socket, operator, struct, warnings, errno - -from twisted.internet.iocpreactor.const import ERROR_IO_PENDING -from twisted.internet.iocpreactor.const import ERROR_CONNECTION_REFUSED -from twisted.internet.iocpreactor.const import ERROR_PORT_UNREACHABLE -from twisted.internet.iocpreactor.interfaces import IReadWriteHandle -from twisted.internet.iocpreactor import iocpsupport as _iocp, abstract - - - -class Port(abstract.FileHandle): - """ - UDP port, listening for packets. - """ - - implements(IReadWriteHandle, interfaces.IUDPTransport, - interfaces.ISystemHandle) - - addressFamily = socket.AF_INET - socketType = socket.SOCK_DGRAM - maxThroughput = 256 * 1024 # max bytes we read in one eventloop iteration - dynamicReadBuffers = False - - # Actual port number being listened on, only set to a non-None - # value when we are actually listening. - _realPortNumber = None - - - def __init__(self, port, proto, interface='', maxPacketSize=8192, - reactor=None): - """ - Initialize with a numeric port to listen on. - """ - self.port = port - self.protocol = proto - self.readBufferSize = maxPacketSize - self.interface = interface - self.setLogStr() - self._connectedAddr = None - - abstract.FileHandle.__init__(self, reactor) - - skt = socket.socket(self.addressFamily, self.socketType) - addrLen = _iocp.maxAddrLen(skt.fileno()) - self.addressBuffer = _iocp.AllocateReadBuffer(addrLen) - - - def __repr__(self): - if self._realPortNumber is not None: - return ("<%s on %s>" % - (self.protocol.__class__, self._realPortNumber)) - else: - return "<%s not connected>" % (self.protocol.__class__,) - - - def getHandle(self): - """ - Return a socket object. - """ - return self.socket - - - def startListening(self): - """ - Create and bind my socket, and begin listening on it. - - This is called on unserialization, and must be called after creating a - server to begin listening on the specified port. - """ - self._bindSocket() - self._connectToProtocol() - - - def createSocket(self): - return self.reactor.createSocket(self.addressFamily, self.socketType) - - - def _bindSocket(self): - try: - skt = self.createSocket() - skt.bind((self.interface, self.port)) - except socket.error, le: - raise error.CannotListenError, (self.interface, self.port, le) - - # Make sure that if we listened on port 0, we update that to - # reflect what the OS actually assigned us. - self._realPortNumber = skt.getsockname()[1] - - log.msg("%s starting on %s" % - (self.protocol.__class__, self._realPortNumber)) - - self.connected = True - self.socket = skt - self.getFileHandle = self.socket.fileno - - - def _connectToProtocol(self): - self.protocol.makeConnection(self) - self.startReading() - self.reactor.addActiveHandle(self) - - - def cbRead(self, rc, bytes, evt): - if self.reading: - self.handleRead(rc, bytes, evt) - self.doRead() - - - def handleRead(self, rc, bytes, evt): - if rc in (errno.WSAECONNREFUSED, errno.WSAECONNRESET, - ERROR_CONNECTION_REFUSED, ERROR_PORT_UNREACHABLE): - if self._connectedAddr: - self.protocol.connectionRefused() - elif rc: - log.msg("error in recvfrom -- %s (%s)" % - (errno.errorcode.get(rc, 'unknown error'), rc)) - else: - try: - self.protocol.datagramReceived(str(evt.buff[:bytes]), - _iocp.makesockaddr(evt.addr_buff)) - except: - log.err() - - - def doRead(self): - read = 0 - while self.reading: - evt = _iocp.Event(self.cbRead, self) - - evt.buff = buff = self._readBuffers[0] - evt.addr_buff = addr_buff = self.addressBuffer - rc, bytes = _iocp.recvfrom(self.getFileHandle(), buff, - addr_buff, evt) - - if (rc == ERROR_IO_PENDING - or (not rc and read >= self.maxThroughput)): - break - else: - evt.ignore = True - self.handleRead(rc, bytes, evt) - read += bytes - - - def write(self, datagram, addr=None): - """ - Write a datagram. - - @param addr: should be a tuple (ip, port), can be None in connected - mode. - """ - if self._connectedAddr: - assert addr in (None, self._connectedAddr) - try: - return self.socket.send(datagram) - except socket.error, se: - no = se.args[0] - if no == errno.WSAEINTR: - return self.write(datagram) - elif no == errno.WSAEMSGSIZE: - raise error.MessageLengthError, "message too long" - elif no in (errno.WSAECONNREFUSED, errno.WSAECONNRESET, - ERROR_CONNECTION_REFUSED, ERROR_PORT_UNREACHABLE): - self.protocol.connectionRefused() - else: - raise - else: - assert addr != None - if not addr[0].replace(".", "").isdigit(): - warnings.warn("Please only pass IPs to write(), not hostnames", - DeprecationWarning, stacklevel=2) - try: - return self.socket.sendto(datagram, addr) - except socket.error, se: - no = se.args[0] - if no == errno.WSAEINTR: - return self.write(datagram, addr) - elif no == errno.WSAEMSGSIZE: - raise error.MessageLengthError, "message too long" - elif no in (errno.WSAECONNREFUSED, errno.WSAECONNRESET, - ERROR_CONNECTION_REFUSED, ERROR_PORT_UNREACHABLE): - # in non-connected UDP ECONNREFUSED is platform dependent, - # I think and the info is not necessarily useful. - # Nevertheless maybe we should call connectionRefused? XXX - return - else: - raise - - - def writeSequence(self, seq, addr): - self.write("".join(seq), addr) - - - def connect(self, host, port): - """ - 'Connect' to remote server. - """ - if self._connectedAddr: - raise RuntimeError( - "already connected, reconnecting is not currently supported " - "(talk to itamar if you want this)") - if not isIPAddress(host): - raise ValueError, "please pass only IP addresses, not domain names" - self._connectedAddr = (host, port) - self.socket.connect((host, port)) - - - def _loseConnection(self): - self.stopReading() - self.reactor.removeActiveHandle(self) - if self.connected: # actually means if we are *listening* - from twisted.internet import reactor - reactor.callLater(0, self.connectionLost) - - - def stopListening(self): - if self.connected: - result = self.d = defer.Deferred() - else: - result = None - self._loseConnection() - return result - - - def loseConnection(self): - warnings.warn("Please use stopListening() to disconnect port", - DeprecationWarning, stacklevel=2) - self.stopListening() - - - def connectionLost(self, reason=None): - """ - Cleans up my socket. - """ - log.msg('(Port %s Closed)' % self._realPortNumber) - self._realPortNumber = None - self.stopReading() - if hasattr(self, "protocol"): - # we won't have attribute in ConnectedPort, in cases - # where there was an error in connection process - self.protocol.doStop() - self.connected = False - self.disconnected = True - self.socket.close() - del self.socket - del self.getFileHandle - if hasattr(self, "d"): - self.d.callback(None) - del self.d - - - def setLogStr(self): - self.logstr = reflect.qual(self.protocol.__class__) + " (UDP)" - - - def logPrefix(self): - """ - Returns the name of my class, to prefix log entries with. - """ - return self.logstr - - - def getHost(self): - """ - Returns an IPv4Address. - - This indicates the address from which I am connecting. - """ - return address.IPv4Address('UDP', *(self.socket.getsockname() + - ('INET_UDP',))) - - - -class MulticastMixin: - """ - Implement multicast functionality. - """ - - - def getOutgoingInterface(self): - i = self.socket.getsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF) - return socket.inet_ntoa(struct.pack("@i", i)) - - - def setOutgoingInterface(self, addr): - """ - Returns Deferred of success. - """ - return self.reactor.resolve(addr).addCallback(self._setInterface) - - - def _setInterface(self, addr): - i = socket.inet_aton(addr) - self.socket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF, i) - return 1 - - - def getLoopbackMode(self): - return self.socket.getsockopt(socket.IPPROTO_IP, - socket.IP_MULTICAST_LOOP) - - - def setLoopbackMode(self, mode): - mode = struct.pack("b", operator.truth(mode)) - self.socket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, - mode) - - - def getTTL(self): - return self.socket.getsockopt(socket.IPPROTO_IP, - socket.IP_MULTICAST_TTL) - - - def setTTL(self, ttl): - ttl = struct.pack("B", ttl) - self.socket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl) - - - def joinGroup(self, addr, interface=""): - """ - Join a multicast group. Returns Deferred of success. - """ - return self.reactor.resolve(addr).addCallback(self._joinAddr1, - interface, 1) - - - def _joinAddr1(self, addr, interface, join): - return self.reactor.resolve(interface).addCallback(self._joinAddr2, - addr, join) - - - def _joinAddr2(self, interface, addr, join): - addr = socket.inet_aton(addr) - interface = socket.inet_aton(interface) - if join: - cmd = socket.IP_ADD_MEMBERSHIP - else: - cmd = socket.IP_DROP_MEMBERSHIP - try: - self.socket.setsockopt(socket.IPPROTO_IP, cmd, addr + interface) - except socket.error, e: - return failure.Failure(error.MulticastJoinError(addr, interface, - *e.args)) - - - def leaveGroup(self, addr, interface=""): - """ - Leave multicast group, return Deferred of success. - """ - return self.reactor.resolve(addr).addCallback(self._joinAddr1, - interface, 0) - - - -class MulticastPort(MulticastMixin, Port): - """ - UDP Port that supports multicasting. - """ - - implements(interfaces.IMulticastTransport) - - - def __init__(self, port, proto, interface='', maxPacketSize=8192, - reactor=None, listenMultiple=False): - Port.__init__(self, port, proto, interface, maxPacketSize, reactor) - self.listenMultiple = listenMultiple - - - def createSocket(self): - skt = Port.createSocket(self) - if self.listenMultiple: - skt.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - if hasattr(socket, "SO_REUSEPORT"): - skt.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) - return skt - - diff --git a/tools/buildbot/pylibs/twisted/internet/kqreactor.py b/tools/buildbot/pylibs/twisted/internet/kqreactor.py deleted file mode 100644 index 8de615c..0000000 --- a/tools/buildbot/pylibs/twisted/internet/kqreactor.py +++ /dev/null @@ -1,232 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -A kqueue()/kevent() based implementation of the Twisted main loop. - -To install the event loop (and you should do this before any connections, -listeners or connectors are added):: - - | from twisted.internet import kqreactor - | kqreactor.install() - -This reactor only works on FreeBSD and requires PyKQueue 1.3, which is -available at: U{http://people.freebsd.org/~dwhite/PyKQueue/} - -Maintainer: U{Itamar Shtull-Trauring} - - - -You're going to need to patch PyKqueue:: - - ===================================================== - --- PyKQueue-1.3/kqsyscallmodule.c Sun Jan 28 21:59:50 2001 - +++ PyKQueue-1.3/kqsyscallmodule.c.new Tue Jul 30 18:06:08 2002 - @@ -137,7 +137,7 @@ - } - - statichere PyTypeObject KQEvent_Type = { - - PyObject_HEAD_INIT(NULL) - + PyObject_HEAD_INIT(&PyType_Type) - 0, // ob_size - "KQEvent", // tp_name - sizeof(KQEventObject), // tp_basicsize - @@ -291,13 +291,14 @@ - - /* Build timespec for timeout */ - totimespec.tv_sec = timeout / 1000; - - totimespec.tv_nsec = (timeout % 1000) * 100000; - + totimespec.tv_nsec = (timeout % 1000) * 1000000; - - // printf("timespec: sec=%d nsec=%d\\n", totimespec.tv_sec, totimespec.tv_nsec); - - /* Make the call */ - - - + Py_BEGIN_ALLOW_THREADS - gotNumEvents = kevent (self->fd, changelist, haveNumEvents, triggered, wantNumEvents, &totimespec); - + Py_END_ALLOW_THREADS - - /* Don't need the input event list anymore, so get rid of it */ - free (changelist); - @@ -361,7 +362,7 @@ - statichere PyTypeObject KQueue_Type = { - /* The ob_type field must be initialized in the module init function - * to be portable to Windows without using C++. */ - - PyObject_HEAD_INIT(NULL) - + PyObject_HEAD_INIT(&PyType_Type) - 0, /*ob_size*/ - "KQueue", /*tp_name*/ - sizeof(KQueueObject), /*tp_basicsize*/ - -""" - -import errno, sys - -from zope.interface import implements - -from kqsyscall import EVFILT_READ, EVFILT_WRITE, EV_DELETE, EV_ADD -from kqsyscall import kqueue, kevent - -from twisted.internet.interfaces import IReactorFDSet - -from twisted.python import log, failure -from twisted.internet import main, posixbase - - -class KQueueReactor(posixbase.PosixReactorBase): - """ - A reactor that uses kqueue(2)/kevent(2). - - @ivar _kq: A L{kqueue} which will be used to check for I/O readiness. - - @ivar _selectables: A dictionary mapping integer file descriptors to - instances of L{FileDescriptor} which have been registered with the - reactor. All L{FileDescriptors} which are currently receiving read or - write readiness notifications will be present as values in this - dictionary. - - @ivar _reads: A dictionary mapping integer file descriptors to arbitrary - values (this is essentially a set). Keys in this dictionary will be - registered with C{_kq} for read readiness notifications which will be - dispatched to the corresponding L{FileDescriptor} instances in - C{_selectables}. - - @ivar _writes: A dictionary mapping integer file descriptors to arbitrary - values (this is essentially a set). Keys in this dictionary will be - registered with C{_kq} for write readiness notifications which will be - dispatched to the corresponding L{FileDescriptor} instances in - C{_selectables}. - """ - implements(IReactorFDSet) - - def __init__(self): - """ - Initialize kqueue object, file descriptor tracking dictionaries, and the - base class. - """ - self._kq = kqueue() - self._reads = {} - self._writes = {} - self._selectables = {} - posixbase.PosixReactorBase.__init__(self) - - - def _updateRegistration(self, *args): - self._kq.kevent([kevent(*args)], 0, 0) - - def addReader(self, reader): - """Add a FileDescriptor for notification of data available to read. - """ - fd = reader.fileno() - if fd not in self._reads: - self._selectables[fd] = reader - self._reads[fd] = 1 - self._updateRegistration(fd, EVFILT_READ, EV_ADD) - - def addWriter(self, writer): - """Add a FileDescriptor for notification of data available to write. - """ - fd = writer.fileno() - if fd not in self._writes: - self._selectables[fd] = writer - self._writes[fd] = 1 - self._updateRegistration(fd, EVFILT_WRITE, EV_ADD) - - def removeReader(self, reader): - """Remove a Selectable for notification of data available to read. - """ - fd = reader.fileno() - if fd in self._reads: - del self._reads[fd] - if fd not in self._writes: - del self._selectables[fd] - self._updateRegistration(fd, EVFILT_READ, EV_DELETE) - - def removeWriter(self, writer): - """Remove a Selectable for notification of data available to write. - """ - fd = writer.fileno() - if fd in self._writes: - del self._writes[fd] - if fd not in self._reads: - del self._selectables[fd] - self._updateRegistration(fd, EVFILT_WRITE, EV_DELETE) - - def removeAll(self): - """Remove all selectables, and return a list of them.""" - if self.waker is not None: - self.removeReader(self.waker) - result = self._selectables.values() - for fd in self._reads.keys(): - self._updateRegistration(fd, EVFILT_READ, EV_DELETE) - for fd in self._writes.keys(): - self._updateRegistration(fd, EVFILT_WRITE, EV_DELETE) - self._reads.clear() - self._writes.clear() - self._selectables.clear() - if self.waker is not None: - self.addReader(self.waker) - return result - - - def getReaders(self): - return [self._selectables[fd] for fd in self._reads] - - - def getWriters(self): - return [self._selectables[fd] for fd in self._writes] - - - def doKEvent(self, timeout): - """Poll the kqueue for new events.""" - if timeout is None: - timeout = 1000 - else: - timeout = int(timeout * 1000) # convert seconds to milliseconds - - try: - l = self._kq.kevent([], len(self._selectables), timeout) - except OSError, e: - if e[0] == errno.EINTR: - return - else: - raise - _drdw = self._doWriteOrRead - for event in l: - why = None - fd, filter = event.ident, event.filter - try: - selectable = self._selectables[fd] - except KeyError: - # Handles the infrequent case where one selectable's - # handler disconnects another. - continue - log.callWithLogger(selectable, _drdw, selectable, fd, filter) - - def _doWriteOrRead(self, selectable, fd, filter): - try: - if filter == EVFILT_READ: - why = selectable.doRead() - if filter == EVFILT_WRITE: - why = selectable.doWrite() - if not selectable.fileno() == fd: - why = main.CONNECTION_LOST - except: - why = sys.exc_info()[1] - log.deferr() - - if why: - self.removeReader(selectable) - self.removeWriter(selectable) - selectable.connectionLost(failure.Failure(why)) - - doIteration = doKEvent - - -def install(): - k = KQueueReactor() - main.installReactor(k) - - -__all__ = ["KQueueReactor", "install"] diff --git a/tools/buildbot/pylibs/twisted/internet/main.py b/tools/buildbot/pylibs/twisted/internet/main.py deleted file mode 100644 index d8c5a5c..0000000 --- a/tools/buildbot/pylibs/twisted/internet/main.py +++ /dev/null @@ -1,28 +0,0 @@ -# -*- test-case-name: twisted.test.test_app -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Backwards compatability, and utility functions. - -In general, this module should not be used, other than by reactor authors -who need to use the 'installReactor' method. - -Maintainer: U{Itamar Shtull-Trauring} -""" - -import error - -CONNECTION_DONE = error.ConnectionDone('Connection done') -CONNECTION_LOST = error.ConnectionLost('Connection lost') - -def installReactor(reactor): - # this stuff should be common to all reactors. - import twisted.internet - import sys - assert not sys.modules.has_key('twisted.internet.reactor'), \ - "reactor already installed" - twisted.internet.reactor = reactor - sys.modules['twisted.internet.reactor'] = reactor - -__all__ = ["CONNECTION_LOST", "CONNECTION_DONE", "installReactor"] diff --git a/tools/buildbot/pylibs/twisted/internet/pollreactor.py b/tools/buildbot/pylibs/twisted/internet/pollreactor.py deleted file mode 100644 index 353e006..0000000 --- a/tools/buildbot/pylibs/twisted/internet/pollreactor.py +++ /dev/null @@ -1,217 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -A poll() based implementation of the twisted main loop. - -To install the event loop (and you should do this before any connections, -listeners or connectors are added):: - - from twisted.internet import pollreactor - pollreactor.install() - -Maintainer: U{Itamar Shtull-Trauring} -""" - -# System imports -import errno, sys -from select import error as SelectError, poll -from select import POLLIN, POLLOUT, POLLHUP, POLLERR, POLLNVAL - -from zope.interface import implements - -# Twisted imports -from twisted.python import log -from twisted.internet import main, posixbase, error -from twisted.internet.interfaces import IReactorFDSet - -POLL_DISCONNECTED = (POLLHUP | POLLERR | POLLNVAL) - - -class PollReactor(posixbase.PosixReactorBase): - """ - A reactor that uses poll(2). - - @ivar _poller: A L{poll} which will be used to check for I/O - readiness. - - @ivar _selectables: A dictionary mapping integer file descriptors to - instances of L{FileDescriptor} which have been registered with the - reactor. All L{FileDescriptors} which are currently receiving read or - write readiness notifications will be present as values in this - dictionary. - - @ivar _reads: A dictionary mapping integer file descriptors to arbitrary - values (this is essentially a set). Keys in this dictionary will be - registered with C{_poller} for read readiness notifications which will - be dispatched to the corresponding L{FileDescriptor} instances in - C{_selectables}. - - @ivar _writes: A dictionary mapping integer file descriptors to arbitrary - values (this is essentially a set). Keys in this dictionary will be - registered with C{_poller} for write readiness notifications which will - be dispatched to the corresponding L{FileDescriptor} instances in - C{_selectables}. - """ - implements(IReactorFDSet) - - def __init__(self): - """ - Initialize polling object, file descriptor tracking dictionaries, and - the base class. - """ - self._poller = poll() - self._selectables = {} - self._reads = {} - self._writes = {} - posixbase.PosixReactorBase.__init__(self) - - - def _updateRegistration(self, fd): - """Register/unregister an fd with the poller.""" - try: - self._poller.unregister(fd) - except KeyError: - pass - - mask = 0 - if fd in self._reads: - mask = mask | POLLIN - if fd in self._writes: - mask = mask | POLLOUT - if mask != 0: - self._poller.register(fd, mask) - else: - if fd in self._selectables: - del self._selectables[fd] - - def _dictRemove(self, selectable, mdict): - try: - # the easy way - fd = selectable.fileno() - # make sure the fd is actually real. In some situations we can get - # -1 here. - mdict[fd] - except: - # the hard way: necessary because fileno() may disappear at any - # moment, thanks to python's underlying sockets impl - for fd, fdes in self._selectables.items(): - if selectable is fdes: - break - else: - # Hmm, maybe not the right course of action? This method can't - # fail, because it happens inside error detection... - return - if fd in mdict: - del mdict[fd] - self._updateRegistration(fd) - - def addReader(self, reader): - """Add a FileDescriptor for notification of data available to read. - """ - fd = reader.fileno() - if fd not in self._reads: - self._selectables[fd] = reader - self._reads[fd] = 1 - self._updateRegistration(fd) - - def addWriter(self, writer): - """Add a FileDescriptor for notification of data available to write. - """ - fd = writer.fileno() - if fd not in self._writes: - self._selectables[fd] = writer - self._writes[fd] = 1 - self._updateRegistration(fd) - - def removeReader(self, reader): - """Remove a Selectable for notification of data available to read. - """ - return self._dictRemove(reader, self._reads) - - def removeWriter(self, writer): - """Remove a Selectable for notification of data available to write. - """ - return self._dictRemove(writer, self._writes) - - def removeAll(self): - """Remove all selectables, and return a list of them.""" - if self.waker is not None: - self.removeReader(self.waker) - result = self._selectables.values() - fds = self._selectables.keys() - self._reads.clear() - self._writes.clear() - self._selectables.clear() - for fd in fds: - self._poller.unregister(fd) - - if self.waker is not None: - self.addReader(self.waker) - return result - - def doPoll(self, timeout): - """Poll the poller for new events.""" - if timeout is not None: - timeout = int(timeout * 1000) # convert seconds to milliseconds - - try: - l = self._poller.poll(timeout) - except SelectError, e: - if e[0] == errno.EINTR: - return - else: - raise - _drdw = self._doReadOrWrite - for fd, event in l: - try: - selectable = self._selectables[fd] - except KeyError: - # Handles the infrequent case where one selectable's - # handler disconnects another. - continue - log.callWithLogger(selectable, _drdw, selectable, fd, event) - - doIteration = doPoll - - def _doReadOrWrite(self, selectable, fd, event): - why = None - inRead = False - if event & POLL_DISCONNECTED and not (event & POLLIN): - why = main.CONNECTION_LOST - else: - try: - if event & POLLIN: - why = selectable.doRead() - inRead = True - if not why and event & POLLOUT: - why = selectable.doWrite() - inRead = False - if not selectable.fileno() == fd: - why = error.ConnectionFdescWentAway('Filedescriptor went away') - inRead = False - except: - log.deferr() - why = sys.exc_info()[1] - if why: - self._disconnectSelectable(selectable, why, inRead) - - - def getReaders(self): - return [self._selectables[fd] for fd in self._reads] - - - def getWriters(self): - return [self._selectables[fd] for fd in self._writes] - - - -def install(): - """Install the poll() reactor.""" - p = PollReactor() - from twisted.internet.main import installReactor - installReactor(p) - - -__all__ = ["PollReactor", "install"] diff --git a/tools/buildbot/pylibs/twisted/internet/posixbase.py b/tools/buildbot/pylibs/twisted/internet/posixbase.py deleted file mode 100644 index b0fc0f9..0000000 --- a/tools/buildbot/pylibs/twisted/internet/posixbase.py +++ /dev/null @@ -1,406 +0,0 @@ -# -*- test-case-name: twisted.test.test_internet -*- -# -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Posix reactor base class - -Maintainer: U{Itamar Shtull-Trauring} -""" - -import warnings -import socket -import errno -import os - -from zope.interface import implements, classImplements - -from twisted.internet.interfaces import IReactorUNIX, IReactorUNIXDatagram -from twisted.internet.interfaces import IReactorTCP, IReactorUDP, IReactorSSL, IReactorArbitrary -from twisted.internet.interfaces import IReactorProcess, IReactorMulticast -from twisted.internet.interfaces import IHalfCloseableDescriptor -from twisted.internet import error -from twisted.internet import tcp, udp - -from twisted.python import log, failure, util -from twisted.persisted import styles -from twisted.python.runtime import platformType, platform - -from twisted.internet.base import ReactorBase, _SignalReactorMixin - -try: - from twisted.internet import ssl - sslEnabled = True -except ImportError: - sslEnabled = False - -try: - from twisted.internet import unix - unixEnabled = True -except ImportError: - unixEnabled = False - -processEnabled = False -if platformType == 'posix': - from twisted.internet import fdesc - import process - processEnabled = True - -if platform.isWindows(): - try: - import win32process - processEnabled = True - except ImportError: - win32process = None - - -class _Win32Waker(log.Logger, styles.Ephemeral): - """I am a workaround for the lack of pipes on win32. - - I am a pair of connected sockets which can wake up the main loop - from another thread. - """ - disconnected = 0 - - def __init__(self, reactor): - """Initialize. - """ - self.reactor = reactor - # Following select_trigger (from asyncore)'s example; - server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - client.setsockopt(socket.IPPROTO_TCP, 1, 1) - server.bind(('127.0.0.1', 0)) - server.listen(1) - client.connect(server.getsockname()) - reader, clientaddr = server.accept() - client.setblocking(0) - reader.setblocking(0) - self.r = reader - self.w = client - self.fileno = self.r.fileno - - def wakeUp(self): - """Send a byte to my connection. - """ - try: - util.untilConcludes(self.w.send, 'x') - except socket.error, (err, msg): - if err != errno.WSAEWOULDBLOCK: - raise - - def doRead(self): - """Read some data from my connection. - """ - try: - self.r.recv(8192) - except socket.error: - pass - - def connectionLost(self, reason): - self.r.close() - self.w.close() - self.reactor.waker = None - -class _UnixWaker(log.Logger, styles.Ephemeral): - """This class provides a simple interface to wake up the event loop. - - This is used by threads or signals to wake up the event loop. - """ - disconnected = 0 - - i = None - o = None - - def __init__(self, reactor): - """Initialize. - """ - self.reactor = reactor - self.i, self.o = os.pipe() - fdesc.setNonBlocking(self.i) - fdesc.setNonBlocking(self.o) - self.fileno = lambda: self.i - - def doRead(self): - """Read some bytes from the pipe. - """ - fdesc.readFromFD(self.fileno(), lambda data: None) - - def wakeUp(self): - """Write one byte to the pipe, and flush it. - """ - # We don't use fdesc.writeToFD since we need to distinguish - # between EINTR (try again) and EAGAIN (do nothing). - if self.o is not None: - try: - util.untilConcludes(os.write, self.o, 'x') - except OSError, e: - if e.errno != errno.EAGAIN: - raise - - def connectionLost(self, reason): - """Close both ends of my pipe. - """ - if not hasattr(self, "o"): - return - for fd in self.i, self.o: - try: - os.close(fd) - except IOError: - pass - del self.i, self.o - self.reactor.waker = None - - -if platformType == 'posix': - _Waker = _UnixWaker -elif platformType == 'win32': - _Waker = _Win32Waker - - -class PosixReactorBase(_SignalReactorMixin, ReactorBase): - """ - A basis for reactors that use file descriptors. - """ - implements(IReactorArbitrary, IReactorTCP, IReactorUDP, IReactorMulticast) - - def __init__(self): - ReactorBase.__init__(self) - if self.usingThreads or platformType == "posix": - self.installWaker() - - - def _disconnectSelectable(self, selectable, why, isRead, faildict={ - error.ConnectionDone: failure.Failure(error.ConnectionDone()), - error.ConnectionLost: failure.Failure(error.ConnectionLost()) - }): - """ - Utility function for disconnecting a selectable. - - Supports half-close notification, isRead should be boolean indicating - whether error resulted from doRead(). - """ - self.removeReader(selectable) - f = faildict.get(why.__class__) - if f: - if (isRead and why.__class__ == error.ConnectionDone - and IHalfCloseableDescriptor.providedBy(selectable)): - selectable.readConnectionLost(f) - else: - self.removeWriter(selectable) - selectable.connectionLost(f) - else: - self.removeWriter(selectable) - selectable.connectionLost(failure.Failure(why)) - - def installWaker(self): - """ - Install a `waker' to allow threads and signals to wake up the IO thread. - - We use the self-pipe trick (http://cr.yp.to/docs/selfpipe.html) to wake - the reactor. On Windows we use a pair of sockets. - """ - if not self.waker: - self.waker = _Waker(self) - self.addReader(self.waker) - - - # IReactorProcess - - def spawnProcess(self, processProtocol, executable, args=(), - env={}, path=None, - uid=None, gid=None, usePTY=0, childFDs=None): - args, env = self._checkProcessArgs(args, env) - if platformType == 'posix': - if usePTY: - if childFDs is not None: - raise ValueError("Using childFDs is not supported with usePTY=True.") - return process.PTYProcess(self, executable, args, env, path, - processProtocol, uid, gid, usePTY) - else: - return process.Process(self, executable, args, env, path, - processProtocol, uid, gid, childFDs) - elif platformType == "win32": - if uid is not None or gid is not None: - raise ValueError("The uid and gid parameters are not supported on Windows.") - if usePTY: - raise ValueError("The usePTY parameter is not supported on Windows.") - if childFDs: - raise ValueError("Customizing childFDs is not supported on Windows.") - - if win32process: - from twisted.internet._dumbwin32proc import Process - return Process(self, processProtocol, executable, args, env, path) - else: - raise NotImplementedError, "spawnProcess not available since pywin32 is not installed." - else: - raise NotImplementedError, "spawnProcess only available on Windows or POSIX." - - # IReactorUDP - - def listenUDP(self, port, protocol, interface='', maxPacketSize=8192): - """Connects a given L{DatagramProtocol} to the given numeric UDP port. - - @returns: object conforming to L{IListeningPort}. - """ - p = udp.Port(port, protocol, interface, maxPacketSize, self) - p.startListening() - return p - - def connectUDP(self, remotehost, remoteport, protocol, localport=0, - interface='', maxPacketSize=8192): - """DEPRECATED. - - Connects a L{ConnectedDatagramProtocol} instance to a UDP port. - """ - warnings.warn("use listenUDP and then transport.connect().", DeprecationWarning, stacklevel=2) - p = udp.ConnectedPort((remotehost, remoteport), localport, protocol, interface, maxPacketSize, self) - p.startListening() - return p - - - # IReactorMulticast - - def listenMulticast(self, port, protocol, interface='', maxPacketSize=8192, listenMultiple=False): - """Connects a given DatagramProtocol to the given numeric UDP port. - - EXPERIMENTAL. - - @returns: object conforming to IListeningPort. - """ - p = udp.MulticastPort(port, protocol, interface, maxPacketSize, self, listenMultiple) - p.startListening() - return p - - - # IReactorUNIX - - def connectUNIX(self, address, factory, timeout=30, checkPID=0): - """@see: twisted.internet.interfaces.IReactorUNIX.connectUNIX - """ - assert unixEnabled, "UNIX support is not present" - c = unix.Connector(address, factory, timeout, self, checkPID) - c.connect() - return c - - def listenUNIX(self, address, factory, backlog=50, mode=0666, wantPID=0): - """@see: twisted.internet.interfaces.IReactorUNIX.listenUNIX - """ - assert unixEnabled, "UNIX support is not present" - p = unix.Port(address, factory, backlog, mode, self, wantPID) - p.startListening() - return p - - - # IReactorUNIXDatagram - - def listenUNIXDatagram(self, address, protocol, maxPacketSize=8192, mode=0666): - """Connects a given L{DatagramProtocol} to the given path. - - EXPERIMENTAL. - - @returns: object conforming to L{IListeningPort}. - """ - assert unixEnabled, "UNIX support is not present" - p = unix.DatagramPort(address, protocol, maxPacketSize, mode, self) - p.startListening() - return p - - def connectUNIXDatagram(self, address, protocol, maxPacketSize=8192, mode=0666, bindAddress=None): - """Connects a L{ConnectedDatagramProtocol} instance to a path. - - EXPERIMENTAL. - """ - assert unixEnabled, "UNIX support is not present" - p = unix.ConnectedDatagramPort(address, protocol, maxPacketSize, mode, bindAddress, self) - p.startListening() - return p - - - # IReactorTCP - - def listenTCP(self, port, factory, backlog=50, interface=''): - """@see: twisted.internet.interfaces.IReactorTCP.listenTCP - """ - p = tcp.Port(port, factory, backlog, interface, self) - p.startListening() - return p - - def connectTCP(self, host, port, factory, timeout=30, bindAddress=None): - """@see: twisted.internet.interfaces.IReactorTCP.connectTCP - """ - c = tcp.Connector(host, port, factory, timeout, bindAddress, self) - c.connect() - return c - - # IReactorSSL (sometimes, not implemented) - - def connectSSL(self, host, port, factory, contextFactory, timeout=30, bindAddress=None): - """@see: twisted.internet.interfaces.IReactorSSL.connectSSL - """ - assert sslEnabled, "SSL support is not present" - c = ssl.Connector(host, port, factory, contextFactory, timeout, bindAddress, self) - c.connect() - return c - - def listenSSL(self, port, factory, contextFactory, backlog=50, interface=''): - """@see: twisted.internet.interfaces.IReactorSSL.listenSSL - """ - assert sslEnabled, "SSL support is not present" - p = ssl.Port(port, factory, contextFactory, backlog, interface, self) - p.startListening() - return p - - # IReactorArbitrary - def listenWith(self, portType, *args, **kw): - kw['reactor'] = self - p = portType(*args, **kw) - p.startListening() - return p - - def connectWith(self, connectorType, *args, **kw): - kw['reactor'] = self - c = connectorType(*args, **kw) - c.connect() - return c - - def _removeAll(self, readers, writers): - """ - Remove all readers and writers, and return list of Selectables. - - Meant for calling from subclasses, to implement removeAll, like:: - - def removeAll(self): - return self._removeAll(reads, writes) - - where C{reads} and C{writes} are iterables. - """ - readers = [reader for reader in readers if - reader is not self.waker] - - readers_dict = {} - for reader in readers: - readers_dict[reader] = 1 - - for reader in readers: - self.removeReader(reader) - self.removeWriter(reader) - - writers = [writer for writer in writers if - writer not in readers_dict] - for writer in writers: - self.removeWriter(writer) - - return readers+writers - - -if sslEnabled: - classImplements(PosixReactorBase, IReactorSSL) -if unixEnabled: - classImplements(PosixReactorBase, IReactorUNIX, IReactorUNIXDatagram) -if processEnabled: - classImplements(PosixReactorBase, IReactorProcess) - -__all__ = ["PosixReactorBase"] diff --git a/tools/buildbot/pylibs/twisted/internet/process.py b/tools/buildbot/pylibs/twisted/internet/process.py deleted file mode 100644 index 93aad22..0000000 --- a/tools/buildbot/pylibs/twisted/internet/process.py +++ /dev/null @@ -1,922 +0,0 @@ -# -*- test-case-name: twisted.test.test_process -*- -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -UNIX Process management. - -Do NOT use this module directly - use reactor.spawnProcess() instead. - -Maintainer: U{Itamar Shtull-Trauring} -""" - -# System Imports -import gc, os, sys, traceback, select, signal, errno -import warnings - -try: - import pty -except ImportError: - pty = None - -try: - import fcntl, termios -except ImportError: - fcntl = None - -from twisted.persisted import styles -from twisted.python import log, failure -from twisted.python.util import switchUID -from twisted.internet import fdesc, abstract, error -from twisted.internet.main import CONNECTION_LOST, CONNECTION_DONE - -# Some people were importing this, which is incorrect, just keeping it -# here for backwards compatibility: -ProcessExitedAlready = error.ProcessExitedAlready - -reapProcessHandlers = {} - -def reapAllProcesses(): - """ - Reap all registered processes. - """ - for process in reapProcessHandlers.values(): - process.reapProcess() - - -def registerReapProcessHandler(pid, process): - """ - Register a process handler for the given pid, in case L{reapAllProcesses} - is called. - - @param pid: the pid of the process. - @param process: a process handler. - """ - if pid in reapProcessHandlers: - raise RuntimeError("Try to register an already registered process.") - try: - auxPID, status = os.waitpid(pid, os.WNOHANG) - except: - log.msg('Failed to reap %d:' % pid) - log.err() - auxPID = None - if auxPID: - process.processEnded(status) - else: - # if auxPID is 0, there are children but none have exited - reapProcessHandlers[pid] = process - - -def unregisterReapProcessHandler(pid, process): - """ - Unregister a process handler previously registered with - L{registerReapProcessHandler}. - """ - if not (pid in reapProcessHandlers - and reapProcessHandlers[pid] == process): - raise RuntimeError("Try to unregister a process not registered.") - del reapProcessHandlers[pid] - - -def detectLinuxBrokenPipeBehavior(): - """ - On some Linux version, write-only pipe are detected as readable. This - function is here to check if this bug is present or not. - - See L{ProcessWriter.doRead} for a more detailed explanation. - """ - global brokenLinuxPipeBehavior - r, w = os.pipe() - os.write(w, 'a') - reads, writes, exes = select.select([w], [], [], 0) - if reads: - # Linux < 2.6.11 says a write-only pipe is readable. - brokenLinuxPipeBehavior = True - else: - brokenLinuxPipeBehavior = False - os.close(r) - os.close(w) - -# Call at import time -detectLinuxBrokenPipeBehavior() - - -class ProcessWriter(abstract.FileDescriptor): - """ - (Internal) Helper class to write into a Process's input pipe. - - I am a helper which describes a selectable asynchronous writer to a - process's input pipe, including stdin. - """ - connected = 1 - ic = 0 - enableReadHack = False - - def __init__(self, reactor, proc, name, fileno, forceReadHack=False): - """ - Initialize, specifying a Process instance to connect to. - """ - abstract.FileDescriptor.__init__(self, reactor) - fdesc.setNonBlocking(fileno) - self.proc = proc - self.name = name - self.fd = fileno - - if forceReadHack: - self.enableReadHack = True - else: - # Detect if this fd is actually a write-only fd. If it's - # valid to read, don't try to detect closing via read. - # This really only means that we cannot detect a TTY's write - # pipe being closed. - try: - os.read(self.fileno(), 0) - except OSError: - # It's a write-only pipe end, enable hack - self.enableReadHack = True - - if self.enableReadHack: - self.startReading() - - def fileno(self): - """ - Return the fileno() of my process's stdin. - """ - return self.fd - - def writeSomeData(self, data): - """ - Write some data to the open process. - """ - rv = fdesc.writeToFD(self.fd, data) - if rv == len(data) and self.enableReadHack: - self.startReading() - return rv - - def write(self, data): - self.stopReading() - abstract.FileDescriptor.write(self, data) - - def doRead(self): - """ - The only way a write pipe can become "readable" is at EOF, because the - child has closed it, and we're using a reactor which doesn't - distinguish between readable and closed (such as the select reactor). - - Except that's not true on linux < 2.6.11. It has the following - characteristics: write pipe is completely empty => POLLOUT (writable in - select), write pipe is not completely empty => POLLIN (readable in - select), write pipe's reader closed => POLLIN|POLLERR (readable and - writable in select) - - That's what this funky code is for. If linux was not broken, this - function could be simply "return CONNECTION_LOST". - - BUG: We call select no matter what the reactor. - If the reactor is pollreactor, and the fd is > 1024, this will fail. - (only occurs on broken versions of linux, though). - """ - if self.enableReadHack: - if brokenLinuxPipeBehavior: - fd = self.fd - r, w, x = select.select([fd], [fd], [], 0) - if r and w: - return CONNECTION_LOST - else: - return CONNECTION_LOST - else: - self.stopReading() - - def connectionLost(self, reason): - """ - See abstract.FileDescriptor.connectionLost. - """ - # At least on OS X 10.4, exiting while stdout is non-blocking can - # result in data loss. For some reason putting the file descriptor - # back into blocking mode seems to resolve this issue. - fdesc.setBlocking(self.fd) - - abstract.FileDescriptor.connectionLost(self, reason) - self.proc.childConnectionLost(self.name, reason) - - - -class ProcessReader(abstract.FileDescriptor): - """ - ProcessReader - - I am a selectable representation of a process's output pipe, such as - stdout and stderr. - """ - connected = 1 - - def __init__(self, reactor, proc, name, fileno): - """ - Initialize, specifying a process to connect to. - """ - abstract.FileDescriptor.__init__(self, reactor) - fdesc.setNonBlocking(fileno) - self.proc = proc - self.name = name - self.fd = fileno - self.startReading() - - def fileno(self): - """ - Return the fileno() of my process's stderr. - """ - return self.fd - - def writeSomeData(self, data): - # the only time this is actually called is after .loseConnection Any - # actual write attempt would fail, so we must avoid that. This hack - # allows us to use .loseConnection on both readers and writers. - assert data == "" - return CONNECTION_LOST - - def doRead(self): - """ - This is called when the pipe becomes readable. - """ - return fdesc.readFromFD(self.fd, self.dataReceived) - - def dataReceived(self, data): - self.proc.childDataReceived(self.name, data) - - def loseConnection(self): - if self.connected and not self.disconnecting: - self.disconnecting = 1 - self.stopReading() - self.reactor.callLater(0, self.connectionLost, - failure.Failure(CONNECTION_DONE)) - - def connectionLost(self, reason): - """ - Close my end of the pipe, signal the Process (which signals the - ProcessProtocol). - """ - abstract.FileDescriptor.connectionLost(self, reason) - self.proc.childConnectionLost(self.name, reason) - - -class _BaseProcess(styles.Ephemeral, object): - """ - Base class for Process and PTYProcess. - """ - - status = -1 - pid = None - - def reapProcess(self): - """ - Try to reap a process (without blocking) via waitpid. - - This is called when sigchild is caught or a Process object loses its - "connection" (stdout is closed) This ought to result in reaping all - zombie processes, since it will be called twice as often as it needs - to be. - - (Unfortunately, this is a slightly experimental approach, since - UNIX has no way to be really sure that your process is going to - go away w/o blocking. I don't want to block.) - """ - try: - try: - pid, status = os.waitpid(self.pid, os.WNOHANG) - except OSError, e: - if e.errno == errno.ECHILD: - # no child process - pid = None - else: - raise - except: - log.msg('Failed to reap %d:' % self.pid) - log.err() - pid = None - if pid: - self.processEnded(status) - unregisterReapProcessHandler(pid, self) - - def signalProcess(self, signalID): - """ - Send the given signal C{signalID} to the process. It'll translate a - few signals ('HUP', 'STOP', 'INT', 'KILL', 'TERM') from a string - representation to its int value, otherwise it'll pass directly the - value provided - - @type signalID: C{str} or C{int} - """ - if signalID in ('HUP', 'STOP', 'INT', 'KILL', 'TERM'): - signalID = getattr(signal, 'SIG%s' % (signalID,)) - if self.pid is None: - raise ProcessExitedAlready() - os.kill(self.pid, signalID) - - def maybeCallProcessEnded(self): - """ - Call processEnded on protocol after final cleanup. - """ - try: - exitCode = sig = None - if self.status != -1: - if os.WIFEXITED(self.status): - exitCode = os.WEXITSTATUS(self.status) - else: - sig = os.WTERMSIG(self.status) - else: - pass # don't think this can happen - if exitCode or sig: - e = error.ProcessTerminated(exitCode, sig, self.status) - else: - e = error.ProcessDone(self.status) - if self.proto is not None: - self.proto.processEnded(failure.Failure(e)) - self.proto = None - except: - log.err() - - def _fork(self, path, uid, gid, executable, args, environment, **kwargs): - """ - Fork and then exec sub-process. - - @param path: the path where to run the new process. - @type path: C{str} - @param uid: if defined, the uid used to run the new process. - @type uid: C{int} - @param gid: if defined, the gid used to run the new process. - @type gid: C{int} - @param executable: the executable to run in a new process. - @type executable: C{str} - @param args: arguments used to create the new process. - @type args: C{list}. - @param environment: environment used for the new process. - @type environment: C{dict}. - @param kwargs: keyword arguments to L{_setupChild} method. - """ - settingUID = (uid is not None) or (gid is not None) - if settingUID: - curegid = os.getegid() - currgid = os.getgid() - cureuid = os.geteuid() - curruid = os.getuid() - if uid is None: - uid = cureuid - if gid is None: - gid = curegid - # prepare to change UID in subprocess - os.setuid(0) - os.setgid(0) - - collectorEnabled = gc.isenabled() - gc.disable() - try: - self.pid = os.fork() - except: - # Still in the parent process - if collectorEnabled: - gc.enable() - raise - else: - if self.pid == 0: # pid is 0 in the child process - # do not put *ANY* code outside the try block. The child process - # must either exec or _exit. If it gets outside this block (due - # to an exception that is not handled here, but which might be - # handled higher up), there will be two copies of the parent - # running in parallel, doing all kinds of damage. - - # After each change to this code, review it to make sure there - # are no exit paths. - try: - # Stop debugging. If I am, I don't care anymore. - sys.settrace(None) - self._setupChild(**kwargs) - self._execChild(path, settingUID, uid, gid, - executable, args, environment) - except: - # If there are errors, bail and try to write something - # descriptive to stderr. - # XXX: The parent's stderr isn't necessarily fd 2 anymore, or - # even still available - # XXXX: however even libc assumes write(2, err) is a useful - # thing to attempt - try: - stderr = os.fdopen(2, 'w') - stderr.write("Upon execvpe %s %s in environment %s\n:" % - (executable, str(args), - "id %s" % id(environment))) - traceback.print_exc(file=stderr) - stderr.flush() - for fd in range(3): - os.close(fd) - except: - pass # make *sure* the child terminates - # Did you read the comment about not adding code here? - os._exit(1) - - # we are now in parent process - if collectorEnabled: - gc.enable() - self.status = -1 # this records the exit status of the child - if settingUID: - os.setregid(currgid, curegid) - os.setreuid(curruid, cureuid) - - def _setupChild(self, *args, **kwargs): - """ - Setup the child process. Override in subclasses. - """ - raise NotImplementedError() - - def _execChild(self, path, settingUID, uid, gid, - executable, args, environment): - """ - The exec() which is done in the forked child. - """ - if path: - os.chdir(path) - # set the UID before I actually exec the process - if settingUID: - switchUID(uid, gid) - os.execvpe(executable, args, environment) - - def __repr__(self): - """ - String representation of a process. - """ - return "<%s pid=%s status=%s>" % (self.__class__.__name__, - self.pid, self.status) - -class Process(_BaseProcess): - """ - An operating-system Process. - - This represents an operating-system process with arbitrary input/output - pipes connected to it. Those pipes may represent standard input, - standard output, and standard error, or any other file descriptor. - - On UNIX, this is implemented using fork(), exec(), pipe() - and fcntl(). These calls may not exist elsewhere so this - code is not cross-platform. (also, windows can only select - on sockets...) - """ - - debug = False - debug_child = False - - status = -1 - pid = None - - processWriterFactory = ProcessWriter - processReaderFactory = ProcessReader - - def __init__(self, - reactor, executable, args, environment, path, proto, - uid=None, gid=None, childFDs=None): - """ - Spawn an operating-system process. - - This is where the hard work of disconnecting all currently open - files / forking / executing the new process happens. (This is - executed automatically when a Process is instantiated.) - - This will also run the subprocess as a given user ID and group ID, if - specified. (Implementation Note: this doesn't support all the arcane - nuances of setXXuid on UNIX: it will assume that either your effective - or real UID is 0.) - """ - if not proto: - assert 'r' not in childFDs.values() - assert 'w' not in childFDs.values() - if not signal.getsignal(signal.SIGCHLD): - warnings.warn( - error.PotentialZombieWarning.MESSAGE, - error.PotentialZombieWarning, - stacklevel=3) - - self.lostProcess = False - - self.pipes = {} - # keys are childFDs, we can sense them closing - # values are ProcessReader/ProcessWriters - - helpers = {} - # keys are childFDs - # values are parentFDs - - if childFDs is None: - childFDs = {0: "w", # we write to the child's stdin - 1: "r", # we read from their stdout - 2: "r", # and we read from their stderr - } - - debug = self.debug - if debug: print "childFDs", childFDs - - # fdmap.keys() are filenos of pipes that are used by the child. - fdmap = {} # maps childFD to parentFD - for childFD, target in childFDs.items(): - if debug: print "[%d]" % childFD, target - if target == "r": - # we need a pipe that the parent can read from - readFD, writeFD = os.pipe() - if debug: print "readFD=%d, writeFD=%d" % (readFD, writeFD) - fdmap[childFD] = writeFD # child writes to this - helpers[childFD] = readFD # parent reads from this - elif target == "w": - # we need a pipe that the parent can write to - readFD, writeFD = os.pipe() - if debug: print "readFD=%d, writeFD=%d" % (readFD, writeFD) - fdmap[childFD] = readFD # child reads from this - helpers[childFD] = writeFD # parent writes to this - else: - assert type(target) == int, '%r should be an int' % (target,) - fdmap[childFD] = target # parent ignores this - if debug: print "fdmap", fdmap - if debug: print "helpers", helpers - # the child only cares about fdmap.values() - - self._fork(path, uid, gid, executable, args, environment, fdmap=fdmap) - - # we are the parent process: - self.proto = proto - - # arrange for the parent-side pipes to be read and written - for childFD, parentFD in helpers.items(): - os.close(fdmap[childFD]) - - if childFDs[childFD] == "r": - reader = self.processReaderFactory(reactor, self, childFD, - parentFD) - self.pipes[childFD] = reader - - if childFDs[childFD] == "w": - writer = self.processWriterFactory(reactor, self, childFD, - parentFD, forceReadHack=True) - self.pipes[childFD] = writer - - try: - # the 'transport' is used for some compatibility methods - if self.proto is not None: - self.proto.makeConnection(self) - except: - log.err() - registerReapProcessHandler(self.pid, self) - - def _setupChild(self, fdmap): - """ - fdmap[childFD] = parentFD - - The child wants to end up with 'childFD' attached to what used to be - the parent's parentFD. As an example, a bash command run like - 'command 2>&1' would correspond to an fdmap of {0:0, 1:1, 2:1}. - 'command >foo.txt' would be {0:0, 1:os.open('foo.txt'), 2:2}. - - This is accomplished in two steps:: - - 1. close all file descriptors that aren't values of fdmap. This - means 0 .. maxfds. - - 2. for each childFD:: - - - if fdmap[childFD] == childFD, the descriptor is already in - place. Make sure the CLOEXEC flag is not set, then delete - the entry from fdmap. - - - if childFD is in fdmap.values(), then the target descriptor - is busy. Use os.dup() to move it elsewhere, update all - fdmap[childFD] items that point to it, then close the - original. Then fall through to the next case. - - - now fdmap[childFD] is not in fdmap.values(), and is free. - Use os.dup2() to move it to the right place, then close the - original. - """ - - debug = self.debug_child - if debug: - errfd = sys.stderr - errfd.write("starting _setupChild\n") - - destList = fdmap.values() - try: - import resource - maxfds = resource.getrlimit(resource.RLIMIT_NOFILE)[1] + 1 - # OS-X reports 9223372036854775808. That's a lot of fds to close - if maxfds > 1024: - maxfds = 1024 - except: - maxfds = 256 - - for fd in xrange(maxfds): - if fd in destList: - continue - if debug and fd == errfd.fileno(): - continue - try: - os.close(fd) - except: - pass - - # at this point, the only fds still open are the ones that need to - # be moved to their appropriate positions in the child (the targets - # of fdmap, i.e. fdmap.values() ) - - if debug: print >>errfd, "fdmap", fdmap - childlist = fdmap.keys() - childlist.sort() - - for child in childlist: - target = fdmap[child] - if target == child: - # fd is already in place - if debug: print >>errfd, "%d already in place" % target - if fcntl and hasattr(fcntl, 'FD_CLOEXEC'): - old = fcntl.fcntl(child, fcntl.F_GETFD) - fcntl.fcntl(child, - fcntl.F_SETFD, old & ~fcntl.FD_CLOEXEC) - else: - if child in fdmap.values(): - # we can't replace child-fd yet, as some other mapping - # still needs the fd it wants to target. We must preserve - # that old fd by duping it to a new home. - newtarget = os.dup(child) # give it a safe home - if debug: print >>errfd, "os.dup(%d) -> %d" % (child, - newtarget) - os.close(child) # close the original - for c, p in fdmap.items(): - if p == child: - fdmap[c] = newtarget # update all pointers - # now it should be available - if debug: print >>errfd, "os.dup2(%d,%d)" % (target, child) - os.dup2(target, child) - - # At this point, the child has everything it needs. We want to close - # everything that isn't going to be used by the child, i.e. - # everything not in fdmap.keys(). The only remaining fds open are - # those in fdmap.values(). - - # Any given fd may appear in fdmap.values() multiple times, so we - # need to remove duplicates first. - - old = [] - for fd in fdmap.values(): - if not fd in old: - if not fd in fdmap.keys(): - old.append(fd) - if debug: print >>errfd, "old", old - for fd in old: - os.close(fd) - - def writeToChild(self, childFD, data): - self.pipes[childFD].write(data) - - def closeChildFD(self, childFD): - # for writer pipes, loseConnection tries to write the remaining data - # out to the pipe before closing it - # if childFD is not in the list of pipes, assume that it is already - # closed - if childFD in self.pipes: - self.pipes[childFD].loseConnection() - - def pauseProducing(self): - for p in self.pipes.itervalues(): - if isinstance(p, ProcessReader): - p.stopReading() - - def resumeProducing(self): - for p in self.pipes.itervalues(): - if isinstance(p, ProcessReader): - p.startReading() - - # compatibility - def closeStdin(self): - """ - Call this to close standard input on this process. - """ - self.closeChildFD(0) - - def closeStdout(self): - self.closeChildFD(1) - - def closeStderr(self): - self.closeChildFD(2) - - def loseConnection(self): - self.closeStdin() - self.closeStderr() - self.closeStdout() - - def write(self, data): - """ - Call this to write to standard input on this process. - - NOTE: This will silently lose data if there is no standard input. - """ - if 0 in self.pipes: - self.pipes[0].write(data) - - def registerProducer(self, producer, streaming): - """ - Call this to register producer for standard input. - - If there is no standard input producer.stopProducing() will - be called immediately. - """ - if 0 in self.pipes: - self.pipes[0].registerProducer(producer, streaming) - else: - producer.stopProducing() - - def unregisterProducer(self): - """ - Call this to unregister producer for standard input.""" - if 0 in self.pipes: - self.pipes[0].unregisterProducer() - - def writeSequence(self, seq): - """ - Call this to write to standard input on this process. - - NOTE: This will silently lose data if there is no standard input. - """ - if 0 in self.pipes: - self.pipes[0].writeSequence(seq) - - def childDataReceived(self, name, data): - self.proto.childDataReceived(name, data) - - def processEnded(self, status): - # this is called when the child terminates (SIGCHLD) - self.status = status - self.lostProcess = True - self.pid = None - self.maybeCallProcessEnded() - - def childConnectionLost(self, childFD, reason): - # this is called when one of the helpers (ProcessReader or - # ProcessWriter) notices their pipe has been closed - os.close(self.pipes[childFD].fileno()) - del self.pipes[childFD] - try: - self.proto.childConnectionLost(childFD) - except: - log.err() - self.maybeCallProcessEnded() - - def maybeCallProcessEnded(self): - # we don't call ProcessProtocol.processEnded until: - # the child has terminated, AND - # all writers have indicated an error status, AND - # all readers have indicated EOF - # This insures that we've gathered all output from the process. - if self.pipes: - return - if not self.lostProcess: - self.reapProcess() - return - _BaseProcess.maybeCallProcessEnded(self) - - -class PTYProcess(abstract.FileDescriptor, _BaseProcess): - """ - An operating-system Process that uses PTY support. - """ - status = -1 - pid = None - - def __init__(self, reactor, executable, args, environment, path, proto, - uid=None, gid=None, usePTY=None): - """ - Spawn an operating-system process. - - This is where the hard work of disconnecting all currently open - files / forking / executing the new process happens. (This is - executed automatically when a Process is instantiated.) - - This will also run the subprocess as a given user ID and group ID, if - specified. (Implementation Note: this doesn't support all the arcane - nuances of setXXuid on UNIX: it will assume that either your effective - or real UID is 0.) - """ - if pty is None and not isinstance(usePTY, (tuple, list)): - # no pty module and we didn't get a pty to use - raise NotImplementedError( - "cannot use PTYProcess on platforms without the pty module.") - abstract.FileDescriptor.__init__(self, reactor) - - if isinstance(usePTY, (tuple, list)): - masterfd, slavefd, ttyname = usePTY - else: - masterfd, slavefd = pty.openpty() - ttyname = os.ttyname(slavefd) - - self._fork(path, uid, gid, executable, args, environment, - masterfd=masterfd, slavefd=slavefd) - - # we are now in parent process: - os.close(slavefd) - fdesc.setNonBlocking(masterfd) - self.fd = masterfd - self.startReading() - self.connected = 1 - self.proto = proto - self.lostProcess = 0 - self.status = -1 - try: - self.proto.makeConnection(self) - except: - log.err() - registerReapProcessHandler(self.pid, self) - - def _setupChild(self, masterfd, slavefd): - """ - Setup child process after fork() but before exec(). - """ - os.close(masterfd) - if hasattr(termios, 'TIOCNOTTY'): - try: - fd = os.open("/dev/tty", os.O_RDWR | os.O_NOCTTY) - except OSError: - pass - else: - try: - fcntl.ioctl(fd, termios.TIOCNOTTY, '') - except: - pass - os.close(fd) - - os.setsid() - - if hasattr(termios, 'TIOCSCTTY'): - fcntl.ioctl(slavefd, termios.TIOCSCTTY, '') - - for fd in range(3): - if fd != slavefd: - os.close(fd) - - os.dup2(slavefd, 0) # stdin - os.dup2(slavefd, 1) # stdout - os.dup2(slavefd, 2) # stderr - - for fd in xrange(3, 256): - try: - os.close(fd) - except: - pass - - # PTYs do not have stdin/stdout/stderr. They only have in and out, just - # like sockets. You cannot close one without closing off the entire PTY. - def closeStdin(self): - pass - - def closeStdout(self): - pass - - def closeStderr(self): - pass - - def processEnded(self, status): - self.status = status - self.lostProcess += 1 - self.pid = None - self.maybeCallProcessEnded() - - def doRead(self): - """ - Called when my standard output stream is ready for reading. - """ - return fdesc.readFromFD( - self.fd, - lambda data: self.proto.childDataReceived(1, data)) - - def fileno(self): - """ - This returns the file number of standard output on this process. - """ - return self.fd - - def maybeCallProcessEnded(self): - # two things must happen before we call the ProcessProtocol's - # processEnded method. 1: the child process must die and be reaped - # (which calls our own processEnded method). 2: the child must close - # their stdin/stdout/stderr fds, causing the pty to close, causing - # our connectionLost method to be called. #2 can also be triggered - # by calling .loseConnection(). - if self.lostProcess == 2: - _BaseProcess.maybeCallProcessEnded(self) - - def connectionLost(self, reason): - """ - I call this to clean up when one or all of my connections has died. - """ - abstract.FileDescriptor.connectionLost(self, reason) - os.close(self.fd) - self.lostProcess += 1 - self.maybeCallProcessEnded() - - def writeSomeData(self, data): - """ - Write some data to the open process. - """ - return fdesc.writeToFD(self.fd, data) - diff --git a/tools/buildbot/pylibs/twisted/internet/protocol.py b/tools/buildbot/pylibs/twisted/internet/protocol.py deleted file mode 100644 index 7bc2925..0000000 --- a/tools/buildbot/pylibs/twisted/internet/protocol.py +++ /dev/null @@ -1,674 +0,0 @@ -# -*- test-case-name: twisted.test.test_factories -*- -# -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Standard implementations of Twisted protocol-related interfaces. - -Start here if you are looking to write a new protocol implementation for -Twisted. The Protocol class contains some introductory material. - -Maintainer: U{Itamar Shtull-Trauring} -""" - -import random -from zope.interface import implements - -# Twisted Imports -from twisted.python import log, failure, components -from twisted.internet import interfaces, error, defer - - -class Factory: - """This is a factory which produces protocols. - - By default, buildProtocol will create a protocol of the class given in - self.protocol. - """ - - implements(interfaces.IProtocolFactory) - - # put a subclass of Protocol here: - protocol = None - - numPorts = 0 - noisy = True - - def doStart(self): - """Make sure startFactory is called. - - Users should not call this function themselves! - """ - if not self.numPorts: - if self.noisy: - log.msg("Starting factory %r" % self) - self.startFactory() - self.numPorts = self.numPorts + 1 - - def doStop(self): - """Make sure stopFactory is called. - - Users should not call this function themselves! - """ - if self.numPorts == 0: - # this shouldn't happen, but does sometimes and this is better - # than blowing up in assert as we did previously. - return - self.numPorts = self.numPorts - 1 - if not self.numPorts: - if self.noisy: - log.msg("Stopping factory %r" % self) - self.stopFactory() - - def startFactory(self): - """This will be called before I begin listening on a Port or Connector. - - It will only be called once, even if the factory is connected - to multiple ports. - - This can be used to perform 'unserialization' tasks that - are best put off until things are actually running, such - as connecting to a database, opening files, etcetera. - """ - - def stopFactory(self): - """This will be called before I stop listening on all Ports/Connectors. - - This can be overridden to perform 'shutdown' tasks such as disconnecting - database connections, closing files, etc. - - It will be called, for example, before an application shuts down, - if it was connected to a port. User code should not call this function - directly. - """ - - def buildProtocol(self, addr): - """Create an instance of a subclass of Protocol. - - The returned instance will handle input on an incoming server - connection, and an attribute \"factory\" pointing to the creating - factory. - - Override this method to alter how Protocol instances get created. - - @param addr: an object implementing L{twisted.internet.interfaces.IAddress} - """ - p = self.protocol() - p.factory = self - return p - - -class ClientFactory(Factory): - """A Protocol factory for clients. - - This can be used together with the various connectXXX methods in - reactors. - """ - - def startedConnecting(self, connector): - """Called when a connection has been started. - - You can call connector.stopConnecting() to stop the connection attempt. - - @param connector: a Connector object. - """ - - def clientConnectionFailed(self, connector, reason): - """Called when a connection has failed to connect. - - It may be useful to call connector.connect() - this will reconnect. - - @type reason: L{twisted.python.failure.Failure} - """ - - def clientConnectionLost(self, connector, reason): - """Called when an established connection is lost. - - It may be useful to call connector.connect() - this will reconnect. - - @type reason: L{twisted.python.failure.Failure} - """ - - -class _InstanceFactory(ClientFactory): - """Factory used by ClientCreator.""" - - noisy = False - - def __init__(self, reactor, instance, deferred): - self.reactor = reactor - self.instance = instance - self.deferred = deferred - - def __repr__(self): - return "" % (self.instance, ) - - def buildProtocol(self, addr): - self.reactor.callLater(0, self.deferred.callback, self.instance) - del self.deferred - return self.instance - - def clientConnectionFailed(self, connector, reason): - self.reactor.callLater(0, self.deferred.errback, reason) - del self.deferred - - -class ClientCreator: - """Client connections that do not require a factory. - - The various connect* methods create a protocol instance using the given - protocol class and arguments, and connect it, returning a Deferred of the - resulting protocol instance. - - Useful for cases when we don't really need a factory. Mainly this - is when there is no shared state between protocol instances, and no need - to reconnect. - """ - - def __init__(self, reactor, protocolClass, *args, **kwargs): - self.reactor = reactor - self.protocolClass = protocolClass - self.args = args - self.kwargs = kwargs - - def connectTCP(self, host, port, timeout=30, bindAddress=None): - """Connect to remote host, return Deferred of resulting protocol instance.""" - d = defer.Deferred() - f = _InstanceFactory(self.reactor, self.protocolClass(*self.args, **self.kwargs), d) - self.reactor.connectTCP(host, port, f, timeout=timeout, bindAddress=bindAddress) - return d - - def connectUNIX(self, address, timeout = 30, checkPID=0): - """Connect to Unix socket, return Deferred of resulting protocol instance.""" - d = defer.Deferred() - f = _InstanceFactory(self.reactor, self.protocolClass(*self.args, **self.kwargs), d) - self.reactor.connectUNIX(address, f, timeout = timeout, checkPID=checkPID) - return d - - def connectSSL(self, host, port, contextFactory, timeout=30, bindAddress=None): - """Connect to SSL server, return Deferred of resulting protocol instance.""" - d = defer.Deferred() - f = _InstanceFactory(self.reactor, self.protocolClass(*self.args, **self.kwargs), d) - self.reactor.connectSSL(host, port, f, contextFactory, timeout=timeout, bindAddress=bindAddress) - return d - - -class ReconnectingClientFactory(ClientFactory): - """My clients auto-reconnect with an exponential back-off. - - Note that clients should call my resetDelay method after they have - connected successfully. - - @ivar maxDelay: Maximum number of seconds between connection attempts. - @ivar initialDelay: Delay for the first reconnection attempt. - @ivar factor: a multiplicitive factor by which the delay grows - @ivar jitter: percentage of randomness to introduce into the delay length - to prevent stampeding. - """ - maxDelay = 3600 - initialDelay = 1.0 - # Note: These highly sensitive factors have been precisely measured by - # the National Institute of Science and Technology. Take extreme care - # in altering them, or you may damage your Internet! - factor = 2.7182818284590451 # (math.e) - # Phi = 1.6180339887498948 # (Phi is acceptable for use as a - # factor if e is too large for your application.) - jitter = 0.11962656492 # molar Planck constant times c, Jule meter/mole - - delay = initialDelay - retries = 0 - maxRetries = None - _callID = None - connector = None - - continueTrying = 1 - - def clientConnectionFailed(self, connector, reason): - if self.continueTrying: - self.connector = connector - self.retry() - - def clientConnectionLost(self, connector, unused_reason): - if self.continueTrying: - self.connector = connector - self.retry() - - def retry(self, connector=None): - """Have this connector connect again, after a suitable delay. - """ - if not self.continueTrying: - if self.noisy: - log.msg("Abandoning %s on explicit request" % (connector,)) - return - - if connector is None: - if self.connector is None: - raise ValueError("no connector to retry") - else: - connector = self.connector - - self.retries += 1 - if self.maxRetries is not None and (self.retries > self.maxRetries): - if self.noisy: - log.msg("Abandoning %s after %d retries." % - (connector, self.retries)) - return - - self.delay = min(self.delay * self.factor, self.maxDelay) - if self.jitter: - self.delay = random.normalvariate(self.delay, - self.delay * self.jitter) - - if self.noisy: - log.msg("%s will retry in %d seconds" % (connector, self.delay,)) - from twisted.internet import reactor - - def reconnector(): - self._callID = None - connector.connect() - self._callID = reactor.callLater(self.delay, reconnector) - - def stopTrying(self): - """I put a stop to any attempt to reconnect in progress. - """ - # ??? Is this function really stopFactory? - if self._callID: - self._callID.cancel() - self._callID = None - if self.connector: - # Hopefully this doesn't just make clientConnectionFailed - # retry again. - try: - self.connector.stopConnecting() - except error.NotConnectingError: - pass - self.continueTrying = 0 - - def resetDelay(self): - """Call me after a successful connection to reset. - - I reset the delay and the retry counter. - """ - self.delay = self.initialDelay - self.retries = 0 - self._callID = None - self.continueTrying = 1 - - - def __getstate__(self): - """ - Remove all of the state which is mutated by connection attempts and - failures, returning just the state which describes how reconnections - should be attempted. This will make the unserialized instance - behave just as this one did when it was first instantiated. - """ - state = self.__dict__.copy() - for key in ['connector', 'retries', 'delay', - 'continueTrying', '_callID']: - if key in state: - del state[key] - return state - - - -class ServerFactory(Factory): - """Subclass this to indicate that your protocol.Factory is only usable for servers. - """ - - -class BaseProtocol: - """This is the abstract superclass of all protocols. - - If you are going to write a new protocol for Twisted, start here. The - docstrings of this class explain how you can get started. Any protocol - implementation, either client or server, should be a subclass of me. - - My API is quite simple. Implement dataReceived(data) to handle both - event-based and synchronous input; output can be sent through the - 'transport' attribute, which is to be an instance that implements - L{twisted.internet.interfaces.ITransport}. - - Some subclasses exist already to help you write common types of protocols: - see the L{twisted.protocols.basic} module for a few of them. - """ - - connected = 0 - transport = None - - def makeConnection(self, transport): - """Make a connection to a transport and a server. - - This sets the 'transport' attribute of this Protocol, and calls the - connectionMade() callback. - """ - self.connected = 1 - self.transport = transport - self.connectionMade() - - def connectionMade(self): - """Called when a connection is made. - - This may be considered the initializer of the protocol, because - it is called when the connection is completed. For clients, - this is called once the connection to the server has been - established; for servers, this is called after an accept() call - stops blocking and a socket has been received. If you need to - send any greeting or initial message, do it here. - """ - -connectionDone=failure.Failure(error.ConnectionDone()) -connectionDone.cleanFailure() - - -class Protocol(BaseProtocol): - - implements(interfaces.IProtocol) - - def dataReceived(self, data): - """Called whenever data is received. - - Use this method to translate to a higher-level message. Usually, some - callback will be made upon the receipt of each complete protocol - message. - - @param data: a string of indeterminate length. Please keep in mind - that you will probably need to buffer some data, as partial - (or multiple) protocol messages may be received! I recommend - that unit tests for protocols call through to this method with - differing chunk sizes, down to one byte at a time. - """ - - def connectionLost(self, reason=connectionDone): - """Called when the connection is shut down. - - Clear any circular references here, and any external references - to this Protocol. The connection has been closed. - - @type reason: L{twisted.python.failure.Failure} - """ - - -class ProtocolToConsumerAdapter(components.Adapter): - implements(interfaces.IConsumer) - - def write(self, data): - self.original.dataReceived(data) - - def registerProducer(self, producer, streaming): - pass - - def unregisterProducer(self): - pass - -components.registerAdapter(ProtocolToConsumerAdapter, interfaces.IProtocol, - interfaces.IConsumer) - -class ConsumerToProtocolAdapter(components.Adapter): - implements(interfaces.IProtocol) - - def dataReceived(self, data): - self.original.write(data) - - def connectionLost(self, reason): - pass - - def makeConnection(self, transport): - pass - - def connectionMade(self): - pass - -components.registerAdapter(ConsumerToProtocolAdapter, interfaces.IConsumer, - interfaces.IProtocol) - -class ProcessProtocol(BaseProtocol): - """ - Base process protocol implementation which does simple dispatching for - stdin, stdout, and stderr file descriptors. - """ - implements(interfaces.IProcessProtocol) - - def childDataReceived(self, childFD, data): - if childFD == 1: - self.outReceived(data) - elif childFD == 2: - self.errReceived(data) - - - def outReceived(self, data): - """ - Some data was received from stdout. - """ - - - def errReceived(self, data): - """ - Some data was received from stderr. - """ - - - def childConnectionLost(self, childFD): - if childFD == 0: - self.inConnectionLost() - elif childFD == 1: - self.outConnectionLost() - elif childFD == 2: - self.errConnectionLost() - - - def inConnectionLost(self): - """ - This will be called when stdin is closed. - """ - - - def outConnectionLost(self): - """ - This will be called when stdout is closed. - """ - - - def errConnectionLost(self): - """ - This will be called when stderr is closed. - """ - - - def processEnded(self, reason): - """ - This will be called when the subprocess is finished. - - @type reason: L{twisted.python.failure.Failure} - """ - - -class AbstractDatagramProtocol: - """ - Abstract protocol for datagram-oriented transports, e.g. IP, ICMP, ARP, UDP. - """ - - transport = None - numPorts = 0 - noisy = True - - def __getstate__(self): - d = self.__dict__.copy() - d['transport'] = None - return d - - def doStart(self): - """Make sure startProtocol is called. - - This will be called by makeConnection(), users should not call it. - """ - if not self.numPorts: - if self.noisy: - log.msg("Starting protocol %s" % self) - self.startProtocol() - self.numPorts = self.numPorts + 1 - - def doStop(self): - """Make sure stopProtocol is called. - - This will be called by the port, users should not call it. - """ - assert self.numPorts > 0 - self.numPorts = self.numPorts - 1 - self.transport = None - if not self.numPorts: - if self.noisy: - log.msg("Stopping protocol %s" % self) - self.stopProtocol() - - def startProtocol(self): - """Called when a transport is connected to this protocol. - - Will only be called once, even if multiple ports are connected. - """ - - def stopProtocol(self): - """Called when the transport is disconnected. - - Will only be called once, after all ports are disconnected. - """ - - def makeConnection(self, transport): - """Make a connection to a transport and a server. - - This sets the 'transport' attribute of this DatagramProtocol, and calls the - doStart() callback. - """ - assert self.transport == None - self.transport = transport - self.doStart() - - def datagramReceived(self, datagram, addr): - """Called when a datagram is received. - - @param datagram: the string received from the transport. - @param addr: tuple of source of datagram. - """ - - -class DatagramProtocol(AbstractDatagramProtocol): - """ - Protocol for datagram-oriented transport, e.g. UDP. - - @type transport: C{NoneType} or - L{IUDPTransport} provider - @ivar transport: The transport with which this protocol is associated, - if it is associated with one. - """ - - def connectionRefused(self): - """Called due to error from write in connected mode. - - Note this is a result of ICMP message generated by *previous* - write. - """ - - -class ConnectedDatagramProtocol(DatagramProtocol): - """Protocol for connected datagram-oriented transport. - - No longer necessary for UDP. - """ - - def datagramReceived(self, datagram): - """Called when a datagram is received. - - @param datagram: the string received from the transport. - """ - - def connectionFailed(self, failure): - """Called if connecting failed. - - Usually this will be due to a DNS lookup failure. - """ - - - -class FileWrapper: - """A wrapper around a file-like object to make it behave as a Transport. - - This doesn't actually stream the file to the attached protocol, - and is thus useful mainly as a utility for debugging protocols. - """ - - implements(interfaces.ITransport) - - closed = 0 - disconnecting = 0 - producer = None - streamingProducer = 0 - - def __init__(self, file): - self.file = file - - def write(self, data): - try: - self.file.write(data) - except: - self.handleException() - # self._checkProducer() - - def _checkProducer(self): - # Cheating; this is called at "idle" times to allow producers to be - # found and dealt with - if self.producer: - self.producer.resumeProducing() - - def registerProducer(self, producer, streaming): - """From abstract.FileDescriptor - """ - self.producer = producer - self.streamingProducer = streaming - if not streaming: - producer.resumeProducing() - - def unregisterProducer(self): - self.producer = None - - def stopConsuming(self): - self.unregisterProducer() - self.loseConnection() - - def writeSequence(self, iovec): - self.write("".join(iovec)) - - def loseConnection(self): - self.closed = 1 - try: - self.file.close() - except (IOError, OSError): - self.handleException() - - def getPeer(self): - # XXX: According to ITransport, this should return an IAddress! - return 'file', 'file' - - def getHost(self): - # XXX: According to ITransport, this should return an IAddress! - return 'file' - - def handleException(self): - pass - - def resumeProducing(self): - # Never sends data anyways - pass - - def pauseProducing(self): - # Never sends data anyways - pass - - def stopProducing(self): - self.loseConnection() - - -__all__ = ["Factory", "ClientFactory", "ReconnectingClientFactory", "connectionDone", - "Protocol", "ProcessProtocol", "FileWrapper", "ServerFactory", - "AbstractDatagramProtocol", "DatagramProtocol", "ConnectedDatagramProtocol", - "ClientCreator"] diff --git a/tools/buildbot/pylibs/twisted/internet/pyuisupport.py b/tools/buildbot/pylibs/twisted/internet/pyuisupport.py deleted file mode 100644 index a845e19..0000000 --- a/tools/buildbot/pylibs/twisted/internet/pyuisupport.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -This module integrates PyUI with twisted.internet's mainloop. - -Maintainer: U{Jp Calderone} - -See doc/examples/pyuidemo.py for example usage. -""" - -# System imports -import pyui - -def _guiUpdate(reactor, delay): - pyui.draw() - if pyui.update() == 0: - pyui.quit() - reactor.stop() - else: - reactor.callLater(delay, _guiUpdate, reactor, delay) - - -def install(ms=10, reactor=None, args=(), kw={}): - """ - Schedule PyUI's display to be updated approximately every C{ms} - milliseconds, and initialize PyUI with the specified arguments. - """ - d = pyui.init(*args, **kw) - - if reactor is None: - from twisted.internet import reactor - _guiUpdate(reactor, ms / 1000.0) - return d - -__all__ = ["install"] diff --git a/tools/buildbot/pylibs/twisted/internet/qtreactor.py b/tools/buildbot/pylibs/twisted/internet/qtreactor.py deleted file mode 100644 index 7754ad8..0000000 --- a/tools/buildbot/pylibs/twisted/internet/qtreactor.py +++ /dev/null @@ -1,15 +0,0 @@ -try: - # 'import qtreactor' would have imported this file instead of the - # top-level qtreactor. __import__ does the right thing - # (kids, don't repeat this at home) - install = __import__('qtreactor').install -except ImportError: - from twisted.plugins.qtreactor_stub import errorMessage - raise ImportError(errorMessage) -else: - import warnings - warnings.warn("Please use qtreactor instead of twisted.internet.qtreactor", - category=DeprecationWarning) - -__all__ = ['install'] - diff --git a/tools/buildbot/pylibs/twisted/internet/reactor.py b/tools/buildbot/pylibs/twisted/internet/reactor.py deleted file mode 100644 index 1fa2861..0000000 --- a/tools/buildbot/pylibs/twisted/internet/reactor.py +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -See twisted.internet.interfaces.IReactor*. -""" -import sys -del sys.modules['twisted.internet.reactor'] -#from twisted.python import log -#log.msg("Installing SelectReactor, since unspecified.") -from twisted.internet import selectreactor -selectreactor.install() diff --git a/tools/buildbot/pylibs/twisted/internet/selectreactor.py b/tools/buildbot/pylibs/twisted/internet/selectreactor.py deleted file mode 100644 index 0d79e55..0000000 --- a/tools/buildbot/pylibs/twisted/internet/selectreactor.py +++ /dev/null @@ -1,204 +0,0 @@ -# -*- test-case-name: twisted.test.test_internet -*- -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Select reactor - -Maintainer: U{Itamar Shtull-Trauring} -""" - -from time import sleep -import sys -import select -from errno import EINTR, EBADF - -from zope.interface import implements - -from twisted.internet.interfaces import IReactorFDSet -from twisted.internet import error -from twisted.internet import posixbase -from twisted.python import log -from twisted.python.runtime import platformType - - -def win32select(r, w, e, timeout=None): - """Win32 select wrapper.""" - if not (r or w): - # windows select() exits immediately when no sockets - if timeout is None: - timeout = 0.01 - else: - timeout = min(timeout, 0.001) - sleep(timeout) - return [], [], [] - # windows doesn't process 'signals' inside select(), so we set a max - # time or ctrl-c will never be recognized - if timeout is None or timeout > 0.5: - timeout = 0.5 - r, w, e = select.select(r, w, w, timeout) - return r, w + e, [] - -if platformType == "win32": - _select = win32select -else: - _select = select.select - -# Exceptions that doSelect might return frequently -_NO_FILENO = error.ConnectionFdescWentAway('Handler has no fileno method') -_NO_FILEDESC = error.ConnectionFdescWentAway('Filedescriptor went away') - -class SelectReactor(posixbase.PosixReactorBase): - """ - A select() based reactor - runs on all POSIX platforms and on Win32. - - @ivar _reads: A dictionary mapping L{FileDescriptor} instances to arbitrary - values (this is essentially a set). Keys in this dictionary will be - checked for read events. - - @ivar _writes: A dictionary mapping L{FileDescriptor} instances to - arbitrary values (this is essentially a set). Keys in this dictionary - will be checked for writability. - """ - implements(IReactorFDSet) - - def __init__(self): - """ - Initialize file descriptor tracking dictionaries and the base class. - """ - self._reads = {} - self._writes = {} - posixbase.PosixReactorBase.__init__(self) - - - def _preenDescriptors(self): - log.msg("Malformed file descriptor found. Preening lists.") - readers = self._reads.keys() - writers = self._writes.keys() - self._reads.clear() - self._writes.clear() - for selDict, selList in ((self._reads, readers), - (self._writes, writers)): - for selectable in selList: - try: - select.select([selectable], [selectable], [selectable], 0) - except Exception, e: - log.msg("bad descriptor %s" % selectable) - self._disconnectSelectable(selectable, e, False) - else: - selDict[selectable] = 1 - - - def doSelect(self, timeout): - """ - Run one iteration of the I/O monitor loop. - - This will run all selectables who had input or output readiness - waiting for them. - """ - while 1: - try: - r, w, ignored = _select(self._reads.keys(), - self._writes.keys(), - [], timeout) - break - except ValueError, ve: - # Possibly a file descriptor has gone negative? - log.err() - self._preenDescriptors() - except TypeError, te: - # Something *totally* invalid (object w/o fileno, non-integral - # result) was passed - log.err() - self._preenDescriptors() - except (select.error, IOError), se: - # select(2) encountered an error - if se.args[0] in (0, 2): - # windows does this if it got an empty list - if (not self._reads) and (not self._writes): - return - else: - raise - elif se.args[0] == EINTR: - return - elif se.args[0] == EBADF: - self._preenDescriptors() - else: - # OK, I really don't know what's going on. Blow up. - raise - _drdw = self._doReadOrWrite - _logrun = log.callWithLogger - for selectables, method, fdset in ((r, "doRead", self._reads), - (w,"doWrite", self._writes)): - for selectable in selectables: - # if this was disconnected in another thread, kill it. - # ^^^^ --- what the !@#*? serious! -exarkun - if selectable not in fdset: - continue - # This for pausing input when we're not ready for more. - _logrun(selectable, _drdw, selectable, method, dict) - - doIteration = doSelect - - def _doReadOrWrite(self, selectable, method, dict): - try: - why = getattr(selectable, method)() - handfn = getattr(selectable, 'fileno', None) - if not handfn: - why = _NO_FILENO - elif handfn() == -1: - why = _NO_FILEDESC - except: - why = sys.exc_info()[1] - log.err() - if why: - self._disconnectSelectable(selectable, why, method=="doRead") - - def addReader(self, reader): - """ - Add a FileDescriptor for notification of data available to read. - """ - self._reads[reader] = 1 - - def addWriter(self, writer): - """ - Add a FileDescriptor for notification of data available to write. - """ - self._writes[writer] = 1 - - def removeReader(self, reader): - """ - Remove a Selectable for notification of data available to read. - """ - if reader in self._reads: - del self._reads[reader] - - def removeWriter(self, writer): - """ - Remove a Selectable for notification of data available to write. - """ - if writer in self._writes: - del self._writes[writer] - - def removeAll(self): - return self._removeAll(self._reads, self._writes) - - - def getReaders(self): - return self._reads.keys() - - - def getWriters(self): - return self._writes.keys() - - - -def install(): - """Configure the twisted mainloop to be run using the select() reactor. - """ - reactor = SelectReactor() - from twisted.internet.main import installReactor - installReactor(reactor) - -__all__ = ['install'] diff --git a/tools/buildbot/pylibs/twisted/internet/serialport.py b/tools/buildbot/pylibs/twisted/internet/serialport.py deleted file mode 100644 index 6ac58ae..0000000 --- a/tools/buildbot/pylibs/twisted/internet/serialport.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Serial Port Protocol -""" - -# system imports -import os, sys - -# all of them require pyserial at the moment, so check that first -import serial -from serial import PARITY_NONE, PARITY_EVEN, PARITY_ODD -from serial import STOPBITS_ONE, STOPBITS_TWO -from serial import FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS - -# common code for serial ports -class BaseSerialPort: - def setBaudRate(self, baudrate): - if hasattr(self._serial, "setBaudrate"): - self._serial.setBaudrate(baudrate) - else: - self._serial.setBaudRate(baudrate) - - def inWaiting(self): - return self._serial.inWaiting() - - def flushInput(self): - self._serial.flushInput() - - def flushOutput(self): - self._serial.flushOutput() - - def sendBreak(self): - self._serial.sendBreak() - - def getDSR(self): - return self._serial.getDSR() - - def getCD(self): - return self._serial.getCD() - - def getRI(self): - return self._serial.getRI() - - def getCTS(self): - return self._serial.getCTS() - - def setDTR(self, on = 1): - self._serial.setDTR(on) - - def setRTS(self, on = 1): - self._serial.setRTS(on) - -class SerialPort(BaseSerialPort): - pass - -# replace SerialPort with appropriate serial port -if os.name == 'posix': - from twisted.internet._posixserialport import SerialPort -elif os.name == 'java': - from twisted.internet._javaserialport import SerialPort -elif sys.platform == 'win32': - from twisted.internet._win32serialport import SerialPort diff --git a/tools/buildbot/pylibs/twisted/internet/ssl.py b/tools/buildbot/pylibs/twisted/internet/ssl.py deleted file mode 100644 index 23bd1e9..0000000 --- a/tools/buildbot/pylibs/twisted/internet/ssl.py +++ /dev/null @@ -1,205 +0,0 @@ -# -*- test-case-name: twisted.test.test_ssl -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -SSL transport. Requires PyOpenSSL (http://pyopenssl.sf.net). - -SSL connections require a ContextFactory so they can create SSL contexts. -End users should only use the ContextFactory classes directly - for SSL -connections use the reactor.connectSSL/listenSSL and so on, as documented -in IReactorSSL. - -All server context factories should inherit from ContextFactory, and all -client context factories should inherit from ClientContextFactory. At the -moment this is not enforced, but in the future it might be. - -Future Plans: - - split module so reactor-specific classes are in a separate module - - support for switching TCP into SSL - - more options - -Maintainer: U{Itamar Shtull-Trauring} -""" - -# If something goes wrong, most notably an OpenSSL import failure, -# sys.modules['twisted.internet.ssl'] will be bound to a partially -# initialized module object. This is wacko, but we will take advantage -# of it to publish whether or not SSL is available. -# See the end of this module for the other half of this solution. - -# The correct idiom to import this module is thus: - -# try: -# from twisted.internet import ssl -# except ImportError: -# # happens the first time the interpreter tries to import it -# ssl = None -# if ssl and not ssl.supported: -# # happens second and later times -# ssl = None - -supported = False - -# System imports -from OpenSSL import SSL -from zope.interface import implements, implementsOnly, implementedBy - -# sibling imports -import tcp, interfaces - -# Twisted imports -from twisted.internet import base, address - - -class ContextFactory: - """A factory for SSL context objects, for server SSL connections.""" - - isClient = 0 - - def getContext(self): - """Return a SSL.Context object. override in subclasses.""" - raise NotImplementedError - - -class DefaultOpenSSLContextFactory(ContextFactory): - - def __init__(self, privateKeyFileName, certificateFileName, - sslmethod=SSL.SSLv23_METHOD): - """ - @param privateKeyFileName: Name of a file containing a private key - @param certificateFileName: Name of a file containing a certificate - @param sslmethod: The SSL method to use - """ - self.privateKeyFileName = privateKeyFileName - self.certificateFileName = certificateFileName - self.sslmethod = sslmethod - self.cacheContext() - - def cacheContext(self): - ctx = SSL.Context(self.sslmethod) - ctx.use_certificate_file(self.certificateFileName) - ctx.use_privatekey_file(self.privateKeyFileName) - self._context = ctx - - def __getstate__(self): - d = self.__dict__.copy() - del d['_context'] - return d - - def __setstate__(self, state): - self.__dict__ = state - self.cacheContext() - - def getContext(self): - """Create an SSL context. - """ - return self._context - - -class ClientContextFactory: - """A context factory for SSL clients.""" - - isClient = 1 - method = SSL.SSLv3_METHOD - - def getContext(self): - return SSL.Context(self.method) - - -class Client(tcp.Client): - """I am an SSL client.""" - - implementsOnly(interfaces.ISSLTransport, - *[i for i in implementedBy(tcp.Client) if i != interfaces.ITLSTransport]) - - def __init__(self, host, port, bindAddress, ctxFactory, connector, reactor=None): - # tcp.Client.__init__ depends on self.ctxFactory being set - self.ctxFactory = ctxFactory - tcp.Client.__init__(self, host, port, bindAddress, connector, reactor) - - def getHost(self): - """Returns the address from which I am connecting.""" - h, p = self.socket.getsockname() - return address.IPv4Address('TCP', h, p, 'SSL') - - def getPeer(self): - """Returns the address that I am connected.""" - return address.IPv4Address('TCP', self.addr[0], self.addr[1], 'SSL') - - def _connectDone(self): - self.startTLS(self.ctxFactory) - self.startWriting() - tcp.Client._connectDone(self) - - -class Server(tcp.Server): - """I am an SSL server. - """ - - implements(interfaces.ISSLTransport) - - def getHost(self): - """Return server's address.""" - h, p = self.socket.getsockname() - return address.IPv4Address('TCP', h, p, 'SSL') - - def getPeer(self): - """Return address of peer.""" - h, p = self.client - return address.IPv4Address('TCP', h, p, 'SSL') - - -class Port(tcp.Port): - """I am an SSL port.""" - _socketShutdownMethod = 'sock_shutdown' - - transport = Server - - def __init__(self, port, factory, ctxFactory, backlog=50, interface='', reactor=None): - tcp.Port.__init__(self, port, factory, backlog, interface, reactor) - self.ctxFactory = ctxFactory - - def createInternetSocket(self): - """(internal) create an SSL socket - """ - sock = tcp.Port.createInternetSocket(self) - return SSL.Connection(self.ctxFactory.getContext(), sock) - - def _preMakeConnection(self, transport): - # *Don't* call startTLS here - # The transport already has the SSL.Connection object from above - transport._startTLS() - return tcp.Port._preMakeConnection(self, transport) - - -class Connector(base.BaseConnector): - def __init__(self, host, port, factory, contextFactory, timeout, bindAddress, reactor=None): - self.host = host - self.port = port - self.bindAddress = bindAddress - self.contextFactory = contextFactory - base.BaseConnector.__init__(self, factory, timeout, reactor) - - def _makeTransport(self): - return Client(self.host, self.port, self.bindAddress, self.contextFactory, self, self.reactor) - - def getDestination(self): - return address.IPv4Address('TCP', self.host, self.port, 'SSL') - -from twisted.internet._sslverify import DistinguishedName, DN, Certificate -from twisted.internet._sslverify import CertificateRequest, PrivateCertificate -from twisted.internet._sslverify import KeyPair -from twisted.internet._sslverify import OpenSSLCertificateOptions as CertificateOptions - -__all__ = [ - "ContextFactory", "DefaultOpenSSLContextFactory", "ClientContextFactory", - - 'DistinguishedName', 'DN', - 'Certificate', 'CertificateRequest', 'PrivateCertificate', - 'KeyPair', - 'CertificateOptions', - ] - -supported = True diff --git a/tools/buildbot/pylibs/twisted/internet/stdio.py b/tools/buildbot/pylibs/twisted/internet/stdio.py deleted file mode 100644 index b10766e..0000000 --- a/tools/buildbot/pylibs/twisted/internet/stdio.py +++ /dev/null @@ -1,31 +0,0 @@ -# -*- test-case-name: twisted.test.test_process.ProcessTestCase.testStdio -*- - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Standard input/out/err support. - -This module exposes one name, StandardIO, which is a factory that takes an -IProtocol provider as an argument. It connects that protocol to standard input -and output on the current process. - -It should work on any UNIX and also on Win32 (with some caveats: due to -platform limitations, it will perform very poorly on Win32). - -Future Plans:: - - support for stderr, perhaps - Rewrite to use the reactor instead of an ad-hoc mechanism for connecting - protocols to transport. - - -Maintainer: U{James Y Knight } -""" - -from twisted.python.runtime import platform - -if platform.isWindows(): - from twisted.internet._win32stdio import StandardIO -else: - from twisted.internet._posixstdio import StandardIO diff --git a/tools/buildbot/pylibs/twisted/internet/task.py b/tools/buildbot/pylibs/twisted/internet/task.py deleted file mode 100644 index 526d555..0000000 --- a/tools/buildbot/pylibs/twisted/internet/task.py +++ /dev/null @@ -1,420 +0,0 @@ -# -*- test-case-name: twisted.test.test_task -*- -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Scheduling utility methods and classes. - -@author: U{Jp Calderone} -""" - -__metaclass__ = type - -import time - -from zope.interface import implements - -from twisted.python import reflect - -from twisted.internet import base, defer -from twisted.internet.interfaces import IReactorTime - - -class LoopingCall: - """Call a function repeatedly. - - If C{f} returns a deferred, rescheduling will not take place until the - deferred has fired. The result value is ignored. - - @ivar f: The function to call. - @ivar a: A tuple of arguments to pass the function. - @ivar kw: A dictionary of keyword arguments to pass to the function. - @ivar clock: A provider of - L{twisted.internet.interfaces.IReactorTime}. The default is - L{twisted.internet.reactor}. Feel free to set this to - something else, but it probably ought to be set *before* - calling L{start}. - - @type _lastTime: C{float} - @ivar _lastTime: The time at which this instance most recently scheduled - itself to run. - """ - - call = None - running = False - deferred = None - interval = None - _lastTime = 0.0 - starttime = None - - def __init__(self, f, *a, **kw): - self.f = f - self.a = a - self.kw = kw - from twisted.internet import reactor - self.clock = reactor - - - def start(self, interval, now=True): - """Start running function every interval seconds. - - @param interval: The number of seconds between calls. May be - less than one. Precision will depend on the underlying - platform, the available hardware, and the load on the system. - - @param now: If True, run this call right now. Otherwise, wait - until the interval has elapsed before beginning. - - @return: A Deferred whose callback will be invoked with - C{self} when C{self.stop} is called, or whose errback will be - invoked when the function raises an exception or returned a - deferred that has its errback invoked. - """ - assert not self.running, ("Tried to start an already running " - "LoopingCall.") - if interval < 0: - raise ValueError, "interval must be >= 0" - self.running = True - d = self.deferred = defer.Deferred() - self.starttime = self.clock.seconds() - self._lastTime = self.starttime - self.interval = interval - if now: - self() - else: - self._reschedule() - return d - - def stop(self): - """Stop running function. - """ - assert self.running, ("Tried to stop a LoopingCall that was " - "not running.") - self.running = False - if self.call is not None: - self.call.cancel() - self.call = None - d, self.deferred = self.deferred, None - d.callback(self) - - def __call__(self): - def cb(result): - if self.running: - self._reschedule() - else: - d, self.deferred = self.deferred, None - d.callback(self) - - def eb(failure): - self.running = False - d, self.deferred = self.deferred, None - d.errback(failure) - - self.call = None - d = defer.maybeDeferred(self.f, *self.a, **self.kw) - d.addCallback(cb) - d.addErrback(eb) - - - def _reschedule(self): - """ - Schedule the next iteration of this looping call. - """ - if self.interval == 0: - self.call = self.clock.callLater(0, self) - return - - currentTime = self.clock.seconds() - # Find how long is left until the interval comes around again. - untilNextTime = (self._lastTime - currentTime) % self.interval - # Make sure it is in the future, in case more than one interval worth - # of time passed since the previous call was made. - nextTime = max( - self._lastTime + self.interval, currentTime + untilNextTime) - # If the interval falls on the current time exactly, skip it and - # schedule the call for the next interval. - if nextTime == currentTime: - nextTime += self.interval - self._lastTime = nextTime - self.call = self.clock.callLater(nextTime - currentTime, self) - - - def __repr__(self): - if hasattr(self.f, 'func_name'): - func = self.f.func_name - if hasattr(self.f, 'im_class'): - func = self.f.im_class.__name__ + '.' + func - else: - func = reflect.safe_repr(self.f) - - return 'LoopingCall<%r>(%s, *%s, **%s)' % ( - self.interval, func, reflect.safe_repr(self.a), - reflect.safe_repr(self.kw)) - - - -class SchedulerStopped(Exception): - """ - The operation could not complete because the scheduler was stopped in - progress or was already stopped. - """ - - - -class _Timer(object): - MAX_SLICE = 0.01 - def __init__(self): - self.end = time.time() + self.MAX_SLICE - - - def __call__(self): - return time.time() >= self.end - - - -_EPSILON = 0.00000001 -def _defaultScheduler(x): - from twisted.internet import reactor - return reactor.callLater(_EPSILON, x) - - - -class Cooperator(object): - """ - Cooperative task scheduler. - """ - - def __init__(self, - terminationPredicateFactory=_Timer, - scheduler=_defaultScheduler, - started=True): - """ - Create a scheduler-like object to which iterators may be added. - - @param terminationPredicateFactory: A no-argument callable which will - be invoked at the beginning of each step and should return a - no-argument callable which will return False when the step should be - terminated. The default factory is time-based and allows iterators to - run for 1/100th of a second at a time. - - @param scheduler: A one-argument callable which takes a no-argument - callable and should invoke it at some future point. This will be used - to schedule each step of this Cooperator. - - @param started: A boolean which indicates whether iterators should be - stepped as soon as they are added, or if they will be queued up until - L{Cooperator.start} is called. - """ - self.iterators = [] - self._metarator = iter(()) - self._terminationPredicateFactory = terminationPredicateFactory - self._scheduler = scheduler - self._delayedCall = None - self._stopped = False - self._started = started - - - def coiterate(self, iterator, doneDeferred=None): - """ - Add an iterator to the list of iterators I am currently running. - - @return: a Deferred that will fire when the iterator finishes. - """ - if doneDeferred is None: - doneDeferred = defer.Deferred() - if self._stopped: - doneDeferred.errback(SchedulerStopped()) - return doneDeferred - self.iterators.append((iterator, doneDeferred)) - self._reschedule() - return doneDeferred - - - def _tasks(self): - terminator = self._terminationPredicateFactory() - while self.iterators: - for i in self._metarator: - yield i - if terminator(): - return - self._metarator = iter(self.iterators) - - - def _tick(self): - """ - Run one scheduler tick. - """ - self._delayedCall = None - for taskObj in self._tasks(): - iterator, doneDeferred = taskObj - try: - result = iterator.next() - except StopIteration: - self.iterators.remove(taskObj) - doneDeferred.callback(iterator) - except: - self.iterators.remove(taskObj) - doneDeferred.errback() - else: - if isinstance(result, defer.Deferred): - self.iterators.remove(taskObj) - def cbContinue(result, taskObj=taskObj): - self.coiterate(*taskObj) - result.addCallbacks(cbContinue, doneDeferred.errback) - self._reschedule() - - - _mustScheduleOnStart = False - def _reschedule(self): - if not self._started: - self._mustScheduleOnStart = True - return - if self._delayedCall is None and self.iterators: - self._delayedCall = self._scheduler(self._tick) - - - def start(self): - """ - Begin scheduling steps. - """ - self._stopped = False - self._started = True - if self._mustScheduleOnStart: - del self._mustScheduleOnStart - self._reschedule() - - - def stop(self): - """ - Stop scheduling steps. Errback the completion Deferreds of all - iterators which have been added and forget about them. - """ - self._stopped = True - for iterator, doneDeferred in self.iterators: - doneDeferred.errback(SchedulerStopped()) - self.iterators = [] - if self._delayedCall is not None: - self._delayedCall.cancel() - self._delayedCall = None - - - -_theCooperator = Cooperator() -def coiterate(iterator): - """ - Cooperatively iterate over the given iterator, dividing runtime between it - and all other iterators which have been passed to this function and not yet - exhausted. - """ - return _theCooperator.coiterate(iterator) - - - -class Clock: - """ - Provide a deterministic, easily-controlled implementation of - L{IReactorTime.callLater}. This is commonly useful for writing - deterministic unit tests for code which schedules events using this API. - """ - implements(IReactorTime) - - rightNow = 0.0 - - def __init__(self): - self.calls = [] - - def seconds(self): - """ - Pretend to be time.time(). This is used internally when an operation - such as L{IDelayedCall.reset} needs to determine a a time value - relative to the current time. - - @rtype: C{float} - @return: The time which should be considered the current time. - """ - return self.rightNow - - - def callLater(self, when, what, *a, **kw): - """ - See L{twisted.internet.interfaces.IReactorTime.callLater}. - """ - dc = base.DelayedCall(self.seconds() + when, - what, a, kw, - self.calls.remove, - lambda c: None, - self.seconds) - self.calls.append(dc) - self.calls.sort(lambda a, b: cmp(a.getTime(), b.getTime())) - return dc - - def getDelayedCalls(self): - """ - See L{twisted.internet.interfaces.IReactorTime.getDelayedCalls} - """ - return self.calls - - def advance(self, amount): - """ - Move time on this clock forward by the given amount and run whatever - pending calls should be run. - - @type amount: C{float} - @param amount: The number of seconds which to advance this clock's - time. - """ - self.rightNow += amount - while self.calls and self.calls[0].getTime() <= self.seconds(): - call = self.calls.pop(0) - call.called = 1 - call.func(*call.args, **call.kw) - - - def pump(self, timings): - """ - Advance incrementally by the given set of times. - - @type timings: iterable of C{float} - """ - for amount in timings: - self.advance(amount) - - -def deferLater(clock, delay, callable, *args, **kw): - """ - Call the given function after a certain period of time has passed. - - @type clock: L{IReactorTime} provider - @param clock: The object which will be used to schedule the delayed - call. - - @type delay: C{float} or C{int} - @param delay: The number of seconds to wait before calling the function. - - @param callable: The object to call after the delay. - - @param *args: The positional arguments to pass to C{callable}. - - @param **kw: The keyword arguments to pass to C{callable}. - - @rtype: L{defer.Deferred} - - @return: A deferred that fires with the result of the callable when the - specified time has elapsed. - """ - d = defer.Deferred() - d.addCallback(lambda ignored: callable(*args, **kw)) - clock.callLater(delay, d.callback, None) - return d - - - -__all__ = [ - 'LoopingCall', - - 'Clock', - - 'SchedulerStopped', 'Cooperator', 'coiterate', - - 'deferLater', - ] diff --git a/tools/buildbot/pylibs/twisted/internet/tcp.py b/tools/buildbot/pylibs/twisted/internet/tcp.py deleted file mode 100644 index 29852ae..0000000 --- a/tools/buildbot/pylibs/twisted/internet/tcp.py +++ /dev/null @@ -1,894 +0,0 @@ -# -*- test-case-name: twisted.test.test_tcp -*- -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Various asynchronous TCP/IP classes. - -End users shouldn't use this module directly - use the reactor APIs instead. - -Maintainer: U{Itamar Shtull-Trauring} -""" - - -# System Imports -import os -import types -import socket -import sys -import operator -import warnings - -try: - import fcntl -except ImportError: - fcntl = None -from zope.interface import implements, classImplements - -try: - from OpenSSL import SSL -except ImportError: - SSL = None - -from twisted.python.runtime import platformType - - -if platformType == 'win32': - # no such thing as WSAEPERM or error code 10001 according to winsock.h or MSDN - EPERM = object() - from errno import WSAEINVAL as EINVAL - from errno import WSAEWOULDBLOCK as EWOULDBLOCK - from errno import WSAEINPROGRESS as EINPROGRESS - from errno import WSAEALREADY as EALREADY - from errno import WSAECONNRESET as ECONNRESET - from errno import WSAEISCONN as EISCONN - from errno import WSAENOTCONN as ENOTCONN - from errno import WSAEINTR as EINTR - from errno import WSAENOBUFS as ENOBUFS - from errno import WSAEMFILE as EMFILE - # No such thing as WSAENFILE, either. - ENFILE = object() - # Nor ENOMEM - ENOMEM = object() - EAGAIN = EWOULDBLOCK - from errno import WSAECONNRESET as ECONNABORTED - - from twisted.python.win32 import formatError as strerror -else: - from errno import EPERM - from errno import EINVAL - from errno import EWOULDBLOCK - from errno import EINPROGRESS - from errno import EALREADY - from errno import ECONNRESET - from errno import EISCONN - from errno import ENOTCONN - from errno import EINTR - from errno import ENOBUFS - from errno import EMFILE - from errno import ENFILE - from errno import ENOMEM - from errno import EAGAIN - from errno import ECONNABORTED - - from os import strerror - -from errno import errorcode - -# Twisted Imports -from twisted.internet import defer, base, address -from twisted.python import log, failure, reflect -from twisted.python.util import unsignedID -from twisted.internet.error import CannotListenError -from twisted.internet import abstract, main, interfaces, error - - - -class _SocketCloser: - _socketShutdownMethod = 'shutdown' - - def _closeSocket(self): - # socket.close() doesn't *really* close if there's another reference - # to it in the TCP/IP stack, e.g. if it was was inherited by a - # subprocess. And we really do want to close the connection. So we - # use shutdown() instead, and then close() in order to release the - # filedescriptor. - skt = self.socket - try: - getattr(skt, self._socketShutdownMethod)(2) - except socket.error: - pass - try: - skt.close() - except socket.error: - pass - -class _TLSMixin: - _socketShutdownMethod = 'sock_shutdown' - - writeBlockedOnRead = 0 - readBlockedOnWrite = 0 - _userWantRead = _userWantWrite = True - - def getPeerCertificate(self): - return self.socket.get_peer_certificate() - - def doRead(self): - if self.writeBlockedOnRead: - self.writeBlockedOnRead = 0 - self._resetReadWrite() - try: - return Connection.doRead(self) - except SSL.ZeroReturnError: - return main.CONNECTION_DONE - except SSL.WantReadError: - return - except SSL.WantWriteError: - self.readBlockedOnWrite = 1 - Connection.startWriting(self) - Connection.stopReading(self) - return - except SSL.SysCallError, (retval, desc): - if ((retval == -1 and desc == 'Unexpected EOF') - or retval > 0): - return main.CONNECTION_LOST - log.err() - return main.CONNECTION_LOST - except SSL.Error, e: - return e - - def doWrite(self): - # Retry disconnecting - if self.disconnected: - return self._postLoseConnection() - if self._writeDisconnected: - return self._closeWriteConnection() - - if self.readBlockedOnWrite: - self.readBlockedOnWrite = 0 - self._resetReadWrite() - return Connection.doWrite(self) - - def writeSomeData(self, data): - try: - return Connection.writeSomeData(self, data) - except SSL.WantWriteError: - return 0 - except SSL.WantReadError: - self.writeBlockedOnRead = 1 - Connection.stopWriting(self) - Connection.startReading(self) - return 0 - except SSL.ZeroReturnError: - return main.CONNECTION_LOST - except SSL.SysCallError, e: - if e[0] == -1 and data == "": - # errors when writing empty strings are expected - # and can be ignored - return 0 - else: - return main.CONNECTION_LOST - except SSL.Error, e: - return e - - def _postLoseConnection(self): - """Gets called after loseConnection(), after buffered data is sent. - - We try to send an SSL shutdown alert, but if it doesn't work, retry - when the socket is writable. - """ - self.disconnected=1 - if hasattr(self.socket, 'set_shutdown'): - self.socket.set_shutdown(SSL.RECEIVED_SHUTDOWN) - return self._sendCloseAlert() - - _first=False - def _sendCloseAlert(self): - # Okay, *THIS* is a bit complicated. - - # Basically, the issue is, OpenSSL seems to not actually return - # errors from SSL_shutdown. Therefore, the only way to - # determine if the close notification has been sent is by - # SSL_shutdown returning "done". However, it will not claim it's - # done until it's both sent *and* received a shutdown notification. - - # I don't actually want to wait for a received shutdown - # notification, though, so, I have to set RECEIVED_SHUTDOWN - # before calling shutdown. Then, it'll return True once it's - # *SENT* the shutdown. - - # However, RECEIVED_SHUTDOWN can't be left set, because then - # reads will fail, breaking half close. - - # Also, since shutdown doesn't report errors, an empty write call is - # done first, to try to detect if the connection has gone away. - # (*NOT* an SSL_write call, because that fails once you've called - # shutdown) - try: - os.write(self.socket.fileno(), '') - except OSError, se: - if se.args[0] in (EINTR, EWOULDBLOCK, ENOBUFS): - return 0 - # Write error, socket gone - return main.CONNECTION_LOST - - try: - if hasattr(self.socket, 'set_shutdown'): - laststate = self.socket.get_shutdown() - self.socket.set_shutdown(laststate | SSL.RECEIVED_SHUTDOWN) - done = self.socket.shutdown() - if not (laststate & SSL.RECEIVED_SHUTDOWN): - self.socket.set_shutdown(SSL.SENT_SHUTDOWN) - else: - #warnings.warn("SSL connection shutdown possibly unreliable, " - # "please upgrade to ver 0.XX", category=UserWarning) - self.socket.shutdown() - done = True - except SSL.Error, e: - return e - - if done: - self.stopWriting() - # Note that this is tested for by identity below. - return main.CONNECTION_DONE - else: - self.startWriting() - return None - - def _closeWriteConnection(self): - result = self._sendCloseAlert() - - if result is main.CONNECTION_DONE: - return Connection._closeWriteConnection(self) - - return result - - def startReading(self): - self._userWantRead = True - if not self.readBlockedOnWrite: - return Connection.startReading(self) - - def stopReading(self): - self._userWantRead = False - if not self.writeBlockedOnRead: - return Connection.stopReading(self) - - def startWriting(self): - self._userWantWrite = True - if not self.writeBlockedOnRead: - return Connection.startWriting(self) - - def stopWriting(self): - self._userWantWrite = False - if not self.readBlockedOnWrite: - return Connection.stopWriting(self) - - def _resetReadWrite(self): - # After changing readBlockedOnWrite or writeBlockedOnRead, - # call this to reset the state to what the user requested. - if self._userWantWrite: - self.startWriting() - else: - self.stopWriting() - - if self._userWantRead: - self.startReading() - else: - self.stopReading() - -def _getTLSClass(klass, _existing={}): - if klass not in _existing: - class TLSConnection(_TLSMixin, klass): - implements(interfaces.ISSLTransport) - _existing[klass] = TLSConnection - return _existing[klass] - -class Connection(abstract.FileDescriptor, _SocketCloser): - """ - Superclass of all socket-based FileDescriptors. - - This is an abstract superclass of all objects which represent a TCP/IP - connection based socket. - - @ivar logstr: prefix used when logging events related to this connection. - @type logstr: C{str} - """ - - implements(interfaces.ITCPTransport, interfaces.ISystemHandle) - - TLS = 0 - - def __init__(self, skt, protocol, reactor=None): - abstract.FileDescriptor.__init__(self, reactor=reactor) - self.socket = skt - self.socket.setblocking(0) - self.fileno = skt.fileno - self.protocol = protocol - - if SSL: - - def startTLS(self, ctx): - assert not self.TLS - error=False - if self.dataBuffer or self._tempDataBuffer: - self.dataBuffer += "".join(self._tempDataBuffer) - self._tempDataBuffer = [] - self._tempDataLen = 0 - written = self.writeSomeData(buffer(self.dataBuffer, self.offset)) - offset = self.offset - dataLen = len(self.dataBuffer) - self.offset = 0 - self.dataBuffer = "" - if isinstance(written, Exception) or (offset + written != dataLen): - error=True - - - self.stopReading() - self.stopWriting() - self._startTLS() - self.socket = SSL.Connection(ctx.getContext(), self.socket) - self.fileno = self.socket.fileno - self.startReading() - if error: - warnings.warn("startTLS with unwritten buffered data currently doesn't work right. See issue #686. Closing connection.", category=RuntimeWarning, stacklevel=2) - self.loseConnection() - return - - def _startTLS(self): - self.TLS = 1 - self.__class__ = _getTLSClass(self.__class__) - - def getHandle(self): - """Return the socket for this connection.""" - return self.socket - - def doRead(self): - """Calls self.protocol.dataReceived with all available data. - - This reads up to self.bufferSize bytes of data from its socket, then - calls self.dataReceived(data) to process it. If the connection is not - lost through an error in the physical recv(), this function will return - the result of the dataReceived call. - """ - try: - data = self.socket.recv(self.bufferSize) - except socket.error, se: - if se.args[0] == EWOULDBLOCK: - return - else: - return main.CONNECTION_LOST - if not data: - return main.CONNECTION_DONE - return self.protocol.dataReceived(data) - - def writeSomeData(self, data): - """Connection.writeSomeData(data) -> #of bytes written | CONNECTION_LOST - This writes as much data as possible to the socket and returns either - the number of bytes read (which is positive) or a connection error code - (which is negative) - """ - try: - # Limit length of buffer to try to send, because some OSes are too - # stupid to do so themselves (ahem windows) - return self.socket.send(buffer(data, 0, self.SEND_LIMIT)) - except socket.error, se: - if se.args[0] == EINTR: - return self.writeSomeData(data) - elif se.args[0] in (EWOULDBLOCK, ENOBUFS): - return 0 - else: - return main.CONNECTION_LOST - - def _closeWriteConnection(self): - try: - getattr(self.socket, self._socketShutdownMethod)(1) - except socket.error: - pass - p = interfaces.IHalfCloseableProtocol(self.protocol, None) - if p: - try: - p.writeConnectionLost() - except: - f = failure.Failure() - log.err() - self.connectionLost(f) - - def readConnectionLost(self, reason): - p = interfaces.IHalfCloseableProtocol(self.protocol, None) - if p: - try: - p.readConnectionLost() - except: - log.err() - self.connectionLost(failure.Failure()) - else: - self.connectionLost(reason) - - def connectionLost(self, reason): - """See abstract.FileDescriptor.connectionLost(). - """ - abstract.FileDescriptor.connectionLost(self, reason) - self._closeSocket() - protocol = self.protocol - del self.protocol - del self.socket - del self.fileno - protocol.connectionLost(reason) - - logstr = "Uninitialized" - - def logPrefix(self): - """Return the prefix to log with when I own the logging thread. - """ - return self.logstr - - def getTcpNoDelay(self): - return operator.truth(self.socket.getsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY)) - - def setTcpNoDelay(self, enabled): - self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, enabled) - - def getTcpKeepAlive(self): - return operator.truth(self.socket.getsockopt(socket.SOL_SOCKET, - socket.SO_KEEPALIVE)) - - def setTcpKeepAlive(self, enabled): - self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, enabled) - -if SSL: - classImplements(Connection, interfaces.ITLSTransport) - -class BaseClient(Connection): - """A base class for client TCP (and similiar) sockets. - """ - addressFamily = socket.AF_INET - socketType = socket.SOCK_STREAM - - def _finishInit(self, whenDone, skt, error, reactor): - """Called by base classes to continue to next stage of initialization.""" - if whenDone: - Connection.__init__(self, skt, None, reactor) - self.doWrite = self.doConnect - self.doRead = self.doConnect - reactor.callLater(0, whenDone) - else: - reactor.callLater(0, self.failIfNotConnected, error) - - def startTLS(self, ctx, client=1): - holder = Connection.startTLS(self, ctx) - if client: - self.socket.set_connect_state() - else: - self.socket.set_accept_state() - return holder - - def stopConnecting(self): - """Stop attempt to connect.""" - self.failIfNotConnected(error.UserError()) - - def failIfNotConnected(self, err): - """ - Generic method called when the attemps to connect failed. It basically - cleans everything it can: call connectionFailed, stop read and write, - delete socket related members. - """ - if (self.connected or self.disconnected or - not hasattr(self, "connector")): - return - - self.connector.connectionFailed(failure.Failure(err)) - if hasattr(self, "reactor"): - # this doesn't happen if we failed in __init__ - self.stopReading() - self.stopWriting() - del self.connector - - try: - self._closeSocket() - except AttributeError: - pass - else: - del self.socket, self.fileno - - def createInternetSocket(self): - """(internal) Create a non-blocking socket using - self.addressFamily, self.socketType. - """ - s = socket.socket(self.addressFamily, self.socketType) - s.setblocking(0) - if fcntl and hasattr(fcntl, 'FD_CLOEXEC'): - old = fcntl.fcntl(s.fileno(), fcntl.F_GETFD) - fcntl.fcntl(s.fileno(), fcntl.F_SETFD, old | fcntl.FD_CLOEXEC) - return s - - def resolveAddress(self): - if abstract.isIPAddress(self.addr[0]): - self._setRealAddress(self.addr[0]) - else: - d = self.reactor.resolve(self.addr[0]) - d.addCallbacks(self._setRealAddress, self.failIfNotConnected) - - def _setRealAddress(self, address): - self.realAddress = (address, self.addr[1]) - self.doConnect() - - def doConnect(self): - """I connect the socket. - - Then, call the protocol's makeConnection, and start waiting for data. - """ - if not hasattr(self, "connector"): - # this happens when connection failed but doConnect - # was scheduled via a callLater in self._finishInit - return - - err = self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR) - if err: - self.failIfNotConnected(error.getConnectError((err, strerror(err)))) - return - - - # doConnect gets called twice. The first time we actually need to - # start the connection attempt. The second time we don't really - # want to (SO_ERROR above will have taken care of any errors, and if - # it reported none, the mere fact that doConnect was called again is - # sufficient to indicate that the connection has succeeded), but it - # is not /particularly/ detrimental to do so. This should get - # cleaned up some day, though. - try: - connectResult = self.socket.connect_ex(self.realAddress) - except socket.error, se: - connectResult = se.args[0] - if connectResult: - if connectResult == EISCONN: - pass - # on Windows EINVAL means sometimes that we should keep trying: - # http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/winsock/connect_2.asp - elif ((connectResult in (EWOULDBLOCK, EINPROGRESS, EALREADY)) or - (connectResult == EINVAL and platformType == "win32")): - self.startReading() - self.startWriting() - return - else: - self.failIfNotConnected(error.getConnectError((connectResult, strerror(connectResult)))) - return - - # If I have reached this point without raising or returning, that means - # that the socket is connected. - del self.doWrite - del self.doRead - # we first stop and then start, to reset any references to the old doRead - self.stopReading() - self.stopWriting() - self._connectDone() - - def _connectDone(self): - self.protocol = self.connector.buildProtocol(self.getPeer()) - self.connected = 1 - self.logstr = self.protocol.__class__.__name__ + ",client" - self.startReading() - self.protocol.makeConnection(self) - - def connectionLost(self, reason): - if not self.connected: - self.failIfNotConnected(error.ConnectError(string=reason)) - else: - Connection.connectionLost(self, reason) - self.connector.connectionLost(reason) - - -class Client(BaseClient): - """A TCP client.""" - - def __init__(self, host, port, bindAddress, connector, reactor=None): - # BaseClient.__init__ is invoked later - self.connector = connector - self.addr = (host, port) - - whenDone = self.resolveAddress - err = None - skt = None - - try: - skt = self.createInternetSocket() - except socket.error, se: - err = error.ConnectBindError(se[0], se[1]) - whenDone = None - if whenDone and bindAddress is not None: - try: - skt.bind(bindAddress) - except socket.error, se: - err = error.ConnectBindError(se[0], se[1]) - whenDone = None - self._finishInit(whenDone, skt, err, reactor) - - def getHost(self): - """Returns an IPv4Address. - - This indicates the address from which I am connecting. - """ - return address.IPv4Address('TCP', *(self.socket.getsockname() + ('INET',))) - - def getPeer(self): - """Returns an IPv4Address. - - This indicates the address that I am connected to. - """ - return address.IPv4Address('TCP', *(self.addr + ('INET',))) - - def __repr__(self): - s = '<%s to %s at %x>' % (self.__class__, self.addr, unsignedID(self)) - return s - - -class Server(Connection): - """ - Serverside socket-stream connection class. - - This is a serverside network connection transport; a socket which came from - an accept() on a server. - """ - - def __init__(self, sock, protocol, client, server, sessionno): - """ - Server(sock, protocol, client, server, sessionno) - - Initialize it with a socket, a protocol, a descriptor for my peer (a - tuple of host, port describing the other end of the connection), an - instance of Port, and a session number. - """ - Connection.__init__(self, sock, protocol) - self.server = server - self.client = client - self.sessionno = sessionno - self.hostname = client[0] - self.logstr = "%s,%s,%s" % (self.protocol.__class__.__name__, - sessionno, - self.hostname) - self.repstr = "<%s #%s on %s>" % (self.protocol.__class__.__name__, - self.sessionno, - self.server._realPortNumber) - self.startReading() - self.connected = 1 - - def __repr__(self): - """A string representation of this connection. - """ - return self.repstr - - def startTLS(self, ctx, server=1): - holder = Connection.startTLS(self, ctx) - if server: - self.socket.set_accept_state() - else: - self.socket.set_connect_state() - return holder - - def getHost(self): - """Returns an IPv4Address. - - This indicates the server's address. - """ - return address.IPv4Address('TCP', *(self.socket.getsockname() + ('INET',))) - - def getPeer(self): - """Returns an IPv4Address. - - This indicates the client's address. - """ - return address.IPv4Address('TCP', *(self.client + ('INET',))) - -class Port(base.BasePort, _SocketCloser): - """I am a TCP server port, listening for connections. - - When a connection is accepted, I will call my factory's buildProtocol with - the incoming connection as an argument, according to the specification - described in twisted.internet.interfaces.IProtocolFactory. - - If you wish to change the sort of transport that will be used, my - `transport' attribute will be called with the signature expected for - Server.__init__, so it can be replaced. - """ - - implements(interfaces.IListeningPort) - - addressFamily = socket.AF_INET - socketType = socket.SOCK_STREAM - - transport = Server - sessionno = 0 - interface = '' - backlog = 50 - - # Actual port number being listened on, only set to a non-None - # value when we are actually listening. - _realPortNumber = None - - def __init__(self, port, factory, backlog=50, interface='', reactor=None): - """Initialize with a numeric port to listen on. - """ - base.BasePort.__init__(self, reactor=reactor) - self.port = port - self.factory = factory - self.backlog = backlog - self.interface = interface - - def __repr__(self): - if self._realPortNumber is not None: - return "<%s of %s on %s>" % (self.__class__, self.factory.__class__, - self._realPortNumber) - else: - return "<%s of %s (not listening)>" % (self.__class__, self.factory.__class__) - - def createInternetSocket(self): - s = base.BasePort.createInternetSocket(self) - if platformType == "posix" and sys.platform != "cygwin": - s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - return s - - def startListening(self): - """Create and bind my socket, and begin listening on it. - - This is called on unserialization, and must be called after creating a - server to begin listening on the specified port. - """ - try: - skt = self.createInternetSocket() - skt.bind((self.interface, self.port)) - except socket.error, le: - raise CannotListenError, (self.interface, self.port, le) - - # Make sure that if we listened on port 0, we update that to - # reflect what the OS actually assigned us. - self._realPortNumber = skt.getsockname()[1] - - log.msg("%s starting on %s" % (self.factory.__class__, self._realPortNumber)) - - # The order of the next 6 lines is kind of bizarre. If no one - # can explain it, perhaps we should re-arrange them. - self.factory.doStart() - skt.listen(self.backlog) - self.connected = 1 - self.socket = skt - self.fileno = self.socket.fileno - self.numberAccepts = 100 - - self.startReading() - - def _buildAddr(self, (host, port)): - return address._ServerFactoryIPv4Address('TCP', host, port) - - def doRead(self): - """Called when my socket is ready for reading. - - This accepts a connection and calls self.protocol() to handle the - wire-level protocol. - """ - try: - if platformType == "posix": - numAccepts = self.numberAccepts - else: - # win32 event loop breaks if we do more than one accept() - # in an iteration of the event loop. - numAccepts = 1 - for i in range(numAccepts): - # we need this so we can deal with a factory's buildProtocol - # calling our loseConnection - if self.disconnecting: - return - try: - skt, addr = self.socket.accept() - except socket.error, e: - if e.args[0] in (EWOULDBLOCK, EAGAIN): - self.numberAccepts = i - break - elif e.args[0] == EPERM: - # Netfilter on Linux may have rejected the - # connection, but we get told to try to accept() - # anyway. - continue - elif e.args[0] in (EMFILE, ENOBUFS, ENFILE, ENOMEM, ECONNABORTED): - - # Linux gives EMFILE when a process is not allowed - # to allocate any more file descriptors. *BSD and - # Win32 give (WSA)ENOBUFS. Linux can also give - # ENFILE if the system is out of inodes, or ENOMEM - # if there is insufficient memory to allocate a new - # dentry. ECONNABORTED is documented as possible on - # both Linux and Windows, but it is not clear - # whether there are actually any circumstances under - # which it can happen (one might expect it to be - # possible if a client sends a FIN or RST after the - # server sends a SYN|ACK but before application code - # calls accept(2), however at least on Linux this - # _seems_ to be short-circuited by syncookies. - - log.msg("Could not accept new connection (%s)" % ( - errorcode[e.args[0]],)) - break - raise - - protocol = self.factory.buildProtocol(self._buildAddr(addr)) - if protocol is None: - skt.close() - continue - s = self.sessionno - self.sessionno = s+1 - transport = self.transport(skt, protocol, addr, self, s) - transport = self._preMakeConnection(transport) - protocol.makeConnection(transport) - else: - self.numberAccepts = self.numberAccepts+20 - except: - # Note that in TLS mode, this will possibly catch SSL.Errors - # raised by self.socket.accept() - # - # There is no "except SSL.Error:" above because SSL may be - # None if there is no SSL support. In any case, all the - # "except SSL.Error:" suite would probably do is log.deferr() - # and return, so handling it here works just as well. - log.deferr() - - def _preMakeConnection(self, transport): - return transport - - def loseConnection(self, connDone=failure.Failure(main.CONNECTION_DONE)): - """Stop accepting connections on this port. - - This will shut down my socket and call self.connectionLost(). - It returns a deferred which will fire successfully when the - port is actually closed. - """ - self.disconnecting = 1 - self.stopReading() - if self.connected: - self.deferred = defer.Deferred() - self.reactor.callLater(0, self.connectionLost, connDone) - return self.deferred - - stopListening = loseConnection - - def connectionLost(self, reason): - """Cleans up my socket. - """ - log.msg('(Port %s Closed)' % self._realPortNumber) - self._realPortNumber = None - base.BasePort.connectionLost(self, reason) - self.connected = 0 - self._closeSocket() - del self.socket - del self.fileno - self.factory.doStop() - if hasattr(self, "deferred"): - self.deferred.callback(None) - del self.deferred - - def logPrefix(self): - """Returns the name of my class, to prefix log entries with. - """ - return reflect.qual(self.factory.__class__) - - def getHost(self): - """Returns an IPv4Address. - - This indicates the server's address. - """ - return address.IPv4Address('TCP', *(self.socket.getsockname() + ('INET',))) - -class Connector(base.BaseConnector): - def __init__(self, host, port, factory, timeout, bindAddress, reactor=None): - self.host = host - if isinstance(port, types.StringTypes): - try: - port = socket.getservbyname(port, 'tcp') - except socket.error, e: - raise error.ServiceNameUnknownError(string="%s (%r)" % (e, port)) - self.port = port - self.bindAddress = bindAddress - base.BaseConnector.__init__(self, factory, timeout, reactor) - - def _makeTransport(self): - return Client(self.host, self.port, self.bindAddress, self, self.reactor) - - def getDestination(self): - return address.IPv4Address('TCP', self.host, self.port, 'INET') diff --git a/tools/buildbot/pylibs/twisted/internet/test/__init__.py b/tools/buildbot/pylibs/twisted/internet/test/__init__.py deleted file mode 100644 index 2c1f28e..0000000 --- a/tools/buildbot/pylibs/twisted/internet/test/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright (c) 2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.internet}. -""" diff --git a/tools/buildbot/pylibs/twisted/internet/test/test_gtk2reactor.py b/tools/buildbot/pylibs/twisted/internet/test/test_gtk2reactor.py deleted file mode 100644 index 22daed8..0000000 --- a/tools/buildbot/pylibs/twisted/internet/test/test_gtk2reactor.py +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright (c) 2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.internet.gtk2reactor}. -""" - -from twisted.trial.unittest import TestCase - - -class Gtk2ReactorTests(TestCase): - """ - Tests for L{twisted.internet.gtk2reactor.Gtk2Reactor}. - """ - def test_stopWhenRunning(self): - """ - When C{reactor.stop} is scheduled with C{callWhenRunning}, - C{reactor.run} will return immediately, and without processing any - timed events. - """ - # This test *should* be part of a general reactor test suite that runs - # tests cases against all reactor implementations. - missed = [] - def calledTooLate(): - missed.append(True) - reactor.crash() - reactor = Gtk2Reactor(useGtk=False) - reactor.callWhenRunning(reactor.stop) - reactor.callLater(0, calledTooLate) - reactor.run(installSignalHandlers=False) - # XXX This explicit calls to clean up the waker should become obsolete - # when bug #3063 is fixed. -radix, 2008-02-29. Fortunately it should - # probably cause an error when bug #3063 is fixed, so it should be - # removed in the same branch that fixes it. - reactor.removeReader(reactor.waker) - reactor.waker.connectionLost(None) - if missed == [True]: - self.fail("callWhenRunning reactor.stop did not take effect") - -try: - from twisted.internet.gtk2reactor import Gtk2Reactor -except ImportError: - Gtk2ReactorTests.skip = "gtk2reactor is unavailable" diff --git a/tools/buildbot/pylibs/twisted/internet/test/test_iocp.py b/tools/buildbot/pylibs/twisted/internet/test/test_iocp.py deleted file mode 100644 index ed72b9e..0000000 --- a/tools/buildbot/pylibs/twisted/internet/test/test_iocp.py +++ /dev/null @@ -1,105 +0,0 @@ -from twisted.internet.protocol import ServerFactory, Protocol, ClientCreator -from twisted.internet.defer import DeferredList, maybeDeferred, Deferred -from twisted.trial import unittest -from twisted.internet import reactor -from twisted.python import log - -from zope.interface.verify import verifyClass - -class StopStartReadingProtocol(Protocol): - def connectionMade(self): - self.transport.pauseProducing() - self.transport.resumeProducing() - reactor.callLater(0, self._beTerrible) - self.data = '' - - - def _beTerrible(self): - self.transport.pauseProducing() - self.transport.resumeProducing() - reactor.callLater(0, self._beMoreTerrible) - - - def _beMoreTerrible(self): - self.transport.pauseProducing() - self.transport.resumeProducing() - reactor.callLater(0, self.factory.ready_d.callback, self) - - - def dataReceived(self, data): - log.msg('got data', len(data)) - self.data += data - if len(self.data) == 4*self.transport.readBufferSize: - self.factory.stop_d.callback(self.data) - - - -class IOCPReactorTestCase(unittest.TestCase): - def test_noPendingTimerEvents(self): - """ - Test reactor behavior (doIteration) when there are no pending time - events. - """ - from twisted.internet.iocpreactor.reactor import IOCPReactor - ir = IOCPReactor() - ir.wakeUp() - self.failIf(ir.doIteration(None)) - - - def test_stopStartReading(self): - """ - This test checks transport read state! There are three bits - of it: - 1) The transport producer is paused -- transport.reading - is False) - 2) The transport is about to schedule an OS read, on the next - reactor iteration -- transport._readScheduled - 3) The OS has a pending asynchronous read on our behalf -- - transport._readScheduledInOS - if 3) is not implemented, it is possible to trick IOCPReactor into - scheduling an OS read before the previous one finishes - """ - sf = ServerFactory() - sf.protocol = StopStartReadingProtocol - sf.ready_d = Deferred() - sf.stop_d = Deferred() - p = reactor.listenTCP(0, sf) - port = p.getHost().port - cc = ClientCreator(reactor, Protocol) - def proceed(protos, port): - log.msg('PROCEEDING WITH THE TESTATHRON') - self.assert_(protos[0]) - self.assert_(protos[1]) - protos = protos[0][1], protos[1][1] - protos[0].transport.write( - 'x' * (2 * protos[0].transport.readBufferSize) + - 'y' * (2 * protos[0].transport.readBufferSize)) - return sf.stop_d.addCallback(cleanup, protos, port) - - def cleanup(data, protos, port): - self.assert_(data == 'x'*(2*protos[0].transport.readBufferSize)+ - 'y'*(2*protos[0].transport.readBufferSize), - 'did not get the right data') - return DeferredList([ - maybeDeferred(protos[0].transport.loseConnection), - maybeDeferred(protos[1].transport.loseConnection), - maybeDeferred(port.stopListening)]) - - return (DeferredList([cc.connectTCP('127.0.0.1', port), sf.ready_d]) - .addCallback(proceed, p)) - - - def test_reactorInterfaces(self): - """ - Verify that IOCP socket-representing classes implement IReadWriteHandle - """ - from twisted.internet.iocpreactor.interfaces import IReadWriteHandle - from twisted.internet.iocpreactor import tcp, udp - verifyClass(IReadWriteHandle, tcp.Connection) - verifyClass(IReadWriteHandle, udp.Port) - - - -if reactor.__class__.__name__ != 'IOCPReactor': - IOCPReactorTestCase.skip = 'This test only applies to IOCPReactor' - diff --git a/tools/buildbot/pylibs/twisted/internet/threads.py b/tools/buildbot/pylibs/twisted/internet/threads.py deleted file mode 100644 index 415b66d..0000000 --- a/tools/buildbot/pylibs/twisted/internet/threads.py +++ /dev/null @@ -1,88 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Extended thread dispatching support. - -For basic support see reactor threading API docs. - -Maintainer: U{Itamar Shtull-Trauring} -""" - -import Queue - -from twisted.python import failure -from twisted.internet import defer - - -def _putResultInDeferred(deferred, f, args, kwargs): - """ - Run a function and give results to a Deferred. - """ - from twisted.internet import reactor - try: - result = f(*args, **kwargs) - except: - f = failure.Failure() - reactor.callFromThread(deferred.errback, f) - else: - reactor.callFromThread(deferred.callback, result) - - -def deferToThread(f, *args, **kwargs): - """ - Run function in thread and return result as Deferred. - """ - d = defer.Deferred() - from twisted.internet import reactor - reactor.callInThread(_putResultInDeferred, d, f, args, kwargs) - return d - - -def _runMultiple(tupleList): - """ - Run a list of functions. - """ - for f, args, kwargs in tupleList: - f(*args, **kwargs) - - -def callMultipleInThread(tupleList): - """ - Run a list of functions in the same thread. - - tupleList should be a list of (function, argsList, kwargsDict) tuples. - """ - from twisted.internet import reactor - reactor.callInThread(_runMultiple, tupleList) - - -def blockingCallFromThread(reactor, f, *a, **kw): - """ - Run a function in the reactor from a thread, and wait for the result - synchronously, i.e. until the callback chain returned by the function - get a result. - - @param reactor: The L{IReactorThreads} provider which will be used to - schedule the function call. - @param f: the callable to run in the reactor thread - @type f: any callable. - @param a: the arguments to pass to C{f}. - @param kw: the keyword arguments to pass to C{f}. - - @return: the result of the callback chain. - @raise: any error raised during the callback chain. - """ - queue = Queue.Queue() - def _callFromThread(): - result = defer.maybeDeferred(f, *a, **kw) - result.addBoth(queue.put) - reactor.callFromThread(_callFromThread) - result = queue.get() - if isinstance(result, failure.Failure): - result.raiseException() - return result - - -__all__ = ["deferToThread", "callMultipleInThread", "blockingCallFromThread"] - diff --git a/tools/buildbot/pylibs/twisted/internet/tksupport.py b/tools/buildbot/pylibs/twisted/internet/tksupport.py deleted file mode 100644 index 3248fa7..0000000 --- a/tools/buildbot/pylibs/twisted/internet/tksupport.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -This module integrates Tkinter with twisted.internet's mainloop. - -Maintainer: U{Itamar Shtull-Trauring} - -To use, do:: - - | tksupport.install(rootWidget) - -and then run your reactor as usual - do *not* call Tk's mainloop(), -use Twisted's regular mechanism for running the event loop. - -Likewise, to stop your program you will need to stop Twisted's -event loop. For example, if you want closing your root widget to -stop Twisted:: - - | root.protocol('WM_DELETE_WINDOW', reactor.stop) - -""" - -# system imports -import Tkinter, tkSimpleDialog, tkMessageBox - -# twisted imports -from twisted.python import log -from twisted.internet import task - - -_task = None - -def install(widget, ms=10, reactor=None): - """Install a Tkinter.Tk() object into the reactor.""" - installTkFunctions() - global _task - _task = task.LoopingCall(widget.update) - _task.start(ms / 1000.0, False) - -def uninstall(): - """Remove the root Tk widget from the reactor. - - Call this before destroy()ing the root widget. - """ - global _task - _task.stop() - _task = None - - -def installTkFunctions(): - import twisted.python.util - twisted.python.util.getPassword = getPassword - - -def getPassword(prompt = '', confirm = 0): - while 1: - try1 = tkSimpleDialog.askstring('Password Dialog', prompt, show='*') - if not confirm: - return try1 - try2 = tkSimpleDialog.askstring('Password Dialog', 'Confirm Password', show='*') - if try1 == try2: - return try1 - else: - tkMessageBox.showerror('Password Mismatch', 'Passwords did not match, starting over') - -__all__ = ["install", "uninstall"] diff --git a/tools/buildbot/pylibs/twisted/internet/udp.py b/tools/buildbot/pylibs/twisted/internet/udp.py deleted file mode 100644 index 1597814..0000000 --- a/tools/buildbot/pylibs/twisted/internet/udp.py +++ /dev/null @@ -1,385 +0,0 @@ -# -*- test-case-name: twisted.test.test_udp -*- - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Various asynchronous UDP classes. - -Please do not use this module directly. - -Maintainer: U{Itamar Shtull-Trauring} -""" - -# System Imports -import os -import socket -import operator -import struct -import warnings -from zope.interface import implements - -from twisted.python.runtime import platformType -if platformType == 'win32': - from errno import WSAEWOULDBLOCK as EWOULDBLOCK - from errno import WSAEINTR as EINTR - from errno import WSAEMSGSIZE as EMSGSIZE - from errno import WSAECONNREFUSED as ECONNREFUSED - from errno import WSAECONNRESET - EAGAIN=EWOULDBLOCK -else: - from errno import EWOULDBLOCK, EINTR, EMSGSIZE, ECONNREFUSED, EAGAIN - -# Twisted Imports -from twisted.internet import protocol, base, defer, address -from twisted.persisted import styles -from twisted.python import log, reflect, failure - -# Sibling Imports -import abstract, error, interfaces - - -class Port(base.BasePort): - """UDP port, listening for packets.""" - - implements(interfaces.IUDPTransport, interfaces.ISystemHandle) - - addressFamily = socket.AF_INET - socketType = socket.SOCK_DGRAM - maxThroughput = 256 * 1024 # max bytes we read in one eventloop iteration - - # Actual port number being listened on, only set to a non-None - # value when we are actually listening. - _realPortNumber = None - - def __init__(self, port, proto, interface='', maxPacketSize=8192, reactor=None): - """Initialize with a numeric port to listen on. - """ - base.BasePort.__init__(self, reactor) - self.port = port - self.protocol = proto - self.maxPacketSize = maxPacketSize - self.interface = interface - self.setLogStr() - self._connectedAddr = None - - def __repr__(self): - if self._realPortNumber is not None: - return "<%s on %s>" % (self.protocol.__class__, self._realPortNumber) - else: - return "<%s not connected>" % (self.protocol.__class__,) - - def getHandle(self): - """Return a socket object.""" - return self.socket - - def startListening(self): - """Create and bind my socket, and begin listening on it. - - This is called on unserialization, and must be called after creating a - server to begin listening on the specified port. - """ - self._bindSocket() - self._connectToProtocol() - - def _bindSocket(self): - try: - skt = self.createInternetSocket() - skt.bind((self.interface, self.port)) - except socket.error, le: - raise error.CannotListenError, (self.interface, self.port, le) - - # Make sure that if we listened on port 0, we update that to - # reflect what the OS actually assigned us. - self._realPortNumber = skt.getsockname()[1] - - log.msg("%s starting on %s"%(self.protocol.__class__, self._realPortNumber)) - - self.connected = 1 - self.socket = skt - self.fileno = self.socket.fileno - - def _connectToProtocol(self): - self.protocol.makeConnection(self) - self.startReading() - - - def doRead(self): - """Called when my socket is ready for reading.""" - read = 0 - while read < self.maxThroughput: - try: - data, addr = self.socket.recvfrom(self.maxPacketSize) - except socket.error, se: - no = se.args[0] - if no in (EAGAIN, EINTR, EWOULDBLOCK): - return - if (no == ECONNREFUSED) or (platformType == "win32" and no == WSAECONNRESET): - if self._connectedAddr: - self.protocol.connectionRefused() - else: - raise - else: - read += len(data) - try: - self.protocol.datagramReceived(data, addr) - except: - log.err() - - - def write(self, datagram, addr=None): - """Write a datagram. - - @param addr: should be a tuple (ip, port), can be None in connected mode. - """ - if self._connectedAddr: - assert addr in (None, self._connectedAddr) - try: - return self.socket.send(datagram) - except socket.error, se: - no = se.args[0] - if no == EINTR: - return self.write(datagram) - elif no == EMSGSIZE: - raise error.MessageLengthError, "message too long" - elif no == ECONNREFUSED: - self.protocol.connectionRefused() - else: - raise - else: - assert addr != None - if not addr[0].replace(".", "").isdigit(): - warnings.warn("Please only pass IPs to write(), not hostnames", DeprecationWarning, stacklevel=2) - try: - return self.socket.sendto(datagram, addr) - except socket.error, se: - no = se.args[0] - if no == EINTR: - return self.write(datagram, addr) - elif no == EMSGSIZE: - raise error.MessageLengthError, "message too long" - elif no == ECONNREFUSED: - # in non-connected UDP ECONNREFUSED is platform dependent, I think - # and the info is not necessarily useful. Nevertheless maybe we - # should call connectionRefused? XXX - return - else: - raise - - def writeSequence(self, seq, addr): - self.write("".join(seq), addr) - - def connect(self, host, port): - """'Connect' to remote server.""" - if self._connectedAddr: - raise RuntimeError, "already connected, reconnecting is not currently supported (talk to itamar if you want this)" - if not abstract.isIPAddress(host): - raise ValueError, "please pass only IP addresses, not domain names" - self._connectedAddr = (host, port) - self.socket.connect((host, port)) - - def _loseConnection(self): - self.stopReading() - if self.connected: # actually means if we are *listening* - from twisted.internet import reactor - reactor.callLater(0, self.connectionLost) - - def stopListening(self): - if self.connected: - result = self.d = defer.Deferred() - else: - result = None - self._loseConnection() - return result - - def loseConnection(self): - warnings.warn("Please use stopListening() to disconnect port", DeprecationWarning, stacklevel=2) - self.stopListening() - - def connectionLost(self, reason=None): - """Cleans up my socket. - """ - log.msg('(Port %s Closed)' % self._realPortNumber) - self._realPortNumber = None - base.BasePort.connectionLost(self, reason) - if hasattr(self, "protocol"): - # we won't have attribute in ConnectedPort, in cases - # where there was an error in connection process - self.protocol.doStop() - self.connected = 0 - self.socket.close() - del self.socket - del self.fileno - if hasattr(self, "d"): - self.d.callback(None) - del self.d - - def setLogStr(self): - self.logstr = reflect.qual(self.protocol.__class__) + " (UDP)" - - def logPrefix(self): - """Returns the name of my class, to prefix log entries with. - """ - return self.logstr - - def getHost(self): - """ - Returns an IPv4Address. - - This indicates the address from which I am connecting. - """ - return address.IPv4Address('UDP', *(self.socket.getsockname() + ('INET_UDP',))) - - -class ConnectedPort(Port): - """DEPRECATED. - - A connected UDP socket.""" - - implements(interfaces.IUDPConnectedTransport) - - def __init__(self, (remotehost, remoteport), port, proto, interface='', maxPacketSize=8192, reactor=None): - Port.__init__(self, port, proto, interface, maxPacketSize, reactor) - self.remotehost = remotehost - self.remoteport = remoteport - - def startListening(self): - self._bindSocket() - if abstract.isIPAddress(self.remotehost): - self.setRealAddress(self.remotehost) - else: - self.realAddress = None - d = self.reactor.resolve(self.remotehost) - d.addCallback(self.setRealAddress).addErrback(self.connectionFailed) - - def setRealAddress(self, addr): - self.realAddress = addr - self.socket.connect((addr, self.remoteport)) - self._connectToProtocol() - - def connectionFailed(self, reason): - self._loseConnection() - self.protocol.connectionFailed(reason) - del self.protocol - - def doRead(self): - """Called when my socket is ready for reading.""" - read = 0 - while read < self.maxThroughput: - try: - data, addr = self.socket.recvfrom(self.maxPacketSize) - read += len(data) - self.protocol.datagramReceived(data) - except socket.error, se: - no = se.args[0] - if no in (EAGAIN, EINTR, EWOULDBLOCK): - return - if (no == ECONNREFUSED) or (platformType == "win32" and no == WSAECONNRESET): - self.protocol.connectionRefused() - else: - raise - except: - log.deferr() - - def write(self, data): - """Write a datagram.""" - try: - return self.socket.send(data) - except socket.error, se: - no = se.args[0] - if no == EINTR: - return self.write(data) - elif no == EMSGSIZE: - raise error.MessageLengthError, "message too long" - elif no == ECONNREFUSED: - self.protocol.connectionRefused() - else: - raise - - def getPeer(self): - """ - Returns a tuple of ('INET_UDP', hostname, port), indicating - the remote address. - """ - return address.IPv4Address('UDP', self.remotehost, self.remoteport, 'INET_UDP') - - -class MulticastMixin: - """Implement multicast functionality.""" - - def getOutgoingInterface(self): - i = self.socket.getsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF) - return socket.inet_ntoa(struct.pack("@i", i)) - - def setOutgoingInterface(self, addr): - """Returns Deferred of success.""" - return self.reactor.resolve(addr).addCallback(self._setInterface) - - def _setInterface(self, addr): - i = socket.inet_aton(addr) - self.socket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF, i) - return 1 - - def getLoopbackMode(self): - return self.socket.getsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP) - - def setLoopbackMode(self, mode): - mode = struct.pack("b", operator.truth(mode)) - self.socket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, mode) - - def getTTL(self): - return self.socket.getsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL) - - def setTTL(self, ttl): - ttl = struct.pack("B", ttl) - self.socket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl) - - def joinGroup(self, addr, interface=""): - """Join a multicast group. Returns Deferred of success.""" - return self.reactor.resolve(addr).addCallback(self._joinAddr1, interface, 1) - - def _joinAddr1(self, addr, interface, join): - return self.reactor.resolve(interface).addCallback(self._joinAddr2, addr, join) - - def _joinAddr2(self, interface, addr, join): - addr = socket.inet_aton(addr) - interface = socket.inet_aton(interface) - if join: - cmd = socket.IP_ADD_MEMBERSHIP - else: - cmd = socket.IP_DROP_MEMBERSHIP - try: - self.socket.setsockopt(socket.IPPROTO_IP, cmd, addr + interface) - except socket.error, e: - return failure.Failure(error.MulticastJoinError(addr, interface, *e.args)) - - def leaveGroup(self, addr, interface=""): - """Leave multicast group, return Deferred of success.""" - return self.reactor.resolve(addr).addCallback(self._joinAddr1, interface, 0) - - -class MulticastPort(MulticastMixin, Port): - """UDP Port that supports multicasting.""" - - implements(interfaces.IMulticastTransport) - - def __init__(self, port, proto, interface='', maxPacketSize=8192, reactor=None, listenMultiple=False): - Port.__init__(self, port, proto, interface, maxPacketSize, reactor) - self.listenMultiple = listenMultiple - - def createInternetSocket(self): - skt = Port.createInternetSocket(self) - if self.listenMultiple: - skt.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - if hasattr(socket, "SO_REUSEPORT"): - skt.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) - return skt - - -class ConnectedMulticastPort(MulticastMixin, ConnectedPort): - """DEPRECATED. - - Connected UDP Port that supports multicasting.""" - - implements(interfaces.IMulticastTransport) diff --git a/tools/buildbot/pylibs/twisted/internet/unix.py b/tools/buildbot/pylibs/twisted/internet/unix.py deleted file mode 100644 index 0fc5ad8..0000000 --- a/tools/buildbot/pylibs/twisted/internet/unix.py +++ /dev/null @@ -1,297 +0,0 @@ -# -*- test-case-name: twisted.test.test_unix -*- - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Various asynchronous TCP/IP classes. - -End users shouldn't use this module directly - use the reactor APIs instead. - -Maintainer: U{Itamar Shtull-Trauring} -""" - -# System imports -import os, stat, socket -from errno import EINTR, EMSGSIZE, EAGAIN, EWOULDBLOCK, ECONNREFUSED - -from zope.interface import implements, implementsOnly, implementedBy - -if not hasattr(socket, 'AF_UNIX'): - raise ImportError("UNIX sockets not supported on this platform") - -# Twisted imports -from twisted.internet import base, tcp, udp, error, interfaces, protocol, address -from twisted.internet.error import CannotListenError -from twisted.python import lockfile, log, reflect, failure - - -class Server(tcp.Server): - def __init__(self, sock, protocol, client, server, sessionno): - tcp.Server.__init__(self, sock, protocol, (client, None), server, sessionno) - - def getHost(self): - return address.UNIXAddress(self.socket.getsockname()) - - def getPeer(self): - return address.UNIXAddress(self.hostname) - - -class Port(tcp.Port): - addressFamily = socket.AF_UNIX - socketType = socket.SOCK_STREAM - - transport = Server - lockFile = None - - def __init__(self, fileName, factory, backlog=50, mode=0666, reactor=None, wantPID = 0): - tcp.Port.__init__(self, fileName, factory, backlog, reactor=reactor) - self.mode = mode - self.wantPID = wantPID - - def __repr__(self): - factoryName = reflect.qual(self.factory.__class__) - if hasattr(self, 'socket'): - return '<%s on %r>' % (factoryName, self.port) - else: - return '<%s (not listening)>' % (factoryName,) - - def _buildAddr(self, name): - return address.UNIXAddress(name) - - def startListening(self): - """Create and bind my socket, and begin listening on it. - - This is called on unserialization, and must be called after creating a - server to begin listening on the specified port. - """ - log.msg("%s starting on %r" % (self.factory.__class__, repr(self.port))) - if self.wantPID: - self.lockFile = lockfile.FilesystemLock(self.port + ".lock") - if not self.lockFile.lock(): - raise CannotListenError, (None, self.port, "Cannot acquire lock") - else: - if not self.lockFile.clean: - try: - # This is a best-attempt at cleaning up - # left-over unix sockets on the filesystem. - # If it fails, there's not much else we can - # do. The bind() below will fail with an - # exception that actually propegates. - if stat.S_ISSOCK(os.stat(self.port).st_mode): - os.remove(self.port) - except: - pass - - self.factory.doStart() - try: - skt = self.createInternetSocket() - skt.bind(self.port) - except socket.error, le: - raise CannotListenError, (None, self.port, le) - else: - # Make the socket readable and writable to the world. - try: - os.chmod(self.port, self.mode) - except: # probably not a visible filesystem name - pass - skt.listen(self.backlog) - self.connected = True - self.socket = skt - self.fileno = self.socket.fileno - self.numberAccepts = 100 - self.startReading() - - def connectionLost(self, reason): - os.unlink(self.port) - if self.lockFile is not None: - self.lockFile.unlock() - tcp.Port.connectionLost(self, reason) - - def getHost(self): - """Returns a UNIXAddress. - - This indicates the server's address. - """ - return address.UNIXAddress(self.socket.getsockname()) - - -class Client(tcp.BaseClient): - """A client for Unix sockets.""" - addressFamily = socket.AF_UNIX - socketType = socket.SOCK_STREAM - - def __init__(self, filename, connector, reactor=None, checkPID = 0): - self.connector = connector - self.realAddress = self.addr = filename - if checkPID and not lockfile.isLocked(filename + ".lock"): - self._finishInit(None, None, error.BadFileError(filename), reactor) - self._finishInit(self.doConnect, self.createInternetSocket(), - None, reactor) - - def getPeer(self): - return address.UNIXAddress(self.addr) - - def getHost(self): - return address.UNIXAddress(None) - - -class Connector(base.BaseConnector): - def __init__(self, address, factory, timeout, reactor, checkPID): - base.BaseConnector.__init__(self, factory, timeout, reactor) - self.address = address - self.checkPID = checkPID - - def _makeTransport(self): - return Client(self.address, self, self.reactor, self.checkPID) - - def getDestination(self): - return address.UNIXAddress(self.address) - - -class DatagramPort(udp.Port): - """Datagram UNIX port, listening for packets.""" - - implements(interfaces.IUNIXDatagramTransport) - - addressFamily = socket.AF_UNIX - - def __init__(self, addr, proto, maxPacketSize=8192, mode=0666, reactor=None): - """Initialize with address to listen on. - """ - udp.Port.__init__(self, addr, proto, maxPacketSize=maxPacketSize, reactor=reactor) - self.mode = mode - - - def __repr__(self): - protocolName = reflect.qual(self.protocol.__class__,) - if hasattr(self, 'socket'): - return '<%s on %r>' % (protocolName, self.port) - else: - return '<%s (not listening)>' % (protocolName,) - - - def _bindSocket(self): - log.msg("%s starting on %s"%(self.protocol.__class__, repr(self.port))) - try: - skt = self.createInternetSocket() # XXX: haha misnamed method - if self.port: - skt.bind(self.port) - except socket.error, le: - raise error.CannotListenError, (None, self.port, le) - if self.port: - try: - os.chmod(self.port, self.mode) - except: # probably not a visible filesystem name - pass - self.connected = 1 - self.socket = skt - self.fileno = self.socket.fileno - - def write(self, datagram, address): - """Write a datagram.""" - try: - return self.socket.sendto(datagram, address) - except socket.error, se: - no = se.args[0] - if no == EINTR: - return self.write(datagram, address) - elif no == EMSGSIZE: - raise error.MessageLengthError, "message too long" - elif no == EAGAIN: - # oh, well, drop the data. The only difference from UDP - # is that UDP won't ever notice. - # TODO: add TCP-like buffering - pass - else: - raise - - def connectionLost(self, reason=None): - """Cleans up my socket. - """ - log.msg('(Port %s Closed)' % repr(self.port)) - base.BasePort.connectionLost(self, reason) - if hasattr(self, "protocol"): - # we won't have attribute in ConnectedPort, in cases - # where there was an error in connection process - self.protocol.doStop() - self.connected = 0 - self.socket.close() - del self.socket - del self.fileno - if hasattr(self, "d"): - self.d.callback(None) - del self.d - - def setLogStr(self): - self.logstr = reflect.qual(self.protocol.__class__) + " (UDP)" - - def getHost(self): - return address.UNIXAddress(self.socket.getsockname()) - - -class ConnectedDatagramPort(DatagramPort): - """A connected datagram UNIX socket.""" - - implementsOnly(interfaces.IUNIXDatagramConnectedTransport, - *(implementedBy(base.BasePort))) - - def __init__(self, addr, proto, maxPacketSize=8192, mode=0666, bindAddress=None, reactor=None): - assert isinstance(proto, protocol.ConnectedDatagramProtocol) - DatagramPort.__init__(self, bindAddress, proto, maxPacketSize, mode, reactor) - self.remoteaddr = addr - - def startListening(self): - try: - self._bindSocket() - self.socket.connect(self.remoteaddr) - self._connectToProtocol() - except: - self.connectionFailed(failure.Failure()) - - def connectionFailed(self, reason): - self.loseConnection() - self.protocol.connectionFailed(reason) - del self.protocol - - def doRead(self): - """Called when my socket is ready for reading.""" - read = 0 - while read < self.maxThroughput: - try: - data, addr = self.socket.recvfrom(self.maxPacketSize) - read += len(data) - self.protocol.datagramReceived(data) - except socket.error, se: - no = se.args[0] - if no in (EAGAIN, EINTR, EWOULDBLOCK): - return - if no == ECONNREFUSED: - self.protocol.connectionRefused() - else: - raise - except: - log.deferr() - - def write(self, data): - """Write a datagram.""" - try: - return self.socket.send(data) - except socket.error, se: - no = se.args[0] - if no == EINTR: - return self.write(data) - elif no == EMSGSIZE: - raise error.MessageLengthError, "message too long" - elif no == ECONNREFUSED: - self.protocol.connectionRefused() - elif no == EAGAIN: - # oh, well, drop the data. The only difference from UDP - # is that UDP won't ever notice. - # TODO: add TCP-like buffering - pass - else: - raise - - def getPeer(self): - return address.UNIXAddress(self.remoteaddr) diff --git a/tools/buildbot/pylibs/twisted/internet/utils.py b/tools/buildbot/pylibs/twisted/internet/utils.py deleted file mode 100644 index 47ae379..0000000 --- a/tools/buildbot/pylibs/twisted/internet/utils.py +++ /dev/null @@ -1,172 +0,0 @@ -# -*- test-case-name: twisted.test.test_iutils -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -"""Utility methods.""" - -import sys, warnings - -from twisted.internet import protocol, defer -from twisted.python import failure, util as tputil - -try: - import cStringIO as StringIO -except ImportError: - import StringIO - -def _callProtocolWithDeferred(protocol, executable, args, env, path, reactor=None): - if reactor is None: - from twisted.internet import reactor - - d = defer.Deferred() - p = protocol(d) - reactor.spawnProcess(p, executable, (executable,)+tuple(args), env, path) - return d - - -class _BackRelay(protocol.ProcessProtocol): - - def __init__(self, deferred, errortoo=0): - self.deferred = deferred - self.s = StringIO.StringIO() - if errortoo: - self.errReceived = self.errReceivedIsGood - else: - self.errReceived = self.errReceivedIsBad - - def errReceivedIsBad(self, text): - if self.deferred is not None: - self.deferred.errback(failure.Failure(IOError("got stderr: %r" % text))) - self.deferred = None - self.transport.loseConnection() - - def errReceivedIsGood(self, text): - self.s.write(text) - - def outReceived(self, text): - self.s.write(text) - - def processEnded(self, reason): - if self.deferred is not None: - self.deferred.callback(self.s.getvalue()) - - -def getProcessOutput(executable, args=(), env={}, path='.', reactor=None, - errortoo=0): - """Spawn a process and return its output as a deferred returning a string. - - @param executable: The file name to run and get the output of - the - full path should be used. - - @param args: the command line arguments to pass to the process; a - sequence of strings. The first string should *NOT* be the - executable's name. - - @param env: the environment variables to pass to the processs; a - dictionary of strings. - - @param path: the path to run the subprocess in - defaults to the - current directory. - - @param reactor: the reactor to use - defaults to the default reactor - @param errortoo: if 1, capture stderr too - """ - return _callProtocolWithDeferred(lambda d: - _BackRelay(d, errortoo=errortoo), - executable, args, env, path, - reactor) - - -class _ValueGetter(protocol.ProcessProtocol): - - def __init__(self, deferred): - self.deferred = deferred - - def processEnded(self, reason): - self.deferred.callback(reason.value.exitCode) - - -def getProcessValue(executable, args=(), env={}, path='.', reactor=None): - """Spawn a process and return its exit code as a Deferred.""" - return _callProtocolWithDeferred(_ValueGetter, executable, args, env, path, - reactor) - - -class _EverythingGetter(protocol.ProcessProtocol): - - def __init__(self, deferred): - self.deferred = deferred - self.outBuf = StringIO.StringIO() - self.errBuf = StringIO.StringIO() - self.outReceived = self.outBuf.write - self.errReceived = self.errBuf.write - - def processEnded(self, reason): - out = self.outBuf.getvalue() - err = self.errBuf.getvalue() - e = reason.value - code = e.exitCode - if e.signal: - self.deferred.errback((out, err, e.signal)) - else: - self.deferred.callback((out, err, code)) - -def getProcessOutputAndValue(executable, args=(), env={}, path='.', - reactor=None): - """Spawn a process and returns a Deferred that will be called back with - its output (from stdout and stderr) and it's exit code as (out, err, code) - If a signal is raised, the Deferred will errback with the stdout and - stderr up to that point, along with the signal, as (out, err, signalNum) - """ - return _callProtocolWithDeferred(_EverythingGetter, executable, args, env, path, - reactor) - -def _resetWarningFilters(passthrough, addedFilters): - for f in addedFilters: - try: - warnings.filters.remove(f) - except ValueError: - pass - return passthrough - - -def runWithWarningsSuppressed(suppressedWarnings, f, *a, **kw): - """Run the function C{f}, but with some warnings suppressed. - - @param suppressedWarnings: A list of arguments to pass to filterwarnings. - Must be a sequence of 2-tuples (args, kwargs). - @param f: A callable, followed by its arguments and keyword arguments - """ - for args, kwargs in suppressedWarnings: - warnings.filterwarnings(*args, **kwargs) - addedFilters = warnings.filters[:len(suppressedWarnings)] - try: - result = f(*a, **kw) - except: - exc_info = sys.exc_info() - _resetWarningFilters(None, addedFilters) - raise exc_info[0], exc_info[1], exc_info[2] - else: - if isinstance(result, defer.Deferred): - result.addBoth(_resetWarningFilters, addedFilters) - else: - _resetWarningFilters(None, addedFilters) - return result - - -def suppressWarnings(f, *suppressedWarnings): - """ - Wrap C{f} in a callable which suppresses the indicated warnings before - invoking C{f} and unsuppresses them afterwards. If f returns a Deferred, - warnings will remain suppressed until the Deferred fires. - """ - def warningSuppressingWrapper(*a, **kw): - return runWithWarningsSuppressed(suppressedWarnings, f, *a, **kw) - return tputil.mergeFunctionMetadata(f, warningSuppressingWrapper) - - -__all__ = [ - "runWithWarningsSuppressed", "suppressWarnings", - - "getProcessOutput", "getProcessValue", "getProcessOutputAndValue", - ] diff --git a/tools/buildbot/pylibs/twisted/internet/win32eventreactor.py b/tools/buildbot/pylibs/twisted/internet/win32eventreactor.py deleted file mode 100644 index a6e0991..0000000 --- a/tools/buildbot/pylibs/twisted/internet/win32eventreactor.py +++ /dev/null @@ -1,244 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -A win32event based implementation of the Twisted main loop. - -This requires win32all or ActivePython to be installed. - -Maintainer: U{Itamar Shtull-Trauring} - - -LIMITATIONS: - 1. WaitForMultipleObjects and thus the event loop can only handle 64 objects. - 2. Process running has some problems (see Process docstring). - - -TODO: - 1. Event loop handling of writes is *very* problematic (this is causing failed tests). - Switch to doing it the correct way, whatever that means (see below). - 2. Replace icky socket loopback waker with event based waker (use dummyEvent object) - 3. Switch everyone to using Free Software so we don't have to deal with proprietary APIs. - - -ALTERNATIVE SOLUTIONS: - - IIRC, sockets can only be registered once. So we switch to a structure - like the poll() reactor, thus allowing us to deal with write events in - a decent fashion. This should allow us to pass tests, but we're still - limited to 64 events. - -Or: - - - Instead of doing a reactor, we make this an addon to the select reactor. - The WFMO event loop runs in a separate thread. This means no need to maintain - separate code for networking, 64 event limit doesn't apply to sockets, - we can run processes and other win32 stuff in default event loop. The - only problem is that we're stuck with the icky socket based waker. - Another benefit is that this could be extended to support >64 events - in a simpler manner than the previous solution. - -The 2nd solution is probably what will get implemented. -""" - -# System imports -import time -import sys - -from zope.interface import implements - -# Win32 imports -from win32file import WSAEventSelect, FD_READ, FD_CLOSE, FD_ACCEPT, FD_CONNECT -from win32event import CreateEvent, MsgWaitForMultipleObjects -from win32event import WAIT_OBJECT_0, WAIT_TIMEOUT, QS_ALLINPUT, QS_ALLEVENTS - -import win32gui - -# Twisted imports -from twisted.internet import posixbase -from twisted.python import log, threadable, failure -from twisted.internet.interfaces import IReactorFDSet, IReactorProcess - -from twisted.internet._dumbwin32proc import Process - - -class Win32Reactor(posixbase.PosixReactorBase): - """ - Reactor that uses Win32 event APIs. - - @ivar _reads: A dictionary mapping L{FileDescriptor} instances to a - win32 event object used to check for read events for that descriptor. - - @ivar _writes: A dictionary mapping L{FileDescriptor} instances to a - arbitrary value. Keys in this dictionary will be given a chance to - write out their data. - - @ivar _events: A dictionary mapping win32 event object to tuples of - L{FileDescriptor} instances and event masks. - """ - implements(IReactorFDSet, IReactorProcess) - - dummyEvent = CreateEvent(None, 0, 0, None) - - def __init__(self): - self._reads = {} - self._writes = {} - self._events = {} - posixbase.PosixReactorBase.__init__(self) - - - def _makeSocketEvent(self, fd, action, why): - """ - Make a win32 event object for a socket. - """ - event = CreateEvent(None, 0, 0, None) - WSAEventSelect(fd, event, why) - self._events[event] = (fd, action) - return event - - - def addEvent(self, event, fd, action): - """ - Add a new win32 event to the event loop. - """ - self._events[event] = (fd, action) - - - def removeEvent(self, event): - """ - Remove an event. - """ - del self._events[event] - - - def addReader(self, reader): - """ - Add a socket FileDescriptor for notification of data available to read. - """ - if reader not in self._reads: - self._reads[reader] = self._makeSocketEvent( - reader, 'doRead', FD_READ | FD_ACCEPT | FD_CONNECT | FD_CLOSE) - - def addWriter(self, writer): - """ - Add a socket FileDescriptor for notification of data available to write. - """ - if writer not in self._writes: - self._writes[writer] = 1 - - def removeReader(self, reader): - """Remove a Selectable for notification of data available to read. - """ - if reader in self._reads: - del self._events[self._reads[reader]] - del self._reads[reader] - - def removeWriter(self, writer): - """Remove a Selectable for notification of data available to write. - """ - if writer in self._writes: - del self._writes[writer] - - def removeAll(self): - """ - Remove all selectables, and return a list of them. - """ - return self._removeAll(self._reads, self._writes) - - - def getReaders(self): - return self._reads.keys() - - - def getWriters(self): - return self._writes.keys() - - - def doWaitForMultipleEvents(self, timeout): - log.msg(channel='system', event='iteration', reactor=self) - if timeout is None: - #timeout = INFINITE - timeout = 100 - else: - timeout = int(timeout * 1000) - - if not (self._events or self._writes): - # sleep so we don't suck up CPU time - time.sleep(timeout / 1000.0) - return - - canDoMoreWrites = 0 - for fd in self._writes.keys(): - if log.callWithLogger(fd, self._runWrite, fd): - canDoMoreWrites = 1 - - if canDoMoreWrites: - timeout = 0 - - handles = self._events.keys() or [self.dummyEvent] - val = MsgWaitForMultipleObjects(handles, 0, timeout, QS_ALLINPUT | QS_ALLEVENTS) - if val == WAIT_TIMEOUT: - return - elif val == WAIT_OBJECT_0 + len(handles): - exit = win32gui.PumpWaitingMessages() - if exit: - self.callLater(0, self.stop) - return - elif val >= WAIT_OBJECT_0 and val < WAIT_OBJECT_0 + len(handles): - fd, action = self._events[handles[val - WAIT_OBJECT_0]] - log.callWithLogger(fd, self._runAction, action, fd) - - def _runWrite(self, fd): - closed = 0 - try: - closed = fd.doWrite() - except: - closed = sys.exc_info()[1] - log.deferr() - - if closed: - self.removeReader(fd) - self.removeWriter(fd) - try: - fd.connectionLost(failure.Failure(closed)) - except: - log.deferr() - elif closed is None: - return 1 - - def _runAction(self, action, fd): - try: - closed = getattr(fd, action)() - except: - closed = sys.exc_info()[1] - log.deferr() - - if closed: - self._disconnectSelectable(fd, closed, action == 'doRead') - - doIteration = doWaitForMultipleEvents - - def spawnProcess(self, processProtocol, executable, args=(), env={}, path=None, uid=None, gid=None, usePTY=0, childFDs=None): - """Spawn a process.""" - if uid is not None: - raise ValueError("Setting UID is unsupported on this platform.") - if gid is not None: - raise ValueError("Setting GID is unsupported on this platform.") - if usePTY: - raise ValueError("PTYs are unsupported on this platform.") - if childFDs is not None: - raise ValueError( - "Custom child file descriptor mappings are unsupported on " - "this platform.") - args, env = self._checkProcessArgs(args, env) - return Process(self, processProtocol, executable, args, env, path) - - -def install(): - threadable.init(1) - r = Win32Reactor() - import main - main.installReactor(r) - - -__all__ = ["Win32Reactor", "install"] diff --git a/tools/buildbot/pylibs/twisted/internet/wxreactor.py b/tools/buildbot/pylibs/twisted/internet/wxreactor.py deleted file mode 100644 index b0708bd..0000000 --- a/tools/buildbot/pylibs/twisted/internet/wxreactor.py +++ /dev/null @@ -1,181 +0,0 @@ -# Copyright (c) 2001-2006 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -This module provides wxPython event loop support for Twisted. - -In order to use this support, simply do the following:: - - | from twisted.internet import wxreactor - | wxreactor.install() - -Then, when your root wxApp has been created:: - - | from twisted.internet import reactor - | reactor.registerWxApp(yourApp) - | reactor.run() - -Then use twisted.internet APIs as usual. Stop the event loop using -reactor.stop(), not yourApp.ExitMainLoop(). - -IMPORTANT: tests will fail when run under this reactor. This is -expected and probably does not reflect on the reactor's ability to run -real applications. - -Maintainer: U{Itamar Shtull-Trauring} -""" - -import Queue -try: - from wx import PySimpleApp as wxPySimpleApp, CallAfter as wxCallAfter, \ - Timer as wxTimer -except ImportError: - # older version of wxPython: - from wxPython.wx import wxPySimpleApp, wxCallAfter, wxTimer - -from twisted.python import log, runtime -from twisted.internet import _threadedselect - - -class ProcessEventsTimer(wxTimer): - """ - Timer that tells wx to process pending events. - - This is necessary on OS X, probably due to a bug in wx, if we want - wxCallAfters to be handled when modal dialogs, menus, etc. are open. - """ - def __init__(self, wxapp): - wxTimer.__init__(self) - self.wxapp = wxapp - - - def Notify(self): - """ - Called repeatedly by wx event loop. - """ - self.wxapp.ProcessPendingEvents() - - - -class WxReactor(_threadedselect.ThreadedSelectReactor): - """ - wxPython reactor. - - wxPython drives the event loop, select() runs in a thread. - """ - - _stopping = False - - def registerWxApp(self, wxapp): - """ - Register wxApp instance with the reactor. - """ - self.wxapp = wxapp - - def _installSignalHandlersAgain(self): - """ - wx sometimes removes our own signal handlers, so re-add them. - """ - try: - # make _handleSignals happy: - import signal - signal.signal(signal.SIGINT, signal.default_int_handler) - except ImportError: - return - self._handleSignals() - - def stop(self): - """ - Stop the reactor. - """ - if self._stopping: - return - self._stopping = True - _threadedselect.ThreadedSelectReactor.stop(self) - - def _runInMainThread(self, f): - """ - Schedule function to run in main wx/Twisted thread. - - Called by the select() thread. - """ - if hasattr(self, "wxapp"): - wxCallAfter(f) - else: - # wx shutdown but twisted hasn't - self._postQueue.put(f) - - def _stopWx(self): - """ - Stop the wx event loop if it hasn't already been stopped. - - Called during Twisted event loop shutdown. - """ - if hasattr(self, "wxapp"): - self.wxapp.ExitMainLoop() - - def run(self, installSignalHandlers=True): - """ - Start the reactor. - """ - self._postQueue = Queue.Queue() - if not hasattr(self, "wxapp"): - log.msg("registerWxApp() was not called on reactor, " - "registering my own wxApp instance.") - self.registerWxApp(wxPySimpleApp()) - - # start select() thread: - self.interleave(self._runInMainThread, - installSignalHandlers=installSignalHandlers) - if installSignalHandlers: - self.callLater(0, self._installSignalHandlersAgain) - - # add cleanup events: - self.addSystemEventTrigger("after", "shutdown", self._stopWx) - self.addSystemEventTrigger("after", "shutdown", - lambda: self._postQueue.put(None)) - - # On Mac OS X, work around wx bug by starting timer to ensure - # wxCallAfter calls are always processed. We don't wake up as - # often as we could since that uses too much CPU. - if runtime.platform.isMacOSX(): - t = ProcessEventsTimer(self.wxapp) - t.Start(2) # wake up every 2ms - - self.wxapp.MainLoop() - wxapp = self.wxapp - del self.wxapp - - if not self._stopping: - # wx event loop exited without reactor.stop() being - # called. At this point events from select() thread will - # be added to _postQueue, but some may still be waiting - # unprocessed in wx, thus the ProcessPendingEvents() - # below. - self.stop() - wxapp.ProcessPendingEvents() # deal with any queued wxCallAfters - while 1: - try: - f = self._postQueue.get(timeout=0.01) - except Queue.Empty: - continue - else: - if f is None: - break - try: - f() - except: - log.err() - - -def install(): - """ - Configure the twisted mainloop to be run inside the wxPython mainloop. - """ - reactor = WxReactor() - from twisted.internet.main import installReactor - installReactor(reactor) - return reactor - - -__all__ = ['install'] diff --git a/tools/buildbot/pylibs/twisted/internet/wxsupport.py b/tools/buildbot/pylibs/twisted/internet/wxsupport.py deleted file mode 100644 index eec84ac..0000000 --- a/tools/buildbot/pylibs/twisted/internet/wxsupport.py +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -"""Old method of wxPython support for Twisted. - -twisted.internet.wxreactor is probably a better choice. - -To use:: - - | # given a wxApp instance called myWxAppInstance: - | from twisted.internet import wxsupport - | wxsupport.install(myWxAppInstance) - -Use Twisted's APIs for running and stopping the event loop, don't use -wxPython's methods. - -On Windows the Twisted event loop might block when dialogs are open -or menus are selected. - -Maintainer: U{Itamar Shtull-Trauring} -""" - -import warnings -warnings.warn("wxsupport is not fully functional on Windows, wxreactor is better.") - -# wxPython imports -from wxPython.wx import wxApp - -# twisted imports -from twisted.internet import reactor -from twisted.python.runtime import platformType - - -class wxRunner: - """Make sure GUI events are handled.""" - - def __init__(self, app): - self.app = app - - def run(self): - """ - Execute pending WX events followed by WX idle events and - reschedule. - """ - # run wx events - while self.app.Pending(): - self.app.Dispatch() - - # run wx idle events - self.app.ProcessIdle() - reactor.callLater(0.02, self.run) - - -def install(app): - """Install the wxPython support, given a wxApp instance""" - runner = wxRunner(app) - reactor.callLater(0.02, runner.run) - - -__all__ = ["install"] diff --git a/tools/buildbot/pylibs/twisted/lore/__init__.py b/tools/buildbot/pylibs/twisted/lore/__init__.py deleted file mode 100644 index 35ee759..0000000 --- a/tools/buildbot/pylibs/twisted/lore/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -''' -The Twisted Documentation Generation System - -Maintainer: U{Andrew Bennetts} -''' - -# TODO -# Abstract -# Bibliography -# Index -# Allow non-web image formats (EPS, specifically) -# Allow pickle output and input to minimize parses -# Numbered headers -# Navigational aides - -from twisted.lore._version import version -__version__ = version.short() diff --git a/tools/buildbot/pylibs/twisted/lore/_version.py b/tools/buildbot/pylibs/twisted/lore/_version.py deleted file mode 100644 index d5c81a2..0000000 --- a/tools/buildbot/pylibs/twisted/lore/_version.py +++ /dev/null @@ -1,3 +0,0 @@ -# This is an auto-generated file. Do not edit it. -from twisted.python import versions -version = versions.Version('twisted.lore', 8, 1, 0) diff --git a/tools/buildbot/pylibs/twisted/lore/default.py b/tools/buildbot/pylibs/twisted/lore/default.py deleted file mode 100644 index 0f46fc4..0000000 --- a/tools/buildbot/pylibs/twisted/lore/default.py +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -from __future__ import nested_scopes - -from twisted.lore import tree, latex, lint, process -from twisted.web import sux, microdom - -htmlDefault = {'template': 'template.tpl', 'baseurl': '%s', 'ext': '.html'} - -class ProcessingFunctionFactory: - - def getDoFile(self): - return tree.doFile - - def generate_html(self, options, filenameGenerator=tree.getOutputFileName): - n = htmlDefault.copy() - n.update(options) - options = n - try: - fp = open(options['template']) - templ = microdom.parse(fp) - except IOError, e: - raise process.NoProcessorError(e.filename+": "+e.strerror) - except sux.ParseError, e: - raise process.NoProcessorError(str(e)) - df = lambda file, linkrel: self.getDoFile()(file, linkrel, options['ext'], - options['baseurl'], templ, options, filenameGenerator) - return df - - latexSpitters = {None: latex.LatexSpitter, - 'section': latex.SectionLatexSpitter, - 'chapter': latex.ChapterLatexSpitter, - 'book': latex.BookLatexSpitter, - } - - def generate_latex(self, options, filenameGenerator=None): - spitter = self.latexSpitters[None] - for (key, value) in self.latexSpitters.items(): - if key and options.get(key): - spitter = value - df = lambda file, linkrel: latex.convertFile(file, spitter) - return df - - def getLintChecker(self): - return lint.getDefaultChecker() - - def generate_lint(self, options, filenameGenerator=None): - checker = self.getLintChecker() - return lambda file, linkrel: lint.doFile(file, checker) - -factory = ProcessingFunctionFactory() diff --git a/tools/buildbot/pylibs/twisted/lore/docbook.py b/tools/buildbot/pylibs/twisted/lore/docbook.py deleted file mode 100644 index 1d18b75..0000000 --- a/tools/buildbot/pylibs/twisted/lore/docbook.py +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -from cStringIO import StringIO -import os, re, cgi -from twisted.python import text -from twisted.web import domhelpers, microdom -import latex, tree - -class DocbookSpitter(latex.BaseLatexSpitter): - - currentLevel = 1 - - def writeNodeData(self, node): - self.writer(node.data) - - def visitNode_body(self, node): - self.visitNodeDefault(node) - self.writer(''*self.currentLevel) - - def visitNodeHeader(self, node): - level = int(node.tagName[1]) - difference, self.currentLevel = level-self.currentLevel, level - self.writer('
'*difference+'
'*-difference) - if difference<=0: - self.writer('\n
') - self.writer('') - self.visitNodeDefault(node) - - def visitNode_a_listing(self, node): - fileName = os.path.join(self.currDir, node.getAttribute('href')) - self.writer('<programlisting>\n') - self.writer(cgi.escape(open(fileName).read())) - self.writer('</programlisting>\n') - - def visitNode_a_href(self, node): - self.visitNodeDefault(node) - - def visitNode_a_name(self, node): - self.visitNodeDefault(node) - - def visitNode_li(self, node): - for child in node.childNodes: - if getattr(child, 'tagName', None) != 'p': - new = microdom.Element('p') - new.childNodes = [child] - node.replaceChild(new, child) - self.visitNodeDefault(node) - - visitNode_h2 = visitNode_h3 = visitNode_h4 = visitNodeHeader - end_h2 = end_h3 = end_h4 = '' - start_title, end_title = '
', '' - start_p, end_p = '', '' - start_strong, end_strong = start_em, end_em = '', '' - start_span_footnote, end_span_footnote = '', '' - start_q = end_q = '"' - start_pre, end_pre = '', '' - start_div_note, end_div_note = '', '' - start_li, end_li = '', '' - start_ul, end_ul = '', '' - start_ol, end_ol = '', '' - start_dl, end_dl = '', '' - start_dt, end_dt = '', '' - start_dd, end_dd = '', '' diff --git a/tools/buildbot/pylibs/twisted/lore/htmlbook.py b/tools/buildbot/pylibs/twisted/lore/htmlbook.py deleted file mode 100644 index a26abb3..0000000 --- a/tools/buildbot/pylibs/twisted/lore/htmlbook.py +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -def getNumber(filename): - return None - -def getReference(filename): - return None - -class Book: - - def __init__(self, filename): - self.chapters = [] - self.indexFilename = None - - global Chapter - Chapter = self.Chapter - global getNumber - getNumber = self.getNumber - global getReference - getReference = self.getNumber - global Index - Index = self.Index - - if filename: - execfile(filename) - - def getFiles(self): - return [c[0] for c in self.chapters] - - def getNumber(self, filename): - for c in self.chapters: - if c[0] == filename: - return c[1] - return None - - def getIndexFilename(self): - return self.indexFilename - - def Chapter(self, filename, number): - self.chapters.append((filename, number)) - - def Index(self, filename): - self.indexFilename = filename - -#_book = Book(None) diff --git a/tools/buildbot/pylibs/twisted/lore/indexer.py b/tools/buildbot/pylibs/twisted/lore/indexer.py deleted file mode 100644 index 5feb95d..0000000 --- a/tools/buildbot/pylibs/twisted/lore/indexer.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -def setIndexFilename(filename='index.xhtml'): - global indexFilename - indexFilename = filename - -def getIndexFilename(): - global indexFilename - return indexFilename - -def addEntry(filename, anchor, text, reference): - global entries - if not entries.has_key(text): - entries[text] = [] - entries[text].append((filename, anchor, reference)) - -def clearEntries(): - global entries - entries = {} - -def generateIndex(): - global entries - global indexFilename - - if not indexFilename: - return - - f = open(indexFilename, 'w') - sortedEntries = [(e.lower(), e) for e in entries] - sortedEntries.sort() - sortedEntries = [e[1] for e in sortedEntries] - for text in sortedEntries: - refs = [] - f.write(text.replace('!', ', ') + ': ') - for (file, anchor, reference) in entries[text]: - refs.append('%s' % (file, anchor, reference)) - if text == 'infinite recursion': - refs.append('See Also: recursion, infinite\n') - if text == 'recursion!infinite': - refs.append('See Also: infinite recursion\n') - f.write('%s
\n' % ", ".join(refs)) - f.close() - -def reset(): - clearEntries() - setIndexFilename() - -reset() diff --git a/tools/buildbot/pylibs/twisted/lore/latex.py b/tools/buildbot/pylibs/twisted/lore/latex.py deleted file mode 100644 index ee27cb1..0000000 --- a/tools/buildbot/pylibs/twisted/lore/latex.py +++ /dev/null @@ -1,455 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -from twisted.web import microdom, domhelpers -from twisted.python import text, procutils -import os, os.path, re, string -from cStringIO import StringIO - -import urlparse - -import tree - -escapingRE = re.compile(r'([\[\]#$%&_{}^~\\])') -lowerUpperRE = re.compile(r'([a-z])([A-Z])') - -def _escapeMatch(match): - c = match.group() - if c == '\\': - return '$\\backslash$' - elif c == '~': - return '\\~{}' - elif c == '^': - return '\\^{}' - elif c in '[]': - return '{'+c+'}' - else: - return '\\' + c - -def latexEscape(text): - text = escapingRE.sub(_escapeMatch, text) - return text.replace('\n', ' ') - -entities = {'amp': '\&', 'gt': '>', 'lt': '<', 'quot': '"', - 'copy': '\\copyright', 'mdash': '---', 'rdquo': '``', - 'ldquo': "''"} - - -def realpath(path): - # Normalise path - cwd = os.getcwd() - path = os.path.normpath(os.path.join(cwd, path)) - if path.startswith(cwd + '/'): - path = path[len(cwd)+1:] - return path.replace('\\', '/') # windows slashes make LaTeX blow up - - -def getLatexText(node, writer, filter=lambda x:x, entities=entities): - if hasattr(node, 'eref'): - return writer(entities.get(node.eref, '')) - if hasattr(node, 'data'): - return writer(filter(node.data)) - for child in node.childNodes: - getLatexText(child, writer, filter, entities) - -class BaseLatexSpitter: - - def __init__(self, writer, currDir='.', filename=''): - self.writer = writer - self.currDir = currDir - self.filename = filename - - def visitNode(self, node): - if isinstance(node, microdom.Comment): - return - if not hasattr(node, 'tagName'): - self.writeNodeData(node) - return - getattr(self, 'visitNode_'+node.tagName, self.visitNodeDefault)(node) - - def visitNodeDefault(self, node): - self.writer(getattr(self, 'start_'+node.tagName, '')) - for child in node.childNodes: - self.visitNode(child) - self.writer(getattr(self, 'end_'+node.tagName, '')) - - def visitNode_a(self, node): - if node.hasAttribute('class'): - if node.getAttribute('class').endswith('listing'): - return self.visitNode_a_listing(node) - if node.hasAttribute('href'): - return self.visitNode_a_href(node) - if node.hasAttribute('name'): - return self.visitNode_a_name(node) - self.visitNodeDefault(node) - - def visitNode_span(self, node): - if not node.hasAttribute('class'): - return self.visitNodeDefault(node) - node.tagName += '_'+node.getAttribute('class') - self.visitNode(node) - - visitNode_div = visitNode_span - - def visitNode_h1(self, node): - pass - - def visitNode_style(self, node): - pass - - -class LatexSpitter(BaseLatexSpitter): - - baseLevel = 0 - diaHack = bool(procutils.which("dia")) - - def writeNodeData(self, node): - buf = StringIO() - getLatexText(node, buf.write, latexEscape) - self.writer(buf.getvalue().replace('<', '$<$').replace('>', '$>$')) - - def visitNode_head(self, node): - authorNodes = domhelpers.findElementsWithAttribute(node, 'rel', 'author') - authorNodes = [n for n in authorNodes if n.tagName == 'link'] - - if authorNodes: - self.writer('\\author{') - authors = [] - for aNode in authorNodes: - name = aNode.getAttribute('title', '') - href = aNode.getAttribute('href', '') - if href.startswith('mailto:'): - href = href[7:] - if href: - if name: - name += ' ' - name += '$<$' + href + '$>$' - if name: - authors.append(name) - - self.writer(' \\and '.join(authors)) - self.writer('}') - - self.visitNodeDefault(node) - - def visitNode_pre(self, node): - self.writer('\\begin{verbatim}\n') - buf = StringIO() - getLatexText(node, buf.write) - self.writer(text.removeLeadingTrailingBlanks(buf.getvalue())) - self.writer('\\end{verbatim}\n') - - def visitNode_code(self, node): - fout = StringIO() - getLatexText(node, fout.write, latexEscape) - data = lowerUpperRE.sub(r'\1\\linebreak[1]\2', fout.getvalue()) - data = data[:1] + data[1:].replace('.', '.\\linebreak[1]') - self.writer('\\texttt{'+data+'}') - - def visitNode_img(self, node): - fileName = os.path.join(self.currDir, node.getAttribute('src')) - target, ext = os.path.splitext(fileName) - if self.diaHack and os.access(target + '.dia', os.R_OK): - ext = '.dia' - fileName = target + ext - f = getattr(self, 'convert_'+ext[1:], None) - if not f: - return - target = os.path.join(self.currDir, os.path.basename(target)+'.eps') - f(fileName, target) - target = os.path.basename(target) - self._write_img(target) - - def _write_img(self, target): - """Write LaTeX for image.""" - self.writer('\\begin{center}\\includegraphics[%%\n' - 'width=1.0\n' - '\\textwidth,height=1.0\\textheight,\nkeepaspectratio]' - '{%s}\\end{center}\n' % target) - - def convert_png(self, src, target): - # XXX there's a *reason* Python comes with the pipes module - - # someone fix this to use it. - r = os.system('pngtopnm "%s" | pnmtops -noturn > "%s"' % (src, target)) - if r != 0: - raise OSError(r) - - def convert_dia(self, src, target): - # EVIL DISGUSTING HACK - data = os.popen("gunzip -dc %s" % (src)).read() - pre = '\n ' - post = '\n ' - open('%s_hacked.dia' % (src), 'wb').write(data.replace(pre, post)) - os.system('gzip %s_hacked.dia' % (src,)) - os.system('mv %s_hacked.dia.gz %s_hacked.dia' % (src,src)) - # Let's pretend we never saw that. - - # Silly dia needs an X server, even though it doesn't display anything. - # If this is a problem for you, try using Xvfb. - os.system("dia %s_hacked.dia -n -e %s" % (src, target)) - - def visitNodeHeader(self, node): - level = (int(node.tagName[1])-2)+self.baseLevel - self.writer('\n\n\\'+level*'sub'+'section{') - spitter = HeadingLatexSpitter(self.writer, self.currDir, self.filename) - spitter.visitNodeDefault(node) - self.writer('}\n') - - def visitNode_a_listing(self, node): - fileName = os.path.join(self.currDir, node.getAttribute('href')) - self.writer('\\begin{verbatim}\n') - lines = map(string.rstrip, open(fileName).readlines()) - lines = lines[int(node.getAttribute('skipLines', 0)):] - self.writer(text.removeLeadingTrailingBlanks('\n'.join(lines))) - self.writer('\\end{verbatim}') - - # Write a caption for this source listing - fileName = os.path.basename(fileName) - caption = domhelpers.getNodeText(node) - if caption == fileName: - caption = 'Source listing' - self.writer('\parbox[b]{\linewidth}{\\begin{center}%s --- ' - '\\begin{em}%s\\end{em}\\end{center}}' - % (latexEscape(caption), latexEscape(fileName))) - - def visitNode_a_href(self, node): - supported_schemes=['http', 'https', 'ftp', 'mailto'] - href = node.getAttribute('href') - if urlparse.urlparse(href)[0] in supported_schemes: - text = domhelpers.getNodeText(node) - self.visitNodeDefault(node) - if text != href: - self.writer('\\footnote{%s}' % latexEscape(href)) - else: - path, fragid = (href.split('#', 1) + [None])[:2] - if path == '': - path = self.filename - else: - path = os.path.join(os.path.dirname(self.filename), path) - #if path == '': - #path = os.path.basename(self.filename) - #else: - # # Hack for linking to man pages from howtos, i.e. - # # ../doc/foo-man.html -> foo-man.html - # path = os.path.basename(path) - - path = realpath(path) - - if fragid: - ref = path + 'HASH' + fragid - else: - ref = path - self.writer('\\textit{') - self.visitNodeDefault(node) - self.writer('}') - self.writer('\\loreref{%s}' % ref) - - def visitNode_a_name(self, node): - #self.writer('\\label{%sHASH%s}' % (os.path.basename(self.filename), - # node.getAttribute('name'))) - self.writer('\\label{%sHASH%s}' % (realpath(self.filename), - node.getAttribute('name'))) - self.visitNodeDefault(node) - - def visitNode_table(self, node): - rows = [[col for col in row.childNodes - if getattr(col, 'tagName', None) in ('th', 'td')] - for row in node.childNodes if getattr(row, 'tagName', None)=='tr'] - numCols = 1+max([len(row) for row in rows]) - self.writer('\\begin{table}[ht]\\begin{center}') - self.writer('\\begin{tabular}{@{}'+'l'*numCols+'@{}}') - for row in rows: - th = 0 - for col in row: - self.visitNode(col) - self.writer('&') - if col.tagName == 'th': - th = 1 - self.writer('\\\\\n') #\\ ends lines - if th: - self.writer('\\hline\n') - self.writer('\\end{tabular}\n') - if node.hasAttribute('title'): - self.writer('\\caption{%s}' - % latexEscape(node.getAttribute('title'))) - self.writer('\\end{center}\\end{table}\n') - - def visitNode_span_footnote(self, node): - self.writer('\\footnote{') - spitter = FootnoteLatexSpitter(self.writer, self.currDir, self.filename) - spitter.visitNodeDefault(node) - self.writer('}') - - def visitNode_span_index(self, node): - self.writer('\\index{%s}\n' % node.getAttribute('value')) - self.visitNodeDefault(node) - - visitNode_h2 = visitNode_h3 = visitNode_h4 = visitNodeHeader - - start_title = '\\title{' - end_title = '}\n' - - start_sub = '$_{' - end_sub = '}$' - - start_sup = '$^{' - end_sup = '}$' - - start_html = '''\\documentclass{article} - \\newcommand{\\loreref}[1]{% - \\ifthenelse{\\value{page}=\\pageref{#1}}% - { (this page)}% - { (page \\pageref{#1})}% - }''' - - start_body = '\\begin{document}\n\\maketitle\n' - end_body = '\\end{document}' - - start_dl = '\\begin{description}\n' - end_dl = '\\end{description}\n' - start_ul = '\\begin{itemize}\n' - end_ul = '\\end{itemize}\n' - - start_ol = '\\begin{enumerate}\n' - end_ol = '\\end{enumerate}\n' - - start_li = '\\item ' - end_li = '\n' - - start_dt = '\\item[' - end_dt = ']' - end_dd = '\n' - - start_p = '\n\n' - - start_strong = start_em = '\\begin{em}' - end_strong = end_em = '\\end{em}' - - start_q = "``" - end_q = "''" - - start_div_note = '\\begin{quotation}\\textbf{Note:}' - end_div_note = '\\end{quotation}' - - start_th = '\\textbf{' - end_th = '}' - - -class SectionLatexSpitter(LatexSpitter): - - baseLevel = 1 - - start_title = '\\section{' - - def visitNode_title(self, node): - self.visitNodeDefault(node) - #self.writer('\\label{%s}}\n' % os.path.basename(self.filename)) - self.writer('\\label{%s}}\n' % realpath(self.filename)) - - end_title = end_body = start_body = start_html = '' - - -class ChapterLatexSpitter(SectionLatexSpitter): - baseLevel = 0 - start_title = '\\chapter{' - - -class HeadingLatexSpitter(BaseLatexSpitter): - start_q = "``" - end_q = "''" - - writeNodeData = LatexSpitter.writeNodeData.im_func - - -class FootnoteLatexSpitter(LatexSpitter): - """For multi-paragraph footnotes, this avoids having an empty leading - paragraph.""" - - start_p = '' - - def visitNode_span_footnote(self, node): - self.visitNodeDefault(node) - - def visitNode_p(self, node): - self.visitNodeDefault(node) - self.start_p = LatexSpitter.start_p - -class BookLatexSpitter(LatexSpitter): - def visitNode_body(self, node): - tocs=domhelpers.locateNodes([node], 'class', 'toc') - domhelpers.clearNode(node) - if len(tocs): - toc=tocs[0] - node.appendChild(toc) - self.visitNodeDefault(node) - - def visitNode_link(self, node): - if not node.hasAttribute('rel'): - return self.visitNodeDefault(node) - node.tagName += '_'+node.getAttribute('rel') - self.visitNode(node) - - def visitNode_link_author(self, node): - self.writer('\\author{%s}\n' % node.getAttribute('text')) - - def visitNode_link_stylesheet(self, node): - if node.hasAttribute('type') and node.hasAttribute('href'): - if node.getAttribute('type')=='application/x-latex': - packagename=node.getAttribute('href') - packagebase,ext=os.path.splitext(packagename) - self.writer('\\usepackage{%s}\n' % packagebase) - - start_html = r'''\documentclass[oneside]{book} -\usepackage{graphicx} -\usepackage{times,mathptmx} -''' - - start_body = r'''\begin{document} -\maketitle -\tableofcontents -''' - - start_li='' - end_li='' - start_ul='' - end_ul='' - - - def visitNode_a(self, node): - if node.hasAttribute('class'): - a_class=node.getAttribute('class') - if a_class.endswith('listing'): - return self.visitNode_a_listing(node) - else: - return getattr(self, 'visitNode_a_%s' % a_class)(node) - if node.hasAttribute('href'): - return self.visitNode_a_href(node) - if node.hasAttribute('name'): - return self.visitNode_a_name(node) - self.visitNodeDefault(node) - - def visitNode_a_chapter(self, node): - self.writer('\\chapter{') - self.visitNodeDefault(node) - self.writer('}\n') - - def visitNode_a_sect(self, node): - base,ext=os.path.splitext(node.getAttribute('href')) - self.writer('\\input{%s}\n' % base) - - - -def processFile(spitter, fin): - dom = microdom.parse(fin).documentElement - spitter.visitNode(dom) - - -def convertFile(filename, spitterClass): - fout = open(os.path.splitext(filename)[0]+".tex", 'w') - spitter = spitterClass(fout.write, os.path.dirname(filename), filename) - fin = open(filename) - processFile(spitter, fin) - fin.close() - fout.close() diff --git a/tools/buildbot/pylibs/twisted/lore/lint.py b/tools/buildbot/pylibs/twisted/lore/lint.py deleted file mode 100644 index 82a15b6..0000000 --- a/tools/buildbot/pylibs/twisted/lore/lint.py +++ /dev/null @@ -1,214 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -from twisted.lore import tree, process -from twisted.web import domhelpers, microdom -from twisted.python import reflect - -import parser, urlparse, os.path - -# parser.suite in Python 2.3 raises SyntaxError, <2.3 raises parser.ParserError -parserErrors = (SyntaxError, parser.ParserError) - -class TagChecker: - - def check(self, dom, filename): - self.hadErrors = 0 - for method in reflect.prefixedMethods(self, 'check_'): - method(dom, filename) - if self.hadErrors: - raise process.ProcessingFailure("invalid format") - - def _reportError(self, filename, element, error): - hlint = element.hasAttribute('hlint') and element.getAttribute('hlint') - if hlint != 'off': - self.hadErrors = 1 - pos = getattr(element, '_markpos', None) or (0, 0) - print "%s:%s:%s: %s" % ((filename,)+pos+(error,)) - - -class DefaultTagChecker(TagChecker): - - def __init__(self, allowedTags, allowedClasses): - self.allowedTags = allowedTags - self.allowedClasses = allowedClasses - - def check_disallowedElements(self, dom, filename): - def m(node, self=self): - return not self.allowedTags(node.tagName) - for element in domhelpers.findElements(dom, m): - self._reportError(filename, element, - 'unrecommended tag %s' % element.tagName) - - def check_disallowedClasses(self, dom, filename): - def matcher(element, self=self): - if not element.hasAttribute('class'): - return 0 - checker = self.allowedClasses.get(element.tagName, lambda x:0) - return not checker(element.getAttribute('class')) - for element in domhelpers.findElements(dom, matcher): - self._reportError(filename, element, - 'unknown class %s' %element.getAttribute('class')) - - def check_quote(self, dom, filename): - def matcher(node): - return ('"' in getattr(node, 'data', '') and - not isinstance(node, microdom.Comment) and - not [1 for n in domhelpers.getParents(node)[1:-1] - if n.tagName in ('pre', 'code')]) - for node in domhelpers.findNodes(dom, matcher): - self._reportError(filename, node.parentNode, 'contains quote') - - def check_styleattr(self, dom, filename): - for node in domhelpers.findElementsWithAttribute(dom, 'style'): - self._reportError(filename, node, 'explicit style') - - def check_align(self, dom, filename): - for node in domhelpers.findElementsWithAttribute(dom, 'align'): - self._reportError(filename, node, 'explicit alignment') - - def check_style(self, dom, filename): - for node in domhelpers.findNodesNamed(dom, 'style'): - if domhelpers.getNodeText(node) != '': - self._reportError(filename, node, 'hand hacked style') - - def check_title(self, dom, filename): - doc = dom.documentElement - title = domhelpers.findNodesNamed(dom, 'title') - if len(title)!=1: - return self._reportError(filename, doc, 'not exactly one title') - h1 = domhelpers.findNodesNamed(dom, 'h1') - if len(h1)!=1: - return self._reportError(filename, doc, 'not exactly one h1') - if domhelpers.getNodeText(h1[0]) != domhelpers.getNodeText(title[0]): - self._reportError(filename, h1[0], 'title and h1 text differ') - - def check_80_columns(self, dom, filename): - for node in domhelpers.findNodesNamed(dom, 'pre'): - # the ps/pdf output is in a font that cuts off at 80 characters, - # so this is enforced to make sure the interesting parts (which - # are likely to be on the right-hand edge) stay on the printed - # page. - for line in domhelpers.gatherTextNodes(node, 1).split('\n'): - if len(line.rstrip()) > 80: - self._reportError(filename, node, - 'text wider than 80 columns in pre') - for node in domhelpers.findNodesNamed(dom, 'a'): - if node.getAttribute('class', '').endswith('listing'): - try: - fn = os.path.dirname(filename) - fn = os.path.join(fn, node.getAttribute('href')) - lines = open(fn,'r').readlines() - except: - self._reportError(filename, node, - 'bad listing href: %r' % - node.getAttribute('href')) - continue - - for line in lines: - if len(line.rstrip()) > 80: - self._reportError(filename, node, - 'listing wider than 80 columns') - - def check_pre_py_listing(self, dom, filename): - for node in domhelpers.findNodesNamed(dom, 'pre'): - if node.getAttribute('class') == 'python': - try: - text = domhelpers.getNodeText(node) - # Fix < and > - text = text.replace('>', '>').replace('<', '<') - # Strip blank lines - lines = filter(None,[l.rstrip() for l in text.split('\n')]) - # Strip leading space - while not [1 for line in lines if line[:1] not in ('',' ')]: - lines = [line[1:] for line in lines] - text = '\n'.join(lines) + '\n' - try: - parser.suite(text) - except parserErrors, e: - # Pretend the "..." idiom is syntactically valid - text = text.replace("...","'...'") - parser.suite(text) - except parserErrors, e: - self._reportError(filename, node, - 'invalid python code:' + str(e)) - - def check_anchor_in_heading(self, dom, filename): - headingNames = ['h%d' % n for n in range(1,7)] - for hname in headingNames: - for node in domhelpers.findNodesNamed(dom, hname): - if domhelpers.findNodesNamed(node, 'a'): - self._reportError(filename, node, 'anchor in heading') - - def check_texturl_matches_href(self, dom, filename): - for node in domhelpers.findNodesNamed(dom, 'a'): - if not node.hasAttribute('href'): - continue - text = domhelpers.getNodeText(node) - proto = urlparse.urlparse(text)[0] - if proto and ' ' not in text: - if text != node.getAttribute('href',''): - self._reportError(filename, node, - 'link text does not match href') - - def check_a_py_listing(self, dom, filename): - for node in domhelpers.findNodesNamed(dom, 'a'): - if node.getAttribute('class') == 'py-listing': - fn = os.path.join(os.path.dirname(filename), - node.getAttribute('href')) - lines = open(fn).readlines() - lines = lines[int(node.getAttribute('skipLines', 0)):] - for line, num in zip(lines, range(len(lines))): - if line.count('59 Temple Place, Suite 330, Boston'): - self._reportError(filename, node, - 'included source file %s has licence boilerplate.' - ' Use skipLines="%d".' - % (fn, int(node.getAttribute('skipLines',0))+num+1)) - - def check_lists(self, dom, filename): - for node in (domhelpers.findNodesNamed(dom, 'ul')+ - domhelpers.findNodesNamed(dom, 'ol')): - if not node.childNodes: - self._reportError(filename, node, 'empty list') - for child in node.childNodes: - if child.nodeName != 'li': - self._reportError(filename, node, - 'only list items allowed in lists') - - -def list2dict(l): - d = {} - for el in l: - d[el] = None - return d - -classes = list2dict(['shell', 'API', 'python', 'py-prototype', 'py-filename', - 'py-src-string', 'py-signature', 'py-src-parameter', - 'py-src-identifier', 'py-src-keyword']) - -tags = list2dict(["html", "title", "head", "body", "h1", "h2", "h3", "ol", "ul", - "dl", "li", "dt", "dd", "p", "code", "img", "blockquote", "a", - "cite", "div", "span", "strong", "em", "pre", "q", "table", - "tr", "td", "th", "style", "sub", "sup", "link"]) - -span = list2dict(['footnote', 'manhole-output', 'index']) - -div = list2dict(['note', 'boxed', 'doit']) - -a = list2dict(['listing', 'py-listing', 'html-listing', 'absolute']) - -pre = list2dict(['python', 'shell', 'python-interpreter', 'elisp']) - -allowed = {'code': classes.has_key, 'span': span.has_key, 'div': div.has_key, - 'a': a.has_key, 'pre': pre.has_key, 'ul': lambda x: x=='toc', - 'ol': lambda x: x=='toc', 'li': lambda x: x=='ignoretoc'} - -def getDefaultChecker(): - return DefaultTagChecker(tags.has_key, allowed) - -def doFile(file, checker): - dom = tree.parseFileAndReport(file) - if dom: - checker.check(dom, file) diff --git a/tools/buildbot/pylibs/twisted/lore/lmath.py b/tools/buildbot/pylibs/twisted/lore/lmath.py deleted file mode 100644 index 6c05cb7..0000000 --- a/tools/buildbot/pylibs/twisted/lore/lmath.py +++ /dev/null @@ -1,76 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -from __future__ import nested_scopes - -import os, tempfile -from twisted.web import domhelpers, microdom -import latex, tree, lint, default - -class MathLatexSpitter(latex.LatexSpitter): - - start_html = '\\documentclass{amsart}\n' - - def visitNode_div_latexmacros(self, node): - self.writer(domhelpers.getNodeText(node)) - - def visitNode_span_latexformula(self, node): - self.writer('\[') - self.writer(domhelpers.getNodeText(node)) - self.writer('\]') - -def formulaeToImages(document, dir): - # gather all macros - macros = '' - for node in domhelpers.findElementsWithAttribute(document, 'class', - 'latexmacros'): - macros += domhelpers.getNodeText(node) - node.parentNode.removeChild(node) - i = 0 - for node in domhelpers.findElementsWithAttribute(document, 'class', - 'latexformula'): - latexText='''\\documentclass[12pt]{amsart}%s - \\begin{document}\[%s\] - \\end{document}''' % (macros, domhelpers.getNodeText(node)) - file = tempfile.mktemp() - open(file+'.tex', 'w').write(latexText) - os.system('latex %s.tex' % file) - os.system('dvips %s.dvi -o %s.ps' % (os.path.basename(file), file)) - baseimgname = 'latexformula%d.png' % i - imgname = os.path.join(dir, baseimgname) - i += 1 - os.system('pstoimg -type png -crop a -trans -interlace -out ' - '%s %s.ps' % (imgname, file)) - newNode = microdom.parseString('

' % - baseimgname) - node.parentNode.replaceChild(newNode, node) - - -def doFile(fn, docsdir, ext, url, templ, linkrel='', d=None): - d = d or {} - doc = tree.parseFileAndReport(fn) - formulaeToImages(doc, os.path.dirname(fn)) - cn = templ.cloneNode(1) - tree.munge(doc, cn, linkrel, docsdir, fn, ext, url, d) - cn.writexml(open(os.path.splitext(fn)[0]+ext, 'wb')) - - -class ProcessingFunctionFactory(default.ProcessingFunctionFactory): - - latexSpitters = {None: MathLatexSpitter} - - def getDoFile(self): - return doFile - - def getLintChecker(self): - checker = lint.getDefaultChecker() - checker.allowedClasses = checker.allowedClasses.copy() - oldDiv = checker.allowedClasses['div'] - oldSpan = checker.allowedClasses['span'] - checker.allowedClasses['div'] = lambda x:oldDiv(x) or x=='latexmacros' - checker.allowedClasses['span'] = (lambda x:oldSpan(x) or - x=='latexformula') - return checker - -factory = ProcessingFunctionFactory() diff --git a/tools/buildbot/pylibs/twisted/lore/man2lore.py b/tools/buildbot/pylibs/twisted/lore/man2lore.py deleted file mode 100644 index efa528a..0000000 --- a/tools/buildbot/pylibs/twisted/lore/man2lore.py +++ /dev/null @@ -1,291 +0,0 @@ -# -*- test-case-name: twisted.lore.test.test_man2lore -*- -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -man2lore: Converts man page source (i.e. groff) into lore-compatible html. - -This is nasty and hackish (and doesn't support lots of real groff), but is good -enough for converting fairly simple man pages. -""" - -import re, os - -quoteRE = re.compile('"(.*?)"') - - - -def escape(text): - text = text.replace('<', '<').replace('>', '>') - text = quoteRE.sub('\\1', text) - return text - - - -def stripQuotes(s): - if s[0] == s[-1] == '"': - s = s[1:-1] - return s - - - -class ManConverter(object): - """ - Convert a man page to the Lore format. - - @ivar tp: State variable for handling text inside a C{TP} token. It can - take values from 0 to 3: - - 0: when outside of a C{TP} token. - - 1: once a C{TP} token has been encountered. If the previous value - was 0, a definition list is started. Then, at the first line of - text, a definition term is started. - - 2: when the first line after the C{TP} token has been handled. - The definition term is closed, and a definition is started with - the next line of text. - - 3: when the first line as definition data has been handled. - @type tp: C{int} - """ - state = 'regular' - name = None - tp = 0 - dl = 0 - para = 0 - - def convert(self, inf, outf): - self.write = outf.write - longline = '' - for line in inf.readlines(): - if line.rstrip() and line.rstrip()[-1] == '\\': - longline += line.rstrip()[:-1] + ' ' - continue - if longline: - line = longline + line - longline = '' - self.lineReceived(line) - self.closeTags() - self.write('\n\n') - - - def lineReceived(self, line): - if line[0] == '.': - f = getattr(self, 'macro_' + line[1:3].rstrip().upper(), None) - if f: - f(line[3:].strip()) - else: - self.text(line) - - - def continueReceived(self, cont): - if not cont: - return - if cont[0].isupper(): - f = getattr(self, 'macro_' + cont[:2].rstrip().upper(), None) - if f: - f(cont[2:].strip()) - else: - self.text(cont) - - - def closeTags(self): - if self.state != 'regular': - self.write('' % self.state) - if self.tp == 3: - self.write('\n\n') - self.tp = 0 - if self.dl: - self.write('\n\n') - self.dl = 0 - if self.para: - self.write('

\n\n') - self.para = 0 - - - def paraCheck(self): - if not self.tp and not self.para: - self.write('

') - self.para = 1 - - - def macro_TH(self, line): - self.write('\n') - parts = [stripQuotes(x) for x in line.split(' ', 2)] + ['', ''] - title, manSection = parts[:2] - self.write('%s.%s' % (title, manSection)) - self.write('\n\n\n') - self.write('

%s.%s

\n\n' % (title, manSection)) - - macro_DT = macro_TH - - - def macro_SH(self, line): - self.closeTags() - self.write('

') - self.para = 1 - self.text(stripQuotes(line)) - self.para = 0 - self.closeTags() - self.write('

\n\n') - - - def macro_B(self, line): - words = line.split() - words[0] = '\\fB' + words[0] + '\\fR ' - self.text(' '.join(words)) - - - def macro_NM(self, line): - if not self.name: - self.name = line - self.text(self.name + ' ') - - - def macro_NS(self, line): - parts = line.split(' Ns ') - i = 0 - for l in parts: - i = not i - if i: - self.text(l) - else: - self.continueReceived(l) - - - def macro_OO(self, line): - self.text('[') - self.continueReceived(line) - - - def macro_OC(self, line): - self.text(']') - self.continueReceived(line) - - - def macro_OP(self, line): - self.text('[') - self.continueReceived(line) - self.text(']') - - - def macro_FL(self, line): - parts = line.split() - self.text('\\fB-%s\\fR' % parts[0]) - self.continueReceived(' '.join(parts[1:])) - - - def macro_AR(self, line): - parts = line.split() - self.text('\\fI %s\\fR' % parts[0]) - self.continueReceived(' '.join(parts[1:])) - - - def macro_PP(self, line): - self.closeTags() - - - def macro_IC(self, line): - cmd = line.split(' ', 1)[0] - args = line[line.index(cmd) + len(cmd):] - args = args.split(' ') - text = cmd - while args: - arg = args.pop(0) - if arg.lower() == "ar": - text += " \\fU%s\\fR" % (args.pop(0),) - elif arg.lower() == "op": - ign = args.pop(0) - text += " [\\fU%s\\fR]" % (args.pop(0),) - - self.text(text) - - - def macro_TP(self, line): - """ - Handle C{TP} token: start a definition list if it's first token, or - close previous definition data. - """ - if self.tp == 3: - self.write('\n\n') - self.tp = 1 - else: - self.tp = 1 - self.write('
') - self.dl = 1 - - - def macro_BL(self, line): - self.write('
') - self.tp = 1 - - - def macro_EL(self, line): - if self.tp == 3: - self.write('') - self.tp = 1 - self.write('
\n\n') - self.tp = 0 - - - def macro_IT(self, line): - if self.tp == 3: - self.write('') - self.tp = 1 - self.continueReceived(line) - - - def text(self, line): - """ - Handle a line of text without detected token. - """ - if self.tp == 1: - self.write('
') - if self.tp == 2: - self.write('
') - self.paraCheck() - - bits = line.split('\\') - self.write(escape(bits[0])) - for bit in bits[1:]: - if bit[:2] == 'fI': - self.write('' + escape(bit[2:])) - self.state = 'em' - elif bit[:2] == 'fB': - self.write('' + escape(bit[2:])) - self.state = 'strong' - elif bit[:2] == 'fR': - self.write('' % self.state) - self.write(escape(bit[2:])) - self.state = 'regular' - elif bit[:2] == 'fU': - # fU doesn't really exist, but it helps us to manage underlined - # text. - self.write('' + escape(bit[2:])) - self.state = 'u' - elif bit[:3] == '(co': - self.write('©' + escape(bit[3:])) - else: - self.write(escape(bit)) - - if self.tp == 1: - self.write('') - self.tp = 2 - elif self.tp == 2: - self.tp = 3 - - - -class ProcessingFunctionFactory: - - def generate_lore(self, d, filenameGenerator=None): - ext = d.get('ext', '.html') - return lambda file,_: ManConverter().convert(open(file), - open(os.path.splitext(file)[0]+ext, 'w')) - - - -factory = ProcessingFunctionFactory() - - -if __name__ == '__main__': - import sys - mc = ManConverter().convert(open(sys.argv[1]), sys.stdout) diff --git a/tools/buildbot/pylibs/twisted/lore/nevowlore.py b/tools/buildbot/pylibs/twisted/lore/nevowlore.py deleted file mode 100644 index f449219..0000000 --- a/tools/buildbot/pylibs/twisted/lore/nevowlore.py +++ /dev/null @@ -1,108 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -""" -Nevow support for lore. DEPRECATED. - -Don't use this module, it will be removed in the release of Twisted -after 2.3. If you want static templating with Nevow, instantiate a -rend.Page() and call renderString (or renderSynchronously) yourself. - -Do something like:: - - lore -inevow --config pageclass=some.module.SomePageSubclass [other-opts] - -Maintainer: U{Christopher Armstrong} - -""" - -import warnings -warnings.warn("twisted.lore.nevowlore is deprecated. Please instantiate " - "rend.Page and call renderString or renderSynchronously " - "yourself.", DeprecationWarning, stacklevel=2) - -import os - -from twisted.web import microdom -from twisted.python import reflect -from twisted.web import sux - -from twisted.lore import default, tree, process - -from nevow import loaders - -def parseStringAndReport(s): - try: - return microdom.parseString(s) - except microdom.MismatchedTags, e: - raise process.ProcessingFailure( - "%s:%s: begin mismatched tags <%s>/" % - (e.begLine, e.begCol, e.got, e.expect), - "%s:%s: end mismatched tags <%s>/" % - (e.endLine, e.endCol, e.got, e.expect)) - except microdom.ParseError, e: - raise process.ProcessingFailure("%s:%s:%s" % (e.line, e.col, e.message)) - except IOError, e: - raise process.ProcessingFailure(e.strerror) - -def ____wait(d): - "." - from twisted.internet import reactor - from twisted.python import failure - l = [] - d.addBoth(l.append) - while not l: - reactor.iterate() - if isinstance(l[0], failure.Failure): - l[0].raiseException() - return l[0] - -def nevowify(filename, linkrel, ext, url, templ, options=None, outfileGenerator=tree.getOutputFileName): - if options is None: - options = {} - pclass = options['pageclass'] - pclass = reflect.namedObject(pclass) - page = pclass(docFactory=loaders.htmlfile(filename)) - s = page.renderString() - s = ____wait(s) - - newFilename = outfileGenerator(filename, ext) - - if options.has_key('nolore'): - open(newFilename, 'w').write(s) - return - - doc = parseStringAndReport(s) - clonedNode = templ.cloneNode(1) - tree.munge(doc, clonedNode, linkrel, os.path.dirname(filename), filename, ext, - url, options, outfileGenerator) - tree.makeSureDirectoryExists(newFilename) - clonedNode.writexml(open(newFilename, 'wb')) - - - -class NevowProcessorFactory: - - def getDoFile(self): - return nevowify - - - def generate_html(self, options, filenameGenerator=tree.getOutputFileName): - n = default.htmlDefault.copy() - n.update(options) - options = n - try: - fp = open(options['template']) - templ = microdom.parse(fp) - except IOError, e: - raise process.NoProcessorError(e.filename+": "+e.strerror) - except sux.ParseError, e: - raise process.NoProcessorError(str(e)) - df = lambda file, linkrel: self.getDoFile()(file, linkrel, options['ext'], - options['baseurl'], templ, options, filenameGenerator) - return df - - -factory = NevowProcessorFactory() diff --git a/tools/buildbot/pylibs/twisted/lore/numberer.py b/tools/buildbot/pylibs/twisted/lore/numberer.py deleted file mode 100644 index aa7582a..0000000 --- a/tools/buildbot/pylibs/twisted/lore/numberer.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -def reset(): - resetFilenum() - setNumberSections(False) - -def resetFilenum(): - setFilenum(0) - -def setFilenum(arg): - global filenum - filenum = arg - -def getFilenum(): - global filenum - return filenum - -def getNextFilenum(): - global filenum - filenum += 1 - return filenum - -def setNumberSections(arg): - global numberSections - numberSections = arg - -def getNumberSections(): - global numberSections - return numberSections - -reset() diff --git a/tools/buildbot/pylibs/twisted/lore/process.py b/tools/buildbot/pylibs/twisted/lore/process.py deleted file mode 100644 index f1b8fb2..0000000 --- a/tools/buildbot/pylibs/twisted/lore/process.py +++ /dev/null @@ -1,120 +0,0 @@ -# -*- test-case-name: twisted.lore.test.test_lore -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -import sys, os -import tree #todo: get rid of this later -import indexer - -class NoProcessorError(Exception): - pass - -class ProcessingFailure(Exception): - pass - -cols = 79 - -def dircount(d): - return len([1 for el in d.split("/") if el != '.']) - - -class Walker: - - def __init__(self, df, fext, linkrel): - self.df = df - self.linkrel = linkrel - self.fext = fext - self.walked = [] - self.failures = [] - - def walkdir(self, topdir, prefix=''): - self.basecount = dircount(topdir) - os.path.walk(topdir, self.walk, prefix) - - def walk(self, prefix, d, names): - linkrel = prefix + '../' * (dircount(d) - self.basecount) - for name in names: - fullpath = os.path.join(d, name) - fext = os.path.splitext(name)[1] - if fext == self.fext: - self.walked.append((linkrel, fullpath)) - - def generate(self): - i = 0 - indexer.clearEntries() - tree.filenum = 0 - for linkrel, fullpath in self.walked: - linkrel = self.linkrel + linkrel - i += 1 - fname = os.path.splitext(fullpath)[0] - self.percentdone((float(i) / len(self.walked)), fname) - try: - self.df(fullpath, linkrel) - except ProcessingFailure, e: - self.failures.append((fullpath, e)) - indexer.generateIndex() - self.percentdone(1., None) - - def percentdone(self, percent, fname): - # override for neater progress bars - proglen = 40 - hashes = int(percent * proglen) - spaces = proglen - hashes - progstat = "[%s%s] (%s)" %('#' * hashes, ' ' * spaces,fname or "*Done*") - progstat += (cols - len(progstat)) * ' ' - progstat += '\r' - sys.stdout.write(progstat) - sys.stdout.flush() - if fname is None: - print - -class PlainReportingWalker(Walker): - - def percentdone(self, percent, fname): - if fname: - print fname - -class NullReportingWalker(Walker): - - def percentdone(self, percent, fname): - pass - -def parallelGenerator(originalFileName, outputExtension): - return os.path.splitext(originalFileName)[0]+outputExtension - -def fooAddingGenerator(originalFileName, outputExtension): - return os.path.splitext(originalFileName)[0]+"foo"+outputExtension - -def outputdirGenerator(originalFileName, outputExtension, inputdir, outputdir): - originalFileName = os.path.abspath(originalFileName) - abs_inputdir = os.path.abspath(inputdir) - if os.path.commonprefix((originalFileName, abs_inputdir)) != abs_inputdir: - raise ValueError("Original file name '" + originalFileName + - "' not under input directory '" + abs_inputdir + "'") - - adjustedPath = os.path.join(outputdir, os.path.basename(originalFileName)) - return tree.getOutputFileName(adjustedPath, outputExtension) - -def getFilenameGenerator(config, outputExt): - if config.get('outputdir'): - return (lambda originalFileName, outputExtension: - outputdirGenerator(originalFileName, outputExtension, - os.path.abspath(config.get('inputdir')), - os.path.abspath(config.get('outputdir')))) - else: - return tree.getOutputFileName - -def getProcessor(module, output, config): - try: - m = getattr(module.factory, 'generate_'+output) - except AttributeError: - raise NoProcessorError("cannot generate "+output+" output") - - if config.get('ext'): - ext = config['ext'] - else: - from default import htmlDefault - ext = htmlDefault['ext'] - - return m(config, getFilenameGenerator(config, ext)) diff --git a/tools/buildbot/pylibs/twisted/lore/scripts/__init__.py b/tools/buildbot/pylibs/twisted/lore/scripts/__init__.py deleted file mode 100644 index 265270e..0000000 --- a/tools/buildbot/pylibs/twisted/lore/scripts/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"lore scripts" diff --git a/tools/buildbot/pylibs/twisted/lore/scripts/lore.py b/tools/buildbot/pylibs/twisted/lore/scripts/lore.py deleted file mode 100644 index 036ab83..0000000 --- a/tools/buildbot/pylibs/twisted/lore/scripts/lore.py +++ /dev/null @@ -1,158 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -import sys - -from zope.interface import Interface, Attribute - -from twisted.lore import process, indexer, numberer, htmlbook - -from twisted.python import usage, plugin as oldplugin, reflect -from twisted import plugin as newplugin - -class IProcessor(Interface): - """ - """ - - factory = Attribute( - "") - -class Options(usage.Options): - - optFlags = [["plain", 'p', "Report filenames without progress bar"], - ["null", 'n', "Do not report filenames"], - ["number", 'N', "Add chapter/section numbers to section headings"], -] - - optParameters = [ - ["input", "i", 'lore'], - ["inputext", "e", ".xhtml", "The extension that your Lore input files have"], - ["docsdir", "d", None], - ["linkrel", "l", ''], - ["output", "o", 'html'], - ["index", "x", None, "The base filename you want to give your index file"], - ["book", "b", None, "The book file to generate a book from"], - ["prefixurl", None, "", "The prefix to stick on to relative links; only useful when processing directories"], - ] - - #zsh_altArgDescr = {"foo":"use this description for foo instead"} - #zsh_multiUse = ["foo", "bar"] - #zsh_mutuallyExclusive = [("foo", "bar"), ("bar", "baz")] - #zsh_actions = {"foo":'_files -g "*.foo"', "bar":"(one two three)"} - #zsh_actionDescr = {"logfile":"log file name", "random":"random seed"} - zsh_extras = ["*:files:_files"] - - def __init__(self, *args, **kw): - usage.Options.__init__(self, *args, **kw) - self.config = {} - - def opt_config(self, s): - if '=' in s: - k, v = s.split('=', 1) - self.config[k] = v - else: - self.config[s] = 1 - - def parseArgs(self, *files): - self['files'] = files - - -def getProcessor(input, output, config): - plugins = oldplugin._getPlugIns("lore") - for plug in plugins: - if plug.tapname == input: - module = plug.load() - break - else: - plugins = newplugin.getPlugins(IProcessor) - for plug in plugins: - if plug.name == input: - module = reflect.namedModule(plug.moduleName) - break - else: - # try treating it as a module name - try: - module = reflect.namedModule(input) - except ImportError: - print '%s: no such input: %s' % (sys.argv[0], input) - return - try: - return process.getProcessor(module, output, config) - except process.NoProcessorError, e: - print "%s: %s" % (sys.argv[0], e) - - -def getWalker(df, opt): - klass = process.Walker - if opt['plain']: - klass = process.PlainReportingWalker - if opt['null']: - klass = process.NullReportingWalker - return klass(df, opt['inputext'], opt['linkrel']) - - -def runGivenOptions(opt): - """Do everything but parse the options; useful for testing. - Returns a descriptive string if there's an error.""" - - book = None - if opt['book']: - book = htmlbook.Book(opt['book']) - - df = getProcessor(opt['input'], opt['output'], opt.config) - if not df: - return 'getProcessor() failed' - - walker = getWalker(df, opt) - - if opt['files']: - for filename in opt['files']: - walker.walked.append(('', filename)) - elif book: - for filename in book.getFiles(): - walker.walked.append(('', filename)) - else: - walker.walkdir(opt['docsdir'] or '.', opt['prefixurl']) - - if opt['index']: - indexFilename = opt['index'] - elif book: - indexFilename = book.getIndexFilename() - else: - indexFilename = None - - if indexFilename: - indexer.setIndexFilename("%s.%s" % (indexFilename, opt['output'])) - else: - indexer.setIndexFilename(None) - - ## TODO: get numberSections from book, if any - numberer.setNumberSections(opt['number']) - - walker.generate() - - if walker.failures: - for (file, errors) in walker.failures: - for error in errors: - print "%s:%s" % (file, error) - return 'Walker failures' - - -def run(): - opt = Options() - try: - opt.parseOptions() - except usage.UsageError, errortext: - print '%s: %s' % (sys.argv[0], errortext) - print '%s: Try --help for usage details.' % sys.argv[0] - sys.exit(1) - - result = runGivenOptions(opt) - if result: - print result - sys.exit(1) - - -if __name__ == '__main__': - run() - diff --git a/tools/buildbot/pylibs/twisted/lore/slides.py b/tools/buildbot/pylibs/twisted/lore/slides.py deleted file mode 100644 index afbf7a8..0000000 --- a/tools/buildbot/pylibs/twisted/lore/slides.py +++ /dev/null @@ -1,352 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -"""Rudimentary slide support for Lore. - -TODO: - - Complete mgp output target - - syntax highlighting - - saner font handling - - probably lots more - - Add HTML output targets - - one slides per page (with navigation links) - - all in one page - -Example input file:: - - - Title of talk - - -

Title of talk

- -

First Slide

- -
    -
  • Bullet point
  • -
  • Look ma, I'm bold!
  • -
  • ... etc ...
  • -
- - -

Second Slide

- -
-    # Sample code sample.
-    print "Hello, World!"
-    
- - - - -""" -from __future__ import nested_scopes - -from twisted.lore import default -from twisted.web import domhelpers, microdom -from twisted.python import text -# These should be factored out -from twisted.lore.latex import BaseLatexSpitter, LatexSpitter, processFile, \ - getLatexText, HeadingLatexSpitter -from twisted.lore.tree import getHeaders -from tree import removeH1, fixAPI, fontifyPython, \ - addPyListings, addHTMLListings, setTitle - -import os, os.path, re -from cStringIO import StringIO - -hacked_entities = { 'amp': ' &', 'gt': ' >', 'lt': ' <', 'quot': ' "', - 'copy': ' (c)'} - -entities = { 'amp': '&', 'gt': '>', 'lt': '<', 'quot': '"', - 'copy': '(c)'} - -class MagicpointOutput(BaseLatexSpitter): - bulletDepth = 0 - - def writeNodeData(self, node): - buf = StringIO() - getLatexText(node, buf.write, entities=hacked_entities) - data = buf.getvalue().rstrip().replace('\n', ' ') - self.writer(re.sub(' +', ' ', data)) - - def visitNode_title(self, node): - self.title = domhelpers.getNodeText(node) - - def visitNode_body(self, node): - # Adapted from tree.generateToC - self.fontStack = [('standard', None)] - - # Title slide - self.writer(self.start_h2) - self.writer(self.title) - self.writer(self.end_h2) - - self.writer('%center\n\n\n\n\n') - for authorNode in domhelpers.findElementsWithAttribute(node, 'class', 'author'): - getLatexText(authorNode, self.writer, entities=entities) - self.writer('\n') - - # Table of contents - self.writer(self.start_h2) - self.writer(self.title) - self.writer(self.end_h2) - - for element in getHeaders(node): - level = int(element.tagName[1])-1 - self.writer(level * '\t') - self.writer(domhelpers.getNodeText(element)) - self.writer('\n') - - self.visitNodeDefault(node) - - def visitNode_div_author(self, node): - # Skip this node; it's already been used by visitNode_body - pass - - def visitNode_div_pause(self, node): - self.writer('%pause\n') - - def visitNode_pre(self, node): - # TODO: Syntax highlighting - buf = StringIO() - getLatexText(node, buf.write, entities=entities) - data = buf.getvalue() - data = text.removeLeadingTrailingBlanks(data) - lines = data.split('\n') - self.fontStack.append(('typewriter', 4)) - self.writer('%' + self.fontName() + '\n') - for line in lines: - self.writer(' ' + line + '\n') - del self.fontStack[-1] - self.writer('%' + self.fontName() + '\n') - - def visitNode_ul(self, node): - if self.bulletDepth > 0: - self.writer(self._start_ul) - self.bulletDepth += 1 - self.start_li = self._start_li * self.bulletDepth - self.visitNodeDefault(node) - self.bulletDepth -= 1 - self.start_li = self._start_li * self.bulletDepth - - def visitNode_strong(self, node): - self.doFont(node, 'bold') - - def visitNode_em(self, node): - self.doFont(node, 'italic') - - def visitNode_code(self, node): - self.doFont(node, 'typewriter') - - def doFont(self, node, style): - self.fontStack.append((style, None)) - self.writer(' \n%cont, ' + self.fontName() + '\n') - self.visitNodeDefault(node) - del self.fontStack[-1] - self.writer('\n%cont, ' + self.fontName() + '\n') - - def fontName(self): - names = [x[0] for x in self.fontStack] - if 'typewriter' in names: - name = 'typewriter' - else: - name = '' - - if 'bold' in names: - name += 'bold' - if 'italic' in names: - name += 'italic' - - if name == '': - name = 'standard' - - sizes = [x[1] for x in self.fontStack] - sizes.reverse() - for size in sizes: - if size: - return 'font "%s", size %d' % (name, size) - - return 'font "%s"' % name - - start_h2 = "%page\n\n" - end_h2 = '\n\n\n' - - _start_ul = '\n' - - _start_li = "\t" - end_li = "\n" - - -def convertFile(filename, outputter, template, ext=".mgp"): - fout = open(os.path.splitext(filename)[0]+ext, 'w') - fout.write(open(template).read()) - spitter = outputter(fout.write, os.path.dirname(filename), filename) - fin = open(filename) - processFile(spitter, fin) - fin.close() - fout.close() - - -# HTML DOM tree stuff - -def splitIntoSlides(document): - body = domhelpers.findNodesNamed(document, 'body')[0] - slides = [] - slide = [] - title = '(unset)' - for child in body.childNodes: - if isinstance(child, microdom.Element) and child.tagName == 'h2': - if slide: - slides.append((title, slide)) - slide = [] - title = domhelpers.getNodeText(child) - else: - slide.append(child) - slides.append((title, slide)) - return slides - -def insertPrevNextLinks(slides, filename, ext): - for slide in slides: - for name, offset in (("previous", -1), ("next", +1)): - if (slide.pos > 0 and name == "previous") or \ - (slide.pos < len(slides)-1 and name == "next"): - for node in domhelpers.findElementsWithAttribute(slide.dom, "class", name): - if node.tagName == 'a': - node.setAttribute('href', '%s-%d%s' - % (filename[0], slide.pos+offset, ext)) - else: - node.appendChild(microdom.Text(slides[slide.pos+offset].title)) - else: - for node in domhelpers.findElementsWithAttribute(slide.dom, "class", name): - pos = 0 - for child in node.parentNode.childNodes: - if child is node: - del node.parentNode.childNodes[pos] - break - pos += 1 - - -class HTMLSlide: - def __init__(self, dom, title, pos): - self.dom = dom - self.title = title - self.pos = pos - - -def munge(document, template, linkrel, d, fullpath, ext, url, config): - # FIXME: This has *way* to much duplicated crap in common with tree.munge - #fixRelativeLinks(template, linkrel) - removeH1(document) - fixAPI(document, url) - fontifyPython(document) - addPyListings(document, d) - addHTMLListings(document, d) - #fixLinks(document, ext) - #putInToC(template, generateToC(document)) - template = template.cloneNode(1) - - # Insert the slides into the template - slides = [] - pos = 0 - for title, slide in splitIntoSlides(document): - t = template.cloneNode(1) - setTitle(t, [microdom.Text(title)]) - tmplbody = domhelpers.findElementsWithAttribute(t, "class", "body")[0] - tmplbody.childNodes = slide - tmplbody.setAttribute("class", "content") - # FIXME: Next/Prev links - # FIXME: Perhaps there should be a "Template" class? (setTitle/setBody - # could be methods...) - slides.append(HTMLSlide(t, title, pos)) - pos += 1 - - insertPrevNextLinks(slides, os.path.splitext(os.path.basename(fullpath)), ext) - - return slides - -from tree import makeSureDirectoryExists - -def getOutputFileName(originalFileName, outputExtension, index): - return os.path.splitext(originalFileName)[0]+'-'+str(index) + outputExtension - -def doFile(filename, linkrel, ext, url, templ, options={}, outfileGenerator=getOutputFileName): - from tree import parseFileAndReport - doc = parseFileAndReport(filename) - slides = munge(doc, templ, linkrel, os.path.dirname(filename), filename, ext, url, options) - for slide, index in zip(slides, range(len(slides))): - newFilename = outfileGenerator(filename, ext, index) - makeSureDirectoryExists(newFilename) - slide.dom.writexml(open(newFilename, 'wb')) - -# Prosper output - -class ProsperSlides(LatexSpitter): - firstSlide = 1 - start_html = '\\documentclass[ps]{prosper}\n' - start_body = '\\begin{document}\n' - start_div_author = '\\author{' - end_div_author = '}' - - def visitNode_h2(self, node): - if self.firstSlide: - self.firstSlide = 0 - self.end_body = '\\end{slide}\n\n' + self.end_body - else: - self.writer('\\end{slide}\n\n') - self.writer('\\begin{slide}{') - spitter = HeadingLatexSpitter(self.writer, self.currDir, self.filename) - spitter.visitNodeDefault(node) - self.writer('}') - - def _write_img(self, target): - self.writer('\\begin{center}\\includegraphics[%%\nwidth=1.0\n\\textwidth,' - 'height=1.0\\textheight,\nkeepaspectratio]{%s}\\end{center}\n' % target) - - -class PagebreakLatex(LatexSpitter): - - everyN = 1 - currentN = 0 - seenH2 = 0 - - start_html = LatexSpitter.start_html+"\\date{}\n" - start_body = '\\begin{document}\n\n' - - def visitNode_h2(self, node): - if not self.seenH2: - self.currentN = 0 - self.seenH2 = 1 - else: - self.currentN += 1 - self.currentN %= self.everyN - if not self.currentN: - self.writer('\\clearpage\n') - level = (int(node.tagName[1])-2)+self.baseLevel - self.writer('\n\n\\'+level*'sub'+'section*{') - spitter = HeadingLatexSpitter(self.writer, self.currDir, self.filename) - spitter.visitNodeDefault(node) - self.writer('}\n') - -class TwoPagebreakLatex(PagebreakLatex): - - everyN = 2 - - -class SlidesProcessingFunctionFactory(default.ProcessingFunctionFactory): - - latexSpitters = default.ProcessingFunctionFactory.latexSpitters.copy() - latexSpitters['prosper'] = ProsperSlides - latexSpitters['page'] = PagebreakLatex - latexSpitters['twopage'] = TwoPagebreakLatex - - def getDoFile(self): - return doFile - - def generate_mgp(self, d, fileNameGenerator=None): - template = d.get('template', 'template.mgp') - df = lambda file, linkrel: convertFile(file, MagicpointOutput, template, ext=".mgp") - return df - -factory=SlidesProcessingFunctionFactory() diff --git a/tools/buildbot/pylibs/twisted/lore/template.mgp b/tools/buildbot/pylibs/twisted/lore/template.mgp deleted file mode 100644 index 79fc4d1..0000000 --- a/tools/buildbot/pylibs/twisted/lore/template.mgp +++ /dev/null @@ -1,24 +0,0 @@ -%%deffont "standard" tfont "Arial.ttf" -%%deffont "bold" tfont "Arial_Bold.ttf" -%%deffont "italic" tfont "Arial_Italic.ttf" -%%deffont "bolditalic" tfont "Arial_Bold_Italic.ttf" -%%deffont "typewriter" tfont "Courier_New.ttf" -%deffont "standard" xfont "Arial-medium-r" -%deffont "bold" xfont "Arial-bold-r" -%deffont "italic" xfont "Arial-medium-i" -%deffont "bolditalic" xfont "Arial-bold-i" -%deffont "typewriter" xfont "andale mono" -%%deffont "standard" tfont "tahoma.ttf" -%%deffont "thick" tfont "tahomabd.ttf" -#%deffont "typewriter" tfont "Andale_Mono.ttf" -%default 1 area 90 90, leftfill, size 2, fore "white", back "black", font "bold" -%default 2 size 7, vgap 10, prefix " ", center -%default 3 size 2, bar "gray70", vgap 10, leftfill -%default 4 size 1, fore "white", vgap 30, prefix " ", font "standard" -%default 5 size 5 -%%tab 1 size 5, vgap 40, prefix " ", icon box "green" 50 -%%tab 2 size 4, vgap 40, prefix " ", icon arc "yellow" 50 -%%tab 3 size 3, vgap 40, prefix " ", icon delta3 "white" 40 -%tab 1 size 5, vgap 50, prefix " ", icon box "green" 50 -%tab 2 size 5, vgap 50, prefix " ", icon arc "yellow" 50 -%tab 3 size 4, vgap 50, prefix " ", icon delta3 "white" 40 diff --git a/tools/buildbot/pylibs/twisted/lore/test/__init__.py b/tools/buildbot/pylibs/twisted/lore/test/__init__.py deleted file mode 100644 index 1641a43..0000000 --- a/tools/buildbot/pylibs/twisted/lore/test/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"lore tests" diff --git a/tools/buildbot/pylibs/twisted/lore/test/good_internal.xhtml b/tools/buildbot/pylibs/twisted/lore/test/good_internal.xhtml deleted file mode 100644 index 3f54f52..0000000 --- a/tools/buildbot/pylibs/twisted/lore/test/good_internal.xhtml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - Twisted Documentation: My Test Lore Input - - - -

My Test Lore Input -

-
-
    -
    -
    -

    A Body. -

    -
    -

    Index -

    - - \ No newline at end of file diff --git a/tools/buildbot/pylibs/twisted/lore/test/good_simple.xhtml b/tools/buildbot/pylibs/twisted/lore/test/good_simple.xhtml deleted file mode 100644 index eff7d2f..0000000 --- a/tools/buildbot/pylibs/twisted/lore/test/good_simple.xhtml +++ /dev/null @@ -1,2 +0,0 @@ -Twisted Documentation: My Test Lore Input

    My Test Lore Input

      A Body.

      Index

      \ No newline at end of file diff --git a/tools/buildbot/pylibs/twisted/lore/test/lore_index_file_out.html b/tools/buildbot/pylibs/twisted/lore/test/lore_index_file_out.html deleted file mode 100644 index 0490f0c..0000000 --- a/tools/buildbot/pylibs/twisted/lore/test/lore_index_file_out.html +++ /dev/null @@ -1,2 +0,0 @@ -language of programming: 1.3
      -programming language: 1.2
      diff --git a/tools/buildbot/pylibs/twisted/lore/test/lore_index_file_out_multiple.html b/tools/buildbot/pylibs/twisted/lore/test/lore_index_file_out_multiple.html deleted file mode 100644 index fa0235e..0000000 --- a/tools/buildbot/pylibs/twisted/lore/test/lore_index_file_out_multiple.html +++ /dev/null @@ -1,5 +0,0 @@ -aahz: link -aahz2: link -language of programming: link -link -programming language: link diff --git a/tools/buildbot/pylibs/twisted/lore/test/lore_index_file_unnumbered_multiple_out.html b/tools/buildbot/pylibs/twisted/lore/test/lore_index_file_unnumbered_multiple_out.html deleted file mode 100644 index 0c869bc..0000000 --- a/tools/buildbot/pylibs/twisted/lore/test/lore_index_file_unnumbered_multiple_out.html +++ /dev/null @@ -1,4 +0,0 @@ -aahz: link
      -aahz2: link
      -language of programming: link, link
      -programming language: link
      diff --git a/tools/buildbot/pylibs/twisted/lore/test/lore_index_file_unnumbered_out.html b/tools/buildbot/pylibs/twisted/lore/test/lore_index_file_unnumbered_out.html deleted file mode 100644 index fa724d7..0000000 --- a/tools/buildbot/pylibs/twisted/lore/test/lore_index_file_unnumbered_out.html +++ /dev/null @@ -1,2 +0,0 @@ -language of programming: link
      -programming language: link
      diff --git a/tools/buildbot/pylibs/twisted/lore/test/lore_index_test.xhtml b/tools/buildbot/pylibs/twisted/lore/test/lore_index_test.xhtml deleted file mode 100644 index 570b411..0000000 --- a/tools/buildbot/pylibs/twisted/lore/test/lore_index_test.xhtml +++ /dev/null @@ -1,21 +0,0 @@ - - - The way of the program - - - - -

      The way of the program

      - -

      The first paragraph.

      - - -

      The Python programming language

      - - - -

      The second paragraph.

      - - - - diff --git a/tools/buildbot/pylibs/twisted/lore/test/lore_index_test2.xhtml b/tools/buildbot/pylibs/twisted/lore/test/lore_index_test2.xhtml deleted file mode 100644 index 4214e48..0000000 --- a/tools/buildbot/pylibs/twisted/lore/test/lore_index_test2.xhtml +++ /dev/null @@ -1,22 +0,0 @@ - - - The second page to index - - - - -

      The second page to index

      - -

      The first paragraph of the second page.

      - - -

      The Jython programming language

      - - - - -

      The second paragraph of the second page.

      - - - - diff --git a/tools/buildbot/pylibs/twisted/lore/test/lore_index_test3.xhtml b/tools/buildbot/pylibs/twisted/lore/test/lore_index_test3.xhtml deleted file mode 100644 index ce19252..0000000 --- a/tools/buildbot/pylibs/twisted/lore/test/lore_index_test3.xhtml +++ /dev/null @@ -1,22 +0,0 @@ - - - The Page with Hierarchical Index Entries - - - - -

      The Page with Hierarchical Index Entries

      - -

      The first paragraph of the second page.

      - - -

      The Jython programming language

      - - - - -

      The second paragraph of the second page.

      - - - - diff --git a/tools/buildbot/pylibs/twisted/lore/test/lore_index_test_out.html b/tools/buildbot/pylibs/twisted/lore/test/lore_index_test_out.html deleted file mode 100644 index a01fdae..0000000 --- a/tools/buildbot/pylibs/twisted/lore/test/lore_index_test_out.html +++ /dev/null @@ -1,2 +0,0 @@ -Twisted Documentation: The way of the program

      The way of the program

      The first paragraph.

      The Python programming language

      The second paragraph.

      Index

      \ No newline at end of file diff --git a/tools/buildbot/pylibs/twisted/lore/test/lore_index_test_out2.html b/tools/buildbot/pylibs/twisted/lore/test/lore_index_test_out2.html deleted file mode 100644 index fa303c4..0000000 --- a/tools/buildbot/pylibs/twisted/lore/test/lore_index_test_out2.html +++ /dev/null @@ -1,2 +0,0 @@ -Twisted Documentation: The second page to index

      The second page to index

      The first paragraph of the second page.

      The Jython programming language

      The second paragraph of the second page.

      Index

      \ No newline at end of file diff --git a/tools/buildbot/pylibs/twisted/lore/test/lore_numbering_test.xhtml b/tools/buildbot/pylibs/twisted/lore/test/lore_numbering_test.xhtml deleted file mode 100644 index 298e758..0000000 --- a/tools/buildbot/pylibs/twisted/lore/test/lore_numbering_test.xhtml +++ /dev/null @@ -1,30 +0,0 @@ - - - The way of the program - - - - -

      The way of the program

      - -

      The first paragraph.

      - - -

      The Python programming language

      - - - -

      The second paragraph.

      - - -

      Section The Second

      - -

      The second section.

      - -

      Section The Third

      - -

      The Third section.

      - - - - diff --git a/tools/buildbot/pylibs/twisted/lore/test/lore_numbering_test_out.html b/tools/buildbot/pylibs/twisted/lore/test/lore_numbering_test_out.html deleted file mode 100644 index 15bb2b7..0000000 --- a/tools/buildbot/pylibs/twisted/lore/test/lore_numbering_test_out.html +++ /dev/null @@ -1,2 +0,0 @@ -Twisted Documentation: 1. The way of the program

      1. The way of the program

      The first paragraph.

      1.1 The Python programming language

      The second paragraph.

      1.2 Section The Second

      The second section.

      1.3 Section The Third

      The Third section.

      Index

      \ No newline at end of file diff --git a/tools/buildbot/pylibs/twisted/lore/test/lore_numbering_test_out2.html b/tools/buildbot/pylibs/twisted/lore/test/lore_numbering_test_out2.html deleted file mode 100644 index 33aff77..0000000 --- a/tools/buildbot/pylibs/twisted/lore/test/lore_numbering_test_out2.html +++ /dev/null @@ -1,2 +0,0 @@ -Twisted Documentation: 2. The second page to index

      2. The second page to index

      The first paragraph of the second page.

      2.1 The Jython programming language

      The second paragraph of the second page.

      2.2 Second Section

      The second section of the second page.

      2.3 Third Section of Second Page

      The Third section.

      Index

      \ No newline at end of file diff --git a/tools/buildbot/pylibs/twisted/lore/test/simple.html b/tools/buildbot/pylibs/twisted/lore/test/simple.html deleted file mode 100644 index 8d77609..0000000 --- a/tools/buildbot/pylibs/twisted/lore/test/simple.html +++ /dev/null @@ -1,9 +0,0 @@ - - -My Test Lore Input - - -

      My Test Lore Input

      -

      A Body.

      - - \ No newline at end of file diff --git a/tools/buildbot/pylibs/twisted/lore/test/simple.xhtml b/tools/buildbot/pylibs/twisted/lore/test/simple.xhtml deleted file mode 100644 index eff7d2f..0000000 --- a/tools/buildbot/pylibs/twisted/lore/test/simple.xhtml +++ /dev/null @@ -1,2 +0,0 @@ -Twisted Documentation: My Test Lore Input

      My Test Lore Input

        A Body.

        Index

        \ No newline at end of file diff --git a/tools/buildbot/pylibs/twisted/lore/test/simple1.xhtml b/tools/buildbot/pylibs/twisted/lore/test/simple1.xhtml deleted file mode 100644 index eff7d2f..0000000 --- a/tools/buildbot/pylibs/twisted/lore/test/simple1.xhtml +++ /dev/null @@ -1,2 +0,0 @@ -Twisted Documentation: My Test Lore Input

        My Test Lore Input

          A Body.

          Index

          \ No newline at end of file diff --git a/tools/buildbot/pylibs/twisted/lore/test/simple2.xhtml b/tools/buildbot/pylibs/twisted/lore/test/simple2.xhtml deleted file mode 100644 index eff7d2f..0000000 --- a/tools/buildbot/pylibs/twisted/lore/test/simple2.xhtml +++ /dev/null @@ -1,2 +0,0 @@ -Twisted Documentation: My Test Lore Input

          My Test Lore Input

            A Body.

            Index

            \ No newline at end of file diff --git a/tools/buildbot/pylibs/twisted/lore/test/simple3.html b/tools/buildbot/pylibs/twisted/lore/test/simple3.html deleted file mode 100644 index 8d77609..0000000 --- a/tools/buildbot/pylibs/twisted/lore/test/simple3.html +++ /dev/null @@ -1,9 +0,0 @@ - - -My Test Lore Input - - -

            My Test Lore Input

            -

            A Body.

            - - \ No newline at end of file diff --git a/tools/buildbot/pylibs/twisted/lore/test/simple3.xhtml b/tools/buildbot/pylibs/twisted/lore/test/simple3.xhtml deleted file mode 100644 index eff7d2f..0000000 --- a/tools/buildbot/pylibs/twisted/lore/test/simple3.xhtml +++ /dev/null @@ -1,2 +0,0 @@ -Twisted Documentation: My Test Lore Input

            My Test Lore Input

              A Body.

              Index

              \ No newline at end of file diff --git a/tools/buildbot/pylibs/twisted/lore/test/simple4.html b/tools/buildbot/pylibs/twisted/lore/test/simple4.html deleted file mode 100644 index 8d77609..0000000 --- a/tools/buildbot/pylibs/twisted/lore/test/simple4.html +++ /dev/null @@ -1,9 +0,0 @@ - - -My Test Lore Input - - -

              My Test Lore Input

              -

              A Body.

              - - \ No newline at end of file diff --git a/tools/buildbot/pylibs/twisted/lore/test/simple4.xhtml b/tools/buildbot/pylibs/twisted/lore/test/simple4.xhtml deleted file mode 100644 index eff7d2f..0000000 --- a/tools/buildbot/pylibs/twisted/lore/test/simple4.xhtml +++ /dev/null @@ -1,2 +0,0 @@ -Twisted Documentation: My Test Lore Input

              My Test Lore Input

                A Body.

                Index

                \ No newline at end of file diff --git a/tools/buildbot/pylibs/twisted/lore/test/simple4foo.xhtml b/tools/buildbot/pylibs/twisted/lore/test/simple4foo.xhtml deleted file mode 100644 index eff7d2f..0000000 --- a/tools/buildbot/pylibs/twisted/lore/test/simple4foo.xhtml +++ /dev/null @@ -1,2 +0,0 @@ -Twisted Documentation: My Test Lore Input

                My Test Lore Input

                  A Body.

                  Index

                  \ No newline at end of file diff --git a/tools/buildbot/pylibs/twisted/lore/test/template.tpl b/tools/buildbot/pylibs/twisted/lore/test/template.tpl deleted file mode 100644 index 48a6c68..0000000 --- a/tools/buildbot/pylibs/twisted/lore/test/template.tpl +++ /dev/null @@ -1,22 +0,0 @@ - - - - - -Twisted Documentation: - - - - -

                  -
                  -
                  - -
                  - -

                  Index

                  - - - diff --git a/tools/buildbot/pylibs/twisted/lore/test/test_lore.py b/tools/buildbot/pylibs/twisted/lore/test/test_lore.py deleted file mode 100644 index 30e6c61..0000000 --- a/tools/buildbot/pylibs/twisted/lore/test/test_lore.py +++ /dev/null @@ -1,352 +0,0 @@ -# IMPORTANT: -# When all the unit tests for Lore run, there's one more test to do: -# from a shell, -# cd Twisted/ -# admin/process-docs -# It takes a while to run (2:03 on a reasonable box) -# Make sure there are no errors! Warnings are OK. - -# ++ single anchor added to individual output file -# ++ two anchors added to individual output file -# ++ anchors added to individual output files -# ++ entry added to index -# ++ index entry pointing to correct file and anchor -# ++ multiple entries added to index -# ++ multiple index entries pointing to correct files and anchors -# __ all of above for files in deep directory structure -# -# ++ group index entries by indexed term -# ++ sort index entries by indexed term -# __ hierarchical index entries (e.g. language!programming) -# -# ++ add parameter for what the index filename should be -# ++ add (default) ability to NOT index (if index not specified) -# -# ++ put actual index filename into INDEX link (if any) in the template -# __ make index links RELATIVE! -# __ make index pay attention to the outputdir! -# -# __ make index look nice -# -# ++ add section numbers to headers in lore output -# ++ make text of index entry links be chapter numbers -# ++ make text of index entry links be section numbers -# -# __ put all of our test files someplace neat and tidy -# - -import os, shutil -from StringIO import StringIO - -from twisted.trial import unittest - -from twisted.lore import tree, process, indexer, numberer, htmlbook, default -from twisted.lore.default import factory -from twisted.lore.latex import LatexSpitter - -from twisted.python.util import sibpath - -from twisted.lore.scripts import lore - -from twisted.web import microdom, domhelpers - -def sp(originalFileName): - return sibpath(__file__, originalFileName) - -options = {"template" : sp("template.tpl"), 'baseurl': '%s', 'ext': '.xhtml' } -d = options - -def filenameGenerator(originalFileName, outputExtension): - return os.path.splitext(originalFileName)[0]+"1"+outputExtension - -def filenameGenerator2(originalFileName, outputExtension): - return os.path.splitext(originalFileName)[0]+"2"+outputExtension - - -class TestFactory(unittest.TestCase): - - file = sp('simple.html') - linkrel = "" - - def assertEqualFiles1(self, exp, act): - if (exp == act): return True - fact = open(act) - self.assertEqualsFile(exp, fact.read()) - - def assertEqualFiles(self, exp, act): - if (exp == act): return True - fact = open(sp(act)) - self.assertEqualsFile(exp, fact.read()) - - def assertEqualsFile(self, exp, act): - expected = open(sp(exp)).read() - self.assertEqualsString(expected, act) - - def assertEqualsString(self, expected, act): - if len(expected) != len(act): print "Actual: " + act ##d - self.assertEquals(len(expected), len(act)) - for i in range(len(expected)): - e = expected[i] - a = act[i] - self.assertEquals(e, a, "differ at %d: %s vs. %s" % (i, e, a)) - self.assertEquals(expected, act) - - def makeTemp(self, *filenames): - tmp = self.mktemp() - os.mkdir(tmp) - for filename in filenames: - tmpFile = os.path.join(tmp, filename) - shutil.copyfile(sp(filename), tmpFile) - return tmp - -######################################## - - def setUp(self): - indexer.reset() - numberer.reset() - - def testProcessingFunctionFactory(self): - htmlGenerator = factory.generate_html(options) - htmlGenerator(self.file, self.linkrel) - self.assertEqualFiles('good_simple.xhtml', 'simple.xhtml') - - def testProcessingFunctionFactoryWithFilenameGenerator(self): - htmlGenerator = factory.generate_html(options, filenameGenerator2) - htmlGenerator(self.file, self.linkrel) - self.assertEqualFiles('good_simple.xhtml', 'simple2.xhtml') - - def test_doFile(self): - templ = microdom.parse(open(d['template'])) - - tree.doFile(self.file, self.linkrel, d['ext'], d['baseurl'], templ, d) - self.assertEqualFiles('good_simple.xhtml', 'simple.xhtml') - - def test_doFile_withFilenameGenerator(self): - templ = microdom.parse(open(d['template'])) - - tree.doFile(self.file, self.linkrel, d['ext'], d['baseurl'], templ, d, filenameGenerator) - self.assertEqualFiles('good_simple.xhtml', 'simple1.xhtml') - - def test_munge(self): - indexer.setIndexFilename("lore_index_file.html") - doc = microdom.parse(open(self.file)) - templ = microdom.parse(open(d['template'])) - node = templ.cloneNode(1) - tree.munge(doc, node, self.linkrel, - os.path.dirname(self.file), - self.file, - d['ext'], d['baseurl'], d) - self.assertEqualsFile('good_internal.xhtml', node.toprettyxml()) - - def test_getProcessor(self): - options = { 'template': sp('template.tpl'), 'ext': '.xhtml', 'baseurl': 'burl', - 'filenameMapping': None } - p = process.getProcessor(default, "html", options) - p(sp('simple3.html'), self.linkrel) - self.assertEqualFiles('good_simple.xhtml', 'simple3.xhtml') - - def test_getProcessorWithFilenameGenerator(self): - options = { 'template': sp('template.tpl'), - 'ext': '.xhtml', - 'baseurl': 'burl', - 'filenameMapping': 'addFoo' } - p = process.getProcessor(default, "html", options) - p(sp('simple4.html'), self.linkrel) - self.assertEqualFiles('good_simple.xhtml', 'simple4foo.xhtml') - - def test_outputdirGenerator(self): - normp = os.path.normpath; join = os.path.join - inputdir = normp(join("/", 'home', 'joe')) - outputdir = normp(join("/", 'away', 'joseph')) - actual = process.outputdirGenerator(join("/", 'home', 'joe', "myfile.html"), - '.xhtml', inputdir, outputdir) - expected = normp(join("/", 'away', 'joseph', 'myfile.xhtml')) - self.assertEquals(expected, actual) - - def test_outputdirGeneratorBadInput(self): - options = {'outputdir': '/away/joseph/', 'inputdir': '/home/joe/' } - self.assertRaises(ValueError, process.outputdirGenerator, '.html', '.xhtml', **options) - - def test_makeSureDirectoryExists(self): - dirname = os.path.join("tmp", 'nonexistentdir') - if os.path.exists(dirname): - os.rmdir(dirname) - self.failIf(os.path.exists(dirname), "Hey: someone already created the dir") - filename = os.path.join(dirname, 'newfile') - tree.makeSureDirectoryExists(filename) - self.failUnless(os.path.exists(dirname), 'should have created dir') - os.rmdir(dirname) - - def test_indexAnchorsAdded(self): - indexer.setIndexFilename('theIndexFile.html') - # generate the output file - templ = microdom.parse(open(d['template'])) - tmp = self.makeTemp('lore_index_test.xhtml') - - tree.doFile(os.path.join(tmp, 'lore_index_test.xhtml'), - self.linkrel, '.html', d['baseurl'], templ, d) - self.assertEqualFiles1("lore_index_test_out.html", - os.path.join(tmp, "lore_index_test.html")) - - def test_indexEntriesAdded(self): - indexer.addEntry('lore_index_test.html', 'index02', 'language of programming', '1.3') - indexer.addEntry('lore_index_test.html', 'index01', 'programming language', '1.2') - indexer.setIndexFilename("lore_index_file.html") - indexer.generateIndex() - self.assertEqualFiles1("lore_index_file_out.html", "lore_index_file.html") - - def test_book(self): - tmp = self.makeTemp() - inputFilename = sp('lore_index_test.xhtml') - - bookFilename = os.path.join(tmp, 'lore_test_book.book') - bf = open(bookFilename, 'w') - bf.write('Chapter(r"%s", None)\r\n' % inputFilename) - bf.close() - - book = htmlbook.Book(bookFilename) - expected = {'indexFilename': None, - 'chapters': [(inputFilename, None)], - } - dct = book.__dict__ - for k in dct: - self.assertEquals(dct[k], expected[k]) - - def test_runningLore(self): - options = lore.Options() - tmp = self.makeTemp('lore_index_test.xhtml') - - templateFilename = sp('template.tpl') - inputFilename = os.path.join(tmp, 'lore_index_test.xhtml') - indexFilename = 'theIndexFile' - - bookFilename = os.path.join(tmp, 'lore_test_book.book') - bf = open(bookFilename, 'w') - bf.write('Chapter(r"%s", None)\n' % inputFilename) - bf.close() - - options.parseOptions(['--null', '--book=%s' % bookFilename, - '--config', 'template=%s' % templateFilename, - '--index=%s' % indexFilename - ]) - result = lore.runGivenOptions(options) - self.assertEquals(None, result) - self.assertEqualFiles1("lore_index_file_unnumbered_out.html", indexFilename + ".html") - - def test_runningLoreMultipleFiles(self): - tmp = self.makeTemp('lore_index_test.xhtml', 'lore_index_test2.xhtml') - templateFilename = sp('template.tpl') - inputFilename = os.path.join(tmp, 'lore_index_test.xhtml') - inputFilename2 = os.path.join(tmp, 'lore_index_test2.xhtml') - indexFilename = 'theIndexFile' - - bookFilename = os.path.join(tmp, 'lore_test_book.book') - bf = open(bookFilename, 'w') - bf.write('Chapter(r"%s", None)\n' % inputFilename) - bf.write('Chapter(r"%s", None)\n' % inputFilename2) - bf.close() - - options = lore.Options() - options.parseOptions(['--null', '--book=%s' % bookFilename, - '--config', 'template=%s' % templateFilename, - '--index=%s' % indexFilename - ]) - result = lore.runGivenOptions(options) - self.assertEquals(None, result) - self.assertEqualFiles1("lore_index_file_unnumbered_multiple_out.html", indexFilename + ".html") - self.assertEqualFiles1("lore_index_test_out.html", - os.path.join(tmp, "lore_index_test.html")) - self.assertEqualFiles1("lore_index_test_out2.html", - os.path.join(tmp, "lore_index_test2.html")) - - def XXXtest_NumberedSections(self): - # run two files through lore, with numbering turned on - # every h2 should be numbered: - # first file's h2s should be 1.1, 1.2 - # second file's h2s should be 2.1, 2.2 - templateFilename = sp('template.tpl') - inputFilename = sp('lore_numbering_test.xhtml') - inputFilename2 = sp('lore_numbering_test2.xhtml') - indexFilename = 'theIndexFile' - - # you can number without a book: - options = lore.Options() - options.parseOptions(['--null', - '--index=%s' % indexFilename, - '--config', 'template=%s' % templateFilename, - '--config', 'ext=%s' % ".tns", - '--number', - inputFilename, inputFilename2]) - result = lore.runGivenOptions(options) - - self.assertEquals(None, result) - #self.assertEqualFiles1("lore_index_file_out_multiple.html", indexFilename + ".tns") - # VVV change to new, numbered files - self.assertEqualFiles("lore_numbering_test_out.html", "lore_numbering_test.tns") - self.assertEqualFiles("lore_numbering_test_out2.html", "lore_numbering_test2.tns") - - - def test_setIndexLink(self): - """ - Tests to make sure that index links are processed when an index page - exists and removed when there is not. - """ - templ = microdom.parse(open(d['template'])) - indexFilename = 'theIndexFile' - numLinks = len(domhelpers.findElementsWithAttribute(templ, - "class", - "index-link")) - - # if our testing template has no index-link nodes, complain about it - self.assertNotEquals( - [], - domhelpers.findElementsWithAttribute(templ, - "class", - "index-link")) - - tree.setIndexLink(templ, indexFilename) - - self.assertEquals( - [], - domhelpers.findElementsWithAttribute(templ, - "class", - "index-link")) - - indexLinks = domhelpers.findElementsWithAttribute(templ, - "href", - indexFilename) - self.assertTrue(len(indexLinks) >= numLinks) - - templ = microdom.parse(open(d['template'])) - self.assertNotEquals( - [], - domhelpers.findElementsWithAttribute(templ, - "class", - "index-link")) - indexFilename = None - - tree.setIndexLink(templ, indexFilename) - - self.assertEquals( - [], - domhelpers.findElementsWithAttribute(templ, - "class", - "index-link")) - - - - -class LatexSpitterTestCase(unittest.TestCase): - """ - Tests for the Latex output plugin. - """ - def test_indexedSpan(self): - """ - Test processing of a span tag with an index class results in a latex - \\index directive the correct value. - """ - dom = microdom.parseString('').documentElement - out = StringIO() - spitter = LatexSpitter(out.write) - spitter.visitNode(dom) - self.assertEqual(out.getvalue(), u'\\index{name}\n') diff --git a/tools/buildbot/pylibs/twisted/lore/test/test_man2lore.py b/tools/buildbot/pylibs/twisted/lore/test/test_man2lore.py deleted file mode 100644 index 72655bf..0000000 --- a/tools/buildbot/pylibs/twisted/lore/test/test_man2lore.py +++ /dev/null @@ -1,162 +0,0 @@ -# Copyright (c) 2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Tests for L{twisted.lore.man2lore}. -""" - -from StringIO import StringIO - -from twisted.trial.unittest import TestCase - -from twisted.lore.man2lore import ManConverter - - - -class ManConverterTestCase(TestCase): - """ - Tests for L{ManConverter}. - """ - - def setUp(self): - """ - Build instance variables useful for tests. - - @ivar converter: a L{ManConverter} to be used during tests. - """ - self.converter = ManConverter() - - - def assertConvert(self, inputLines, expectedOutput): - """ - Helper method to check conversion from a man page to a Lore output. - - @param inputLines: lines of the manpages. - @type inputLines: C{list} - - @param expectedOutput: expected Lore content. - @type expectedOutput: C{str} - """ - inputFile = StringIO() - for line in inputLines: - inputFile.write(line + '\n') - inputFile.seek(0) - outputFile = StringIO() - self.converter.convert(inputFile, outputFile) - self.assertEquals(outputFile.getvalue(), expectedOutput) - - - def test_convert(self): - """ - Test convert on a minimal example. - """ - inputLines = ['.TH BAR "1" "Oct 2007" "" ""', "Foo\n"] - output = ("\nBAR.1\n\n\n" - "

                  BAR.1

                  \n\n

                  Foo\n\n

                  \n\n\n\n") - self.assertConvert(inputLines, output) - - - def test_TP(self): - """ - Test C{TP} parsing. - """ - inputLines = ['.TH BAR "1" "Oct 2007" "" ""', - ".SH HEADER", - ".TP", - "\\fB-o\\fR, \\fB--option\\fR", - "An option"] - output = ("\nBAR.1\n\n\n" - "

                  BAR.1

                  \n\n

                  HEADER

                  \n\n
                  " - "-o, --option\n
                  " - "
                  An option\n
                  \n\n
                  \n\n\n\n") - self.assertConvert(inputLines, output) - - - def test_TPMultipleOptions(self): - """ - Try to parse multiple C{TP} fields. - """ - inputLines = ['.TH BAR "1" "Oct 2007" "" ""', - ".SH HEADER", - ".TP", - "\\fB-o\\fR, \\fB--option\\fR", - "An option", - ".TP", - "\\fB-n\\fR, \\fB--another\\fR", - "Another option", - ] - output = ("\nBAR.1\n\n\n" - "

                  BAR.1

                  \n\n

                  HEADER

                  \n\n
                  " - "-o, --option\n
                  " - "
                  An option\n
                  \n\n
                  " - "-n, --another\n
                  " - "
                  Another option\n
                  \n\n
                  \n\n\n\n") - self.assertConvert(inputLines, output) - - - def test_TPMultiLineOptions(self): - """ - Try to parse multiple C{TP} fields, with options text on several lines. - """ - inputLines = ['.TH BAR "1" "Oct 2007" "" ""', - ".SH HEADER", - ".TP", - "\\fB-o\\fR, \\fB--option\\fR", - "An option", - "on two lines", - ".TP", - "\\fB-n\\fR, \\fB--another\\fR", - "Another option", - "on two lines", - ] - output = ("\nBAR.1\n\n\n" - "

                  BAR.1

                  \n\n

                  HEADER

                  \n\n
                  " - "-o, --option\n
                  " - "
                  An option\non two lines\n
                  \n\n" - "
                  -n, --another\n
                  " - "
                  Another option\non two lines\n
                  \n\n
                  \n\n" - "\n\n") - self.assertConvert(inputLines, output) - - - def test_ITLegacyManagement(self): - """ - Test management of BL/IT/EL used in some man pages. - """ - inputLines = ['.TH BAR "1" "Oct 2007" "" ""', - ".SH HEADER", - ".BL", - ".IT An option", - "on two lines", - ".IT", - "Another option", - "on two lines", - ".EL" - ] - output = ("\nBAR.1\n\n\n" - "

                  BAR.1

                  \n\n

                  HEADER

                  \n\n
                  " - "
                  on two lines\n
                  Another option\non two lines\n" - "
                  \n\n\n\n") - self.assertConvert(inputLines, output) - - - def test_interactiveCommand(self): - """ - Test management of interactive command tag. - """ - inputLines = ['.TH BAR "1" "Oct 2007" "" ""', - ".SH HEADER", - ".BL", - ".IT IC foo AR bar", - "option 1", - ".IT IC egg AR spam OP AR stuff", - "option 2", - ".EL" - ] - output = ("\nBAR.1\n\n\n" - "

                  BAR.1

                  \n\n

                  HEADER

                  \n\n
                  " - "
                  foo bar
                  option 1\n
                  egg " - "spam [stuff]
                  option 2\n
                  " - "\n\n\n\n") - self.assertConvert(inputLines, output) diff --git a/tools/buildbot/pylibs/twisted/lore/texi.py b/tools/buildbot/pylibs/twisted/lore/texi.py deleted file mode 100644 index 2763951..0000000 --- a/tools/buildbot/pylibs/twisted/lore/texi.py +++ /dev/null @@ -1,109 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -from cStringIO import StringIO -import os, re -from twisted.python import text -from twisted.web import domhelpers -import latex, tree - -spaceRe = re.compile('\s+') - -def texiEscape(text): - return spaceRe.sub(text, ' ') - -entities = latex.entities.copy() -entities['copy'] = '@copyright{}' - -class TexiSpitter(latex.BaseLatexSpitter): - - baseLevel = 1 - - def writeNodeData(self, node): - buf = StringIO() - latex.getLatexText(node, self.writer, texiEscape, entities) - - def visitNode_title(self, node): - self.writer('@node ') - self.visitNodeDefault(node) - self.writer('\n') - self.writer('@section ') - self.visitNodeDefault(node) - self.writer('\n') - headers = tree.getHeaders(domhelpers.getParents(node)[-1]) - if not headers: - return - self.writer('@menu\n') - for header in headers: - self.writer('* %s::\n' % domhelpers.getNodeText(header)) - self.writer('@end menu\n') - - def visitNode_pre(self, node): - self.writer('@verbatim\n') - buf = StringIO() - latex.getLatexText(node, buf.write, entities=entities) - self.writer(text.removeLeadingTrailingBlanks(buf.getvalue())) - self.writer('@end verbatim\n') - - def visitNode_code(self, node): - fout = StringIO() - latex.getLatexText(node, fout.write, texiEscape, entities) - self.writer('@code{'+fout.getvalue()+'}') - - def visitNodeHeader(self, node): - self.writer('\n\n@node ') - self.visitNodeDefault(node) - self.writer('\n') - level = (int(node.tagName[1])-2)+self.baseLevel - self.writer('\n\n@'+level*'sub'+'section ') - self.visitNodeDefault(node) - self.writer('\n') - - def visitNode_a_listing(self, node): - fileName = os.path.join(self.currDir, node.getAttribute('href')) - self.writer('@verbatim\n') - self.writer(open(fileName).read()) - self.writer('@end verbatim') - # Write a caption for this source listing - - def visitNode_a_href(self, node): - self.visitNodeDefault(node) - - def visitNode_a_name(self, node): - self.visitNodeDefault(node) - - visitNode_h2 = visitNode_h3 = visitNode_h4 = visitNodeHeader - - start_dl = '@itemize\n' - end_dl = '@end itemize\n' - start_ul = '@itemize\n' - end_ul = '@end itemize\n' - - start_ol = '@enumerate\n' - end_ol = '@end enumerate\n' - - start_li = '@item\n' - end_li = '\n' - - start_dt = '@item\n' - end_dt = ': ' - end_dd = '\n' - - start_p = '\n\n' - - start_strong = start_em = '@emph{' - end_strong = end_em = '}' - - start_q = "``" - end_q = "''" - - start_span_footnote = '@footnote{' - end_span_footnote = '}' - - start_div_note = '@quotation\n@strong{Note:}' - end_div_note = '@end quotation\n' - - start_th = '@strong{' - end_th = '}' diff --git a/tools/buildbot/pylibs/twisted/lore/topfiles/NEWS b/tools/buildbot/pylibs/twisted/lore/topfiles/NEWS deleted file mode 100644 index ccfd57c..0000000 --- a/tools/buildbot/pylibs/twisted/lore/topfiles/NEWS +++ /dev/null @@ -1,60 +0,0 @@ -8.1.0 (2008-05-18) -================== - -Fixes ------ - - The deprecated mktap API is no longer used (#3127) - - -8.0.0 (2008-03-17) -================== - -Fixes ------ - - Change twisted.lore.tree.setIndexLin so that it removes node with index-link - class when the specified index filename is None. (#812) - - Fix the conversion of the list of options in man pages to Lore format. - (#3017) - - Fix conch man pages generation. (#3075) - - Fix management of the interactive command tag in man2lore. (#3076) - -Misc ----- - - #2847 - - -0.3.0 (2007-01-06) -================== - -Features --------- - - Many docstrings were added to twisted.lore.tree (#2301) - -Fixes ------ - - Emitting a span with an index class to latex now works (#2134) - - -0.2.0 (2006-05-24) -================== - -Features --------- - - Docstring improvements. - -Fixes ------ - - Embedded Dia support for Latex no longer requires the 'which' - command line tool. - - Misc: #1142. - -Deprecations ------------- - - The unused, undocumented, untested and severely crashy 'bookify' - functionality was removed. - - -0.1.0 -===== - - Use htmlizer mode that doesn't insert extra span tags, thus making - it not mess up in Safari. diff --git a/tools/buildbot/pylibs/twisted/lore/topfiles/README b/tools/buildbot/pylibs/twisted/lore/topfiles/README deleted file mode 100644 index 4f4a95e..0000000 --- a/tools/buildbot/pylibs/twisted/lore/topfiles/README +++ /dev/null @@ -1,3 +0,0 @@ -Twisted Lore 8.1.0 - -Twisted Lore depends on Twisted and Twisted Web. diff --git a/tools/buildbot/pylibs/twisted/lore/topfiles/setup.py b/tools/buildbot/pylibs/twisted/lore/topfiles/setup.py deleted file mode 100644 index d6a906b..0000000 --- a/tools/buildbot/pylibs/twisted/lore/topfiles/setup.py +++ /dev/null @@ -1,27 +0,0 @@ -import sys - -try: - from twisted.python import dist -except ImportError: - raise SystemExit("twisted.python.dist module not found. Make sure you " - "have installed the Twisted core package before " - "attempting to install any other Twisted projects.") - -if __name__ == '__main__': - dist.setup( - twisted_subproject="lore", - scripts=dist.getScripts("lore"), - # metadata - name="Twisted Lore", - description="Twisted documentation system", - author="Twisted Matrix Laboratories", - author_email="twisted-python@twistedmatrix.com", - maintainer="Andrew Bennetts", - maintainer_email="spiv@twistedmatrix.com", - url="http://twistedmatrix.com/trac/wiki/TwistedLore", - license="MIT", - long_description="""\ -Twisted Lore is a documentation generator with HTML and LaTeX support, -used in the Twisted project. -""", - ) diff --git a/tools/buildbot/pylibs/twisted/lore/tree.py b/tools/buildbot/pylibs/twisted/lore/tree.py deleted file mode 100644 index 263522c..0000000 --- a/tools/buildbot/pylibs/twisted/lore/tree.py +++ /dev/null @@ -1,901 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -import re, os, cStringIO, time, cgi, string, urlparse -from twisted import copyright -from twisted.python import htmlizer, text -from twisted.web import microdom, domhelpers -import process, latex, indexer, numberer, htmlbook -from twisted.python.util import InsensitiveDict - -# relative links to html files -def fixLinks(document, ext): - """ - Rewrite links to XHTML lore input documents so they point to lore XHTML - output documents. - - Any node with an C{href} attribute which does not contain a value starting - with C{http}, C{https}, C{ftp}, or C{mailto} and which does not have a - C{class} attribute of C{absolute} or which contains C{listing} and which - does point to an URL ending with C{html} will have that attribute value - rewritten so that the filename extension is C{ext} instead of C{html}. - - @type document: A DOM Node or Document - @param document: The input document which contains all of the content to be - presented. - - @type ext: C{str} - @param ext: The extension to use when selecting an output file name. This - replaces the extension of the input file name. - - @return: C{None} - """ - supported_schemes=['http', 'https', 'ftp', 'mailto'] - for node in domhelpers.findElementsWithAttribute(document, 'href'): - href = node.getAttribute("href") - if urlparse.urlparse(href)[0] in supported_schemes: - continue - if node.getAttribute("class", "") == "absolute": - continue - if node.getAttribute("class", "").find('listing') != -1: - continue - - # This is a relative link, so it should be munged. - if href.endswith('html') or href[:href.rfind('#')].endswith('html'): - fname, fext = os.path.splitext(href) - if '#' in fext: - fext = ext+'#'+fext.split('#', 1)[1] - else: - fext = ext - node.setAttribute("href", fname + fext) - - - -def addMtime(document, fullpath): - """ - Set the last modified time of the given document. - - @type document: A DOM Node or Document - @param document: The output template which defines the presentation of the - last modified time. - - @type fullpath: C{str} - @param fullpath: The file name from which to take the last modified time. - - @return: C{None} - """ - for node in domhelpers.findElementsWithAttribute(document, "class","mtime"): - node.appendChild(microdom.Text(time.ctime(os.path.getmtime(fullpath)))) - - - -def _getAPI(node): - """ - Retrieve the fully qualified Python name represented by the given node. - - The name is represented by one or two aspects of the node: the value of the - node's first child forms the end of the name. If the node has a C{base} - attribute, that attribute's value is prepended to the node's value, with - C{.} separating the two parts. - - @rtype: C{str} - @return: The fully qualified Python name. - """ - base = "" - if node.hasAttribute("base"): - base = node.getAttribute("base") + "." - return base+node.childNodes[0].nodeValue - - - -def fixAPI(document, url): - """ - Replace API references with links to API documentation. - - @type document: A DOM Node or Document - @param document: The input document which contains all of the content to be - presented. - - @type url: C{str} - @param url: A string which will be interpolated with the fully qualified - Python name of any API reference encountered in the input document, the - result of which will be used as a link to API documentation for that name - in the output document. - - @return: C{None} - """ - # API references - for node in domhelpers.findElementsWithAttribute(document, "class", "API"): - fullname = _getAPI(node) - node2 = microdom.Element('a', {'href': url%fullname, 'title': fullname}) - node2.childNodes = node.childNodes - node.childNodes = [node2] - node.removeAttribute('base') - - - -def fontifyPython(document): - """ - Syntax color any node in the given document which contains a Python source - listing. - - @type document: A DOM Node or Document - @param document: The input document which contains all of the content to be - presented. - - @return: C{None} - """ - def matcher(node): - return (node.nodeName == 'pre' and node.hasAttribute('class') and - node.getAttribute('class') == 'python') - for node in domhelpers.findElements(document, matcher): - fontifyPythonNode(node) - - - -def fontifyPythonNode(node): - """ - Syntax color the given node containing Python source code. - - @return: C{None} - """ - oldio = cStringIO.StringIO() - latex.getLatexText(node, oldio.write, - entities={'lt': '<', 'gt': '>', 'amp': '&'}) - oldio = cStringIO.StringIO(oldio.getvalue().strip()+'\n') - newio = cStringIO.StringIO() - htmlizer.filter(oldio, newio, writer=htmlizer.SmallerHTMLWriter) - newio.seek(0) - newel = microdom.parse(newio).documentElement - newel.setAttribute("class", "python") - node.parentNode.replaceChild(newel, node) - - - -def addPyListings(document, dir): - """ - Insert Python source listings into the given document from files in the - given directory based on C{py-listing} nodes. - - Any node in C{document} with a C{class} attribute set to C{py-listing} will - have source lines taken from the file named in that node's C{href} - attribute (searched for in C{dir}) inserted in place of that node. - - If a node has a C{skipLines} attribute, its value will be parsed as an - integer and that many lines will be skipped at the beginning of the source - file. - - @type document: A DOM Node or Document - @param document: The document within which to make listing replacements. - - @type dir: C{str} - @param dir: The directory in which to find source files containing the - referenced Python listings. - - @return: C{None} - """ - for node in domhelpers.findElementsWithAttribute(document, "class", - "py-listing"): - filename = node.getAttribute("href") - outfile = cStringIO.StringIO() - lines = map(string.rstrip, open(os.path.join(dir, filename)).readlines()) - data = '\n'.join(lines[int(node.getAttribute('skipLines', 0)):]) - data = cStringIO.StringIO(text.removeLeadingTrailingBlanks(data)) - htmlizer.filter(data, outfile, writer=htmlizer.SmallerHTMLWriter) - val = outfile.getvalue() - _replaceWithListing(node, val, filename, "py-listing") - - - -def _replaceWithListing(node, val, filename, class_): - captionTitle = domhelpers.getNodeText(node) - if captionTitle == os.path.basename(filename): - captionTitle = 'Source listing' - text = ('
                  %s
                  %s - ' - '%s
                  ' % - (class_, val, captionTitle, filename, filename)) - newnode = microdom.parseString(text).documentElement - node.parentNode.replaceChild(newnode, node) - - - -def addHTMLListings(document, dir): - """ - Insert HTML source listings into the given document from files in the given - directory based on C{html-listing} nodes. - - Any node in C{document} with a C{class} attribute set to C{html-listing} - will have source lines taken from the file named in that node's C{href} - attribute (searched for in C{dir}) inserted in place of that node. - - @type document: A DOM Node or Document - @param document: The document within which to make listing replacements. - - @type dir: C{str} - @param dir: The directory in which to find source files containing the - referenced HTML listings. - - @return: C{None} - """ - for node in domhelpers.findElementsWithAttribute(document, "class", - "html-listing"): - filename = node.getAttribute("href") - val = ('
                  \n%s
                  ' % - cgi.escape(open(os.path.join(dir, filename)).read())) - _replaceWithListing(node, val, filename, "html-listing") - - - -def addPlainListings(document, dir): - """ - Insert text listings into the given document from files in the given - directory based on C{listing} nodes. - - Any node in C{document} with a C{class} attribute set to C{listing} will - have source lines taken from the file named in that node's C{href} - attribute (searched for in C{dir}) inserted in place of that node. - - @type document: A DOM Node or Document - @param document: The document within which to make listing replacements. - - @type dir: C{str} - @param dir: The directory in which to find source files containing the - referenced text listings. - - @return: C{None} - """ - for node in domhelpers.findElementsWithAttribute(document, "class", - "listing"): - filename = node.getAttribute("href") - val = ('
                  \n%s
                  ' % - cgi.escape(open(os.path.join(dir, filename)).read())) - _replaceWithListing(node, val, filename, "listing") - - - -def getHeaders(document): - """ - Return all H2 and H3 nodes in the given document. - - @type document: A DOM Node or Document - - @rtype: C{list} - """ - return domhelpers.findElements( - document, - lambda n, m=re.compile('h[23]$').match: m(n.nodeName)) - - - -def generateToC(document): - """ - Create a table of contents for the given document. - - @type document: A DOM Node or Document - - @rtype: A DOM Node - @return: a Node containing a table of contents based on the headers of the - given document. - """ - toc, level, id = '\n
                    \n', 0, 0 - for element in getHeaders(document): - elementLevel = int(element.tagName[1])-2 - toc += (level-elementLevel)*'\n' - toc += (elementLevel-level)*'\n' * level - toc += '
                  \n' - return microdom.parseString(toc).documentElement - - - -def putInToC(document, toc): - """ - Insert the given table of contents into the given document. - - The node with C{class} attribute set to C{toc} has its children replaced - with C{toc}. - - @type document: A DOM Node or Document - @type toc: A DOM Node - """ - tocOrig = domhelpers.findElementsWithAttribute(document, 'class', 'toc') - if tocOrig: - tocOrig= tocOrig[0] - tocOrig.childNodes = [toc] - - - -def removeH1(document): - """ - Replace all C{h1} nodes in the given document with empty C{span} nodes. - - C{h1} nodes mark up document sections and the output template is given an - opportunity to present this information in a different way. - - @type document: A DOM Node or Document - @param document: The input document which contains all of the content to be - presented. - - @return: C{None} - """ - h1 = domhelpers.findNodesNamed(document, 'h1') - empty = microdom.Element('span') - for node in h1: - node.parentNode.replaceChild(empty, node) - - - -def footnotes(document): - """ - Find footnotes in the given document, move them to the end of the body, and - generate links to them. - - A footnote is any node with a C{class} attribute set to C{footnote}. - Footnote links are generated as superscript. Footnotes are collected in a - C{ol} node at the end of the document. - - @type document: A DOM Node or Document - @param document: The input document which contains all of the content to be - presented. - - @return: C{None} - """ - footnotes = domhelpers.findElementsWithAttribute(document, "class", - "footnote") - if not footnotes: - return - footnoteElement = microdom.Element('ol') - id = 1 - for footnote in footnotes: - href = microdom.parseString('' - '%(id)d' - % vars()).documentElement - text = ' '.join(domhelpers.getNodeText(footnote).split()) - href.setAttribute('title', text) - target = microdom.Element('a', attributes={'name': 'footnote-%d' % id}) - target.childNodes = [footnote] - footnoteContent = microdom.Element('li') - footnoteContent.childNodes = [target] - footnoteElement.childNodes.append(footnoteContent) - footnote.parentNode.replaceChild(href, footnote) - id += 1 - body = domhelpers.findNodesNamed(document, "body")[0] - header = microdom.parseString('

                  Footnotes

                  ').documentElement - body.childNodes.append(header) - body.childNodes.append(footnoteElement) - - - -def notes(document): - """ - Find notes in the given document and mark them up as such. - - A note is any node with a C{class} attribute set to C{note}. - - (I think this is a very stupid feature. When I found it I actually - exclaimed out loud. -exarkun) - - @type document: A DOM Node or Document - @param document: The input document which contains all of the content to be - presented. - - @return: C{None} - """ - notes = domhelpers.findElementsWithAttribute(document, "class", "note") - notePrefix = microdom.parseString('Note: ').documentElement - for note in notes: - note.childNodes.insert(0, notePrefix) - - - -def compareMarkPos(a, b): - """ - Perform in every way identically to L{cmp} for valid inputs. - - XXX - replace this with L{cmp} - """ - linecmp = cmp(a[0], b[0]) - if linecmp: - return linecmp - return cmp(a[1], b[1]) - - - -def comparePosition(firstElement, secondElement): - """ - Compare the two elements given by their position in the document or - documents they were parsed from. - - @type firstElement: C{twisted.web.microdom.Element} - @type secondElement: C{twisted.web.microdom.Element} - - @return: C{-1}, C{0}, or C{1}, with the same meanings as the return value - of L{cmp}. - """ - return compareMarkPos(firstElement._markpos, secondElement._markpos) - - - -def findNodeJustBefore(target, nodes): - """ - Find the node in C{nodes} which appeared immediately before C{target} in - the input document. - - @type target: L{twisted.web.microdom.Element} - @type nodes: C{list} of L{twisted.web.microdom.Element} - @return: An element from C{nodes} - """ - result = None - for node in nodes: - if comparePosition(target, node) < 0: - return result - result = node - return result - - - -def getFirstAncestorWithSectionHeader(entry): - """ - Visit the ancestors of C{entry} until one with at least one C{h2} child - node is found, then return all of that node's C{h2} child nodes. - - @type entry: A DOM Node - @param entry: The node from which to begin traversal. This node itself is - excluded from consideration. - - @rtype: C{list} of DOM Nodes - @return: All C{h2} nodes of the ultimately selected parent node. - """ - for a in domhelpers.getParents(entry)[1:]: - headers = domhelpers.findNodesNamed(a, "h2") - if len(headers) > 0: - return headers - return [] - - - -def getSectionNumber(header): - """ - Retrieve the section number of the given node. - - @type header: A DOM Node or L{None} - @param header: The section from which to extract a number. The section - number is the value of this node's first child. - - @return: C{None} or a C{str} giving the section number. - """ - if not header: - return None - return header.childNodes[0].value.strip() - - - -def getSectionReference(entry): - """ - Find the section number which contains the given node. - - This function looks at the given node's ancestry until it finds a node - which defines a section, then returns that section's number. - - @type entry: A DOM Node - @param entry: The node for which to determine the section. - - @rtype: C{str} - @return: The section number, as returned by C{getSectionNumber} of the - first ancestor of C{entry} which defines a section, as determined by - L{getFirstAncestorWithSectionHeader}. - """ - headers = getFirstAncestorWithSectionHeader(entry) - myHeader = findNodeJustBefore(entry, headers) - return getSectionNumber(myHeader) - - - -def index(document, filename, chapterReference): - """ - Extract index entries from the given document and store them for later use - and insert named anchors so that the index can link back to those entries. - - Any node with a C{class} attribute set to C{index} is considered an index - entry. - - @type document: A DOM Node or Document - @param document: The input document which contains all of the content to be - presented. - - @type filename: C{str} - @param filename: A link to the output for the given document which will be - included in the index to link to any index entry found here. - - @type chapterReference: ??? - @param chapterReference: ??? - - @return: C{None} - """ - entries = domhelpers.findElementsWithAttribute(document, "class", "index") - if not entries: - return - i = 0; - for entry in entries: - i += 1 - anchor = 'index%02d' % i - if chapterReference: - ref = getSectionReference(entry) or chapterReference - else: - ref = 'link' - indexer.addEntry(filename, anchor, entry.attributes['value'], ref) - # does nodeName even affect anything? - entry.nodeName = entry.tagName = entry.endTagName = 'a' - entry.attributes = InsensitiveDict({'name': anchor}) - - - -def setIndexLink(template, indexFilename): - """ - Insert a link to an index document. - - Any node with a C{class} attribute set to C{index-link} will have its tag - name changed to C{a} and its C{href} attribute set to C{indexFilename}. - - @type template: A DOM Node or Document - @param template: The output template which defines the presentation of the - version information. - - @type indexFilename: C{str} - @param indexFilename: The address of the index document to which to link. - If any C{False} value, this function will remove all index-link nodes. - - @return: C{None} - """ - indexLinks = domhelpers.findElementsWithAttribute(template, - "class", - "index-link") - for link in indexLinks: - if indexFilename is None: - link.parentNode.removeChild(link) - else: - link.nodeName = link.tagName = link.endTagName = 'a' - link.attributes = InsensitiveDict({'href': indexFilename}) - - - -def numberDocument(document, chapterNumber): - """ - Number the sections of the given document. - - A dot-separated chapter, section number is added to the beginning of each - section, as defined by C{h2} nodes. - - @type document: A DOM Node or Document - @param document: The input document which contains all of the content to be - presented. - - @type chapterNumber: C{int} - @param chapterNumber: The chapter number of this content in an overall - document. - - @return: C{None} - """ - i = 1 - for node in domhelpers.findNodesNamed(document, "h2"): - node.childNodes = [microdom.Text("%s.%d " % (chapterNumber, i))] + node.childNodes - i += 1 - - - -def fixRelativeLinks(document, linkrel): - """ - Replace relative links in C{str} and C{href} attributes with links relative - to C{linkrel}. - - @type document: A DOM Node or Document - @param document: The output template. - - @type linkrel: C{str} - @param linkrel: An prefix to apply to all relative links in C{src} or - C{href} attributes in the input document when generating the output - document. - """ - for attr in 'src', 'href': - for node in domhelpers.findElementsWithAttribute(document, attr): - href = node.getAttribute(attr) - if not href.startswith('http') and not href.startswith('/'): - node.setAttribute(attr, linkrel+node.getAttribute(attr)) - - - -def setTitle(template, title, chapterNumber): - """ - Add title and chapter number information to the template document. - - The title is added to the end of the first C{title} tag and the end of the - first tag with a C{class} attribute set to C{title}. If specified, the - chapter is inserted before the title. - - @type template: A DOM Node or Document - @param template: The output template which defines the presentation of the - version information. - - @type title: C{list} of DOM Nodes - @param title: Nodes from the input document defining its title. - - @type chapterNumber: C{int} - @param chapterNumber: The chapter number of this content in an overall - document. If not applicable, any C{False} value will result in this - information being omitted. - - @return: C{None} - """ - for nodeList in (domhelpers.findNodesNamed(template, "title"), - domhelpers.findElementsWithAttribute(template, "class", - 'title')): - if nodeList: - if numberer.getNumberSections() and chapterNumber: - nodeList[0].childNodes.append(microdom.Text('%s. ' % chapterNumber)) - nodeList[0].childNodes.extend(title) - - - -def setAuthors(template, authors): - """ - Add author information to the template document. - - Names and contact information for authors are added to each node with a - C{class} attribute set to C{authors} and to the template head as C{link} - nodes. - - @type template: A DOM Node or Document - @param template: The output template which defines the presentation of the - version information. - - @type authors: C{list} of two-tuples of C{str} - @param authors: List of names and contact information for the authors of - the input document. - - @return: C{None} - """ - # First, similarly to setTitle, insert text into an
                  - text = '' - for name, href in authors: - # FIXME: Do proper quoting/escaping (is it ok to use - # xml.sax.saxutils.{escape,quoteattr}?) - anchor = '%s' % (href, name) - if (name, href) == authors[-1]: - if len(authors) == 1: - text = anchor - else: - text += 'and ' + anchor - else: - text += anchor + ',' - - childNodes = microdom.parseString('' + text +'').childNodes - - for node in domhelpers.findElementsWithAttribute(template, - "class", 'authors'): - node.childNodes.extend(childNodes) - - # Second, add appropriate tags to the . - head = domhelpers.findNodesNamed(template, 'head')[0] - authors = [microdom.parseString('' - % (href, name)).childNodes[0] - for name, href in authors] - head.childNodes.extend(authors) - - - -def setVersion(template, version): - """ - Add a version indicator to the given template. - - @type template: A DOM Node or Document - @param template: The output template which defines the presentation of the - version information. - - @type version: C{str} - @param version: The version string to add to the template. - - @return: C{None} - """ - for node in domhelpers.findElementsWithAttribute(template, "class", - "version"): - node.appendChild(microdom.Text(version)) - - - -def getOutputFileName(originalFileName, outputExtension, index=None): - """ - Return a filename which is the same as C{originalFileName} except for the - extension, which is replaced with C{outputExtension}. - - For example, if C{originalFileName} is C{'/foo/bar.baz'} and - C{outputExtension} is C{'quux'}, the return value will be - C{'/foo/bar.quux'}. - - @type originalFileName: C{str} - @type outputExtension: C{stR} - @param index: ignored, never passed. - @rtype: C{str} - """ - return os.path.splitext(originalFileName)[0]+outputExtension - - - -def munge(document, template, linkrel, dir, fullpath, ext, url, config, outfileGenerator=getOutputFileName): - """ - Mutate C{template} until it resembles C{document}. - - @type document: A DOM Node or Document - @param document: The input document which contains all of the content to be - presented. - - @type template: A DOM Node or Document - @param template: The template document which defines the desired - presentation format of the content. - - @type linkrel: C{str} - @param linkrel: An prefix to apply to all relative links in C{src} or - C{href} attributes in the input document when generating the output - document. - - @type dir: C{str} - @param dir: The directory in which to search for source listing files. - - @type fullpath: C{str} - @param fullpath: The file name which contained the input document. - - @type ext: C{str} - @param ext: The extension to use when selecting an output file name. This - replaces the extension of the input file name. - - @type url: C{str} - @param url: A string which will be interpolated with the fully qualified - Python name of any API reference encountered in the input document, the - result of which will be used as a link to API documentation for that name - in the output document. - - @type config: C{dict} - @param config: Further specification of the desired form of the output. - Valid keys in this dictionary:: - - noapi: If present and set to a True value, links to API documentation - will not be generated. - - version: A string which will be included in the output to indicate the - version of this documentation. - - @type outfileGenerator: Callable of C{str}, C{str} returning C{str} - @param outfileGenerator: Output filename factory. This is invoked with the - intput filename and C{ext} and the output document is serialized to the - file with the name returned. - - @return: C{None} - """ - fixRelativeLinks(template, linkrel) - addMtime(template, fullpath) - removeH1(document) - if not config.get('noapi', False): - fixAPI(document, url) - fontifyPython(document) - fixLinks(document, ext) - addPyListings(document, dir) - addHTMLListings(document, dir) - addPlainListings(document, dir) - putInToC(template, generateToC(document)) - footnotes(document) - notes(document) - - setIndexLink(template, indexer.getIndexFilename()) - setVersion(template, config.get('version', '')) - - # Insert the document into the template - chapterNumber = htmlbook.getNumber(fullpath) - title = domhelpers.findNodesNamed(document, 'title')[0].childNodes - setTitle(template, title, chapterNumber) - if numberer.getNumberSections() and chapterNumber: - numberDocument(document, chapterNumber) - index(document, outfileGenerator(os.path.split(fullpath)[1], ext), - htmlbook.getReference(fullpath)) - - authors = domhelpers.findNodesNamed(document, 'link') - authors = [(node.getAttribute('title',''), node.getAttribute('href', '')) - for node in authors if node.getAttribute('rel', '') == 'author'] - setAuthors(template, authors) - - body = domhelpers.findNodesNamed(document, "body")[0] - tmplbody = domhelpers.findElementsWithAttribute(template, "class", - "body")[0] - tmplbody.childNodes = body.childNodes - tmplbody.setAttribute("class", "content") - - -def parseFileAndReport(filename): - """ - Parse and return the contents of the given lore XHTML document. - - @type filename: C{str} - @param filename: The name of a file containing a lore XHTML document to - load. - - @raise process.ProcessingFailure: When the contents of the specified file - cannot be parsed. - - @rtype: A DOM Document - @return: The document contained in C{filename}. - """ - try: - return microdom.parse(open(filename)) - except microdom.MismatchedTags, e: - raise process.ProcessingFailure( - "%s:%s: begin mismatched tags <%s>/" % - (e.begLine, e.begCol, e.got, e.expect), - "%s:%s: end mismatched tags <%s>/" % - (e.endLine, e.endCol, e.got, e.expect)) - except microdom.ParseError, e: - raise process.ProcessingFailure("%s:%s:%s" % (e.line, e.col, e.message)) - except IOError, e: - raise process.ProcessingFailure(e.strerror + ", filename was '" + filename + "'") - -def makeSureDirectoryExists(filename): - filename = os.path.abspath(filename) - dirname = os.path.dirname(filename) - if (not os.path.exists(dirname)): - os.makedirs(dirname) - -def doFile(filename, linkrel, ext, url, templ, options={}, outfileGenerator=getOutputFileName): - """ - Process the input document at C{filename} and write an output document. - - @type filename: C{str} - @param filename: The path to the input file which will be processed. - - @type linkrel: C{str} - @param linkrel: An prefix to apply to all relative links in C{src} or - C{href} attributes in the input document when generating the output - document. - - @type ext: C{str} - @param ext: The extension to use when selecting an output file name. This - replaces the extension of the input file name. - - @type url: C{str} - @param url: A string which will be interpolated with the fully qualified - Python name of any API reference encountered in the input document, the - result of which will be used as a link to API documentation for that name - in the output document. - - @type templ: A DOM Node or Document - @param templ: The template on which the output document will be based. - This is mutated and then serialized to the output file. - - @type options: C{dict} - @param options: Further specification of the desired form of the output. - Valid keys in this dictionary:: - - noapi: If present and set to a True value, links to API documentation - will not be generated. - - version: A string which will be included in the output to indicate the - version of this documentation. - - @type outfileGenerator: Callable of C{str}, C{str} returning C{str} - @param outfileGenerator: Output filename factory. This is invoked with the - intput filename and C{ext} and the output document is serialized to the - file with the name returned. - - @return: C{None} - """ - doc = parseFileAndReport(filename) - clonedNode = templ.cloneNode(1) - munge(doc, clonedNode, linkrel, os.path.dirname(filename), filename, ext, - url, options, outfileGenerator) - newFilename = outfileGenerator(filename, ext) - makeSureDirectoryExists(newFilename) - clonedNode.writexml(open(newFilename, 'wb')) diff --git a/tools/buildbot/pylibs/twisted/mail/__init__.py b/tools/buildbot/pylibs/twisted/mail/__init__.py deleted file mode 100644 index 628b727..0000000 --- a/tools/buildbot/pylibs/twisted/mail/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" - -Twisted Mail: a Twisted E-Mail Server. - -Maintainer: U{Jp Calderone} - -""" - -from twisted.mail._version import version -__version__ = version.short() diff --git a/tools/buildbot/pylibs/twisted/mail/_version.py b/tools/buildbot/pylibs/twisted/mail/_version.py deleted file mode 100644 index 7398f41..0000000 --- a/tools/buildbot/pylibs/twisted/mail/_version.py +++ /dev/null @@ -1,3 +0,0 @@ -# This is an auto-generated file. Do not edit it. -from twisted.python import versions -version = versions.Version('twisted.mail', 8, 1, 0) diff --git a/tools/buildbot/pylibs/twisted/mail/alias.py b/tools/buildbot/pylibs/twisted/mail/alias.py deleted file mode 100644 index 4005c74..0000000 --- a/tools/buildbot/pylibs/twisted/mail/alias.py +++ /dev/null @@ -1,435 +0,0 @@ -# -*- test-case-name: twisted.mail.test.test_mail -*- -# -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Support for aliases(5) configuration files - -@author: U{Jp Calderone} - -TODO:: - Monitor files for reparsing - Handle non-local alias targets - Handle maildir alias targets -""" - -import os -import tempfile - -from twisted.mail import smtp -from twisted.internet import reactor -from twisted.internet import protocol -from twisted.internet import defer -from twisted.python import failure -from twisted.python import log -from zope.interface import implements, Interface - - -def handle(result, line, filename, lineNo): - parts = [p.strip() for p in line.split(':', 1)] - if len(parts) != 2: - fmt = "Invalid format on line %d of alias file %s." - arg = (lineNo, filename) - log.err(fmt % arg) - else: - user, alias = parts - result.setdefault(user.strip(), []).extend(map(str.strip, alias.split(','))) - -def loadAliasFile(domains, filename=None, fp=None): - """Load a file containing email aliases. - - Lines in the file should be formatted like so:: - - username: alias1,alias2,...,aliasN - - Aliases beginning with a | will be treated as programs, will be run, and - the message will be written to their stdin. - - Aliases without a host part will be assumed to be addresses on localhost. - - If a username is specified multiple times, the aliases for each are joined - together as if they had all been on one line. - - @type domains: C{dict} of implementor of C{IDomain} - @param domains: The domains to which these aliases will belong. - - @type filename: C{str} - @param filename: The filename from which to load aliases. - - @type fp: Any file-like object. - @param fp: If specified, overrides C{filename}, and aliases are read from - it. - - @rtype: C{dict} - @return: A dictionary mapping usernames to C{AliasGroup} objects. - """ - result = {} - if fp is None: - fp = file(filename) - else: - filename = getattr(fp, 'name', '') - i = 0 - prev = '' - for line in fp: - i += 1 - line = line.rstrip() - if line.lstrip().startswith('#'): - continue - elif line.startswith(' ') or line.startswith('\t'): - prev = prev + line - else: - if prev: - handle(result, prev, filename, i) - prev = line - if prev: - handle(result, prev, filename, i) - for (u, a) in result.items(): - addr = smtp.Address(u) - result[u] = AliasGroup(a, domains, u) - return result - -class IAlias(Interface): - def createMessageReceiver(): - pass - -class AliasBase: - def __init__(self, domains, original): - self.domains = domains - self.original = smtp.Address(original) - - def domain(self): - return self.domains[self.original.domain] - - def resolve(self, aliasmap, memo=None): - if memo is None: - memo = {} - if str(self) in memo: - return None - memo[str(self)] = None - return self.createMessageReceiver() - -class AddressAlias(AliasBase): - """The simplest alias, translating one email address into another.""" - - implements(IAlias) - - def __init__(self, alias, *args): - AliasBase.__init__(self, *args) - self.alias = smtp.Address(alias) - - def __str__(self): - return '
                  ' % (self.alias,) - - def createMessageReceiver(self): - return self.domain().startMessage(str(self.alias)) - - def resolve(self, aliasmap, memo=None): - if memo is None: - memo = {} - if str(self) in memo: - return None - memo[str(self)] = None - try: - return self.domain().exists(smtp.User(self.alias, None, None, None), memo)() - except smtp.SMTPBadRcpt: - pass - if self.alias.local in aliasmap: - return aliasmap[self.alias.local].resolve(aliasmap, memo) - return None - -class FileWrapper: - implements(smtp.IMessage) - - def __init__(self, filename): - self.fp = tempfile.TemporaryFile() - self.finalname = filename - - def lineReceived(self, line): - self.fp.write(line + '\n') - - def eomReceived(self): - self.fp.seek(0, 0) - try: - f = file(self.finalname, 'a') - except: - return defer.fail(failure.Failure()) - - f.write(self.fp.read()) - self.fp.close() - f.close() - - return defer.succeed(self.finalname) - - def connectionLost(self): - self.fp.close() - self.fp = None - - def __str__(self): - return '' % (self.finalname,) - - -class FileAlias(AliasBase): - - implements(IAlias) - - def __init__(self, filename, *args): - AliasBase.__init__(self, *args) - self.filename = filename - - def __str__(self): - return '' % (self.filename,) - - def createMessageReceiver(self): - return FileWrapper(self.filename) - - - -class ProcessAliasTimeout(Exception): - """ - A timeout occurred while processing aliases. - """ - - - -class MessageWrapper: - """ - A message receiver which delivers content to a child process. - - @type completionTimeout: C{int} or C{float} - @ivar completionTimeout: The number of seconds to wait for the child - process to exit before reporting the delivery as a failure. - - @type _timeoutCallID: C{NoneType} or L{IDelayedCall} - @ivar _timeoutCallID: The call used to time out delivery, started when the - connection to the child process is closed. - - @type done: C{bool} - @ivar done: Flag indicating whether the child process has exited or not. - - @ivar reactor: An L{IReactorTime} provider which will be used to schedule - timeouts. - """ - implements(smtp.IMessage) - - done = False - - completionTimeout = 60 - _timeoutCallID = None - - reactor = reactor - - def __init__(self, protocol, process=None, reactor=None): - self.processName = process - self.protocol = protocol - self.completion = defer.Deferred() - self.protocol.onEnd = self.completion - self.completion.addBoth(self._processEnded) - - if reactor is not None: - self.reactor = reactor - - - def _processEnded(self, result): - """ - Record process termination and cancel the timeout call if it is active. - """ - self.done = True - if self._timeoutCallID is not None: - # eomReceived was called, we're actually waiting for the process to - # exit. - self._timeoutCallID.cancel() - self._timeoutCallID = None - else: - # eomReceived was not called, this is unexpected, propagate the - # error. - return result - - - def lineReceived(self, line): - if self.done: - return - self.protocol.transport.write(line + '\n') - - - def eomReceived(self): - """ - Disconnect from the child process, set up a timeout to wait for it to - exit, and return a Deferred which will be called back when the child - process exits. - """ - if not self.done: - self.protocol.transport.loseConnection() - self._timeoutCallID = self.reactor.callLater( - self.completionTimeout, self._completionCancel) - return self.completion - - - def _completionCancel(self): - """ - Handle the expiration of the timeout for the child process to exit by - terminating the child process forcefully and issuing a failure to the - completion deferred returned by L{eomReceived}. - """ - self._timeoutCallID = None - self.protocol.transport.signalProcess('KILL') - exc = ProcessAliasTimeout( - "No answer after %s seconds" % (self.completionTimeout,)) - self.protocol.onEnd = None - self.completion.errback(failure.Failure(exc)) - - - def connectionLost(self): - # Heh heh - pass - - - def __str__(self): - return '' % (self.processName,) - - - -class ProcessAliasProtocol(protocol.ProcessProtocol): - """ - Trivial process protocol which will callback a Deferred when the associated - process ends. - - @ivar onEnd: If not C{None}, a L{Deferred} which will be called back with - the failure passed to C{processEnded}, when C{processEnded} is called. - """ - - onEnd = None - - def processEnded(self, reason): - """ - Call back C{onEnd} if it is set. - """ - if self.onEnd is not None: - self.onEnd.errback(reason) - - - -class ProcessAlias(AliasBase): - """ - An alias which is handled by the execution of a particular program. - - @ivar reactor: An L{IReactorProcess} and L{IReactorTime} provider which - will be used to create and timeout the alias child process. - """ - implements(IAlias) - - reactor = reactor - - def __init__(self, path, *args): - AliasBase.__init__(self, *args) - self.path = path.split() - self.program = self.path[0] - - - def __str__(self): - """ - Build a string representation containing the path. - """ - return '' % (self.path,) - - - def spawnProcess(self, proto, program, path): - """ - Wrapper around C{reactor.spawnProcess}, to be customized for tests - purpose. - """ - return self.reactor.spawnProcess(proto, program, path) - - - def createMessageReceiver(self): - """ - Create a message receiver by launching a process. - """ - p = ProcessAliasProtocol() - m = MessageWrapper(p, self.program, self.reactor) - fd = self.spawnProcess(p, self.program, self.path) - return m - - - -class MultiWrapper: - """ - Wrapper to deliver a single message to multiple recipients. - """ - - implements(smtp.IMessage) - - def __init__(self, objs): - self.objs = objs - - def lineReceived(self, line): - for o in self.objs: - o.lineReceived(line) - - def eomReceived(self): - return defer.DeferredList([ - o.eomReceived() for o in self.objs - ]) - - def connectionLost(self): - for o in self.objs: - o.connectionLost() - - def __str__(self): - return '' % (map(str, self.objs),) - - - -class AliasGroup(AliasBase): - """ - An alias which points to more than one recipient. - - @ivar processAliasFactory: a factory for resolving process aliases. - @type processAliasFactory: C{class} - """ - - implements(IAlias) - - processAliasFactory = ProcessAlias - - def __init__(self, items, *args): - AliasBase.__init__(self, *args) - self.aliases = [] - while items: - addr = items.pop().strip() - if addr.startswith(':'): - try: - f = file(addr[1:]) - except: - log.err("Invalid filename in alias file %r" % (addr[1:],)) - else: - addr = ' '.join([l.strip() for l in f]) - items.extend(addr.split(',')) - elif addr.startswith('|'): - self.aliases.append(self.processAliasFactory(addr[1:], *args)) - elif addr.startswith('/'): - if os.path.isdir(addr): - log.err("Directory delivery not supported") - else: - self.aliases.append(FileAlias(addr, *args)) - else: - self.aliases.append(AddressAlias(addr, *args)) - - def __len__(self): - return len(self.aliases) - - def __str__(self): - return '' % (', '.join(map(str, self.aliases))) - - def createMessageReceiver(self): - return MultiWrapper([a.createMessageReceiver() for a in self.aliases]) - - def resolve(self, aliasmap, memo=None): - if memo is None: - memo = {} - r = [] - for a in self.aliases: - r.append(a.resolve(aliasmap, memo)) - return MultiWrapper(filter(None, r)) - diff --git a/tools/buildbot/pylibs/twisted/mail/bounce.py b/tools/buildbot/pylibs/twisted/mail/bounce.py deleted file mode 100644 index d57c495..0000000 --- a/tools/buildbot/pylibs/twisted/mail/bounce.py +++ /dev/null @@ -1,61 +0,0 @@ -# -*- test-case-name: twisted.mail.test.test_bounce -*- -# -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -import StringIO -import rfc822 -import string -import time -import os - - -from twisted.mail import smtp - -BOUNCE_FORMAT = """\ -From: postmaster@%(failedDomain)s -To: %(failedFrom)s -Subject: Returned Mail: see transcript for details -Message-ID: %(messageID)s -Content-Type: multipart/report; report-type=delivery-status; - boundary="%(boundary)s" - ---%(boundary)s - -%(transcript)s - ---%(boundary)s -Content-Type: message/delivery-status -Arrival-Date: %(ctime)s -Final-Recipient: RFC822; %(failedTo)s -""" - -def generateBounce(message, failedFrom, failedTo, transcript=''): - if not transcript: - transcript = '''\ -I'm sorry, the following address has permanent errors: %(failedTo)s. -I've given up, and I will not retry the message again. -''' % vars() - - boundary = "%s_%s_%s" % (time.time(), os.getpid(), 'XXXXX') - failedAddress = rfc822.AddressList(failedTo)[0][1] - failedDomain = string.split(failedAddress, '@', 1)[1] - messageID = smtp.messageid(uniq='bounce') - ctime = time.ctime(time.time()) - - fp = StringIO.StringIO() - fp.write(BOUNCE_FORMAT % vars()) - orig = message.tell() - message.seek(2, 0) - sz = message.tell() - message.seek(0, orig) - if sz > 10000: - while 1: - line = message.readline() - if len(line)<=1: - break - fp.write(line) - else: - fp.write(message.read()) - return '', failedFrom, fp.getvalue() diff --git a/tools/buildbot/pylibs/twisted/mail/imap4.py b/tools/buildbot/pylibs/twisted/mail/imap4.py deleted file mode 100644 index bb3a156..0000000 --- a/tools/buildbot/pylibs/twisted/mail/imap4.py +++ /dev/null @@ -1,5490 +0,0 @@ -# -*- test-case-name: twisted.mail.test.test_imap -*- -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -An IMAP4 protocol implementation - -@author: U{Jp Calderone} - -To do:: - Suspend idle timeout while server is processing - Use an async message parser instead of buffering in memory - Figure out a way to not queue multi-message client requests (Flow? A simple callback?) - Clarify some API docs (Query, etc) - Make APPEND recognize (again) non-existent mailboxes before accepting the literal -""" - -import rfc822 -import base64 -import binascii -import hmac -import re -import tempfile -import string -import time -import random -import types - -import email.Utils - -try: - import cStringIO as StringIO -except: - import StringIO - -from zope.interface import implements, Interface - -from twisted.protocols import basic -from twisted.protocols import policies -from twisted.internet import defer -from twisted.internet import error -from twisted.internet.defer import maybeDeferred -from twisted.python import log, text -from twisted.internet import interfaces - -from twisted import cred -import twisted.cred.error -import twisted.cred.credentials - -class MessageSet(object): - """ - Essentially an infinite bitfield, with some extra features. - - @type getnext: Function taking C{int} returning C{int} - @ivar getnext: A function that returns the next message number, - used when iterating through the MessageSet. By default, a function - returning the next integer is supplied, but as this can be rather - inefficient for sparse UID iterations, it is recommended to supply - one when messages are requested by UID. The argument is provided - as a hint to the implementation and may be ignored if it makes sense - to do so (eg, if an iterator is being used that maintains its own - state, it is guaranteed that it will not be called out-of-order). - """ - _empty = [] - - def __init__(self, start=_empty, end=_empty): - """ - Create a new MessageSet() - - @type start: Optional C{int} - @param start: Start of range, or only message number - - @type end: Optional C{int} - @param end: End of range. - """ - self._last = self._empty # Last message/UID in use - self.ranges = [] # List of ranges included - self.getnext = lambda x: x+1 # A function which will return the next - # message id. Handy for UID requests. - - if start is self._empty: - return - - if isinstance(start, types.ListType): - self.ranges = start[:] - self.clean() - else: - self.add(start,end) - - # Ooo. A property. - def last(): - def _setLast(self,value): - if self._last is not self._empty: - raise ValueError("last already set") - - self._last = value - for i,(l,h) in enumerate(self.ranges): - if l is not None: - break # There are no more Nones after this - l = value - if h is None: - h = value - if l > h: - l, h = h, l - self.ranges[i] = (l,h) - - self.clean() - - def _getLast(self): - return self._last - - doc = ''' - "Highest" message number, refered to by "*". - Must be set before attempting to use the MessageSet. - ''' - return _getLast, _setLast, None, doc - last = property(*last()) - - def add(self, start, end=_empty): - """ - Add another range - - @type start: C{int} - @param start: Start of range, or only message number - - @type end: Optional C{int} - @param end: End of range. - """ - if end is self._empty: - end = start - - if self._last is not self._empty: - if start is None: - start = self.last - if end is None: - end = self.last - - if start > end: - # Try to keep in low, high order if possible - # (But we don't know what None means, this will keep - # None at the start of the ranges list) - start, end = end, start - - self.ranges.append((start,end)) - self.clean() - - def __add__(self, other): - if isinstance(other, MessageSet): - ranges = self.ranges + other.ranges - return MessageSet(ranges) - else: - res = MessageSet(self.ranges) - try: - res.add(*other) - except TypeError: - res.add(other) - return res - - def extend(self, other): - if isinstance(other, MessageSet): - self.ranges.extend(other.ranges) - self.clean() - else: - try: - self.add(*other) - except TypeError: - self.add(other) - - return self - - def clean(self): - """ - Clean ranges list, combining adjacent ranges - """ - - self.ranges.sort() - - oldl, oldh = None, None - for i,(l,h) in enumerate(self.ranges): - if l is None: - continue - # l is >= oldl and h is >= oldh due to sort() - if oldl is not None and l <= oldh+1: - l = oldl - h = max(oldh,h) - self.ranges[i-1] = None - self.ranges[i] = (l,h) - - oldl,oldh = l,h - - self.ranges = filter(None, self.ranges) - - def __contains__(self, value): - """ - May raise TypeError if we encounter unknown "high" values - """ - for l,h in self.ranges: - if l is None: - raise TypeError( - "Can't determine membership; last value not set") - if l <= value <= h: - return True - - return False - - def _iterator(self): - for l,h in self.ranges: - l = self.getnext(l-1) - while l <= h: - yield l - l = self.getnext(l) - if l is None: - break - - def __iter__(self): - if self.ranges and self.ranges[0][0] is None: - raise TypeError("Can't iterate; last value not set") - - return self._iterator() - - def __len__(self): - res = 0 - for l, h in self.ranges: - if l is None: - raise TypeError("Can't size object; last value not set") - res += (h - l) + 1 - - return res - - def __str__(self): - p = [] - for low, high in self.ranges: - if low == high: - if low is None: - p.append('*') - else: - p.append(str(low)) - elif low is None: - p.append('%d:*' % (high,)) - else: - p.append('%d:%d' % (low, high)) - return ','.join(p) - - def __repr__(self): - return '' % (str(self),) - - def __eq__(self, other): - if isinstance(other, MessageSet): - return self.ranges == other.ranges - return False - - -class LiteralString: - def __init__(self, size, defered): - self.size = size - self.data = [] - self.defer = defered - - def write(self, data): - self.size -= len(data) - passon = None - if self.size > 0: - self.data.append(data) - else: - if self.size: - data, passon = data[:self.size], data[self.size:] - else: - passon = '' - if data: - self.data.append(data) - return passon - - def callback(self, line): - """ - Call defered with data and rest of line - """ - self.defer.callback((''.join(self.data), line)) - -class LiteralFile: - _memoryFileLimit = 1024 * 1024 * 10 - - def __init__(self, size, defered): - self.size = size - self.defer = defered - if size > self._memoryFileLimit: - self.data = tempfile.TemporaryFile() - else: - self.data = StringIO.StringIO() - - def write(self, data): - self.size -= len(data) - passon = None - if self.size > 0: - self.data.write(data) - else: - if self.size: - data, passon = data[:self.size], data[self.size:] - else: - passon = '' - if data: - self.data.write(data) - return passon - - def callback(self, line): - """ - Call defered with data and rest of line - """ - self.data.seek(0,0) - self.defer.callback((self.data, line)) - - -class WriteBuffer: - """Buffer up a bunch of writes before sending them all to a transport at once. - """ - def __init__(self, transport, size=8192): - self.bufferSize = size - self.transport = transport - self._length = 0 - self._writes = [] - - def write(self, s): - self._length += len(s) - self._writes.append(s) - if self._length > self.bufferSize: - self.flush() - - def flush(self): - if self._writes: - self.transport.writeSequence(self._writes) - self._writes = [] - self._length = 0 - - -class Command: - _1_RESPONSES = ('CAPABILITY', 'FLAGS', 'LIST', 'LSUB', 'STATUS', 'SEARCH', 'NAMESPACE') - _2_RESPONSES = ('EXISTS', 'EXPUNGE', 'FETCH', 'RECENT') - _OK_RESPONSES = ('UIDVALIDITY', 'READ-WRITE', 'READ-ONLY', 'UIDNEXT', 'PERMANENTFLAGS') - defer = None - - def __init__(self, command, args=None, wantResponse=(), - continuation=None, *contArgs, **contKw): - self.command = command - self.args = args - self.wantResponse = wantResponse - self.continuation = lambda x: continuation(x, *contArgs, **contKw) - self.lines = [] - - def format(self, tag): - if self.args is None: - return ' '.join((tag, self.command)) - return ' '.join((tag, self.command, self.args)) - - def finish(self, lastLine, unusedCallback): - send = [] - unuse = [] - for L in self.lines: - names = parseNestedParens(L) - N = len(names) - if (N >= 1 and names[0] in self._1_RESPONSES or - N >= 2 and names[0] == 'OK' and isinstance(names[1], types.ListType) and names[1][0] in self._OK_RESPONSES): - send.append(L) - elif N >= 3 and names[1] in self._2_RESPONSES: - if isinstance(names[2], list) and len(names[2]) >= 1 and names[2][0] == 'FLAGS' and 'FLAGS' not in self.args: - unuse.append(L) - else: - send.append(L) - elif N >= 2 and names[1] in self._2_RESPONSES: - send.append(L) - else: - unuse.append(L) - d, self.defer = self.defer, None - d.callback((send, lastLine)) - if unuse: - unusedCallback(unuse) - -class LOGINCredentials(cred.credentials.UsernamePassword): - def __init__(self): - self.challenges = ['Password\0', 'User Name\0'] - self.responses = ['password', 'username'] - cred.credentials.UsernamePassword.__init__(self, None, None) - - def getChallenge(self): - return self.challenges.pop() - - def setResponse(self, response): - setattr(self, self.responses.pop(), response) - - def moreChallenges(self): - return bool(self.challenges) - -class PLAINCredentials(cred.credentials.UsernamePassword): - def __init__(self): - cred.credentials.UsernamePassword.__init__(self, None, None) - - def getChallenge(self): - return '' - - def setResponse(self, response): - parts = response[:-1].split('\0', 1) - if len(parts) != 2: - raise IllegalClientResponse("Malformed Response - wrong number of parts") - self.username, self.password = parts - - def moreChallenges(self): - return False - -class IMAP4Exception(Exception): - def __init__(self, *args): - Exception.__init__(self, *args) - -class IllegalClientResponse(IMAP4Exception): pass - -class IllegalOperation(IMAP4Exception): pass - -class IllegalMailboxEncoding(IMAP4Exception): pass - -class IMailboxListener(Interface): - """Interface for objects interested in mailbox events""" - - def modeChanged(writeable): - """Indicates that the write status of a mailbox has changed. - - @type writeable: C{bool} - @param writeable: A true value if write is now allowed, false - otherwise. - """ - - def flagsChanged(newFlags): - """Indicates that the flags of one or more messages have changed. - - @type newFlags: C{dict} - @param newFlags: A mapping of message identifiers to tuples of flags - now set on that message. - """ - - def newMessages(exists, recent): - """Indicates that the number of messages in a mailbox has changed. - - @type exists: C{int} or C{None} - @param exists: The total number of messages now in this mailbox. - If the total number of messages has not changed, this should be - C{None}. - - @type recent: C{int} - @param recent: The number of messages now flagged \\Recent. - If the number of recent messages has not changed, this should be - C{None}. - """ - -class IMAP4Server(basic.LineReceiver, policies.TimeoutMixin): - """ - Protocol implementation for an IMAP4rev1 server. - - The server can be in any of four states: - - Non-authenticated - - Authenticated - - Selected - - Logout - """ - implements(IMailboxListener) - - # Identifier for this server software - IDENT = 'Twisted IMAP4rev1 Ready' - - # Number of seconds before idle timeout - # Initially 1 minute. Raised to 30 minutes after login. - timeOut = 60 - - POSTAUTH_TIMEOUT = 60 * 30 - - # Whether STARTTLS has been issued successfully yet or not. - startedTLS = False - - # Whether our transport supports TLS - canStartTLS = False - - # Mapping of tags to commands we have received - tags = None - - # The object which will handle logins for us - portal = None - - # The account object for this connection - account = None - - # Logout callback - _onLogout = None - - # The currently selected mailbox - mbox = None - - # Command data to be processed when literal data is received - _pendingLiteral = None - - # Maximum length to accept for a "short" string literal - _literalStringLimit = 4096 - - # IChallengeResponse factories for AUTHENTICATE command - challengers = None - - state = 'unauth' - - parseState = 'command' - - def __init__(self, chal = None, contextFactory = None, scheduler = None): - if chal is None: - chal = {} - self.challengers = chal - self.ctx = contextFactory - if scheduler is None: - scheduler = iterateInReactor - self._scheduler = scheduler - self._queuedAsync = [] - - def capabilities(self): - cap = {'AUTH': self.challengers.keys()} - if self.ctx and self.canStartTLS: - if not self.startedTLS and interfaces.ISSLTransport(self.transport, None) is None: - cap['LOGINDISABLED'] = None - cap['STARTTLS'] = None - cap['NAMESPACE'] = None - cap['IDLE'] = None - return cap - - def connectionMade(self): - self.tags = {} - self.canStartTLS = interfaces.ITLSTransport(self.transport, None) is not None - self.setTimeout(self.timeOut) - self.sendServerGreeting() - - def connectionLost(self, reason): - self.setTimeout(None) - if self._onLogout: - self._onLogout() - self._onLogout = None - - def timeoutConnection(self): - self.sendLine('* BYE Autologout; connection idle too long') - self.transport.loseConnection() - if self.mbox: - self.mbox.removeListener(self) - cmbx = ICloseableMailbox(self.mbox, None) - if cmbx is not None: - maybeDeferred(cmbx.close).addErrback(log.err) - self.mbox = None - self.state = 'timeout' - - def rawDataReceived(self, data): - self.resetTimeout() - passon = self._pendingLiteral.write(data) - if passon is not None: - self.setLineMode(passon) - - # Avoid processing commands while buffers are being dumped to - # our transport - blocked = None - - def _unblock(self): - commands = self.blocked - self.blocked = None - while commands and self.blocked is None: - self.lineReceived(commands.pop(0)) - if self.blocked is not None: - self.blocked.extend(commands) - -# def sendLine(self, line): -# print 'C:', repr(line) -# return basic.LineReceiver.sendLine(self, line) - - def lineReceived(self, line): -# print 'S:', repr(line) - if self.blocked is not None: - self.blocked.append(line) - return - - self.resetTimeout() - - f = getattr(self, 'parse_' + self.parseState) - try: - f(line) - except Exception, e: - self.sendUntaggedResponse('BAD Server error: ' + str(e)) - log.err() - - def parse_command(self, line): - args = line.split(None, 2) - rest = None - if len(args) == 3: - tag, cmd, rest = args - elif len(args) == 2: - tag, cmd = args - elif len(args) == 1: - tag = args[0] - self.sendBadResponse(tag, 'Missing command') - return None - else: - self.sendBadResponse(None, 'Null command') - return None - - cmd = cmd.upper() - try: - return self.dispatchCommand(tag, cmd, rest) - except IllegalClientResponse, e: - self.sendBadResponse(tag, 'Illegal syntax: ' + str(e)) - except IllegalOperation, e: - self.sendNegativeResponse(tag, 'Illegal operation: ' + str(e)) - except IllegalMailboxEncoding, e: - self.sendNegativeResponse(tag, 'Illegal mailbox name: ' + str(e)) - - def parse_pending(self, line): - d = self._pendingLiteral - self._pendingLiteral = None - self.parseState = 'command' - d.callback(line) - - def dispatchCommand(self, tag, cmd, rest, uid=None): - f = self.lookupCommand(cmd) - if f: - fn = f[0] - parseargs = f[1:] - self.__doCommand(tag, fn, [self, tag], parseargs, rest, uid) - else: - self.sendBadResponse(tag, 'Unsupported command') - - def lookupCommand(self, cmd): - return getattr(self, '_'.join((self.state, cmd.upper())), None) - - def __doCommand(self, tag, handler, args, parseargs, line, uid): - for (i, arg) in enumerate(parseargs): - if callable(arg): - parseargs = parseargs[i+1:] - maybeDeferred(arg, self, line).addCallback( - self.__cbDispatch, tag, handler, args, - parseargs, uid).addErrback(self.__ebDispatch, tag) - return - else: - args.append(arg) - - if line: - # Too many arguments - raise IllegalClientResponse("Too many arguments for command: " + repr(line)) - - if uid is not None: - handler(uid=uid, *args) - else: - handler(*args) - - def __cbDispatch(self, (arg, rest), tag, fn, args, parseargs, uid): - args.append(arg) - self.__doCommand(tag, fn, args, parseargs, rest, uid) - - def __ebDispatch(self, failure, tag): - if failure.check(IllegalClientResponse): - self.sendBadResponse(tag, 'Illegal syntax: ' + str(failure.value)) - elif failure.check(IllegalOperation): - self.sendNegativeResponse(tag, 'Illegal operation: ' + - str(failure.value)) - elif failure.check(IllegalMailboxEncoding): - self.sendNegativeResponse(tag, 'Illegal mailbox name: ' + - str(failure.value)) - else: - self.sendBadResponse(tag, 'Server error: ' + str(failure.value)) - log.err(failure) - - def _stringLiteral(self, size): - if size > self._literalStringLimit: - raise IllegalClientResponse( - "Literal too long! I accept at most %d octets" % - (self._literalStringLimit,)) - d = defer.Deferred() - self.parseState = 'pending' - self._pendingLiteral = LiteralString(size, d) - self.sendContinuationRequest('Ready for %d octets of text' % size) - self.setRawMode() - return d - - def _fileLiteral(self, size): - d = defer.Deferred() - self.parseState = 'pending' - self._pendingLiteral = LiteralFile(size, d) - self.sendContinuationRequest('Ready for %d octets of data' % size) - self.setRawMode() - return d - - def arg_astring(self, line): - """ - Parse an astring from the line, return (arg, rest), possibly - via a deferred (to handle literals) - """ - line = line.strip() - if not line: - raise IllegalClientResponse("Missing argument") - d = None - arg, rest = None, None - if line[0] == '"': - try: - spam, arg, rest = line.split('"',2) - rest = rest[1:] # Strip space - except ValueError: - raise IllegalClientResponse("Unmatched quotes") - elif line[0] == '{': - # literal - if line[-1] != '}': - raise IllegalClientResponse("Malformed literal") - try: - size = int(line[1:-1]) - except ValueError: - raise IllegalClientResponse("Bad literal size: " + line[1:-1]) - d = self._stringLiteral(size) - else: - arg = line.split(' ',1) - if len(arg) == 1: - arg.append('') - arg, rest = arg - return d or (arg, rest) - - # ATOM: Any CHAR except ( ) { % * " \ ] CTL SP (CHAR is 7bit) - atomre = re.compile(r'(?P[^\](){%*"\\\x00-\x20\x80-\xff]+)( (?P.*$)|$)') - - def arg_atom(self, line): - """ - Parse an atom from the line - """ - if not line: - raise IllegalClientResponse("Missing argument") - m = self.atomre.match(line) - if m: - return m.group('atom'), m.group('rest') - else: - raise IllegalClientResponse("Malformed ATOM") - - def arg_plist(self, line): - """ - Parse a (non-nested) parenthesised list from the line - """ - if not line: - raise IllegalClientResponse("Missing argument") - - if line[0] != "(": - raise IllegalClientResponse("Missing parenthesis") - - i = line.find(")") - - if i == -1: - raise IllegalClientResponse("Mismatched parenthesis") - - return (parseNestedParens(line[1:i],0), line[i+2:]) - - def arg_literal(self, line): - """ - Parse a literal from the line - """ - if not line: - raise IllegalClientResponse("Missing argument") - - if line[0] != '{': - raise IllegalClientResponse("Missing literal") - - if line[-1] != '}': - raise IllegalClientResponse("Malformed literal") - - try: - size = int(line[1:-1]) - except ValueError: - raise IllegalClientResponse("Bad literal size: " + line[1:-1]) - - return self._fileLiteral(size) - - def arg_searchkeys(self, line): - """ - searchkeys - """ - query = parseNestedParens(line) - # XXX Should really use list of search terms and parse into - # a proper tree - - return (query, '') - - def arg_seqset(self, line): - """ - sequence-set - """ - rest = '' - arg = line.split(' ',1) - if len(arg) == 2: - rest = arg[1] - arg = arg[0] - - try: - return (parseIdList(arg), rest) - except IllegalIdentifierError, e: - raise IllegalClientResponse("Bad message number " + str(e)) - - def arg_fetchatt(self, line): - """ - fetch-att - """ - p = _FetchParser() - p.parseString(line) - return (p.result, '') - - def arg_flaglist(self, line): - """ - Flag part of store-att-flag - """ - flags = [] - if line[0] == '(': - if line[-1] != ')': - raise IllegalClientResponse("Mismatched parenthesis") - line = line[1:-1] - - while line: - m = self.atomre.search(line) - if not m: - raise IllegalClientResponse("Malformed flag") - if line[0] == '\\' and m.start() == 1: - flags.append('\\' + m.group('atom')) - elif m.start() == 0: - flags.append(m.group('atom')) - else: - raise IllegalClientResponse("Malformed flag") - line = m.group('rest') - - return (flags, '') - - def arg_line(self, line): - """ - Command line of UID command - """ - return (line, '') - - def opt_plist(self, line): - """ - Optional parenthesised list - """ - if line.startswith('('): - return self.arg_plist(line) - else: - return (None, line) - - def opt_datetime(self, line): - """ - Optional date-time string - """ - if line.startswith('"'): - try: - spam, date, rest = line.split('"',2) - except IndexError: - raise IllegalClientResponse("Malformed date-time") - return (date, rest[1:]) - else: - return (None, line) - - def opt_charset(self, line): - """ - Optional charset of SEARCH command - """ - if line[:7].upper() == 'CHARSET': - arg = line.split(' ',2) - if len(arg) == 1: - raise IllegalClientResponse("Missing charset identifier") - if len(arg) == 2: - arg.append('') - spam, arg, rest = arg - return (arg, rest) - else: - return (None, line) - - def sendServerGreeting(self): - msg = '[CAPABILITY %s] %s' % (' '.join(self.listCapabilities()), self.IDENT) - self.sendPositiveResponse(message=msg) - - def sendBadResponse(self, tag = None, message = ''): - self._respond('BAD', tag, message) - - def sendPositiveResponse(self, tag = None, message = ''): - self._respond('OK', tag, message) - - def sendNegativeResponse(self, tag = None, message = ''): - self._respond('NO', tag, message) - - def sendUntaggedResponse(self, message, async=False): - if not async or (self.blocked is None): - self._respond(message, None, None) - else: - self._queuedAsync.append(message) - - def sendContinuationRequest(self, msg = 'Ready for additional command text'): - if msg: - self.sendLine('+ ' + msg) - else: - self.sendLine('+') - - def _respond(self, state, tag, message): - if state in ('OK', 'NO', 'BAD') and self._queuedAsync: - lines = self._queuedAsync - self._queuedAsync = [] - for msg in lines: - self._respond(msg, None, None) - if not tag: - tag = '*' - if message: - self.sendLine(' '.join((tag, state, message))) - else: - self.sendLine(' '.join((tag, state))) - - def listCapabilities(self): - caps = ['IMAP4rev1'] - for c, v in self.capabilities().iteritems(): - if v is None: - caps.append(c) - elif len(v): - caps.extend([('%s=%s' % (c, cap)) for cap in v]) - return caps - - def do_CAPABILITY(self, tag): - self.sendUntaggedResponse('CAPABILITY ' + ' '.join(self.listCapabilities())) - self.sendPositiveResponse(tag, 'CAPABILITY completed') - - unauth_CAPABILITY = (do_CAPABILITY,) - auth_CAPABILITY = unauth_CAPABILITY - select_CAPABILITY = unauth_CAPABILITY - logout_CAPABILITY = unauth_CAPABILITY - - def do_LOGOUT(self, tag): - self.sendUntaggedResponse('BYE Nice talking to you') - self.sendPositiveResponse(tag, 'LOGOUT successful') - self.transport.loseConnection() - - unauth_LOGOUT = (do_LOGOUT,) - auth_LOGOUT = unauth_LOGOUT - select_LOGOUT = unauth_LOGOUT - logout_LOGOUT = unauth_LOGOUT - - def do_NOOP(self, tag): - self.sendPositiveResponse(tag, 'NOOP No operation performed') - - unauth_NOOP = (do_NOOP,) - auth_NOOP = unauth_NOOP - select_NOOP = unauth_NOOP - logout_NOOP = unauth_NOOP - - def do_AUTHENTICATE(self, tag, args): - args = args.upper().strip() - if args not in self.challengers: - self.sendNegativeResponse(tag, 'AUTHENTICATE method unsupported') - else: - self.authenticate(self.challengers[args](), tag) - - unauth_AUTHENTICATE = (do_AUTHENTICATE, arg_atom) - - def authenticate(self, chal, tag): - if self.portal is None: - self.sendNegativeResponse(tag, 'Temporary authentication failure') - return - - self._setupChallenge(chal, tag) - - def _setupChallenge(self, chal, tag): - try: - challenge = chal.getChallenge() - except Exception, e: - self.sendBadResponse(tag, 'Server error: ' + str(e)) - else: - coded = base64.encodestring(challenge)[:-1] - self.parseState = 'pending' - self._pendingLiteral = defer.Deferred() - self.sendContinuationRequest(coded) - self._pendingLiteral.addCallback(self.__cbAuthChunk, chal, tag) - self._pendingLiteral.addErrback(self.__ebAuthChunk, tag) - - def __cbAuthChunk(self, result, chal, tag): - try: - uncoded = base64.decodestring(result) - except binascii.Error: - raise IllegalClientResponse("Malformed Response - not base64") - - chal.setResponse(uncoded) - if chal.moreChallenges(): - self._setupChallenge(chal, tag) - else: - self.portal.login(chal, None, IAccount).addCallbacks( - self.__cbAuthResp, - self.__ebAuthResp, - (tag,), None, (tag,), None - ) - - def __cbAuthResp(self, (iface, avatar, logout), tag): - assert iface is IAccount, "IAccount is the only supported interface" - self.account = avatar - self.state = 'auth' - self._onLogout = logout - self.sendPositiveResponse(tag, 'Authentication successful') - self.setTimeout(self.POSTAUTH_TIMEOUT) - - def __ebAuthResp(self, failure, tag): - if failure.check(cred.error.UnauthorizedLogin): - self.sendNegativeResponse(tag, 'Authentication failed: unauthorized') - elif failure.check(cred.error.UnhandledCredentials): - self.sendNegativeResponse(tag, 'Authentication failed: server misconfigured') - else: - self.sendBadResponse(tag, 'Server error: login failed unexpectedly') - log.err(failure) - - def __ebAuthChunk(self, failure, tag): - self.sendNegativeResponse(tag, 'Authentication failed: ' + str(failure.value)) - - def do_STARTTLS(self, tag): - if self.startedTLS: - self.sendNegativeResponse(tag, 'TLS already negotiated') - elif self.ctx and self.canStartTLS: - self.sendPositiveResponse(tag, 'Begin TLS negotiation now') - self.transport.startTLS(self.ctx) - self.startedTLS = True - self.challengers = self.challengers.copy() - if 'LOGIN' not in self.challengers: - self.challengers['LOGIN'] = LOGINCredentials - if 'PLAIN' not in self.challengers: - self.challengers['PLAIN'] = PLAINCredentials - else: - self.sendNegativeResponse(tag, 'TLS not available') - - unauth_STARTTLS = (do_STARTTLS,) - - def do_LOGIN(self, tag, user, passwd): - if 'LOGINDISABLED' in self.capabilities(): - self.sendBadResponse(tag, 'LOGIN is disabled before STARTTLS') - return - - maybeDeferred(self.authenticateLogin, user, passwd - ).addCallback(self.__cbLogin, tag - ).addErrback(self.__ebLogin, tag - ) - - unauth_LOGIN = (do_LOGIN, arg_astring, arg_astring) - - def authenticateLogin(self, user, passwd): - """Lookup the account associated with the given parameters - - Override this method to define the desired authentication behavior. - - The default behavior is to defer authentication to C{self.portal} - if it is not None, or to deny the login otherwise. - - @type user: C{str} - @param user: The username to lookup - - @type passwd: C{str} - @param passwd: The password to login with - """ - if self.portal: - return self.portal.login( - cred.credentials.UsernamePassword(user, passwd), - None, IAccount - ) - raise cred.error.UnauthorizedLogin() - - def __cbLogin(self, (iface, avatar, logout), tag): - if iface is not IAccount: - self.sendBadResponse(tag, 'Server error: login returned unexpected value') - log.err("__cbLogin called with %r, IAccount expected" % (iface,)) - else: - self.account = avatar - self._onLogout = logout - self.sendPositiveResponse(tag, 'LOGIN succeeded') - self.state = 'auth' - self.setTimeout(self.POSTAUTH_TIMEOUT) - - def __ebLogin(self, failure, tag): - if failure.check(cred.error.UnauthorizedLogin): - self.sendNegativeResponse(tag, 'LOGIN failed') - else: - self.sendBadResponse(tag, 'Server error: ' + str(failure.value)) - log.err(failure) - - def do_NAMESPACE(self, tag): - personal = public = shared = None - np = INamespacePresenter(self.account, None) - if np is not None: - personal = np.getPersonalNamespaces() - public = np.getSharedNamespaces() - shared = np.getSharedNamespaces() - self.sendUntaggedResponse('NAMESPACE ' + collapseNestedLists([personal, public, shared])) - self.sendPositiveResponse(tag, "NAMESPACE command completed") - - auth_NAMESPACE = (do_NAMESPACE,) - select_NAMESPACE = auth_NAMESPACE - - def _parseMbox(self, name): - if isinstance(name, unicode): - return name - try: - return name.decode('imap4-utf-7') - except: - log.err() - raise IllegalMailboxEncoding(name) - - def _selectWork(self, tag, name, rw, cmdName): - if self.mbox: - self.mbox.removeListener(self) - cmbx = ICloseableMailbox(self.mbox, None) - if cmbx is not None: - maybeDeferred(cmbx.close).addErrback(log.err) - self.mbox = None - self.state = 'auth' - - name = self._parseMbox(name) - maybeDeferred(self.account.select, self._parseMbox(name), rw - ).addCallback(self._cbSelectWork, cmdName, tag - ).addErrback(self._ebSelectWork, cmdName, tag - ) - - def _ebSelectWork(self, failure, cmdName, tag): - self.sendBadResponse(tag, "%s failed: Server error" % (cmdName,)) - log.err(failure) - - def _cbSelectWork(self, mbox, cmdName, tag): - if mbox is None: - self.sendNegativeResponse(tag, 'No such mailbox') - return - if '\\noselect' in [s.lower() for s in mbox.getFlags()]: - self.sendNegativeResponse(tag, 'Mailbox cannot be selected') - return - - flags = mbox.getFlags() - self.sendUntaggedResponse(str(mbox.getMessageCount()) + ' EXISTS') - self.sendUntaggedResponse(str(mbox.getRecentCount()) + ' RECENT') - self.sendUntaggedResponse('FLAGS (%s)' % ' '.join(flags)) - self.sendPositiveResponse(None, '[UIDVALIDITY %d]' % mbox.getUIDValidity()) - - s = mbox.isWriteable() and 'READ-WRITE' or 'READ-ONLY' - mbox.addListener(self) - self.sendPositiveResponse(tag, '[%s] %s successful' % (s, cmdName)) - self.state = 'select' - self.mbox = mbox - - auth_SELECT = ( _selectWork, arg_astring, 1, 'SELECT' ) - select_SELECT = auth_SELECT - - auth_EXAMINE = ( _selectWork, arg_astring, 0, 'EXAMINE' ) - select_EXAMINE = auth_EXAMINE - - - def do_IDLE(self, tag): - self.sendContinuationRequest(None) - self.parseTag = tag - self.lastState = self.parseState - self.parseState = 'idle' - - def parse_idle(self, *args): - self.parseState = self.lastState - del self.lastState - self.sendPositiveResponse(self.parseTag, "IDLE terminated") - del self.parseTag - - select_IDLE = ( do_IDLE, ) - auth_IDLE = select_IDLE - - - def do_CREATE(self, tag, name): - name = self._parseMbox(name) - try: - result = self.account.create(name) - except MailboxException, c: - self.sendNegativeResponse(tag, str(c)) - except: - self.sendBadResponse(tag, "Server error encountered while creating mailbox") - log.err() - else: - if result: - self.sendPositiveResponse(tag, 'Mailbox created') - else: - self.sendNegativeResponse(tag, 'Mailbox not created') - - auth_CREATE = (do_CREATE, arg_astring) - select_CREATE = auth_CREATE - - def do_DELETE(self, tag, name): - name = self._parseMbox(name) - if name.lower() == 'inbox': - self.sendNegativeResponse(tag, 'You cannot delete the inbox') - return - try: - self.account.delete(name) - except MailboxException, m: - self.sendNegativeResponse(tag, str(m)) - except: - self.sendBadResponse(tag, "Server error encountered while deleting mailbox") - log.err() - else: - self.sendPositiveResponse(tag, 'Mailbox deleted') - - auth_DELETE = (do_DELETE, arg_astring) - select_DELETE = auth_DELETE - - def do_RENAME(self, tag, oldname, newname): - oldname, newname = [self._parseMbox(n) for n in oldname, newname] - if oldname.lower() == 'inbox' or newname.lower() == 'inbox': - self.sendNegativeResponse(tag, 'You cannot rename the inbox, or rename another mailbox to inbox.') - return - try: - self.account.rename(oldname, newname) - except TypeError: - self.sendBadResponse(tag, 'Invalid command syntax') - except MailboxException, m: - self.sendNegativeResponse(tag, str(m)) - except: - self.sendBadResponse(tag, "Server error encountered while renaming mailbox") - log.err() - else: - self.sendPositiveResponse(tag, 'Mailbox renamed') - - auth_RENAME = (do_RENAME, arg_astring, arg_astring) - select_RENAME = auth_RENAME - - def do_SUBSCRIBE(self, tag, name): - name = self._parseMbox(name) - try: - self.account.subscribe(name) - except MailboxException, m: - self.sendNegativeResponse(tag, str(m)) - except: - self.sendBadResponse(tag, "Server error encountered while subscribing to mailbox") - log.err() - else: - self.sendPositiveResponse(tag, 'Subscribed') - - auth_SUBSCRIBE = (do_SUBSCRIBE, arg_astring) - select_SUBSCRIBE = auth_SUBSCRIBE - - def do_UNSUBSCRIBE(self, tag, name): - name = self._parseMbox(name) - try: - self.account.unsubscribe(name) - except MailboxException, m: - self.sendNegativeResponse(tag, str(m)) - except: - self.sendBadResponse(tag, "Server error encountered while unsubscribing from mailbox") - log.err() - else: - self.sendPositiveResponse(tag, 'Unsubscribed') - - auth_UNSUBSCRIBE = (do_UNSUBSCRIBE, arg_astring) - select_UNSUBSCRIBE = auth_UNSUBSCRIBE - - def _listWork(self, tag, ref, mbox, sub, cmdName): - mbox = self._parseMbox(mbox) - maybeDeferred(self.account.listMailboxes, ref, mbox - ).addCallback(self._cbListWork, tag, sub, cmdName - ).addErrback(self._ebListWork, tag - ) - - def _cbListWork(self, mailboxes, tag, sub, cmdName): - for (name, box) in mailboxes: - if not sub or self.account.isSubscribed(name): - flags = box.getFlags() - delim = box.getHierarchicalDelimiter() - resp = (DontQuoteMe(cmdName), map(DontQuoteMe, flags), delim, name.encode('imap4-utf-7')) - self.sendUntaggedResponse(collapseNestedLists(resp)) - self.sendPositiveResponse(tag, '%s completed' % (cmdName,)) - - def _ebListWork(self, failure, tag): - self.sendBadResponse(tag, "Server error encountered while listing mailboxes.") - log.err(failure) - - auth_LIST = (_listWork, arg_astring, arg_astring, 0, 'LIST') - select_LIST = auth_LIST - - auth_LSUB = (_listWork, arg_astring, arg_astring, 1, 'LSUB') - select_LSUB = auth_LSUB - - def do_STATUS(self, tag, mailbox, names): - mailbox = self._parseMbox(mailbox) - maybeDeferred(self.account.select, mailbox, 0 - ).addCallback(self._cbStatusGotMailbox, tag, mailbox, names - ).addErrback(self._ebStatusGotMailbox, tag - ) - - def _cbStatusGotMailbox(self, mbox, tag, mailbox, names): - if mbox: - maybeDeferred(mbox.requestStatus, names).addCallbacks( - self.__cbStatus, self.__ebStatus, - (tag, mailbox), None, (tag, mailbox), None - ) - else: - self.sendNegativeResponse(tag, "Could not open mailbox") - - def _ebStatusGotMailbox(self, failure, tag): - self.sendBadResponse(tag, "Server error encountered while opening mailbox.") - log.err(failure) - - auth_STATUS = (do_STATUS, arg_astring, arg_plist) - select_STATUS = auth_STATUS - - def __cbStatus(self, status, tag, box): - line = ' '.join(['%s %s' % x for x in status.iteritems()]) - self.sendUntaggedResponse('STATUS %s (%s)' % (box, line)) - self.sendPositiveResponse(tag, 'STATUS complete') - - def __ebStatus(self, failure, tag, box): - self.sendBadResponse(tag, 'STATUS %s failed: %s' % (box, str(failure.value))) - - def do_APPEND(self, tag, mailbox, flags, date, message): - mailbox = self._parseMbox(mailbox) - maybeDeferred(self.account.select, mailbox - ).addCallback(self._cbAppendGotMailbox, tag, flags, date, message - ).addErrback(self._ebAppendGotMailbox, tag - ) - - def _cbAppendGotMailbox(self, mbox, tag, flags, date, message): - if not mbox: - self.sendNegativeResponse(tag, '[TRYCREATE] No such mailbox') - return - - d = mbox.addMessage(message, flags, date) - d.addCallback(self.__cbAppend, tag, mbox) - d.addErrback(self.__ebAppend, tag) - - def _ebAppendGotMailbox(self, failure, tag): - self.sendBadResponse(tag, "Server error encountered while opening mailbox.") - log.err(failure) - - auth_APPEND = (do_APPEND, arg_astring, opt_plist, opt_datetime, - arg_literal) - select_APPEND = auth_APPEND - - def __cbAppend(self, result, tag, mbox): - self.sendUntaggedResponse('%d EXISTS' % mbox.getMessageCount()) - self.sendPositiveResponse(tag, 'APPEND complete') - - def __ebAppend(self, failure, tag): - self.sendBadResponse(tag, 'APPEND failed: ' + str(failure.value)) - - def do_CHECK(self, tag): - d = self.checkpoint() - if d is None: - self.__cbCheck(None, tag) - else: - d.addCallbacks( - self.__cbCheck, - self.__ebCheck, - callbackArgs=(tag,), - errbackArgs=(tag,) - ) - select_CHECK = (do_CHECK,) - - def __cbCheck(self, result, tag): - self.sendPositiveResponse(tag, 'CHECK completed') - - def __ebCheck(self, failure, tag): - self.sendBadResponse(tag, 'CHECK failed: ' + str(failure.value)) - - def checkpoint(self): - """Called when the client issues a CHECK command. - - This should perform any checkpoint operations required by the server. - It may be a long running operation, but may not block. If it returns - a deferred, the client will only be informed of success (or failure) - when the deferred's callback (or errback) is invoked. - """ - return None - - def do_CLOSE(self, tag): - d = None - if self.mbox.isWriteable(): - d = maybeDeferred(self.mbox.expunge) - cmbx = ICloseableMailbox(self.mbox, None) - if cmbx is not None: - if d is not None: - d.addCallback(lambda result: cmbx.close()) - else: - d = maybeDeferred(cmbx.close) - if d is not None: - d.addCallbacks(self.__cbClose, self.__ebClose, (tag,), None, (tag,), None) - else: - self.__cbClose(None, tag) - - select_CLOSE = (do_CLOSE,) - - def __cbClose(self, result, tag): - self.sendPositiveResponse(tag, 'CLOSE completed') - self.mbox.removeListener(self) - self.mbox = None - self.state = 'auth' - - def __ebClose(self, failure, tag): - self.sendBadResponse(tag, 'CLOSE failed: ' + str(failure.value)) - - def do_EXPUNGE(self, tag): - if self.mbox.isWriteable(): - maybeDeferred(self.mbox.expunge).addCallbacks( - self.__cbExpunge, self.__ebExpunge, (tag,), None, (tag,), None - ) - else: - self.sendNegativeResponse(tag, 'EXPUNGE ignored on read-only mailbox') - - select_EXPUNGE = (do_EXPUNGE,) - - def __cbExpunge(self, result, tag): - for e in result: - self.sendUntaggedResponse('%d EXPUNGE' % e) - self.sendPositiveResponse(tag, 'EXPUNGE completed') - - def __ebExpunge(self, failure, tag): - self.sendBadResponse(tag, 'EXPUNGE failed: ' + str(failure.value)) - log.err(failure) - - def do_SEARCH(self, tag, charset, query, uid=0): - sm = ISearchableMailbox(self.mbox, None) - if sm is not None: - maybeDeferred(sm.search, query, uid=uid).addCallbacks( - self.__cbSearch, self.__ebSearch, - (tag, self.mbox, uid), None, (tag,), None - ) - else: - s = parseIdList('1:*') - maybeDeferred(self.mbox.fetch, s, uid=uid).addCallbacks( - self.__cbManualSearch, self.__ebSearch, - (tag, self.mbox, query, uid), None, (tag,), None - ) - - select_SEARCH = (do_SEARCH, opt_charset, arg_searchkeys) - - def __cbSearch(self, result, tag, mbox, uid): - if uid: - result = map(mbox.getUID, result) - ids = ' '.join([str(i) for i in result]) - self.sendUntaggedResponse('SEARCH ' + ids) - self.sendPositiveResponse(tag, 'SEARCH completed') - - def __cbManualSearch(self, result, tag, mbox, query, uid, searchResults = None): - if searchResults is None: - searchResults = [] - i = 0 - for (i, (id, msg)) in zip(range(5), result): - if self.searchFilter(query, id, msg): - if uid: - searchResults.append(str(msg.getUID())) - else: - searchResults.append(str(id)) - if i == 4: - from twisted.internet import reactor - reactor.callLater(0, self.__cbManualSearch, result, tag, mbox, query, uid, searchResults) - else: - if searchResults: - self.sendUntaggedResponse('SEARCH ' + ' '.join(searchResults)) - self.sendPositiveResponse(tag, 'SEARCH completed') - - def searchFilter(self, query, id, msg): - while query: - if not self.singleSearchStep(query, id, msg): - return False - return True - - def singleSearchStep(self, query, id, msg): - q = query.pop(0) - if isinstance(q, list): - if not self.searchFilter(q, id, msg): - return False - else: - c = q.upper() - f = getattr(self, 'search_' + c) - if f: - if not f(query, id, msg): - return False - else: - # IMAP goes *out of its way* to be complex - # Sequence sets to search should be specified - # with a command, like EVERYTHING ELSE. - try: - m = parseIdList(c) - except: - log.err('Unknown search term: ' + c) - else: - if id not in m: - return False - return True - - def search_ALL(self, query, id, msg): - return True - - def search_ANSWERED(self, query, id, msg): - return '\\Answered' in msg.getFlags() - - def search_BCC(self, query, id, msg): - bcc = msg.getHeaders(False, 'bcc').get('bcc', '') - return bcc.lower().find(query.pop(0).lower()) != -1 - - def search_BEFORE(self, query, id, msg): - date = parseTime(query.pop(0)) - return rfc822.parsedate(msg.getInternalDate()) < date - - def search_BODY(self, query, id, msg): - body = query.pop(0).lower() - return text.strFile(body, msg.getBodyFile(), False) - - def search_CC(self, query, id, msg): - cc = msg.getHeaders(False, 'cc').get('cc', '') - return cc.lower().find(query.pop(0).lower()) != -1 - - def search_DELETED(self, query, id, msg): - return '\\Deleted' in msg.getFlags() - - def search_DRAFT(self, query, id, msg): - return '\\Draft' in msg.getFlags() - - def search_FLAGGED(self, query, id, msg): - return '\\Flagged' in msg.getFlags() - - def search_FROM(self, query, id, msg): - fm = msg.getHeaders(False, 'from').get('from', '') - return fm.lower().find(query.pop(0).lower()) != -1 - - def search_HEADER(self, query, id, msg): - hdr = query.pop(0).lower() - hdr = msg.getHeaders(False, hdr).get(hdr, '') - return hdr.lower().find(query.pop(0).lower()) != -1 - - def search_KEYWORD(self, query, id, msg): - query.pop(0) - return False - - def search_LARGER(self, query, id, msg): - return int(query.pop(0)) < msg.getSize() - - def search_NEW(self, query, id, msg): - return '\\Recent' in msg.getFlags() and '\\Seen' not in msg.getFlags() - - def search_NOT(self, query, id, msg): - return not self.singleSearchStep(query, id, msg) - - def search_OLD(self, query, id, msg): - return '\\Recent' not in msg.getFlags() - - def search_ON(self, query, id, msg): - date = parseTime(query.pop(0)) - return rfc822.parsedate(msg.getInternalDate()) == date - - def search_OR(self, query, id, msg): - a = self.singleSearchStep(query, id, msg) - b = self.singleSearchStep(query, id, msg) - return a or b - - def search_RECENT(self, query, id, msg): - return '\\Recent' in msg.getFlags() - - def search_SEEN(self, query, id, msg): - return '\\Seen' in msg.getFlags() - - def search_SENTBEFORE(self, query, id, msg): - date = msg.getHeader(False, 'date').get('date', '') - date = rfc822.parsedate(date) - return date < parseTime(query.pop(0)) - - def search_SENTON(self, query, id, msg): - date = msg.getHeader(False, 'date').get('date', '') - date = rfc822.parsedate(date) - return date[:3] == parseTime(query.pop(0))[:3] - - def search_SENTSINCE(self, query, id, msg): - date = msg.getHeader(False, 'date').get('date', '') - date = rfc822.parsedate(date) - return date > parseTime(query.pop(0)) - - def search_SINCE(self, query, id, msg): - date = parseTime(query.pop(0)) - return rfc822.parsedate(msg.getInternalDate()) > date - - def search_SMALLER(self, query, id, msg): - return int(query.pop(0)) > msg.getSize() - - def search_SUBJECT(self, query, id, msg): - subj = msg.getHeaders(False, 'subject').get('subject', '') - return subj.lower().find(query.pop(0).lower()) != -1 - - def search_TEXT(self, query, id, msg): - # XXX - This must search headers too - body = query.pop(0).lower() - return text.strFile(body, msg.getBodyFile(), False) - - def search_TO(self, query, id, msg): - to = msg.getHeaders(False, 'to').get('to', '') - return to.lower().find(query.pop(0).lower()) != -1 - - def search_UID(self, query, id, msg): - c = query.pop(0) - m = parseIdList(c) - return msg.getUID() in m - - def search_UNANSWERED(self, query, id, msg): - return '\\Answered' not in msg.getFlags() - - def search_UNDELETED(self, query, id, msg): - return '\\Deleted' not in msg.getFlags() - - def search_UNDRAFT(self, query, id, msg): - return '\\Draft' not in msg.getFlags() - - def search_UNFLAGGED(self, query, id, msg): - return '\\Flagged' not in msg.getFlags() - - def search_UNKEYWORD(self, query, id, msg): - query.pop(0) - return False - - def search_UNSEEN(self, query, id, msg): - return '\\Seen' not in msg.getFlags() - - def __ebSearch(self, failure, tag): - self.sendBadResponse(tag, 'SEARCH failed: ' + str(failure.value)) - log.err(failure) - - def do_FETCH(self, tag, messages, query, uid=0): - if query: - self._oldTimeout = self.setTimeout(None) - maybeDeferred(self.mbox.fetch, messages, uid=uid - ).addCallback(iter - ).addCallback(self.__cbFetch, tag, query, uid - ).addErrback(self.__ebFetch, tag - ) - else: - self.sendPositiveResponse(tag, 'FETCH complete') - - select_FETCH = (do_FETCH, arg_seqset, arg_fetchatt) - - def __cbFetch(self, results, tag, query, uid): - if self.blocked is None: - self.blocked = [] - try: - id, msg = results.next() - except StopIteration: - # The idle timeout was suspended while we delivered results, - # restore it now. - self.setTimeout(self._oldTimeout) - del self._oldTimeout - - # All results have been processed, deliver completion notification. - - # It's important to run this *after* resetting the timeout to "rig - # a race" in some test code. writing to the transport will - # synchronously call test code, which synchronously loses the - # connection, calling our connectionLost method, which cancels the - # timeout. We want to make sure that timeout is cancelled *after* - # we reset it above, so that the final state is no timed - # calls. This avoids reactor uncleanliness errors in the test - # suite. - # XXX: Perhaps loopback should be fixed to not call the user code - # synchronously in transport.write? - self.sendPositiveResponse(tag, 'FETCH completed') - - # Instance state is now consistent again (ie, it is as though - # the fetch command never ran), so allow any pending blocked - # commands to execute. - self._unblock() - else: - self.spewMessage(id, msg, query, uid - ).addCallback(lambda _: self.__cbFetch(results, tag, query, uid) - ).addErrback(self.__ebSpewMessage - ) - - def __ebSpewMessage(self, failure): - # This indicates a programming error. - # There's no reliable way to indicate anything to the client, since we - # may have already written an arbitrary amount of data in response to - # the command. - log.err(failure) - self.transport.loseConnection() - - def spew_envelope(self, id, msg, _w=None, _f=None): - if _w is None: - _w = self.transport.write - _w('ENVELOPE ' + collapseNestedLists([getEnvelope(msg)])) - - def spew_flags(self, id, msg, _w=None, _f=None): - if _w is None: - _w = self.transport.write - _w('FLAGS ' + '(%s)' % (' '.join(msg.getFlags()))) - - def spew_internaldate(self, id, msg, _w=None, _f=None): - if _w is None: - _w = self.transport.write - idate = msg.getInternalDate() - ttup = rfc822.parsedate_tz(idate) - if ttup is None: - log.msg("%d:%r: unpareseable internaldate: %r" % (id, msg, idate)) - raise IMAP4Exception("Internal failure generating INTERNALDATE") - - odate = time.strftime("%d-%b-%Y %H:%M:%S ", ttup[:9]) - if ttup[9] is None: - odate = odate + "+0000" - else: - if ttup[9] >= 0: - sign = "+" - else: - sign = "-" - odate = odate + sign + string.zfill(str(((abs(ttup[9]) / 3600) * 100 + (abs(ttup[9]) % 3600) / 60)), 4) - _w('INTERNALDATE ' + _quote(odate)) - - def spew_rfc822header(self, id, msg, _w=None, _f=None): - if _w is None: - _w = self.transport.write - hdrs = _formatHeaders(msg.getHeaders(True)) - _w('RFC822.HEADER ' + _literal(hdrs)) - - def spew_rfc822text(self, id, msg, _w=None, _f=None): - if _w is None: - _w = self.transport.write - _w('RFC822.TEXT ') - _f() - return FileProducer(msg.getBodyFile() - ).beginProducing(self.transport - ) - - def spew_rfc822size(self, id, msg, _w=None, _f=None): - if _w is None: - _w = self.transport.write - _w('RFC822.SIZE ' + str(msg.getSize())) - - def spew_rfc822(self, id, msg, _w=None, _f=None): - if _w is None: - _w = self.transport.write - _w('RFC822 ') - _f() - mf = IMessageFile(msg, None) - if mf is not None: - return FileProducer(mf.open() - ).beginProducing(self.transport - ) - return MessageProducer(msg, None, self._scheduler - ).beginProducing(self.transport - ) - - def spew_uid(self, id, msg, _w=None, _f=None): - if _w is None: - _w = self.transport.write - _w('UID ' + str(msg.getUID())) - - def spew_bodystructure(self, id, msg, _w=None, _f=None): - _w('BODYSTRUCTURE ' + collapseNestedLists([getBodyStructure(msg, True)])) - - def spew_body(self, part, id, msg, _w=None, _f=None): - if _w is None: - _w = self.transport.write - for p in part.part: - if msg.isMultipart(): - msg = msg.getSubPart(p) - elif p > 0: - # Non-multipart messages have an implicit first part but no - # other parts - reject any request for any other part. - raise TypeError("Requested subpart of non-multipart message") - - if part.header: - hdrs = msg.getHeaders(part.header.negate, *part.header.fields) - hdrs = _formatHeaders(hdrs) - _w(str(part) + ' ' + _literal(hdrs)) - elif part.text: - _w(str(part) + ' ') - _f() - return FileProducer(msg.getBodyFile() - ).beginProducing(self.transport - ) - elif part.mime: - hdrs = _formatHeaders(msg.getHeaders(True)) - _w(str(part) + ' ' + _literal(hdrs)) - elif part.empty: - _w(str(part) + ' ') - _f() - if part.part: - return FileProducer(msg.getBodyFile() - ).beginProducing(self.transport - ) - else: - mf = IMessageFile(msg, None) - if mf is not None: - return FileProducer(mf.open()).beginProducing(self.transport) - return MessageProducer(msg, None, self._scheduler).beginProducing(self.transport) - - else: - _w('BODY ' + collapseNestedLists([getBodyStructure(msg)])) - - def spewMessage(self, id, msg, query, uid): - wbuf = WriteBuffer(self.transport) - write = wbuf.write - flush = wbuf.flush - def start(): - write('* %d FETCH (' % (id,)) - def finish(): - write(')\r\n') - def space(): - write(' ') - - def spew(): - seenUID = False - start() - for part in query: - if part.type == 'uid': - seenUID = True - if part.type == 'body': - yield self.spew_body(part, id, msg, write, flush) - else: - f = getattr(self, 'spew_' + part.type) - yield f(id, msg, write, flush) - if part is not query[-1]: - space() - if uid and not seenUID: - space() - yield self.spew_uid(id, msg, write, flush) - finish() - flush() - return self._scheduler(spew()) - - def __ebFetch(self, failure, tag): - self.setTimeout(self._oldTimeout) - del self._oldTimeout - log.err(failure) - self.sendBadResponse(tag, 'FETCH failed: ' + str(failure.value)) - - def do_STORE(self, tag, messages, mode, flags, uid=0): - mode = mode.upper() - silent = mode.endswith('SILENT') - if mode.startswith('+'): - mode = 1 - elif mode.startswith('-'): - mode = -1 - else: - mode = 0 - - maybeDeferred(self.mbox.store, messages, flags, mode, uid=uid).addCallbacks( - self.__cbStore, self.__ebStore, (tag, self.mbox, uid, silent), None, (tag,), None - ) - - select_STORE = (do_STORE, arg_seqset, arg_atom, arg_flaglist) - - def __cbStore(self, result, tag, mbox, uid, silent): - if result and not silent: - for (k, v) in result.iteritems(): - if uid: - uidstr = ' UID %d' % mbox.getUID(k) - else: - uidstr = '' - self.sendUntaggedResponse('%d FETCH (FLAGS (%s)%s)' % - (k, ' '.join(v), uidstr)) - self.sendPositiveResponse(tag, 'STORE completed') - - def __ebStore(self, failure, tag): - self.sendBadResponse(tag, 'Server error: ' + str(failure.value)) - - def do_COPY(self, tag, messages, mailbox, uid=0): - mailbox = self._parseMbox(mailbox) - maybeDeferred(self.account.select, mailbox - ).addCallback(self._cbCopySelectedMailbox, tag, messages, mailbox, uid - ).addErrback(self._ebCopySelectedMailbox, tag - ) - select_COPY = (do_COPY, arg_seqset, arg_astring) - - def _cbCopySelectedMailbox(self, mbox, tag, messages, mailbox, uid): - if not mbox: - self.sendNegativeResponse(tag, 'No such mailbox: ' + mailbox) - else: - maybeDeferred(self.mbox.fetch, messages, uid - ).addCallback(self.__cbCopy, tag, mbox - ).addCallback(self.__cbCopied, tag, mbox - ).addErrback(self.__ebCopy, tag - ) - - def _ebCopySelectedMailbox(self, failure, tag): - self.sendBadResponse(tag, 'Server error: ' + str(failure.value)) - - def __cbCopy(self, messages, tag, mbox): - # XXX - This should handle failures with a rollback or something - addedDeferreds = [] - addedIDs = [] - failures = [] - - fastCopyMbox = IMessageCopier(mbox, None) - for (id, msg) in messages: - if fastCopyMbox is not None: - d = maybeDeferred(fastCopyMbox.copy, msg) - addedDeferreds.append(d) - continue - - # XXX - The following should be an implementation of IMessageCopier.copy - # on an IMailbox->IMessageCopier adapter. - - flags = msg.getFlags() - date = msg.getInternalDate() - - body = IMessageFile(msg, None) - if body is not None: - bodyFile = body.open() - d = maybeDeferred(mbox.addMessage, bodyFile, flags, date) - else: - def rewind(f): - f.seek(0) - return f - buffer = tempfile.TemporaryFile() - d = MessageProducer(msg, buffer, self._scheduler - ).beginProducing(None - ).addCallback(lambda _, b=buffer, f=flags, d=date: mbox.addMessage(rewind(b), f, d) - ) - addedDeferreds.append(d) - return defer.DeferredList(addedDeferreds) - - def __cbCopied(self, deferredIds, tag, mbox): - ids = [] - failures = [] - for (status, result) in deferredIds: - if status: - ids.append(result) - else: - failures.append(result.value) - if failures: - self.sendNegativeResponse(tag, '[ALERT] Some messages were not copied') - else: - self.sendPositiveResponse(tag, 'COPY completed') - - def __ebCopy(self, failure, tag): - self.sendBadResponse(tag, 'COPY failed:' + str(failure.value)) - log.err(failure) - - def do_UID(self, tag, command, line): - command = command.upper() - - if command not in ('COPY', 'FETCH', 'STORE', 'SEARCH'): - raise IllegalClientResponse(command) - - self.dispatchCommand(tag, command, line, uid=1) - - select_UID = (do_UID, arg_atom, arg_line) - # - # IMailboxListener implementation - # - def modeChanged(self, writeable): - if writeable: - self.sendUntaggedResponse(message='[READ-WRITE]', async=True) - else: - self.sendUntaggedResponse(message='[READ-ONLY]', async=True) - - def flagsChanged(self, newFlags): - for (mId, flags) in newFlags.iteritems(): - msg = '%d FETCH (FLAGS (%s))' % (mId, ' '.join(flags)) - self.sendUntaggedResponse(msg, async=True) - - def newMessages(self, exists, recent): - if exists is not None: - self.sendUntaggedResponse('%d EXISTS' % exists, async=True) - if recent is not None: - self.sendUntaggedResponse('%d RECENT' % recent, async=True) - - -class UnhandledResponse(IMAP4Exception): pass - -class NegativeResponse(IMAP4Exception): pass - -class NoSupportedAuthentication(IMAP4Exception): - def __init__(self, serverSupports, clientSupports): - IMAP4Exception.__init__(self, 'No supported authentication schemes available') - self.serverSupports = serverSupports - self.clientSupports = clientSupports - - def __str__(self): - return (IMAP4Exception.__str__(self) - + ': Server supports %r, client supports %r' - % (self.serverSupports, self.clientSupports)) - -class IllegalServerResponse(IMAP4Exception): pass - -TIMEOUT_ERROR = error.TimeoutError() - -class IMAP4Client(basic.LineReceiver, policies.TimeoutMixin): - """IMAP4 client protocol implementation - - @ivar state: A string representing the state the connection is currently - in. - """ - implements(IMailboxListener) - - tags = None - waiting = None - queued = None - tagID = 1 - state = None - - startedTLS = False - - # Number of seconds to wait before timing out a connection. - # If the number is <= 0 no timeout checking will be performed. - timeout = 0 - - # Capabilities are not allowed to change during the session - # So cache the first response and use that for all later - # lookups - _capCache = None - - _memoryFileLimit = 1024 * 1024 * 10 - - # Authentication is pluggable. This maps names to IClientAuthentication - # objects. - authenticators = None - - STATUS_CODES = ('OK', 'NO', 'BAD', 'PREAUTH', 'BYE') - - STATUS_TRANSFORMATIONS = { - 'MESSAGES': int, 'RECENT': int, 'UNSEEN': int - } - - context = None - - def __init__(self, contextFactory = None): - self.tags = {} - self.queued = [] - self.authenticators = {} - self.context = contextFactory - - self._tag = None - self._parts = None - self._lastCmd = None - - def registerAuthenticator(self, auth): - """Register a new form of authentication - - When invoking the authenticate() method of IMAP4Client, the first - matching authentication scheme found will be used. The ordering is - that in which the server lists support authentication schemes. - - @type auth: Implementor of C{IClientAuthentication} - @param auth: The object to use to perform the client - side of this authentication scheme. - """ - self.authenticators[auth.getName().upper()] = auth - - def rawDataReceived(self, data): - if self.timeout > 0: - self.resetTimeout() - - self._pendingSize -= len(data) - if self._pendingSize > 0: - self._pendingBuffer.write(data) - else: - passon = '' - if self._pendingSize < 0: - data, passon = data[:self._pendingSize], data[self._pendingSize:] - self._pendingBuffer.write(data) - rest = self._pendingBuffer - self._pendingBuffer = None - self._pendingSize = None - rest.seek(0, 0) - self._parts.append(rest.read()) - self.setLineMode(passon.lstrip('\r\n')) - -# def sendLine(self, line): -# print 'S:', repr(line) -# return basic.LineReceiver.sendLine(self, line) - - def _setupForLiteral(self, rest, octets): - self._pendingBuffer = self.messageFile(octets) - self._pendingSize = octets - if self._parts is None: - self._parts = [rest, '\r\n'] - else: - self._parts.extend([rest, '\r\n']) - self.setRawMode() - - def connectionMade(self): - if self.timeout > 0: - self.setTimeout(self.timeout) - - def connectionLost(self, reason): - """We are no longer connected""" - if self.timeout > 0: - self.setTimeout(None) - if self.queued is not None: - queued = self.queued - self.queued = None - for cmd in queued: - cmd.defer.errback(reason) - if self.tags is not None: - tags = self.tags - self.tags = None - for cmd in tags.itervalues(): - if cmd is not None and cmd.defer is not None: - cmd.defer.errback(reason) - - - def lineReceived(self, line): - """ - Attempt to parse a single line from the server. - - @type line: C{str} - @param line: The line from the server, without the line delimiter. - - @raise IllegalServerResponse: If the line or some part of the line - does not represent an allowed message from the server at this time. - """ -# print 'C: ' + repr(line) - if self.timeout > 0: - self.resetTimeout() - - lastPart = line.rfind('{') - if lastPart != -1: - lastPart = line[lastPart + 1:] - if lastPart.endswith('}'): - # It's a literal a-comin' in - try: - octets = int(lastPart[:-1]) - except ValueError: - raise IllegalServerResponse(line) - if self._parts is None: - self._tag, parts = line.split(None, 1) - else: - parts = line - self._setupForLiteral(parts, octets) - return - - if self._parts is None: - # It isn't a literal at all - self._regularDispatch(line) - else: - # If an expression is in progress, no tag is required here - # Since we didn't find a literal indicator, this expression - # is done. - self._parts.append(line) - tag, rest = self._tag, ''.join(self._parts) - self._tag = self._parts = None - self.dispatchCommand(tag, rest) - - def timeoutConnection(self): - if self._lastCmd and self._lastCmd.defer is not None: - d, self._lastCmd.defer = self._lastCmd.defer, None - d.errback(TIMEOUT_ERROR) - - if self.queued: - for cmd in self.queued: - if cmd.defer is not None: - d, cmd.defer = cmd.defer, d - d.errback(TIMEOUT_ERROR) - - self.transport.loseConnection() - - def _regularDispatch(self, line): - parts = line.split(None, 1) - if len(parts) != 2: - parts.append('') - tag, rest = parts - self.dispatchCommand(tag, rest) - - def messageFile(self, octets): - """Create a file to which an incoming message may be written. - - @type octets: C{int} - @param octets: The number of octets which will be written to the file - - @rtype: Any object which implements C{write(string)} and - C{seek(int, int)} - @return: A file-like object - """ - if octets > self._memoryFileLimit: - return tempfile.TemporaryFile() - else: - return StringIO.StringIO() - - def makeTag(self): - tag = '%0.4X' % self.tagID - self.tagID += 1 - return tag - - def dispatchCommand(self, tag, rest): - if self.state is None: - f = self.response_UNAUTH - else: - f = getattr(self, 'response_' + self.state.upper(), None) - if f: - try: - f(tag, rest) - except: - log.err() - self.transport.loseConnection() - else: - log.err("Cannot dispatch: %s, %s, %s" % (self.state, tag, rest)) - self.transport.loseConnection() - - def response_UNAUTH(self, tag, rest): - if self.state is None: - # Server greeting, this is - status, rest = rest.split(None, 1) - if status.upper() == 'OK': - self.state = 'unauth' - elif status.upper() == 'PREAUTH': - self.state = 'auth' - else: - # XXX - This is rude. - self.transport.loseConnection() - raise IllegalServerResponse(tag + ' ' + rest) - - b, e = rest.find('['), rest.find(']') - if b != -1 and e != -1: - self.serverGreeting(self.__cbCapabilities(([rest[b:e]], None))) - else: - self.serverGreeting(None) - else: - self._defaultHandler(tag, rest) - - def response_AUTH(self, tag, rest): - self._defaultHandler(tag, rest) - - def _defaultHandler(self, tag, rest): - if tag == '*' or tag == '+': - if not self.waiting: - self._extraInfo([rest]) - else: - cmd = self.tags[self.waiting] - if tag == '+': - cmd.continuation(rest) - else: - cmd.lines.append(rest) - else: - try: - cmd = self.tags[tag] - except KeyError: - # XXX - This is rude. - self.transport.loseConnection() - raise IllegalServerResponse(tag + ' ' + rest) - else: - status, line = rest.split(None, 1) - if status == 'OK': - # Give them this last line, too - cmd.finish(rest, self._extraInfo) - else: - cmd.defer.errback(IMAP4Exception(line)) - del self.tags[tag] - self.waiting = None - self._flushQueue() - - def _flushQueue(self): - if self.queued: - cmd = self.queued.pop(0) - t = self.makeTag() - self.tags[t] = cmd - self.sendLine(cmd.format(t)) - self.waiting = t - - def _extraInfo(self, lines): - # XXX - This is terrible. - # XXX - Also, this should collapse temporally proximate calls into single - # invocations of IMailboxListener methods, where possible. - flags = {} - recent = exists = None - for L in lines: - if L.find('EXISTS') != -1: - exists = int(L.split()[0]) - elif L.find('RECENT') != -1: - recent = int(L.split()[0]) - elif L.find('READ-ONLY') != -1: - self.modeChanged(0) - elif L.find('READ-WRITE') != -1: - self.modeChanged(1) - elif L.find('FETCH') != -1: - for (mId, fetched) in self.__cbFetch(([L], None)).iteritems(): - sum = [] - for f in fetched.get('FLAGS', []): - sum.append(f) - flags.setdefault(mId, []).extend(sum) - else: - log.msg('Unhandled unsolicited response: ' + repr(L)) - if flags: - self.flagsChanged(flags) - if recent is not None or exists is not None: - self.newMessages(exists, recent) - - def sendCommand(self, cmd): - cmd.defer = defer.Deferred() - if self.waiting: - self.queued.append(cmd) - return cmd.defer - t = self.makeTag() - self.tags[t] = cmd - self.sendLine(cmd.format(t)) - self.waiting = t - self._lastCmd = cmd - return cmd.defer - - def getCapabilities(self, useCache=1): - """Request the capabilities available on this server. - - This command is allowed in any state of connection. - - @type useCache: C{bool} - @param useCache: Specify whether to use the capability-cache or to - re-retrieve the capabilities from the server. Server capabilities - should never change, so for normal use, this flag should never be - false. - - @rtype: C{Deferred} - @return: A deferred whose callback will be invoked with a - dictionary mapping capability types to lists of supported - mechanisms, or to None if a support list is not applicable. - """ - if useCache and self._capCache is not None: - return defer.succeed(self._capCache) - cmd = 'CAPABILITY' - resp = ('CAPABILITY',) - d = self.sendCommand(Command(cmd, wantResponse=resp)) - d.addCallback(self.__cbCapabilities) - return d - - def __cbCapabilities(self, (lines, tagline)): - caps = {} - for rest in lines: - rest = rest.split()[1:] - for cap in rest: - parts = cap.split('=', 1) - if len(parts) == 1: - category, value = parts[0], None - else: - category, value = parts - caps.setdefault(category, []).append(value) - - # Preserve a non-ideal API for backwards compatibility. It would - # probably be entirely sensible to have an object with a wider API than - # dict here so this could be presented less insanely. - for category in caps: - if caps[category] == [None]: - caps[category] = None - self._capCache = caps - return caps - - def logout(self): - """Inform the server that we are done with the connection. - - This command is allowed in any state of connection. - - @rtype: C{Deferred} - @return: A deferred whose callback will be invoked with None - when the proper server acknowledgement has been received. - """ - d = self.sendCommand(Command('LOGOUT', wantResponse=('BYE',))) - d.addCallback(self.__cbLogout) - return d - - def __cbLogout(self, (lines, tagline)): - self.transport.loseConnection() - # We don't particularly care what the server said - return None - - - def noop(self): - """Perform no operation. - - This command is allowed in any state of connection. - - @rtype: C{Deferred} - @return: A deferred whose callback will be invoked with a list - of untagged status updates the server responds with. - """ - d = self.sendCommand(Command('NOOP')) - d.addCallback(self.__cbNoop) - return d - - def __cbNoop(self, (lines, tagline)): - # Conceivable, this is elidable. - # It is, afterall, a no-op. - return lines - - def startTLS(self, contextFactory=None): - """ - Initiates a 'STARTTLS' request and negotiates the TLS / SSL - Handshake. - - @param contextFactory: The TLS / SSL Context Factory to - leverage. If the contextFactory is None the IMAP4Client will - either use the current TLS / SSL Context Factory or attempt to - create a new one. - - @type contextFactory: C{ssl.ClientContextFactory} - - @return: A Deferred which fires when the transport has been - secured according to the given contextFactory, or which fails - if the transport cannot be secured. - """ - assert not self.startedTLS, "Client and Server are currently communicating via TLS" - - if contextFactory is None: - contextFactory = self._getContextFactory() - - if contextFactory is None: - return defer.fail(IMAP4Exception( - "IMAP4Client requires a TLS context to " - "initiate the STARTTLS handshake")) - - if 'STARTTLS' not in self._capCache: - return defer.fail(IMAP4Exception( - "Server does not support secure communication " - "via TLS / SSL")) - - tls = interfaces.ITLSTransport(self.transport, None) - if tls is None: - return defer.fail(IMAP4Exception( - "IMAP4Client transport does not implement " - "interfaces.ITLSTransport")) - - d = self.sendCommand(Command('STARTTLS')) - d.addCallback(self._startedTLS, contextFactory) - d.addCallback(lambda _: self.getCapabilities()) - return d - - - def authenticate(self, secret): - """Attempt to enter the authenticated state with the server - - This command is allowed in the Non-Authenticated state. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked if the authentication - succeeds and whose errback will be invoked otherwise. - """ - if self._capCache is None: - d = self.getCapabilities() - else: - d = defer.succeed(self._capCache) - d.addCallback(self.__cbAuthenticate, secret) - return d - - def __cbAuthenticate(self, caps, secret): - auths = caps.get('AUTH', ()) - for scheme in auths: - if scheme.upper() in self.authenticators: - cmd = Command('AUTHENTICATE', scheme, (), - self.__cbContinueAuth, scheme, - secret) - return self.sendCommand(cmd) - - if self.startedTLS: - return defer.fail(NoSupportedAuthentication( - auths, self.authenticators.keys())) - else: - def ebStartTLS(err): - err.trap(IMAP4Exception) - # We couldn't negotiate TLS for some reason - return defer.fail(NoSupportedAuthentication( - auths, self.authenticators.keys())) - - d = self.startTLS() - d.addErrback(ebStartTLS) - d.addCallback(lambda _: self.getCapabilities()) - d.addCallback(self.__cbAuthTLS, secret) - return d - - - def __cbContinueAuth(self, rest, scheme, secret): - try: - chal = base64.decodestring(rest + '\n') - except binascii.Error: - self.sendLine('*') - raise IllegalServerResponse(rest) - self.transport.loseConnection() - else: - auth = self.authenticators[scheme] - chal = auth.challengeResponse(secret, chal) - self.sendLine(base64.encodestring(chal).strip()) - - def __cbAuthTLS(self, caps, secret): - auths = caps.get('AUTH', ()) - for scheme in auths: - if scheme.upper() in self.authenticators: - cmd = Command('AUTHENTICATE', scheme, (), - self.__cbContinueAuth, scheme, - secret) - return self.sendCommand(cmd) - raise NoSupportedAuthentication(auths, self.authenticators.keys()) - - - def login(self, username, password): - """Authenticate with the server using a username and password - - This command is allowed in the Non-Authenticated state. If the - server supports the STARTTLS capability and our transport supports - TLS, TLS is negotiated before the login command is issued. - - A more secure way to log in is to use C{startTLS} or - C{authenticate} or both. - - @type username: C{str} - @param username: The username to log in with - - @type password: C{str} - @param password: The password to log in with - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked if login is successful - and whose errback is invoked otherwise. - """ - d = maybeDeferred(self.getCapabilities) - d.addCallback(self.__cbLoginCaps, username, password) - return d - - def serverGreeting(self, caps): - """Called when the server has sent us a greeting. - - @type caps: C{dict} - @param caps: Capabilities the server advertised in its greeting. - """ - - def _getContextFactory(self): - if self.context is not None: - return self.context - try: - from twisted.internet import ssl - except ImportError: - return None - else: - context = ssl.ClientContextFactory() - context.method = ssl.SSL.TLSv1_METHOD - return context - - def __cbLoginCaps(self, capabilities, username, password): - # If the server advertises STARTTLS, we might want to try to switch to TLS - tryTLS = 'STARTTLS' in capabilities - - # If our transport supports switching to TLS, we might want to try to switch to TLS. - tlsableTransport = interfaces.ITLSTransport(self.transport, None) is not None - - # If our transport is not already using TLS, we might want to try to switch to TLS. - nontlsTransport = interfaces.ISSLTransport(self.transport, None) is None - - if not self.startedTLS and tryTLS and tlsableTransport and nontlsTransport: - d = self.startTLS() - - d.addCallbacks( - self.__cbLoginTLS, - self.__ebLoginTLS, - callbackArgs=(username, password), - ) - return d - else: - if nontlsTransport: - log.msg("Server has no TLS support. logging in over cleartext!") - args = ' '.join((_quote(username), _quote(password))) - return self.sendCommand(Command('LOGIN', args)) - - def _startedTLS(self, result, context): - self.transport.startTLS(context) - self._capCache = None - self.startedTLS = True - return result - - def __cbLoginTLS(self, result, username, password): - args = ' '.join((_quote(username), _quote(password))) - return self.sendCommand(Command('LOGIN', args)) - - def __ebLoginTLS(self, failure): - log.err(failure) - return failure - - def namespace(self): - """Retrieve information about the namespaces available to this account - - This command is allowed in the Authenticated and Selected states. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with namespace - information. An example of this information is:: - - [[['', '/']], [], []] - - which indicates a single personal namespace called '' with '/' - as its hierarchical delimiter, and no shared or user namespaces. - """ - cmd = 'NAMESPACE' - resp = ('NAMESPACE',) - d = self.sendCommand(Command(cmd, wantResponse=resp)) - d.addCallback(self.__cbNamespace) - return d - - def __cbNamespace(self, (lines, last)): - for line in lines: - parts = line.split(None, 1) - if len(parts) == 2: - if parts[0] == 'NAMESPACE': - # XXX UGGG parsing hack :( - r = parseNestedParens('(' + parts[1] + ')')[0] - return [e or [] for e in r] - log.err("No NAMESPACE response to NAMESPACE command") - return [[], [], []] - - def select(self, mailbox): - """Select a mailbox - - This command is allowed in the Authenticated and Selected states. - - @type mailbox: C{str} - @param mailbox: The name of the mailbox to select - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with mailbox - information if the select is successful and whose errback is - invoked otherwise. Mailbox information consists of a dictionary - with the following keys and values:: - - FLAGS: A list of strings containing the flags settable on - messages in this mailbox. - - EXISTS: An integer indicating the number of messages in this - mailbox. - - RECENT: An integer indicating the number of \"recent\" - messages in this mailbox. - - UNSEEN: An integer indicating the number of messages not - flagged \\Seen in this mailbox. - - PERMANENTFLAGS: A list of strings containing the flags that - can be permanently set on messages in this mailbox. - - UIDVALIDITY: An integer uniquely identifying this mailbox. - """ - cmd = 'SELECT' - args = _prepareMailboxName(mailbox) - resp = ('FLAGS', 'EXISTS', 'RECENT', 'UNSEEN', 'PERMANENTFLAGS', 'UIDVALIDITY') - d = self.sendCommand(Command(cmd, args, wantResponse=resp)) - d.addCallback(self.__cbSelect, 1) - return d - - def examine(self, mailbox): - """Select a mailbox in read-only mode - - This command is allowed in the Authenticated and Selected states. - - @type mailbox: C{str} - @param mailbox: The name of the mailbox to examine - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with mailbox - information if the examine is successful and whose errback - is invoked otherwise. Mailbox information consists of a dictionary - with the following keys and values:: - - 'FLAGS': A list of strings containing the flags settable on - messages in this mailbox. - - 'EXISTS': An integer indicating the number of messages in this - mailbox. - - 'RECENT': An integer indicating the number of \"recent\" - messages in this mailbox. - - 'UNSEEN': An integer indicating the number of messages not - flagged \\Seen in this mailbox. - - 'PERMANENTFLAGS': A list of strings containing the flags that - can be permanently set on messages in this mailbox. - - 'UIDVALIDITY': An integer uniquely identifying this mailbox. - """ - cmd = 'EXAMINE' - args = _prepareMailboxName(mailbox) - resp = ('FLAGS', 'EXISTS', 'RECENT', 'UNSEEN', 'PERMANENTFLAGS', 'UIDVALIDITY') - d = self.sendCommand(Command(cmd, args, wantResponse=resp)) - d.addCallback(self.__cbSelect, 0) - return d - - def __cbSelect(self, (lines, tagline), rw): - # In the absense of specification, we are free to assume: - # READ-WRITE access - datum = {'READ-WRITE': rw} - lines.append(tagline) - for parts in lines: - split = parts.split() - if len(split) == 2: - if split[1].upper().strip() == 'EXISTS': - try: - datum['EXISTS'] = int(split[0]) - except ValueError: - raise IllegalServerResponse(parts) - elif split[1].upper().strip() == 'RECENT': - try: - datum['RECENT'] = int(split[0]) - except ValueError: - raise IllegalServerResponse(parts) - else: - log.err('Unhandled SELECT response (1): ' + parts) - elif split[0].upper().strip() == 'FLAGS': - split = parts.split(None, 1) - datum['FLAGS'] = tuple(parseNestedParens(split[1])[0]) - elif split[0].upper().strip() == 'OK': - begin = parts.find('[') - end = parts.find(']') - if begin == -1 or end == -1: - raise IllegalServerResponse(parts) - else: - content = parts[begin+1:end].split(None, 1) - if len(content) >= 1: - key = content[0].upper() - if key == 'READ-ONLY': - datum['READ-WRITE'] = 0 - elif key == 'READ-WRITE': - datum['READ-WRITE'] = 1 - elif key == 'UIDVALIDITY': - try: - datum['UIDVALIDITY'] = int(content[1]) - except ValueError: - raise IllegalServerResponse(parts) - elif key == 'UNSEEN': - try: - datum['UNSEEN'] = int(content[1]) - except ValueError: - raise IllegalServerResponse(parts) - elif key == 'UIDNEXT': - datum['UIDNEXT'] = int(content[1]) - elif key == 'PERMANENTFLAGS': - datum['PERMANENTFLAGS'] = tuple(parseNestedParens(content[1])[0]) - else: - log.err('Unhandled SELECT response (2): ' + parts) - else: - log.err('Unhandled SELECT response (3): ' + parts) - else: - log.err('Unhandled SELECT response (4): ' + parts) - return datum - - def create(self, name): - """Create a new mailbox on the server - - This command is allowed in the Authenticated and Selected states. - - @type name: C{str} - @param name: The name of the mailbox to create. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked if the mailbox creation - is successful and whose errback is invoked otherwise. - """ - return self.sendCommand(Command('CREATE', _prepareMailboxName(name))) - - def delete(self, name): - """Delete a mailbox - - This command is allowed in the Authenticated and Selected states. - - @type name: C{str} - @param name: The name of the mailbox to delete. - - @rtype: C{Deferred} - @return: A deferred whose calblack is invoked if the mailbox is - deleted successfully and whose errback is invoked otherwise. - """ - return self.sendCommand(Command('DELETE', _prepareMailboxName(name))) - - def rename(self, oldname, newname): - """Rename a mailbox - - This command is allowed in the Authenticated and Selected states. - - @type oldname: C{str} - @param oldname: The current name of the mailbox to rename. - - @type newname: C{str} - @param newname: The new name to give the mailbox. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked if the rename is - successful and whose errback is invoked otherwise. - """ - oldname = _prepareMailboxName(oldname) - newname = _prepareMailboxName(newname) - return self.sendCommand(Command('RENAME', ' '.join((oldname, newname)))) - - def subscribe(self, name): - """Add a mailbox to the subscription list - - This command is allowed in the Authenticated and Selected states. - - @type name: C{str} - @param name: The mailbox to mark as 'active' or 'subscribed' - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked if the subscription - is successful and whose errback is invoked otherwise. - """ - return self.sendCommand(Command('SUBSCRIBE', _prepareMailboxName(name))) - - def unsubscribe(self, name): - """Remove a mailbox from the subscription list - - This command is allowed in the Authenticated and Selected states. - - @type name: C{str} - @param name: The mailbox to unsubscribe - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked if the unsubscription - is successful and whose errback is invoked otherwise. - """ - return self.sendCommand(Command('UNSUBSCRIBE', _prepareMailboxName(name))) - - def list(self, reference, wildcard): - """List a subset of the available mailboxes - - This command is allowed in the Authenticated and Selected states. - - @type reference: C{str} - @param reference: The context in which to interpret C{wildcard} - - @type wildcard: C{str} - @param wildcard: The pattern of mailbox names to match, optionally - including either or both of the '*' and '%' wildcards. '*' will - match zero or more characters and cross hierarchical boundaries. - '%' will also match zero or more characters, but is limited to a - single hierarchical level. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a list of C{tuple}s, - the first element of which is a C{tuple} of mailbox flags, the second - element of which is the hierarchy delimiter for this mailbox, and the - third of which is the mailbox name; if the command is unsuccessful, - the deferred's errback is invoked instead. - """ - cmd = 'LIST' - args = '"%s" "%s"' % (reference, wildcard.encode('imap4-utf-7')) - resp = ('LIST',) - d = self.sendCommand(Command(cmd, args, wantResponse=resp)) - d.addCallback(self.__cbList, 'LIST') - return d - - def lsub(self, reference, wildcard): - """List a subset of the subscribed available mailboxes - - This command is allowed in the Authenticated and Selected states. - - The parameters and returned object are the same as for the C{list} - method, with one slight difference: Only mailboxes which have been - subscribed can be included in the resulting list. - """ - cmd = 'LSUB' - args = '"%s" "%s"' % (reference, wildcard.encode('imap4-utf-7')) - resp = ('LSUB',) - d = self.sendCommand(Command(cmd, args, wantResponse=resp)) - d.addCallback(self.__cbList, 'LSUB') - return d - - def __cbList(self, (lines, last), command): - results = [] - for L in lines: - parts = parseNestedParens(L) - if len(parts) != 4: - raise IllegalServerResponse, L - if parts[0] == command: - parts[1] = tuple(parts[1]) - results.append(tuple(parts[1:])) - return results - - def status(self, mailbox, *names): - """Retrieve the status of the given mailbox - - This command is allowed in the Authenticated and Selected states. - - @type mailbox: C{str} - @param mailbox: The name of the mailbox to query - - @type names: C{str} - @param names: The status names to query. These may be any number of: - MESSAGES, RECENT, UIDNEXT, UIDVALIDITY, and UNSEEN. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with the status information - if the command is successful and whose errback is invoked otherwise. - """ - cmd = 'STATUS' - args = "%s (%s)" % (_prepareMailboxName(mailbox), ' '.join(names)) - resp = ('STATUS',) - d = self.sendCommand(Command(cmd, args, wantResponse=resp)) - d.addCallback(self.__cbStatus) - return d - - def __cbStatus(self, (lines, last)): - status = {} - for line in lines: - parts = parseNestedParens(line) - if parts[0] == 'STATUS': - items = parts[2] - items = [items[i:i+2] for i in range(0, len(items), 2)] - status.update(dict(items)) - for k in status.keys(): - t = self.STATUS_TRANSFORMATIONS.get(k) - if t: - try: - status[k] = t(status[k]) - except Exception, e: - raise IllegalServerResponse('(%s %s): %s' % (k, status[k], str(e))) - return status - - def append(self, mailbox, message, flags = (), date = None): - """Add the given message to the given mailbox. - - This command is allowed in the Authenticated and Selected states. - - @type mailbox: C{str} - @param mailbox: The mailbox to which to add this message. - - @type message: Any file-like object - @param message: The message to add, in RFC822 format. Newlines - in this file should be \\r\\n-style. - - @type flags: Any iterable of C{str} - @param flags: The flags to associated with this message. - - @type date: C{str} - @param date: The date to associate with this message. This should - be of the format DD-MM-YYYY HH:MM:SS +/-HHMM. For example, in - Eastern Standard Time, on July 1st 2004 at half past 1 PM, - \"01-07-2004 13:30:00 -0500\". - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked when this command - succeeds or whose errback is invoked if it fails. - """ - message.seek(0, 2) - L = message.tell() - message.seek(0, 0) - fmt = '%s (%s)%s {%d}' - if date: - date = ' "%s"' % date - else: - date = '' - cmd = fmt % ( - _prepareMailboxName(mailbox), ' '.join(flags), - date, L - ) - d = self.sendCommand(Command('APPEND', cmd, (), self.__cbContinueAppend, message)) - return d - - def __cbContinueAppend(self, lines, message): - s = basic.FileSender() - return s.beginFileTransfer(message, self.transport, None - ).addCallback(self.__cbFinishAppend) - - def __cbFinishAppend(self, foo): - self.sendLine('') - - def check(self): - """Tell the server to perform a checkpoint - - This command is allowed in the Selected state. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked when this command - succeeds or whose errback is invoked if it fails. - """ - return self.sendCommand(Command('CHECK')) - - def close(self): - """Return the connection to the Authenticated state. - - This command is allowed in the Selected state. - - Issuing this command will also remove all messages flagged \\Deleted - from the selected mailbox if it is opened in read-write mode, - otherwise it indicates success by no messages are removed. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked when the command - completes successfully or whose errback is invoked if it fails. - """ - return self.sendCommand(Command('CLOSE')) - - def expunge(self): - """Return the connection to the Authenticate state. - - This command is allowed in the Selected state. - - Issuing this command will perform the same actions as issuing the - close command, but will also generate an 'expunge' response for - every message deleted. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a list of the - 'expunge' responses when this command is successful or whose errback - is invoked otherwise. - """ - cmd = 'EXPUNGE' - resp = ('EXPUNGE',) - d = self.sendCommand(Command(cmd, wantResponse=resp)) - d.addCallback(self.__cbExpunge) - return d - - def __cbExpunge(self, (lines, last)): - ids = [] - for line in lines: - parts = line.split(None, 1) - if len(parts) == 2: - if parts[1] == 'EXPUNGE': - try: - ids.append(int(parts[0])) - except ValueError: - raise IllegalServerResponse, line - return ids - - def search(self, *queries, **kwarg): - """Search messages in the currently selected mailbox - - This command is allowed in the Selected state. - - Any non-zero number of queries are accepted by this method, as - returned by the C{Query}, C{Or}, and C{Not} functions. - - One keyword argument is accepted: if uid is passed in with a non-zero - value, the server is asked to return message UIDs instead of message - sequence numbers. - - @rtype: C{Deferred} - @return: A deferred whose callback will be invoked with a list of all - the message sequence numbers return by the search, or whose errback - will be invoked if there is an error. - """ - if kwarg.get('uid'): - cmd = 'UID SEARCH' - else: - cmd = 'SEARCH' - args = ' '.join(queries) - d = self.sendCommand(Command(cmd, args, wantResponse=(cmd,))) - d.addCallback(self.__cbSearch) - return d - - def __cbSearch(self, (lines, end)): - ids = [] - for line in lines: - parts = line.split(None, 1) - if len(parts) == 2: - if parts[0] == 'SEARCH': - try: - ids.extend(map(int, parts[1].split())) - except ValueError: - raise IllegalServerResponse, line - return ids - - def fetchUID(self, messages, uid=0): - """Retrieve the unique identifier for one or more messages - - This command is allowed in the Selected state. - - @type messages: C{MessageSet} or C{str} - @param messages: A message sequence set - - @type uid: C{bool} - @param uid: Indicates whether the message sequence set is of message - numbers or of unique message IDs. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a dict mapping - message sequence numbers to unique message identifiers, or whose - errback is invoked if there is an error. - """ - d = self._fetch(messages, useUID=uid, uid=1) - d.addCallback(self.__cbFetch) - return d - - def fetchFlags(self, messages, uid=0): - """Retrieve the flags for one or more messages - - This command is allowed in the Selected state. - - @type messages: C{MessageSet} or C{str} - @param messages: The messages for which to retrieve flags. - - @type uid: C{bool} - @param uid: Indicates whether the message sequence set is of message - numbers or of unique message IDs. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a dict mapping - message numbers to lists of flags, or whose errback is invoked if - there is an error. - """ - d = self._fetch(str(messages), useUID=uid, flags=1) - d.addCallback(self.__cbFetch) - return d - - def fetchInternalDate(self, messages, uid=0): - """Retrieve the internal date associated with one or more messages - - This command is allowed in the Selected state. - - @type messages: C{MessageSet} or C{str} - @param messages: The messages for which to retrieve the internal date. - - @type uid: C{bool} - @param uid: Indicates whether the message sequence set is of message - numbers or of unique message IDs. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a dict mapping - message numbers to date strings, or whose errback is invoked - if there is an error. Date strings take the format of - \"day-month-year time timezone\". - """ - d = self._fetch(str(messages), useUID=uid, internaldate=1) - d.addCallback(self.__cbFetch) - return d - - def fetchEnvelope(self, messages, uid=0): - """Retrieve the envelope data for one or more messages - - This command is allowed in the Selected state. - - @type messages: C{MessageSet} or C{str} - @param messages: The messages for which to retrieve envelope data. - - @type uid: C{bool} - @param uid: Indicates whether the message sequence set is of message - numbers or of unique message IDs. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a dict mapping - message numbers to envelope data, or whose errback is invoked - if there is an error. Envelope data consists of a sequence of the - date, subject, from, sender, reply-to, to, cc, bcc, in-reply-to, - and message-id header fields. The date, subject, in-reply-to, and - message-id fields are strings, while the from, sender, reply-to, - to, cc, and bcc fields contain address data. Address data consists - of a sequence of name, source route, mailbox name, and hostname. - Fields which are not present for a particular address may be C{None}. - """ - d = self._fetch(str(messages), useUID=uid, envelope=1) - d.addCallback(self.__cbFetch) - return d - - def fetchBodyStructure(self, messages, uid=0): - """Retrieve the structure of the body of one or more messages - - This command is allowed in the Selected state. - - @type messages: C{MessageSet} or C{str} - @param messages: The messages for which to retrieve body structure - data. - - @type uid: C{bool} - @param uid: Indicates whether the message sequence set is of message - numbers or of unique message IDs. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a dict mapping - message numbers to body structure data, or whose errback is invoked - if there is an error. Body structure data describes the MIME-IMB - format of a message and consists of a sequence of mime type, mime - subtype, parameters, content id, description, encoding, and size. - The fields following the size field are variable: if the mime - type/subtype is message/rfc822, the contained message's envelope - information, body structure data, and number of lines of text; if - the mime type is text, the number of lines of text. Extension fields - may also be included; if present, they are: the MD5 hash of the body, - body disposition, body language. - """ - d = self._fetch(messages, useUID=uid, bodystructure=1) - d.addCallback(self.__cbFetch) - return d - - def fetchSimplifiedBody(self, messages, uid=0): - """Retrieve the simplified body structure of one or more messages - - This command is allowed in the Selected state. - - @type messages: C{MessageSet} or C{str} - @param messages: A message sequence set - - @type uid: C{bool} - @param uid: Indicates whether the message sequence set is of message - numbers or of unique message IDs. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a dict mapping - message numbers to body data, or whose errback is invoked - if there is an error. The simplified body structure is the same - as the body structure, except that extension fields will never be - present. - """ - d = self._fetch(messages, useUID=uid, body=1) - d.addCallback(self.__cbFetch) - return d - - def fetchMessage(self, messages, uid=0): - """Retrieve one or more entire messages - - This command is allowed in the Selected state. - - @type messages: C{MessageSet} or C{str} - @param messages: A message sequence set - - @type uid: C{bool} - @param uid: Indicates whether the message sequence set is of message - numbers or of unique message IDs. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a dict mapping - message objects (as returned by self.messageFile(), file objects by - default), to additional information, or whose errback is invoked if - there is an error. - """ - d = self._fetch(messages, useUID=uid, rfc822=1) - d.addCallback(self.__cbFetch) - return d - - def fetchHeaders(self, messages, uid=0): - """Retrieve headers of one or more messages - - This command is allowed in the Selected state. - - @type messages: C{MessageSet} or C{str} - @param messages: A message sequence set - - @type uid: C{bool} - @param uid: Indicates whether the message sequence set is of message - numbers or of unique message IDs. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a dict mapping - message numbers to dicts of message headers, or whose errback is - invoked if there is an error. - """ - d = self._fetch(messages, useUID=uid, rfc822header=1) - d.addCallback(self.__cbFetch) - return d - - def fetchBody(self, messages, uid=0): - """Retrieve body text of one or more messages - - This command is allowed in the Selected state. - - @type messages: C{MessageSet} or C{str} - @param messages: A message sequence set - - @type uid: C{bool} - @param uid: Indicates whether the message sequence set is of message - numbers or of unique message IDs. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a dict mapping - message numbers to file-like objects containing body text, or whose - errback is invoked if there is an error. - """ - d = self._fetch(messages, useUID=uid, rfc822text=1) - d.addCallback(self.__cbFetch) - return d - - def fetchSize(self, messages, uid=0): - """Retrieve the size, in octets, of one or more messages - - This command is allowed in the Selected state. - - @type messages: C{MessageSet} or C{str} - @param messages: A message sequence set - - @type uid: C{bool} - @param uid: Indicates whether the message sequence set is of message - numbers or of unique message IDs. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a dict mapping - message numbers to sizes, or whose errback is invoked if there is - an error. - """ - d = self._fetch(messages, useUID=uid, rfc822size=1) - d.addCallback(self.__cbFetch) - return d - - def fetchFull(self, messages, uid=0): - """Retrieve several different fields of one or more messages - - This command is allowed in the Selected state. This is equivalent - to issuing all of the C{fetchFlags}, C{fetchInternalDate}, - C{fetchSize}, C{fetchEnvelope}, and C{fetchSimplifiedBody} - functions. - - @type messages: C{MessageSet} or C{str} - @param messages: A message sequence set - - @type uid: C{bool} - @param uid: Indicates whether the message sequence set is of message - numbers or of unique message IDs. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a dict mapping - message numbers to dict of the retrieved data values, or whose - errback is invoked if there is an error. They dictionary keys - are "flags", "date", "size", "envelope", and "body". - """ - d = self._fetch( - messages, useUID=uid, flags=1, internaldate=1, - rfc822size=1, envelope=1, body=1 - ) - d.addCallback(self.__cbFetch) - return d - - def fetchAll(self, messages, uid=0): - """Retrieve several different fields of one or more messages - - This command is allowed in the Selected state. This is equivalent - to issuing all of the C{fetchFlags}, C{fetchInternalDate}, - C{fetchSize}, and C{fetchEnvelope} functions. - - @type messages: C{MessageSet} or C{str} - @param messages: A message sequence set - - @type uid: C{bool} - @param uid: Indicates whether the message sequence set is of message - numbers or of unique message IDs. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a dict mapping - message numbers to dict of the retrieved data values, or whose - errback is invoked if there is an error. They dictionary keys - are "flags", "date", "size", and "envelope". - """ - d = self._fetch( - messages, useUID=uid, flags=1, internaldate=1, - rfc822size=1, envelope=1 - ) - d.addCallback(self.__cbFetch) - return d - - def fetchFast(self, messages, uid=0): - """Retrieve several different fields of one or more messages - - This command is allowed in the Selected state. This is equivalent - to issuing all of the C{fetchFlags}, C{fetchInternalDate}, and - C{fetchSize} functions. - - @type messages: C{MessageSet} or C{str} - @param messages: A message sequence set - - @type uid: C{bool} - @param uid: Indicates whether the message sequence set is of message - numbers or of unique message IDs. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a dict mapping - message numbers to dict of the retrieved data values, or whose - errback is invoked if there is an error. They dictionary keys are - "flags", "date", and "size". - """ - d = self._fetch( - messages, useUID=uid, flags=1, internaldate=1, rfc822size=1 - ) - d.addCallback(self.__cbFetch) - return d - - def __cbFetch(self, (lines, last)): - flags = {} - for line in lines: - parts = line.split(None, 2) - if len(parts) == 3: - if parts[1] == 'FETCH': - try: - id = int(parts[0]) - except ValueError: - raise IllegalServerResponse, line - else: - data = parseNestedParens(parts[2]) - while len(data) == 1 and isinstance(data, types.ListType): - data = data[0] - while data: - if len(data) < 2: - raise IllegalServerResponse("Not enough arguments", data) - flags.setdefault(id, {})[data[0]] = data[1] - del data[:2] - else: - print '(2)Ignoring ', parts - else: - print '(3)Ignoring ', parts - return flags - - def fetchSpecific(self, messages, uid=0, headerType=None, - headerNumber=None, headerArgs=None, peek=None, - offset=None, length=None): - """Retrieve a specific section of one or more messages - - @type messages: C{MessageSet} or C{str} - @param messages: A message sequence set - - @type uid: C{bool} - @param uid: Indicates whether the message sequence set is of message - numbers or of unique message IDs. - - @type headerType: C{str} - @param headerType: If specified, must be one of HEADER, - HEADER.FIELDS, HEADER.FIELDS.NOT, MIME, or TEXT, and will determine - which part of the message is retrieved. For HEADER.FIELDS and - HEADER.FIELDS.NOT, C{headerArgs} must be a sequence of header names. - For MIME, C{headerNumber} must be specified. - - @type headerNumber: C{int} or C{int} sequence - @param headerNumber: The nested rfc822 index specifying the - entity to retrieve. For example, C{1} retrieves the first - entity of the message, and C{(2, 1, 3}) retrieves the 3rd - entity inside the first entity inside the second entity of - the message. - - @type headerArgs: A sequence of C{str} - @param headerArgs: If C{headerType} is HEADER.FIELDS, these are the - headers to retrieve. If it is HEADER.FIELDS.NOT, these are the - headers to exclude from retrieval. - - @type peek: C{bool} - @param peek: If true, cause the server to not set the \\Seen - flag on this message as a result of this command. - - @type offset: C{int} - @param offset: The number of octets at the beginning of the result - to skip. - - @type length: C{int} - @param length: The number of octets to retrieve. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a mapping of - message numbers to retrieved data, or whose errback is invoked - if there is an error. - """ - fmt = '%s BODY%s[%s%s%s]%s' - if headerNumber is None: - number = '' - elif isinstance(headerNumber, types.IntType): - number = str(headerNumber) - else: - number = '.'.join(headerNumber) - if headerType is None: - header = '' - elif number: - header = '.' + headerType - else: - header = headerType - if header: - if headerArgs is not None: - payload = ' (%s)' % ' '.join(headerArgs) - else: - payload = ' ()' - else: - payload = '' - if offset is None: - extra = '' - else: - extra = '<%d.%d>' % (offset, length) - fetch = uid and 'UID FETCH' or 'FETCH' - cmd = fmt % (messages, peek and '.PEEK' or '', number, header, payload, extra) - d = self.sendCommand(Command(fetch, cmd, wantResponse=('FETCH',))) - d.addCallback(self.__cbFetchSpecific) - return d - - def __cbFetchSpecific(self, (lines, last)): - info = {} - for line in lines: - parts = line.split(None, 2) - if len(parts) == 3: - if parts[1] == 'FETCH': - try: - id = int(parts[0]) - except ValueError: - raise IllegalServerResponse, line - else: - info[id] = parseNestedParens(parts[2]) - return info - - def _fetch(self, messages, useUID=0, **terms): - fetch = useUID and 'UID FETCH' or 'FETCH' - - if 'rfc822text' in terms: - del terms['rfc822text'] - terms['rfc822.text'] = True - if 'rfc822size' in terms: - del terms['rfc822size'] - terms['rfc822.size'] = True - if 'rfc822header' in terms: - del terms['rfc822header'] - terms['rfc822.header'] = True - - cmd = '%s (%s)' % (messages, ' '.join([s.upper() for s in terms.keys()])) - d = self.sendCommand(Command(fetch, cmd, wantResponse=('FETCH',))) - return d - - def setFlags(self, messages, flags, silent=1, uid=0): - """Set the flags for one or more messages. - - This command is allowed in the Selected state. - - @type messages: C{MessageSet} or C{str} - @param messages: A message sequence set - - @type flags: Any iterable of C{str} - @param flags: The flags to set - - @type silent: C{bool} - @param silent: If true, cause the server to supress its verbose - response. - - @type uid: C{bool} - @param uid: Indicates whether the message sequence set is of message - numbers or of unique message IDs. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a list of the - the server's responses (C{[]} if C{silent} is true) or whose - errback is invoked if there is an error. - """ - return self._store(str(messages), silent and 'FLAGS.SILENT' or 'FLAGS', flags, uid) - - def addFlags(self, messages, flags, silent=1, uid=0): - """Add to the set flags for one or more messages. - - This command is allowed in the Selected state. - - @type messages: C{MessageSet} or C{str} - @param messages: A message sequence set - - @type flags: Any iterable of C{str} - @param flags: The flags to set - - @type silent: C{bool} - @param silent: If true, cause the server to supress its verbose - response. - - @type uid: C{bool} - @param uid: Indicates whether the message sequence set is of message - numbers or of unique message IDs. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a list of the - the server's responses (C{[]} if C{silent} is true) or whose - errback is invoked if there is an error. - """ - return self._store(str(messages), silent and '+FLAGS.SILENT' or '+FLAGS', flags, uid) - - def removeFlags(self, messages, flags, silent=1, uid=0): - """Remove from the set flags for one or more messages. - - This command is allowed in the Selected state. - - @type messages: C{MessageSet} or C{str} - @param messages: A message sequence set - - @type flags: Any iterable of C{str} - @param flags: The flags to set - - @type silent: C{bool} - @param silent: If true, cause the server to supress its verbose - response. - - @type uid: C{bool} - @param uid: Indicates whether the message sequence set is of message - numbers or of unique message IDs. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a list of the - the server's responses (C{[]} if C{silent} is true) or whose - errback is invoked if there is an error. - """ - return self._store(str(messages), silent and '-FLAGS.SILENT' or '-FLAGS', flags, uid) - - def _store(self, messages, cmd, flags, uid): - store = uid and 'UID STORE' or 'STORE' - args = ' '.join((messages, cmd, '(%s)' % ' '.join(flags))) - d = self.sendCommand(Command(store, args, wantResponse=('FETCH',))) - d.addCallback(self.__cbFetch) - return d - - def copy(self, messages, mailbox, uid): - """Copy the specified messages to the specified mailbox. - - This command is allowed in the Selected state. - - @type messages: C{str} - @param messages: A message sequence set - - @type mailbox: C{str} - @param mailbox: The mailbox to which to copy the messages - - @type uid: C{bool} - @param uid: If true, the C{messages} refers to message UIDs, rather - than message sequence numbers. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with a true value - when the copy is successful, or whose errback is invoked if there - is an error. - """ - if uid: - cmd = 'UID COPY' - else: - cmd = 'COPY' - args = '%s %s' % (messages, _prepareMailboxName(mailbox)) - return self.sendCommand(Command(cmd, args)) - - # - # IMailboxListener methods - # - def modeChanged(self, writeable): - """Override me""" - - def flagsChanged(self, newFlags): - """Override me""" - - def newMessages(self, exists, recent): - """Override me""" - - -class IllegalIdentifierError(IMAP4Exception): pass - -def parseIdList(s): - res = MessageSet() - parts = s.split(',') - for p in parts: - if ':' in p: - low, high = p.split(':', 1) - try: - if low == '*': - low = None - else: - low = long(low) - if high == '*': - high = None - else: - high = long(high) - res.extend((low, high)) - except ValueError: - raise IllegalIdentifierError(p) - else: - try: - if p == '*': - p = None - else: - p = long(p) - except ValueError: - raise IllegalIdentifierError(p) - else: - res.extend(p) - return res - -class IllegalQueryError(IMAP4Exception): pass - -_SIMPLE_BOOL = ( - 'ALL', 'ANSWERED', 'DELETED', 'DRAFT', 'FLAGGED', 'NEW', 'OLD', 'RECENT', - 'SEEN', 'UNANSWERED', 'UNDELETED', 'UNDRAFT', 'UNFLAGGED', 'UNSEEN' -) - -_NO_QUOTES = ( - 'LARGER', 'SMALLER', 'UID' -) - -def Query(sorted=0, **kwarg): - """Create a query string - - Among the accepted keywords are:: - - all : If set to a true value, search all messages in the - current mailbox - - answered : If set to a true value, search messages flagged with - \\Answered - - bcc : A substring to search the BCC header field for - - before : Search messages with an internal date before this - value. The given date should be a string in the format - of 'DD-Mon-YYYY'. For example, '03-Mar-2003'. - - body : A substring to search the body of the messages for - - cc : A substring to search the CC header field for - - deleted : If set to a true value, search messages flagged with - \\Deleted - - draft : If set to a true value, search messages flagged with - \\Draft - - flagged : If set to a true value, search messages flagged with - \\Flagged - - from : A substring to search the From header field for - - header : A two-tuple of a header name and substring to search - for in that header - - keyword : Search for messages with the given keyword set - - larger : Search for messages larger than this number of octets - - messages : Search only the given message sequence set. - - new : If set to a true value, search messages flagged with - \\Recent but not \\Seen - - old : If set to a true value, search messages not flagged with - \\Recent - - on : Search messages with an internal date which is on this - date. The given date should be a string in the format - of 'DD-Mon-YYYY'. For example, '03-Mar-2003'. - - recent : If set to a true value, search for messages flagged with - \\Recent - - seen : If set to a true value, search for messages flagged with - \\Seen - - sentbefore : Search for messages with an RFC822 'Date' header before - this date. The given date should be a string in the format - of 'DD-Mon-YYYY'. For example, '03-Mar-2003'. - - senton : Search for messages with an RFC822 'Date' header which is - on this date The given date should be a string in the format - of 'DD-Mon-YYYY'. For example, '03-Mar-2003'. - - sentsince : Search for messages with an RFC822 'Date' header which is - after this date. The given date should be a string in the format - of 'DD-Mon-YYYY'. For example, '03-Mar-2003'. - - since : Search for messages with an internal date that is after - this date.. The given date should be a string in the format - of 'DD-Mon-YYYY'. For example, '03-Mar-2003'. - - smaller : Search for messages smaller than this number of octets - - subject : A substring to search the 'subject' header for - - text : A substring to search the entire message for - - to : A substring to search the 'to' header for - - uid : Search only the messages in the given message set - - unanswered : If set to a true value, search for messages not - flagged with \\Answered - - undeleted : If set to a true value, search for messages not - flagged with \\Deleted - - undraft : If set to a true value, search for messages not - flagged with \\Draft - - unflagged : If set to a true value, search for messages not - flagged with \\Flagged - - unkeyword : Search for messages without the given keyword set - - unseen : If set to a true value, search for messages not - flagged with \\Seen - - @type sorted: C{bool} - @param sorted: If true, the output will be sorted, alphabetically. - The standard does not require it, but it makes testing this function - easier. The default is zero, and this should be acceptable for any - application. - - @rtype: C{str} - @return: The formatted query string - """ - cmd = [] - keys = kwarg.keys() - if sorted: - keys.sort() - for k in keys: - v = kwarg[k] - k = k.upper() - if k in _SIMPLE_BOOL and v: - cmd.append(k) - elif k == 'HEADER': - cmd.extend([k, v[0], '"%s"' % (v[1],)]) - elif k not in _NO_QUOTES: - cmd.extend([k, '"%s"' % (v,)]) - else: - cmd.extend([k, '%s' % (v,)]) - if len(cmd) > 1: - return '(%s)' % ' '.join(cmd) - else: - return ' '.join(cmd) - -def Or(*args): - """The disjunction of two or more queries""" - if len(args) < 2: - raise IllegalQueryError, args - elif len(args) == 2: - return '(OR %s %s)' % args - else: - return '(OR %s %s)' % (args[0], Or(*args[1:])) - -def Not(query): - """The negation of a query""" - return '(NOT %s)' % (query,) - -class MismatchedNesting(IMAP4Exception): - pass - -class MismatchedQuoting(IMAP4Exception): - pass - -def wildcardToRegexp(wildcard, delim=None): - wildcard = wildcard.replace('*', '(?:.*?)') - if delim is None: - wildcard = wildcard.replace('%', '(?:.*?)') - else: - wildcard = wildcard.replace('%', '(?:(?:[^%s])*?)' % re.escape(delim)) - return re.compile(wildcard, re.I) - -def splitQuoted(s): - """Split a string into whitespace delimited tokens - - Tokens that would otherwise be separated but are surrounded by \" - remain as a single token. Any token that is not quoted and is - equal to \"NIL\" is tokenized as C{None}. - - @type s: C{str} - @param s: The string to be split - - @rtype: C{list} of C{str} - @return: A list of the resulting tokens - - @raise MismatchedQuoting: Raised if an odd number of quotes are present - """ - s = s.strip() - result = [] - inQuote = inWord = start = 0 - for (i, c) in zip(range(len(s)), s): - if c == '"' and not inQuote: - inQuote = 1 - start = i + 1 - elif c == '"' and inQuote: - inQuote = 0 - result.append(s[start:i]) - start = i + 1 - elif not inWord and not inQuote and c not in ('"' + string.whitespace): - inWord = 1 - start = i - elif inWord and not inQuote and c in string.whitespace: - if s[start:i] == 'NIL': - result.append(None) - else: - result.append(s[start:i]) - start = i - inWord = 0 - if inQuote: - raise MismatchedQuoting(s) - if inWord: - if s[start:] == 'NIL': - result.append(None) - else: - result.append(s[start:]) - return result - - -def splitOn(sequence, predicate, transformers): - result = [] - mode = predicate(sequence[0]) - tmp = [sequence[0]] - for e in sequence[1:]: - p = predicate(e) - if p != mode: - result.extend(transformers[mode](tmp)) - tmp = [e] - mode = p - else: - tmp.append(e) - result.extend(transformers[mode](tmp)) - return result - -def collapseStrings(results): - """ - Turns a list of length-one strings and lists into a list of longer - strings and lists. For example, - - ['a', 'b', ['c', 'd']] is returned as ['ab', ['cd']] - - @type results: C{list} of C{str} and C{list} - @param results: The list to be collapsed - - @rtype: C{list} of C{str} and C{list} - @return: A new list which is the collapsed form of C{results} - """ - copy = [] - begun = None - listsList = [isinstance(s, types.ListType) for s in results] - - pred = lambda e: isinstance(e, types.TupleType) - tran = { - 0: lambda e: splitQuoted(''.join(e)), - 1: lambda e: [''.join([i[0] for i in e])] - } - for (i, c, isList) in zip(range(len(results)), results, listsList): - if isList: - if begun is not None: - copy.extend(splitOn(results[begun:i], pred, tran)) - begun = None - copy.append(collapseStrings(c)) - elif begun is None: - begun = i - if begun is not None: - copy.extend(splitOn(results[begun:], pred, tran)) - return copy - - -def parseNestedParens(s, handleLiteral = 1): - """Parse an s-exp-like string into a more useful data structure. - - @type s: C{str} - @param s: The s-exp-like string to parse - - @rtype: C{list} of C{str} and C{list} - @return: A list containing the tokens present in the input. - - @raise MismatchedNesting: Raised if the number or placement - of opening or closing parenthesis is invalid. - """ - s = s.strip() - inQuote = 0 - contentStack = [[]] - try: - i = 0 - L = len(s) - while i < L: - c = s[i] - if inQuote: - if c == '\\': - contentStack[-1].append(s[i+1]) - i += 2 - continue - elif c == '"': - inQuote = not inQuote - contentStack[-1].append(c) - i += 1 - else: - if c == '"': - contentStack[-1].append(c) - inQuote = not inQuote - i += 1 - elif handleLiteral and c == '{': - end = s.find('}', i) - if end == -1: - raise ValueError, "Malformed literal" - literalSize = int(s[i+1:end]) - contentStack[-1].append((s[end+3:end+3+literalSize],)) - i = end + 3 + literalSize - elif c == '(' or c == '[': - contentStack.append([]) - i += 1 - elif c == ')' or c == ']': - contentStack[-2].append(contentStack.pop()) - i += 1 - else: - contentStack[-1].append(c) - i += 1 - except IndexError: - raise MismatchedNesting(s) - if len(contentStack) != 1: - raise MismatchedNesting(s) - return collapseStrings(contentStack[0]) - -def _quote(s): - return '"%s"' % (s.replace('\\', '\\\\').replace('"', '\\"'),) - -def _literal(s): - return '{%d}\r\n%s' % (len(s), s) - -class DontQuoteMe: - def __init__(self, value): - self.value = value - - def __str__(self): - return str(self.value) - -_ATOM_SPECIALS = '(){ %*"' -def _needsQuote(s): - if s == '': - return 1 - for c in s: - if c < '\x20' or c > '\x7f': - return 1 - if c in _ATOM_SPECIALS: - return 1 - return 0 - -def _prepareMailboxName(name): - name = name.encode('imap4-utf-7') - if _needsQuote(name): - return _quote(name) - return name - -def _needsLiteral(s): - # Change this to "return 1" to wig out stupid clients - return '\n' in s or '\r' in s or len(s) > 1000 - -def collapseNestedLists(items): - """Turn a nested list structure into an s-exp-like string. - - Strings in C{items} will be sent as literals if they contain CR or LF, - otherwise they will be quoted. References to None in C{items} will be - translated to the atom NIL. Objects with a 'read' attribute will have - it called on them with no arguments and the returned string will be - inserted into the output as a literal. Integers will be converted to - strings and inserted into the output unquoted. Instances of - C{DontQuoteMe} will be converted to strings and inserted into the output - unquoted. - - This function used to be much nicer, and only quote things that really - needed to be quoted (and C{DontQuoteMe} did not exist), however, many - broken IMAP4 clients were unable to deal with this level of sophistication, - forcing the current behavior to be adopted for practical reasons. - - @type items: Any iterable - - @rtype: C{str} - """ - pieces = [] - for i in items: - if i is None: - pieces.extend([' ', 'NIL']) - elif isinstance(i, (DontQuoteMe, int, long)): - pieces.extend([' ', str(i)]) - elif isinstance(i, types.StringTypes): - if _needsLiteral(i): - pieces.extend([' ', '{', str(len(i)), '}', IMAP4Server.delimiter, i]) - else: - pieces.extend([' ', _quote(i)]) - elif hasattr(i, 'read'): - d = i.read() - pieces.extend([' ', '{', str(len(d)), '}', IMAP4Server.delimiter, d]) - else: - pieces.extend([' ', '(%s)' % (collapseNestedLists(i),)]) - return ''.join(pieces[1:]) - - -class IClientAuthentication(Interface): - def getName(): - """Return an identifier associated with this authentication scheme. - - @rtype: C{str} - """ - - def challengeResponse(secret, challenge): - """Generate a challenge response string""" - -class CramMD5ClientAuthenticator: - implements(IClientAuthentication) - - def __init__(self, user): - self.user = user - - def getName(self): - return "CRAM-MD5" - - def challengeResponse(self, secret, chal): - response = hmac.HMAC(secret, chal).hexdigest() - return '%s %s' % (self.user, response) - -class LOGINAuthenticator: - implements(IClientAuthentication) - - def __init__(self, user): - self.user = user - self.challengeResponse = self.challengeUsername - - def getName(self): - return "LOGIN" - - def challengeUsername(self, secret, chal): - # Respond to something like "Username:" - self.challengeResponse = self.challengeSecret - return self.user - - def challengeSecret(self, secret, chal): - # Respond to something like "Password:" - return secret - -class PLAINAuthenticator: - implements(IClientAuthentication) - - def __init__(self, user): - self.user = user - - def getName(self): - return "PLAIN" - - def challengeResponse(self, secret, chal): - return '%s\0%s\0' % (self.user, secret) - - -class MailboxException(IMAP4Exception): pass - -class MailboxCollision(MailboxException): - def __str__(self): - return 'Mailbox named %s already exists' % self.args - -class NoSuchMailbox(MailboxException): - def __str__(self): - return 'No mailbox named %s exists' % self.args - -class ReadOnlyMailbox(MailboxException): - def __str__(self): - return 'Mailbox open in read-only state' - - -class IAccount(Interface): - """Interface for Account classes - - Implementors of this interface should consider implementing - C{INamespacePresenter}. - """ - - def addMailbox(name, mbox = None): - """Add a new mailbox to this account - - @type name: C{str} - @param name: The name associated with this mailbox. It may not - contain multiple hierarchical parts. - - @type mbox: An object implementing C{IMailbox} - @param mbox: The mailbox to associate with this name. If C{None}, - a suitable default is created and used. - - @rtype: C{Deferred} or C{bool} - @return: A true value if the creation succeeds, or a deferred whose - callback will be invoked when the creation succeeds. - - @raise MailboxException: Raised if this mailbox cannot be added for - some reason. This may also be raised asynchronously, if a C{Deferred} - is returned. - """ - - def create(pathspec): - """Create a new mailbox from the given hierarchical name. - - @type pathspec: C{str} - @param pathspec: The full hierarchical name of a new mailbox to create. - If any of the inferior hierarchical names to this one do not exist, - they are created as well. - - @rtype: C{Deferred} or C{bool} - @return: A true value if the creation succeeds, or a deferred whose - callback will be invoked when the creation succeeds. - - @raise MailboxException: Raised if this mailbox cannot be added. - This may also be raised asynchronously, if a C{Deferred} is - returned. - """ - - def select(name, rw=True): - """Acquire a mailbox, given its name. - - @type name: C{str} - @param name: The mailbox to acquire - - @type rw: C{bool} - @param rw: If a true value, request a read-write version of this - mailbox. If a false value, request a read-only version. - - @rtype: Any object implementing C{IMailbox} or C{Deferred} - @return: The mailbox object, or a C{Deferred} whose callback will - be invoked with the mailbox object. None may be returned if the - specified mailbox may not be selected for any reason. - """ - - def delete(name): - """Delete the mailbox with the specified name. - - @type name: C{str} - @param name: The mailbox to delete. - - @rtype: C{Deferred} or C{bool} - @return: A true value if the mailbox is successfully deleted, or a - C{Deferred} whose callback will be invoked when the deletion - completes. - - @raise MailboxException: Raised if this mailbox cannot be deleted. - This may also be raised asynchronously, if a C{Deferred} is returned. - """ - - def rename(oldname, newname): - """Rename a mailbox - - @type oldname: C{str} - @param oldname: The current name of the mailbox to rename. - - @type newname: C{str} - @param newname: The new name to associate with the mailbox. - - @rtype: C{Deferred} or C{bool} - @return: A true value if the mailbox is successfully renamed, or a - C{Deferred} whose callback will be invoked when the rename operation - is completed. - - @raise MailboxException: Raised if this mailbox cannot be - renamed. This may also be raised asynchronously, if a C{Deferred} - is returned. - """ - - def isSubscribed(name): - """Check the subscription status of a mailbox - - @type name: C{str} - @param name: The name of the mailbox to check - - @rtype: C{Deferred} or C{bool} - @return: A true value if the given mailbox is currently subscribed - to, a false value otherwise. A C{Deferred} may also be returned - whose callback will be invoked with one of these values. - """ - - def subscribe(name): - """Subscribe to a mailbox - - @type name: C{str} - @param name: The name of the mailbox to subscribe to - - @rtype: C{Deferred} or C{bool} - @return: A true value if the mailbox is subscribed to successfully, - or a Deferred whose callback will be invoked with this value when - the subscription is successful. - - @raise MailboxException: Raised if this mailbox cannot be - subscribed to. This may also be raised asynchronously, if a - C{Deferred} is returned. - """ - - def unsubscribe(name): - """Unsubscribe from a mailbox - - @type name: C{str} - @param name: The name of the mailbox to unsubscribe from - - @rtype: C{Deferred} or C{bool} - @return: A true value if the mailbox is unsubscribed from successfully, - or a Deferred whose callback will be invoked with this value when - the unsubscription is successful. - - @raise MailboxException: Raised if this mailbox cannot be - unsubscribed from. This may also be raised asynchronously, if a - C{Deferred} is returned. - """ - - def listMailboxes(ref, wildcard): - """List all the mailboxes that meet a certain criteria - - @type ref: C{str} - @param ref: The context in which to apply the wildcard - - @type wildcard: C{str} - @param wildcard: An expression against which to match mailbox names. - '*' matches any number of characters in a mailbox name, and '%' - matches similarly, but will not match across hierarchical boundaries. - - @rtype: C{list} of C{tuple} - @return: A list of C{(mailboxName, mailboxObject)} which meet the - given criteria. C{mailboxObject} should implement either - C{IMailboxInfo} or C{IMailbox}. A Deferred may also be returned. - """ - -class INamespacePresenter(Interface): - def getPersonalNamespaces(): - """Report the available personal namespaces. - - Typically there should be only one personal namespace. A common - name for it is \"\", and its hierarchical delimiter is usually - \"/\". - - @rtype: iterable of two-tuples of strings - @return: The personal namespaces and their hierarchical delimiters. - If no namespaces of this type exist, None should be returned. - """ - - def getSharedNamespaces(): - """Report the available shared namespaces. - - Shared namespaces do not belong to any individual user but are - usually to one or more of them. Examples of shared namespaces - might be \"#news\" for a usenet gateway. - - @rtype: iterable of two-tuples of strings - @return: The shared namespaces and their hierarchical delimiters. - If no namespaces of this type exist, None should be returned. - """ - - def getUserNamespaces(): - """Report the available user namespaces. - - These are namespaces that contain folders belonging to other users - access to which this account has been granted. - - @rtype: iterable of two-tuples of strings - @return: The user namespaces and their hierarchical delimiters. - If no namespaces of this type exist, None should be returned. - """ - - -class MemoryAccount(object): - implements(IAccount, INamespacePresenter) - - mailboxes = None - subscriptions = None - top_id = 0 - - def __init__(self, name): - self.name = name - self.mailboxes = {} - self.subscriptions = [] - - def allocateID(self): - id = self.top_id - self.top_id += 1 - return id - - ## - ## IAccount - ## - def addMailbox(self, name, mbox = None): - name = name.upper() - if self.mailboxes.has_key(name): - raise MailboxCollision, name - if mbox is None: - mbox = self._emptyMailbox(name, self.allocateID()) - self.mailboxes[name] = mbox - return 1 - - def create(self, pathspec): - paths = filter(None, pathspec.split('/')) - for accum in range(1, len(paths)): - try: - self.addMailbox('/'.join(paths[:accum])) - except MailboxCollision: - pass - try: - self.addMailbox('/'.join(paths)) - except MailboxCollision: - if not pathspec.endswith('/'): - return False - return True - - def _emptyMailbox(self, name, id): - raise NotImplementedError - - def select(self, name, readwrite=1): - return self.mailboxes.get(name.upper()) - - def delete(self, name): - name = name.upper() - # See if this mailbox exists at all - mbox = self.mailboxes.get(name) - if not mbox: - raise MailboxException("No such mailbox") - # See if this box is flagged \Noselect - if r'\Noselect' in mbox.getFlags(): - # Check for hierarchically inferior mailboxes with this one - # as part of their root. - for others in self.mailboxes.keys(): - if others != name and others.startswith(name): - raise MailboxException, "Hierarchically inferior mailboxes exist and \\Noselect is set" - mbox.destroy() - - # iff there are no hierarchically inferior names, we will - # delete it from our ken. - if self._inferiorNames(name) > 1: - del self.mailboxes[name] - - def rename(self, oldname, newname): - oldname = oldname.upper() - newname = newname.upper() - if not self.mailboxes.has_key(oldname): - raise NoSuchMailbox, oldname - - inferiors = self._inferiorNames(oldname) - inferiors = [(o, o.replace(oldname, newname, 1)) for o in inferiors] - - for (old, new) in inferiors: - if self.mailboxes.has_key(new): - raise MailboxCollision, new - - for (old, new) in inferiors: - self.mailboxes[new] = self.mailboxes[old] - del self.mailboxes[old] - - def _inferiorNames(self, name): - inferiors = [] - for infname in self.mailboxes.keys(): - if infname.startswith(name): - inferiors.append(infname) - return inferiors - - def isSubscribed(self, name): - return name.upper() in self.subscriptions - - def subscribe(self, name): - name = name.upper() - if name not in self.subscriptions: - self.subscriptions.append(name) - - def unsubscribe(self, name): - name = name.upper() - if name not in self.subscriptions: - raise MailboxException, "Not currently subscribed to " + name - self.subscriptions.remove(name) - - def listMailboxes(self, ref, wildcard): - ref = self._inferiorNames(ref.upper()) - wildcard = wildcardToRegexp(wildcard, '/') - return [(i, self.mailboxes[i]) for i in ref if wildcard.match(i)] - - ## - ## INamespacePresenter - ## - def getPersonalNamespaces(self): - return [["", "/"]] - - def getSharedNamespaces(self): - return None - - def getOtherNamespaces(self): - return None - - - -_statusRequestDict = { - 'MESSAGES': 'getMessageCount', - 'RECENT': 'getRecentCount', - 'UIDNEXT': 'getUIDNext', - 'UIDVALIDITY': 'getUIDValidity', - 'UNSEEN': 'getUnseenCount' -} -def statusRequestHelper(mbox, names): - r = {} - for n in names: - r[n] = getattr(mbox, _statusRequestDict[n.upper()])() - return r - -def parseAddr(addr): - if addr is None: - return [(None, None, None),] - addrs = email.Utils.getaddresses([addr]) - return [[fn or None, None] + addr.split('@') for fn, addr in addrs] - -def getEnvelope(msg): - headers = msg.getHeaders(True) - date = headers.get('date') - subject = headers.get('subject') - from_ = headers.get('from') - sender = headers.get('sender', from_) - reply_to = headers.get('reply-to', from_) - to = headers.get('to') - cc = headers.get('cc') - bcc = headers.get('bcc') - in_reply_to = headers.get('in-reply-to') - mid = headers.get('message-id') - return (date, subject, parseAddr(from_), parseAddr(sender), - reply_to and parseAddr(reply_to), to and parseAddr(to), - cc and parseAddr(cc), bcc and parseAddr(bcc), in_reply_to, mid) - -def getLineCount(msg): - # XXX - Super expensive, CACHE THIS VALUE FOR LATER RE-USE - # XXX - This must be the number of lines in the ENCODED version - lines = 0 - for _ in msg.getBodyFile(): - lines += 1 - return lines - -def unquote(s): - if s[0] == s[-1] == '"': - return s[1:-1] - return s - -def getBodyStructure(msg, extended=False): - # XXX - This does not properly handle multipart messages - # BODYSTRUCTURE is obscenely complex and criminally under-documented. - - attrs = {} - headers = 'content-type', 'content-id', 'content-description', 'content-transfer-encoding' - headers = msg.getHeaders(False, *headers) - mm = headers.get('content-type') - if mm: - mm = ''.join(mm.splitlines()) - mimetype = mm.split(';') - if mimetype: - type = mimetype[0].split('/', 1) - if len(type) == 1: - major = type[0] - minor = None - elif len(type) == 2: - major, minor = type - else: - major = minor = None - attrs = dict([x.strip().lower().split('=', 1) for x in mimetype[1:]]) - else: - major = minor = None - else: - major = minor = None - - - size = str(msg.getSize()) - unquotedAttrs = [(k, unquote(v)) for (k, v) in attrs.iteritems()] - result = [ - major, minor, # Main and Sub MIME types - unquotedAttrs, # content-type parameter list - headers.get('content-id'), - headers.get('content-description'), - headers.get('content-transfer-encoding'), - size, # Number of octets total - ] - - if major is not None: - if major.lower() == 'text': - result.append(str(getLineCount(msg))) - elif (major.lower(), minor.lower()) == ('message', 'rfc822'): - contained = msg.getSubPart(0) - result.append(getEnvelope(contained)) - result.append(getBodyStructure(contained, False)) - result.append(str(getLineCount(contained))) - - if not extended or major is None: - return result - - if major.lower() != 'multipart': - headers = 'content-md5', 'content-disposition', 'content-language' - headers = msg.getHeaders(False, *headers) - disp = headers.get('content-disposition') - - # XXX - I dunno if this is really right - if disp: - disp = disp.split('; ') - if len(disp) == 1: - disp = (disp[0].lower(), None) - elif len(disp) > 1: - disp = (disp[0].lower(), [x.split('=') for x in disp[1:]]) - - result.append(headers.get('content-md5')) - result.append(disp) - result.append(headers.get('content-language')) - else: - result = [result] - try: - i = 0 - while True: - submsg = msg.getSubPart(i) - result.append(getBodyStructure(submsg)) - i += 1 - except IndexError: - result.append(minor) - result.append(attrs.items()) - - # XXX - I dunno if this is really right - headers = msg.getHeaders(False, 'content-disposition', 'content-language') - disp = headers.get('content-disposition') - if disp: - disp = disp.split('; ') - if len(disp) == 1: - disp = (disp[0].lower(), None) - elif len(disp) > 1: - disp = (disp[0].lower(), [x.split('=') for x in disp[1:]]) - - result.append(disp) - result.append(headers.get('content-language')) - - return result - -class IMessagePart(Interface): - def getHeaders(negate, *names): - """Retrieve a group of message headers. - - @type names: C{tuple} of C{str} - @param names: The names of the headers to retrieve or omit. - - @type negate: C{bool} - @param negate: If True, indicates that the headers listed in C{names} - should be omitted from the return value, rather than included. - - @rtype: C{dict} - @return: A mapping of header field names to header field values - """ - - def getBodyFile(): - """Retrieve a file object containing only the body of this message. - """ - - def getSize(): - """Retrieve the total size, in octets, of this message. - - @rtype: C{int} - """ - - def isMultipart(): - """Indicate whether this message has subparts. - - @rtype: C{bool} - """ - - def getSubPart(part): - """Retrieve a MIME sub-message - - @type part: C{int} - @param part: The number of the part to retrieve, indexed from 0. - - @raise IndexError: Raised if the specified part does not exist. - @raise TypeError: Raised if this message is not multipart. - - @rtype: Any object implementing C{IMessagePart}. - @return: The specified sub-part. - """ - -class IMessage(IMessagePart): - def getUID(): - """Retrieve the unique identifier associated with this message. - """ - - def getFlags(): - """Retrieve the flags associated with this message. - - @rtype: C{iterable} - @return: The flags, represented as strings. - """ - - def getInternalDate(): - """Retrieve the date internally associated with this message. - - @rtype: C{str} - @return: An RFC822-formatted date string. - """ - -class IMessageFile(Interface): - """Optional message interface for representing messages as files. - - If provided by message objects, this interface will be used instead - the more complex MIME-based interface. - """ - def open(): - """Return an file-like object opened for reading. - - Reading from the returned file will return all the bytes - of which this message consists. - """ - -class ISearchableMailbox(Interface): - def search(query, uid): - """Search for messages that meet the given query criteria. - - If this interface is not implemented by the mailbox, L{IMailbox.fetch} - and various methods of L{IMessage} will be used instead. - - Implementations which wish to offer better performance than the - default implementation should implement this interface. - - @type query: C{list} - @param query: The search criteria - - @type uid: C{bool} - @param uid: If true, the IDs specified in the query are UIDs; - otherwise they are message sequence IDs. - - @rtype: C{list} or C{Deferred} - @return: A list of message sequence numbers or message UIDs which - match the search criteria or a C{Deferred} whose callback will be - invoked with such a list. - """ - -class IMessageCopier(Interface): - def copy(messageObject): - """Copy the given message object into this mailbox. - - The message object will be one which was previously returned by - L{IMailbox.fetch}. - - Implementations which wish to offer better performance than the - default implementation should implement this interface. - - If this interface is not implemented by the mailbox, IMailbox.addMessage - will be used instead. - - @rtype: C{Deferred} or C{int} - @return: Either the UID of the message or a Deferred which fires - with the UID when the copy finishes. - """ - -class IMailboxInfo(Interface): - """Interface specifying only the methods required for C{listMailboxes}. - - Implementations can return objects implementing only these methods for - return to C{listMailboxes} if it can allow them to operate more - efficiently. - """ - - def getFlags(): - """Return the flags defined in this mailbox - - Flags with the \\ prefix are reserved for use as system flags. - - @rtype: C{list} of C{str} - @return: A list of the flags that can be set on messages in this mailbox. - """ - - def getHierarchicalDelimiter(): - """Get the character which delimits namespaces for in this mailbox. - - @rtype: C{str} - """ - -class IMailbox(IMailboxInfo): - def getUIDValidity(): - """Return the unique validity identifier for this mailbox. - - @rtype: C{int} - """ - - def getUIDNext(): - """Return the likely UID for the next message added to this mailbox. - - @rtype: C{int} - """ - - def getUID(message): - """Return the UID of a message in the mailbox - - @type message: C{int} - @param message: The message sequence number - - @rtype: C{int} - @return: The UID of the message. - """ - - def getMessageCount(): - """Return the number of messages in this mailbox. - - @rtype: C{int} - """ - - def getRecentCount(): - """Return the number of messages with the 'Recent' flag. - - @rtype: C{int} - """ - - def getUnseenCount(): - """Return the number of messages with the 'Unseen' flag. - - @rtype: C{int} - """ - - def isWriteable(): - """Get the read/write status of the mailbox. - - @rtype: C{int} - @return: A true value if write permission is allowed, a false value otherwise. - """ - - def destroy(): - """Called before this mailbox is deleted, permanently. - - If necessary, all resources held by this mailbox should be cleaned - up here. This function _must_ set the \\Noselect flag on this - mailbox. - """ - - def requestStatus(names): - """Return status information about this mailbox. - - Mailboxes which do not intend to do any special processing to - generate the return value, C{statusRequestHelper} can be used - to build the dictionary by calling the other interface methods - which return the data for each name. - - @type names: Any iterable - @param names: The status names to return information regarding. - The possible values for each name are: MESSAGES, RECENT, UIDNEXT, - UIDVALIDITY, UNSEEN. - - @rtype: C{dict} or C{Deferred} - @return: A dictionary containing status information about the - requested names is returned. If the process of looking this - information up would be costly, a deferred whose callback will - eventually be passed this dictionary is returned instead. - """ - - def addListener(listener): - """Add a mailbox change listener - - @type listener: Any object which implements C{IMailboxListener} - @param listener: An object to add to the set of those which will - be notified when the contents of this mailbox change. - """ - - def removeListener(listener): - """Remove a mailbox change listener - - @type listener: Any object previously added to and not removed from - this mailbox as a listener. - @param listener: The object to remove from the set of listeners. - - @raise ValueError: Raised when the given object is not a listener for - this mailbox. - """ - - def addMessage(message, flags = (), date = None): - """Add the given message to this mailbox. - - @type message: A file-like object - @param message: The RFC822 formatted message - - @type flags: Any iterable of C{str} - @param flags: The flags to associate with this message - - @type date: C{str} - @param date: If specified, the date to associate with this - message. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked with the message - id if the message is added successfully and whose errback is - invoked otherwise. - - @raise ReadOnlyMailbox: Raised if this Mailbox is not open for - read-write. - """ - - def expunge(): - """Remove all messages flagged \\Deleted. - - @rtype: C{list} or C{Deferred} - @return: The list of message sequence numbers which were deleted, - or a C{Deferred} whose callback will be invoked with such a list. - - @raise ReadOnlyMailbox: Raised if this Mailbox is not open for - read-write. - """ - - def fetch(messages, uid): - """Retrieve one or more messages. - - @type messages: C{MessageSet} - @param messages: The identifiers of messages to retrieve information - about - - @type uid: C{bool} - @param uid: If true, the IDs specified in the query are UIDs; - otherwise they are message sequence IDs. - - @rtype: Any iterable of two-tuples of message sequence numbers and - implementors of C{IMessage}. - """ - - def store(messages, flags, mode, uid): - """Set the flags of one or more messages. - - @type messages: A MessageSet object with the list of messages requested - @param messages: The identifiers of the messages to set the flags of. - - @type flags: sequence of C{str} - @param flags: The flags to set, unset, or add. - - @type mode: -1, 0, or 1 - @param mode: If mode is -1, these flags should be removed from the - specified messages. If mode is 1, these flags should be added to - the specified messages. If mode is 0, all existing flags should be - cleared and these flags should be added. - - @type uid: C{bool} - @param uid: If true, the IDs specified in the query are UIDs; - otherwise they are message sequence IDs. - - @rtype: C{dict} or C{Deferred} - @return: A C{dict} mapping message sequence numbers to sequences of C{str} - representing the flags set on the message after this operation has - been performed, or a C{Deferred} whose callback will be invoked with - such a C{dict}. - - @raise ReadOnlyMailbox: Raised if this mailbox is not open for - read-write. - """ - -class ICloseableMailbox(Interface): - """A supplementary interface for mailboxes which require cleanup on close. - - Implementing this interface is optional. If it is implemented, the protocol - code will call the close method defined whenever a mailbox is closed. - """ - def close(): - """Close this mailbox. - - @return: A C{Deferred} which fires when this mailbox - has been closed, or None if the mailbox can be closed - immediately. - """ - -def _formatHeaders(headers): - hdrs = [': '.join((k.title(), '\r\n'.join(v.splitlines()))) for (k, v) - in headers.iteritems()] - hdrs = '\r\n'.join(hdrs) + '\r\n' - return hdrs - -def subparts(m): - i = 0 - try: - while True: - yield m.getSubPart(i) - i += 1 - except IndexError: - pass - -def iterateInReactor(i): - """Consume an interator at most a single iteration per reactor iteration. - - If the iterator produces a Deferred, the next iteration will not occur - until the Deferred fires, otherwise the next iteration will be taken - in the next reactor iteration. - - @rtype: C{Deferred} - @return: A deferred which fires (with None) when the iterator is - exhausted or whose errback is called if there is an exception. - """ - from twisted.internet import reactor - d = defer.Deferred() - def go(last): - try: - r = i.next() - except StopIteration: - d.callback(last) - except: - d.errback() - else: - if isinstance(r, defer.Deferred): - r.addCallback(go) - else: - reactor.callLater(0, go, r) - go(None) - return d - -class MessageProducer: - CHUNK_SIZE = 2 ** 2 ** 2 ** 2 - - def __init__(self, msg, buffer = None, scheduler = None): - """Produce this message. - - @param msg: The message I am to produce. - @type msg: L{IMessage} - - @param buffer: A buffer to hold the message in. If None, I will - use a L{tempfile.TemporaryFile}. - @type buffer: file-like - """ - self.msg = msg - if buffer is None: - buffer = tempfile.TemporaryFile() - self.buffer = buffer - if scheduler is None: - scheduler = iterateInReactor - self.scheduler = scheduler - self.write = self.buffer.write - - def beginProducing(self, consumer): - self.consumer = consumer - return self.scheduler(self._produce()) - - def _produce(self): - headers = self.msg.getHeaders(True) - boundary = None - if self.msg.isMultipart(): - content = headers.get('content-type') - parts = [x.split('=', 1) for x in content.split(';')[1:]] - parts = dict([(k.lower().strip(), v) for (k, v) in parts]) - boundary = parts.get('boundary') - if boundary is None: - # Bastards - boundary = '----=_%f_boundary_%f' % (time.time(), random.random()) - headers['content-type'] += '; boundary="%s"' % (boundary,) - else: - if boundary.startswith('"') and boundary.endswith('"'): - boundary = boundary[1:-1] - - self.write(_formatHeaders(headers)) - self.write('\r\n') - if self.msg.isMultipart(): - for p in subparts(self.msg): - self.write('\r\n--%s\r\n' % (boundary,)) - yield MessageProducer(p, self.buffer, self.scheduler - ).beginProducing(None - ) - self.write('\r\n--%s--\r\n' % (boundary,)) - else: - f = self.msg.getBodyFile() - while True: - b = f.read(self.CHUNK_SIZE) - if b: - self.buffer.write(b) - yield None - else: - break - if self.consumer: - self.buffer.seek(0, 0) - yield FileProducer(self.buffer - ).beginProducing(self.consumer - ).addCallback(lambda _: self - ) - -class _FetchParser: - class Envelope: - # Response should be a list of fields from the message: - # date, subject, from, sender, reply-to, to, cc, bcc, in-reply-to, - # and message-id. - # - # from, sender, reply-to, to, cc, and bcc are themselves lists of - # address information: - # personal name, source route, mailbox name, host name - # - # reply-to and sender must not be None. If not present in a message - # they should be defaulted to the value of the from field. - type = 'envelope' - __str__ = lambda self: 'envelope' - - class Flags: - type = 'flags' - __str__ = lambda self: 'flags' - - class InternalDate: - type = 'internaldate' - __str__ = lambda self: 'internaldate' - - class RFC822Header: - type = 'rfc822header' - __str__ = lambda self: 'rfc822.header' - - class RFC822Text: - type = 'rfc822text' - __str__ = lambda self: 'rfc822.text' - - class RFC822Size: - type = 'rfc822size' - __str__ = lambda self: 'rfc822.size' - - class RFC822: - type = 'rfc822' - __str__ = lambda self: 'rfc822' - - class UID: - type = 'uid' - __str__ = lambda self: 'uid' - - class Body: - type = 'body' - peek = False - header = None - mime = None - text = None - part = () - empty = False - partialBegin = None - partialLength = None - def __str__(self): - base = 'BODY' - part = '' - separator = '' - if self.part: - part = '.'.join([str(x + 1) for x in self.part]) - separator = '.' -# if self.peek: -# base += '.PEEK' - if self.header: - base += '[%s%s%s]' % (part, separator, self.header,) - elif self.text: - base += '[%s%sTEXT]' % (part, separator) - elif self.mime: - base += '[%s%sMIME]' % (part, separator) - elif self.empty: - base += '[%s]' % (part,) - if self.partialBegin is not None: - base += '<%d.%d>' % (self.partialBegin, self.partialLength) - return base - - class BodyStructure: - type = 'bodystructure' - __str__ = lambda self: 'bodystructure' - - # These three aren't top-level, they don't need type indicators - class Header: - negate = False - fields = None - part = None - def __str__(self): - base = 'HEADER' - if self.fields: - base += '.FIELDS' - if self.negate: - base += '.NOT' - fields = [] - for f in self.fields: - f = f.title() - if _needsQuote(f): - f = _quote(f) - fields.append(f) - base += ' (%s)' % ' '.join(fields) - if self.part: - base = '.'.join([str(x + 1) for x in self.part]) + '.' + base - return base - - class Text: - pass - - class MIME: - pass - - parts = None - - _simple_fetch_att = [ - ('envelope', Envelope), - ('flags', Flags), - ('internaldate', InternalDate), - ('rfc822.header', RFC822Header), - ('rfc822.text', RFC822Text), - ('rfc822.size', RFC822Size), - ('rfc822', RFC822), - ('uid', UID), - ('bodystructure', BodyStructure), - ] - - def __init__(self): - self.state = ['initial'] - self.result = [] - self.remaining = '' - - def parseString(self, s): - s = self.remaining + s - try: - while s or self.state: - # print 'Entering state_' + self.state[-1] + ' with', repr(s) - state = self.state.pop() - try: - used = getattr(self, 'state_' + state)(s) - except: - self.state.append(state) - raise - else: - # print state, 'consumed', repr(s[:used]) - s = s[used:] - finally: - self.remaining = s - - def state_initial(self, s): - # In the initial state, the literals "ALL", "FULL", and "FAST" - # are accepted, as is a ( indicating the beginning of a fetch_att - # token, as is the beginning of a fetch_att token. - if s == '': - return 0 - - l = s.lower() - if l.startswith('all'): - self.result.extend(( - self.Flags(), self.InternalDate(), - self.RFC822Size(), self.Envelope() - )) - return 3 - if l.startswith('full'): - self.result.extend(( - self.Flags(), self.InternalDate(), - self.RFC822Size(), self.Envelope(), - self.Body() - )) - return 4 - if l.startswith('fast'): - self.result.extend(( - self.Flags(), self.InternalDate(), self.RFC822Size(), - )) - return 4 - - if l.startswith('('): - self.state.extend(('close_paren', 'maybe_fetch_att', 'fetch_att')) - return 1 - - self.state.append('fetch_att') - return 0 - - def state_close_paren(self, s): - if s.startswith(')'): - return 1 - raise Exception("Missing )") - - def state_whitespace(self, s): - # Eat up all the leading whitespace - if not s or not s[0].isspace(): - raise Exception("Whitespace expected, none found") - i = 0 - for i in range(len(s)): - if not s[i].isspace(): - break - return i - - def state_maybe_fetch_att(self, s): - if not s.startswith(')'): - self.state.extend(('maybe_fetch_att', 'fetch_att', 'whitespace')) - return 0 - - def state_fetch_att(self, s): - # Allowed fetch_att tokens are "ENVELOPE", "FLAGS", "INTERNALDATE", - # "RFC822", "RFC822.HEADER", "RFC822.SIZE", "RFC822.TEXT", "BODY", - # "BODYSTRUCTURE", "UID", - # "BODY [".PEEK"] [
                  ] ["<" "." ">"] - - l = s.lower() - for (name, cls) in self._simple_fetch_att: - if l.startswith(name): - self.result.append(cls()) - return len(name) - - b = self.Body() - if l.startswith('body.peek'): - b.peek = True - used = 9 - elif l.startswith('body'): - used = 4 - else: - raise Exception("Nothing recognized in fetch_att: %s" % (l,)) - - self.pending_body = b - self.state.extend(('got_body', 'maybe_partial', 'maybe_section')) - return used - - def state_got_body(self, s): - self.result.append(self.pending_body) - del self.pending_body - return 0 - - def state_maybe_section(self, s): - if not s.startswith("["): - return 0 - - self.state.extend(('section', 'part_number')) - return 1 - - _partExpr = re.compile(r'(\d+(?:\.\d+)*)\.?') - def state_part_number(self, s): - m = self._partExpr.match(s) - if m is not None: - self.parts = [int(p) - 1 for p in m.groups()[0].split('.')] - return m.end() - else: - self.parts = [] - return 0 - - def state_section(self, s): - # Grab "HEADER]" or "HEADER.FIELDS (Header list)]" or - # "HEADER.FIELDS.NOT (Header list)]" or "TEXT]" or "MIME]" or - # just "]". - - l = s.lower() - used = 0 - if l.startswith(']'): - self.pending_body.empty = True - used += 1 - elif l.startswith('header]'): - h = self.pending_body.header = self.Header() - h.negate = True - h.fields = () - used += 7 - elif l.startswith('text]'): - self.pending_body.text = self.Text() - used += 5 - elif l.startswith('mime]'): - self.pending_body.mime = self.MIME() - used += 5 - else: - h = self.Header() - if l.startswith('header.fields.not'): - h.negate = True - used += 17 - elif l.startswith('header.fields'): - used += 13 - else: - raise Exception("Unhandled section contents: %r" % (l,)) - - self.pending_body.header = h - self.state.extend(('finish_section', 'header_list', 'whitespace')) - self.pending_body.part = tuple(self.parts) - self.parts = None - return used - - def state_finish_section(self, s): - if not s.startswith(']'): - raise Exception("section must end with ]") - return 1 - - def state_header_list(self, s): - if not s.startswith('('): - raise Exception("Header list must begin with (") - end = s.find(')') - if end == -1: - raise Exception("Header list must end with )") - - headers = s[1:end].split() - self.pending_body.header.fields = map(str.upper, headers) - return end + 1 - - def state_maybe_partial(self, s): - # Grab or nothing at all - if not s.startswith('<'): - return 0 - end = s.find('>') - if end == -1: - raise Exception("Found < but not >") - - partial = s[1:end] - parts = partial.split('.', 1) - if len(parts) != 2: - raise Exception("Partial specification did not include two .-delimited integers") - begin, length = map(int, parts) - self.pending_body.partialBegin = begin - self.pending_body.partialLength = length - - return end + 1 - -class FileProducer: - CHUNK_SIZE = 2 ** 2 ** 2 ** 2 - - firstWrite = True - - def __init__(self, f): - self.f = f - - def beginProducing(self, consumer): - self.consumer = consumer - self.produce = consumer.write - d = self._onDone = defer.Deferred() - self.consumer.registerProducer(self, False) - return d - - def resumeProducing(self): - b = '' - if self.firstWrite: - b = '{%d}\r\n' % self._size() - self.firstWrite = False - if not self.f: - return - b = b + self.f.read(self.CHUNK_SIZE) - if not b: - self.consumer.unregisterProducer() - self._onDone.callback(self) - self._onDone = self.f = self.consumer = None - else: - self.produce(b) - - def pauseProducing(self): - pass - - def stopProducing(self): - pass - - def _size(self): - b = self.f.tell() - self.f.seek(0, 2) - e = self.f.tell() - self.f.seek(b, 0) - return e - b - -def parseTime(s): - # XXX - This may require localization :( - months = [ - 'jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', - 'nov', 'dec', 'january', 'february', 'march', 'april', 'may', 'june', - 'july', 'august', 'september', 'october', 'november', 'december' - ] - expr = { - 'day': r"(?P3[0-1]|[1-2]\d|0[1-9]|[1-9]| [1-9])", - 'mon': r"(?P\w+)", - 'year': r"(?P\d\d\d\d)" - } - m = re.match('%(day)s-%(mon)s-%(year)s' % expr, s) - if not m: - raise ValueError, "Cannot parse time string %r" % (s,) - d = m.groupdict() - try: - d['mon'] = 1 + (months.index(d['mon'].lower()) % 12) - d['year'] = int(d['year']) - d['day'] = int(d['day']) - except ValueError: - raise ValueError, "Cannot parse time string %r" % (s,) - else: - return time.struct_time( - (d['year'], d['mon'], d['day'], 0, 0, 0, -1, -1, -1) - ) - -import codecs -def modified_base64(s): - s_utf7 = s.encode('utf-7') - return s_utf7[1:-1].replace('/', ',') - -def modified_unbase64(s): - s_utf7 = '+' + s.replace(',', '/') + '-' - return s_utf7.decode('utf-7') - -def encoder(s, errors=None): - """ - Encode the given C{unicode} string using the IMAP4 specific variation of - UTF-7. - - @type s: C{unicode} - @param s: The text to encode. - - @param errors: Policy for handling encoding errors. Currently ignored. - - @return: C{tuple} of a C{str} giving the encoded bytes and an C{int} - giving the number of code units consumed from the input. - """ - r = [] - _in = [] - for c in s: - if ord(c) in (range(0x20, 0x26) + range(0x27, 0x7f)): - if _in: - r.extend(['&', modified_base64(''.join(_in)), '-']) - del _in[:] - r.append(str(c)) - elif c == '&': - if _in: - r.extend(['&', modified_base64(''.join(_in)), '-']) - del _in[:] - r.append('&-') - else: - _in.append(c) - if _in: - r.extend(['&', modified_base64(''.join(_in)), '-']) - return (''.join(r), len(s)) - -def decoder(s, errors=None): - """ - Decode the given C{str} using the IMAP4 specific variation of UTF-7. - - @type s: C{str} - @param s: The bytes to decode. - - @param errors: Policy for handling decoding errors. Currently ignored. - - @return: a C{tuple} of a C{unicode} string giving the text which was - decoded and an C{int} giving the number of bytes consumed from the - input. - """ - r = [] - decode = [] - for c in s: - if c == '&' and not decode: - decode.append('&') - elif c == '-' and decode: - if len(decode) == 1: - r.append('&') - else: - r.append(modified_unbase64(''.join(decode[1:]))) - decode = [] - elif decode: - decode.append(c) - else: - r.append(c) - if decode: - r.append(modified_unbase64(''.join(decode[1:]))) - return (''.join(r), len(s)) - -class StreamReader(codecs.StreamReader): - def decode(self, s, errors='strict'): - return decoder(s) - -class StreamWriter(codecs.StreamWriter): - def decode(self, s, errors='strict'): - return encoder(s) - -def imap4_utf_7(name): - if name == 'imap4-utf-7': - return (encoder, decoder, StreamReader, StreamWriter) -codecs.register(imap4_utf_7) - -__all__ = [ - # Protocol classes - 'IMAP4Server', 'IMAP4Client', - - # Interfaces - 'IMailboxListener', 'IClientAuthentication', 'IAccount', 'IMailbox', - 'INamespacePresenter', 'ICloseableMailbox', 'IMailboxInfo', - 'IMessage', 'IMessageCopier', 'IMessageFile', 'ISearchableMailbox', - - # Exceptions - 'IMAP4Exception', 'IllegalClientResponse', 'IllegalOperation', - 'IllegalMailboxEncoding', 'UnhandledResponse', 'NegativeResponse', - 'NoSupportedAuthentication', 'IllegalServerResponse', - 'IllegalIdentifierError', 'IllegalQueryError', 'MismatchedNesting', - 'MismatchedQuoting', 'MailboxException', 'MailboxCollision', - 'NoSuchMailbox', 'ReadOnlyMailbox', - - # Auth objects - 'CramMD5ClientAuthenticator', 'PLAINAuthenticator', 'LOGINAuthenticator', - 'PLAINCredentials', 'LOGINCredentials', - - # Simple query interface - 'Query', 'Not', 'Or', - - # Miscellaneous - 'MemoryAccount', - 'statusRequestHelper', -] diff --git a/tools/buildbot/pylibs/twisted/mail/mail.py b/tools/buildbot/pylibs/twisted/mail/mail.py deleted file mode 100644 index 233c1b6..0000000 --- a/tools/buildbot/pylibs/twisted/mail/mail.py +++ /dev/null @@ -1,333 +0,0 @@ -# -*- test-case-name: twisted.mail.test.test_mail -*- -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Mail support for twisted python. -""" - -# Twisted imports -from twisted.internet import defer -from twisted.application import service, internet -from twisted.python import util -from twisted.python import log - -from twisted import cred -import twisted.cred.portal - -# Sibling imports -from twisted.mail import protocols, smtp - -# System imports -import os -from zope.interface import implements, Interface - - -class DomainWithDefaultDict: - '''Simulate a dictionary with a default value for non-existing keys. - ''' - def __init__(self, domains, default): - self.domains = domains - self.default = default - - def setDefaultDomain(self, domain): - self.default = domain - - def has_key(self, name): - return 1 - - def fromkeys(klass, keys, value=None): - d = klass() - for k in keys: - d[k] = value - return d - fromkeys = classmethod(fromkeys) - - def __contains__(self, name): - return 1 - - def __getitem__(self, name): - return self.domains.get(name, self.default) - - def __setitem__(self, name, value): - self.domains[name] = value - - def __delitem__(self, name): - del self.domains[name] - - def __iter__(self): - return iter(self.domains) - - def __len__(self): - return len(self.domains) - - - def __str__(self): - """ - Return a string describing the underlying domain mapping of this - object. - """ - return '' % (self.domains,) - - - def __repr__(self): - """ - Return a pseudo-executable string describing the underlying domain - mapping of this object. - """ - return 'DomainWithDefaultDict(%s)' % (self.domains,) - - - def get(self, key, default=None): - return self.domains.get(key, default) - - def copy(self): - return DomainWithDefaultDict(self.domains.copy(), self.default) - - def iteritems(self): - return self.domains.iteritems() - - def iterkeys(self): - return self.domains.iterkeys() - - def itervalues(self): - return self.domains.itervalues() - - def keys(self): - return self.domains.keys() - - def values(self): - return self.domains.values() - - def items(self): - return self.domains.items() - - def popitem(self): - return self.domains.popitem() - - def update(self, other): - return self.domains.update(other) - - def clear(self): - return self.domains.clear() - - def setdefault(self, key, default): - return self.domains.setdefault(key, default) - -class IDomain(Interface): - """An email domain.""" - - def exists(user): - """ - Check whether or not the specified user exists in this domain. - - @type user: C{twisted.protocols.smtp.User} - @param user: The user to check - - @rtype: No-argument callable - @return: A C{Deferred} which becomes, or a callable which - takes no arguments and returns an object implementing C{IMessage}. - This will be called and the returned object used to deliver the - message when it arrives. - - @raise twisted.protocols.smtp.SMTPBadRcpt: Raised if the given - user does not exist in this domain. - """ - - def addUser(user, password): - """Add a username/password to this domain.""" - - def startMessage(user): - """Create and return a new message to be delivered to the given user. - - DEPRECATED. Implement validateTo() correctly instead. - """ - - def getCredentialsCheckers(): - """Return a list of ICredentialsChecker implementors for this domain. - """ - -class IAliasableDomain(IDomain): - def setAliasGroup(aliases): - """Set the group of defined aliases for this domain - - @type aliases: C{dict} - @param aliases: Mapping of domain names to objects implementing - C{IAlias} - """ - - def exists(user, memo=None): - """ - Check whether or not the specified user exists in this domain. - - @type user: C{twisted.protocols.smtp.User} - @param user: The user to check - - @type memo: C{dict} - @param memo: A record of the addresses already considered while - resolving aliases. The default value should be used by all - external code. - - @rtype: No-argument callable - @return: A C{Deferred} which becomes, or a callable which - takes no arguments and returns an object implementing C{IMessage}. - This will be called and the returned object used to deliver the - message when it arrives. - - @raise twisted.protocols.smtp.SMTPBadRcpt: Raised if the given - user does not exist in this domain. - """ - -class BounceDomain: - """A domain in which no user exists. - - This can be used to block off certain domains. - """ - - implements(IDomain) - - def exists(self, user): - raise smtp.SMTPBadRcpt(user) - - def willRelay(self, user, protocol): - return False - - def addUser(self, user, password): - pass - - def startMessage(self, user): - """ - No code should ever call this function. - """ - raise NotImplementedError( - "No code should ever call this method for any reason") - - def getCredentialsCheckers(self): - return [] - - -class FileMessage: - """A file we can write an email too.""" - - implements(smtp.IMessage) - - def __init__(self, fp, name, finalName): - self.fp = fp - self.name = name - self.finalName = finalName - - def lineReceived(self, line): - self.fp.write(line+'\n') - - def eomReceived(self): - self.fp.close() - os.rename(self.name, self.finalName) - return defer.succeed(self.finalName) - - def connectionLost(self): - self.fp.close() - os.remove(self.name) - - -class MailService(service.MultiService): - """An email service.""" - - queue = None - domains = None - portals = None - aliases = None - smtpPortal = None - - def __init__(self): - service.MultiService.__init__(self) - # Domains and portals for "client" protocols - POP3, IMAP4, etc - self.domains = DomainWithDefaultDict({}, BounceDomain()) - self.portals = {} - - self.monitor = FileMonitoringService() - self.monitor.setServiceParent(self) - self.smtpPortal = cred.portal.Portal(self) - - def getPOP3Factory(self): - return protocols.POP3Factory(self) - - def getSMTPFactory(self): - return protocols.SMTPFactory(self, self.smtpPortal) - - def getESMTPFactory(self): - return protocols.ESMTPFactory(self, self.smtpPortal) - - def addDomain(self, name, domain): - portal = cred.portal.Portal(domain) - map(portal.registerChecker, domain.getCredentialsCheckers()) - self.domains[name] = domain - self.portals[name] = portal - if self.aliases and IAliasableDomain.providedBy(domain): - domain.setAliasGroup(self.aliases) - - def setQueue(self, queue): - """Set the queue for outgoing emails.""" - self.queue = queue - - def requestAvatar(self, avatarId, mind, *interfaces): - if smtp.IMessageDelivery in interfaces: - a = protocols.ESMTPDomainDelivery(self, avatarId) - return smtp.IMessageDelivery, a, lambda: None - raise NotImplementedError() - - def lookupPortal(self, name): - return self.portals[name] - - def defaultPortal(self): - return self.portals[''] - - -class FileMonitoringService(internet.TimerService): - - def __init__(self): - self.files = [] - self.intervals = iter(util.IntervalDifferential([], 60)) - - def startService(self): - service.Service.startService(self) - self._setupMonitor() - - def _setupMonitor(self): - from twisted.internet import reactor - t, self.index = self.intervals.next() - self._call = reactor.callLater(t, self._monitor) - - def stopService(self): - service.Service.stopService(self) - if self._call: - self._call.cancel() - self._call = None - - def monitorFile(self, name, callback, interval=10): - try: - mtime = os.path.getmtime(name) - except: - mtime = 0 - self.files.append([interval, name, callback, mtime]) - self.intervals.addInterval(interval) - - def unmonitorFile(self, name): - for i in range(len(self.files)): - if name == self.files[i][1]: - self.intervals.removeInterval(self.files[i][0]) - del self.files[i] - break - - def _monitor(self): - self._call = None - if self.index is not None: - name, callback, mtime = self.files[self.index][1:] - try: - now = os.path.getmtime(name) - except: - now = 0 - if now > mtime: - log.msg("%s changed, notifying listener" % (name,)) - self.files[self.index][3] = now - callback(name) - self._setupMonitor() diff --git a/tools/buildbot/pylibs/twisted/mail/maildir.py b/tools/buildbot/pylibs/twisted/mail/maildir.py deleted file mode 100644 index 439e92e38..0000000 --- a/tools/buildbot/pylibs/twisted/mail/maildir.py +++ /dev/null @@ -1,459 +0,0 @@ -# -*- test-case-name: twisted.mail.test.test_mail -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Maildir-style mailbox support -""" - -from __future__ import generators - -import os -import stat -import socket -import time -import md5 -import cStringIO - -from zope.interface import implements - -try: - import cStringIO as StringIO -except ImportError: - import StringIO - -from twisted.mail import pop3 -from twisted.mail import smtp -from twisted.protocols import basic -from twisted.persisted import dirdbm -from twisted.python import log, failure -from twisted.mail import mail -from twisted.mail import alias -from twisted.internet import interfaces, defer, reactor - -from twisted import cred -import twisted.cred.portal -import twisted.cred.credentials -import twisted.cred.checkers -import twisted.cred.error - -INTERNAL_ERROR = '''\ -From: Twisted.mail Internals -Subject: An Error Occurred - - An internal server error has occurred. Please contact the - server administrator. -''' - -class _MaildirNameGenerator: - """Utility class to generate a unique maildir name - """ - n = 0 - p = os.getpid() - s = socket.gethostname().replace('/', r'\057').replace(':', r'\072') - - def generate(self): - self.n = self.n + 1 - t = time.time() - seconds = str(int(t)) - microseconds = str(int((t-int(t))*10e6)) - return '%s.M%sP%sQ%s.%s' % (seconds, microseconds, - self.p, self.n, self.s) - -_generateMaildirName = _MaildirNameGenerator().generate - -def initializeMaildir(dir): - if not os.path.isdir(dir): - os.mkdir(dir, 0700) - for subdir in ['new', 'cur', 'tmp', '.Trash']: - os.mkdir(os.path.join(dir, subdir), 0700) - for subdir in ['new', 'cur', 'tmp']: - os.mkdir(os.path.join(dir, '.Trash', subdir), 0700) - # touch - open(os.path.join(dir, '.Trash', 'maildirfolder'), 'w').close() - - -class MaildirMessage(mail.FileMessage): - size = None - - def __init__(self, address, fp, *a, **kw): - header = "Delivered-To: %s\n" % address - fp.write(header) - self.size = len(header) - mail.FileMessage.__init__(self, fp, *a, **kw) - - def lineReceived(self, line): - mail.FileMessage.lineReceived(self, line) - self.size += len(line)+1 - - def eomReceived(self): - self.finalName = self.finalName+',S=%d' % self.size - return mail.FileMessage.eomReceived(self) - -class AbstractMaildirDomain: - """Abstract maildir-backed domain. - """ - alias = None - root = None - - def __init__(self, service, root): - """Initialize. - """ - self.root = root - - def userDirectory(self, user): - """Get the maildir directory for a given user - - Override to specify where to save mails for users. - Return None for non-existing users. - """ - return None - - ## - ## IAliasableDomain - ## - - def setAliasGroup(self, alias): - self.alias = alias - - ## - ## IDomain - ## - def exists(self, user, memo=None): - """Check for existence of user in the domain - """ - if self.userDirectory(user.dest.local) is not None: - return lambda: self.startMessage(user) - try: - a = self.alias[user.dest.local] - except: - raise smtp.SMTPBadRcpt(user) - else: - aliases = a.resolve(self.alias, memo) - if aliases: - return lambda: aliases - log.err("Bad alias configuration: " + str(user)) - raise smtp.SMTPBadRcpt(user) - - def startMessage(self, user): - """Save a message for a given user - """ - if isinstance(user, str): - name, domain = user.split('@', 1) - else: - name, domain = user.dest.local, user.dest.domain - dir = self.userDirectory(name) - fname = _generateMaildirName() - filename = os.path.join(dir, 'tmp', fname) - fp = open(filename, 'w') - return MaildirMessage('%s@%s' % (name, domain), fp, filename, - os.path.join(dir, 'new', fname)) - - def willRelay(self, user, protocol): - return False - - def addUser(self, user, password): - raise NotImplementedError - - def getCredentialsCheckers(self): - raise NotImplementedError - ## - ## end of IDomain - ## - -class _MaildirMailboxAppendMessageTask: - implements(interfaces.IConsumer) - - osopen = staticmethod(os.open) - oswrite = staticmethod(os.write) - osclose = staticmethod(os.close) - osrename = staticmethod(os.rename) - - def __init__(self, mbox, msg): - self.mbox = mbox - self.defer = defer.Deferred() - self.openCall = None - if not hasattr(msg, "read"): - msg = StringIO.StringIO(msg) - self.msg = msg - # This is needed, as this startup phase might call defer.errback and zero out self.defer - # By doing it on the reactor iteration appendMessage is able to use .defer without problems. - reactor.callLater(0, self.startUp) - - def startUp(self): - self.createTempFile() - if self.fh != -1: - self.filesender = basic.FileSender() - self.filesender.beginFileTransfer(self.msg, self) - - def registerProducer(self, producer, streaming): - self.myproducer = producer - self.streaming = streaming - if not streaming: - self.prodProducer() - - def prodProducer(self): - self.openCall = None - if self.myproducer is not None: - self.openCall = reactor.callLater(0, self.prodProducer) - self.myproducer.resumeProducing() - - def unregisterProducer(self): - self.myproducer = None - self.streaming = None - self.osclose(self.fh) - self.moveFileToNew() - - def write(self, data): - try: - self.oswrite(self.fh, data) - except: - self.fail() - - def fail(self, err=None): - if err is None: - err = failure.Failure() - if self.openCall is not None: - self.openCall.cancel() - self.defer.errback(err) - self.defer = None - - def moveFileToNew(self): - while True: - newname = os.path.join(self.mbox.path, "new", _generateMaildirName()) - try: - self.osrename(self.tmpname, newname) - break - except OSError, (err, estr): - import errno - # if the newname exists, retry with a new newname. - if err != errno.EEXIST: - self.fail() - newname = None - break - if newname is not None: - self.mbox.list.append(newname) - self.defer.callback(None) - self.defer = None - - def createTempFile(self): - attr = (os.O_RDWR | os.O_CREAT | os.O_EXCL - | getattr(os, "O_NOINHERIT", 0) - | getattr(os, "O_NOFOLLOW", 0)) - tries = 0 - self.fh = -1 - while True: - self.tmpname = os.path.join(self.mbox.path, "tmp", _generateMaildirName()) - try: - self.fh = self.osopen(self.tmpname, attr, 0600) - return None - except OSError: - tries += 1 - if tries > 500: - self.defer.errback(RuntimeError("Could not create tmp file for %s" % self.mbox.path)) - self.defer = None - return None - -class MaildirMailbox(pop3.Mailbox): - """Implement the POP3 mailbox semantics for a Maildir mailbox - """ - AppendFactory = _MaildirMailboxAppendMessageTask - - def __init__(self, path): - """Initialize with name of the Maildir mailbox - """ - self.path = path - self.list = [] - self.deleted = {} - initializeMaildir(path) - for name in ('cur', 'new'): - for file in os.listdir(os.path.join(path, name)): - self.list.append((file, os.path.join(path, name, file))) - self.list.sort() - self.list = [e[1] for e in self.list] - - def listMessages(self, i=None): - """Return a list of lengths of all files in new/ and cur/ - """ - if i is None: - ret = [] - for mess in self.list: - if mess: - ret.append(os.stat(mess)[stat.ST_SIZE]) - else: - ret.append(0) - return ret - return self.list[i] and os.stat(self.list[i])[stat.ST_SIZE] or 0 - - def getMessage(self, i): - """Return an open file-pointer to a message - """ - return open(self.list[i]) - - def getUidl(self, i): - """Return a unique identifier for a message - - This is done using the basename of the filename. - It is globally unique because this is how Maildirs are designed. - """ - # Returning the actual filename is a mistake. Hash it. - base = os.path.basename(self.list[i]) - return md5.md5(base).hexdigest() - - def deleteMessage(self, i): - """Delete a message - - This only moves a message to the .Trash/ subfolder, - so it can be undeleted by an administrator. - """ - trashFile = os.path.join( - self.path, '.Trash', 'cur', os.path.basename(self.list[i]) - ) - os.rename(self.list[i], trashFile) - self.deleted[self.list[i]] = trashFile - self.list[i] = 0 - - def undeleteMessages(self): - """Undelete any deleted messages it is possible to undelete - - This moves any messages from .Trash/ subfolder back to their - original position, and empties out the deleted dictionary. - """ - for (real, trash) in self.deleted.items(): - try: - os.rename(trash, real) - except OSError, (err, estr): - import errno - # If the file has been deleted from disk, oh well! - if err != errno.ENOENT: - raise - # This is a pass - else: - try: - self.list[self.list.index(0)] = real - except ValueError: - self.list.append(real) - self.deleted.clear() - - def appendMessage(self, txt): - """Appends a message into the mailbox.""" - task = self.AppendFactory(self, txt) - return task.defer - -class StringListMailbox: - implements(pop3.IMailbox) - - def __init__(self, msgs): - self.msgs = msgs - - def listMessages(self, i=None): - if i is None: - return map(len, self.msgs) - return len(self.msgs[i]) - - def getMessage(self, i): - return StringIO.StringIO(self.msgs[i]) - - def getUidl(self, i): - return md5.new(self.msgs[i]).hexdigest() - - def deleteMessage(self, i): - pass - - def undeleteMessages(self): - pass - - def sync(self): - pass - -class MaildirDirdbmDomain(AbstractMaildirDomain): - """A Maildir Domain where membership is checked by a dirdbm file - """ - - implements(cred.portal.IRealm, mail.IAliasableDomain) - - portal = None - _credcheckers = None - - def __init__(self, service, root, postmaster=0): - """Initialize - - The first argument is where the Domain directory is rooted. - The second is whether non-existing addresses are simply - forwarded to postmaster instead of outright bounce - - The directory structure of a MailddirDirdbmDomain is: - - /passwd <-- a dirdbm file - /USER/{cur,new,del} <-- each user has these three directories - """ - AbstractMaildirDomain.__init__(self, service, root) - dbm = os.path.join(root, 'passwd') - if not os.path.exists(dbm): - os.makedirs(dbm) - self.dbm = dirdbm.open(dbm) - self.postmaster = postmaster - - def userDirectory(self, name): - """Get the directory for a user - - If the user exists in the dirdbm file, return the directory - os.path.join(root, name), creating it if necessary. - Otherwise, returns postmaster's mailbox instead if bounces - go to postmaster, otherwise return None - """ - if not self.dbm.has_key(name): - if not self.postmaster: - return None - name = 'postmaster' - dir = os.path.join(self.root, name) - if not os.path.exists(dir): - initializeMaildir(dir) - return dir - - ## - ## IDomain - ## - def addUser(self, user, password): - self.dbm[user] = password - # Ensure it is initialized - self.userDirectory(user) - - def getCredentialsCheckers(self): - if self._credcheckers is None: - self._credcheckers = [DirdbmDatabase(self.dbm)] - return self._credcheckers - - ## - ## IRealm - ## - def requestAvatar(self, avatarId, mind, *interfaces): - if pop3.IMailbox not in interfaces: - raise NotImplementedError("No interface") - if avatarId == cred.checkers.ANONYMOUS: - mbox = StringListMailbox([INTERNAL_ERROR]) - else: - mbox = MaildirMailbox(os.path.join(self.root, avatarId)) - - return ( - pop3.IMailbox, - mbox, - lambda: None - ) - -class DirdbmDatabase: - implements(cred.checkers.ICredentialsChecker) - - credentialInterfaces = ( - cred.credentials.IUsernamePassword, - cred.credentials.IUsernameHashedPassword - ) - - def __init__(self, dbm): - self.dirdbm = dbm - - def requestAvatarId(self, c): - if c.username in self.dirdbm: - if c.checkPassword(self.dirdbm[c.username]): - return c.username - raise cred.error.UnauthorizedLogin() diff --git a/tools/buildbot/pylibs/twisted/mail/pb.py b/tools/buildbot/pylibs/twisted/mail/pb.py deleted file mode 100644 index dfe72d3..0000000 --- a/tools/buildbot/pylibs/twisted/mail/pb.py +++ /dev/null @@ -1,115 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -from twisted.spread import pb -from twisted.spread import banana - -import os -import types - -class Maildir(pb.Referenceable): - - def __init__(self, directory, rootDirectory): - self.virtualDirectory = directory - self.rootDirectory = rootDirectory - self.directory = os.path.join(rootDirectory, directory) - - def getFolderMessage(self, folder, name): - if '/' in name: - raise IOError("can only open files in '%s' directory'" % folder) - fp = open(os.path.join(self.directory, 'new', name)) - try: - return fp.read() - finally: - fp.close() - - def deleteFolderMessage(self, folder, name): - if '/' in name: - raise IOError("can only delete files in '%s' directory'" % folder) - os.rename(os.path.join(self.directory, folder, name), - os.path.join(self.rootDirectory, '.Trash', folder, name)) - - def deleteNewMessage(self, name): - return self.deleteFolderMessage('new', name) - remote_deleteNewMessage = deleteNewMessage - - def deleteCurMessage(self, name): - return self.deleteFolderMessage('cur', name) - remote_deleteCurMessage = deleteCurMessage - - def getNewMessages(self): - return os.listdir(os.path.join(self.directory, 'new')) - remote_getNewMessages = getNewMessages - - def getCurMessages(self): - return os.listdir(os.path.join(self.directory, 'cur')) - remote_getCurMessages = getCurMessages - - def getNewMessage(self, name): - return self.getFolderMessage('new', name) - remote_getNewMessage = getNewMessage - - def getCurMessage(self, name): - return self.getFolderMessage('cur', name) - remote_getCurMessage = getCurMessage - - def getSubFolder(self, name): - if name[0] == '.': - raise IOError("subfolder name cannot begin with a '.'") - name = name.replace('/', ':') - if self.virtualDirectoy == '.': - name = '.'+name - else: - name = self.virtualDirectory+':'+name - if not self._isSubFolder(name): - raise IOError("not a subfolder") - return Maildir(name, self.rootDirectory) - remote_getSubFolder = getSubFolder - - def _isSubFolder(self, name): - return (not os.path.isdir(os.path.join(self.rootDirectory, name)) or - not os.path.isfile(os.path.join(self.rootDirectory, name, - 'maildirfolder'))) - - -class MaildirCollection(pb.Referenceable): - - def __init__(self, root): - self.root = root - - def getSubFolders(self): - return os.listdir(self.getRoot()) - remote_getSubFolders = getSubFolders - - def getSubFolder(self, name): - if '/' in name or name[0] == '.': - raise IOError("invalid name") - return Maildir('.', os.path.join(self.getRoot(), name)) - remote_getSubFolder = getSubFolder - - -class MaildirBroker(pb.Broker): - - def proto_getCollection(self, requestID, name, domain, password): - collection = self._getCollection() - if collection is None: - self.sendError(requestID, "permission denied") - else: - self.sendAnswer(requestID, collection) - - def getCollection(self, name, domain, password): - if not self.domains.has_key(domain): - return - domain = self.domains[domain] - if (domain.dbm.has_key(name) and - domain.dbm[name] == password): - return MaildirCollection(domain.userDirectory(name)) - - -class MaildirClient(pb.Broker): - - def getCollection(self, name, domain, password, callback, errback): - requestID = self.newRequestID() - self.waitingForAnswers[requestID] = callback, errback - self.sendCall("getCollection", requestID, name, domain, password) diff --git a/tools/buildbot/pylibs/twisted/mail/pop3.py b/tools/buildbot/pylibs/twisted/mail/pop3.py deleted file mode 100644 index 5c3dd13..0000000 --- a/tools/buildbot/pylibs/twisted/mail/pop3.py +++ /dev/null @@ -1,1072 +0,0 @@ -# -*- test-case-name: twisted.mail.test.test_pop3 -*- -# -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Post-office Protocol version 3 - -@author: U{Glyph Lefkowitz} -@author: U{Jp Calderone} -""" - -import string -import base64 -import binascii -import md5 -import warnings - -from zope.interface import implements, Interface - -from twisted.mail import smtp -from twisted.protocols import basic -from twisted.protocols import policies -from twisted.internet import task -from twisted.internet import defer -from twisted.internet import interfaces -from twisted.python import log - -from twisted import cred -import twisted.cred.error -import twisted.cred.credentials - -## -## Authentication -## -class APOPCredentials: - implements(cred.credentials.IUsernamePassword) - - def __init__(self, magic, username, digest): - self.magic = magic - self.username = username - self.digest = digest - - def checkPassword(self, password): - seed = self.magic + password - myDigest = md5.new(seed).hexdigest() - return myDigest == self.digest - - -class _HeadersPlusNLines: - def __init__(self, f, n): - self.f = f - self.n = n - self.linecount = 0 - self.headers = 1 - self.done = 0 - self.buf = '' - - def read(self, bytes): - if self.done: - return '' - data = self.f.read(bytes) - if not data: - return data - if self.headers: - df, sz = data.find('\r\n\r\n'), 4 - if df == -1: - df, sz = data.find('\n\n'), 2 - if df != -1: - df += sz - val = data[:df] - data = data[df:] - self.linecount = 1 - self.headers = 0 - else: - val = '' - if self.linecount > 0: - dsplit = (self.buf+data).split('\n') - self.buf = dsplit[-1] - for ln in dsplit[:-1]: - if self.linecount > self.n: - self.done = 1 - return val - val += (ln + '\n') - self.linecount += 1 - return val - else: - return data - - - -class _POP3MessageDeleted(Exception): - """ - Internal control-flow exception. Indicates the file of a deleted message - was requested. - """ - - -class POP3Error(Exception): - pass - - - -class _IteratorBuffer(object): - bufSize = 0 - - def __init__(self, write, iterable, memoryBufferSize=None): - """ - Create a _IteratorBuffer. - - @param write: A one-argument callable which will be invoked with a list - of strings which have been buffered. - - @param iterable: The source of input strings as any iterable. - - @param memoryBufferSize: The upper limit on buffered string length, - beyond which the buffer will be flushed to the writer. - """ - self.lines = [] - self.write = write - self.iterator = iter(iterable) - if memoryBufferSize is None: - memoryBufferSize = 2 ** 16 - self.memoryBufferSize = memoryBufferSize - - - def __iter__(self): - return self - - - def next(self): - try: - v = self.iterator.next() - except StopIteration: - if self.lines: - self.write(self.lines) - # Drop some references, in case they're edges in a cycle. - del self.iterator, self.lines, self.write - raise - else: - if v is not None: - self.lines.append(v) - self.bufSize += len(v) - if self.bufSize > self.memoryBufferSize: - self.write(self.lines) - self.lines = [] - self.bufSize = 0 - - - -def iterateLineGenerator(proto, gen): - """ - Hook the given protocol instance up to the given iterator with an - _IteratorBuffer and schedule the result to be exhausted via the protocol. - - @type proto: L{POP3} - @type gen: iterator - @rtype: L{twisted.internet.defer.Deferred} - """ - coll = _IteratorBuffer(proto.transport.writeSequence, gen) - return proto.schedule(coll) - - - -def successResponse(response): - """ - Format the given object as a positive response. - """ - response = str(response) - return '+OK %s\r\n' % (response,) - - - -def formatStatResponse(msgs): - """ - Format the list of message sizes appropriately for a STAT response. - - Yields None until it finishes computing a result, then yields a str - instance that is suitable for use as a response to the STAT command. - Intended to be used with a L{twisted.internet.task.Cooperator}. - """ - i = 0 - bytes = 0 - for size in msgs: - i += 1 - bytes += size - yield None - yield successResponse('%d %d' % (i, bytes)) - - - -def formatListLines(msgs): - """ - Format a list of message sizes appropriately for the lines of a LIST - response. - - Yields str instances formatted appropriately for use as lines in the - response to the LIST command. Does not include the trailing '.'. - """ - i = 0 - for size in msgs: - i += 1 - yield '%d %d\r\n' % (i, size) - - - -def formatListResponse(msgs): - """ - Format a list of message sizes appropriately for a complete LIST response. - - Yields str instances formatted appropriately for use as a LIST command - response. - """ - yield successResponse(len(msgs)) - for ele in formatListLines(msgs): - yield ele - yield '.\r\n' - - - -def formatUIDListLines(msgs, getUidl): - """ - Format the list of message sizes appropriately for the lines of a UIDL - response. - - Yields str instances formatted appropriately for use as lines in the - response to the UIDL command. Does not include the trailing '.'. - """ - for i, m in enumerate(msgs): - if m is not None: - uid = getUidl(i) - yield '%d %s\r\n' % (i + 1, uid) - - - -def formatUIDListResponse(msgs, getUidl): - """ - Format a list of message sizes appropriately for a complete UIDL response. - - Yields str instances formatted appropriately for use as a UIDL command - response. - """ - yield successResponse('') - for ele in formatUIDListLines(msgs, getUidl): - yield ele - yield '.\r\n' - - - -class POP3(basic.LineOnlyReceiver, policies.TimeoutMixin): - """ - POP3 server protocol implementation. - - @ivar portal: A reference to the L{twisted.cred.portal.Portal} instance we - will authenticate through. - - @ivar factory: A L{twisted.mail.pop3.IServerFactory} which will be used to - determine some extended behavior of the server. - - @ivar timeOut: An integer which defines the minimum amount of time which - may elapse without receiving any traffic after which the client will be - disconnected. - - @ivar schedule: A one-argument callable which should behave like - L{twisted.internet.task.coiterate}. - """ - implements(interfaces.IProducer) - - magic = None - _userIs = None - _onLogout = None - - AUTH_CMDS = ['CAPA', 'USER', 'PASS', 'APOP', 'AUTH', 'RPOP', 'QUIT'] - - portal = None - factory = None - - # The mailbox we're serving - mbox = None - - # Set this pretty low -- POP3 clients are expected to log in, download - # everything, and log out. - timeOut = 300 - - # Current protocol state - state = "COMMAND" - - # PIPELINE - blocked = None - - # Cooperate and suchlike. - schedule = staticmethod(task.coiterate) - - # Message index of the highest retrieved message. - _highest = 0 - - def connectionMade(self): - if self.magic is None: - self.magic = self.generateMagic() - self.successResponse(self.magic) - self.setTimeout(self.timeOut) - if getattr(self.factory, 'noisy', True): - log.msg("New connection from " + str(self.transport.getPeer())) - - - def connectionLost(self, reason): - if self._onLogout is not None: - self._onLogout() - self._onLogout = None - self.setTimeout(None) - - - def generateMagic(self): - return smtp.messageid() - - - def successResponse(self, message=''): - self.transport.write(successResponse(message)) - - def failResponse(self, message=''): - self.sendLine('-ERR ' + str(message)) - -# def sendLine(self, line): -# print 'S:', repr(line) -# basic.LineOnlyReceiver.sendLine(self, line) - - def lineReceived(self, line): -# print 'C:', repr(line) - self.resetTimeout() - getattr(self, 'state_' + self.state)(line) - - def _unblock(self, _): - commands = self.blocked - self.blocked = None - while commands and self.blocked is None: - cmd, args = commands.pop(0) - self.processCommand(cmd, *args) - if self.blocked is not None: - self.blocked.extend(commands) - - def state_COMMAND(self, line): - try: - return self.processCommand(*line.split(' ')) - except (ValueError, AttributeError, POP3Error, TypeError), e: - log.err() - self.failResponse('bad protocol or server: %s: %s' % (e.__class__.__name__, e)) - - def processCommand(self, command, *args): - if self.blocked is not None: - self.blocked.append((command, args)) - return - - command = string.upper(command) - authCmd = command in self.AUTH_CMDS - if not self.mbox and not authCmd: - raise POP3Error("not authenticated yet: cannot do " + command) - f = getattr(self, 'do_' + command, None) - if f: - return f(*args) - raise POP3Error("Unknown protocol command: " + command) - - - def listCapabilities(self): - baseCaps = [ - "TOP", - "USER", - "UIDL", - "PIPELINE", - "CELERITY", - "AUSPEX", - "POTENCE", - ] - - if IServerFactory.providedBy(self.factory): - # Oh my god. We can't just loop over a list of these because - # each has spectacularly different return value semantics! - try: - v = self.factory.cap_IMPLEMENTATION() - except NotImplementedError: - pass - except: - log.err() - else: - baseCaps.append("IMPLEMENTATION " + str(v)) - - try: - v = self.factory.cap_EXPIRE() - except NotImplementedError: - pass - except: - log.err() - else: - if v is None: - v = "NEVER" - if self.factory.perUserExpiration(): - if self.mbox: - v = str(self.mbox.messageExpiration) - else: - v = str(v) + " USER" - v = str(v) - baseCaps.append("EXPIRE " + v) - - try: - v = self.factory.cap_LOGIN_DELAY() - except NotImplementedError: - pass - except: - log.err() - else: - if self.factory.perUserLoginDelay(): - if self.mbox: - v = str(self.mbox.loginDelay) - else: - v = str(v) + " USER" - v = str(v) - baseCaps.append("LOGIN-DELAY " + v) - - try: - v = self.factory.challengers - except AttributeError: - pass - except: - log.err() - else: - baseCaps.append("SASL " + ' '.join(v.keys())) - return baseCaps - - def do_CAPA(self): - self.successResponse("I can do the following:") - for cap in self.listCapabilities(): - self.sendLine(cap) - self.sendLine(".") - - def do_AUTH(self, args=None): - if not getattr(self.factory, 'challengers', None): - self.failResponse("AUTH extension unsupported") - return - - if args is None: - self.successResponse("Supported authentication methods:") - for a in self.factory.challengers: - self.sendLine(a.upper()) - self.sendLine(".") - return - - auth = self.factory.challengers.get(args.strip().upper()) - if not self.portal or not auth: - self.failResponse("Unsupported SASL selected") - return - - self._auth = auth() - chal = self._auth.getChallenge() - - self.sendLine('+ ' + base64.encodestring(chal).rstrip('\n')) - self.state = 'AUTH' - - def state_AUTH(self, line): - self.state = "COMMAND" - try: - parts = base64.decodestring(line).split(None, 1) - except binascii.Error: - self.failResponse("Invalid BASE64 encoding") - else: - if len(parts) != 2: - self.failResponse("Invalid AUTH response") - return - self._auth.username = parts[0] - self._auth.response = parts[1] - d = self.portal.login(self._auth, None, IMailbox) - d.addCallback(self._cbMailbox, parts[0]) - d.addErrback(self._ebMailbox) - d.addErrback(self._ebUnexpected) - - def do_APOP(self, user, digest): - d = defer.maybeDeferred(self.authenticateUserAPOP, user, digest) - d.addCallbacks(self._cbMailbox, self._ebMailbox, callbackArgs=(user,) - ).addErrback(self._ebUnexpected) - - def _cbMailbox(self, (interface, avatar, logout), user): - if interface is not IMailbox: - self.failResponse('Authentication failed') - log.err("_cbMailbox() called with an interface other than IMailbox") - return - - self.mbox = avatar - self._onLogout = logout - self.successResponse('Authentication succeeded') - if getattr(self.factory, 'noisy', True): - log.msg("Authenticated login for " + user) - - def _ebMailbox(self, failure): - failure = failure.trap(cred.error.LoginDenied, cred.error.LoginFailed) - if issubclass(failure, cred.error.LoginDenied): - self.failResponse("Access denied: " + str(failure)) - elif issubclass(failure, cred.error.LoginFailed): - self.failResponse('Authentication failed') - if getattr(self.factory, 'noisy', True): - log.msg("Denied login attempt from " + str(self.transport.getPeer())) - - def _ebUnexpected(self, failure): - self.failResponse('Server error: ' + failure.getErrorMessage()) - log.err(failure) - - def do_USER(self, user): - self._userIs = user - self.successResponse('USER accepted, send PASS') - - def do_PASS(self, password): - if self._userIs is None: - self.failResponse("USER required before PASS") - return - user = self._userIs - self._userIs = None - d = defer.maybeDeferred(self.authenticateUserPASS, user, password) - d.addCallbacks(self._cbMailbox, self._ebMailbox, callbackArgs=(user,) - ).addErrback(self._ebUnexpected) - - - def _longOperation(self, d): - # Turn off timeouts and block further processing until the Deferred - # fires, then reverse those changes. - timeOut = self.timeOut - self.setTimeout(None) - self.blocked = [] - d.addCallback(self._unblock) - d.addCallback(lambda ign: self.setTimeout(timeOut)) - return d - - - def _coiterate(self, gen): - return self.schedule(_IteratorBuffer(self.transport.writeSequence, gen)) - - - def do_STAT(self): - d = defer.maybeDeferred(self.mbox.listMessages) - def cbMessages(msgs): - return self._coiterate(formatStatResponse(msgs)) - def ebMessages(err): - self.failResponse(err.getErrorMessage()) - log.msg("Unexpected do_STAT failure:") - log.err(err) - return self._longOperation(d.addCallbacks(cbMessages, ebMessages)) - - - def do_LIST(self, i=None): - if i is None: - d = defer.maybeDeferred(self.mbox.listMessages) - def cbMessages(msgs): - return self._coiterate(formatListResponse(msgs)) - def ebMessages(err): - self.failResponse(err.getErrorMessage()) - log.msg("Unexpected do_LIST failure:") - log.err(err) - return self._longOperation(d.addCallbacks(cbMessages, ebMessages)) - else: - try: - i = int(i) - if i < 1: - raise ValueError() - except ValueError: - self.failResponse("Invalid message-number: %r" % (i,)) - else: - d = defer.maybeDeferred(self.mbox.listMessages, i - 1) - def cbMessage(msg): - self.successResponse('%d %d' % (i, msg)) - def ebMessage(err): - errcls = err.check(ValueError, IndexError) - if errcls is not None: - if errcls is IndexError: - # IndexError was supported for a while, but really - # shouldn't be. One error condition, one exception - # type. - warnings.warn( - "twisted.mail.pop3.IMailbox.listMessages may not " - "raise IndexError for out-of-bounds message numbers: " - "raise ValueError instead.", - PendingDeprecationWarning) - self.failResponse("Invalid message-number: %r" % (i,)) - else: - self.failResponse(err.getErrorMessage()) - log.msg("Unexpected do_LIST failure:") - log.err(err) - return self._longOperation(d.addCallbacks(cbMessage, ebMessage)) - - - def do_UIDL(self, i=None): - if i is None: - d = defer.maybeDeferred(self.mbox.listMessages) - def cbMessages(msgs): - return self._coiterate(formatUIDListResponse(msgs, self.mbox.getUidl)) - def ebMessages(err): - self.failResponse(err.getErrorMessage()) - log.msg("Unexpected do_UIDL failure:") - log.err(err) - return self._longOperation(d.addCallbacks(cbMessages, ebMessages)) - else: - try: - i = int(i) - if i < 1: - raise ValueError() - except ValueError: - self.failResponse("Bad message number argument") - else: - try: - msg = self.mbox.getUidl(i - 1) - except IndexError: - # XXX TODO See above comment regarding IndexError. - warnings.warn( - "twisted.mail.pop3.IMailbox.getUidl may not " - "raise IndexError for out-of-bounds message numbers: " - "raise ValueError instead.", - PendingDeprecationWarning) - self.failResponse("Bad message number argument") - except ValueError: - self.failResponse("Bad message number argument") - else: - self.successResponse(str(msg)) - - - def _getMessageFile(self, i): - """ - Retrieve the size and contents of a given message, as a two-tuple. - - @param i: The number of the message to operate on. This is a base-ten - string representation starting at 1. - - @return: A Deferred which fires with a two-tuple of an integer and a - file-like object. - """ - try: - msg = int(i) - 1 - if msg < 0: - raise ValueError() - except ValueError: - self.failResponse("Bad message number argument") - return defer.succeed(None) - - sizeDeferred = defer.maybeDeferred(self.mbox.listMessages, msg) - def cbMessageSize(size): - if not size: - return defer.fail(_POP3MessageDeleted()) - fileDeferred = defer.maybeDeferred(self.mbox.getMessage, msg) - fileDeferred.addCallback(lambda fObj: (size, fObj)) - return fileDeferred - - def ebMessageSomething(err): - errcls = err.check(_POP3MessageDeleted, ValueError, IndexError) - if errcls is _POP3MessageDeleted: - self.failResponse("message deleted") - elif errcls in (ValueError, IndexError): - if errcls is IndexError: - # XXX TODO See above comment regarding IndexError. - warnings.warn( - "twisted.mail.pop3.IMailbox.listMessages may not " - "raise IndexError for out-of-bounds message numbers: " - "raise ValueError instead.", - PendingDeprecationWarning) - self.failResponse("Bad message number argument") - else: - log.msg("Unexpected _getMessageFile failure:") - log.err(err) - return None - - sizeDeferred.addCallback(cbMessageSize) - sizeDeferred.addErrback(ebMessageSomething) - return sizeDeferred - - - def _sendMessageContent(self, i, fpWrapper, successResponse): - d = self._getMessageFile(i) - def cbMessageFile(info): - if info is None: - # Some error occurred - a failure response has been sent - # already, just give up. - return - - self._highest = max(self._highest, int(i)) - resp, fp = info - fp = fpWrapper(fp) - self.successResponse(successResponse(resp)) - s = basic.FileSender() - d = s.beginFileTransfer(fp, self.transport, self.transformChunk) - - def cbFileTransfer(lastsent): - if lastsent != '\n': - line = '\r\n.' - else: - line = '.' - self.sendLine(line) - - def ebFileTransfer(err): - self.transport.loseConnection() - log.msg("Unexpected error in _sendMessageContent:") - log.err(err) - - d.addCallback(cbFileTransfer) - d.addErrback(ebFileTransfer) - return d - return self._longOperation(d.addCallback(cbMessageFile)) - - - def do_TOP(self, i, size): - try: - size = int(size) - if size < 0: - raise ValueError - except ValueError: - self.failResponse("Bad line count argument") - else: - return self._sendMessageContent( - i, - lambda fp: _HeadersPlusNLines(fp, size), - lambda size: "Top of message follows") - - - def do_RETR(self, i): - return self._sendMessageContent( - i, - lambda fp: fp, - lambda size: "%d" % (size,)) - - - def transformChunk(self, chunk): - return chunk.replace('\n', '\r\n').replace('\r\n.', '\r\n..') - - - def finishedFileTransfer(self, lastsent): - if lastsent != '\n': - line = '\r\n.' - else: - line = '.' - self.sendLine(line) - - - def do_DELE(self, i): - i = int(i)-1 - self.mbox.deleteMessage(i) - self.successResponse() - - - def do_NOOP(self): - """Perform no operation. Return a success code""" - self.successResponse() - - - def do_RSET(self): - """Unset all deleted message flags""" - try: - self.mbox.undeleteMessages() - except: - log.err() - self.failResponse() - else: - self._highest = 0 - self.successResponse() - - - def do_LAST(self): - """ - Return the index of the highest message yet downloaded. - """ - self.successResponse(self._highest) - - - def do_RPOP(self, user): - self.failResponse('permission denied, sucker') - - - def do_QUIT(self): - if self.mbox: - self.mbox.sync() - self.successResponse() - self.transport.loseConnection() - - - def authenticateUserAPOP(self, user, digest): - """Perform authentication of an APOP login. - - @type user: C{str} - @param user: The name of the user attempting to log in. - - @type digest: C{str} - @param digest: The response string with which the user replied. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked if the login is - successful, and whose errback will be invoked otherwise. The - callback will be passed a 3-tuple consisting of IMailbox, - an object implementing IMailbox, and a zero-argument callable - to be invoked when this session is terminated. - """ - if self.portal is not None: - return self.portal.login( - APOPCredentials(self.magic, user, digest), - None, - IMailbox - ) - raise cred.error.UnauthorizedLogin() - - def authenticateUserPASS(self, user, password): - """Perform authentication of a username/password login. - - @type user: C{str} - @param user: The name of the user attempting to log in. - - @type password: C{str} - @param password: The password to attempt to authenticate with. - - @rtype: C{Deferred} - @return: A deferred whose callback is invoked if the login is - successful, and whose errback will be invoked otherwise. The - callback will be passed a 3-tuple consisting of IMailbox, - an object implementing IMailbox, and a zero-argument callable - to be invoked when this session is terminated. - """ - if self.portal is not None: - return self.portal.login( - cred.credentials.UsernamePassword(user, password), - None, - IMailbox - ) - raise cred.error.UnauthorizedLogin() - - -class IServerFactory(Interface): - """Interface for querying additional parameters of this POP3 server. - - Any cap_* method may raise NotImplementedError if the particular - capability is not supported. If cap_EXPIRE() does not raise - NotImplementedError, perUserExpiration() must be implemented, otherwise - they are optional. If cap_LOGIN_DELAY() is implemented, - perUserLoginDelay() must be implemented, otherwise they are optional. - - @ivar challengers: A dictionary mapping challenger names to classes - implementing C{IUsernameHashedPassword}. - """ - - def cap_IMPLEMENTATION(): - """Return a string describing this POP3 server implementation.""" - - def cap_EXPIRE(): - """Return the minimum number of days messages are retained.""" - - def perUserExpiration(): - """Indicate whether message expiration is per-user. - - @return: True if it is, false otherwise. - """ - - def cap_LOGIN_DELAY(): - """Return the minimum number of seconds between client logins.""" - - def perUserLoginDelay(): - """Indicate whether the login delay period is per-user. - - @return: True if it is, false otherwise. - """ - -class IMailbox(Interface): - """ - @type loginDelay: C{int} - @ivar loginDelay: The number of seconds between allowed logins for the - user associated with this mailbox. None - - @type messageExpiration: C{int} - @ivar messageExpiration: The number of days messages in this mailbox will - remain on the server before being deleted. - """ - - def listMessages(index=None): - """Retrieve the size of one or more messages. - - @type index: C{int} or C{None} - @param index: The number of the message for which to retrieve the - size (starting at 0), or None to retrieve the size of all messages. - - @rtype: C{int} or any iterable of C{int} or a L{Deferred} which fires - with one of these. - - @return: The number of octets in the specified message, or an iterable - of integers representing the number of octets in all the messages. Any - value which would have referred to a deleted message should be set to 0. - - @raise ValueError: if C{index} is greater than the index of any message - in the mailbox. - """ - - def getMessage(index): - """Retrieve a file-like object for a particular message. - - @type index: C{int} - @param index: The number of the message to retrieve - - @rtype: A file-like object - @return: A file containing the message data with lines delimited by - C{\\n}. - """ - - def getUidl(index): - """Get a unique identifier for a particular message. - - @type index: C{int} - @param index: The number of the message for which to retrieve a UIDL - - @rtype: C{str} - @return: A string of printable characters uniquely identifying for all - time the specified message. - - @raise ValueError: if C{index} is greater than the index of any message - in the mailbox. - """ - - def deleteMessage(index): - """Delete a particular message. - - This must not change the number of messages in this mailbox. Further - requests for the size of deleted messages should return 0. Further - requests for the message itself may raise an exception. - - @type index: C{int} - @param index: The number of the message to delete. - """ - - def undeleteMessages(): - """ - Undelete any messages which have been marked for deletion since the - most recent L{sync} call. - - Any message which can be undeleted should be returned to its - original position in the message sequence and retain its original - UID. - """ - - def sync(): - """Perform checkpointing. - - This method will be called to indicate the mailbox should attempt to - clean up any remaining deleted messages. - """ - - - -class Mailbox: - implements(IMailbox) - - def listMessages(self, i=None): - return [] - def getMessage(self, i): - raise ValueError - def getUidl(self, i): - raise ValueError - def deleteMessage(self, i): - raise ValueError - def undeleteMessages(self): - pass - def sync(self): - pass - - -NONE, SHORT, FIRST_LONG, LONG = range(4) - -NEXT = {} -NEXT[NONE] = NONE -NEXT[SHORT] = NONE -NEXT[FIRST_LONG] = LONG -NEXT[LONG] = NONE - -class POP3Client(basic.LineOnlyReceiver): - - mode = SHORT - command = 'WELCOME' - import re - welcomeRe = re.compile('<(.*)>') - - def __init__(self): - import warnings - warnings.warn("twisted.mail.pop3.POP3Client is deprecated, " - "please use twisted.mail.pop3.AdvancedPOP3Client " - "instead.", DeprecationWarning, - stacklevel=3) - - def sendShort(self, command, params=None): - if params is not None: - self.sendLine('%s %s' % (command, params)) - else: - self.sendLine(command) - self.command = command - self.mode = SHORT - - def sendLong(self, command, params): - if params: - self.sendLine('%s %s' % (command, params)) - else: - self.sendLine(command) - self.command = command - self.mode = FIRST_LONG - - def handle_default(self, line): - if line[:-4] == '-ERR': - self.mode = NONE - - def handle_WELCOME(self, line): - code, data = line.split(' ', 1) - if code != '+OK': - self.transport.loseConnection() - else: - m = self.welcomeRe.match(line) - if m: - self.welcomeCode = m.group(1) - - def _dispatch(self, command, default, *args): - try: - method = getattr(self, 'handle_'+command, default) - if method is not None: - method(*args) - except: - log.err() - - def lineReceived(self, line): - if self.mode == SHORT or self.mode == FIRST_LONG: - self.mode = NEXT[self.mode] - self._dispatch(self.command, self.handle_default, line) - elif self.mode == LONG: - if line == '.': - self.mode = NEXT[self.mode] - self._dispatch(self.command+'_end', None) - return - if line[:1] == '.': - line = line[1:] - self._dispatch(self.command+"_continue", None, line) - - def apopAuthenticate(self, user, password, magic): - digest = md5.new(magic + password).hexdigest() - self.apop(user, digest) - - def apop(self, user, digest): - self.sendLong('APOP', ' '.join((user, digest))) - def retr(self, i): - self.sendLong('RETR', i) - def dele(self, i): - self.sendShort('DELE', i) - def list(self, i=''): - self.sendLong('LIST', i) - def uidl(self, i=''): - self.sendLong('UIDL', i) - def user(self, name): - self.sendShort('USER', name) - def pass_(self, pass_): - self.sendShort('PASS', pass_) - def quit(self): - self.sendShort('QUIT') - -from twisted.mail.pop3client import POP3Client as AdvancedPOP3Client -from twisted.mail.pop3client import POP3ClientError -from twisted.mail.pop3client import InsecureAuthenticationDisallowed -from twisted.mail.pop3client import ServerErrorResponse -from twisted.mail.pop3client import LineTooLong - -__all__ = [ - # Interfaces - 'IMailbox', 'IServerFactory', - - # Exceptions - 'POP3Error', 'POP3ClientError', 'InsecureAuthenticationDisallowed', - 'ServerErrorResponse', 'LineTooLong', - - # Protocol classes - 'POP3', 'POP3Client', 'AdvancedPOP3Client', - - # Misc - 'APOPCredentials', 'Mailbox'] diff --git a/tools/buildbot/pylibs/twisted/mail/pop3client.py b/tools/buildbot/pylibs/twisted/mail/pop3client.py deleted file mode 100644 index 5b7986c..0000000 --- a/tools/buildbot/pylibs/twisted/mail/pop3client.py +++ /dev/null @@ -1,704 +0,0 @@ -# -*- test-case-name: twisted.mail.test.test_pop3client -*- -# Copyright (c) 2001-2004 Divmod Inc. -# See LICENSE for details. - -""" -POP3 client protocol implementation - -Don't use this module directly. Use twisted.mail.pop3 instead. - -@author: U{Jp Calderone} -""" - -import re, md5 - -from twisted.python import log -from twisted.internet import defer -from twisted.protocols import basic -from twisted.protocols import policies -from twisted.internet import error -from twisted.internet import interfaces - -OK = '+OK' -ERR = '-ERR' - -class POP3ClientError(Exception): - """Base class for all exceptions raised by POP3Client. - """ - -class InsecureAuthenticationDisallowed(POP3ClientError): - """Secure authentication was required but no mechanism could be found. - """ - -class TLSError(POP3ClientError): - """ - Secure authentication was required but either the transport does - not support TLS or no TLS context factory was supplied. - """ - -class TLSNotSupportedError(POP3ClientError): - """ - Secure authentication was required but the server does not support - TLS. - """ - -class ServerErrorResponse(POP3ClientError): - """The server returned an error response to a request. - """ - def __init__(self, reason, consumer=None): - POP3ClientError.__init__(self, reason) - self.consumer = consumer - -class LineTooLong(POP3ClientError): - """The server sent an extremely long line. - """ - -class _ListSetter: - # Internal helper. POP3 responses sometimes occur in the - # form of a list of lines containing two pieces of data, - # a message index and a value of some sort. When a message - # is deleted, it is omitted from these responses. The - # setitem method of this class is meant to be called with - # these two values. In the cases where indexes are skipped, - # it takes care of padding out the missing values with None. - def __init__(self, L): - self.L = L - def setitem(self, (item, value)): - diff = item - len(self.L) + 1 - if diff > 0: - self.L.extend([None] * diff) - self.L[item] = value - - -def _statXform(line): - # Parse a STAT response - numMsgs, totalSize = line.split(None, 1) - return int(numMsgs), int(totalSize) - - -def _listXform(line): - # Parse a LIST response - index, size = line.split(None, 1) - return int(index) - 1, int(size) - - -def _uidXform(line): - # Parse a UIDL response - index, uid = line.split(None, 1) - return int(index) - 1, uid - -def _codeStatusSplit(line): - # Parse an +OK or -ERR response - parts = line.split(' ', 1) - if len(parts) == 1: - return parts[0], '' - return parts - -def _dotUnquoter(line): - """ - C{'.'} characters which begin a line of a message are doubled to avoid - confusing with the terminating C{'.\\r\\n'} sequence. This function - unquotes them. - """ - if line.startswith('..'): - return line[1:] - return line - -class POP3Client(basic.LineOnlyReceiver, policies.TimeoutMixin): - """POP3 client protocol implementation class - - Instances of this class provide a convenient, efficient API for - retrieving and deleting messages from a POP3 server. - - @type startedTLS: C{bool} - @ivar startedTLS: Whether TLS has been negotiated successfully. - - - @type allowInsecureLogin: C{bool} - @ivar allowInsecureLogin: Indicate whether login() should be - allowed if the server offers no authentication challenge and if - our transport does not offer any protection via encryption. - - @type serverChallenge: C{str} or C{None} - @ivar serverChallenge: Challenge received from the server - - @type timeout: C{int} - @ivar timeout: Number of seconds to wait before timing out a - connection. If the number is <= 0, no timeout checking will be - performed. - """ - - startedTLS = False - allowInsecureLogin = False - timeout = 0 - serverChallenge = None - - # Capabilities are not allowed to change during the session - # (except when TLS is negotiated), so cache the first response and - # use that for all later lookups - _capCache = None - - # Regular expression to search for in the challenge string in the server - # greeting line. - _challengeMagicRe = re.compile('(<[^>]+>)') - - # List of pending calls. - # We are a pipelining API but don't actually - # support pipelining on the network yet. - _blockedQueue = None - - # The Deferred to which the very next result will go. - _waiting = None - - # Whether we dropped the connection because of a timeout - _timedOut = False - - # If the server sends an initial -ERR, this is the message it sent - # with it. - _greetingError = None - - def _blocked(self, f, *a): - # Internal helper. If commands are being blocked, append - # the given command and arguments to a list and return a Deferred - # that will be chained with the return value of the function - # when it eventually runs. Otherwise, set up for commands to be - - # blocked and return None. - if self._blockedQueue is not None: - d = defer.Deferred() - self._blockedQueue.append((d, f, a)) - return d - self._blockedQueue = [] - return None - - def _unblock(self): - # Internal helper. Indicate that a function has completed. - # If there are blocked commands, run the next one. If there - # are not, set up for the next command to not be blocked. - if self._blockedQueue == []: - self._blockedQueue = None - elif self._blockedQueue is not None: - _blockedQueue = self._blockedQueue - self._blockedQueue = None - - d, f, a = _blockedQueue.pop(0) - d2 = f(*a) - d2.chainDeferred(d) - # f is a function which uses _blocked (otherwise it wouldn't - # have gotten into the blocked queue), which means it will have - # re-set _blockedQueue to an empty list, so we can put the rest - # of the blocked queue back into it now. - self._blockedQueue.extend(_blockedQueue) - - - def sendShort(self, cmd, args): - # Internal helper. Send a command to which a short response - # is expected. Return a Deferred that fires when the response - # is received. Block all further commands from being sent until - # the response is received. Transition the state to SHORT. - d = self._blocked(self.sendShort, cmd, args) - if d is not None: - return d - - if args: - self.sendLine(cmd + ' ' + args) - else: - self.sendLine(cmd) - self.state = 'SHORT' - self._waiting = defer.Deferred() - return self._waiting - - def sendLong(self, cmd, args, consumer, xform): - # Internal helper. Send a command to which a multiline - # response is expected. Return a Deferred that fires when - # the entire response is received. Block all further commands - # from being sent until the entire response is received. - # Transition the state to LONG_INITIAL. - d = self._blocked(self.sendLong, cmd, args, consumer, xform) - if d is not None: - return d - - if args: - self.sendLine(cmd + ' ' + args) - else: - self.sendLine(cmd) - self.state = 'LONG_INITIAL' - self._xform = xform - self._consumer = consumer - self._waiting = defer.Deferred() - return self._waiting - - # Twisted protocol callback - def connectionMade(self): - if self.timeout > 0: - self.setTimeout(self.timeout) - - self.state = 'WELCOME' - self._blockedQueue = [] - - def timeoutConnection(self): - self._timedOut = True - self.transport.loseConnection() - - def connectionLost(self, reason): - if self.timeout > 0: - self.setTimeout(None) - - if self._timedOut: - reason = error.TimeoutError() - elif self._greetingError: - reason = ServerErrorResponse(self._greetingError) - - d = [] - if self._waiting is not None: - d.append(self._waiting) - self._waiting = None - if self._blockedQueue is not None: - d.extend([deferred for (deferred, f, a) in self._blockedQueue]) - self._blockedQueue = None - for w in d: - w.errback(reason) - - def lineReceived(self, line): - if self.timeout > 0: - self.resetTimeout() - - state = self.state - self.state = None - state = getattr(self, 'state_' + state)(line) or state - if self.state is None: - self.state = state - - def lineLengthExceeded(self, buffer): - # XXX - We need to be smarter about this - if self._waiting is not None: - waiting, self._waiting = self._waiting, None - waiting.errback(LineTooLong()) - self.transport.loseConnection() - - # POP3 Client state logic - don't touch this. - def state_WELCOME(self, line): - # WELCOME is the first state. The server sends one line of text - # greeting us, possibly with an APOP challenge. Transition the - # state to WAITING. - code, status = _codeStatusSplit(line) - if code != OK: - self._greetingError = status - self.transport.loseConnection() - else: - m = self._challengeMagicRe.search(status) - - if m is not None: - self.serverChallenge = m.group(1) - - self.serverGreeting(status) - - self._unblock() - return 'WAITING' - - def state_WAITING(self, line): - # The server isn't supposed to send us anything in this state. - log.msg("Illegal line from server: " + repr(line)) - - def state_SHORT(self, line): - # This is the state we are in when waiting for a single - # line response. Parse it and fire the appropriate callback - # or errback. Transition the state back to WAITING. - deferred, self._waiting = self._waiting, None - self._unblock() - code, status = _codeStatusSplit(line) - if code == OK: - deferred.callback(status) - else: - deferred.errback(ServerErrorResponse(status)) - return 'WAITING' - - def state_LONG_INITIAL(self, line): - # This is the state we are in when waiting for the first - # line of a long response. Parse it and transition the - # state to LONG if it is an okay response; if it is an - # error response, fire an errback, clean up the things - # waiting for a long response, and transition the state - # to WAITING. - code, status = _codeStatusSplit(line) - if code == OK: - return 'LONG' - consumer = self._consumer - deferred = self._waiting - self._consumer = self._waiting = self._xform = None - self._unblock() - deferred.errback(ServerErrorResponse(status, consumer)) - return 'WAITING' - - def state_LONG(self, line): - # This is the state for each line of a long response. - # If it is the last line, finish things, fire the - # Deferred, and transition the state to WAITING. - # Otherwise, pass the line to the consumer. - if line == '.': - consumer = self._consumer - deferred = self._waiting - self._consumer = self._waiting = self._xform = None - self._unblock() - deferred.callback(consumer) - return 'WAITING' - else: - if self._xform is not None: - self._consumer(self._xform(line)) - else: - self._consumer(line) - return 'LONG' - - - # Callbacks - override these - def serverGreeting(self, greeting): - """Called when the server has sent us a greeting. - - @type greeting: C{str} or C{None} - @param greeting: The status message sent with the server - greeting. For servers implementing APOP authentication, this - will be a challenge string. . - """ - - - # External API - call these (most of 'em anyway) - def startTLS(self, contextFactory=None): - """ - Initiates a 'STLS' request and negotiates the TLS / SSL - Handshake. - - @type contextFactory: C{ssl.ClientContextFactory} @param - contextFactory: The context factory with which to negotiate - TLS. If C{None}, try to create a new one. - - @return: A Deferred which fires when the transport has been - secured according to the given contextFactory, or which fails - if the transport cannot be secured. - """ - tls = interfaces.ITLSTransport(self.transport, None) - if tls is None: - return defer.fail(TLSError( - "POP3Client transport does not implement " - "interfaces.ITLSTransport")) - - if contextFactory is None: - contextFactory = self._getContextFactory() - - if contextFactory is None: - return defer.fail(TLSError( - "POP3Client requires a TLS context to " - "initiate the STLS handshake")) - - d = self.capabilities() - d.addCallback(self._startTLS, contextFactory, tls) - return d - - - def _startTLS(self, caps, contextFactory, tls): - assert not self.startedTLS, "Client and Server are currently communicating via TLS" - - if 'STLS' not in caps: - return defer.fail(TLSNotSupportedError( - "Server does not support secure communication " - "via TLS / SSL")) - - d = self.sendShort('STLS', None) - d.addCallback(self._startedTLS, contextFactory, tls) - d.addCallback(lambda _: self.capabilities()) - return d - - - def _startedTLS(self, result, context, tls): - self.transport = tls - self.transport.startTLS(context) - self._capCache = None - self.startedTLS = True - return result - - - def _getContextFactory(self): - try: - from twisted.internet import ssl - except ImportError: - return None - else: - context = ssl.ClientContextFactory() - context.method = ssl.SSL.TLSv1_METHOD - return context - - - def login(self, username, password): - """Log into the server. - - If APOP is available it will be used. Otherwise, if TLS is - available an 'STLS' session will be started and plaintext - login will proceed. Otherwise, if the instance attribute - allowInsecureLogin is set to True, insecure plaintext login - will proceed. Otherwise, InsecureAuthenticationDisallowed - will be raised (asynchronously). - - @param username: The username with which to log in. - @param password: The password with which to log in. - - @rtype: C{Deferred} - @return: A deferred which fires when login has - completed. - """ - d = self.capabilities() - d.addCallback(self._login, username, password) - return d - - - def _login(self, caps, username, password): - if self.serverChallenge is not None: - return self._apop(username, password, self.serverChallenge) - - tryTLS = 'STLS' in caps - - #If our transport supports switching to TLS, we might want to try to switch to TLS. - tlsableTransport = interfaces.ITLSTransport(self.transport, None) is not None - - # If our transport is not already using TLS, we might want to try to switch to TLS. - nontlsTransport = interfaces.ISSLTransport(self.transport, None) is None - - if not self.startedTLS and tryTLS and tlsableTransport and nontlsTransport: - d = self.startTLS() - - d.addCallback(self._loginTLS, username, password) - return d - - elif self.startedTLS or not nontlsTransport or self.allowInsecureLogin: - return self._plaintext(username, password) - else: - return defer.fail(InsecureAuthenticationDisallowed()) - - - def _loginTLS(self, res, username, password): - return self._plaintext(username, password) - - def _plaintext(self, username, password): - # Internal helper. Send a username/password pair, returning a Deferred - # that fires when both have succeeded or fails when the server rejects - # either. - return self.user(username).addCallback(lambda r: self.password(password)) - - def _apop(self, username, password, challenge): - # Internal helper. Computes and sends an APOP response. Returns - # a Deferred that fires when the server responds to the response. - digest = md5.new(challenge + password).hexdigest() - return self.apop(username, digest) - - def apop(self, username, digest): - """Perform APOP login. - - This should be used in special circumstances only, when it is - known that the server supports APOP authentication, and APOP - authentication is absolutely required. For the common case, - use L{login} instead. - - @param username: The username with which to log in. - @param digest: The challenge response to authenticate with. - """ - return self.sendShort('APOP', username + ' ' + digest) - - def user(self, username): - """Send the user command. - - This performs the first half of plaintext login. Unless this - is absolutely required, use the L{login} method instead. - - @param username: The username with which to log in. - """ - return self.sendShort('USER', username) - - def password(self, password): - """Send the password command. - - This performs the second half of plaintext login. Unless this - is absolutely required, use the L{login} method instead. - - @param password: The plaintext password with which to authenticate. - """ - return self.sendShort('PASS', password) - - def delete(self, index): - """Delete a message from the server. - - @type index: C{int} - @param index: The index of the message to delete. - This is 0-based. - - @rtype: C{Deferred} - @return: A deferred which fires when the delete command - is successful, or fails if the server returns an error. - """ - return self.sendShort('DELE', str(index + 1)) - - def _consumeOrSetItem(self, cmd, args, consumer, xform): - # Internal helper. Send a long command. If no consumer is - # provided, create a consumer that puts results into a list - # and return a Deferred that fires with that list when it - # is complete. - if consumer is None: - L = [] - consumer = _ListSetter(L).setitem - return self.sendLong(cmd, args, consumer, xform).addCallback(lambda r: L) - return self.sendLong(cmd, args, consumer, xform) - - def _consumeOrAppend(self, cmd, args, consumer, xform): - # Internal helper. Send a long command. If no consumer is - # provided, create a consumer that appends results to a list - # and return a Deferred that fires with that list when it is - # complete. - if consumer is None: - L = [] - consumer = L.append - return self.sendLong(cmd, args, consumer, xform).addCallback(lambda r: L) - return self.sendLong(cmd, args, consumer, xform) - - def capabilities(self, useCache=True): - """Retrieve the capabilities supported by this server. - - Not all servers support this command. If the server does not - support this, it is treated as though it returned a successful - response listing no capabilities. At some future time, this may be - changed to instead seek out information about a server's - capabilities in some other fashion (only if it proves useful to do - so, and only if there are servers still in use which do not support - CAPA but which do support POP3 extensions that are useful). - - @type useCache: C{bool} - @param useCache: If set, and if capabilities have been - retrieved previously, just return the previously retrieved - results. - - @return: A Deferred which fires with a C{dict} mapping C{str} - to C{None} or C{list}s of C{str}. For example:: - - C: CAPA - S: +OK Capability list follows - S: TOP - S: USER - S: SASL CRAM-MD5 KERBEROS_V4 - S: RESP-CODES - S: LOGIN-DELAY 900 - S: PIPELINING - S: EXPIRE 60 - S: UIDL - S: IMPLEMENTATION Shlemazle-Plotz-v302 - S: . - - will be lead to a result of:: - - | {'TOP': None, - | 'USER': None, - | 'SASL': ['CRAM-MD5', 'KERBEROS_V4'], - | 'RESP-CODES': None, - | 'LOGIN-DELAY': ['900'], - | 'PIPELINING': None, - | 'EXPIRE': ['60'], - | 'UIDL': None, - | 'IMPLEMENTATION': ['Shlemazle-Plotz-v302']} - """ - if useCache and self._capCache is not None: - return defer.succeed(self._capCache) - - cache = {} - def consume(line): - tmp = line.split() - if len(tmp) == 1: - cache[tmp[0]] = None - elif len(tmp) > 1: - cache[tmp[0]] = tmp[1:] - - def capaNotSupported(err): - err.trap(ServerErrorResponse) - return None - - def gotCapabilities(result): - self._capCache = cache - return cache - - d = self._consumeOrAppend('CAPA', None, consume, None) - d.addErrback(capaNotSupported).addCallback(gotCapabilities) - return d - - - def noop(self): - """Do nothing, with the help of the server. - - No operation is performed. The returned Deferred fires when - the server responds. - """ - return self.sendShort("NOOP", None) - - - def reset(self): - """Remove the deleted flag from any messages which have it. - - The returned Deferred fires when the server responds. - """ - return self.sendShort("RSET", None) - - - def retrieve(self, index, consumer=None, lines=None): - """Retrieve a message from the server. - - If L{consumer} is not None, it will be called with - each line of the message as it is received. Otherwise, - the returned Deferred will be fired with a list of all - the lines when the message has been completely received. - """ - idx = str(index + 1) - if lines is None: - return self._consumeOrAppend('RETR', idx, consumer, _dotUnquoter) - - return self._consumeOrAppend('TOP', '%s %d' % (idx, lines), consumer, _dotUnquoter) - - - def stat(self): - """Get information about the size of this mailbox. - - The returned Deferred will be fired with a tuple containing - the number or messages in the mailbox and the size (in bytes) - of the mailbox. - """ - return self.sendShort('STAT', None).addCallback(_statXform) - - - def listSize(self, consumer=None): - """Retrieve a list of the size of all messages on the server. - - If L{consumer} is not None, it will be called with two-tuples - of message index number and message size as they are received. - Otherwise, a Deferred which will fire with a list of B{only} - message sizes will be returned. For messages which have been - deleted, None will be used in place of the message size. - """ - return self._consumeOrSetItem('LIST', None, consumer, _listXform) - - - def listUID(self, consumer=None): - """Retrieve a list of the UIDs of all messages on the server. - - If L{consumer} is not None, it will be called with two-tuples - of message index number and message UID as they are received. - Otherwise, a Deferred which will fire with of list of B{only} - message UIDs will be returned. For messages which have been - deleted, None will be used in place of the message UID. - """ - return self._consumeOrSetItem('UIDL', None, consumer, _uidXform) - - - def quit(self): - """Disconnect from the server. - """ - return self.sendShort('QUIT', None) - -__all__ = [ - # Exceptions - 'InsecureAuthenticationDisallowed', 'LineTooLong', 'POP3ClientError', - 'ServerErrorResponse', 'TLSError', 'TLSNotSupportedError', - - # Protocol classes - 'POP3Client'] diff --git a/tools/buildbot/pylibs/twisted/mail/protocols.py b/tools/buildbot/pylibs/twisted/mail/protocols.py deleted file mode 100644 index dc449af..0000000 --- a/tools/buildbot/pylibs/twisted/mail/protocols.py +++ /dev/null @@ -1,225 +0,0 @@ -# -*- test-case-name: twisted.mail.test.test_mail -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Protocol support for twisted.mail.""" - -# twisted imports -from twisted.mail import pop3 -from twisted.mail import smtp -from twisted.internet import protocol -from twisted.internet import defer -from twisted.copyright import longversion -from twisted.python import log - -from twisted import cred -import twisted.cred.error -import twisted.cred.credentials - -from twisted.mail import relay - -from zope.interface import implements - - -class DomainDeliveryBase: - """A server that uses twisted.mail service's domains.""" - - implements(smtp.IMessageDelivery) - - service = None - protocolName = None - - def __init__(self, service, user, host=smtp.DNSNAME): - self.service = service - self.user = user - self.host = host - - def receivedHeader(self, helo, origin, recipients): - authStr = heloStr = "" - if self.user: - authStr = " auth=%s" % (self.user.encode('xtext'),) - if helo[0]: - heloStr = " helo=%s" % (helo[0],) - from_ = "from %s ([%s]%s%s)" % (helo[0], helo[1], heloStr, authStr) - by = "by %s with %s (%s)" % ( - self.host, self.protocolName, longversion - ) - for_ = "for <%s>; %s" % (' '.join(map(str, recipients)), smtp.rfc822date()) - return "Received: %s\n\t%s\n\t%s" % (from_, by, for_) - - def validateTo(self, user): - # XXX - Yick. This needs cleaning up. - if self.user and self.service.queue: - d = self.service.domains.get(user.dest.domain, None) - if d is None: - d = relay.DomainQueuer(self.service, True) - else: - d = self.service.domains[user.dest.domain] - return defer.maybeDeferred(d.exists, user) - - def validateFrom(self, helo, origin): - if not helo: - raise smtp.SMTPBadSender(origin, 503, "Who are you? Say HELO first.") - if origin.local != '' and origin.domain == '': - raise smtp.SMTPBadSender(origin, 501, "Sender address must contain domain.") - return origin - - def startMessage(self, users): - ret = [] - for user in users: - ret.append(self.service.domains[user.dest.domain].startMessage(user)) - return ret - - -class SMTPDomainDelivery(DomainDeliveryBase): - protocolName = 'smtp' - -class ESMTPDomainDelivery(DomainDeliveryBase): - protocolName = 'esmtp' - -class DomainSMTP(SMTPDomainDelivery, smtp.SMTP): - service = user = None - - def __init__(self, *args, **kw): - import warnings - warnings.warn( - "DomainSMTP is deprecated. Use IMessageDelivery objects instead.", - DeprecationWarning, stacklevel=2, - ) - smtp.SMTP.__init__(self, *args, **kw) - if self.delivery is None: - self.delivery = self - -class DomainESMTP(ESMTPDomainDelivery, smtp.ESMTP): - service = user = None - - def __init__(self, *args, **kw): - import warnings - warnings.warn( - "DomainESMTP is deprecated. Use IMessageDelivery objects instead.", - DeprecationWarning, stacklevel=2, - ) - smtp.ESMTP.__init__(self, *args, **kw) - if self.delivery is None: - self.delivery = self - -class SMTPFactory(smtp.SMTPFactory): - """A protocol factory for SMTP.""" - - protocol = smtp.SMTP - portal = None - - def __init__(self, service, portal = None): - smtp.SMTPFactory.__init__(self) - self.service = service - self.portal = portal - - def buildProtocol(self, addr): - log.msg('Connection from %s' % (addr,)) - p = smtp.SMTPFactory.buildProtocol(self, addr) - p.service = self.service - p.portal = self.portal - return p - -class ESMTPFactory(SMTPFactory): - protocol = smtp.ESMTP - context = None - - def __init__(self, *args): - SMTPFactory.__init__(self, *args) - self.challengers = { - 'CRAM-MD5': cred.credentials.CramMD5Credentials - } - - def buildProtocol(self, addr): - p = SMTPFactory.buildProtocol(self, addr) - p.challengers = self.challengers - p.ctx = self.context - return p - -class VirtualPOP3(pop3.POP3): - """Virtual hosting POP3.""" - - service = None - - domainSpecifier = '@' # Gaagh! I hate POP3. No standardized way - # to indicate user@host. '@' doesn't work - # with NS, e.g. - - def authenticateUserAPOP(self, user, digest): - # Override the default lookup scheme to allow virtual domains - user, domain = self.lookupDomain(user) - try: - portal = self.service.lookupPortal(domain) - except KeyError: - return defer.fail(cred.error.UnauthorizedLogin()) - else: - return portal.login( - pop3.APOPCredentials(self.magic, user, digest), - None, - pop3.IMailbox - ) - - def authenticateUserPASS(self, user, password): - user, domain = self.lookupDomain(user) - try: - portal = self.service.lookupPortal(domain) - except KeyError: - return defer.fail(cred.error.UnauthorizedLogin()) - else: - return portal.login( - cred.credentials.UsernamePassword(user, password), - None, - pop3.IMailbox - ) - - def lookupDomain(self, user): - try: - user, domain = user.split(self.domainSpecifier, 1) - except ValueError: - domain = '' - if domain not in self.service.domains: - raise pop3.POP3Error("no such domain %s" % domain) - return user, domain - - -class POP3Factory(protocol.ServerFactory): - """POP3 protocol factory.""" - - protocol = VirtualPOP3 - service = None - - def __init__(self, service): - self.service = service - - def buildProtocol(self, addr): - p = protocol.ServerFactory.buildProtocol(self, addr) - p.service = self.service - return p - -# -# It is useful to know, perhaps, that the required file for this to work can -# be created thusly: -# -# openssl req -x509 -newkey rsa:2048 -keyout file.key -out file.crt \ -# -days 365 -nodes -# -# And then cat file.key and file.crt together. The number of days and bits -# can be changed, of course. -# -class SSLContextFactory: - """An SSL Context Factory - - This loads a certificate and private key from a specified file. - """ - def __init__(self, filename): - self.filename = filename - - def getContext(self): - """Create an SSL context.""" - from OpenSSL import SSL - ctx = SSL.Context(SSL.SSLv23_METHOD) - ctx.use_certificate_file(self.filename) - ctx.use_privatekey_file(self.filename) - return ctx diff --git a/tools/buildbot/pylibs/twisted/mail/relay.py b/tools/buildbot/pylibs/twisted/mail/relay.py deleted file mode 100644 index 5fbf48f..0000000 --- a/tools/buildbot/pylibs/twisted/mail/relay.py +++ /dev/null @@ -1,114 +0,0 @@ -# -*- test-case-name: twisted.mail.test.test_mail -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Support for relaying mail for twisted.mail""" - -from twisted.mail import smtp -from twisted.python import log -from twisted.internet.address import UNIXAddress - -import os - -try: - import cPickle as pickle -except ImportError: - import pickle - -class DomainQueuer: - """An SMTP domain which add messages to a queue intended for relaying.""" - - def __init__(self, service, authenticated=False): - self.service = service - self.authed = authenticated - - def exists(self, user): - """Check whether we will relay - - Call overridable willRelay method - """ - if self.willRelay(user.dest, user.protocol): - # The most cursor form of verification of the addresses - orig = filter(None, str(user.orig).split('@', 1)) - dest = filter(None, str(user.dest).split('@', 1)) - if len(orig) == 2 and len(dest) == 2: - return lambda: self.startMessage(user) - raise smtp.SMTPBadRcpt(user) - - def willRelay(self, address, protocol): - """Check whether we agree to relay - - The default is to relay for all connections over UNIX - sockets and all connections from localhost. - """ - peer = protocol.transport.getPeer() - return self.authed or isinstance(peer, UNIXAddress) or peer.host == '127.0.0.1' - - def startMessage(self, user): - """Add envelope to queue and returns ISMTPMessage.""" - queue = self.service.queue - envelopeFile, smtpMessage = queue.createNewMessage() - try: - log.msg('Queueing mail %r -> %r' % (str(user.orig), str(user.dest))) - pickle.dump([str(user.orig), str(user.dest)], envelopeFile) - finally: - envelopeFile.close() - return smtpMessage - -class RelayerMixin: - - # XXX - This is -totally- bogus - # It opens about a -hundred- -billion- files - # and -leaves- them open! - - def loadMessages(self, messagePaths): - self.messages = [] - self.names = [] - for message in messagePaths: - fp = open(message+'-H') - try: - messageContents = pickle.load(fp) - finally: - fp.close() - fp = open(message+'-D') - messageContents.append(fp) - self.messages.append(messageContents) - self.names.append(message) - - def getMailFrom(self): - if not self.messages: - return None - return self.messages[0][0] - - def getMailTo(self): - if not self.messages: - return None - return [self.messages[0][1]] - - def getMailData(self): - if not self.messages: - return None - return self.messages[0][2] - - def sentMail(self, code, resp, numOk, addresses, log): - """Since we only use one recipient per envelope, this - will be called with 0 or 1 addresses. We probably want - to do something with the error message if we failed. - """ - if code in smtp.SUCCESS: - # At least one, i.e. all, recipients successfully delivered - os.remove(self.names[0]+'-D') - os.remove(self.names[0]+'-H') - del self.messages[0] - del self.names[0] - -class SMTPRelayer(RelayerMixin, smtp.SMTPClient): - def __init__(self, messagePaths, *args, **kw): - smtp.SMTPClient.__init__(self, *args, **kw) - self.loadMessages(messagePaths) - -class ESMTPRelayer(RelayerMixin, smtp.ESMTPClient): - def __init__(self, messagePaths, *args, **kw): - smtp.ESMTPClient.__init__(self, *args, **kw) - self.loadMessages(messagePaths) diff --git a/tools/buildbot/pylibs/twisted/mail/relaymanager.py b/tools/buildbot/pylibs/twisted/mail/relaymanager.py deleted file mode 100644 index 8cf4edac..0000000 --- a/tools/buildbot/pylibs/twisted/mail/relaymanager.py +++ /dev/null @@ -1,631 +0,0 @@ -# -*- test-case-name: twisted.mail.test.test_mail -*- -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Infrastructure for relaying mail through smart host - -Today, internet e-mail has stopped being Peer-to-peer for many problems, -spam (unsolicited bulk mail) among them. Instead, most nodes on the -internet send all e-mail to a single computer, usually the ISP's though -sometimes other schemes, such as SMTP-after-POP, are used. This computer -is supposedly permanently up and traceable, and will do the work of -figuring out MXs and connecting to them. This kind of configuration -is usually termed "smart host", since the host we are connecting to -is "smart" (and will find MXs and connect to them) rather then just -accepting mail for a small set of domains. - -The classes here are meant to facilitate support for such a configuration -for the twisted.mail SMTP server -""" - -import rfc822 -import os -import time - -try: - import cPickle as pickle -except ImportError: - import pickle - -from twisted.python import log -from twisted.python.failure import Failure -from twisted.python.compat import set -from twisted.mail import relay -from twisted.mail import bounce -from twisted.internet import protocol -from twisted.internet.defer import Deferred, DeferredList -from twisted.internet.error import DNSLookupError -from twisted.mail import smtp -from twisted.application import internet - -class ManagedRelayerMixin: - """SMTP Relayer which notifies a manager - - Notify the manager about successful mail, failed mail - and broken connections - """ - - def __init__(self, manager): - self.manager = manager - - def sentMail(self, code, resp, numOk, addresses, log): - """called when e-mail has been sent - - we will always get 0 or 1 addresses. - """ - message = self.names[0] - if code in smtp.SUCCESS: - self.manager.notifySuccess(self.factory, message) - else: - self.manager.notifyFailure(self.factory, message) - del self.messages[0] - del self.names[0] - - def connectionLost(self, reason): - """called when connection is broken - - notify manager we will try to send no more e-mail - """ - self.manager.notifyDone(self.factory) - -class SMTPManagedRelayer(ManagedRelayerMixin, relay.SMTPRelayer): - def __init__(self, messages, manager, *args, **kw): - """ - @type messages: C{list} of C{str} - @param messages: Filenames of messages to relay - - manager should support .notifySuccess, .notifyFailure - and .notifyDone - """ - ManagedRelayerMixin.__init__(self, manager) - relay.SMTPRelayer.__init__(self, messages, *args, **kw) - -class ESMTPManagedRelayer(ManagedRelayerMixin, relay.ESMTPRelayer): - def __init__(self, messages, manager, *args, **kw): - """ - @type messages: C{list} of C{str} - @param messages: Filenames of messages to relay - - manager should support .notifySuccess, .notifyFailure - and .notifyDone - """ - ManagedRelayerMixin.__init__(self, manager) - relay.ESMTPRelayer.__init__(self, messages, *args, **kw) - -class SMTPManagedRelayerFactory(protocol.ClientFactory): - protocol = SMTPManagedRelayer - - def __init__(self, messages, manager, *args, **kw): - self.messages = messages - self.manager = manager - self.pArgs = args - self.pKwArgs = kw - - def buildProtocol(self, addr): - protocol = self.protocol(self.messages, self.manager, *self.pArgs, - **self.pKwArgs) - protocol.factory = self - return protocol - - def clientConnectionFailed(self, connector, reason): - """called when connection could not be made - - our manager should be notified that this happened, - it might prefer some other host in that case""" - self.manager.notifyNoConnection(self) - self.manager.notifyDone(self) - -class ESMTPManagedRelayerFactory(SMTPManagedRelayerFactory): - protocol = ESMTPManagedRelayer - - def __init__(self, messages, manager, secret, contextFactory, *args, **kw): - self.secret = secret - self.contextFactory = contextFactory - SMTPManagedRelayerFactory.__init__(self, messages, manager, *args, **kw) - - def buildProtocol(self, addr): - s = self.secret and self.secret(addr) - protocol = self.protocol(self.messages, self.manager, s, - self.contextFactory, *self.pArgs, **self.pKwArgs) - protocol.factory = self - return protocol - -class Queue: - """A queue of ougoing emails.""" - - noisy = True - - def __init__(self, directory): - self.directory = directory - self._init() - - def _init(self): - self.n = 0 - self.waiting = {} - self.relayed = {} - self.readDirectory() - - def __getstate__(self): - """(internal) delete volatile state""" - return {'directory' : self.directory} - - def __setstate__(self, state): - """(internal) restore volatile state""" - self.__dict__.update(state) - self._init() - - def readDirectory(self): - """Read the messages directory. - - look for new messages. - """ - for message in os.listdir(self.directory): - # Skip non data files - if message[-2:]!='-D': - continue - self.addMessage(message[:-2]) - - def getWaiting(self): - return self.waiting.keys() - - def hasWaiting(self): - return len(self.waiting) > 0 - - def getRelayed(self): - return self.relayed.keys() - - def setRelaying(self, message): - del self.waiting[message] - self.relayed[message] = 1 - - def setWaiting(self, message): - del self.relayed[message] - self.waiting[message] = 1 - - def addMessage(self, message): - if message not in self.relayed: - self.waiting[message] = 1 - if self.noisy: - log.msg('Set ' + message + ' waiting') - - def done(self, message): - """Remove message to from queue.""" - message = os.path.basename(message) - os.remove(self.getPath(message) + '-D') - os.remove(self.getPath(message) + '-H') - del self.relayed[message] - - def getPath(self, message): - """Get the path in the filesystem of a message.""" - return os.path.join(self.directory, message) - - def getEnvelope(self, message): - return pickle.load(self.getEnvelopeFile(message)) - - def getEnvelopeFile(self, message): - return open(os.path.join(self.directory, message+'-H'), 'rb') - - def createNewMessage(self): - """Create a new message in the queue. - - Return a tuple - file-like object for headers, and ISMTPMessage. - """ - fname = "%s_%s_%s_%s" % (os.getpid(), time.time(), self.n, id(self)) - self.n = self.n + 1 - headerFile = open(os.path.join(self.directory, fname+'-H'), 'wb') - tempFilename = os.path.join(self.directory, fname+'-C') - finalFilename = os.path.join(self.directory, fname+'-D') - messageFile = open(tempFilename, 'wb') - - from twisted.mail.mail import FileMessage - return headerFile,FileMessage(messageFile, tempFilename, finalFilename) - - -class _AttemptManager(object): - """ - Manage the state of a single attempt to flush the relay queue. - """ - def __init__(self, manager): - self.manager = manager - self._completionDeferreds = [] - - - def getCompletionDeferred(self): - self._completionDeferreds.append(Deferred()) - return self._completionDeferreds[-1] - - - def _finish(self, relay, message): - self.manager.managed[relay].remove(os.path.basename(message)) - self.manager.queue.done(message) - - - def notifySuccess(self, relay, message): - """a relay sent a message successfully - - Mark it as sent in our lists - """ - if self.manager.queue.noisy: - log.msg("success sending %s, removing from queue" % message) - self._finish(relay, message) - - - def notifyFailure(self, relay, message): - """Relaying the message has failed.""" - if self.manager.queue.noisy: - log.msg("could not relay "+message) - # Moshe - Bounce E-mail here - # Be careful: if it's a bounced bounce, silently - # discard it - message = os.path.basename(message) - fp = self.manager.queue.getEnvelopeFile(message) - from_, to = pickle.load(fp) - fp.close() - from_, to, bounceMessage = bounce.generateBounce(open(self.manager.queue.getPath(message)+'-D'), from_, to) - fp, outgoingMessage = self.manager.queue.createNewMessage() - pickle.dump([from_, to], fp) - fp.close() - for line in bounceMessage.splitlines(): - outgoingMessage.lineReceived(line) - outgoingMessage.eomReceived() - self._finish(relay, self.manager.queue.getPath(message)) - - - def notifyDone(self, relay): - """A relaying SMTP client is disconnected. - - unmark all pending messages under this relay's responsibility - as being relayed, and remove the relay. - """ - for message in self.manager.managed.get(relay, ()): - if self.manager.queue.noisy: - log.msg("Setting " + message + " waiting") - self.manager.queue.setWaiting(message) - try: - del self.manager.managed[relay] - except KeyError: - pass - notifications = self._completionDeferreds - self._completionDeferreds = None - for d in notifications: - d.callback(None) - - - def notifyNoConnection(self, relay): - """Relaying SMTP client couldn't connect. - - Useful because it tells us our upstream server is unavailable. - """ - # Back off a bit - try: - msgs = self.manager.managed[relay] - except KeyError: - log.msg("notifyNoConnection passed unknown relay!") - return - - if self.manager.queue.noisy: - log.msg("Backing off on delivery of " + str(msgs)) - def setWaiting(queue, messages): - map(queue.setWaiting, messages) - from twisted.internet import reactor - reactor.callLater(30, setWaiting, self.manager.queue, msgs) - del self.manager.managed[relay] - - - -class SmartHostSMTPRelayingManager: - """Manage SMTP Relayers - - Manage SMTP relayers, keeping track of the existing connections, - each connection's responsibility in term of messages. Create - more relayers if the need arises. - - Someone should press .checkState periodically - - @ivar fArgs: Additional positional arguments used to instantiate - C{factory}. - - @ivar fKwArgs: Additional keyword arguments used to instantiate - C{factory}. - - @ivar factory: A callable which returns a ClientFactory suitable for - making SMTP connections. - """ - - factory = SMTPManagedRelayerFactory - - PORT = 25 - - mxcalc = None - - def __init__(self, queue, maxConnections=2, maxMessagesPerConnection=10): - """ - @type queue: Any implementor of C{IQueue} - @param queue: The object used to queue messages on their way to - delivery. - - @type maxConnections: C{int} - @param maxConnections: The maximum number of SMTP connections to - allow to be opened at any given time. - - @type maxMessagesPerConnection: C{int} - @param maxMessagesPerConnection: The maximum number of messages a - relayer will be given responsibility for. - - Default values are meant for a small box with 1-5 users. - """ - self.maxConnections = maxConnections - self.maxMessagesPerConnection = maxMessagesPerConnection - self.managed = {} # SMTP clients we're managing - self.queue = queue - self.fArgs = () - self.fKwArgs = {} - - def __getstate__(self): - """(internal) delete volatile state""" - dct = self.__dict__.copy() - del dct['managed'] - return dct - - def __setstate__(self, state): - """(internal) restore volatile state""" - self.__dict__.update(state) - self.managed = {} - - def checkState(self): - """ - Synchronize with the state of the world, and maybe launch a new - relay. - - Call me periodically to check I am still up to date. - - @return: None or a Deferred which fires when all of the SMTP clients - started by this call have disconnected. - """ - self.queue.readDirectory() - if (len(self.managed) >= self.maxConnections): - return - if not self.queue.hasWaiting(): - return - - return self._checkStateMX() - - def _checkStateMX(self): - nextMessages = self.queue.getWaiting() - nextMessages.reverse() - - exchanges = {} - for msg in nextMessages: - from_, to = self.queue.getEnvelope(msg) - name, addr = rfc822.parseaddr(to) - parts = addr.split('@', 1) - if len(parts) != 2: - log.err("Illegal message destination: " + to) - continue - domain = parts[1] - - self.queue.setRelaying(msg) - exchanges.setdefault(domain, []).append(self.queue.getPath(msg)) - if len(exchanges) >= (self.maxConnections - len(self.managed)): - break - - if self.mxcalc is None: - self.mxcalc = MXCalculator() - - relays = [] - for (domain, msgs) in exchanges.iteritems(): - manager = _AttemptManager(self) - factory = self.factory(msgs, manager, *self.fArgs, **self.fKwArgs) - self.managed[factory] = map(os.path.basename, msgs) - relayAttemptDeferred = manager.getCompletionDeferred() - connectSetupDeferred = self.mxcalc.getMX(domain) - connectSetupDeferred.addCallback(lambda mx: str(mx.name)) - connectSetupDeferred.addCallback(self._cbExchange, self.PORT, factory) - connectSetupDeferred.addErrback(lambda err: (relayAttemptDeferred.errback(err), err)[1]) - connectSetupDeferred.addErrback(self._ebExchange, factory, domain) - relays.append(relayAttemptDeferred) - return DeferredList(relays) - - - def _cbExchange(self, address, port, factory): - from twisted.internet import reactor - reactor.connectTCP(address, port, factory) - - def _ebExchange(self, failure, factory, domain): - log.err('Error setting up managed relay factory for ' + domain) - log.err(failure) - def setWaiting(queue, messages): - map(queue.setWaiting, messages) - from twisted.internet import reactor - reactor.callLater(30, setWaiting, self.queue, self.managed[factory]) - del self.managed[factory] - -class SmartHostESMTPRelayingManager(SmartHostSMTPRelayingManager): - factory = ESMTPManagedRelayerFactory - -def _checkState(manager): - manager.checkState() - -def RelayStateHelper(manager, delay): - return internet.TimerService(delay, _checkState, manager) - - - -class CanonicalNameLoop(Exception): - """ - When trying to look up the MX record for a host, a set of CNAME records was - found which form a cycle and resolution was abandoned. - """ - - -class CanonicalNameChainTooLong(Exception): - """ - When trying to look up the MX record for a host, too many CNAME records - which point to other CNAME records were encountered and resolution was - abandoned. - """ - - -class MXCalculator: - """ - A utility for looking up mail exchange hosts and tracking whether they are - working or not. - - @ivar clock: L{IReactorTime} provider which will be used to decide when to - retry mail exchanges which have not been working. - """ - timeOutBadMX = 60 * 60 # One hour - fallbackToDomain = True - - def __init__(self, resolver=None, clock=None): - self.badMXs = {} - if resolver is None: - from twisted.names.client import createResolver - resolver = createResolver() - self.resolver = resolver - if clock is None: - from twisted.internet import reactor as clock - self.clock = clock - - - def markBad(self, mx): - """Indicate a given mx host is not currently functioning. - - @type mx: C{str} - @param mx: The hostname of the host which is down. - """ - self.badMXs[str(mx)] = self.clock.seconds() + self.timeOutBadMX - - def markGood(self, mx): - """Indicate a given mx host is back online. - - @type mx: C{str} - @param mx: The hostname of the host which is up. - """ - try: - del self.badMXs[mx] - except KeyError: - pass - - def getMX(self, domain, maximumCanonicalChainLength=3): - """ - Find an MX record for the given domain. - - @type domain: C{str} - @param domain: The domain name for which to look up an MX record. - - @type maximumCanonicalChainLength: C{int} - @param maximumCanonicalChainLength: The maximum number of unique CNAME - records to follow while looking up the MX record. - - @return: A L{Deferred} which is called back with a string giving the - name in the found MX record or which is errbacked if no MX record - can be found. - """ - mailExchangeDeferred = self.resolver.lookupMailExchange(domain) - mailExchangeDeferred.addCallback(self._filterRecords) - mailExchangeDeferred.addCallback( - self._cbMX, domain, maximumCanonicalChainLength) - mailExchangeDeferred.addErrback(self._ebMX, domain) - return mailExchangeDeferred - - - def _filterRecords(self, records): - """ - Convert a DNS response (a three-tuple of lists of RRHeaders) into a - mapping from record names to lists of corresponding record payloads. - """ - recordBag = {} - for answer in records[0]: - recordBag.setdefault(str(answer.name), []).append(answer.payload) - return recordBag - - - def _cbMX(self, answers, domain, cnamesLeft): - """ - Try to find the MX host from the given DNS information. - - This will attempt to resolve CNAME results. It can recognize loops - and will give up on non-cyclic chains after a specified number of - lookups. - """ - # Do this import here so that relaymanager.py doesn't depend on - # twisted.names, only MXCalculator will. - from twisted.names import dns, error - - seenAliases = set() - exchanges = [] - # Examine the answers for the domain we asked about - pertinentRecords = answers.get(domain, []) - while pertinentRecords: - record = pertinentRecords.pop() - - # If it's a CNAME, we'll need to do some more processing - if record.TYPE == dns.CNAME: - - # Remember that this name was an alias. - seenAliases.add(domain) - - canonicalName = str(record.name) - # See if we have some local records which might be relevant. - if canonicalName in answers: - - # Make sure it isn't a loop contained entirely within the - # results we have here. - if canonicalName in seenAliases: - return Failure(CanonicalNameLoop(record)) - - pertinentRecords = answers[canonicalName] - exchanges = [] - else: - if cnamesLeft: - # Request more information from the server. - return self.getMX(canonicalName, cnamesLeft - 1) - else: - # Give up. - return Failure(CanonicalNameChainTooLong(record)) - - # If it's an MX, collect it. - if record.TYPE == dns.MX: - exchanges.append((record.preference, record)) - - if exchanges: - exchanges.sort() - for (preference, record) in exchanges: - host = str(record.name) - if host not in self.badMXs: - return record - t = self.clock.seconds() - self.badMXs[host] - if t >= 0: - del self.badMXs[host] - return record - return exchanges[0][1] - else: - # Treat no answers the same as an error - jump to the errback to try - # to look up an A record. This provides behavior described as a - # special case in RFC 974 in the section headed I{Interpreting the - # List of MX RRs}. - return Failure( - error.DNSNameError("No MX records for %r" % (domain,))) - - - def _ebMX(self, failure, domain): - from twisted.names import error, dns - - if self.fallbackToDomain: - failure.trap(error.DNSNameError) - log.msg("MX lookup failed; attempting to use hostname (%s) directly" % (domain,)) - - # Alright, I admit, this is a bit icky. - d = self.resolver.getHostByName(domain) - def cbResolved(addr): - return dns.Record_MX(name=addr) - def ebResolved(err): - err.trap(error.DNSNameError) - raise DNSLookupError() - d.addCallbacks(cbResolved, ebResolved) - return d - elif failure.check(error.DNSNameError): - raise IOError("No MX found for %r" % (domain,)) - return failure diff --git a/tools/buildbot/pylibs/twisted/mail/scripts/__init__.py b/tools/buildbot/pylibs/twisted/mail/scripts/__init__.py deleted file mode 100644 index f653cc7..0000000 --- a/tools/buildbot/pylibs/twisted/mail/scripts/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"mail scripts" diff --git a/tools/buildbot/pylibs/twisted/mail/scripts/mailmail.py b/tools/buildbot/pylibs/twisted/mail/scripts/mailmail.py deleted file mode 100644 index 1f138e4..0000000 --- a/tools/buildbot/pylibs/twisted/mail/scripts/mailmail.py +++ /dev/null @@ -1,363 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -""" -Implementation module for the `newtexaco` command. - -The name is preliminary and subject to change. -""" - -import os -import sys -import rfc822 -import socket -import getpass -from ConfigParser import ConfigParser - -try: - import cStringIO as StringIO -except: - import StringIO - -from twisted.internet import reactor -from twisted.mail import bounce, smtp - -GLOBAL_CFG = "/etc/mailmail" -LOCAL_CFG = os.path.expanduser("~/.twisted/mailmail") -SMARTHOST = '127.0.0.1' - -ERROR_FMT = """\ -Subject: Failed Message Delivery - - Message delivery failed. The following occurred: - - %s --- -The Twisted sendmail application. -""" - -def log(message, *args): - sys.stderr.write(str(message) % args + '\n') - -class Options: - """ - @type to: C{list} of C{str} - @ivar to: The addresses to which to deliver this message. - - @type sender: C{str} - @ivar sender: The address from which this message is being sent. - - @type body: C{file} - @ivar body: The object from which the message is to be read. - """ - -def getlogin(): - try: - return os.getlogin() - except: - return getpass.getuser() - - -def parseOptions(argv): - o = Options() - o.to = [e for e in argv if not e.startswith('-')] - o.sender = getlogin() - - # Just be very stupid - - # Skip -bm -- it is the default - - # -bp lists queue information. Screw that. - if '-bp' in argv: - raise ValueError, "Unsupported option" - - # -bs makes sendmail use stdin/stdout as its transport. Screw that. - if '-bs' in argv: - raise ValueError, "Unsupported option" - - # -F sets who the mail is from, but is overridable by the From header - if '-F' in argv: - o.sender = argv[argv.index('-F') + 1] - o.to.remove(o.sender) - - # -i and -oi makes us ignore lone "." - if ('-i' in argv) or ('-oi' in argv): - raise ValueError, "Unsupported option" - - # -odb is background delivery - if '-odb' in argv: - o.background = True - else: - o.background = False - - # -odf is foreground delivery - if '-odf' in argv: - o.background = False - else: - o.background = True - - # -oem and -em cause errors to be mailed back to the sender. - # It is also the default. - - # -oep and -ep cause errors to be printed to stderr - if ('-oep' in argv) or ('-ep' in argv): - o.printErrors = True - else: - o.printErrors = False - - # -om causes a copy of the message to be sent to the sender if the sender - # appears in an alias expansion. We do not support aliases. - if '-om' in argv: - raise ValueError, "Unsupported option" - - # -t causes us to pick the recipients of the message from the To, Cc, and Bcc - # headers, and to remove the Bcc header if present. - if '-t' in argv: - o.recipientsFromHeaders = True - o.excludeAddresses = o.to - o.to = [] - else: - o.recipientsFromHeaders = False - o.exludeAddresses = [] - - requiredHeaders = { - 'from': [], - 'to': [], - 'cc': [], - 'bcc': [], - 'date': [], - } - - headers = [] - buffer = StringIO.StringIO() - while 1: - write = 1 - line = sys.stdin.readline() - if not line.strip(): - break - - hdrs = line.split(': ', 1) - - hdr = hdrs[0].lower() - if o.recipientsFromHeaders and hdr in ('to', 'cc', 'bcc'): - o.to.extend([ - a[1] for a in rfc822.AddressList(hdrs[1]).addresslist - ]) - if hdr == 'bcc': - write = 0 - elif hdr == 'from': - o.sender = rfc822.parseaddr(hdrs[1])[1] - - if hdr in requiredHeaders: - requiredHeaders[hdr].append(hdrs[1]) - - if write: - buffer.write(line) - - if not requiredHeaders['from']: - buffer.write('From: %s\r\n' % (o.sender,)) - if not requiredHeaders['to']: - if not o.to: - raise ValueError, "No recipients specified" - buffer.write('To: %s\r\n' % (', '.join(o.to),)) - if not requiredHeaders['date']: - buffer.write('Date: %s\r\n' % (smtp.rfc822date(),)) - - buffer.write(line) - - if o.recipientsFromHeaders: - for a in o.excludeAddresses: - try: - o.to.remove(a) - except: - pass - - buffer.seek(0, 0) - o.body = StringIO.StringIO(buffer.getvalue() + sys.stdin.read()) - return o - -class Configuration: - """ - @ivar allowUIDs: A list of UIDs which are allowed to send mail. - @ivar allowGIDs: A list of GIDs which are allowed to send mail. - @ivar denyUIDs: A list of UIDs which are not allowed to send mail. - @ivar denyGIDs: A list of GIDs which are not allowed to send mail. - - @type defaultAccess: C{bool} - @ivar defaultAccess: C{True} if access will be allowed when no other access - control rule matches or C{False} if it will be denied in that case. - - @ivar useraccess: Either C{'allow'} to check C{allowUID} first - or C{'deny'} to check C{denyUID} first. - - @ivar groupaccess: Either C{'allow'} to check C{allowGID} first or - C{'deny'} to check C{denyGID} first. - - @ivar identities: A C{dict} mapping hostnames to credentials to use when - sending mail to that host. - - @ivar smarthost: C{None} or a hostname through which all outgoing mail will - be sent. - - @ivar domain: C{None} or the hostname with which to identify ourselves when - connecting to an MTA. - """ - def __init__(self): - self.allowUIDs = [] - self.denyUIDs = [] - self.allowGIDs = [] - self.denyGIDs = [] - self.useraccess = 'deny' - self.groupaccess= 'deny' - - self.identities = {} - self.smarthost = None - self.domain = None - - self.defaultAccess = True - - -def loadConfig(path): - # [useraccess] - # allow=uid1,uid2,... - # deny=uid1,uid2,... - # order=allow,deny - # [groupaccess] - # allow=gid1,gid2,... - # deny=gid1,gid2,... - # order=deny,allow - # [identity] - # host1=username:password - # host2=username:password - # [addresses] - # smarthost=a.b.c.d - # default_domain=x.y.z - - c = Configuration() - - if not os.access(path, os.R_OK): - return c - - p = ConfigParser() - p.read(path) - - au = c.allowUIDs - du = c.denyUIDs - ag = c.allowGIDs - dg = c.denyGIDs - for (section, a, d) in (('useraccess', au, du), ('groupaccess', ag, dg)): - if p.has_section(section): - for (mode, L) in (('allow', a), ('deny', d)): - if p.has_option(section, mode) and p.get(section, mode): - for id in p.get(section, mode).split(','): - try: - id = int(id) - except ValueError: - log("Illegal %sID in [%s] section: %s", section[0].upper(), section, id) - else: - L.append(id) - order = p.get(section, 'order') - order = map(str.split, map(str.lower, order.split(','))) - if order[0] == 'allow': - setattr(c, section, 'allow') - else: - setattr(c, section, 'deny') - - if p.has_section('identity'): - for (host, up) in p.items('identity'): - parts = up.split(':', 1) - if len(parts) != 2: - log("Illegal entry in [identity] section: %s", up) - continue - p.identities[host] = parts - - if p.has_section('addresses'): - if p.has_option('addresses', 'smarthost'): - c.smarthost = p.get('addresses', 'smarthost') - if p.has_option('addresses', 'default_domain'): - c.domain = p.get('addresses', 'default_domain') - - return c - -def success(result): - reactor.stop() - -failed = None -def failure(f): - global failed - reactor.stop() - failed = f - -def sendmail(host, options, ident): - d = smtp.sendmail(host, options.sender, options.to, options.body) - d.addCallbacks(success, failure) - reactor.run() - -def senderror(failure, options): - recipient = [options.sender] - sender = '"Internally Generated Message (%s)"' % (sys.argv[0], smtp.DNSNAME) - error = StringIO.StringIO() - failure.printTraceback(file=error) - body = StringIO.StringIO(ERROR_FMT % error.getvalue()) - - d = smtp.sendmail('localhost', sender, recipient, body) - d.addBoth(lambda _: reactor.stop()) - -def deny(conf): - uid = os.getuid() - gid = os.getgid() - - if conf.useraccess == 'deny': - if uid in conf.denyUIDs: - return True - if uid in conf.allowUIDs: - return False - else: - if uid in conf.allowUIDs: - return False - if uid in conf.denyUIDs: - return True - - if conf.groupaccess == 'deny': - if gid in conf.denyGIDs: - return True - if gid in conf.allowGIDs: - return False - else: - if gid in conf.allowGIDs: - return False - if gid in conf.denyGIDs: - return True - - return not conf.defaultAccess - -def run(): - o = parseOptions(sys.argv[1:]) - gConf = loadConfig(GLOBAL_CFG) - lConf = loadConfig(LOCAL_CFG) - - if deny(gConf) or deny(lConf): - log("Permission denied") - return - - host = lConf.smarthost or gConf.smarthost or SMARTHOST - - ident = gConf.identities.copy() - ident.update(lConf.identities) - - if lConf.domain: - smtp.DNSNAME = lConf.domain - elif gConf.domain: - smtp.DNSNAME = gConf.domain - - sendmail(host, o, ident) - - if failed: - if o.printErrors: - failed.printTraceback(file=sys.stderr) - raise SystemExit(1) - else: - senderror(failed, o) diff --git a/tools/buildbot/pylibs/twisted/mail/smtp.py b/tools/buildbot/pylibs/twisted/mail/smtp.py deleted file mode 100644 index 54b561e..0000000 --- a/tools/buildbot/pylibs/twisted/mail/smtp.py +++ /dev/null @@ -1,2016 +0,0 @@ -# -*- test-case-name: twisted.mail.test.test_smtp -*- -# -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Simple Mail Transfer Protocol implementation. -""" - -from __future__ import generators - -# Twisted imports -from twisted.copyright import longversion -from twisted.protocols import basic -from twisted.protocols import policies -from twisted.internet import protocol -from twisted.internet import defer -from twisted.internet import error -from twisted.internet import reactor -from twisted.internet.interfaces import ITLSTransport -from twisted.python import log -from twisted.python import util -from twisted.python import failure - -from twisted import cred -import twisted.cred.checkers -import twisted.cred.credentials -from twisted.python.runtime import platform - -# System imports -import time, re, base64, types, socket, os, random, hmac -import MimeWriter, tempfile, rfc822 -import warnings -import binascii - -from zope.interface import implements, Interface - -try: - from email.base64MIME import encode as encode_base64 -except ImportError: - def encode_base64(s, eol='\n'): - return s.encode('base64').rstrip() + eol - -try: - from cStringIO import StringIO -except ImportError: - from StringIO import StringIO - -# Cache the hostname (XXX Yes - this is broken) -if platform.isMacOSX(): - # On OS X, getfqdn() is ridiculously slow - use the - # probably-identical-but-sometimes-not gethostname() there. - DNSNAME = socket.gethostname() -else: - DNSNAME = socket.getfqdn() - -# Used for fast success code lookup -SUCCESS = dict(map(None, range(200, 300), [])) - -class IMessageDelivery(Interface): - def receivedHeader(helo, origin, recipients): - """ - Generate the Received header for a message - - @type helo: C{(str, str)} - @param helo: The argument to the HELO command and the client's IP - address. - - @type origin: C{Address} - @param origin: The address the message is from - - @type recipients: C{list} of L{User} - @param recipients: A list of the addresses for which this message - is bound. - - @rtype: C{str} - @return: The full \"Received\" header string. - """ - - def validateTo(user): - """ - Validate the address for which the message is destined. - - @type user: C{User} - @param user: The address to validate. - - @rtype: no-argument callable - @return: A C{Deferred} which becomes, or a callable which - takes no arguments and returns an object implementing C{IMessage}. - This will be called and the returned object used to deliver the - message when it arrives. - - @raise SMTPBadRcpt: Raised if messages to the address are - not to be accepted. - """ - - def validateFrom(helo, origin): - """ - Validate the address from which the message originates. - - @type helo: C{(str, str)} - @param helo: The argument to the HELO command and the client's IP - address. - - @type origin: C{Address} - @param origin: The address the message is from - - @rtype: C{Deferred} or C{Address} - @return: C{origin} or a C{Deferred} whose callback will be - passed C{origin}. - - @raise SMTPBadSender: Raised of messages from this address are - not to be accepted. - """ - -class IMessageDeliveryFactory(Interface): - """An alternate interface to implement for handling message delivery. - - It is useful to implement this interface instead of L{IMessageDelivery} - directly because it allows the implementor to distinguish between - different messages delivery over the same connection. This can be - used to optimize delivery of a single message to multiple recipients, - something which cannot be done by L{IMessageDelivery} implementors - due to their lack of information. - """ - def getMessageDelivery(): - """Return an L{IMessageDelivery} object. - - This will be called once per message. - """ - -class SMTPError(Exception): - pass - -class SMTPClientError(SMTPError): - """Base class for SMTP client errors. - """ - def __init__(self, code, resp, log=None, addresses=None, isFatal=False, retry=False): - """ - @param code: The SMTP response code associated with this error. - @param resp: The string response associated with this error. - @param log: A string log of the exchange leading up to and including the error. - - @param isFatal: A boolean indicating whether this connection can proceed - or not. If True, the connection will be dropped. - @param retry: A boolean indicating whether the delivery should be retried. - If True and the factory indicates further retries are desirable, they will - be attempted, otherwise the delivery will be failed. - """ - self.code = code - self.resp = resp - self.log = log - self.addresses = addresses - self.isFatal = isFatal - self.retry = retry - - def __str__(self): - if self.code > 0: - res = ["%.3d %s" % (self.code, self.resp)] - else: - res = [self.resp] - if self.log: - res.append('') - res.append(self.log) - return '\n'.join(res) - - -class ESMTPClientError(SMTPClientError): - """Base class for ESMTP client errors. - """ - -class EHLORequiredError(ESMTPClientError): - """The server does not support EHLO. - - This is considered a non-fatal error (the connection will not be - dropped). - """ - -class AUTHRequiredError(ESMTPClientError): - """Authentication was required but the server does not support it. - - This is considered a non-fatal error (the connection will not be - dropped). - """ - -class TLSRequiredError(ESMTPClientError): - """Transport security was required but the server does not support it. - - This is considered a non-fatal error (the connection will not be - dropped). - """ - -class AUTHDeclinedError(ESMTPClientError): - """The server rejected our credentials. - - Either the username, password, or challenge response - given to the server was rejected. - - This is considered a non-fatal error (the connection will not be - dropped). - """ - -class AuthenticationError(ESMTPClientError): - """An error ocurred while authenticating. - - Either the server rejected our request for authentication or the - challenge received was malformed. - - This is considered a non-fatal error (the connection will not be - dropped). - """ - -class TLSError(ESMTPClientError): - """An error occurred while negiotiating for transport security. - - This is considered a non-fatal error (the connection will not be - dropped). - """ - -class SMTPConnectError(SMTPClientError): - """Failed to connect to the mail exchange host. - - This is considered a fatal error. A retry will be made. - """ - def __init__(self, code, resp, log=None, addresses=None, isFatal=True, retry=True): - SMTPClientError.__init__(self, code, resp, log, addresses, isFatal, retry) - -class SMTPTimeoutError(SMTPClientError): - """Failed to receive a response from the server in the expected time period. - - This is considered a fatal error. A retry will be made. - """ - def __init__(self, code, resp, log=None, addresses=None, isFatal=True, retry=True): - SMTPClientError.__init__(self, code, resp, log, addresses, isFatal, retry) - -class SMTPProtocolError(SMTPClientError): - """The server sent a mangled response. - - This is considered a fatal error. A retry will not be made. - """ - def __init__(self, code, resp, log=None, addresses=None, isFatal=True, retry=False): - SMTPClientError.__init__(self, code, resp, log, addresses, isFatal, retry) - -class SMTPDeliveryError(SMTPClientError): - """Indicates that a delivery attempt has had an error. - """ - -class SMTPServerError(SMTPError): - def __init__(self, code, resp): - self.code = code - self.resp = resp - - def __str__(self): - return "%.3d %s" % (self.code, self.resp) - -class SMTPAddressError(SMTPServerError): - def __init__(self, addr, code, resp): - SMTPServerError.__init__(self, code, resp) - self.addr = Address(addr) - - def __str__(self): - return "%.3d <%s>... %s" % (self.code, self.addr, self.resp) - -class SMTPBadRcpt(SMTPAddressError): - def __init__(self, addr, code=550, - resp='Cannot receive for specified address'): - SMTPAddressError.__init__(self, addr, code, resp) - -class SMTPBadSender(SMTPAddressError): - def __init__(self, addr, code=550, resp='Sender not acceptable'): - SMTPAddressError.__init__(self, addr, code, resp) - -def rfc822date(timeinfo=None,local=1): - """ - Format an RFC-2822 compliant date string. - - @param timeinfo: (optional) A sequence as returned by C{time.localtime()} - or C{time.gmtime()}. Default is now. - @param local: (optional) Indicates if the supplied time is local or - universal time, or if no time is given, whether now should be local or - universal time. Default is local, as suggested (SHOULD) by rfc-2822. - - @returns: A string representing the time and date in RFC-2822 format. - """ - if not timeinfo: - if local: - timeinfo = time.localtime() - else: - timeinfo = time.gmtime() - if local: - if timeinfo[8]: - # DST - tz = -time.altzone - else: - tz = -time.timezone - - (tzhr, tzmin) = divmod(abs(tz), 3600) - if tz: - tzhr *= int(abs(tz)/tz) - (tzmin, tzsec) = divmod(tzmin, 60) - else: - (tzhr, tzmin) = (0,0) - - return "%s, %02d %s %04d %02d:%02d:%02d %+03d%02d" % ( - ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'][timeinfo[6]], - timeinfo[2], - ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', - 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][timeinfo[1] - 1], - timeinfo[0], timeinfo[3], timeinfo[4], timeinfo[5], - tzhr, tzmin) - -def idGenerator(): - i = 0 - while True: - yield i - i += 1 - -def messageid(uniq=None, N=idGenerator().next): - """Return a globally unique random string in RFC 2822 Message-ID format - - - - Optional uniq string will be added to strenghten uniqueness if given. - """ - datetime = time.strftime('%Y%m%d%H%M%S', time.gmtime()) - pid = os.getpid() - rand = random.randrange(2**31L-1) - if uniq is None: - uniq = '' - else: - uniq = '.' + uniq - - return '<%s.%s.%s%s.%s@%s>' % (datetime, pid, rand, uniq, N(), DNSNAME) - -def quoteaddr(addr): - """Turn an email address, possibly with realname part etc, into - a form suitable for and SMTP envelope. - """ - - if isinstance(addr, Address): - return '<%s>' % str(addr) - - res = rfc822.parseaddr(addr) - - if res == (None, None): - # It didn't parse, use it as-is - return '<%s>' % str(addr) - else: - return '<%s>' % str(res[1]) - -COMMAND, DATA, AUTH = 'COMMAND', 'DATA', 'AUTH' - -class AddressError(SMTPError): - "Parse error in address" - -# Character classes for parsing addresses -atom = r"[-A-Za-z0-9!\#$%&'*+/=?^_`{|}~]" - -class Address: - """Parse and hold an RFC 2821 address. - - Source routes are stipped and ignored, UUCP-style bang-paths - and %-style routing are not parsed. - - @type domain: C{str} - @ivar domain: The domain within which this address resides. - - @type local: C{str} - @ivar local: The local (\"user\") portion of this address. - """ - - tstring = re.compile(r'''( # A string of - (?:"[^"]*" # quoted string - |\\. # backslash-escaped characted - |''' + atom + r''' # atom character - )+|.) # or any single character''',re.X) - atomre = re.compile(atom) # match any one atom character - - def __init__(self, addr, defaultDomain=None): - if isinstance(addr, User): - addr = addr.dest - if isinstance(addr, Address): - self.__dict__ = addr.__dict__.copy() - return - elif not isinstance(addr, types.StringTypes): - addr = str(addr) - self.addrstr = addr - - # Tokenize - atl = filter(None,self.tstring.split(addr)) - - local = [] - domain = [] - - while atl: - if atl[0] == '<': - if atl[-1] != '>': - raise AddressError, "Unbalanced <>" - atl = atl[1:-1] - elif atl[0] == '@': - atl = atl[1:] - if not local: - # Source route - while atl and atl[0] != ':': - # remove it - atl = atl[1:] - if not atl: - raise AddressError, "Malformed source route" - atl = atl[1:] # remove : - elif domain: - raise AddressError, "Too many @" - else: - # Now in domain - domain = [''] - elif len(atl[0]) == 1 and not self.atomre.match(atl[0]) and atl[0] != '.': - raise AddressError, "Parse error at %r of %r" % (atl[0], (addr, atl)) - else: - if not domain: - local.append(atl[0]) - else: - domain.append(atl[0]) - atl = atl[1:] - - self.local = ''.join(local) - self.domain = ''.join(domain) - if self.local != '' and self.domain == '': - if defaultDomain is None: - defaultDomain = DNSNAME - self.domain = defaultDomain - - dequotebs = re.compile(r'\\(.)') - - def dequote(self,addr): - """Remove RFC-2821 quotes from address.""" - res = [] - - atl = filter(None,self.tstring.split(str(addr))) - - for t in atl: - if t[0] == '"' and t[-1] == '"': - res.append(t[1:-1]) - elif '\\' in t: - res.append(self.dequotebs.sub(r'\1',t)) - else: - res.append(t) - - return ''.join(res) - - def __str__(self): - if self.local or self.domain: - return '@'.join((self.local, self.domain)) - else: - return '' - - def __repr__(self): - return "%s.%s(%s)" % (self.__module__, self.__class__.__name__, - repr(str(self))) - -class User: - """Hold information about and SMTP message recipient, - including information on where the message came from - """ - - def __init__(self, destination, helo, protocol, orig): - host = getattr(protocol, 'host', None) - self.dest = Address(destination, host) - self.helo = helo - self.protocol = protocol - if isinstance(orig, Address): - self.orig = orig - else: - self.orig = Address(orig, host) - - def __getstate__(self): - """Helper for pickle. - - protocol isn't picklabe, but we want User to be, so skip it in - the pickle. - """ - return { 'dest' : self.dest, - 'helo' : self.helo, - 'protocol' : None, - 'orig' : self.orig } - - def __str__(self): - return str(self.dest) - -class IMessage(Interface): - """Interface definition for messages that can be sent via SMTP.""" - - def lineReceived(line): - """handle another line""" - - def eomReceived(): - """handle end of message - - return a deferred. The deferred should be called with either: - callback(string) or errback(error) - """ - - def connectionLost(): - """handle message truncated - - semantics should be to discard the message - """ - -class SMTP(basic.LineOnlyReceiver, policies.TimeoutMixin): - """SMTP server-side protocol.""" - - timeout = 600 - host = DNSNAME - portal = None - - # Control whether we log SMTP events - noisy = True - - # A factory for IMessageDelivery objects. If an - # avatar implementing IMessageDeliveryFactory can - # be acquired from the portal, it will be used to - # create a new IMessageDelivery object for each - # message which is received. - deliveryFactory = None - - # An IMessageDelivery object. A new instance is - # used for each message received if we can get an - # IMessageDeliveryFactory from the portal. Otherwise, - # a single instance is used throughout the lifetime - # of the connection. - delivery = None - - # Cred cleanup function. - _onLogout = None - - def __init__(self, delivery=None, deliveryFactory=None): - self.mode = COMMAND - self._from = None - self._helo = None - self._to = [] - self.delivery = delivery - self.deliveryFactory = deliveryFactory - - def timeoutConnection(self): - msg = '%s Timeout. Try talking faster next time!' % (self.host,) - self.sendCode(421, msg) - self.transport.loseConnection() - - def greeting(self): - return '%s NO UCE NO UBE NO RELAY PROBES' % (self.host,) - - def connectionMade(self): - # Ensure user-code always gets something sane for _helo - peer = self.transport.getPeer() - try: - host = peer.host - except AttributeError: # not an IPv4Address - host = str(peer) - self._helo = (None, host) - self.sendCode(220, self.greeting()) - self.setTimeout(self.timeout) - - def sendCode(self, code, message=''): - "Send an SMTP code with a message." - lines = message.splitlines() - lastline = lines[-1:] - for line in lines[:-1]: - self.sendLine('%3.3d-%s' % (code, line)) - self.sendLine('%3.3d %s' % (code, - lastline and lastline[0] or '')) - - def lineReceived(self, line): - self.resetTimeout() - return getattr(self, 'state_' + self.mode)(line) - - def state_COMMAND(self, line): - # Ignore leading and trailing whitespace, as well as an arbitrary - # amount of whitespace between the command and its argument, though - # it is not required by the protocol, for it is a nice thing to do. - line = line.strip() - - parts = line.split(None, 1) - if parts: - method = self.lookupMethod(parts[0]) or self.do_UNKNOWN - if len(parts) == 2: - method(parts[1]) - else: - method('') - else: - self.sendSyntaxError() - - def sendSyntaxError(self): - self.sendCode(500, 'Error: bad syntax') - - def lookupMethod(self, command): - return getattr(self, 'do_' + command.upper(), None) - - def lineLengthExceeded(self, line): - if self.mode is DATA: - for message in self.__messages: - message.connectionLost() - self.mode = COMMAND - del self.__messages - self.sendCode(500, 'Line too long') - - def do_UNKNOWN(self, rest): - self.sendCode(500, 'Command not implemented') - - def do_HELO(self, rest): - peer = self.transport.getPeer() - try: - host = peer.host - except AttributeError: - host = str(peer) - self._helo = (rest, host) - self._from = None - self._to = [] - self.sendCode(250, '%s Hello %s, nice to meet you' % (self.host, host)) - - def do_QUIT(self, rest): - self.sendCode(221, 'See you later') - self.transport.loseConnection() - - # A string of quoted strings, backslash-escaped character or - # atom characters + '@.,:' - qstring = r'("[^"]*"|\\.|' + atom + r'|[@.,:])+' - - mail_re = re.compile(r'''\s*FROM:\s*(?P<> # Empty <> - |<''' + qstring + r'''> # - |''' + qstring + r''' # addr - )\s*(\s(?P.*))? # Optional WS + ESMTP options - $''',re.I|re.X) - rcpt_re = re.compile(r'\s*TO:\s*(?P<' + qstring + r'''> # - |''' + qstring + r''' # addr - )\s*(\s(?P.*))? # Optional WS + ESMTP options - $''',re.I|re.X) - - def do_MAIL(self, rest): - if self._from: - self.sendCode(503,"Only one sender per message, please") - return - # Clear old recipient list - self._to = [] - m = self.mail_re.match(rest) - if not m: - self.sendCode(501, "Syntax error") - return - - try: - addr = Address(m.group('path'), self.host) - except AddressError, e: - self.sendCode(553, str(e)) - return - - validated = defer.maybeDeferred(self.validateFrom, self._helo, addr) - validated.addCallbacks(self._cbFromValidate, self._ebFromValidate) - - - def _cbFromValidate(self, from_, code=250, msg='Sender address accepted'): - self._from = from_ - self.sendCode(code, msg) - - - def _ebFromValidate(self, failure): - if failure.check(SMTPBadSender): - self.sendCode(failure.value.code, - 'Cannot receive from specified address %s: %s' - % (quoteaddr(failure.value.addr), failure.value.resp)) - elif failure.check(SMTPServerError): - self.sendCode(failure.value.code, failure.value.resp) - else: - log.err(failure, "SMTP sender validation failure") - self.sendCode( - 451, - 'Requested action aborted: local error in processing') - - - def do_RCPT(self, rest): - if not self._from: - self.sendCode(503, "Must have sender before recipient") - return - m = self.rcpt_re.match(rest) - if not m: - self.sendCode(501, "Syntax error") - return - - try: - user = User(m.group('path'), self._helo, self, self._from) - except AddressError, e: - self.sendCode(553, str(e)) - return - - d = defer.maybeDeferred(self.validateTo, user) - d.addCallbacks( - self._cbToValidate, - self._ebToValidate, - callbackArgs=(user,) - ) - - def _cbToValidate(self, to, user=None, code=250, msg='Recipient address accepted'): - if user is None: - user = to - self._to.append((user, to)) - self.sendCode(code, msg) - - def _ebToValidate(self, failure): - if failure.check(SMTPBadRcpt, SMTPServerError): - self.sendCode(failure.value.code, failure.value.resp) - else: - log.err(failure) - self.sendCode( - 451, - 'Requested action aborted: local error in processing' - ) - - def _disconnect(self, msgs): - for msg in msgs: - try: - msg.connectionLost() - except: - log.msg("msg raised exception from connectionLost") - log.err() - - def do_DATA(self, rest): - if self._from is None or (not self._to): - self.sendCode(503, 'Must have valid receiver and originator') - return - self.mode = DATA - helo, origin = self._helo, self._from - recipients = self._to - - self._from = None - self._to = [] - self.datafailed = None - - msgs = [] - for (user, msgFunc) in recipients: - try: - msg = msgFunc() - rcvdhdr = self.receivedHeader(helo, origin, [user]) - if rcvdhdr: - msg.lineReceived(rcvdhdr) - msgs.append(msg) - except SMTPServerError, e: - self.sendCode(e.code, e.resp) - self.mode = COMMAND - self._disconnect(msgs) - return - except: - log.err() - self.sendCode(550, "Internal server error") - self.mode = COMMAND - self._disconnect(msgs) - return - self.__messages = msgs - - self.__inheader = self.__inbody = 0 - self.sendCode(354, 'Continue') - - if self.noisy: - fmt = 'Receiving message for delivery: from=%s to=%s' - log.msg(fmt % (origin, [str(u) for (u, f) in recipients])) - - def connectionLost(self, reason): - # self.sendCode(421, 'Dropping connection.') # This does nothing... - # Ideally, if we (rather than the other side) lose the connection, - # we should be able to tell the other side that we are going away. - # RFC-2821 requires that we try. - if self.mode is DATA: - try: - for message in self.__messages: - try: - message.connectionLost() - except: - log.err() - del self.__messages - except AttributeError: - pass - if self._onLogout: - self._onLogout() - self._onLogout = None - self.setTimeout(None) - - def do_RSET(self, rest): - self._from = None - self._to = [] - self.sendCode(250, 'I remember nothing.') - - def dataLineReceived(self, line): - if line[:1] == '.': - if line == '.': - self.mode = COMMAND - if self.datafailed: - self.sendCode(self.datafailed.code, - self.datafailed.resp) - return - if not self.__messages: - self._messageHandled("thrown away") - return - defer.DeferredList([ - m.eomReceived() for m in self.__messages - ], consumeErrors=True).addCallback(self._messageHandled - ) - del self.__messages - return - line = line[1:] - - if self.datafailed: - return - - try: - # Add a blank line between the generated Received:-header - # and the message body if the message comes in without any - # headers - if not self.__inheader and not self.__inbody: - if ':' in line: - self.__inheader = 1 - elif line: - for message in self.__messages: - message.lineReceived('') - self.__inbody = 1 - - if not line: - self.__inbody = 1 - - for message in self.__messages: - message.lineReceived(line) - except SMTPServerError, e: - self.datafailed = e - for message in self.__messages: - message.connectionLost() - state_DATA = dataLineReceived - - def _messageHandled(self, resultList): - failures = 0 - for (success, result) in resultList: - if not success: - failures += 1 - log.err(result) - if failures: - msg = 'Could not send e-mail' - L = len(resultList) - if L > 1: - msg += ' (%d failures out of %d recipients)' % (failures, L) - self.sendCode(550, msg) - else: - self.sendCode(250, 'Delivery in progress') - - - def _cbAnonymousAuthentication(self, (iface, avatar, logout)): - """ - Save the state resulting from a successful anonymous cred login. - """ - if issubclass(iface, IMessageDeliveryFactory): - self.deliveryFactory = avatar - self.delivery = None - elif issubclass(iface, IMessageDelivery): - self.deliveryFactory = None - self.delivery = avatar - else: - raise RuntimeError("%s is not a supported interface" % (iface.__name__,)) - self._onLogout = logout - self.challenger = None - - - # overridable methods: - def validateFrom(self, helo, origin): - """ - Validate the address from which the message originates. - - @type helo: C{(str, str)} - @param helo: The argument to the HELO command and the client's IP - address. - - @type origin: C{Address} - @param origin: The address the message is from - - @rtype: C{Deferred} or C{Address} - @return: C{origin} or a C{Deferred} whose callback will be - passed C{origin}. - - @raise SMTPBadSender: Raised of messages from this address are - not to be accepted. - """ - if self.deliveryFactory is not None: - self.delivery = self.deliveryFactory.getMessageDelivery() - - if self.delivery is not None: - return defer.maybeDeferred(self.delivery.validateFrom, - helo, origin) - - # No login has been performed, no default delivery object has been - # provided: try to perform an anonymous login and then invoke this - # method again. - if self.portal: - - result = self.portal.login( - cred.credentials.Anonymous(), - None, - IMessageDeliveryFactory, IMessageDelivery) - - def ebAuthentication(err): - """ - Translate cred exceptions into SMTP exceptions so that the - protocol code which invokes C{validateFrom} can properly report - the failure. - """ - if err.check(cred.error.UnauthorizedLogin): - exc = SMTPBadSender(origin) - elif err.check(cred.error.UnhandledCredentials): - exc = SMTPBadSender( - origin, resp="Unauthenticated senders not allowed") - else: - return err - return defer.fail(exc) - - result.addCallbacks( - self._cbAnonymousAuthentication, ebAuthentication) - - def continueValidation(ignored): - """ - Re-attempt from address validation. - """ - return self.validateFrom(helo, origin) - - result.addCallback(continueValidation) - return result - - raise SMTPBadSender(origin) - - - def validateTo(self, user): - """ - Validate the address for which the message is destined. - - @type user: C{User} - @param user: The address to validate. - - @rtype: no-argument callable - @return: A C{Deferred} which becomes, or a callable which - takes no arguments and returns an object implementing C{IMessage}. - This will be called and the returned object used to deliver the - message when it arrives. - - @raise SMTPBadRcpt: Raised if messages to the address are - not to be accepted. - """ - if self.delivery is not None: - return self.delivery.validateTo(user) - raise SMTPBadRcpt(user) - - def receivedHeader(self, helo, origin, recipients): - if self.delivery is not None: - return self.delivery.receivedHeader(helo, origin, recipients) - - heloStr = "" - if helo[0]: - heloStr = " helo=%s" % (helo[0],) - domain = self.transport.getHost().host - from_ = "from %s ([%s]%s)" % (helo[0], helo[1], heloStr) - by = "by %s with %s (%s)" % (domain, - self.__class__.__name__, - longversion) - for_ = "for %s; %s" % (' '.join(map(str, recipients)), - rfc822date()) - return "Received: %s\n\t%s\n\t%s" % (from_, by, for_) - - def startMessage(self, recipients): - if self.delivery: - return self.delivery.startMessage(recipients) - return [] - - -class SMTPFactory(protocol.ServerFactory): - """Factory for SMTP.""" - - # override in instances or subclasses - domain = DNSNAME - timeout = 600 - protocol = SMTP - - portal = None - - def __init__(self, portal = None): - self.portal = portal - - def buildProtocol(self, addr): - p = protocol.ServerFactory.buildProtocol(self, addr) - p.portal = self.portal - p.host = self.domain - return p - -class SMTPClient(basic.LineReceiver, policies.TimeoutMixin): - """SMTP client for sending emails.""" - - # If enabled then log SMTP client server communication - debug = True - - # Number of seconds to wait before timing out a connection. If - # None, perform no timeout checking. - timeout = None - - def __init__(self, identity, logsize=10): - self.identity = identity or '' - self.toAddressesResult = [] - self.successAddresses = [] - self._from = None - self.resp = [] - self.code = -1 - self.log = util.LineLog(logsize) - - def sendLine(self, line): - # Log sendLine only if you are in debug mode for performance - if self.debug: - self.log.append('>>> ' + line) - - basic.LineReceiver.sendLine(self,line) - - def connectionMade(self): - self.setTimeout(self.timeout) - - self._expected = [ 220 ] - self._okresponse = self.smtpState_helo - self._failresponse = self.smtpConnectionFailed - - def connectionLost(self, reason=protocol.connectionDone): - """We are no longer connected""" - self.setTimeout(None) - self.mailFile = None - - def timeoutConnection(self): - self.sendError( - SMTPTimeoutError(-1, - "Timeout waiting for SMTP server response", - self.log)) - - def lineReceived(self, line): - self.resetTimeout() - - # Log lineReceived only if you are in debug mode for performance - if self.debug: - self.log.append('<<< ' + line) - - why = None - - try: - self.code = int(line[:3]) - except ValueError: - # This is a fatal error and will disconnect the transport lineReceived will not be called again - self.sendError(SMTPProtocolError(-1, "Invalid response from SMTP server: %s" % line, self.log.str())) - return - - if line[0] == '0': - # Verbose informational message, ignore it - return - - self.resp.append(line[4:]) - - if line[3:4] == '-': - # continuation - return - - if self.code in self._expected: - why = self._okresponse(self.code,'\n'.join(self.resp)) - else: - why = self._failresponse(self.code,'\n'.join(self.resp)) - - self.code = -1 - self.resp = [] - return why - - def smtpConnectionFailed(self, code, resp): - self.sendError(SMTPConnectError(code, resp, self.log.str())) - - def smtpTransferFailed(self, code, resp): - if code < 0: - self.sendError(SMTPProtocolError(code, resp, self.log.str())) - else: - self.smtpState_msgSent(code, resp) - - def smtpState_helo(self, code, resp): - self.sendLine('HELO ' + self.identity) - self._expected = SUCCESS - self._okresponse = self.smtpState_from - - def smtpState_from(self, code, resp): - self._from = self.getMailFrom() - self._failresponse = self.smtpTransferFailed - if self._from is not None: - self.sendLine('MAIL FROM:%s' % quoteaddr(self._from)) - self._expected = [250] - self._okresponse = self.smtpState_to - else: - # All messages have been sent, disconnect - self._disconnectFromServer() - - def smtpState_disconnect(self, code, resp): - self.transport.loseConnection() - - def smtpState_to(self, code, resp): - self.toAddresses = iter(self.getMailTo()) - self.toAddressesResult = [] - self.successAddresses = [] - self._okresponse = self.smtpState_toOrData - self._expected = xrange(0,1000) - self.lastAddress = None - return self.smtpState_toOrData(0, '') - - def smtpState_toOrData(self, code, resp): - if self.lastAddress is not None: - self.toAddressesResult.append((self.lastAddress, code, resp)) - if code in SUCCESS: - self.successAddresses.append(self.lastAddress) - try: - self.lastAddress = self.toAddresses.next() - except StopIteration: - if self.successAddresses: - self.sendLine('DATA') - self._expected = [ 354 ] - self._okresponse = self.smtpState_data - else: - return self.smtpState_msgSent(code,'No recipients accepted') - else: - self.sendLine('RCPT TO:%s' % quoteaddr(self.lastAddress)) - - def smtpState_data(self, code, resp): - s = basic.FileSender() - s.beginFileTransfer( - self.getMailData(), self.transport, self.transformChunk - ).addCallback(self.finishedFileTransfer) - self._expected = SUCCESS - self._okresponse = self.smtpState_msgSent - - def smtpState_msgSent(self, code, resp): - if self._from is not None: - self.sentMail(code, resp, len(self.successAddresses), - self.toAddressesResult, self.log) - - self.toAddressesResult = [] - self._from = None - self.sendLine('RSET') - self._expected = SUCCESS - self._okresponse = self.smtpState_from - - ## - ## Helpers for FileSender - ## - def transformChunk(self, chunk): - return chunk.replace('\n', '\r\n').replace('\r\n.', '\r\n..') - - def finishedFileTransfer(self, lastsent): - if lastsent != '\n': - line = '\r\n.' - else: - line = '.' - self.sendLine(line) - ## - - # these methods should be overriden in subclasses - def getMailFrom(self): - """Return the email address the mail is from.""" - raise NotImplementedError - - def getMailTo(self): - """Return a list of emails to send to.""" - raise NotImplementedError - - def getMailData(self): - """Return file-like object containing data of message to be sent. - - Lines in the file should be delimited by '\\n'. - """ - raise NotImplementedError - - def sendError(self, exc): - """ - If an error occurs before a mail message is sent sendError will be - called. This base class method sends a QUIT if the error is - non-fatal and disconnects the connection. - - @param exc: The SMTPClientError (or child class) raised - @type exc: C{SMTPClientError} - """ - assert isinstance(exc, SMTPClientError) - - if exc.isFatal: - # If the error was fatal then the communication channel with the SMTP Server is - # broken so just close the transport connection - self.smtpState_disconnect(-1, None) - else: - self._disconnectFromServer() - - def sentMail(self, code, resp, numOk, addresses, log): - """Called when an attempt to send an email is completed. - - If some addresses were accepted, code and resp are the response - to the DATA command. If no addresses were accepted, code is -1 - and resp is an informative message. - - @param code: the code returned by the SMTP Server - @param resp: The string response returned from the SMTP Server - @param numOK: the number of addresses accepted by the remote host. - @param addresses: is a list of tuples (address, code, resp) listing - the response to each RCPT command. - @param log: is the SMTP session log - """ - raise NotImplementedError - - def _disconnectFromServer(self): - self._expected = xrange(0, 1000) - self._okresponse = self.smtpState_disconnect - self.sendLine('QUIT') - -class ESMTPClient(SMTPClient): - # Fall back to HELO if the server does not support EHLO - heloFallback = True - - # Refuse to proceed if authentication cannot be performed - requireAuthentication = False - - # Refuse to proceed if TLS is not available - requireTransportSecurity = False - - # Indicate whether or not our transport can be considered secure. - tlsMode = False - - # ClientContextFactory to use for STARTTLS - context = None - - def __init__(self, secret, contextFactory=None, *args, **kw): - SMTPClient.__init__(self, *args, **kw) - self.authenticators = [] - self.secret = secret - self.context = contextFactory - self.tlsMode = False - - - def esmtpEHLORequired(self, code=-1, resp=None): - self.sendError(EHLORequiredError(502, "Server does not support ESMTP Authentication", self.log.str())) - - - def esmtpAUTHRequired(self, code=-1, resp=None): - tmp = [] - - for a in self.authenticators: - tmp.append(a.getName().upper()) - - auth = "[%s]" % ', '.join(tmp) - - self.sendError(AUTHRequiredError(502, "Server does not support Client Authentication schemes %s" % auth, - self.log.str())) - - - def esmtpTLSRequired(self, code=-1, resp=None): - self.sendError(TLSRequiredError(502, "Server does not support secure communication via TLS / SSL", - self.log.str())) - - def esmtpTLSFailed(self, code=-1, resp=None): - self.sendError(TLSError(code, "Could not complete the SSL/TLS handshake", self.log.str())) - - def esmtpAUTHDeclined(self, code=-1, resp=None): - self.sendError(AUTHDeclinedError(code, resp, self.log.str())) - - def esmtpAUTHMalformedChallenge(self, code=-1, resp=None): - str = "Login failed because the SMTP Server returned a malformed Authentication Challenge" - self.sendError(AuthenticationError(501, str, self.log.str())) - - def esmtpAUTHServerError(self, code=-1, resp=None): - self.sendError(AuthenticationError(code, resp, self.log.str())) - - def registerAuthenticator(self, auth): - """Registers an Authenticator with the ESMTPClient. The ESMTPClient - will attempt to login to the SMTP Server in the order the - Authenticators are registered. The most secure Authentication - mechanism should be registered first. - - @param auth: The Authentication mechanism to register - @type auth: class implementing C{IClientAuthentication} - """ - - self.authenticators.append(auth) - - def connectionMade(self): - SMTPClient.connectionMade(self) - self._okresponse = self.esmtpState_ehlo - - def esmtpState_ehlo(self, code, resp): - self._expected = SUCCESS - - self._okresponse = self.esmtpState_serverConfig - self._failresponse = self.esmtpEHLORequired - - if self.heloFallback: - self._failresponse = self.smtpState_helo - - self.sendLine('EHLO ' + self.identity) - - def esmtpState_serverConfig(self, code, resp): - items = {} - for line in resp.splitlines(): - e = line.split(None, 1) - if len(e) > 1: - items[e[0]] = e[1] - else: - items[e[0]] = None - - if self.tlsMode: - self.authenticate(code, resp, items) - else: - self.tryTLS(code, resp, items) - - def tryTLS(self, code, resp, items): - if self.context and 'STARTTLS' in items: - self._expected = [220] - self._okresponse = self.esmtpState_starttls - self._failresponse = self.esmtpTLSFailed - self.sendLine('STARTTLS') - elif self.requireTransportSecurity: - self.tlsMode = False - self.esmtpTLSRequired() - else: - self.tlsMode = False - self.authenticate(code, resp, items) - - def esmtpState_starttls(self, code, resp): - try: - self.transport.startTLS(self.context) - self.tlsMode = True - except: - log.err() - self.esmtpTLSFailed(451) - - # Send another EHLO once TLS has been started to - # get the TLS / AUTH schemes. Some servers only allow AUTH in TLS mode. - self.esmtpState_ehlo(code, resp) - - def authenticate(self, code, resp, items): - if self.secret and items.get('AUTH'): - schemes = items['AUTH'].split() - tmpSchemes = {} - - #XXX: May want to come up with a more efficient way to do this - for s in schemes: - tmpSchemes[s.upper()] = 1 - - for a in self.authenticators: - auth = a.getName().upper() - - if auth in tmpSchemes: - self._authinfo = a - - # Special condition handled - if auth == "PLAIN": - self._okresponse = self.smtpState_from - self._failresponse = self._esmtpState_plainAuth - self._expected = [235] - challenge = encode_base64(self._authinfo.challengeResponse(self.secret, 1), eol="") - self.sendLine('AUTH ' + auth + ' ' + challenge) - else: - self._expected = [334] - self._okresponse = self.esmtpState_challenge - # If some error occurs here, the server declined the AUTH - # before the user / password phase. This would be - # a very rare case - self._failresponse = self.esmtpAUTHServerError - self.sendLine('AUTH ' + auth) - return - - if self.requireAuthentication: - self.esmtpAUTHRequired() - else: - self.smtpState_from(code, resp) - - def _esmtpState_plainAuth(self, code, resp): - self._okresponse = self.smtpState_from - self._failresponse = self.esmtpAUTHDeclined - self._expected = [235] - challenge = encode_base64(self._authinfo.challengeResponse(self.secret, 2), eol="") - self.sendLine('AUTH PLAIN ' + challenge) - - def esmtpState_challenge(self, code, resp): - auth = self._authinfo - del self._authinfo - self._authResponse(auth, resp) - - def _authResponse(self, auth, challenge): - self._failresponse = self.esmtpAUTHDeclined - - try: - challenge = base64.decodestring(challenge) - except binascii.Error, e: - # Illegal challenge, give up, then quit - self.sendLine('*') - self._okresponse = self.esmtpAUTHMalformedChallenge - self._failresponse = self.esmtpAUTHMalformedChallenge - else: - resp = auth.challengeResponse(self.secret, challenge) - self._expected = [235] - self._okresponse = self.smtpState_from - self.sendLine(encode_base64(resp, eol="")) - - if auth.getName() == "LOGIN" and challenge == "Username:": - self._expected = [334] - self._authinfo = auth - self._okresponse = self.esmtpState_challenge - - -class ESMTP(SMTP): - - ctx = None - canStartTLS = False - startedTLS = False - - authenticated = False - - def __init__(self, chal = None, contextFactory = None): - SMTP.__init__(self) - if chal is None: - chal = {} - self.challengers = chal - self.authenticated = False - self.ctx = contextFactory - - def connectionMade(self): - SMTP.connectionMade(self) - self.canStartTLS = ITLSTransport.providedBy(self.transport) - self.canStartTLS = self.canStartTLS and (self.ctx is not None) - - - def greeting(self): - return SMTP.greeting(self) + ' ESMTP' - - - def extensions(self): - ext = {'AUTH': self.challengers.keys()} - if self.canStartTLS and not self.startedTLS: - ext['STARTTLS'] = None - return ext - - def lookupMethod(self, command): - m = SMTP.lookupMethod(self, command) - if m is None: - m = getattr(self, 'ext_' + command.upper(), None) - return m - - def listExtensions(self): - r = [] - for (c, v) in self.extensions().iteritems(): - if v is not None: - if v: - # Intentionally omit extensions with empty argument lists - r.append('%s %s' % (c, ' '.join(v))) - else: - r.append(c) - return '\n'.join(r) - - def do_EHLO(self, rest): - peer = self.transport.getPeer().host - self._helo = (rest, peer) - self._from = None - self._to = [] - self.sendCode( - 250, - '%s Hello %s, nice to meet you\n%s' % ( - self.host, peer, - self.listExtensions(), - ) - ) - - def ext_STARTTLS(self, rest): - if self.startedTLS: - self.sendCode(503, 'TLS already negotiated') - elif self.ctx and self.canStartTLS: - self.sendCode(220, 'Begin TLS negotiation now') - self.transport.startTLS(self.ctx) - self.startedTLS = True - else: - self.sendCode(454, 'TLS not available') - - def ext_AUTH(self, rest): - if self.authenticated: - self.sendCode(503, 'Already authenticated') - return - parts = rest.split(None, 1) - chal = self.challengers.get(parts[0].upper(), lambda: None)() - if not chal: - self.sendCode(504, 'Unrecognized authentication type') - return - - self.mode = AUTH - self.challenger = chal - - if len(parts) > 1: - chal.getChallenge() # Discard it, apparently the client does not - # care about it. - rest = parts[1] - else: - rest = None - self.state_AUTH(rest) - - - def _cbAuthenticated(self, loginInfo): - """ - Save the state resulting from a successful cred login and mark this - connection as authenticated. - """ - result = SMTP._cbAnonymousAuthentication(self, loginInfo) - self.authenticated = True - return result - - - def _ebAuthenticated(self, reason): - """ - Handle cred login errors by translating them to the SMTP authenticate - failed. Translate all other errors into a generic SMTP error code and - log the failure for inspection. Stop all errors from propagating. - """ - self.challenge = None - if reason.check(cred.error.UnauthorizedLogin): - self.sendCode(535, 'Authentication failed') - else: - log.err(failure, "SMTP authentication failure") - self.sendCode( - 451, - 'Requested action aborted: local error in processing') - - - def state_AUTH(self, response): - """ - Handle one step of challenge/response authentication. - - @param response: The text of a response. If None, this - function has been called as a result of an AUTH command with - no initial response. A response of '*' aborts authentication, - as per RFC 2554. - """ - if self.portal is None: - self.sendCode(454, 'Temporary authentication failure') - self.mode = COMMAND - return - - if response is None: - challenge = self.challenger.getChallenge() - encoded = challenge.encode('base64') - self.sendCode(334, encoded) - return - - if response == '*': - self.sendCode(501, 'Authentication aborted') - self.challenger = None - self.mode = COMMAND - return - - try: - uncoded = response.decode('base64') - except binascii.Error: - self.sendCode(501, 'Syntax error in parameters or arguments') - self.challenger = None - self.mode = COMMAND - return - - self.challenger.setResponse(uncoded) - if self.challenger.moreChallenges(): - challenge = self.challenger.getChallenge() - coded = challenge.encode('base64')[:-1] - self.sendCode(334, coded) - return - - self.mode = COMMAND - result = self.portal.login( - self.challenger, None, - IMessageDeliveryFactory, IMessageDelivery) - result.addCallback(self._cbAuthenticated) - result.addCallback(lambda ign: self.sendCode(235, 'Authentication successful.')) - result.addErrback(self._ebAuthenticated) - - - -class SenderMixin: - """Utility class for sending emails easily. - - Use with SMTPSenderFactory or ESMTPSenderFactory. - """ - done = 0 - - def getMailFrom(self): - if not self.done: - self.done = 1 - return str(self.factory.fromEmail) - else: - return None - - def getMailTo(self): - return self.factory.toEmail - - def getMailData(self): - return self.factory.file - - def sendError(self, exc): - # Call the base class to close the connection with the SMTP server - SMTPClient.sendError(self, exc) - - # Do not retry to connect to SMTP Server if: - # 1. No more retries left (This allows the correct error to be returned to the errorback) - # 2. retry is false - # 3. The error code is not in the 4xx range (Communication Errors) - - if (self.factory.retries >= 0 or - (not exc.retry and not (exc.code >= 400 and exc.code < 500))): - self.factory.sendFinished = 1 - self.factory.result.errback(exc) - - def sentMail(self, code, resp, numOk, addresses, log): - # Do not retry, the SMTP server acknowledged the request - self.factory.sendFinished = 1 - if code not in SUCCESS: - errlog = [] - for addr, acode, aresp in addresses: - if code not in SUCCESS: - errlog.append("%s: %03d %s" % (addr, acode, aresp)) - - errlog.append(log.str()) - - exc = SMTPDeliveryError(code, resp, '\n'.join(errlog), addresses) - self.factory.result.errback(exc) - else: - self.factory.result.callback((numOk, addresses)) - - -class SMTPSender(SenderMixin, SMTPClient): - pass - - -class SMTPSenderFactory(protocol.ClientFactory): - """ - Utility factory for sending emails easily. - """ - - domain = DNSNAME - protocol = SMTPSender - - def __init__(self, fromEmail, toEmail, file, deferred, retries=5, - timeout=None): - """ - @param fromEmail: The RFC 2821 address from which to send this - message. - - @param toEmail: A sequence of RFC 2821 addresses to which to - send this message. - - @param file: A file-like object containing the message to send. - - @param deferred: A Deferred to callback or errback when sending - of this message completes. - - @param retries: The number of times to retry delivery of this - message. - - @param timeout: Period, in seconds, for which to wait for - server responses, or None to wait forever. - """ - assert isinstance(retries, (int, long)) - - if isinstance(toEmail, types.StringTypes): - toEmail = [toEmail] - self.fromEmail = Address(fromEmail) - self.nEmails = len(toEmail) - self.toEmail = iter(toEmail) - self.file = file - self.result = deferred - self.result.addBoth(self._removeDeferred) - self.sendFinished = 0 - - self.retries = -retries - self.timeout = timeout - - def _removeDeferred(self, argh): - del self.result - return argh - - def clientConnectionFailed(self, connector, err): - self._processConnectionError(connector, err) - - def clientConnectionLost(self, connector, err): - self._processConnectionError(connector, err) - - def _processConnectionError(self, connector, err): - if self.retries < self.sendFinished <= 0: - log.msg("SMTP Client retrying server. Retry: %s" % -self.retries) - - connector.connect() - self.retries += 1 - elif self.sendFinished <= 0: - # If we were unable to communicate with the SMTP server a ConnectionDone will be - # returned. We want a more clear error message for debugging - if err.check(error.ConnectionDone): - err.value = SMTPConnectError(-1, "Unable to connect to server.") - self.result.errback(err.value) - - def buildProtocol(self, addr): - p = self.protocol(self.domain, self.nEmails*2+2) - p.factory = self - p.timeout = self.timeout - return p - - -class IClientAuthentication(Interface): - def getName(): - """Return an identifier associated with this authentication scheme. - - @rtype: C{str} - """ - - def challengeResponse(secret, challenge): - """Generate a challenge response string""" - - -class CramMD5ClientAuthenticator: - implements(IClientAuthentication) - - def __init__(self, user): - self.user = user - - def getName(self): - return "CRAM-MD5" - - def challengeResponse(self, secret, chal): - response = hmac.HMAC(secret, chal).hexdigest() - return '%s %s' % (self.user, response) - - -class LOGINAuthenticator: - implements(IClientAuthentication) - - def __init__(self, user): - self.user = user - - def getName(self): - return "LOGIN" - - def challengeResponse(self, secret, chal): - if chal== "Username:": - return self.user - elif chal == 'Password:': - return secret - -class PLAINAuthenticator: - implements(IClientAuthentication) - - def __init__(self, user): - self.user = user - - def getName(self): - return "PLAIN" - - def challengeResponse(self, secret, chal=1): - if chal == 1: - return "%s\0%s\0%s" % (self.user, self.user, secret) - else: - return "%s\0%s" % (self.user, secret) - - -class ESMTPSender(SenderMixin, ESMTPClient): - - requireAuthentication = True - requireTransportSecurity = True - - def __init__(self, username, secret, contextFactory=None, *args, **kw): - self.heloFallback = 0 - self.username = username - - if contextFactory is None: - contextFactory = self._getContextFactory() - - ESMTPClient.__init__(self, secret, contextFactory, *args, **kw) - - self._registerAuthenticators() - - def _registerAuthenticators(self): - # Register Authenticator in order from most secure to least secure - self.registerAuthenticator(CramMD5ClientAuthenticator(self.username)) - self.registerAuthenticator(LOGINAuthenticator(self.username)) - self.registerAuthenticator(PLAINAuthenticator(self.username)) - - def _getContextFactory(self): - if self.context is not None: - return self.context - try: - from twisted.internet import ssl - except ImportError: - return None - else: - try: - context = ssl.ClientContextFactory() - context.method = ssl.SSL.TLSv1_METHOD - return context - except AttributeError: - return None - - -class ESMTPSenderFactory(SMTPSenderFactory): - """ - Utility factory for sending emails easily. - """ - - protocol = ESMTPSender - - def __init__(self, username, password, fromEmail, toEmail, file, - deferred, retries=5, timeout=None, - contextFactory=None, heloFallback=False, - requireAuthentication=True, - requireTransportSecurity=True): - - SMTPSenderFactory.__init__(self, fromEmail, toEmail, file, deferred, retries, timeout) - self.username = username - self.password = password - self._contextFactory = contextFactory - self._heloFallback = heloFallback - self._requireAuthentication = requireAuthentication - self._requireTransportSecurity = requireTransportSecurity - - def buildProtocol(self, addr): - p = self.protocol(self.username, self.password, self._contextFactory, self.domain, self.nEmails*2+2) - p.heloFallback = self._heloFallback - p.requireAuthentication = self._requireAuthentication - p.requireTransportSecurity = self._requireTransportSecurity - p.factory = self - p.timeout = self.timeout - return p - -def sendmail(smtphost, from_addr, to_addrs, msg, senderDomainName=None, port=25): - """Send an email - - This interface is intended to be a direct replacement for - smtplib.SMTP.sendmail() (with the obvious change that - you specify the smtphost as well). Also, ESMTP options - are not accepted, as we don't do ESMTP yet. I reserve the - right to implement the ESMTP options differently. - - @param smtphost: The host the message should be sent to - @param from_addr: The (envelope) address sending this mail. - @param to_addrs: A list of addresses to send this mail to. A string will - be treated as a list of one address - @param msg: The message, including headers, either as a file or a string. - File-like objects need to support read() and close(). Lines must be - delimited by '\\n'. If you pass something that doesn't look like a - file, we try to convert it to a string (so you should be able to - pass an email.Message directly, but doing the conversion with - email.Generator manually will give you more control over the - process). - - @param senderDomainName: Name by which to identify. If None, try - to pick something sane (but this depends on external configuration - and may not succeed). - - @param port: Remote port to which to connect. - - @rtype: L{Deferred} - @returns: A L{Deferred}, its callback will be called if a message is sent - to ANY address, the errback if no message is sent. - - The callback will be called with a tuple (numOk, addresses) where numOk - is the number of successful recipient addresses and addresses is a list - of tuples (address, code, resp) giving the response to the RCPT command - for each address. - """ - if not hasattr(msg,'read'): - # It's not a file - msg = StringIO(str(msg)) - - d = defer.Deferred() - factory = SMTPSenderFactory(from_addr, to_addrs, msg, d) - - if senderDomainName is not None: - factory.domain = senderDomainName - - reactor.connectTCP(smtphost, port, factory) - - return d - -def sendEmail(smtphost, fromEmail, toEmail, content, headers = None, attachments = None, multipartbody = "mixed"): - """Send an email, optionally with attachments. - - @type smtphost: str - @param smtphost: hostname of SMTP server to which to connect - - @type fromEmail: str - @param fromEmail: email address to indicate this email is from - - @type toEmail: str - @param toEmail: email address to which to send this email - - @type content: str - @param content: The body if this email. - - @type headers: dict - @param headers: Dictionary of headers to include in the email - - @type attachments: list of 3-tuples - @param attachments: Each 3-tuple should consist of the name of the - attachment, the mime-type of the attachment, and a string that is - the attachment itself. - - @type multipartbody: str - @param multipartbody: The type of MIME multi-part body. Generally - either "mixed" (as in text and images) or "alternative" (html email - with a fallback to text/plain). - - @rtype: Deferred - @return: The returned Deferred has its callback or errback invoked when - the mail is successfully sent or when an error occurs, respectively. - """ - warnings.warn("smtp.sendEmail may go away in the future.\n" - " Consider revising your code to use the email module\n" - " and smtp.sendmail.", - category=DeprecationWarning, stacklevel=2) - - f = tempfile.TemporaryFile() - writer = MimeWriter.MimeWriter(f) - - writer.addheader("Mime-Version", "1.0") - if headers: - # Setup the mail headers - for (header, value) in headers.items(): - writer.addheader(header, value) - - headkeys = [k.lower() for k in headers.keys()] - else: - headkeys = () - - # Add required headers if not present - if "message-id" not in headkeys: - writer.addheader("Message-ID", messageid()) - if "date" not in headkeys: - writer.addheader("Date", rfc822date()) - if "from" not in headkeys and "sender" not in headkeys: - writer.addheader("From", fromEmail) - if "to" not in headkeys and "cc" not in headkeys and "bcc" not in headkeys: - writer.addheader("To", toEmail) - - writer.startmultipartbody(multipartbody) - - # message body - part = writer.nextpart() - body = part.startbody("text/plain") - body.write(content) - - if attachments is not None: - # add attachments - for (file, mime, attachment) in attachments: - part = writer.nextpart() - if mime.startswith('text'): - encoding = "7bit" - else: - attachment = base64.encodestring(attachment) - encoding = "base64" - part.addheader("Content-Transfer-Encoding", encoding) - body = part.startbody("%s; name=%s" % (mime, file)) - body.write(attachment) - - # finish - writer.lastpart() - - # send message - f.seek(0, 0) - d = defer.Deferred() - factory = SMTPSenderFactory(fromEmail, toEmail, f, d) - reactor.connectTCP(smtphost, 25, factory) - - return d - -## -## Yerg. Codecs! -## -import codecs -def xtext_encode(s): - r = [] - for ch in s: - o = ord(ch) - if ch == '+' or ch == '=' or o < 33 or o > 126: - r.append('+%02X' % o) - else: - r.append(ch) - return (''.join(r), len(s)) - -try: - from twisted.protocols._c_urlarg import unquote as _helper_unquote -except ImportError: - def xtext_decode(s): - r = [] - i = 0 - while i < len(s): - if s[i] == '+': - try: - r.append(chr(int(s[i + 1:i + 3], 16))) - except ValueError: - r.append(s[i:i + 3]) - i += 3 - else: - r.append(s[i]) - i += 1 - return (''.join(r), len(s)) -else: - def xtext_decode(s): - return (_helper_unquote(s, '+'), len(s)) - -class xtextStreamReader(codecs.StreamReader): - def decode(self, s, errors='strict'): - return xtext_decode(s) - -class xtextStreamWriter(codecs.StreamWriter): - def decode(self, s, errors='strict'): - return xtext_encode(s) - -def xtext_codec(name): - if name == 'xtext': - return (xtext_encode, xtext_decode, xtextStreamReader, xtextStreamWriter) -codecs.register(xtext_codec) diff --git a/tools/buildbot/pylibs/twisted/mail/tap.py b/tools/buildbot/pylibs/twisted/mail/tap.py deleted file mode 100644 index 6ce3ebe..0000000 --- a/tools/buildbot/pylibs/twisted/mail/tap.py +++ /dev/null @@ -1,185 +0,0 @@ -# -*- test-case-name: twisted.mail.test.test_options -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""I am the support module for creating mail servers with 'mktap' -""" - -import os -import sys - -from twisted.mail import mail -from twisted.mail import maildir -from twisted.mail import relay -from twisted.mail import relaymanager -from twisted.mail import alias - -from twisted.python import usage - -from twisted.cred import checkers -from twisted.application import internet - - -class Options(usage.Options): - synopsis = "Usage: mktap mail [options]" - - optParameters = [ - ["pop3", "p", 8110, "Port to start the POP3 server on (0 to disable).", usage.portCoerce], - ["pop3s", "S", 0, "Port to start the POP3-over-SSL server on (0 to disable).", usage.portCoerce], - ["smtp", "s", 8025, "Port to start the SMTP server on (0 to disable).", usage.portCoerce], - ["certificate", "c", None, "Certificate file to use for SSL connections"], - ["relay", "R", None, - "Relay messages according to their envelope 'To', using the given" - "path as a queue directory."], - ["hostname", "H", None, "The hostname by which to identify this server."], - ] - - optFlags = [ - ["esmtp", "E", "Use RFC 1425/1869 SMTP extensions"], - ["disable-anonymous", None, "Disallow non-authenticated SMTP connections"], - ] - zsh_actions = {"hostname" : "_hosts"} - - longdesc = "This creates a mail.tap file that can be used by twistd." - - def __init__(self): - usage.Options.__init__(self) - self.service = mail.MailService() - self.last_domain = None - - def opt_passwordfile(self, filename): - """Specify a file containing username:password login info for authenticated ESMTP connections.""" - ch = checkers.OnDiskUsernamePasswordDatabase(filename) - self.service.smtpPortal.registerChecker(ch) - opt_P = opt_passwordfile - - def opt_default(self): - """Make the most recently specified domain the default domain.""" - if self.last_domain: - self.service.addDomain('', self.last_domain) - else: - raise usage.UsageError("Specify a domain before specifying using --default") - opt_D = opt_default - - def opt_maildirdbmdomain(self, domain): - """generate an SMTP/POP3 virtual domain which saves to \"path\" - """ - try: - name, path = domain.split('=') - except ValueError: - raise usage.UsageError("Argument to --maildirdbmdomain must be of the form 'name=path'") - - self.last_domain = maildir.MaildirDirdbmDomain(self.service, os.path.abspath(path)) - self.service.addDomain(name, self.last_domain) - opt_d = opt_maildirdbmdomain - - def opt_user(self, user_pass): - """add a user/password to the last specified domains - """ - try: - user, password = user_pass.split('=', 1) - except ValueError: - raise usage.UsageError("Argument to --user must be of the form 'user=password'") - if self.last_domain: - self.last_domain.addUser(user, password) - else: - raise usage.UsageError("Specify a domain before specifying users") - opt_u = opt_user - - def opt_bounce_to_postmaster(self): - """undelivered mails are sent to the postmaster - """ - self.last_domain.postmaster = 1 - opt_b = opt_bounce_to_postmaster - - def opt_aliases(self, filename): - """Specify an aliases(5) file to use for this domain""" - if self.last_domain is not None: - if mail.IAliasableDomain.providedBy(self.last_domain): - aliases = alias.loadAliasFile(self.service.domains, filename) - self.last_domain.setAliasGroup(aliases) - self.service.monitor.monitorFile( - filename, - AliasUpdater(self.service.domains, self.last_domain) - ) - else: - raise usage.UsageError( - "%s does not support alias files" % ( - self.last_domain.__class__.__name__, - ) - ) - else: - raise usage.UsageError("Specify a domain before specifying aliases") - opt_A = opt_aliases - - def postOptions(self): - if self['pop3s']: - if not self['certificate']: - raise usage.UsageError("Cannot specify --pop3s without " - "--certificate") - elif not os.path.exists(self['certificate']): - raise usage.UsageError("Certificate file %r does not exist." - % self['certificate']) - - if not self['disable-anonymous']: - self.service.smtpPortal.registerChecker(checkers.AllowAnonymousAccess()) - - if not (self['pop3'] or self['smtp'] or self['pop3s']): - raise usage.UsageError("You cannot disable all protocols") - -class AliasUpdater: - def __init__(self, domains, domain): - self.domains = domains - self.domain = domain - def __call__(self, new): - self.domain.setAliasGroup(alias.loadAliasFile(self.domains, new)) - -def makeService(config): - if config['esmtp']: - rmType = relaymanager.SmartHostESMTPRelayingManager - smtpFactory = config.service.getESMTPFactory - else: - rmType = relaymanager.SmartHostSMTPRelayingManager - smtpFactory = config.service.getSMTPFactory - - if config['relay']: - dir = config['relay'] - if not os.path.isdir(dir): - os.mkdir(dir) - - config.service.setQueue(relaymanager.Queue(dir)) - default = relay.DomainQueuer(config.service) - - manager = rmType(config.service.queue) - if config['esmtp']: - manager.fArgs += (None, None) - manager.fArgs += (config['hostname'],) - - helper = relaymanager.RelayStateHelper(manager, 1) - helper.setServiceParent(config.service) - config.service.domains.setDefaultDomain(default) - - ctx = None - if config['certificate']: - from twisted.mail.protocols import SSLContextFactory - ctx = SSLContextFactory(config['certificate']) - - if config['pop3']: - s = internet.TCPServer(config['pop3'], config.service.getPOP3Factory()) - s.setServiceParent(config.service) - if config['pop3s']: - s = internet.SSLServer(config['pop3s'], - config.service.getPOP3Factory(), ctx) - s.setServiceParent(config.service) - if config['smtp']: - f = smtpFactory() - f.context = ctx - if config['hostname']: - f.domain = config['hostname'] - f.fArgs = (f.domain,) - if config['esmtp']: - f.fArgs = (None, None) + f.fArgs - s = internet.TCPServer(config['smtp'], f) - s.setServiceParent(config.service) - return config.service diff --git a/tools/buildbot/pylibs/twisted/mail/test/__init__.py b/tools/buildbot/pylibs/twisted/mail/test/__init__.py deleted file mode 100644 index f8ec705..0000000 --- a/tools/buildbot/pylibs/twisted/mail/test/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"Tests for twistd.mail" diff --git a/tools/buildbot/pylibs/twisted/mail/test/pop3testserver.py b/tools/buildbot/pylibs/twisted/mail/test/pop3testserver.py deleted file mode 100644 index 360aae0..0000000 --- a/tools/buildbot/pylibs/twisted/mail/test/pop3testserver.py +++ /dev/null @@ -1,311 +0,0 @@ -#!/usr/bin/python -# -*- test-case-name: twisted.mail.test.test_pop3client -*- - -from twisted.internet.protocol import Factory -from twisted.protocols import basic -from twisted.internet import reactor -import sys, time - -USER = "test" -PASS = "twisted" - -PORT = 1100 - -SSL_SUPPORT = True -UIDL_SUPPORT = True -INVALID_SERVER_RESPONSE = False -INVALID_CAPABILITY_RESPONSE = False -INVALID_LOGIN_RESPONSE = False -DENY_CONNECTION = False -DROP_CONNECTION = False -BAD_TLS_RESPONSE = False -TIMEOUT_RESPONSE = False -TIMEOUT_DEFERRED = False -SLOW_GREETING = False - -"""Commands""" -CONNECTION_MADE = "+OK POP3 localhost v2003.83 server ready" - -CAPABILITIES = [ -"TOP", -"LOGIN-DELAY 180", -"USER", -"SASL LOGIN" -] - -CAPABILITIES_SSL = "STLS" -CAPABILITIES_UIDL = "UIDL" - - -INVALID_RESPONSE = "-ERR Unknown request" -VALID_RESPONSE = "+OK Command Completed" -AUTH_DECLINED = "-ERR LOGIN failed" -AUTH_ACCEPTED = "+OK Mailbox open, 0 messages" -TLS_ERROR = "-ERR server side error start TLS handshake" -LOGOUT_COMPLETE = "+OK quit completed" -NOT_LOGGED_IN = "-ERR Unknown AUHORIZATION state command" -STAT = "+OK 0 0" -UIDL = "+OK Unique-ID listing follows\r\n." -LIST = "+OK Mailbox scan listing follows\r\n." -CAP_START = "+OK Capability list follows:" - - -class POP3TestServer(basic.LineReceiver): - def __init__(self, contextFactory = None): - self.loggedIn = False - self.caps = None - self.tmpUser = None - self.ctx = contextFactory - - def sendSTATResp(self, req): - self.sendLine(STAT) - - def sendUIDLResp(self, req): - self.sendLine(UIDL) - - def sendLISTResp(self, req): - self.sendLine(LIST) - - def sendCapabilities(self): - if self.caps is None: - self.caps = [CAP_START] - - if UIDL_SUPPORT: - self.caps.append(CAPABILITIES_UIDL) - - if SSL_SUPPORT: - self.caps.append(CAPABILITIES_SSL) - - for cap in CAPABILITIES: - self.caps.append(cap) - resp = '\r\n'.join(self.caps) - resp += "\r\n." - - self.sendLine(resp) - - - def connectionMade(self): - if DENY_CONNECTION: - self.disconnect() - return - - if SLOW_GREETING: - reactor.callLater(20, self.sendGreeting) - - else: - self.sendGreeting() - - def sendGreeting(self): - self.sendLine(CONNECTION_MADE) - - def lineReceived(self, line): - """Error Conditions""" - - uline = line.upper() - find = lambda s: uline.find(s) != -1 - - if TIMEOUT_RESPONSE: - # Do not respond to clients request - return - - if DROP_CONNECTION: - self.disconnect() - return - - elif find("CAPA"): - if INVALID_CAPABILITY_RESPONSE: - self.sendLine(INVALID_RESPONSE) - else: - self.sendCapabilities() - - elif find("STLS") and SSL_SUPPORT: - self.startTLS() - - elif find("USER"): - if INVALID_LOGIN_RESPONSE: - self.sendLine(INVALID_RESPONSE) - return - - resp = None - try: - self.tmpUser = line.split(" ")[1] - resp = VALID_RESPONSE - except: - resp = AUTH_DECLINED - - self.sendLine(resp) - - elif find("PASS"): - resp = None - try: - pwd = line.split(" ")[1] - - if self.tmpUser is None or pwd is None: - resp = AUTH_DECLINED - elif self.tmpUser == USER and pwd == PASS: - resp = AUTH_ACCEPTED - self.loggedIn = True - else: - resp = AUTH_DECLINED - except: - resp = AUTH_DECLINED - - self.sendLine(resp) - - elif find("QUIT"): - self.loggedIn = False - self.sendLine(LOGOUT_COMPLETE) - self.disconnect() - - elif INVALID_SERVER_RESPONSE: - self.sendLine(INVALID_RESPONSE) - - elif not self.loggedIn: - self.sendLine(NOT_LOGGED_IN) - - elif find("NOOP"): - self.sendLine(VALID_RESPONSE) - - elif find("STAT"): - if TIMEOUT_DEFERRED: - return - self.sendLine(STAT) - - elif find("LIST"): - if TIMEOUT_DEFERRED: - return - self.sendLine(LIST) - - elif find("UIDL"): - if TIMEOUT_DEFERRED: - return - elif not UIDL_SUPPORT: - self.sendLine(INVALID_RESPONSE) - return - - self.sendLine(UIDL) - - def startTLS(self): - if self.ctx is None: - self.getContext() - - if SSL_SUPPORT and self.ctx is not None: - self.sendLine('+OK Begin TLS negotiation now') - self.transport.startTLS(self.ctx) - else: - self.sendLine('-ERR TLS not available') - - def disconnect(self): - self.transport.loseConnection() - - def getContext(self): - try: - from twisted.internet import ssl - except ImportError: - self.ctx = None - else: - self.ctx = ssl.ClientContextFactory() - self.ctx.method = ssl.SSL.TLSv1_METHOD - - -usage = """popServer.py [arg] (default is Standard POP Server with no messages) -no_ssl - Start with no SSL support -no_uidl - Start with no UIDL support -bad_resp - Send a non-RFC compliant response to the Client -bad_cap_resp - send a non-RFC compliant response when the Client sends a 'CAPABILITY' request -bad_login_resp - send a non-RFC compliant response when the Client sends a 'LOGIN' request -deny - Deny the connection -drop - Drop the connection after sending the greeting -bad_tls - Send a bad response to a STARTTLS -timeout - Do not return a response to a Client request -to_deferred - Do not return a response on a 'Select' request. This - will test Deferred callback handling -slow - Wait 20 seconds after the connection is made to return a Server Greeting -""" - -def printMessage(msg): - print "Server Starting in %s mode" % msg - -def processArg(arg): - - if arg.lower() == 'no_ssl': - global SSL_SUPPORT - SSL_SUPPORT = False - printMessage("NON-SSL") - - elif arg.lower() == 'no_uidl': - global UIDL_SUPPORT - UIDL_SUPPORT = False - printMessage("NON-UIDL") - - elif arg.lower() == 'bad_resp': - global INVALID_SERVER_RESPONSE - INVALID_SERVER_RESPONSE = True - printMessage("Invalid Server Response") - - elif arg.lower() == 'bad_cap_resp': - global INVALID_CAPABILITY_RESPONSE - INVALID_CAPABILITY_RESPONSE = True - printMessage("Invalid Capability Response") - - elif arg.lower() == 'bad_login_resp': - global INVALID_LOGIN_RESPONSE - INVALID_LOGIN_RESPONSE = True - printMessage("Invalid Capability Response") - - elif arg.lower() == 'deny': - global DENY_CONNECTION - DENY_CONNECTION = True - printMessage("Deny Connection") - - elif arg.lower() == 'drop': - global DROP_CONNECTION - DROP_CONNECTION = True - printMessage("Drop Connection") - - - elif arg.lower() == 'bad_tls': - global BAD_TLS_RESPONSE - BAD_TLS_RESPONSE = True - printMessage("Bad TLS Response") - - elif arg.lower() == 'timeout': - global TIMEOUT_RESPONSE - TIMEOUT_RESPONSE = True - printMessage("Timeout Response") - - elif arg.lower() == 'to_deferred': - global TIMEOUT_DEFERRED - TIMEOUT_DEFERRED = True - printMessage("Timeout Deferred Response") - - elif arg.lower() == 'slow': - global SLOW_GREETING - SLOW_GREETING = True - printMessage("Slow Greeting") - - elif arg.lower() == '--help': - print usage - sys.exit() - - else: - print usage - sys.exit() - -def main(): - - if len(sys.argv) < 2: - printMessage("POP3 with no messages") - else: - args = sys.argv[1:] - - for arg in args: - processArg(arg) - - f = Factory() - f.protocol = POP3TestServer - reactor.listenTCP(PORT, f) - reactor.run() - -if __name__ == '__main__': - main() diff --git a/tools/buildbot/pylibs/twisted/mail/test/rfc822.message b/tools/buildbot/pylibs/twisted/mail/test/rfc822.message deleted file mode 100644 index ee97ab9..0000000 --- a/tools/buildbot/pylibs/twisted/mail/test/rfc822.message +++ /dev/null @@ -1,86 +0,0 @@ -Return-Path: -Delivered-To: exarkun@meson.dyndns.org -Received: from localhost [127.0.0.1] - by localhost with POP3 (fetchmail-6.2.1) - for exarkun@localhost (single-drop); Thu, 20 Mar 2003 14:50:20 -0500 (EST) -Received: from pyramid.twistedmatrix.com (adsl-64-123-27-105.dsl.austtx.swbell.net [64.123.27.105]) - by intarweb.us (Postfix) with ESMTP id 4A4A513EA4 - for ; Thu, 20 Mar 2003 14:49:27 -0500 (EST) -Received: from localhost ([127.0.0.1] helo=pyramid.twistedmatrix.com) - by pyramid.twistedmatrix.com with esmtp (Exim 3.35 #1 (Debian)) - id 18w648-0007Vl-00; Thu, 20 Mar 2003 13:51:04 -0600 -Received: from acapnotic by pyramid.twistedmatrix.com with local (Exim 3.35 #1 (Debian)) - id 18w63j-0007VK-00 - for ; Thu, 20 Mar 2003 13:50:39 -0600 -To: twisted-commits@twistedmatrix.com -From: etrepum CVS -Reply-To: twisted-python@twistedmatrix.com -X-Mailer: CVSToys -Message-Id: -Subject: [Twisted-commits] rebuild now works on python versions from 2.2.0 and up. -Sender: twisted-commits-admin@twistedmatrix.com -Errors-To: twisted-commits-admin@twistedmatrix.com -X-BeenThere: twisted-commits@twistedmatrix.com -X-Mailman-Version: 2.0.11 -Precedence: bulk -List-Help: -List-Post: -List-Subscribe: , - -List-Id: -List-Unsubscribe: , - -List-Archive: -Date: Thu, 20 Mar 2003 13:50:39 -0600 - -Modified files: -Twisted/twisted/python/rebuild.py 1.19 1.20 - -Log message: -rebuild now works on python versions from 2.2.0 and up. - - -ViewCVS links: -http://twistedmatrix.com/users/jh.twistd/viewcvs/cgi/viewcvs.cgi/twisted/python/rebuild.py.diff?r1=text&tr1=1.19&r2=text&tr2=1.20&cvsroot=Twisted - -Index: Twisted/twisted/python/rebuild.py -diff -u Twisted/twisted/python/rebuild.py:1.19 Twisted/twisted/python/rebuild.py:1.20 ---- Twisted/twisted/python/rebuild.py:1.19 Fri Jan 17 13:50:49 2003 -+++ Twisted/twisted/python/rebuild.py Thu Mar 20 11:50:08 2003 -@@ -206,15 +206,27 @@ - clazz.__dict__.clear() - clazz.__getattr__ = __getattr__ - clazz.__module__ = module.__name__ -+ if newclasses: -+ import gc -+ if (2, 2, 0) <= sys.version_info[:3] < (2, 2, 2): -+ hasBrokenRebuild = 1 -+ gc_objects = gc.get_objects() -+ else: -+ hasBrokenRebuild = 0 - for nclass in newclasses: - ga = getattr(module, nclass.__name__) - if ga is nclass: - log.msg("WARNING: new-class %s not replaced by reload!" % reflect.qual(nclass)) - else: -- import gc -- for r in gc.get_referrers(nclass): -- if isinstance(r, nclass): -+ if hasBrokenRebuild: -+ for r in gc_objects: -+ if not getattr(r, '__class__', None) is nclass: -+ continue - r.__class__ = ga -+ else: -+ for r in gc.get_referrers(nclass): -+ if getattr(r, '__class__', None) is nclass: -+ r.__class__ = ga - if doLog: - log.msg('') - log.msg(' (fixing %s): ' % str(module.__name__)) - - -_______________________________________________ -Twisted-commits mailing list -Twisted-commits@twistedmatrix.com -http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-commits diff --git a/tools/buildbot/pylibs/twisted/mail/test/test_bounce.py b/tools/buildbot/pylibs/twisted/mail/test/test_bounce.py deleted file mode 100644 index ece9281..0000000 --- a/tools/buildbot/pylibs/twisted/mail/test/test_bounce.py +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Test cases for bounce message generation -""" - -from twisted.trial import unittest -from twisted.mail import bounce -import rfc822, cStringIO - -class BounceTestCase(unittest.TestCase): - """ - testcases for bounce message generation - """ - - def testBounceFormat(self): - from_, to, s = bounce.generateBounce(cStringIO.StringIO('''\ -From: Moshe Zadka -To: nonexistant@example.org -Subject: test - -'''), 'moshez@example.com', 'nonexistant@example.org') - self.assertEquals(from_, '') - self.assertEquals(to, 'moshez@example.com') - mess = rfc822.Message(cStringIO.StringIO(s)) - self.assertEquals(mess['To'], 'moshez@example.com') - self.assertEquals(mess['From'], 'postmaster@example.org') - self.assertEquals(mess['subject'], 'Returned Mail: see transcript for details') - - def testBounceMIME(self): - pass diff --git a/tools/buildbot/pylibs/twisted/mail/test/test_imap.py b/tools/buildbot/pylibs/twisted/mail/test/test_imap.py deleted file mode 100644 index 6d11e1e..0000000 --- a/tools/buildbot/pylibs/twisted/mail/test/test_imap.py +++ /dev/null @@ -1,3040 +0,0 @@ -# -*- test-case-name: twisted.mail.test.test_imap -*- -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Test case for twisted.mail.imap4 -""" - -try: - from cStringIO import StringIO -except ImportError: - from StringIO import StringIO - -import os -import types - -from zope.interface import implements - -from twisted.mail.imap4 import MessageSet -from twisted.mail import imap4 -from twisted.protocols import loopback -from twisted.internet import defer -from twisted.internet import error -from twisted.internet import reactor -from twisted.internet import interfaces -from twisted.internet.task import Clock -from twisted.trial import unittest -from twisted.python import util -from twisted.python import failure - -from twisted import cred -import twisted.cred.error -import twisted.cred.checkers -import twisted.cred.credentials -import twisted.cred.portal - -from twisted.test.proto_helpers import StringTransport, StringTransportWithDisconnection - -try: - from twisted.test.ssl_helpers import ClientTLSContext, ServerTLSContext -except ImportError: - ClientTLSContext = ServerTLSContext = None - -def strip(f): - return lambda result, f=f: f() - -def sortNest(l): - l = l[:] - l.sort() - for i in range(len(l)): - if isinstance(l[i], types.ListType): - l[i] = sortNest(l[i]) - elif isinstance(l[i], types.TupleType): - l[i] = tuple(sortNest(list(l[i]))) - return l - -class IMAP4UTF7TestCase(unittest.TestCase): - tests = [ - [u'Hello world', 'Hello world'], - [u'Hello & world', 'Hello &- world'], - [u'Hello\xffworld', 'Hello&AP8-world'], - [u'\xff\xfe\xfd\xfc', '&AP8A,gD9APw-'], - [u'~peter/mail/\u65e5\u672c\u8a9e/\u53f0\u5317', - '~peter/mail/&ZeVnLIqe-/&U,BTFw-'], # example from RFC 2060 - ] - - def test_encodeWithErrors(self): - """ - Specifying an error policy to C{unicode.encode} with the - I{imap4-utf-7} codec should produce the same result as not - specifying the error policy. - """ - text = u'Hello world' - self.assertEqual( - text.encode('imap4-utf-7', 'strict'), - text.encode('imap4-utf-7')) - - - def test_decodeWithErrors(self): - """ - Similar to L{test_encodeWithErrors}, but for C{str.decode}. - """ - bytes = 'Hello world' - self.assertEqual( - bytes.decode('imap4-utf-7', 'strict'), - bytes.decode('imap4-utf-7')) - - - def testEncode(self): - for (input, output) in self.tests: - self.assertEquals(input.encode('imap4-utf-7'), output) - - def testDecode(self): - for (input, output) in self.tests: - # XXX - Piece of *crap* 2.1 - self.assertEquals(input, imap4.decoder(output)[0]) - - def testPrintableSingletons(self): - # All printables represent themselves - for o in range(0x20, 0x26) + range(0x27, 0x7f): - self.failUnlessEqual(chr(o), chr(o).encode('imap4-utf-7')) - self.failUnlessEqual(chr(o), chr(o).decode('imap4-utf-7')) - self.failUnlessEqual('&'.encode('imap4-utf-7'), '&-') - self.failUnlessEqual('&-'.decode('imap4-utf-7'), '&') - -class BufferingConsumer: - def __init__(self): - self.buffer = [] - - def write(self, bytes): - self.buffer.append(bytes) - if self.consumer: - self.consumer.resumeProducing() - - def registerProducer(self, consumer, streaming): - self.consumer = consumer - self.consumer.resumeProducing() - - def unregisterProducer(self): - self.consumer = None - -class MessageProducerTestCase(unittest.TestCase): - def testSinglePart(self): - body = 'This is body text. Rar.' - headers = util.OrderedDict() - headers['from'] = 'sender@host' - headers['to'] = 'recipient@domain' - headers['subject'] = 'booga booga boo' - headers['content-type'] = 'text/plain' - - msg = FakeyMessage(headers, (), None, body, 123, None ) - - c = BufferingConsumer() - p = imap4.MessageProducer(msg) - d = p.beginProducing(c) - - def cbProduced(result): - self.assertIdentical(result, p) - self.assertEquals( - ''.join(c.buffer), - - '{119}\r\n' - 'From: sender@host\r\n' - 'To: recipient@domain\r\n' - 'Subject: booga booga boo\r\n' - 'Content-Type: text/plain\r\n' - '\r\n' - + body) - return d.addCallback(cbProduced) - - - def testSingleMultiPart(self): - outerBody = '' - innerBody = 'Contained body message text. Squarge.' - headers = util.OrderedDict() - headers['from'] = 'sender@host' - headers['to'] = 'recipient@domain' - headers['subject'] = 'booga booga boo' - headers['content-type'] = 'multipart/alternative; boundary="xyz"' - - innerHeaders = util.OrderedDict() - innerHeaders['subject'] = 'this is subject text' - innerHeaders['content-type'] = 'text/plain' - msg = FakeyMessage(headers, (), None, outerBody, 123, - [FakeyMessage(innerHeaders, (), None, innerBody, - None, None)], - ) - - c = BufferingConsumer() - p = imap4.MessageProducer(msg) - d = p.beginProducing(c) - - def cbProduced(result): - self.failUnlessIdentical(result, p) - - self.assertEquals( - ''.join(c.buffer), - - '{239}\r\n' - 'From: sender@host\r\n' - 'To: recipient@domain\r\n' - 'Subject: booga booga boo\r\n' - 'Content-Type: multipart/alternative; boundary="xyz"\r\n' - '\r\n' - '\r\n' - '--xyz\r\n' - 'Subject: this is subject text\r\n' - 'Content-Type: text/plain\r\n' - '\r\n' - + innerBody - + '\r\n--xyz--\r\n') - - return d.addCallback(cbProduced) - - - def testMultipleMultiPart(self): - outerBody = '' - innerBody1 = 'Contained body message text. Squarge.' - innerBody2 = 'Secondary message text of squarge body.' - headers = util.OrderedDict() - headers['from'] = 'sender@host' - headers['to'] = 'recipient@domain' - headers['subject'] = 'booga booga boo' - headers['content-type'] = 'multipart/alternative; boundary="xyz"' - innerHeaders = util.OrderedDict() - innerHeaders['subject'] = 'this is subject text' - innerHeaders['content-type'] = 'text/plain' - innerHeaders2 = util.OrderedDict() - innerHeaders2['subject'] = 'this is subject' - innerHeaders2['content-type'] = 'text/html' - msg = FakeyMessage(headers, (), None, outerBody, 123, [ - FakeyMessage(innerHeaders, (), None, innerBody1, None, None), - FakeyMessage(innerHeaders2, (), None, innerBody2, None, None) - ], - ) - - c = BufferingConsumer() - p = imap4.MessageProducer(msg) - d = p.beginProducing(c) - - def cbProduced(result): - self.failUnlessIdentical(result, p) - - self.assertEquals( - ''.join(c.buffer), - - '{354}\r\n' - 'From: sender@host\r\n' - 'To: recipient@domain\r\n' - 'Subject: booga booga boo\r\n' - 'Content-Type: multipart/alternative; boundary="xyz"\r\n' - '\r\n' - '\r\n' - '--xyz\r\n' - 'Subject: this is subject text\r\n' - 'Content-Type: text/plain\r\n' - '\r\n' - + innerBody1 - + '\r\n--xyz\r\n' - 'Subject: this is subject\r\n' - 'Content-Type: text/html\r\n' - '\r\n' - + innerBody2 - + '\r\n--xyz--\r\n') - return d.addCallback(cbProduced) - - -class IMAP4HelperTestCase(unittest.TestCase): - def testFileProducer(self): - b = (('x' * 1) + ('y' * 1) + ('z' * 1)) * 10 - c = BufferingConsumer() - f = StringIO(b) - p = imap4.FileProducer(f) - d = p.beginProducing(c) - - def cbProduced(result): - self.failUnlessIdentical(result, p) - self.assertEquals( - ('{%d}\r\n' % len(b))+ b, - ''.join(c.buffer)) - return d.addCallback(cbProduced) - - def testWildcard(self): - cases = [ - ['foo/%gum/bar', - ['foo/bar', 'oo/lalagum/bar', 'foo/gumx/bar', 'foo/gum/baz'], - ['foo/xgum/bar', 'foo/gum/bar'], - ], ['foo/x%x/bar', - ['foo', 'bar', 'fuz fuz fuz', 'foo/*/bar', 'foo/xyz/bar', 'foo/xx/baz'], - ['foo/xyx/bar', 'foo/xx/bar', 'foo/xxxxxxxxxxxxxx/bar'], - ], ['foo/xyz*abc/bar', - ['foo/xyz/bar', 'foo/abc/bar', 'foo/xyzab/cbar', 'foo/xyza/bcbar'], - ['foo/xyzabc/bar', 'foo/xyz/abc/bar', 'foo/xyz/123/abc/bar'], - ] - ] - - for (wildcard, fail, succeed) in cases: - wildcard = imap4.wildcardToRegexp(wildcard, '/') - for x in fail: - self.failIf(wildcard.match(x)) - for x in succeed: - self.failUnless(wildcard.match(x)) - - def testWildcardNoDelim(self): - cases = [ - ['foo/%gum/bar', - ['foo/bar', 'oo/lalagum/bar', 'foo/gumx/bar', 'foo/gum/baz'], - ['foo/xgum/bar', 'foo/gum/bar', 'foo/x/gum/bar'], - ], ['foo/x%x/bar', - ['foo', 'bar', 'fuz fuz fuz', 'foo/*/bar', 'foo/xyz/bar', 'foo/xx/baz'], - ['foo/xyx/bar', 'foo/xx/bar', 'foo/xxxxxxxxxxxxxx/bar', 'foo/x/x/bar'], - ], ['foo/xyz*abc/bar', - ['foo/xyz/bar', 'foo/abc/bar', 'foo/xyzab/cbar', 'foo/xyza/bcbar'], - ['foo/xyzabc/bar', 'foo/xyz/abc/bar', 'foo/xyz/123/abc/bar'], - ] - ] - - for (wildcard, fail, succeed) in cases: - wildcard = imap4.wildcardToRegexp(wildcard, None) - for x in fail: - self.failIf(wildcard.match(x), x) - for x in succeed: - self.failUnless(wildcard.match(x), x) - - def testHeaderFormatter(self): - cases = [ - ({'Header1': 'Value1', 'Header2': 'Value2'}, 'Header2: Value2\r\nHeader1: Value1\r\n'), - ] - - for (input, output) in cases: - self.assertEquals(imap4._formatHeaders(input), output) - - def testMessageSet(self): - m1 = MessageSet() - m2 = MessageSet() - - self.assertEquals(m1, m2) - - m1 = m1 + (1, 3) - self.assertEquals(len(m1), 3) - self.assertEquals(list(m1), [1, 2, 3]) - - m2 = m2 + (1, 3) - self.assertEquals(m1, m2) - self.assertEquals(list(m1 + m2), [1, 2, 3]) - - def testQuotedSplitter(self): - cases = [ - '''Hello World''', - '''Hello "World!"''', - '''World "Hello" "How are you?"''', - '''"Hello world" How "are you?"''', - '''foo bar "baz buz" NIL''', - '''foo bar "baz buz" "NIL"''', - '''foo NIL "baz buz" bar''', - '''foo "NIL" "baz buz" bar''', - '''"NIL" bar "baz buz" foo''', - ] - - answers = [ - ['Hello', 'World'], - ['Hello', 'World!'], - ['World', 'Hello', 'How are you?'], - ['Hello world', 'How', 'are you?'], - ['foo', 'bar', 'baz buz', None], - ['foo', 'bar', 'baz buz', 'NIL'], - ['foo', None, 'baz buz', 'bar'], - ['foo', 'NIL', 'baz buz', 'bar'], - ['NIL', 'bar', 'baz buz', 'foo'], - ] - - errors = [ - '"mismatched quote', - 'mismatched quote"', - 'mismatched"quote', - '"oops here is" another"', - ] - - for s in errors: - self.assertRaises(imap4.MismatchedQuoting, imap4.splitQuoted, s) - - for (case, expected) in zip(cases, answers): - self.assertEquals(imap4.splitQuoted(case), expected) - - - def testStringCollapser(self): - cases = [ - ['a', 'b', 'c', 'd', 'e'], - ['a', ' ', '"', 'b', 'c', ' ', '"', ' ', 'd', 'e'], - [['a', 'b', 'c'], 'd', 'e'], - ['a', ['b', 'c', 'd'], 'e'], - ['a', 'b', ['c', 'd', 'e']], - ['"', 'a', ' ', '"', ['b', 'c', 'd'], '"', ' ', 'e', '"'], - ['a', ['"', ' ', 'b', 'c', ' ', ' ', '"'], 'd', 'e'], - ] - - answers = [ - ['abcde'], - ['a', 'bc ', 'de'], - [['abc'], 'de'], - ['a', ['bcd'], 'e'], - ['ab', ['cde']], - ['a ', ['bcd'], ' e'], - ['a', [' bc '], 'de'], - ] - - for (case, expected) in zip(cases, answers): - self.assertEquals(imap4.collapseStrings(case), expected) - - def testParenParser(self): - s = '\r\n'.join(['xx'] * 4) - cases = [ - '(BODY.PEEK[HEADER.FIELDS.NOT (subject bcc cc)] {%d}\r\n%s)' % (len(s), s,), - -# '(FLAGS (\Seen) INTERNALDATE "17-Jul-1996 02:44:25 -0700" ' -# 'RFC822.SIZE 4286 ENVELOPE ("Wed, 17 Jul 1996 02:23:25 -0700 (PDT)" ' -# '"IMAP4rev1 WG mtg summary and minutes" ' -# '(("Terry Gray" NIL "gray" "cac.washington.edu")) ' -# '(("Terry Gray" NIL "gray" "cac.washington.edu")) ' -# '(("Terry Gray" NIL "gray" "cac.washington.edu")) ' -# '((NIL NIL "imap" "cac.washington.edu")) ' -# '((NIL NIL "minutes" "CNRI.Reston.VA.US") ' -# '("John Klensin" NIL "KLENSIN" "INFOODS.MIT.EDU")) NIL NIL ' -# '"") ' -# 'BODY ("TEXT" "PLAIN" ("CHARSET" "US-ASCII") NIL NIL "7BIT" 3028 92))', - - '(FLAGS (\Seen) INTERNALDATE "17-Jul-1996 02:44:25 -0700" ' - 'RFC822.SIZE 4286 ENVELOPE ("Wed, 17 Jul 1996 02:23:25 -0700 (PDT)" ' - '"IMAP4rev1 WG mtg summary and minutes" ' - '(("Terry Gray" NIL gray cac.washington.edu)) ' - '(("Terry Gray" NIL gray cac.washington.edu)) ' - '(("Terry Gray" NIL gray cac.washington.edu)) ' - '((NIL NIL imap cac.washington.edu)) ' - '((NIL NIL minutes CNRI.Reston.VA.US) ' - '("John Klensin" NIL KLENSIN INFOODS.MIT.EDU)) NIL NIL ' - ') ' - 'BODY (TEXT PLAIN (CHARSET US-ASCII) NIL NIL 7BIT 3028 92))', - ] - - answers = [ - ['BODY.PEEK', ['HEADER.FIELDS.NOT', ['subject', 'bcc', 'cc']], s], - - ['FLAGS', [r'\Seen'], 'INTERNALDATE', - '17-Jul-1996 02:44:25 -0700', 'RFC822.SIZE', '4286', 'ENVELOPE', - ['Wed, 17 Jul 1996 02:23:25 -0700 (PDT)', - 'IMAP4rev1 WG mtg summary and minutes', [["Terry Gray", None, - "gray", "cac.washington.edu"]], [["Terry Gray", None, - "gray", "cac.washington.edu"]], [["Terry Gray", None, - "gray", "cac.washington.edu"]], [[None, None, "imap", - "cac.washington.edu"]], [[None, None, "minutes", - "CNRI.Reston.VA.US"], ["John Klensin", None, "KLENSIN", - "INFOODS.MIT.EDU"]], None, None, - ""], "BODY", ["TEXT", "PLAIN", - ["CHARSET", "US-ASCII"], None, None, "7BIT", "3028", "92"]], - ] - - for (case, expected) in zip(cases, answers): - self.assertEquals(imap4.parseNestedParens(case), [expected]) - - # XXX This code used to work, but changes occurred within the - # imap4.py module which made it no longer necessary for *all* of it - # to work. In particular, only the part that makes - # 'BODY.PEEK[HEADER.FIELDS.NOT (Subject Bcc Cc)]' come out correctly - # no longer needs to work. So, I am loathe to delete the entire - # section of the test. --exarkun - # - -# for (case, expected) in zip(answers, cases): -# self.assertEquals('(' + imap4.collapseNestedLists(case) + ')', expected) - - def testFetchParserSimple(self): - cases = [ - ['ENVELOPE', 'Envelope'], - ['FLAGS', 'Flags'], - ['INTERNALDATE', 'InternalDate'], - ['RFC822.HEADER', 'RFC822Header'], - ['RFC822.SIZE', 'RFC822Size'], - ['RFC822.TEXT', 'RFC822Text'], - ['RFC822', 'RFC822'], - ['UID', 'UID'], - ['BODYSTRUCTURE', 'BodyStructure'], - ] - - for (inp, outp) in cases: - p = imap4._FetchParser() - p.parseString(inp) - self.assertEquals(len(p.result), 1) - self.failUnless(isinstance(p.result[0], getattr(p, outp))) - - def testFetchParserMacros(self): - cases = [ - ['ALL', (4, ['flags', 'internaldate', 'rfc822.size', 'envelope'])], - ['FULL', (5, ['flags', 'internaldate', 'rfc822.size', 'envelope', 'body'])], - ['FAST', (3, ['flags', 'internaldate', 'rfc822.size'])], - ] - - for (inp, outp) in cases: - p = imap4._FetchParser() - p.parseString(inp) - self.assertEquals(len(p.result), outp[0]) - p = [str(p).lower() for p in p.result] - p.sort() - outp[1].sort() - self.assertEquals(p, outp[1]) - - def testFetchParserBody(self): - P = imap4._FetchParser - - p = P() - p.parseString('BODY') - self.assertEquals(len(p.result), 1) - self.failUnless(isinstance(p.result[0], p.Body)) - self.assertEquals(p.result[0].peek, False) - self.assertEquals(p.result[0].header, None) - self.assertEquals(str(p.result[0]), 'BODY') - - p = P() - p.parseString('BODY.PEEK') - self.assertEquals(len(p.result), 1) - self.failUnless(isinstance(p.result[0], p.Body)) - self.assertEquals(p.result[0].peek, True) - self.assertEquals(str(p.result[0]), 'BODY') - - p = P() - p.parseString('BODY[]') - self.assertEquals(len(p.result), 1) - self.failUnless(isinstance(p.result[0], p.Body)) - self.assertEquals(p.result[0].empty, True) - self.assertEquals(str(p.result[0]), 'BODY[]') - - p = P() - p.parseString('BODY[HEADER]') - self.assertEquals(len(p.result), 1) - self.failUnless(isinstance(p.result[0], p.Body)) - self.assertEquals(p.result[0].peek, False) - self.failUnless(isinstance(p.result[0].header, p.Header)) - self.assertEquals(p.result[0].header.negate, True) - self.assertEquals(p.result[0].header.fields, ()) - self.assertEquals(p.result[0].empty, False) - self.assertEquals(str(p.result[0]), 'BODY[HEADER]') - - p = P() - p.parseString('BODY.PEEK[HEADER]') - self.assertEquals(len(p.result), 1) - self.failUnless(isinstance(p.result[0], p.Body)) - self.assertEquals(p.result[0].peek, True) - self.failUnless(isinstance(p.result[0].header, p.Header)) - self.assertEquals(p.result[0].header.negate, True) - self.assertEquals(p.result[0].header.fields, ()) - self.assertEquals(p.result[0].empty, False) - self.assertEquals(str(p.result[0]), 'BODY[HEADER]') - - p = P() - p.parseString('BODY[HEADER.FIELDS (Subject Cc Message-Id)]') - self.assertEquals(len(p.result), 1) - self.failUnless(isinstance(p.result[0], p.Body)) - self.assertEquals(p.result[0].peek, False) - self.failUnless(isinstance(p.result[0].header, p.Header)) - self.assertEquals(p.result[0].header.negate, False) - self.assertEquals(p.result[0].header.fields, ['SUBJECT', 'CC', 'MESSAGE-ID']) - self.assertEquals(p.result[0].empty, False) - self.assertEquals(str(p.result[0]), 'BODY[HEADER.FIELDS (Subject Cc Message-Id)]') - - p = P() - p.parseString('BODY.PEEK[HEADER.FIELDS (Subject Cc Message-Id)]') - self.assertEquals(len(p.result), 1) - self.failUnless(isinstance(p.result[0], p.Body)) - self.assertEquals(p.result[0].peek, True) - self.failUnless(isinstance(p.result[0].header, p.Header)) - self.assertEquals(p.result[0].header.negate, False) - self.assertEquals(p.result[0].header.fields, ['SUBJECT', 'CC', 'MESSAGE-ID']) - self.assertEquals(p.result[0].empty, False) - self.assertEquals(str(p.result[0]), 'BODY[HEADER.FIELDS (Subject Cc Message-Id)]') - - p = P() - p.parseString('BODY.PEEK[HEADER.FIELDS.NOT (Subject Cc Message-Id)]') - self.assertEquals(len(p.result), 1) - self.failUnless(isinstance(p.result[0], p.Body)) - self.assertEquals(p.result[0].peek, True) - self.failUnless(isinstance(p.result[0].header, p.Header)) - self.assertEquals(p.result[0].header.negate, True) - self.assertEquals(p.result[0].header.fields, ['SUBJECT', 'CC', 'MESSAGE-ID']) - self.assertEquals(p.result[0].empty, False) - self.assertEquals(str(p.result[0]), 'BODY[HEADER.FIELDS.NOT (Subject Cc Message-Id)]') - - p = P() - p.parseString('BODY[1.MIME]<10.50>') - self.assertEquals(len(p.result), 1) - self.failUnless(isinstance(p.result[0], p.Body)) - self.assertEquals(p.result[0].peek, False) - self.failUnless(isinstance(p.result[0].mime, p.MIME)) - self.assertEquals(p.result[0].part, (0,)) - self.assertEquals(p.result[0].partialBegin, 10) - self.assertEquals(p.result[0].partialLength, 50) - self.assertEquals(p.result[0].empty, False) - self.assertEquals(str(p.result[0]), 'BODY[1.MIME]<10.50>') - - p = P() - p.parseString('BODY.PEEK[1.3.9.11.HEADER.FIELDS.NOT (Message-Id Date)]<103.69>') - self.assertEquals(len(p.result), 1) - self.failUnless(isinstance(p.result[0], p.Body)) - self.assertEquals(p.result[0].peek, True) - self.failUnless(isinstance(p.result[0].header, p.Header)) - self.assertEquals(p.result[0].part, (0, 2, 8, 10)) - self.assertEquals(p.result[0].header.fields, ['MESSAGE-ID', 'DATE']) - self.assertEquals(p.result[0].partialBegin, 103) - self.assertEquals(p.result[0].partialLength, 69) - self.assertEquals(p.result[0].empty, False) - self.assertEquals(str(p.result[0]), 'BODY[1.3.9.11.HEADER.FIELDS.NOT (Message-Id Date)]<103.69>') - - - def testFiles(self): - inputStructure = [ - 'foo', 'bar', 'baz', StringIO('this is a file\r\n'), 'buz' - ] - - output = '"foo" "bar" "baz" {16}\r\nthis is a file\r\n "buz"' - - self.assertEquals(imap4.collapseNestedLists(inputStructure), output) - - def testQuoteAvoider(self): - input = [ - 'foo', imap4.DontQuoteMe('bar'), "baz", StringIO('this is a file\r\n'), - imap4.DontQuoteMe('buz'), "" - ] - - output = '"foo" bar "baz" {16}\r\nthis is a file\r\n buz ""' - - self.assertEquals(imap4.collapseNestedLists(input), output) - - def testLiterals(self): - cases = [ - ('({10}\r\n0123456789)', [['0123456789']]), - ] - - for (case, expected) in cases: - self.assertEquals(imap4.parseNestedParens(case), expected) - - def testQueryBuilder(self): - inputs = [ - imap4.Query(flagged=1), - imap4.Query(sorted=1, unflagged=1, deleted=1), - imap4.Or(imap4.Query(flagged=1), imap4.Query(deleted=1)), - imap4.Query(before='today'), - imap4.Or( - imap4.Query(deleted=1), - imap4.Query(unseen=1), - imap4.Query(new=1) - ), - imap4.Or( - imap4.Not( - imap4.Or( - imap4.Query(sorted=1, since='yesterday', smaller=1000), - imap4.Query(sorted=1, before='tuesday', larger=10000), - imap4.Query(sorted=1, unseen=1, deleted=1, before='today'), - imap4.Not( - imap4.Query(subject='spam') - ), - ), - ), - imap4.Not( - imap4.Query(uid='1:5') - ), - ) - ] - - outputs = [ - 'FLAGGED', - '(DELETED UNFLAGGED)', - '(OR FLAGGED DELETED)', - '(BEFORE "today")', - '(OR DELETED (OR UNSEEN NEW))', - '(OR (NOT (OR (SINCE "yesterday" SMALLER 1000) ' # Continuing - '(OR (BEFORE "tuesday" LARGER 10000) (OR (BEFORE ' # Some more - '"today" DELETED UNSEEN) (NOT (SUBJECT "spam")))))) ' # And more - '(NOT (UID 1:5)))', - ] - - for (query, expected) in zip(inputs, outputs): - self.assertEquals(query, expected) - - def testIdListParser(self): - inputs = [ - '1:*', - '5:*', - '1:2,5:*', - '1', - '1,2', - '1,3,5', - '1:10', - '1:10,11', - '1:5,10:20', - '1,5:10', - '1,5:10,15:20', - '1:10,15,20:25', - ] - - outputs = [ - MessageSet(1, None), - MessageSet(5, None), - MessageSet(5, None) + MessageSet(1, 2), - MessageSet(1), - MessageSet(1, 2), - MessageSet(1) + MessageSet(3) + MessageSet(5), - MessageSet(1, 10), - MessageSet(1, 11), - MessageSet(1, 5) + MessageSet(10, 20), - MessageSet(1) + MessageSet(5, 10), - MessageSet(1) + MessageSet(5, 10) + MessageSet(15, 20), - MessageSet(1, 10) + MessageSet(15) + MessageSet(20, 25), - ] - - lengths = [ - None, None, None, - 1, 2, 3, 10, 11, 16, 7, 13, 17, - ] - - for (input, expected) in zip(inputs, outputs): - self.assertEquals(imap4.parseIdList(input), expected) - - for (input, expected) in zip(inputs, lengths): - try: - L = len(imap4.parseIdList(input)) - except TypeError: - L = None - self.assertEquals(L, expected, - "len(%r) = %r != %r" % (input, L, expected)) - -class SimpleMailbox: - implements(imap4.IMailboxInfo, imap4.IMailbox, imap4.ICloseableMailbox) - - flags = ('\\Flag1', 'Flag2', '\\AnotherSysFlag', 'LastFlag') - messages = [] - mUID = 0 - rw = 1 - closed = False - - def __init__(self): - self.listeners = [] - self.addListener = self.listeners.append - self.removeListener = self.listeners.remove - - def getFlags(self): - return self.flags - - def getUIDValidity(self): - return 42 - - def getUIDNext(self): - return len(self.messages) + 1 - - def getMessageCount(self): - return 9 - - def getRecentCount(self): - return 3 - - def getUnseenCount(self): - return 4 - - def isWriteable(self): - return self.rw - - def destroy(self): - pass - - def getHierarchicalDelimiter(self): - return '/' - - def requestStatus(self, names): - r = {} - if 'MESSAGES' in names: - r['MESSAGES'] = self.getMessageCount() - if 'RECENT' in names: - r['RECENT'] = self.getRecentCount() - if 'UIDNEXT' in names: - r['UIDNEXT'] = self.getMessageCount() + 1 - if 'UIDVALIDITY' in names: - r['UIDVALIDITY'] = self.getUID() - if 'UNSEEN' in names: - r['UNSEEN'] = self.getUnseenCount() - return defer.succeed(r) - - def addMessage(self, message, flags, date = None): - self.messages.append((message, flags, date, self.mUID)) - self.mUID += 1 - return defer.succeed(None) - - def expunge(self): - delete = [] - for i in self.messages: - if '\\Deleted' in i[1]: - delete.append(i) - for i in delete: - self.messages.remove(i) - return [i[3] for i in delete] - - def close(self): - self.closed = True - -class Account(imap4.MemoryAccount): - mailboxFactory = SimpleMailbox - def _emptyMailbox(self, name, id): - return self.mailboxFactory() - - def select(self, name, rw=1): - mbox = imap4.MemoryAccount.select(self, name) - if mbox is not None: - mbox.rw = rw - return mbox - -class SimpleServer(imap4.IMAP4Server): - def __init__(self, *args, **kw): - imap4.IMAP4Server.__init__(self, *args, **kw) - realm = TestRealm() - realm.theAccount = Account('testuser') - portal = cred.portal.Portal(realm) - c = cred.checkers.InMemoryUsernamePasswordDatabaseDontUse() - self.checker = c - self.portal = portal - portal.registerChecker(c) - self.timeoutTest = False - - def lineReceived(self, line): - if self.timeoutTest: - #Do not send a respones - return - - imap4.IMAP4Server.lineReceived(self, line) - - _username = 'testuser' - _password = 'password-test' - def authenticateLogin(self, username, password): - if username == self._username and password == self._password: - return imap4.IAccount, self.theAccount, lambda: None - raise cred.error.UnauthorizedLogin() - - -class SimpleClient(imap4.IMAP4Client): - def __init__(self, deferred, contextFactory = None): - imap4.IMAP4Client.__init__(self, contextFactory) - self.deferred = deferred - self.events = [] - - def serverGreeting(self, caps): - self.deferred.callback(None) - - def modeChanged(self, writeable): - self.events.append(['modeChanged', writeable]) - self.transport.loseConnection() - - def flagsChanged(self, newFlags): - self.events.append(['flagsChanged', newFlags]) - self.transport.loseConnection() - - def newMessages(self, exists, recent): - self.events.append(['newMessages', exists, recent]) - self.transport.loseConnection() - - def fetchBodyParts(self, message, parts): - """Fetch some parts of the body. - - @param message: message with parts to fetch - @type message: C{str} - @param parts: a list of int/str - @type parts: C{list} - """ - cmd = "%s (BODY[%s]" % (message, parts[0]) - for p in parts[1:]: - cmd += " BODY[%s]" % p - cmd += ")" - d = self.sendCommand(imap4.Command("FETCH", cmd, - wantResponse=("FETCH",))) - d.addCallback(self.__cb_fetchBodyParts) - return d - - def __cb_fetchBodyParts(self, (lines, last)): - info = {} - for line in lines: - parts = line.split(None, 2) - if len(parts) == 3: - if parts[1] == "FETCH": - try: - mail_id = int(parts[0]) - except ValueError: - raise imap4.IllegalServerResponse, line - else: - body_parts = imap4.parseNestedParens(parts[2])[0] - dict_parts = {} - for i in range(len(body_parts)/3): - dict_parts[body_parts[3*i+1][0]] = body_parts[3*i+2] - info[mail_id] = dict_parts - return info - -class IMAP4HelperMixin: - serverCTX = None - clientCTX = None - - def setUp(self): - d = defer.Deferred() - self.server = SimpleServer(contextFactory=self.serverCTX) - self.client = SimpleClient(d, contextFactory=self.clientCTX) - self.connected = d - - SimpleMailbox.messages = [] - theAccount = Account('testuser') - theAccount.mboxType = SimpleMailbox - SimpleServer.theAccount = theAccount - - def tearDown(self): - del self.server - del self.client - del self.connected - - def _cbStopClient(self, ignore): - self.client.transport.loseConnection() - - def _ebGeneral(self, failure): - self.client.transport.loseConnection() - self.server.transport.loseConnection() - failure.printTraceback(open('failure.log', 'w')) - failure.printTraceback() - raise failure.value - - def loopback(self): - return loopback.loopbackAsync(self.server, self.client) - -class IMAP4ServerTestCase(IMAP4HelperMixin, unittest.TestCase): - def testCapability(self): - caps = {} - def getCaps(): - def gotCaps(c): - caps.update(c) - self.server.transport.loseConnection() - return self.client.getCapabilities().addCallback(gotCaps) - d1 = self.connected.addCallback(strip(getCaps)).addErrback(self._ebGeneral) - d = defer.gatherResults([self.loopback(), d1]) - expected = {'IMAP4rev1': None, 'NAMESPACE': None, 'IDLE': None} - return d.addCallback(lambda _: self.assertEquals(expected, caps)) - - def testCapabilityWithAuth(self): - caps = {} - self.server.challengers['CRAM-MD5'] = cred.credentials.CramMD5Credentials - def getCaps(): - def gotCaps(c): - caps.update(c) - self.server.transport.loseConnection() - return self.client.getCapabilities().addCallback(gotCaps) - d1 = self.connected.addCallback(strip(getCaps)).addErrback(self._ebGeneral) - d = defer.gatherResults([self.loopback(), d1]) - - expCap = {'IMAP4rev1': None, 'NAMESPACE': None, - 'IDLE': None, 'AUTH': ['CRAM-MD5']} - - return d.addCallback(lambda _: self.assertEquals(expCap, caps)) - - def testLogout(self): - self.loggedOut = 0 - def logout(): - def setLoggedOut(): - self.loggedOut = 1 - self.client.logout().addCallback(strip(setLoggedOut)) - self.connected.addCallback(strip(logout)).addErrback(self._ebGeneral) - d = self.loopback() - return d.addCallback(lambda _: self.assertEquals(self.loggedOut, 1)) - - def testNoop(self): - self.responses = None - def noop(): - def setResponses(responses): - self.responses = responses - self.server.transport.loseConnection() - self.client.noop().addCallback(setResponses) - self.connected.addCallback(strip(noop)).addErrback(self._ebGeneral) - d = self.loopback() - return d.addCallback(lambda _: self.assertEquals(self.responses, [])) - - def testLogin(self): - def login(): - d = self.client.login('testuser', 'password-test') - d.addCallback(self._cbStopClient) - d1 = self.connected.addCallback(strip(login)).addErrback(self._ebGeneral) - d = defer.gatherResults([d1, self.loopback()]) - return d.addCallback(self._cbTestLogin) - - def _cbTestLogin(self, ignored): - self.assertEquals(self.server.account, SimpleServer.theAccount) - self.assertEquals(self.server.state, 'auth') - - def testFailedLogin(self): - def login(): - d = self.client.login('testuser', 'wrong-password') - d.addBoth(self._cbStopClient) - - d1 = self.connected.addCallback(strip(login)).addErrback(self._ebGeneral) - d2 = self.loopback() - d = defer.gatherResults([d1, d2]) - return d.addCallback(self._cbTestFailedLogin) - - def _cbTestFailedLogin(self, ignored): - self.assertEquals(self.server.account, None) - self.assertEquals(self.server.state, 'unauth') - - - def testLoginRequiringQuoting(self): - self.server._username = '{test}user' - self.server._password = '{test}password' - - def login(): - d = self.client.login('{test}user', '{test}password') - d.addBoth(self._cbStopClient) - - d1 = self.connected.addCallback(strip(login)).addErrback(self._ebGeneral) - d = defer.gatherResults([self.loopback(), d1]) - return d.addCallback(self._cbTestLoginRequiringQuoting) - - def _cbTestLoginRequiringQuoting(self, ignored): - self.assertEquals(self.server.account, SimpleServer.theAccount) - self.assertEquals(self.server.state, 'auth') - - - def testNamespace(self): - self.namespaceArgs = None - def login(): - return self.client.login('testuser', 'password-test') - def namespace(): - def gotNamespace(args): - self.namespaceArgs = args - self._cbStopClient(None) - return self.client.namespace().addCallback(gotNamespace) - - d1 = self.connected.addCallback(strip(login)) - d1.addCallback(strip(namespace)) - d1.addErrback(self._ebGeneral) - d2 = self.loopback() - d = defer.gatherResults([d1, d2]) - d.addCallback(lambda _: self.assertEquals(self.namespaceArgs, - [[['', '/']], [], []])) - return d - - def testSelect(self): - SimpleServer.theAccount.addMailbox('test-mailbox') - self.selectedArgs = None - def login(): - return self.client.login('testuser', 'password-test') - def select(): - def selected(args): - self.selectedArgs = args - self._cbStopClient(None) - d = self.client.select('test-mailbox') - d.addCallback(selected) - return d - - d1 = self.connected.addCallback(strip(login)) - d1.addCallback(strip(select)) - d1.addErrback(self._ebGeneral) - d2 = self.loopback() - return defer.gatherResults([d1, d2]).addCallback(self._cbTestSelect) - - def _cbTestSelect(self, ignored): - mbox = SimpleServer.theAccount.mailboxes['TEST-MAILBOX'] - self.assertEquals(self.server.mbox, mbox) - self.assertEquals(self.selectedArgs, { - 'EXISTS': 9, 'RECENT': 3, 'UIDVALIDITY': 42, - 'FLAGS': ('\\Flag1', 'Flag2', '\\AnotherSysFlag', 'LastFlag'), - 'READ-WRITE': 1 - }) - - def testExamine(self): - SimpleServer.theAccount.addMailbox('test-mailbox') - self.examinedArgs = None - def login(): - return self.client.login('testuser', 'password-test') - def examine(): - def examined(args): - self.examinedArgs = args - self._cbStopClient(None) - d = self.client.examine('test-mailbox') - d.addCallback(examined) - return d - - d1 = self.connected.addCallback(strip(login)) - d1.addCallback(strip(examine)) - d1.addErrback(self._ebGeneral) - d2 = self.loopback() - d = defer.gatherResults([d1, d2]) - return d.addCallback(self._cbTestExamine) - - def _cbTestExamine(self, ignored): - mbox = SimpleServer.theAccount.mailboxes['TEST-MAILBOX'] - self.assertEquals(self.server.mbox, mbox) - self.assertEquals(self.examinedArgs, { - 'EXISTS': 9, 'RECENT': 3, 'UIDVALIDITY': 42, - 'FLAGS': ('\\Flag1', 'Flag2', '\\AnotherSysFlag', 'LastFlag'), - 'READ-WRITE': 0 - }) - - def testCreate(self): - succeed = ('testbox', 'test/box', 'test/', 'test/box/box', 'INBOX') - fail = ('testbox', 'test/box') - - def cb(): self.result.append(1) - def eb(failure): self.result.append(0) - - def login(): - return self.client.login('testuser', 'password-test') - def create(): - for name in succeed + fail: - d = self.client.create(name) - d.addCallback(strip(cb)).addErrback(eb) - d.addCallbacks(self._cbStopClient, self._ebGeneral) - - self.result = [] - d1 = self.connected.addCallback(strip(login)).addCallback(strip(create)) - d2 = self.loopback() - d = defer.gatherResults([d1, d2]) - return d.addCallback(self._cbTestCreate, succeed, fail) - - def _cbTestCreate(self, ignored, succeed, fail): - self.assertEquals(self.result, [1] * len(succeed) + [0] * len(fail)) - mbox = SimpleServer.theAccount.mailboxes.keys() - answers = ['inbox', 'testbox', 'test/box', 'test', 'test/box/box'] - mbox.sort() - answers.sort() - self.assertEquals(mbox, [a.upper() for a in answers]) - - def testDelete(self): - SimpleServer.theAccount.addMailbox('delete/me') - - def login(): - return self.client.login('testuser', 'password-test') - def delete(): - return self.client.delete('delete/me') - d1 = self.connected.addCallback(strip(login)) - d1.addCallbacks(strip(delete), self._ebGeneral) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d2 = self.loopback() - d = defer.gatherResults([d1, d2]) - d.addCallback(lambda _: - self.assertEquals(SimpleServer.theAccount.mailboxes.keys(), [])) - return d - - def testIllegalInboxDelete(self): - self.stashed = None - def login(): - return self.client.login('testuser', 'password-test') - def delete(): - return self.client.delete('inbox') - def stash(result): - self.stashed = result - - d1 = self.connected.addCallback(strip(login)) - d1.addCallbacks(strip(delete), self._ebGeneral) - d1.addBoth(stash) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d2 = self.loopback() - d = defer.gatherResults([d1, d2]) - d.addCallback(lambda _: self.failUnless(isinstance(self.stashed, - failure.Failure))) - return d - - - def testNonExistentDelete(self): - def login(): - return self.client.login('testuser', 'password-test') - def delete(): - return self.client.delete('delete/me') - def deleteFailed(failure): - self.failure = failure - - self.failure = None - d1 = self.connected.addCallback(strip(login)) - d1.addCallback(strip(delete)).addErrback(deleteFailed) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d2 = self.loopback() - d = defer.gatherResults([d1, d2]) - d.addCallback(lambda _: self.assertEquals(str(self.failure.value), - 'No such mailbox')) - return d - - - def testIllegalDelete(self): - m = SimpleMailbox() - m.flags = (r'\Noselect',) - SimpleServer.theAccount.addMailbox('delete', m) - SimpleServer.theAccount.addMailbox('delete/me') - - def login(): - return self.client.login('testuser', 'password-test') - def delete(): - return self.client.delete('delete') - def deleteFailed(failure): - self.failure = failure - - self.failure = None - d1 = self.connected.addCallback(strip(login)) - d1.addCallback(strip(delete)).addErrback(deleteFailed) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d2 = self.loopback() - d = defer.gatherResults([d1, d2]) - expected = "Hierarchically inferior mailboxes exist and \\Noselect is set" - d.addCallback(lambda _: - self.assertEquals(str(self.failure.value), expected)) - return d - - def testRename(self): - SimpleServer.theAccount.addMailbox('oldmbox') - def login(): - return self.client.login('testuser', 'password-test') - def rename(): - return self.client.rename('oldmbox', 'newname') - - d1 = self.connected.addCallback(strip(login)) - d1.addCallbacks(strip(rename), self._ebGeneral) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d2 = self.loopback() - d = defer.gatherResults([d1, d2]) - d.addCallback(lambda _: - self.assertEquals(SimpleServer.theAccount.mailboxes.keys(), - ['NEWNAME'])) - return d - - def testIllegalInboxRename(self): - self.stashed = None - def login(): - return self.client.login('testuser', 'password-test') - def rename(): - return self.client.rename('inbox', 'frotz') - def stash(stuff): - self.stashed = stuff - - d1 = self.connected.addCallback(strip(login)) - d1.addCallbacks(strip(rename), self._ebGeneral) - d1.addBoth(stash) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d2 = self.loopback() - d = defer.gatherResults([d1, d2]) - d.addCallback(lambda _: - self.failUnless(isinstance(self.stashed, failure.Failure))) - return d - - def testHierarchicalRename(self): - SimpleServer.theAccount.create('oldmbox/m1') - SimpleServer.theAccount.create('oldmbox/m2') - def login(): - return self.client.login('testuser', 'password-test') - def rename(): - return self.client.rename('oldmbox', 'newname') - - d1 = self.connected.addCallback(strip(login)) - d1.addCallbacks(strip(rename), self._ebGeneral) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d2 = self.loopback() - d = defer.gatherResults([d1, d2]) - return d.addCallback(self._cbTestHierarchicalRename) - - def _cbTestHierarchicalRename(self, ignored): - mboxes = SimpleServer.theAccount.mailboxes.keys() - expected = ['newname', 'newname/m1', 'newname/m2'] - mboxes.sort() - self.assertEquals(mboxes, [s.upper() for s in expected]) - - def testSubscribe(self): - def login(): - return self.client.login('testuser', 'password-test') - def subscribe(): - return self.client.subscribe('this/mbox') - - d1 = self.connected.addCallback(strip(login)) - d1.addCallbacks(strip(subscribe), self._ebGeneral) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d2 = self.loopback() - d = defer.gatherResults([d1, d2]) - d.addCallback(lambda _: - self.assertEquals(SimpleServer.theAccount.subscriptions, - ['THIS/MBOX'])) - return d - - def testUnsubscribe(self): - SimpleServer.theAccount.subscriptions = ['THIS/MBOX', 'THAT/MBOX'] - def login(): - return self.client.login('testuser', 'password-test') - def unsubscribe(): - return self.client.unsubscribe('this/mbox') - - d1 = self.connected.addCallback(strip(login)) - d1.addCallbacks(strip(unsubscribe), self._ebGeneral) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d2 = self.loopback() - d = defer.gatherResults([d1, d2]) - d.addCallback(lambda _: - self.assertEquals(SimpleServer.theAccount.subscriptions, - ['THAT/MBOX'])) - return d - - def _listSetup(self, f): - SimpleServer.theAccount.addMailbox('root/subthing') - SimpleServer.theAccount.addMailbox('root/another-thing') - SimpleServer.theAccount.addMailbox('non-root/subthing') - - def login(): - return self.client.login('testuser', 'password-test') - def listed(answers): - self.listed = answers - - self.listed = None - d1 = self.connected.addCallback(strip(login)) - d1.addCallbacks(strip(f), self._ebGeneral) - d1.addCallbacks(listed, self._ebGeneral) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d2 = self.loopback() - return defer.gatherResults([d1, d2]).addCallback(lambda _: self.listed) - - def testList(self): - def list(): - return self.client.list('root', '%') - d = self._listSetup(list) - d.addCallback(lambda listed: self.assertEquals( - sortNest(listed), - sortNest([ - (SimpleMailbox.flags, "/", "ROOT/SUBTHING"), - (SimpleMailbox.flags, "/", "ROOT/ANOTHER-THING") - ]) - )) - return d - - def testLSub(self): - SimpleServer.theAccount.subscribe('ROOT/SUBTHING') - def lsub(): - return self.client.lsub('root', '%') - d = self._listSetup(lsub) - d.addCallback(self.assertEquals, - [(SimpleMailbox.flags, "/", "ROOT/SUBTHING")]) - return d - - def testStatus(self): - SimpleServer.theAccount.addMailbox('root/subthing') - def login(): - return self.client.login('testuser', 'password-test') - def status(): - return self.client.status('root/subthing', 'MESSAGES', 'UIDNEXT', 'UNSEEN') - def statused(result): - self.statused = result - - self.statused = None - d1 = self.connected.addCallback(strip(login)) - d1.addCallbacks(strip(status), self._ebGeneral) - d1.addCallbacks(statused, self._ebGeneral) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d2 = self.loopback() - d = defer.gatherResults([d1, d2]) - d.addCallback(lambda _: self.assertEquals( - self.statused, - {'MESSAGES': 9, 'UIDNEXT': '10', 'UNSEEN': 4} - )) - return d - - def testFailedStatus(self): - def login(): - return self.client.login('testuser', 'password-test') - def status(): - return self.client.status('root/nonexistent', 'MESSAGES', 'UIDNEXT', 'UNSEEN') - def statused(result): - self.statused = result - def failed(failure): - self.failure = failure - - self.statused = self.failure = None - d1 = self.connected.addCallback(strip(login)) - d1.addCallbacks(strip(status), self._ebGeneral) - d1.addCallbacks(statused, failed) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d2 = self.loopback() - return defer.gatherResults([d1, d2]).addCallback(self._cbTestFailedStatus) - - def _cbTestFailedStatus(self, ignored): - self.assertEquals( - self.statused, None - ) - self.assertEquals( - self.failure.value.args, - ('Could not open mailbox',) - ) - - def testFullAppend(self): - infile = util.sibpath(__file__, 'rfc822.message') - message = open(infile) - SimpleServer.theAccount.addMailbox('root/subthing') - def login(): - return self.client.login('testuser', 'password-test') - def append(): - return self.client.append( - 'root/subthing', - message, - ('\\SEEN', '\\DELETED'), - 'Tue, 17 Jun 2003 11:22:16 -0600 (MDT)', - ) - - d1 = self.connected.addCallback(strip(login)) - d1.addCallbacks(strip(append), self._ebGeneral) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d2 = self.loopback() - d = defer.gatherResults([d1, d2]) - return d.addCallback(self._cbTestFullAppend, infile) - - def _cbTestFullAppend(self, ignored, infile): - mb = SimpleServer.theAccount.mailboxes['ROOT/SUBTHING'] - self.assertEquals(1, len(mb.messages)) - self.assertEquals( - (['\\SEEN', '\\DELETED'], 'Tue, 17 Jun 2003 11:22:16 -0600 (MDT)', 0), - mb.messages[0][1:] - ) - self.assertEquals(open(infile).read(), mb.messages[0][0].getvalue()) - - def testPartialAppend(self): - infile = util.sibpath(__file__, 'rfc822.message') - message = open(infile) - SimpleServer.theAccount.addMailbox('PARTIAL/SUBTHING') - def login(): - return self.client.login('testuser', 'password-test') - def append(): - message = file(infile) - return self.client.sendCommand( - imap4.Command( - 'APPEND', - 'PARTIAL/SUBTHING (\\SEEN) "Right now" {%d}' % os.path.getsize(infile), - (), self.client._IMAP4Client__cbContinueAppend, message - ) - ) - d1 = self.connected.addCallback(strip(login)) - d1.addCallbacks(strip(append), self._ebGeneral) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d2 = self.loopback() - d = defer.gatherResults([d1, d2]) - return d.addCallback(self._cbTestPartialAppend, infile) - - def _cbTestPartialAppend(self, ignored, infile): - mb = SimpleServer.theAccount.mailboxes['PARTIAL/SUBTHING'] - self.assertEquals(1, len(mb.messages)) - self.assertEquals( - (['\\SEEN'], 'Right now', 0), - mb.messages[0][1:] - ) - self.assertEquals(open(infile).read(), mb.messages[0][0].getvalue()) - - def testCheck(self): - SimpleServer.theAccount.addMailbox('root/subthing') - def login(): - return self.client.login('testuser', 'password-test') - def select(): - return self.client.select('root/subthing') - def check(): - return self.client.check() - - d = self.connected.addCallback(strip(login)) - d.addCallbacks(strip(select), self._ebGeneral) - d.addCallbacks(strip(check), self._ebGeneral) - d.addCallbacks(self._cbStopClient, self._ebGeneral) - return self.loopback() - - # Okay, that was fun - - def testClose(self): - m = SimpleMailbox() - m.messages = [ - ('Message 1', ('\\Deleted', 'AnotherFlag'), None, 0), - ('Message 2', ('AnotherFlag',), None, 1), - ('Message 3', ('\\Deleted',), None, 2), - ] - SimpleServer.theAccount.addMailbox('mailbox', m) - def login(): - return self.client.login('testuser', 'password-test') - def select(): - return self.client.select('mailbox') - def close(): - return self.client.close() - - d = self.connected.addCallback(strip(login)) - d.addCallbacks(strip(select), self._ebGeneral) - d.addCallbacks(strip(close), self._ebGeneral) - d.addCallbacks(self._cbStopClient, self._ebGeneral) - d2 = self.loopback() - return defer.gatherResults([d, d2]).addCallback(self._cbTestClose, m) - - def _cbTestClose(self, ignored, m): - self.assertEquals(len(m.messages), 1) - self.assertEquals(m.messages[0], ('Message 2', ('AnotherFlag',), None, 1)) - self.failUnless(m.closed) - - def testExpunge(self): - m = SimpleMailbox() - m.messages = [ - ('Message 1', ('\\Deleted', 'AnotherFlag'), None, 0), - ('Message 2', ('AnotherFlag',), None, 1), - ('Message 3', ('\\Deleted',), None, 2), - ] - SimpleServer.theAccount.addMailbox('mailbox', m) - def login(): - return self.client.login('testuser', 'password-test') - def select(): - return self.client.select('mailbox') - def expunge(): - return self.client.expunge() - def expunged(results): - self.failIf(self.server.mbox is None) - self.results = results - - self.results = None - d1 = self.connected.addCallback(strip(login)) - d1.addCallbacks(strip(select), self._ebGeneral) - d1.addCallbacks(strip(expunge), self._ebGeneral) - d1.addCallbacks(expunged, self._ebGeneral) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d2 = self.loopback() - d = defer.gatherResults([d1, d2]) - return d.addCallback(self._cbTestExpunge, m) - - def _cbTestExpunge(self, ignored, m): - self.assertEquals(len(m.messages), 1) - self.assertEquals(m.messages[0], ('Message 2', ('AnotherFlag',), None, 1)) - - self.assertEquals(self.results, [0, 2]) - -class TestRealm: - theAccount = None - - def requestAvatar(self, avatarId, mind, *interfaces): - return imap4.IAccount, self.theAccount, lambda: None - -class TestChecker: - credentialInterfaces = (cred.credentials.IUsernameHashedPassword, cred.credentials.IUsernamePassword) - - users = { - 'testuser': 'secret' - } - - def requestAvatarId(self, credentials): - if credentials.username in self.users: - return defer.maybeDeferred( - credentials.checkPassword, self.users[credentials.username] - ).addCallback(self._cbCheck, credentials.username) - - def _cbCheck(self, result, username): - if result: - return username - raise cred.error.UnauthorizedLogin() - -class AuthenticatorTestCase(IMAP4HelperMixin, unittest.TestCase): - def setUp(self): - IMAP4HelperMixin.setUp(self) - - realm = TestRealm() - realm.theAccount = Account('testuser') - portal = cred.portal.Portal(realm) - portal.registerChecker(TestChecker()) - self.server.portal = portal - - self.authenticated = 0 - self.account = realm.theAccount - - def testCramMD5(self): - self.server.challengers['CRAM-MD5'] = cred.credentials.CramMD5Credentials - cAuth = imap4.CramMD5ClientAuthenticator('testuser') - self.client.registerAuthenticator(cAuth) - - def auth(): - return self.client.authenticate('secret') - def authed(): - self.authenticated = 1 - - d1 = self.connected.addCallback(strip(auth)) - d1.addCallbacks(strip(authed), self._ebGeneral) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d2 = self.loopback() - d = defer.gatherResults([d1, d2]) - return d.addCallback(self._cbTestCramMD5) - - def _cbTestCramMD5(self, ignored): - self.assertEquals(self.authenticated, 1) - self.assertEquals(self.server.account, self.account) - - def testFailedCramMD5(self): - self.server.challengers['CRAM-MD5'] = cred.credentials.CramMD5Credentials - cAuth = imap4.CramMD5ClientAuthenticator('testuser') - self.client.registerAuthenticator(cAuth) - - def misauth(): - return self.client.authenticate('not the secret') - def authed(): - self.authenticated = 1 - def misauthed(): - self.authenticated = -1 - - d1 = self.connected.addCallback(strip(misauth)) - d1.addCallbacks(strip(authed), strip(misauthed)) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d = defer.gatherResults([self.loopback(), d1]) - return d.addCallback(self._cbTestFailedCramMD5) - - def _cbTestFailedCramMD5(self, ignored): - self.assertEquals(self.authenticated, -1) - self.assertEquals(self.server.account, None) - - def testLOGIN(self): - self.server.challengers['LOGIN'] = imap4.LOGINCredentials - cAuth = imap4.LOGINAuthenticator('testuser') - self.client.registerAuthenticator(cAuth) - - def auth(): - return self.client.authenticate('secret') - def authed(): - self.authenticated = 1 - - d1 = self.connected.addCallback(strip(auth)) - d1.addCallbacks(strip(authed), self._ebGeneral) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d = defer.gatherResults([self.loopback(), d1]) - return d.addCallback(self._cbTestLOGIN) - - def _cbTestLOGIN(self, ignored): - self.assertEquals(self.authenticated, 1) - self.assertEquals(self.server.account, self.account) - - def testFailedLOGIN(self): - self.server.challengers['LOGIN'] = imap4.LOGINCredentials - cAuth = imap4.LOGINAuthenticator('testuser') - self.client.registerAuthenticator(cAuth) - - def misauth(): - return self.client.authenticate('not the secret') - def authed(): - self.authenticated = 1 - def misauthed(): - self.authenticated = -1 - - d1 = self.connected.addCallback(strip(misauth)) - d1.addCallbacks(strip(authed), strip(misauthed)) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d = defer.gatherResults([self.loopback(), d1]) - return d.addCallback(self._cbTestFailedLOGIN) - - def _cbTestFailedLOGIN(self, ignored): - self.assertEquals(self.authenticated, -1) - self.assertEquals(self.server.account, None) - - def testPLAIN(self): - self.server.challengers['PLAIN'] = imap4.PLAINCredentials - cAuth = imap4.PLAINAuthenticator('testuser') - self.client.registerAuthenticator(cAuth) - - def auth(): - return self.client.authenticate('secret') - def authed(): - self.authenticated = 1 - - d1 = self.connected.addCallback(strip(auth)) - d1.addCallbacks(strip(authed), self._ebGeneral) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d = defer.gatherResults([self.loopback(), d1]) - return d.addCallback(self._cbTestPLAIN) - - def _cbTestPLAIN(self, ignored): - self.assertEquals(self.authenticated, 1) - self.assertEquals(self.server.account, self.account) - - def testFailedPLAIN(self): - self.server.challengers['PLAIN'] = imap4.PLAINCredentials - cAuth = imap4.PLAINAuthenticator('testuser') - self.client.registerAuthenticator(cAuth) - - def misauth(): - return self.client.authenticate('not the secret') - def authed(): - self.authenticated = 1 - def misauthed(): - self.authenticated = -1 - - d1 = self.connected.addCallback(strip(misauth)) - d1.addCallbacks(strip(authed), strip(misauthed)) - d1.addCallbacks(self._cbStopClient, self._ebGeneral) - d = defer.gatherResults([self.loopback(), d1]) - return d.addCallback(self._cbTestFailedPLAIN) - - def _cbTestFailedPLAIN(self, ignored): - self.assertEquals(self.authenticated, -1) - self.assertEquals(self.server.account, None) - - -class UnsolicitedResponseTestCase(IMAP4HelperMixin, unittest.TestCase): - def testReadWrite(self): - def login(): - return self.client.login('testuser', 'password-test') - def loggedIn(): - self.server.modeChanged(1) - - d1 = self.connected.addCallback(strip(login)) - d1.addCallback(strip(loggedIn)).addErrback(self._ebGeneral) - d = defer.gatherResults([self.loopback(), d1]) - return d.addCallback(self._cbTestReadWrite) - - def _cbTestReadWrite(self, ignored): - E = self.client.events - self.assertEquals(E, [['modeChanged', 1]]) - - def testReadOnly(self): - def login(): - return self.client.login('testuser', 'password-test') - def loggedIn(): - self.server.modeChanged(0) - - d1 = self.connected.addCallback(strip(login)) - d1.addCallback(strip(loggedIn)).addErrback(self._ebGeneral) - d = defer.gatherResults([self.loopback(), d1]) - return d.addCallback(self._cbTestReadOnly) - - def _cbTestReadOnly(self, ignored): - E = self.client.events - self.assertEquals(E, [['modeChanged', 0]]) - - def testFlagChange(self): - flags = { - 1: ['\\Answered', '\\Deleted'], - 5: [], - 10: ['\\Recent'] - } - def login(): - return self.client.login('testuser', 'password-test') - def loggedIn(): - self.server.flagsChanged(flags) - - d1 = self.connected.addCallback(strip(login)) - d1.addCallback(strip(loggedIn)).addErrback(self._ebGeneral) - d = defer.gatherResults([self.loopback(), d1]) - return d.addCallback(self._cbTestFlagChange, flags) - - def _cbTestFlagChange(self, ignored, flags): - E = self.client.events - expect = [['flagsChanged', {x[0]: x[1]}] for x in flags.items()] - E.sort() - expect.sort() - self.assertEquals(E, expect) - - def testNewMessages(self): - def login(): - return self.client.login('testuser', 'password-test') - def loggedIn(): - self.server.newMessages(10, None) - - d1 = self.connected.addCallback(strip(login)) - d1.addCallback(strip(loggedIn)).addErrback(self._ebGeneral) - d = defer.gatherResults([self.loopback(), d1]) - return d.addCallback(self._cbTestNewMessages) - - def _cbTestNewMessages(self, ignored): - E = self.client.events - self.assertEquals(E, [['newMessages', 10, None]]) - - def testNewRecentMessages(self): - def login(): - return self.client.login('testuser', 'password-test') - def loggedIn(): - self.server.newMessages(None, 10) - - d1 = self.connected.addCallback(strip(login)) - d1.addCallback(strip(loggedIn)).addErrback(self._ebGeneral) - d = defer.gatherResults([self.loopback(), d1]) - return d.addCallback(self._cbTestNewRecentMessages) - - def _cbTestNewRecentMessages(self, ignored): - E = self.client.events - self.assertEquals(E, [['newMessages', None, 10]]) - - def testNewMessagesAndRecent(self): - def login(): - return self.client.login('testuser', 'password-test') - def loggedIn(): - self.server.newMessages(20, 10) - - d1 = self.connected.addCallback(strip(login)) - d1.addCallback(strip(loggedIn)).addErrback(self._ebGeneral) - d = defer.gatherResults([self.loopback(), d1]) - return d.addCallback(self._cbTestNewMessagesAndRecent) - - def _cbTestNewMessagesAndRecent(self, ignored): - E = self.client.events - self.assertEquals(E, [['newMessages', 20, None], ['newMessages', None, 10]]) - - -class ClientCapabilityTests(unittest.TestCase): - """ - Tests for issuance of the CAPABILITY command and handling of its response. - """ - def setUp(self): - """ - Create an L{imap4.IMAP4Client} connected to a L{StringTransport}. - """ - self.transport = StringTransport() - self.protocol = imap4.IMAP4Client() - self.protocol.makeConnection(self.transport) - self.protocol.dataReceived('* OK [IMAP4rev1]\r\n') - - - def test_simpleAtoms(self): - """ - A capability response consisting only of atoms without C{'='} in them - should result in a dict mapping those atoms to C{None}. - """ - capabilitiesResult = self.protocol.getCapabilities(useCache=False) - self.protocol.dataReceived('* CAPABILITY IMAP4rev1 LOGINDISABLED\r\n') - self.protocol.dataReceived('0001 OK Capability completed.\r\n') - def gotCapabilities(capabilities): - self.assertEqual( - capabilities, {'IMAP4rev1': None, 'LOGINDISABLED': None}) - capabilitiesResult.addCallback(gotCapabilities) - return capabilitiesResult - - - def test_categoryAtoms(self): - """ - A capability response consisting of atoms including C{'='} should have - those atoms split on that byte and have capabilities in the same - category aggregated into lists in the resulting dictionary. - - (n.b. - I made up the word "category atom"; the protocol has no notion - of structure here, but rather allows each capability to define the - semantics of its entry in the capability response in a freeform manner. - If I had realized this earlier, the API for capabilities would look - different. As it is, we can hope that no one defines any crazy - semantics which are incompatible with this API, or try to figure out a - better API when someone does. -exarkun) - """ - capabilitiesResult = self.protocol.getCapabilities(useCache=False) - self.protocol.dataReceived('* CAPABILITY IMAP4rev1 AUTH=LOGIN AUTH=PLAIN\r\n') - self.protocol.dataReceived('0001 OK Capability completed.\r\n') - def gotCapabilities(capabilities): - self.assertEqual( - capabilities, {'IMAP4rev1': None, 'AUTH': ['LOGIN', 'PLAIN']}) - capabilitiesResult.addCallback(gotCapabilities) - return capabilitiesResult - - - def test_mixedAtoms(self): - """ - A capability response consisting of both simple and category atoms of - the same type should result in a list containing C{None} as well as the - values for the category. - """ - capabilitiesResult = self.protocol.getCapabilities(useCache=False) - # Exercise codepath for both orderings of =-having and =-missing - # capabilities. - self.protocol.dataReceived( - '* CAPABILITY IMAP4rev1 FOO FOO=BAR BAR=FOO BAR\r\n') - self.protocol.dataReceived('0001 OK Capability completed.\r\n') - def gotCapabilities(capabilities): - self.assertEqual(capabilities, {'IMAP4rev1': None, - 'FOO': [None, 'BAR'], - 'BAR': ['FOO', None]}) - capabilitiesResult.addCallback(gotCapabilities) - return capabilitiesResult - - - - -class HandCraftedTestCase(IMAP4HelperMixin, unittest.TestCase): - def testTrailingLiteral(self): - transport = StringTransport() - c = imap4.IMAP4Client() - c.makeConnection(transport) - c.lineReceived('* OK [IMAP4rev1]') - - def cbSelect(ignored): - d = c.fetchMessage('1') - c.dataReceived('* 1 FETCH (RFC822 {10}\r\n0123456789\r\n RFC822.SIZE 10)\r\n') - c.dataReceived('0003 OK FETCH\r\n') - return d - - def cbLogin(ignored): - d = c.select('inbox') - c.lineReceived('0002 OK SELECT') - d.addCallback(cbSelect) - return d - - d = c.login('blah', 'blah') - c.dataReceived('0001 OK LOGIN\r\n') - d.addCallback(cbLogin) - return d - - def testPathelogicalScatteringOfLiterals(self): - self.server.checker.addUser('testuser', 'password-test') - transport = StringTransport() - self.server.makeConnection(transport) - - transport.clear() - self.server.dataReceived("01 LOGIN {8}\r\n") - self.assertEquals(transport.value(), "+ Ready for 8 octets of text\r\n") - - transport.clear() - self.server.dataReceived("testuser {13}\r\n") - self.assertEquals(transport.value(), "+ Ready for 13 octets of text\r\n") - - transport.clear() - self.server.dataReceived("password-test\r\n") - self.assertEquals(transport.value(), "01 OK LOGIN succeeded\r\n") - self.assertEquals(self.server.state, 'auth') - - self.server.connectionLost(error.ConnectionDone("Connection done.")) - - def testUnsolicitedResponseMixedWithSolicitedResponse(self): - - class StillSimplerClient(imap4.IMAP4Client): - events = [] - def flagsChanged(self, newFlags): - self.events.append(['flagsChanged', newFlags]) - - transport = StringTransport() - c = StillSimplerClient() - c.makeConnection(transport) - c.lineReceived('* OK [IMAP4rev1]') - - def login(): - d = c.login('blah', 'blah') - c.dataReceived('0001 OK LOGIN\r\n') - return d - def select(): - d = c.select('inbox') - c.lineReceived('0002 OK SELECT') - return d - def fetch(): - d = c.fetchSpecific('1:*', - headerType='HEADER.FIELDS', - headerArgs=['SUBJECT']) - c.dataReceived('* 1 FETCH (BODY[HEADER.FIELDS ("SUBJECT")] {38}\r\n') - c.dataReceived('Subject: Suprise for your woman...\r\n') - c.dataReceived('\r\n') - c.dataReceived(')\r\n') - c.dataReceived('* 1 FETCH (FLAGS (\Seen))\r\n') - c.dataReceived('* 2 FETCH (BODY[HEADER.FIELDS ("SUBJECT")] {75}\r\n') - c.dataReceived('Subject: What you been doing. Order your meds here . ,. handcuff madsen\r\n') - c.dataReceived('\r\n') - c.dataReceived(')\r\n') - c.dataReceived('0003 OK FETCH completed\r\n') - return d - def test(res): - self.assertEquals(res, { - 1: [['BODY', ['HEADER.FIELDS', ['SUBJECT']], - 'Subject: Suprise for your woman...\r\n\r\n']], - 2: [['BODY', ['HEADER.FIELDS', ['SUBJECT']], - 'Subject: What you been doing. Order your meds here . ,. handcuff madsen\r\n\r\n']] - }) - - self.assertEquals(c.events, [['flagsChanged', {1: ['\\Seen']}]]) - - return login( - ).addCallback(strip(select) - ).addCallback(strip(fetch) - ).addCallback(test) - - - def test_literalWithoutPrecedingWhitespace(self): - """ - Literals should be recognized even when they are not preceded by - whitespace. - """ - transport = StringTransport() - protocol = imap4.IMAP4Client() - - protocol.makeConnection(transport) - protocol.lineReceived('* OK [IMAP4rev1]') - - def login(): - d = protocol.login('blah', 'blah') - protocol.dataReceived('0001 OK LOGIN\r\n') - return d - def select(): - d = protocol.select('inbox') - protocol.lineReceived('0002 OK SELECT') - return d - def fetch(): - d = protocol.fetchSpecific('1:*', - headerType='HEADER.FIELDS', - headerArgs=['SUBJECT']) - protocol.dataReceived( - '* 1 FETCH (BODY[HEADER.FIELDS ({7}\r\nSUBJECT)] "Hello")\r\n') - protocol.dataReceived('0003 OK FETCH completed\r\n') - return d - def test(result): - self.assertEqual( - result, {1: [['BODY', ['HEADER.FIELDS', ['SUBJECT']], 'Hello']]}) - - d = login() - d.addCallback(strip(select)) - d.addCallback(strip(fetch)) - d.addCallback(test) - return d - - - def test_nonIntegerLiteralLength(self): - """ - If the server sends a literal length which cannot be parsed as an - integer, L{IMAP4Client.lineReceived} should cause the protocol to be - disconnected by raising L{imap4.IllegalServerResponse}. - """ - transport = StringTransport() - protocol = imap4.IMAP4Client() - - protocol.makeConnection(transport) - protocol.lineReceived('* OK [IMAP4rev1]') - - def login(): - d = protocol.login('blah', 'blah') - protocol.dataReceived('0001 OK LOGIN\r\n') - return d - def select(): - d = protocol.select('inbox') - protocol.lineReceived('0002 OK SELECT') - return d - def fetch(): - d = protocol.fetchSpecific('1:*', - headerType='HEADER.FIELDS', - headerArgs=['SUBJECT']) - self.assertRaises( - imap4.IllegalServerResponse, - protocol.dataReceived, - '* 1 FETCH {xyz}\r\n...') - d = login() - d.addCallback(strip(select)) - d.addCallback(strip(fetch)) - return d - - - -class FakeyServer(imap4.IMAP4Server): - state = 'select' - timeout = None - - def sendServerGreeting(self): - pass - -class FakeyMessage: - implements(imap4.IMessage) - - def __init__(self, headers, flags, date, body, uid, subpart): - self.headers = headers - self.flags = flags - self.body = StringIO(body) - self.size = len(body) - self.date = date - self.uid = uid - self.subpart = subpart - - def getHeaders(self, negate, *names): - self.got_headers = negate, names - return self.headers - - def getFlags(self): - return self.flags - - def getInternalDate(self): - return self.date - - def getBodyFile(self): - return self.body - - def getSize(self): - return self.size - - def getUID(self): - return self.uid - - def isMultipart(self): - return self.subpart is not None - - def getSubPart(self, part): - self.got_subpart = part - return self.subpart[part] - -class NewStoreTestCase(unittest.TestCase, IMAP4HelperMixin): - result = None - storeArgs = None - - def setUp(self): - self.received_messages = self.received_uid = None - - self.server = imap4.IMAP4Server() - self.server.state = 'select' - self.server.mbox = self - self.connected = defer.Deferred() - self.client = SimpleClient(self.connected) - - def addListener(self, x): - pass - def removeListener(self, x): - pass - - def store(self, *args, **kw): - self.storeArgs = args, kw - return self.response - - def _storeWork(self): - def connected(): - return self.function(self.messages, self.flags, self.silent, self.uid) - def result(R): - self.result = R - - self.connected.addCallback(strip(connected) - ).addCallback(result - ).addCallback(self._cbStopClient - ).addErrback(self._ebGeneral) - - def check(ignored): - self.assertEquals(self.result, self.expected) - self.assertEquals(self.storeArgs, self.expectedArgs) - d = loopback.loopbackTCP(self.server, self.client, noisy=False) - d.addCallback(check) - return d - - def testSetFlags(self, uid=0): - self.function = self.client.setFlags - self.messages = '1,5,9' - self.flags = ['\\A', '\\B', 'C'] - self.silent = False - self.uid = uid - self.response = { - 1: ['\\A', '\\B', 'C'], - 5: ['\\A', '\\B', 'C'], - 9: ['\\A', '\\B', 'C'], - } - self.expected = { - 1: {'FLAGS': ['\\A', '\\B', 'C']}, - 5: {'FLAGS': ['\\A', '\\B', 'C']}, - 9: {'FLAGS': ['\\A', '\\B', 'C']}, - } - msg = imap4.MessageSet() - msg.add(1) - msg.add(5) - msg.add(9) - self.expectedArgs = ((msg, ['\\A', '\\B', 'C'], 0), {'uid': 0}) - return self._storeWork() - - -class NewFetchTestCase(unittest.TestCase, IMAP4HelperMixin): - def setUp(self): - self.received_messages = self.received_uid = None - self.result = None - - self.server = imap4.IMAP4Server() - self.server.state = 'select' - self.server.mbox = self - self.connected = defer.Deferred() - self.client = SimpleClient(self.connected) - - def addListener(self, x): - pass - def removeListener(self, x): - pass - - def fetch(self, messages, uid): - self.received_messages = messages - self.received_uid = uid - return iter(zip(range(len(self.msgObjs)), self.msgObjs)) - - def _fetchWork(self, uid): - if uid: - for (i, msg) in zip(range(len(self.msgObjs)), self.msgObjs): - self.expected[i]['UID'] = str(msg.getUID()) - - def result(R): - self.result = R - - self.connected.addCallback(lambda _: self.function(self.messages, uid) - ).addCallback(result - ).addCallback(self._cbStopClient - ).addErrback(self._ebGeneral) - - d = loopback.loopbackTCP(self.server, self.client, noisy=False) - d.addCallback(lambda x : self.assertEquals(self.result, self.expected)) - return d - - def testFetchUID(self): - self.function = lambda m, u: self.client.fetchUID(m) - - self.messages = '7' - self.msgObjs = [ - FakeyMessage({}, (), '', '', 12345, None), - FakeyMessage({}, (), '', '', 999, None), - FakeyMessage({}, (), '', '', 10101, None), - ] - self.expected = { - 0: {'UID': '12345'}, - 1: {'UID': '999'}, - 2: {'UID': '10101'}, - } - return self._fetchWork(0) - - def testFetchFlags(self, uid=0): - self.function = self.client.fetchFlags - self.messages = '9' - self.msgObjs = [ - FakeyMessage({}, ['FlagA', 'FlagB', '\\FlagC'], '', '', 54321, None), - FakeyMessage({}, ['\\FlagC', 'FlagA', 'FlagB'], '', '', 12345, None), - ] - self.expected = { - 0: {'FLAGS': ['FlagA', 'FlagB', '\\FlagC']}, - 1: {'FLAGS': ['\\FlagC', 'FlagA', 'FlagB']}, - } - return self._fetchWork(uid) - - def testFetchFlagsUID(self): - return self.testFetchFlags(1) - - def testFetchInternalDate(self, uid=0): - self.function = self.client.fetchInternalDate - self.messages = '13' - self.msgObjs = [ - FakeyMessage({}, (), 'Fri, 02 Nov 2003 21:25:10 GMT', '', 23232, None), - FakeyMessage({}, (), 'Thu, 29 Dec 2013 11:31:52 EST', '', 101, None), - FakeyMessage({}, (), 'Mon, 10 Mar 1992 02:44:30 CST', '', 202, None), - FakeyMessage({}, (), 'Sat, 11 Jan 2000 14:40:24 PST', '', 303, None), - ] - self.expected = { - 0: {'INTERNALDATE': '02-Nov-2003 21:25:10 +0000'}, - 1: {'INTERNALDATE': '29-Dec-2013 11:31:52 -0500'}, - 2: {'INTERNALDATE': '10-Mar-1992 02:44:30 -0600'}, - 3: {'INTERNALDATE': '11-Jan-2000 14:40:24 -0800'}, - } - return self._fetchWork(uid) - - def testFetchInternalDateUID(self): - return self.testFetchInternalDate(1) - - def testFetchEnvelope(self, uid=0): - self.function = self.client.fetchEnvelope - self.messages = '15' - self.msgObjs = [ - FakeyMessage({ - 'from': 'user@domain', 'to': 'resu@domain', - 'date': 'thursday', 'subject': 'it is a message', - 'message-id': 'id-id-id-yayaya'}, (), '', '', 65656, - None), - ] - self.expected = { - 0: {'ENVELOPE': - ['thursday', 'it is a message', - [[None, None, 'user', 'domain']], - [[None, None, 'user', 'domain']], - [[None, None, 'user', 'domain']], - [[None, None, 'resu', 'domain']], - None, None, None, 'id-id-id-yayaya'] - } - } - return self._fetchWork(uid) - - def testFetchEnvelopeUID(self): - return self.testFetchEnvelope(1) - - def testFetchBodyStructure(self, uid=0): - self.function = self.client.fetchBodyStructure - self.messages = '3:9,10:*' - self.msgObjs = [FakeyMessage({ - 'content-type': 'text/plain; name=thing; key="value"', - 'content-id': 'this-is-the-content-id', - 'content-description': 'describing-the-content-goes-here!', - 'content-transfer-encoding': '8BIT', - }, (), '', 'Body\nText\nGoes\nHere\n', 919293, None)] - self.expected = {0: {'BODYSTRUCTURE': [ - 'text', 'plain', [['name', 'thing'], ['key', 'value']], - 'this-is-the-content-id', 'describing-the-content-goes-here!', - '8BIT', '20', '4', None, None, None]}} - return self._fetchWork(uid) - - def testFetchBodyStructureUID(self): - return self.testFetchBodyStructure(1) - - def testFetchSimplifiedBody(self, uid=0): - self.function = self.client.fetchSimplifiedBody - self.messages = '21' - self.msgObjs = [FakeyMessage({}, (), '', 'Yea whatever', 91825, - [FakeyMessage({'content-type': 'image/jpg'}, (), '', - 'Body Body Body', None, None - )] - )] - self.expected = {0: - {'BODY': - [None, None, [], None, None, None, - '12' - ] - } - } - - return self._fetchWork(uid) - - def testFetchSimplifiedBodyUID(self): - return self.testFetchSimplifiedBody(1) - - def testFetchSimplifiedBodyText(self, uid=0): - self.function = self.client.fetchSimplifiedBody - self.messages = '21' - self.msgObjs = [FakeyMessage({'content-type': 'text/plain'}, - (), '', 'Yea whatever', 91825, None)] - self.expected = {0: - {'BODY': - ['text', 'plain', [], None, None, None, - '12', '1' - ] - } - } - - return self._fetchWork(uid) - - def testFetchSimplifiedBodyTextUID(self): - return self.testFetchSimplifiedBodyText(1) - - def testFetchSimplifiedBodyRFC822(self, uid=0): - self.function = self.client.fetchSimplifiedBody - self.messages = '21' - self.msgObjs = [FakeyMessage({'content-type': 'message/rfc822'}, - (), '', 'Yea whatever', 91825, - [FakeyMessage({'content-type': 'image/jpg'}, (), '', - 'Body Body Body', None, None - )] - )] - self.expected = {0: - {'BODY': - ['message', 'rfc822', [], None, None, None, - '12', [None, None, [[None, None, None]], - [[None, None, None]], None, None, None, - None, None, None], ['image', 'jpg', [], - None, None, None, '14'], '1' - ] - } - } - - return self._fetchWork(uid) - - def testFetchSimplifiedBodyRFC822UID(self): - return self.testFetchSimplifiedBodyRFC822(1) - - def testFetchMessage(self, uid=0): - self.function = self.client.fetchMessage - self.messages = '1,3,7,10101' - self.msgObjs = [ - FakeyMessage({'Header': 'Value'}, (), '', 'BODY TEXT\r\n', 91, None), - ] - self.expected = { - 0: {'RFC822': 'Header: Value\r\n\r\nBODY TEXT\r\n'} - } - return self._fetchWork(uid) - - def testFetchMessageUID(self): - return self.testFetchMessage(1) - - def testFetchHeaders(self, uid=0): - self.function = self.client.fetchHeaders - self.messages = '9,6,2' - self.msgObjs = [ - FakeyMessage({'H1': 'V1', 'H2': 'V2'}, (), '', '', 99, None), - ] - self.expected = { - 0: {'RFC822.HEADER': imap4._formatHeaders({'H1': 'V1', 'H2': 'V2'})}, - } - return self._fetchWork(uid) - - def testFetchHeadersUID(self): - return self.testFetchHeaders(1) - - def testFetchBody(self, uid=0): - self.function = self.client.fetchBody - self.messages = '1,2,3,4,5,6,7' - self.msgObjs = [ - FakeyMessage({'Header': 'Value'}, (), '', 'Body goes here\r\n', 171, None), - ] - self.expected = { - 0: {'RFC822.TEXT': 'Body goes here\r\n'}, - } - return self._fetchWork(uid) - - def testFetchBodyUID(self): - return self.testFetchBody(1) - - def testFetchBodyParts(self): - self.function = self.client.fetchBodyParts - self.messages = '1' - parts = [1, 2] - outerBody = '' - innerBody1 = 'Contained body message text. Squarge.' - innerBody2 = 'Secondary message text of squarge body.' - headers = util.OrderedDict() - headers['from'] = 'sender@host' - headers['to'] = 'recipient@domain' - headers['subject'] = 'booga booga boo' - headers['content-type'] = 'multipart/alternative; boundary="xyz"' - innerHeaders = util.OrderedDict() - innerHeaders['subject'] = 'this is subject text' - innerHeaders['content-type'] = 'text/plain' - innerHeaders2 = util.OrderedDict() - innerHeaders2['subject'] = 'this is subject' - innerHeaders2['content-type'] = 'text/html' - self.msgObjs = [FakeyMessage( - headers, (), None, outerBody, 123, - [FakeyMessage(innerHeaders, (), None, innerBody1, None, None), - FakeyMessage(innerHeaders2, (), None, innerBody2, None, None)])] - self.expected = { - 0: {'1': innerBody1, '2': innerBody2}, - } - - def result(R): - self.result = R - - self.connected.addCallback(lambda _: self.function(self.messages, parts)) - self.connected.addCallback(result) - self.connected.addCallback(self._cbStopClient) - self.connected.addErrback(self._ebGeneral) - - d = loopback.loopbackTCP(self.server, self.client, noisy=False) - d.addCallback(lambda ign: self.assertEquals(self.result, self.expected)) - return d - - - def test_fetchBodyPartOfNonMultipart(self): - """ - Single-part messages have an implicit first part which clients - should be able to retrieve explicitly. Test that a client - requesting part 1 of a text/plain message receives the body of the - text/plain part. - """ - self.function = self.client.fetchBodyParts - self.messages = '1' - parts = [1] - outerBody = 'DA body' - headers = util.OrderedDict() - headers['from'] = 'sender@host' - headers['to'] = 'recipient@domain' - headers['subject'] = 'booga booga boo' - headers['content-type'] = 'text/plain' - self.msgObjs = [FakeyMessage( - headers, (), None, outerBody, 123, None)] - - self.expected = { - 0: {'1': outerBody}, - } - - def result(R): - self.result = R - - self.connected.addCallback(lambda _: self.function(self.messages, parts)) - self.connected.addCallback(result) - self.connected.addCallback(self._cbStopClient) - self.connected.addErrback(self._ebGeneral) - - d = loopback.loopbackTCP(self.server, self.client, noisy=False) - d.addCallback(lambda ign: self.assertEquals(self.result, self.expected)) - return d - - - def testFetchSize(self, uid=0): - self.function = self.client.fetchSize - self.messages = '1:100,2:*' - self.msgObjs = [ - FakeyMessage({}, (), '', 'x' * 20, 123, None), - ] - self.expected = { - 0: {'RFC822.SIZE': '20'}, - } - return self._fetchWork(uid) - - def testFetchSizeUID(self): - return self.testFetchSize(1) - - def testFetchFull(self, uid=0): - self.function = self.client.fetchFull - self.messages = '1,3' - self.msgObjs = [ - FakeyMessage({}, ('\\XYZ', '\\YZX', 'Abc'), - 'Sun, 25 Jul 2010 06:20:30 -0400 (EDT)', - 'xyz' * 2, 654, None), - FakeyMessage({}, ('\\One', '\\Two', 'Three'), - 'Mon, 14 Apr 2003 19:43:44 -0400', - 'abc' * 4, 555, None), - ] - self.expected = { - 0: {'FLAGS': ['\\XYZ', '\\YZX', 'Abc'], - 'INTERNALDATE': '25-Jul-2010 06:20:30 -0400', - 'RFC822.SIZE': '6', - 'ENVELOPE': [None, None, [[None, None, None]], [[None, None, None]], None, None, None, None, None, None], - 'BODY': [None, None, [], None, None, None, '6']}, - 1: {'FLAGS': ['\\One', '\\Two', 'Three'], - 'INTERNALDATE': '14-Apr-2003 19:43:44 -0400', - 'RFC822.SIZE': '12', - 'ENVELOPE': [None, None, [[None, None, None]], [[None, None, None]], None, None, None, None, None, None], - 'BODY': [None, None, [], None, None, None, '12']}, - } - return self._fetchWork(uid) - - def testFetchFullUID(self): - return self.testFetchFull(1) - - def testFetchAll(self, uid=0): - self.function = self.client.fetchAll - self.messages = '1,2:3' - self.msgObjs = [ - FakeyMessage({}, (), 'Mon, 14 Apr 2003 19:43:44 +0400', - 'Lalala', 10101, None), - FakeyMessage({}, (), 'Tue, 15 Apr 2003 19:43:44 +0200', - 'Alalal', 20202, None), - ] - self.expected = { - 0: {'ENVELOPE': [None, None, [[None, None, None]], [[None, None, None]], None, None, None, None, None, None], - 'RFC822.SIZE': '6', - 'INTERNALDATE': '14-Apr-2003 19:43:44 +0400', - 'FLAGS': []}, - 1: {'ENVELOPE': [None, None, [[None, None, None]], [[None, None, None]], None, None, None, None, None, None], - 'RFC822.SIZE': '6', - 'INTERNALDATE': '15-Apr-2003 19:43:44 +0200', - 'FLAGS': []}, - } - return self._fetchWork(uid) - - def testFetchAllUID(self): - return self.testFetchAll(1) - - def testFetchFast(self, uid=0): - self.function = self.client.fetchFast - self.messages = '1' - self.msgObjs = [ - FakeyMessage({}, ('\\X',), '19 Mar 2003 19:22:21 -0500', '', 9, None), - ] - self.expected = { - 0: {'FLAGS': ['\\X'], - 'INTERNALDATE': '19-Mar-2003 19:22:21 -0500', - 'RFC822.SIZE': '0'}, - } - return self._fetchWork(uid) - - def testFetchFastUID(self): - return self.testFetchFast(1) - - -class FetchSearchStoreTestCase(unittest.TestCase, IMAP4HelperMixin): - implements(imap4.ISearchableMailbox) - - def setUp(self): - self.expected = self.result = None - self.server_received_query = None - self.server_received_uid = None - self.server_received_parts = None - self.server_received_messages = None - - self.server = imap4.IMAP4Server() - self.server.state = 'select' - self.server.mbox = self - self.connected = defer.Deferred() - self.client = SimpleClient(self.connected) - - def search(self, query, uid): - self.server_received_query = query - self.server_received_uid = uid - return self.expected - - def addListener(self, *a, **kw): - pass - removeListener = addListener - - def _searchWork(self, uid): - def search(): - return self.client.search(self.query, uid=uid) - def result(R): - self.result = R - - self.connected.addCallback(strip(search) - ).addCallback(result - ).addCallback(self._cbStopClient - ).addErrback(self._ebGeneral) - - def check(ignored): - # Ensure no short-circuiting wierdness is going on - self.failIf(self.result is self.expected) - - self.assertEquals(self.result, self.expected) - self.assertEquals(self.uid, self.server_received_uid) - self.assertEquals( - imap4.parseNestedParens(self.query), - self.server_received_query - ) - d = loopback.loopbackTCP(self.server, self.client, noisy=False) - d.addCallback(check) - return d - - def testSearch(self): - self.query = imap4.Or( - imap4.Query(header=('subject', 'substring')), - imap4.Query(larger=1024, smaller=4096), - ) - self.expected = [1, 4, 5, 7] - self.uid = 0 - return self._searchWork(0) - - def testUIDSearch(self): - self.query = imap4.Or( - imap4.Query(header=('subject', 'substring')), - imap4.Query(larger=1024, smaller=4096), - ) - self.uid = 1 - self.expected = [1, 2, 3] - return self._searchWork(1) - - def getUID(self, msg): - try: - return self.expected[msg]['UID'] - except (TypeError, IndexError): - return self.expected[msg-1] - except KeyError: - return 42 - - def fetch(self, messages, uid): - self.server_received_uid = uid - self.server_received_messages = str(messages) - return self.expected - - def _fetchWork(self, fetch): - def result(R): - self.result = R - - self.connected.addCallback(strip(fetch) - ).addCallback(result - ).addCallback(self._cbStopClient - ).addErrback(self._ebGeneral) - - def check(ignored): - # Ensure no short-circuiting wierdness is going on - self.failIf(self.result is self.expected) - - self.parts and self.parts.sort() - self.server_received_parts and self.server_received_parts.sort() - - if self.uid: - for (k, v) in self.expected.items(): - v['UID'] = str(k) - - self.assertEquals(self.result, self.expected) - self.assertEquals(self.uid, self.server_received_uid) - self.assertEquals(self.parts, self.server_received_parts) - self.assertEquals(imap4.parseIdList(self.messages), - imap4.parseIdList(self.server_received_messages)) - - d = loopback.loopbackTCP(self.server, self.client, noisy=False) - d.addCallback(check) - return d - -class FakeMailbox: - def __init__(self): - self.args = [] - def addMessage(self, body, flags, date): - self.args.append((body, flags, date)) - return defer.succeed(None) - -class FeaturefulMessage: - implements(imap4.IMessageFile) - - def getFlags(self): - return 'flags' - - def getInternalDate(self): - return 'internaldate' - - def open(self): - return StringIO("open") - -class MessageCopierMailbox: - implements(imap4.IMessageCopier) - - def __init__(self): - self.msgs = [] - - def copy(self, msg): - self.msgs.append(msg) - return len(self.msgs) - -class CopyWorkerTestCase(unittest.TestCase): - def testFeaturefulMessage(self): - s = imap4.IMAP4Server() - - # Yes. I am grabbing this uber-non-public method to test it. - # It is complex. It needs to be tested directly! - # Perhaps it should be refactored, simplified, or split up into - # not-so-private components, but that is a task for another day. - - # Ha ha! Addendum! Soon it will be split up, and this test will - # be re-written to just use the default adapter for IMailbox to - # IMessageCopier and call .copy on that adapter. - f = s._IMAP4Server__cbCopy - - m = FakeMailbox() - d = f([(i, FeaturefulMessage()) for i in range(1, 11)], 'tag', m) - - def cbCopy(results): - for a in m.args: - self.assertEquals(a[0].read(), "open") - self.assertEquals(a[1], "flags") - self.assertEquals(a[2], "internaldate") - - for (status, result) in results: - self.failUnless(status) - self.assertEquals(result, None) - - return d.addCallback(cbCopy) - - - def testUnfeaturefulMessage(self): - s = imap4.IMAP4Server() - - # See above comment - f = s._IMAP4Server__cbCopy - - m = FakeMailbox() - msgs = [FakeyMessage({'Header-Counter': str(i)}, (), 'Date', 'Body %d' % (i,), i + 10, None) for i in range(1, 11)] - d = f([im for im in zip(range(1, 11), msgs)], 'tag', m) - - def cbCopy(results): - seen = [] - for a in m.args: - seen.append(a[0].read()) - self.assertEquals(a[1], ()) - self.assertEquals(a[2], "Date") - - seen.sort() - exp = ["Header-Counter: %d\r\n\r\nBody %d" % (i, i) for i in range(1, 11)] - exp.sort() - self.assertEquals(seen, exp) - - for (status, result) in results: - self.failUnless(status) - self.assertEquals(result, None) - - return d.addCallback(cbCopy) - - def testMessageCopier(self): - s = imap4.IMAP4Server() - - # See above comment - f = s._IMAP4Server__cbCopy - - m = MessageCopierMailbox() - msgs = [object() for i in range(1, 11)] - d = f([im for im in zip(range(1, 11), msgs)], 'tag', m) - - def cbCopy(results): - self.assertEquals(results, zip([1] * 10, range(1, 11))) - for (orig, new) in zip(msgs, m.msgs): - self.assertIdentical(orig, new) - - return d.addCallback(cbCopy) - - -class TLSTestCase(IMAP4HelperMixin, unittest.TestCase): - serverCTX = ServerTLSContext and ServerTLSContext() - clientCTX = ClientTLSContext and ClientTLSContext() - - def loopback(self): - return loopback.loopbackTCP(self.server, self.client, noisy=False) - - def testAPileOfThings(self): - SimpleServer.theAccount.addMailbox('inbox') - called = [] - def login(): - called.append(None) - return self.client.login('testuser', 'password-test') - def list(): - called.append(None) - return self.client.list('inbox', '%') - def status(): - called.append(None) - return self.client.status('inbox', 'UIDNEXT') - def examine(): - called.append(None) - return self.client.examine('inbox') - def logout(): - called.append(None) - return self.client.logout() - - self.client.requireTransportSecurity = True - - methods = [login, list, status, examine, logout] - map(self.connected.addCallback, map(strip, methods)) - self.connected.addCallbacks(self._cbStopClient, self._ebGeneral) - def check(ignored): - self.assertEquals(self.server.startedTLS, True) - self.assertEquals(self.client.startedTLS, True) - self.assertEquals(len(called), len(methods)) - d = self.loopback() - d.addCallback(check) - return d - - def testLoginLogin(self): - self.server.checker.addUser('testuser', 'password-test') - success = [] - self.client.registerAuthenticator(imap4.LOGINAuthenticator('testuser')) - self.connected.addCallback( - lambda _: self.client.authenticate('password-test') - ).addCallback( - lambda _: self.client.logout() - ).addCallback(success.append - ).addCallback(self._cbStopClient - ).addErrback(self._ebGeneral) - - d = self.loopback() - d.addCallback(lambda x : self.assertEquals(len(success), 1)) - return d - - def testStartTLS(self): - success = [] - self.connected.addCallback(lambda _: self.client.startTLS()) - self.connected.addCallback(lambda _: self.assertNotEquals(-1, self.client.transport.__class__.__name__.find('TLS'))) - self.connected.addCallback(self._cbStopClient) - self.connected.addCallback(success.append) - self.connected.addErrback(self._ebGeneral) - - d = self.loopback() - d.addCallback(lambda x : self.failUnless(success)) - return d - - def testFailedStartTLS(self): - failure = [] - def breakServerTLS(ign): - self.server.canStartTLS = False - - self.connected.addCallback(breakServerTLS) - self.connected.addCallback(lambda ign: self.client.startTLS()) - self.connected.addErrback(lambda err: failure.append(err.trap(imap4.IMAP4Exception))) - self.connected.addCallback(self._cbStopClient) - self.connected.addErrback(self._ebGeneral) - - def check(ignored): - self.failUnless(failure) - self.assertIdentical(failure[0], imap4.IMAP4Exception) - return self.loopback().addCallback(check) - - - -class SlowMailbox(SimpleMailbox): - howSlow = 2 - callLater = None - fetchDeferred = None - - # Not a very nice implementation of fetch(), but it'll - # do for the purposes of testing. - def fetch(self, messages, uid): - d = defer.Deferred() - self.callLater(self.howSlow, d.callback, ()) - self.fetchDeferred.callback(None) - return d - -class Timeout(IMAP4HelperMixin, unittest.TestCase): - - def test_serverTimeout(self): - """ - The *client* has a timeout mechanism which will close connections that - are inactive for a period. - """ - c = Clock() - self.server.timeoutTest = True - self.client.timeout = 5 #seconds - self.client.callLater = c.callLater - self.selectedArgs = None - - def login(): - d = self.client.login('testuser', 'password-test') - c.advance(5) - d.addErrback(timedOut) - return d - - def timedOut(failure): - self._cbStopClient(None) - failure.trap(error.TimeoutError) - - d = self.connected.addCallback(strip(login)) - d.addErrback(self._ebGeneral) - return defer.gatherResults([d, self.loopback()]) - - - def test_longFetchDoesntTimeout(self): - """ - The connection timeout does not take effect during fetches. - """ - c = Clock() - SlowMailbox.callLater = c.callLater - SlowMailbox.fetchDeferred = defer.Deferred() - self.server.callLater = c.callLater - SimpleServer.theAccount.mailboxFactory = SlowMailbox - SimpleServer.theAccount.addMailbox('mailbox-test') - - self.server.setTimeout(1) - - def login(): - return self.client.login('testuser', 'password-test') - def select(): - self.server.setTimeout(1) - return self.client.select('mailbox-test') - def fetch(): - return self.client.fetchUID('1:*') - def stillConnected(): - self.assertNotEquals(self.server.state, 'timeout') - - def cbAdvance(ignored): - for i in xrange(4): - c.advance(.5) - - SlowMailbox.fetchDeferred.addCallback(cbAdvance) - - d1 = self.connected.addCallback(strip(login)) - d1.addCallback(strip(select)) - d1.addCallback(strip(fetch)) - d1.addCallback(strip(stillConnected)) - d1.addCallback(self._cbStopClient) - d1.addErrback(self._ebGeneral) - d = defer.gatherResults([d1, self.loopback()]) - return d - - - def test_idleClientDoesDisconnect(self): - """ - The *server* has a timeout mechanism which will close connections that - are inactive for a period. - """ - c = Clock() - # Hook up our server protocol - transport = StringTransportWithDisconnection() - transport.protocol = self.server - self.server.callLater = c.callLater - self.server.makeConnection(transport) - - # Make sure we can notice when the connection goes away - lost = [] - connLost = self.server.connectionLost - self.server.connectionLost = lambda reason: (lost.append(None), connLost(reason))[1] - - # 2/3rds of the idle timeout elapses... - c.pump([0.0] + [self.server.timeOut / 3.0] * 2) - self.failIf(lost, lost) - - # Now some more - c.pump([0.0, self.server.timeOut / 2.0]) - self.failUnless(lost) - - - -class Disconnection(unittest.TestCase): - def testClientDisconnectFailsDeferreds(self): - c = imap4.IMAP4Client() - t = StringTransportWithDisconnection() - c.makeConnection(t) - d = self.assertFailure(c.login('testuser', 'example.com'), error.ConnectionDone) - c.connectionLost(error.ConnectionDone("Connection closed")) - return d - - - -class SynchronousMailbox(object): - """ - Trivial, in-memory mailbox implementation which can produce a message - synchronously. - """ - def __init__(self, messages): - self.messages = messages - - - def fetch(self, msgset, uid): - assert not uid, "Cannot handle uid requests." - for msg in msgset: - yield msg, self.messages[msg - 1] - - - -class StringTransportConsumer(StringTransport): - producer = None - streaming = None - - def registerProducer(self, producer, streaming): - self.producer = producer - self.streaming = streaming - - - -class Pipelining(unittest.TestCase): - """ - Tests for various aspects of the IMAP4 server's pipelining support. - """ - messages = [ - FakeyMessage({}, [], '', '0', None, None), - FakeyMessage({}, [], '', '1', None, None), - FakeyMessage({}, [], '', '2', None, None), - ] - - def setUp(self): - self.iterators = [] - - self.transport = StringTransportConsumer() - self.server = imap4.IMAP4Server(None, None, self.iterateInReactor) - self.server.makeConnection(self.transport) - - - def iterateInReactor(self, iterator): - d = defer.Deferred() - self.iterators.append((iterator, d)) - return d - - - def tearDown(self): - self.server.connectionLost(failure.Failure(error.ConnectionDone())) - - - def test_synchronousFetch(self): - """ - Test that pipelined FETCH commands which can be responded to - synchronously are responded to correctly. - """ - mailbox = SynchronousMailbox(self.messages) - - # Skip over authentication and folder selection - self.server.state = 'select' - self.server.mbox = mailbox - - # Get rid of any greeting junk - self.transport.clear() - - # Here's some pipelined stuff - self.server.dataReceived( - '01 FETCH 1 BODY[]\r\n' - '02 FETCH 2 BODY[]\r\n' - '03 FETCH 3 BODY[]\r\n') - - # Flush anything the server has scheduled to run - while self.iterators: - for e in self.iterators[0][0]: - break - else: - self.iterators.pop(0)[1].callback(None) - - # The bodies are empty because we aren't simulating a transport - # exactly correctly (we have StringTransportConsumer but we never - # call resumeProducing on its producer). It doesn't matter: just - # make sure the surrounding structure is okay, and that no - # exceptions occurred. - self.assertEquals( - self.transport.value(), - '* 1 FETCH (BODY[] )\r\n' - '01 OK FETCH completed\r\n' - '* 2 FETCH (BODY[] )\r\n' - '02 OK FETCH completed\r\n' - '* 3 FETCH (BODY[] )\r\n' - '03 OK FETCH completed\r\n') - - - -if ClientTLSContext is None: - for case in (TLSTestCase,): - case.skip = "OpenSSL not present" -elif interfaces.IReactorSSL(reactor, None) is None: - for case in (TLSTestCase,): - case.skip = "Reactor doesn't support SSL" diff --git a/tools/buildbot/pylibs/twisted/mail/test/test_mail.py b/tools/buildbot/pylibs/twisted/mail/test/test_mail.py deleted file mode 100644 index 5a888c8..0000000 --- a/tools/buildbot/pylibs/twisted/mail/test/test_mail.py +++ /dev/null @@ -1,1863 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for large portions of L{twisted.mail}. -""" - -import os -import errno -import md5 -import shutil -import pickle -import StringIO -import rfc822 -import tempfile -import signal - -from zope.interface import Interface, implements - -from twisted.trial import unittest -from twisted.mail import smtp -from twisted.mail import pop3 -from twisted.names import dns -from twisted.internet import protocol -from twisted.internet import defer -from twisted.internet.defer import Deferred -from twisted.internet import reactor -from twisted.internet import interfaces -from twisted.internet import task -from twisted.internet.error import DNSLookupError, CannotListenError -from twisted.internet.error import ProcessDone, ProcessTerminated -from twisted.internet import address -from twisted.python import failure -from twisted.python.filepath import FilePath - -from twisted import mail -import twisted.mail.mail -import twisted.mail.maildir -import twisted.mail.relay -import twisted.mail.relaymanager -import twisted.mail.protocols -import twisted.mail.alias - -from twisted.names.error import DNSNameError -from twisted.names.dns import RRHeader, Record_CNAME, Record_MX - -from twisted import cred -import twisted.cred.credentials -import twisted.cred.checkers -import twisted.cred.portal - -from twisted.test.proto_helpers import LineSendingProtocol - -class DomainWithDefaultsTestCase(unittest.TestCase): - def testMethods(self): - d = dict([(x, x + 10) for x in range(10)]) - d = mail.mail.DomainWithDefaultDict(d, 'Default') - - self.assertEquals(len(d), 10) - self.assertEquals(list(iter(d)), range(10)) - self.assertEquals(list(d.iterkeys()), list(iter(d))) - - items = list(d.iteritems()) - items.sort() - self.assertEquals(items, [(x, x + 10) for x in range(10)]) - - values = list(d.itervalues()) - values.sort() - self.assertEquals(values, range(10, 20)) - - items = d.items() - items.sort() - self.assertEquals(items, [(x, x + 10) for x in range(10)]) - - values = d.values() - values.sort() - self.assertEquals(values, range(10, 20)) - - for x in range(10): - self.assertEquals(d[x], x + 10) - self.assertEquals(d.get(x), x + 10) - self.failUnless(x in d) - self.failUnless(d.has_key(x)) - - del d[2], d[4], d[6] - - self.assertEquals(len(d), 7) - self.assertEquals(d[2], 'Default') - self.assertEquals(d[4], 'Default') - self.assertEquals(d[6], 'Default') - - d.update({'a': None, 'b': (), 'c': '*'}) - self.assertEquals(len(d), 10) - self.assertEquals(d['a'], None) - self.assertEquals(d['b'], ()) - self.assertEquals(d['c'], '*') - - d.clear() - self.assertEquals(len(d), 0) - - self.assertEquals(d.setdefault('key', 'value'), 'value') - self.assertEquals(d['key'], 'value') - - self.assertEquals(d.popitem(), ('key', 'value')) - self.assertEquals(len(d), 0) - - dcopy = d.copy() - self.assertEquals(d.domains, dcopy.domains) - self.assertEquals(d.default, dcopy.default) - - - def _stringificationTest(self, stringifier): - """ - Assert that the class name of a L{mail.mail.DomainWithDefaultDict} - instance and the string-formatted underlying domain dictionary both - appear in the string produced by the given string-returning function. - - @type stringifier: one-argument callable - @param stringifier: either C{str} or C{repr}, to be used to get a - string to make assertions against. - """ - domain = mail.mail.DomainWithDefaultDict({}, 'Default') - self.assertIn(domain.__class__.__name__, stringifier(domain)) - domain['key'] = 'value' - self.assertIn(str({'key': 'value'}), stringifier(domain)) - - - def test_str(self): - """ - L{DomainWithDefaultDict.__str__} should return a string including - the class name and the domain mapping held by the instance. - """ - self._stringificationTest(str) - - - def test_repr(self): - """ - L{DomainWithDefaultDict.__repr__} should return a string including - the class name and the domain mapping held by the instance. - """ - self._stringificationTest(repr) - - - -class BounceTestCase(unittest.TestCase): - def setUp(self): - self.domain = mail.mail.BounceDomain() - - def testExists(self): - self.assertRaises(smtp.AddressError, self.domain.exists, "any user") - - def testRelay(self): - self.assertEquals( - self.domain.willRelay("random q emailer", "protocol"), - False - ) - - def testMessage(self): - self.assertRaises(NotImplementedError, self.domain.startMessage, "whomever") - - def testAddUser(self): - self.domain.addUser("bob", "password") - self.assertRaises(smtp.SMTPBadRcpt, self.domain.exists, "bob") - -class FileMessageTestCase(unittest.TestCase): - def setUp(self): - self.name = "fileMessage.testFile" - self.final = "final.fileMessage.testFile" - self.f = file(self.name, 'w') - self.fp = mail.mail.FileMessage(self.f, self.name, self.final) - - def tearDown(self): - try: - self.f.close() - except: - pass - try: - os.remove(self.name) - except: - pass - try: - os.remove(self.final) - except: - pass - - def testFinalName(self): - return self.fp.eomReceived().addCallback(self._cbFinalName) - - def _cbFinalName(self, result): - self.assertEquals(result, self.final) - self.failUnless(self.f.closed) - self.failIf(os.path.exists(self.name)) - - def testContents(self): - contents = "first line\nsecond line\nthird line\n" - for line in contents.splitlines(): - self.fp.lineReceived(line) - self.fp.eomReceived() - self.assertEquals(file(self.final).read(), contents) - - def testInterrupted(self): - contents = "first line\nsecond line\n" - for line in contents.splitlines(): - self.fp.lineReceived(line) - self.fp.connectionLost() - self.failIf(os.path.exists(self.name)) - self.failIf(os.path.exists(self.final)) - -class MailServiceTestCase(unittest.TestCase): - def setUp(self): - self.service = mail.mail.MailService() - - def testFactories(self): - f = self.service.getPOP3Factory() - self.failUnless(isinstance(f, protocol.ServerFactory)) - self.failUnless(f.buildProtocol(('127.0.0.1', 12345)), pop3.POP3) - - f = self.service.getSMTPFactory() - self.failUnless(isinstance(f, protocol.ServerFactory)) - self.failUnless(f.buildProtocol(('127.0.0.1', 12345)), smtp.SMTP) - - f = self.service.getESMTPFactory() - self.failUnless(isinstance(f, protocol.ServerFactory)) - self.failUnless(f.buildProtocol(('127.0.0.1', 12345)), smtp.ESMTP) - - def testPortals(self): - o1 = object() - o2 = object() - self.service.portals['domain'] = o1 - self.service.portals[''] = o2 - - self.failUnless(self.service.lookupPortal('domain') is o1) - self.failUnless(self.service.defaultPortal() is o2) - -class FailingMaildirMailboxAppendMessageTask(mail.maildir._MaildirMailboxAppendMessageTask): - _openstate = True - _writestate = True - _renamestate = True - def osopen(self, fn, attr, mode): - if self._openstate: - return os.open(fn, attr, mode) - else: - raise OSError(errno.EPERM, "Faked Permission Problem") - def oswrite(self, fh, data): - if self._writestate: - return os.write(fh, data) - else: - raise OSError(errno.ENOSPC, "Faked Space problem") - def osrename(self, oldname, newname): - if self._renamestate: - return os.rename(oldname, newname) - else: - raise OSError(errno.EPERM, "Faked Permission Problem") - -class MaildirAppendStringTestCase(unittest.TestCase): - def setUp(self): - self.d = self.mktemp() - mail.maildir.initializeMaildir(self.d) - - def tearDown(self): - shutil.rmtree(self.d) - - def _append(self, ignored, mbox): - d = mbox.appendMessage('TEST') - return self.assertFailure(d, Exception) - - def _setState(self, ignored, mbox, rename=None, write=None, open=None): - if rename is not None: - mbox.AppendFactory._renameState = rename - if write is not None: - mbox.AppendFactory._writeState = write - if open is not None: - mbox.AppendFactory._openstate = open - - def testAppend(self): - mbox = mail.maildir.MaildirMailbox(self.d) - mbox.AppendFactory = FailingMaildirMailboxAppendMessageTask - ds = [] - for i in xrange(1, 11): - ds.append(mbox.appendMessage("X" * i)) - ds[-1].addCallback(self.assertEqual, None) - d = defer.gatherResults(ds) - d.addCallback(self._cbTestAppend, mbox) - return d - - def _cbTestAppend(self, result, mbox): - self.assertEquals(len(mbox.listMessages()), - 10) - self.assertEquals(len(mbox.getMessage(5).read()), 6) - # test in the right order: last to first error location. - mbox.AppendFactory._renamestate = False - d = self._append(None, mbox) - d.addCallback(self._setState, mbox, rename=True, write=False) - d.addCallback(self._append, mbox) - d.addCallback(self._setState, mbox, write=True, open=False) - d.addCallback(self._append, mbox) - d.addCallback(self._setState, mbox, open=True) - return d - - -class MaildirAppendFileTestCase(unittest.TestCase): - def setUp(self): - self.d = self.mktemp() - mail.maildir.initializeMaildir(self.d) - - def tearDown(self): - shutil.rmtree(self.d) - - def testAppend(self): - mbox = mail.maildir.MaildirMailbox(self.d) - ds = [] - def _check(res, t): - t.close() - self.assertEqual(res, None) - for i in xrange(1, 11): - temp = tempfile.TemporaryFile() - temp.write("X" * i) - temp.seek(0,0) - ds.append(mbox.appendMessage(temp)) - ds[-1].addCallback(_check, temp) - return defer.gatherResults(ds).addCallback(self._cbTestAppend, mbox) - - def _cbTestAppend(self, result, mbox): - self.assertEquals(len(mbox.listMessages()), - 10) - self.assertEquals(len(mbox.getMessage(5).read()), 6) - - -class MaildirTestCase(unittest.TestCase): - def setUp(self): - self.d = self.mktemp() - mail.maildir.initializeMaildir(self.d) - - def tearDown(self): - shutil.rmtree(self.d) - - def testInitializer(self): - d = self.d - trash = os.path.join(d, '.Trash') - - self.failUnless(os.path.exists(d) and os.path.isdir(d)) - self.failUnless(os.path.exists(os.path.join(d, 'new'))) - self.failUnless(os.path.exists(os.path.join(d, 'cur'))) - self.failUnless(os.path.exists(os.path.join(d, 'tmp'))) - self.failUnless(os.path.isdir(os.path.join(d, 'new'))) - self.failUnless(os.path.isdir(os.path.join(d, 'cur'))) - self.failUnless(os.path.isdir(os.path.join(d, 'tmp'))) - - self.failUnless(os.path.exists(os.path.join(trash, 'new'))) - self.failUnless(os.path.exists(os.path.join(trash, 'cur'))) - self.failUnless(os.path.exists(os.path.join(trash, 'tmp'))) - self.failUnless(os.path.isdir(os.path.join(trash, 'new'))) - self.failUnless(os.path.isdir(os.path.join(trash, 'cur'))) - self.failUnless(os.path.isdir(os.path.join(trash, 'tmp'))) - - def testMailbox(self): - j = os.path.join - n = mail.maildir._generateMaildirName - msgs = [j(b, n()) for b in ('cur', 'new') for x in range(5)] - - # Toss a few files into the mailbox - i = 1 - for f in msgs: - f = file(j(self.d, f), 'w') - f.write('x' * i) - f.close() - i = i + 1 - - mb = mail.maildir.MaildirMailbox(self.d) - self.assertEquals(mb.listMessages(), range(1, 11)) - self.assertEquals(mb.listMessages(1), 2) - self.assertEquals(mb.listMessages(5), 6) - - self.assertEquals(mb.getMessage(6).read(), 'x' * 7) - self.assertEquals(mb.getMessage(1).read(), 'x' * 2) - - d = {} - for i in range(10): - u = mb.getUidl(i) - self.failIf(u in d) - d[u] = None - - p, f = os.path.split(msgs[5]) - - mb.deleteMessage(5) - self.assertEquals(mb.listMessages(5), 0) - self.failUnless(os.path.exists(j(self.d, '.Trash', 'cur', f))) - self.failIf(os.path.exists(j(self.d, msgs[5]))) - - mb.undeleteMessages() - self.assertEquals(mb.listMessages(5), 6) - self.failIf(os.path.exists(j(self.d, '.Trash', 'cur', f))) - self.failUnless(os.path.exists(j(self.d, msgs[5]))) - -class MaildirDirdbmDomainTestCase(unittest.TestCase): - def setUp(self): - self.P = self.mktemp() - self.S = mail.mail.MailService() - self.D = mail.maildir.MaildirDirdbmDomain(self.S, self.P) - - def tearDown(self): - shutil.rmtree(self.P) - - def testAddUser(self): - toAdd = (('user1', 'pwd1'), ('user2', 'pwd2'), ('user3', 'pwd3')) - for (u, p) in toAdd: - self.D.addUser(u, p) - - for (u, p) in toAdd: - self.failUnless(u in self.D.dbm) - self.assertEquals(self.D.dbm[u], p) - self.failUnless(os.path.exists(os.path.join(self.P, u))) - - def testCredentials(self): - creds = self.D.getCredentialsCheckers() - - self.assertEquals(len(creds), 1) - self.failUnless(cred.checkers.ICredentialsChecker.providedBy(creds[0])) - self.failUnless(cred.credentials.IUsernamePassword in creds[0].credentialInterfaces) - - def testRequestAvatar(self): - class ISomething(Interface): - pass - - self.D.addUser('user', 'password') - self.assertRaises( - NotImplementedError, - self.D.requestAvatar, 'user', None, ISomething - ) - - t = self.D.requestAvatar('user', None, pop3.IMailbox) - self.assertEquals(len(t), 3) - self.failUnless(t[0] is pop3.IMailbox) - self.failUnless(pop3.IMailbox.providedBy(t[1])) - - t[2]() - - def testRequestAvatarId(self): - self.D.addUser('user', 'password') - database = self.D.getCredentialsCheckers()[0] - - creds = cred.credentials.UsernamePassword('user', 'wrong password') - self.assertRaises( - cred.error.UnauthorizedLogin, - database.requestAvatarId, creds - ) - - creds = cred.credentials.UsernamePassword('user', 'password') - self.assertEquals(database.requestAvatarId(creds), 'user') - - -class StubAliasableDomain(object): - """ - Minimal testable implementation of IAliasableDomain. - """ - implements(mail.mail.IAliasableDomain) - - def exists(self, user): - """ - No test coverage for invocations of this method on domain objects, - so we just won't implement it. - """ - raise NotImplementedError() - - - def addUser(self, user, password): - """ - No test coverage for invocations of this method on domain objects, - so we just won't implement it. - """ - raise NotImplementedError() - - - def getCredentialsCheckers(self): - """ - This needs to succeed in order for other tests to complete - successfully, but we don't actually assert anything about its - behavior. Return an empty list. Sometime later we should return - something else and assert that a portal got set up properly. - """ - return [] - - - def setAliasGroup(self, aliases): - """ - Just record the value so the test can check it later. - """ - self.aliasGroup = aliases - - -class ServiceDomainTestCase(unittest.TestCase): - def setUp(self): - self.S = mail.mail.MailService() - self.D = mail.protocols.DomainDeliveryBase(self.S, None) - self.D.service = self.S - self.D.protocolName = 'TEST' - self.D.host = 'hostname' - - self.tmpdir = self.mktemp() - domain = mail.maildir.MaildirDirdbmDomain(self.S, self.tmpdir) - domain.addUser('user', 'password') - self.S.addDomain('test.domain', domain) - - def tearDown(self): - shutil.rmtree(self.tmpdir) - - - def testAddAliasableDomain(self): - """ - Test that adding an IAliasableDomain to a mail service properly sets - up alias group references and such. - """ - aliases = object() - domain = StubAliasableDomain() - self.S.aliases = aliases - self.S.addDomain('example.com', domain) - self.assertIdentical(domain.aliasGroup, aliases) - - - def testReceivedHeader(self): - hdr = self.D.receivedHeader( - ('remotehost', '123.232.101.234'), - smtp.Address(''), - ['user@host.name'] - ) - fp = StringIO.StringIO(hdr) - m = rfc822.Message(fp) - self.assertEquals(len(m.items()), 1) - self.failUnless(m.has_key('Received')) - - def testValidateTo(self): - user = smtp.User('user@test.domain', 'helo', None, 'wherever@whatever') - return defer.maybeDeferred(self.D.validateTo, user - ).addCallback(self._cbValidateTo - ) - - def _cbValidateTo(self, result): - self.failUnless(callable(result)) - - def testValidateToBadUsername(self): - user = smtp.User('resu@test.domain', 'helo', None, 'wherever@whatever') - return self.assertFailure( - defer.maybeDeferred(self.D.validateTo, user), - smtp.SMTPBadRcpt) - - def testValidateToBadDomain(self): - user = smtp.User('user@domain.test', 'helo', None, 'wherever@whatever') - return self.assertFailure( - defer.maybeDeferred(self.D.validateTo, user), - smtp.SMTPBadRcpt) - - def testValidateFrom(self): - helo = ('hostname', '127.0.0.1') - origin = smtp.Address('') - self.failUnless(self.D.validateFrom(helo, origin) is origin) - - helo = ('hostname', '1.2.3.4') - origin = smtp.Address('') - self.failUnless(self.D.validateFrom(helo, origin) is origin) - - helo = ('hostname', '1.2.3.4') - origin = smtp.Address('<>') - self.failUnless(self.D.validateFrom(helo, origin) is origin) - - self.assertRaises( - smtp.SMTPBadSender, - self.D.validateFrom, None, origin - ) - -class VirtualPOP3TestCase(unittest.TestCase): - def setUp(self): - self.tmpdir = self.mktemp() - self.S = mail.mail.MailService() - self.D = mail.maildir.MaildirDirdbmDomain(self.S, self.tmpdir) - self.D.addUser('user', 'password') - self.S.addDomain('test.domain', self.D) - - portal = cred.portal.Portal(self.D) - map(portal.registerChecker, self.D.getCredentialsCheckers()) - self.S.portals[''] = self.S.portals['test.domain'] = portal - - self.P = mail.protocols.VirtualPOP3() - self.P.service = self.S - self.P.magic = '' - - def tearDown(self): - shutil.rmtree(self.tmpdir) - - def testAuthenticateAPOP(self): - resp = md5.new(self.P.magic + 'password').hexdigest() - return self.P.authenticateUserAPOP('user', resp - ).addCallback(self._cbAuthenticateAPOP - ) - - def _cbAuthenticateAPOP(self, result): - self.assertEquals(len(result), 3) - self.assertEquals(result[0], pop3.IMailbox) - self.failUnless(pop3.IMailbox.providedBy(result[1])) - result[2]() - - def testAuthenticateIncorrectUserAPOP(self): - resp = md5.new(self.P.magic + 'password').hexdigest() - return self.assertFailure( - self.P.authenticateUserAPOP('resu', resp), - cred.error.UnauthorizedLogin) - - def testAuthenticateIncorrectResponseAPOP(self): - resp = md5.new('wrong digest').hexdigest() - return self.assertFailure( - self.P.authenticateUserAPOP('user', resp), - cred.error.UnauthorizedLogin) - - def testAuthenticatePASS(self): - return self.P.authenticateUserPASS('user', 'password' - ).addCallback(self._cbAuthenticatePASS - ) - - def _cbAuthenticatePASS(self, result): - self.assertEquals(len(result), 3) - self.assertEquals(result[0], pop3.IMailbox) - self.failUnless(pop3.IMailbox.providedBy(result[1])) - result[2]() - - def testAuthenticateBadUserPASS(self): - return self.assertFailure( - self.P.authenticateUserPASS('resu', 'password'), - cred.error.UnauthorizedLogin) - - def testAuthenticateBadPasswordPASS(self): - return self.assertFailure( - self.P.authenticateUserPASS('user', 'wrong password'), - cred.error.UnauthorizedLogin) - -class empty(smtp.User): - def __init__(self): - pass - -class RelayTestCase(unittest.TestCase): - def testExists(self): - service = mail.mail.MailService() - domain = mail.relay.DomainQueuer(service) - - doRelay = [ - address.UNIXAddress('/var/run/mail-relay'), - address.IPv4Address('TCP', '127.0.0.1', 12345), - ] - - dontRelay = [ - address.IPv4Address('TCP', '192.168.2.1', 62), - address.IPv4Address('TCP', '1.2.3.4', 1943), - ] - - for peer in doRelay: - user = empty() - user.orig = 'user@host' - user.dest = 'tsoh@resu' - user.protocol = empty() - user.protocol.transport = empty() - user.protocol.transport.getPeer = lambda: peer - - self.failUnless(callable(domain.exists(user))) - - for peer in dontRelay: - user = empty() - user.orig = 'some@place' - user.protocol = empty() - user.protocol.transport = empty() - user.protocol.transport.getPeer = lambda: peer - user.dest = 'who@cares' - - self.assertRaises(smtp.SMTPBadRcpt, domain.exists, user) - -class RelayerTestCase(unittest.TestCase): - def setUp(self): - self.tmpdir = self.mktemp() - os.mkdir(self.tmpdir) - self.messageFiles = [] - for i in range(10): - name = os.path.join(self.tmpdir, 'body-%d' % (i,)) - f = file(name + '-H', 'w') - pickle.dump(['from-%d' % (i,), 'to-%d' % (i,)], f) - f.close() - - f = file(name + '-D', 'w') - f.write(name) - f.seek(0, 0) - self.messageFiles.append(name) - - self.R = mail.relay.RelayerMixin() - self.R.loadMessages(self.messageFiles) - - def tearDown(self): - shutil.rmtree(self.tmpdir) - - def testMailFrom(self): - for i in range(10): - self.assertEquals(self.R.getMailFrom(), 'from-%d' % (i,)) - self.R.sentMail(250, None, None, None, None) - self.assertEquals(self.R.getMailFrom(), None) - - def testMailTo(self): - for i in range(10): - self.assertEquals(self.R.getMailTo(), ['to-%d' % (i,)]) - self.R.sentMail(250, None, None, None, None) - self.assertEquals(self.R.getMailTo(), None) - - def testMailData(self): - for i in range(10): - name = os.path.join(self.tmpdir, 'body-%d' % (i,)) - self.assertEquals(self.R.getMailData().read(), name) - self.R.sentMail(250, None, None, None, None) - self.assertEquals(self.R.getMailData(), None) - -class Manager: - def __init__(self): - self.success = [] - self.failure = [] - self.done = [] - - def notifySuccess(self, factory, message): - self.success.append((factory, message)) - - def notifyFailure(self, factory, message): - self.failure.append((factory, message)) - - def notifyDone(self, factory): - self.done.append(factory) - -class ManagedRelayerTestCase(unittest.TestCase): - def setUp(self): - self.manager = Manager() - self.messages = range(0, 20, 2) - self.factory = object() - self.relay = mail.relaymanager.ManagedRelayerMixin(self.manager) - self.relay.messages = self.messages[:] - self.relay.names = self.messages[:] - self.relay.factory = self.factory - - def testSuccessfulSentMail(self): - for i in self.messages: - self.relay.sentMail(250, None, None, None, None) - - self.assertEquals( - self.manager.success, - [(self.factory, m) for m in self.messages] - ) - - def testFailedSentMail(self): - for i in self.messages: - self.relay.sentMail(550, None, None, None, None) - - self.assertEquals( - self.manager.failure, - [(self.factory, m) for m in self.messages] - ) - - def testConnectionLost(self): - self.relay.connectionLost(failure.Failure(Exception())) - self.assertEquals(self.manager.done, [self.factory]) - -class DirectoryQueueTestCase(unittest.TestCase): - def setUp(self): - # This is almost a test case itself. - self.tmpdir = self.mktemp() - os.mkdir(self.tmpdir) - self.queue = mail.relaymanager.Queue(self.tmpdir) - self.queue.noisy = False - for m in range(25): - hdrF, msgF = self.queue.createNewMessage() - pickle.dump(['header', m], hdrF) - hdrF.close() - msgF.lineReceived('body: %d' % (m,)) - msgF.eomReceived() - self.queue.readDirectory() - - def tearDown(self): - shutil.rmtree(self.tmpdir) - - def testWaiting(self): - self.failUnless(self.queue.hasWaiting()) - self.assertEquals(len(self.queue.getWaiting()), 25) - - waiting = self.queue.getWaiting() - self.queue.setRelaying(waiting[0]) - self.assertEquals(len(self.queue.getWaiting()), 24) - - self.queue.setWaiting(waiting[0]) - self.assertEquals(len(self.queue.getWaiting()), 25) - - def testRelaying(self): - for m in self.queue.getWaiting(): - self.queue.setRelaying(m) - self.assertEquals( - len(self.queue.getRelayed()), - 25 - len(self.queue.getWaiting()) - ) - - self.failIf(self.queue.hasWaiting()) - - relayed = self.queue.getRelayed() - self.queue.setWaiting(relayed[0]) - self.assertEquals(len(self.queue.getWaiting()), 1) - self.assertEquals(len(self.queue.getRelayed()), 24) - - def testDone(self): - msg = self.queue.getWaiting()[0] - self.queue.setRelaying(msg) - self.queue.done(msg) - - self.assertEquals(len(self.queue.getWaiting()), 24) - self.assertEquals(len(self.queue.getRelayed()), 0) - - self.failIf(msg in self.queue.getWaiting()) - self.failIf(msg in self.queue.getRelayed()) - - def testEnvelope(self): - envelopes = [] - - for msg in self.queue.getWaiting(): - envelopes.append(self.queue.getEnvelope(msg)) - - envelopes.sort() - for i in range(25): - self.assertEquals( - envelopes.pop(0), - ['header', i] - ) - -from twisted.names import server -from twisted.names import client -from twisted.names import common - -class TestAuthority(common.ResolverBase): - def __init__(self): - common.ResolverBase.__init__(self) - self.addresses = {} - - def _lookup(self, name, cls, type, timeout = None): - if name in self.addresses and type == dns.MX: - results = [] - for a in self.addresses[name]: - hdr = dns.RRHeader( - name, dns.MX, dns.IN, 60, dns.Record_MX(0, a) - ) - results.append(hdr) - return defer.succeed((results, [], [])) - return defer.fail(failure.Failure(dns.DomainError(name))) - -def setUpDNS(self): - self.auth = TestAuthority() - factory = server.DNSServerFactory([self.auth]) - protocol = dns.DNSDatagramProtocol(factory) - while 1: - self.port = reactor.listenTCP(0, factory, interface='127.0.0.1') - portNumber = self.port.getHost().port - - try: - self.udpPort = reactor.listenUDP(portNumber, protocol, interface='127.0.0.1') - except CannotListenError: - self.port.stopListening() - else: - break - self.resolver = client.Resolver(servers=[('127.0.0.1', portNumber)]) - - -def tearDownDNS(self): - dl = [] - dl.append(defer.maybeDeferred(self.port.stopListening)) - dl.append(defer.maybeDeferred(self.udpPort.stopListening)) - if self.resolver.protocol.transport is not None: - dl.append(defer.maybeDeferred(self.resolver.protocol.transport.stopListening)) - try: - self.resolver._parseCall.cancel() - except: - pass - return defer.DeferredList(dl) - -class MXTestCase(unittest.TestCase): - """ - Tests for L{mail.relaymanager.MXCalculator}. - """ - def setUp(self): - setUpDNS(self) - self.clock = task.Clock() - self.mx = mail.relaymanager.MXCalculator(self.resolver, self.clock) - - def tearDown(self): - return tearDownDNS(self) - - - def test_defaultClock(self): - """ - L{MXCalculator}'s default clock is C{twisted.internet.reactor}. - """ - self.assertIdentical( - mail.relaymanager.MXCalculator(self.resolver).clock, - reactor) - - - def testSimpleSuccess(self): - self.auth.addresses['test.domain'] = ['the.email.test.domain'] - return self.mx.getMX('test.domain').addCallback(self._cbSimpleSuccess) - - def _cbSimpleSuccess(self, mx): - self.assertEquals(mx.preference, 0) - self.assertEquals(str(mx.name), 'the.email.test.domain') - - def testSimpleFailure(self): - self.mx.fallbackToDomain = False - return self.assertFailure(self.mx.getMX('test.domain'), IOError) - - def testSimpleFailureWithFallback(self): - return self.assertFailure(self.mx.getMX('test.domain'), DNSLookupError) - - - def _exchangeTest(self, domain, records, correctMailExchange): - """ - Issue an MX request for the given domain and arrange for it to be - responded to with the given records. Verify that the resulting mail - exchange is the indicated host. - - @type domain: C{str} - @type records: C{list} of L{RRHeader} - @type correctMailExchange: C{str} - @rtype: L{Deferred} - """ - class DummyResolver(object): - def lookupMailExchange(self, name): - if name == domain: - return defer.succeed(( - records, - [], - [])) - return defer.fail(DNSNameError(domain)) - - self.mx.resolver = DummyResolver() - d = self.mx.getMX(domain) - def gotMailExchange(record): - self.assertEqual(str(record.name), correctMailExchange) - d.addCallback(gotMailExchange) - return d - - - def test_mailExchangePreference(self): - """ - The MX record with the lowest preference is returned by - L{MXCalculator.getMX}. - """ - domain = "example.com" - good = "good.example.com" - bad = "bad.example.com" - - records = [ - RRHeader(name=domain, - type=Record_MX.TYPE, - payload=Record_MX(1, bad)), - RRHeader(name=domain, - type=Record_MX.TYPE, - payload=Record_MX(0, good)), - RRHeader(name=domain, - type=Record_MX.TYPE, - payload=Record_MX(2, bad))] - return self._exchangeTest(domain, records, good) - - - def test_badExchangeExcluded(self): - """ - L{MXCalculator.getMX} returns the MX record with the lowest preference - which is not also marked as bad. - """ - domain = "example.com" - good = "good.example.com" - bad = "bad.example.com" - - records = [ - RRHeader(name=domain, - type=Record_MX.TYPE, - payload=Record_MX(0, bad)), - RRHeader(name=domain, - type=Record_MX.TYPE, - payload=Record_MX(1, good))] - self.mx.markBad(bad) - return self._exchangeTest(domain, records, good) - - - def test_fallbackForAllBadExchanges(self): - """ - L{MXCalculator.getMX} returns the MX record with the lowest preference - if all the MX records in the response have been marked bad. - """ - domain = "example.com" - bad = "bad.example.com" - worse = "worse.example.com" - - records = [ - RRHeader(name=domain, - type=Record_MX.TYPE, - payload=Record_MX(0, bad)), - RRHeader(name=domain, - type=Record_MX.TYPE, - payload=Record_MX(1, worse))] - self.mx.markBad(bad) - self.mx.markBad(worse) - return self._exchangeTest(domain, records, bad) - - - def test_badExchangeExpires(self): - """ - L{MXCalculator.getMX} returns the MX record with the lowest preference - if it was last marked bad longer than L{MXCalculator.timeOutBadMX} - seconds ago. - """ - domain = "example.com" - good = "good.example.com" - previouslyBad = "bad.example.com" - - records = [ - RRHeader(name=domain, - type=Record_MX.TYPE, - payload=Record_MX(0, previouslyBad)), - RRHeader(name=domain, - type=Record_MX.TYPE, - payload=Record_MX(1, good))] - self.mx.markBad(previouslyBad) - self.clock.advance(self.mx.timeOutBadMX) - return self._exchangeTest(domain, records, previouslyBad) - - - def test_goodExchangeUsed(self): - """ - L{MXCalculator.getMX} returns the MX record with the lowest preference - if it was marked good after it was marked bad. - """ - domain = "example.com" - good = "good.example.com" - previouslyBad = "bad.example.com" - - records = [ - RRHeader(name=domain, - type=Record_MX.TYPE, - payload=Record_MX(0, previouslyBad)), - RRHeader(name=domain, - type=Record_MX.TYPE, - payload=Record_MX(1, good))] - self.mx.markBad(previouslyBad) - self.mx.markGood(previouslyBad) - self.clock.advance(self.mx.timeOutBadMX) - return self._exchangeTest(domain, records, previouslyBad) - - - def test_successWithoutResults(self): - """ - If an MX lookup succeeds but the result set is empty, - L{MXCalculator.getMX} should try to look up an I{A} record for the - requested name and call back its returned Deferred with that - address. - """ - ip = '1.2.3.4' - domain = 'example.org' - - class DummyResolver(object): - """ - Fake resolver which will respond to an MX lookup with an empty - result set. - - @ivar mx: A dictionary mapping hostnames to three-tuples of - results to be returned from I{MX} lookups. - - @ivar a: A dictionary mapping hostnames to addresses to be - returned from I{A} lookups. - """ - mx = {domain: ([], [], [])} - a = {domain: ip} - - def lookupMailExchange(self, domain): - return defer.succeed(self.mx[domain]) - - def getHostByName(self, domain): - return defer.succeed(self.a[domain]) - - self.mx.resolver = DummyResolver() - d = self.mx.getMX(domain) - d.addCallback(self.assertEqual, Record_MX(name=ip)) - return d - - - def test_failureWithSuccessfulFallback(self): - """ - Test that if the MX record lookup fails, fallback is enabled, and an A - record is available for the name, then the Deferred returned by - L{MXCalculator.getMX} ultimately fires with a Record_MX instance which - gives the address in the A record for the name. - """ - class DummyResolver(object): - """ - Fake resolver which will fail an MX lookup but then succeed a - getHostByName call. - """ - def lookupMailExchange(self, domain): - return defer.fail(DNSNameError()) - - def getHostByName(self, domain): - return defer.succeed("1.2.3.4") - - self.mx.resolver = DummyResolver() - d = self.mx.getMX("domain") - d.addCallback(self.assertEqual, Record_MX(name="1.2.3.4")) - return d - - - def test_cnameWithoutGlueRecords(self): - """ - If an MX lookup returns a single CNAME record as a result, MXCalculator - will perform an MX lookup for the canonical name indicated and return - the MX record which results. - """ - alias = "alias.example.com" - canonical = "canonical.example.com" - exchange = "mail.example.com" - - class DummyResolver(object): - """ - Fake resolver which will return a CNAME for an MX lookup of a name - which is an alias and an MX for an MX lookup of the canonical name. - """ - def lookupMailExchange(self, domain): - if domain == alias: - return defer.succeed(( - [RRHeader(name=domain, - type=Record_CNAME.TYPE, - payload=Record_CNAME(canonical))], - [], [])) - elif domain == canonical: - return defer.succeed(( - [RRHeader(name=domain, - type=Record_MX.TYPE, - payload=Record_MX(0, exchange))], - [], [])) - else: - return defer.fail(DNSNameError(domain)) - - self.mx.resolver = DummyResolver() - d = self.mx.getMX(alias) - d.addCallback(self.assertEqual, Record_MX(name=exchange)) - return d - - - def test_cnameChain(self): - """ - If L{MXCalculator.getMX} encounters a CNAME chain which is longer than - the length specified, the returned L{Deferred} should errback with - L{CanonicalNameChainTooLong}. - """ - class DummyResolver(object): - """ - Fake resolver which generates a CNAME chain of infinite length in - response to MX lookups. - """ - chainCounter = 0 - - def lookupMailExchange(self, domain): - self.chainCounter += 1 - name = 'x-%d.example.com' % (self.chainCounter,) - return defer.succeed(( - [RRHeader(name=domain, - type=Record_CNAME.TYPE, - payload=Record_CNAME(name))], - [], [])) - - cnameLimit = 3 - self.mx.resolver = DummyResolver() - d = self.mx.getMX("mail.example.com", cnameLimit) - self.assertFailure( - d, twisted.mail.relaymanager.CanonicalNameChainTooLong) - def cbChainTooLong(error): - self.assertEqual(error.args[0], Record_CNAME("x-%d.example.com" % (cnameLimit + 1,))) - self.assertEqual(self.mx.resolver.chainCounter, cnameLimit + 1) - d.addCallback(cbChainTooLong) - return d - - - def test_cnameWithGlueRecords(self): - """ - If an MX lookup returns a CNAME and the MX record for the CNAME, the - L{Deferred} returned by L{MXCalculator.getMX} should be called back - with the name from the MX record without further lookups being - attempted. - """ - lookedUp = [] - alias = "alias.example.com" - canonical = "canonical.example.com" - exchange = "mail.example.com" - - class DummyResolver(object): - def lookupMailExchange(self, domain): - if domain != alias or lookedUp: - # Don't give back any results for anything except the alias - # or on any request after the first. - return ([], [], []) - return defer.succeed(( - [RRHeader(name=alias, - type=Record_CNAME.TYPE, - payload=Record_CNAME(canonical)), - RRHeader(name=canonical, - type=Record_MX.TYPE, - payload=Record_MX(name=exchange))], - [], [])) - - self.mx.resolver = DummyResolver() - d = self.mx.getMX(alias) - d.addCallback(self.assertEqual, Record_MX(name=exchange)) - return d - - - def test_cnameLoopWithGlueRecords(self): - """ - If an MX lookup returns two CNAME records which point to each other, - the loop should be detected and the L{Deferred} returned by - L{MXCalculator.getMX} should be errbacked with L{CanonicalNameLoop}. - """ - firstAlias = "cname1.example.com" - secondAlias = "cname2.example.com" - - class DummyResolver(object): - def lookupMailExchange(self, domain): - return defer.succeed(( - [RRHeader(name=firstAlias, - type=Record_CNAME.TYPE, - payload=Record_CNAME(secondAlias)), - RRHeader(name=secondAlias, - type=Record_CNAME.TYPE, - payload=Record_CNAME(firstAlias))], - [], [])) - - self.mx.resolver = DummyResolver() - d = self.mx.getMX(firstAlias) - self.assertFailure(d, twisted.mail.relaymanager.CanonicalNameLoop) - return d - - - def testManyRecords(self): - self.auth.addresses['test.domain'] = [ - 'mx1.test.domain', 'mx2.test.domain', 'mx3.test.domain' - ] - return self.mx.getMX('test.domain' - ).addCallback(self._cbManyRecordsSuccessfulLookup - ) - - def _cbManyRecordsSuccessfulLookup(self, mx): - self.failUnless(str(mx.name).split('.', 1)[0] in ('mx1', 'mx2', 'mx3')) - self.mx.markBad(str(mx.name)) - return self.mx.getMX('test.domain' - ).addCallback(self._cbManyRecordsDifferentResult, mx - ) - - def _cbManyRecordsDifferentResult(self, nextMX, mx): - self.assertNotEqual(str(mx.name), str(nextMX.name)) - self.mx.markBad(str(nextMX.name)) - - return self.mx.getMX('test.domain' - ).addCallback(self._cbManyRecordsLastResult, mx, nextMX - ) - - def _cbManyRecordsLastResult(self, lastMX, mx, nextMX): - self.assertNotEqual(str(mx.name), str(lastMX.name)) - self.assertNotEqual(str(nextMX.name), str(lastMX.name)) - - self.mx.markBad(str(lastMX.name)) - self.mx.markGood(str(nextMX.name)) - - return self.mx.getMX('test.domain' - ).addCallback(self._cbManyRecordsRepeatSpecificResult, nextMX - ) - - def _cbManyRecordsRepeatSpecificResult(self, againMX, nextMX): - self.assertEqual(str(againMX.name), str(nextMX.name)) - -class LiveFireExercise(unittest.TestCase): - if interfaces.IReactorUDP(reactor, None) is None: - skip = "UDP support is required to determining MX records" - - def setUp(self): - setUpDNS(self) - self.tmpdirs = [ - 'domainDir', 'insertionDomain', 'insertionQueue', - 'destinationDomain', 'destinationQueue' - ] - - def tearDown(self): - for d in self.tmpdirs: - if os.path.exists(d): - shutil.rmtree(d) - return tearDownDNS(self) - - def testLocalDelivery(self): - service = mail.mail.MailService() - service.smtpPortal.registerChecker(cred.checkers.AllowAnonymousAccess()) - domain = mail.maildir.MaildirDirdbmDomain(service, 'domainDir') - domain.addUser('user', 'password') - service.addDomain('test.domain', domain) - service.portals[''] = service.portals['test.domain'] - map(service.portals[''].registerChecker, domain.getCredentialsCheckers()) - - service.setQueue(mail.relay.DomainQueuer(service)) - manager = mail.relaymanager.SmartHostSMTPRelayingManager(service.queue, None) - helper = mail.relaymanager.RelayStateHelper(manager, 1) - - f = service.getSMTPFactory() - - self.smtpServer = reactor.listenTCP(0, f, interface='127.0.0.1') - - client = LineSendingProtocol([ - 'HELO meson', - 'MAIL FROM: ', - 'RCPT TO: ', - 'DATA', - 'This is the message', - '.', - 'QUIT' - ]) - - done = Deferred() - f = protocol.ClientFactory() - f.protocol = lambda: client - f.clientConnectionLost = lambda *args: done.callback(None) - reactor.connectTCP('127.0.0.1', self.smtpServer.getHost().port, f) - - def finished(ign): - mbox = domain.requestAvatar('user', None, pop3.IMailbox)[1] - msg = mbox.getMessage(0).read() - self.failIfEqual(msg.find('This is the message'), -1) - - return self.smtpServer.stopListening() - done.addCallback(finished) - return done - - - def testRelayDelivery(self): - # Here is the service we will connect to and send mail from - insServ = mail.mail.MailService() - insServ.smtpPortal.registerChecker(cred.checkers.AllowAnonymousAccess()) - domain = mail.maildir.MaildirDirdbmDomain(insServ, 'insertionDomain') - insServ.addDomain('insertion.domain', domain) - os.mkdir('insertionQueue') - insServ.setQueue(mail.relaymanager.Queue('insertionQueue')) - insServ.domains.setDefaultDomain(mail.relay.DomainQueuer(insServ)) - manager = mail.relaymanager.SmartHostSMTPRelayingManager(insServ.queue) - manager.fArgs += ('test.identity.hostname',) - helper = mail.relaymanager.RelayStateHelper(manager, 1) - # Yoink! Now the internet obeys OUR every whim! - manager.mxcalc = mail.relaymanager.MXCalculator(self.resolver) - # And this is our whim. - self.auth.addresses['destination.domain'] = ['127.0.0.1'] - - f = insServ.getSMTPFactory() - self.insServer = reactor.listenTCP(0, f, interface='127.0.0.1') - - # Here is the service the previous one will connect to for final - # delivery - destServ = mail.mail.MailService() - destServ.smtpPortal.registerChecker(cred.checkers.AllowAnonymousAccess()) - domain = mail.maildir.MaildirDirdbmDomain(destServ, 'destinationDomain') - domain.addUser('user', 'password') - destServ.addDomain('destination.domain', domain) - os.mkdir('destinationQueue') - destServ.setQueue(mail.relaymanager.Queue('destinationQueue')) - manager2 = mail.relaymanager.SmartHostSMTPRelayingManager(destServ.queue) - helper = mail.relaymanager.RelayStateHelper(manager, 1) - helper.startService() - - f = destServ.getSMTPFactory() - self.destServer = reactor.listenTCP(0, f, interface='127.0.0.1') - - # Update the port number the *first* relay will connect to, because we can't use - # port 25 - manager.PORT = self.destServer.getHost().port - - client = LineSendingProtocol([ - 'HELO meson', - 'MAIL FROM: ', - 'RCPT TO: ', - 'DATA', - 'This is the message', - '.', - 'QUIT' - ]) - - done = Deferred() - f = protocol.ClientFactory() - f.protocol = lambda: client - f.clientConnectionLost = lambda *args: done.callback(None) - reactor.connectTCP('127.0.0.1', self.insServer.getHost().port, f) - - def finished(ign): - # First part of the delivery is done. Poke the queue manually now - # so we don't have to wait for the queue to be flushed. - delivery = manager.checkState() - def delivered(ign): - mbox = domain.requestAvatar('user', None, pop3.IMailbox)[1] - msg = mbox.getMessage(0).read() - self.failIfEqual(msg.find('This is the message'), -1) - - self.insServer.stopListening() - self.destServer.stopListening() - helper.stopService() - delivery.addCallback(delivered) - return delivery - done.addCallback(finished) - return done - - -aliasFile = StringIO.StringIO("""\ -# Here's a comment - # woop another one -testuser: address1,address2, address3, - continuation@address, |/bin/process/this - -usertwo:thisaddress,thataddress, lastaddress -lastuser: :/includable, /filename, |/program, address -""") - -class LineBufferMessage: - def __init__(self): - self.lines = [] - self.eom = False - self.lost = False - - def lineReceived(self, line): - self.lines.append(line) - - def eomReceived(self): - self.eom = True - return defer.succeed('') - - def connectionLost(self): - self.lost = True - -class AliasTestCase(unittest.TestCase): - lines = [ - 'First line', - 'Next line', - '', - 'After a blank line', - 'Last line' - ] - - def setUp(self): - aliasFile.seek(0) - - def testHandle(self): - result = {} - lines = [ - 'user: another@host\n', - 'nextuser: |/bin/program\n', - 'user: me@again\n', - 'moreusers: :/etc/include/filename\n', - 'multiuser: first@host, second@host,last@anotherhost', - ] - - for l in lines: - mail.alias.handle(result, l, 'TestCase', None) - - self.assertEquals(result['user'], ['another@host', 'me@again']) - self.assertEquals(result['nextuser'], ['|/bin/program']) - self.assertEquals(result['moreusers'], [':/etc/include/filename']) - self.assertEquals(result['multiuser'], ['first@host', 'second@host', 'last@anotherhost']) - - def testFileLoader(self): - domains = {'': object()} - result = mail.alias.loadAliasFile(domains, fp=aliasFile) - - self.assertEquals(len(result), 3) - - group = result['testuser'] - s = str(group) - for a in ('address1', 'address2', 'address3', 'continuation@address', '/bin/process/this'): - self.failIfEqual(s.find(a), -1) - self.assertEquals(len(group), 5) - - group = result['usertwo'] - s = str(group) - for a in ('thisaddress', 'thataddress', 'lastaddress'): - self.failIfEqual(s.find(a), -1) - self.assertEquals(len(group), 3) - - group = result['lastuser'] - s = str(group) - self.failUnlessEqual(s.find('/includable'), -1) - for a in ('/filename', 'program', 'address'): - self.failIfEqual(s.find(a), -1, '%s not found' % a) - self.assertEquals(len(group), 3) - - def testMultiWrapper(self): - msgs = LineBufferMessage(), LineBufferMessage(), LineBufferMessage() - msg = mail.alias.MultiWrapper(msgs) - - for L in self.lines: - msg.lineReceived(L) - return msg.eomReceived().addCallback(self._cbMultiWrapper, msgs) - - def _cbMultiWrapper(self, ignored, msgs): - for m in msgs: - self.failUnless(m.eom) - self.failIf(m.lost) - self.assertEquals(self.lines, m.lines) - - def testFileAlias(self): - tmpfile = self.mktemp() - a = mail.alias.FileAlias(tmpfile, None, None) - m = a.createMessageReceiver() - - for l in self.lines: - m.lineReceived(l) - return m.eomReceived().addCallback(self._cbTestFileAlias, tmpfile) - - def _cbTestFileAlias(self, ignored, tmpfile): - lines = file(tmpfile).readlines() - self.assertEquals([L[:-1] for L in lines], self.lines) - - - -class DummyProcess(object): - __slots__ = ['onEnd'] - - - -class MockProcessAlias(mail.alias.ProcessAlias): - """ - A alias processor that doesn't actually launch processes. - """ - - def spawnProcess(self, proto, program, path): - """ - Don't spawn a process. - """ - - - -class MockAliasGroup(mail.alias.AliasGroup): - """ - An alias group using C{MockProcessAlias}. - """ - processAliasFactory = MockProcessAlias - - - -class StubProcess(object): - """ - Fake implementation of L{IProcessTransport}. - - @ivar signals: A list of all the signals which have been sent to this fake - process. - """ - def __init__(self): - self.signals = [] - - - def loseConnection(self): - """ - No-op implementation of disconnection. - """ - - - def signalProcess(self, signal): - """ - Record a signal sent to this process for later inspection. - """ - self.signals.append(signal) - - - -class ProcessAliasTestCase(unittest.TestCase): - """ - Tests for alias resolution. - """ - - lines = [ - 'First line', - 'Next line', - '', - 'After a blank line', - 'Last line' - ] - - def exitStatus(self, code): - """ - Construct a status from the given exit code. - - @type code: L{int} between 0 and 255 inclusive. - @param code: The exit status which the code will represent. - - @rtype: L{int} - @return: A status integer for the given exit code. - """ - # /* Macros for constructing status values. */ - # #define __W_EXITCODE(ret, sig) ((ret) << 8 | (sig)) - status = (code << 8) | 0 - - # Sanity check - self.assertTrue(os.WIFEXITED(status)) - self.assertEqual(os.WEXITSTATUS(status), code) - self.assertFalse(os.WIFSIGNALED(status)) - - return status - - - def signalStatus(self, signal): - """ - Construct a status from the given signal. - - @type signal: L{int} between 0 and 255 inclusive. - @param signal: The signal number which the status will represent. - - @rtype: L{int} - @return: A status integer for the given signal. - """ - # /* If WIFSIGNALED(STATUS), the terminating signal. */ - # #define __WTERMSIG(status) ((status) & 0x7f) - # /* Nonzero if STATUS indicates termination by a signal. */ - # #define __WIFSIGNALED(status) \ - # (((signed char) (((status) & 0x7f) + 1) >> 1) > 0) - status = signal - - # Sanity check - self.assertTrue(os.WIFSIGNALED(status)) - self.assertEqual(os.WTERMSIG(status), signal) - self.assertFalse(os.WIFEXITED(status)) - - return status - - - def setUp(self): - """ - Replace L{smtp.DNSNAME} with a well-known value. - """ - self.DNSNAME = smtp.DNSNAME - smtp.DNSNAME = '' - - - def tearDown(self): - """ - Restore the original value of L{smtp.DNSNAME}. - """ - smtp.DNSNAME = self.DNSNAME - - - def test_processAlias(self): - """ - Standard call to C{mail.alias.ProcessAlias}: check that the specified - script is called, and that the input is correctly transferred to it. - """ - sh = FilePath(self.mktemp()) - sh.setContent("""\ -#!/bin/sh -rm -f process.alias.out -while read i; do - echo $i >> process.alias.out -done""") - os.chmod(sh.path, 0700) - a = mail.alias.ProcessAlias(sh.path, None, None) - m = a.createMessageReceiver() - - for l in self.lines: - m.lineReceived(l) - - def _cbProcessAlias(ignored): - lines = file('process.alias.out').readlines() - self.assertEquals([L[:-1] for L in lines], self.lines) - - return m.eomReceived().addCallback(_cbProcessAlias) - - - def test_processAliasTimeout(self): - """ - If the alias child process does not exit within a particular period of - time, the L{Deferred} returned by L{MessageWrapper.eomReceived} should - fail with L{ProcessAliasTimeout} and send the I{KILL} signal to the - child process.. - """ - reactor = task.Clock() - transport = StubProcess() - proto = mail.alias.ProcessAliasProtocol() - proto.makeConnection(transport) - - receiver = mail.alias.MessageWrapper(proto, None, reactor) - d = receiver.eomReceived() - reactor.advance(receiver.completionTimeout) - def timedOut(ignored): - self.assertEqual(transport.signals, ['KILL']) - # Now that it has been killed, disconnect the protocol associated - # with it. - proto.processEnded( - ProcessTerminated(self.signalStatus(signal.SIGKILL))) - self.assertFailure(d, mail.alias.ProcessAliasTimeout) - d.addCallback(timedOut) - return d - - - def test_earlyProcessTermination(self): - """ - If the process associated with an L{mail.alias.MessageWrapper} exits - before I{eomReceived} is called, the L{Deferred} returned by - I{eomReceived} should fail. - """ - transport = StubProcess() - protocol = mail.alias.ProcessAliasProtocol() - protocol.makeConnection(transport) - receiver = mail.alias.MessageWrapper(protocol, None, None) - protocol.processEnded(failure.Failure(ProcessDone(0))) - return self.assertFailure(receiver.eomReceived(), ProcessDone) - - - def _terminationTest(self, status): - """ - Verify that if the process associated with an - L{mail.alias.MessageWrapper} exits with the given status, the - L{Deferred} returned by I{eomReceived} fails with L{ProcessTerminated}. - """ - transport = StubProcess() - protocol = mail.alias.ProcessAliasProtocol() - protocol.makeConnection(transport) - receiver = mail.alias.MessageWrapper(protocol, None, None) - protocol.processEnded( - failure.Failure(ProcessTerminated(status))) - return self.assertFailure(receiver.eomReceived(), ProcessTerminated) - - - def test_errorProcessTermination(self): - """ - If the process associated with an L{mail.alias.MessageWrapper} exits - with a non-zero exit code, the L{Deferred} returned by I{eomReceived} - should fail. - """ - return self._terminationTest(self.exitStatus(1)) - - - def test_signalProcessTermination(self): - """ - If the process associated with an L{mail.alias.MessageWrapper} exits - because it received a signal, the L{Deferred} returned by - I{eomReceived} should fail. - """ - return self._terminationTest(self.signalStatus(signal.SIGHUP)) - - - def test_aliasResolution(self): - """ - Check that the C{resolve} method of alias processors produce the correct - set of objects: - - direct alias with L{mail.alias.AddressAlias} if a simple input is passed - - aliases in a file with L{mail.alias.FileWrapper} if an input in the format - '/file' is given - - aliases resulting of a process call wrapped by L{mail.alias.MessageWrapper} - if the format is '|process' - """ - aliases = {} - domain = {'': TestDomain(aliases, ['user1', 'user2', 'user3'])} - A1 = MockAliasGroup(['user1', '|echo', '/file'], domain, 'alias1') - A2 = MockAliasGroup(['user2', 'user3'], domain, 'alias2') - A3 = mail.alias.AddressAlias('alias1', domain, 'alias3') - aliases.update({ - 'alias1': A1, - 'alias2': A2, - 'alias3': A3, - }) - - res1 = A1.resolve(aliases) - r1 = map(str, res1.objs) - r1.sort() - expected = map(str, [ - mail.alias.AddressAlias('user1', None, None), - mail.alias.MessageWrapper(DummyProcess(), 'echo'), - mail.alias.FileWrapper('/file'), - ]) - expected.sort() - self.assertEquals(r1, expected) - - res2 = A2.resolve(aliases) - r2 = map(str, res2.objs) - r2.sort() - expected = map(str, [ - mail.alias.AddressAlias('user2', None, None), - mail.alias.AddressAlias('user3', None, None) - ]) - expected.sort() - self.assertEquals(r2, expected) - - res3 = A3.resolve(aliases) - r3 = map(str, res3.objs) - r3.sort() - expected = map(str, [ - mail.alias.AddressAlias('user1', None, None), - mail.alias.MessageWrapper(DummyProcess(), 'echo'), - mail.alias.FileWrapper('/file'), - ]) - expected.sort() - self.assertEquals(r3, expected) - - - def test_cyclicAlias(self): - """ - Check that a cycle in alias resolution is correctly handled. - """ - aliases = {} - domain = {'': TestDomain(aliases, [])} - A1 = mail.alias.AddressAlias('alias2', domain, 'alias1') - A2 = mail.alias.AddressAlias('alias3', domain, 'alias2') - A3 = mail.alias.AddressAlias('alias1', domain, 'alias3') - aliases.update({ - 'alias1': A1, - 'alias2': A2, - 'alias3': A3 - }) - - self.assertEquals(aliases['alias1'].resolve(aliases), None) - self.assertEquals(aliases['alias2'].resolve(aliases), None) - self.assertEquals(aliases['alias3'].resolve(aliases), None) - - A4 = MockAliasGroup(['|echo', 'alias1'], domain, 'alias4') - aliases['alias4'] = A4 - - res = A4.resolve(aliases) - r = map(str, res.objs) - r.sort() - expected = map(str, [ - mail.alias.MessageWrapper(DummyProcess(), 'echo') - ]) - expected.sort() - self.assertEquals(r, expected) - - - -if interfaces.IReactorProcess(reactor, None) is None: - ProcessAliasTestCase = "IReactorProcess not supported" - - - -class TestDomain: - def __init__(self, aliases, users): - self.aliases = aliases - self.users = users - - def exists(self, user, memo=None): - user = user.dest.local - if user in self.users: - return lambda: mail.alias.AddressAlias(user, None, None) - try: - a = self.aliases[user] - except: - raise smtp.SMTPBadRcpt(user) - else: - aliases = a.resolve(self.aliases, memo) - if aliases: - return lambda: aliases - raise smtp.SMTPBadRcpt(user) - - -from twisted.python.runtime import platformType -import types -if platformType != "posix": - for o in locals().values(): - if isinstance(o, (types.ClassType, type)) and issubclass(o, unittest.TestCase): - o.skip = "twisted.mail only works on posix" diff --git a/tools/buildbot/pylibs/twisted/mail/test/test_options.py b/tools/buildbot/pylibs/twisted/mail/test/test_options.py deleted file mode 100644 index 65c360b..0000000 --- a/tools/buildbot/pylibs/twisted/mail/test/test_options.py +++ /dev/null @@ -1,38 +0,0 @@ - -from twisted.trial.unittest import TestCase - -from twisted.python.usage import UsageError -from twisted.mail.tap import Options - - -class OptionsTestCase(TestCase): - """ - Tests for the command line option parser used for C{mktap mail}. - """ - def setUp(self): - self.aliasFilename = self.mktemp() - aliasFile = file(self.aliasFilename, 'w') - aliasFile.write('someuser:\tdifferentuser\n') - aliasFile.close() - - - def testAliasesWithoutDomain(self): - """ - Test that adding an aliases(5) file before adding a domain raises a - UsageError. - """ - self.assertRaises( - UsageError, - Options().parseOptions, - ['--aliases', self.aliasFilename]) - - - def testAliases(self): - """ - Test that adding an aliases(5) file to an IAliasableDomain at least - doesn't raise an unhandled exception. - """ - Options().parseOptions([ - '--maildirdbmdomain', 'example.com=example.com', - '--aliases', self.aliasFilename]) - diff --git a/tools/buildbot/pylibs/twisted/mail/test/test_pop3.py b/tools/buildbot/pylibs/twisted/mail/test/test_pop3.py deleted file mode 100644 index 2830218..0000000 --- a/tools/buildbot/pylibs/twisted/mail/test/test_pop3.py +++ /dev/null @@ -1,1071 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Test cases for twisted.mail.pop3 module. -""" - -import StringIO -import string -import hmac -import base64 -import itertools - -from zope.interface import implements - -from twisted.internet import defer - -from twisted.trial import unittest, util -from twisted import mail -import twisted.mail.protocols -import twisted.mail.pop3 -import twisted.internet.protocol -from twisted import internet -from twisted.mail import pop3 -from twisted.protocols import loopback -from twisted.python import failure - -from twisted import cred -import twisted.cred.portal -import twisted.cred.checkers -import twisted.cred.credentials - -from twisted.test.proto_helpers import LineSendingProtocol - - -class UtilityTestCase(unittest.TestCase): - """ - Test the various helper functions and classes used by the POP3 server - protocol implementation. - """ - - def testLineBuffering(self): - """ - Test creating a LineBuffer and feeding it some lines. The lines should - build up in its internal buffer for a while and then get spat out to - the writer. - """ - output = [] - input = iter(itertools.cycle(['012', '345', '6', '7', '8', '9'])) - c = pop3._IteratorBuffer(output.extend, input, 6) - i = iter(c) - self.assertEquals(output, []) # nothing is buffer - i.next() - self.assertEquals(output, []) # '012' is buffered - i.next() - self.assertEquals(output, []) # '012345' is buffered - i.next() - self.assertEquals(output, ['012', '345', '6']) # nothing is buffered - for n in range(5): - i.next() - self.assertEquals(output, ['012', '345', '6', '7', '8', '9', '012', '345']) - - - def testFinishLineBuffering(self): - """ - Test that a LineBuffer flushes everything when its iterator is - exhausted, and itself raises StopIteration. - """ - output = [] - input = iter(['a', 'b', 'c']) - c = pop3._IteratorBuffer(output.extend, input, 5) - for i in c: - pass - self.assertEquals(output, ['a', 'b', 'c']) - - - def testSuccessResponseFormatter(self): - """ - Test that the thing that spits out POP3 'success responses' works - right. - """ - self.assertEquals( - pop3.successResponse('Great.'), - '+OK Great.\r\n') - - - def testStatLineFormatter(self): - """ - Test that the function which formats stat lines does so appropriately. - """ - statLine = list(pop3.formatStatResponse([]))[-1] - self.assertEquals(statLine, '+OK 0 0\r\n') - - statLine = list(pop3.formatStatResponse([10, 31, 0, 10101]))[-1] - self.assertEquals(statLine, '+OK 4 10142\r\n') - - - def testListLineFormatter(self): - """ - Test that the function which formats the lines in response to a LIST - command does so appropriately. - """ - listLines = list(pop3.formatListResponse([])) - self.assertEquals( - listLines, - ['+OK 0\r\n', '.\r\n']) - - listLines = list(pop3.formatListResponse([1, 2, 3, 100])) - self.assertEquals( - listLines, - ['+OK 4\r\n', '1 1\r\n', '2 2\r\n', '3 3\r\n', '4 100\r\n', '.\r\n']) - - - - def testUIDListLineFormatter(self): - """ - Test that the function which formats lines in response to a UIDL - command does so appropriately. - """ - UIDs = ['abc', 'def', 'ghi'] - listLines = list(pop3.formatUIDListResponse([], UIDs.__getitem__)) - self.assertEquals( - listLines, - ['+OK \r\n', '.\r\n']) - - listLines = list(pop3.formatUIDListResponse([123, 431, 591], UIDs.__getitem__)) - self.assertEquals( - listLines, - ['+OK \r\n', '1 abc\r\n', '2 def\r\n', '3 ghi\r\n', '.\r\n']) - - listLines = list(pop3.formatUIDListResponse([0, None, 591], UIDs.__getitem__)) - self.assertEquals( - listLines, - ['+OK \r\n', '1 abc\r\n', '3 ghi\r\n', '.\r\n']) - - - -class MyVirtualPOP3(mail.protocols.VirtualPOP3): - - magic = '' - - def authenticateUserAPOP(self, user, digest): - user, domain = self.lookupDomain(user) - return self.service.domains['baz.com'].authenticateUserAPOP(user, digest, self.magic, domain) - -class DummyDomain: - - def __init__(self): - self.users = {} - - def addUser(self, name): - self.users[name] = [] - - def addMessage(self, name, message): - self.users[name].append(message) - - def authenticateUserAPOP(self, name, digest, magic, domain): - return pop3.IMailbox, ListMailbox(self.users[name]), lambda: None - - -class ListMailbox: - - def __init__(self, list): - self.list = list - - def listMessages(self, i=None): - if i is None: - return map(len, self.list) - return len(self.list[i]) - - def getMessage(self, i): - return StringIO.StringIO(self.list[i]) - - def getUidl(self, i): - return i - - def deleteMessage(self, i): - self.list[i] = '' - - def sync(self): - pass - -class MyPOP3Downloader(pop3.POP3Client): - - def handle_WELCOME(self, line): - pop3.POP3Client.handle_WELCOME(self, line) - self.apop('hello@baz.com', 'world') - - def handle_APOP(self, line): - parts = line.split() - code = parts[0] - data = (parts[1:] or ['NONE'])[0] - if code != '+OK': - print parts - raise AssertionError, 'code is ' + code - self.lines = [] - self.retr(1) - - def handle_RETR_continue(self, line): - self.lines.append(line) - - def handle_RETR_end(self): - self.message = '\n'.join(self.lines) + '\n' - self.quit() - - def handle_QUIT(self, line): - if line[:3] != '+OK': - raise AssertionError, 'code is ' + line - - -class POP3TestCase(unittest.TestCase): - - message = '''\ -Subject: urgent - -Someone set up us the bomb! -''' - - expectedOutput = '''\ -+OK \015 -+OK Authentication succeeded\015 -+OK \015 -1 0\015 -.\015 -+OK %d\015 -Subject: urgent\015 -\015 -Someone set up us the bomb!\015 -.\015 -+OK \015 -''' % len(message) - - def setUp(self): - self.factory = internet.protocol.Factory() - self.factory.domains = {} - self.factory.domains['baz.com'] = DummyDomain() - self.factory.domains['baz.com'].addUser('hello') - self.factory.domains['baz.com'].addMessage('hello', self.message) - - def testMessages(self): - client = LineSendingProtocol([ - 'APOP hello@baz.com world', - 'UIDL', - 'RETR 1', - 'QUIT', - ]) - server = MyVirtualPOP3() - server.service = self.factory - def check(ignored): - output = '\r\n'.join(client.response) + '\r\n' - self.assertEquals(output, self.expectedOutput) - return loopback.loopbackTCP(server, client).addCallback(check) - - def testLoopback(self): - protocol = MyVirtualPOP3() - protocol.service = self.factory - clientProtocol = MyPOP3Downloader() - def check(ignored): - self.failUnlessEqual(clientProtocol.message, self.message) - protocol.connectionLost( - failure.Failure(Exception("Test harness disconnect"))) - d = loopback.loopbackAsync(protocol, clientProtocol) - return d.addCallback(check) - testLoopback.suppress = [util.suppress(message="twisted.mail.pop3.POP3Client is deprecated")] - - - -class DummyPOP3(pop3.POP3): - - magic = '' - - def authenticateUserAPOP(self, user, password): - return pop3.IMailbox, DummyMailbox(ValueError), lambda: None - - - -class DummyMailbox(pop3.Mailbox): - - messages = [ -'''\ -From: moshe -To: moshe - -How are you, friend? -'''] - - def __init__(self, exceptionType): - self.messages = DummyMailbox.messages[:] - self.exceptionType = exceptionType - - def listMessages(self, i=None): - if i is None: - return map(len, self.messages) - if i >= len(self.messages): - raise self.exceptionType() - return len(self.messages[i]) - - def getMessage(self, i): - return StringIO.StringIO(self.messages[i]) - - def getUidl(self, i): - if i >= len(self.messages): - raise self.exceptionType() - return str(i) - - def deleteMessage(self, i): - self.messages[i] = '' - - -class AnotherPOP3TestCase(unittest.TestCase): - - def runTest(self, lines): - dummy = DummyPOP3() - client = LineSendingProtocol([ - "APOP moshez dummy", - "LIST", - "UIDL", - "RETR 1", - "RETR 2", - "DELE 1", - "RETR 1", - "QUIT", - ]) - d = loopback.loopbackAsync(dummy, client) - return d.addCallback(self._cbRunTest, client, dummy) - - def _cbRunTest(self, ignored, client, dummy): - expected_output = [ - '+OK ', - '+OK Authentication succeeded', - '+OK 1', - '1 44', - '.', - '+OK ', - '1 0', - '.', - '+OK 44', - 'From: moshe', - 'To: moshe', - '', - 'How are you, friend?', - '', - '.', - '-ERR Bad message number argument', - '+OK ', - '-ERR message deleted', - '+OK ', - '' - ] - self.failUnlessEqual('\r\n'.join(expected_output), - '\r\n'.join(client.response) + '\r\n') - dummy.connectionLost(failure.Failure(Exception("Test harness disconnect"))) - return ignored - - - def testBuffer(self): - lines = string.split('''\ -APOP moshez dummy -LIST -UIDL -RETR 1 -RETR 2 -DELE 1 -RETR 1 -QUIT''', '\n') - return self.runTest(lines) - - def testNoop(self): - lines = ['APOP spiv dummy', 'NOOP', 'QUIT'] - return self.runTest(lines) - - def testAuthListing(self): - p = DummyPOP3() - p.factory = internet.protocol.Factory() - p.factory.challengers = {'Auth1': None, 'secondAuth': None, 'authLast': None} - client = LineSendingProtocol([ - "AUTH", - "QUIT", - ]) - - d = loopback.loopbackAsync(p, client) - return d.addCallback(self._cbTestAuthListing, client) - - def _cbTestAuthListing(self, ignored, client): - self.failUnless(client.response[1].startswith('+OK')) - self.assertEquals(client.response[2:6], - ["AUTH1", "SECONDAUTH", "AUTHLAST", "."]) - - def testIllegalPASS(self): - dummy = DummyPOP3() - client = LineSendingProtocol([ - "PASS fooz", - "QUIT" - ]) - d = loopback.loopbackAsync(dummy, client) - return d.addCallback(self._cbTestIllegalPASS, client, dummy) - - def _cbTestIllegalPASS(self, ignored, client, dummy): - expected_output = '+OK \r\n-ERR USER required before PASS\r\n+OK \r\n' - self.failUnlessEqual(expected_output, '\r\n'.join(client.response) + '\r\n') - dummy.connectionLost(failure.Failure(Exception("Test harness disconnect"))) - - def testEmptyPASS(self): - dummy = DummyPOP3() - client = LineSendingProtocol([ - "PASS ", - "QUIT" - ]) - d = loopback.loopbackAsync(dummy, client) - return d.addCallback(self._cbTestEmptyPASS, client, dummy) - - def _cbTestEmptyPASS(self, ignored, client, dummy): - expected_output = '+OK \r\n-ERR USER required before PASS\r\n+OK \r\n' - self.failUnlessEqual(expected_output, '\r\n'.join(client.response) + '\r\n') - dummy.connectionLost(failure.Failure(Exception("Test harness disconnect"))) - - -class TestServerFactory: - implements(pop3.IServerFactory) - - def cap_IMPLEMENTATION(self): - return "Test Implementation String" - - def cap_EXPIRE(self): - return 60 - - challengers = {"SCHEME_1": None, "SCHEME_2": None} - - def cap_LOGIN_DELAY(self): - return 120 - - pue = True - def perUserExpiration(self): - return self.pue - - puld = True - def perUserLoginDelay(self): - return self.puld - - -class TestMailbox: - loginDelay = 100 - messageExpiration = 25 - - -class CapabilityTestCase(unittest.TestCase): - def setUp(self): - s = StringIO.StringIO() - p = pop3.POP3() - p.factory = TestServerFactory() - p.transport = internet.protocol.FileWrapper(s) - p.connectionMade() - p.do_CAPA() - - self.caps = p.listCapabilities() - self.pcaps = s.getvalue().splitlines() - - s = StringIO.StringIO() - p.mbox = TestMailbox() - p.transport = internet.protocol.FileWrapper(s) - p.do_CAPA() - - self.lpcaps = s.getvalue().splitlines() - p.connectionLost(failure.Failure(Exception("Test harness disconnect"))) - - def contained(self, s, *caps): - for c in caps: - self.assertIn(s, c) - - def testUIDL(self): - self.contained("UIDL", self.caps, self.pcaps, self.lpcaps) - - def testTOP(self): - self.contained("TOP", self.caps, self.pcaps, self.lpcaps) - - def testUSER(self): - self.contained("USER", self.caps, self.pcaps, self.lpcaps) - - def testEXPIRE(self): - self.contained("EXPIRE 60 USER", self.caps, self.pcaps) - self.contained("EXPIRE 25", self.lpcaps) - - def testIMPLEMENTATION(self): - self.contained( - "IMPLEMENTATION Test Implementation String", - self.caps, self.pcaps, self.lpcaps - ) - - def testSASL(self): - self.contained( - "SASL SCHEME_1 SCHEME_2", - self.caps, self.pcaps, self.lpcaps - ) - - def testLOGIN_DELAY(self): - self.contained("LOGIN-DELAY 120 USER", self.caps, self.pcaps) - self.assertIn("LOGIN-DELAY 100", self.lpcaps) - - - -class GlobalCapabilitiesTestCase(unittest.TestCase): - def setUp(self): - s = StringIO.StringIO() - p = pop3.POP3() - p.factory = TestServerFactory() - p.factory.pue = p.factory.puld = False - p.transport = internet.protocol.FileWrapper(s) - p.connectionMade() - p.do_CAPA() - - self.caps = p.listCapabilities() - self.pcaps = s.getvalue().splitlines() - - s = StringIO.StringIO() - p.mbox = TestMailbox() - p.transport = internet.protocol.FileWrapper(s) - p.do_CAPA() - - self.lpcaps = s.getvalue().splitlines() - p.connectionLost(failure.Failure(Exception("Test harness disconnect"))) - - def contained(self, s, *caps): - for c in caps: - self.assertIn(s, c) - - def testEXPIRE(self): - self.contained("EXPIRE 60", self.caps, self.pcaps, self.lpcaps) - - def testLOGIN_DELAY(self): - self.contained("LOGIN-DELAY 120", self.caps, self.pcaps, self.lpcaps) - - - -class TestRealm: - def requestAvatar(self, avatarId, mind, *interfaces): - if avatarId == 'testuser': - return pop3.IMailbox, DummyMailbox(ValueError), lambda: None - assert False - - - -class SASLTestCase(unittest.TestCase): - def testValidLogin(self): - p = pop3.POP3() - p.factory = TestServerFactory() - p.factory.challengers = {'CRAM-MD5': cred.credentials.CramMD5Credentials} - p.portal = cred.portal.Portal(TestRealm()) - ch = cred.checkers.InMemoryUsernamePasswordDatabaseDontUse() - ch.addUser('testuser', 'testpassword') - p.portal.registerChecker(ch) - - s = StringIO.StringIO() - p.transport = internet.protocol.FileWrapper(s) - p.connectionMade() - - p.lineReceived("CAPA") - self.failUnless(s.getvalue().find("SASL CRAM-MD5") >= 0) - - p.lineReceived("AUTH CRAM-MD5") - chal = s.getvalue().splitlines()[-1][2:] - chal = base64.decodestring(chal) - response = hmac.HMAC('testpassword', chal).hexdigest() - - p.lineReceived(base64.encodestring('testuser ' + response).rstrip('\n')) - self.failUnless(p.mbox) - self.failUnless(s.getvalue().splitlines()[-1].find("+OK") >= 0) - p.connectionLost(failure.Failure(Exception("Test harness disconnect"))) - - - -class CommandMixin: - """ - Tests for all the commands a POP3 server is allowed to receive. - """ - - extraMessage = '''\ -From: guy -To: fellow - -More message text for you. -''' - - - def setUp(self): - """ - Make a POP3 server protocol instance hooked up to a simple mailbox and - a transport that buffers output to a StringIO. - """ - p = pop3.POP3() - p.mbox = self.mailboxType(self.exceptionType) - p.schedule = list - self.pop3Server = p - - s = StringIO.StringIO() - p.transport = internet.protocol.FileWrapper(s) - p.connectionMade() - s.truncate(0) - self.pop3Transport = s - - - def tearDown(self): - """ - Disconnect the server protocol so it can clean up anything it might - need to clean up. - """ - self.pop3Server.connectionLost(failure.Failure(Exception("Test harness disconnect"))) - - - def _flush(self): - """ - Do some of the things that the reactor would take care of, if the - reactor were actually running. - """ - # Oh man FileWrapper is pooh. - self.pop3Server.transport._checkProducer() - - - def testLIST(self): - """ - Test the two forms of list: with a message index number, which should - return a short-form response, and without a message index number, which - should return a long-form response, one line per message. - """ - p = self.pop3Server - s = self.pop3Transport - - p.lineReceived("LIST 1") - self._flush() - self.assertEquals(s.getvalue(), "+OK 1 44\r\n") - s.truncate(0) - - p.lineReceived("LIST") - self._flush() - self.assertEquals(s.getvalue(), "+OK 1\r\n1 44\r\n.\r\n") - - - def testLISTWithBadArgument(self): - """ - Test that non-integers and out-of-bound integers produce appropriate - error responses. - """ - p = self.pop3Server - s = self.pop3Transport - - p.lineReceived("LIST a") - self.assertEquals( - s.getvalue(), - "-ERR Invalid message-number: 'a'\r\n") - s.truncate(0) - - p.lineReceived("LIST 0") - self.assertEquals( - s.getvalue(), - "-ERR Invalid message-number: 0\r\n") - s.truncate(0) - - p.lineReceived("LIST 2") - self.assertEquals( - s.getvalue(), - "-ERR Invalid message-number: 2\r\n") - s.truncate(0) - - - def testUIDL(self): - """ - Test the two forms of the UIDL command. These are just like the two - forms of the LIST command. - """ - p = self.pop3Server - s = self.pop3Transport - - p.lineReceived("UIDL 1") - self.assertEquals(s.getvalue(), "+OK 0\r\n") - s.truncate(0) - - p.lineReceived("UIDL") - self._flush() - self.assertEquals(s.getvalue(), "+OK \r\n1 0\r\n.\r\n") - - - def testUIDLWithBadArgument(self): - """ - Test that UIDL with a non-integer or an out-of-bounds integer produces - the appropriate error response. - """ - p = self.pop3Server - s = self.pop3Transport - - p.lineReceived("UIDL a") - self.assertEquals( - s.getvalue(), - "-ERR Bad message number argument\r\n") - s.truncate(0) - - p.lineReceived("UIDL 0") - self.assertEquals( - s.getvalue(), - "-ERR Bad message number argument\r\n") - s.truncate(0) - - p.lineReceived("UIDL 2") - self.assertEquals( - s.getvalue(), - "-ERR Bad message number argument\r\n") - s.truncate(0) - - - def testSTAT(self): - """ - Test the single form of the STAT command, which returns a short-form - response of the number of messages in the mailbox and their total size. - """ - p = self.pop3Server - s = self.pop3Transport - - p.lineReceived("STAT") - self._flush() - self.assertEquals(s.getvalue(), "+OK 1 44\r\n") - - - def testRETR(self): - """ - Test downloading a message. - """ - p = self.pop3Server - s = self.pop3Transport - - p.lineReceived("RETR 1") - self._flush() - self.assertEquals( - s.getvalue(), - "+OK 44\r\n" - "From: moshe\r\n" - "To: moshe\r\n" - "\r\n" - "How are you, friend?\r\n" - ".\r\n") - s.truncate(0) - - - def testRETRWithBadArgument(self): - """ - Test that trying to download a message with a bad argument, either not - an integer or an out-of-bounds integer, fails with the appropriate - error response. - """ - p = self.pop3Server - s = self.pop3Transport - - p.lineReceived("RETR a") - self.assertEquals( - s.getvalue(), - "-ERR Bad message number argument\r\n") - s.truncate(0) - - p.lineReceived("RETR 0") - self.assertEquals( - s.getvalue(), - "-ERR Bad message number argument\r\n") - s.truncate(0) - - p.lineReceived("RETR 2") - self.assertEquals( - s.getvalue(), - "-ERR Bad message number argument\r\n") - s.truncate(0) - - - def testTOP(self): - """ - Test downloading the headers and part of the body of a message. - """ - p = self.pop3Server - s = self.pop3Transport - p.mbox.messages.append(self.extraMessage) - - p.lineReceived("TOP 1 0") - self._flush() - self.assertEquals( - s.getvalue(), - "+OK Top of message follows\r\n" - "From: moshe\r\n" - "To: moshe\r\n" - "\r\n" - ".\r\n") - - - def testTOPWithBadArgument(self): - """ - Test that trying to download a message with a bad argument, either a - message number which isn't an integer or is an out-of-bounds integer or - a number of lines which isn't an integer or is a negative integer, - fails with the appropriate error response. - """ - p = self.pop3Server - s = self.pop3Transport - p.mbox.messages.append(self.extraMessage) - - p.lineReceived("TOP 1 a") - self.assertEquals( - s.getvalue(), - "-ERR Bad line count argument\r\n") - s.truncate(0) - - p.lineReceived("TOP 1 -1") - self.assertEquals( - s.getvalue(), - "-ERR Bad line count argument\r\n") - s.truncate(0) - - p.lineReceived("TOP a 1") - self.assertEquals( - s.getvalue(), - "-ERR Bad message number argument\r\n") - s.truncate(0) - - p.lineReceived("TOP 0 1") - self.assertEquals( - s.getvalue(), - "-ERR Bad message number argument\r\n") - s.truncate(0) - - p.lineReceived("TOP 3 1") - self.assertEquals( - s.getvalue(), - "-ERR Bad message number argument\r\n") - s.truncate(0) - - - def testLAST(self): - """ - Test the exceedingly pointless LAST command, which tells you the - highest message index which you have already downloaded. - """ - p = self.pop3Server - s = self.pop3Transport - p.mbox.messages.append(self.extraMessage) - - p.lineReceived('LAST') - self.assertEquals( - s.getvalue(), - "+OK 0\r\n") - s.truncate(0) - - - def testRetrieveUpdatesHighest(self): - """ - Test that issuing a RETR command updates the LAST response. - """ - p = self.pop3Server - s = self.pop3Transport - p.mbox.messages.append(self.extraMessage) - - p.lineReceived('RETR 2') - self._flush() - s.truncate(0) - p.lineReceived('LAST') - self.assertEquals( - s.getvalue(), - '+OK 2\r\n') - s.truncate(0) - - - def testTopUpdatesHighest(self): - """ - Test that issuing a TOP command updates the LAST response. - """ - p = self.pop3Server - s = self.pop3Transport - p.mbox.messages.append(self.extraMessage) - - p.lineReceived('TOP 2 10') - self._flush() - s.truncate(0) - p.lineReceived('LAST') - self.assertEquals( - s.getvalue(), - '+OK 2\r\n') - - - def testHighestOnlyProgresses(self): - """ - Test that downloading a message with a smaller index than the current - LAST response doesn't change the LAST response. - """ - p = self.pop3Server - s = self.pop3Transport - p.mbox.messages.append(self.extraMessage) - - p.lineReceived('RETR 2') - self._flush() - p.lineReceived('TOP 1 10') - self._flush() - s.truncate(0) - p.lineReceived('LAST') - self.assertEquals( - s.getvalue(), - '+OK 2\r\n') - - - def testResetClearsHighest(self): - """ - Test that issuing RSET changes the LAST response to 0. - """ - p = self.pop3Server - s = self.pop3Transport - p.mbox.messages.append(self.extraMessage) - - p.lineReceived('RETR 2') - self._flush() - p.lineReceived('RSET') - s.truncate(0) - p.lineReceived('LAST') - self.assertEquals( - s.getvalue(), - '+OK 0\r\n') - - - -_listMessageDeprecation = ( - "twisted.mail.pop3.IMailbox.listMessages may not " - "raise IndexError for out-of-bounds message numbers: " - "raise ValueError instead.") -_listMessageSuppression = util.suppress( - message=_listMessageDeprecation, - category=PendingDeprecationWarning) - -_getUidlDeprecation = ( - "twisted.mail.pop3.IMailbox.getUidl may not " - "raise IndexError for out-of-bounds message numbers: " - "raise ValueError instead.") -_getUidlSuppression = util.suppress( - message=_getUidlDeprecation, - category=PendingDeprecationWarning) - -class IndexErrorCommandTestCase(CommandMixin, unittest.TestCase): - """ - Run all of the command tests against a mailbox which raises IndexError - when an out of bounds request is made. This behavior will be deprecated - shortly and then removed. - """ - exceptionType = IndexError - mailboxType = DummyMailbox - - def testLISTWithBadArgument(self): - return CommandMixin.testLISTWithBadArgument(self) - testLISTWithBadArgument.suppress = [_listMessageSuppression] - - - def testUIDLWithBadArgument(self): - return CommandMixin.testUIDLWithBadArgument(self) - testUIDLWithBadArgument.suppress = [_getUidlSuppression] - - - def testTOPWithBadArgument(self): - return CommandMixin.testTOPWithBadArgument(self) - testTOPWithBadArgument.suppress = [_listMessageSuppression] - - - def testRETRWithBadArgument(self): - return CommandMixin.testRETRWithBadArgument(self) - testRETRWithBadArgument.suppress = [_listMessageSuppression] - - - -class ValueErrorCommandTestCase(CommandMixin, unittest.TestCase): - """ - Run all of the command tests against a mailbox which raises ValueError - when an out of bounds request is made. This is the correct behavior and - after support for mailboxes which raise IndexError is removed, this will - become just C{CommandTestCase}. - """ - exceptionType = ValueError - mailboxType = DummyMailbox - - - -class SyncDeferredMailbox(DummyMailbox): - """ - Mailbox which has a listMessages implementation which returns a Deferred - which has already fired. - """ - def listMessages(self, n=None): - return defer.succeed(DummyMailbox.listMessages(self, n)) - - - -class IndexErrorSyncDeferredCommandTestCase(IndexErrorCommandTestCase): - """ - Run all of the L{IndexErrorCommandTestCase} tests with a - synchronous-Deferred returning IMailbox implementation. - """ - mailboxType = SyncDeferredMailbox - - - -class ValueErrorSyncDeferredCommandTestCase(ValueErrorCommandTestCase): - """ - Run all of the L{ValueErrorCommandTestCase} tests with a - synchronous-Deferred returning IMailbox implementation. - """ - mailboxType = SyncDeferredMailbox - - - -class AsyncDeferredMailbox(DummyMailbox): - """ - Mailbox which has a listMessages implementation which returns a Deferred - which has not yet fired. - """ - def __init__(self, *a, **kw): - self.waiting = [] - DummyMailbox.__init__(self, *a, **kw) - - - def listMessages(self, n=None): - d = defer.Deferred() - # See AsyncDeferredMailbox._flush - self.waiting.append((d, DummyMailbox.listMessages(self, n))) - return d - - - -class IndexErrorAsyncDeferredCommandTestCase(IndexErrorCommandTestCase): - """ - Run all of the L{IndexErrorCommandTestCase} tests with an asynchronous-Deferred - returning IMailbox implementation. - """ - mailboxType = AsyncDeferredMailbox - - def _flush(self): - """ - Fire whatever Deferreds we've built up in our mailbox. - """ - while self.pop3Server.mbox.waiting: - d, a = self.pop3Server.mbox.waiting.pop() - d.callback(a) - IndexErrorCommandTestCase._flush(self) - - - -class ValueErrorAsyncDeferredCommandTestCase(ValueErrorCommandTestCase): - """ - Run all of the L{IndexErrorCommandTestCase} tests with an asynchronous-Deferred - returning IMailbox implementation. - """ - mailboxType = AsyncDeferredMailbox - - def _flush(self): - """ - Fire whatever Deferreds we've built up in our mailbox. - """ - while self.pop3Server.mbox.waiting: - d, a = self.pop3Server.mbox.waiting.pop() - d.callback(a) - ValueErrorCommandTestCase._flush(self) - -class POP3MiscTestCase(unittest.TestCase): - """ - Miscellaneous tests more to do with module/package structure than - anything to do with the Post Office Protocol. - """ - def test_all(self): - """ - This test checks that all names listed in - twisted.mail.pop3.__all__ are actually present in the module. - """ - mod = twisted.mail.pop3 - for attr in mod.__all__: - self.failUnless(hasattr(mod, attr)) diff --git a/tools/buildbot/pylibs/twisted/mail/test/test_pop3client.py b/tools/buildbot/pylibs/twisted/mail/test/test_pop3client.py deleted file mode 100644 index e2c3b8d..0000000 --- a/tools/buildbot/pylibs/twisted/mail/test/test_pop3client.py +++ /dev/null @@ -1,573 +0,0 @@ -# -*- test-case-name: twisted.mail.test.test_pop3client -*- -# Copyright (c) 2001-2004 Divmod Inc. -# See LICENSE for details. - -from zope.interface import directlyProvides - -from twisted.mail.pop3 import AdvancedPOP3Client as POP3Client -from twisted.mail.pop3 import InsecureAuthenticationDisallowed -from twisted.mail.pop3 import ServerErrorResponse -from twisted.protocols import loopback -from twisted.internet import reactor, defer, error, protocol, interfaces -from twisted.python import log - -from twisted.trial import unittest -from twisted.test.proto_helpers import StringTransport -from twisted.protocols import basic - -from twisted.mail.test import pop3testserver - -try: - from twisted.test.ssl_helpers import ClientTLSContext, ServerTLSContext -except ImportError: - ClientTLSContext = ServerTLSContext = None - - -class StringTransportWithConnectionLosing(StringTransport): - def loseConnection(self): - self.protocol.connectionLost(error.ConnectionDone()) - - -capCache = {"TOP": None, "LOGIN-DELAY": "180", "UIDL": None, \ - "STLS": None, "USER": None, "SASL": "LOGIN"} -def setUp(greet=True): - p = POP3Client() - - # Skip the CAPA login will issue if it doesn't already have a - # capability cache - p._capCache = capCache - - t = StringTransportWithConnectionLosing() - t.protocol = p - p.makeConnection(t) - - if greet: - p.dataReceived('+OK Hello!\r\n') - - return p, t - -def strip(f): - return lambda result, f=f: f() - -class POP3ClientLoginTestCase(unittest.TestCase): - def testNegativeGreeting(self): - p, t = setUp(greet=False) - p.allowInsecureLogin = True - d = p.login("username", "password") - p.dataReceived('-ERR Offline for maintenance\r\n') - return self.assertFailure( - d, ServerErrorResponse).addCallback( - lambda exc: self.assertEquals(exc.args[0], "Offline for maintenance")) - - - def testOkUser(self): - p, t = setUp() - d = p.user("username") - self.assertEquals(t.value(), "USER username\r\n") - p.dataReceived("+OK send password\r\n") - return d.addCallback(self.assertEqual, "send password") - - def testBadUser(self): - p, t = setUp() - d = p.user("username") - self.assertEquals(t.value(), "USER username\r\n") - p.dataReceived("-ERR account suspended\r\n") - return self.assertFailure( - d, ServerErrorResponse).addCallback( - lambda exc: self.assertEquals(exc.args[0], "account suspended")) - - def testOkPass(self): - p, t = setUp() - d = p.password("password") - self.assertEquals(t.value(), "PASS password\r\n") - p.dataReceived("+OK you're in!\r\n") - return d.addCallback(self.assertEqual, "you're in!") - - def testBadPass(self): - p, t = setUp() - d = p.password("password") - self.assertEquals(t.value(), "PASS password\r\n") - p.dataReceived("-ERR go away\r\n") - return self.assertFailure( - d, ServerErrorResponse).addCallback( - lambda exc: self.assertEquals(exc.args[0], "go away")) - - def testOkLogin(self): - p, t = setUp() - p.allowInsecureLogin = True - d = p.login("username", "password") - self.assertEquals(t.value(), "USER username\r\n") - p.dataReceived("+OK go ahead\r\n") - self.assertEquals(t.value(), "USER username\r\nPASS password\r\n") - p.dataReceived("+OK password accepted\r\n") - return d.addCallback(self.assertEqual, "password accepted") - - def testBadPasswordLogin(self): - p, t = setUp() - p.allowInsecureLogin = True - d = p.login("username", "password") - self.assertEquals(t.value(), "USER username\r\n") - p.dataReceived("+OK waiting on you\r\n") - self.assertEquals(t.value(), "USER username\r\nPASS password\r\n") - p.dataReceived("-ERR bogus login\r\n") - return self.assertFailure( - d, ServerErrorResponse).addCallback( - lambda exc: self.assertEquals(exc.args[0], "bogus login")) - - def testBadUsernameLogin(self): - p, t = setUp() - p.allowInsecureLogin = True - d = p.login("username", "password") - self.assertEquals(t.value(), "USER username\r\n") - p.dataReceived("-ERR bogus login\r\n") - return self.assertFailure( - d, ServerErrorResponse).addCallback( - lambda exc: self.assertEquals(exc.args[0], "bogus login")) - - def testServerGreeting(self): - p, t = setUp(greet=False) - p.dataReceived("+OK lalala this has no challenge\r\n") - self.assertEquals(p.serverChallenge, None) - - def testServerGreetingWithChallenge(self): - p, t = setUp(greet=False) - p.dataReceived("+OK \r\n") - self.assertEquals(p.serverChallenge, "") - - def testAPOP(self): - p, t = setUp(greet=False) - p.dataReceived("+OK \r\n") - d = p.login("username", "password") - self.assertEquals(t.value(), "APOP username f34f1e464d0d7927607753129cabe39a\r\n") - p.dataReceived("+OK Welcome!\r\n") - return d.addCallback(self.assertEqual, "Welcome!") - - def testInsecureLoginRaisesException(self): - p, t = setUp(greet=False) - p.dataReceived("+OK Howdy\r\n") - d = p.login("username", "password") - self.failIf(t.value()) - return self.assertFailure( - d, InsecureAuthenticationDisallowed) - - - def testSSLTransportConsideredSecure(self): - """ - If a server doesn't offer APOP but the transport is secured using - SSL or TLS, a plaintext login should be allowed, not rejected with - an InsecureAuthenticationDisallowed exception. - """ - p, t = setUp(greet=False) - directlyProvides(t, interfaces.ISSLTransport) - p.dataReceived("+OK Howdy\r\n") - d = p.login("username", "password") - self.assertEquals(t.value(), "USER username\r\n") - t.clear() - p.dataReceived("+OK\r\n") - self.assertEquals(t.value(), "PASS password\r\n") - p.dataReceived("+OK\r\n") - return d - - - -class ListConsumer: - def __init__(self): - self.data = {} - - def consume(self, (item, value)): - self.data.setdefault(item, []).append(value) - -class MessageConsumer: - def __init__(self): - self.data = [] - - def consume(self, line): - self.data.append(line) - -class POP3ClientListTestCase(unittest.TestCase): - def testListSize(self): - p, t = setUp() - d = p.listSize() - self.assertEquals(t.value(), "LIST\r\n") - p.dataReceived("+OK Here it comes\r\n") - p.dataReceived("1 3\r\n2 2\r\n3 1\r\n.\r\n") - return d.addCallback(self.assertEqual, [3, 2, 1]) - - def testListSizeWithConsumer(self): - p, t = setUp() - c = ListConsumer() - f = c.consume - d = p.listSize(f) - self.assertEquals(t.value(), "LIST\r\n") - p.dataReceived("+OK Here it comes\r\n") - p.dataReceived("1 3\r\n2 2\r\n3 1\r\n") - self.assertEquals(c.data, {0: [3], 1: [2], 2: [1]}) - p.dataReceived("5 3\r\n6 2\r\n7 1\r\n") - self.assertEquals(c.data, {0: [3], 1: [2], 2: [1], 4: [3], 5: [2], 6: [1]}) - p.dataReceived(".\r\n") - return d.addCallback(self.assertIdentical, f) - - def testFailedListSize(self): - p, t = setUp() - d = p.listSize() - self.assertEquals(t.value(), "LIST\r\n") - p.dataReceived("-ERR Fatal doom server exploded\r\n") - return self.assertFailure( - d, ServerErrorResponse).addCallback( - lambda exc: self.assertEquals(exc.args[0], "Fatal doom server exploded")) - - def testListUID(self): - p, t = setUp() - d = p.listUID() - self.assertEquals(t.value(), "UIDL\r\n") - p.dataReceived("+OK Here it comes\r\n") - p.dataReceived("1 abc\r\n2 def\r\n3 ghi\r\n.\r\n") - return d.addCallback(self.assertEqual, ["abc", "def", "ghi"]) - - def testListUIDWithConsumer(self): - p, t = setUp() - c = ListConsumer() - f = c.consume - d = p.listUID(f) - self.assertEquals(t.value(), "UIDL\r\n") - p.dataReceived("+OK Here it comes\r\n") - p.dataReceived("1 xyz\r\n2 abc\r\n5 mno\r\n") - self.assertEquals(c.data, {0: ["xyz"], 1: ["abc"], 4: ["mno"]}) - p.dataReceived(".\r\n") - return d.addCallback(self.assertIdentical, f) - - def testFailedListUID(self): - p, t = setUp() - d = p.listUID() - self.assertEquals(t.value(), "UIDL\r\n") - p.dataReceived("-ERR Fatal doom server exploded\r\n") - return self.assertFailure( - d, ServerErrorResponse).addCallback( - lambda exc: self.assertEquals(exc.args[0], "Fatal doom server exploded")) - -class POP3ClientMessageTestCase(unittest.TestCase): - def testRetrieve(self): - p, t = setUp() - d = p.retrieve(7) - self.assertEquals(t.value(), "RETR 8\r\n") - p.dataReceived("+OK Message incoming\r\n") - p.dataReceived("La la la here is message text\r\n") - p.dataReceived("..Further message text tra la la\r\n") - p.dataReceived(".\r\n") - return d.addCallback( - self.assertEqual, - ["La la la here is message text", - ".Further message text tra la la"]) - - def testRetrieveWithConsumer(self): - p, t = setUp() - c = MessageConsumer() - f = c.consume - d = p.retrieve(7, f) - self.assertEquals(t.value(), "RETR 8\r\n") - p.dataReceived("+OK Message incoming\r\n") - p.dataReceived("La la la here is message text\r\n") - p.dataReceived("..Further message text\r\n.\r\n") - return d.addCallback(self._cbTestRetrieveWithConsumer, f, c) - - def _cbTestRetrieveWithConsumer(self, result, f, c): - self.assertIdentical(result, f) - self.assertEquals(c.data, ["La la la here is message text", - ".Further message text"]) - - def testPartialRetrieve(self): - p, t = setUp() - d = p.retrieve(7, lines=2) - self.assertEquals(t.value(), "TOP 8 2\r\n") - p.dataReceived("+OK 2 lines on the way\r\n") - p.dataReceived("Line the first! Woop\r\n") - p.dataReceived("Line the last! Bye\r\n") - p.dataReceived(".\r\n") - return d.addCallback( - self.assertEqual, - ["Line the first! Woop", - "Line the last! Bye"]) - - def testPartialRetrieveWithConsumer(self): - p, t = setUp() - c = MessageConsumer() - f = c.consume - d = p.retrieve(7, f, lines=2) - self.assertEquals(t.value(), "TOP 8 2\r\n") - p.dataReceived("+OK 2 lines on the way\r\n") - p.dataReceived("Line the first! Woop\r\n") - p.dataReceived("Line the last! Bye\r\n") - p.dataReceived(".\r\n") - return d.addCallback(self._cbTestPartialRetrieveWithConsumer, f, c) - - def _cbTestPartialRetrieveWithConsumer(self, result, f, c): - self.assertIdentical(result, f) - self.assertEquals(c.data, ["Line the first! Woop", - "Line the last! Bye"]) - - def testFailedRetrieve(self): - p, t = setUp() - d = p.retrieve(0) - self.assertEquals(t.value(), "RETR 1\r\n") - p.dataReceived("-ERR Fatal doom server exploded\r\n") - return self.assertFailure( - d, ServerErrorResponse).addCallback( - lambda exc: self.assertEquals(exc.args[0], "Fatal doom server exploded")) - - - def test_concurrentRetrieves(self): - """ - Issue three retrieve calls immediately without waiting for any to - succeed and make sure they all do succeed eventually. - """ - p, t = setUp() - messages = [ - p.retrieve(i).addCallback( - self.assertEquals, - ["First line of %d." % (i + 1,), - "Second line of %d." % (i + 1,)]) - for i - in range(3)] - - for i in range(1, 4): - self.assertEquals(t.value(), "RETR %d\r\n" % (i,)) - t.clear() - p.dataReceived("+OK 2 lines on the way\r\n") - p.dataReceived("First line of %d.\r\n" % (i,)) - p.dataReceived("Second line of %d.\r\n" % (i,)) - self.assertEquals(t.value(), "") - p.dataReceived(".\r\n") - - return defer.DeferredList(messages, fireOnOneErrback=True) - - - -class POP3ClientMiscTestCase(unittest.TestCase): - def testCapability(self): - p, t = setUp() - d = p.capabilities(useCache=0) - self.assertEquals(t.value(), "CAPA\r\n") - p.dataReceived("+OK Capabilities on the way\r\n") - p.dataReceived("X\r\nY\r\nZ\r\nA 1 2 3\r\nB 1 2\r\nC 1\r\n.\r\n") - return d.addCallback( - self.assertEqual, - {"X": None, "Y": None, "Z": None, - "A": ["1", "2", "3"], - "B": ["1", "2"], - "C": ["1"]}) - - def testCapabilityError(self): - p, t = setUp() - d = p.capabilities(useCache=0) - self.assertEquals(t.value(), "CAPA\r\n") - p.dataReceived("-ERR This server is lame!\r\n") - return d.addCallback(self.assertEquals, {}) - - def testStat(self): - p, t = setUp() - d = p.stat() - self.assertEquals(t.value(), "STAT\r\n") - p.dataReceived("+OK 1 1212\r\n") - return d.addCallback(self.assertEqual, (1, 1212)) - - def testStatError(self): - p, t = setUp() - d = p.stat() - self.assertEquals(t.value(), "STAT\r\n") - p.dataReceived("-ERR This server is lame!\r\n") - return self.assertFailure( - d, ServerErrorResponse).addCallback( - lambda exc: self.assertEquals(exc.args[0], "This server is lame!")) - - def testNoop(self): - p, t = setUp() - d = p.noop() - self.assertEquals(t.value(), "NOOP\r\n") - p.dataReceived("+OK No-op to you too!\r\n") - return d.addCallback(self.assertEqual, "No-op to you too!") - - def testNoopError(self): - p, t = setUp() - d = p.noop() - self.assertEquals(t.value(), "NOOP\r\n") - p.dataReceived("-ERR This server is lame!\r\n") - return self.assertFailure( - d, ServerErrorResponse).addCallback( - lambda exc: self.assertEquals(exc.args[0], "This server is lame!")) - - def testRset(self): - p, t = setUp() - d = p.reset() - self.assertEquals(t.value(), "RSET\r\n") - p.dataReceived("+OK Reset state\r\n") - return d.addCallback(self.assertEqual, "Reset state") - - def testRsetError(self): - p, t = setUp() - d = p.reset() - self.assertEquals(t.value(), "RSET\r\n") - p.dataReceived("-ERR This server is lame!\r\n") - return self.assertFailure( - d, ServerErrorResponse).addCallback( - lambda exc: self.assertEquals(exc.args[0], "This server is lame!")) - - def testDelete(self): - p, t = setUp() - d = p.delete(3) - self.assertEquals(t.value(), "DELE 4\r\n") - p.dataReceived("+OK Hasta la vista\r\n") - return d.addCallback(self.assertEqual, "Hasta la vista") - - def testDeleteError(self): - p, t = setUp() - d = p.delete(3) - self.assertEquals(t.value(), "DELE 4\r\n") - p.dataReceived("-ERR Winner is not you.\r\n") - return self.assertFailure( - d, ServerErrorResponse).addCallback( - lambda exc: self.assertEquals(exc.args[0], "Winner is not you.")) - - -class SimpleClient(POP3Client): - def __init__(self, deferred, contextFactory = None): - self.deferred = deferred - self.allowInsecureLogin = True - - def serverGreeting(self, challenge): - self.deferred.callback(None) - -class POP3HelperMixin: - serverCTX = None - clientCTX = None - - def setUp(self): - d = defer.Deferred() - self.server = pop3testserver.POP3TestServer(contextFactory=self.serverCTX) - self.client = SimpleClient(d, contextFactory=self.clientCTX) - self.client.timeout = 30 - self.connected = d - - def tearDown(self): - del self.server - del self.client - del self.connected - - def _cbStopClient(self, ignore): - self.client.transport.loseConnection() - - def _ebGeneral(self, failure): - self.client.transport.loseConnection() - self.server.transport.loseConnection() - return failure - - def loopback(self): - return loopback.loopbackTCP(self.server, self.client, noisy=False) - - -class TLSServerFactory(protocol.ServerFactory): - class protocol(basic.LineReceiver): - context = None - output = [] - def connectionMade(self): - self.factory.input = [] - self.output = self.output[:] - map(self.sendLine, self.output.pop(0)) - def lineReceived(self, line): - self.factory.input.append(line) - map(self.sendLine, self.output.pop(0)) - if line == 'STLS': - self.transport.startTLS(self.context) - - -class POP3TLSTestCase(unittest.TestCase): - def testStartTLS(self): - sf = TLSServerFactory() - sf.protocol.output = [ - ['+OK'], # Server greeting - ['+OK', 'STLS', '.'], # CAPA response - ['+OK'], # STLS response - ['+OK', '.'], # Second CAPA response - ['+OK'] # QUIT response - ] - sf.protocol.context = ServerTLSContext() - port = reactor.listenTCP(0, sf, interface='127.0.0.1') - H = port.getHost().host - P = port.getHost().port - - cp = SimpleClient(defer.Deferred(), ClientTLSContext()) - cf = protocol.ClientFactory() - cf.protocol = lambda: cp - - conn = reactor.connectTCP(H, P, cf) - - def cbConnected(ignored): - log.msg("Connected to server; starting TLS") - return cp.startTLS() - - def cbStartedTLS(ignored): - log.msg("Started TLS; disconnecting") - return cp.quit() - - def cbDisconnected(ign): - log.msg("Disconnected; asserting correct input received") - self.assertEquals( - sf.input, - ['CAPA', 'STLS', 'CAPA', 'QUIT']) - - def cleanup(result): - log.msg("Asserted correct input; disconnecting client and shutting down server") - conn.disconnect() - - def cbShutdown(ignored): - log.msg("Shut down server") - return result - - return defer.maybeDeferred(port.stopListening).addCallback(cbShutdown) - - cp.deferred.addCallback(cbConnected) - cp.deferred.addCallback(cbStartedTLS) - cp.deferred.addCallback(cbDisconnected) - cp.deferred.addBoth(cleanup) - - return cp.deferred - - -class POP3TimeoutTestCase(POP3HelperMixin, unittest.TestCase): - def testTimeout(self): - def login(): - d = self.client.login('test', 'twisted') - d.addCallback(loggedIn) - d.addErrback(timedOut) - return d - - def loggedIn(result): - self.fail("Successfully logged in!? Impossible!") - - - def timedOut(failure): - failure.trap(error.TimeoutError) - self._cbStopClient(None) - - def quit(): - return self.client.quit() - - self.client.timeout = 0.01 - - # Tell the server to not return a response to client. This - # will trigger a timeout. - pop3testserver.TIMEOUT_RESPONSE = True - - methods = [login, quit] - map(self.connected.addCallback, map(strip, methods)) - self.connected.addCallback(self._cbStopClient) - self.connected.addErrback(self._ebGeneral) - return self.loopback() - - -if ClientTLSContext is None: - for case in (POP3TLSTestCase,): - case.skip = "OpenSSL not present" -elif interfaces.IReactorSSL(reactor, None) is None: - for case in (POP3TLSTestCase,): - case.skip = "Reactor doesn't support SSL" - diff --git a/tools/buildbot/pylibs/twisted/mail/test/test_smtp.py b/tools/buildbot/pylibs/twisted/mail/test/test_smtp.py deleted file mode 100644 index 34d8bcf..0000000 --- a/tools/buildbot/pylibs/twisted/mail/test/test_smtp.py +++ /dev/null @@ -1,982 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test cases for twisted.mail.smtp module. -""" - -from zope.interface import implements - -from twisted.trial import unittest, util -from twisted.protocols import basic, loopback -from twisted.mail import smtp -from twisted.internet import defer, protocol, reactor, interfaces -from twisted.internet import address, error, task -from twisted.test.test_protocols import StringIOWithoutClosing -from twisted.test.proto_helpers import StringTransport - -from twisted import cred -import twisted.cred.error -import twisted.cred.portal -import twisted.cred.checkers -import twisted.cred.credentials - -from twisted.cred.portal import IRealm, Portal -from twisted.cred.checkers import ICredentialsChecker, AllowAnonymousAccess -from twisted.cred.credentials import IAnonymous -from twisted.cred.error import UnauthorizedLogin - -from twisted.mail import imap4 - - -try: - from twisted.test.ssl_helpers import ClientTLSContext, ServerTLSContext -except ImportError: - ClientTLSContext = ServerTLSContext = None - -import re - -try: - from cStringIO import StringIO -except ImportError: - from StringIO import StringIO - -def spameater(*spam, **eggs): - return None - -class DummyMessage: - - def __init__(self, domain, user): - self.domain = domain - self.user = user - self.buffer = [] - - def lineReceived(self, line): - # Throw away the generated Received: header - if not re.match('Received: From yyy.com \(\[.*\]\) by localhost;', line): - self.buffer.append(line) - - def eomReceived(self): - message = '\n'.join(self.buffer) + '\n' - self.domain.messages[self.user.dest.local].append(message) - deferred = defer.Deferred() - deferred.callback("saved") - return deferred - - -class DummyDomain: - - def __init__(self, names): - self.messages = {} - for name in names: - self.messages[name] = [] - - def exists(self, user): - if self.messages.has_key(user.dest.local): - return defer.succeed(lambda: self.startMessage(user)) - return defer.fail(smtp.SMTPBadRcpt(user)) - - def startMessage(self, user): - return DummyMessage(self, user) - -class SMTPTestCase(unittest.TestCase): - - messages = [('foo@bar.com', ['foo@baz.com', 'qux@baz.com'], '''\ -Subject: urgent\015 -\015 -Someone set up us the bomb!\015 -''')] - - mbox = {'foo': ['Subject: urgent\n\nSomeone set up us the bomb!\n']} - - def setUp(self): - self.factory = smtp.SMTPFactory() - self.factory.domains = {} - self.factory.domains['baz.com'] = DummyDomain(['foo']) - self.output = StringIOWithoutClosing() - self.transport = protocol.FileWrapper(self.output) - - def testMessages(self): - from twisted.mail import protocols - protocol = protocols.DomainSMTP() - protocol.service = self.factory - protocol.factory = self.factory - protocol.receivedHeader = spameater - protocol.makeConnection(self.transport) - protocol.lineReceived('HELO yyy.com') - for message in self.messages: - protocol.lineReceived('MAIL FROM:<%s>' % message[0]) - for target in message[1]: - protocol.lineReceived('RCPT TO:<%s>' % target) - protocol.lineReceived('DATA') - protocol.dataReceived(message[2]) - protocol.lineReceived('.') - protocol.lineReceived('QUIT') - if self.mbox != self.factory.domains['baz.com'].messages: - raise AssertionError(self.factory.domains['baz.com'].messages) - protocol.setTimeout(None) - - testMessages.suppress = [util.suppress(message='DomainSMTP', category=DeprecationWarning)] - -mail = '''\ -Subject: hello - -Goodbye -''' - -class MyClient: - def __init__(self): - self.mail = 'moshez@foo.bar', ['moshez@foo.bar'], mail - - def getMailFrom(self): - return self.mail[0] - - def getMailTo(self): - return self.mail[1] - - def getMailData(self): - return StringIO(self.mail[2]) - - def sentMail(self, code, resp, numOk, addresses, log): - self.mail = None, None, None - -class MySMTPClient(MyClient, smtp.SMTPClient): - def __init__(self): - smtp.SMTPClient.__init__(self, 'foo.baz') - MyClient.__init__(self) - -class MyESMTPClient(MyClient, smtp.ESMTPClient): - def __init__(self, secret = '', contextFactory = None): - smtp.ESMTPClient.__init__(self, secret, contextFactory, 'foo.baz') - MyClient.__init__(self) - -class LoopbackMixin: - def loopback(self, server, client): - return loopback.loopbackTCP(server, client) - -class LoopbackTestCase(LoopbackMixin): - def testMessages(self): - factory = smtp.SMTPFactory() - factory.domains = {} - factory.domains['foo.bar'] = DummyDomain(['moshez']) - from twisted.mail.protocols import DomainSMTP - protocol = DomainSMTP() - protocol.service = factory - protocol.factory = factory - clientProtocol = self.clientClass() - return self.loopback(protocol, clientProtocol) - testMessages.suppress = [util.suppress(message='DomainSMTP', category=DeprecationWarning)] - -class LoopbackSMTPTestCase(LoopbackTestCase, unittest.TestCase): - clientClass = MySMTPClient - -class LoopbackESMTPTestCase(LoopbackTestCase, unittest.TestCase): - clientClass = MyESMTPClient - - -class FakeSMTPServer(basic.LineReceiver): - - clientData = [ - '220 hello', '250 nice to meet you', - '250 great', '250 great', '354 go on, lad' - ] - - def connectionMade(self): - self.buffer = [] - self.clientData = self.clientData[:] - self.clientData.reverse() - self.sendLine(self.clientData.pop()) - - def lineReceived(self, line): - self.buffer.append(line) - if line == "QUIT": - self.transport.write("221 see ya around\r\n") - self.transport.loseConnection() - elif line == ".": - self.transport.write("250 gotcha\r\n") - elif line == "RSET": - self.transport.loseConnection() - - if self.clientData: - self.sendLine(self.clientData.pop()) - - -class SMTPClientTestCase(unittest.TestCase, LoopbackMixin): - - expected_output = [ - 'HELO foo.baz', 'MAIL FROM:', - 'RCPT TO:', 'DATA', - 'Subject: hello', '', 'Goodbye', '.', 'RSET' - ] - - def testMessages(self): - # this test is disabled temporarily - client = MySMTPClient() - server = FakeSMTPServer() - d = self.loopback(server, client) - d.addCallback(lambda x : - self.assertEquals(server.buffer, self.expected_output)) - return d - -class DummySMTPMessage: - - def __init__(self, protocol, users): - self.protocol = protocol - self.users = users - self.buffer = [] - - def lineReceived(self, line): - self.buffer.append(line) - - def eomReceived(self): - message = '\n'.join(self.buffer) + '\n' - helo, origin = self.users[0].helo[0], str(self.users[0].orig) - recipients = [] - for user in self.users: - recipients.append(str(user)) - self.protocol.message[tuple(recipients)] = (helo, origin, recipients, message) - return defer.succeed("saved") - -class DummyProto: - def connectionMade(self): - self.dummyMixinBase.connectionMade(self) - self.message = {} - - def startMessage(self, users): - return DummySMTPMessage(self, users) - - def receivedHeader(*spam): - return None - - def validateTo(self, user): - self.delivery = DummyDelivery() - return lambda: self.startMessage([user]) - - def validateFrom(self, helo, origin): - return origin - -class DummySMTP(DummyProto, smtp.SMTP): - dummyMixinBase = smtp.SMTP - -class DummyESMTP(DummyProto, smtp.ESMTP): - dummyMixinBase = smtp.ESMTP - -class AnotherTestCase: - serverClass = None - clientClass = None - - messages = [ ('foo.com', 'moshez@foo.com', ['moshez@bar.com'], - 'moshez@foo.com', ['moshez@bar.com'], '''\ -From: Moshe -To: Moshe - -Hi, -how are you? -'''), - ('foo.com', 'tttt@rrr.com', ['uuu@ooo', 'yyy@eee'], - 'tttt@rrr.com', ['uuu@ooo', 'yyy@eee'], '''\ -Subject: pass - -..rrrr.. -'''), - ('foo.com', '@this,@is,@ignored:foo@bar.com', - ['@ignore,@this,@too:bar@foo.com'], - 'foo@bar.com', ['bar@foo.com'], '''\ -Subject: apa -To: foo - -123 -. -456 -'''), - ] - - data = [ - ('', '220.*\r\n$', None, None), - ('HELO foo.com\r\n', '250.*\r\n$', None, None), - ('RSET\r\n', '250.*\r\n$', None, None), - ] - for helo_, from_, to_, realfrom, realto, msg in messages: - data.append(('MAIL FROM:<%s>\r\n' % from_, '250.*\r\n', - None, None)) - for rcpt in to_: - data.append(('RCPT TO:<%s>\r\n' % rcpt, '250.*\r\n', - None, None)) - - data.append(('DATA\r\n','354.*\r\n', - msg, ('250.*\r\n', - (helo_, realfrom, realto, msg)))) - - - def testBuffer(self): - output = StringIOWithoutClosing() - a = self.serverClass() - class fooFactory: - domain = 'foo.com' - - a.factory = fooFactory() - a.makeConnection(protocol.FileWrapper(output)) - for (send, expect, msg, msgexpect) in self.data: - if send: - a.dataReceived(send) - data = output.getvalue() - output.truncate(0) - if not re.match(expect, data): - raise AssertionError, (send, expect, data) - if data[:3] == '354': - for line in msg.splitlines(): - if line and line[0] == '.': - line = '.' + line - a.dataReceived(line + '\r\n') - a.dataReceived('.\r\n') - # Special case for DATA. Now we want a 250, and then - # we compare the messages - data = output.getvalue() - output.truncate() - resp, msgdata = msgexpect - if not re.match(resp, data): - raise AssertionError, (resp, data) - for recip in msgdata[2]: - expected = list(msgdata[:]) - expected[2] = [recip] - self.assertEquals( - a.message[(recip,)], - tuple(expected) - ) - a.setTimeout(None) - - -class AnotherESMTPTestCase(AnotherTestCase, unittest.TestCase): - serverClass = DummyESMTP - clientClass = MyESMTPClient - -class AnotherSMTPTestCase(AnotherTestCase, unittest.TestCase): - serverClass = DummySMTP - clientClass = MySMTPClient - - - -class DummyChecker: - implements(cred.checkers.ICredentialsChecker) - - users = { - 'testuser': 'testpassword' - } - - credentialInterfaces = (cred.credentials.IUsernameHashedPassword,) - - def requestAvatarId(self, credentials): - return defer.maybeDeferred( - credentials.checkPassword, self.users[credentials.username] - ).addCallback(self._cbCheck, credentials.username) - - def _cbCheck(self, result, username): - if result: - return username - raise cred.error.UnauthorizedLogin() - -class DummyDelivery: - implements(smtp.IMessageDelivery) - - def validateTo(self, user): - return user - - def validateFrom(self, helo, origin): - return origin - - def receivedHeader(*args): - return None - -class DummyRealm: - def requestAvatar(self, avatarId, mind, *interfaces): - return smtp.IMessageDelivery, DummyDelivery(), lambda: None - -class AuthTestCase(unittest.TestCase, LoopbackMixin): - def testAuth(self): - realm = DummyRealm() - p = cred.portal.Portal(realm) - p.registerChecker(DummyChecker()) - - server = DummyESMTP({'CRAM-MD5': cred.credentials.CramMD5Credentials}) - server.portal = p - client = MyESMTPClient('testpassword') - - cAuth = imap4.CramMD5ClientAuthenticator('testuser') - client.registerAuthenticator(cAuth) - - d = self.loopback(server, client) - d.addCallback(lambda x : self.assertEquals(server.authenticated, 1)) - return d - -class SMTPHelperTestCase(unittest.TestCase): - def testMessageID(self): - d = {} - for i in range(1000): - m = smtp.messageid('testcase') - self.failIf(m in d) - d[m] = None - - def testQuoteAddr(self): - cases = [ - ['user@host.name', ''], - ['"User Name" ', ''], - [smtp.Address('someguy@someplace'), ''], - ['', '<>'], - [smtp.Address(''), '<>'], - ] - - for (c, e) in cases: - self.assertEquals(smtp.quoteaddr(c), e) - - def testUser(self): - u = smtp.User('user@host', 'helo.host.name', None, None) - self.assertEquals(str(u), 'user@host') - - def testXtextEncoding(self): - cases = [ - ('Hello world', 'Hello+20world'), - ('Hello+world', 'Hello+2Bworld'), - ('\0\1\2\3\4\5', '+00+01+02+03+04+05'), - ('e=mc2@example.com', 'e+3Dmc2@example.com') - ] - - for (case, expected) in cases: - self.assertEquals(case.encode('xtext'), expected) - self.assertEquals(expected.decode('xtext'), case) - - -class NoticeTLSClient(MyESMTPClient): - tls = False - - def esmtpState_starttls(self, code, resp): - MyESMTPClient.esmtpState_starttls(self, code, resp) - self.tls = True - -class TLSTestCase(unittest.TestCase, LoopbackMixin): - def testTLS(self): - clientCTX = ClientTLSContext() - serverCTX = ServerTLSContext() - - client = NoticeTLSClient(contextFactory=clientCTX) - server = DummyESMTP(contextFactory=serverCTX) - - def check(ignored): - self.assertEquals(client.tls, True) - self.assertEquals(server.startedTLS, True) - - return self.loopback(server, client).addCallback(check) - -if ClientTLSContext is None: - for case in (TLSTestCase,): - case.skip = "OpenSSL not present" - -if not interfaces.IReactorSSL.providedBy(reactor): - for case in (TLSTestCase,): - case.skip = "Reactor doesn't support SSL" - -class EmptyLineTestCase(unittest.TestCase): - def testEmptyLineSyntaxError(self): - proto = smtp.SMTP() - output = StringIOWithoutClosing() - transport = protocol.FileWrapper(output) - proto.makeConnection(transport) - proto.lineReceived('') - proto.setTimeout(None) - - out = output.getvalue().splitlines() - self.assertEquals(len(out), 2) - self.failUnless(out[0].startswith('220')) - self.assertEquals(out[1], "500 Error: bad syntax") - - - -class TimeoutTestCase(unittest.TestCase, LoopbackMixin): - """ - Check that SMTP client factories correctly use the timeout. - """ - - def _timeoutTest(self, onDone, clientFactory): - """ - Connect the clientFactory, and check the timeout on the request. - """ - clock = task.Clock() - client = clientFactory.buildProtocol( - address.IPv4Address('TCP', 'example.net', 25)) - client.callLater = clock.callLater - t = StringTransport() - client.makeConnection(t) - t.protocol = client - def check(ign): - self.assertEquals(clock.seconds(), 0.5) - d = self.assertFailure(onDone, smtp.SMTPTimeoutError - ).addCallback(check) - # The first call should not trigger the timeout - clock.advance(0.1) - # But this one should - clock.advance(0.4) - return d - - - def test_SMTPClient(self): - """ - Test timeout for L{smtp.SMTPSenderFactory}: the response L{Deferred} - should be errback with a L{smtp.SMTPTimeoutError}. - """ - onDone = defer.Deferred() - clientFactory = smtp.SMTPSenderFactory( - 'source@address', 'recipient@address', - StringIO("Message body"), onDone, - retries=0, timeout=0.5) - return self._timeoutTest(onDone, clientFactory) - - - def test_ESMTPClient(self): - """ - Test timeout for L{smtp.ESMTPSenderFactory}: the response L{Deferred} - should be errback with a L{smtp.SMTPTimeoutError}. - """ - onDone = defer.Deferred() - clientFactory = smtp.ESMTPSenderFactory( - 'username', 'password', - 'source@address', 'recipient@address', - StringIO("Message body"), onDone, - retries=0, timeout=0.5) - return self._timeoutTest(onDone, clientFactory) - - - -class SingletonRealm(object): - """ - Trivial realm implementation which is constructed with an interface and an - avatar and returns that avatar when asked for that interface. - """ - implements(IRealm) - - def __init__(self, interface, avatar): - self.interface = interface - self.avatar = avatar - - - def requestAvatar(self, avatarId, mind, *interfaces): - for iface in interfaces: - if iface is self.interface: - return iface, self.avatar, lambda: None - - - -class NotImplementedDelivery(object): - """ - Non-implementation of L{smtp.IMessageDelivery} which only has methods which - raise L{NotImplementedError}. Subclassed by various tests to provide the - particular behavior being tested. - """ - def validateFrom(self, helo, origin): - raise NotImplementedError("This oughtn't be called in the course of this test.") - - - def validateTo(self, user): - raise NotImplementedError("This oughtn't be called in the course of this test.") - - - def receivedHeader(self, helo, origin, recipients): - raise NotImplementedError("This oughtn't be called in the course of this test.") - - - -class SMTPServerTestCase(unittest.TestCase): - """ - Test various behaviors of L{twisted.mail.smtp.SMTP} and - L{twisted.mail.smtp.ESMTP}. - """ - def testSMTPGreetingHost(self, serverClass=smtp.SMTP): - """ - Test that the specified hostname shows up in the SMTP server's - greeting. - """ - s = serverClass() - s.host = "example.com" - t = StringTransport() - s.makeConnection(t) - s.connectionLost(error.ConnectionDone()) - self.assertIn("example.com", t.value()) - - - def testSMTPGreetingNotExtended(self): - """ - Test that the string "ESMTP" does not appear in the SMTP server's - greeting since that string strongly suggests the presence of support - for various SMTP extensions which are not supported by L{smtp.SMTP}. - """ - s = smtp.SMTP() - t = StringTransport() - s.makeConnection(t) - s.connectionLost(error.ConnectionDone()) - self.assertNotIn("ESMTP", t.value()) - - - def testESMTPGreetingHost(self): - """ - Similar to testSMTPGreetingHost, but for the L{smtp.ESMTP} class. - """ - self.testSMTPGreetingHost(smtp.ESMTP) - - - def testESMTPGreetingExtended(self): - """ - Test that the string "ESMTP" does appear in the ESMTP server's - greeting since L{smtp.ESMTP} does support the SMTP extensions which - that advertises to the client. - """ - s = smtp.ESMTP() - t = StringTransport() - s.makeConnection(t) - s.connectionLost(error.ConnectionDone()) - self.assertIn("ESMTP", t.value()) - - - def test_acceptSenderAddress(self): - """ - Test that a C{MAIL FROM} command with an acceptable address is - responded to with the correct success code. - """ - class AcceptanceDelivery(NotImplementedDelivery): - """ - Delivery object which accepts all senders as valid. - """ - def validateFrom(self, helo, origin): - return origin - - realm = SingletonRealm(smtp.IMessageDelivery, AcceptanceDelivery()) - portal = Portal(realm, [AllowAnonymousAccess()]) - proto = smtp.SMTP() - proto.portal = portal - trans = StringTransport() - proto.makeConnection(trans) - - # Deal with the necessary preliminaries - proto.dataReceived('HELO example.com\r\n') - trans.clear() - - # Try to specify our sender address - proto.dataReceived('MAIL FROM:\r\n') - - # Clean up the protocol before doing anything that might raise an - # exception. - proto.connectionLost(error.ConnectionLost()) - - # Make sure that we received exactly the correct response - self.assertEqual( - trans.value(), - '250 Sender address accepted\r\n') - - - def test_deliveryRejectedSenderAddress(self): - """ - Test that a C{MAIL FROM} command with an address rejected by a - L{smtp.IMessageDelivery} instance is responded to with the correct - error code. - """ - class RejectionDelivery(NotImplementedDelivery): - """ - Delivery object which rejects all senders as invalid. - """ - def validateFrom(self, helo, origin): - raise smtp.SMTPBadSender(origin) - - realm = SingletonRealm(smtp.IMessageDelivery, RejectionDelivery()) - portal = Portal(realm, [AllowAnonymousAccess()]) - proto = smtp.SMTP() - proto.portal = portal - trans = StringTransport() - proto.makeConnection(trans) - - # Deal with the necessary preliminaries - proto.dataReceived('HELO example.com\r\n') - trans.clear() - - # Try to specify our sender address - proto.dataReceived('MAIL FROM:\r\n') - - # Clean up the protocol before doing anything that might raise an - # exception. - proto.connectionLost(error.ConnectionLost()) - - # Make sure that we received exactly the correct response - self.assertEqual( - trans.value(), - '550 Cannot receive from specified address ' - ': Sender not acceptable\r\n') - - - def test_portalRejectedSenderAddress(self): - """ - Test that a C{MAIL FROM} command with an address rejected by an - L{smtp.SMTP} instance's portal is responded to with the correct error - code. - """ - class DisallowAnonymousAccess(object): - """ - Checker for L{IAnonymous} which rejects authentication attempts. - """ - implements(ICredentialsChecker) - - credentialInterfaces = (IAnonymous,) - - def requestAvatarId(self, credentials): - return defer.fail(UnauthorizedLogin()) - - realm = SingletonRealm(smtp.IMessageDelivery, NotImplementedDelivery()) - portal = Portal(realm, [DisallowAnonymousAccess()]) - proto = smtp.SMTP() - proto.portal = portal - trans = StringTransport() - proto.makeConnection(trans) - - # Deal with the necessary preliminaries - proto.dataReceived('HELO example.com\r\n') - trans.clear() - - # Try to specify our sender address - proto.dataReceived('MAIL FROM:\r\n') - - # Clean up the protocol before doing anything that might raise an - # exception. - proto.connectionLost(error.ConnectionLost()) - - # Make sure that we received exactly the correct response - self.assertEqual( - trans.value(), - '550 Cannot receive from specified address ' - ': Sender not acceptable\r\n') - - - def test_portalRejectedAnonymousSender(self): - """ - Test that a C{MAIL FROM} command issued without first authenticating - when a portal has been configured to disallow anonymous logins is - responded to with the correct error code. - """ - realm = SingletonRealm(smtp.IMessageDelivery, NotImplementedDelivery()) - portal = Portal(realm, []) - proto = smtp.SMTP() - proto.portal = portal - trans = StringTransport() - proto.makeConnection(trans) - - # Deal with the necessary preliminaries - proto.dataReceived('HELO example.com\r\n') - trans.clear() - - # Try to specify our sender address - proto.dataReceived('MAIL FROM:\r\n') - - # Clean up the protocol before doing anything that might raise an - # exception. - proto.connectionLost(error.ConnectionLost()) - - # Make sure that we received exactly the correct response - self.assertEqual( - trans.value(), - '550 Cannot receive from specified address ' - ': Unauthenticated senders not allowed\r\n') - - - -class ESMTPAuthenticationTestCase(unittest.TestCase): - def assertServerResponse(self, bytes, response): - """ - Assert that when the given bytes are delivered to the ESMTP server - instance, it responds with the indicated lines. - - @type bytes: str - @type response: list of str - """ - self.transport.clear() - self.server.dataReceived(bytes) - self.assertEqual( - response, - self.transport.value().splitlines()) - - - def assertServerAuthenticated(self, loginArgs, username="username", password="password"): - """ - Assert that a login attempt has been made, that the credentials and - interfaces passed to it are correct, and that when the login request - is satisfied, a successful response is sent by the ESMTP server - instance. - - @param loginArgs: A C{list} previously passed to L{portalFactory}. - """ - d, credentials, mind, interfaces = loginArgs.pop() - self.assertEqual(loginArgs, []) - self.failUnless(twisted.cred.credentials.IUsernamePassword.providedBy(credentials)) - self.assertEqual(credentials.username, username) - self.failUnless(credentials.checkPassword(password)) - self.assertIn(smtp.IMessageDeliveryFactory, interfaces) - self.assertIn(smtp.IMessageDelivery, interfaces) - d.callback((smtp.IMessageDeliveryFactory, None, lambda: None)) - - self.assertEqual( - ["235 Authentication successful."], - self.transport.value().splitlines()) - - - def setUp(self): - """ - Create an ESMTP instance attached to a StringTransport. - """ - self.server = smtp.ESMTP({ - 'LOGIN': imap4.LOGINCredentials}) - self.server.host = 'localhost' - self.transport = StringTransport( - peerAddress=address.IPv4Address('TCP', '127.0.0.1', 12345)) - self.server.makeConnection(self.transport) - - - def tearDown(self): - """ - Disconnect the ESMTP instance to clean up its timeout DelayedCall. - """ - self.server.connectionLost(error.ConnectionDone()) - - - def portalFactory(self, loginList): - class DummyPortal: - def login(self, credentials, mind, *interfaces): - d = defer.Deferred() - loginList.append((d, credentials, mind, interfaces)) - return d - return DummyPortal() - - - def test_authenticationCapabilityAdvertised(self): - """ - Test that AUTH is advertised to clients which issue an EHLO command. - """ - self.transport.clear() - self.server.dataReceived('EHLO\r\n') - responseLines = self.transport.value().splitlines() - self.assertEqual( - responseLines[0], - "250-localhost Hello 127.0.0.1, nice to meet you") - self.assertEqual( - responseLines[1], - "250 AUTH LOGIN") - self.assertEqual(len(responseLines), 2) - - - def test_plainAuthentication(self): - """ - Test that the LOGIN authentication mechanism can be used - """ - loginArgs = [] - self.server.portal = self.portalFactory(loginArgs) - - self.server.dataReceived('EHLO\r\n') - self.transport.clear() - - self.assertServerResponse( - 'AUTH LOGIN\r\n', - ["334 " + "User Name\0".encode('base64').strip()]) - - self.assertServerResponse( - 'username'.encode('base64') + '\r\n', - ["334 " + "Password\0".encode('base64').strip()]) - - self.assertServerResponse( - 'password'.encode('base64').strip() + '\r\n', - []) - - self.assertServerAuthenticated(loginArgs) - - - def test_plainAuthenticationEmptyPassword(self): - """ - Test that giving an empty password for plain auth succeeds. - """ - loginArgs = [] - self.server.portal = self.portalFactory(loginArgs) - - self.server.dataReceived('EHLO\r\n') - self.transport.clear() - - self.assertServerResponse( - 'AUTH LOGIN\r\n', - ["334 " + "User Name\0".encode('base64').strip()]) - - self.assertServerResponse( - 'username'.encode('base64') + '\r\n', - ["334 " + "Password\0".encode('base64').strip()]) - - self.assertServerResponse('\r\n', []) - self.assertServerAuthenticated(loginArgs, password='') - - def test_plainAuthenticationInitialResponse(self): - """ - The response to the first challenge may be included on the AUTH command - line. Test that this is also supported. - """ - loginArgs = [] - self.server.portal = self.portalFactory(loginArgs) - - self.server.dataReceived('EHLO\r\n') - self.transport.clear() - - self.assertServerResponse( - 'AUTH LOGIN ' + "username".encode('base64').strip() + '\r\n', - ["334 " + "Password\0".encode('base64').strip()]) - - self.assertServerResponse( - 'password'.encode('base64').strip() + '\r\n', - []) - - self.assertServerAuthenticated(loginArgs) - - - def test_abortAuthentication(self): - """ - Test that a challenge/response sequence can be aborted by the client. - """ - loginArgs = [] - self.server.portal = self.portalFactory(loginArgs) - - self.server.dataReceived('EHLO\r\n') - self.server.dataReceived('AUTH LOGIN\r\n') - - self.assertServerResponse( - '*\r\n', - ['501 Authentication aborted']) - - - def test_invalidBase64EncodedResponse(self): - """ - Test that a response which is not properly Base64 encoded results in - the appropriate error code. - """ - loginArgs = [] - self.server.portal = self.portalFactory(loginArgs) - - self.server.dataReceived('EHLO\r\n') - self.server.dataReceived('AUTH LOGIN\r\n') - - self.assertServerResponse( - 'x\r\n', - ['501 Syntax error in parameters or arguments']) - - self.assertEqual(loginArgs, []) - - - def test_invalidBase64EncodedInitialResponse(self): - """ - Like L{test_invalidBase64EncodedResponse} but for the case of an - initial response included with the C{AUTH} command. - """ - loginArgs = [] - self.server.portal = self.portalFactory(loginArgs) - - self.server.dataReceived('EHLO\r\n') - self.assertServerResponse( - 'AUTH LOGIN x\r\n', - ['501 Syntax error in parameters or arguments']) - - self.assertEqual(loginArgs, []) diff --git a/tools/buildbot/pylibs/twisted/mail/topfiles/NEWS b/tools/buildbot/pylibs/twisted/mail/topfiles/NEWS deleted file mode 100644 index 08785be..0000000 --- a/tools/buildbot/pylibs/twisted/mail/topfiles/NEWS +++ /dev/null @@ -1,113 +0,0 @@ -8.1.0 (2008-05-18) -================== - -Fixes ------ - - The deprecated mktap API is no longer used (#3127) - - -8.0.0 (2008-03-17) -================== - -Features --------- - - Support CAPABILITY responses that include atoms of the form "FOO" and - "FOO=BAR" in IMAP4 (#2695) - - Parameterize error handling behavior of imap4.encoder and imap4.decoder. - (#2929) - -Fixes ------ - - Handle empty passwords in SMTP auth. (#2521) - - Fix IMAP4Client's parsing of literals which are not preceeded by whitespace. - (#2700) - - Handle MX lookup suceeding without answers. (#2807) - - Fix issues with aliases(5) process support. (#2729) - -Misc ----- - - #2371, #2123, #2378, #739, #2640, #2746, #1917, #2266, #2864, #2832, #2063, - #2865, #2847 - - -0.4.0 (2007-01-06) -================== - -Features --------- - - Plaintext POP3 logins are now possible over SSL or TLS (#1809) - -Fixes ------ - - ESMTP servers now greet with an "ESMTP" string (#1891) - - The POP3 client can now correctly deal with concurrent POP3 - retrievals (#1988, #1691) - - In the IMAP4 server, a bug involving retrieving the first part - of a single-part message was fixed. This improves compatibility - with Pine (#1978) - - A bug in the IMAP4 server which caused corruption under heavy - pipelining was fixed (#1992) - - More strict support for the AUTH command was added to the SMTP - server, to support the AUTH - form of the command (#1552) - - An SMTP bug involving the interaction with validateFrom, which - caused multiple conflicting SMTP messages to be sent over the wire, - was fixed (#2158) - -Misc ----- - - #1648, #1801, #1636, #2003, #1936, #1202, #2051, #2072, #2248, #2250 - -0.3.0 (2006-05-21) -================== - -Features --------- - - Support Deferred results from POP3's IMailbox.listMessages (#1701). - -Fixes ------ - - Quote usernames and passwords automatically in the IMAP client (#1411). - - Improved parsing of literals in IMAP4 client and server (#1417). - - Recognize unsolicted FLAGS response in IMAP4 client (#1105). - - Parse and respond to requests with multiple BODY arguments in IMAP4 - server (#1307). - - Misc: #1356, #1290, #1602 - -0.2.0: - - SMTP server: - - Now gives application-level code opportunity to set a different - Received header for each recipient of a multi-recipient message. - - IMAP client: - - New `startTLS' method to allow explicit negotiation of transport - security. -- POP client: - - Support for per-command timeouts - - New `startTLS' method, similar to the one added to the IMAP - client. - - NOOP, RSET, and STAT support added -- POP server: - - Bug handling passwords of "" fixed - - -0.1.0: - - Tons of bugfixes in IMAP4, POP3, and SMTP protocols - - Maildir append support - - Brand new, improved POP3 client (twisted.mail.pop3.AdvancedPOP3Client) - - Deprecated the old POP3 client (twisted.mail.pop3.POP3Client) - - SMTP client: - - Support SMTP AUTH - - Allow user to supply SSL context - - Improved error handling, via new exception classes and an overridable - hook to customize handling. - - Order to try the authenication schemes is user-definable. - - Timeout support. - - SMTP server: - - Properly understand <> sender. - - Parameterize remote port - - IMAP4: - - LOGIN authentication compatibility improved - - Improved unicode mailbox support - - Fix parsing/handling of "FETCH BODY[HEADER]" - - Many many quoting fixes - - Timeout support on client diff --git a/tools/buildbot/pylibs/twisted/mail/topfiles/README b/tools/buildbot/pylibs/twisted/mail/topfiles/README deleted file mode 100644 index 7f70b08..0000000 --- a/tools/buildbot/pylibs/twisted/mail/topfiles/README +++ /dev/null @@ -1,5 +0,0 @@ -Twisted Mail 8.1.0 - -Mail was recently split out of Twisted. - -Twisted Mail depends on Twisted and (sometimes) Twisted Names. diff --git a/tools/buildbot/pylibs/twisted/mail/topfiles/setup.py b/tools/buildbot/pylibs/twisted/mail/topfiles/setup.py deleted file mode 100644 index 037d5f2..0000000 --- a/tools/buildbot/pylibs/twisted/mail/topfiles/setup.py +++ /dev/null @@ -1,48 +0,0 @@ -import sys - -try: - from twisted.python import dist -except ImportError: - raise SystemExit("twisted.python.dist module not found. Make sure you " - "have installed the Twisted core package before " - "attempting to install any other Twisted projects.") - -if __name__ == '__main__': - if sys.version_info[:2] >= (2, 4): - extraMeta = dict( - classifiers=[ - "Development Status :: 4 - Beta", - "Environment :: No Input/Output (Daemon)", - "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", - "Programming Language :: Python", - "Topic :: Communications :: Email :: Post-Office :: IMAP", - "Topic :: Communications :: Email :: Post-Office :: POP3", - "Topic :: Software Development :: Libraries :: Python Modules", - ]) - else: - extraMeta = {} - - dist.setup( - twisted_subproject="mail", - scripts=dist.getScripts("mail"), - # metadata - name="Twisted Mail", - description="A Twisted Mail library, server and client.", - author="Twisted Matrix Laboratories", - author_email="twisted-python@twistedmatrix.com", - maintainer="Jp Calderone", - maintainer_email="exarkun@divmod.com", - url="http://twistedmatrix.com/trac/wiki/TwistedMail", - license="MIT", - long_description="""\ -An SMTP, IMAP and POP protocol implementation together with clients -and servers. - -Twisted Mail contains high-level, efficient protocol implementations -for both clients and servers of SMTP, POP3, and IMAP4. Additionally, -it contains an "out of the box" combination SMTP/POP3 virtual-hosting -mail server. Also included is a read/write Maildir implementation and -a basic Mail Exchange calculator. -""", - **extraMeta) diff --git a/tools/buildbot/pylibs/twisted/manhole/__init__.py b/tools/buildbot/pylibs/twisted/manhole/__init__.py deleted file mode 100644 index 3647cf5..0000000 --- a/tools/buildbot/pylibs/twisted/manhole/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Twisted Manhole: interactive interpreter and direct manipulation support for Twisted. -""" diff --git a/tools/buildbot/pylibs/twisted/manhole/_inspectro.py b/tools/buildbot/pylibs/twisted/manhole/_inspectro.py deleted file mode 100644 index 12767ab..0000000 --- a/tools/buildbot/pylibs/twisted/manhole/_inspectro.py +++ /dev/null @@ -1,369 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""An input/output window for the glade reactor inspector. -""" - -import time -import gtk -import gobject -import gtk.glade -from twisted.python.util import sibpath -from twisted.python import reflect - -from twisted.manhole.ui import gtk2manhole -from twisted.python.components import Adapter, registerAdapter -from twisted.python import log -from twisted.protocols import policies -from zope.interface import implements, Interface - -# the glade file uses stock icons, which requires gnome to be installed -import gnome -version = "$Revision: 1.1 $"[11:-2] -gnome.init("gladereactor Inspector", version) - -class ConsoleOutput(gtk2manhole.ConsoleOutput): - def _captureLocalLog(self): - self.fobs = log.FileLogObserver(gtk2manhole._Notafile(self, "log")) - self.fobs.start() - - def stop(self): - self.fobs.stop() - del self.fobs - -class ConsoleInput(gtk2manhole.ConsoleInput): - def sendMessage(self): - buffer = self.textView.get_buffer() - iter1, iter2 = buffer.get_bounds() - text = buffer.get_text(iter1, iter2, False) - self.do(text) - - def do(self, text): - self.toplevel.do(text) - -class INode(Interface): - """A node in the inspector tree model. - """ - - def __adapt__(adaptable, default): - if hasattr(adaptable, "__dict__"): - return InstanceNode(adaptable) - return AttributesNode(adaptable) - -class InspectorNode(Adapter): - implements(INode) - - def postInit(self, offset, parent, slot): - self.offset = offset - self.parent = parent - self.slot = slot - - def getPath(self): - L = [] - x = self - while x.parent is not None: - L.append(x.offset) - x = x.parent - L.reverse() - return L - - def __getitem__(self, index): - slot, o = self.get(index) - n = INode(o, persist=False) - n.postInit(index, self, slot) - return n - - def origstr(self): - return str(self.original) - - def format(self): - return (self.slot, self.origstr()) - - -class ConstantNode(InspectorNode): - def __len__(self): - return 0 - -class DictionaryNode(InspectorNode): - def get(self, index): - L = self.original.items() - L.sort() - return L[index] - - def __len__(self): - return len(self.original) - - def origstr(self): - return "Dictionary" - -class ListNode(InspectorNode): - def get(self, index): - return index, self.original[index] - - def origstr(self): - return "List" - - def __len__(self): - return len(self.original) - -class AttributesNode(InspectorNode): - def __len__(self): - return len(dir(self.original)) - - def get(self, index): - L = dir(self.original) - L.sort() - return L[index], getattr(self.original, L[index]) - -class InstanceNode(InspectorNode): - def __len__(self): - return len(self.original.__dict__) + 1 - - def get(self, index): - if index == 0: - if hasattr(self.original, "__class__"): - v = self.original.__class__ - else: - v = type(self.original) - return "__class__", v - else: - index -= 1 - L = self.original.__dict__.items() - L.sort() - return L[index] - -import types - -for x in dict, types.DictProxyType: - registerAdapter(DictionaryNode, x, INode) -for x in list, tuple: - registerAdapter(ListNode, x, INode) -for x in int, str: - registerAdapter(ConstantNode, x, INode) - - -class InspectorTreeModel(gtk.GenericTreeModel): - def __init__(self, root): - gtk.GenericTreeModel.__init__(self) - self.root = INode(root, persist=False) - self.root.postInit(0, None, 'root') - - def on_get_flags(self): - return 0 - - def on_get_n_columns(self): - return 1 - - def on_get_column_type(self, index): - return gobject.TYPE_STRING - - def on_get_path(self, node): - return node.getPath() - - def on_get_iter(self, path): - x = self.root - for elem in path: - x = x[elem] - return x - - def on_get_value(self, node, column): - return node.format()[column] - - def on_iter_next(self, node): - try: - return node.parent[node.offset + 1] - except IndexError: - return None - - def on_iter_children(self, node): - return node[0] - - def on_iter_has_child(self, node): - return len(node) - - def on_iter_n_children(self, node): - return len(node) - - def on_iter_nth_child(self, node, n): - if node is None: - return None - return node[n] - - def on_iter_parent(self, node): - return node.parent - - -class Inspectro: - selected = None - def __init__(self, o=None): - self.xml = x = gtk.glade.XML(sibpath(__file__, "inspectro.glade")) - self.tree_view = x.get_widget("treeview") - colnames = ["Name", "Value"] - for i in range(len(colnames)): - self.tree_view.append_column( - gtk.TreeViewColumn( - colnames[i], gtk.CellRendererText(), text=i)) - d = {} - for m in reflect.prefixedMethods(self, "on_"): - d[m.im_func.__name__] = m - self.xml.signal_autoconnect(d) - if o is not None: - self.inspect(o) - self.ns = {'inspect': self.inspect} - iwidget = x.get_widget('input') - self.input = ConsoleInput(iwidget) - self.input.toplevel = self - iwidget.connect("key_press_event", self.input._on_key_press_event) - self.output = ConsoleOutput(x.get_widget('output')) - - def select(self, o): - self.selected = o - self.ns['it'] = o - self.xml.get_widget("itname").set_text(repr(o)) - self.xml.get_widget("itpath").set_text("???") - - def inspect(self, o): - self.model = InspectorTreeModel(o) - self.tree_view.set_model(self.model) - self.inspected = o - - def do(self, command): - filename = '' - try: - print repr(command) - try: - code = compile(command, filename, 'eval') - except: - code = compile(command, filename, 'single') - val = eval(code, self.ns, self.ns) - if val is not None: - print repr(val) - self.ns['_'] = val - except: - log.err() - - def on_inspect(self, *a): - self.inspect(self.selected) - - def on_inspect_new(self, *a): - Inspectro(self.selected) - - def on_row_activated(self, tv, path, column): - self.select(self.model.on_get_iter(path).original) - - -class LoggingProtocol(policies.ProtocolWrapper): - """Log network traffic.""" - - logging = True - logViewer = None - - def __init__(self, *args): - policies.ProtocolWrapper.__init__(self, *args) - self.inLog = [] - self.outLog = [] - - def write(self, data): - if self.logging: - self.outLog.append((time.time(), data)) - if self.logViewer: - self.logViewer.updateOut(self.outLog[-1]) - policies.ProtocolWrapper.write(self, data) - - def dataReceived(self, data): - if self.logging: - self.inLog.append((time.time(), data)) - if self.logViewer: - self.logViewer.updateIn(self.inLog[-1]) - policies.ProtocolWrapper.dataReceived(self, data) - - def __repr__(self): - r = "wrapped " + repr(self.wrappedProtocol) - if self.logging: - r += " (logging)" - return r - - -class LoggingFactory(policies.WrappingFactory): - """Wrap protocols with logging wrappers.""" - - protocol = LoggingProtocol - logging = True - - def buildProtocol(self, addr): - p = self.protocol(self, self.wrappedFactory.buildProtocol(addr)) - p.logging = self.logging - return p - - def __repr__(self): - r = "wrapped " + repr(self.wrappedFactory) - if self.logging: - r += " (logging)" - return r - - -class LogViewer: - """Display log of network traffic.""" - - def __init__(self, p): - self.p = p - vals = [time.time()] - if p.inLog: - vals.append(p.inLog[0][0]) - if p.outLog: - vals.append(p.outLog[0][0]) - self.startTime = min(vals) - p.logViewer = self - self.xml = x = gtk.glade.XML(sibpath(__file__, "logview.glade")) - self.xml.signal_autoconnect(self) - self.loglist = self.xml.get_widget("loglist") - # setup model, connect it to my treeview - self.model = gtk.ListStore(str, str, str) - self.loglist.set_model(self.model) - self.loglist.set_reorderable(1) - self.loglist.set_headers_clickable(1) - # self.servers.set_headers_draggable(1) - # add a column - for col in [ - gtk.TreeViewColumn('Time', - gtk.CellRendererText(), - text=0), - gtk.TreeViewColumn('D', - gtk.CellRendererText(), - text=1), - gtk.TreeViewColumn('Data', - gtk.CellRendererText(), - text=2)]: - self.loglist.append_column(col) - col.set_resizable(1) - r = [] - for t, data in p.inLog: - r.append(((str(t - self.startTime), "R", repr(data)[1:-1]))) - for t, data in p.outLog: - r.append(((str(t - self.startTime), "S", repr(data)[1:-1]))) - r.sort() - for i in r: - self.model.append(i) - - def updateIn(self, (time, data)): - self.model.append((str(time - self.startTime), "R", repr(data)[1:-1])) - - def updateOut(self, (time, data)): - self.model.append((str(time - self.startTime), "S", repr(data)[1:-1])) - - def on_logview_destroy(self, w): - self.p.logViewer = None - del self.p - - -def main(): - x = Inspectro() - x.inspect(x) - gtk.main() - -if __name__ == '__main__': - import sys - log.startLogging(sys.stdout) - main() - diff --git a/tools/buildbot/pylibs/twisted/manhole/explorer.py b/tools/buildbot/pylibs/twisted/manhole/explorer.py deleted file mode 100644 index e1b8dc5..0000000 --- a/tools/buildbot/pylibs/twisted/manhole/explorer.py +++ /dev/null @@ -1,655 +0,0 @@ -# -*- test-case-name: twisted.test.test_explorer -*- -# $Id: explorer.py,v 1.6 2003/02/18 21:15:30 acapnotic Exp $ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Support for python object introspection and exploration. - -Note that Explorers, what with their list of attributes, are much like -manhole.coil.Configurables. Someone should investigate this further. (TODO) - -Also TODO: Determine how much code in here (particularly the function -signature stuff) can be replaced with functions available in the -L{inspect} module available in Python 2.1. -""" - -# System Imports -import inspect, new, string, sys, types -import UserDict - -# Twisted Imports -from twisted.spread import pb -from twisted.python import reflect - - -True=(1==1) -False=not True - -class Pool(UserDict.UserDict): - def getExplorer(self, object, identifier): - oid = id(object) - if self.data.has_key(oid): - # XXX: This potentially returns something with - # 'identifier' set to a different value. - return self.data[oid] - else: - klass = typeTable.get(type(object), ExplorerGeneric) - e = new.instance(klass, {}) - self.data[oid] = e - klass.__init__(e, object, identifier) - return e - -explorerPool = Pool() - -class Explorer(pb.Cacheable): - properties = ["id", "identifier"] - attributeGroups = [] - accessors = ["get_refcount"] - - id = None - identifier = None - - def __init__(self, object, identifier): - self.object = object - self.identifier = identifier - self.id = id(object) - - self.properties = [] - reflect.accumulateClassList(self.__class__, 'properties', - self.properties) - - self.attributeGroups = [] - reflect.accumulateClassList(self.__class__, 'attributeGroups', - self.attributeGroups) - - self.accessors = [] - reflect.accumulateClassList(self.__class__, 'accessors', - self.accessors) - - def getStateToCopyFor(self, perspective): - all = ["properties", "attributeGroups", "accessors"] - all.extend(self.properties) - all.extend(self.attributeGroups) - - state = {} - for key in all: - state[key] = getattr(self, key) - - state['view'] = pb.ViewPoint(perspective, self) - state['explorerClass'] = self.__class__.__name__ - return state - - def view_get_refcount(self, perspective): - return sys.getrefcount(self) - -class ExplorerGeneric(Explorer): - properties = ["str", "repr", "typename"] - - def __init__(self, object, identifier): - Explorer.__init__(self, object, identifier) - self.str = str(object) - self.repr = repr(object) - self.typename = type(object).__name__ - - -class ExplorerImmutable(Explorer): - properties = ["value"] - - def __init__(self, object, identifier): - Explorer.__init__(self, object, identifier) - self.value = object - - -class ExplorerSequence(Explorer): - properties = ["len"] - attributeGroups = ["elements"] - accessors = ["get_elements"] - - def __init__(self, seq, identifier): - Explorer.__init__(self, seq, identifier) - self.seq = seq - self.len = len(seq) - - # Use accessor method to fill me in. - self.elements = [] - - def get_elements(self): - self.len = len(self.seq) - l = [] - for i in xrange(self.len): - identifier = "%s[%s]" % (self.identifier, i) - - # GLOBAL: using global explorerPool - l.append(explorerPool.getExplorer(self.seq[i], identifier)) - - return l - - def view_get_elements(self, perspective): - # XXX: set the .elements member of all my remoteCaches - return self.get_elements() - - -class ExplorerMapping(Explorer): - properties = ["len"] - attributeGroups = ["keys"] - accessors = ["get_keys", "get_item"] - - def __init__(self, dct, identifier): - Explorer.__init__(self, dct, identifier) - - self.dct = dct - self.len = len(dct) - - # Use accessor method to fill me in. - self.keys = [] - - def get_keys(self): - keys = self.dct.keys() - self.len = len(keys) - l = [] - for i in xrange(self.len): - identifier = "%s.keys()[%s]" % (self.identifier, i) - - # GLOBAL: using global explorerPool - l.append(explorerPool.getExplorer(keys[i], identifier)) - - return l - - def view_get_keys(self, perspective): - # XXX: set the .keys member of all my remoteCaches - return self.get_keys() - - def view_get_item(self, perspective, key): - if type(key) is types.InstanceType: - key = key.object - - item = self.dct[key] - - identifier = "%s[%s]" % (self.identifier, repr(key)) - # GLOBAL: using global explorerPool - item = explorerPool.getExplorer(item, identifier) - return item - - -class ExplorerBuiltin(Explorer): - """ - @ivar name: the name the function was defined as - @ivar doc: function's docstring, or C{None} if unavailable - @ivar self: if not C{None}, the function is a method of this object. - """ - properties = ["doc", "name", "self"] - def __init__(self, function, identifier): - Explorer.__init__(self, function, identifier) - self.doc = function.__doc__ - self.name = function.__name__ - self.self = function.__self__ - - -class ExplorerInstance(Explorer): - """ - Attribute groups: - - B{methods} -- dictionary of methods - - B{data} -- dictionary of data members - - Note these are only the *instance* methods and members -- - if you want the class methods, you'll have to look up the class. - - TODO: Detail levels (me, me & class, me & class ancestory) - - @ivar klass: the class this is an instance of. - """ - properties = ["klass"] - attributeGroups = ["methods", "data"] - - def __init__(self, instance, identifier): - Explorer.__init__(self, instance, identifier) - members = {} - methods = {} - for i in dir(instance): - # TODO: Make screening of private attributes configurable. - if i[0] == '_': - continue - mIdentifier = string.join([identifier, i], ".") - member = getattr(instance, i) - mType = type(member) - - if mType is types.MethodType: - methods[i] = explorerPool.getExplorer(member, mIdentifier) - else: - members[i] = explorerPool.getExplorer(member, mIdentifier) - - self.klass = explorerPool.getExplorer(instance.__class__, - self.identifier + - '.__class__') - self.data = members - self.methods = methods - - -class ExplorerClass(Explorer): - """ - @ivar name: the name the class was defined with - @ivar doc: the class's docstring - @ivar bases: a list of this class's base classes. - @ivar module: the module the class is defined in - - Attribute groups: - - B{methods} -- class methods - - B{data} -- other members of the class - """ - properties = ["name", "doc", "bases", "module"] - attributeGroups = ["methods", "data"] - def __init__(self, theClass, identifier): - Explorer.__init__(self, theClass, identifier) - if not identifier: - identifier = theClass.__name__ - members = {} - methods = {} - for i in dir(theClass): - if (i[0] == '_') and (i != '__init__'): - continue - - mIdentifier = string.join([identifier, i], ".") - member = getattr(theClass, i) - mType = type(member) - - if mType is types.MethodType: - methods[i] = explorerPool.getExplorer(member, mIdentifier) - else: - members[i] = explorerPool.getExplorer(member, mIdentifier) - - self.name = theClass.__name__ - self.doc = inspect.getdoc(theClass) - self.data = members - self.methods = methods - self.bases = explorerPool.getExplorer(theClass.__bases__, - identifier + ".__bases__") - self.module = getattr(theClass, '__module__', None) - - -class ExplorerFunction(Explorer): - properties = ["name", "doc", "file", "line","signature"] - """ - name -- the name the function was defined as - signature -- the function's calling signature (Signature instance) - doc -- the function's docstring - file -- the file the function is defined in - line -- the line in the file the function begins on - """ - def __init__(self, function, identifier): - Explorer.__init__(self, function, identifier) - code = function.func_code - argcount = code.co_argcount - takesList = (code.co_flags & 0x04) and 1 - takesKeywords = (code.co_flags & 0x08) and 1 - - n = (argcount + takesList + takesKeywords) - signature = Signature(code.co_varnames[:n]) - - if function.func_defaults: - i_d = 0 - for i in xrange(argcount - len(function.func_defaults), - argcount): - default = function.func_defaults[i_d] - default = explorerPool.getExplorer( - default, '%s.func_defaults[%d]' % (identifier, i_d)) - signature.set_default(i, default) - - i_d = i_d + 1 - - if takesKeywords: - signature.set_keyword(n - 1) - - if takesList: - signature.set_varlist(n - 1 - takesKeywords) - - # maybe also: function.func_globals, - # or at least func_globals.__name__? - # maybe the bytecode, for disassembly-view? - - self.name = function.__name__ - self.signature = signature - self.doc = inspect.getdoc(function) - self.file = code.co_filename - self.line = code.co_firstlineno - - -class ExplorerMethod(ExplorerFunction): - properties = ["self", "klass"] - """ - In addition to ExplorerFunction properties: - self -- the object I am bound to, or None if unbound - klass -- the class I am a method of - """ - def __init__(self, method, identifier): - - function = method.im_func - if type(function) is types.InstanceType: - function = function.__call__.im_func - - ExplorerFunction.__init__(self, function, identifier) - self.id = id(method) - self.klass = explorerPool.getExplorer(method.im_class, - identifier + '.im_class') - self.self = explorerPool.getExplorer(method.im_self, - identifier + '.im_self') - - if method.im_self: - # I'm a bound method -- eat the 'self' arg. - self.signature.discardSelf() - - -class ExplorerModule(Explorer): - """ - @ivar name: the name the module was defined as - @ivar doc: documentation string for the module - @ivar file: the file the module is defined in - - Attribute groups: - - B{classes} -- the public classes provided by the module - - B{functions} -- the public functions provided by the module - - B{data} -- the public data members provided by the module - - (\"Public\" is taken to be \"anything that doesn't start with _\") - """ - properties = ["name","doc","file"] - attributeGroups = ["classes", "functions", "data"] - - def __init__(self, module, identifier): - Explorer.__init__(self, module, identifier) - functions = {} - classes = {} - data = {} - for key, value in module.__dict__.items(): - if key[0] == '_': - continue - - mIdentifier = "%s.%s" % (identifier, key) - - if type(value) is types.ClassType: - classes[key] = explorerPool.getExplorer(value, - mIdentifier) - elif type(value) is types.FunctionType: - functions[key] = explorerPool.getExplorer(value, - mIdentifier) - elif type(value) is types.ModuleType: - pass # pass on imported modules - else: - data[key] = explorerPool.getExplorer(value, mIdentifier) - - self.name = module.__name__ - self.doc = inspect.getdoc(module) - self.file = getattr(module, '__file__', None) - self.classes = classes - self.functions = functions - self.data = data - -typeTable = {types.InstanceType: ExplorerInstance, - types.ClassType: ExplorerClass, - types.MethodType: ExplorerMethod, - types.FunctionType: ExplorerFunction, - types.ModuleType: ExplorerModule, - types.BuiltinFunctionType: ExplorerBuiltin, - types.ListType: ExplorerSequence, - types.TupleType: ExplorerSequence, - types.DictType: ExplorerMapping, - types.StringType: ExplorerImmutable, - types.NoneType: ExplorerImmutable, - types.IntType: ExplorerImmutable, - types.FloatType: ExplorerImmutable, - types.LongType: ExplorerImmutable, - types.ComplexType: ExplorerImmutable, - } - -class Signature(pb.Copyable): - """I represent the signature of a callable. - - Signatures are immutable, so don't expect my contents to change once - they've been set. - """ - _FLAVOURLESS = None - _HAS_DEFAULT = 2 - _VAR_LIST = 4 - _KEYWORD_DICT = 8 - - def __init__(self, argNames): - self.name = argNames - self.default = [None] * len(argNames) - self.flavour = [None] * len(argNames) - - def get_name(self, arg): - return self.name[arg] - - def get_default(self, arg): - if arg is types.StringType: - arg = self.name.index(arg) - - # Wouldn't it be nice if we just returned "None" when there - # wasn't a default? Well, yes, but often times "None" *is* - # the default, so return a tuple instead. - if self.flavour[arg] == self._HAS_DEFAULT: - return (True, self.default[arg]) - else: - return (False, None) - - def set_default(self, arg, value): - if arg is types.StringType: - arg = self.name.index(arg) - - self.flavour[arg] = self._HAS_DEFAULT - self.default[arg] = value - - def set_varlist(self, arg): - if arg is types.StringType: - arg = self.name.index(arg) - - self.flavour[arg] = self._VAR_LIST - - def set_keyword(self, arg): - if arg is types.StringType: - arg = self.name.index(arg) - - self.flavour[arg] = self._KEYWORD_DICT - - def is_varlist(self, arg): - if arg is types.StringType: - arg = self.name.index(arg) - - return (self.flavour[arg] == self._VAR_LIST) - - def is_keyword(self, arg): - if arg is types.StringType: - arg = self.name.index(arg) - - return (self.flavour[arg] == self._KEYWORD_DICT) - - def discardSelf(self): - """Invoke me to discard the first argument if this is a bound method. - """ - ## if self.name[0] != 'self': - ## log.msg("Warning: Told to discard self, but name is %s" % - ## self.name[0]) - self.name = self.name[1:] - self.default.pop(0) - self.flavour.pop(0) - - def getStateToCopy(self): - return {'name': tuple(self.name), - 'flavour': tuple(self.flavour), - 'default': tuple(self.default)} - - def __len__(self): - return len(self.name) - - def __str__(self): - arglist = [] - for arg in xrange(len(self)): - name = self.get_name(arg) - hasDefault, default = self.get_default(arg) - if hasDefault: - a = "%s=%s" % (name, default) - elif self.is_varlist(arg): - a = "*%s" % (name,) - elif self.is_keyword(arg): - a = "**%s" % (name,) - else: - a = name - arglist.append(a) - - return string.join(arglist,", ") - - - - - -class CRUFT_WatchyThingie: - # TODO: - # - # * an exclude mechanism for the watcher's browser, to avoid - # sending back large and uninteresting data structures. - # - # * an exclude mechanism for the watcher's trigger, to avoid - # triggering on some frequently-called-method-that-doesn't- - # actually-change-anything. - # - # * XXX! need removeWatch() - - def watchIdentifier(self, identifier, callback): - """Watch the object returned by evaluating the identifier. - - Whenever I think the object might have changed, I'll send an - ObjectLink of it to the callback. - - WARNING: This calls eval() on its argument! - """ - object = eval(identifier, - self.globalNamespace, - self.localNamespace) - return self.watchObject(object, identifier, callback) - - def watchObject(self, object, identifier, callback): - """Watch the given object. - - Whenever I think the object might have changed, I'll send an - ObjectLink of it to the callback. - - The identifier argument is used to generate identifiers for - objects which are members of this one. - """ - if type(object) is not types.InstanceType: - raise TypeError, "Sorry, can only place a watch on Instances." - - # uninstallers = [] - - dct = {} - reflect.addMethodNamesToDict(object.__class__, dct, '') - for k in object.__dict__.keys(): - dct[k] = 1 - - members = dct.keys() - - clazzNS = {} - clazz = new.classobj('Watching%s%X' % - (object.__class__.__name__, id(object)), - (_MonkeysSetattrMixin, object.__class__,), - clazzNS) - - clazzNS['_watchEmitChanged'] = new.instancemethod( - lambda slf, i=identifier, b=self, cb=callback: - cb(b.browseObject(slf, i)), - None, clazz) - - # orig_class = object.__class__ - object.__class__ = clazz - - for name in members: - m = getattr(object, name) - # Only hook bound methods. - if ((type(m) is types.MethodType) - and (m.im_self is not None)): - # What's the use of putting watch monkeys on methods - # in addition to __setattr__? Well, um, uh, if the - # methods modify their attributes (i.e. add a key to - # a dictionary) instead of [re]setting them, then - # we wouldn't know about it unless we did this. - # (Is that convincing?) - - monkey = _WatchMonkey(object) - monkey.install(name) - # uninstallers.append(monkey.uninstall) - - # XXX: This probably prevents these objects from ever having a - # zero refcount. Leak, Leak! - ## self.watchUninstallers[object] = uninstallers - - -class _WatchMonkey: - """I hang on a method and tell you what I see. - - TODO: Aya! Now I just do browseObject all the time, but I could - tell you what got called with what when and returning what. - """ - oldMethod = None - - def __init__(self, instance): - """Make a monkey to hang on this instance object. - """ - self.instance = instance - - def install(self, methodIdentifier): - """Install myself on my instance in place of this method. - """ - oldMethod = getattr(self.instance, methodIdentifier, None) - - # XXX: this conditional probably isn't effective. - if oldMethod is not self: - # avoid triggering __setattr__ - self.instance.__dict__[methodIdentifier] = ( - new.instancemethod(self, self.instance, - self.instance.__class__)) - self.oldMethod = (methodIdentifier, oldMethod) - - def uninstall(self): - """Remove myself from this instance and restore the original method. - - (I hope.) - """ - if self.oldMethod is None: - return - - # XXX: This probably doesn't work if multiple monkies are hanging - # on a method and they're not removed in order. - if self.oldMethod[1] is None: - delattr(self.instance, self.oldMethod[0]) - else: - setattr(self.instance, self.oldMethod[0], self.oldMethod[1]) - - def __call__(self, instance, *a, **kw): - """Pretend to be the method I replaced, and ring the bell. - """ - if self.oldMethod[1]: - rval = apply(self.oldMethod[1], a, kw) - else: - rval = None - - instance._watchEmitChanged() - return rval - - -class _MonkeysSetattrMixin: - """A mix-in class providing __setattr__ for objects being watched. - """ - def __setattr__(self, k, v): - """Set the attribute and ring the bell. - """ - if hasattr(self.__class__.__bases__[1], '__setattr__'): - # Hack! Using __bases__[1] is Bad, but since we created - # this class, we can be reasonably sure it'll work. - self.__class__.__bases__[1].__setattr__(self, k, v) - else: - self.__dict__[k] = v - - # XXX: Hey, waitasec, did someone just hang a new method on me? - # Do I need to put a monkey on it? - - self._watchEmitChanged() diff --git a/tools/buildbot/pylibs/twisted/manhole/gladereactor.glade b/tools/buildbot/pylibs/twisted/manhole/gladereactor.glade deleted file mode 100644 index c78dd5a..0000000 --- a/tools/buildbot/pylibs/twisted/manhole/gladereactor.glade +++ /dev/null @@ -1,342 +0,0 @@ - - - - - - - True - Twisted Daemon - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - 256 - 300 - True - False - - - - True - False - 0 - - - - True - True - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - GTK_SHADOW_NONE - GTK_CORNER_TOP_LEFT - - - - True - True - True - False - True - True - - - - - 0 - True - True - - - - - - True - GTK_BUTTONBOX_DEFAULT_STYLE - 0 - - - - True - True - True - GTK_RELIEF_NORMAL - - - - - True - 0.5 - 0.5 - 0 - 0 - - - - True - False - 2 - - - - True - gtk-undo - 4 - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - True - Suspend - True - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - - - - - - - True - True - True - GTK_RELIEF_NORMAL - - - - - True - 0.5 - 0.5 - 0 - 0 - - - - True - False - 2 - - - - True - gtk-dialog-warning - 4 - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - True - Disconnect - True - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - - - - - - - True - True - True - GTK_RELIEF_NORMAL - - - - - True - 0.5 - 0.5 - 0 - 0 - - - - True - False - 2 - - - - True - gtk-open - 4 - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - True - Inspect - True - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - - - - - - - True - True - True - GTK_RELIEF_NORMAL - - - - - True - 0.5 - 0.5 - 0 - 0 - - - - True - False - 2 - - - - True - gtk-dialog-info - 4 - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - True - View Log - True - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - - - - - - - True - True - True - gtk-quit - True - GTK_RELIEF_NORMAL - - - - - - 0 - False - True - - - - - - - diff --git a/tools/buildbot/pylibs/twisted/manhole/gladereactor.py b/tools/buildbot/pylibs/twisted/manhole/gladereactor.py deleted file mode 100644 index b9250d0..0000000 --- a/tools/buildbot/pylibs/twisted/manhole/gladereactor.py +++ /dev/null @@ -1,219 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -A modified gtk2 reactor with a Glade dialog in-process that allows you to stop, -suspend, resume and inspect transports interactively. -""" - -__all__ = ['install'] - -# Twisted Imports -from twisted.python import log, threadable, runtime, failure, util, reflect -from twisted.internet.gtk2reactor import Gtk2Reactor as sup - -import gtk -import gobject -import gtk.glade - -COLUMN_DESCRIPTION = 0 -COLUMN_TRANSPORT = 1 -COLUMN_READING = 2 -COLUMN_WRITING = 3 - - -class GladeReactor(sup): - """GTK+-2 event loop reactor with GUI. - """ - - def listenTCP(self, port, factory, backlog=50, interface=''): - from _inspectro import LoggingFactory - factory = LoggingFactory(factory) - return sup.listenTCP(self, port, factory, backlog, interface) - - def connectTCP(self, host, port, factory, timeout=30, bindAddress=None): - from _inspectro import LoggingFactory - factory = LoggingFactory(factory) - return sup.connectTCP(self, host, port, factory, timeout, bindAddress) - - def listenSSL(self, port, factory, contextFactory, backlog=50, interface=''): - from _inspectro import LoggingFactory - factory = LoggingFactory(factory) - return sup.listenSSL(self, port, factory, contextFactory, backlog, interface) - - def connectSSL(self, host, port, factory, contextFactory, timeout=30, bindAddress=None): - from _inspectro import LoggingFactory - factory = LoggingFactory(factory) - return sup.connectSSL(self, host, port, factory, contextFactory, timeout, bindAddress) - - def connectUNIX(self, address, factory, timeout=30): - from _inspectro import LoggingFactory - factory = LoggingFactory(factory) - return sup.connectUNIX(self, address, factory, timeout) - - def listenUNIX(self, address, factory, backlog=50, mode=0666): - from _inspectro import LoggingFactory - factory = LoggingFactory(factory) - return sup.listenUNIX(self, address, factory, backlog, mode) - - def on_disconnect_clicked(self, w): - store, iter = self.servers.get_selection().get_selected() - store[iter][COLUMN_TRANSPORT].loseConnection() - - def on_viewlog_clicked(self, w): - store, iter = self.servers.get_selection().get_selected() - data = store[iter][1] - from _inspectro import LogViewer - if hasattr(data, "protocol") and not data.protocol.logViewer: - LogViewer(data.protocol) - - def on_inspect_clicked(self, w): - store, iter = self.servers.get_selection().get_selected() - data = store[iter] - from _inspectro import Inspectro - Inspectro(data[1]) - - def on_suspend_clicked(self, w): - store, iter = self.servers.get_selection().get_selected() - data = store[iter] - sup.removeReader(self, data[1]) - sup.removeWriter(self, data[1]) - if data[COLUMN_DESCRIPTION].endswith('(suspended)'): - if data[COLUMN_READING]: - sup.addReader(self, data[COLUMN_TRANSPORT]) - if data[COLUMN_WRITING]: - sup.addWriter(self, data[COLUMN_TRANSPORT]) - data[COLUMN_DESCRIPTION] = str(data[COLUMN_TRANSPORT]) - self.toggle_suspend(1) - else: - data[0] += ' (suspended)' - self.toggle_suspend(0) - - def toggle_suspend(self, suspending=0): - stock, nonstock = [('gtk-redo', 'Resume'), - ('gtk-undo', 'Suspend')][suspending] - b = self.xml.get_widget("suspend") - b.set_use_stock(1) - b.set_label(stock) - b.get_child().get_child().get_children()[1].set_label(nonstock) - - def servers_selection_changed(self, w): - store, iter = w.get_selected() - if iter is None: - self.xml.get_widget("suspend").set_sensitive(0) - self.xml.get_widget('disconnect').set_sensitive(0) - else: - data = store[iter] - self.toggle_suspend(not - data[COLUMN_DESCRIPTION].endswith('(suspended)')) - self.xml.get_widget("suspend").set_sensitive(1) - self.xml.get_widget('disconnect').set_sensitive(1) - - def on_quit_clicked(self, w): - self.stop() - - def __init__(self): - self.xml = gtk.glade.XML(util.sibpath(__file__,"gladereactor.glade")) - d = {} - for m in reflect.prefixedMethods(self, "on_"): - d[m.im_func.__name__] = m - self.xml.signal_autoconnect(d) - self.xml.get_widget('window1').connect('destroy', - lambda w: self.stop()) - self.servers = self.xml.get_widget("servertree") - sel = self.servers.get_selection() - sel.set_mode(gtk.SELECTION_SINGLE) - sel.connect("changed", - self.servers_selection_changed) - ## argh coredump: self.servers_selection_changed(sel) - self.xml.get_widget('suspend').set_sensitive(0) - self.xml.get_widget('disconnect').set_sensitive(0) - # setup model, connect it to my treeview - self.model = gtk.ListStore(str, object, gobject.TYPE_BOOLEAN, - gobject.TYPE_BOOLEAN) - self.servers.set_model(self.model) - self.servers.set_reorderable(1) - self.servers.set_headers_clickable(1) - # self.servers.set_headers_draggable(1) - # add a column - for col in [ - gtk.TreeViewColumn('Server', - gtk.CellRendererText(), - text=0), - gtk.TreeViewColumn('Reading', - gtk.CellRendererToggle(), - active=2), - gtk.TreeViewColumn('Writing', - gtk.CellRendererToggle(), - active=3)]: - - self.servers.append_column(col) - col.set_resizable(1) - sup.__init__(self) - - def addReader(self, reader): - sup.addReader(self, reader) -## gtk docs suggest this - but it's stupid -## self.model.set(self.model.append(), -## 0, str(reader), -## 1, reader) - self._maybeAddServer(reader, read=1) - - def _goAway(self,reader): - for p in range(len(self.model)): - if self.model[p][1] == reader: - self.model.remove(self.model.get_iter_from_string(str(p))) - return - - - def _maybeAddServer(self, reader, read=0, write=0): - p = 0 - for x in self.model: - if x[1] == reader: - if reader == 0: - reader += 1 - x[2] += read - x[3] += write - x[2] = max(x[2],0) - x[3] = max(x[3],0) - - if not (x[2] or x[3]): - x[0] = x[0] + '(disconnected)' - self.callLater(5, self._goAway, reader) - return - p += 1 - else: - read = max(read,0) - write = max(write, 0) - if read or write: - self.model.append((reader,reader,read,write)) - - def addWriter(self, writer): - sup.addWriter(self, writer) - self._maybeAddServer(writer, write=1) - - def removeReader(self, reader): - sup.removeReader(self, reader) - self._maybeAddServer(reader, read=-1) - - def removeWriter(self, writer): - sup.removeWriter(self, writer) - self._maybeAddServer(writer, write=-1) - - def crash(self): - gtk.main_quit() - - def run(self, installSignalHandlers=1): - self.startRunning(installSignalHandlers=installSignalHandlers) - self.simulate() - gtk.main() - - -def install(): - """Configure the twisted mainloop to be run inside the gtk mainloop. - """ - reactor = GladeReactor() - from twisted.internet.main import installReactor - installReactor(reactor) - return reactor diff --git a/tools/buildbot/pylibs/twisted/manhole/inspectro.glade b/tools/buildbot/pylibs/twisted/manhole/inspectro.glade deleted file mode 100644 index 94b8717..0000000 --- a/tools/buildbot/pylibs/twisted/manhole/inspectro.glade +++ /dev/null @@ -1,510 +0,0 @@ - - - - - - - - - True - Inspectro - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - 640 - 480 - True - False - True - - - - True - True - - - - True - GTK_SHADOW_NONE - - - - True - - - - True - Inspector - True - - - - - - - True - Select - True - - - - - - - True - Inspect - True - - - - - - - True - Inspect New - True - - - - - - - - - - - True - GNOMEUIINFO_MENU_HELP_TREE - - - - - - - True - GNOMEUIINFO_MENU_ABOUT_ITEM - - - - - - - - - - - - BONOBO_DOCK_TOP - 0 - 0 - 0 - BONOBO_DOCK_ITEM_BEH_EXCLUSIVE|BONOBO_DOCK_ITEM_BEH_NEVER_VERTICAL|BONOBO_DOCK_ITEM_BEH_LOCKED - - - - - - True - GTK_SHADOW_OUT - - - - True - GTK_ORIENTATION_HORIZONTAL - GTK_TOOLBAR_BOTH - True - - - - True - Select - True - gtk-convert - - - - - - - True - Inspect - True - gtk-jump-to - - - - - - - True - Inspect New - True - gtk-redo - - - - - - - - BONOBO_DOCK_TOP - 1 - 0 - 0 - BONOBO_DOCK_ITEM_BEH_EXCLUSIVE - - - - - - 350 - True - True - 250 - - - - True - False - 0 - - - - True - True - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - GTK_SHADOW_NONE - GTK_CORNER_TOP_LEFT - - - - True - True - True - False - False - True - - - - - - 0 - True - True - - - - - - True - 2 - 2 - False - 0 - 0 - - - - True - None - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - - - 1 - 2 - 0 - 1 - - - - - - - True - [] - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - - - 1 - 2 - 1 - 2 - - - - - - - True - It: - False - False - GTK_JUSTIFY_RIGHT - False - False - 0 - 0.5 - 0 - 0 - - - 0 - 1 - 0 - 1 - 3 - fill - - - - - - - True - Path: - False - False - GTK_JUSTIFY_RIGHT - False - False - 0 - 0.5 - 0 - 0 - - - 0 - 1 - 1 - 2 - 3 - fill - - - - - - 3 - False - True - - - - - True - False - - - - - - True - True - 303 - - - - True - True - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - GTK_SHADOW_NONE - GTK_CORNER_TOP_LEFT - - - - True - True - False - GTK_JUSTIFY_LEFT - GTK_WRAP_NONE - True - 0 - 0 - 0 - 0 - 0 - 0 - - - - - - False - True - - - - - - True - True - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - GTK_SHADOW_NONE - GTK_CORNER_TOP_LEFT - - - - True - GTK_SHADOW_IN - - - - True - False - 0 - - - - True - True - GTK_RELIEF_NORMAL - - - - - True - 0.5 - 0.5 - 0 - 0 - - - - True - False - 2 - - - - True - gtk-execute - 4 - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - True - >>> - True - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - - - - 0 - False - False - - - - - - 25 - True - True - True - True - GTK_JUSTIFY_LEFT - GTK_WRAP_NONE - True - 0 - 0 - 0 - 0 - 0 - 0 - - - - 0 - True - True - - - - - - - - - False - True - - - - - True - True - - - - - - - 0 - True - True - - - - - - True - False - True - - - 0 - True - True - - - - - diff --git a/tools/buildbot/pylibs/twisted/manhole/logview.glade b/tools/buildbot/pylibs/twisted/manhole/logview.glade deleted file mode 100644 index 1ec0b1f..0000000 --- a/tools/buildbot/pylibs/twisted/manhole/logview.glade +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - True - Log - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - True - False - - - - - True - True - GTK_POLICY_ALWAYS - GTK_POLICY_ALWAYS - GTK_SHADOW_NONE - GTK_CORNER_TOP_LEFT - - - - True - True - True - False - False - True - - - - - - - diff --git a/tools/buildbot/pylibs/twisted/manhole/service.py b/tools/buildbot/pylibs/twisted/manhole/service.py deleted file mode 100644 index 28572ad..0000000 --- a/tools/buildbot/pylibs/twisted/manhole/service.py +++ /dev/null @@ -1,399 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""L{twisted.manhole} L{PB} service implementation. -""" - -# twisted imports -from twisted import copyright -from twisted.spread import pb -from twisted.python import log, failure -from twisted.cred import portal -from twisted.application import service -from zope.interface import implements, Interface - -# sibling imports -import explorer - -# system imports -from cStringIO import StringIO - -import string -import sys -import traceback -import types - - -class FakeStdIO: - def __init__(self, type_, list): - self.type = type_ - self.list = list - - def write(self, text): - log.msg("%s: %s" % (self.type, string.strip(str(text)))) - self.list.append((self.type, text)) - - def flush(self): - pass - - def consolidate(self): - """Concatenate adjacent messages of same type into one. - - Greatly cuts down on the number of elements, increasing - network transport friendliness considerably. - """ - if not self.list: - return - - inlist = self.list - outlist = [] - last_type = inlist[0] - block_begin = 0 - for i in xrange(1, len(self.list)): - (mtype, message) = inlist[i] - if mtype == last_type: - continue - else: - if (i - block_begin) == 1: - outlist.append(inlist[block_begin]) - else: - messages = map(lambda l: l[1], - inlist[block_begin:i]) - message = string.join(messages, '') - outlist.append((last_type, message)) - last_type = mtype - block_begin = i - - -class IManholeClient(Interface): - def console(list_of_messages): - """Takes a list of (type, message) pairs to display. - - Types include: - - \"stdout\" -- string sent to sys.stdout - - - \"stderr\" -- string sent to sys.stderr - - - \"result\" -- string repr of the resulting value - of the expression - - - \"exception\" -- a L{failure.Failure} - """ - - def receiveExplorer(xplorer): - """Receives an explorer.Explorer - """ - - def listCapabilities(): - """List what manholey things I am capable of doing. - - i.e. C{\"Explorer\"}, C{\"Failure\"} - """ - -def runInConsole(command, console, globalNS=None, localNS=None, - filename=None, args=None, kw=None, unsafeTracebacks=False): - """Run this, directing all output to the specified console. - - If command is callable, it will be called with the args and keywords - provided. Otherwise, command will be compiled and eval'd. - (Wouldn't you like a macro?) - - Returns the command's return value. - - The console is called with a list of (type, message) pairs for - display, see L{IManholeClient.console}. - """ - output = [] - fakeout = FakeStdIO("stdout", output) - fakeerr = FakeStdIO("stderr", output) - errfile = FakeStdIO("exception", output) - code = None - val = None - if filename is None: - filename = str(console) - if args is None: - args = () - if kw is None: - kw = {} - if localNS is None: - localNS = globalNS - if (globalNS is None) and (not callable(command)): - raise ValueError("Need a namespace to evaluate the command in.") - - try: - out = sys.stdout - err = sys.stderr - sys.stdout = fakeout - sys.stderr = fakeerr - try: - if callable(command): - val = apply(command, args, kw) - else: - try: - code = compile(command, filename, 'eval') - except: - code = compile(command, filename, 'single') - - if code: - val = eval(code, globalNS, localNS) - finally: - sys.stdout = out - sys.stderr = err - except: - (eType, eVal, tb) = sys.exc_info() - fail = failure.Failure(eVal, eType, tb) - del tb - # In CVS reversion 1.35, there was some code here to fill in the - # source lines in the traceback for frames in the local command - # buffer. But I can't figure out when that's triggered, so it's - # going away in the conversion to Failure, until you bring it back. - errfile.write(pb.failure2Copyable(fail, unsafeTracebacks)) - - if console: - fakeout.consolidate() - console(output) - - return val - -def _failureOldStyle(fail): - """Pre-Failure manhole representation of exceptions. - - For compatibility with manhole clients without the \"Failure\" - capability. - - A dictionary with two members: - - \'traceback\' -- traceback.extract_tb output; a list of tuples - (filename, line number, function name, text) suitable for - feeding to traceback.format_list. - - - \'exception\' -- a list of one or more strings, each - ending in a newline. (traceback.format_exception_only output) - """ - import linecache - tb = [] - for f in fail.frames: - # (filename, line number, function name, text) - tb.append((f[1], f[2], f[0], linecache.getline(f[1], f[2]))) - - return { - 'traceback': tb, - 'exception': traceback.format_exception_only(fail.type, fail.value) - } - -# Capabilities clients are likely to have before they knew how to answer a -# "listCapabilities" query. -_defaultCapabilities = { - "Explorer": 'Set' - } - -class Perspective(pb.Avatar): - lastDeferred = 0 - def __init__(self, service): - self.localNamespace = { - "service": service, - "avatar": self, - "_": None, - } - self.clients = {} - self.service = service - - def __getstate__(self): - state = self.__dict__.copy() - state['clients'] = {} - if state['localNamespace'].has_key("__builtins__"): - del state['localNamespace']['__builtins__'] - return state - - def attached(self, client, identity): - """A client has attached -- welcome them and add them to the list. - """ - self.clients[client] = identity - - host = ':'.join(map(str, client.broker.transport.getHost()[1:])) - - msg = self.service.welcomeMessage % { - 'you': getattr(identity, 'name', str(identity)), - 'host': host, - 'longversion': copyright.longversion, - } - - client.callRemote('console', [("stdout", msg)]) - - client.capabilities = _defaultCapabilities - client.callRemote('listCapabilities').addCallbacks( - self._cbClientCapable, self._ebClientCapable, - callbackArgs=(client,),errbackArgs=(client,)) - - def detached(self, client, identity): - try: - del self.clients[client] - except KeyError: - pass - - def runInConsole(self, command, *args, **kw): - """Convience method to \"runInConsole with my stuff\". - """ - return runInConsole(command, - self.console, - self.service.namespace, - self.localNamespace, - str(self.service), - args=args, - kw=kw, - unsafeTracebacks=self.service.unsafeTracebacks) - - - ### Methods for communicating to my clients. - - def console(self, message): - """Pass a message to my clients' console. - """ - clients = self.clients.keys() - origMessage = message - compatMessage = None - for client in clients: - try: - if not client.capabilities.has_key("Failure"): - if compatMessage is None: - compatMessage = origMessage[:] - for i in xrange(len(message)): - if ((message[i][0] == "exception") and - isinstance(message[i][1], failure.Failure)): - compatMessage[i] = ( - message[i][0], - _failureOldStyle(message[i][1])) - client.callRemote('console', compatMessage) - else: - client.callRemote('console', message) - except pb.ProtocolError: - # Stale broker. - self.detached(client, None) - - def receiveExplorer(self, objectLink): - """Pass an Explorer on to my clients. - """ - clients = self.clients.keys() - for client in clients: - try: - client.callRemote('receiveExplorer', objectLink) - except pb.ProtocolError: - # Stale broker. - self.detached(client, None) - - - def _cbResult(self, val, dnum): - self.console([('result', "Deferred #%s Result: %r\n" %(dnum, val))]) - return val - - def _cbClientCapable(self, capabilities, client): - log.msg("client %x has %s" % (id(client), capabilities)) - client.capabilities = capabilities - - def _ebClientCapable(self, reason, client): - reason.trap(AttributeError) - log.msg("Couldn't get capabilities from %s, assuming defaults." % - (client,)) - - ### perspective_ methods, commands used by the client. - - def perspective_do(self, expr): - """Evaluate the given expression, with output to the console. - - The result is stored in the local variable '_', and its repr() - string is sent to the console as a \"result\" message. - """ - log.msg(">>> %s" % expr) - val = self.runInConsole(expr) - if val is not None: - self.localNamespace["_"] = val - from twisted.internet.defer import Deferred - # TODO: client support for Deferred. - if isinstance(val, Deferred): - self.lastDeferred += 1 - self.console([('result', "Waiting for Deferred #%s...\n" % self.lastDeferred)]) - val.addBoth(self._cbResult, self.lastDeferred) - else: - self.console([("result", repr(val) + '\n')]) - log.msg("<<<") - - def perspective_explore(self, identifier): - """Browse the object obtained by evaluating the identifier. - - The resulting ObjectLink is passed back through the client's - receiveBrowserObject method. - """ - object = self.runInConsole(identifier) - if object: - expl = explorer.explorerPool.getExplorer(object, identifier) - self.receiveExplorer(expl) - - def perspective_watch(self, identifier): - """Watch the object obtained by evaluating the identifier. - - Whenever I think this object might have changed, I will pass - an ObjectLink of it back to the client's receiveBrowserObject - method. - """ - raise NotImplementedError - object = self.runInConsole(identifier) - if object: - # Return an ObjectLink of this right away, before the watch. - oLink = self.runInConsole(self.browser.browseObject, - object, identifier) - self.receiveExplorer(oLink) - - self.runInConsole(self.browser.watchObject, - object, identifier, - self.receiveExplorer) - - -class Realm: - - implements(portal.IRealm) - - def __init__(self, service): - self.service = service - self._cache = {} - - def requestAvatar(self, avatarId, mind, *interfaces): - if pb.IPerspective not in interfaces: - raise NotImplementedError("no interface") - if avatarId in self._cache: - p = self._cache[avatarId] - else: - p = Perspective(self.service) - p.attached(mind, avatarId) - def detached(): - p.detached(mind, avatarId) - return (pb.IPerspective, p, detached) - - -class Service(service.Service): - - welcomeMessage = ( - "\nHello %(you)s, welcome to Manhole " - "on %(host)s.\n" - "%(longversion)s.\n\n") - - def __init__(self, unsafeTracebacks=False, namespace=None): - self.unsafeTracebacks = unsafeTracebacks - self.namespace = { - '__name__': '__manhole%x__' % (id(self),), - 'sys': sys - } - if namespace: - self.namespace.update(namespace) - - def __getstate__(self): - """This returns the persistent state of this shell factory. - """ - # TODO -- refactor this and twisted.reality.author.Author to - # use common functionality (perhaps the 'code' module?) - dict = self.__dict__.copy() - ns = dict['namespace'].copy() - dict['namespace'] = ns - if ns.has_key('__builtins__'): - del ns['__builtins__'] - return dict diff --git a/tools/buildbot/pylibs/twisted/manhole/telnet.py b/tools/buildbot/pylibs/twisted/manhole/telnet.py deleted file mode 100644 index 2e623647..0000000 --- a/tools/buildbot/pylibs/twisted/manhole/telnet.py +++ /dev/null @@ -1,117 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Telnet-based shell.""" - -# twisted imports -from twisted.protocols import telnet -from twisted.internet import protocol -from twisted.python import log, failure - -# system imports -import string, copy, sys -from cStringIO import StringIO - - -class Shell(telnet.Telnet): - """A Python command-line shell.""" - - def connectionMade(self): - telnet.Telnet.connectionMade(self) - self.lineBuffer = [] - - def loggedIn(self): - self.transport.write(">>> ") - - def checkUserAndPass(self, username, password): - return ((self.factory.username == username) and (password == self.factory.password)) - - def write(self, data): - """Write some data to the transport. - """ - self.transport.write(data) - - def telnet_Command(self, cmd): - if self.lineBuffer: - if not cmd: - cmd = string.join(self.lineBuffer, '\n') + '\n\n\n' - self.doCommand(cmd) - self.lineBuffer = [] - return "Command" - else: - self.lineBuffer.append(cmd) - self.transport.write("... ") - return "Command" - else: - self.doCommand(cmd) - return "Command" - - def doCommand(self, cmd): - - # TODO -- refactor this, Reality.author.Author, and the manhole shell - #to use common functionality (perhaps a twisted.python.code module?) - fn = '$telnet$' - result = None - try: - out = sys.stdout - sys.stdout = self - try: - code = compile(cmd,fn,'eval') - result = eval(code, self.factory.namespace) - except: - try: - code = compile(cmd, fn, 'exec') - exec code in self.factory.namespace - except SyntaxError, e: - if not self.lineBuffer and str(e)[:14] == "unexpected EOF": - self.lineBuffer.append(cmd) - self.transport.write("... ") - return - else: - failure.Failure().printTraceback(file=self) - log.deferr() - self.write('\r\n>>> ') - return - except: - io = StringIO() - failure.Failure().printTraceback(file=self) - log.deferr() - self.write('\r\n>>> ') - return - finally: - sys.stdout = out - - self.factory.namespace['_'] = result - if result is not None: - self.transport.write(repr(result)) - self.transport.write('\r\n') - self.transport.write(">>> ") - - - -class ShellFactory(protocol.Factory): - username = "admin" - password = "admin" - protocol = Shell - service = None - - def __init__(self): - self.namespace = { - 'factory': self, - 'service': None, - '_': None - } - - def setService(self, service): - self.namespace['service'] = self.service = service - - def __getstate__(self): - """This returns the persistent state of this shell factory. - """ - dict = self.__dict__ - ns = copy.copy(dict['namespace']) - dict['namespace'] = ns - if ns.has_key('__builtins__'): - del ns['__builtins__'] - return dict diff --git a/tools/buildbot/pylibs/twisted/manhole/ui/__init__.py b/tools/buildbot/pylibs/twisted/manhole/ui/__init__.py deleted file mode 100644 index adfa9ac..0000000 --- a/tools/buildbot/pylibs/twisted/manhole/ui/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Twisted Manhole UI: User interface for direct manipulation in Twisted. -""" diff --git a/tools/buildbot/pylibs/twisted/manhole/ui/gtk2manhole.glade b/tools/buildbot/pylibs/twisted/manhole/ui/gtk2manhole.glade deleted file mode 100644 index 423b3fb..0000000 --- a/tools/buildbot/pylibs/twisted/manhole/ui/gtk2manhole.glade +++ /dev/null @@ -1,268 +0,0 @@ - - - - - - - True - Manhole - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - 620 - 320 - True - False - True - False - False - GDK_WINDOW_TYPE_HINT_NORMAL - GDK_GRAVITY_NORTH_WEST - - - - - True - False - 0 - - - - True - - - - True - _File - True - - - - - - - True - gtk-open - True - - - - - - - True - Reload the manhole client code. (Only useful for client development.) - _Reload self - True - - - - - True - gtk-revert-to-saved - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - - - - - - True - gtk-quit - True - - - - - - - - - - - True - _Edit - True - - - - - - - True - gtk-cut - True - - - - - - - True - gtk-copy - True - - - - - - - True - gtk-paste - True - - - - - - - True - gtk-delete - True - - - - - - - - - - - True - _Help - True - - - - - - - True - _About - True - - - - - - - - - - 0 - False - False - - - - - - True - True - - - - True - True - GTK_POLICY_AUTOMATIC - GTK_POLICY_ALWAYS - GTK_SHADOW_NONE - GTK_CORNER_TOP_LEFT - - - - True - True - False - False - True - GTK_JUSTIFY_LEFT - GTK_WRAP_WORD - True - 0 - 0 - 0 - 0 - 0 - 0 - - - - - - True - True - - - - - - True - True - GTK_POLICY_AUTOMATIC - GTK_POLICY_ALWAYS - GTK_SHADOW_NONE - GTK_CORNER_TOP_LEFT - - - - True - True - True - True - False - True - GTK_JUSTIFY_LEFT - GTK_WRAP_NONE - True - 0 - 0 - 0 - 0 - 0 - 0 - - - - - - True - False - - - - - 0 - True - True - - - - - - True - True - - - 0 - False - False - - - - - - - diff --git a/tools/buildbot/pylibs/twisted/manhole/ui/gtk2manhole.py b/tools/buildbot/pylibs/twisted/manhole/ui/gtk2manhole.py deleted file mode 100644 index cff81da..0000000 --- a/tools/buildbot/pylibs/twisted/manhole/ui/gtk2manhole.py +++ /dev/null @@ -1,377 +0,0 @@ -# -*- Python -*- -# $Id: gtk2manhole.py,v 1.9 2003/09/07 19:58:09 acapnotic Exp $ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Manhole client with a GTK v2.x front-end. -""" - -__version__ = '$Revision: 1.9 $'[11:-2] - -from twisted import copyright -from twisted.internet import reactor -from twisted.python import components, failure, log, util -from twisted.spread import pb -from twisted.spread.ui import gtk2util - -from twisted.manhole.service import IManholeClient -from zope.interface import implements - -# The pygtk.require for version 2.0 has already been done by the reactor. -import gtk - -import code, types, inspect - -# TODO: -# Make wrap-mode a run-time option. -# Explorer. -# Code doesn't cleanly handle opening a second connection. Fix that. -# Make some acknowledgement of when a command has completed, even if -# it has no return value so it doesn't print anything to the console. - -class OfflineError(Exception): - pass - -class ManholeWindow(components.Componentized, gtk2util.GladeKeeper): - gladefile = util.sibpath(__file__, "gtk2manhole.glade") - - _widgets = ('input','output','manholeWindow') - - def __init__(self): - self.defaults = {} - gtk2util.GladeKeeper.__init__(self) - components.Componentized.__init__(self) - - self.input = ConsoleInput(self._input) - self.input.toplevel = self - self.output = ConsoleOutput(self._output) - - # Ugh. GladeKeeper actually isn't so good for composite objects. - # I want this connected to the ConsoleInput's handler, not something - # on this class. - self._input.connect("key_press_event", self.input._on_key_press_event) - - def setDefaults(self, defaults): - self.defaults = defaults - - def login(self): - client = self.getComponent(IManholeClient) - d = gtk2util.login(client, **self.defaults) - d.addCallback(self._cbLogin) - d.addCallback(client._cbLogin) - d.addErrback(self._ebLogin) - - def _cbDisconnected(self, perspective): - self.output.append("%s went away. :(\n" % (perspective,), "local") - self._manholeWindow.set_title("Manhole") - - def _cbLogin(self, perspective): - peer = perspective.broker.transport.getPeer() - self.output.append("Connected to %s\n" % (peer,), "local") - perspective.notifyOnDisconnect(self._cbDisconnected) - self._manholeWindow.set_title("Manhole - %s" % (peer)) - return perspective - - def _ebLogin(self, reason): - self.output.append("Login FAILED %s\n" % (reason.value,), "exception") - - def _on_aboutMenuItem_activate(self, widget, *unused): - import sys - from os import path - self.output.append("""\ -a Twisted Manhole client - Versions: - %(twistedVer)s - Python %(pythonVer)s on %(platform)s - GTK %(gtkVer)s / PyGTK %(pygtkVer)s - %(module)s %(modVer)s -http://twistedmatrix.com/ -""" % {'twistedVer': copyright.longversion, - 'pythonVer': sys.version.replace('\n', '\n '), - 'platform': sys.platform, - 'gtkVer': ".".join(map(str, gtk.gtk_version)), - 'pygtkVer': ".".join(map(str, gtk.pygtk_version)), - 'module': path.basename(__file__), - 'modVer': __version__, - }, "local") - - def _on_openMenuItem_activate(self, widget, userdata=None): - self.login() - - def _on_manholeWindow_delete_event(self, widget, *unused): - reactor.stop() - - def _on_quitMenuItem_activate(self, widget, *unused): - reactor.stop() - - def on_reload_self_activate(self, *unused): - from twisted.python import rebuild - rebuild.rebuild(inspect.getmodule(self.__class__)) - - -tagdefs = { - 'default': {"family": "monospace"}, - # These are message types we get from the server. - 'stdout': {"foreground": "black"}, - 'stderr': {"foreground": "#AA8000"}, - 'result': {"foreground": "blue"}, - 'exception': {"foreground": "red"}, - # Messages generate locally. - 'local': {"foreground": "#008000"}, - 'log': {"foreground": "#000080"}, - 'command': {"foreground": "#666666"}, - } - -# TODO: Factor Python console stuff back out to pywidgets. - -class ConsoleOutput: - _willScroll = None - def __init__(self, textView): - self.textView = textView - self.buffer = textView.get_buffer() - - # TODO: Make this a singleton tag table. - for name, props in tagdefs.iteritems(): - tag = self.buffer.create_tag(name) - # This can be done in the constructor in newer pygtk (post 1.99.14) - for k, v in props.iteritems(): - tag.set_property(k, v) - - self.buffer.tag_table.lookup("default").set_priority(0) - - self._captureLocalLog() - - def _captureLocalLog(self): - return log.startLogging(_Notafile(self, "log"), setStdout=False) - - def append(self, text, kind=None): - # XXX: It seems weird to have to do this thing with always applying - # a 'default' tag. Can't we change the fundamental look instead? - tags = ["default"] - if kind is not None: - tags.append(kind) - - self.buffer.insert_with_tags_by_name(self.buffer.get_end_iter(), - text, *tags) - # Silly things, the TextView needs to update itself before it knows - # where the bottom is. - if self._willScroll is None: - self._willScroll = gtk.idle_add(self._scrollDown) - - def _scrollDown(self, *unused): - self.textView.scroll_to_iter(self.buffer.get_end_iter(), 0, - True, 1.0, 1.0) - self._willScroll = None - return False - -class History: - def __init__(self, maxhist=10000): - self.ringbuffer = [''] - self.maxhist = maxhist - self.histCursor = 0 - - def append(self, htext): - self.ringbuffer.insert(-1, htext) - if len(self.ringbuffer) > self.maxhist: - self.ringbuffer.pop(0) - self.histCursor = len(self.ringbuffer) - 1 - self.ringbuffer[-1] = '' - - def move(self, prevnext=1): - ''' - Return next/previous item in the history, stopping at top/bottom. - ''' - hcpn = self.histCursor + prevnext - if hcpn >= 0 and hcpn < len(self.ringbuffer): - self.histCursor = hcpn - return self.ringbuffer[hcpn] - else: - return None - - def histup(self, textbuffer): - if self.histCursor == len(self.ringbuffer) - 1: - si, ei = textbuffer.get_start_iter(), textbuffer.get_end_iter() - self.ringbuffer[-1] = textbuffer.get_text(si,ei) - newtext = self.move(-1) - if newtext is None: - return - textbuffer.set_text(newtext) - - def histdown(self, textbuffer): - newtext = self.move(1) - if newtext is None: - return - textbuffer.set_text(newtext) - - -class ConsoleInput: - toplevel, rkeymap = None, None - __debug = False - - def __init__(self, textView): - self.textView=textView - self.rkeymap = {} - self.history = History() - for name in dir(gtk.keysyms): - try: - self.rkeymap[getattr(gtk.keysyms, name)] = name - except TypeError: - pass - - def _on_key_press_event(self, entry, event): - stopSignal = False - ksym = self.rkeymap.get(event.keyval, None) - - mods = [] - for prefix, mask in [('ctrl', gtk.gdk.CONTROL_MASK), ('shift', gtk.gdk.SHIFT_MASK)]: - if event.state & mask: - mods.append(prefix) - - if mods: - ksym = '_'.join(mods + [ksym]) - - if ksym: - rvalue = getattr( - self, 'key_%s' % ksym, lambda *a, **kw: None)(entry, event) - - if self.__debug: - print ksym - return rvalue - - def getText(self): - buffer = self.textView.get_buffer() - iter1, iter2 = buffer.get_bounds() - text = buffer.get_text(iter1, iter2, False) - return text - - def setText(self, text): - self.textView.get_buffer().set_text(text) - - def key_Return(self, entry, event): - text = self.getText() - # Figure out if that Return meant "next line" or "execute." - try: - c = code.compile_command(text) - except SyntaxError, e: - # This could conceivably piss you off if the client's python - # doesn't accept keywords that are known to the manhole's - # python. - point = buffer.get_iter_at_line_offset(e.lineno, e.offset) - buffer.place(point) - # TODO: Componentize! - self.toplevel.output.append(str(e), "exception") - except (OverflowError, ValueError), e: - self.toplevel.output.append(str(e), "exception") - else: - if c is not None: - self.sendMessage() - # Don't insert Return as a newline in the buffer. - self.history.append(text) - self.clear() - # entry.emit_stop_by_name("key_press_event") - return True - else: - # not a complete code block - return False - - return False - - def key_Up(self, entry, event): - # if I'm at the top, previous history item. - textbuffer = self.textView.get_buffer() - if textbuffer.get_iter_at_mark(textbuffer.get_insert()).get_line() == 0: - self.history.histup(textbuffer) - return True - return False - - def key_Down(self, entry, event): - textbuffer = self.textView.get_buffer() - if textbuffer.get_iter_at_mark(textbuffer.get_insert()).get_line() == ( - textbuffer.get_line_count() - 1): - self.history.histdown(textbuffer) - return True - return False - - key_ctrl_p = key_Up - key_ctrl_n = key_Down - - def key_ctrl_shift_F9(self, entry, event): - if self.__debug: - import pdb; pdb.set_trace() - - def clear(self): - buffer = self.textView.get_buffer() - buffer.delete(*buffer.get_bounds()) - - def sendMessage(self): - buffer = self.textView.get_buffer() - iter1, iter2 = buffer.get_bounds() - text = buffer.get_text(iter1, iter2, False) - self.toplevel.output.append(pythonify(text), 'command') - # TODO: Componentize better! - try: - return self.toplevel.getComponent(IManholeClient).do(text) - except OfflineError: - self.toplevel.output.append("Not connected, command not sent.\n", - "exception") - - -def pythonify(text): - ''' - Make some text appear as though it was typed in at a Python prompt. - ''' - lines = text.split('\n') - lines[0] = '>>> ' + lines[0] - return '\n... '.join(lines) + '\n' - -class _Notafile: - """Curry to make failure.printTraceback work with the output widget.""" - def __init__(self, output, kind): - self.output = output - self.kind = kind - - def write(self, txt): - self.output.append(txt, self.kind) - - def flush(self): - pass - -class ManholeClient(components.Adapter, pb.Referenceable): - implements(IManholeClient) - - capabilities = { -# "Explorer": 'Set', - "Failure": 'Set' - } - - def _cbLogin(self, perspective): - self.perspective = perspective - perspective.notifyOnDisconnect(self._cbDisconnected) - return perspective - - def remote_console(self, messages): - for kind, content in messages: - if isinstance(content, types.StringTypes): - self.original.output.append(content, kind) - elif (kind == "exception") and isinstance(content, failure.Failure): - content.printTraceback(_Notafile(self.original.output, - "exception")) - else: - self.original.output.append(str(content), kind) - - def remote_receiveExplorer(self, xplorer): - pass - - def remote_listCapabilities(self): - return self.capabilities - - def _cbDisconnected(self, perspective): - self.perspective = None - - def do(self, text): - if self.perspective is None: - raise OfflineError - return self.perspective.callRemote("do", text) - -components.registerAdapter(ManholeClient, ManholeWindow, IManholeClient) diff --git a/tools/buildbot/pylibs/twisted/manhole/ui/gtkmanhole.py b/tools/buildbot/pylibs/twisted/manhole/ui/gtkmanhole.py deleted file mode 100644 index 6772001..0000000 --- a/tools/buildbot/pylibs/twisted/manhole/ui/gtkmanhole.py +++ /dev/null @@ -1,184 +0,0 @@ -# -*- Python -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -# TODO: -# * send script -# * replace method -# * save readline history -# * save-history-as-python -# * save transcript -# * identifier completion - -import code, string, sys, traceback, types -import gtk - -from twisted.python import rebuild, util -from twisted.spread.ui import gtkutil -from twisted.spread import pb -from twisted.manhole import explorer - -True = gtk.TRUE -False = gtk.FALSE - -try: - import spelunk_gnome -except ImportError: - _GNOME_POWER = False -else: - _GNOME_POWER = True - - -## def findBeginningOfLineWithPoint(entry): -## pos = entry.get_point() -## while pos: -## pos = pos - 1 -## c = entry.get_chars(pos, pos+1) -## if c == '\n': -## return pos+1 -## return 0 - -import pywidgets - -class Interaction(pywidgets.Interaction, pb.Referenceable): - loginWindow = None - - capabilities = { - "Explorer": 'Set', - } - - def __init__(self): - pywidgets.Interaction.__init__(self) - self.signal_connect('destroy', gtk.mainquit, None) - - if _GNOME_POWER: - self.display = BrowserDisplay() - dWindow = gtk.GtkWindow(title="Spelunking") - dWindow.add(self.display) - dWindow.show_all() - self.display.makeDefaultCanvas() - else: - self.display = BrowserDisplay(self) - - # The referencable attached to the Perspective - self.client = self - - def remote_console(self, message): - self.output.console(message) - - def remote_receiveExplorer(self, xplorer): - if _GNOME_POWER: - self.display.receiveExplorer(xplorer) - else: - XXX # text display? - - def remote_listCapabilities(self): - return self.capabilities - - def connected(self, perspective): - self.loginWindow.hide() - self.name = self.loginWindow.username.get_text() - self.hostname = self.loginWindow.hostname.get_text() - perspective.broker.notifyOnDisconnect(self.connectionLost) - self.perspective = perspective - self.show_all() - self.set_title("Manhole: %s@%s" % (self.name, self.hostname)) - - def connectionLost(self, reason=None): - if not reason: - reason = "Connection Lost" - self.loginWindow.loginReport(reason) - self.hide() - self.loginWindow.show() - - def codeInput(self, text): - methodName = 'do' - if text[0] == '/': - split = string.split(text[1:],' ',1) - statement = split[0] - if len(split) == 2: - remainder = split[1] - if statement in ('browse', 'explore'): - methodName = 'explore' - text = remainder - elif statement == 'watch': - methodName = 'watch' - text = remainder - elif statement == 'self_rebuild': - rebuild.rebuild(explorer) - if _GNOME_POWER: - rebuild.rebuild(spelunk_gnome) - rebuild.rebuild(sys.modules[__name__]) - return - try: - self.perspective.callRemote(methodName, text) - except pb.ProtocolError: - # ASSUMPTION: pb.ProtocolError means we lost our connection. - (eType, eVal, tb) = sys.exc_info() - del tb - s = string.join(traceback.format_exception_only(eType, eVal), - '') - self.connectionLost(s) - except: - traceback.print_exc() - gtk.mainquit() - - -class LineOrientedBrowserDisplay: - def __init__(self, toplevel=None): - if toplevel: - self.toplevel = toplevel - - def receiveBrowserObject(self, obj): - """Display a browser ObjectLink. - """ - # This is a stop-gap implementation. Ideally, everything - # would be nicely formatted with pretty colours and you could - # select referenced objects to browse them with - # browse(selectedLink.identifier) - - if obj.type in map(explorer.typeString, [types.FunctionType, - types.MethodType]): - arglist = [] - for arg in obj.value['signature']: - if arg.has_key('default'): - a = "%s=%s" % (arg['name'], arg['default']) - elif arg.has_key('list'): - a = "*%s" % (arg['name'],) - elif arg.has_key('keywords'): - a = "**%s" % (arg['name'],) - else: - a = arg['name'] - arglist.append(a) - - things = '' - if obj.value.has_key('class'): - things = "Class: %s\n" % (obj.value['class'],) - if obj.value.has_key('self'): - things = things + "Self: %s\n" % (obj.value['self'],) - - s = "%(name)s(%(arglist)s)\n%(things)s\n%(doc)s\n" % { - 'name': obj.value['name'], - 'doc': obj.value['doc'], - 'things': things, - 'arglist': string.join(arglist,", "), - } - else: - s = str(obj) + '\n' - - self.toplevel.output.console([('stdout',s)]) - - -if _GNOME_POWER: - BrowserDisplay = spelunk_gnome.SpelunkDisplay -else: - BrowserDisplay = LineOrientedBrowserDisplay - -class Signature(pb.RemoteCopy, explorer.Signature): - def __init__(self): - pass - - __str__ = explorer.Signature.__str__ - -pb.setCopierForClass('twisted.manhole.explorer.Signature', Signature) diff --git a/tools/buildbot/pylibs/twisted/manhole/ui/gtkrc b/tools/buildbot/pylibs/twisted/manhole/ui/gtkrc deleted file mode 100644 index 891747e..0000000 --- a/tools/buildbot/pylibs/twisted/manhole/ui/gtkrc +++ /dev/null @@ -1,62 +0,0 @@ -style "codefont" { - font = "-adobe-courier-medium-r-normal-*-*-120-*-*-m-*-iso8859-1" -} - -style "Input" = "codefont" { - # pass -} - -style "Console" = "codefont" { - # XXX: We should include a bg[NORMAL] line here, but doing so - # messes things up as it doesn't seem to set the color of the - # backdrop. -} - -style "Console_stdout" = "Console" { - fg[NORMAL] = { 0, 0, 0 } -} - -style "Console_stderr" = "Console" { - fg[NORMAL] = { 0.66, 0.5, 0 } -} - -style "Console_result" = "Console" { - fg[NORMAL] = { 0, 0, 1.0 } -} - -style "Console_exception" = "Console" { - fg[NORMAL] = { 1.0, 0, 0 } -} - -style "Console_command" = "Console" { - fg[NORMAL] = { 0.4, 0.4, 0.4 } -} - -widget "Manhole.*.Input" style "Input" -widget "Manhole.*.Console" style "Console" - -style "Bold" { - font = "-urw-nimbus sans l-bold-r-normal-*-*-120-*-*-p-*-iso8859-1" -} - -style "BoldCompressed" { - font = "-urw-nimbus sans l-bold-r-condensed-*-*-120-*-*-p-*-iso8859-1" -} - -style "Compressed" { - font = "-urw-nimbus sans l-regular-r-condensed-*-*-120-*-*-p-*-iso8859-1" -} - -style "AttributeName" = "BoldCompressed" { - fg[NORMAL] = { 0.0, 0.3, 0.0 } -} - -style "AttributeValue" = "Compressed" { - fg[NORMAL] = { 0.0, 0.4, 0.6 } -} - -widget "*.Visage.*.AttributeGroupTitle*" style "Bold" -widget "*.Visage.*.PropertyName*" style "AttributeName" -widget "*.Visage.*.AttributeName*" style "AttributeName" -widget "*.Visage.*.PropertyValue*" style "AttributeValue" -widget "*.Visage.*.AttributeValue*" style "AttributeValue" diff --git a/tools/buildbot/pylibs/twisted/manhole/ui/pywidgets.py b/tools/buildbot/pylibs/twisted/manhole/ui/pywidgets.py deleted file mode 100644 index 5f8a6ab..0000000 --- a/tools/buildbot/pylibs/twisted/manhole/ui/pywidgets.py +++ /dev/null @@ -1,250 +0,0 @@ - -# System Imports -import code, string, sys, traceback -import gtk -True = 1 -False = 0 - -# Twisted Imports -from twisted.spread.ui import gtkutil -from twisted.python import util -rcfile = util.sibpath(__file__, 'gtkrc') -gtk.rc_parse(rcfile) - - -def isCursorOnFirstLine(entry): - firstnewline = string.find(entry.get_chars(0,-1), '\n') - if entry.get_point() <= firstnewline or firstnewline == -1: - return 1 - -def isCursorOnLastLine(entry): - if entry.get_point() >= string.rfind(string.rstrip(entry.get_chars(0,-1)), '\n'): - return 1 - - -class InputText(gtk.GtkText): - linemode = 0 - blockcount = 0 - - def __init__(self, toplevel=None): - gtk.GtkText.__init__(self) - self['name'] = 'Input' - self.set_editable(gtk.TRUE) - self.connect("key_press_event", self.processKey) - #self.set_word_wrap(gtk.TRUE) - - self.history = [] - self.histpos = 0 - - if toplevel: - self.toplevel = toplevel - - def historyUp(self): - if self.histpos > 0: - self.histpos = self.histpos - 1 - self.delete_text(0, -1) - self.insert_defaults(self.history[self.histpos]) - self.set_position(0) - - def historyDown(self): - if self.histpos < len(self.history) - 1: - self.histpos = self.histpos + 1 - self.delete_text(0, -1) - self.insert_defaults(self.history[self.histpos]) - elif self.histpos == len(self.history) - 1: - self.histpos = self.histpos + 1 - self.delete_text(0, -1) - - def processKey(self, entry, event): - # TODO: make key bindings easier to customize. - - stopSignal = False - # ASSUMPTION: Assume Meta == mod4 - isMeta = event.state & gtk.GDK.MOD4_MASK - if event.keyval == gtk.GDK.Return: - isShift = event.state & gtk.GDK.SHIFT_MASK - if isShift: - self.linemode = True - self.insert_defaults('\n') - else: - stopSignal = True - text = self.get_chars(0,-1) - if not text: return - try: - if text[0] == '/': - # It's a local-command, don't evaluate it as - # Python. - c = True - else: - # This will tell us it's a complete expression. - c = code.compile_command(text) - except SyntaxError, e: - # Ding! - self.set_positionLineOffset(e.lineno, e.offset) - print "offset", e.offset - errmsg = {'traceback': [], - 'exception': [str(e) + '\n']} - self.toplevel.output.console([('exception', errmsg)]) - except OverflowError, e: - e = traceback.format_exception_only(OverflowError, e) - errmsg = {'traceback': [], - 'exception': e} - self.toplevel.output.console([('exception', errmsg)]) - else: - if c is None: - self.linemode = True - stopSignal = False - else: - self.sendMessage(entry) - self.clear() - - elif ((event.keyval == gtk.GDK.Up and isCursorOnFirstLine(self)) - or (isMeta and event.string == 'p')): - self.historyUp() - stopSignal = True - elif ((event.keyval == gtk.GDK.Down and isCursorOnLastLine(self)) - or (isMeta and event.string == 'n')): - self.historyDown() - stopSignal = True - - if stopSignal: - self.emit_stop_by_name("key_press_event") - return True - - def clear(self): - self.delete_text(0, -1) - self.linemode = False - - def set_positionLineOffset(self, line, offset): - text = self.get_chars(0, -1) - pos = 0 - for l in xrange(line - 1): - pos = string.index(text, '\n', pos) + 1 - pos = pos + offset - 1 - self.set_position(pos) - - def sendMessage(self, unused_data=None): - text = self.get_chars(0,-1) - if self.linemode: - self.blockcount = self.blockcount + 1 - fmt = ">>> # begin %s\n%%s\n#end %s\n" % ( - self.blockcount, self.blockcount) - else: - fmt = ">>> %s\n" - self.history.append(text) - self.histpos = len(self.history) - self.toplevel.output.console([['command',fmt % text]]) - self.toplevel.codeInput(text) - - - def readHistoryFile(self, filename=None): - if filename is None: - filename = self.historyfile - - f = open(filename, 'r', 1) - self.history.extend(f.readlines()) - f.close() - self.histpos = len(self.history) - - def writeHistoryFile(self, filename=None): - if filename is None: - filename = self.historyfile - - f = open(filename, 'a', 1) - f.writelines(self.history) - f.close() - - -class Interaction(gtk.GtkWindow): - titleText = "Abstract Python Console" - - def __init__(self): - gtk.GtkWindow.__init__(self, gtk.WINDOW_TOPLEVEL) - self.set_title(self.titleText) - self.set_default_size(300, 300) - self.set_name("Manhole") - - vbox = gtk.GtkVBox() - pane = gtk.GtkVPaned() - - self.output = OutputConsole(toplevel=self) - pane.pack1(gtkutil.scrollify(self.output), gtk.TRUE, gtk.FALSE) - - self.input = InputText(toplevel=self) - pane.pack2(gtkutil.scrollify(self.input), gtk.FALSE, gtk.TRUE) - vbox.pack_start(pane, 1,1,0) - - self.add(vbox) - self.input.grab_focus() - - def codeInput(self, text): - raise NotImplementedError("Bleh.") - - -class LocalInteraction(Interaction): - titleText = "Local Python Console" - def __init__(self): - Interaction.__init__(self) - self.globalNS = {} - self.localNS = {} - self.filename = "" - - def codeInput(self, text): - from twisted.manhole.service import runInConsole - val = runInConsole(text, self.output.console, - self.globalNS, self.localNS, self.filename) - if val is not None: - self.localNS["_"] = val - self.output.console([("result", repr(val) + "\n")]) - -class OutputConsole(gtk.GtkText): - maxBufSz = 10000 - - def __init__(self, toplevel=None): - gtk.GtkText.__init__(self) - self['name'] = "Console" - gtkutil.defocusify(self) - #self.set_word_wrap(gtk.TRUE) - - if toplevel: - self.toplevel = toplevel - - def console(self, message): - self.set_point(self.get_length()) - self.freeze() - previous_kind = None - style = self.get_style() - style_cache = {} - try: - for element in message: - if element[0] == 'exception': - s = traceback.format_list(element[1]['traceback']) - s.extend(element[1]['exception']) - s = string.join(s, '') - else: - s = element[1] - - if element[0] != previous_kind: - style = style_cache.get(element[0], None) - if style is None: - gtk.rc_parse_string( - 'widget \"Manhole.*.Console\" ' - 'style \"Console_%s\"\n' - % (element[0])) - self.set_rc_style() - style_cache[element[0]] = style = self.get_style() - # XXX: You'd think we'd use style.bg instead of 'None' - # here, but that doesn't seem to match the color of - # the backdrop. - self.insert(style.font, style.fg[gtk.STATE_NORMAL], - None, s) - previous_kind = element[0] - l = self.get_length() - diff = self.maxBufSz - l - if diff < 0: - diff = - diff - self.delete_text(0,diff) - finally: - self.thaw() - a = self.get_vadjustment() - a.set_value(a.upper - a.page_size) diff --git a/tools/buildbot/pylibs/twisted/manhole/ui/spelunk_gnome.py b/tools/buildbot/pylibs/twisted/manhole/ui/spelunk_gnome.py deleted file mode 100644 index 72a509d..0000000 --- a/tools/buildbot/pylibs/twisted/manhole/ui/spelunk_gnome.py +++ /dev/null @@ -1,665 +0,0 @@ -# -*- Python -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Object browser GUI, GnomeCanvas implementation. -""" - -from twisted.python import log - -# TODO: -# gzigzag-style navigation - -class SillyModule: - def __init__(self, module, prefix): - self.__module = module - self.__prefix = prefix - - def __getattr__(self, attr): - try: - return getattr(self.__module, self.__prefix + attr) - except AttributeError: - return getattr(self.__module, attr) - - -# We use gnome.ui because that's what happens to have Python bindings -# for the Canvas. I think this canvas widget is available seperately -# in "libart", but nobody's given me Python bindings for just that. - -# The Gnome canvas is said to be modeled after the Tk canvas, so we -# could probably write this in Tk too. But my experience is with GTK, -# not with Tk, so this is what I use. - -import gnome.ui -gnome = SillyModule(gnome.ui, 'Gnome') - -import gtk -(True, False) = (gtk.TRUE, gtk.FALSE) -gtk = SillyModule(gtk, 'Gtk') - -import GDK - -from twisted.python import reflect, text -from twisted.spread import pb -from twisted.manhole import explorer - -import string, sys, types -import UserList -_PIXELS_PER_UNIT=10 - -#### Support class. - -class PairList(UserList.UserList): - """An ordered list of key, value pairs. - - Kinda like an ordered dictionary. Made with small data sets - in mind, as get() does a linear search, not hashing. - """ - def get(self, key): - i = 0 - for k, v in self.data: - if key == k: - return (i, v) - i = i + 1 - else: - return (None, None) - - def keys(self): - return map(lambda x: x[0], self.data) - - -#### Public - -class SpelunkDisplay(gnome.Canvas): - """Spelunk widget. - - The top-level widget for this module. This gtk.Widget is where the - explorer display will be, and this object is also your interface to - creating new visages. - """ - def __init__(self, aa=False): - gnome.Canvas.__init__(self, aa) - self.set_pixels_per_unit(_PIXELS_PER_UNIT) - self.visages = {} - - def makeDefaultCanvas(self): - """Make myself the default canvas which new visages are created on. - """ - # XXX: For some reason, the 'canvas' and 'parent' properties - # of CanvasItems aren't accessible thorugh pygnome. - Explorer.canvas = self - - def receiveExplorer(self, xplorer): - if self.visages.has_key(xplorer.id): - log.msg("Using cached visage for %d" % (xplorer.id, )) - # Ikk. Just because we just received this explorer, that - # doesn't necessarily mean its attributes are fresh. Fix - # that, either by having this side pull or the server - # side push. - visage = self.visages[xplorer.id] - #xplorer.give_properties(visage) - #xplorer.give_attributes(visage) - else: - log.msg("Making new visage for %d" % (xplorer.id, )) - self.visages[xplorer.id] = xplorer.newVisage(self.root(), - self) - -#### Base classes - -class Explorer(pb.RemoteCache): - """Base class for all RemoteCaches of explorer.Explorer cachables. - - Meaning that when an Explorer comes back over the wire, one of - these is created. From this, you can make a Visage for the - SpelunkDisplay, or a widget to display as an Attribute. - """ - canvas = None - # From our cache: - id = None - identifier = None - explorerClass = None - attributeGroups = None - - def newVisage(self, group, canvas=None): - """Make a new visage for the object I explore. - - Returns a Visage. - """ - canvas = canvas or self.canvas - klass = spelunkerClassTable.get(self.explorerClass, None) - if (not klass) or (klass[0] is None): - log.msg("%s not in table, using generic" % self.explorerClass) - klass = GenericVisage - else: - klass = klass[0] - spelunker = klass(self, group, canvas) - if hasattr(canvas, "visages") \ - and not canvas.visages.has_key(self.id): - canvas.visages[self.id] = spelunker - - self.give_properties(spelunker) - - self.give_attributes(spelunker) - - return spelunker - - def newAttributeWidget(self, group): - """Make a new attribute item for my object. - - Returns a gtk.Widget. - """ - klass = spelunkerClassTable.get(self.explorerClass, None) - if (not klass) or (klass[1] is None): - log.msg("%s not in table, using generic" % self.explorerClass) - klass = GenericAttributeWidget - else: - klass = klass[1] - - return klass(self, group) - - def give_properties(self, spelunker): - """Give a spelunker my properties in an ordered list. - """ - valuelist = PairList() - for p in spelunker.propertyLabels.keys(): - value = getattr(self, p, None) - valuelist.append((p,value)) - spelunker.fill_properties(valuelist) - - def give_attributes(self, spelunker): - for a in spelunker.groupLabels.keys(): - things = getattr(self, a) - spelunker.fill_attributeGroup(a, things) - -class _LooseBoxBorder: - box = None - color = 'black' - width = 1 - def __init__(self, box): - self.box = box - -class LooseBox(gnome.CanvasGroup): - def __init__(self): - self.border = _LooseBoxBorder(self) - -class Visage(gnome.CanvasGroup): - """A \"face\" of an object under exploration. - - A Visage is a representation of an object presented to the user. - The \"face\" in \"interface\". - - 'propertyLabels' and 'groupLabels' are lists of (key, name) - 2-ples, with 'key' being the string the property or group is - denoted by in the code, and 'name' being the pretty human-readable - string you want me to show on the Visage. These attributes are - accumulated from base classes as well. - - I am a gnome.CanvasItem (more specifically, CanvasGroup). - """ - color = {'border': '#006644'} - border_width = 8 - detail_level = 0 - # These are mappings from the strings the code calls these by - # and the pretty names you want to see on the screen. - # (e.g. Capitalized or localized) - propertyLabels = [] - groupLabels = [] - - drag_x0 = 0 - drag_y0 = 0 - - def __init__(self, explorer, rootGroup, canvas): - """Place a new Visage of an explorer in a canvas group. - - I also need a 'canvas' reference is for certain coordinate - conversions, and pygnome doesn't give access to my GtkObject's - .canvas attribute. :( - """ - # Ugh. PyGtk/GtkObject/GnomeCanvas interfacing grits. - gnome.CanvasGroup.__init__(self, - _obj = rootGroup.add('group')._o) - - self.propertyLabels = PairList() - reflect.accumulateClassList(self.__class__, 'propertyLabels', - self.propertyLabels) - self.groupLabels = PairList() - reflect.accumulateClassList(self.__class__, 'groupLabels', - self.groupLabels) - - self.explorer = explorer - self.identifier = explorer.identifier - self.objectId = explorer.id - - self.canvas = canvas - self.rootGroup = rootGroup - - self.ebox = gtk.EventBox() - self.ebox.set_name("Visage") - self.frame = gtk.Frame(self.identifier) - self.container = gtk.VBox() - self.ebox.add(self.frame) - self.frame.add(self.container) - - self.canvasWidget = self.add('widget', widget=self.ebox, - x=0, y=0, anchor=gtk.ANCHOR_NW, - size_pixels=0) - - self.border = self.add('rect', x1=0, y1=0, - x2=1, y2=1, - fill_color=None, - outline_color=self.color['border'], - width_pixels=self.border_width) - - self.subtable = {} - - self._setup_table() - - # TODO: - # Collapse me - # Movable/resizeable me - # Destroy me - # Set my detail level - - self.frame.connect("size_allocate", self.signal_size_allocate, - None) - self.connect("destroy", self.signal_destroy, None) - self.connect("event", self.signal_event) - - self.ebox.show_all() - - # Our creator will call our fill_ methods when she has the goods. - - def _setup_table(self): - """Called by __init__ to set up my main table. - - You can easily override me instead of clobbering __init__. - """ - - table = gtk.Table(len(self.propertyLabels), 2) - self.container.add(table) - table.set_name("PropertyTable") - self.subtable['properties'] = table - row = 0 - - for p, name in self.propertyLabels: - label = gtk.Label(name) - label.set_name("PropertyName") - label.set_data("property", p) - table.attach(label, 0, 1, row, row + 1) - label.set_alignment(0, 0) - row = row + 1 - - # XXX: make these guys collapsable - for g, name in self.groupLabels: - table = gtk.Table(1, 2) - self.container.add(table) - table.set_name("AttributeGroupTable") - self.subtable[g] = table - label = gtk.Label(name) - label.set_name("AttributeGroupTitle") - table.attach(label, 0, 2, 0, 1) - - def fill_properties(self, propValues): - """Fill in values for my properites. - - Takes a list of (name, value) pairs. 'name' should be one of - the keys in my propertyLabels, and 'value' either an Explorer - or a string. - """ - table = self.subtable['properties'] - - table.resize(len(propValues), 2) - - # XXX: Do I need to destroy previously attached children? - - for name, value in propValues: - self.fill_property(name, value) - - table.show_all() - - def fill_property(self, property, value): - """Set a value for a particular property. - - 'property' should be one of the keys in my propertyLabels. - """ - row, name = self.propertyLabels.get(property) - if type(value) is not types.InstanceType: - widget = gtk.Label(str(value)) - widget.set_alignment(0, 0) - else: - widget = value.newAttributeWidget(self) - widget.set_name("PropertyValue") - - self.subtable['properties'].attach(widget, 1, 2, row, row+1) - - def fill_attributeGroup(self, group, attributes): - """Provide members of an attribute group. - - 'group' should be one of the keys in my groupLabels, and - 'attributes' a list of (name, value) pairs, with each value as - either an Explorer or string. - """ - - # XXX: How to indicate detail level of members? - - table = self.subtable[group] - if not attributes: - table.hide() - return - - table.resize(len(attributes)+1, 2) - - # XXX: Do I need to destroy previously attached children? - - row = 1 # 0 is title - - for name, value in attributes.items(): - label = gtk.Label(name) - label.set_name("AttributeName") - label.set_alignment(0, 0) - - if type(value) is types.StringType: - widget = gtk.Label(value) - widget.set_alignment(0, 0) - else: - widget = value.newAttributeWidget(self) - - table.attach(label, 0, 1, row, row + 1) - table.attach(widget, 1, 2, row, row + 1) - row = row + 1 - - table.show_all() - - def signal_event(self, widget, event=None): - if not event: - log.msg("Huh? got event signal with no event.") - return - if event.type == GDK.BUTTON_PRESS: - if event.button == 1: - self.drag_x0, self.drag_y0 = event.x, event.y - return True - elif event.type == GDK.MOTION_NOTIFY: - if event.state & GDK.BUTTON1_MASK: - self.move(event.x - self.drag_x0, event.y - self.drag_y0) - self.drag_x0, self.drag_y0 = event.x, event.y - return True - return False - - def signal_size_allocate(self, frame_widget, - unusable_allocation, unused_data): - (x, y, w, h) = frame_widget.get_allocation() - - # XXX: allocation PyCObject is apparently unusable! - # (w, h) = allocation.width, allocation.height - - w, h = (float(w)/_PIXELS_PER_UNIT, float(h)/_PIXELS_PER_UNIT) - - x1, y1 = (self.canvasWidget['x'], self.canvasWidget['y']) - - b = self.border - (b['x1'], b['y1'], b['x2'], b['y2']) = (x1, y1, x1+w, y1+h) - - def signal_destroy(self, unused_object, unused_data): - del self.explorer - - del self.canvasWidget - del self.border - - del self.ebox - del self.frame - del self.container - - self.subtable.clear() - - -class AttributeWidget(gtk.Widget): - """A widget briefly describing an object. - - This is similar to a Visage, but has far less detail. This should - display only essential identifiying information, a gtk.Widget - suitable for including in a single table cell. - - (gtk.Widgets are used here instead of the more graphically - pleasing gnome.CanvasItems because I was too lazy to re-write - gtk.table for the canvas. A new table widget/item would be great - though, not only for canvas prettiness, but also because we could - use one with a mone pythonic API.) - - """ - def __init__(self, explorer, parent): - """A new AttributeWidget describing an explorer. - """ - self.parent = parent - - self.explorer = explorer - self.identifier = explorer.identifier - self.id = explorer.id - - widgetObj = self._makeWidgetObject() - gtk.Widget.__init__(self, _obj=widgetObj) - self.set_name("AttributeValue") - self.connect("destroy", self.signal_destroy, None) - self.connect("button-press-event", self.signal_buttonPressEvent, - None) - - def getTextForLabel(self): - """Returns text for my label. - - The default implementation of AttributeWidget is a gtk.Label - widget. You may override this method to change the text which - appears in the label. However, if you don't want to be a - label, override _makeWidgetObject instead. - """ - return self.identifier - - def _makeWidgetObject(self): - """Make the GTK widget object that is me. - - Called by __init__ to construct the GtkObject I wrap-- the ._o - member of a pygtk GtkObject. Isn't subclassing GtkObjects in - Python fun? - """ - ebox = gtk.EventBox() - label = gtk.Label(self.getTextForLabel()) - label.set_alignment(0,0) - ebox.add(label) - return ebox._o - - def signal_destroy(self, unused_object, unused_data): - del self.explorer - - def signal_buttonPressEvent(self, widget, eventButton, unused_data): - if eventButton.type == GDK._2BUTTON_PRESS: - if self.parent.canvas.visages.has_key(self.explorer.id): - visage = self.parent.canvas.visages[self.explorer.id] - else: - visage = self.explorer.newVisage(self.parent.rootGroup, - self.parent.canvas) - (x, y, w, h) = self.get_allocation() - wx, wy = self.parent.canvas.c2w(x, y) - - x1, y1, x2, y2 = self.parent.get_bounds() - - v_x1, v_y1, v_x2, v_y2 = visage.get_bounds() - - visage.move(x2 - v_x1, wy + y1 - v_y1) - - -#### Widget-specific subclasses of Explorer, Visage, and Attribute - -# Instance - -class ExplorerInstance(Explorer): - pass - -class InstanceVisage(Visage): - # Detail levels: - # Just me - # me and my class - # me and my whole class heirarchy - - propertyLabels = [('klass', "Class")] - groupLabels = [('data', "Data"), - ('methods', "Methods")] - - detail = 0 - - def __init__(self, explorer, group, canvas): - Visage.__init__(self, explorer, group, canvas) - - class_identifier = self.explorer.klass.name - # XXX: include partial module name in class? - self.frame.set_label("%s (%s)" % (self.identifier, - class_identifier)) - -class InstanceAttributeWidget(AttributeWidget): - def getTextForLabel(self): - return "%s instance" % (self.explorer.klass.name,) - - -# Class - -class ExplorerClass(Explorer): - pass - -class ClassVisage(Visage): - propertyLabels = [("name", "Name"), - ("module", "Module"), - ("bases", "Bases")] - groupLabels = [('data', "Data"), - ('methods', "Methods")] - - def fill_properties(self, propValues): - Visage.fill_properties(self, propValues) - basesExplorer = propValues.get('bases')[1] - basesExplorer.view.callRemote("get_elements").addCallback(self.fill_bases) - - def fill_bases(self, baseExplorers): - box = gtk.HBox() - for b in baseExplorers: - box.add(b.newAttributeWidget(self)) - row = self.propertyLabels.get('bases')[0] - self.subtable["properties"].attach(box, 1, 2, row, row+1) - box.show_all() - -class ClassAttributeWidget(AttributeWidget): - def getTextForLabel(self): - return self.explorer.name - - -# Function - -class ExplorerFunction(Explorer): - pass - -class FunctionAttributeWidget(AttributeWidget): - def getTextForLabel(self): - signature = self.explorer.signature - arglist = [] - for arg in xrange(len(signature)): - name = signature.name[arg] - hasDefault, default = signature.get_default(arg) - if hasDefault: - if default.explorerClass == "ExplorerImmutable": - default = default.value - else: - # XXX - pass - a = "%s=%s" % (name, default) - elif signature.is_varlist(arg): - a = "*%s" % (name,) - elif signature.is_keyword(arg): - a = "**%s" % (name,) - else: - a = name - arglist.append(a) - - return string.join(arglist, ", ") - - -# Method - -class ExplorerMethod(ExplorerFunction): - pass - -class MethodAttributeWidget(FunctionAttributeWidget): - pass - -class ExplorerBulitin(Explorer): - pass - -class ExplorerModule(Explorer): - pass - -class ExplorerSequence(Explorer): - pass - - -# Sequence - -class SequenceVisage(Visage): - propertyLabels = [('len', 'length')] - # XXX: add elements group - -class SequenceAttributeWidget(AttributeWidget): - def getTextForLabel(self): - # XXX: Differentiate between lists and tuples. - if self.explorer.len: - txt = "list of length %d" % (self.explorer.len,) - else: - txt = "[]" - return txt - - -# Mapping - -class ExplorerMapping(Explorer): - pass - -class MappingVisage(Visage): - propertyLabels = [('len', 'length')] - # XXX: add items group - -class MappingAttributeWidget(AttributeWidget): - def getTextForLabel(self): - if self.explorer.len: - txt = "dict with %d elements" % (self.explorer.len,) - else: - txt = "{}" - return txt - -class ExplorerImmutable(Explorer): - pass - - -# Immutable - -class ImmutableVisage(Visage): - def __init__(self, explorer, rootGroup, canvas): - Visage.__init__(self, explorer, rootGroup, canvas) - widget = explorer.newAttributeWidget(self) - self.container.add(widget) - self.container.show_all() - -class ImmutableAttributeWidget(AttributeWidget): - def getTextForLabel(self): - return repr(self.explorer.value) - - -#### misc. module definitions - -spelunkerClassTable = { - "ExplorerInstance": (InstanceVisage, InstanceAttributeWidget), - "ExplorerFunction": (None, FunctionAttributeWidget), - "ExplorerMethod": (None, MethodAttributeWidget), - "ExplorerImmutable": (ImmutableVisage, ImmutableAttributeWidget), - "ExplorerClass": (ClassVisage, ClassAttributeWidget), - "ExplorerSequence": (SequenceVisage, SequenceAttributeWidget), - "ExplorerMapping": (MappingVisage, MappingAttributeWidget), - } -GenericVisage = Visage -GenericAttributeWidget = AttributeWidget - -pb.setCopierForClassTree(sys.modules[__name__], - Explorer, 'twisted.manhole.explorer') diff --git a/tools/buildbot/pylibs/twisted/names/__init__.py b/tools/buildbot/pylibs/twisted/names/__init__.py deleted file mode 100644 index e6a29c1..0000000 --- a/tools/buildbot/pylibs/twisted/names/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -"""Resolving Internet Names""" - -from twisted.names._version import version -__version__ = version.short() diff --git a/tools/buildbot/pylibs/twisted/names/_version.py b/tools/buildbot/pylibs/twisted/names/_version.py deleted file mode 100644 index dafa545..0000000 --- a/tools/buildbot/pylibs/twisted/names/_version.py +++ /dev/null @@ -1,3 +0,0 @@ -# This is an auto-generated file. Do not edit it. -from twisted.python import versions -version = versions.Version('twisted.names', 8, 1, 0) diff --git a/tools/buildbot/pylibs/twisted/names/authority.py b/tools/buildbot/pylibs/twisted/names/authority.py deleted file mode 100644 index 991bdb6..0000000 --- a/tools/buildbot/pylibs/twisted/names/authority.py +++ /dev/null @@ -1,322 +0,0 @@ -# -*- test-case-name: twisted.names.test.test_names -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -from __future__ import nested_scopes - -import os -import time - -from twisted.names import dns -from twisted.internet import defer -from twisted.python import failure - -import common - -def getSerial(filename = '/tmp/twisted-names.serial'): - """Return a monotonically increasing (across program runs) integer. - - State is stored in the given file. If it does not exist, it is - created with rw-/---/--- permissions. - """ - serial = time.strftime('%Y%m%d') - - o = os.umask(0177) - try: - if not os.path.exists(filename): - f = file(filename, 'w') - f.write(serial + ' 0') - f.close() - finally: - os.umask(o) - - serialFile = file(filename, 'r') - lastSerial, ID = serialFile.readline().split() - ID = (lastSerial == serial) and (int(ID) + 1) or 0 - serialFile.close() - serialFile = file(filename, 'w') - serialFile.write('%s %d' % (serial, ID)) - serialFile.close() - serial = serial + ('%02d' % (ID,)) - return serial - - -#class LookupCacherMixin(object): -# _cache = None -# -# def _lookup(self, name, cls, type, timeout = 10): -# if not self._cache: -# self._cache = {} -# self._meth = super(LookupCacherMixin, self)._lookup -# -# if self._cache.has_key((name, cls, type)): -# return self._cache[(name, cls, type)] -# else: -# r = self._meth(name, cls, type, timeout) -# self._cache[(name, cls, type)] = r -# return r - - -class FileAuthority(common.ResolverBase): - """An Authority that is loaded from a file.""" - - soa = None - records = None - - def __init__(self, filename): - common.ResolverBase.__init__(self) - self.loadFile(filename) - self._cache = {} - - - def __setstate__(self, state): - self.__dict__ = state -# print 'setstate ', self.soa - - def _lookup(self, name, cls, type, timeout = None): - cnames = [] - results = [] - authority = [] - additional = [] - default_ttl = max(self.soa[1].minimum, self.soa[1].expire) - - domain_records = self.records.get(name.lower()) - - if domain_records: - for record in domain_records: - if record.ttl is not None: - ttl = record.ttl - else: - ttl = default_ttl - - if record.TYPE == type or type == dns.ALL_RECORDS: - results.append( - dns.RRHeader(name, record.TYPE, dns.IN, ttl, record, auth=True) - ) - elif record.TYPE == dns.NS and type != dns.ALL_RECORDS: - authority.append( - dns.RRHeader(name, record.TYPE, dns.IN, ttl, record, auth=True) - ) - if record.TYPE == dns.CNAME: - cnames.append( - dns.RRHeader(name, record.TYPE, dns.IN, ttl, record, auth=True) - ) - if not results: - results = cnames - - for record in results + authority: - section = {dns.NS: additional, dns.CNAME: results, dns.MX: additional}.get(record.type) - if section is not None: - n = str(record.payload.name) - for rec in self.records.get(n.lower(), ()): - if rec.TYPE == dns.A: - section.append( - dns.RRHeader(n, dns.A, dns.IN, rec.ttl or default_ttl, rec, auth=True) - ) - - return defer.succeed((results, authority, additional)) - else: - if name.lower().endswith(self.soa[0].lower()): - # We are the authority and we didn't find it. Goodbye. - return defer.fail(failure.Failure(dns.AuthoritativeDomainError(name))) - return defer.fail(failure.Failure(dns.DomainError(name))) - - - def lookupZone(self, name, timeout = 10): - if self.soa[0].lower() == name.lower(): - # Wee hee hee hooo yea - default_ttl = max(self.soa[1].minimum, self.soa[1].expire) - if self.soa[1].ttl is not None: - soa_ttl = self.soa[1].ttl - else: - soa_ttl = default_ttl - results = [dns.RRHeader(self.soa[0], dns.SOA, dns.IN, soa_ttl, self.soa[1], auth=True)] - for (k, r) in self.records.items(): - for rec in r: - if rec.ttl is not None: - ttl = rec.ttl - else: - ttl = default_ttl - if rec.TYPE != dns.SOA: - results.append(dns.RRHeader(k, rec.TYPE, dns.IN, ttl, rec, auth=True)) - results.append(results[0]) - return defer.succeed((results, (), ())) - return defer.fail(failure.Failure(dns.DomainError(name))) - - def _cbAllRecords(self, results): - ans, auth, add = [], [], [] - for res in results: - if res[0]: - ans.extend(res[1][0]) - auth.extend(res[1][1]) - add.extend(res[1][2]) - return ans, auth, add - - -class PySourceAuthority(FileAuthority): - """A FileAuthority that is built up from Python source code.""" - - def loadFile(self, filename): - g, l = self.setupConfigNamespace(), {} - execfile(filename, g, l) - if not l.has_key('zone'): - raise ValueError, "No zone defined in " + filename - - self.records = {} - for rr in l['zone']: - if isinstance(rr[1], dns.Record_SOA): - self.soa = rr - self.records.setdefault(rr[0].lower(), []).append(rr[1]) - - - def wrapRecord(self, type): - return lambda name, *arg, **kw: (name, type(*arg, **kw)) - - - def setupConfigNamespace(self): - r = {} - items = dns.__dict__.iterkeys() - for record in [x for x in items if x.startswith('Record_')]: - type = getattr(dns, record) - f = self.wrapRecord(type) - r[record[len('Record_'):]] = f - return r - - -class BindAuthority(FileAuthority): - """An Authority that loads BIND configuration files""" - - def loadFile(self, filename): - self.origin = os.path.basename(filename) + '.' # XXX - this might suck - lines = open(filename).readlines() - lines = self.stripComments(lines) - lines = self.collapseContinuations(lines) - self.parseLines(lines) - - - def stripComments(self, lines): - return [ - a.find(';') == -1 and a or a[:a.find(';')] for a in [ - b.strip() for b in lines - ] - ] - - - def collapseContinuations(self, lines): - L = [] - state = 0 - for line in lines: - if state == 0: - if line.find('(') == -1: - L.append(line) - else: - L.append(line[:line.find('(')]) - state = 1 - else: - if line.find(')') != -1: - L[-1] += ' ' + line[:line.find(')')] - state = 0 - else: - L[-1] += ' ' + line - lines = L - L = [] - for line in lines: - L.append(line.split()) - return filter(None, L) - - - def parseLines(self, lines): - TTL = 60 * 60 * 3 - ORIGIN = self.origin - - self.records = {} - - for (line, index) in zip(lines, range(len(lines))): - if line[0] == '$TTL': - TTL = dns.str2time(line[1]) - elif line[0] == '$ORIGIN': - ORIGIN = line[1] - elif line[0] == '$INCLUDE': # XXX - oh, fuck me - raise NotImplementedError('$INCLUDE directive not implemented') - elif line[0] == '$GENERATE': - raise NotImplementedError('$GENERATE directive not implemented') - else: - self.parseRecordLine(ORIGIN, TTL, line) - - - def addRecord(self, owner, ttl, type, domain, cls, rdata): - if not domain.endswith('.'): - domain = domain + '.' + owner - else: - domain = domain[:-1] - f = getattr(self, 'class_%s' % cls, None) - if f: - f(ttl, type, domain, rdata) - else: - raise NotImplementedError, "Record class %r not supported" % cls - - - def class_IN(self, ttl, type, domain, rdata): - record = getattr(dns, 'Record_%s' % type, None) - if record: - r = record(*rdata) - r.ttl = ttl - self.records.setdefault(domain.lower(), []).append(r) - - print 'Adding IN Record', domain, ttl, r - if type == 'SOA': - self.soa = (domain, r) - else: - raise NotImplementedError, "Record type %r not supported" % type - - - # - # This file ends here. Read no further. - # - def parseRecordLine(self, origin, ttl, line): - MARKERS = dns.QUERY_CLASSES.values() + dns.QUERY_TYPES.values() - cls = 'IN' - owner = origin - - if line[0] == '@': - line = line[1:] - owner = origin -# print 'default owner' - elif not line[0].isdigit() and line[0] not in MARKERS: - owner = line[0] - line = line[1:] -# print 'owner is ', owner - - if line[0].isdigit() or line[0] in MARKERS: - domain = owner - owner = origin -# print 'woops, owner is ', owner, ' domain is ', domain - else: - domain = line[0] - line = line[1:] -# print 'domain is ', domain - - if line[0] in dns.QUERY_CLASSES.values(): - cls = line[0] - line = line[1:] -# print 'cls is ', cls - if line[0].isdigit(): - ttl = int(line[0]) - line = line[1:] -# print 'ttl is ', ttl - elif line[0].isdigit(): - ttl = int(line[0]) - line = line[1:] -# print 'ttl is ', ttl - if line[0] in dns.QUERY_CLASSES.values(): - cls = line[0] - line = line[1:] -# print 'cls is ', cls - - type = line[0] -# print 'type is ', type - rdata = line[1:] -# print 'rdata is ', rdata - - self.addRecord(owner, ttl, type, domain, cls, rdata) diff --git a/tools/buildbot/pylibs/twisted/names/cache.py b/tools/buildbot/pylibs/twisted/names/cache.py deleted file mode 100644 index 3f16d27..0000000 --- a/tools/buildbot/pylibs/twisted/names/cache.py +++ /dev/null @@ -1,96 +0,0 @@ -# -*- test-case-name: twisted.names.test -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -import time - -from zope.interface import implements - -from twisted.names import dns -from twisted.python import failure, log -from twisted.internet import interfaces, defer - -import common - -class CacheResolver(common.ResolverBase): - """A resolver that serves records from a local, memory cache.""" - - implements(interfaces.IResolver) - - cache = None - - def __init__(self, cache = None, verbose = 0): - common.ResolverBase.__init__(self) - - if cache is None: - cache = {} - self.cache = cache - self.verbose = verbose - self.cancel = {} - - - def __setstate__(self, state): - self.__dict__ = state - - now = time.time() - for (k, (when, (ans, add, ns))) in self.cache.items(): - diff = now - when - for rec in ans + add + ns: - if rec.ttl < diff: - del self.cache[k] - break - - - def __getstate__(self): - for c in self.cancel.values(): - c.cancel() - self.cancel.clear() - return self.__dict__ - - - def _lookup(self, name, cls, type, timeout): - now = time.time() - q = dns.Query(name, type, cls) - try: - when, (ans, auth, add) = self.cache[q] - except KeyError: - if self.verbose > 1: - log.msg('Cache miss for ' + repr(name)) - return defer.fail(failure.Failure(dns.DomainError(name))) - else: - if self.verbose: - log.msg('Cache hit for ' + repr(name)) - diff = now - when - return defer.succeed(( - [dns.RRHeader(str(r.name), r.type, r.cls, r.ttl - diff, r.payload) for r in ans], - [dns.RRHeader(str(r.name), r.type, r.cls, r.ttl - diff, r.payload) for r in auth], - [dns.RRHeader(str(r.name), r.type, r.cls, r.ttl - diff, r.payload) for r in add] - )) - - - def lookupAllRecords(self, name, timeout = None): - return defer.fail(failure.Failure(dns.DomainError(name))) - - - def cacheResult(self, query, payload): - if self.verbose > 1: - log.msg('Adding %r to cache' % query) - - self.cache[query] = (time.time(), payload) - - if self.cancel.has_key(query): - self.cancel[query].cancel() - - s = list(payload[0]) + list(payload[1]) + list(payload[2]) - m = s[0].ttl - for r in s: - m = min(m, r.ttl) - - from twisted.internet import reactor - self.cancel[query] = reactor.callLater(m, self.clearEntry, query) - - - def clearEntry(self, query): - del self.cache[query] - del self.cancel[query] diff --git a/tools/buildbot/pylibs/twisted/names/client.py b/tools/buildbot/pylibs/twisted/names/client.py deleted file mode 100644 index 45e717b..0000000 --- a/tools/buildbot/pylibs/twisted/names/client.py +++ /dev/null @@ -1,814 +0,0 @@ -# -*- test-case-name: twisted.names.test.test_names -*- -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Asynchronous client DNS - -The functions exposed in this module can be used for asynchronous name -resolution and dns queries. - -If you need to create a resolver with specific requirements, such as needing to -do queries against a particular host, the L{createResolver} function will -return an C{IResolver}. - -Future plans: Proper nameserver acquisition on Windows/MacOS, -better caching, respect timeouts - -@author: U{Jp Calderone} -""" - -from __future__ import nested_scopes - -import os -import errno - -from zope.interface import implements - -# Twisted imports -from twisted.python.runtime import platform -from twisted.internet import error, defer, protocol, interfaces -from twisted.python import log, failure -from twisted.names import dns, common -from twisted.names.error import DNSFormatError, DNSServerError, DNSNameError -from twisted.names.error import DNSNotImplementedError, DNSQueryRefusedError -from twisted.names.error import DNSUnknownError - - -class Resolver(common.ResolverBase): - implements(interfaces.IResolver) - - index = 0 - timeout = None - - factory = None - servers = None - dynServers = () - pending = None - protocol = None - connections = None - - resolv = None - _lastResolvTime = None - _resolvReadInterval = 60 - - _errormap = { - dns.EFORMAT: DNSFormatError, - dns.ESERVER: DNSServerError, - dns.ENAME: DNSNameError, - dns.ENOTIMP: DNSNotImplementedError, - dns.EREFUSED: DNSQueryRefusedError} - - def __init__(self, resolv = None, servers = None, timeout = (1, 3, 11, 45)): - """ - Construct a resolver which will query domain name servers listed in - the C{resolv.conf(5)}-format file given by C{resolv} as well as - those in the given C{servers} list. Servers are queried in a - round-robin fashion. If given, C{resolv} is periodically checked - for modification and re-parsed if it is noticed to have changed. - - @type servers: C{list} of C{(str, int)} or C{None} - @param servers: If not C{None}, interpreted as a list of addresses of - domain name servers to attempt to use for this lookup. Addresses - should be in dotted-quad form. If specified, overrides C{resolv}. - - @type resolv: C{str} - @param resolv: Filename to read and parse as a resolver(5) - configuration file. - - @type timeout: Sequence of C{int} - @param timeout: Default number of seconds after which to reissue the query. - When the last timeout expires, the query is considered failed. - - @raise ValueError: Raised if no nameserver addresses can be found. - """ - common.ResolverBase.__init__(self) - - self.timeout = timeout - - if servers is None: - self.servers = [] - else: - self.servers = servers - - self.resolv = resolv - - if not len(self.servers) and not resolv: - raise ValueError, "No nameservers specified" - - self.factory = DNSClientFactory(self, timeout) - self.factory.noisy = 0 # Be quiet by default - - self.protocol = dns.DNSDatagramProtocol(self) - self.protocol.noisy = 0 # You too - - self.connections = [] - self.pending = [] - - self.maybeParseConfig() - - - def __getstate__(self): - d = self.__dict__.copy() - d['connections'] = [] - d['_parseCall'] = None - return d - - - def __setstate__(self, state): - self.__dict__.update(state) - self.maybeParseConfig() - - - def maybeParseConfig(self): - if self.resolv is None: - # Don't try to parse it, don't set up a call loop - return - - try: - resolvConf = file(self.resolv) - except IOError, e: - if e.errno == errno.ENOENT: - # Missing resolv.conf is treated the same as an empty resolv.conf - self.parseConfig(()) - else: - raise - else: - mtime = os.fstat(resolvConf.fileno()).st_mtime - if mtime != self._lastResolvTime: - log.msg('%s changed, reparsing' % (self.resolv,)) - self._lastResolvTime = mtime - self.parseConfig(resolvConf) - - # Check again in a little while - from twisted.internet import reactor - self._parseCall = reactor.callLater(self._resolvReadInterval, self.maybeParseConfig) - - - def parseConfig(self, resolvConf): - servers = [] - for L in resolvConf: - L = L.strip() - if L.startswith('nameserver'): - resolver = (L.split()[1], dns.PORT) - servers.append(resolver) - log.msg("Resolver added %r to server list" % (resolver,)) - elif L.startswith('domain'): - try: - self.domain = L.split()[1] - except IndexError: - self.domain = '' - self.search = None - elif L.startswith('search'): - try: - self.search = L.split()[1:] - except IndexError: - self.search = '' - self.domain = None - if not servers: - servers.append(('127.0.0.1', dns.PORT)) - self.dynServers = servers - - - def pickServer(self): - """ - Return the address of a nameserver. - - TODO: Weight servers for response time so faster ones can be - preferred. - """ - if not self.servers and not self.dynServers: - return None - serverL = len(self.servers) - dynL = len(self.dynServers) - - self.index += 1 - self.index %= (serverL + dynL) - if self.index < serverL: - return self.servers[self.index] - else: - return self.dynServers[self.index - serverL] - - def connectionMade(self, protocol): - self.connections.append(protocol) - for (d, q, t) in self.pending: - self.queryTCP(q, t).chainDeferred(d) - del self.pending[:] - - - def messageReceived(self, message, protocol, address = None): - log.msg("Unexpected message (%d) received from %r" % (message.id, address)) - - - def queryUDP(self, queries, timeout = None): - """ - Make a number of DNS queries via UDP. - - @type queries: A C{list} of C{dns.Query} instances - @param queries: The queries to make. - - @type timeout: Sequence of C{int} - @param timeout: Number of seconds after which to reissue the query. - When the last timeout expires, the query is considered failed. - - @rtype: C{Deferred} - @raise C{twisted.internet.defer.TimeoutError}: When the query times - out. - """ - if timeout is None: - timeout = self.timeout - - addresses = self.servers + list(self.dynServers) - if not addresses: - return defer.fail(IOError("No domain name servers available")) - - # Make sure we go through servers in the list in the order they were - # specified. - addresses.reverse() - - used = addresses.pop() - return self.protocol.query(used, queries, timeout[0] - ).addErrback(self._reissue, addresses, [used], queries, timeout - ) - - - def _reissue(self, reason, addressesLeft, addressesUsed, query, timeout): - reason.trap(dns.DNSQueryTimeoutError) - - # If there are no servers left to be tried, adjust the timeout - # to the next longest timeout period and move all the - # "used" addresses back to the list of addresses to try. - if not addressesLeft: - addressesLeft = addressesUsed - addressesLeft.reverse() - addressesUsed = [] - timeout = timeout[1:] - - # If all timeout values have been used, or the protocol has no - # transport, this query has failed. Tell the protocol we're - # giving up on it and return a terminal timeout failure to our - # caller. - if not timeout or self.protocol.transport is None: - self.protocol.removeResend(reason.value.id) - return failure.Failure(defer.TimeoutError(query)) - - # Get an address to try. Take it out of the list of addresses - # to try and put it ino the list of already tried addresses. - address = addressesLeft.pop() - addressesUsed.append(address) - - # Issue a query to a server. Use the current timeout. Add this - # function as a timeout errback in case another retry is required. - d = self.protocol.query(address, query, timeout[0], reason.value.id) - d.addErrback(self._reissue, addressesLeft, addressesUsed, query, timeout) - return d - - - def queryTCP(self, queries, timeout = 10): - """ - Make a number of DNS queries via TCP. - - @type queries: Any non-zero number of C{dns.Query} instances - @param queries: The queries to make. - - @type timeout: C{int} - @param timeout: The number of seconds after which to fail. - - @rtype: C{Deferred} - """ - if not len(self.connections): - address = self.pickServer() - if address is None: - return defer.fail(IOError("No domain name servers available")) - host, port = address - from twisted.internet import reactor - reactor.connectTCP(host, port, self.factory) - self.pending.append((defer.Deferred(), queries, timeout)) - return self.pending[-1][0] - else: - return self.connections[0].query(queries, timeout) - - - def filterAnswers(self, message): - """ - Extract results from the given message. - - If the message was truncated, re-attempt the query over TCP and return - a Deferred which will fire with the results of that query. - - If the message's result code is not L{dns.OK}, return a Failure - indicating the type of error which occurred. - - Otherwise, return a three-tuple of lists containing the results from - the answers section, the authority section, and the additional section. - """ - if message.trunc: - return self.queryTCP(message.queries).addCallback(self.filterAnswers) - if message.rCode != dns.OK: - return failure.Failure(self._errormap.get(message.rCode, DNSUnknownError)(message)) - return (message.answers, message.authority, message.additional) - - - def _lookup(self, name, cls, type, timeout): - return self.queryUDP( - [dns.Query(name, type, cls)], timeout - ).addCallback(self.filterAnswers) - - - # This one doesn't ever belong on UDP - def lookupZone(self, name, timeout = 10): - """ - Perform an AXFR request. This is quite different from usual - DNS requests. See http://cr.yp.to/djbdns/axfr-notes.html for - more information. - """ - address = self.pickServer() - if address is None: - return defer.fail(IOError('No domain name servers available')) - host, port = address - d = defer.Deferred() - controller = AXFRController(name, d) - factory = DNSClientFactory(controller, timeout) - factory.noisy = False #stfu - - from twisted.internet import reactor - connector = reactor.connectTCP(host, port, factory) - controller.timeoutCall = reactor.callLater(timeout or 10, - self._timeoutZone, - d, controller, - connector, - timeout or 10) - return d.addCallback(self._cbLookupZone, connector) - - def _timeoutZone(self, d, controller, connector, seconds): - connector.disconnect() - controller.timeoutCall = None - controller.deferred = None - d.errback(error.TimeoutError("Zone lookup timed out after %d seconds" % (seconds,))) - - def _cbLookupZone(self, result, connector): - connector.disconnect() - return (result, [], []) - - -class AXFRController: - timeoutCall = None - - def __init__(self, name, deferred): - self.name = name - self.deferred = deferred - self.soa = None - self.records = [] - - def connectionMade(self, protocol): - # dig saids recursion-desired to 0, so I will too - message = dns.Message(protocol.pickID(), recDes=0) - message.queries = [dns.Query(self.name, dns.AXFR, dns.IN)] - protocol.writeMessage(message) - - def messageReceived(self, message, protocol): - # Caveat: We have to handle two cases: All records are in 1 - # message, or all records are in N messages. - - # According to http://cr.yp.to/djbdns/axfr-notes.html, - # 'authority' and 'additional' are always empty, and only - # 'answers' is present. - self.records.extend(message.answers) - if not self.records: - return - if not self.soa: - if self.records[0].type == dns.SOA: - #print "first SOA!" - self.soa = self.records[0] - if len(self.records) > 1 and self.records[-1].type == dns.SOA: - #print "It's the second SOA! We're done." - if self.timeoutCall is not None: - self.timeoutCall.cancel() - self.timeoutCall = None - if self.deferred is not None: - self.deferred.callback(self.records) - self.deferred = None - - - -from twisted.internet.base import ThreadedResolver as _ThreadedResolverImpl - -class ThreadedResolver(_ThreadedResolverImpl): - def __init__(self, reactor=None): - if reactor is None: - from twisted.internet import reactor - _ThreadedResolverImpl.__init__(self, reactor) - # warnings.warn("twisted.names.client.ThreadedResolver is deprecated, use XXX instead.") - -class DNSClientFactory(protocol.ClientFactory): - def __init__(self, controller, timeout = 10): - self.controller = controller - self.timeout = timeout - - - def clientConnectionLost(self, connector, reason): - pass - - - def buildProtocol(self, addr): - p = dns.DNSProtocol(self.controller) - p.factory = self - return p - - - -def createResolver(servers=None, resolvconf=None, hosts=None): - """ - Create and return a Resolver. - - @type servers: C{list} of C{(str, int)} or C{None} - @param servers: If not C{None}, interpreted as a list of addresses of - domain name servers to attempt to use. Addresses should be in dotted-quad - form. - - @type resolvconf: C{str} or C{None} - @param resolvconf: If not C{None}, on posix systems will be interpreted as - an alternate resolv.conf to use. Will do nothing on windows systems. If - C{None}, /etc/resolv.conf will be used. - - @type hosts: C{str} or C{None} - @param hosts: If not C{None}, an alternate hosts file to use. If C{None} - on posix systems, /etc/hosts will be used. On windows, C:\windows\hosts - will be used. - - @rtype: C{IResolver} - """ - from twisted.names import resolve, cache, root, hosts as hostsModule - if platform.getType() == 'posix': - if resolvconf is None: - resolvconf = '/etc/resolv.conf' - if hosts is None: - hosts = '/etc/hosts' - theResolver = Resolver(resolvconf, servers) - hostResolver = hostsModule.Resolver(hosts) - else: - if hosts is None: - hosts = r'c:\windows\hosts' - from twisted.internet import reactor - bootstrap = _ThreadedResolverImpl(reactor) - hostResolver = hostsModule.Resolver(hosts) - theResolver = root.bootstrap(bootstrap) - - L = [hostResolver, cache.CacheResolver(), theResolver] - return resolve.ResolverChain(L) - -theResolver = None -def getResolver(): - """ - Get a Resolver instance. - - Create twisted.names.client.theResolver if it is C{None}, and then return - that value. - - @rtype: C{IResolver} - """ - global theResolver - if theResolver is None: - try: - theResolver = createResolver() - except ValueError: - theResolver = createResolver(servers=[('127.0.0.1', 53)]) - return theResolver - -def getHostByName(name, timeout=None, effort=10): - """ - Resolve a name to a valid ipv4 or ipv6 address. - - Will errback with C{DNSQueryTimeoutError} on a timeout, C{DomainError} or - C{AuthoritativeDomainError} (or subclasses) on other errors. - - @type name: C{str} - @param name: DNS name to resolve. - - @type timeout: Sequence of C{int} - @param timeout: Number of seconds after which to reissue the query. - When the last timeout expires, the query is considered failed. - - @type effort: C{int} - @param effort: How many times CNAME and NS records to follow while - resolving this name. - - @rtype: C{Deferred} - """ - return getResolver().getHostByName(name, timeout, effort) - -def lookupAddress(name, timeout=None): - """ - Perform an A record lookup. - - @type name: C{str} - @param name: DNS name to resolve. - - @type timeout: Sequence of C{int} - @param timeout: Number of seconds after which to reissue the query. - When the last timeout expires, the query is considered failed. - - @rtype: C{Deferred} - """ - return getResolver().lookupAddress(name, timeout) - -def lookupIPV6Address(name, timeout=None): - """ - Perform an AAAA record lookup. - - @type name: C{str} - @param name: DNS name to resolve. - - @type timeout: Sequence of C{int} - @param timeout: Number of seconds after which to reissue the query. - When the last timeout expires, the query is considered failed. - - @rtype: C{Deferred} - """ - return getResolver().lookupIPV6Address(name, timeout) - -def lookupAddress6(name, timeout=None): - """ - Perform an A6 record lookup. - - @type name: C{str} - @param name: DNS name to resolve. - - @type timeout: Sequence of C{int} - @param timeout: Number of seconds after which to reissue the query. - When the last timeout expires, the query is considered failed. - - @rtype: C{Deferred} - """ - return getResolver().lookupAddress6(name, timeout) - -def lookupMailExchange(name, timeout=None): - """ - Perform an MX record lookup. - - @type name: C{str} - @param name: DNS name to resolve. - - @type timeout: Sequence of C{int} - @param timeout: Number of seconds after which to reissue the query. - When the last timeout expires, the query is considered failed. - - @rtype: C{Deferred} - """ - return getResolver().lookupMailExchange(name, timeout) - -def lookupNameservers(name, timeout=None): - """ - Perform an NS record lookup. - - @type name: C{str} - @param name: DNS name to resolve. - - @type timeout: Sequence of C{int} - @param timeout: Number of seconds after which to reissue the query. - When the last timeout expires, the query is considered failed. - - @rtype: C{Deferred} - """ - return getResolver().lookupNameservers(name, timeout) - -def lookupCanonicalName(name, timeout=None): - """ - Perform a CNAME record lookup. - - @type name: C{str} - @param name: DNS name to resolve. - - @type timeout: Sequence of C{int} - @param timeout: Number of seconds after which to reissue the query. - When the last timeout expires, the query is considered failed. - - @rtype: C{Deferred} - """ - return getResolver().lookupCanonicalName(name, timeout) - -def lookupMailBox(name, timeout=None): - """ - Perform an MB record lookup. - - @type name: C{str} - @param name: DNS name to resolve. - - @type timeout: Sequence of C{int} - @param timeout: Number of seconds after which to reissue the query. - When the last timeout expires, the query is considered failed. - - @rtype: C{Deferred} - """ - return getResolver().lookupMailBox(name, timeout) - -def lookupMailGroup(name, timeout=None): - """ - Perform an MG record lookup. - - @type name: C{str} - @param name: DNS name to resolve. - - @type timeout: Sequence of C{int} - @param timeout: Number of seconds after which to reissue the query. - When the last timeout expires, the query is considered failed. - - @rtype: C{Deferred} - """ - return getResolver().lookupMailGroup(name, timeout) - -def lookupMailRename(name, timeout=None): - """ - Perform an MR record lookup. - - @type name: C{str} - @param name: DNS name to resolve. - - @type timeout: Sequence of C{int} - @param timeout: Number of seconds after which to reissue the query. - When the last timeout expires, the query is considered failed. - - @rtype: C{Deferred} - """ - return getResolver().lookupMailRename(name, timeout) - -def lookupPointer(name, timeout=None): - """ - Perform a PTR record lookup. - - @type name: C{str} - @param name: DNS name to resolve. - - @type timeout: Sequence of C{int} - @param timeout: Number of seconds after which to reissue the query. - When the last timeout expires, the query is considered failed. - - @rtype: C{Deferred} - """ - return getResolver().lookupPointer(name, timeout) - -def lookupAuthority(name, timeout=None): - """ - Perform an SOA record lookup. - - @type name: C{str} - @param name: DNS name to resolve. - - @type timeout: Sequence of C{int} - @param timeout: Number of seconds after which to reissue the query. - When the last timeout expires, the query is considered failed. - - @rtype: C{Deferred} - """ - return getResolver().lookupAuthority(name, timeout) - -def lookupNull(name, timeout=None): - """ - Perform a NULL record lookup. - - @type name: C{str} - @param name: DNS name to resolve. - - @type timeout: Sequence of C{int} - @param timeout: Number of seconds after which to reissue the query. - When the last timeout expires, the query is considered failed. - - @rtype: C{Deferred} - """ - return getResolver().lookupNull(name, timeout) - -def lookupWellKnownServices(name, timeout=None): - """ - Perform a WKS record lookup. - - @type name: C{str} - @param name: DNS name to resolve. - - @type timeout: Sequence of C{int} - @param timeout: Number of seconds after which to reissue the query. - When the last timeout expires, the query is considered failed. - - @rtype: C{Deferred} - """ - return getResolver().lookupWellKnownServices(name, timeout) - -def lookupService(name, timeout=None): - """ - Perform an SRV record lookup. - - @type name: C{str} - @param name: DNS name to resolve. - - @type timeout: Sequence of C{int} - @param timeout: Number of seconds after which to reissue the query. - When the last timeout expires, the query is considered failed. - - @rtype: C{Deferred} - """ - return getResolver().lookupService(name, timeout) - -def lookupHostInfo(name, timeout=None): - """ - Perform a HINFO record lookup. - - @type name: C{str} - @param name: DNS name to resolve. - - @type timeout: Sequence of C{int} - @param timeout: Number of seconds after which to reissue the query. - When the last timeout expires, the query is considered failed. - - @rtype: C{Deferred} - """ - return getResolver().lookupHostInfo(name, timeout) - -def lookupMailboxInfo(name, timeout=None): - """ - Perform an MINFO record lookup. - - @type name: C{str} - @param name: DNS name to resolve. - - @type timeout: Sequence of C{int} - @param timeout: Number of seconds after which to reissue the query. - When the last timeout expires, the query is considered failed. - - @rtype: C{Deferred} - """ - return getResolver().lookupMailboxInfo(name, timeout) - -def lookupText(name, timeout=None): - """ - Perform a TXT record lookup. - - @type name: C{str} - @param name: DNS name to resolve. - - @type timeout: Sequence of C{int} - @param timeout: Number of seconds after which to reissue the query. - When the last timeout expires, the query is considered failed. - - @rtype: C{Deferred} - """ - return getResolver().lookupText(name, timeout) - -def lookupResponsibility(name, timeout=None): - """ - Perform an RP record lookup. - - @type name: C{str} - @param name: DNS name to resolve. - - @type timeout: Sequence of C{int} - @param timeout: Number of seconds after which to reissue the query. - When the last timeout expires, the query is considered failed. - - @rtype: C{Deferred} - """ - return getResolver().lookupResponsibility(name, timeout) - -def lookupAFSDatabase(name, timeout=None): - """ - Perform an AFSDB record lookup. - - @type name: C{str} - @param name: DNS name to resolve. - - @type timeout: Sequence of C{int} - @param timeout: Number of seconds after which to reissue the query. - When the last timeout expires, the query is considered failed. - - @rtype: C{Deferred} - """ - return getResolver().lookupAFSDatabase(name, timeout) - -def lookupZone(name, timeout=None): - """ - Perform an AXFR record lookup. - - @type name: C{str} - @param name: DNS name to resolve. - - @type timeout: C{int} - @param timeout: When this timeout expires, the query is considered failed. - - @rtype: C{Deferred} - """ - # XXX: timeout here is not a list of ints, it is a single int. - return getResolver().lookupZone(name, timeout) - -def lookupAllRecords(name, timeout=None): - """ - ALL_RECORD lookup. - - @type name: C{str} - @param name: DNS name to resolve. - - @type timeout: Sequence of C{int} - @param timeout: Number of seconds after which to reissue the query. - When the last timeout expires, the query is considered failed. - - @rtype: C{Deferred} - """ - return getResolver().lookupAllRecords(name, timeout) diff --git a/tools/buildbot/pylibs/twisted/names/common.py b/tools/buildbot/pylibs/twisted/names/common.py deleted file mode 100644 index b93769d..0000000 --- a/tools/buildbot/pylibs/twisted/names/common.py +++ /dev/null @@ -1,224 +0,0 @@ -# -*- test-case-name: twisted.names.test -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -import socket - -from twisted.names import dns -from twisted.internet import defer, error -from twisted.python import failure - -EMPTY_RESULT = (), (), () - -class ResolverBase: - typeToMethod = None - - def __init__(self): - self.typeToMethod = {} - for (k, v) in typeToMethod.items(): - self.typeToMethod[k] = getattr(self, v) - - def query(self, query, timeout = None): - try: - return self.typeToMethod[query.type](str(query.name), timeout) - except KeyError, e: - return defer.fail(failure.Failure(NotImplementedError(str(self.__class__) + " " + str(query.type)))) - - def _lookup(self, name, cls, type, timeout): - return defer.fail(NotImplementedError("ResolverBase._lookup")) - - def lookupAddress(self, name, timeout = None): - """ - @see: twisted.names.client.lookupAddress - """ - return self._lookup(name, dns.IN, dns.A, timeout) - - def lookupIPV6Address(self, name, timeout = None): - """ - @see: twisted.names.client.lookupIPV6Address - """ - return self._lookup(name, dns.IN, dns.AAAA, timeout) - - def lookupAddress6(self, name, timeout = None): - """ - @see: twisted.names.client.lookupAddress6 - """ - return self._lookup(name, dns.IN, dns.A6, timeout) - - def lookupMailExchange(self, name, timeout = None): - """ - @see: twisted.names.client.lookupMailExchange - """ - return self._lookup(name, dns.IN, dns.MX, timeout) - - def lookupNameservers(self, name, timeout = None): - """ - @see: twisted.names.client.lookupNameservers - """ - return self._lookup(name, dns.IN, dns.NS, timeout) - - def lookupCanonicalName(self, name, timeout = None): - """ - @see: twisted.names.client.lookupCanonicalName - """ - return self._lookup(name, dns.IN, dns.CNAME, timeout) - - def lookupMailBox(self, name, timeout = None): - """ - @see: twisted.names.client.lookupMailBox - """ - return self._lookup(name, dns.IN, dns.MB, timeout) - - def lookupMailGroup(self, name, timeout = None): - """ - @see: twisted.names.client.lookupMailGroup - """ - return self._lookup(name, dns.IN, dns.MG, timeout) - - def lookupMailRename(self, name, timeout = None): - """ - @see: twisted.names.client.lookupMailRename - """ - return self._lookup(name, dns.IN, dns.MR, timeout) - - def lookupPointer(self, name, timeout = None): - """ - @see: twisted.names.client.lookupPointer - """ - return self._lookup(name, dns.IN, dns.PTR, timeout) - - def lookupAuthority(self, name, timeout = None): - """ - @see: twisted.names.client.lookupAuthority - """ - return self._lookup(name, dns.IN, dns.SOA, timeout) - - def lookupNull(self, name, timeout = None): - """ - @see: twisted.names.client.lookupNull - """ - return self._lookup(name, dns.IN, dns.NULL, timeout) - - def lookupWellKnownServices(self, name, timeout = None): - """ - @see: twisted.names.client.lookupWellKnownServices - """ - return self._lookup(name, dns.IN, dns.WKS, timeout) - - def lookupService(self, name, timeout = None): - """ - @see: twisted.names.client.lookupService - """ - return self._lookup(name, dns.IN, dns.SRV, timeout) - - def lookupHostInfo(self, name, timeout = None): - """ - @see: twisted.names.client.lookupHostInfo - """ - return self._lookup(name, dns.IN, dns.HINFO, timeout) - - def lookupMailboxInfo(self, name, timeout = None): - """ - @see: twisted.names.client.lookupMailboxInfo - """ - return self._lookup(name, dns.IN, dns.MINFO, timeout) - - def lookupText(self, name, timeout = None): - """ - @see: twisted.names.client.lookupText - """ - return self._lookup(name, dns.IN, dns.TXT, timeout) - - def lookupResponsibility(self, name, timeout = None): - """ - @see: twisted.names.client.lookupResponsibility - """ - return self._lookup(name, dns.IN, dns.RP, timeout) - - def lookupAFSDatabase(self, name, timeout = None): - """ - @see: twisted.names.client.lookupAFSDatabase - """ - return self._lookup(name, dns.IN, dns.AFSDB, timeout) - - def lookupZone(self, name, timeout = None): - """ - @see: twisted.names.client.lookupZone - """ - return self._lookup(name, dns.IN, dns.AXFR, timeout) - - def lookupAllRecords(self, name, timeout = None): - """ - @see: twisted.names.client.lookupAllRecords - """ - return self._lookup(name, dns.IN, dns.ALL_RECORDS, timeout) - - def getHostByName(self, name, timeout = None, effort = 10): - """ - @see: twisted.names.client.getHostByName - """ - # XXX - respect timeout - return self.lookupAllRecords(name, timeout - ).addCallback(self._cbRecords, name, effort - ) - - def _cbRecords(self, (ans, auth, add), name, effort): - result = extractRecord(self, dns.Name(name), ans + auth + add, effort) - if not result: - raise error.DNSLookupError(name) - return result - -def extractRecord(resolver, name, answers, level = 10): - if not level: - return None - if hasattr(socket, 'inet_ntop'): - for r in answers: - if r.name == name and r.type == dns.A6: - return socket.inet_ntop(socket.AF_INET6, r.payload.address) - for r in answers: - if r.name == name and r.type == dns.AAAA: - return socket.inet_ntop(socket.AF_INET6, r.payload.address) - for r in answers: - if r.name == name and r.type == dns.A: - return socket.inet_ntop(socket.AF_INET, r.payload.address) - for r in answers: - if r.name == name and r.type == dns.CNAME: - result = extractRecord(resolver, r.payload.name, answers, level - 1) - if not result: - return resolver.getHostByName(str(r.payload.name), effort=level-1) - return result - # No answers, but maybe there's a hint at who we should be asking about this - for r in answers: - if r.type == dns.NS: - from twisted.names import client - r = client.Resolver(servers=[(str(r.payload.name), dns.PORT)]) - return r.lookupAddress(str(name) - ).addCallback(lambda (ans, auth, add): extractRecord(r, name, ans + auth + add, level - 1) - ).addBoth(lambda passthrough: (r.protocol.transport.stopListening(), passthrough)[1]) - -typeToMethod = { - dns.A: 'lookupAddress', - dns.AAAA: 'lookupIPV6Address', - dns.A6: 'lookupAddress6', - dns.NS: 'lookupNameservers', - dns.CNAME: 'lookupCanonicalName', - dns.SOA: 'lookupAuthority', - dns.MB: 'lookupMailBox', - dns.MG: 'lookupMailGroup', - dns.MR: 'lookupMailRename', - dns.NULL: 'lookupNull', - dns.WKS: 'lookupWellKnownServices', - dns.PTR: 'lookupPointer', - dns.HINFO: 'lookupHostInfo', - dns.MINFO: 'lookupMailboxInfo', - dns.MX: 'lookupMailExchange', - dns.TXT: 'lookupText', - - dns.RP: 'lookupResponsibility', - dns.AFSDB: 'lookupAFSDatabase', - dns.SRV: 'lookupService', - - dns.AXFR: 'lookupZone', - dns.ALL_RECORDS: 'lookupAllRecords', -} diff --git a/tools/buildbot/pylibs/twisted/names/dns.py b/tools/buildbot/pylibs/twisted/names/dns.py deleted file mode 100644 index eaebb48..0000000 --- a/tools/buildbot/pylibs/twisted/names/dns.py +++ /dev/null @@ -1,1621 +0,0 @@ -# -*- test-case-name: twisted.names.test.test_dns -*- -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -DNS protocol implementation. - -Future Plans: - - Get rid of some toplevels, maybe. - - Put in a better lookupRecordType implementation. - -@author: U{Moshe Zadka}, - U{Jp Calderone} -""" - -# System imports -import warnings - -import struct, random, types, socket - -try: - import cStringIO as StringIO -except ImportError: - import StringIO - -AF_INET6 = socket.AF_INET6 - -from zope.interface import implements, Interface - - -# Twisted imports -from twisted.internet import protocol, defer -from twisted.internet.error import CannotListenError -from twisted.python import log, failure -from twisted.python import util as tputil -from twisted.python import randbytes - - -def randomSource(): - """ - Wrapper around L{randbytes.secureRandom} to return 2 random chars. - """ - return struct.unpack('H', randbytes.secureRandom(2, fallback=True))[0] - - -PORT = 53 - -(A, NS, MD, MF, CNAME, SOA, MB, MG, MR, NULL, WKS, PTR, HINFO, MINFO, MX, TXT, - RP, AFSDB) = range(1, 19) -AAAA = 28 -SRV = 33 -A6 = 38 -DNAME = 39 - -QUERY_TYPES = { - A: 'A', - NS: 'NS', - MD: 'MD', - MF: 'MF', - CNAME: 'CNAME', - SOA: 'SOA', - MB: 'MB', - MG: 'MG', - MR: 'MR', - NULL: 'NULL', - WKS: 'WKS', - PTR: 'PTR', - HINFO: 'HINFO', - MINFO: 'MINFO', - MX: 'MX', - TXT: 'TXT', - RP: 'RP', - AFSDB: 'AFSDB', - - # 19 through 27? Eh, I'll get to 'em. - - AAAA: 'AAAA', - SRV: 'SRV', - - A6: 'A6', - DNAME: 'DNAME' -} - -IXFR, AXFR, MAILB, MAILA, ALL_RECORDS = range(251, 256) - -# "Extended" queries (Hey, half of these are deprecated, good job) -EXT_QUERIES = { - IXFR: 'IXFR', - AXFR: 'AXFR', - MAILB: 'MAILB', - MAILA: 'MAILA', - ALL_RECORDS: 'ALL_RECORDS' -} - -REV_TYPES = dict([ - (v, k) for (k, v) in QUERY_TYPES.items() + EXT_QUERIES.items() -]) - -IN, CS, CH, HS = range(1, 5) -ANY = 255 - -QUERY_CLASSES = { - IN: 'IN', - CS: 'CS', - CH: 'CH', - HS: 'HS', - ANY: 'ANY' -} -REV_CLASSES = dict([ - (v, k) for (k, v) in QUERY_CLASSES.items() -]) - - -# Opcodes -OP_QUERY, OP_INVERSE, OP_STATUS = range(3) -OP_NOTIFY = 4 # RFC 1996 -OP_UPDATE = 5 # RFC 2136 - - -# Response Codes -OK, EFORMAT, ESERVER, ENAME, ENOTIMP, EREFUSED = range(6) - -class IRecord(Interface): - """ - An single entry in a zone of authority. - - @cvar TYPE: An indicator of what kind of record this is. - """ - - -# Backwards compatibility aliases - these should be deprecated or something I -# suppose. -exarkun -from twisted.names.error import DomainError, AuthoritativeDomainError -from twisted.names.error import DNSQueryTimeoutError - - -def str2time(s): - suffixes = ( - ('S', 1), ('M', 60), ('H', 60 * 60), ('D', 60 * 60 * 24), - ('W', 60 * 60 * 24 * 7), ('Y', 60 * 60 * 24 * 365) - ) - if isinstance(s, types.StringType): - s = s.upper().strip() - for (suff, mult) in suffixes: - if s.endswith(suff): - return int(float(s[:-1]) * mult) - try: - s = int(s) - except ValueError: - raise ValueError, "Invalid time interval specifier: " + s - return s - - -def readPrecisely(file, l): - buff = file.read(l) - if len(buff) < l: - raise EOFError - return buff - - -class IEncodable(Interface): - """ - Interface for something which can be encoded to and decoded - from a file object. - """ - def encode(strio, compDict = None): - """ - Write a representation of this object to the given - file object. - - @type strio: File-like object - @param strio: The stream to which to write bytes - - @type compDict: C{dict} or C{None} - @param compDict: A dictionary of backreference addresses that have - have already been written to this stream and that may be used for - compression. - """ - - def decode(strio, length = None): - """ - Reconstruct an object from data read from the given - file object. - - @type strio: File-like object - @param strio: The stream from which bytes may be read - - @type length: C{int} or C{None} - @param length: The number of bytes in this RDATA field. Most - implementations can ignore this value. Only in the case of - records similar to TXT where the total length is in no way - encoded in the data is it necessary. - """ - - -class Name: - implements(IEncodable) - - def __init__(self, name=''): - assert isinstance(name, types.StringTypes), "%r is not a string" % (name,) - self.name = name - - def encode(self, strio, compDict=None): - """ - Encode this Name into the appropriate byte format. - - @type strio: file - @param strio: The byte representation of this Name will be written to - this file. - - @type compDict: dict - @param compDict: dictionary of Names that have already been encoded - and whose addresses may be backreferenced by this Name (for the purpose - of reducing the message size). - """ - name = self.name - while name: - if compDict is not None: - if name in compDict: - strio.write( - struct.pack("!H", 0xc000 | compDict[name])) - return - else: - compDict[name] = strio.tell() + Message.headerSize - ind = name.find('.') - if ind > 0: - label, name = name[:ind], name[ind + 1:] - else: - label, name = name, '' - ind = len(label) - strio.write(chr(ind)) - strio.write(label) - strio.write(chr(0)) - - - def decode(self, strio, length=None): - """ - Decode a byte string into this Name. - - @type strio: file - @param strio: Bytes will be read from this file until the full Name - is decoded. - - @raise EOFError: Raised when there are not enough bytes available - from C{strio}. - """ - self.name = '' - off = 0 - while 1: - l = ord(readPrecisely(strio, 1)) - if l == 0: - if off > 0: - strio.seek(off) - return - if (l >> 6) == 3: - new_off = ((l&63) << 8 - | ord(readPrecisely(strio, 1))) - if off == 0: - off = strio.tell() - strio.seek(new_off) - continue - label = readPrecisely(strio, l) - if self.name == '': - self.name = label - else: - self.name = self.name + '.' + label - - def __eq__(self, other): - if isinstance(other, Name): - return str(self) == str(other) - return 0 - - - def __hash__(self): - return hash(str(self)) - - - def __str__(self): - return self.name - -class Query: - """ - Represent a single DNS query. - - @ivar name: The name about which this query is requesting information. - @ivar type: The query type. - @ivar cls: The query class. - """ - - implements(IEncodable) - - name = None - type = None - cls = None - - def __init__(self, name='', type=A, cls=IN): - """ - @type name: C{str} - @param name: The name about which to request information. - - @type type: C{int} - @param type: The query type. - - @type cls: C{int} - @param cls: The query class. - """ - self.name = Name(name) - self.type = type - self.cls = cls - - - def encode(self, strio, compDict=None): - self.name.encode(strio, compDict) - strio.write(struct.pack("!HH", self.type, self.cls)) - - - def decode(self, strio, length = None): - self.name.decode(strio) - buff = readPrecisely(strio, 4) - self.type, self.cls = struct.unpack("!HH", buff) - - - def __hash__(self): - return hash((str(self.name).lower(), self.type, self.cls)) - - - def __cmp__(self, other): - return isinstance(other, Query) and cmp( - (str(self.name).lower(), self.type, self.cls), - (str(other.name).lower(), other.type, other.cls) - ) or cmp(self.__class__, other.__class__) - - - def __str__(self): - t = QUERY_TYPES.get(self.type, EXT_QUERIES.get(self.type, 'UNKNOWN (%d)' % self.type)) - c = QUERY_CLASSES.get(self.cls, 'UNKNOWN (%d)' % self.cls) - return '' % (self.name, t, c) - - - def __repr__(self): - return 'Query(%r, %r, %r)' % (str(self.name), self.type, self.cls) - - -class RRHeader: - """ - A resource record header. - - @cvar fmt: C{str} specifying the byte format of an RR. - - @ivar name: The name about which this reply contains information. - @ivar type: The query type of the original request. - @ivar cls: The query class of the original request. - @ivar ttl: The time-to-live for this record. - @ivar payload: An object that implements the IEncodable interface - @ivar auth: Whether this header is authoritative or not. - """ - - implements(IEncodable) - - fmt = "!HHIH" - - name = None - type = None - cls = None - ttl = None - payload = None - rdlength = None - - cachedResponse = None - - def __init__(self, name='', type=A, cls=IN, ttl=0, payload=None, auth=False): - """ - @type name: C{str} - @param name: The name about which this reply contains information. - - @type type: C{int} - @param type: The query type. - - @type cls: C{int} - @param cls: The query class. - - @type ttl: C{int} - @param ttl: Time to live for this record. - - @type payload: An object implementing C{IEncodable} - @param payload: A Query Type specific data object. - """ - assert (payload is None) or (payload.TYPE == type) - - self.name = Name(name) - self.type = type - self.cls = cls - self.ttl = ttl - self.payload = payload - self.auth = auth - - - def encode(self, strio, compDict=None): - self.name.encode(strio, compDict) - strio.write(struct.pack(self.fmt, self.type, self.cls, self.ttl, 0)) - if self.payload: - prefix = strio.tell() - self.payload.encode(strio, compDict) - aft = strio.tell() - strio.seek(prefix - 2, 0) - strio.write(struct.pack('!H', aft - prefix)) - strio.seek(aft, 0) - - - def decode(self, strio, length = None): - self.name.decode(strio) - l = struct.calcsize(self.fmt) - buff = readPrecisely(strio, l) - r = struct.unpack(self.fmt, buff) - self.type, self.cls, self.ttl, self.rdlength = r - - - def isAuthoritative(self): - return self.auth - - - def __str__(self): - t = QUERY_TYPES.get(self.type, EXT_QUERIES.get(self.type, 'UNKNOWN (%d)' % self.type)) - c = QUERY_CLASSES.get(self.cls, 'UNKNOWN (%d)' % self.cls) - return '' % (self.name, t, c, self.ttl, self.auth and 'True' or 'False') - - - __repr__ = __str__ - - - -class SimpleRecord(tputil.FancyStrMixin, tputil.FancyEqMixin): - """ - A Resource Record which consists of a single RFC 1035 domain-name. - - @type name: L{Name} - @ivar name: The name associated with this record. - - @type ttl: C{int} - @ivar ttl: The maximum number of seconds which this record should be - cached. - """ - implements(IEncodable, IRecord) - - showAttributes = (('name', 'name', '%s'), 'ttl') - compareAttributes = ('name', 'ttl') - - TYPE = None - name = None - - def __init__(self, name='', ttl=None): - self.name = Name(name) - self.ttl = str2time(ttl) - - - def encode(self, strio, compDict = None): - self.name.encode(strio, compDict) - - - def decode(self, strio, length = None): - self.name = Name() - self.name.decode(strio) - - - def __hash__(self): - return hash(self.name) - - -# Kinds of RRs - oh my! -class Record_NS(SimpleRecord): - """ - An authoritative nameserver. - """ - TYPE = NS - - - -class Record_MD(SimpleRecord): - """ - A mail destination. - - This record type is obsolete. - - @see: L{Record_MX} - """ - TYPE = MD - - - -class Record_MF(SimpleRecord): - """ - A mail forwarder. - - This record type is obsolete. - - @see: L{Record_MX} - """ - TYPE = MF - - - -class Record_CNAME(SimpleRecord): - """ - The canonical name for an alias. - """ - TYPE = CNAME - - - -class Record_MB(SimpleRecord): - """ - A mailbox domain name. - - This is an experimental record type. - """ - TYPE = MB - - - -class Record_MG(SimpleRecord): - """ - A mail group member. - - This is an experimental record type. - """ - TYPE = MG - - - -class Record_MR(SimpleRecord): - """ - A mail rename domain name. - - This is an experimental record type. - """ - TYPE = MR - - - -class Record_PTR(SimpleRecord): - """ - A domain name pointer. - """ - TYPE = PTR - - - -class Record_DNAME(SimpleRecord): - """ - A non-terminal DNS name redirection. - - This record type provides the capability to map an entire subtree of the - DNS name space to another domain. It differs from the CNAME record which - maps a single node of the name space. - - @see: U{http://www.faqs.org/rfcs/rfc2672.html} - """ - TYPE = DNAME - - - -class Record_A(tputil.FancyEqMixin): - """ - An IPv4 host address. - - @type address: C{str} - @ivar address: The packed network-order representation of the IPv4 address - associated with this record. - - @type ttl: C{int} - @ivar ttl: The maximum number of seconds which this record should be - cached. - """ - implements(IEncodable, IRecord) - - compareAttributes = ('address', 'ttl') - - TYPE = A - address = None - - def __init__(self, address='0.0.0.0', ttl=None): - address = socket.inet_aton(address) - self.address = address - self.ttl = str2time(ttl) - - - def encode(self, strio, compDict = None): - strio.write(self.address) - - - def decode(self, strio, length = None): - self.address = readPrecisely(strio, 4) - - - def __hash__(self): - return hash(self.address) - - - def __str__(self): - return '' % (self.dottedQuad(), self.ttl) - - - def dottedQuad(self): - return socket.inet_ntoa(self.address) - - - -class Record_SOA(tputil.FancyEqMixin, tputil.FancyStrMixin): - """ - Marks the start of a zone of authority. - - This record describes parameters which are shared by all records within a - particular zone. - - @type mname: L{Name} - @ivar mname: The domain-name of the name server that was the original or - primary source of data for this zone. - - @type rname: L{Name} - @ivar rname: A domain-name which specifies the mailbox of the person - responsible for this zone. - - @type serial: C{int} - @ivar serial: The unsigned 32 bit version number of the original copy of - the zone. Zone transfers preserve this value. This value wraps and - should be compared using sequence space arithmetic. - - @type refresh: C{int} - @ivar refresh: A 32 bit time interval before the zone should be refreshed. - - @type minimum: C{int} - @ivar minimum: The unsigned 32 bit minimum TTL field that should be - exported with any RR from this zone. - - @type expire: C{int} - @ivar expire: A 32 bit time value that specifies the upper limit on the - time interval that can elapse before the zone is no longer - authoritative. - - @type retry: C{int} - @ivar retry: A 32 bit time interval that should elapse before a failed - refresh should be retried. - - @type ttl: C{int} - @ivar ttl: The default TTL to use for records served from this zone. - """ - implements(IEncodable, IRecord) - - compareAttributes = ('serial', 'mname', 'rname', 'refresh', 'expire', 'retry', 'ttl') - showAttributes = (('mname', 'mname', '%s'), ('rname', 'rname', '%s'), 'serial', 'refresh', 'retry', 'expire', 'minimum', 'ttl') - - TYPE = SOA - - def __init__(self, mname='', rname='', serial=0, refresh=0, retry=0, expire=0, minimum=0, ttl=None): - self.mname, self.rname = Name(mname), Name(rname) - self.serial, self.refresh = str2time(serial), str2time(refresh) - self.minimum, self.expire = str2time(minimum), str2time(expire) - self.retry = str2time(retry) - self.ttl = str2time(ttl) - - - def encode(self, strio, compDict = None): - self.mname.encode(strio, compDict) - self.rname.encode(strio, compDict) - strio.write( - struct.pack( - '!LlllL', - self.serial, self.refresh, self.retry, self.expire, - self.minimum - ) - ) - - - def decode(self, strio, length = None): - self.mname, self.rname = Name(), Name() - self.mname.decode(strio) - self.rname.decode(strio) - r = struct.unpack('!LlllL', readPrecisely(strio, 20)) - self.serial, self.refresh, self.retry, self.expire, self.minimum = r - - - def __hash__(self): - return hash(( - self.serial, self.mname, self.rname, - self.refresh, self.expire, self.retry - )) - - - -class Record_NULL: # EXPERIMENTAL - """ - A null record. - - This is an experimental record type. - - @type ttl: C{int} - @ivar ttl: The maximum number of seconds which this record should be - cached. - """ - implements(IEncodable, IRecord) - - TYPE = NULL - - def __init__(self, payload=None, ttl=None): - self.payload = payload - self.ttl = str2time(ttl) - - - def encode(self, strio, compDict = None): - strio.write(self.payload) - - - def decode(self, strio, length = None): - self.payload = readPrecisely(strio, length) - - - def __hash__(self): - return hash(self.payload) - - - -class Record_WKS(tputil.FancyEqMixin, tputil.FancyStrMixin): # OBSOLETE - """ - A well known service description. - - This record type is obsolete. See L{Record_SRV}. - - @type address: C{str} - @ivar address: The packed network-order representation of the IPv4 address - associated with this record. - - @type protocol: C{int} - @ivar protocol: The 8 bit IP protocol number for which this service map is - relevant. - - @type map: C{str} - @ivar map: A bitvector indicating the services available at the specified - address. - - @type ttl: C{int} - @ivar ttl: The maximum number of seconds which this record should be - cached. - """ - implements(IEncodable, IRecord) - - compareAttributes = ('address', 'protocol', 'map', 'ttl') - showAttributes = ('address', 'protocol', 'ttl') - - TYPE = WKS - - def __init__(self, address='0.0.0.0', protocol=0, map='', ttl=None): - self.address = socket.inet_aton(address) - self.protocol, self.map = protocol, map - self.ttl = str2time(ttl) - - - def encode(self, strio, compDict = None): - strio.write(self.address) - strio.write(struct.pack('!B', self.protocol)) - strio.write(self.map) - - - def decode(self, strio, length = None): - self.address = readPrecisely(strio, 4) - self.protocol = struct.unpack('!B', readPrecisely(strio, 1))[0] - self.map = readPrecisely(strio, length - 5) - - - def __hash__(self): - return hash((self.address, self.protocol, self.map)) - - - -class Record_AAAA(tputil.FancyEqMixin): # OBSOLETE (or headed there) - """ - An IPv6 host address. - - This record type is obsolete. - - @type address: C{str} - @ivar address: The packed network-order representation of the IPv6 address - associated with this record. - - @type ttl: C{int} - @ivar ttl: The maximum number of seconds which this record should be - cached. - - @see: L{Record_A6} - """ - implements(IEncodable, IRecord) - TYPE = AAAA - - compareAttributes = ('address', 'ttl') - - def __init__(self, address = '::', ttl=None): - self.address = socket.inet_pton(AF_INET6, address) - self.ttl = str2time(ttl) - - - def encode(self, strio, compDict = None): - strio.write(self.address) - - - def decode(self, strio, length = None): - self.address = readPrecisely(strio, 16) - - - def __hash__(self): - return hash(self.address) - - - def __str__(self): - return '' % (socket.inet_ntop(AF_INET6, self.address), self.ttl) - - - -class Record_A6: - """ - An IPv6 address. - - @type prefixLen: C{int} - @ivar prefixLen: The length of the suffix. - - @type suffix: C{str} - @ivar suffix: An IPv6 address suffix in network order. - - @type prefix: L{Name} - @ivar prefix: If specified, a name which will be used as a prefix for other - A6 records. - - @type bytes: C{int} - @ivar bytes: The length of the prefix. - - @type ttl: C{int} - @ivar ttl: The maximum number of seconds which this record should be - cached. - - @see: U{http://www.faqs.org/rfcs/rfc2874.html} - """ - implements(IEncodable, IRecord) - TYPE = A6 - - def __init__(self, prefixLen=0, suffix='::', prefix='', ttl=None): - self.prefixLen = prefixLen - self.suffix = socket.inet_pton(AF_INET6, suffix) - self.prefix = Name(prefix) - self.bytes = int((128 - self.prefixLen) / 8.0) - self.ttl = str2time(ttl) - - - def encode(self, strio, compDict = None): - strio.write(struct.pack('!B', self.prefixLen)) - if self.bytes: - strio.write(self.suffix[-self.bytes:]) - if self.prefixLen: - # This may not be compressed - self.prefix.encode(strio, None) - - - def decode(self, strio, length = None): - self.prefixLen = struct.unpack('!B', readPrecisely(strio, 1))[0] - self.bytes = int((128 - self.prefixLen) / 8.0) - if self.bytes: - self.suffix = '\x00' * (16 - self.bytes) + readPrecisely(strio, self.bytes) - if self.prefixLen: - self.prefix.decode(strio) - - - def __eq__(self, other): - if isinstance(other, Record_A6): - return (self.prefixLen == other.prefixLen and - self.suffix[-self.bytes:] == other.suffix[-self.bytes:] and - self.prefix == other.prefix and - self.ttl == other.ttl) - return 0 - - - def __hash__(self): - return hash((self.prefixLen, self.suffix[-self.bytes:], self.prefix)) - - - def __str__(self): - return '' % ( - self.prefix, - socket.inet_ntop(AF_INET6, self.suffix), - self.prefixLen, self.ttl - ) - - - -class Record_SRV(tputil.FancyEqMixin, tputil.FancyStrMixin): - """ - The location of the server(s) for a specific protocol and domain. - - This is an experimental record type. - - @type priority: C{int} - @ivar priority: The priority of this target host. A client MUST attempt to - contact the target host with the lowest-numbered priority it can reach; - target hosts with the same priority SHOULD be tried in an order defined - by the weight field. - - @type weight: C{int} - @ivar weight: Specifies a relative weight for entries with the same - priority. Larger weights SHOULD be given a proportionately higher - probability of being selected. - - @type port: C{int} - @ivar port: The port on this target host of this service. - - @type target: L{Name} - @ivar target: The domain name of the target host. There MUST be one or - more address records for this name, the name MUST NOT be an alias (in - the sense of RFC 1034 or RFC 2181). Implementors are urged, but not - required, to return the address record(s) in the Additional Data - section. Unless and until permitted by future standards action, name - compression is not to be used for this field. - - @type ttl: C{int} - @ivar ttl: The maximum number of seconds which this record should be - cached. - - @see: U{http://www.faqs.org/rfcs/rfc2782.html} - """ - implements(IEncodable, IRecord) - TYPE = SRV - - compareAttributes = ('priority', 'weight', 'target', 'port', 'ttl') - showAttributes = ('priority', 'weight', ('target', 'target', '%s'), 'port', 'ttl') - - def __init__(self, priority=0, weight=0, port=0, target='', ttl=None): - self.priority = int(priority) - self.weight = int(weight) - self.port = int(port) - self.target = Name(target) - self.ttl = str2time(ttl) - - - def encode(self, strio, compDict = None): - strio.write(struct.pack('!HHH', self.priority, self.weight, self.port)) - # This can't be compressed - self.target.encode(strio, None) - - - def decode(self, strio, length = None): - r = struct.unpack('!HHH', readPrecisely(strio, struct.calcsize('!HHH'))) - self.priority, self.weight, self.port = r - self.target = Name() - self.target.decode(strio) - - - def __hash__(self): - return hash((self.priority, self.weight, self.port, self.target)) - - - -class Record_AFSDB(tputil.FancyStrMixin, tputil.FancyEqMixin): - """ - Map from a domain name to the name of an AFS cell database server. - - @type subtype: C{int} - @ivar subtype: In the case of subtype 1, the host has an AFS version 3.0 - Volume Location Server for the named AFS cell. In the case of subtype - 2, the host has an authenticated name server holding the cell-root - directory node for the named DCE/NCA cell. - - @type hostname: L{Name} - @ivar hostname: The domain name of a host that has a server for the cell - named by this record. - - @type ttl: C{int} - @ivar ttl: The maximum number of seconds which this record should be - cached. - - @see: U{http://www.faqs.org/rfcs/rfc1183.html} - """ - implements(IEncodable, IRecord) - TYPE = AFSDB - - compareAttributes = ('subtype', 'hostname', 'ttl') - showAttributes = ('subtype', ('hostname', 'hostname', '%s'), 'ttl') - - def __init__(self, subtype=0, hostname='', ttl=None): - self.subtype = int(subtype) - self.hostname = Name(hostname) - self.ttl = str2time(ttl) - - - def encode(self, strio, compDict = None): - strio.write(struct.pack('!H', self.subtype)) - self.hostname.encode(strio, compDict) - - - def decode(self, strio, length = None): - r = struct.unpack('!H', readPrecisely(strio, struct.calcsize('!H'))) - self.subtype, = r - self.hostname.decode(strio) - - - def __hash__(self): - return hash((self.subtype, self.hostname)) - - - -class Record_RP(tputil.FancyEqMixin, tputil.FancyStrMixin): - """ - The responsible person for a domain. - - @type mbox: L{Name} - @ivar mbox: A domain name that specifies the mailbox for the responsible - person. - - @type txt: L{Name} - @ivar txt: A domain name for which TXT RR's exist (indirection through - which allows information sharing about the contents of this RP record). - - @type ttl: C{int} - @ivar ttl: The maximum number of seconds which this record should be - cached. - - @see: U{http://www.faqs.org/rfcs/rfc1183.html} - """ - implements(IEncodable, IRecord) - TYPE = RP - - compareAttributes = ('mbox', 'txt', 'ttl') - showAttributes = (('mbox', 'mbox', '%s'), ('txt', 'txt', '%s'), 'ttl') - - def __init__(self, mbox='', txt='', ttl=None): - self.mbox = Name(mbox) - self.txt = Name(txt) - self.ttl = str2time(ttl) - - - def encode(self, strio, compDict = None): - self.mbox.encode(strio, compDict) - self.txt.encode(strio, compDict) - - - def decode(self, strio, length = None): - self.mbox = Name() - self.txt = Name() - self.mbox.decode(strio) - self.txt.decode(strio) - - - def __hash__(self): - return hash((self.mbox, self.txt)) - - - -class Record_HINFO(tputil.FancyStrMixin): - """ - Host information. - - @type cpu: C{str} - @ivar cpu: Specifies the CPU type. - - @type os: C{str} - @ivar os: Specifies the OS. - - @type ttl: C{int} - @ivar ttl: The maximum number of seconds which this record should be - cached. - """ - implements(IEncodable, IRecord) - TYPE = HINFO - - showAttributes = ('cpu', 'os', 'ttl') - - def __init__(self, cpu='', os='', ttl=None): - self.cpu, self.os = cpu, os - self.ttl = str2time(ttl) - - - def encode(self, strio, compDict = None): - strio.write(struct.pack('!B', len(self.cpu)) + self.cpu) - strio.write(struct.pack('!B', len(self.os)) + self.os) - - - def decode(self, strio, length = None): - cpu = struct.unpack('!B', readPrecisely(strio, 1))[0] - self.cpu = readPrecisely(strio, cpu) - os = struct.unpack('!B', readPrecisely(strio, 1))[0] - self.os = readPrecisely(strio, os) - - - def __eq__(self, other): - if isinstance(other, Record_HINFO): - return (self.os.lower() == other.os.lower() and - self.cpu.lower() == other.cpu.lower() and - self.ttl == other.ttl) - return 0 - - - def __hash__(self): - return hash((self.os.lower(), self.cpu.lower())) - - - -class Record_MINFO(tputil.FancyEqMixin, tputil.FancyStrMixin): - """ - Mailbox or mail list information. - - This is an experimental record type. - - @type rmailbx: L{Name} - @ivar rmailbx: A domain-name which specifies a mailbox which is responsible - for the mailing list or mailbox. If this domain name names the root, - the owner of the MINFO RR is responsible for itself. - - @type emailbx: L{Name} - @ivar emailbx: A domain-name which specifies a mailbox which is to receive - error messages related to the mailing list or mailbox specified by the - owner of the MINFO record. If this domain name names the root, errors - should be returned to the sender of the message. - - @type ttl: C{int} - @ivar ttl: The maximum number of seconds which this record should be - cached. - """ - implements(IEncodable, IRecord) - TYPE = MINFO - - rmailbx = None - emailbx = None - - compareAttributes = ('rmailbx', 'emailbx', 'ttl') - showAttributes = (('rmailbx', 'responsibility', '%s'), - ('emailbx', 'errors', '%s'), - 'ttl') - - def __init__(self, rmailbx='', emailbx='', ttl=None): - self.rmailbx, self.emailbx = Name(rmailbx), Name(emailbx) - self.ttl = str2time(ttl) - - - def encode(self, strio, compDict = None): - self.rmailbx.encode(strio, compDict) - self.emailbx.encode(strio, compDict) - - - def decode(self, strio, length = None): - self.rmailbx, self.emailbx = Name(), Name() - self.rmailbx.decode(strio) - self.emailbx.decode(strio) - - - def __hash__(self): - return hash((self.rmailbx, self.emailbx)) - - - -class Record_MX(tputil.FancyStrMixin, tputil.FancyEqMixin): - """ - Mail exchange. - - @type preference: C{int} - @ivar preference: Specifies the preference given to this RR among others at - the same owner. Lower values are preferred. - - @type name: L{Name} - @ivar name: A domain-name which specifies a host willing to act as a mail - exchange. - - @type ttl: C{int} - @ivar ttl: The maximum number of seconds which this record should be - cached. - """ - implements(IEncodable, IRecord) - TYPE = MX - - compareAttributes = ('preference', 'name', 'ttl') - showAttributes = ('preference', ('name', 'name', '%s'), 'ttl') - - def __init__(self, preference=0, name='', ttl=None, **kwargs): - self.preference, self.name = int(preference), Name(kwargs.get('exchange', name)) - self.ttl = str2time(ttl) - - def encode(self, strio, compDict = None): - strio.write(struct.pack('!H', self.preference)) - self.name.encode(strio, compDict) - - - def decode(self, strio, length = None): - self.preference = struct.unpack('!H', readPrecisely(strio, 2))[0] - self.name = Name() - self.name.decode(strio) - - def exchange(self): - warnings.warn("use Record_MX.name instead", DeprecationWarning, stacklevel=2) - return self.name - - exchange = property(exchange) - - def __hash__(self): - return hash((self.preference, self.name)) - - - -# Oh god, Record_TXT how I hate thee. -class Record_TXT(tputil.FancyEqMixin, tputil.FancyStrMixin): - """ - Freeform text. - - @type data: C{list} of C{str} - @ivar data: Freeform text which makes up this record. - """ - implements(IEncodable, IRecord) - - TYPE = TXT - - showAttributes = compareAttributes = ('data', 'ttl') - - def __init__(self, *data, **kw): - self.data = list(data) - # arg man python sucks so bad - self.ttl = str2time(kw.get('ttl', None)) - - - def encode(self, strio, compDict = None): - for d in self.data: - strio.write(struct.pack('!B', len(d)) + d) - - - def decode(self, strio, length = None): - soFar = 0 - self.data = [] - while soFar < length: - L = struct.unpack('!B', readPrecisely(strio, 1))[0] - self.data.append(readPrecisely(strio, L)) - soFar += L + 1 - if soFar != length: - log.msg( - "Decoded %d bytes in TXT record, but rdlength is %d" % ( - soFar, length - ) - ) - - - def __hash__(self): - return hash(tuple(self.data)) - - - -class Message: - headerFmt = "!H2B4H" - headerSize = struct.calcsize(headerFmt) - - # Question, answer, additional, and nameserver lists - queries = answers = add = ns = None - - def __init__(self, id=0, answer=0, opCode=0, recDes=0, recAv=0, - auth=0, rCode=OK, trunc=0, maxSize=512): - self.maxSize = maxSize - self.id = id - self.answer = answer - self.opCode = opCode - self.auth = auth - self.trunc = trunc - self.recDes = recDes - self.recAv = recAv - self.rCode = rCode - self.queries = [] - self.answers = [] - self.authority = [] - self.additional = [] - - - def addQuery(self, name, type=ALL_RECORDS, cls=IN): - """ - Add another query to this Message. - - @type name: C{str} - @param name: The name to query. - - @type type: C{int} - @param type: Query type - - @type cls: C{int} - @param cls: Query class - """ - self.queries.append(Query(name, type, cls)) - - - def encode(self, strio): - compDict = {} - body_tmp = StringIO.StringIO() - for q in self.queries: - q.encode(body_tmp, compDict) - for q in self.answers: - q.encode(body_tmp, compDict) - for q in self.authority: - q.encode(body_tmp, compDict) - for q in self.additional: - q.encode(body_tmp, compDict) - body = body_tmp.getvalue() - size = len(body) + self.headerSize - if self.maxSize and size > self.maxSize: - self.trunc = 1 - body = body[:self.maxSize - self.headerSize] - byte3 = (( ( self.answer & 1 ) << 7 ) - | ((self.opCode & 0xf ) << 3 ) - | ((self.auth & 1 ) << 2 ) - | ((self.trunc & 1 ) << 1 ) - | ( self.recDes & 1 ) ) - byte4 = ( ( (self.recAv & 1 ) << 7 ) - | (self.rCode & 0xf ) ) - - strio.write(struct.pack(self.headerFmt, self.id, byte3, byte4, - len(self.queries), len(self.answers), - len(self.authority), len(self.additional))) - strio.write(body) - - - def decode(self, strio, length=None): - self.maxSize = 0 - header = readPrecisely(strio, self.headerSize) - r = struct.unpack(self.headerFmt, header) - self.id, byte3, byte4, nqueries, nans, nns, nadd = r - self.answer = ( byte3 >> 7 ) & 1 - self.opCode = ( byte3 >> 3 ) & 0xf - self.auth = ( byte3 >> 2 ) & 1 - self.trunc = ( byte3 >> 1 ) & 1 - self.recDes = byte3 & 1 - self.recAv = ( byte4 >> 7 ) & 1 - self.rCode = byte4 & 0xf - - self.queries = [] - for i in range(nqueries): - q = Query() - try: - q.decode(strio) - except EOFError: - return - self.queries.append(q) - - items = ((self.answers, nans), (self.authority, nns), (self.additional, nadd)) - for (l, n) in items: - self.parseRecords(l, n, strio) - - - def parseRecords(self, list, num, strio): - for i in range(num): - header = RRHeader() - try: - header.decode(strio) - except EOFError: - return - t = self.lookupRecordType(header.type) - if not t: - continue - header.payload = t(ttl=header.ttl) - try: - header.payload.decode(strio, header.rdlength) - except EOFError: - return - list.append(header) - - - def lookupRecordType(self, type): - return globals().get('Record_' + QUERY_TYPES.get(type, ''), None) - - - def toStr(self): - strio = StringIO.StringIO() - self.encode(strio) - return strio.getvalue() - - - def fromStr(self, str): - strio = StringIO.StringIO(str) - self.decode(strio) - -class DNSMixin(object): - """ - DNS protocol mixin shared by UDP and TCP implementations. - """ - id = None - liveMessages = None - - def __init__(self, controller): - self.controller = controller - self.id = random.randrange(2 ** 10, 2 ** 15) - - def pickID(self): - """ - Return a unique ID for queries. - """ - while True: - self.id += randomSource() % (2 ** 10) - self.id %= 2 ** 16 - if self.id not in self.liveMessages: - break - return self.id - - def callLater(self, period, func, *args): - """ - Wrapper around reactor.callLater, mainly for test purpose. - """ - from twisted.internet import reactor - return reactor.callLater(period, func, *args) - - def _query(self, queries, timeout, id, writeMessage): - """ - Send out a message with the given queries. - - @type queries: C{list} of C{Query} instances - @param queries: The queries to transmit - - @type timeout: C{int} or C{float} - @param timeout: How long to wait before giving up - - @type id: C{int} - @param id: Unique key for this request - - @type writeMessage: C{callable} - @param writeMessage: One-parameter callback which writes the message - - @rtype: C{Deferred} - @return: a C{Deferred} which will be fired with the result of the - query, or errbacked with any errors that could happen (exceptions - during writing of the query, timeout errors, ...). - """ - m = Message(id, recDes=1) - m.queries = queries - - try: - writeMessage(m) - except: - return defer.fail() - - resultDeferred = defer.Deferred() - cancelCall = self.callLater(timeout, self._clearFailed, resultDeferred, id) - self.liveMessages[id] = (resultDeferred, cancelCall) - - return resultDeferred - - def _clearFailed(self, deferred, id): - """ - Clean the Deferred after a timeout. - """ - try: - del self.liveMessages[id] - except KeyError: - pass - deferred.errback(failure.Failure(DNSQueryTimeoutError(id))) - - -class DNSDatagramProtocol(DNSMixin, protocol.DatagramProtocol): - """ - DNS protocol over UDP. - """ - resends = None - - def stopProtocol(self): - """ - Stop protocol: reset state variables. - """ - self.liveMessages = {} - self.resends = {} - self.transport = None - - def startProtocol(self): - """ - Upon start, reset internal state. - """ - self.liveMessages = {} - self.resends = {} - - def writeMessage(self, message, address): - """ - Send a message holding DNS queries. - - @type message: L{Message} - """ - self.transport.write(message.toStr(), address) - - def startListening(self): - from twisted.internet import reactor - reactor.listenUDP(0, self, maxPacketSize=512) - - def datagramReceived(self, data, addr): - """ - Read a datagram, extract the message in it and trigger the associated - Deferred. - """ - m = Message() - try: - m.fromStr(data) - except EOFError: - log.msg("Truncated packet (%d bytes) from %s" % (len(data), addr)) - return - except: - # Nothing should trigger this, but since we're potentially - # invoking a lot of different decoding methods, we might as well - # be extra cautious. Anything that triggers this is itself - # buggy. - log.err(failure.Failure(), "Unexpected decoding error") - return - - if m.id in self.liveMessages: - d, canceller = self.liveMessages[m.id] - del self.liveMessages[m.id] - canceller.cancel() - # XXX we shouldn't need this hack of catching exception on callback() - try: - d.callback(m) - except: - log.err() - else: - if m.id not in self.resends: - self.controller.messageReceived(m, self, addr) - - - def removeResend(self, id): - """ - Mark message ID as no longer having duplication suppression. - """ - try: - del self.resends[id] - except KeyError: - pass - - def query(self, address, queries, timeout=10, id=None): - """ - Send out a message with the given queries. - - @type address: C{tuple} of C{str} and C{int} - @param address: The address to which to send the query - - @type queries: C{list} of C{Query} instances - @param queries: The queries to transmit - - @rtype: C{Deferred} - """ - if not self.transport: - # XXX transport might not get created automatically, use callLater? - try: - self.startListening() - except CannotListenError: - return defer.fail() - - if id is None: - id = self.pickID() - else: - self.resends[id] = 1 - - def writeMessage(m): - self.writeMessage(m, address) - - return self._query(queries, timeout, id, writeMessage) - - -class DNSProtocol(DNSMixin, protocol.Protocol): - """ - DNS protocol over TCP. - """ - length = None - buffer = '' - - def writeMessage(self, message): - """ - Send a message holding DNS queries. - - @type message: L{Message} - """ - s = message.toStr() - self.transport.write(struct.pack('!H', len(s)) + s) - - def connectionMade(self): - """ - Connection is made: reset internal state, and notify the controller. - """ - self.liveMessages = {} - self.controller.connectionMade(self) - - def dataReceived(self, data): - self.buffer += data - - while self.buffer: - if self.length is None and len(self.buffer) >= 2: - self.length = struct.unpack('!H', self.buffer[:2])[0] - self.buffer = self.buffer[2:] - - if len(self.buffer) >= self.length: - myChunk = self.buffer[:self.length] - m = Message() - m.fromStr(myChunk) - - try: - d, canceller = self.liveMessages[m.id] - except KeyError: - self.controller.messageReceived(m, self) - else: - del self.liveMessages[m.id] - canceller.cancel() - # XXX we shouldn't need this hack - try: - d.callback(m) - except: - log.err() - - self.buffer = self.buffer[self.length:] - self.length = None - else: - break - - def query(self, queries, timeout=60): - """ - Send out a message with the given queries. - - @type queries: C{list} of C{Query} instances - @param queries: The queries to transmit - - @rtype: C{Deferred} - """ - id = self.pickID() - return self._query(queries, timeout, id, self.writeMessage) - diff --git a/tools/buildbot/pylibs/twisted/names/error.py b/tools/buildbot/pylibs/twisted/names/error.py deleted file mode 100644 index 5206164..0000000 --- a/tools/buildbot/pylibs/twisted/names/error.py +++ /dev/null @@ -1,88 +0,0 @@ -# -*- test-case-name: twisted.names.test -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Exception class definitions for Twisted Names. -""" - -from twisted.internet.defer import TimeoutError - - -class DomainError(ValueError): - """ - Indicates a lookup failed because there were no records matching the given - C{name, class, type} triple. - """ - - - -class AuthoritativeDomainError(ValueError): - """ - Indicates a lookup failed for a name for which this server is authoritative - because there were no records matching the given C{name, class, type} - triple. - """ - - - -class DNSQueryTimeoutError(TimeoutError): - """ - Indicates a lookup failed due to a timeout. - - @ivar id: The id of the message which timed out. - """ - def __init__(self, id): - TimeoutError.__init__(self) - self.id = id - - - -class DNSFormatError(DomainError): - """ - Indicates a query failed with a result of L{twisted.names.dns.EFORMAT}. - """ - - - -class DNSServerError(DomainError): - """ - Indicates a query failed with a result of L{twisted.names.dns.ESERVER}. - """ - - - -class DNSNameError(DomainError): - """ - Indicates a query failed with a result of L{twisted.names.dns.ENAME}. - """ - - - -class DNSNotImplementedError(DomainError): - """ - Indicates a query failed with a result of L{twisted.names.dns.ENOTIMP}. - """ - - - -class DNSQueryRefusedError(DomainError): - """ - Indicates a query failed with a result of L{twisted.names.dns.EREFUSED}. - """ - - - -class DNSUnknownError(DomainError): - """ - Indicates a query failed with an unknown result. - """ - - - -__all__ = [ - 'DomainError', 'AuthoritativeDomainError', 'DNSQueryTimeoutError', - - 'DNSFormatError', 'DNSServerError', 'DNSNameError', - 'DNSNotImplementedError', 'DNSQueryRefusedError', - 'DNSUnknownError'] diff --git a/tools/buildbot/pylibs/twisted/names/hosts.py b/tools/buildbot/pylibs/twisted/names/hosts.py deleted file mode 100644 index fa0b340..0000000 --- a/tools/buildbot/pylibs/twisted/names/hosts.py +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -from twisted.names import dns -from twisted.persisted import styles -from twisted.python import failure -from twisted.internet import defer - -from twisted.names import common - -def searchFileFor(file, name): - try: - fp = open(file) - except: - return None - - lines = fp.readlines() - for line in lines: - idx = line.find('#') - if idx != -1: - line = line[:idx] - if not line: - continue - parts = line.split() - if name.lower() in [s.lower() for s in parts[1:]]: - return parts[0] - return None - - - -class Resolver(common.ResolverBase, styles.Versioned): - """A resolver that services hosts(5) format files.""" - #TODO: IPv6 support - - persistenceVersion = 1 - - def upgradeToVersion1(self): - # <3 exarkun - self.typeToMethod = {} - for (k, v) in common.typeToMethod.items(): - self.typeToMethod[k] = getattr(self, v) - - - def __init__(self, file='/etc/hosts', ttl = 60 * 60): - common.ResolverBase.__init__(self) - self.file = file - self.ttl = ttl - - - def lookupAddress(self, name, timeout = None): - res = searchFileFor(self.file, name) - if res: - return defer.succeed([ - (dns.RRHeader(name, dns.A, dns.IN, self.ttl, dns.Record_A(res, self.ttl)),), (), () - ]) - return defer.fail(failure.Failure(dns.DomainError(name))) - - - # When we put IPv6 support in, this'll need a real impl - lookupAllRecords = lookupAddress diff --git a/tools/buildbot/pylibs/twisted/names/resolve.py b/tools/buildbot/pylibs/twisted/names/resolve.py deleted file mode 100644 index b1f5d23..0000000 --- a/tools/buildbot/pylibs/twisted/names/resolve.py +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Lookup a name using multiple resolvers. - -Future Plans: This needs someway to specify which resolver answered -the query, or someway to specify (authority|ttl|cache behavior|more?) - -@author: U{Jp Calderone} -""" - -from twisted.internet import defer, interfaces -from twisted.names import dns -from zope.interface import implements -import common - -class FailureHandler: - def __init__(self, resolver, query, timeout): - self.resolver = resolver - self.query = query - self.timeout = timeout - - - def __call__(self, failure): - # AuthoritativeDomainErrors should halt resolution attempts - failure.trap(dns.DomainError, defer.TimeoutError, NotImplementedError) - return self.resolver(self.query, self.timeout) - - -class ResolverChain(common.ResolverBase): - """Lookup an address using multiple C{IResolver}s""" - - implements(interfaces.IResolver) - - - def __init__(self, resolvers): - common.ResolverBase.__init__(self) - self.resolvers = resolvers - - - def _lookup(self, name, cls, type, timeout): - q = dns.Query(name, type, cls) - d = self.resolvers[0].query(q, timeout) - for r in self.resolvers[1:]: - d = d.addErrback( - FailureHandler(r.query, q, timeout) - ) - return d - - - def lookupAllRecords(self, name, timeout = None): - d = self.resolvers[0].lookupAllRecords(name, timeout) - for r in self.resolvers[1:]: - d = d.addErrback( - FailureHandler(r.lookupAllRecords, name, timeout) - ) - return d diff --git a/tools/buildbot/pylibs/twisted/names/root.py b/tools/buildbot/pylibs/twisted/names/root.py deleted file mode 100644 index b5b64b2..0000000 --- a/tools/buildbot/pylibs/twisted/names/root.py +++ /dev/null @@ -1,208 +0,0 @@ -# -*- test-case-name: twisted.names.test.test_rootresolve -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Resolver implementation for querying successive authoritative servers to -lookup a record, starting from the root nameservers. - -@author: U{Jp Calderone} - -todo:: - robustify it - break discoverAuthority into several smaller functions - documentation -""" - -from __future__ import generators - -import sys - -from twisted.python import log -from twisted.internet import defer -from twisted.names import dns -from twisted.names import common - -def retry(t, p, *args): - assert t, "Timeout is required" - t = list(t) - def errback(failure): - failure.trap(defer.TimeoutError) - if not t: - return failure - return p.query(timeout=t.pop(0), *args - ).addErrback(errback - ) - return p.query(timeout=t.pop(0), *args - ).addErrback(errback - ) - -class _DummyController: - def messageReceived(self, *args): - pass - -class Resolver(common.ResolverBase): - def __init__(self, hints): - common.ResolverBase.__init__(self) - self.hints = hints - - def _lookup(self, name, cls, type, timeout): - d = discoverAuthority(name, self.hints - ).addCallback(self.discoveredAuthority, name, cls, type, timeout - ) - return d - - def discoveredAuthority(self, auth, name, cls, type, timeout): - from twisted.names import client - q = dns.Query(name, type, cls) - r = client.Resolver(servers=[(auth, dns.PORT)]) - d = r.queryUDP([q], timeout) - d.addCallback(r.filterAnswers) - return d - -def lookupNameservers(host, atServer, p=None): - # print 'Nameserver lookup for', host, 'at', atServer, 'with', p - if p is None: - p = dns.DNSDatagramProtocol(_DummyController()) - p.noisy = False - return retry( - (1, 3, 11, 45), # Timeouts - p, # Protocol instance - (atServer, dns.PORT), # Server to query - [dns.Query(host, dns.NS, dns.IN)] # Question to ask - ) - -def lookupAddress(host, atServer, p=None): - # print 'Address lookup for', host, 'at', atServer, 'with', p - if p is None: - p = dns.DNSDatagramProtocol(_DummyController()) - p.noisy = False - return retry( - (1, 3, 11, 45), # Timeouts - p, # Protocol instance - (atServer, dns.PORT), # Server to query - [dns.Query(host, dns.A, dns.IN)] # Question to ask - ) - -def extractAuthority(msg, cache): - records = msg.answers + msg.authority + msg.additional - nameservers = [r for r in records if r.type == dns.NS] - - # print 'Records for', soFar, ':', records - # print 'NS for', soFar, ':', nameservers - - if not nameservers: - return None, nameservers - if not records: - raise IOError("No records") - for r in records: - if r.type == dns.A: - cache[str(r.name)] = r.payload.dottedQuad() - for r in records: - if r.type == dns.NS: - if str(r.payload.name) in cache: - return cache[str(r.payload.name)], nameservers - for addr in records: - if addr.type == dns.A and addr.name == r.name: - return addr.payload.dottedQuad(), nameservers - return None, nameservers - -def discoverAuthority(host, roots, cache=None, p=None): - if cache is None: - cache = {} - - rootAuths = list(roots) - - parts = host.rstrip('.').split('.') - parts.reverse() - - authority = rootAuths.pop() - - soFar = '' - for part in parts: - soFar = part + '.' + soFar - # print '///////', soFar, authority, p - msg = defer.waitForDeferred(lookupNameservers(soFar, authority, p)) - yield msg - msg = msg.getResult() - - newAuth, nameservers = extractAuthority(msg, cache) - - if newAuth is not None: - # print "newAuth is not None" - authority = newAuth - else: - if nameservers: - r = str(nameservers[0].payload.name) - # print 'Recursively discovering authority for', r - authority = defer.waitForDeferred(discoverAuthority(r, roots, cache, p)) - yield authority - authority = authority.getResult() - # print 'Discovered to be', authority, 'for', r -## else: -## # print 'Doing address lookup for', soFar, 'at', authority -## msg = defer.waitForDeferred(lookupAddress(soFar, authority, p)) -## yield msg -## msg = msg.getResult() -## records = msg.answers + msg.authority + msg.additional -## addresses = [r for r in records if r.type == dns.A] -## if addresses: -## authority = addresses[0].payload.dottedQuad() -## else: -## raise IOError("Resolution error") - # print "Yielding authority", authority - yield authority - -discoverAuthority = defer.deferredGenerator(discoverAuthority) - -def makePlaceholder(deferred, name): - def placeholder(*args, **kw): - deferred.addCallback(lambda r: getattr(r, name)(*args, **kw)) - return deferred - return placeholder - -class DeferredResolver: - def __init__(self, resolverDeferred): - self.waiting = [] - resolverDeferred.addCallback(self.gotRealResolver) - - def gotRealResolver(self, resolver): - w = self.waiting - self.__dict__ = resolver.__dict__ - self.__class__ = resolver.__class__ - for d in w: - d.callback(resolver) - - def __getattr__(self, name): - if name.startswith('lookup') or name in ('getHostByName', 'query'): - self.waiting.append(defer.Deferred()) - return makePlaceholder(self.waiting[-1], name) - raise AttributeError(name) - -def bootstrap(resolver): - """Lookup the root nameserver addresses using the given resolver - - Return a Resolver which will eventually become a C{root.Resolver} - instance that has references to all the root servers that we were able - to look up. - """ - domains = [chr(ord('a') + i) for i in range(13)] - # f = lambda r: (log.msg('Root server address: ' + str(r)), r)[1] - f = lambda r: r - L = [resolver.getHostByName('%s.root-servers.net' % d).addCallback(f) for d in domains] - d = defer.DeferredList(L) - d.addCallback(lambda r: Resolver([e[1] for e in r if e[0]])) - return DeferredResolver(d) - -if __name__ == '__main__': - if len(sys.argv) < 2: - print 'Specify a domain' - else: - log.startLogging(sys.stdout) - from twisted.names.client import ThreadedResolver - r = bootstrap(ThreadedResolver()) - d = r.lookupAddress(sys.argv[1]) - d.addCallbacks(log.msg, log.err).addBoth(lambda _: reactor.stop()) - from twisted.internet import reactor - reactor.run() diff --git a/tools/buildbot/pylibs/twisted/names/secondary.py b/tools/buildbot/pylibs/twisted/names/secondary.py deleted file mode 100644 index 19afa24..0000000 --- a/tools/buildbot/pylibs/twisted/names/secondary.py +++ /dev/null @@ -1,102 +0,0 @@ -# Copyright (c) 2001-2006 Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.internet import task, defer -from twisted.names import dns -from twisted.names import common -from twisted.names import client -from twisted.names import resolve -from twisted.python import log, failure -from twisted.application import service - -class SecondaryAuthorityService(service.Service): - calls = None - - def __init__(self, primary, domains): - """ - @param primary: The IP address of the server from which to perform - zone transfers. - - @param domains: A sequence of domain names for which to perform - zone transfers. - """ - self.primary = primary - self.domains = [SecondaryAuthority(primary, d) for d in domains] - - def getAuthority(self): - return resolve.ResolverChain(self.domains) - - def startService(self): - service.Service.startService(self) - self.calls = [task.LoopingCall(d.transfer) for d in self.domains] - i = 0 - from twisted.internet import reactor - for c in self.calls: - # XXX Add errbacks, respect proper timeouts - reactor.callLater(i, c.start, 60 * 60) - i += 1 - - def stopService(self): - service.Service.stopService(self) - for c in self.calls: - c.stop() - - -from twisted.names.authority import FileAuthority - -class SecondaryAuthority(common.ResolverBase): - """An Authority that keeps itself updated by performing zone transfers""" - - transferring = False - - soa = records = None - def __init__(self, primaryIP, domain): - common.ResolverBase.__init__(self) - self.primary = primaryIP - self.domain = domain - - def transfer(self): - if self.transferring: - return - self.transfering = True - return client.Resolver(servers=[(self.primary, dns.PORT)] - ).lookupZone(self.domain - ).addCallback(self._cbZone - ).addErrback(self._ebZone - ) - - - def _lookup(self, name, cls, type, timeout=None): - if not self.soa or not self.records: - return defer.fail(failure.Failure(dns.DomainError(name))) - - - return FileAuthority.__dict__['_lookup'](self, name, cls, type, timeout) - - #shouldn't we just subclass? :P - - lookupZone = FileAuthority.__dict__['lookupZone'] - - def _cbZone(self, zone): - ans, _, _ = zone - self.records = r = {} - for rec in ans: - if not self.soa and rec.type == dns.SOA: - self.soa = (str(rec.name).lower(), rec.payload) - else: - r.setdefault(str(rec.name).lower(), []).append(rec.payload) - - def _ebZone(self, failure): - log.msg("Updating %s from %s failed during zone transfer" % (self.domain, self.primary)) - log.err(failure) - - def update(self): - self.transfer().addCallbacks(self._cbTransferred, self._ebTransferred) - - def _cbTransferred(self, result): - self.transferring = False - - def _ebTransferred(self, failure): - self.transferred = False - log.msg("Transferring %s from %s failed after zone transfer" % (self.domain, self.primary)) - log.err(failure) diff --git a/tools/buildbot/pylibs/twisted/names/server.py b/tools/buildbot/pylibs/twisted/names/server.py deleted file mode 100644 index 2d731a9..0000000 --- a/tools/buildbot/pylibs/twisted/names/server.py +++ /dev/null @@ -1,188 +0,0 @@ -# -*- test-case-name: twisted.names.test.test_names -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Async DNS server - -Future plans: - - Better config file format maybe - - Make sure to differentiate between different classes - - notice truncation bit - -Important: No additional processing is done on some of the record types. -This violates the most basic RFC and is just plain annoying -for resolvers to deal with. Fix it. - -@author: U{Jp Calderone } -""" - -from __future__ import nested_scopes -import time - -# Twisted imports -from twisted.internet import protocol -from twisted.names import dns -from twisted.python import log - -import resolve - -class DNSServerFactory(protocol.ServerFactory): - protocol = dns.DNSProtocol - cache = None - - def __init__(self, authorities = None, caches = None, clients = None, verbose = 0): - resolvers = [] - if authorities is not None: - resolvers.extend(authorities) - if caches is not None: - resolvers.extend(caches) - if clients is not None: - resolvers.extend(clients) - - self.canRecurse = not not clients - self.resolver = resolve.ResolverChain(resolvers) - self.verbose = verbose - if caches: - self.cache = caches[-1] - - - def buildProtocol(self, addr): - p = self.protocol(self) - p.factory = self - return p - - def connectionMade(self, protocol): - pass - - - def sendReply(self, protocol, message, address): - if self.verbose > 1: - s = ' '.join([str(a.payload) for a in message.answers]) - auth = ' '.join([str(a.payload) for a in message.authority]) - add = ' '.join([str(a.payload) for a in message.additional]) - if not s: - log.msg("Replying with no answers") - else: - log.msg("Answers are " + s) - log.msg("Authority is " + auth) - log.msg("Additional is " + add) - - if address is None: - protocol.writeMessage(message) - else: - protocol.writeMessage(message, address) - - if self.verbose > 1: - log.msg("Processed query in %0.3f seconds" % (time.time() - message.timeReceived)) - - - def gotResolverResponse(self, (ans, auth, add), protocol, message, address): - message.rCode = dns.OK - message.answers = ans - for x in ans: - if x.isAuthoritative(): - message.auth = 1 - break - message.authority = auth - message.additional = add - self.sendReply(protocol, message, address) - - l = len(ans) + len(auth) + len(add) - if self.verbose: - log.msg("Lookup found %d record%s" % (l, l != 1 and "s" or "")) - - if self.cache and l: - self.cache.cacheResult( - message.queries[0], (ans, auth, add) - ) - - - def gotResolverError(self, failure, protocol, message, address): - if failure.check(dns.DomainError, dns.AuthoritativeDomainError): - message.rCode = dns.ENAME - else: - message.rCode = dns.ESERVER - log.err(failure) - - self.sendReply(protocol, message, address) - if self.verbose: - log.msg("Lookup failed") - - - def handleQuery(self, message, protocol, address): - # Discard all but the first query! HOO-AAH HOOOOO-AAAAH - # (no other servers implement multi-query messages, so we won't either) - query = message.queries[0] - - return self.resolver.query(query).addCallback( - self.gotResolverResponse, protocol, message, address - ).addErrback( - self.gotResolverError, protocol, message, address - ) - - - def handleInverseQuery(self, message, protocol, address): - message.rCode = dns.ENOTIMP - self.sendReply(protocol, message, address) - if self.verbose: - log.msg("Inverse query from %r" % (address,)) - - - def handleStatus(self, message, protocol, address): - message.rCode = dns.ENOTIMP - self.sendReply(protocol, message, address) - if self.verbose: - log.msg("Status request from %r" % (address,)) - - - def handleNotify(self, message, protocol, address): - message.rCode = dns.ENOTIMP - self.sendReply(protocol, message, address) - if self.verbose: - log.msg("Notify message from %r" % (address,)) - - - def handleOther(self, message, protocol, address): - message.rCode = dns.ENOTIMP - self.sendReply(protocol, message, address) - if self.verbose: - log.msg("Unknown op code (%d) from %r" % (message.opCode, address)) - - - def messageReceived(self, message, proto, address = None): - message.timeReceived = time.time() - - if self.verbose: - if self.verbose > 1: - s = ' '.join([str(q) for q in message.queries]) - elif self.verbose > 0: - s = ' '.join([dns.QUERY_TYPES.get(q.type, 'UNKNOWN') for q in message.queries]) - - if not len(s): - log.msg("Empty query from %r" % ((address or proto.transport.getPeer()),)) - else: - log.msg("%s query from %r" % (s, address or proto.transport.getPeer())) - - message.recAv = self.canRecurse - message.answer = 1 - - if not self.allowQuery(message, proto, address): - message.rCode = dns.EREFUSED - self.sendReply(proto, message, address) - elif message.opCode == dns.OP_QUERY: - self.handleQuery(message, proto, address) - elif message.opCode == dns.OP_INVERSE: - self.handleInverseQuery(message, proto, address) - elif message.opCode == dns.OP_STATUS: - self.handleStatus(message, proto, address) - elif message.opCode == dns.OP_NOTIFY: - self.handleNotify(message, proto, address) - else: - self.handleOther(message, proto, address) - - - def allowQuery(self, message, protocol, address): - # Allow anything but empty queries - return len(message.queries) diff --git a/tools/buildbot/pylibs/twisted/names/srvconnect.py b/tools/buildbot/pylibs/twisted/names/srvconnect.py deleted file mode 100644 index 8120d95..0000000 --- a/tools/buildbot/pylibs/twisted/names/srvconnect.py +++ /dev/null @@ -1,185 +0,0 @@ -# -*- test-case-name: twisted.names.test.test_srvconnect -*- -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -import random - -from zope.interface import implements - -from twisted.internet import error, interfaces - -from twisted.names import client, dns -from twisted.names.error import DNSNameError - -class _SRVConnector_ClientFactoryWrapper: - def __init__(self, connector, wrappedFactory): - self.__connector = connector - self.__wrappedFactory = wrappedFactory - - def startedConnecting(self, connector): - self.__wrappedFactory.startedConnecting(self.__connector) - - def clientConnectionFailed(self, connector, reason): - self.__connector.connectionFailed(reason) - - def clientConnectionLost(self, connector, reason): - self.__connector.connectionLost(reason) - - def __getattr__(self, key): - return getattr(self.__wrappedFactory, key) - -class SRVConnector: - """A connector that looks up DNS SRV records. See RFC2782.""" - - implements(interfaces.IConnector) - - stopAfterDNS=0 - - def __init__(self, reactor, service, domain, factory, - protocol='tcp', connectFuncName='connectTCP', - connectFuncArgs=(), - connectFuncKwArgs={}, - ): - self.reactor = reactor - self.service = service - self.domain = domain - self.factory = factory - - self.protocol = protocol - self.connectFuncName = connectFuncName - self.connectFuncArgs = connectFuncArgs - self.connectFuncKwArgs = connectFuncKwArgs - - self.connector = None - self.servers = None - self.orderedServers = None # list of servers already used in this round - - def connect(self): - """Start connection to remote server.""" - self.factory.doStart() - self.factory.startedConnecting(self) - - if not self.servers: - if self.domain is None: - self.connectionFailed(error.DNSLookupError("Domain is not defined.")) - return - d = client.lookupService('_%s._%s.%s' % (self.service, - self.protocol, - self.domain)) - d.addCallbacks(self._cbGotServers, self._ebGotServers) - d.addCallback(lambda x, self=self: self._reallyConnect()) - d.addErrback(self.connectionFailed) - elif self.connector is None: - self._reallyConnect() - else: - self.connector.connect() - - def _ebGotServers(self, failure): - failure.trap(DNSNameError) - - # Some DNS servers reply with NXDOMAIN when in fact there are - # just no SRV records for that domain. Act as if we just got an - # empty response and use fallback. - - self.servers = [] - self.orderedServers = [] - - def _cbGotServers(self, (answers, auth, add)): - if len(answers) == 1 and answers[0].type == dns.SRV \ - and answers[0].payload \ - and answers[0].payload.target == dns.Name('.'): - # decidedly not available - raise error.DNSLookupError("Service %s not available for domain %s." - % (repr(self.service), repr(self.domain))) - - self.servers = [] - self.orderedServers = [] - for a in answers: - if a.type != dns.SRV or not a.payload: - continue - - self.orderedServers.append((a.payload.priority, a.payload.weight, - str(a.payload.target), a.payload.port)) - - def _serverCmp(self, a, b): - if a[0]!=b[0]: - return cmp(a[0], b[0]) - else: - return cmp(a[1], b[1]) - - def pickServer(self): - assert self.servers is not None - assert self.orderedServers is not None - - if not self.servers and not self.orderedServers: - # no SRV record, fall back.. - return self.domain, self.service - - if not self.servers and self.orderedServers: - # start new round - self.servers = self.orderedServers - self.orderedServers = [] - - assert self.servers - - self.servers.sort(self._serverCmp) - minPriority=self.servers[0][0] - - weightIndex = zip(xrange(len(self.servers)), [x[1] for x in self.servers - if x[0]==minPriority]) - weightSum = reduce(lambda x, y: (None, x[1]+y[1]), weightIndex, (None, 0))[1] - rand = random.randint(0, weightSum) - - for index, weight in weightIndex: - weightSum -= weight - if weightSum <= 0: - chosen = self.servers[index] - del self.servers[index] - self.orderedServers.append(chosen) - - p, w, host, port = chosen - return host, port - - raise RuntimeError, 'Impossible %s pickServer result.' % self.__class__.__name__ - - def _reallyConnect(self): - if self.stopAfterDNS: - self.stopAfterDNS=0 - return - - self.host, self.port = self.pickServer() - assert self.host is not None, 'Must have a host to connect to.' - assert self.port is not None, 'Must have a port to connect to.' - - connectFunc = getattr(self.reactor, self.connectFuncName) - self.connector=connectFunc( - self.host, self.port, - _SRVConnector_ClientFactoryWrapper(self, self.factory), - *self.connectFuncArgs, **self.connectFuncKwArgs) - - def stopConnecting(self): - """Stop attempting to connect.""" - if self.connector: - self.connector.stopConnecting() - else: - self.stopAfterDNS=1 - - def disconnect(self): - """Disconnect whatever our are state is.""" - if self.connector is not None: - self.connector.disconnect() - else: - self.stopConnecting() - - def getDestination(self): - assert self.connector - return self.connector.getDestination() - - def connectionFailed(self, reason): - self.factory.clientConnectionFailed(self, reason) - self.factory.doStop() - - def connectionLost(self, reason): - self.factory.clientConnectionLost(self, reason) - self.factory.doStop() - diff --git a/tools/buildbot/pylibs/twisted/names/tap.py b/tools/buildbot/pylibs/twisted/names/tap.py deleted file mode 100644 index f22f6c6..0000000 --- a/tools/buildbot/pylibs/twisted/names/tap.py +++ /dev/null @@ -1,119 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Domain Name Server -""" - -import os, traceback - -from twisted.python import usage -from twisted.names import dns -from twisted.application import internet, service - -from twisted.names import server -from twisted.names import authority -from twisted.names import secondary - -class Options(usage.Options): - optParameters = [ - ["interface", "i", "", "The interface to which to bind"], - ["port", "p", "53", "The port on which to listen"], - ["resolv-conf", None, None, - "Override location of resolv.conf (implies --recursive)"], - ["hosts-file", None, None, "Perform lookups with a hosts file"], - ] - - optFlags = [ - ["cache", "c", "Enable record caching"], - ["recursive", "r", "Perform recursive lookups"], - ["verbose", "v", "Log verbosely"], - ] - - zones = None - zonefiles = None - - def __init__(self): - usage.Options.__init__(self) - self['verbose'] = 0 - self.bindfiles = [] - self.zonefiles = [] - self.secondaries = [] - - - def opt_pyzone(self, filename): - """Specify the filename of a Python syntax zone definition""" - if not os.path.exists(filename): - raise usage.UsageError(filename + ": No such file") - self.zonefiles.append(filename) - - def opt_bindzone(self, filename): - """Specify the filename of a BIND9 syntax zone definition""" - if not os.path.exists(filename): - raise usage.UsageError(filename + ": No such file") - self.bindfiles.append(filename) - - - def opt_secondary(self, ip_domain): - """Act as secondary for the specified domain, performing - zone transfers from the specified IP (IP/domain) - """ - args = ip_domain.split('/', 1) - if len(args) != 2: - raise usage.UsageError("Argument must be of the form IP/domain") - self.secondaries.append((args[0], [args[1]])) - - def opt_verbose(self): - """Increment verbosity level""" - self['verbose'] += 1 - - - def postOptions(self): - if self['resolv-conf']: - self['recursive'] = True - - self.svcs = [] - self.zones = [] - for f in self.zonefiles: - try: - self.zones.append(authority.PySourceAuthority(f)) - except Exception, e: - traceback.print_exc() - raise usage.UsageError("Invalid syntax in " + f) - for f in self.bindfiles: - try: - self.zones.append(authority.BindAuthority(f)) - except Exception, e: - traceback.print_exc() - raise usage.UsageError("Invalid syntax in " + f) - for f in self.secondaries: - self.svcs.append(secondary.SecondaryAuthorityService(*f)) - self.zones.append(self.svcs[-1].getAuthority()) - try: - self['port'] = int(self['port']) - except ValueError: - raise usage.UsageError("Invalid port: %r" % (self['port'],)) - - -def makeService(config): - import client, cache, hosts - - ca, cl = [], [] - if config['cache']: - ca.append(cache.CacheResolver(verbose=config['verbose'])) - if config['recursive']: - cl.append(client.createResolver(resolvconf=config['resolv-conf'])) - if config['hosts-file']: - cl.append(hosts.Resolver(file=config['hosts-file'])) - - f = server.DNSServerFactory(config.zones, ca, cl, config['verbose']) - p = dns.DNSDatagramProtocol(f) - f.noisy = 0 - ret = service.MultiService() - for (klass, arg) in [(internet.TCPServer, f), (internet.UDPServer, p)]: - s = klass(config['port'], arg, interface=config['interface']) - s.setServiceParent(ret) - for svc in config.svcs: - svc.setServiceParent(ret) - return ret diff --git a/tools/buildbot/pylibs/twisted/names/test/__init__.py b/tools/buildbot/pylibs/twisted/names/test/__init__.py deleted file mode 100644 index f6b7e3a..0000000 --- a/tools/buildbot/pylibs/twisted/names/test/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"Tests for twisted.names" diff --git a/tools/buildbot/pylibs/twisted/names/test/test_cache.py b/tools/buildbot/pylibs/twisted/names/test/test_cache.py deleted file mode 100644 index 00253e9..0000000 --- a/tools/buildbot/pylibs/twisted/names/test/test_cache.py +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) 2006 Twisted Matrix Laboratories. -# See LICENSE for details. - -import time - -from twisted.trial import unittest - -from twisted.names import dns, cache - -class Caching(unittest.TestCase): - def testLookup(self): - c = cache.CacheResolver({ - dns.Query(name='example.com', type=dns.MX, cls=dns.IN): (time.time(), ([], [], []))}) - return c.lookupMailExchange('example.com').addCallback(self.assertEquals, ([], [], [])) diff --git a/tools/buildbot/pylibs/twisted/names/test/test_client.py b/tools/buildbot/pylibs/twisted/names/test/test_client.py deleted file mode 100644 index bc98dbd..0000000 --- a/tools/buildbot/pylibs/twisted/names/test/test_client.py +++ /dev/null @@ -1,307 +0,0 @@ -# -*- test-case-name: twisted.names.test.test_client -*- -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test cases for twisted.names.client -""" - -from twisted.names import client, dns -from twisted.names.error import DNSQueryTimeoutError -from twisted.trial import unittest -from twisted.names.common import ResolverBase -from twisted.internet import defer - -class FakeResolver(ResolverBase): - - def _lookup(self, name, cls, qtype, timeout): - """ - The getHostByNameTest does a different type of query that requires it - return an A record from an ALL_RECORDS lookup, so we accomodate that - here. - """ - if name == 'getHostByNameTest': - rr = dns.RRHeader(name=name, type=dns.A, cls=cls, ttl=60, - payload=dns.Record_A(address='127.0.0.1', ttl=60)) - else: - rr = dns.RRHeader(name=name, type=qtype, cls=cls, ttl=60) - - results = [rr] - authority = [] - addtional = [] - return defer.succeed((results, authority, addtional)) - - - -class StubDNSDatagramProtocol(object): - """ - L{dns.DNSDatagramProtocol}-alike. - - @ivar queries: A C{list} of tuples giving the arguments passed to - C{query} along with the L{defer.Deferred} which was returned from - the call. - """ - def __init__(self): - self.queries = [] - - - def query(self, address, queries, timeout=10, id=None): - """ - Record the given arguments and return a Deferred which will not be - called back by this code. - """ - result = defer.Deferred() - self.queries.append((address, queries, timeout, id, result)) - return result - - - -class ResolverTests(unittest.TestCase): - """ - Tests for L{client.Resolver}. - """ - def test_datagramQueryServerOrder(self): - """ - L{client.Resolver.queryUDP} should issue queries to its - L{dns.DNSDatagramProtocol} with server addresses taken from its own - C{servers} and C{dynServers} lists, proceeding through them in order - as L{DNSQueryTimeoutError}s occur. - """ - protocol = StubDNSDatagramProtocol() - protocol.transport = object() - - servers = [object(), object()] - dynServers = [object(), object()] - resolver = client.Resolver(servers=servers) - resolver.dynServers = dynServers - resolver.protocol = protocol - - expectedResult = object() - queryResult = resolver.queryUDP(None) - queryResult.addCallback(self.assertEqual, expectedResult) - - self.assertEqual(len(protocol.queries), 1) - self.assertIdentical(protocol.queries[0][0], servers[0]) - protocol.queries[0][-1].errback(DNSQueryTimeoutError(0)) - self.assertEqual(len(protocol.queries), 2) - self.assertIdentical(protocol.queries[1][0], servers[1]) - protocol.queries[1][-1].errback(DNSQueryTimeoutError(1)) - self.assertEqual(len(protocol.queries), 3) - self.assertIdentical(protocol.queries[2][0], dynServers[0]) - protocol.queries[2][-1].errback(DNSQueryTimeoutError(2)) - self.assertEqual(len(protocol.queries), 4) - self.assertIdentical(protocol.queries[3][0], dynServers[1]) - protocol.queries[3][-1].callback(expectedResult) - - return queryResult - - - -class ClientTestCase(unittest.TestCase): - - def setUp(self): - """ - Replace the resolver with a FakeResolver - """ - client.theResolver = FakeResolver() - self.hostname = 'example.com' - self.ghbntest = 'getHostByNameTest' - - def tearDown(self): - """ - By setting the resolver to None, it will be recreated next time a name - lookup is done. - """ - client.theResolver = None - - def checkResult(self, (results, authority, additional), qtype): - """ - Verify that the result is the same query type as what is expected. - """ - result = results[0] - self.assertEquals(str(result.name), self.hostname) - self.assertEquals(result.type, qtype) - - def checkGetHostByName(self, result): - """ - Test that the getHostByName query returns the 127.0.0.1 address. - """ - self.assertEquals(result, '127.0.0.1') - - def test_getHostByName(self): - """ - do a getHostByName of a value that should return 127.0.0.1. - """ - d = client.getHostByName(self.ghbntest) - d.addCallback(self.checkGetHostByName) - return d - - def test_lookupAddress(self): - """ - Do a lookup and test that the resolver will issue the correct type of - query type. We do this by checking that FakeResolver returns a result - record with the same query type as what we issued. - """ - d = client.lookupAddress(self.hostname) - d.addCallback(self.checkResult, dns.A) - return d - - def test_lookupIPV6Address(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupIPV6Address(self.hostname) - d.addCallback(self.checkResult, dns.AAAA) - return d - - def test_lookupAddress6(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupAddress6(self.hostname) - d.addCallback(self.checkResult, dns.A6) - return d - - def test_lookupNameservers(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupNameservers(self.hostname) - d.addCallback(self.checkResult, dns.NS) - return d - - def test_lookupCanonicalName(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupCanonicalName(self.hostname) - d.addCallback(self.checkResult, dns.CNAME) - return d - - def test_lookupAuthority(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupAuthority(self.hostname) - d.addCallback(self.checkResult, dns.SOA) - return d - - def test_lookupMailBox(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupMailBox(self.hostname) - d.addCallback(self.checkResult, dns.MB) - return d - - def test_lookupMailGroup(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupMailGroup(self.hostname) - d.addCallback(self.checkResult, dns.MG) - return d - - def test_lookupMailRename(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupMailRename(self.hostname) - d.addCallback(self.checkResult, dns.MR) - return d - - def test_lookupNull(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupNull(self.hostname) - d.addCallback(self.checkResult, dns.NULL) - return d - - def test_lookupWellKnownServices(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupWellKnownServices(self.hostname) - d.addCallback(self.checkResult, dns.WKS) - return d - - def test_lookupPointer(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupPointer(self.hostname) - d.addCallback(self.checkResult, dns.PTR) - return d - - def test_lookupHostInfo(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupHostInfo(self.hostname) - d.addCallback(self.checkResult, dns.HINFO) - return d - - def test_lookupMailboxInfo(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupMailboxInfo(self.hostname) - d.addCallback(self.checkResult, dns.MINFO) - return d - - def test_lookupMailExchange(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupMailExchange(self.hostname) - d.addCallback(self.checkResult, dns.MX) - return d - - def test_lookupText(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupText(self.hostname) - d.addCallback(self.checkResult, dns.TXT) - return d - - def test_lookupResponsibility(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupResponsibility(self.hostname) - d.addCallback(self.checkResult, dns.RP) - return d - - def test_lookupAFSDatabase(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupAFSDatabase(self.hostname) - d.addCallback(self.checkResult, dns.AFSDB) - return d - - def test_lookupService(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupService(self.hostname) - d.addCallback(self.checkResult, dns.SRV) - return d - - def test_lookupZone(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupZone(self.hostname) - d.addCallback(self.checkResult, dns.AXFR) - return d - - def test_lookupAllRecords(self): - """ - See L{test_lookupAddress} - """ - d = client.lookupAllRecords(self.hostname) - d.addCallback(self.checkResult, dns.ALL_RECORDS) - return d diff --git a/tools/buildbot/pylibs/twisted/names/test/test_dns.py b/tools/buildbot/pylibs/twisted/names/test/test_dns.py deleted file mode 100644 index a4a8cf4..0000000 --- a/tools/buildbot/pylibs/twisted/names/test/test_dns.py +++ /dev/null @@ -1,340 +0,0 @@ -# test-case-name: twisted.names.test.test_dns -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for twisted.names.dns. -""" - -try: - from cStringIO import StringIO -except ImportError: - from StringIO import StringIO - -import struct - -from twisted.internet import address, task -from twisted.internet.error import CannotListenError -from twisted.trial import unittest -from twisted.names import dns - -from twisted.test import proto_helpers - - - -class RoundtripDNSTestCase(unittest.TestCase): - """Encoding and then decoding various objects.""" - - names = ["example.org", "go-away.fish.tv", "23strikesback.net"] - - def testName(self): - for n in self.names: - # encode the name - f = StringIO() - dns.Name(n).encode(f) - - # decode the name - f.seek(0, 0) - result = dns.Name() - result.decode(f) - self.assertEquals(result.name, n) - - def testQuery(self): - for n in self.names: - for dnstype in range(1, 17): - for dnscls in range(1, 5): - # encode the query - f = StringIO() - dns.Query(n, dnstype, dnscls).encode(f) - - # decode the result - f.seek(0, 0) - result = dns.Query() - result.decode(f) - self.assertEquals(result.name.name, n) - self.assertEquals(result.type, dnstype) - self.assertEquals(result.cls, dnscls) - - def testRR(self): - # encode the RR - f = StringIO() - dns.RRHeader("test.org", 3, 4, 17).encode(f) - - # decode the result - f.seek(0, 0) - result = dns.RRHeader() - result.decode(f) - self.assertEquals(str(result.name), "test.org") - self.assertEquals(result.type, 3) - self.assertEquals(result.cls, 4) - self.assertEquals(result.ttl, 17) - - - def testResources(self): - names = ( - "this.are.test.name", - "will.compress.will.this.will.name.will.hopefully", - "test.CASE.preSErVatIOn.YeAH", - "a.s.h.o.r.t.c.a.s.e.t.o.t.e.s.t", - "singleton" - ) - for s in names: - f = StringIO() - dns.SimpleRecord(s).encode(f) - f.seek(0, 0) - result = dns.SimpleRecord() - result.decode(f) - self.assertEquals(str(result.name), s) - - def testHashable(self): - records = [ - dns.Record_NS, dns.Record_MD, dns.Record_MF, dns.Record_CNAME, - dns.Record_MB, dns.Record_MG, dns.Record_MR, dns.Record_PTR, - dns.Record_DNAME, dns.Record_A, dns.Record_SOA, dns.Record_NULL, - dns.Record_WKS, dns.Record_SRV, dns.Record_AFSDB, dns.Record_RP, - dns.Record_HINFO, dns.Record_MINFO, dns.Record_MX, dns.Record_TXT, - dns.Record_AAAA, dns.Record_A6 - ] - - for k in records: - k1, k2 = k(), k() - hk1 = hash(k1) - hk2 = hash(k2) - self.assertEquals(hk1, hk2, "%s != %s (for %s)" % (hk1,hk2,k)) - - - -class MessageTestCase(unittest.TestCase): - def testEmptyMessage(self): - """ - Test that a message which has been truncated causes an EOFError to - be raised when it is parsed. - """ - msg = dns.Message() - self.assertRaises(EOFError, msg.fromStr, '') - - - def testEmptyQuery(self): - """ - Test that bytes representing an empty query message can be decoded - as such. - """ - msg = dns.Message() - msg.fromStr( - '\x01\x00' # Message ID - '\x00' # answer bit, opCode nibble, auth bit, trunc bit, recursive bit - '\x00' # recursion bit, empty bit, empty bit, empty bit, response code nibble - '\x00\x00' # number of queries - '\x00\x00' # number of answers - '\x00\x00' # number of authorities - '\x00\x00' # number of additionals - ) - self.assertEquals(msg.id, 256) - self.failIf(msg.answer, "Message was not supposed to be an answer.") - self.assertEquals(msg.opCode, dns.OP_QUERY) - self.failIf(msg.auth, "Message was not supposed to be authoritative.") - self.failIf(msg.trunc, "Message was not supposed to be truncated.") - self.assertEquals(msg.queries, []) - self.assertEquals(msg.answers, []) - self.assertEquals(msg.authority, []) - self.assertEquals(msg.additional, []) - - - def testNULL(self): - bytes = ''.join([chr(i) for i in range(256)]) - rec = dns.Record_NULL(bytes) - rr = dns.RRHeader('testname', dns.NULL, payload=rec) - msg1 = dns.Message() - msg1.answers.append(rr) - s = StringIO() - msg1.encode(s) - s.seek(0, 0) - msg2 = dns.Message() - msg2.decode(s) - - self.failUnless(isinstance(msg2.answers[0].payload, dns.Record_NULL)) - self.assertEquals(msg2.answers[0].payload.payload, bytes) - - - -class TestController(object): - """ - Pretend to be a DNS query processor for a DNSDatagramProtocol. - - @ivar messages: the list of received messages. - @type messages: C{list} of (msg, protocol, address) - """ - - def __init__(self): - """ - Initialize the controller: create a list of messages. - """ - self.messages = [] - - - def messageReceived(self, msg, proto, addr): - """ - Save the message so that it can be checked during the tests. - """ - self.messages.append((msg, proto, addr)) - - - -class DatagramProtocolTestCase(unittest.TestCase): - """ - Test various aspects of L{dns.DNSDatagramProtocol}. - """ - - def setUp(self): - """ - Create a L{dns.DNSDatagramProtocol} with a deterministic clock. - """ - self.clock = task.Clock() - self.controller = TestController() - self.proto = dns.DNSDatagramProtocol(self.controller) - transport = proto_helpers.FakeDatagramTransport() - self.proto.makeConnection(transport) - self.proto.callLater = self.clock.callLater - - - def test_truncatedPacket(self): - """ - Test that when a short datagram is received, datagramReceived does - not raise an exception while processing it. - """ - self.proto.datagramReceived('', - address.IPv4Address('UDP', '127.0.0.1', 12345)) - self.assertEquals(self.controller.messages, []) - - - def test_simpleQuery(self): - """ - Test content received after a query. - """ - d = self.proto.query(('127.0.0.1', 21345), [dns.Query('foo')]) - self.assertEquals(len(self.proto.liveMessages.keys()), 1) - m = dns.Message() - m.id = self.proto.liveMessages.items()[0][0] - m.answers = [dns.RRHeader(payload=dns.Record_A(address='1.2.3.4'))] - called = False - def cb(result): - self.assertEquals(result.answers[0].payload.dottedQuad(), '1.2.3.4') - d.addCallback(cb) - self.proto.datagramReceived(m.toStr(), ('127.0.0.1', 21345)) - return d - - - def test_queryTimeout(self): - """ - Test that query timeouts after some seconds. - """ - d = self.proto.query(('127.0.0.1', 21345), [dns.Query('foo')]) - self.assertEquals(len(self.proto.liveMessages), 1) - self.clock.advance(10) - self.assertFailure(d, dns.DNSQueryTimeoutError) - self.assertEquals(len(self.proto.liveMessages), 0) - return d - - - def test_writeError(self): - """ - Exceptions raised by the transport's write method should be turned into - C{Failure}s passed to errbacks of the C{Deferred} returned by - L{DNSDatagramProtocol.query}. - """ - def writeError(message, addr): - raise RuntimeError("bar") - self.proto.transport.write = writeError - - d = self.proto.query(('127.0.0.1', 21345), [dns.Query('foo')]) - return self.assertFailure(d, RuntimeError) - - - def test_listenError(self): - """ - Exception L{CannotListenError} raised by C{listenUDP} should be turned - into a C{Failure} passed to errback of the C{Deferred} returned by - L{DNSDatagramProtocol.query}. - """ - def startListeningError(): - raise CannotListenError(None, None, None) - self.proto.startListening = startListeningError - # Clean up transport so that the protocol calls startListening again - self.proto.transport = None - - d = self.proto.query(('127.0.0.1', 21345), [dns.Query('foo')]) - return self.assertFailure(d, CannotListenError) - - - -class TestTCPController(TestController): - """ - Pretend to be a DNS query processor for a DNSProtocol. - """ - def connectionMade(self, proto): - pass - - - -class DNSProtocolTestCase(unittest.TestCase): - """ - Test various aspects of L{dns.DNSProtocol}. - """ - - def setUp(self): - """ - Create a L{dns.DNSProtocol} with a deterministic clock. - """ - self.clock = task.Clock() - controller = TestTCPController() - self.proto = dns.DNSProtocol(controller) - self.proto.makeConnection(proto_helpers.StringTransport()) - self.proto.callLater = self.clock.callLater - - - def test_queryTimeout(self): - """ - Test that query timeouts after some seconds. - """ - d = self.proto.query([dns.Query('foo')]) - self.assertEquals(len(self.proto.liveMessages), 1) - self.clock.advance(60) - self.assertFailure(d, dns.DNSQueryTimeoutError) - self.assertEquals(len(self.proto.liveMessages), 0) - return d - - - def test_simpleQuery(self): - """ - Test content received after a query. - """ - d = self.proto.query([dns.Query('foo')]) - self.assertEquals(len(self.proto.liveMessages.keys()), 1) - m = dns.Message() - m.id = self.proto.liveMessages.items()[0][0] - m.answers = [dns.RRHeader(payload=dns.Record_A(address='1.2.3.4'))] - called = False - def cb(result): - self.assertEquals(result.answers[0].payload.dottedQuad(), '1.2.3.4') - d.addCallback(cb) - s = m.toStr() - s = struct.pack('!H', len(s)) + s - self.proto.dataReceived(s) - return d - - - def test_writeError(self): - """ - Exceptions raised by the transport's write method should be turned into - C{Failure}s passed to errbacks of the C{Deferred} returned by - L{DNSProtocol.query}. - """ - def writeError(message): - raise RuntimeError("bar") - self.proto.transport.write = writeError - - d = self.proto.query([dns.Query('foo')]) - return self.assertFailure(d, RuntimeError) - - - diff --git a/tools/buildbot/pylibs/twisted/names/test/test_names.py b/tools/buildbot/pylibs/twisted/names/test/test_names.py deleted file mode 100644 index 6446ebf..0000000 --- a/tools/buildbot/pylibs/twisted/names/test/test_names.py +++ /dev/null @@ -1,712 +0,0 @@ -# -*- test-case-name: twisted.names.test.test_names -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test cases for twisted.names. -""" -from __future__ import nested_scopes - -import socket, operator, copy - -from twisted.trial import unittest - -from twisted.internet import reactor, defer, error -from twisted.internet.defer import succeed -from twisted.names import client, server, common, authority, hosts, dns -from twisted.python import failure -from twisted.names.error import DNSFormatError, DNSServerError, DNSNameError -from twisted.names.error import DNSNotImplementedError, DNSQueryRefusedError -from twisted.names.error import DNSUnknownError -from twisted.names.dns import EFORMAT, ESERVER, ENAME, ENOTIMP, EREFUSED -from twisted.names.dns import Message -from twisted.names.client import Resolver - - -def justPayload(results): - return [r.payload for r in results[0]] - -class NoFileAuthority(authority.FileAuthority): - def __init__(self, soa, records): - # Yes, skip FileAuthority - common.ResolverBase.__init__(self) - self.soa, self.records = soa, records - - -soa_record = dns.Record_SOA( - mname = 'test-domain.com', - rname = 'root.test-domain.com', - serial = 100, - refresh = 1234, - minimum = 7654, - expire = 19283784, - retry = 15, - ttl=1 - ) - -reverse_soa = dns.Record_SOA( - mname = '93.84.28.in-addr.arpa', - rname = '93.84.28.in-addr.arpa', - serial = 120, - refresh = 54321, - minimum = 382, - expire = 11193983, - retry = 30, - ttl=3 - ) - -my_soa = dns.Record_SOA( - mname = 'my-domain.com', - rname = 'postmaster.test-domain.com', - serial = 130, - refresh = 12345, - minimum = 1, - expire = 999999, - retry = 100, - ) - -test_domain_com = NoFileAuthority( - soa = ('test-domain.com', soa_record), - records = { - 'test-domain.com': [ - soa_record, - dns.Record_A('127.0.0.1'), - dns.Record_NS('39.28.189.39'), - dns.Record_MX(10, 'host.test-domain.com'), - dns.Record_HINFO(os='Linux', cpu='A Fast One, Dontcha know'), - dns.Record_CNAME('canonical.name.com'), - dns.Record_MB('mailbox.test-domain.com'), - dns.Record_MG('mail.group.someplace'), - dns.Record_TXT('A First piece of Text', 'a SecoNd piece'), - dns.Record_A6(0, 'ABCD::4321', ''), - dns.Record_A6(12, '0:0069::0', 'some.network.tld'), - dns.Record_A6(8, '0:5634:1294:AFCB:56AC:48EF:34C3:01FF', 'tra.la.la.net'), - dns.Record_TXT('Some more text, haha! Yes. \0 Still here?'), - dns.Record_MR('mail.redirect.or.whatever'), - dns.Record_MINFO(rmailbx='r mail box', emailbx='e mail box'), - dns.Record_AFSDB(subtype=1, hostname='afsdb.test-domain.com'), - dns.Record_RP(mbox='whatever.i.dunno', txt='some.more.text'), - dns.Record_WKS('12.54.78.12', socket.IPPROTO_TCP, '\x12\x01\x16\xfe\xc1\x00\x01'), - dns.Record_AAAA('AF43:5634:1294:AFCB:56AC:48EF:34C3:01FF')], - 'http.tcp.test-domain.com': [ - dns.Record_SRV(257, 16383, 43690, 'some.other.place.fool') - ], - 'host.test-domain.com': [ - dns.Record_A('123.242.1.5'), - dns.Record_A('0.255.0.255'), - ], - 'host-two.test-domain.com': [ -# -# Python bug -# dns.Record_A('255.255.255.255'), -# - dns.Record_A('255.255.255.254'), - dns.Record_A('0.0.0.0') - ], - 'cname.test-domain.com': [ - dns.Record_CNAME('test-domain.com') - ], - 'anothertest-domain.com': [ - dns.Record_A('1.2.3.4')], - } -) - -reverse_domain = NoFileAuthority( - soa = ('93.84.28.in-addr.arpa', reverse_soa), - records = { - '123.93.84.28.in-addr.arpa': [ - dns.Record_PTR('test.host-reverse.lookup.com'), - reverse_soa - ] - } -) - - -my_domain_com = NoFileAuthority( - soa = ('my-domain.com', my_soa), - records = { - 'my-domain.com': [ - my_soa, - dns.Record_A('1.2.3.4', ttl='1S'), - dns.Record_NS('ns1.domain', ttl='2M'), - dns.Record_NS('ns2.domain', ttl='3H'), - dns.Record_SRV(257, 16383, 43690, 'some.other.place.fool', ttl='4D') - ] - } - ) - - -class ServerDNSTestCase(unittest.TestCase): - """ - Test cases for DNS server and client. - """ - - def setUp(self): - self.factory = server.DNSServerFactory([ - test_domain_com, reverse_domain, my_domain_com - ], verbose=2) - - p = dns.DNSDatagramProtocol(self.factory) - - while 1: - self.listenerTCP = reactor.listenTCP(0, self.factory, interface="127.0.0.1") - port = self.listenerTCP.getHost().port - - try: - self.listenerUDP = reactor.listenUDP(port, p, interface="127.0.0.1") - except error.CannotListenError: - self.listenerTCP.stopListening() - else: - break - - self.resolver = client.Resolver(servers=[('127.0.0.1', port)]) - - - def tearDown(self): - """ - Asynchronously disconnect listenerTCP, listenerUDP and resolver. - """ - d1 = self.listenerTCP.loseConnection() - d2 = defer.maybeDeferred(self.listenerUDP.stopListening) - d = defer.gatherResults([d1, d2]) - def disconnectTransport(ignored): - if getattr(self.resolver.protocol, 'transport', None) is not None: - return self.resolver.protocol.transport.stopListening() - d.addCallback(disconnectTransport) - d.addCallback(lambda x : self.failUnless( - self.listenerUDP.disconnected - and self.listenerTCP.disconnected)) - return d - - - def namesTest(self, d, r): - self.response = None - def setDone(response): - self.response = response - - def checkResults(ignored): - if isinstance(self.response, failure.Failure): - raise self.response - results = justPayload(self.response) - assert len(results) == len(r), "%s != %s" % (map(str, results), map(str, r)) - for rec in results: - assert rec in r, "%s not in %s" % (rec, map(str, r)) - - d.addBoth(setDone) - d.addCallback(checkResults) - return d - - def testAddressRecord1(self): - """Test simple DNS 'A' record queries""" - return self.namesTest( - self.resolver.lookupAddress('test-domain.com'), - [dns.Record_A('127.0.0.1', ttl=19283784)] - ) - - - def testAddressRecord2(self): - """Test DNS 'A' record queries with multiple answers""" - return self.namesTest( - self.resolver.lookupAddress('host.test-domain.com'), - [dns.Record_A('123.242.1.5', ttl=19283784), dns.Record_A('0.255.0.255', ttl=19283784)] - ) - - - def testAdressRecord3(self): - """Test DNS 'A' record queries with edge cases""" - return self.namesTest( - self.resolver.lookupAddress('host-two.test-domain.com'), - [dns.Record_A('255.255.255.254', ttl=19283784), dns.Record_A('0.0.0.0', ttl=19283784)] - ) - - def testAuthority(self): - """Test DNS 'SOA' record queries""" - return self.namesTest( - self.resolver.lookupAuthority('test-domain.com'), - [soa_record] - ) - - - def testMailExchangeRecord(self): - """Test DNS 'MX' record queries""" - return self.namesTest( - self.resolver.lookupMailExchange('test-domain.com'), - [dns.Record_MX(10, 'host.test-domain.com', ttl=19283784)] - ) - - - def testNameserver(self): - """Test DNS 'NS' record queries""" - return self.namesTest( - self.resolver.lookupNameservers('test-domain.com'), - [dns.Record_NS('39.28.189.39', ttl=19283784)] - ) - - - def testHINFO(self): - """Test DNS 'HINFO' record queries""" - return self.namesTest( - self.resolver.lookupHostInfo('test-domain.com'), - [dns.Record_HINFO(os='Linux', cpu='A Fast One, Dontcha know', ttl=19283784)] - ) - - def testPTR(self): - """Test DNS 'PTR' record queries""" - return self.namesTest( - self.resolver.lookupPointer('123.93.84.28.in-addr.arpa'), - [dns.Record_PTR('test.host-reverse.lookup.com', ttl=11193983)] - ) - - - def testCNAME(self): - """Test DNS 'CNAME' record queries""" - return self.namesTest( - self.resolver.lookupCanonicalName('test-domain.com'), - [dns.Record_CNAME('canonical.name.com', ttl=19283784)] - ) - - def testCNAMEAdditional(self): - """Test additional processing for CNAME records""" - return self.namesTest( - self.resolver.lookupAddress('cname.test-domain.com'), - [dns.Record_CNAME('test-domain.com', ttl=19283784), dns.Record_A('127.0.0.1', ttl=19283784)] - ) - - def testMB(self): - """Test DNS 'MB' record queries""" - return self.namesTest( - self.resolver.lookupMailBox('test-domain.com'), - [dns.Record_MB('mailbox.test-domain.com', ttl=19283784)] - ) - - - def testMG(self): - """Test DNS 'MG' record queries""" - return self.namesTest( - self.resolver.lookupMailGroup('test-domain.com'), - [dns.Record_MG('mail.group.someplace', ttl=19283784)] - ) - - - def testMR(self): - """Test DNS 'MR' record queries""" - return self.namesTest( - self.resolver.lookupMailRename('test-domain.com'), - [dns.Record_MR('mail.redirect.or.whatever', ttl=19283784)] - ) - - - def testMINFO(self): - """Test DNS 'MINFO' record queries""" - return self.namesTest( - self.resolver.lookupMailboxInfo('test-domain.com'), - [dns.Record_MINFO(rmailbx='r mail box', emailbx='e mail box', ttl=19283784)] - ) - - - def testSRV(self): - """Test DNS 'SRV' record queries""" - return self.namesTest( - self.resolver.lookupService('http.tcp.test-domain.com'), - [dns.Record_SRV(257, 16383, 43690, 'some.other.place.fool', ttl=19283784)] - ) - - def testAFSDB(self): - """Test DNS 'AFSDB' record queries""" - return self.namesTest( - self.resolver.lookupAFSDatabase('test-domain.com'), - [dns.Record_AFSDB(subtype=1, hostname='afsdb.test-domain.com', ttl=19283784)] - ) - - - def testRP(self): - """Test DNS 'RP' record queries""" - return self.namesTest( - self.resolver.lookupResponsibility('test-domain.com'), - [dns.Record_RP(mbox='whatever.i.dunno', txt='some.more.text', ttl=19283784)] - ) - - - def testTXT(self): - """Test DNS 'TXT' record queries""" - return self.namesTest( - self.resolver.lookupText('test-domain.com'), - [dns.Record_TXT('A First piece of Text', 'a SecoNd piece', ttl=19283784), - dns.Record_TXT('Some more text, haha! Yes. \0 Still here?', ttl=19283784)] - ) - - - def testWKS(self): - """Test DNS 'WKS' record queries""" - return self.namesTest( - self.resolver.lookupWellKnownServices('test-domain.com'), - [dns.Record_WKS('12.54.78.12', socket.IPPROTO_TCP, '\x12\x01\x16\xfe\xc1\x00\x01', ttl=19283784)] - ) - - - def testSomeRecordsWithTTLs(self): - result_soa = copy.copy(my_soa) - result_soa.ttl = my_soa.expire - return self.namesTest( - self.resolver.lookupAllRecords('my-domain.com'), - [result_soa, - dns.Record_A('1.2.3.4', ttl='1S'), - dns.Record_NS('ns1.domain', ttl='2M'), - dns.Record_NS('ns2.domain', ttl='3H'), - dns.Record_SRV(257, 16383, 43690, 'some.other.place.fool', ttl='4D')] - ) - - - def testAAAA(self): - """Test DNS 'AAAA' record queries (IPv6)""" - return self.namesTest( - self.resolver.lookupIPV6Address('test-domain.com'), - [dns.Record_AAAA('AF43:5634:1294:AFCB:56AC:48EF:34C3:01FF', ttl=19283784)] - ) - - def testA6(self): - """Test DNS 'A6' record queries (IPv6)""" - return self.namesTest( - self.resolver.lookupAddress6('test-domain.com'), - [dns.Record_A6(0, 'ABCD::4321', '', ttl=19283784), - dns.Record_A6(12, '0:0069::0', 'some.network.tld', ttl=19283784), - dns.Record_A6(8, '0:5634:1294:AFCB:56AC:48EF:34C3:01FF', 'tra.la.la.net', ttl=19283784)] - ) - - - def testZoneTransfer(self): - """Test DNS 'AXFR' queries (Zone transfer)""" - default_ttl = soa_record.expire - results = [copy.copy(r) for r in reduce(operator.add, test_domain_com.records.values())] - for r in results: - if r.ttl is None: - r.ttl = default_ttl - return self.namesTest( - self.resolver.lookupZone('test-domain.com').addCallback(lambda r: (r[0][:-1],)), - results - ) - - def testSimilarZonesDontInterfere(self): - """Tests that unrelated zones don't mess with each other.""" - return self.namesTest( - self.resolver.lookupAddress("anothertest-domain.com"), - [dns.Record_A('1.2.3.4', ttl=19283784)] - ) - - - -class DNSServerFactoryTests(unittest.TestCase): - """ - Tests for L{server.DNSServerFactory}. - """ - def _messageReceivedTest(self, methodName, message): - """ - Assert that the named method is called with the given message when - it is passed to L{DNSServerFactory.messageReceived}. - """ - # Make it appear to have some queries so that - # DNSServerFactory.allowQuery allows it. - message.queries = [None] - - receivedMessages = [] - def fakeHandler(message, protocol, address): - receivedMessages.append((message, protocol, address)) - - class FakeProtocol(object): - def writeMessage(self, message): - pass - - protocol = FakeProtocol() - factory = server.DNSServerFactory(None) - setattr(factory, methodName, fakeHandler) - factory.messageReceived(message, protocol) - self.assertEqual(receivedMessages, [(message, protocol, None)]) - - - def test_notifyMessageReceived(self): - """ - L{DNSServerFactory.messageReceived} passes messages with an opcode - of C{OP_NOTIFY} on to L{DNSServerFactory.handleNotify}. - """ - # RFC 1996, section 4.5 - opCode = 4 - self._messageReceivedTest('handleNotify', Message(opCode=opCode)) - - - def test_updateMessageReceived(self): - """ - L{DNSServerFactory.messageReceived} passes messages with an opcode - of C{OP_UPDATE} on to L{DNSServerFactory.handleOther}. - - This may change if the implementation ever covers update messages. - """ - # RFC 2136, section 1.3 - opCode = 5 - self._messageReceivedTest('handleOther', Message(opCode=opCode)) - - - -class HelperTestCase(unittest.TestCase): - def testSerialGenerator(self): - f = self.mktemp() - a = authority.getSerial(f) - for i in range(20): - b = authority.getSerial(f) - self.failUnless(a < b) - a = b - - -class AXFRTest(unittest.TestCase): - def setUp(self): - self.results = None - self.d = defer.Deferred() - self.d.addCallback(self._gotResults) - self.controller = client.AXFRController('fooby.com', self.d) - - self.soa = dns.RRHeader(name='fooby.com', type=dns.SOA, cls=dns.IN, ttl=86400, auth=False, - payload=dns.Record_SOA(mname='fooby.com', - rname='hooj.fooby.com', - serial=100, - refresh=200, - retry=300, - expire=400, - minimum=500, - ttl=600)) - - self.records = [ - self.soa, - dns.RRHeader(name='fooby.com', type=dns.NS, cls=dns.IN, ttl=700, auth=False, - payload=dns.Record_NS(name='ns.twistedmatrix.com', ttl=700)), - - dns.RRHeader(name='fooby.com', type=dns.MX, cls=dns.IN, ttl=700, auth=False, - payload=dns.Record_MX(preference=10, exchange='mail.mv3d.com', ttl=700)), - - dns.RRHeader(name='fooby.com', type=dns.A, cls=dns.IN, ttl=700, auth=False, - payload=dns.Record_A(address='64.123.27.105', ttl=700)), - self.soa - ] - - def _makeMessage(self): - # hooray they all have the same message format - return dns.Message(id=999, answer=1, opCode=0, recDes=0, recAv=1, auth=1, rCode=0, trunc=0, maxSize=0) - - def testBindAndTNamesStyle(self): - # Bind style = One big single message - m = self._makeMessage() - m.queries = [dns.Query('fooby.com', dns.AXFR, dns.IN)] - m.answers = self.records - self.controller.messageReceived(m, None) - self.assertEquals(self.results, self.records) - - def _gotResults(self, result): - self.results = result - - def testDJBStyle(self): - # DJB style = message per record - records = self.records[:] - while records: - m = self._makeMessage() - m.queries = [] # DJB *doesn't* specify any queries.. hmm.. - m.answers = [records.pop(0)] - self.controller.messageReceived(m, None) - self.assertEquals(self.results, self.records) - -class HostsTestCase(unittest.TestCase): - def setUp(self): - f = open('EtcHosts', 'w') - f.write(''' -1.1.1.1 EXAMPLE EXAMPLE.EXAMPLETHING -1.1.1.2 HOOJY -::1 ip6thingy -''') - f.close() - self.resolver = hosts.Resolver('EtcHosts') - - def testGetHostByName(self): - data = [('EXAMPLE', '1.1.1.1'), - ('EXAMPLE.EXAMPLETHING', '1.1.1.1'), - ('HOOJY', '1.1.1.2'), - ] - ds = [self.resolver.getHostByName(n).addCallback(self.assertEqual, ip) - for n, ip in data] - return defer.gatherResults(ds) - - def testLookupAddress(self): - d = self.resolver.lookupAddress('HOOJY') - d.addCallback(lambda x: self.assertEqual(x[0][0].payload.dottedQuad(), - '1.1.1.2')) - return d - - def testIPv6(self): - d = self.resolver.lookupIPV6Address('ip6thingy') - d.addCallback(self.assertEqual, '::1') - return d - - testIPv6.skip = 'IPv6 support is not in our hosts resolver yet' - - def testNotImplemented(self): - return self.assertFailure(self.resolver.lookupMailExchange('EXAMPLE'), - NotImplementedError) - - def testQuery(self): - d = self.resolver.query(dns.Query('EXAMPLE')) - d.addCallback(lambda x: self.assertEqual(x[0][0].payload.dottedQuad(), - '1.1.1.1')) - return d - - def testNotFound(self): - return self.assertFailure(self.resolver.lookupAddress('foueoa'), - dns.DomainError) - - -class FakeDNSDatagramProtocol(object): - transport = object() - - def __init__(self): - self.queries = [] - - def query(self, address, queries, timeout=10, id=None): - self.queries.append((address, queries, timeout, id)) - return defer.fail(dns.DNSQueryTimeoutError(queries)) - - def removeResend(self, id): - # Ignore this for the time being. - pass - -class RetryLogic(unittest.TestCase): - testServers = [ - '1.2.3.4', - '4.3.2.1', - 'a.b.c.d', - 'z.y.x.w'] - - def testRoundRobinBackoff(self): - addrs = [(x, 53) for x in self.testServers] - r = client.Resolver(resolv=None, servers=addrs) - r.protocol = proto = FakeDNSDatagramProtocol() - return r.lookupAddress("foo.example.com" - ).addCallback(self._cbRoundRobinBackoff - ).addErrback(self._ebRoundRobinBackoff, proto - ) - - def _cbRoundRobinBackoff(self, result): - raise unittest.FailTest("Lookup address succeeded, should have timed out") - - def _ebRoundRobinBackoff(self, failure, fakeProto): - failure.trap(defer.TimeoutError) - - # Assert that each server is tried with a particular timeout - # before the timeout is increased and the attempts are repeated. - - for t in (1, 3, 11, 45): - tries = fakeProto.queries[:len(self.testServers)] - del fakeProto.queries[:len(self.testServers)] - - tries.sort() - expected = list(self.testServers) - expected.sort() - - for ((addr, query, timeout, id), expectedAddr) in zip(tries, expected): - self.assertEquals(addr, (expectedAddr, 53)) - self.assertEquals(timeout, t) - - self.failIf(fakeProto.queries) - -class ResolvConfHandling(unittest.TestCase): - def testMissing(self): - resolvConf = self.mktemp() - r = client.Resolver(resolv=resolvConf) - self.assertEquals(r.dynServers, [('127.0.0.1', 53)]) - r._parseCall.cancel() - - def testEmpty(self): - resolvConf = self.mktemp() - fObj = file(resolvConf, 'w') - fObj.close() - r = client.Resolver(resolv=resolvConf) - self.assertEquals(r.dynServers, [('127.0.0.1', 53)]) - r._parseCall.cancel() - - - -class FilterAnswersTests(unittest.TestCase): - """ - Test L{twisted.names.client.Resolver.filterAnswers}'s handling of various - error conditions it might encounter. - """ - def setUp(self): - # Create a resolver pointed at an invalid server - we won't be hitting - # the network in any of these tests. - self.resolver = Resolver(servers=[('0.0.0.0', 0)]) - - - def test_truncatedMessage(self): - """ - Test that a truncated message results in an equivalent request made via - TCP. - """ - m = Message(trunc=True) - m.addQuery('example.com') - - def queryTCP(queries): - self.assertEqual(queries, m.queries) - response = Message() - response.answers = ['answer'] - response.authority = ['authority'] - response.additional = ['additional'] - return succeed(response) - self.resolver.queryTCP = queryTCP - d = self.resolver.filterAnswers(m) - d.addCallback( - self.assertEqual, (['answer'], ['authority'], ['additional'])) - return d - - - def _rcodeTest(self, rcode, exc): - m = Message(rCode=rcode) - err = self.resolver.filterAnswers(m) - err.trap(exc) - - - def test_formatError(self): - """ - Test that a message with a result code of C{EFORMAT} results in a - failure wrapped around L{DNSFormatError}. - """ - return self._rcodeTest(EFORMAT, DNSFormatError) - - - def test_serverError(self): - """ - Like L{test_formatError} but for C{ESERVER}/L{DNSServerError}. - """ - return self._rcodeTest(ESERVER, DNSServerError) - - - def test_nameError(self): - """ - Like L{test_formatError} but for C{ENAME}/L{DNSNameError}. - """ - return self._rcodeTest(ENAME, DNSNameError) - - - def test_notImplementedError(self): - """ - Like L{test_formatError} but for C{ENOTIMP}/L{DNSNotImplementedError}. - """ - return self._rcodeTest(ENOTIMP, DNSNotImplementedError) - - - def test_refusedError(self): - """ - Like L{test_formatError} but for C{EREFUSED}/L{DNSQueryRefusedError}. - """ - return self._rcodeTest(EREFUSED, DNSQueryRefusedError) - - - def test_refusedErrorUnknown(self): - """ - Like L{test_formatError} but for an unrecognized error code and - L{DNSUnknownError}. - """ - return self._rcodeTest(EREFUSED + 1, DNSUnknownError) diff --git a/tools/buildbot/pylibs/twisted/names/test/test_rootresolve.py b/tools/buildbot/pylibs/twisted/names/test/test_rootresolve.py deleted file mode 100644 index 6a587d4..0000000 --- a/tools/buildbot/pylibs/twisted/names/test/test_rootresolve.py +++ /dev/null @@ -1,13 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Test cases for Twisted.names' root resolver. -""" - -from twisted.trial import unittest - -class RootResolverTestCase(unittest.TestCase): - pass diff --git a/tools/buildbot/pylibs/twisted/names/test/test_srvconnect.py b/tools/buildbot/pylibs/twisted/names/test/test_srvconnect.py deleted file mode 100644 index b6aa5d8..0000000 --- a/tools/buildbot/pylibs/twisted/names/test/test_srvconnect.py +++ /dev/null @@ -1,140 +0,0 @@ -# Copyright (c) 2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test cases for L{twisted.names.srvconnect}. -""" - -from twisted.internet import defer, protocol -from twisted.names import client, dns, srvconnect -from twisted.names.common import ResolverBase -from twisted.names.error import DNSNameError -from twisted.internet.error import DNSLookupError -from twisted.trial import unittest - -class FakeResolver(ResolverBase): - """ - Resolver that only gives out one given result. - - Either L{results} or L{failure} must be set and will be used for - the return value of L{_lookup} - - @ivar results: List of L{dns.RRHeader} for the desired result. - @type results: C{list} - @ivar failure: Failure with an exception from L{twisted.names.error}. - @type failure: L{Failure} - """ - - def __init__(self, results=None, failure=None): - self.results = results - self.failure = failure - - def _lookup(self, name, cls, qtype, timeout): - """ - Return the result or failure on lookup. - """ - if self.results is not None: - return defer.succeed((self.results, [], [])) - else: - return defer.fail(self.failure) - -class DummyReactor(object): - """ - Dummy reactor with fake connectTCP that stores the passed parameters. - """ - def __init__(self): - self.host = None - self.port = None - self.factory = None - - def connectTCP(self, host, port, factory, timeout=30, bindaddress=None): - self.host = host - self.port = port - self.factory = factory - -class DummyFactory(protocol.ClientFactory): - """ - Dummy client factory that stores the reason of connection failure. - """ - def __init__(self): - self.reason = None - - def clientConnectionFailed(self, connector, reason): - self.reason = reason - -class SRVConnectorTest(unittest.TestCase): - - def setUp(self): - client.theResolver = FakeResolver() - self.reactor = DummyReactor() - self.factory = DummyFactory() - self.connector = srvconnect.SRVConnector(self.reactor, 'xmpp-server', - 'example.org', self.factory) - - def tearDown(self): - client.theResolver = None - - def test_SRVPresent(self): - """ - Test connectTCP gets called with the address from the SRV record. - """ - payload = dns.Record_SRV(port=6269, target='host.example.org', ttl=60) - client.theResolver.results = [dns.RRHeader(name='example.org', - type=dns.SRV, - cls=dns.IN, ttl=60, - payload=payload)] - self.connector.connect() - - self.assertIdentical(None, self.factory.reason) - self.assertEqual('host.example.org', self.reactor.host) - self.assertEqual(6269, self.reactor.port) - - def test_SRVNotPresent(self): - """ - Test connectTCP gets called with fallback parameters on NXDOMAIN. - """ - client.theResolver.failure = DNSNameError('example.org') - self.connector.connect() - - self.assertIdentical(None, self.factory.reason) - self.assertEqual('example.org', self.reactor.host) - self.assertEqual('xmpp-server', self.reactor.port) - - def test_SRVNoResult(self): - """ - Test connectTCP gets called with fallback parameters on empty result. - """ - client.theResolver.results = [] - self.connector.connect() - - self.assertIdentical(None, self.factory.reason) - self.assertEqual('example.org', self.reactor.host) - self.assertEqual('xmpp-server', self.reactor.port) - - def test_SRVBadResult(self): - """ - Test connectTCP gets called with fallback parameters on bad result. - """ - client.theResolver.results = [dns.RRHeader(name='example.org', - type=dns.CNAME, - cls=dns.IN, ttl=60, - payload=None)] - self.connector.connect() - - self.assertIdentical(None, self.factory.reason) - self.assertEqual('example.org', self.reactor.host) - self.assertEqual('xmpp-server', self.reactor.port) - - def test_SRVNoService(self): - """ - Test that connecting fails when no service is present. - """ - payload = dns.Record_SRV(port=5269, target='.', ttl=60) - client.theResolver.results = [dns.RRHeader(name='example.org', - type=dns.SRV, - cls=dns.IN, ttl=60, - payload=payload)] - self.connector.connect() - - self.assertNotIdentical(None, self.factory.reason) - self.factory.reason.trap(DNSLookupError) diff --git a/tools/buildbot/pylibs/twisted/names/topfiles/NEWS b/tools/buildbot/pylibs/twisted/names/topfiles/NEWS deleted file mode 100644 index 1955441..0000000 --- a/tools/buildbot/pylibs/twisted/names/topfiles/NEWS +++ /dev/null @@ -1,75 +0,0 @@ -8.1.0 (2008-05-18) -================== - -Fixes ------ - - The deprecated mktap API is no longer used (#3127) - - -8.0.0 (2008-03-17) -================== - -Fixes ------ - - - Refactor DNSDatagramProtocol and DNSProtocol to use same base class (#2414) - - Change Resolver to query specified nameservers in specified order, instead - of reverse order. (#2290) - - Make SRVConnector work with bad results and NXDOMAIN responses. - (#1908, #2777) - - Handle write errors happening in dns queries, to have correct deferred - failures. (#2492) - - Fix the value of OP_NOTIFY and add a definition for OP_UPDATE. (#2945) - -Misc ----- - - #2685, #2936, #2581, #2847 - - -0.4.0 (2007-01-06) -================== - -Features --------- - - - In the twisted.names client, DNS responses which represent errors - are now translated to informative exception objects, rather than - empty lists. This means that client requests which fail will now - errback their Deferreds (#2248) - -Fixes ------ - - A major DoS vulnerability in the UDP DNS server was fixed (#1708) - -Misc ----- - - #1799, #1636, #2149, #2181 - - -0.3.0 (2006-05-21) -================== - -Features --------- - - Some docstring improvements - -Fixes ------ - - Fix a problem where the response for the first query with a - newly-created Resolver object would be dropped.(#1447) - - Misc: #1581, #1583 - - -0.2.0 -===== - - Fix occassional TCP connection leak in gethostbyname() - - Fix TCP connection leak in recursive lookups - - Remove deprecated use of Deferred.setTimeout - - Improved test coverage for zone transfers - -0.1.0 -===== - - Fix TCP connection leak in zone transfers - - Handle empty or missing resolv.conf as if 127.0.0.1 was specified - - Don't use blocking kernel entropy sources - - Retry logic now properly tries all specified servers. diff --git a/tools/buildbot/pylibs/twisted/names/topfiles/README b/tools/buildbot/pylibs/twisted/names/topfiles/README deleted file mode 100644 index aa1ae54..0000000 --- a/tools/buildbot/pylibs/twisted/names/topfiles/README +++ /dev/null @@ -1,3 +0,0 @@ -Twisted Names 8.1.0 - -Twisted Names depends on Twisted Core. diff --git a/tools/buildbot/pylibs/twisted/names/topfiles/setup.py b/tools/buildbot/pylibs/twisted/names/topfiles/setup.py deleted file mode 100644 index 5206815..0000000 --- a/tools/buildbot/pylibs/twisted/names/topfiles/setup.py +++ /dev/null @@ -1,48 +0,0 @@ -import sys - -try: - from twisted.python import dist -except ImportError: - raise SystemExit("twisted.python.dist module not found. Make sure you " - "have installed the Twisted core package before " - "attempting to install any other Twisted projects.") - -if __name__ == '__main__': - if sys.version_info[:2] >= (2, 4): - extraMeta = dict( - classifiers=[ - "Development Status :: 4 - Beta", - "Environment :: No Input/Output (Daemon)", - "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", - "Programming Language :: Python", - "Topic :: Internet :: Name Service (DNS)", - "Topic :: Software Development :: Libraries :: Python Modules", - ]) - else: - extraMeta = {} - - dist.setup( - twisted_subproject="names", - # metadata - name="Twisted Names", - description="A Twisted DNS implementation.", - author="Twisted Matrix Laboratories", - author_email="twisted-python@twistedmatrix.com", - maintainer="Jp Calderone", - maintainer_email="exarkun@divmod.com", - url="http://twistedmatrix.com/trac/wiki/TwistedNames", - license="MIT", - long_description="""\ -Twisted Names is both a domain name server as well as a client -resolver library. Twisted Names comes with an "out of the box" -nameserver which can read most BIND-syntax zone files as well as a -simple Python-based configuration format. Twisted Names can act as an -authoritative server, perform zone transfers from a master to act as a -secondary, act as a caching nameserver, or any combination of -these. Twisted Names' client resolver library provides functions to -query for all commonly used record types as well as a replacement for -the blocking gethostbyname() function provided by the Python stdlib -socket module. -""", - **extraMeta) diff --git a/tools/buildbot/pylibs/twisted/news/__init__.py b/tools/buildbot/pylibs/twisted/news/__init__.py deleted file mode 100644 index 78cb848..0000000 --- a/tools/buildbot/pylibs/twisted/news/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" - -Twisted News: an NNTP-based news service. - -""" - -from twisted.news._version import version -__version__ = version.short() diff --git a/tools/buildbot/pylibs/twisted/news/_version.py b/tools/buildbot/pylibs/twisted/news/_version.py deleted file mode 100644 index 5b2dce1..0000000 --- a/tools/buildbot/pylibs/twisted/news/_version.py +++ /dev/null @@ -1,3 +0,0 @@ -# This is an auto-generated file. Do not edit it. -from twisted.python import versions -version = versions.Version('twisted.news', 8, 1, 0) diff --git a/tools/buildbot/pylibs/twisted/news/database.py b/tools/buildbot/pylibs/twisted/news/database.py deleted file mode 100644 index b39192f..0000000 --- a/tools/buildbot/pylibs/twisted/news/database.py +++ /dev/null @@ -1,995 +0,0 @@ -# -*- test-case-name: twisted.news.test.test_news -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -News server backend implementations - -Maintainer: U{Jp Calderone} - -Future Plans: A PyFramer-based backend and a new backend interface that is -less NNTP specific -""" - - -from __future__ import nested_scopes - -from twisted.news.nntp import NNTPError -from twisted.mail import smtp -from twisted.internet import defer -from twisted.enterprise import adbapi -from twisted.persisted import dirdbm - -import getpass, pickle, time, socket, md5 -import os -import StringIO -from zope.interface import implements, Interface - - -ERR_NOGROUP, ERR_NOARTICLE = range(2, 4) # XXX - put NNTP values here (I guess?) - -OVERVIEW_FMT = [ - 'Subject', 'From', 'Date', 'Message-ID', 'References', - 'Bytes', 'Lines', 'Xref' -] - -def hexdigest(md5): #XXX: argh. 1.5.2 doesn't have this. - return ''.join(map(lambda x: hex(ord(x))[2:], md5.digest())) - -class Article: - def __init__(self, head, body): - self.body = body - self.headers = {} - header = None - for line in head.split('\r\n'): - if line[0] in ' \t': - i = list(self.headers[header]) - i[1] += '\r\n' + line - else: - i = line.split(': ', 1) - header = i[0].lower() - self.headers[header] = tuple(i) - - if not self.getHeader('Message-ID'): - s = str(time.time()) + self.body - id = hexdigest(md5.md5(s)) + '@' + socket.gethostname() - self.putHeader('Message-ID', '<%s>' % id) - - if not self.getHeader('Bytes'): - self.putHeader('Bytes', str(len(self.body))) - - if not self.getHeader('Lines'): - self.putHeader('Lines', str(self.body.count('\n'))) - - if not self.getHeader('Date'): - self.putHeader('Date', time.ctime(time.time())) - - - def getHeader(self, header): - h = header.lower() - if self.headers.has_key(h): - return self.headers[h][1] - else: - return '' - - - def putHeader(self, header, value): - self.headers[header.lower()] = (header, value) - - - def textHeaders(self): - headers = [] - for i in self.headers.values(): - headers.append('%s: %s' % i) - return '\r\n'.join(headers) + '\r\n' - - def overview(self): - xover = [] - for i in OVERVIEW_FMT: - xover.append(self.getHeader(i)) - return xover - - -class NewsServerError(Exception): - pass - - -class INewsStorage(Interface): - """ - An interface for storing and requesting news articles - """ - - def listRequest(): - """ - Returns a deferred whose callback will be passed a list of 4-tuples - containing (name, max index, min index, flags) for each news group - """ - - - def subscriptionRequest(): - """ - Returns a deferred whose callback will be passed the list of - recommended subscription groups for new server users - """ - - - def postRequest(message): - """ - Returns a deferred whose callback will be invoked if 'message' - is successfully posted to one or more specified groups and - whose errback will be invoked otherwise. - """ - - - def overviewRequest(): - """ - Returns a deferred whose callback will be passed the a list of - headers describing this server's overview format. - """ - - - def xoverRequest(group, low, high): - """ - Returns a deferred whose callback will be passed a list of xover - headers for the given group over the given range. If low is None, - the range starts at the first article. If high is None, the range - ends at the last article. - """ - - - def xhdrRequest(group, low, high, header): - """ - Returns a deferred whose callback will be passed a list of XHDR data - for the given group over the given range. If low is None, - the range starts at the first article. If high is None, the range - ends at the last article. - """ - - - def listGroupRequest(group): - """ - Returns a deferred whose callback will be passed a two-tuple of - (group name, [article indices]) - """ - - - def groupRequest(group): - """ - Returns a deferred whose callback will be passed a five-tuple of - (group name, article count, highest index, lowest index, group flags) - """ - - - def articleExistsRequest(id): - """ - Returns a deferred whose callback will be passed with a true value - if a message with the specified Message-ID exists in the database - and with a false value otherwise. - """ - - - def articleRequest(group, index, id = None): - """ - Returns a deferred whose callback will be passed a file-like object - containing the full article text (headers and body) for the article - of the specified index in the specified group, and whose errback - will be invoked if the article or group does not exist. If id is - not None, index is ignored and the article with the given Message-ID - will be returned instead, along with its index in the specified - group. - """ - - - def headRequest(group, index): - """ - Returns a deferred whose callback will be passed the header for - the article of the specified index in the specified group, and - whose errback will be invoked if the article or group does not - exist. - """ - - - def bodyRequest(group, index): - """ - Returns a deferred whose callback will be passed the body for - the article of the specified index in the specified group, and - whose errback will be invoked if the article or group does not - exist. - """ - -class NewsStorage: - """ - Backwards compatibility class -- There is no reason to inherit from this, - just implement INewsStorage instead. - """ - def listRequest(self): - raise NotImplementedError() - def subscriptionRequest(self): - raise NotImplementedError() - def postRequest(self, message): - raise NotImplementedError() - def overviewRequest(self): - return defer.succeed(OVERVIEW_FMT) - def xoverRequest(self, group, low, high): - raise NotImplementedError() - def xhdrRequest(self, group, low, high, header): - raise NotImplementedError() - def listGroupRequest(self, group): - raise NotImplementedError() - def groupRequest(self, group): - raise NotImplementedError() - def articleExistsRequest(self, id): - raise NotImplementedError() - def articleRequest(self, group, index, id = None): - raise NotImplementedError() - def headRequest(self, group, index): - raise NotImplementedError() - def bodyRequest(self, group, index): - raise NotImplementedError() - - -class PickleStorage: - """A trivial NewsStorage implementation using pickles - - Contains numerous flaws and is generally unsuitable for any - real applications. Consider yourself warned! - """ - - implements(INewsStorage) - - sharedDBs = {} - - def __init__(self, filename, groups = None, moderators = ()): - self.datafile = filename - self.load(filename, groups, moderators) - - - def getModerators(self, groups): - # first see if any groups are moderated. if so, nothing gets posted, - # but the whole messages gets forwarded to the moderator address - moderators = [] - for group in groups: - moderators.append(self.db['moderators'].get(group, None)) - return filter(None, moderators) - - - def notifyModerators(self, moderators, article): - # Moderated postings go through as long as they have an Approved - # header, regardless of what the value is - article.putHeader('To', ', '.join(moderators)) - return smtp.sendEmail( - 'twisted@' + socket.gethostname(), - moderators, - article.body, - dict(article.headers.values()) - ) - - - def listRequest(self): - "Returns a list of 4-tuples: (name, max index, min index, flags)" - l = self.db['groups'] - r = [] - for i in l: - if len(self.db[i].keys()): - low = min(self.db[i].keys()) - high = max(self.db[i].keys()) + 1 - else: - low = high = 0 - if self.db['moderators'].has_key(i): - flags = 'm' - else: - flags = 'y' - r.append((i, high, low, flags)) - return defer.succeed(r) - - def subscriptionRequest(self): - return defer.succeed(['alt.test']) - - def postRequest(self, message): - cleave = message.find('\r\n\r\n') - headers, article = message[:cleave], message[cleave + 4:] - - a = Article(headers, article) - groups = a.getHeader('Newsgroups').split() - xref = [] - - # Check moderated status - moderators = self.getModerators(groups) - if moderators and not a.getHeader('Approved'): - return self.notifyModerators(moderators, a) - - for group in groups: - if self.db.has_key(group): - if len(self.db[group].keys()): - index = max(self.db[group].keys()) + 1 - else: - index = 1 - xref.append((group, str(index))) - self.db[group][index] = a - - if len(xref) == 0: - return defer.fail(None) - - a.putHeader('Xref', '%s %s' % ( - socket.gethostname().split()[0], - ''.join(map(lambda x: ':'.join(x), xref)) - )) - - self.flush() - return defer.succeed(None) - - - def overviewRequest(self): - return defer.succeed(OVERVIEW_FMT) - - - def xoverRequest(self, group, low, high): - if not self.db.has_key(group): - return defer.succeed([]) - r = [] - for i in self.db[group].keys(): - if (low is None or i >= low) and (high is None or i <= high): - r.append([str(i)] + self.db[group][i].overview()) - return defer.succeed(r) - - - def xhdrRequest(self, group, low, high, header): - if not self.db.has_key(group): - return defer.succeed([]) - r = [] - for i in self.db[group].keys(): - if low is None or i >= low and high is None or i <= high: - r.append((i, self.db[group][i].getHeader(header))) - return defer.succeed(r) - - - def listGroupRequest(self, group): - if self.db.has_key(group): - return defer.succeed((group, self.db[group].keys())) - else: - return defer.fail(None) - - def groupRequest(self, group): - if self.db.has_key(group): - if len(self.db[group].keys()): - num = len(self.db[group].keys()) - low = min(self.db[group].keys()) - high = max(self.db[group].keys()) - else: - num = low = high = 0 - flags = 'y' - return defer.succeed((group, num, high, low, flags)) - else: - return defer.fail(ERR_NOGROUP) - - - def articleExistsRequest(self, id): - for g in self.db.values(): - for a in g.values(): - if a.getHeader('Message-ID') == id: - return defer.succeed(1) - return defer.succeed(0) - - - def articleRequest(self, group, index, id = None): - if id is not None: - raise NotImplementedError - - if self.db.has_key(group): - if self.db[group].has_key(index): - a = self.db[group][index] - return defer.succeed(( - index, - a.getHeader('Message-ID'), - StringIO.StringIO(a.textHeaders() + '\r\n' + a.body) - )) - else: - return defer.fail(ERR_NOARTICLE) - else: - return defer.fail(ERR_NOGROUP) - - - def headRequest(self, group, index): - if self.db.has_key(group): - if self.db[group].has_key(index): - a = self.db[group][index] - return defer.succeed((index, a.getHeader('Message-ID'), a.textHeaders())) - else: - return defer.fail(ERR_NOARTICLE) - else: - return defer.fail(ERR_NOGROUP) - - - def bodyRequest(self, group, index): - if self.db.has_key(group): - if self.db[group].has_key(index): - a = self.db[group][index] - return defer.succeed((index, a.getHeader('Message-ID'), StringIO.StringIO(a.body))) - else: - return defer.fail(ERR_NOARTICLE) - else: - return defer.fail(ERR_NOGROUP) - - - def flush(self): - pickle.dump(self.db, open(self.datafile, 'w')) - - - def load(self, filename, groups = None, moderators = ()): - if PickleStorage.sharedDBs.has_key(filename): - self.db = PickleStorage.sharedDBs[filename] - else: - try: - self.db = pickle.load(open(filename)) - PickleStorage.sharedDBs[filename] = self.db - except IOError, e: - self.db = PickleStorage.sharedDBs[filename] = {} - self.db['groups'] = groups - if groups is not None: - for i in groups: - self.db[i] = {} - self.db['moderators'] = dict(moderators) - self.flush() - - -class Group: - name = None - flags = '' - minArticle = 1 - maxArticle = 0 - articles = None - - def __init__(self, name, flags = 'y'): - self.name = name - self.flags = flags - self.articles = {} - - -class NewsShelf: - """ - A NewStorage implementation using Twisted's dirdbm persistence module. - """ - - implements(INewsStorage) - - def __init__(self, mailhost, path): - self.path = path - self.mailhost = mailhost - - if not os.path.exists(path): - os.mkdir(path) - - self.dbm = dirdbm.Shelf(os.path.join(path, "newsshelf")) - if not len(self.dbm.keys()): - self.initialize() - - - def initialize(self): - # A dictionary of group name/Group instance items - self.dbm['groups'] = dirdbm.Shelf(os.path.join(self.path, 'groups')) - - # A dictionary of group name/email address - self.dbm['moderators'] = dirdbm.Shelf(os.path.join(self.path, 'moderators')) - - # A list of group names - self.dbm['subscriptions'] = [] - - # A dictionary of MessageID strings/xref lists - self.dbm['Message-IDs'] = dirdbm.Shelf(os.path.join(self.path, 'Message-IDs')) - - - def addGroup(self, name, flags): - self.dbm['groups'][name] = Group(name, flags) - - - def addSubscription(self, name): - self.dbm['subscriptions'] = self.dbm['subscriptions'] + [name] - - - def addModerator(self, group, email): - self.dbm['moderators'][group] = email - - - def listRequest(self): - result = [] - for g in self.dbm['groups'].values(): - result.append((g.name, g.maxArticle, g.minArticle, g.flags)) - return defer.succeed(result) - - - def subscriptionRequest(self): - return defer.succeed(self.dbm['subscriptions']) - - - def getModerator(self, groups): - # first see if any groups are moderated. if so, nothing gets posted, - # but the whole messages gets forwarded to the moderator address - for group in groups: - try: - return self.dbm['moderators'][group] - except KeyError: - pass - return None - - - def notifyModerator(self, moderator, article): - # Moderated postings go through as long as they have an Approved - # header, regardless of what the value is - print 'To is ', moderator - article.putHeader('To', moderator) - return smtp.sendEmail( - self.mailhost, - 'twisted-news@' + socket.gethostname(), - moderator, - article.body, - dict(article.headers.values()) - ) - - - def postRequest(self, message): - cleave = message.find('\r\n\r\n') - headers, article = message[:cleave], message[cleave + 4:] - - article = Article(headers, article) - groups = article.getHeader('Newsgroups').split() - xref = [] - - # Check for moderated status - moderator = self.getModerator(groups) - if moderator and not article.getHeader('Approved'): - return self.notifyModerator(moderator, article) - - - for group in groups: - try: - g = self.dbm['groups'][group] - except KeyError: - pass - else: - index = g.maxArticle + 1 - g.maxArticle += 1 - g.articles[index] = article - xref.append((group, str(index))) - self.dbm['groups'][group] = g - - if not xref: - return defer.fail(NewsServerError("No groups carried: " + ' '.join(groups))) - - article.putHeader('Xref', '%s %s' % (socket.gethostname().split()[0], ' '.join(map(lambda x: ':'.join(x), xref)))) - self.dbm['Message-IDs'][article.getHeader('Message-ID')] = xref - return defer.succeed(None) - - - def overviewRequest(self): - return defer.succeed(OVERVIEW_FMT) - - - def xoverRequest(self, group, low, high): - if not self.dbm['groups'].has_key(group): - return defer.succeed([]) - - if low is None: - low = 0 - if high is None: - high = self.dbm['groups'][group].maxArticle - r = [] - for i in range(low, high + 1): - if self.dbm['groups'][group].articles.has_key(i): - r.append([str(i)] + self.dbm['groups'][group].articles[i].overview()) - return defer.succeed(r) - - - def xhdrRequest(self, group, low, high, header): - if group not in self.dbm['groups']: - return defer.succeed([]) - - if low is None: - low = 0 - if high is None: - high = self.dbm['groups'][group].maxArticle - r = [] - for i in range(low, high + 1): - if self.dbm['groups'][group].articles.has_key(i): - r.append((i, self.dbm['groups'][group].articles[i].getHeader(header))) - return defer.succeed(r) - - - def listGroupRequest(self, group): - if self.dbm['groups'].has_key(group): - return defer.succeed((group, self.dbm['groups'][group].articles.keys())) - return defer.fail(NewsServerError("No such group: " + group)) - - - def groupRequest(self, group): - try: - g = self.dbm['groups'][group] - except KeyError: - return defer.fail(NewsServerError("No such group: " + group)) - else: - flags = g.flags - low = g.minArticle - high = g.maxArticle - num = high - low + 1 - return defer.succeed((group, num, high, low, flags)) - - - def articleExistsRequest(self, id): - return defer.succeed(id in self.dbm['Message-IDs']) - - - def articleRequest(self, group, index, id = None): - if id is not None: - try: - xref = self.dbm['Message-IDs'][id] - except KeyError: - return defer.fail(NewsServerError("No such article: " + id)) - else: - group, index = xref[0] - index = int(index) - - try: - a = self.dbm['groups'][group].articles[index] - except KeyError: - return defer.fail(NewsServerError("No such group: " + group)) - else: - return defer.succeed(( - index, - a.getHeader('Message-ID'), - StringIO.StringIO(a.textHeaders() + '\r\n' + a.body) - )) - - - def headRequest(self, group, index, id = None): - if id is not None: - try: - xref = self.dbm['Message-IDs'][id] - except KeyError: - return defer.fail(NewsServerError("No such article: " + id)) - else: - group, index = xref[0] - index = int(index) - - try: - a = self.dbm['groups'][group].articles[index] - except KeyError: - return defer.fail(NewsServerError("No such group: " + group)) - else: - return defer.succeed((index, a.getHeader('Message-ID'), a.textHeaders())) - - - def bodyRequest(self, group, index, id = None): - if id is not None: - try: - xref = self.dbm['Message-IDs'][id] - except KeyError: - return defer.fail(NewsServerError("No such article: " + id)) - else: - group, index = xref[0] - index = int(index) - - try: - a = self.dbm['groups'][group].articles[index] - except KeyError: - return defer.fail(NewsServerError("No such group: " + group)) - else: - return defer.succeed((index, a.getHeader('Message-ID'), StringIO.StringIO(a.body))) - - -class NewsStorageAugmentation: - """ - A NewsStorage implementation using Twisted's asynchronous DB-API - """ - - implements(INewsStorage) - - schema = """ - - CREATE TABLE groups ( - group_id SERIAL, - name VARCHAR(80) NOT NULL, - - flags INTEGER DEFAULT 0 NOT NULL - ); - - CREATE UNIQUE INDEX group_id_index ON groups (group_id); - CREATE UNIQUE INDEX name_id_index ON groups (name); - - CREATE TABLE articles ( - article_id SERIAL, - message_id TEXT, - - header TEXT, - body TEXT - ); - - CREATE UNIQUE INDEX article_id_index ON articles (article_id); - CREATE UNIQUE INDEX article_message_index ON articles (message_id); - - CREATE TABLE postings ( - group_id INTEGER, - article_id INTEGER, - article_index INTEGER NOT NULL - ); - - CREATE UNIQUE INDEX posting_article_index ON postings (article_id); - - CREATE TABLE subscriptions ( - group_id INTEGER - ); - - CREATE TABLE overview ( - header TEXT - ); - """ - - def __init__(self, info): - self.info = info - self.dbpool = adbapi.ConnectionPool(**self.info) - - - def __setstate__(self, state): - self.__dict__ = state - self.info['password'] = getpass.getpass('Database password for %s: ' % (self.info['user'],)) - self.dbpool = adbapi.ConnectionPool(**self.info) - del self.info['password'] - - - def listRequest(self): - # COALESCE may not be totally portable - # it is shorthand for - # CASE WHEN (first parameter) IS NOT NULL then (first parameter) ELSE (second parameter) END - sql = """ - SELECT groups.name, - COALESCE(MAX(postings.article_index), 0), - COALESCE(MIN(postings.article_index), 0), - groups.flags - FROM groups LEFT OUTER JOIN postings - ON postings.group_id = groups.group_id - GROUP BY groups.name, groups.flags - ORDER BY groups.name - """ - return self.dbpool.runQuery(sql) - - - def subscriptionRequest(self): - sql = """ - SELECT groups.name FROM groups,subscriptions WHERE groups.group_id = subscriptions.group_id - """ - return self.dbpool.runQuery(sql) - - - def postRequest(self, message): - cleave = message.find('\r\n\r\n') - headers, article = message[:cleave], message[cleave + 4:] - article = Article(headers, article) - return self.dbpool.runInteraction(self._doPost, article) - - - def _doPost(self, transaction, article): - # Get the group ids - groups = article.getHeader('Newsgroups').split() - if not len(groups): - raise NNTPError('Missing Newsgroups header') - - sql = """ - SELECT name, group_id FROM groups - WHERE name IN (%s) - """ % (', '.join([("'%s'" % (adbapi.safe(group),)) for group in groups]),) - - transaction.execute(sql) - result = transaction.fetchall() - - # No relevant groups, bye bye! - if not len(result): - raise NNTPError('None of groups in Newsgroup header carried') - - # Got some groups, now find the indices this article will have in each - sql = """ - SELECT groups.group_id, COALESCE(MAX(postings.article_index), 0) + 1 - FROM groups LEFT OUTER JOIN postings - ON postings.group_id = groups.group_id - WHERE groups.group_id IN (%s) - GROUP BY groups.group_id - """ % (', '.join([("%d" % (id,)) for (group, id) in result]),) - - transaction.execute(sql) - indices = transaction.fetchall() - - if not len(indices): - raise NNTPError('Internal server error - no indices found') - - # Associate indices with group names - gidToName = dict([(b, a) for (a, b) in result]) - gidToIndex = dict(indices) - - nameIndex = [] - for i in gidToName: - nameIndex.append((gidToName[i], gidToIndex[i])) - - # Build xrefs - xrefs = socket.gethostname().split()[0] - xrefs = xrefs + ' ' + ' '.join([('%s:%d' % (group, id)) for (group, id) in nameIndex]) - article.putHeader('Xref', xrefs) - - # Hey! The article is ready to be posted! God damn f'in finally. - sql = """ - INSERT INTO articles (message_id, header, body) - VALUES ('%s', '%s', '%s') - """ % ( - adbapi.safe(article.getHeader('Message-ID')), - adbapi.safe(article.textHeaders()), - adbapi.safe(article.body) - ) - - transaction.execute(sql) - - # Now update the posting to reflect the groups to which this belongs - for gid in gidToName: - sql = """ - INSERT INTO postings (group_id, article_id, article_index) - VALUES (%d, (SELECT last_value FROM articles_article_id_seq), %d) - """ % (gid, gidToIndex[gid]) - transaction.execute(sql) - - return len(nameIndex) - - - def overviewRequest(self): - sql = """ - SELECT header FROM overview - """ - return self.dbpool.runQuery(sql).addCallback(lambda result: [header[0] for header in result]) - - - def xoverRequest(self, group, low, high): - sql = """ - SELECT postings.article_index, articles.header - FROM articles,postings,groups - WHERE postings.group_id = groups.group_id - AND groups.name = '%s' - AND postings.article_id = articles.article_id - %s - %s - """ % ( - adbapi.safe(group), - low is not None and "AND postings.article_index >= %d" % (low,) or "", - high is not None and "AND postings.article_index <= %d" % (high,) or "" - ) - - return self.dbpool.runQuery(sql).addCallback( - lambda results: [ - [id] + Article(header, None).overview() for (id, header) in results - ] - ) - - - def xhdrRequest(self, group, low, high, header): - sql = """ - SELECT articles.header - FROM groups,postings,articles - WHERE groups.name = '%s' AND postings.group_id = groups.group_id - AND postings.article_index >= %d - AND postings.article_index <= %d - """ % (adbapi.safe(group), low, high) - - return self.dbpool.runQuery(sql).addCallback( - lambda results: [ - (i, Article(h, None).getHeader(h)) for (i, h) in results - ] - ) - - - def listGroupRequest(self, group): - sql = """ - SELECT postings.article_index FROM postings,groups - WHERE postings.group_id = groups.group_id - AND groups.name = '%s' - """ % (adbapi.safe(group),) - - return self.dbpool.runQuery(sql).addCallback( - lambda results, group = group: (group, [res[0] for res in results]) - ) - - - def groupRequest(self, group): - sql = """ - SELECT groups.name, - COUNT(postings.article_index), - COALESCE(MAX(postings.article_index), 0), - COALESCE(MIN(postings.article_index), 0), - groups.flags - FROM groups LEFT OUTER JOIN postings - ON postings.group_id = groups.group_id - WHERE groups.name = '%s' - GROUP BY groups.name, groups.flags - """ % (adbapi.safe(group),) - - return self.dbpool.runQuery(sql).addCallback( - lambda results: tuple(results[0]) - ) - - - def articleExistsRequest(self, id): - sql = """ - SELECT COUNT(message_id) FROM articles - WHERE message_id = '%s' - """ % (adbapi.safe(id),) - - return self.dbpool.runQuery(sql).addCallback( - lambda result: bool(result[0][0]) - ) - - - def articleRequest(self, group, index, id = None): - if id is not None: - sql = """ - SELECT postings.article_index, articles.message_id, articles.header, articles.body - FROM groups,postings LEFT OUTER JOIN articles - ON articles.message_id = '%s' - WHERE groups.name = '%s' - AND groups.group_id = postings.group_id - """ % (adbapi.safe(id), adbapi.safe(group)) - else: - sql = """ - SELECT postings.article_index, articles.message_id, articles.header, articles.body - FROM groups,articles LEFT OUTER JOIN postings - ON postings.article_id = articles.article_id - WHERE postings.article_index = %d - AND postings.group_id = groups.group_id - AND groups.name = '%s' - """ % (index, adbapi.safe(group)) - - return self.dbpool.runQuery(sql).addCallback( - lambda result: ( - result[0][0], - result[0][1], - StringIO.StringIO(result[0][2] + '\r\n' + result[0][3]) - ) - ) - - - def headRequest(self, group, index): - sql = """ - SELECT postings.article_index, articles.message_id, articles.header - FROM groups,articles LEFT OUTER JOIN postings - ON postings.article_id = articles.article_id - WHERE postings.article_index = %d - AND postings.group_id = groups.group_id - AND groups.name = '%s' - """ % (index, adbapi.safe(group)) - - return self.dbpool.runQuery(sql).addCallback(lambda result: result[0]) - - - def bodyRequest(self, group, index): - sql = """ - SELECT postings.article_index, articles.message_id, articles.body - FROM groups,articles LEFT OUTER JOIN postings - ON postings.article_id = articles.article_id - WHERE postings.article_index = %d - AND postings.group_id = groups.group_id - AND groups.name = '%s' - """ % (index, adbapi.safe(group)) - - return self.dbpool.runQuery(sql).addCallback( - lambda result: result[0] - ).addCallback( - lambda (index, id, body): (index, id, StringIO.StringIO(body)) - ) - -#### -#### XXX - make these static methods some day -#### -def makeGroupSQL(groups): - res = '' - for g in groups: - res = res + """\n INSERT INTO groups (name) VALUES ('%s');\n""" % (adbapi.safe(g),) - return res - - -def makeOverviewSQL(): - res = '' - for o in OVERVIEW_FMT: - res = res + """\n INSERT INTO overview (header) VALUES ('%s');\n""" % (adbapi.safe(o),) - return res diff --git a/tools/buildbot/pylibs/twisted/news/news.py b/tools/buildbot/pylibs/twisted/news/news.py deleted file mode 100644 index 2aad86c..0000000 --- a/tools/buildbot/pylibs/twisted/news/news.py +++ /dev/null @@ -1,90 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Maintainer: U{Jp Calderone} -""" - -from twisted.news import nntp -from twisted.internet import protocol, reactor - -import time - -class NNTPFactory(protocol.ServerFactory): - """A factory for NNTP server protocols.""" - - protocol = nntp.NNTPServer - - def __init__(self, backend): - self.backend = backend - - def buildProtocol(self, connection): - p = self.protocol() - p.factory = self - return p - - -class UsenetClientFactory(protocol.ClientFactory): - def __init__(self, groups, storage): - self.lastChecks = {} - self.groups = groups - self.storage = storage - - - def clientConnectionLost(self, connector, reason): - pass - - - def clientConnectionFailed(self, connector, reason): - print 'Connection failed: ', reason - - - def updateChecks(self, addr): - self.lastChecks[addr] = time.mktime(time.gmtime()) - - - def buildProtocol(self, addr): - last = self.lastChecks.setdefault(addr, time.mktime(time.gmtime()) - (60 * 60 * 24 * 7)) - p = nntp.UsenetClientProtocol(self.groups, last, self.storage) - p.factory = self - return p - - -# XXX - Maybe this inheritence doesn't make so much sense? -class UsenetServerFactory(NNTPFactory): - """A factory for NNTP Usenet server protocols.""" - - protocol = nntp.NNTPServer - - def __init__(self, backend, remoteHosts = None, updatePeriod = 60): - NNTPFactory.__init__(self, backend) - self.updatePeriod = updatePeriod - self.remoteHosts = remoteHosts or [] - self.clientFactory = UsenetClientFactory(self.remoteHosts, self.backend) - - - def startFactory(self): - self._updateCall = reactor.callLater(0, self.syncWithRemotes) - - - def stopFactory(self): - if self._updateCall: - self._updateCall.cancel() - self._updateCall = None - - - def buildProtocol(self, connection): - p = self.protocol() - p.factory = self - return p - - - def syncWithRemotes(self): - for remote in self.remoteHosts: - reactor.connectTCP(remote, 119, self.clientFactory) - self._updateCall = reactor.callLater(self.updatePeriod, self.syncWithRemotes) - - -# backwards compatability -Factory = UsenetServerFactory diff --git a/tools/buildbot/pylibs/twisted/news/nntp.py b/tools/buildbot/pylibs/twisted/news/nntp.py deleted file mode 100644 index 2e9861e..0000000 --- a/tools/buildbot/pylibs/twisted/news/nntp.py +++ /dev/null @@ -1,1069 +0,0 @@ -# -*- test-case-name: twisted.news.test.test_nntp -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -NNTP protocol support. - -Maintainer: U{Jp Calderone} - -The following protocol commands are currently understood:: - - LIST LISTGROUP XOVER XHDR - POST GROUP ARTICLE STAT HEAD - BODY NEXT MODE STREAM MODE READER SLAVE - LAST QUIT HELP IHAVE XPATH - XINDEX XROVER TAKETHIS CHECK - -The following protocol commands require implementation:: - - NEWNEWS - XGTITLE XPAT - XTHREAD AUTHINFO NEWGROUPS - - -Other desired features: - - - A real backend - - More robust client input handling - - A control protocol -""" - -import time -import types - -try: - import cStringIO as StringIO -except: - import StringIO - -from twisted.protocols import basic -from twisted.python import log - -def parseRange(text): - articles = text.split('-') - if len(articles) == 1: - try: - a = int(articles[0]) - return a, a - except ValueError, e: - return None, None - elif len(articles) == 2: - try: - if len(articles[0]): - l = int(articles[0]) - else: - l = None - if len(articles[1]): - h = int(articles[1]) - else: - h = None - except ValueError, e: - return None, None - return l, h - - -def extractCode(line): - line = line.split(' ', 1) - if len(line) != 2: - return None - try: - return int(line[0]), line[1] - except ValueError: - return None - - -class NNTPError(Exception): - def __init__(self, string): - self.string = string - - def __str__(self): - return 'NNTPError: %s' % self.string - - -class NNTPClient(basic.LineReceiver): - MAX_COMMAND_LENGTH = 510 - - def __init__(self): - self.currentGroup = None - - self._state = [] - self._error = [] - self._inputBuffers = [] - self._responseCodes = [] - self._responseHandlers = [] - - self._postText = [] - - self._newState(self._statePassive, None, self._headerInitial) - - - def gotAllGroups(self, groups): - "Override for notification when fetchGroups() action is completed" - - - def getAllGroupsFailed(self, error): - "Override for notification when fetchGroups() action fails" - - - def gotOverview(self, overview): - "Override for notification when fetchOverview() action is completed" - - - def getOverviewFailed(self, error): - "Override for notification when fetchOverview() action fails" - - - def gotSubscriptions(self, subscriptions): - "Override for notification when fetchSubscriptions() action is completed" - - - def getSubscriptionsFailed(self, error): - "Override for notification when fetchSubscriptions() action fails" - - - def gotGroup(self, group): - "Override for notification when fetchGroup() action is completed" - - - def getGroupFailed(self, error): - "Override for notification when fetchGroup() action fails" - - - def gotArticle(self, article): - "Override for notification when fetchArticle() action is completed" - - - def getArticleFailed(self, error): - "Override for notification when fetchArticle() action fails" - - - def gotHead(self, head): - "Override for notification when fetchHead() action is completed" - - - def getHeadFailed(self, error): - "Override for notification when fetchHead() action fails" - - - def gotBody(self, info): - "Override for notification when fetchBody() action is completed" - - - def getBodyFailed(self, body): - "Override for notification when fetchBody() action fails" - - - def postedOk(self): - "Override for notification when postArticle() action is successful" - - - def postFailed(self, error): - "Override for notification when postArticle() action fails" - - - def gotXHeader(self, headers): - "Override for notification when getXHeader() action is successful" - - - def getXHeaderFailed(self, error): - "Override for notification when getXHeader() action fails" - - - def gotNewNews(self, news): - "Override for notification when getNewNews() action is successful" - - - def getNewNewsFailed(self, error): - "Override for notification when getNewNews() action fails" - - - def gotNewGroups(self, groups): - "Override for notification when getNewGroups() action is successful" - - - def getNewGroupsFailed(self, error): - "Override for notification when getNewGroups() action fails" - - - def setStreamSuccess(self): - "Override for notification when setStream() action is successful" - - - def setStreamFailed(self, error): - "Override for notification when setStream() action fails" - - - def fetchGroups(self): - """ - Request a list of all news groups from the server. gotAllGroups() - is called on success, getGroupsFailed() on failure - """ - self.sendLine('LIST') - self._newState(self._stateList, self.getAllGroupsFailed) - - - def fetchOverview(self): - """ - Request the overview format from the server. gotOverview() is called - on success, getOverviewFailed() on failure - """ - self.sendLine('LIST OVERVIEW.FMT') - self._newState(self._stateOverview, self.getOverviewFailed) - - - def fetchSubscriptions(self): - """ - Request a list of the groups it is recommended a new user subscribe to. - gotSubscriptions() is called on success, getSubscriptionsFailed() on - failure - """ - self.sendLine('LIST SUBSCRIPTIONS') - self._newState(self._stateSubscriptions, self.getSubscriptionsFailed) - - - def fetchGroup(self, group): - """ - Get group information for the specified group from the server. gotGroup() - is called on success, getGroupFailed() on failure. - """ - self.sendLine('GROUP %s' % (group,)) - self._newState(None, self.getGroupFailed, self._headerGroup) - - - def fetchHead(self, index = ''): - """ - Get the header for the specified article (or the currently selected - article if index is '') from the server. gotHead() is called on - success, getHeadFailed() on failure - """ - self.sendLine('HEAD %s' % (index,)) - self._newState(self._stateHead, self.getHeadFailed) - - - def fetchBody(self, index = ''): - """ - Get the body for the specified article (or the currently selected - article if index is '') from the server. gotBody() is called on - success, getBodyFailed() on failure - """ - self.sendLine('BODY %s' % (index,)) - self._newState(self._stateBody, self.getBodyFailed) - - - def fetchArticle(self, index = ''): - """ - Get the complete article with the specified index (or the currently - selected article if index is '') or Message-ID from the server. - gotArticle() is called on success, getArticleFailed() on failure. - """ - self.sendLine('ARTICLE %s' % (index,)) - self._newState(self._stateArticle, self.getArticleFailed) - - - def postArticle(self, text): - """ - Attempt to post an article with the specified text to the server. 'text' - must consist of both head and body data, as specified by RFC 850. If the - article is posted successfully, postedOk() is called, otherwise postFailed() - is called. - """ - self.sendLine('POST') - self._newState(None, self.postFailed, self._headerPost) - self._postText.append(text) - - - def fetchNewNews(self, groups, date, distributions = ''): - """ - Get the Message-IDs for all new news posted to any of the given - groups since the specified date - in seconds since the epoch, GMT - - optionally restricted to the given distributions. gotNewNews() is - called on success, getNewNewsFailed() on failure. - - One invocation of this function may result in multiple invocations - of gotNewNews()/getNewNewsFailed(). - """ - date, timeStr = time.strftime('%y%m%d %H%M%S', time.gmtime(date)).split() - line = 'NEWNEWS %%s %s %s %s' % (date, timeStr, distributions) - groupPart = '' - while len(groups) and len(line) + len(groupPart) + len(groups[-1]) + 1 < NNTPClient.MAX_COMMAND_LENGTH: - group = groups.pop() - groupPart = groupPart + ',' + group - - self.sendLine(line % (groupPart,)) - self._newState(self._stateNewNews, self.getNewNewsFailed) - - if len(groups): - self.fetchNewNews(groups, date, distributions) - - - def fetchNewGroups(self, date, distributions): - """ - Get the names of all new groups created/added to the server since - the specified date - in seconds since the ecpoh, GMT - optionally - restricted to the given distributions. gotNewGroups() is called - on success, getNewGroupsFailed() on failure. - """ - date, timeStr = time.strftime('%y%m%d %H%M%S', time.gmtime(date)).split() - self.sendLine('NEWGROUPS %s %s %s' % (date, timeStr, distributions)) - self._newState(self._stateNewGroups, self.getNewGroupsFailed) - - - def fetchXHeader(self, header, low = None, high = None, id = None): - """ - Request a specific header from the server for an article or range - of articles. If 'id' is not None, a header for only the article - with that Message-ID will be requested. If both low and high are - None, a header for the currently selected article will be selected; - If both low and high are zero-length strings, headers for all articles - in the currently selected group will be requested; Otherwise, high - and low will be used as bounds - if one is None the first or last - article index will be substituted, as appropriate. - """ - if id is not None: - r = header + ' <%s>' % (id,) - elif low is high is None: - r = header - elif high is None: - r = header + ' %d-' % (low,) - elif low is None: - r = header + ' -%d' % (high,) - else: - r = header + ' %d-%d' % (low, high) - self.sendLine('XHDR ' + r) - self._newState(self._stateXHDR, self.getXHeaderFailed) - - - def setStream(self): - """ - Set the mode to STREAM, suspending the normal "lock-step" mode of - communications. setStreamSuccess() is called on success, - setStreamFailed() on failure. - """ - self.sendLine('MODE STREAM') - self._newState(None, self.setStreamFailed, self._headerMode) - - - def quit(self): - self.sendLine('QUIT') - self.transport.loseConnection() - - - def _newState(self, method, error, responseHandler = None): - self._inputBuffers.append([]) - self._responseCodes.append(None) - self._state.append(method) - self._error.append(error) - self._responseHandlers.append(responseHandler) - - - def _endState(self): - buf = self._inputBuffers[0] - del self._responseCodes[0] - del self._inputBuffers[0] - del self._state[0] - del self._error[0] - del self._responseHandlers[0] - return buf - - - def _newLine(self, line, check = 1): - if check and line and line[0] == '.': - line = line[1:] - self._inputBuffers[0].append(line) - - - def _setResponseCode(self, code): - self._responseCodes[0] = code - - - def _getResponseCode(self): - return self._responseCodes[0] - - - def lineReceived(self, line): - if not len(self._state): - self._statePassive(line) - elif self._getResponseCode() is None: - code = extractCode(line) - if code is None or not (200 <= code[0] < 400): # An error! - self._error[0](line) - self._endState() - else: - self._setResponseCode(code) - if self._responseHandlers[0]: - self._responseHandlers[0](code) - else: - self._state[0](line) - - - def _statePassive(self, line): - log.msg('Server said: %s' % line) - - - def _passiveError(self, error): - log.err('Passive Error: %s' % (error,)) - - - def _headerInitial(self, (code, message)): - if code == 200: - self.canPost = 1 - else: - self.canPost = 0 - self._endState() - - - def _stateList(self, line): - if line != '.': - data = filter(None, line.strip().split()) - self._newLine((data[0], int(data[1]), int(data[2]), data[3]), 0) - else: - self.gotAllGroups(self._endState()) - - - def _stateOverview(self, line): - if line != '.': - self._newLine(filter(None, line.strip().split()), 0) - else: - self.gotOverview(self._endState()) - - - def _stateSubscriptions(self, line): - if line != '.': - self._newLine(line.strip(), 0) - else: - self.gotSubscriptions(self._endState()) - - - def _headerGroup(self, (code, line)): - self.gotGroup(tuple(line.split())) - self._endState() - - - def _stateArticle(self, line): - if line != '.': - if line.startswith('.'): - line = line[1:] - self._newLine(line, 0) - else: - self.gotArticle('\n'.join(self._endState())+'\n') - - - def _stateHead(self, line): - if line != '.': - self._newLine(line, 0) - else: - self.gotHead('\n'.join(self._endState())) - - - def _stateBody(self, line): - if line != '.': - if line.startswith('.'): - line = line[1:] - self._newLine(line, 0) - else: - self.gotBody('\n'.join(self._endState())+'\n') - - - def _headerPost(self, (code, message)): - if code == 340: - self.transport.write(self._postText[0].replace('\n', '\r\n').replace('\r\n.', '\r\n..')) - if self._postText[0][-1:] != '\n': - self.sendLine('') - self.sendLine('.') - del self._postText[0] - self._newState(None, self.postFailed, self._headerPosted) - else: - self.postFailed('%d %s' % (code, message)) - self._endState() - - - def _headerPosted(self, (code, message)): - if code == 240: - self.postedOk() - else: - self.postFailed('%d %s' % (code, message)) - self._endState() - - - def _stateXHDR(self, line): - if line != '.': - self._newLine(line.split(), 0) - else: - self._gotXHeader(self._endState()) - - - def _stateNewNews(self, line): - if line != '.': - self._newLine(line, 0) - else: - self.gotNewNews(self._endState()) - - - def _stateNewGroups(self, line): - if line != '.': - self._newLine(line, 0) - else: - self.gotNewGroups(self._endState()) - - - def _headerMode(self, (code, message)): - if code == 203: - self.setStreamSuccess() - else: - self.setStreamFailed((code, message)) - self._endState() - - -class NNTPServer(basic.LineReceiver): - COMMANDS = [ - 'LIST', 'GROUP', 'ARTICLE', 'STAT', 'MODE', 'LISTGROUP', 'XOVER', - 'XHDR', 'HEAD', 'BODY', 'NEXT', 'LAST', 'POST', 'QUIT', 'IHAVE', - 'HELP', 'SLAVE', 'XPATH', 'XINDEX', 'XROVER', 'TAKETHIS', 'CHECK' - ] - - def __init__(self): - self.servingSlave = 0 - - - def connectionMade(self): - self.inputHandler = None - self.currentGroup = None - self.currentIndex = None - self.sendLine('200 server ready - posting allowed') - - def lineReceived(self, line): - if self.inputHandler is not None: - self.inputHandler(line) - else: - parts = line.strip().split() - if len(parts): - cmd, parts = parts[0].upper(), parts[1:] - if cmd in NNTPServer.COMMANDS: - func = getattr(self, 'do_%s' % cmd) - try: - func(*parts) - except TypeError: - self.sendLine('501 command syntax error') - log.msg("501 command syntax error") - log.msg("command was", line) - log.deferr() - except: - self.sendLine('503 program fault - command not performed') - log.msg("503 program fault") - log.msg("command was", line) - log.deferr() - else: - self.sendLine('500 command not recognized') - - - def do_LIST(self, subcmd = '', *dummy): - subcmd = subcmd.strip().lower() - if subcmd == 'newsgroups': - # XXX - this could use a real implementation, eh? - self.sendLine('215 Descriptions in form "group description"') - self.sendLine('.') - elif subcmd == 'overview.fmt': - defer = self.factory.backend.overviewRequest() - defer.addCallbacks(self._gotOverview, self._errOverview) - log.msg('overview') - elif subcmd == 'subscriptions': - defer = self.factory.backend.subscriptionRequest() - defer.addCallbacks(self._gotSubscription, self._errSubscription) - log.msg('subscriptions') - elif subcmd == '': - defer = self.factory.backend.listRequest() - defer.addCallbacks(self._gotList, self._errList) - else: - self.sendLine('500 command not recognized') - - - def _gotList(self, list): - self.sendLine('215 newsgroups in form "group high low flags"') - for i in list: - self.sendLine('%s %d %d %s' % tuple(i)) - self.sendLine('.') - - - def _errList(self, failure): - print 'LIST failed: ', failure - self.sendLine('503 program fault - command not performed') - - - def _gotSubscription(self, parts): - self.sendLine('215 information follows') - for i in parts: - self.sendLine(i) - self.sendLine('.') - - - def _errSubscription(self, failure): - print 'SUBSCRIPTIONS failed: ', failure - self.sendLine('503 program fault - comand not performed') - - - def _gotOverview(self, parts): - self.sendLine('215 Order of fields in overview database.') - for i in parts: - self.sendLine(i + ':') - self.sendLine('.') - - - def _errOverview(self, failure): - print 'LIST OVERVIEW.FMT failed: ', failure - self.sendLine('503 program fault - command not performed') - - - def do_LISTGROUP(self, group = None): - group = group or self.currentGroup - if group is None: - self.sendLine('412 Not currently in newsgroup') - else: - defer = self.factory.backend.listGroupRequest(group) - defer.addCallbacks(self._gotListGroup, self._errListGroup) - - - def _gotListGroup(self, (group, articles)): - self.currentGroup = group - if len(articles): - self.currentIndex = int(articles[0]) - else: - self.currentIndex = None - - self.sendLine('211 list of article numbers follow') - for i in articles: - self.sendLine(str(i)) - self.sendLine('.') - - - def _errListGroup(self, failure): - print 'LISTGROUP failed: ', failure - self.sendLine('502 no permission') - - - def do_XOVER(self, range): - if self.currentGroup is None: - self.sendLine('412 No news group currently selected') - else: - l, h = parseRange(range) - defer = self.factory.backend.xoverRequest(self.currentGroup, l, h) - defer.addCallbacks(self._gotXOver, self._errXOver) - - - def _gotXOver(self, parts): - self.sendLine('224 Overview information follows') - for i in parts: - self.sendLine('\t'.join(map(str, i))) - self.sendLine('.') - - - def _errXOver(self, failure): - print 'XOVER failed: ', failure - self.sendLine('420 No article(s) selected') - - - def xhdrWork(self, header, range): - if self.currentGroup is None: - self.sendLine('412 No news group currently selected') - else: - if range is None: - if self.currentIndex is None: - self.sendLine('420 No current article selected') - return - else: - l = h = self.currentIndex - else: - # FIXME: articles may be a message-id - l, h = parseRange(range) - - if l is h is None: - self.sendLine('430 no such article') - else: - return self.factory.backend.xhdrRequest(self.currentGroup, l, h, header) - - - def do_XHDR(self, header, range = None): - d = self.xhdrWork(header, range) - if d: - d.addCallbacks(self._gotXHDR, self._errXHDR) - - - def _gotXHDR(self, parts): - self.sendLine('221 Header follows') - for i in parts: - self.sendLine('%d %s' % i) - self.sendLine('.') - - def _errXHDR(self, failure): - print 'XHDR failed: ', failure - self.sendLine('502 no permission') - - - def do_XROVER(self, header, range = None): - d = self.xhdrWork(header, range) - if d: - d.addCallbacks(self._gotXROVER, self._errXROVER) - - - def _gotXROVER(self, parts): - self.sendLine('224 Overview information follows') - for i in parts: - self.sendLine('%d %s' % i) - self.sendLine('.') - - - def _errXROVER(self, failure): - print 'XROVER failed: ', - self._errXHDR(failure) - - - def do_POST(self): - self.inputHandler = self._doingPost - self.message = '' - self.sendLine('340 send article to be posted. End with .') - - - def _doingPost(self, line): - if line == '.': - self.inputHandler = None - group, article = self.currentGroup, self.message - self.message = '' - - defer = self.factory.backend.postRequest(article) - defer.addCallbacks(self._gotPost, self._errPost) - else: - self.message = self.message + line + '\r\n' - - - def _gotPost(self, parts): - self.sendLine('240 article posted ok') - - - def _errPost(self, failure): - print 'POST failed: ', failure - self.sendLine('441 posting failed') - - - def do_CHECK(self, id): - d = self.factory.backend.articleExistsRequest(id) - d.addCallbacks(self._gotCheck, self._errCheck) - - - def _gotCheck(self, result): - if result: - self.sendLine("438 already have it, please don't send it to me") - else: - self.sendLine('238 no such article found, please send it to me') - - - def _errCheck(self, failure): - print 'CHECK failed: ', failure - self.sendLine('431 try sending it again later') - - - def do_TAKETHIS(self, id): - self.inputHandler = self._doingTakeThis - self.message = '' - - - def _doingTakeThis(self, line): - if line == '.': - self.inputHandler = None - article = self.message - self.message = '' - d = self.factory.backend.postRequest(article) - d.addCallbacks(self._didTakeThis, self._errTakeThis) - else: - self.message = self.message + line + '\r\n' - - - def _didTakeThis(self, result): - self.sendLine('239 article transferred ok') - - - def _errTakeThis(self, failure): - print 'TAKETHIS failed: ', failure - self.sendLine('439 article transfer failed') - - - def do_GROUP(self, group): - defer = self.factory.backend.groupRequest(group) - defer.addCallbacks(self._gotGroup, self._errGroup) - - - def _gotGroup(self, (name, num, high, low, flags)): - self.currentGroup = name - self.currentIndex = low - self.sendLine('211 %d %d %d %s group selected' % (num, low, high, name)) - - - def _errGroup(self, failure): - print 'GROUP failed: ', failure - self.sendLine('411 no such group') - - - def articleWork(self, article, cmd, func): - if self.currentGroup is None: - self.sendLine('412 no newsgroup has been selected') - else: - if not article: - if self.currentIndex is None: - self.sendLine('420 no current article has been selected') - else: - article = self.currentIndex - else: - if article[0] == '<': - return func(self.currentGroup, index = None, id = article) - else: - try: - article = int(article) - return func(self.currentGroup, article) - except ValueError, e: - self.sendLine('501 command syntax error') - - - def do_ARTICLE(self, article = None): - defer = self.articleWork(article, 'ARTICLE', self.factory.backend.articleRequest) - if defer: - defer.addCallbacks(self._gotArticle, self._errArticle) - - - def _gotArticle(self, (index, id, article)): - if isinstance(article, types.StringType): - import warnings - warnings.warn( - "Returning the article as a string from `articleRequest' " - "is deprecated. Return a file-like object instead." - ) - article = StringIO.StringIO(article) - self.currentIndex = index - self.sendLine('220 %d %s article' % (index, id)) - s = basic.FileSender() - d = s.beginFileTransfer(article, self.transport) - d.addCallback(self.finishedFileTransfer) - - ## - ## Helper for FileSender - ## - def finishedFileTransfer(self, lastsent): - if lastsent != '\n': - line = '\r\n.' - else: - line = '.' - self.sendLine(line) - ## - - def _errArticle(self, failure): - print 'ARTICLE failed: ', failure - self.sendLine('423 bad article number') - - - def do_STAT(self, article = None): - defer = self.articleWork(article, 'STAT', self.factory.backend.articleRequest) - if defer: - defer.addCallbacks(self._gotStat, self._errStat) - - - def _gotStat(self, (index, id, article)): - self.currentIndex = index - self.sendLine('223 %d %s article retreived - request text separately' % (index, id)) - - - def _errStat(self, failure): - print 'STAT failed: ', failure - self.sendLine('423 bad article number') - - - def do_HEAD(self, article = None): - defer = self.articleWork(article, 'HEAD', self.factory.backend.headRequest) - if defer: - defer.addCallbacks(self._gotHead, self._errHead) - - - def _gotHead(self, (index, id, head)): - self.currentIndex = index - self.sendLine('221 %d %s article retrieved' % (index, id)) - self.transport.write(head + '\r\n') - self.sendLine('.') - - - def _errHead(self, failure): - print 'HEAD failed: ', failure - self.sendLine('423 no such article number in this group') - - - def do_BODY(self, article): - defer = self.articleWork(article, 'BODY', self.factory.backend.bodyRequest) - if defer: - defer.addCallbacks(self._gotBody, self._errBody) - - - def _gotBody(self, (index, id, body)): - if isinstance(body, types.StringType): - import warnings - warnings.warn( - "Returning the article as a string from `articleRequest' " - "is deprecated. Return a file-like object instead." - ) - body = StringIO.StringIO(body) - self.currentIndex = index - self.sendLine('221 %d %s article retrieved' % (index, id)) - self.lastsent = '' - s = basic.FileSender() - d = s.beginFileTransfer(body, self.transport) - d.addCallback(self.finishedFileTransfer) - - def _errBody(self, failure): - print 'BODY failed: ', failure - self.sendLine('423 no such article number in this group') - - - # NEXT and LAST are just STATs that increment currentIndex first. - # Accordingly, use the STAT callbacks. - def do_NEXT(self): - i = self.currentIndex + 1 - defer = self.factory.backend.articleRequest(self.currentGroup, i) - defer.addCallbacks(self._gotStat, self._errStat) - - - def do_LAST(self): - i = self.currentIndex - 1 - defer = self.factory.backend.articleRequest(self.currentGroup, i) - defer.addCallbacks(self._gotStat, self._errStat) - - - def do_MODE(self, cmd): - cmd = cmd.strip().upper() - if cmd == 'READER': - self.servingSlave = 0 - self.sendLine('200 Hello, you can post') - elif cmd == 'STREAM': - self.sendLine('500 Command not understood') - else: - # This is not a mistake - self.sendLine('500 Command not understood') - - - def do_QUIT(self): - self.sendLine('205 goodbye') - self.transport.loseConnection() - - - def do_HELP(self): - self.sendLine('100 help text follows') - self.sendLine('Read the RFC.') - self.sendLine('.') - - - def do_SLAVE(self): - self.sendLine('202 slave status noted') - self.servingeSlave = 1 - - - def do_XPATH(self, article): - # XPATH is a silly thing to have. No client has the right to ask - # for this piece of information from me, and so that is what I'll - # tell them. - self.sendLine('502 access restriction or permission denied') - - - def do_XINDEX(self, article): - # XINDEX is another silly command. The RFC suggests it be relegated - # to the history books, and who am I to disagree? - self.sendLine('502 access restriction or permission denied') - - - def do_XROVER(self, range = None): - self.do_XHDR(self, 'References', range) - - - def do_IHAVE(self, id): - self.factory.backend.articleExistsRequest(id).addCallback(self._foundArticle) - - - def _foundArticle(self, result): - if result: - self.sendLine('437 article rejected - do not try again') - else: - self.sendLine('335 send article to be transferred. End with .') - self.inputHandler = self._handleIHAVE - self.message = '' - - - def _handleIHAVE(self, line): - if line == '.': - self.inputHandler = None - self.factory.backend.postRequest( - self.message - ).addCallbacks(self._gotIHAVE, self._errIHAVE) - - self.message = '' - else: - self.message = self.message + line + '\r\n' - - - def _gotIHAVE(self, result): - self.sendLine('235 article transferred ok') - - - def _errIHAVE(self, failure): - print 'IHAVE failed: ', failure - self.sendLine('436 transfer failed - try again later') - - -class UsenetClientProtocol(NNTPClient): - """ - A client that connects to an NNTP server and asks for articles new - since a certain time. - """ - - def __init__(self, groups, date, storage): - """ - Fetch all new articles from the given groups since the - given date and dump them into the given storage. groups - is a list of group names. date is an integer or floating - point representing seconds since the epoch (GMT). storage is - any object that implements the NewsStorage interface. - """ - NNTPClient.__init__(self) - self.groups, self.date, self.storage = groups, date, storage - - - def connectionMade(self): - NNTPClient.connectionMade(self) - log.msg("Initiating update with remote host: " + str(self.transport.getPeer())) - self.setStream() - self.fetchNewNews(self.groups, self.date, '') - - - def articleExists(self, exists, article): - if exists: - self.fetchArticle(article) - else: - self.count = self.count - 1 - self.disregard = self.disregard + 1 - - - def gotNewNews(self, news): - self.disregard = 0 - self.count = len(news) - log.msg("Transfering " + str(self.count) + " articles from remote host: " + str(self.transport.getPeer())) - for i in news: - self.storage.articleExistsRequest(i).addCallback(self.articleExists, i) - - - def getNewNewsFailed(self, reason): - log.msg("Updated failed (" + reason + ") with remote host: " + str(self.transport.getPeer())) - self.quit() - - - def gotArticle(self, article): - self.storage.postRequest(article) - self.count = self.count - 1 - if not self.count: - log.msg("Completed update with remote host: " + str(self.transport.getPeer())) - if self.disregard: - log.msg("Disregarded %d articles." % (self.disregard,)) - self.factory.updateChecks(self.transport.getPeer()) - self.quit() diff --git a/tools/buildbot/pylibs/twisted/news/tap.py b/tools/buildbot/pylibs/twisted/news/tap.py deleted file mode 100644 index 910e5da..0000000 --- a/tools/buildbot/pylibs/twisted/news/tap.py +++ /dev/null @@ -1,132 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -from twisted.news import news, database -from twisted.application import strports -from twisted.python import usage, log - -class DBOptions(usage.Options): - optParameters = [ - ['module', None, 'pyPgSQL.PgSQL', "DB-API 2.0 module to use"], - ['dbhost', None, 'localhost', "Host where database manager is listening"], - ['dbuser', None, 'news', "Username with which to connect to database"], - ['database', None, 'news', "Database name to use"], - ['schema', None, 'schema.sql', "File to which to write SQL schema initialisation"], - - # XXX - Hrm. - ["groups", "g", "groups.list", "File containing group list"], - ["servers", "s", "servers.list", "File containing server list"] - ] - - def postOptions(self): - # XXX - Hmmm. - self['groups'] = [g.strip() for g in open(self['groups']).readlines() if not g.startswith('#')] - self['servers'] = [s.strip() for s in open(self['servers']).readlines() if not s.startswith('#')] - - try: - __import__(self['module']) - except ImportError: - log.msg("Warning: Cannot import %s" % (self['module'],)) - - open(self['schema'], 'w').write( - database.NewsStorageAugmentation.schema + '\n' + - database.makeGroupSQL(self['groups']) + '\n' + - database.makeOverviewSQL() - ) - - info = { - 'host': self['dbhost'], 'user': self['dbuser'], - 'database': self['database'], 'dbapiName': self['module'] - } - self.db = database.NewsStorageAugmentation(info) - - -class PickleOptions(usage.Options): - optParameters = [ - ['file', None, 'news.pickle', "File to which to save pickle"], - - # XXX - Hrm. - ["groups", "g", "groups.list", "File containing group list"], - ["servers", "s", "servers.list", "File containing server list"], - ["moderators", "m", "moderators.list", - "File containing moderators list"], - ] - - subCommands = None - - def postOptions(self): - # XXX - Hmmm. - filename = self['file'] - self['groups'] = [g.strip() for g in open(self['groups']).readlines() - if not g.startswith('#')] - self['servers'] = [s.strip() for s in open(self['servers']).readlines() - if not s.startswith('#')] - self['moderators'] = [s.split() - for s in open(self['moderators']).readlines() - if not s.startswith('#')] - self.db = database.PickleStorage(filename, self['groups'], - self['moderators']) - - -class Options(usage.Options): - synopsis = "Usage: mktap news [options]" - - groups = None - servers = None - subscriptions = None - - optParameters = [ - ["port", "p", "119", "Listen port"], - ["interface", "i", "", "Interface to which to bind"], - ["datadir", "d", "news.db", "Root data storage path"], - ["mailhost", "m", "localhost", "Host of SMTP server to use"] - ] - zsh_actions = {"datadir" : "_dirs", "mailhost" : "_hosts"} - - def __init__(self): - usage.Options.__init__(self) - self.groups = [] - self.servers = [] - self.subscriptions = [] - - - def opt_group(self, group): - """The name of a newsgroup to carry.""" - self.groups.append([group, None]) - - - def opt_moderator(self, moderator): - """The email of the moderator for the most recently passed group.""" - self.groups[-1][1] = moderator - - - def opt_subscription(self, group): - """A newsgroup to list as a recommended subscription.""" - self.subscriptions.append(group) - - - def opt_server(self, server): - """The address of a Usenet server to pass messages to and receive messages from.""" - self.servers.append(server) - - -def makeService(config): - if not len(config.groups): - raise usage.UsageError("No newsgroups specified") - - db = database.NewsShelf(config['mailhost'], config['datadir']) - for (g, m) in config.groups: - if m: - db.addGroup(g, 'm') - db.addModerator(g, m) - else: - db.addGroup(g, 'y') - for s in config.subscriptions: - print s - db.addSubscription(s) - s = config['port'] - if config['interface']: - # Add a warning here - s += ':interface='+config['interface'] - return strports.service(s, news.UsenetServerFactory(db, config.servers)) diff --git a/tools/buildbot/pylibs/twisted/news/test/__init__.py b/tools/buildbot/pylibs/twisted/news/test/__init__.py deleted file mode 100644 index 677518d..0000000 --- a/tools/buildbot/pylibs/twisted/news/test/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""News Tests""" diff --git a/tools/buildbot/pylibs/twisted/news/test/test_news.py b/tools/buildbot/pylibs/twisted/news/test/test_news.py deleted file mode 100644 index f1fdaa7..0000000 --- a/tools/buildbot/pylibs/twisted/news/test/test_news.py +++ /dev/null @@ -1,107 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -import sys, types -from pprint import pformat - -from twisted.trial import unittest -from twisted.news import database -from twisted.internet import reactor - -MESSAGE_ID = "f83ba57450ed0fd8ac9a472b847e830e" - -POST_STRING = """Path: not-for-mail -From: -Subject: a test -Newsgroups: alt.test.nntp -Organization: -Summary: -Keywords: -Message-Id: %s -User-Agent: tin/1.4.5-20010409 ("One More Nightmare") (UNIX) (Linux/2.4.17 (i686)) - -this is a test -... -lala -moo --- -"One World, one Web, one Program." - Microsoft(R) promotional ad -"Ein Volk, ein Reich, ein Fuhrer." - Adolf Hitler --- - 10:56pm up 4 days, 4:42, 1 user, load average: 0.08, 0.08, 0.12 -""" % (MESSAGE_ID) - -class NewsTestCase(unittest.TestCase): - def setUp(self): - self.backend = database.NewsShelf(None, 'news2.db') - self.backend.addGroup('alt.test.nntp', 'y') - self.backend.postRequest(POST_STRING.replace('\n', '\r\n')) - - - def testArticleExists(self): - d = self.backend.articleExistsRequest(MESSAGE_ID) - d.addCallback(self.failUnless) - return d - - - def testArticleRequest(self): - d = self.backend.articleRequest(None, None, MESSAGE_ID) - - def cbArticle(result): - self.failUnless(isinstance(result, tuple), - 'callback result is wrong type: ' + str(result)) - self.assertEquals(len(result), 3, - 'callback result list should have three entries: ' + - str(result)) - self.assertEquals(result[1], MESSAGE_ID, - "callback result Message-Id doesn't match: %s vs %s" % - (MESSAGE_ID, result[1])) - body = result[2].read() - self.failIfEqual(body.find('\r\n\r\n'), -1, - "Can't find \\r\\n\\r\\n between header and body") - return result - - d.addCallback(cbArticle) - return d - - - def testHeadRequest(self): - d = self.testArticleRequest() - - def cbArticle(result): - index = result[0] - - d = self.backend.headRequest("alt.test.nntp", index) - d.addCallback(cbHead) - return d - - def cbHead(result): - self.assertEquals(result[1], MESSAGE_ID, - "callback result Message-Id doesn't match: %s vs %s" % - (MESSAGE_ID, result[1])) - - self.assertEquals(result[2][-2:], '\r\n', - "headers must be \\r\\n terminated.") - - d.addCallback(cbArticle) - return d - - - def testBodyRequest(self): - d = self.testArticleRequest() - - def cbArticle(result): - index = result[0] - - d = self.backend.bodyRequest("alt.test.nntp", index) - d.addCallback(cbBody) - return d - - def cbBody(result): - body = result[2].read() - self.assertEquals(body[0:4], 'this', - "message body has been altered: " + - pformat(body[0:4])) - - d.addCallback(cbArticle) - return d diff --git a/tools/buildbot/pylibs/twisted/news/test/test_nntp.py b/tools/buildbot/pylibs/twisted/news/test/test_nntp.py deleted file mode 100644 index 5a061db..0000000 --- a/tools/buildbot/pylibs/twisted/news/test/test_nntp.py +++ /dev/null @@ -1,124 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.trial import unittest -from twisted.news import database -from twisted.news import nntp -from twisted.protocols import loopback - -ALL_GROUPS = ('alt.test.nntp', 0, 1, 'y'), -GROUP = ('0', '1', '0', 'alt.test.nntp', 'group', 'selected') -SUBSCRIPTIONS = ['alt.test.nntp', 'news.testgroup'] - -POST_STRING = """Path: not-for-mail -From: -Subject: a test -Newsgroups: alt.test.nntp -Organization: -Summary: -Keywords: -User-Agent: tin/1.4.5-20010409 ("One More Nightmare") (UNIX) (Linux/2.4.17 (i686)) - -this is a test -. -.. -... -lala -moo --- -"One World, one Web, one Program." - Microsoft(R) promotional ad -"Ein Volk, ein Reich, ein Fuhrer." - Adolf Hitler --- - 10:56pm up 4 days, 4:42, 1 user, load average: 0.08, 0.08, 0.12 -""" - -class TestNNTPClient(nntp.NNTPClient): - def __init__(self): - nntp.NNTPClient.__init__(self) - - def assertEquals(self, foo, bar): - if foo != bar: raise AssertionError("%r != %r!" % (foo, bar)) - - def connectionMade(self): - nntp.NNTPClient.connectionMade(self) - self.fetchSubscriptions() - - - def gotSubscriptions(self, subscriptions): - self.assertEquals(len(subscriptions), len(SUBSCRIPTIONS)) - for s in subscriptions: - assert s in SUBSCRIPTIONS - - self.fetchGroups() - - def gotAllGroups(self, info): - self.assertEquals(len(info), len(ALL_GROUPS)) - self.assertEquals(info[0], ALL_GROUPS[0]) - - self.fetchGroup('alt.test.nntp') - - - def getAllGroupsFailed(self, error): - raise AssertionError("fetchGroups() failed: %s" % (error,)) - - - def gotGroup(self, info): - self.assertEquals(len(info), 6) - self.assertEquals(info, GROUP) - - self.postArticle(POST_STRING) - - - def getSubscriptionsFailed(self, error): - raise AssertionError("fetchSubscriptions() failed: %s" % (error,)) - - - def getGroupFailed(self, error): - raise AssertionError("fetchGroup() failed: %s" % (error,)) - - - def postFailed(self, error): - raise AssertionError("postArticle() failed: %s" % (error,)) - - - def postedOk(self): - self.fetchArticle(1) - - - def gotArticle(self, info): - origBody = POST_STRING.split('\n\n')[1] - newBody = info.split('\n\n', 1)[1] - - self.assertEquals(origBody, newBody) - - # We're done - self.transport.loseConnection() - - - def getArticleFailed(self, error): - raise AssertionError("fetchArticle() failed: %s" % (error,)) - - -class NNTPTestCase(unittest.TestCase): - def setUp(self): - self.server = nntp.NNTPServer() - self.server.factory = self - self.backend = database.NewsShelf(None, 'news.db') - self.backend.addGroup('alt.test.nntp', 'y') - - for s in SUBSCRIPTIONS: - self.backend.addSubscription(s) - - self.client = TestNNTPClient() - - def testLoopback(self): - return loopback.loopbackAsync(self.server, self.client) - - # XXX This test is woefully incomplete. It tests the single - # most common code path and nothing else. Expand it and the - # test fairy will leave you a surprise. - - # reactor.iterate(1) # fetchGroups() - # reactor.iterate(1) # fetchGroup() - # reactor.iterate(1) # postArticle() - diff --git a/tools/buildbot/pylibs/twisted/news/topfiles/NEWS b/tools/buildbot/pylibs/twisted/news/topfiles/NEWS deleted file mode 100644 index bf4b031..0000000 --- a/tools/buildbot/pylibs/twisted/news/topfiles/NEWS +++ /dev/null @@ -1,31 +0,0 @@ -8.1.0 (2008-05-18) -================== - -Fixes ------ - - The deprecated mktap API is no longer used (#3127) - - -8.0.0 (2008-03-17) -================== - -Misc ----- - - Remove all "API Stability" markers (#2847) - - -0.3.0 (2007-01-06) -================== -Fixes ------ - - News was updated to work with the latest twisted.components changes - to Twisted (#1636) - - The 'ip' attribute is no longer available on NNTP protocols (#1936) - - -0.2.0 (2006-05-24) -================== - -Fixes: - - Fixed a critical bug in moderation support. - diff --git a/tools/buildbot/pylibs/twisted/news/topfiles/README b/tools/buildbot/pylibs/twisted/news/topfiles/README deleted file mode 100644 index eb56818..0000000 --- a/tools/buildbot/pylibs/twisted/news/topfiles/README +++ /dev/null @@ -1,4 +0,0 @@ -Twisted News 8.1.0 - -News depends on Twisted, and, if you want to use the moderation -features, Twisted Mail. diff --git a/tools/buildbot/pylibs/twisted/news/topfiles/setup.py b/tools/buildbot/pylibs/twisted/news/topfiles/setup.py deleted file mode 100644 index 89646e9..0000000 --- a/tools/buildbot/pylibs/twisted/news/topfiles/setup.py +++ /dev/null @@ -1,27 +0,0 @@ - -try: - from twisted.python import dist -except ImportError: - raise SystemExit("twisted.python.dist module not found. Make sure you " - "have installed the Twisted core package before " - "attempting to install any other Twisted projects.") - -if __name__ == '__main__': - dist.setup( - twisted_subproject="news", - # metadata - name="Twisted News", - description="Twisted News is an NNTP server and programming library.", - author="Twisted Matrix Laboratories", - author_email="twisted-python@twistedmatrix.com", - maintainer="Jp Calderone", - maintainer_email="exarkun@divmod.com", - url="http://twistedmatrix.com/trac/wiki/TwistedNews", - license="MIT", - long_description="""\ -Twisted News is an NNTP protocol (Usenet) programming library. The -library contains server and client protocol implementations. A simple -NNTP server is also provided. -""", - ) - diff --git a/tools/buildbot/pylibs/twisted/pair/__init__.py b/tools/buildbot/pylibs/twisted/pair/__init__.py deleted file mode 100644 index 7535bc0..0000000 --- a/tools/buildbot/pylibs/twisted/pair/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" - -Twisted Pair: The framework of your ethernet. - -Low-level networking transports and utilities. - -See also twisted.protocols.ethernet, twisted.protocols.ip, -twisted.protocols.raw and twisted.protocols.rawudp. - -Maintainer: U{Tommi Virtanen } - -""" - -from twisted.pair._version import version -__version__ = version.short() diff --git a/tools/buildbot/pylibs/twisted/pair/_version.py b/tools/buildbot/pylibs/twisted/pair/_version.py deleted file mode 100644 index 9d0784e..0000000 --- a/tools/buildbot/pylibs/twisted/pair/_version.py +++ /dev/null @@ -1,3 +0,0 @@ -# This is an auto-generated file. Do not edit it. -from twisted.python import versions -version = versions.Version('twisted.pair', 8, 0, 0) diff --git a/tools/buildbot/pylibs/twisted/pair/ethernet.py b/tools/buildbot/pylibs/twisted/pair/ethernet.py deleted file mode 100644 index 6d5c36e..0000000 --- a/tools/buildbot/pylibs/twisted/pair/ethernet.py +++ /dev/null @@ -1,56 +0,0 @@ -# -*- test-case-name: twisted.pair.test.test_ethernet -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - - -"""Support for working directly with ethernet frames""" - -import struct - - -from twisted.internet import protocol -from twisted.pair import raw -from zope.interface import implements, Interface - - -class IEthernetProtocol(Interface): - """An interface for protocols that handle Ethernet frames""" - def addProto(): - """Add an IRawPacketProtocol protocol""" - - def datagramReceived(): - """An Ethernet frame has been received""" - -class EthernetHeader: - def __init__(self, data): - - (self.dest, self.source, self.proto) \ - = struct.unpack("!6s6sH", data[:6+6+2]) - -class EthernetProtocol(protocol.AbstractDatagramProtocol): - - implements(IEthernetProtocol) - - def __init__(self): - self.etherProtos = {} - - def addProto(self, num, proto): - proto = raw.IRawPacketProtocol(proto) - if num < 0: - raise TypeError, 'Added protocol must be positive or zero' - if num >= 2**16: - raise TypeError, 'Added protocol must fit in 16 bits' - if num not in self.etherProtos: - self.etherProtos[num] = [] - self.etherProtos[num].append(proto) - - def datagramReceived(self, data, partial=0): - header = EthernetHeader(data[:14]) - for proto in self.etherProtos.get(header.proto, ()): - proto.datagramReceived(data=data[14:], - partial=partial, - dest=header.dest, - source=header.source, - protocol=header.proto) diff --git a/tools/buildbot/pylibs/twisted/pair/ip.py b/tools/buildbot/pylibs/twisted/pair/ip.py deleted file mode 100644 index 245a7d9..0000000 --- a/tools/buildbot/pylibs/twisted/pair/ip.py +++ /dev/null @@ -1,72 +0,0 @@ -# -*- test-case-name: twisted.pair.test.test_ip -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - - -"""Support for working directly with IP packets""" - -import struct -import socket - -from twisted.internet import protocol -from twisted.pair import raw -from zope.interface import implements - - -class IPHeader: - def __init__(self, data): - - (ihlversion, self.tos, self.tot_len, self.fragment_id, frag_off, - self.ttl, self.protocol, self.check, saddr, daddr) \ - = struct.unpack("!BBHHHBBH4s4s", data[:20]) - self.saddr = socket.inet_ntoa(saddr) - self.daddr = socket.inet_ntoa(daddr) - self.version = ihlversion & 0x0F - self.ihl = ((ihlversion & 0xF0) >> 4) << 2 - self.fragment_offset = frag_off & 0x1FFF - self.dont_fragment = (frag_off & 0x4000 != 0) - self.more_fragments = (frag_off & 0x2000 != 0) - -MAX_SIZE = 2L**32 - -class IPProtocol(protocol.AbstractDatagramProtocol): - implements(raw.IRawPacketProtocol) - - def __init__(self): - self.ipProtos = {} - - def addProto(self, num, proto): - proto = raw.IRawDatagramProtocol(proto) - if num < 0: - raise TypeError, 'Added protocol must be positive or zero' - if num >= MAX_SIZE: - raise TypeError, 'Added protocol must fit in 32 bits' - if num not in self.ipProtos: - self.ipProtos[num] = [] - self.ipProtos[num].append(proto) - - def datagramReceived(self, - data, - partial, - dest, - source, - protocol): - header = IPHeader(data) - for proto in self.ipProtos.get(header.protocol, ()): - proto.datagramReceived(data=data[20:], - partial=partial, - source=header.saddr, - dest=header.daddr, - protocol=header.protocol, - version=header.version, - ihl=header.ihl, - tos=header.tos, - tot_len=header.tot_len, - fragment_id=header.fragment_id, - fragment_offset=header.fragment_offset, - dont_fragment=header.dont_fragment, - more_fragments=header.more_fragments, - ttl=header.ttl, - ) diff --git a/tools/buildbot/pylibs/twisted/pair/raw.py b/tools/buildbot/pylibs/twisted/pair/raw.py deleted file mode 100644 index a1866a8..0000000 --- a/tools/buildbot/pylibs/twisted/pair/raw.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -"""Interface definitions for working with raw packets""" - -from twisted.internet import protocol -from zope.interface import Interface - -class IRawDatagramProtocol(Interface): - """An interface for protocols such as UDP, ICMP and TCP.""" - - def addProto(): - """ - Add a protocol on top of this one. - """ - - def datagramReceived(): - """ - An IP datagram has been received. Parse and process it. - """ - -class IRawPacketProtocol(Interface): - """An interface for low-level protocols such as IP and ARP.""" - - def addProto(): - """ - Add a protocol on top of this one. - """ - - def datagramReceived(): - """ - An IP datagram has been received. Parse and process it. - """ diff --git a/tools/buildbot/pylibs/twisted/pair/rawudp.py b/tools/buildbot/pylibs/twisted/pair/rawudp.py deleted file mode 100644 index 42f1d2f..0000000 --- a/tools/buildbot/pylibs/twisted/pair/rawudp.py +++ /dev/null @@ -1,55 +0,0 @@ -# -*- test-case-name: twisted.pair.test.test_rawudp -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -"""Implementation of raw packet interfaces for UDP""" - -import struct - -from twisted.internet import protocol -from twisted.pair import raw -from zope.interface import implements - -class UDPHeader: - def __init__(self, data): - - (self.source, self.dest, self.len, self.check) \ - = struct.unpack("!HHHH", data[:8]) - -class RawUDPProtocol(protocol.AbstractDatagramProtocol): - implements(raw.IRawDatagramProtocol) - def __init__(self): - self.udpProtos = {} - - def addProto(self, num, proto): - if not isinstance(proto, protocol.DatagramProtocol): - raise TypeError, 'Added protocol must be an instance of DatagramProtocol' - if num < 0: - raise TypeError, 'Added protocol must be positive or zero' - if num >= 2**16: - raise TypeError, 'Added protocol must fit in 16 bits' - if num not in self.udpProtos: - self.udpProtos[num] = [] - self.udpProtos[num].append(proto) - - def datagramReceived(self, - data, - partial, - source, - dest, - protocol, - version, - ihl, - tos, - tot_len, - fragment_id, - fragment_offset, - dont_fragment, - more_fragments, - ttl): - header = UDPHeader(data) - for proto in self.udpProtos.get(header.dest, ()): - proto.datagramReceived(data[8:], - (source, header.source)) diff --git a/tools/buildbot/pylibs/twisted/pair/test/__init__.py b/tools/buildbot/pylibs/twisted/pair/test/__init__.py deleted file mode 100644 index 5aa286e..0000000 --- a/tools/buildbot/pylibs/twisted/pair/test/__init__.py +++ /dev/null @@ -1 +0,0 @@ -'pair tests' diff --git a/tools/buildbot/pylibs/twisted/pair/test/test_ethernet.py b/tools/buildbot/pylibs/twisted/pair/test/test_ethernet.py deleted file mode 100644 index 1cd1619..0000000 --- a/tools/buildbot/pylibs/twisted/pair/test/test_ethernet.py +++ /dev/null @@ -1,226 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -from twisted.trial import unittest - -from twisted.internet import protocol, reactor, error -from twisted.python import failure, components -from twisted.pair import ethernet, raw -from zope.interface import implements - -class MyProtocol: - implements(raw.IRawPacketProtocol) - - def __init__(self, expecting): - self.expecting = list(expecting) - - def datagramReceived(self, data, **kw): - assert self.expecting, 'Got a packet when not expecting anymore.' - expect = self.expecting.pop(0) - assert expect == (data, kw), \ - "Expected %r, got %r" % ( - expect, (data, kw), - ) - -class EthernetTestCase(unittest.TestCase): - def testPacketParsing(self): - proto = ethernet.EthernetProtocol() - p1 = MyProtocol([ - - ('foobar', { - 'partial': 0, - 'dest': "123456", - 'source': "987654", - 'protocol': 0x0800, - }), - - ]) - proto.addProto(0x0800, p1) - - proto.datagramReceived("123456987654\x08\x00foobar", - partial=0) - - assert not p1.expecting, \ - 'Should not expect any more packets, but still want %r' % p1.expecting - - - def testMultiplePackets(self): - proto = ethernet.EthernetProtocol() - p1 = MyProtocol([ - - ('foobar', { - 'partial': 0, - 'dest': "123456", - 'source': "987654", - 'protocol': 0x0800, - }), - - ('quux', { - 'partial': 1, - 'dest': "012345", - 'source': "abcdef", - 'protocol': 0x0800, - }), - - ]) - proto.addProto(0x0800, p1) - - proto.datagramReceived("123456987654\x08\x00foobar", - partial=0) - proto.datagramReceived("012345abcdef\x08\x00quux", - partial=1) - - assert not p1.expecting, \ - 'Should not expect any more packets, but still want %r' % p1.expecting - - - def testMultipleSameProtos(self): - proto = ethernet.EthernetProtocol() - p1 = MyProtocol([ - - ('foobar', { - 'partial': 0, - 'dest': "123456", - 'source': "987654", - 'protocol': 0x0800, - }), - - ]) - - p2 = MyProtocol([ - - ('foobar', { - 'partial': 0, - 'dest': "123456", - 'source': "987654", - 'protocol': 0x0800, - }), - - ]) - - proto.addProto(0x0800, p1) - proto.addProto(0x0800, p2) - - proto.datagramReceived("123456987654\x08\x00foobar", - partial=0) - - assert not p1.expecting, \ - 'Should not expect any more packets, but still want %r' % p1.expecting - assert not p2.expecting, \ - 'Should not expect any more packets, but still want %r' % p2.expecting - - def testWrongProtoNotSeen(self): - proto = ethernet.EthernetProtocol() - p1 = MyProtocol([]) - proto.addProto(0x0801, p1) - - proto.datagramReceived("123456987654\x08\x00foobar", - partial=0) - proto.datagramReceived("012345abcdef\x08\x00quux", - partial=1) - - def testDemuxing(self): - proto = ethernet.EthernetProtocol() - p1 = MyProtocol([ - - ('foobar', { - 'partial': 0, - 'dest': "123456", - 'source': "987654", - 'protocol': 0x0800, - }), - - ('quux', { - 'partial': 1, - 'dest': "012345", - 'source': "abcdef", - 'protocol': 0x0800, - }), - - ]) - proto.addProto(0x0800, p1) - - p2 = MyProtocol([ - - ('quux', { - 'partial': 1, - 'dest': "012345", - 'source': "abcdef", - 'protocol': 0x0806, - }), - - ('foobar', { - 'partial': 0, - 'dest': "123456", - 'source': "987654", - 'protocol': 0x0806, - }), - - ]) - proto.addProto(0x0806, p2) - - proto.datagramReceived("123456987654\x08\x00foobar", - partial=0) - proto.datagramReceived("012345abcdef\x08\x06quux", - partial=1) - proto.datagramReceived("123456987654\x08\x06foobar", - partial=0) - proto.datagramReceived("012345abcdef\x08\x00quux", - partial=1) - - assert not p1.expecting, \ - 'Should not expect any more packets, but still want %r' % p1.expecting - assert not p2.expecting, \ - 'Should not expect any more packets, but still want %r' % p2.expecting - - def testAddingBadProtos_WrongLevel(self): - """Adding a wrong level protocol raises an exception.""" - e = ethernet.EthernetProtocol() - try: - e.addProto(42, "silliness") - except components.CannotAdapt: - pass - else: - raise AssertionError, 'addProto must raise an exception for bad protocols' - - - def testAddingBadProtos_TooSmall(self): - """Adding a protocol with a negative number raises an exception.""" - e = ethernet.EthernetProtocol() - try: - e.addProto(-1, MyProtocol([])) - except TypeError, e: - if e.args == ('Added protocol must be positive or zero',): - pass - else: - raise - else: - raise AssertionError, 'addProto must raise an exception for bad protocols' - - - def testAddingBadProtos_TooBig(self): - """Adding a protocol with a number >=2**16 raises an exception.""" - e = ethernet.EthernetProtocol() - try: - e.addProto(2**16, MyProtocol([])) - except TypeError, e: - if e.args == ('Added protocol must fit in 16 bits',): - pass - else: - raise - else: - raise AssertionError, 'addProto must raise an exception for bad protocols' - - def testAddingBadProtos_TooBig2(self): - """Adding a protocol with a number >=2**16 raises an exception.""" - e = ethernet.EthernetProtocol() - try: - e.addProto(2**16+1, MyProtocol([])) - except TypeError, e: - if e.args == ('Added protocol must fit in 16 bits',): - pass - else: - raise - else: - raise AssertionError, 'addProto must raise an exception for bad protocols' diff --git a/tools/buildbot/pylibs/twisted/pair/test/test_ip.py b/tools/buildbot/pylibs/twisted/pair/test/test_ip.py deleted file mode 100644 index 321ba10..0000000 --- a/tools/buildbot/pylibs/twisted/pair/test/test_ip.py +++ /dev/null @@ -1,417 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -from twisted.trial import unittest - -from twisted.internet import protocol, reactor, error -from twisted.python import failure, components -from twisted.pair import ip, raw -from zope import interface - -class MyProtocol: - interface.implements(raw.IRawDatagramProtocol) - - def __init__(self, expecting): - self.expecting = list(expecting) - - def datagramReceived(self, data, **kw): - assert self.expecting, 'Got a packet when not expecting anymore.' - expectData, expectKw = self.expecting.pop(0) - - expectKwKeys = expectKw.keys(); expectKwKeys.sort() - kwKeys = kw.keys(); kwKeys.sort() - assert expectKwKeys == kwKeys, "Expected %r, got %r" % (expectKwKeys, kwKeys) - - for k in expectKwKeys: - assert expectKw[k] == kw[k], "Expected %s=%r, got %r" % (k, expectKw[k], kw[k]) - assert expectKw == kw, "Expected %r, got %r" % (expectKw, kw) - assert expectData == data, "Expected %r, got %r" % (expectData, data) - -class IPTestCase(unittest.TestCase): - def testPacketParsing(self): - proto = ip.IPProtocol() - p1 = MyProtocol([ - - ('foobar', { - 'partial': 0, - 'dest': '1.2.3.4', - 'source': '5.6.7.8', - 'protocol': 0x0F, - 'version': 4, - 'ihl': 20, - 'tos': 7, - 'tot_len': 20+6, - 'fragment_id': 0xDEAD, - 'fragment_offset': 0x1EEF, - 'dont_fragment': 0, - 'more_fragments': 1, - 'ttl': 0xC0, - }), - - ]) - proto.addProto(0x0F, p1) - - proto.datagramReceived("\x54" #ihl version - + "\x07" #tos - + "\x00\x1a" #tot_len - + "\xDE\xAD" #id - + "\xBE\xEF" #frag_off - + "\xC0" #ttl - + "\x0F" #protocol - + "FE" #checksum - + "\x05\x06\x07\x08" + "\x01\x02\x03\x04" + "foobar", - partial=0, - dest='dummy', - source='dummy', - protocol='dummy', - ) - - assert not p1.expecting, \ - 'Should not expect any more packets, but still want %r' % p1.expecting - - def testMultiplePackets(self): - proto = ip.IPProtocol() - p1 = MyProtocol([ - - ('foobar', { - 'partial': 0, - 'dest': '1.2.3.4', - 'source': '5.6.7.8', - 'protocol': 0x0F, - 'version': 4, - 'ihl': 20, - 'tos': 7, - 'tot_len': 20+6, - 'fragment_id': 0xDEAD, - 'fragment_offset': 0x1EEF, - 'dont_fragment': 0, - 'more_fragments': 1, - 'ttl': 0xC0, - }), - - ('quux', { - 'partial': 1, - 'dest': '5.4.3.2', - 'source': '6.7.8.9', - 'protocol': 0x0F, - 'version': 4, - 'ihl': 20, - 'tos': 7, - 'tot_len': 20+6, - 'fragment_id': 0xDEAD, - 'fragment_offset': 0x1EEF, - 'dont_fragment': 0, - 'more_fragments': 1, - 'ttl': 0xC0, - }), - - ]) - proto.addProto(0x0F, p1) - proto.datagramReceived("\x54" #ihl version - + "\x07" #tos - + "\x00\x1a" #tot_len - + "\xDE\xAD" #id - + "\xBE\xEF" #frag_off - + "\xC0" #ttl - + "\x0F" #protocol - + "FE" #checksum - + "\x05\x06\x07\x08" + "\x01\x02\x03\x04" + "foobar", - partial=0, - dest='dummy', - source='dummy', - protocol='dummy', - ) - proto.datagramReceived("\x54" #ihl version - + "\x07" #tos - + "\x00\x1a" #tot_len - + "\xDE\xAD" #id - + "\xBE\xEF" #frag_off - + "\xC0" #ttl - + "\x0F" #protocol - + "FE" #checksum - + "\x06\x07\x08\x09" + "\x05\x04\x03\x02" + "quux", - partial=1, - dest='dummy', - source='dummy', - protocol='dummy', - ) - - assert not p1.expecting, \ - 'Should not expect any more packets, but still want %r' % p1.expecting - - - def testMultipleSameProtos(self): - proto = ip.IPProtocol() - p1 = MyProtocol([ - - ('foobar', { - 'partial': 0, - 'dest': '1.2.3.4', - 'source': '5.6.7.8', - 'protocol': 0x0F, - 'version': 4, - 'ihl': 20, - 'tos': 7, - 'tot_len': 20+6, - 'fragment_id': 0xDEAD, - 'fragment_offset': 0x1EEF, - 'dont_fragment': 0, - 'more_fragments': 1, - 'ttl': 0xC0, - }), - - ]) - - p2 = MyProtocol([ - - ('foobar', { - 'partial': 0, - 'dest': '1.2.3.4', - 'source': '5.6.7.8', - 'protocol': 0x0F, - 'version': 4, - 'ihl': 20, - 'tos': 7, - 'tot_len': 20+6, - 'fragment_id': 0xDEAD, - 'fragment_offset': 0x1EEF, - 'dont_fragment': 0, - 'more_fragments': 1, - 'ttl': 0xC0, - }), - - ]) - - proto.addProto(0x0F, p1) - proto.addProto(0x0F, p2) - - proto.datagramReceived("\x54" #ihl version - + "\x07" #tos - + "\x00\x1a" #tot_len - + "\xDE\xAD" #id - + "\xBE\xEF" #frag_off - + "\xC0" #ttl - + "\x0F" #protocol - + "FE" #checksum - + "\x05\x06\x07\x08" + "\x01\x02\x03\x04" + "foobar", - partial=0, - dest='dummy', - source='dummy', - protocol='dummy', - ) - - assert not p1.expecting, \ - 'Should not expect any more packets, but still want %r' % p1.expecting - assert not p2.expecting, \ - 'Should not expect any more packets, but still want %r' % p2.expecting - - def testWrongProtoNotSeen(self): - proto = ip.IPProtocol() - p1 = MyProtocol([]) - proto.addProto(1, p1) - - proto.datagramReceived("\x54" #ihl version - + "\x07" #tos - + "\x00\x1a" #tot_len - + "\xDE\xAD" #id - + "\xBE\xEF" #frag_off - + "\xC0" #ttl - + "\x0F" #protocol - + "FE" #checksum - + "\x05\x06\x07\x08" + "\x01\x02\x03\x04" + "foobar", - partial=0, - dest='dummy', - source='dummy', - protocol='dummy', - ) - - def testDemuxing(self): - proto = ip.IPProtocol() - p1 = MyProtocol([ - - ('foobar', { - 'partial': 0, - 'dest': '1.2.3.4', - 'source': '5.6.7.8', - 'protocol': 0x0F, - 'version': 4, - 'ihl': 20, - 'tos': 7, - 'tot_len': 20+6, - 'fragment_id': 0xDEAD, - 'fragment_offset': 0x1EEF, - 'dont_fragment': 0, - 'more_fragments': 1, - 'ttl': 0xC0, - }), - - ('quux', { - 'partial': 1, - 'dest': '5.4.3.2', - 'source': '6.7.8.9', - 'protocol': 0x0F, - 'version': 4, - 'ihl': 20, - 'tos': 7, - 'tot_len': 20+6, - 'fragment_id': 0xDEAD, - 'fragment_offset': 0x1EEF, - 'dont_fragment': 0, - 'more_fragments': 1, - 'ttl': 0xC0, - }), - - ]) - proto.addProto(0x0F, p1) - - p2 = MyProtocol([ - - ('quux', { - 'partial': 1, - 'dest': '5.4.3.2', - 'source': '6.7.8.9', - 'protocol': 0x0A, - 'version': 4, - 'ihl': 20, - 'tos': 7, - 'tot_len': 20+6, - 'fragment_id': 0xDEAD, - 'fragment_offset': 0x1EEF, - 'dont_fragment': 0, - 'more_fragments': 1, - 'ttl': 0xC0, - }), - - ('foobar', { - 'partial': 0, - 'dest': '1.2.3.4', - 'source': '5.6.7.8', - 'protocol': 0x0A, - 'version': 4, - 'ihl': 20, - 'tos': 7, - 'tot_len': 20+6, - 'fragment_id': 0xDEAD, - 'fragment_offset': 0x1EEF, - 'dont_fragment': 0, - 'more_fragments': 1, - 'ttl': 0xC0, - }), - - - ]) - proto.addProto(0x0A, p2) - - proto.datagramReceived("\x54" #ihl version - + "\x07" #tos - + "\x00\x1a" #tot_len - + "\xDE\xAD" #id - + "\xBE\xEF" #frag_off - + "\xC0" #ttl - + "\x0A" #protocol - + "FE" #checksum - + "\x06\x07\x08\x09" + "\x05\x04\x03\x02" + "quux", - partial=1, - dest='dummy', - source='dummy', - protocol='dummy', - ) - proto.datagramReceived("\x54" #ihl version - + "\x07" #tos - + "\x00\x1a" #tot_len - + "\xDE\xAD" #id - + "\xBE\xEF" #frag_off - + "\xC0" #ttl - + "\x0F" #protocol - + "FE" #checksum - + "\x05\x06\x07\x08" + "\x01\x02\x03\x04" + "foobar", - partial=0, - dest='dummy', - source='dummy', - protocol='dummy', - ) - proto.datagramReceived("\x54" #ihl version - + "\x07" #tos - + "\x00\x1a" #tot_len - + "\xDE\xAD" #id - + "\xBE\xEF" #frag_off - + "\xC0" #ttl - + "\x0F" #protocol - + "FE" #checksum - + "\x06\x07\x08\x09" + "\x05\x04\x03\x02" + "quux", - partial=1, - dest='dummy', - source='dummy', - protocol='dummy', - ) - proto.datagramReceived("\x54" #ihl version - + "\x07" #tos - + "\x00\x1a" #tot_len - + "\xDE\xAD" #id - + "\xBE\xEF" #frag_off - + "\xC0" #ttl - + "\x0A" #protocol - + "FE" #checksum - + "\x05\x06\x07\x08" + "\x01\x02\x03\x04" + "foobar", - partial=0, - dest='dummy', - source='dummy', - protocol='dummy', - ) - - assert not p1.expecting, \ - 'Should not expect any more packets, but still want %r' % p1.expecting - assert not p2.expecting, \ - 'Should not expect any more packets, but still want %r' % p2.expecting - - def testAddingBadProtos_WrongLevel(self): - """Adding a wrong level protocol raises an exception.""" - e = ip.IPProtocol() - try: - e.addProto(42, "silliness") - except components.CannotAdapt: - pass - else: - raise AssertionError, 'addProto must raise an exception for bad protocols' - - - def testAddingBadProtos_TooSmall(self): - """Adding a protocol with a negative number raises an exception.""" - e = ip.IPProtocol() - try: - e.addProto(-1, MyProtocol([])) - except TypeError, e: - if e.args == ('Added protocol must be positive or zero',): - pass - else: - raise - else: - raise AssertionError, 'addProto must raise an exception for bad protocols' - - - def testAddingBadProtos_TooBig(self): - """Adding a protocol with a number >=2**32 raises an exception.""" - e = ip.IPProtocol() - try: - e.addProto(2L**32, MyProtocol([])) - except TypeError, e: - if e.args == ('Added protocol must fit in 32 bits',): - pass - else: - raise - else: - raise AssertionError, 'addProto must raise an exception for bad protocols' - - def testAddingBadProtos_TooBig2(self): - """Adding a protocol with a number >=2**32 raises an exception.""" - e = ip.IPProtocol() - try: - e.addProto(2L**32+1, MyProtocol([])) - except TypeError, e: - if e.args == ('Added protocol must fit in 32 bits',): - pass - else: - raise - else: - raise AssertionError, 'addProto must raise an exception for bad protocols' diff --git a/tools/buildbot/pylibs/twisted/pair/test/test_rawudp.py b/tools/buildbot/pylibs/twisted/pair/test/test_rawudp.py deleted file mode 100644 index 8e4bc4d..0000000 --- a/tools/buildbot/pylibs/twisted/pair/test/test_rawudp.py +++ /dev/null @@ -1,327 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -from twisted.trial import unittest - -from twisted.internet import protocol, reactor, error -from twisted.python import failure -from twisted.pair import rawudp - -class MyProtocol(protocol.DatagramProtocol): - def __init__(self, expecting): - self.expecting = list(expecting) - - def datagramReceived(self, data, (host, port)): - assert self.expecting, 'Got a packet when not expecting anymore.' - expectData, expectHost, expectPort = self.expecting.pop(0) - - assert expectData == data, "Expected data %r, got %r" % (expectData, data) - assert expectHost == host, "Expected host %r, got %r" % (expectHost, host) - assert expectPort == port, "Expected port %d=0x%04x, got %d=0x%04x" % (expectPort, expectPort, port, port) - -class RawUDPTestCase(unittest.TestCase): - def testPacketParsing(self): - proto = rawudp.RawUDPProtocol() - p1 = MyProtocol([ - - ('foobar', 'testHost', 0x43A2), - - ]) - proto.addProto(0xF00F, p1) - - proto.datagramReceived("\x43\xA2" #source - + "\xf0\x0f" #dest - + "\x00\x06" #len - + "\xDE\xAD" #check - + "foobar", - partial=0, - dest='dummy', - source='testHost', - protocol='dummy', - version='dummy', - ihl='dummy', - tos='dummy', - tot_len='dummy', - fragment_id='dummy', - fragment_offset='dummy', - dont_fragment='dummy', - more_fragments='dummy', - ttl='dummy', - ) - - assert not p1.expecting, \ - 'Should not expect any more packets, but still want %r' % p1.expecting - - def testMultiplePackets(self): - proto = rawudp.RawUDPProtocol() - p1 = MyProtocol([ - - ('foobar', 'testHost', 0x43A2), - ('quux', 'otherHost', 0x33FE), - - ]) - proto.addProto(0xF00F, p1) - proto.datagramReceived("\x43\xA2" #source - + "\xf0\x0f" #dest - + "\x00\x06" #len - + "\xDE\xAD" #check - + "foobar", - partial=0, - dest='dummy', - source='testHost', - protocol='dummy', - version='dummy', - ihl='dummy', - tos='dummy', - tot_len='dummy', - fragment_id='dummy', - fragment_offset='dummy', - dont_fragment='dummy', - more_fragments='dummy', - ttl='dummy', - ) - proto.datagramReceived("\x33\xFE" #source - + "\xf0\x0f" #dest - + "\x00\x05" #len - + "\xDE\xAD" #check - + "quux", - partial=0, - dest='dummy', - source='otherHost', - protocol='dummy', - version='dummy', - ihl='dummy', - tos='dummy', - tot_len='dummy', - fragment_id='dummy', - fragment_offset='dummy', - dont_fragment='dummy', - more_fragments='dummy', - ttl='dummy', - ) - - assert not p1.expecting, \ - 'Should not expect any more packets, but still want %r' % p1.expecting - - - def testMultipleSameProtos(self): - proto = rawudp.RawUDPProtocol() - p1 = MyProtocol([ - - ('foobar', 'testHost', 0x43A2), - - ]) - - p2 = MyProtocol([ - - ('foobar', 'testHost', 0x43A2), - - ]) - - proto.addProto(0xF00F, p1) - proto.addProto(0xF00F, p2) - - proto.datagramReceived("\x43\xA2" #source - + "\xf0\x0f" #dest - + "\x00\x06" #len - + "\xDE\xAD" #check - + "foobar", - partial=0, - dest='dummy', - source='testHost', - protocol='dummy', - version='dummy', - ihl='dummy', - tos='dummy', - tot_len='dummy', - fragment_id='dummy', - fragment_offset='dummy', - dont_fragment='dummy', - more_fragments='dummy', - ttl='dummy', - ) - - assert not p1.expecting, \ - 'Should not expect any more packets, but still want %r' % p1.expecting - assert not p2.expecting, \ - 'Should not expect any more packets, but still want %r' % p2.expecting - - def testWrongProtoNotSeen(self): - proto = rawudp.RawUDPProtocol() - p1 = MyProtocol([]) - proto.addProto(1, p1) - - proto.datagramReceived("\x43\xA2" #source - + "\xf0\x0f" #dest - + "\x00\x06" #len - + "\xDE\xAD" #check - + "foobar", - partial=0, - dest='dummy', - source='testHost', - protocol='dummy', - version='dummy', - ihl='dummy', - tos='dummy', - tot_len='dummy', - fragment_id='dummy', - fragment_offset='dummy', - dont_fragment='dummy', - more_fragments='dummy', - ttl='dummy', - ) - - def testDemuxing(self): - proto = rawudp.RawUDPProtocol() - p1 = MyProtocol([ - - ('foobar', 'testHost', 0x43A2), - ('quux', 'otherHost', 0x33FE), - - ]) - proto.addProto(0xF00F, p1) - - p2 = MyProtocol([ - - ('quux', 'otherHost', 0xA401), - ('foobar', 'testHost', 0xA302), - - ]) - proto.addProto(0xB050, p2) - - proto.datagramReceived("\xA4\x01" #source - + "\xB0\x50" #dest - + "\x00\x05" #len - + "\xDE\xAD" #check - + "quux", - partial=0, - dest='dummy', - source='otherHost', - protocol='dummy', - version='dummy', - ihl='dummy', - tos='dummy', - tot_len='dummy', - fragment_id='dummy', - fragment_offset='dummy', - dont_fragment='dummy', - more_fragments='dummy', - ttl='dummy', - ) - proto.datagramReceived("\x43\xA2" #source - + "\xf0\x0f" #dest - + "\x00\x06" #len - + "\xDE\xAD" #check - + "foobar", - partial=0, - dest='dummy', - source='testHost', - protocol='dummy', - version='dummy', - ihl='dummy', - tos='dummy', - tot_len='dummy', - fragment_id='dummy', - fragment_offset='dummy', - dont_fragment='dummy', - more_fragments='dummy', - ttl='dummy', - ) - proto.datagramReceived("\x33\xFE" #source - + "\xf0\x0f" #dest - + "\x00\x05" #len - + "\xDE\xAD" #check - + "quux", - partial=0, - dest='dummy', - source='otherHost', - protocol='dummy', - version='dummy', - ihl='dummy', - tos='dummy', - tot_len='dummy', - fragment_id='dummy', - fragment_offset='dummy', - dont_fragment='dummy', - more_fragments='dummy', - ttl='dummy', - ) - proto.datagramReceived("\xA3\x02" #source - + "\xB0\x50" #dest - + "\x00\x06" #len - + "\xDE\xAD" #check - + "foobar", - partial=0, - dest='dummy', - source='testHost', - protocol='dummy', - version='dummy', - ihl='dummy', - tos='dummy', - tot_len='dummy', - fragment_id='dummy', - fragment_offset='dummy', - dont_fragment='dummy', - more_fragments='dummy', - ttl='dummy', - ) - - assert not p1.expecting, \ - 'Should not expect any more packets, but still want %r' % p1.expecting - assert not p2.expecting, \ - 'Should not expect any more packets, but still want %r' % p2.expecting - - def testAddingBadProtos_WrongLevel(self): - """Adding a wrong level protocol raises an exception.""" - e = rawudp.RawUDPProtocol() - try: - e.addProto(42, "silliness") - except TypeError, e: - if e.args == ('Added protocol must be an instance of DatagramProtocol',): - pass - else: - raise - else: - raise AssertionError, 'addProto must raise an exception for bad protocols' - - - def testAddingBadProtos_TooSmall(self): - """Adding a protocol with a negative number raises an exception.""" - e = rawudp.RawUDPProtocol() - try: - e.addProto(-1, protocol.DatagramProtocol()) - except TypeError, e: - if e.args == ('Added protocol must be positive or zero',): - pass - else: - raise - else: - raise AssertionError, 'addProto must raise an exception for bad protocols' - - - def testAddingBadProtos_TooBig(self): - """Adding a protocol with a number >=2**16 raises an exception.""" - e = rawudp.RawUDPProtocol() - try: - e.addProto(2**16, protocol.DatagramProtocol()) - except TypeError, e: - if e.args == ('Added protocol must fit in 16 bits',): - pass - else: - raise - else: - raise AssertionError, 'addProto must raise an exception for bad protocols' - - def testAddingBadProtos_TooBig2(self): - """Adding a protocol with a number >=2**16 raises an exception.""" - e = rawudp.RawUDPProtocol() - try: - e.addProto(2**16+1, protocol.DatagramProtocol()) - except TypeError, e: - if e.args == ('Added protocol must fit in 16 bits',): - pass - else: - raise - else: - raise AssertionError, 'addProto must raise an exception for bad protocols' diff --git a/tools/buildbot/pylibs/twisted/pair/topfiles/README b/tools/buildbot/pylibs/twisted/pair/topfiles/README deleted file mode 100644 index 4932808..0000000 --- a/tools/buildbot/pylibs/twisted/pair/topfiles/README +++ /dev/null @@ -1,4 +0,0 @@ -Twisted Pair 8.0.0 - -Twisted Pair was recently split out of Twisted. - diff --git a/tools/buildbot/pylibs/twisted/pair/topfiles/setup.py b/tools/buildbot/pylibs/twisted/pair/topfiles/setup.py deleted file mode 100644 index a7ad2db..0000000 --- a/tools/buildbot/pylibs/twisted/pair/topfiles/setup.py +++ /dev/null @@ -1,26 +0,0 @@ -import sys - -try: - from twisted.python import dist -except ImportError: - raise SystemExit("twisted.python.dist module not found. Make sure you " - "have installed the Twisted core package before " - "attempting to install any other Twisted projects.") - -if __name__ == '__main__': - dist.setup( - twisted_subproject="pair", - # metadata - name="Twisted Pair", - description="Twisted Pair contains low-level networking support.", - author="Twisted Matrix Laboratories", - author_email="twisted-python@twistedmatrix.com", - maintainer="Tommi Virtanen", - maintainer_email="tv@twistedmatrix.com", - url="http://twistedmatrix.com/trac/wiki/TwistedPair", - license="MIT", - long_description=""" -Raw network packet parsing routines, including ethernet, IP and UDP -packets, and tuntap support. -""", - ) diff --git a/tools/buildbot/pylibs/twisted/pair/tuntap.py b/tools/buildbot/pylibs/twisted/pair/tuntap.py deleted file mode 100644 index a8da85e..0000000 --- a/tools/buildbot/pylibs/twisted/pair/tuntap.py +++ /dev/null @@ -1,170 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -import errno, os -from twisted.python import log, reflect, components -from twisted.internet import base, fdesc, error -from twisted.pair import ethernet, ip - -""" -You need Eunuchs for twisted.pair.tuntap to work. - -Eunuchs is a library containing the missing manly parts of -UNIX API for Python. - -Eunuchs is a library of Python extension that complement the standard -libraries in parts where full support for the UNIX API (or the Linux -API) is missing. - -Most of the functions wrapped by Eunuchs are low-level, dirty, but -absolutely necessary functions for real systems programming. The aim is -to have the functions added to mainstream Python libraries. - -Current list of functions included: - - - fchdir(2) - - recvmsg(2) and sendmsg(2), including use of cmsg(3) - - socketpair(2) - - support for TUN/TAP virtual network interfaces - -Eunuchs doesn't have a proper web home right now, but you can fetch -the source from http://ftp.debian.org/debian/pool/main/e/eunuch --- debian users can just use 'apt-get install python-eunuchs'. - -""" -from eunuchs.tuntap import opentuntap, TuntapPacketInfo, makePacketInfo - -class TuntapPort(base.BasePort): - """A Port that reads and writes packets from/to a TUN/TAP-device. - - TODO: Share general start/stop etc implementation details with - twisted.internet.udp.Port. - """ - maxThroughput = 256 * 1024 # max bytes we read in one eventloop iteration - - def __init__(self, interface, proto, maxPacketSize=8192, reactor=None): - if components.implements(proto, ethernet.IEthernetProtocol): - self.ethernet = 1 - else: - self.ethernet = 0 - assert components.implements(proto, ip.IIPProtocol) # XXX: fix me - base.BasePort.__init__(self, reactor) - self.interface = interface - self.protocol = proto - self.maxPacketSize = maxPacketSize - self.setLogStr() - - def __repr__(self): - return "<%s on %s>" % (self.protocol.__class__, self.interface) - - def startListening(self): - """Create and bind my socket, and begin listening on it. - - This is called on unserialization, and must be called after creating a - server to begin listening on the specified port. - """ - self._bindSocket() - self._connectToProtocol() - - def _bindSocket(self): - log.msg("%s starting on %s"%(self.protocol.__class__, self.interface)) - try: - fd, name = opentuntap(name=self.interface, - ethernet=self.ethernet, - packetinfo=0) - except OSError, e: - raise error.CannotListenError, (None, self.interface, e) - fdesc.setNonBlocking(fd) - self.interface = name - self.connected = 1 - self.fd = fd - - def fileno(self): - return self.fd - - def _connectToProtocol(self): - self.protocol.makeConnection(self) - self.startReading() - - def doRead(self): - """Called when my socket is ready for reading.""" - read = 0 - while read < self.maxThroughput: - try: - data = os.read(self.fd, self.maxPacketSize) - read += len(data) -# pkt = TuntapPacketInfo(data) - self.protocol.datagramReceived(data, - partial=0 # pkt.isPartial(), - ) - except OSError, e: - if e.errno in (errno.EWOULDBLOCK,): - return - else: - raise - except IOError, e: - if e.errno in (errno.EAGAIN, errno.EINTR): - return - else: - raise - except: - log.deferr() - - def write(self, datagram): - """Write a datagram.""" -# header = makePacketInfo(0, 0) - try: - return os.write(self.fd, datagram) - except IOError, e: - if e.errno == errno.EINTR: - return self.write(datagram) - elif e.errno == errno.EMSGSIZE: - raise error.MessageLengthError, "message too long" - elif e.errno == errno.ECONNREFUSED: - raise error.ConnectionRefusedError - else: - raise - - def writeSequence(self, seq): - self.write("".join(seq)) - - def loseConnection(self): - """Stop accepting connections on this port. - - This will shut down my socket and call self.connectionLost(). - """ - self.stopReading() - if self.connected: - from twisted.internet import reactor - reactor.callLater(0, self.connectionLost) - - stopListening = loseConnection - - def connectionLost(self, reason=None): - """Cleans up my socket. - """ - log.msg('(Tuntap %s Closed)' % self.interface) - base.BasePort.connectionLost(self, reason) - if hasattr(self, "protocol"): - # we won't have attribute in ConnectedPort, in cases - # where there was an error in connection process - self.protocol.doStop() - self.connected = 0 - os.close(self.fd) - del self.fd - - def setLogStr(self): - self.logstr = reflect.qual(self.protocol.__class__) + " (TUNTAP)" - - def logPrefix(self): - """Returns the name of my class, to prefix log entries with. - """ - return self.logstr - - def getHost(self): - """ - Returns a tuple of ('TUNTAP', interface), indicating - the servers address - """ - return ('TUNTAP',)+self.interface diff --git a/tools/buildbot/pylibs/twisted/persisted/__init__.py b/tools/buildbot/pylibs/twisted/persisted/__init__.py deleted file mode 100644 index a00b854a..0000000 --- a/tools/buildbot/pylibs/twisted/persisted/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" - -Twisted Persisted: utilities for managing persistence. - -""" diff --git a/tools/buildbot/pylibs/twisted/persisted/aot.py b/tools/buildbot/pylibs/twisted/persisted/aot.py deleted file mode 100644 index 90e0e37..0000000 --- a/tools/buildbot/pylibs/twisted/persisted/aot.py +++ /dev/null @@ -1,560 +0,0 @@ -# -*- test-case-name: twisted.test.test_persisted -*- - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - - -""" -AOT: Abstract Object Trees -The source-code-marshallin'est abstract-object-serializin'est persister -this side of Marmalade! -""" - -import types, new, string, copy_reg, tokenize, re - -from twisted.python import reflect, log -from twisted.persisted import crefutil - -########################### -# Abstract Object Classes # -########################### - -#"\0" in a getSource means "insert variable-width indention here". -#see `indentify'. - -class Named: - def __init__(self, name): - self.name = name - -class Class(Named): - def getSource(self): - return "Class(%r)" % self.name - -class Function(Named): - def getSource(self): - return "Function(%r)" % self.name - -class Module(Named): - def getSource(self): - return "Module(%r)" % self.name - - -class InstanceMethod: - def __init__(self, name, klass, inst): - if not (isinstance(inst, Ref) or isinstance(inst, Instance) or isinstance(inst, Deref)): - raise TypeError("%s isn't an Instance, Ref, or Deref!" % inst) - self.name = name - self.klass = klass - self.instance = inst - - def getSource(self): - return "InstanceMethod(%r, %r, \n\0%s)" % (self.name, self.klass, prettify(self.instance)) - - -class _NoStateObj: - pass -NoStateObj = _NoStateObj() - -_SIMPLE_BUILTINS = [ - types.StringType, types.UnicodeType, types.IntType, types.FloatType, - types.ComplexType, types.LongType, types.NoneType, types.SliceType, - types.EllipsisType] - -try: - _SIMPLE_BUILTINS.append(types.BooleanType) -except AttributeError: - pass - -class Instance: - def __init__(self, className, __stateObj__=NoStateObj, **state): - if not isinstance(className, types.StringType): - raise TypeError("%s isn't a string!" % className) - self.klass = className - if __stateObj__ is not NoStateObj: - self.state = __stateObj__ - self.stateIsDict = 0 - else: - self.state = state - self.stateIsDict = 1 - - def getSource(self): - #XXX make state be foo=bar instead of a dict. - if self.stateIsDict: - stateDict = self.state - elif isinstance(self.state, Ref) and isinstance(self.state.obj, types.DictType): - stateDict = self.state.obj - else: - stateDict = None - if stateDict is not None: - try: - return "Instance(%r, %s)" % (self.klass, dictToKW(stateDict)) - except NonFormattableDict: - return "Instance(%r, %s)" % (self.klass, prettify(stateDict)) - return "Instance(%r, %s)" % (self.klass, prettify(self.state)) - -class Ref: - - def __init__(self, *args): - #blargh, lame. - if len(args) == 2: - self.refnum = args[0] - self.obj = args[1] - elif not args: - self.refnum = None - self.obj = None - - def setRef(self, num): - if self.refnum: - raise ValueError("Error setting id %s, I already have %s" % (num, self.refnum)) - self.refnum = num - - def setObj(self, obj): - if self.obj: - raise ValueError("Error setting obj %s, I already have %s" % (obj, self.obj)) - self.obj = obj - - def getSource(self): - if self.obj is None: - raise RuntimeError("Don't try to display me before setting an object on me!") - if self.refnum: - return "Ref(%d, \n\0%s)" % (self.refnum, prettify(self.obj)) - return prettify(self.obj) - - -class Deref: - def __init__(self, num): - self.refnum = num - - def getSource(self): - return "Deref(%d)" % self.refnum - - __repr__ = getSource - - -class Copyreg: - def __init__(self, loadfunc, state): - self.loadfunc = loadfunc - self.state = state - - def getSource(self): - return "Copyreg(%r, %s)" % (self.loadfunc, prettify(self.state)) - - - -############### -# Marshalling # -############### - - -def getSource(ao): - """Pass me an AO, I'll return a nicely-formatted source representation.""" - return indentify("app = " + prettify(ao)) - - -class NonFormattableDict(Exception): - """A dictionary was not formattable. - """ - -r = re.compile('[a-zA-Z_][a-zA-Z0-9_]*$') - -def dictToKW(d): - out = [] - items = d.items() - items.sort() - for k,v in items: - if not isinstance(k, types.StringType): - raise NonFormattableDict("%r ain't a string" % k) - if not r.match(k): - raise NonFormattableDict("%r ain't an identifier" % k) - out.append( - "\n\0%s=%s," % (k, prettify(v)) - ) - return string.join(out, '') - - -def prettify(obj): - if hasattr(obj, 'getSource'): - return obj.getSource() - else: - #basic type - t = type(obj) - - if t in _SIMPLE_BUILTINS: - return repr(obj) - - elif t is types.DictType: - out = ['{'] - for k,v in obj.items(): - out.append('\n\0%s: %s,' % (prettify(k), prettify(v))) - out.append(len(obj) and '\n\0}' or '}') - return string.join(out, '') - - elif t is types.ListType: - out = ["["] - for x in obj: - out.append('\n\0%s,' % prettify(x)) - out.append(len(obj) and '\n\0]' or ']') - return string.join(out, '') - - elif t is types.TupleType: - out = ["("] - for x in obj: - out.append('\n\0%s,' % prettify(x)) - out.append(len(obj) and '\n\0)' or ')') - return string.join(out, '') - else: - raise TypeError("Unsupported type %s when trying to prettify %s." % (t, obj)) - -def indentify(s): - out = [] - stack = [] - def eater(type, val, r, c, l, out=out, stack=stack): - #import sys - #sys.stdout.write(val) - if val in ['[', '(', '{']: - stack.append(val) - elif val in [']', ')', '}']: - stack.pop() - if val == '\0': - out.append(' '*len(stack)) - else: - out.append(val) - l = ['', s] - tokenize.tokenize(l.pop, eater) - return string.join(out, '') - - - - - -########### -# Unjelly # -########### - -def unjellyFromAOT(aot): - """ - Pass me an Abstract Object Tree, and I'll unjelly it for you. - """ - return AOTUnjellier().unjelly(aot) - -def unjellyFromSource(stringOrFile): - """ - Pass me a string of code or a filename that defines an 'app' variable (in - terms of Abstract Objects!), and I'll execute it and unjelly the resulting - AOT for you, returning a newly unpersisted Application object! - """ - - ns = {"Instance": Instance, - "InstanceMethod": InstanceMethod, - "Class": Class, - "Function": Function, - "Module": Module, - "Ref": Ref, - "Deref": Deref, - "Copyreg": Copyreg, - } - - if hasattr(stringOrFile, "read"): - exec stringOrFile.read() in ns - else: - exec stringOrFile in ns - - if ns.has_key('app'): - return unjellyFromAOT(ns['app']) - else: - raise ValueError("%s needs to define an 'app', it didn't!" % stringOrFile) - - -class AOTUnjellier: - """I handle the unjellying of an Abstract Object Tree. - See AOTUnjellier.unjellyAO - """ - def __init__(self): - self.references = {} - self.stack = [] - self.afterUnjelly = [] - - ## - # unjelly helpers (copied pretty much directly from marmalade XXX refactor) - ## - def unjellyLater(self, node): - """Unjelly a node, later. - """ - d = crefutil._Defer() - self.unjellyInto(d, 0, node) - return d - - def unjellyInto(self, obj, loc, ao): - """Utility method for unjellying one object into another. - This automates the handling of backreferences. - """ - o = self.unjellyAO(ao) - obj[loc] = o - if isinstance(o, crefutil.NotKnown): - o.addDependant(obj, loc) - return o - - def callAfter(self, callable, result): - if isinstance(result, crefutil.NotKnown): - l = [None] - result.addDependant(l, 1) - else: - l = [result] - self.afterUnjelly.append((callable, l)) - - def unjellyAttribute(self, instance, attrName, ao): - #XXX this is unused???? - """Utility method for unjellying into instances of attributes. - - Use this rather than unjellyAO unless you like surprising bugs! - Alternatively, you can use unjellyInto on your instance's __dict__. - """ - self.unjellyInto(instance.__dict__, attrName, ao) - - def unjellyAO(self, ao): - """Unjelly an Abstract Object and everything it contains. - I return the real object. - """ - self.stack.append(ao) - t = type(ao) - if t is types.InstanceType: - #Abstract Objects - c = ao.__class__ - if c is Module: - return reflect.namedModule(ao.name) - - elif c in [Class, Function] or issubclass(c, type): - return reflect.namedObject(ao.name) - - elif c is InstanceMethod: - im_name = ao.name - im_class = reflect.namedObject(ao.klass) - im_self = self.unjellyAO(ao.instance) - if im_name in im_class.__dict__: - if im_self is None: - return getattr(im_class, im_name) - elif isinstance(im_self, crefutil.NotKnown): - return crefutil._InstanceMethod(im_name, im_self, im_class) - else: - return new.instancemethod(im_class.__dict__[im_name], - im_self, - im_class) - else: - raise TypeError("instance method changed") - - elif c is Instance: - klass = reflect.namedObject(ao.klass) - state = self.unjellyAO(ao.state) - if hasattr(klass, "__setstate__"): - inst = new.instance(klass, {}) - self.callAfter(inst.__setstate__, state) - else: - inst = new.instance(klass, state) - return inst - - elif c is Ref: - o = self.unjellyAO(ao.obj) #THIS IS CHANGING THE REF OMG - refkey = ao.refnum - ref = self.references.get(refkey) - if ref is None: - self.references[refkey] = o - elif isinstance(ref, crefutil.NotKnown): - ref.resolveDependants(o) - self.references[refkey] = o - elif refkey is None: - # This happens when you're unjellying from an AOT not read from source - pass - else: - raise ValueError("Multiple references with the same ID: %s, %s, %s!" % (ref, refkey, ao)) - return o - - elif c is Deref: - num = ao.refnum - ref = self.references.get(num) - if ref is None: - der = crefutil._Dereference(num) - self.references[num] = der - return der - return ref - - elif c is Copyreg: - loadfunc = reflect.namedObject(ao.loadfunc) - d = self.unjellyLater(ao.state).addCallback( - lambda result, _l: apply(_l, result), loadfunc) - return d - - #Types - - elif t in _SIMPLE_BUILTINS: - return ao - - elif t is types.ListType: - l = [] - for x in ao: - l.append(None) - self.unjellyInto(l, len(l)-1, x) - return l - - elif t is types.TupleType: - l = [] - tuple_ = tuple - for x in ao: - l.append(None) - if isinstance(self.unjellyInto(l, len(l)-1, x), crefutil.NotKnown): - tuple_ = crefutil._Tuple - return tuple_(l) - - elif t is types.DictType: - d = {} - for k,v in ao.items(): - kvd = crefutil._DictKeyAndValue(d) - self.unjellyInto(kvd, 0, k) - self.unjellyInto(kvd, 1, v) - return d - - else: - raise TypeError("Unsupported AOT type: %s" % t) - - del self.stack[-1] - - - def unjelly(self, ao): - try: - l = [None] - self.unjellyInto(l, 0, ao) - for callable, v in self.afterUnjelly: - callable(v[0]) - return l[0] - except: - log.msg("Error jellying object! Stacktrace follows::") - log.msg(string.join(map(repr, self.stack), "\n")) - raise -######### -# Jelly # -######### - - -def jellyToAOT(obj): - """Convert an object to an Abstract Object Tree.""" - return AOTJellier().jelly(obj) - -def jellyToSource(obj, file=None): - """ - Pass me an object and, optionally, a file object. - I'll convert the object to an AOT either return it (if no file was - specified) or write it to the file. - """ - - aot = jellyToAOT(obj) - if file: - file.write(getSource(aot)) - else: - return getSource(aot) - - -class AOTJellier: - def __init__(self): - # dict of {id(obj): (obj, node)} - self.prepared = {} - self._ref_id = 0 - self.stack = [] - - def prepareForRef(self, aoref, object): - """I prepare an object for later referencing, by storing its id() - and its _AORef in a cache.""" - self.prepared[id(object)] = aoref - - def jellyToAO(self, obj): - """I turn an object into an AOT and return it.""" - objType = type(obj) - self.stack.append(repr(obj)) - - #immutable: We don't care if these have multiple refs! - if objType in _SIMPLE_BUILTINS: - retval = obj - - elif objType is types.MethodType: - # TODO: make methods 'prefer' not to jelly the object internally, - # so that the object will show up where it's referenced first NOT - # by a method. - retval = InstanceMethod(obj.im_func.__name__, reflect.qual(obj.im_class), - self.jellyToAO(obj.im_self)) - - elif objType is types.ModuleType: - retval = Module(obj.__name__) - - elif objType is types.ClassType: - retval = Class(reflect.qual(obj)) - - elif issubclass(objType, type): - retval = Class(reflect.qual(obj)) - - elif objType is types.FunctionType: - retval = Function(reflect.fullFuncName(obj)) - - else: #mutable! gotta watch for refs. - -#Marmalade had the nicety of being able to just stick a 'reference' attribute -#on any Node object that was referenced, but in AOT, the referenced object -#is *inside* of a Ref call (Ref(num, obj) instead of -#). The problem is, especially for built-in types, -#I can't just assign some attribute to them to give them a refnum. So, I have -#to "wrap" a Ref(..) around them later -- that's why I put *everything* that's -#mutable inside one. The Ref() class will only print the "Ref(..)" around an -#object if it has a Reference explicitly attached. - - if self.prepared.has_key(id(obj)): - oldRef = self.prepared[id(obj)] - if oldRef.refnum: - # it's been referenced already - key = oldRef.refnum - else: - # it hasn't been referenced yet - self._ref_id = self._ref_id + 1 - key = self._ref_id - oldRef.setRef(key) - return Deref(key) - - retval = Ref() - self.prepareForRef(retval, obj) - - if objType is types.ListType: - retval.setObj(map(self.jellyToAO, obj)) #hah! - - elif objType is types.TupleType: - retval.setObj(tuple(map(self.jellyToAO, obj))) - - elif objType is types.DictionaryType: - d = {} - for k,v in obj.items(): - d[self.jellyToAO(k)] = self.jellyToAO(v) - retval.setObj(d) - - elif objType is types.InstanceType: - if hasattr(obj, "__getstate__"): - state = self.jellyToAO(obj.__getstate__()) - else: - state = self.jellyToAO(obj.__dict__) - retval.setObj(Instance(reflect.qual(obj.__class__), state)) - - elif copy_reg.dispatch_table.has_key(objType): - unpickleFunc, state = copy_reg.dispatch_table[objType](obj) - - retval.setObj(Copyreg( reflect.fullFuncName(unpickleFunc), - self.jellyToAO(state))) - - else: - raise TypeError("Unsupported type: %s" % objType.__name__) - - del self.stack[-1] - return retval - - def jelly(self, obj): - try: - ao = self.jellyToAO(obj) - return ao - except: - log.msg("Error jellying object! Stacktrace follows::") - log.msg(string.join(self.stack, '\n')) - raise diff --git a/tools/buildbot/pylibs/twisted/persisted/crefutil.py b/tools/buildbot/pylibs/twisted/persisted/crefutil.py deleted file mode 100644 index 59e04fe..0000000 --- a/tools/buildbot/pylibs/twisted/persisted/crefutil.py +++ /dev/null @@ -1,167 +0,0 @@ -# -*- test-case-name: twisted.test.test_persisted -*- - -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Utility classes for dealing with circular references. -""" - -from twisted.python import log, reflect - -try: - from new import instancemethod -except: - from org.python.core import PyMethod - instancemethod = PyMethod - - -class NotKnown: - def __init__(self): - self.dependants = [] - self.resolved = 0 - - def addDependant(self, mutableObject, key): - assert not self.resolved - self.dependants.append( (mutableObject, key) ) - - resolvedObject = None - - def resolveDependants(self, newObject): - self.resolved = 1 - self.resolvedObject = newObject - for mut, key in self.dependants: - mut[key] = newObject - if isinstance(newObject, NotKnown): - newObject.addDependant(mut, key) - - def __hash__(self): - assert 0, "I am not to be used as a dictionary key." - - - -class _Container(NotKnown): - """ - Helper class to resolve circular references on container objects. - """ - - def __init__(self, l, containerType): - """ - @param l: The list of object which may contain some not yet referenced - objects. - - @param containerType: A type of container objects (e.g., C{tuple} or - C{set}). - """ - NotKnown.__init__(self) - self.containerType = containerType - self.l = l - self.locs = range(len(l)) - for idx in xrange(len(l)): - if not isinstance(l[idx], NotKnown): - self.locs.remove(idx) - else: - l[idx].addDependant(self, idx) - if not self.locs: - self.resolveDependants(self.containerType(self.l)) - - - def __setitem__(self, n, obj): - """ - Change the value of one contained objects, and resolve references if - all objects have been referenced. - """ - self.l[n] = obj - if not isinstance(obj, NotKnown): - self.locs.remove(n) - if not self.locs: - self.resolveDependants(self.containerType(self.l)) - - - -class _Tuple(_Container): - """ - Manage tuple containing circular references. Deprecated: use C{_Container} - instead. - """ - - def __init__(self, l): - """ - @param l: The list of object which may contain some not yet referenced - objects. - """ - _Container.__init__(self, l, tuple) - - - -class _InstanceMethod(NotKnown): - def __init__(self, im_name, im_self, im_class): - NotKnown.__init__(self) - self.my_class = im_class - self.name = im_name - # im_self _must_ be a - im_self.addDependant(self, 0) - - def __call__(self, *args, **kw): - import traceback - log.msg('instance method %s.%s' % (reflect.qual(self.my_class), self.name)) - log.msg('being called with %r %r' % (args, kw)) - traceback.print_stack(file=log.logfile) - assert 0 - - def __setitem__(self, n, obj): - assert n == 0, "only zero index allowed" - if not isinstance(obj, NotKnown): - self.resolveDependants(instancemethod(self.my_class.__dict__[self.name], - obj, - self.my_class)) - -class _DictKeyAndValue: - def __init__(self, dict): - self.dict = dict - def __setitem__(self, n, obj): - if n not in (1, 0): - raise RuntimeError("DictKeyAndValue should only ever be called with 0 or 1") - if n: # value - self.value = obj - else: - self.key = obj - if hasattr(self, "key") and hasattr(self, "value"): - self.dict[self.key] = self.value - - -class _Dereference(NotKnown): - def __init__(self, id): - NotKnown.__init__(self) - self.id = id - - -from twisted.internet.defer import Deferred - -class _Catcher: - def catch(self, value): - self.value = value - -class _Defer(Deferred, NotKnown): - def __init__(self): - Deferred.__init__(self) - NotKnown.__init__(self) - self.pause() - - wasset = 0 - - def __setitem__(self, n, obj): - if self.wasset: - raise RuntimeError('setitem should only be called once, setting %r to %r' % (n, obj)) - else: - self.wasset = 1 - self.callback(obj) - - def addDependant(self, dep, key): - # by the time I'm adding a dependant, I'm *not* adding any more - # callbacks - NotKnown.addDependant(self, dep, key) - self.unpause() - resovd = self.result - self.resolveDependants(resovd) diff --git a/tools/buildbot/pylibs/twisted/persisted/dirdbm.py b/tools/buildbot/pylibs/twisted/persisted/dirdbm.py deleted file mode 100644 index 91106bf..0000000 --- a/tools/buildbot/pylibs/twisted/persisted/dirdbm.py +++ /dev/null @@ -1,358 +0,0 @@ -# -*- test-case-name: twisted.test.test_dirdbm -*- -# -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - - -""" -DBM-style interface to a directory. - -Each key is stored as a single file. This is not expected to be very fast or -efficient, but it's good for easy debugging. - -DirDBMs are *not* thread-safe, they should only be accessed by one thread at -a time. - -No files should be placed in the working directory of a DirDBM save those -created by the DirDBM itself! - -Maintainer: U{Itamar Shtull-Trauring} -""" - - -import os -import types -import base64 -import glob - -try: - import cPickle as pickle -except ImportError: - import pickle - -try: - _open -except NameError: - _open = open - - -class DirDBM: - """A directory with a DBM interface. - - This class presents a hash-like interface to a directory of small, - flat files. It can only use strings as keys or values. - """ - - def __init__(self, name): - """ - @type name: str - @param name: Base path to use for the directory storage. - """ - self.dname = os.path.abspath(name) - if not os.path.isdir(self.dname): - os.mkdir(self.dname) - else: - # Run recovery, in case we crashed. we delete all files ending - # with ".new". Then we find all files who end with ".rpl". If a - # corresponding file exists without ".rpl", we assume the write - # failed and delete the ".rpl" file. If only a ".rpl" exist we - # assume the program crashed right after deleting the old entry - # but before renaming the replacement entry. - # - # NOTE: '.' is NOT in the base64 alphabet! - for f in glob.glob(os.path.join(self.dname, "*.new")): - os.remove(f) - replacements = glob.glob(os.path.join(self.dname, "*.rpl")) - for f in replacements: - old = f[:-4] - if os.path.exists(old): - os.remove(f) - else: - os.rename(f, old) - - def _encode(self, k): - """Encode a key so it can be used as a filename. - """ - # NOTE: '_' is NOT in the base64 alphabet! - return base64.encodestring(k).replace('\n', '_').replace("/", "-") - - def _decode(self, k): - """Decode a filename to get the key. - """ - return base64.decodestring(k.replace('_', '\n').replace("-", "/")) - - def _readFile(self, path): - """Read in the contents of a file. - - Override in subclasses to e.g. provide transparently encrypted dirdbm. - """ - f = _open(path, "rb") - s = f.read() - f.close() - return s - - def _writeFile(self, path, data): - """Write data to a file. - - Override in subclasses to e.g. provide transparently encrypted dirdbm. - """ - f = _open(path, "wb") - f.write(data) - f.flush() - f.close() - - def __len__(self): - """ - @return: The number of key/value pairs in this Shelf - """ - return len(os.listdir(self.dname)) - - def __setitem__(self, k, v): - """ - C{dirdbm[k] = v} - Create or modify a textfile in this directory - - @type k: str - @param k: key to set - - @type v: str - @param v: value to associate with C{k} - """ - assert type(k) == types.StringType, "DirDBM key must be a string" - assert type(v) == types.StringType, "DirDBM value must be a string" - k = self._encode(k) - - # we create a new file with extension .new, write the data to it, and - # if the write succeeds delete the old file and rename the new one. - old = os.path.join(self.dname, k) - if os.path.exists(old): - new = old + ".rpl" # replacement entry - else: - new = old + ".new" # new entry - try: - self._writeFile(new, v) - except: - os.remove(new) - raise - else: - if os.path.exists(old): os.remove(old) - os.rename(new, old) - - def __getitem__(self, k): - """ - C{dirdbm[k]} - Get the contents of a file in this directory as a string. - - @type k: str - @param k: key to lookup - - @return: The value associated with C{k} - @raise KeyError: Raised when there is no such key - """ - assert type(k) == types.StringType, "DirDBM key must be a string" - path = os.path.join(self.dname, self._encode(k)) - try: - return self._readFile(path) - except: - raise KeyError, k - - def __delitem__(self, k): - """ - C{del dirdbm[foo]} - Delete a file in this directory. - - @type k: str - @param k: key to delete - - @raise KeyError: Raised when there is no such key - """ - assert type(k) == types.StringType, "DirDBM key must be a string" - k = self._encode(k) - try: os.remove(os.path.join(self.dname, k)) - except (OSError, IOError): raise KeyError(self._decode(k)) - - def keys(self): - """ - @return: a C{list} of filenames (keys). - """ - return map(self._decode, os.listdir(self.dname)) - - def values(self): - """ - @return: a C{list} of file-contents (values). - """ - vals = [] - keys = self.keys() - for key in keys: - vals.append(self[key]) - return vals - - def items(self): - """ - @return: a C{list} of 2-tuples containing key/value pairs. - """ - items = [] - keys = self.keys() - for key in keys: - items.append((key, self[key])) - return items - - def has_key(self, key): - """ - @type key: str - @param key: The key to test - - @return: A true value if this dirdbm has the specified key, a faluse - value otherwise. - """ - assert type(key) == types.StringType, "DirDBM key must be a string" - key = self._encode(key) - return os.path.isfile(os.path.join(self.dname, key)) - - def setdefault(self, key, value): - """ - @type key: str - @param key: The key to lookup - - @param value: The value to associate with key if key is not already - associated with a value. - """ - if not self.has_key(key): - self[key] = value - return value - return self[key] - - def get(self, key, default = None): - """ - @type key: str - @param key: The key to lookup - - @param default: The value to return if the given key does not exist - - @return: The value associated with C{key} or C{default} if not - C{self.has_key(key)} - """ - if self.has_key(key): - return self[key] - else: - return default - - def __contains__(self, key): - """ - C{key in dirdbm} - - @type key: str - @param key: The key to test - - @return: A true value if C{self.has_key(key)}, a false value otherwise. - """ - assert type(key) == types.StringType, "DirDBM key must be a string" - key = self._encode(key) - return os.path.isfile(os.path.join(self.dname, key)) - - def update(self, dict): - """ - Add all the key/value pairs in C{dict} to this dirdbm. Any conflicting - keys will be overwritten with the values from C{dict}. - - @type dict: mapping - @param dict: A mapping of key/value pairs to add to this dirdbm. - """ - for key, val in dict.items(): - self[key]=val - - def copyTo(self, path): - """ - Copy the contents of this dirdbm to the dirdbm at C{path}. - - @type path: C{str} - @param path: The path of the dirdbm to copy to. If a dirdbm - exists at the destination path, it is cleared first. - - @rtype: C{DirDBM} - @return: The dirdbm this dirdbm was copied to. - """ - path = os.path.abspath(path) - assert path != self.dname - - d = self.__class__(path) - d.clear() - for k in self.keys(): - d[k] = self[k] - return d - - def clear(self): - """ - Delete all key/value pairs in this dirdbm. - """ - for k in self.keys(): - del self[k] - - def close(self): - """ - Close this dbm: no-op, for dbm-style interface compliance. - """ - - def getModificationTime(self, key): - """ - Returns modification time of an entry. - - @return: Last modification date (seconds since epoch) of entry C{key} - @raise KeyError: Raised when there is no such key - """ - assert type(key) == types.StringType, "DirDBM key must be a string" - path = os.path.join(self.dname, self._encode(key)) - if os.path.isfile(path): - return os.path.getmtime(path) - else: - raise KeyError, key - - -class Shelf(DirDBM): - """A directory with a DBM shelf interface. - - This class presents a hash-like interface to a directory of small, - flat files. Keys must be strings, but values can be any given object. - """ - - def __setitem__(self, k, v): - """ - C{shelf[foo] = bar} - Create or modify a textfile in this directory. - - @type k: str - @param k: The key to set - - @param v: The value to associate with C{key} - """ - v = pickle.dumps(v) - DirDBM.__setitem__(self, k, v) - - def __getitem__(self, k): - """ - C{dirdbm[foo]} - Get and unpickle the contents of a file in this directory. - - @type k: str - @param k: The key to lookup - - @return: The value associated with the given key - @raise KeyError: Raised if the given key does not exist - """ - return pickle.loads(DirDBM.__getitem__(self, k)) - - -def open(file, flag = None, mode = None): - """ - This is for 'anydbm' compatibility. - - @param file: The parameter to pass to the DirDBM constructor. - - @param flag: ignored - @param mode: ignored - """ - return DirDBM(file) - - -__all__ = ["open", "DirDBM", "Shelf"] diff --git a/tools/buildbot/pylibs/twisted/persisted/journal/__init__.py b/tools/buildbot/pylibs/twisted/persisted/journal/__init__.py deleted file mode 100644 index 414af94..0000000 --- a/tools/buildbot/pylibs/twisted/persisted/journal/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -""" -Command-journalling persistence framework inspired by Prevayler. - -Maintainer: U{Itamar Shtull-Trauring} -""" diff --git a/tools/buildbot/pylibs/twisted/persisted/journal/base.py b/tools/buildbot/pylibs/twisted/persisted/journal/base.py deleted file mode 100644 index 196a47c..0000000 --- a/tools/buildbot/pylibs/twisted/persisted/journal/base.py +++ /dev/null @@ -1,226 +0,0 @@ -# -*- test-case-name: twisted.test.test_journal -*- -# -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - - -"""Basic classes and interfaces for journal.""" - -from __future__ import nested_scopes - -# system imports -import os, time - -try: - import cPickle as pickle -except ImportError: - import pickle - -# twisted imports -from zope.interface import implements, Interface - - -class Journal: - """All commands to the system get routed through here. - - Subclasses should implement the actual snapshotting capability. - """ - - def __init__(self, log, journaledService): - self.log = log - self.journaledService = journaledService - self.latestIndex = self.log.getCurrentIndex() - - def updateFromLog(self): - """Run all commands from log that haven't been run yet. - - This method should be run on startup to ensure the snapshot - is up-to-date. - """ - snapshotIndex = self.getLastSnapshot() - if snapshotIndex < self.latestIndex: - for cmdtime, command in self.log.getCommandsSince(snapshotIndex + 1): - command.execute(self.journaledService, cmdtime) - - def executeCommand(self, command): - """Log and execute a command.""" - runTime = time.time() - d = self.log.logCommand(command, runTime) - d.addCallback(self._reallyExecute, command, runTime) - return d - - def _reallyExecute(self, index, command, runTime): - """Callback called when logging command is done.""" - result = command.execute(self.journaledService, runTime) - self.latestIndex = index - return result - - def getLastSnapshot(self): - """Return command index of the last snapshot taken.""" - raise NotImplementedError - - def sync(self, *args, **kwargs): - """Save journal to disk, returns Deferred of finish status. - - Subclasses may choose whatever signature is appropriate, or may - not implement this at all. - """ - raise NotImplementedError - - - -class MemoryJournal(Journal): - """Prevayler-like journal that dumps from memory to disk.""" - - def __init__(self, log, journaledService, path, loadedCallback): - self.path = path - if os.path.exists(path): - try: - self.lastSync, obj = pickle.load(open(path, "rb")) - except (IOError, OSError, pickle.UnpicklingError): - self.lastSync, obj = 0, None - loadedCallback(obj) - else: - self.lastSync = 0 - loadedCallback(None) - Journal.__init__(self, log, journaledService) - - def getLastSnapshot(self): - return self.lastSync - - def sync(self, obj): - # make this more reliable at some point - f = open(self.path, "wb") - pickle.dump((self.latestIndex, obj), f, 1) - f.close() - self.lastSync = self.latestIndex - - -class ICommand(Interface): - """A serializable command which interacts with a journaled service.""" - - def execute(journaledService, runTime): - """Run the command and return result.""" - - -class ICommandLog(Interface): - """Interface for command log.""" - - def logCommand(command, runTime): - """Add a command and its run time to the log. - - @return: Deferred of command index. - """ - - def getCurrentIndex(): - """Return index of last command that was logged.""" - - def getCommandsSince(index): - """Return commands who's index >= the given one. - - @return: list of (time, command) tuples, sorted with ascending times. - """ - - -class LoadingService: - """Base class for journalled service used with Wrappables.""" - - def loadObject(self, objType, objId): - """Return object of specified type and id.""" - raise NotImplementedError - - -class Wrappable: - """Base class for objects used with LoadingService.""" - - objectType = None # override in base class - - def getUid(self): - """Return uid for loading with LoadingService.loadObject""" - raise NotImplementedError - - -class WrapperCommand: - - implements(ICommand) - - def __init__(self, methodName, obj, args=(), kwargs={}): - self.obj = obj - self.objId = obj.getUid() - self.objType = obj.objectType - self.methodName = methodName - self.args = args - self.kwargs = kwargs - - def execute(self, svc, commandTime): - if not hasattr(self, "obj"): - obj = svc.loadObject(self.objType, self.objId) - else: - obj = self.obj - return getattr(obj, self.methodName)(*self.args, **self.kwargs) - - def __getstate__(self): - d = self.__dict__.copy() - del d["obj"] - return d - - -def command(methodName, cmdClass=WrapperCommand): - """Wrap a method so it gets turned into command automatically. - - For use with Wrappables. - - Usage:: - - | class Foo(Wrappable): - | objectType = "foo" - | def getUid(self): - | return self.id - | def _bar(self, x): - | return x + 1 - | - | bar = command('_bar') - - The resulting callable will have signature identical to wrapped - function, except that it expects journal as first argument, and - returns a Deferred. - """ - def wrapper(obj, journal, *args, **kwargs): - return journal.executeCommand(cmdClass(methodName, obj, args, kwargs)) - return wrapper - - -class ServiceWrapperCommand: - - implements(ICommand) - - def __init__(self, methodName, args=(), kwargs={}): - self.methodName = methodName - self.args = args - self.kwargs = kwargs - - def execute(self, svc, commandTime): - return getattr(svc, self.methodName)(*self.args, **self.kwargs) - - def __repr__(self): - return "" % (self.methodName, self.args, self.kwargs) - - def __cmp__(self, other): - if hasattr(other, "__dict__"): - return cmp(self.__dict__, other.__dict__) - else: - return 0 - - -def serviceCommand(methodName, cmdClass=ServiceWrapperCommand): - """Wrap methods into commands for a journalled service. - - The resulting callable will have signature identical to wrapped - function, except that it expects journal as first argument, and - returns a Deferred. - """ - def wrapper(obj, journal, *args, **kwargs): - return journal.executeCommand(cmdClass(methodName, args, kwargs)) - return wrapper diff --git a/tools/buildbot/pylibs/twisted/persisted/journal/picklelog.py b/tools/buildbot/pylibs/twisted/persisted/journal/picklelog.py deleted file mode 100644 index eae6a30..0000000 --- a/tools/buildbot/pylibs/twisted/persisted/journal/picklelog.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -# -*- test-case-name: twisted.test.test_journal -*- - -"""Logging that uses pickles. - -TODO: add log that logs to a file. -""" - -# twisted imports -from twisted.persisted import dirdbm -from twisted.internet import defer -from zope.interface import implements - -# sibling imports -import base - - -class DirDBMLog: - """Log pickles to DirDBM directory.""" - - implements(base.ICommandLog) - - def __init__(self, logPath): - self.db = dirdbm.Shelf(logPath) - indexs = map(int, self.db.keys()) - if indexs: - self.currentIndex = max(indexs) - else: - self.currentIndex = 0 - - def logCommand(self, command, time): - """Log a command.""" - self.currentIndex += 1 - self.db[str(self.currentIndex)] = (time, command) - return defer.succeed(1) - - def getCurrentIndex(self): - """Return index of last command logged.""" - return self.currentIndex - - def getCommandsSince(self, index): - result = [] - for i in range(index, self.currentIndex + 1): - result.append(self.db[str(i)]) - return result diff --git a/tools/buildbot/pylibs/twisted/persisted/journal/rowjournal.py b/tools/buildbot/pylibs/twisted/persisted/journal/rowjournal.py deleted file mode 100644 index 0246222..0000000 --- a/tools/buildbot/pylibs/twisted/persisted/journal/rowjournal.py +++ /dev/null @@ -1,99 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -"""Journal using twisted.enterprise.row RDBMS support. - -You're going to need the following table in your database:: - - | CREATE TABLE journalinfo - | ( - | commandIndex int - | ); - | INSERT INTO journalinfo VALUES (0); - -""" - -from __future__ import nested_scopes - -# twisted imports -from twisted.internet import defer - -# sibling imports -import base - - -# constants for command list -INSERT, DELETE, UPDATE = range(3) - - -class RowJournal(base.Journal): - """Journal that stores data 'snapshot' in using twisted.enterprise.row. - - Use this as the reflector instead of the original reflector. - - It may block on creation, if it has to run recovery. - """ - - def __init__(self, log, journaledService, reflector): - self.reflector = reflector - self.commands = [] - self.syncing = 0 - base.Journal.__init__(self, log, journaledService) - - def updateRow(self, obj): - """Mark on object for updating when sync()ing.""" - self.commands.append((UPDATE, obj)) - - def insertRow(self, obj): - """Mark on object for inserting when sync()ing.""" - self.commands.append((INSERT, obj)) - - def deleteRow(self, obj): - """Mark on object for deleting when sync()ing.""" - self.commands.append((DELETE, obj)) - - def loadObjectsFrom(self, tableName, parentRow=None, data=None, whereClause=None, forceChildren=0): - """Flush all objects to the database and then load objects.""" - d = self.sync() - d.addCallback(lambda result: self.reflector.loadObjectsFrom( - tableName, parentRow=parentRow, data=data, whereClause=whereClause, - forceChildren=forceChildren)) - return d - - def sync(self): - """Commit changes to database.""" - if self.syncing: - raise ValueError, "sync already in progress" - comandMap = {INSERT : self.reflector.insertRowSQL, - UPDATE : self.reflector.updateRowSQL, - DELETE : self.reflector.deleteRowSQL} - sqlCommands = [] - for kind, obj in self.commands: - sqlCommands.append(comandMap[kind](obj)) - self.commands = [] - if sqlCommands: - self.syncing = 1 - d = self.reflector.dbpool.runInteraction(self._sync, self.latestIndex, sqlCommands) - d.addCallback(self._syncDone) - return d - else: - return defer.succeed(1) - - def _sync(self, txn, index, commands): - """Do the actual database synchronization.""" - for c in commands: - txn.execute(c) - txn.update("UPDATE journalinfo SET commandIndex = %d" % index) - - def _syncDone(self, result): - self.syncing = 0 - return result - - def getLastSnapshot(self): - """Return command index of last snapshot.""" - conn = self.reflector.dbpool.connect() - cursor = conn.cursor() - cursor.execute("SELECT commandIndex FROM journalinfo") - return cursor.fetchall()[0][0] diff --git a/tools/buildbot/pylibs/twisted/persisted/marmalade.py b/tools/buildbot/pylibs/twisted/persisted/marmalade.py deleted file mode 100644 index 0b87c9f..0000000 --- a/tools/buildbot/pylibs/twisted/persisted/marmalade.py +++ /dev/null @@ -1,416 +0,0 @@ -# -*- test-case-name: twisted.test.test_persisted -*- - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Marmalade: jelly, with just a hint of bitterness. - -I can serialize a Python object to an XML DOM tree (twisted.web.microdom), and -therefore to XML data, similarly to twisted.spread.jelly. Because both Python -lists and DOM trees are tree data-structures, many of the idioms used here are -identical. - -""" - -import warnings -warnings.warn("twisted.persisted.marmalade is deprecated", DeprecationWarning, stacklevel=2) - -import new - -from twisted.python.reflect import namedModule, namedClass, namedObject, fullFuncName, qual -from twisted.persisted.crefutil import NotKnown, _Tuple, _InstanceMethod, _DictKeyAndValue, _Dereference, _Defer - -try: - from new import instancemethod -except: - from org.python.core import PyMethod - instancemethod = PyMethod - -import types -import copy_reg - -#for some reason, __builtins__ == __builtin__.__dict__ in the context where this is used. -#Can someone tell me why? -import __builtin__ - - -def instance(klass, d): - if isinstance(klass, types.ClassType): - return new.instance(klass, d) - elif isinstance(klass, type): - o = object.__new__(klass) - o.__dict__ = d - return o - else: - raise TypeError, "%s is not a class" % klass - - -def getValueElement(node): - """Get the one child element of a given element. - - If there is more than one child element, raises ValueError. Otherwise, - returns the value element. - """ - valueNode = None - for subnode in node.childNodes: - if isinstance(subnode, Element): - if valueNode is None: - valueNode = subnode - else: - raise ValueError("Only one value node allowed per instance!") - return valueNode - - -class DOMJellyable: - - jellyDOMVersion = 1 - - def jellyToDOM(self, jellier, element): - element.setAttribute("marmalade:version", str(self.jellyDOMVersion)) - method = getattr(self, "jellyToDOM_%s" % self.jellyDOMVersion, None) - if method: - method(jellier, element) - else: - element.appendChild(jellier.jellyToNode(self.__dict__)) - - def unjellyFromDOM(self, unjellier, element): - pDOMVersion = element.getAttribute("marmalade:version") or "0" - method = getattr(self, "unjellyFromDOM_%s" % pDOMVersion, None) - if method: - method(unjellier, element) - else: - # XXX: DOMJellyable.unjellyNode does not exist - # XXX: 'node' is undefined - did you mean 'self', 'element', or 'Node'? - state = self.unjellyNode(getValueElement(node)) - if hasattr(self.__class__, "__setstate__"): - self.__setstate__(state) - else: - self.__dict__ = state - - - -class DOMUnjellier: - def __init__(self): - self.references = {} - self._savedLater = [] - - def unjellyLater(self, node): - """Unjelly a node, later. - """ - d = _Defer() - self.unjellyInto(d, 0, node) - self._savedLater.append(d) - return d - - def unjellyInto(self, obj, loc, node): - """Utility method for unjellying one object into another. - - This automates the handling of backreferences. - """ - o = self.unjellyNode(node) - obj[loc] = o - if isinstance(o, NotKnown): - o.addDependant(obj, loc) - return o - - def unjellyAttribute(self, instance, attrName, valueNode): - """Utility method for unjellying into instances of attributes. - - Use this rather than unjellyNode unless you like surprising bugs! - Alternatively, you can use unjellyInto on your instance's __dict__. - """ - self.unjellyInto(instance.__dict__, attrName, valueNode) - - def unjellyNode(self, node): - if node.tagName.lower() == "none": - retval = None - elif node.tagName == "string": - # XXX FIXME this is obviously insecure - # if you doubt: - # >>> unjellyFromXML('''''') - # "hi" - retval = str(eval('"%s"' % node.getAttribute("value"))) - elif node.tagName == "int": - retval = int(node.getAttribute("value")) - elif node.tagName == "float": - retval = float(node.getAttribute("value")) - elif node.tagName == "longint": - retval = long(node.getAttribute("value")) - elif node.tagName == "bool": - retval = int(node.getAttribute("value")) - if retval: - retval = True - else: - retval = False - elif node.tagName == "module": - retval = namedModule(str(node.getAttribute("name"))) - elif node.tagName == "class": - retval = namedClass(str(node.getAttribute("name"))) - elif node.tagName == "unicode": - retval = unicode(str(node.getAttribute("value")).replace("\\n", "\n").replace("\\t", "\t"), "raw_unicode_escape") - elif node.tagName == "function": - retval = namedObject(str(node.getAttribute("name"))) - elif node.tagName == "method": - im_name = node.getAttribute("name") - im_class = namedClass(node.getAttribute("class")) - im_self = self.unjellyNode(getValueElement(node)) - if im_class.__dict__.has_key(im_name): - if im_self is None: - retval = getattr(im_class, im_name) - elif isinstance(im_self, NotKnown): - retval = _InstanceMethod(im_name, im_self, im_class) - else: - retval = instancemethod(im_class.__dict__[im_name], - im_self, - im_class) - else: - raise TypeError("instance method changed") - elif node.tagName == "tuple": - l = [] - tupFunc = tuple - for subnode in node.childNodes: - if isinstance(subnode, Element): - l.append(None) - if isinstance(self.unjellyInto(l, len(l)-1, subnode), NotKnown): - tupFunc = _Tuple - retval = tupFunc(l) - elif node.tagName == "list": - l = [] - finished = 1 - for subnode in node.childNodes: - if isinstance(subnode, Element): - l.append(None) - self.unjellyInto(l, len(l)-1, subnode) - retval = l - elif node.tagName == "dictionary": - d = {} - keyMode = 1 - for subnode in node.childNodes: - if isinstance(subnode, Element): - if keyMode: - kvd = _DictKeyAndValue(d) - if not subnode.getAttribute("role") == "key": - raise TypeError("Unjellying Error: key role not set") - self.unjellyInto(kvd, 0, subnode) - else: - self.unjellyInto(kvd, 1, subnode) - keyMode = not keyMode - retval = d - elif node.tagName == "instance": - className = node.getAttribute("class") - clasz = namedClass(className) - if issubclass(clasz, DOMJellyable): - retval = instance(clasz, {}) - retval.unjellyFromDOM(self, node) - else: - state = self.unjellyNode(getValueElement(node)) - if hasattr(clasz, "__setstate__"): - inst = instance(clasz, {}) - inst.__setstate__(state) - else: - inst = instance(clasz, state) - retval = inst - elif node.tagName == "reference": - refkey = node.getAttribute("key") - retval = self.references.get(refkey) - if retval is None: - der = _Dereference(refkey) - self.references[refkey] = der - retval = der - elif node.tagName == "copyreg": - nodefunc = namedObject(node.getAttribute("loadfunc")) - loaddef = self.unjellyLater(getValueElement(node)).addCallback( - lambda result, _l: apply(_l, result), nodefunc) - retval = loaddef - else: - raise TypeError("Unsupported Node Type: %s" % (node.tagName,)) - if node.hasAttribute("reference"): - refkey = node.getAttribute("reference") - ref = self.references.get(refkey) - if ref is None: - self.references[refkey] = retval - elif isinstance(ref, NotKnown): - ref.resolveDependants(retval) - self.references[refkey] = retval - else: - assert 0, "Multiple references with the same ID!" - return retval - - def unjelly(self, doc): - l = [None] - self.unjellyInto(l, 0, doc.childNodes[0]) - for svd in self._savedLater: - svd.unpause() - return l[0] - - -class DOMJellier: - def __init__(self): - # dict of {id(obj): (obj, node)} - self.prepared = {} - self.document = Document() - self._ref_id = 0 - - def prepareElement(self, element, object): - self.prepared[id(object)] = (object, element) - - def jellyToNode(self, obj): - """Create a node representing the given object and return it. - """ - objType = type(obj) - #immutable (We don't care if these have multiple refs) - if objType is types.NoneType: - node = self.document.createElement("None") - elif objType is types.StringType: - node = self.document.createElement("string") - r = repr(obj) - if r[0] == '"': - r = r.replace("'", "\\'") - else: - r = r.replace('"', '\\"') - node.setAttribute("value", r[1:-1]) - # node.appendChild(CDATASection(obj)) - elif objType is types.IntType: - node = self.document.createElement("int") - node.setAttribute("value", str(obj)) - elif objType is types.LongType: - node = self.document.createElement("longint") - s = str(obj) - if s[-1] == 'L': - s = s[:-1] - node.setAttribute("value", s) - elif objType is types.FloatType: - node = self.document.createElement("float") - node.setAttribute("value", repr(obj)) - elif objType is types.MethodType: - node = self.document.createElement("method") - node.setAttribute("name", obj.im_func.__name__) - node.setAttribute("class", qual(obj.im_class)) - # TODO: make methods 'prefer' not to jelly the object internally, - # so that the object will show up where it's referenced first NOT - # by a method. - node.appendChild(self.jellyToNode(obj.im_self)) - elif hasattr(types, 'BooleanType') and objType is types.BooleanType: - node = self.document.createElement("bool") - node.setAttribute("value", str(int(obj))) - elif objType is types.ModuleType: - node = self.document.createElement("module") - node.setAttribute("name", obj.__name__) - elif objType==types.ClassType or issubclass(objType, type): - node = self.document.createElement("class") - node.setAttribute("name", qual(obj)) - elif objType is types.UnicodeType: - node = self.document.createElement("unicode") - obj = obj.encode('raw_unicode_escape') - s = obj.replace("\n", "\\n").replace("\t", "\\t") - node.setAttribute("value", s) - elif objType in (types.FunctionType, types.BuiltinFunctionType): - # TODO: beat pickle at its own game, and do BuiltinFunctionType - # separately, looking for __self__ attribute and unpickling methods - # of C objects when possible. - node = self.document.createElement("function") - node.setAttribute("name", fullFuncName(obj)) - else: - #mutable! - if self.prepared.has_key(id(obj)): - oldNode = self.prepared[id(obj)][1] - if oldNode.hasAttribute("reference"): - # it's been referenced already - key = oldNode.getAttribute("reference") - else: - # it hasn't been referenced yet - self._ref_id = self._ref_id + 1 - key = str(self._ref_id) - oldNode.setAttribute("reference", key) - node = self.document.createElement("reference") - node.setAttribute("key", key) - return node - node = self.document.createElement("UNNAMED") - self.prepareElement(node, obj) - if objType is types.ListType or __builtin__.__dict__.has_key('object') and isinstance(obj, NodeList): - node.tagName = "list" - for subobj in obj: - node.appendChild(self.jellyToNode(subobj)) - elif objType is types.TupleType: - node.tagName = "tuple" - for subobj in obj: - node.appendChild(self.jellyToNode(subobj)) - elif objType is types.DictionaryType: - node.tagName = "dictionary" - for k, v in obj.items(): - n = self.jellyToNode(k) - n.setAttribute("role", "key") - n2 = self.jellyToNode(v) - node.appendChild(n) - node.appendChild(n2) - elif copy_reg.dispatch_table.has_key(objType): - unpickleFunc, state = copy_reg.dispatch_table[objType](obj) - node = self.document.createElement("copyreg") - # node.setAttribute("type", objType.__name__) - node.setAttribute("loadfunc", fullFuncName(unpickleFunc)) - node.appendChild(self.jellyToNode(state)) - elif objType is types.InstanceType or hasattr(objType, "__module__"): - className = qual(obj.__class__) - node.tagName = "instance" - node.setAttribute("class", className) - if isinstance(obj, DOMJellyable): - obj.jellyToDOM(self, node) - else: - if hasattr(obj, "__getstate__"): - state = obj.__getstate__() - else: - state = obj.__dict__ - n = self.jellyToNode(state) - node.appendChild(n) - else: - raise TypeError("Unsupported type: %s" % (objType.__name__,)) - return node - - def jelly(self, obj): - """Create a document representing the current object, and return it. - """ - node = self.jellyToNode(obj) - self.document.appendChild(node) - return self.document - - -def jellyToDOM(object): - """Convert an Object into an twisted.web.microdom.Document. - """ - dj = DOMJellier() - document = dj.jelly(object) - return document - - -def unjellyFromDOM(document): - """Convert an twisted.web.microdom.Document into a Python object. - """ - du = DOMUnjellier() - return du.unjelly(document) - - -def jellyToXML(object, file=None): - """jellyToXML(object, [file]) -> None | string - - Converts a Python object to an XML stream. If you pass a file, the XML - will be written to that file; otherwise, a string of the XML will be - returned. - """ - document = jellyToDOM(object) - if file: - document.writexml(file, "", " ", "\n") - else: - return document.toprettyxml(" ", "\n") - -def unjellyFromXML(stringOrFile): - """I convert a string or the contents of an XML file into a Python object. - """ - if hasattr(stringOrFile, "read"): - document = parse(stringOrFile) - else: - document = parseString(stringOrFile) - return unjellyFromDOM(document) - - -from twisted.web.microdom import Element, Document, parse, parseString, NodeList diff --git a/tools/buildbot/pylibs/twisted/persisted/sob.py b/tools/buildbot/pylibs/twisted/persisted/sob.py deleted file mode 100644 index 84d318d..0000000 --- a/tools/buildbot/pylibs/twisted/persisted/sob.py +++ /dev/null @@ -1,233 +0,0 @@ -# -*- test-case-name: twisted.test.test_sob -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -""" -Save and load Small OBjects to and from files, using various formats. - -Maintainer: U{Moshe Zadka} -""" - -import os, md5, sys -try: - import cPickle as pickle -except ImportError: - import pickle -try: - import cStringIO as StringIO -except ImportError: - import StringIO -from twisted.python import log, runtime -from twisted.persisted import styles -from zope.interface import implements, Interface - -# Note: -# These encrypt/decrypt functions only work for data formats -# which are immune to having spaces tucked at the end. -# All data formats which persist saves hold that condition. -def _encrypt(passphrase, data): - from Crypto.Cipher import AES as cipher - leftover = len(data) % cipher.block_size - if leftover: - data += ' '*(cipher.block_size - leftover) - return cipher.new(md5.new(passphrase).digest()[:16]).encrypt(data) - -def _decrypt(passphrase, data): - from Crypto.Cipher import AES - return AES.new(md5.new(passphrase).digest()[:16]).decrypt(data) - - -class IPersistable(Interface): - - """An object which can be saved in several formats to a file""" - - def setStyle(style): - """Set desired format. - - @type style: string (one of 'pickle', 'source' or 'xml') - """ - - def save(tag=None, filename=None, passphrase=None): - """Save object to file. - - @type tag: string - @type filename: string - @type passphrase: string - """ - - -class Persistent: - - implements(IPersistable) - - style = "pickle" - - def __init__(self, original, name): - self.original = original - self.name = name - - def setStyle(self, style): - """Set desired format. - - @type style: string (one of 'pickle', 'source' or 'xml') - """ - self.style = style - - def _getFilename(self, filename, ext, tag): - if filename: - finalname = filename - filename = finalname + "-2" - elif tag: - filename = "%s-%s-2.%s" % (self.name, tag, ext) - finalname = "%s-%s.%s" % (self.name, tag, ext) - else: - filename = "%s-2.%s" % (self.name, ext) - finalname = "%s.%s" % (self.name, ext) - return finalname, filename - - def _saveTemp(self, filename, passphrase, dumpFunc): - f = open(filename, 'wb') - if passphrase is None: - dumpFunc(self.original, f) - else: - s = StringIO.StringIO() - dumpFunc(self.original, s) - f.write(_encrypt(passphrase, s.getvalue())) - f.close() - - def _getStyle(self): - if self.style == "xml": - from twisted.persisted.marmalade import jellyToXML as dumpFunc - ext = "tax" - elif self.style == "source": - from twisted.persisted.aot import jellyToSource as dumpFunc - ext = "tas" - else: - def dumpFunc(obj, file): - pickle.dump(obj, file, 2) - ext = "tap" - return ext, dumpFunc - - def save(self, tag=None, filename=None, passphrase=None): - """Save object to file. - - @type tag: string - @type filename: string - @type passphrase: string - """ - ext, dumpFunc = self._getStyle() - if passphrase: - ext = 'e' + ext - finalname, filename = self._getFilename(filename, ext, tag) - log.msg("Saving "+self.name+" application to "+finalname+"...") - self._saveTemp(filename, passphrase, dumpFunc) - if runtime.platformType == "win32" and os.path.isfile(finalname): - os.remove(finalname) - os.rename(filename, finalname) - log.msg("Saved.") - -# "Persistant" has been present since 1.0.7, so retain it for compatibility -Persistant = Persistent - -class _EverythingEphemeral(styles.Ephemeral): - - initRun = 0 - - def __init__(self, mainMod): - """ - @param mainMod: The '__main__' module that this class will proxy. - """ - self.mainMod = mainMod - - def __getattr__(self, key): - try: - return getattr(self.mainMod, key) - except AttributeError: - if self.initRun: - raise - else: - log.msg("Warning! Loading from __main__: %s" % key) - return styles.Ephemeral() - - -def load(filename, style, passphrase=None): - """Load an object from a file. - - Deserialize an object from a file. The file can be encrypted. - - @param filename: string - @param style: string (one of 'source', 'xml' or 'pickle') - @param passphrase: string - """ - mode = 'r' - if style=='source': - from twisted.persisted.aot import unjellyFromSource as _load - elif style=='xml': - from twisted.persisted.marmalade import unjellyFromXML as _load - else: - _load, mode = pickle.load, 'rb' - if passphrase: - fp = StringIO.StringIO(_decrypt(passphrase, - open(filename, 'rb').read())) - else: - fp = open(filename, mode) - ee = _EverythingEphemeral(sys.modules['__main__']) - sys.modules['__main__'] = ee - ee.initRun = 1 - try: - value = _load(fp) - finally: - # restore __main__ if an exception is raised. - sys.modules['__main__'] = ee.mainMod - - styles.doUpgrade() - ee.initRun = 0 - persistable = IPersistable(value, None) - if persistable is not None: - persistable.setStyle(style) - return value - - -def loadValueFromFile(filename, variable, passphrase=None): - """Load the value of a variable in a Python file. - - Run the contents of the file, after decrypting if C{passphrase} is - given, in a namespace and return the result of the variable - named C{variable}. - - @param filename: string - @param variable: string - @param passphrase: string - """ - if passphrase: - mode = 'rb' - else: - mode = 'r' - fileObj = open(filename, mode) - d = {'__file__': filename} - if passphrase: - data = fileObj.read() - data = _decrypt(passphrase, data) - exec data in d, d - else: - exec fileObj in d, d - value = d[variable] - return value - -def guessType(filename): - ext = os.path.splitext(filename)[1] - return { - '.tac': 'python', - '.etac': 'python', - '.py': 'python', - '.tap': 'pickle', - '.etap': 'pickle', - '.tas': 'source', - '.etas': 'source', - '.tax': 'xml', - '.etax': 'xml' - }[ext] - -__all__ = ['loadValueFromFile', 'load', 'Persistent', 'Persistant', - 'IPersistable', 'guessType'] diff --git a/tools/buildbot/pylibs/twisted/persisted/styles.py b/tools/buildbot/pylibs/twisted/persisted/styles.py deleted file mode 100644 index a684935..0000000 --- a/tools/buildbot/pylibs/twisted/persisted/styles.py +++ /dev/null @@ -1,256 +0,0 @@ -# -*- test-case-name: twisted.test.test_persisted -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - - -""" -Different styles of persisted objects. -""" - -# System Imports -import types -import copy_reg -import copy - -try: - import cStringIO as StringIO -except ImportError: - import StringIO - -# Twisted Imports -from twisted.python import log - -try: - from new import instancemethod -except: - from org.python.core import PyMethod - instancemethod = PyMethod - -oldModules = {} - -## First, let's register support for some stuff that really ought to -## be registerable... - -def pickleMethod(method): - 'support function for copy_reg to pickle method refs' - return unpickleMethod, (method.im_func.__name__, - method.im_self, - method.im_class) - -def unpickleMethod(im_name, - im_self, - im_class): - 'support function for copy_reg to unpickle method refs' - try: - unbound = getattr(im_class,im_name) - if im_self is None: - return unbound - bound=instancemethod(unbound.im_func, - im_self, - im_class) - return bound - except AttributeError: - log.msg("Method",im_name,"not on class",im_class) - assert im_self is not None,"No recourse: no instance to guess from." - # Attempt a common fix before bailing -- if classes have - # changed around since we pickled this method, we may still be - # able to get it by looking on the instance's current class. - unbound = getattr(im_self.__class__,im_name) - log.msg("Attempting fixup with",unbound) - if im_self is None: - return unbound - bound=instancemethod(unbound.im_func, - im_self, - im_self.__class__) - return bound - -copy_reg.pickle(types.MethodType, - pickleMethod, - unpickleMethod) - -def pickleModule(module): - 'support function for copy_reg to pickle module refs' - return unpickleModule, (module.__name__,) - -def unpickleModule(name): - 'support function for copy_reg to unpickle module refs' - if oldModules.has_key(name): - log.msg("Module has moved: %s" % name) - name = oldModules[name] - log.msg(name) - return __import__(name,{},{},'x') - - -copy_reg.pickle(types.ModuleType, - pickleModule, - unpickleModule) - -def pickleStringO(stringo): - 'support function for copy_reg to pickle StringIO.OutputTypes' - return unpickleStringO, (stringo.getvalue(), stringo.tell()) - -def unpickleStringO(val, sek): - x = StringIO.StringIO() - x.write(val) - x.seek(sek) - return x - -if hasattr(StringIO, 'OutputType'): - copy_reg.pickle(StringIO.OutputType, - pickleStringO, - unpickleStringO) - -def pickleStringI(stringi): - return unpickleStringI, (stringi.getvalue(), stringi.tell()) - -def unpickleStringI(val, sek): - x = StringIO.StringIO(val) - x.seek(sek) - return x - - -if hasattr(StringIO, 'InputType'): - copy_reg.pickle(StringIO.InputType, - pickleStringI, - unpickleStringI) - -class Ephemeral: - """ - This type of object is never persisted; if possible, even references to it - are eliminated. - """ - - def __getstate__(self): - log.msg( "WARNING: serializing ephemeral %s" % self ) - import gc - for r in gc.get_referrers(self): - log.msg( " referred to by %s" % (r,)) - return None - - def __setstate__(self, state): - log.msg( "WARNING: unserializing ephemeral %s" % self.__class__ ) - self.__class__ = Ephemeral - - -versionedsToUpgrade = {} -upgraded = {} - -def doUpgrade(): - global versionedsToUpgrade, upgraded - for versioned in versionedsToUpgrade.values(): - requireUpgrade(versioned) - versionedsToUpgrade = {} - upgraded = {} - -def requireUpgrade(obj): - """Require that a Versioned instance be upgraded completely first. - """ - objID = id(obj) - if objID in versionedsToUpgrade and objID not in upgraded: - upgraded[objID] = 1 - obj.versionUpgrade() - return obj - -from twisted.python import reflect - -def _aybabtu(c): - l = [] - for b in reflect.allYourBase(c, Versioned): - if b not in l and b is not Versioned: - l.append(b) - return l - -class Versioned: - """ - This type of object is persisted with versioning information. - - I have a single class attribute, the int persistenceVersion. After I am - unserialized (and styles.doUpgrade() is called), self.upgradeToVersionX() - will be called for each version upgrade I must undergo. - - For example, if I serialize an instance of a Foo(Versioned) at version 4 - and then unserialize it when the code is at version 9, the calls:: - - self.upgradeToVersion5() - self.upgradeToVersion6() - self.upgradeToVersion7() - self.upgradeToVersion8() - self.upgradeToVersion9() - - will be made. If any of these methods are undefined, a warning message - will be printed. - """ - persistenceVersion = 0 - persistenceForgets = () - - def __setstate__(self, state): - versionedsToUpgrade[id(self)] = self - self.__dict__ = state - - def __getstate__(self, dict=None): - """Get state, adding a version number to it on its way out. - """ - dct = copy.copy(dict or self.__dict__) - bases = _aybabtu(self.__class__) - bases.reverse() - bases.append(self.__class__) # don't forget me!! - for base in bases: - if base.__dict__.has_key('persistenceForgets'): - for slot in base.persistenceForgets: - if dct.has_key(slot): - del dct[slot] - if base.__dict__.has_key('persistenceVersion'): - dct['%s.persistenceVersion' % reflect.qual(base)] = base.persistenceVersion - return dct - - def versionUpgrade(self): - """(internal) Do a version upgrade. - """ - bases = _aybabtu(self.__class__) - # put the bases in order so superclasses' persistenceVersion methods - # will be called first. - bases.reverse() - bases.append(self.__class__) # don't forget me!! - # first let's look for old-skool versioned's - if self.__dict__.has_key("persistenceVersion"): - - # Hacky heuristic: if more than one class subclasses Versioned, - # we'll assume that the higher version number wins for the older - # class, so we'll consider the attribute the version of the older - # class. There are obviously possibly times when this will - # eventually be an incorrect assumption, but hopefully old-school - # persistenceVersion stuff won't make it that far into multiple - # classes inheriting from Versioned. - - pver = self.__dict__['persistenceVersion'] - del self.__dict__['persistenceVersion'] - highestVersion = 0 - highestBase = None - for base in bases: - if not base.__dict__.has_key('persistenceVersion'): - continue - if base.persistenceVersion > highestVersion: - highestBase = base - highestVersion = base.persistenceVersion - if highestBase: - self.__dict__['%s.persistenceVersion' % reflect.qual(highestBase)] = pver - for base in bases: - # ugly hack, but it's what the user expects, really - if (Versioned not in base.__bases__ and - not base.__dict__.has_key('persistenceVersion')): - continue - currentVers = base.persistenceVersion - pverName = '%s.persistenceVersion' % reflect.qual(base) - persistVers = (self.__dict__.get(pverName) or 0) - if persistVers: - del self.__dict__[pverName] - assert persistVers <= currentVers, "Sorry, can't go backwards in time." - while persistVers < currentVers: - persistVers = persistVers + 1 - method = base.__dict__.get('upgradeToVersion%s' % persistVers, None) - if method: - log.msg( "Upgrading %s (of %s @ %s) to version %s" % (reflect.qual(base), reflect.qual(self.__class__), id(self), persistVers) ) - method(self) - else: - log.msg( 'Warning: cannot upgrade %s to version %s' % (base, persistVers) ) diff --git a/tools/buildbot/pylibs/twisted/plugin.py b/tools/buildbot/pylibs/twisted/plugin.py deleted file mode 100644 index 0b33a70..0000000 --- a/tools/buildbot/pylibs/twisted/plugin.py +++ /dev/null @@ -1,246 +0,0 @@ -# -*- test-case-name: twisted.test.test_plugin -*- -# Copyright (c) 2005 Divmod, Inc. -# Copyright (c) 2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Plugin system for Twisted. - -@author: U{Jp Calderone} -@author: U{Glyph Lefkowitz} -""" - -import os -import sys - -from zope.interface import Interface, providedBy - -def _determinePickleModule(): - """ - Determine which 'pickle' API module to use. - """ - try: - import cPickle - return cPickle - except ImportError: - import pickle - return pickle - -pickle = _determinePickleModule() - -from twisted.python.components import getAdapterFactory -from twisted.python.reflect import namedAny -from twisted.python import log -from twisted.python.modules import getModule - - - -class IPlugin(Interface): - """ - Interface that must be implemented by all plugins. - - Only objects which implement this interface will be considered for return - by C{getPlugins}. To be useful, plugins should also implement some other - application-specific interface. - """ - - - -class CachedPlugin(object): - def __init__(self, dropin, name, description, provided): - self.dropin = dropin - self.name = name - self.description = description - self.provided = provided - self.dropin.plugins.append(self) - - def __repr__(self): - return '' % ( - self.name, self.dropin.moduleName, - ', '.join([i.__name__ for i in self.provided])) - - def load(self): - return namedAny(self.dropin.moduleName + '.' + self.name) - - def __conform__(self, interface, registry=None, default=None): - for providedInterface in self.provided: - if providedInterface.isOrExtends(interface): - return self.load() - if getAdapterFactory(providedInterface, interface, None) is not None: - return interface(self.load(), default) - return default - - # backwards compat HOORJ - getComponent = __conform__ - - - -class CachedDropin(object): - """ - A collection of L{CachedPlugin} instances from a particular module in a - plugin package. - - @type moduleName: C{str} - @ivar moduleName: The fully qualified name of the plugin module this - represents. - - @type description: C{str} or C{NoneType} - @ivar description: A brief explanation of this collection of plugins - (probably the plugin module's docstring). - - @type plugins: C{list} - @ivar plugins: The L{CachedPlugin} instances which were loaded from this - dropin. - """ - def __init__(self, moduleName, description): - self.moduleName = moduleName - self.description = description - self.plugins = [] - - - -def _generateCacheEntry(provider): - dropin = CachedDropin(provider.__name__, - provider.__doc__) - for k, v in provider.__dict__.iteritems(): - plugin = IPlugin(v, None) - if plugin is not None: - cachedPlugin = CachedPlugin(dropin, k, v.__doc__, list(providedBy(plugin))) - return dropin - -try: - fromkeys = dict.fromkeys -except AttributeError: - def fromkeys(keys, value=None): - d = {} - for k in keys: - d[k] = value - return d - -def getCache(module): - """ - Compute all the possible loadable plugins, while loading as few as - possible and hitting the filesystem as little as possible. - - @param module: a Python module object. This represents a package to search - for plugins. - - @return: a dictionary mapping module names to CachedDropin instances. - """ - allCachesCombined = {} - mod = getModule(module.__name__) - # don't want to walk deep, only immediate children. - lastPath = None - buckets = {} - # Fill buckets with modules by related entry on the given package's - # __path__. There's an abstraction inversion going on here, because this - # information is already represented internally in twisted.python.modules, - # but it's simple enough that I'm willing to live with it. If anyone else - # wants to fix up this iteration so that it's one path segment at a time, - # be my guest. --glyph - for plugmod in mod.iterModules(): - fpp = plugmod.filePath.parent() - if fpp not in buckets: - buckets[fpp] = [] - bucket = buckets[fpp] - bucket.append(plugmod) - for pseudoPackagePath, bucket in buckets.iteritems(): - dropinPath = pseudoPackagePath.child('dropin.cache') - try: - lastCached = dropinPath.getModificationTime() - dropinDotCache = pickle.load(dropinPath.open('rb')) - except: - dropinDotCache = {} - lastCached = 0 - - needsWrite = False - existingKeys = {} - for pluginModule in bucket: - pluginKey = pluginModule.name.split('.')[-1] - existingKeys[pluginKey] = True - if ((pluginKey not in dropinDotCache) or - (pluginModule.filePath.getModificationTime() >= lastCached)): - needsWrite = True - try: - provider = pluginModule.load() - except: - # dropinDotCache.pop(pluginKey, None) - log.err() - else: - entry = _generateCacheEntry(provider) - dropinDotCache[pluginKey] = entry - # Make sure that the cache doesn't contain any stale plugins. - for pluginKey in dropinDotCache.keys(): - if pluginKey not in existingKeys: - del dropinDotCache[pluginKey] - needsWrite = True - if needsWrite: - try: - dropinPath.setContent(pickle.dumps(dropinDotCache)) - except: - log.err() - allCachesCombined.update(dropinDotCache) - return allCachesCombined - - -def getPlugins(interface, package=None): - """ - Retrieve all plugins implementing the given interface beneath the given module. - - @param interface: An interface class. Only plugins which implement this - interface will be returned. - - @param package: A package beneath which plugins are installed. For - most uses, the default value is correct. - - @return: An iterator of plugins. - """ - if package is None: - import twisted.plugins as package - allDropins = getCache(package) - for dropin in allDropins.itervalues(): - for plugin in dropin.plugins: - try: - adapted = interface(plugin, None) - except: - log.err() - else: - if adapted is not None: - yield adapted - - -# Old, backwards compatible name. Don't use this. -getPlugIns = getPlugins - - -def pluginPackagePaths(name): - """ - Return a list of additional directories which should be searched for - modules to be included as part of the named plugin package. - - @type name: C{str} - @param name: The fully-qualified Python name of a plugin package, eg - C{'twisted.plugins'}. - - @rtype: C{list} of C{str} - @return: The absolute paths to other directories which may contain plugin - modules for the named plugin package. - """ - package = name.split('.') - # Note that this may include directories which do not exist. It may be - # preferable to remove such directories at this point, rather than allow - # them to be searched later on. - # - # Note as well that only '__init__.py' will be considered to make a - # directory a package (and thus exclude it from this list). This means - # that if you create a master plugin package which has some other kind of - # __init__ (eg, __init__.pyc) it will be incorrectly treated as a - # supplementary plugin directory. - return [ - os.path.abspath(os.path.join(x, *package)) - for x - in sys.path - if - not os.path.exists(os.path.join(x, *package + ['__init__.py']))] - -__all__ = ['getPlugins', 'pluginPackagePaths'] diff --git a/tools/buildbot/pylibs/twisted/plugins/__init__.py b/tools/buildbot/pylibs/twisted/plugins/__init__.py deleted file mode 100644 index 9bb6d68..0000000 --- a/tools/buildbot/pylibs/twisted/plugins/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -# -*- test-case-name: twisted.test.test_plugin -*- -# Copyright (c) 2005 Divmod, Inc. -# Copyright (c) 2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Plugins go in directories on your PYTHONPATH named twisted/plugins: -this is the only place where an __init__.py is necessary, thanks to -the __path__ variable. - -@author: U{Jp Calderone} -@author: U{Glyph Lefkowitz} -""" - -from twisted.plugin import pluginPackagePaths -__path__.extend(pluginPackagePaths(__name__)) -__all__ = [] # nothing to see here, move along, move along diff --git a/tools/buildbot/pylibs/twisted/plugins/cred_anonymous.py b/tools/buildbot/pylibs/twisted/plugins/cred_anonymous.py deleted file mode 100644 index 8b4c00b..0000000 --- a/tools/buildbot/pylibs/twisted/plugins/cred_anonymous.py +++ /dev/null @@ -1,40 +0,0 @@ -# -*- test-case-name: twisted.test.test_strcred -*- -# -# Copyright (c) 2007-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Cred plugin for anonymous logins. -""" - -from zope.interface import implements - -from twisted import plugin -from twisted.cred.checkers import AllowAnonymousAccess -from twisted.cred.strcred import ICheckerFactory -from twisted.cred.credentials import IAnonymous - - -anonymousCheckerFactoryHelp = """ -This allows anonymous authentication for servers that support it. -""" - - -class AnonymousCheckerFactory(object): - """ - Generates checkers that will authenticate an anonymous request. - """ - implements(ICheckerFactory, plugin.IPlugin) - authType = 'anonymous' - authHelp = anonymousCheckerFactoryHelp - argStringFormat = 'No argstring required.' - credentialInterfaces = (IAnonymous,) - - - def generateChecker(self, argstring=''): - return AllowAnonymousAccess() - - - -theAnonymousCheckerFactory = AnonymousCheckerFactory() - diff --git a/tools/buildbot/pylibs/twisted/plugins/cred_file.py b/tools/buildbot/pylibs/twisted/plugins/cred_file.py deleted file mode 100644 index fbc6145..0000000 --- a/tools/buildbot/pylibs/twisted/plugins/cred_file.py +++ /dev/null @@ -1,60 +0,0 @@ -# -*- test-case-name: twisted.test.test_strcred -*- -# -# Copyright (c) 2007-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Cred plugin for a file of the format 'username:password'. -""" - -import sys - -from zope.interface import implements - -from twisted import plugin -from twisted.cred.checkers import FilePasswordDB -from twisted.cred.strcred import ICheckerFactory -from twisted.cred.credentials import IUsernamePassword, IUsernameHashedPassword - - - -fileCheckerFactoryHelp = """ -This checker expects to receive the location of a file that -conforms to the FilePasswordDB format. Each line in the file -should be of the format 'username:password', in plain text. -""" - -invalidFileWarning = 'Warning: not a valid file' - - - -class FileCheckerFactory(object): - """ - A factory for instances of L{FilePasswordDB}. - """ - implements(ICheckerFactory, plugin.IPlugin) - authType = 'file' - authHelp = fileCheckerFactoryHelp - argStringFormat = 'Location of a FilePasswordDB-formatted file.' - # Explicitly defined here because FilePasswordDB doesn't do it for us - credentialInterfaces = (IUsernamePassword, IUsernameHashedPassword) - - errorOutput = sys.stderr - - def generateChecker(self, argstring): - """ - This checker factory expects to get the location of a file. - The file should conform to the format required by - L{FilePasswordDB} (using defaults for all - initialization parameters). - """ - from twisted.python.filepath import FilePath - if not argstring.strip(): - raise ValueError, '%r requires a filename' % self.authType - elif not FilePath(argstring).isfile(): - self.errorOutput.write('%s: %s\n' % (invalidFileWarning, argstring)) - return FilePasswordDB(argstring) - - - -theFileCheckerFactory = FileCheckerFactory() diff --git a/tools/buildbot/pylibs/twisted/plugins/cred_memory.py b/tools/buildbot/pylibs/twisted/plugins/cred_memory.py deleted file mode 100644 index 33153f7..0000000 --- a/tools/buildbot/pylibs/twisted/plugins/cred_memory.py +++ /dev/null @@ -1,68 +0,0 @@ -# -*- test-case-name: twisted.test.test_strcred -*- -# -# Copyright (c) 2007-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Cred plugin for an in-memory user database. -""" - -from zope.interface import implements - -from twisted import plugin -from twisted.cred.strcred import ICheckerFactory -from twisted.cred.checkers import InMemoryUsernamePasswordDatabaseDontUse -from twisted.cred.credentials import IUsernamePassword, IUsernameHashedPassword - - - -inMemoryCheckerFactoryHelp = """ -A checker that uses an in-memory user database. - -This is only of use in one-off test programs or examples which -don't want to focus too much on how credentials are verified. You -really don't want to use this for anything else. It is a toy. -""" - - - -class InMemoryCheckerFactory(object): - """ - A factory for in-memory credentials checkers. - - This is only of use in one-off test programs or examples which don't - want to focus too much on how credentials are verified. - - You really don't want to use this for anything else. It is, at best, a - toy. If you need a simple credentials checker for a real application, - see L{cred_passwd.PasswdCheckerFactory}. - """ - implements(ICheckerFactory, plugin.IPlugin) - authType = 'memory' - authHelp = inMemoryCheckerFactoryHelp - argStringFormat = 'A colon-separated list (name:password:...)' - credentialInterfaces = (IUsernamePassword, - IUsernameHashedPassword) - - def generateChecker(self, argstring): - """ - This checker factory expects to get a list of - username:password pairs, with each pair also separated by a - colon. For example, the string 'alice:f:bob:g' would generate - two users, one named 'alice' and one named 'bob'. - """ - checker = InMemoryUsernamePasswordDatabaseDontUse() - if argstring: - pieces = argstring.split(':') - if len(pieces) % 2: - from twisted.cred.strcred import InvalidAuthArgumentString - raise InvalidAuthArgumentString( - "argstring must be in format U:P:...") - for i in range(0, len(pieces), 2): - username, password = pieces[i], pieces[i+1] - checker.addUser(username, password) - return checker - - - -theInMemoryCheckerFactory = InMemoryCheckerFactory() diff --git a/tools/buildbot/pylibs/twisted/plugins/cred_unix.py b/tools/buildbot/pylibs/twisted/plugins/cred_unix.py deleted file mode 100644 index b67df8f..0000000 --- a/tools/buildbot/pylibs/twisted/plugins/cred_unix.py +++ /dev/null @@ -1,138 +0,0 @@ -# -*- test-case-name: twisted.test.test_strcred -*- -# -# Copyright (c) 2007-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Cred plugin for UNIX user accounts. -""" - -from zope.interface import implements - -from twisted import plugin -from twisted.cred.strcred import ICheckerFactory -from twisted.cred.checkers import ICredentialsChecker -from twisted.cred.credentials import IUsernamePassword -from twisted.cred.error import UnauthorizedLogin -from twisted.internet import defer - - - -def verifyCryptedPassword(crypted, pw): - if crypted[0] == '$': # md5_crypt encrypted - salt = '$1$' + crypted.split('$')[2] - else: - salt = crypted[:2] - try: - import crypt - except ImportError: - crypt = None - - if crypt is None: - raise NotImplementedError("cred_unix not supported on this platform") - return crypt.crypt(pw, salt) == crypted - - - -class UNIXChecker(object): - """ - A credentials checker for a UNIX server. This will check that - an authenticating username/password is a valid user on the system. - - Does not work on Windows. - - Right now this supports Python's pwd and spwd modules, if they are - installed. It does not support PAM. - """ - implements(ICredentialsChecker) - credentialInterfaces = (IUsernamePassword,) - - - def checkPwd(self, pwd, username, password): - try: - cryptedPass = pwd.getpwnam(username)[1] - except KeyError: - return defer.fail(UnauthorizedLogin()) - else: - if cryptedPass in ('*', 'x'): - # Allow checkSpwd to take over - return None - elif verifyCryptedPassword(cryptedPass, password): - return defer.succeed(username) - - - def checkSpwd(self, spwd, username, password): - try: - cryptedPass = spwd.getspnam(username)[1] - except KeyError: - return defer.fail(UnauthorizedLogin()) - else: - if verifyCryptedPassword(cryptedPass, password): - return defer.succeed(username) - - - def requestAvatarId(self, credentials): - username, password = credentials.username, credentials.password - - try: - import pwd - except ImportError: - pwd = None - - if pwd is not None: - checked = self.checkPwd(pwd, username, password) - if checked is not None: - return checked - - try: - import spwd - except ImportError: - spwd = None - - if spwd is not None: - checked = self.checkSpwd(spwd, username, password) - if checked is not None: - return checked - # TODO: check_pam? - # TODO: check_shadow? - return defer.fail(UnauthorizedLogin()) - - - -unixCheckerFactoryHelp = """ -This checker will attempt to use every resource available to -authenticate against the list of users on the local UNIX system. -(This does not support Windows servers for very obvious reasons.) - -Right now, this includes support for: - - * Python's pwd module (which checks /etc/passwd) - * Python's spwd module (which checks /etc/shadow) - -Future versions may include support for PAM authentication. -""" - - - -class UNIXCheckerFactory(object): - """ - A factory for L{UNIXChecker}. - """ - implements(ICheckerFactory, plugin.IPlugin) - authType = 'unix' - authHelp = unixCheckerFactoryHelp - argStringFormat = 'No argstring required.' - credentialInterfaces = UNIXChecker.credentialInterfaces - - def generateChecker(self, argstring): - """ - This checker factory ignores the argument string. Everything - needed to generate a user database is pulled out of the local - UNIX environment. - """ - return UNIXChecker() - - - -theUnixCheckerFactory = UNIXCheckerFactory() - diff --git a/tools/buildbot/pylibs/twisted/plugins/twisted_conch.py b/tools/buildbot/pylibs/twisted/plugins/twisted_conch.py deleted file mode 100644 index 3214866..0000000 --- a/tools/buildbot/pylibs/twisted/plugins/twisted_conch.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.application.service import ServiceMaker - -TwistedSSH = ServiceMaker( - "Twisted Conch Server", - "twisted.conch.tap", - "A Conch SSH service.", - "conch") - -TwistedManhole = ServiceMaker( - "Twisted Manhole (new)", - "twisted.conch.manhole_tap", - ("An interactive remote debugger service accessible via telnet " - "and ssh and providing syntax coloring and basic line editing " - "functionality."), - "manhole") diff --git a/tools/buildbot/pylibs/twisted/plugins/twisted_ftp.py b/tools/buildbot/pylibs/twisted/plugins/twisted_ftp.py deleted file mode 100644 index a3d2a1f..0000000 --- a/tools/buildbot/pylibs/twisted/plugins/twisted_ftp.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.application.service import ServiceMaker - -TwistedFTP = ServiceMaker( - "Twisted FTP", - "twisted.tap.ftp", - "An FTP server.", - "ftp") diff --git a/tools/buildbot/pylibs/twisted/plugins/twisted_inet.py b/tools/buildbot/pylibs/twisted/plugins/twisted_inet.py deleted file mode 100644 index b05df88..0000000 --- a/tools/buildbot/pylibs/twisted/plugins/twisted_inet.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.application.service import ServiceMaker - -TwistedINETD = ServiceMaker( - "Twisted INETD Server", - "twisted.runner.inetdtap", - "An inetd(8) replacement.", - "inetd") diff --git a/tools/buildbot/pylibs/twisted/plugins/twisted_lore.py b/tools/buildbot/pylibs/twisted/plugins/twisted_lore.py deleted file mode 100644 index 43bb913..0000000 --- a/tools/buildbot/pylibs/twisted/plugins/twisted_lore.py +++ /dev/null @@ -1,38 +0,0 @@ - -from zope.interface import implements - -from twisted.lore.scripts.lore import IProcessor -from twisted.plugin import IPlugin - -class _LorePlugin(object): - implements(IPlugin, IProcessor) - - def __init__(self, name, moduleName, description): - self.name = name - self.moduleName = moduleName - self.description = description - -DefaultProcessor = _LorePlugin( - "lore", - "twisted.lore.default", - "Lore format") - -MathProcessor = _LorePlugin( - "mlore", - "twsited.lore.lmath", - "Lore format with LaTeX formula") - -SlideProcessor = _LorePlugin( - "lore-slides", - "twisted.lore.slides", - "Lore for slides") - -ManProcessor = _LorePlugin( - "man", - "twisted.lore.man2lore", - "UNIX Man pages") - -NevowProcessor = _LorePlugin( - "nevow", - "twisted.lore.nevowlore", - "Nevow for Lore") diff --git a/tools/buildbot/pylibs/twisted/plugins/twisted_mail.py b/tools/buildbot/pylibs/twisted/plugins/twisted_mail.py deleted file mode 100644 index 869b0cb..0000000 --- a/tools/buildbot/pylibs/twisted/plugins/twisted_mail.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.application.service import ServiceMaker - -TwistedMail = ServiceMaker( - "Twisted Mail", - "twisted.mail.tap", - "An email service", - "mail") diff --git a/tools/buildbot/pylibs/twisted/plugins/twisted_manhole.py b/tools/buildbot/pylibs/twisted/plugins/twisted_manhole.py deleted file mode 100644 index 126f251..0000000 --- a/tools/buildbot/pylibs/twisted/plugins/twisted_manhole.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.application.service import ServiceMaker - -TwistedManhole = ServiceMaker( - "Twisted Manhole (old)", - "twisted.tap.manhole", - "An interactive remote debugger service.", - "manhole-old") diff --git a/tools/buildbot/pylibs/twisted/plugins/twisted_names.py b/tools/buildbot/pylibs/twisted/plugins/twisted_names.py deleted file mode 100644 index e48edaf..0000000 --- a/tools/buildbot/pylibs/twisted/plugins/twisted_names.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.application.service import ServiceMaker - -TwistedNames = ServiceMaker( - "Twisted DNS Server", - "twisted.names.tap", - "A domain name server.", - "dns") diff --git a/tools/buildbot/pylibs/twisted/plugins/twisted_news.py b/tools/buildbot/pylibs/twisted/plugins/twisted_news.py deleted file mode 100644 index 8970ae2..0000000 --- a/tools/buildbot/pylibs/twisted/plugins/twisted_news.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.application.service import ServiceMaker - -TwistedNews = ServiceMaker( - "Twisted News", - "twisted.news.tap", - "A news server.", - "news") diff --git a/tools/buildbot/pylibs/twisted/plugins/twisted_portforward.py b/tools/buildbot/pylibs/twisted/plugins/twisted_portforward.py deleted file mode 100644 index 77d605e..0000000 --- a/tools/buildbot/pylibs/twisted/plugins/twisted_portforward.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.application.service import ServiceMaker - -TwistedPortForward = ServiceMaker( - "Twisted Port-Forwarding", - "twisted.tap.portforward", - "A simple port-forwarder.", - "portforward") diff --git a/tools/buildbot/pylibs/twisted/plugins/twisted_qtstub.py b/tools/buildbot/pylibs/twisted/plugins/twisted_qtstub.py deleted file mode 100644 index 1b9b08a..0000000 --- a/tools/buildbot/pylibs/twisted/plugins/twisted_qtstub.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright (c) 2006 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Backwards-compatibility plugin for the Qt reactor. - -This provides a Qt reactor plugin named C{qt} which emits a deprecation -warning and a pointer to the separately distributed Qt reactor plugins. -""" - -import warnings - -from twisted.application.reactors import Reactor, NoSuchReactor - -wikiURL = 'http://twistedmatrix.com/trac/wiki/QTReactor' -errorMessage = ('qtreactor is no longer a part of Twisted due to licensing ' - 'issues. Please see %s for details.' % (wikiURL,)) - -class QTStub(Reactor): - """ - Reactor plugin which emits a deprecation warning on the successful - installation of its reactor or a pointer to further information if an - ImportError occurs while attempting to install it. - """ - def __init__(self): - super(QTStub, self).__init__( - 'qt', 'qtreactor', 'QT integration reactor') - - - def install(self): - """ - Install the Qt reactor with a deprecation warning or try to point - the user to further information if it cannot be installed. - """ - try: - super(QTStub, self).install() - except (ValueError, ImportError): - raise NoSuchReactor(errorMessage) - else: - warnings.warn( - "Please use -r qt3 to import qtreactor", - category=DeprecationWarning) - - -qt = QTStub() diff --git a/tools/buildbot/pylibs/twisted/plugins/twisted_reactors.py b/tools/buildbot/pylibs/twisted/plugins/twisted_reactors.py deleted file mode 100644 index 428e96c..0000000 --- a/tools/buildbot/pylibs/twisted/plugins/twisted_reactors.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright (c) 2006 Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.application.reactors import Reactor - -default = Reactor( - 'default', 'twisted.internet.default', - 'The best reactor for the current platform.') - -select = Reactor( - 'select', 'twisted.internet.selectreactor', 'select(2)-based reactor.') -wx = Reactor( - 'wx', 'twisted.internet.wxreactor', 'wxPython integration reactor.') -gtk = Reactor( - 'gtk', 'twisted.internet.gtkreactor', 'Gtk1 integration reactor.') -gtk2 = Reactor( - 'gtk2', 'twisted.internet.gtk2reactor', 'Gtk2 integration reactor.') -glib2 = Reactor( - 'glib2', 'twisted.internet.glib2reactor', - 'GLib2 event-loop integration reactor.') -glade = Reactor( - 'debug-gui', 'twisted.manhole.gladereactor', - 'Semi-functional debugging/introspection reactor.') -win32er = Reactor( - 'win32', 'twisted.internet.win32eventreactor', - 'Win32 WaitForMultipleObjects-based reactor.') -poll = Reactor( - 'poll', 'twisted.internet.pollreactor', 'poll(2)-based reactor.') -epoll = Reactor( - 'epoll', 'twisted.internet.epollreactor', 'epoll(4)-based reactor.') -cf = Reactor( - 'cf' , 'twisted.internet.cfreactor', - 'CoreFoundation integration reactor.') -kqueue = Reactor( - 'kqueue', 'twisted.internet.kqreactor', 'kqueue(2)-based reactor.') -iocp = Reactor( - 'iocp', 'twisted.internet.iocpreactor', - 'Win32 IO Completion Ports-based reactor.') diff --git a/tools/buildbot/pylibs/twisted/plugins/twisted_socks.py b/tools/buildbot/pylibs/twisted/plugins/twisted_socks.py deleted file mode 100644 index 354a4de..0000000 --- a/tools/buildbot/pylibs/twisted/plugins/twisted_socks.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.application.service import ServiceMaker - -TwistedSOCKS = ServiceMaker( - "Twisted SOCKS", - "twisted.tap.socks", - "A SOCKSv4 proxy service.", - "socks") diff --git a/tools/buildbot/pylibs/twisted/plugins/twisted_telnet.py b/tools/buildbot/pylibs/twisted/plugins/twisted_telnet.py deleted file mode 100644 index 62be602..0000000 --- a/tools/buildbot/pylibs/twisted/plugins/twisted_telnet.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.application.service import ServiceMaker - -TwistedTelnet = ServiceMaker( - "Twisted Telnet Shell Server", - "twisted.tap.telnet", - "A simple, telnet-based remote debugging service.", - "telnet") diff --git a/tools/buildbot/pylibs/twisted/plugins/twisted_trial.py b/tools/buildbot/pylibs/twisted/plugins/twisted_trial.py deleted file mode 100644 index 35401a8..0000000 --- a/tools/buildbot/pylibs/twisted/plugins/twisted_trial.py +++ /dev/null @@ -1,53 +0,0 @@ - -from zope.interface import implements - -from twisted.trial.itrial import IReporter -from twisted.plugin import IPlugin - -class _Reporter(object): - implements(IPlugin, IReporter) - - def __init__(self, name, module, description, longOpt, shortOpt, klass): - self.name = name - self.module = module - self.description = description - self.longOpt = longOpt - self.shortOpt = shortOpt - self.klass = klass - - -Tree = _Reporter("Tree Reporter", - "twisted.trial.reporter", - description="verbose color output (default reporter)", - longOpt="verbose", - shortOpt="v", - klass="TreeReporter") - -BlackAndWhite = _Reporter("Black-And-White Reporter", - "twisted.trial.reporter", - description="Colorless verbose output", - longOpt="bwverbose", - shortOpt="o", - klass="VerboseTextReporter") - -Minimal = _Reporter("Minimal Reporter", - "twisted.trial.reporter", - description="minimal summary output", - longOpt="summary", - shortOpt="s", - klass="MinimalReporter") - -Classic = _Reporter("Classic Reporter", - "twisted.trial.reporter", - description="terse text output", - longOpt="text", - shortOpt="t", - klass="TextReporter") - -Timing = _Reporter("Timing Reporter", - "twisted.trial.reporter", - description="Timing output", - longOpt="timing", - shortOpt=None, - klass="TimingTextReporter") - diff --git a/tools/buildbot/pylibs/twisted/plugins/twisted_web.py b/tools/buildbot/pylibs/twisted/plugins/twisted_web.py deleted file mode 100644 index 861e4df..0000000 --- a/tools/buildbot/pylibs/twisted/plugins/twisted_web.py +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.application.service import ServiceMaker - -TwistedWeb = ServiceMaker( - "Twisted Web", - "twisted.web.tap", - ("A general-purpose web server which can serve from a " - "filesystem or application resource."), - "web") diff --git a/tools/buildbot/pylibs/twisted/plugins/twisted_words.py b/tools/buildbot/pylibs/twisted/plugins/twisted_words.py deleted file mode 100644 index 85d820a..0000000 --- a/tools/buildbot/pylibs/twisted/plugins/twisted_words.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -from zope.interface import classProvides - -from twisted.plugin import IPlugin - -from twisted.application.service import ServiceMaker -from twisted.words import iwords - -TwistedTOC = ServiceMaker( - "Twisted TOC Server", - "twisted.words.toctap", - "An AIM TOC service.", - "toc") - -NewTwistedWords = ServiceMaker( - "New Twisted Words", - "twisted.words.tap", - "A modern words server", - "words") - -class RelayChatInterface(object): - classProvides(IPlugin, iwords.IProtocolPlugin) - - name = 'irc' - - def getFactory(cls, realm, portal): - from twisted.words import service - return service.IRCFactory(realm, portal) - getFactory = classmethod(getFactory) - -class PBChatInterface(object): - classProvides(IPlugin, iwords.IProtocolPlugin) - - name = 'pb' - - def getFactory(cls, realm, portal): - from twisted.spread import pb - return pb.PBServerFactory(portal, True) - getFactory = classmethod(getFactory) - diff --git a/tools/buildbot/pylibs/twisted/protocols/__init__.py b/tools/buildbot/pylibs/twisted/protocols/__init__.py deleted file mode 100644 index 6a5014e..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" - -Twisted Protocols: a collection of internet protocol implementations. - -""" diff --git a/tools/buildbot/pylibs/twisted/protocols/_c_urlarg.c b/tools/buildbot/pylibs/twisted/protocols/_c_urlarg.c deleted file mode 100644 index 15c9996..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/_c_urlarg.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (c) 2001-2004 Twisted Matrix Laboratories. - * See LICENSE for details. - - * - */ -/* _c_urlarg.c */ - -#ifdef __cplusplus -extern "C" { -#endif -#include -#include -#ifdef __cplusplus -} -#endif - -#ifdef __GNUC__ -# define TM_INLINE inline -#else -# define TM_INLINE /* */ -#endif - -static PyObject* UrlargError; - -#define OUTPUTCHAR(c,n) PycStringIO->cwrite(output, c, n) - -#define STATE_INITIAL 0 -#define STATE_PERCENT 1 -#define STATE_HEXDIGIT 2 - -#define NOT_HEXDIGIT 255 -unsigned char hexdigits[256]; - -TM_INLINE int ishexdigit(unsigned char c) { - return hexdigits[c]; -} - -static PyObject *unquote(PyObject *self, PyObject *args, PyObject *kwargs) -{ - unsigned char *s, *r, *end; - unsigned char quotedchar, quotedchartmp = 0, tmp; - unsigned char escchar = '%'; /* the character we use to begin %AB sequences */ - static char *kwlist[] = {"s", "escchar", NULL}; - int state = STATE_INITIAL, length; - PyObject *output, *str; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|c:unquote", kwlist, &s, &length, &escchar)) { - return NULL; - } - /* output = cStringIO() */ - output = PycStringIO->NewOutput(length); - if (output == NULL) { - return NULL; - } - end = s + length; - s = s - 1; - while ((++s) < end) { - switch(state) { - case STATE_INITIAL: - if (*s == escchar) { - state = STATE_PERCENT; - } else { - r = s - 1; - while (*(++r) != escchar && r < end); - OUTPUTCHAR(s, r-s); - s = r-1; - } - break; - case STATE_PERCENT: - if ((quotedchartmp = ishexdigit(*s)) != NOT_HEXDIGIT) { - tmp = *s; - state = STATE_HEXDIGIT; - } else { - state = STATE_INITIAL; - OUTPUTCHAR(&escchar, 1); - s--; - } - break; - case STATE_HEXDIGIT: - state = STATE_INITIAL; - if ((quotedchar = ishexdigit(*s)) != NOT_HEXDIGIT) { - quotedchar |= (quotedchartmp << 4); - OUTPUTCHAR("edchar, 1); - } else { - OUTPUTCHAR(&escchar, 1); - s -= 2; - } - break; - } - } - switch(state) { - case STATE_PERCENT: - OUTPUTCHAR(&escchar, 1); - break; - case STATE_HEXDIGIT: - OUTPUTCHAR(&escchar, 1); - OUTPUTCHAR(&tmp, 1); - break; - } - - /* return output.getvalue() */ - str = PycStringIO->cgetvalue(output); - Py_DECREF(output); - return str; -} - -static PyMethodDef _c_urlarg_methods[] = { - {"unquote", (PyCFunction)unquote, METH_VARARGS|METH_KEYWORDS}, - {NULL, NULL} /* sentinel */ -}; - -DL_EXPORT(void) init_c_urlarg(void) -{ - PyObject* m; - PyObject* d; - unsigned char i; - - PycString_IMPORT; - m = Py_InitModule("_c_urlarg", _c_urlarg_methods); - d = PyModule_GetDict(m); - - /* add our base exception class */ - UrlargError = PyErr_NewException("urlarg.UrlargError", PyExc_Exception, NULL); - PyDict_SetItemString(d, "UrlargError", UrlargError); - - /* initialize hexdigits */ - for(i = 0; i < 255; i++) { - hexdigits[i] = NOT_HEXDIGIT; - } - hexdigits[255] = NOT_HEXDIGIT; - for(i = '0'; i <= '9'; i++) { - hexdigits[i] = i - '0'; - } - for(i = 'a'; i <= 'f'; i++) { - hexdigits[i] = 10 + (i - 'a'); - } - for(i = 'A'; i <= 'F'; i++) { - hexdigits[i] = 10 + (i - 'A'); - } - /* Check for errors */ - if (PyErr_Occurred()) { - PyErr_Print(); - Py_FatalError("can't initialize module _c_urlarg"); - } -} - diff --git a/tools/buildbot/pylibs/twisted/protocols/amp.py b/tools/buildbot/pylibs/twisted/protocols/amp.py deleted file mode 100644 index 9f0d8e7..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/amp.py +++ /dev/null @@ -1,2223 +0,0 @@ -# -*- test-case-name: twisted.test.test_amp -*- -# Copyright (c) 2005 Divmod, Inc. -# Copyright (c) 2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -This module implements AMP, the Asynchronous Messaging Protocol. - -AMP is a protocol for sending multiple asynchronous request/response pairs over -the same connection. Requests and responses are both collections of key/value -pairs. - -AMP is a very simple protocol which is not an application. This module is a -"protocol construction kit" of sorts; it attempts to be the simplest wire-level -implementation of Deferreds. AMP provides the following base-level features: - - - Asynchronous request/response handling (hence the name) - - - Requests and responses are both key/value pairs - - - Binary transfer of all data: all data is length-prefixed. Your - application will never need to worry about quoting. - - - Command dispatching (like HTTP Verbs): the protocol is extensible, and - multiple AMP sub-protocols can be grouped together easily. - -The protocol implementation also provides a few additional features which are -not part of the core wire protocol, but are nevertheless very useful: - - - Tight TLS integration, with an included StartTLS command. - - - Handshaking to other protocols: because AMP has well-defined message - boundaries and maintains all incoming and outgoing requests for you, you - can start a connection over AMP and then switch to another protocol. - This makes it ideal for firewall-traversal applications where you may - have only one forwarded port but multiple applications that want to use - it. - -Using AMP with Twisted is simple. Each message is a command, with a response. -You begin by defining a command type. Commands specify their input and output -in terms of the types that they expect to see in the request and response -key-value pairs. Here's an example of a command that adds two integers, 'a' -and 'b':: - - class Sum(amp.Command): - arguments = [('a', amp.Integer()), - ('b', amp.Integer())] - response = [('total', amp.Integer())] - -Once you have specified a command, you need to make it part of a protocol, and -define a responder for it. Here's a 'JustSum' protocol that includes a -responder for our 'Sum' command:: - - class JustSum(amp.AMP): - def sum(self, a, b): - total = a + b - print 'Did a sum: %d + %d = %d' % (a, b, total) - return {'total': total} - Sum.responder(sum) - -Later, when you want to actually do a sum, the following expression will return -a Deferred which will fire with the result:: - - ClientCreator(reactor, amp.AMP).connectTCP(...).addCallback( - lambda p: p.callRemote(Sum, a=13, b=81)).addCallback( - lambda result: result['total']) - -You can also define the propagation of specific errors in AMP. For example, -for the slightly more complicated case of division, we might have to deal with -division by zero:: - - class Divide(amp.Command): - arguments = [('numerator', amp.Integer()), - ('denominator', amp.Integer())] - response = [('result', amp.Float())] - errors = {ZeroDivisionError: 'ZERO_DIVISION'} - -The 'errors' mapping here tells AMP that if a responder to Divide emits a -L{ZeroDivisionError}, then the other side should be informed that an error of -the type 'ZERO_DIVISION' has occurred. Writing a responder which takes -advantage of this is very simple - just raise your exception normally:: - - class JustDivide(amp.AMP): - def divide(self, numerator, denominator): - result = numerator / denominator - print 'Divided: %d / %d = %d' % (numerator, denominator, total) - return {'result': result} - Divide.responder(divide) - -On the client side, the errors mapping will be used to determine what the -'ZERO_DIVISION' error means, and translated into an asynchronous exception, -which can be handled normally as any L{Deferred} would be:: - - def trapZero(result): - result.trap(ZeroDivisionError) - print "Divided by zero: returning INF" - return 1e1000 - ClientCreator(reactor, amp.AMP).connectTCP(...).addCallback( - lambda p: p.callRemote(Divide, numerator=1234, - denominator=0) - ).addErrback(trapZero) - -For a complete, runnable example of both of these commands, see the files in -the Twisted repository:: - - doc/core/examples/ampserver.py - doc/core/examples/ampclient.py - -On the wire, AMP is a protocol which uses 2-byte lengths to prefix keys and -values, and empty keys to separate messages:: - - <2-byte length><2-byte length> - <2-byte length><2-byte length> - ... - <2-byte length><2-byte length> - # Empty Key == End of Message - -And so on. Because it's tedious to refer to lengths and NULs constantly, the -documentation will refer to packets as if they were newline delimited, like -so:: - - C: _command: sum - C: _ask: ef639e5c892ccb54 - C: a: 13 - C: b: 81 - - S: _answer: ef639e5c892ccb54 - S: total: 94 - -Notes: - -Values are limited to the maximum encodable size in a 16-bit length, 65535 -bytes. - -Keys are limited to the maximum encodable size in a 8-bit length, 255 bytes. -Note that we still use 2-byte lengths to encode keys. This small redundancy -has several features: - - - If an implementation becomes confused and starts emitting corrupt data, - or gets keys confused with values, many common errors will be - signalled immediately instead of delivering obviously corrupt packets. - - - A single NUL will separate every key, and a double NUL separates - messages. This provides some redundancy when debugging traffic dumps. - - - NULs will be present at regular intervals along the protocol, providing - some padding for otherwise braindead C implementations of the protocol, - so that string functions will see the NUL and stop. - - - This makes it possible to run an AMP server on a port also used by a - plain-text protocol, and easily distinguish between non-AMP clients (like - web browsers) which issue non-NUL as the first byte, and AMP clients, - which always issue NUL as the first byte. - -""" - -__metaclass__ = type - -import types, warnings - -from cStringIO import StringIO -from struct import pack - -from zope.interface import Interface, implements - -from twisted.python.reflect import accumulateClassDict -from twisted.python.failure import Failure -from twisted.python import log, filepath - -from twisted.internet.main import CONNECTION_LOST -from twisted.internet.error import PeerVerifyError, ConnectionLost -from twisted.internet.defer import Deferred, maybeDeferred, fail -from twisted.protocols.basic import Int16StringReceiver, StatefulStringProtocol - -from twisted.internet._sslverify import problemsFromTransport - -# I'd like this to use the exposed public API, but for some reason, when it was -# moved, these names were not exposed by internet.ssl. - -from twisted.internet.ssl import CertificateOptions, Certificate, DN, KeyPair - -ASK = '_ask' -ANSWER = '_answer' -COMMAND = '_command' -ERROR = '_error' -ERROR_CODE = '_error_code' -ERROR_DESCRIPTION = '_error_description' -UNKNOWN_ERROR_CODE = 'UNKNOWN' -UNHANDLED_ERROR_CODE = 'UNHANDLED' - -MAX_KEY_LENGTH = 0xff -MAX_VALUE_LENGTH = 0xffff - - -class IBoxSender(Interface): - """ - A transport which can send L{AmpBox} objects. - """ - - def sendBox(box): - """ - Send an L{AmpBox}. - - @raise ProtocolSwitched: if the underlying protocol has been - switched. - - @raise ConnectionLost: if the underlying connection has already been - lost. - """ - - def unhandledError(failure): - """ - An unhandled error occurred in response to a box. Log it - appropriately. - - @param failure: a L{Failure} describing the error that occurred. - """ - - - -class IBoxReceiver(Interface): - """ - An application object which can receive L{AmpBox} objects and dispatch them - appropriately. - """ - - def startReceivingBoxes(boxSender): - """ - The L{ampBoxReceived} method will start being called; boxes may be - responded to by responding to the given L{IBoxSender}. - - @param boxSender: an L{IBoxSender} provider. - """ - - - def ampBoxReceived(box): - """ - A box was received from the transport; dispatch it appropriately. - """ - - - def stopReceivingBoxes(reason): - """ - No further boxes will be received on this connection. - - @type reason: L{Failure} - """ - - - -class IResponderLocator(Interface): - """ - An application object which can look up appropriate responder methods for - AMP commands. - """ - - def locateResponder(self, name): - """ - Locate a responder method appropriate for the named command. - - @param name: the wire-level name (commandName) of the AMP command to be - responded to. - - @return: a 1-argument callable that takes an L{AmpBox} with argument - values for the given command, and returns an L{AmpBox} containing - argument values for the named command, or a L{Deferred} that fires the - same. - """ - - - -class AmpError(Exception): - """ - Base class of all Amp-related exceptions. - """ - - - -class ProtocolSwitched(Exception): - """ - Connections which have been switched to other protocols can no longer - accept traffic at the AMP level. This is raised when you try to send it. - """ - - - -class OnlyOneTLS(AmpError): - """ - This is an implementation limitation; TLS may only be started once per - connection. - """ - - - -class NoEmptyBoxes(AmpError): - """ - You can't have empty boxes on the connection. This is raised when you - receive or attempt to send one. - """ - - - -class InvalidSignature(AmpError): - """ - You didn't pass all the required arguments. - """ - - - -class TooLong(AmpError): - """ - One of the protocol's length limitations was violated. - - @ivar isKey: true if the string being encoded in a key position, false if - it was in a value position. - - @ivar isLocal: Was the string encoded locally, or received too long from - the network? (It's only physically possible to encode "too long" values on - the network for keys.) - - @ivar value: The string that was too long. - - @ivar keyName: If the string being encoded was in a value position, what - key was it being encoded for? - """ - - def __init__(self, isKey, isLocal, value, keyName=None): - AmpError.__init__(self) - self.isKey = isKey - self.isLocal = isLocal - self.value = value - self.keyName = keyName - - - def __repr__(self): - hdr = self.isKey and "key" or "value" - if not self.isKey: - hdr += ' ' + repr(self.keyName) - lcl = self.isLocal and "local" or "remote" - return "%s %s too long: %d" % (lcl, hdr, len(self.value)) - - - -class BadLocalReturn(AmpError): - """ - A bad value was returned from a local command; we were unable to coerce it. - """ - def __init__(self, message, enclosed): - AmpError.__init__(self) - self.message = message - self.enclosed = enclosed - - - def __repr__(self): - return self.message + " " + self.enclosed.getBriefTraceback() - - __str__ = __repr__ - - - -class RemoteAmpError(AmpError): - """ - This error indicates that something went wrong on the remote end of the - connection, and the error was serialized and transmitted to you. - """ - def __init__(self, errorCode, description, fatal=False, local=None): - """Create a remote error with an error code and description. - - @param errorCode: the AMP error code of this error. - - @param description: some text to show to the user. - - @param fatal: a boolean, true if this error should terminate the - connection. - - @param local: a local Failure, if one exists. - """ - if local: - localwhat = ' (local)' - othertb = local.getBriefTraceback() - else: - localwhat = '' - othertb = '' - Exception.__init__(self, "Code<%s>%s: %s%s" % ( - errorCode, localwhat, - description, othertb)) - self.local = local - self.errorCode = errorCode - self.description = description - self.fatal = fatal - - - -class UnknownRemoteError(RemoteAmpError): - """ - This means that an error whose type we can't identify was raised from the - other side. - """ - def __init__(self, description): - errorCode = UNKNOWN_ERROR_CODE - RemoteAmpError.__init__(self, errorCode, description) - - - -class MalformedAmpBox(AmpError): - """ - This error indicates that the wire-level protocol was malformed. - """ - - - -class UnhandledCommand(AmpError): - """ - A command received via amp could not be dispatched. - """ - - - -class IncompatibleVersions(AmpError): - """ - It was impossible to negotiate a compatible version of the protocol with - the other end of the connection. - """ - - -PROTOCOL_ERRORS = {UNHANDLED_ERROR_CODE: UnhandledCommand} - -class AmpBox(dict): - """ - I am a packet in the AMP protocol, much like a regular str:str dictionary. - """ - __slots__ = [] # be like a regular dictionary, don't magically - # acquire a __dict__... - - - def copy(self): - """ - Return another AmpBox just like me. - """ - newBox = self.__class__() - newBox.update(self) - return newBox - - - def serialize(self): - """ - Convert me into a wire-encoded string. - - @return: a str encoded according to the rules described in the module - docstring. - """ - i = self.items() - i.sort() - L = [] - w = L.append - for k, v in i: - if len(k) > MAX_KEY_LENGTH: - raise TooLong(True, True, k, None) - if len(v) > MAX_VALUE_LENGTH: - raise TooLong(False, True, v, k) - for kv in k, v: - w(pack("!H", len(kv))) - w(kv) - w(pack("!H", 0)) - return ''.join(L) - - - def _sendTo(self, proto): - """ - Serialize and send this box to a Amp instance. By the time it is being - sent, several keys are required. I must have exactly ONE of:: - - _ask - _answer - _error - - If the '_ask' key is set, then the '_command' key must also be - set. - - @param proto: an AMP instance. - """ - proto.sendBox(self) - - def __repr__(self): - return 'AmpBox(%s)' % (dict.__repr__(self),) - -# amp.Box => AmpBox - -Box = AmpBox - -class QuitBox(AmpBox): - """ - I am an AmpBox that, upon being sent, terminates the connection. - """ - __slots__ = [] - - - def __repr__(self): - return 'QuitBox(**%s)' % (super(QuitBox, self).__repr__(),) - - - def _sendTo(self, proto): - """ - Immediately call loseConnection after sending. - """ - super(QuitBox, self)._sendTo(proto) - proto.transport.loseConnection() - - - -class _SwitchBox(AmpBox): - """ - Implementation detail of ProtocolSwitchCommand: I am a AmpBox which sets - up state for the protocol to switch. - """ - - # DON'T set __slots__ here; we do have an attribute. - - def __init__(self, innerProto, **kw): - """ - Create a _SwitchBox with the protocol to switch to after being sent. - - @param innerProto: the protocol instance to switch to. - @type innerProto: an IProtocol provider. - """ - super(_SwitchBox, self).__init__(**kw) - self.innerProto = innerProto - - - def __repr__(self): - return '_SwitchBox(%r, **%s)' % (self.innerProto, - dict.__repr__(self),) - - - def _sendTo(self, proto): - """ - Send me; I am the last box on the connection. All further traffic will be - over the new protocol. - """ - super(_SwitchBox, self)._sendTo(proto) - proto._lockForSwitch() - proto._switchTo(self.innerProto) - - - -class BoxDispatcher: - """ - A L{BoxDispatcher} dispatches '_ask', '_answer', and '_error' L{AmpBox}es, - both incoming and outgoing, to their appropriate destinations. - - Outgoing commands are converted into L{Deferred}s and outgoing boxes, and - associated tracking state to fire those L{Deferred} when '_answer' boxes - come back. Incoming '_answer' and '_error' boxes are converted into - callbacks and errbacks on those L{Deferred}s, respectively. - - Incoming '_ask' boxes are converted into method calls on a supplied method - locator. - - @ivar _outstandingRequests: a dictionary mapping request IDs to - L{Deferred}s which were returned for those requests. - - @ivar locator: an object with a L{locateResponder} method that locates a - responder function that takes a Box and returns a result (either a Box or a - Deferred which fires one). - - @ivar boxSender: an object which can send boxes, via the L{_sendBox} - method, such as an L{AMP} instance. - @type boxSender: L{IBoxSender} - """ - - implements(IBoxReceiver) - - _failAllReason = None - _outstandingRequests = None - _counter = 0L - boxSender = None - - def __init__(self, locator): - self._outstandingRequests = {} - self.locator = locator - - - def startReceivingBoxes(self, boxSender): - """ - The given boxSender is going to start calling boxReceived on this - L{BoxDispatcher}. - - @param boxSender: The L{IBoxSender} to send command responses to. - """ - self.boxSender = boxSender - - - def stopReceivingBoxes(self, reason): - """ - No further boxes will be received here. Terminate all currently - oustanding command deferreds with the given reason. - """ - self.failAllOutgoing(reason) - - - def failAllOutgoing(self, reason): - """ - Call the errback on all outstanding requests awaiting responses. - - @param reason: the Failure instance to pass to those errbacks. - """ - self._failAllReason = reason - OR = self._outstandingRequests.items() - self._outstandingRequests = None # we can never send another request - for key, value in OR: - value.errback(reason) - - - def _nextTag(self): - """ - Generate protocol-local serial numbers for _ask keys. - - @return: a string that has not yet been used on this connection. - """ - self._counter += 1 - return '%x' % (self._counter,) - - - def _sendBoxCommand(self, command, box, requiresAnswer=True): - """ - Send a command across the wire with the given C{amp.Box}. - - Mutate the given box to give it any additional keys (_command, _ask) - required for the command and request/response machinery, then send it. - - If requiresAnswer is True, returns a C{Deferred} which fires when a - response is received. The C{Deferred} is fired with an C{amp.Box} on - success, or with an C{amp.RemoteAmpError} if an error is received. - - If the Deferred fails and the error is not handled by the caller of - this method, the failure will be logged and the connection dropped. - - @param command: a str, the name of the command to issue. - - @param box: an AmpBox with the arguments for the command. - - @param requiresAnswer: a boolean. Defaults to True. If True, return a - Deferred which will fire when the other side responds to this command. - If False, return None and do not ask the other side for acknowledgement. - - @return: a Deferred which fires the AmpBox that holds the response to - this command, or None, as specified by requiresAnswer. - - @raise ProtocolSwitched: if the protocol has been switched. - """ - if self._failAllReason is not None: - return fail(self._failAllReason) - box[COMMAND] = command - tag = self._nextTag() - if requiresAnswer: - box[ASK] = tag - box._sendTo(self.boxSender) - if requiresAnswer: - result = self._outstandingRequests[tag] = Deferred() - else: - result = None - return result - - - def callRemoteString(self, command, requiresAnswer=True, **kw): - """ - This is a low-level API, designed only for optimizing simple messages - for which the overhead of parsing is too great. - - @param command: a str naming the command. - - @param kw: arguments to the amp box. - - @param requiresAnswer: a boolean. Defaults to True. If True, return a - Deferred which will fire when the other side responds to this command. - If False, return None and do not ask the other side for acknowledgement. - - @return: a Deferred which fires the AmpBox that holds the response to - this command, or None, as specified by requiresAnswer. - """ - box = Box(kw) - return self._sendBoxCommand(command, box) - - - def callRemote(self, commandType, *a, **kw): - """ - This is the primary high-level API for sending messages via AMP. Invoke it - with a command and appropriate arguments to send a message to this - connection's peer. - - @param commandType: a subclass of Command. - @type commandType: L{type} - - @param a: Positional (special) parameters taken by the command. - Positional parameters will typically not be sent over the wire. The - only command included with AMP which uses positional parameters is - L{ProtocolSwitchCommand}, which takes the protocol that will be - switched to as its first argument. - - @param kw: Keyword arguments taken by the command. These are the - arguments declared in the command's 'arguments' attribute. They will - be encoded and sent to the peer as arguments for the L{commandType}. - - @return: If L{commandType} has a C{requiresAnswer} attribute set to - L{False}, then return L{None}. Otherwise, return a L{Deferred} which - fires with a dictionary of objects representing the result of this - call. Additionally, this L{Deferred} may fail with an exception - representing a connection failure, with L{UnknownRemoteError} if the - other end of the connection fails for an unknown reason, or with any - error specified as a key in L{commandType}'s C{errors} dictionary. - """ - - # XXX this takes command subclasses and not command objects on purpose. - # There's really no reason to have all this back-and-forth between - # command objects and the protocol, and the extra object being created - # (the Command instance) is pointless. Command is kind of like - # Interface, and should be more like it. - - # In other words, the fact that commandType is instantiated here is an - # implementation detail. Don't rely on it. - - co = commandType(*a, **kw) - return co._doCommand(self) - - - def unhandledError(self, failure): - """ - This is a terminal callback called after application code has had a - chance to quash any errors. - """ - return self.boxSender.unhandledError(failure) - - - def _answerReceived(self, box): - """ - An AMP box was received that answered a command previously sent with - L{callRemote}. - - @param box: an AmpBox with a value for its L{ANSWER} key. - """ - question = self._outstandingRequests.pop(box[ANSWER]) - question.addErrback(self.unhandledError) - question.callback(box) - - - def _errorReceived(self, box): - """ - An AMP box was received that answered a command previously sent with - L{callRemote}, with an error. - - @param box: an L{AmpBox} with a value for its L{ERROR}, L{ERROR_CODE}, - and L{ERROR_DESCRIPTION} keys. - """ - question = self._outstandingRequests.pop(box[ERROR]) - question.addErrback(self.unhandledError) - errorCode = box[ERROR_CODE] - description = box[ERROR_DESCRIPTION] - if errorCode in PROTOCOL_ERRORS: - exc = PROTOCOL_ERRORS[errorCode](errorCode, description) - else: - exc = RemoteAmpError(errorCode, description) - question.errback(Failure(exc)) - - - def _commandReceived(self, box): - """ - @param box: an L{AmpBox} with a value for its L{COMMAND} and L{ASK} - keys. - """ - cmd = box[COMMAND] - def formatAnswer(answerBox): - answerBox[ANSWER] = box[ASK] - return answerBox - def formatError(error): - if error.check(RemoteAmpError): - code = error.value.errorCode - desc = error.value.description - if error.value.fatal: - errorBox = QuitBox() - else: - errorBox = AmpBox() - else: - errorBox = QuitBox() - log.err(error) # here is where server-side logging happens - # if the error isn't handled - code = UNKNOWN_ERROR_CODE - desc = "Unknown Error" - errorBox[ERROR] = box[ASK] - errorBox[ERROR_DESCRIPTION] = desc - errorBox[ERROR_CODE] = code - return errorBox - deferred = self.dispatchCommand(box) - if ASK in box: - deferred.addCallbacks(formatAnswer, formatError) - deferred.addCallback(self._safeEmit) - deferred.addErrback(self.unhandledError) - - - def ampBoxReceived(self, box): - """ - An AmpBox was received, representing a command, or an answer to a - previously issued command (either successful or erroneous). Respond to - it according to its contents. - - @param box: an AmpBox - - @raise NoEmptyBoxes: when a box is received that does not contain an - '_answer', '_command' / '_ask', or '_error' key; i.e. one which does not - fit into the command / response protocol defined by AMP. - """ - if ANSWER in box: - self._answerReceived(box) - elif ERROR in box: - self._errorReceived(box) - elif COMMAND in box: - self._commandReceived(box) - else: - raise NoEmptyBoxes(box) - - - def _safeEmit(self, aBox): - """ - Emit a box, ignoring L{ProtocolSwitched} and L{ConnectionLost} errors - which cannot be usefully handled. - """ - try: - aBox._sendTo(self.boxSender) - except (ProtocolSwitched, ConnectionLost): - pass - - - def dispatchCommand(self, box): - """ - A box with a _command key was received. - - Dispatch it to a local handler call it. - - @param proto: an AMP instance. - @param box: an AmpBox to be dispatched. - """ - cmd = box[COMMAND] - responder = self.locator.locateResponder(cmd) - if responder is None: - return fail(RemoteAmpError( - UNHANDLED_ERROR_CODE, - "Unhandled Command: %r" % (cmd,), - False, - local=Failure(UnhandledCommand()))) - return maybeDeferred(responder, box) - - - -class CommandLocator: - """ - A L{CommandLocator} is a collection of responders to AMP L{Command}s, with - the help of the L{Command.responder} decorator. - """ - - class __metaclass__(type): - """ - This metaclass keeps track of all of the Command.responder-decorated - methods defined since the last CommandLocator subclass was defined. It - assumes (usually correctly, but unfortunately not necessarily so) that - those commands responders were all declared as methods of the class - being defined. Note that this list can be incorrect if users use the - Command.responder decorator outside the context of a CommandLocator - class declaration. - - The Command.responder decorator explicitly cooperates with this - metaclass. - """ - - _currentClassCommands = [] - def __new__(cls, name, bases, attrs): - commands = cls._currentClassCommands[:] - cls._currentClassCommands[:] = [] - cd = attrs['_commandDispatch'] = {} - for base in bases: - cls._grabFromBase(cd, base) - for commandClass, responderFunc in commands: - cd[commandClass.commandName] = (commandClass, responderFunc) - subcls = type.__new__(cls, name, bases, attrs) - if (bases and ( - subcls.lookupFunction != CommandLocator.lookupFunction)): - def locateResponder(self, name): - warnings.warn( - "Override locateResponder, not lookupFunction.", - category=PendingDeprecationWarning, - stacklevel=2) - return self.lookupFunction(name) - subcls.locateResponder = locateResponder - return subcls - - def _grabFromBase(cls, cd, base): - if hasattr(base, "_commandDispatch"): - cd.update(base._commandDispatch) - for subbase in base.__bases__: - cls._grabFromBase(cd, subbase) - _grabFromBase = classmethod(_grabFromBase) - - implements(IResponderLocator) - - - def _wrapWithSerialization(self, aCallable, command): - """ - Wrap aCallable with its command's argument de-serialization - and result serialization logic. - - @param aCallable: a callable with a 'command' attribute, designed to be - called with keyword arguments. - - @param command: the command class whose serialization to use. - - @return: a 1-arg callable which, when invoked with an AmpBox, will - deserialize the argument list and invoke appropriate user code for the - callable's command, returning a Deferred which fires with the result or - fails with an error. - """ - def doit(box): - kw = command.parseArguments(box, self) - def checkKnownErrors(error): - key = error.trap(*command.allErrors) - code = command.allErrors[key] - desc = str(error.value) - return Failure(RemoteAmpError( - code, desc, key in command.fatalErrors, local=error)) - def makeResponseFor(objects): - try: - return command.makeResponse(objects, self) - except: - # let's helpfully log this. - originalFailure = Failure() - raise BadLocalReturn( - "%r returned %r and %r could not serialize it" % ( - aCallable, - objects, - command), - originalFailure) - return maybeDeferred(aCallable, **kw).addCallback( - makeResponseFor).addErrback( - checkKnownErrors) - return doit - - - def lookupFunction(self, name): - """ - Deprecated synonym for L{locateResponder} - """ - if self.__class__.lookupFunction != CommandLocator.lookupFunction: - return CommandLocator.locateResponder(self, name) - else: - warnings.warn("Call locateResponder, not lookupFunction.", - category=PendingDeprecationWarning, - stacklevel=2) - return self.locateResponder(name) - - - def locateResponder(self, name): - """ - Locate a callable to invoke when executing the named command. - - @param name: the normalized name (from the wire) of the command. - - @return: a 1-argument function that takes a Box and returns a box or a - Deferred which fires a Box, for handling the command identified by the - given name, or None, if no appropriate responder can be found. - """ - # Try to find a high-level method to invoke, and if we can't find one, - # fall back to a low-level one. - cd = self._commandDispatch - if name in cd: - commandClass, responderFunc = cd[name] - responderMethod = types.MethodType( - responderFunc, self, self.__class__) - return self._wrapWithSerialization(responderMethod, commandClass) - - - -class SimpleStringLocator(object): - """ - Implement the L{locateResponder} method to do simple, string-based - dispatch. - """ - - implements(IResponderLocator) - - baseDispatchPrefix = 'amp_' - - def locateResponder(self, name): - """ - Locate a callable to invoke when executing the named command. - - @return: a function with the name C{"amp_" + name} on L{self}, or None - if no such function exists. This function will then be called with the - L{AmpBox} itself as an argument. - - @param name: the normalized name (from the wire) of the command. - """ - fName = self.baseDispatchPrefix + (name.upper()) - return getattr(self, fName, None) - - - -PYTHON_KEYWORDS = [ - 'and', 'del', 'for', 'is', 'raise', 'assert', 'elif', 'from', 'lambda', - 'return', 'break', 'else', 'global', 'not', 'try', 'class', 'except', - 'if', 'or', 'while', 'continue', 'exec', 'import', 'pass', 'yield', - 'def', 'finally', 'in', 'print'] - - - -def _wireNameToPythonIdentifier(key): - """ - (Private) Normalize an argument name from the wire for use with Python - code. If the return value is going to be a python keyword it will be - capitalized. If it contains any dashes they will be replaced with - underscores. - - The rationale behind this method is that AMP should be an inherently - multi-language protocol, so message keys may contain all manner of bizarre - bytes. This is not a complete solution; there are still forms of arguments - that this implementation will be unable to parse. However, Python - identifiers share a huge raft of properties with identifiers from many - other languages, so this is a 'good enough' effort for now. We deal - explicitly with dashes because that is the most likely departure: Lisps - commonly use dashes to separate method names, so protocols initially - implemented in a lisp amp dialect may use dashes in argument or command - names. - - @param key: a str, looking something like 'foo-bar-baz' or 'from' - - @return: a str which is a valid python identifier, looking something like - 'foo_bar_baz' or 'From'. - """ - lkey = key.replace("-", "_") - if lkey in PYTHON_KEYWORDS: - return lkey.title() - return lkey - - - -class Argument: - """ - Base-class of all objects that take values from Amp packets and convert - them into objects for Python functions. - """ - optional = False - - - def __init__(self, optional=False): - """ - Create an Argument. - - @param optional: a boolean indicating whether this argument can be - omitted in the protocol. - """ - self.optional = optional - - - def retrieve(self, d, name, proto): - """ - Retrieve the given key from the given dictionary, removing it if found. - - @param d: a dictionary. - - @param name: a key in L{d}. - - @param proto: an instance of an AMP. - - @raise KeyError: if I am not optional and no value was found. - - @return: d[name]. - """ - if self.optional: - value = d.get(name) - if value is not None: - del d[name] - else: - value = d.pop(name) - return value - - - def fromBox(self, name, strings, objects, proto): - """ - Populate an 'out' dictionary with mapping names to Python values - decoded from an 'in' AmpBox mapping strings to string values. - - @param name: the argument name to retrieve - @type name: str - - @param strings: The AmpBox to read string(s) from, a mapping of - argument names to string values. - @type strings: AmpBox - - @param objects: The dictionary to write object(s) to, a mapping of - names to Python objects. - @type objects: dict - - @param proto: an AMP instance. - """ - st = self.retrieve(strings, name, proto) - nk = _wireNameToPythonIdentifier(name) - if self.optional and st is None: - objects[nk] = None - else: - objects[nk] = self.fromStringProto(st, proto) - - - def toBox(self, name, strings, objects, proto): - """ - Populate an 'out' AmpBox with strings encoded from an 'in' dictionary - mapping names to Python values. - - @param name: the argument name to retrieve - @type name: str - - @param strings: The AmpBox to write string(s) to, a mapping of - argument names to string values. - @type strings: AmpBox - - @param objects: The dictionary to read object(s) from, a mapping of - names to Python objects. - - @type objects: dict - - @param proto: the protocol we are converting for. - @type proto: AMP - """ - obj = self.retrieve(objects, _wireNameToPythonIdentifier(name), proto) - if self.optional and obj is None: - # strings[name] = None - pass - else: - strings[name] = self.toStringProto(obj, proto) - - - def fromStringProto(self, inString, proto): - """ - Convert a string to a Python value. - - @param inString: the string to convert. - - @param proto: the protocol we are converting for. - @type proto: AMP - - @return: a Python object. - """ - return self.fromString(inString) - - - def toStringProto(self, inObject, proto): - """ - Convert a Python object to a string. - - @param inObject: the object to convert. - - @param proto: the protocol we are converting for. - @type proto: AMP - """ - return self.toString(inObject) - - - def fromString(self, inString): - """ - Convert a string to a Python object. Subclasses must implement this. - - @param inString: the string to convert. - @type inString: str - - @return: the decoded value from inString - """ - - - def toString(self, inObject): - """ - Convert a Python object into a string for passing over the network. - - @param inObject: an object of the type that this Argument is intended - to deal with. - - @return: the wire encoding of inObject - @rtype: str - """ - - - -class Integer(Argument): - """ - Convert to and from 'int'. - """ - fromString = int - def toString(self, inObject): - return str(int(inObject)) - - - -class String(Argument): - """ - Don't do any conversion at all; just pass through 'str'. - """ - def toString(self, inObject): - return inObject - - - def fromString(self, inString): - return inString - - - -class Float(Argument): - """ - Encode floating-point values on the wire as their repr. - """ - fromString = float - toString = repr - - - -class Boolean(Argument): - """ - Encode True or False as "True" or "False" on the wire. - """ - def fromString(self, inString): - if inString == 'True': - return True - elif inString == 'False': - return False - else: - raise TypeError("Bad boolean value: %r" % (inString,)) - - - def toString(self, inObject): - if inObject: - return 'True' - else: - return 'False' - - - -class Unicode(String): - """ - Encode a unicode string on the wire as UTF-8. - """ - - def toString(self, inObject): - # assert isinstance(inObject, unicode) - return String.toString(self, inObject.encode('utf-8')) - - - def fromString(self, inString): - # assert isinstance(inString, str) - return String.fromString(self, inString).decode('utf-8') - - - -class Path(Unicode): - """ - Encode and decode L{filepath.FilePath} instances as paths on the wire. - - This is really intended for use with subprocess communication tools: - exchanging pathnames on different machines over a network is not generally - meaningful, but neither is it disallowed; you can use this to communicate - about NFS paths, for example. - """ - def fromString(self, inString): - return filepath.FilePath(Unicode.fromString(self, inString)) - - - def toString(self, inObject): - return Unicode.toString(self, inObject.path) - - - -class AmpList(Argument): - """ - Convert a list of dictionaries into a list of AMP boxes on the wire. - - For example, if you want to pass:: - - [{'a': 7, 'b': u'hello'}, {'a': 9, 'b': u'goodbye'}] - - You might use an AmpList like this in your arguments or response list:: - - AmpList([('a', Integer()), - ('b', Unicode())]) - """ - def __init__(self, subargs): - """ - Create an AmpList. - - @param subargs: a list of 2-tuples of ('name', argument) describing the - schema of the dictionaries in the sequence of amp boxes. - """ - self.subargs = subargs - - - def fromStringProto(self, inString, proto): - boxes = parseString(inString) - values = [_stringsToObjects(box, self.subargs, proto) - for box in boxes] - return values - - - def toStringProto(self, inObject, proto): - return ''.join([_objectsToStrings( - objects, self.subargs, Box(), proto - ).serialize() for objects in inObject]) - -class Command: - """ - Subclass me to specify an AMP Command. - - @cvar arguments: A list of 2-tuples of (name, Argument-subclass-instance), - specifying the names and values of the parameters which are required for - this command. - - @cvar response: A list like L{arguments}, but instead used for the return - value. - - @cvar errors: A mapping of subclasses of L{Exception} to wire-protocol tags - for errors represented as L{str}s. Responders which raise keys from this - dictionary will have the error translated to the corresponding tag on the - wire. Invokers which receive Deferreds from invoking this command with - L{AMP.callRemote} will potentially receive Failures with keys from this - mapping as their value. This mapping is inherited; if you declare a - command which handles C{FooError} as 'FOO_ERROR', then subclass it and - specify C{BarError} as 'BAR_ERROR', responders to the subclass may raise - either C{FooError} or C{BarError}, and invokers must be able to deal with - either of those exceptions. - - @cvar fatalErrors: like 'errors', but errors in this list will always - terminate the connection, despite being of a recognizable error type. - - @cvar commandType: The type of Box used to issue commands; useful only for - protocol-modifying behavior like startTLS or protocol switching. Defaults - to a plain vanilla L{Box}. - - @cvar responseType: The type of Box used to respond to this command; only - useful for protocol-modifying behavior like startTLS or protocol switching. - Defaults to a plain vanilla L{Box}. - - @ivar requiresAnswer: a boolean; defaults to True. Set it to False on your - subclass if you want callRemote to return None. Note: this is a hint only - to the client side of the protocol. The return-type of a command responder - method must always be a dictionary adhering to the contract specified by - L{response}, because clients are always free to request a response if they - want one. - """ - - class __metaclass__(type): - """ - Metaclass hack to establish reverse-mappings for 'errors' and - 'fatalErrors' as class vars. - """ - def __new__(cls, name, bases, attrs): - re = attrs['reverseErrors'] = {} - er = attrs['allErrors'] = {} - if 'commandName' not in attrs: - attrs['commandName'] = name - newtype = type.__new__(cls, name, bases, attrs) - errors = {} - fatalErrors = {} - accumulateClassDict(newtype, 'errors', errors) - accumulateClassDict(newtype, 'fatalErrors', fatalErrors) - for v, k in errors.iteritems(): - re[k] = v - er[v] = k - for v, k in fatalErrors.iteritems(): - re[k] = v - er[v] = k - return newtype - - arguments = [] - response = [] - extra = [] - errors = {} - fatalErrors = {} - - commandType = Box - responseType = Box - - requiresAnswer = True - - - def __init__(self, **kw): - """ - Create an instance of this command with specified values for its - parameters. - - @param kw: a dict containing an appropriate value for each name - specified in the L{arguments} attribute of my class. - - @raise InvalidSignature: if you forgot any required arguments. - """ - self.structured = kw - givenArgs = kw.keys() - forgotten = [] - for name, arg in self.arguments: - pythonName = _wireNameToPythonIdentifier(name) - if pythonName not in givenArgs and not arg.optional: - forgotten.append(pythonName) - if forgotten: - raise InvalidSignature("forgot %s for %s" % ( - ', '.join(forgotten), self.commandName)) - forgotten = [] - - - def makeResponse(cls, objects, proto): - """ - Serialize a mapping of arguments using this L{Command}'s - response schema. - - @param objects: a dict with keys matching the names specified in - self.response, having values of the types that the Argument objects in - self.response can format. - - @param proto: an L{AMP}. - - @return: an L{AmpBox}. - """ - return _objectsToStrings(objects, cls.response, cls.responseType(), - proto) - makeResponse = classmethod(makeResponse) - - - def makeArguments(cls, objects, proto): - """ - Serialize a mapping of arguments using this L{Command}'s - argument schema. - - @param objects: a dict with keys similar to the names specified in - self.arguments, having values of the types that the Argument objects in - self.arguments can parse. - - @param proto: an L{AMP}. - - @return: An instance of this L{Command}'s C{commandType}. - """ - return _objectsToStrings(objects, cls.arguments, cls.commandType(), - proto) - makeArguments = classmethod(makeArguments) - - - def parseResponse(cls, box, protocol): - """ - Parse a mapping of serialized arguments using this - L{Command}'s response schema. - - @param box: A mapping of response-argument names to the - serialized forms of those arguments. - @param protocol: The L{AMP} protocol. - - @return: A mapping of response-argument names to the parsed - forms. - """ - return _stringsToObjects(box, cls.response, protocol) - parseResponse = classmethod(parseResponse) - - - def parseArguments(cls, box, protocol): - """ - Parse a mapping of serialized arguments using this - L{Command}'s argument schema. - - @param box: A mapping of argument names to the seralized forms - of those arguments. - @param protocol: The L{AMP} protocol. - - @return: A mapping of argument names to the parsed forms. - """ - return _stringsToObjects(box, cls.arguments, protocol) - parseArguments = classmethod(parseArguments) - - - def responder(cls, methodfunc): - """ - Declare a method to be a responder for a particular command. - - This is a decorator. - - Use like so:: - - class MyCommand(Command): - arguments = [('a', ...), ('b', ...)] - - class MyProto(AMP): - def myFunMethod(self, a, b): - ... - MyCommand.responder(myFunMethod) - - Notes: Although decorator syntax is not used within Twisted, this - function returns its argument and is therefore safe to use with - decorator syntax. - - This is not thread safe. Don't declare AMP subclasses in other - threads. Don't declare responders outside the scope of AMP subclasses; - the behavior is undefined. - - @param methodfunc: A function which will later become a method, which - has a keyword signature compatible with this command's L{argument} list - and returns a dictionary with a set of keys compatible with this - command's L{response} list. - - @return: the methodfunc parameter. - """ - CommandLocator._currentClassCommands.append((cls, methodfunc)) - return methodfunc - responder = classmethod(responder) - - - # Our only instance method - def _doCommand(self, proto): - """ - Encode and send this Command to the given protocol. - - @param proto: an AMP, representing the connection to send to. - - @return: a Deferred which will fire or error appropriately when the - other side responds to the command (or error if the connection is lost - before it is responded to). - """ - - def _massageError(error): - error.trap(RemoteAmpError) - rje = error.value - errorType = self.reverseErrors.get(rje.errorCode, - UnknownRemoteError) - return Failure(errorType(rje.description)) - - d = proto._sendBoxCommand(self.commandName, - self.makeArguments(self.structured, proto), - self.requiresAnswer) - - if self.requiresAnswer: - d.addCallback(self.parseResponse, proto) - d.addErrback(_massageError) - - return d - - - -class _NoCertificate: - """ - This is for peers which don't want to use a local certificate. Used by - AMP because AMP's internal language is all about certificates and this - duck-types in the appropriate place; this API isn't really stable though, - so it's not exposed anywhere public. - - For clients, it will use ephemeral DH keys, or whatever the default is for - certificate-less clients in OpenSSL. For servers, it will generate a - temporary self-signed certificate with garbage values in the DN and use - that. - """ - - def __init__(self, client): - """ - Create a _NoCertificate which either is or isn't for the client side of - the connection. - - @param client: True if we are a client and should truly have no - certificate and be anonymous, False if we are a server and actually - have to generate a temporary certificate. - - @type client: bool - """ - self.client = client - - - def options(self, *authorities): - """ - Behaves like L{twisted.internet.ssl.PrivateCertificate.options}(). - """ - if not self.client: - # do some crud with sslverify to generate a temporary self-signed - # certificate. This is SLOOOWWWWW so it is only in the absolute - # worst, most naive case. - - # We have to do this because OpenSSL will not let both the server - # and client be anonymous. - sharedDN = DN(CN='TEMPORARY CERTIFICATE') - key = KeyPair.generate() - cr = key.certificateRequest(sharedDN) - sscrd = key.signCertificateRequest(sharedDN, cr, lambda dn: True, 1) - cert = key.newCertificate(sscrd) - return cert.options(*authorities) - options = dict() - if authorities: - options.update(dict(verify=True, - requireCertificate=True, - caCerts=[auth.original for auth in authorities])) - occo = CertificateOptions(**options) - return occo - - - -class _TLSBox(AmpBox): - """ - I am an AmpBox that, upon being sent, initiates a TLS connection. - """ - __slots__ = [] - - def _keyprop(k, default): - return property(lambda self: self.get(k, default)) - - - # These properties are described in startTLS - certificate = _keyprop('tls_localCertificate', _NoCertificate(False)) - verify = _keyprop('tls_verifyAuthorities', None) - - def _sendTo(self, proto): - """ - Send my encoded value to the protocol, then initiate TLS. - """ - ab = AmpBox(self) - for k in ['tls_localCertificate', - 'tls_verifyAuthorities']: - ab.pop(k, None) - ab._sendTo(proto) - proto._startTLS(self.certificate, self.verify) - - - -class _LocalArgument(String): - """ - Local arguments are never actually relayed across the wire. This is just a - shim so that StartTLS can pretend to have some arguments: if arguments - acquire documentation properties, replace this with something nicer later. - """ - - def fromBox(self, name, strings, objects, proto): - pass - - - -class StartTLS(Command): - """ - Use, or subclass, me to implement a command that starts TLS. - - Callers of StartTLS may pass several special arguments, which affect the - TLS negotiation: - - - tls_localCertificate: This is a - twisted.internet.ssl.PrivateCertificate which will be used to secure - the side of the connection it is returned on. - - - tls_verifyAuthorities: This is a list of - twisted.internet.ssl.Certificate objects that will be used as the - certificate authorities to verify our peer's certificate. - - Each of those special parameters may also be present as a key in the - response dictionary. - """ - - arguments = [("tls_localCertificate", _LocalArgument(optional=True)), - ("tls_verifyAuthorities", _LocalArgument(optional=True))] - - response = [("tls_localCertificate", _LocalArgument(optional=True)), - ("tls_verifyAuthorities", _LocalArgument(optional=True))] - - responseType = _TLSBox - - def __init__(self, **kw): - """ - Create a StartTLS command. (This is private. Use AMP.callRemote.) - - @param tls_localCertificate: the PrivateCertificate object to use to - secure the connection. If it's None, or unspecified, an ephemeral DH - key is used instead. - - @param tls_verifyAuthorities: a list of Certificate objects which - represent root certificates to verify our peer with. - """ - self.certificate = kw.pop('tls_localCertificate', _NoCertificate(True)) - self.authorities = kw.pop('tls_verifyAuthorities', None) - Command.__init__(self, **kw) - - - def _doCommand(self, proto): - """ - When a StartTLS command is sent, prepare to start TLS, but don't actually - do it; wait for the acknowledgement, then initiate the TLS handshake. - """ - d = Command._doCommand(self, proto) - proto._prepareTLS(self.certificate, self.authorities) - # XXX before we get back to user code we are going to start TLS... - def actuallystart(response): - proto._startTLS(self.certificate, self.authorities) - return response - d.addCallback(actuallystart) - return d - - - -class ProtocolSwitchCommand(Command): - """ - Use this command to switch from something Amp-derived to a different - protocol mid-connection. This can be useful to use amp as the - connection-startup negotiation phase. Since TLS is a different layer - entirely, you can use Amp to negotiate the security parameters of your - connection, then switch to a different protocol, and the connection will - remain secured. - """ - - def __init__(self, _protoToSwitchToFactory, **kw): - """ - Create a ProtocolSwitchCommand. - - @param _protoToSwitchToFactory: a ProtocolFactory which will generate - the Protocol to switch to. - - @param kw: Keyword arguments, encoded and handled normally as - L{Command} would. - """ - - self.protoToSwitchToFactory = _protoToSwitchToFactory - super(ProtocolSwitchCommand, self).__init__(**kw) - - - def makeResponse(cls, innerProto, proto): - return _SwitchBox(innerProto) - makeResponse = classmethod(makeResponse) - - - def _doCommand(self, proto): - """ - When we emit a ProtocolSwitchCommand, lock the protocol, but don't actually - switch to the new protocol unless an acknowledgement is received. If - an error is received, switch back. - """ - d = super(ProtocolSwitchCommand, self)._doCommand(proto) - proto._lockForSwitch() - def switchNow(ign): - innerProto = self.protoToSwitchToFactory.buildProtocol( - proto.transport.getPeer()) - proto._switchTo(innerProto, self.protoToSwitchToFactory) - return ign - def handle(ign): - proto._unlockFromSwitch() - self.protoToSwitchToFactory.clientConnectionFailed( - None, Failure(CONNECTION_LOST)) - return ign - return d.addCallbacks(switchNow, handle) - - - -class BinaryBoxProtocol(StatefulStringProtocol, Int16StringReceiver): - """ - A protocol for receving L{Box}es - key/value pairs - via length-prefixed - strings. A box is composed of: - - - any number of key-value pairs, described by: - - a 2-byte network-endian packed key length (of which the first - byte must be null, and the second must be non-null: i.e. the - value of the length must be 1-255) - - a key, comprised of that many bytes - - a 2-byte network-endian unsigned value length (up to the maximum - of 65535) - - a value, comprised of that many bytes - - 2 null bytes - - In other words, an even number of strings prefixed with packed unsigned - 16-bit integers, and then a 0-length string to indicate the end of the box. - - This protocol also implements 2 extra private bits of functionality related - to the byte boundaries between messages; it can start TLS between two given - boxes or switch to an entirely different protocol. However, due to some - tricky elements of the implementation, the public interface to this - functionality is L{ProtocolSwitchCommand} and L{StartTLS}. - - @ivar boxReceiver: an L{IBoxReceiver} provider, whose L{ampBoxReceived} - method will be invoked for each L{Box} that is received. - """ - - implements(IBoxSender) - - _justStartedTLS = False - _startingTLSBuffer = None - _locked = False - _currentKey = None - _currentBox = None - - hostCertificate = None - noPeerCertificate = False # for tests - innerProtocol = None - innerProtocolClientFactory = None - - _sslVerifyProblems = () - # ^ Later this will become a mutable list - we can't get the handle during - # connection shutdown thanks to the fact that Twisted destroys the socket - # on our transport before notifying us of a lost connection (which I guess - # is reasonable - the socket is dead by then) See a few lines below in - # startTLS for details. --glyph - - - def __init__(self, boxReceiver): - self.boxReceiver = boxReceiver - - - def _switchTo(self, newProto, clientFactory=None): - """ - Switch this BinaryBoxProtocol's transport to a new protocol. You need - to do this 'simultaneously' on both ends of a connection; the easiest - way to do this is to use a subclass of ProtocolSwitchCommand. - - @param newProto: the new protocol instance to switch to. - - @param clientFactory: the ClientFactory to send the - L{clientConnectionLost} notification to. - """ - # All the data that Int16Receiver has not yet dealt with belongs to our - # new protocol: luckily it's keeping that in a handy (although - # ostensibly internal) variable for us: - newProtoData = self.recvd - # We're quite possibly in the middle of a 'dataReceived' loop in - # Int16StringReceiver: let's make sure that the next iteration, the - # loop will break and not attempt to look at something that isn't a - # length prefix. - self.recvd = '' - # Finally, do the actual work of setting up the protocol and delivering - # its first chunk of data, if one is available. - self.innerProtocol = newProto - self.innerProtocolClientFactory = clientFactory - newProto.makeConnection(self.transport) - newProto.dataReceived(newProtoData) - - - def sendBox(self, box): - """ - Send a amp.Box to my peer. - - Note: transport.write is never called outside of this method. - - @param box: an AmpBox. - - @raise ProtocolSwitched: if the protocol has previously been switched. - - @raise ConnectionLost: if the connection has previously been lost. - """ - if self._locked: - raise ProtocolSwitched( - "This connection has switched: no AMP traffic allowed.") - if self.transport is None: - raise ConnectionLost() - if self._startingTLSBuffer is not None: - self._startingTLSBuffer.append(box) - else: - self.transport.write(box.serialize()) - - - def makeConnection(self, transport): - """ - Notify L{boxReceiver} that it is about to receive boxes from this - protocol by invoking L{startReceivingBoxes}. - """ - self.boxReceiver.startReceivingBoxes(self) - Int16StringReceiver.makeConnection(self, transport) - - - def dataReceived(self, data): - """ - Either parse incoming data as L{AmpBox}es or relay it to our nested - protocol. - """ - if self._justStartedTLS: - self._justStartedTLS = False - # If we already have an inner protocol, then we don't deliver data to - # the protocol parser any more; we just hand it off. - if self.innerProtocol is not None: - self.innerProtocol.dataReceived(data) - return - return Int16StringReceiver.dataReceived(self, data) - - - def connectionLost(self, reason): - """ - The connection was lost; notify any nested protocol. - """ - if self.innerProtocol is not None: - self.innerProtocol.connectionLost(reason) - if self.innerProtocolClientFactory is not None: - self.innerProtocolClientFactory.clientConnectionLost(None, reason) - # XXX this may be a slight oversimplification, but I believe that if - # there are pending SSL errors, they _are_ the reason that the - # connection was lost. a totally correct implementation of this would - # set up a simple state machine to track whether any bytes were - # received after startTLS was called. --glyph - problems = self._sslVerifyProblems - if problems: - failReason = Failure(problems[0]) - elif self._justStartedTLS: - # We just started TLS and haven't received any data. This means - # the other connection didn't like our cert (although they may not - # have told us why - later Twisted should make 'reason' into a TLS - # error.) - failReason = PeerVerifyError( - "Peer rejected our certificate for an unknown reason.") - else: - failReason = reason - self.boxReceiver.stopReceivingBoxes(failReason) - - - - def proto_init(self, string): - """ - String received in the 'init' state. - """ - self._currentBox = AmpBox() - return self.proto_key(string) - - - def proto_key(self, string): - """ - String received in the 'key' state. If the key is empty, a complete - box has been received. - """ - if string: - self._currentKey = string - return 'value' - else: - self.boxReceiver.ampBoxReceived(self._currentBox) - self._currentBox = None - return 'init' - - - def proto_value(self, string): - """ - String received in the 'value' state. - """ - self._currentBox[self._currentKey] = string - self._currentKey = None - return 'key' - - - def _lockForSwitch(self): - """ - Lock this binary protocol so that no further boxes may be sent. This - is used when sending a request to switch underlying protocols. You - probably want to subclass ProtocolSwitchCommand rather than calling - this directly. - """ - self._locked = True - - - def _unlockFromSwitch(self): - """ - Unlock this locked binary protocol so that further boxes may be sent - again. This is used after an attempt to switch protocols has failed - for some reason. - """ - if self.innerProtocol is not None: - raise ProtocolSwitched("Protocol already switched. Cannot unlock.") - self._locked = False - - - def _prepareTLS(self, certificate, verifyAuthorities): - """ - Used by StartTLSCommand to put us into the state where we don't - actually send things that get sent, instead we buffer them. see - L{_sendBox}. - """ - self._startingTLSBuffer = [] - if self.hostCertificate is not None: - raise OnlyOneTLS( - "Previously authenticated connection between %s and %s " - "is trying to re-establish as %s" % ( - self.hostCertificate, - self.peerCertificate, - (certificate, verifyAuthorities))) - - - def _startTLS(self, certificate, verifyAuthorities): - """ - Used by TLSBox to initiate the SSL handshake. - - @param certificate: a L{twisted.internet.ssl.PrivateCertificate} for - use locally. - - @param verifyAuthorities: L{twisted.internet.ssl.Certificate} instances - representing certificate authorities which will verify our peer. - """ - self.hostCertificate = certificate - self._justStartedTLS = True - if verifyAuthorities is None: - verifyAuthorities = () - self.transport.startTLS(certificate.options(*verifyAuthorities)) - # Remember that mutable list that we were just talking about? Here - # it is. sslverify.py takes care of populating this list as - # necessary. --glyph - self._sslVerifyProblems = problemsFromTransport(self.transport) - stlsb = self._startingTLSBuffer - if stlsb is not None: - self._startingTLSBuffer = None - for box in stlsb: - self.sendBox(box) - - - def _getPeerCertificate(self): - if self.noPeerCertificate: - return None - return Certificate.peerFromTransport(self.transport) - peerCertificate = property(_getPeerCertificate) - - - def unhandledError(self, failure): - """ - The buck stops here. This error was completely unhandled, time to - terminate the connection. - """ - log.msg("Amp server or network failure " - "unhandled by client application:") - log.err(failure) - log.msg( - "Dropping connection! " - "To avoid, add errbacks to ALL remote commands!") - if self.transport is not None: - self.transport.loseConnection() - - - def _defaultStartTLSResponder(self): - """ - The default TLS responder doesn't specify any certificate or anything. - - From a security perspective, it's little better than a plain-text - connection - but it is still a *bit* better, so it's included for - convenience. - - You probably want to override this by providing your own StartTLS.responder. - """ - return {} - StartTLS.responder(_defaultStartTLSResponder) - - - -class AMP(BinaryBoxProtocol, BoxDispatcher, - CommandLocator, SimpleStringLocator): - """ - This protocol is an AMP connection. See the module docstring for protocol - details. - """ - - _ampInitialized = False - - def __init__(self, boxReceiver=None, locator=None): - # For backwards compatibility. When AMP did not separate parsing logic - # (L{BinaryBoxProtocol}), request-response logic (L{BoxDispatcher}) and - # command routing (L{CommandLocator}), it did not have a constructor. - # Now it does, so old subclasses might have defined their own that did - # not upcall. If this flag isn't set, we'll call the constructor in - # makeConnection before anything actually happens. - self._ampInitialized = True - if boxReceiver is None: - boxReceiver = self - if locator is None: - locator = self - boxSender = self - BoxDispatcher.__init__(self, locator) - BinaryBoxProtocol.__init__(self, boxReceiver) - - - def locateResponder(self, name): - """ - Unify the implementations of L{CommandLocator} and - L{SimpleStringLocator} to perform both kinds of dispatch, preferring - L{CommandLocator}. - """ - firstResponder = CommandLocator.locateResponder(self, name) - if firstResponder is not None: - return firstResponder - secondResponder = SimpleStringLocator.locateResponder(self, name) - return secondResponder - - - def __repr__(self): - """ - A verbose string representation which gives us information about this - AMP connection. - """ - return '<%s %s at 0x%x>' % ( - self.__class__.__name__, - self.innerProtocol, id(self)) - - - def makeConnection(self, transport): - """ - Emit a helpful log message when the connection is made. - """ - if not self._ampInitialized: - # See comment in the constructor re: backward compatibility. I - # should probably emit a deprecation warning here. - AMP.__init__(self) - # Save these so we can emit a similar log message in L{connectionLost}. - self._transportPeer = transport.getPeer() - self._transportHost = transport.getHost() - log.msg("%s connection established (HOST:%s PEER:%s)" % ( - self.__class__.__name__, - self._transportHost, - self._transportPeer)) - BinaryBoxProtocol.makeConnection(self, transport) - - - def connectionLost(self, reason): - """ - Emit a helpful log message when the connection is lost. - """ - log.msg("%s connection lost (HOST:%s PEER:%s)" % - (self.__class__.__name__, - self._transportHost, - self._transportPeer)) - BinaryBoxProtocol.connectionLost(self, reason) - self.transport = None - - - -class _ParserHelper: - """ - A box receiver which records all boxes received. - """ - def __init__(self): - self.boxes = [] - - - def getPeer(self): - return 'string' - - - def getHost(self): - return 'string' - - disconnecting = False - - - def startReceivingBoxes(self, sender): - """ - No initialization is required. - """ - - - def ampBoxReceived(self, box): - self.boxes.append(box) - - - # Synchronous helpers - def parse(cls, fileObj): - """ - Parse some amp data stored in a file. - - @param fileObj: a file-like object. - - @return: a list of AmpBoxes encoded in the given file. - """ - parserHelper = cls() - bbp = BinaryBoxProtocol(boxReceiver=parserHelper) - bbp.makeConnection(parserHelper) - bbp.dataReceived(fileObj.read()) - return parserHelper.boxes - parse = classmethod(parse) - - - def parseString(cls, data): - """ - Parse some amp data stored in a string. - - @param data: a str holding some amp-encoded data. - - @return: a list of AmpBoxes encoded in the given string. - """ - return cls.parse(StringIO(data)) - parseString = classmethod(parseString) - - - -parse = _ParserHelper.parse -parseString = _ParserHelper.parseString - -def _stringsToObjects(strings, arglist, proto): - """ - Convert an AmpBox to a dictionary of python objects, converting through a - given arglist. - - @param strings: an AmpBox (or dict of strings) - - @param arglist: a list of 2-tuples of strings and Argument objects, as - described in L{Command.arguments}. - - @param proto: an L{AMP} instance. - - @return: the converted dictionary mapping names to argument objects. - """ - objects = {} - myStrings = strings.copy() - for argname, argparser in arglist: - argparser.fromBox(argname, myStrings, objects, proto) - return objects - - - -def _objectsToStrings(objects, arglist, strings, proto): - """ - Convert a dictionary of python objects to an AmpBox, converting through a - given arglist. - - @param objects: a dict mapping names to python objects - - @param arglist: a list of 2-tuples of strings and Argument objects, as - described in L{Command.arguments}. - - @param strings: [OUT PARAMETER] An object providing the L{dict} - interface which will be populated with serialized data. - - @param proto: an L{AMP} instance. - - @return: The converted dictionary mapping names to encoded argument - strings (identical to C{strings}). - """ - myObjects = {} - for (k, v) in objects.items(): - myObjects[k] = v - - for argname, argparser in arglist: - argparser.toBox(argname, strings, myObjects, proto) - return strings - - diff --git a/tools/buildbot/pylibs/twisted/protocols/basic.py b/tools/buildbot/pylibs/twisted/protocols/basic.py deleted file mode 100644 index a4c5312..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/basic.py +++ /dev/null @@ -1,486 +0,0 @@ -# -*- test-case-name: twisted.test.test_protocols -*- -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Basic protocols, such as line-oriented, netstring, and int prefixed strings. - -Maintainer: U{Itamar Shtull-Trauring} -""" - -# System imports -import re -import struct - -from zope.interface import implements - -# Twisted imports -from twisted.internet import protocol, defer, interfaces, error -from twisted.python import log - -LENGTH, DATA, COMMA = range(3) -NUMBER = re.compile('(\d*)(:?)') -DEBUG = 0 - -class NetstringParseError(ValueError): - """The incoming data is not in valid Netstring format.""" - pass - - -class NetstringReceiver(protocol.Protocol): - """This uses djb's Netstrings protocol to break up the input into strings. - - Each string makes a callback to stringReceived, with a single - argument of that string. - - Security features: - 1. Messages are limited in size, useful if you don't want someone - sending you a 500MB netstring (change MAX_LENGTH to the maximum - length you wish to accept). - 2. The connection is lost if an illegal message is received. - """ - - MAX_LENGTH = 99999 - brokenPeer = 0 - _readerState = LENGTH - _readerLength = 0 - - def stringReceived(self, line): - """ - Override this. - """ - raise NotImplementedError - - def doData(self): - buffer,self.__data = self.__data[:int(self._readerLength)],self.__data[int(self._readerLength):] - self._readerLength = self._readerLength - len(buffer) - self.__buffer = self.__buffer + buffer - if self._readerLength != 0: - return - self.stringReceived(self.__buffer) - self._readerState = COMMA - - def doComma(self): - self._readerState = LENGTH - if self.__data[0] != ',': - if DEBUG: - raise NetstringParseError(repr(self.__data)) - else: - raise NetstringParseError - self.__data = self.__data[1:] - - - def doLength(self): - m = NUMBER.match(self.__data) - if not m.end(): - if DEBUG: - raise NetstringParseError(repr(self.__data)) - else: - raise NetstringParseError - self.__data = self.__data[m.end():] - if m.group(1): - try: - self._readerLength = self._readerLength * (10**len(m.group(1))) + long(m.group(1)) - except OverflowError: - raise NetstringParseError, "netstring too long" - if self._readerLength > self.MAX_LENGTH: - raise NetstringParseError, "netstring too long" - if m.group(2): - self.__buffer = '' - self._readerState = DATA - - def dataReceived(self, data): - self.__data = data - try: - while self.__data: - if self._readerState == DATA: - self.doData() - elif self._readerState == COMMA: - self.doComma() - elif self._readerState == LENGTH: - self.doLength() - else: - raise RuntimeError, "mode is not DATA, COMMA or LENGTH" - except NetstringParseError: - self.transport.loseConnection() - self.brokenPeer = 1 - - def sendString(self, data): - self.transport.write('%d:%s,' % (len(data), data)) - - -class SafeNetstringReceiver(NetstringReceiver): - """This class is deprecated, use NetstringReceiver instead. - """ - - -class LineOnlyReceiver(protocol.Protocol): - """A protocol that receives only lines. - - This is purely a speed optimisation over LineReceiver, for the - cases that raw mode is known to be unnecessary. - - @cvar delimiter: The line-ending delimiter to use. By default this is - '\\r\\n'. - @cvar MAX_LENGTH: The maximum length of a line to allow (If a - sent line is longer than this, the connection is dropped). - Default is 16384. - """ - _buffer = '' - delimiter = '\r\n' - MAX_LENGTH = 16384 - - def dataReceived(self, data): - """Translates bytes into lines, and calls lineReceived.""" - lines = (self._buffer+data).split(self.delimiter) - self._buffer = lines.pop(-1) - for line in lines: - if self.transport.disconnecting: - # this is necessary because the transport may be told to lose - # the connection by a line within a larger packet, and it is - # important to disregard all the lines in that packet following - # the one that told it to close. - return - if len(line) > self.MAX_LENGTH: - return self.lineLengthExceeded(line) - else: - self.lineReceived(line) - if len(self._buffer) > self.MAX_LENGTH: - return self.lineLengthExceeded(self._buffer) - - def lineReceived(self, line): - """Override this for when each line is received. - """ - raise NotImplementedError - - def sendLine(self, line): - """Sends a line to the other end of the connection. - """ - return self.transport.writeSequence((line,self.delimiter)) - - def lineLengthExceeded(self, line): - """Called when the maximum line length has been reached. - Override if it needs to be dealt with in some special way. - """ - return error.ConnectionLost('Line length exceeded') - - -class _PauseableMixin: - paused = False - - def pauseProducing(self): - self.paused = True - self.transport.pauseProducing() - - def resumeProducing(self): - self.paused = False - self.transport.resumeProducing() - self.dataReceived('') - - def stopProducing(self): - self.paused = True - self.transport.stopProducing() - - -class LineReceiver(protocol.Protocol, _PauseableMixin): - """A protocol that receives lines and/or raw data, depending on mode. - - In line mode, each line that's received becomes a callback to - L{lineReceived}. In raw data mode, each chunk of raw data becomes a - callback to L{rawDataReceived}. The L{setLineMode} and L{setRawMode} - methods switch between the two modes. - - This is useful for line-oriented protocols such as IRC, HTTP, POP, etc. - - @cvar delimiter: The line-ending delimiter to use. By default this is - '\\r\\n'. - @cvar MAX_LENGTH: The maximum length of a line to allow (If a - sent line is longer than this, the connection is dropped). - Default is 16384. - """ - line_mode = 1 - __buffer = '' - delimiter = '\r\n' - MAX_LENGTH = 16384 - - def clearLineBuffer(self): - """Clear buffered data.""" - self.__buffer = "" - - def dataReceived(self, data): - """Protocol.dataReceived. - Translates bytes into lines, and calls lineReceived (or - rawDataReceived, depending on mode.) - """ - self.__buffer = self.__buffer+data - while self.line_mode and not self.paused: - try: - line, self.__buffer = self.__buffer.split(self.delimiter, 1) - except ValueError: - if len(self.__buffer) > self.MAX_LENGTH: - line, self.__buffer = self.__buffer, '' - return self.lineLengthExceeded(line) - break - else: - linelength = len(line) - if linelength > self.MAX_LENGTH: - exceeded = line + self.__buffer - self.__buffer = '' - return self.lineLengthExceeded(exceeded) - why = self.lineReceived(line) - if why or self.transport and self.transport.disconnecting: - return why - else: - if not self.paused: - data=self.__buffer - self.__buffer='' - if data: - return self.rawDataReceived(data) - - def setLineMode(self, extra=''): - """Sets the line-mode of this receiver. - - If you are calling this from a rawDataReceived callback, - you can pass in extra unhandled data, and that data will - be parsed for lines. Further data received will be sent - to lineReceived rather than rawDataReceived. - - Do not pass extra data if calling this function from - within a lineReceived callback. - """ - self.line_mode = 1 - if extra: - return self.dataReceived(extra) - - def setRawMode(self): - """Sets the raw mode of this receiver. - Further data received will be sent to rawDataReceived rather - than lineReceived. - """ - self.line_mode = 0 - - def rawDataReceived(self, data): - """Override this for when raw data is received. - """ - raise NotImplementedError - - def lineReceived(self, line): - """Override this for when each line is received. - """ - raise NotImplementedError - - def sendLine(self, line): - """Sends a line to the other end of the connection. - """ - return self.transport.write(line + self.delimiter) - - def lineLengthExceeded(self, line): - """Called when the maximum line length has been reached. - Override if it needs to be dealt with in some special way. - - The argument 'line' contains the remainder of the buffer, starting - with (at least some part) of the line which is too long. This may - be more than one line, or may be only the initial portion of the - line. - """ - return self.transport.loseConnection() - - -class StringTooLongError(AssertionError): - """ - Raised when trying to send a string too long for a length prefixed - protocol. - """ - - -class IntNStringReceiver(protocol.Protocol, _PauseableMixin): - """ - Generic class for length prefixed protocols. - - @ivar recvd: buffer holding received data when splitted. - @type recvd: C{str} - - @ivar structFormat: format used for struct packing/unpacking. Define it in - subclass. - @type structFormat: C{str} - - @ivar prefixLength: length of the prefix, in bytes. Define it in subclass, - using C{struct.calcSize(structFormat)} - @type prefixLength: C{int} - """ - MAX_LENGTH = 99999 - recvd = "" - - def stringReceived(self, msg): - """ - Override this. - """ - raise NotImplementedError - - def dataReceived(self, recd): - """ - Convert int prefixed strings into calls to stringReceived. - """ - self.recvd = self.recvd + recd - while len(self.recvd) >= self.prefixLength and not self.paused: - length ,= struct.unpack( - self.structFormat, self.recvd[:self.prefixLength]) - if length > self.MAX_LENGTH: - self.transport.loseConnection() - return - if len(self.recvd) < length + self.prefixLength: - break - packet = self.recvd[self.prefixLength:length + self.prefixLength] - self.recvd = self.recvd[length + self.prefixLength:] - self.stringReceived(packet) - - def sendString(self, data): - """ - Send an prefixed string to the other end of the connection. - - @type data: C{str} - """ - if len(data) >= 2 ** (8 * self.prefixLength): - raise StringTooLongError( - "Try to send %s bytes whereas maximum is %s" % ( - len(data), 2 ** (8 * self.prefixLength))) - self.transport.write(struct.pack(self.structFormat, len(data)) + data) - - -class Int32StringReceiver(IntNStringReceiver): - """ - A receiver for int32-prefixed strings. - - An int32 string is a string prefixed by 4 bytes, the 32-bit length of - the string encoded in network byte order. - - This class publishes the same interface as NetstringReceiver. - """ - structFormat = "!I" - prefixLength = struct.calcsize(structFormat) - - -class Int16StringReceiver(IntNStringReceiver): - """ - A receiver for int16-prefixed strings. - - An int16 string is a string prefixed by 2 bytes, the 16-bit length of - the string encoded in network byte order. - - This class publishes the same interface as NetstringReceiver. - """ - structFormat = "!H" - prefixLength = struct.calcsize(structFormat) - - -class Int8StringReceiver(IntNStringReceiver): - """ - A receiver for int8-prefixed strings. - - An int8 string is a string prefixed by 1 byte, the 8-bit length of - the string. - - This class publishes the same interface as NetstringReceiver. - """ - structFormat = "!B" - prefixLength = struct.calcsize(structFormat) - - -class StatefulStringProtocol: - """ - A stateful string protocol. - - This is a mixin for string protocols (Int32StringReceiver, - NetstringReceiver) which translates stringReceived into a callback - (prefixed with 'proto_') depending on state. - - The state 'done' is special; if a proto_* method returns it, the - connection will be closed immediately. - """ - - state = 'init' - - def stringReceived(self,string): - """Choose a protocol phase function and call it. - - Call back to the appropriate protocol phase; this begins with - the function proto_init and moves on to proto_* depending on - what each proto_* function returns. (For example, if - self.proto_init returns 'foo', then self.proto_foo will be the - next function called when a protocol message is received. - """ - try: - pto = 'proto_'+self.state - statehandler = getattr(self,pto) - except AttributeError: - log.msg('callback',self.state,'not found') - else: - self.state = statehandler(string) - if self.state == 'done': - self.transport.loseConnection() - -class FileSender: - """A producer that sends the contents of a file to a consumer. - - This is a helper for protocols that, at some point, will take a - file-like object, read its contents, and write them out to the network, - optionally performing some transformation on the bytes in between. - """ - implements(interfaces.IProducer) - - CHUNK_SIZE = 2 ** 14 - - lastSent = '' - deferred = None - - def beginFileTransfer(self, file, consumer, transform = None): - """Begin transferring a file - - @type file: Any file-like object - @param file: The file object to read data from - - @type consumer: Any implementor of IConsumer - @param consumer: The object to write data to - - @param transform: A callable taking one string argument and returning - the same. All bytes read from the file are passed through this before - being written to the consumer. - - @rtype: C{Deferred} - @return: A deferred whose callback will be invoked when the file has been - completely written to the consumer. The last byte written to the consumer - is passed to the callback. - """ - self.file = file - self.consumer = consumer - self.transform = transform - - self.deferred = deferred = defer.Deferred() - self.consumer.registerProducer(self, False) - return deferred - - def resumeProducing(self): - chunk = '' - if self.file: - chunk = self.file.read(self.CHUNK_SIZE) - if not chunk: - self.file = None - self.consumer.unregisterProducer() - if self.deferred: - self.deferred.callback(self.lastSent) - self.deferred = None - return - - if self.transform: - chunk = self.transform(chunk) - self.consumer.write(chunk) - self.lastSent = chunk[-1] - - def pauseProducing(self): - pass - - def stopProducing(self): - if self.deferred: - self.deferred.errback(Exception("Consumer asked us to stop producing")) - self.deferred = None diff --git a/tools/buildbot/pylibs/twisted/protocols/dict.py b/tools/buildbot/pylibs/twisted/protocols/dict.py deleted file mode 100644 index 855ab6a..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/dict.py +++ /dev/null @@ -1,362 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Dict client protocol implementation. - -@author: U{Pavel Pergamenshchik} -""" - -from twisted.protocols import basic -from twisted.internet import defer, protocol -from twisted.python import log -from StringIO import StringIO - -def parseParam(line): - """Chew one dqstring or atom from beginning of line and return (param, remaningline)""" - if line == '': - return (None, '') - elif line[0] != '"': # atom - mode = 1 - else: # dqstring - mode = 2 - res = "" - io = StringIO(line) - if mode == 2: # skip the opening quote - io.read(1) - while 1: - a = io.read(1) - if a == '"': - if mode == 2: - io.read(1) # skip the separating space - return (res, io.read()) - elif a == '\\': - a = io.read(1) - if a == '': - return (None, line) # unexpected end of string - elif a == '': - if mode == 1: - return (res, io.read()) - else: - return (None, line) # unexpected end of string - elif a == ' ': - if mode == 1: - return (res, io.read()) - res += a - -def makeAtom(line): - """Munch a string into an 'atom'""" - # FIXME: proper quoting - return filter(lambda x: not (x in map(chr, range(33)+[34, 39, 92])), line) - -def makeWord(s): - mustquote = range(33)+[34, 39, 92] - result = [] - for c in s: - if ord(c) in mustquote: - result.append("\\") - result.append(c) - s = "".join(result) - return s - -def parseText(line): - if len(line) == 1 and line == '.': - return None - else: - if len(line) > 1 and line[0:2] == '..': - line = line[1:] - return line - -class Definition: - """A word definition""" - def __init__(self, name, db, dbdesc, text): - self.name = name - self.db = db - self.dbdesc = dbdesc - self.text = text # list of strings not terminated by newline - -class DictClient(basic.LineReceiver): - """dict (RFC2229) client""" - - data = None # multiline data - MAX_LENGTH = 1024 - state = None - mode = None - result = None - factory = None - - def __init__(self): - self.data = None - self.result = None - - def connectionMade(self): - self.state = "conn" - self.mode = "command" - - def sendLine(self, line): - """Throw up if the line is longer than 1022 characters""" - if len(line) > self.MAX_LENGTH - 2: - raise ValueError("DictClient tried to send a too long line") - basic.LineReceiver.sendLine(self, line) - - def lineReceived(self, line): - try: - line = line.decode("UTF-8") - except UnicodeError: # garbage received, skip - return - if self.mode == "text": # we are receiving textual data - code = "text" - else: - if len(line) < 4: - log.msg("DictClient got invalid line from server -- %s" % line) - self.protocolError("Invalid line from server") - self.transport.LoseConnection() - return - code = int(line[:3]) - line = line[4:] - method = getattr(self, 'dictCode_%s_%s' % (code, self.state), self.dictCode_default) - method(line) - - def dictCode_default(self, line): - """Unkown message""" - log.msg("DictClient got unexpected message from server -- %s" % line) - self.protocolError("Unexpected server message") - self.transport.loseConnection() - - def dictCode_221_ready(self, line): - """We are about to get kicked off, do nothing""" - pass - - def dictCode_220_conn(self, line): - """Greeting message""" - self.state = "ready" - self.dictConnected() - - def dictCode_530_conn(self): - self.protocolError("Access denied") - self.transport.loseConnection() - - def dictCode_420_conn(self): - self.protocolError("Server temporarily unavailable") - self.transport.loseConnection() - - def dictCode_421_conn(self): - self.protocolError("Server shutting down at operator request") - self.transport.loseConnection() - - def sendDefine(self, database, word): - """Send a dict DEFINE command""" - assert self.state == "ready", "DictClient.sendDefine called when not in ready state" - self.result = None # these two are just in case. In "ready" state, result and data - self.data = None # should be None - self.state = "define" - command = "DEFINE %s %s" % (makeAtom(database.encode("UTF-8")), makeWord(word.encode("UTF-8"))) - self.sendLine(command) - - def sendMatch(self, database, strategy, word): - """Send a dict MATCH command""" - assert self.state == "ready", "DictClient.sendMatch called when not in ready state" - self.result = None - self.data = None - self.state = "match" - command = "MATCH %s %s %s" % (makeAtom(database), makeAtom(strategy), makeAtom(word)) - self.sendLine(command.encode("UTF-8")) - - def dictCode_550_define(self, line): - """Invalid database""" - self.mode = "ready" - self.defineFailed("Invalid database") - - def dictCode_550_match(self, line): - """Invalid database""" - self.mode = "ready" - self.matchFailed("Invalid database") - - def dictCode_551_match(self, line): - """Invalid strategy""" - self.mode = "ready" - self.matchFailed("Invalid strategy") - - def dictCode_552_define(self, line): - """No match""" - self.mode = "ready" - self.defineFailed("No match") - - def dictCode_552_match(self, line): - """No match""" - self.mode = "ready" - self.matchFailed("No match") - - def dictCode_150_define(self, line): - """n definitions retrieved""" - self.result = [] - - def dictCode_151_define(self, line): - """Definition text follows""" - self.mode = "text" - (word, line) = parseParam(line) - (db, line) = parseParam(line) - (dbdesc, line) = parseParam(line) - if not (word and db and dbdesc): - self.protocolError("Invalid server response") - self.transport.loseConnection() - else: - self.result.append(Definition(word, db, dbdesc, [])) - self.data = [] - - def dictCode_152_match(self, line): - """n matches found, text follows""" - self.mode = "text" - self.result = [] - self.data = [] - - def dictCode_text_define(self, line): - """A line of definition text received""" - res = parseText(line) - if res == None: - self.mode = "command" - self.result[-1].text = self.data - self.data = None - else: - self.data.append(line) - - def dictCode_text_match(self, line): - """One line of match text received""" - def l(s): - p1, t = parseParam(s) - p2, t = parseParam(t) - return (p1, p2) - res = parseText(line) - if res == None: - self.mode = "command" - self.result = map(l, self.data) - self.data = None - else: - self.data.append(line) - - def dictCode_250_define(self, line): - """ok""" - t = self.result - self.result = None - self.state = "ready" - self.defineDone(t) - - def dictCode_250_match(self, line): - """ok""" - t = self.result - self.result = None - self.state = "ready" - self.matchDone(t) - - def protocolError(self, reason): - """override to catch unexpected dict protocol conditions""" - pass - - def dictConnected(self): - """override to be notified when the server is ready to accept commands""" - pass - - def defineFailed(self, reason): - """override to catch reasonable failure responses to DEFINE""" - pass - - def defineDone(self, result): - """override to catch succesful DEFINE""" - pass - - def matchFailed(self, reason): - """override to catch resonable failure responses to MATCH""" - pass - - def matchDone(self, result): - """override to catch succesful MATCH""" - pass - - -class InvalidResponse(Exception): - pass - - -class DictLookup(DictClient): - """Utility class for a single dict transaction. To be used with DictLookupFactory""" - - def protocolError(self, reason): - if not self.factory.done: - self.factory.d.errback(InvalidResponse(reason)) - self.factory.clientDone() - - def dictConnected(self): - if self.factory.queryType == "define": - apply(self.sendDefine, self.factory.param) - elif self.factory.queryType == "match": - apply(self.sendMatch, self.factory.param) - - def defineFailed(self, reason): - self.factory.d.callback([]) - self.factory.clientDone() - self.transport.loseConnection() - - def defineDone(self, result): - self.factory.d.callback(result) - self.factory.clientDone() - self.transport.loseConnection() - - def matchFailed(self, reason): - self.factory.d.callback([]) - self.factory.clientDone() - self.transport.loseConnection() - - def matchDone(self, result): - self.factory.d.callback(result) - self.factory.clientDone() - self.transport.loseConnection() - - -class DictLookupFactory(protocol.ClientFactory): - """Utility factory for a single dict transaction""" - protocol = DictLookup - done = None - - def __init__(self, queryType, param, d): - self.queryType = queryType - self.param = param - self.d = d - self.done = 0 - - def clientDone(self): - """Called by client when done.""" - self.done = 1 - del self.d - - def clientConnectionFailed(self, connector, error): - self.d.errback(error) - - def clientConnectionLost(self, connector, error): - if not self.done: - self.d.errback(error) - - def buildProtocol(self, addr): - p = self.protocol() - p.factory = self - return p - - -def define(host, port, database, word): - """Look up a word using a dict server""" - d = defer.Deferred() - factory = DictLookupFactory("define", (database, word), d) - - from twisted.internet import reactor - reactor.connectTCP(host, port, factory) - return d - -def match(host, port, database, strategy, word): - """Match a word using a dict server""" - d = defer.Deferred() - factory = DictLookupFactory("match", (database, strategy, word), d) - - from twisted.internet import reactor - reactor.connectTCP(host, port, factory) - return d - diff --git a/tools/buildbot/pylibs/twisted/protocols/dns.py b/tools/buildbot/pylibs/twisted/protocols/dns.py deleted file mode 100644 index 208bc7d..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/dns.py +++ /dev/null @@ -1,6 +0,0 @@ -from twisted.python import util - -util.moduleMovedForSplit('twisted.protocols.dns', 'twisted.names.dns', - 'DNS protocol support', 'Names', - 'http://twistedmatrix.com/projects/names', - globals()) diff --git a/tools/buildbot/pylibs/twisted/protocols/ethernet.py b/tools/buildbot/pylibs/twisted/protocols/ethernet.py deleted file mode 100644 index dca2448..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/ethernet.py +++ /dev/null @@ -1,7 +0,0 @@ -from twisted.python import util - -util.moduleMovedForSplit('twisted.protocols.ethernet', 'twisted.pair.ethernet', - 'Ethernet Protocol', 'Pair', - 'http://twistedmatrix.com/projects/pair', - globals()) - diff --git a/tools/buildbot/pylibs/twisted/protocols/finger.py b/tools/buildbot/pylibs/twisted/protocols/finger.py deleted file mode 100644 index 409b82c..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/finger.py +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""The Finger User Information Protocol (RFC 1288)""" - -from twisted.protocols import basic -import string - -class Finger(basic.LineReceiver): - - def lineReceived(self, line): - parts = string.split(line) - if not parts: - parts = [''] - if len(parts) == 1: - slash_w = 0 - else: - slash_w = 1 - user = parts[-1] - if '@' in user: - host_place = string.rfind(user, '@') - user = user[:host_place] - host = user[host_place+1:] - return self.forwardQuery(slash_w, user, host) - if user: - return self.getUser(slash_w, user) - else: - return self.getDomain(slash_w) - - def _refuseMessage(self, message): - self.transport.write(message+"\n") - self.transport.loseConnection() - - def forwardQuery(self, slash_w, user, host): - self._refuseMessage('Finger forwarding service denied') - - def getDomain(self, slash_w): - self._refuseMessage('Finger online list denied') - - def getUser(self, slash_w, user): - self.transport.write('Login: '+user+'\n') - self._refuseMessage('No such user') diff --git a/tools/buildbot/pylibs/twisted/protocols/ftp.py b/tools/buildbot/pylibs/twisted/protocols/ftp.py deleted file mode 100644 index 7bf6f8f..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/ftp.py +++ /dev/null @@ -1,2625 +0,0 @@ -# -*- test-case-name: twisted.test.test_ftp -*- -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -An FTP protocol implementation - -@author: U{Itamar Shtull-Trauring} -@author: U{Jp Calderone} -@author: U{Andrew Bennetts} -""" - -# System Imports -import os -import time -import re -import operator -import stat -import errno -import fnmatch - -try: - import pwd, grp -except ImportError: - pwd = grp = None - -from zope.interface import Interface, implements - -# Twisted Imports -from twisted import copyright -from twisted.internet import reactor, interfaces, protocol, error, defer -from twisted.protocols import basic, policies - -from twisted.python import log, failure, filepath - -from twisted.cred import error as cred_error, portal, credentials, checkers - -# constants -# response codes - -RESTART_MARKER_REPLY = "100" -SERVICE_READY_IN_N_MINUTES = "120" -DATA_CNX_ALREADY_OPEN_START_XFR = "125" -FILE_STATUS_OK_OPEN_DATA_CNX = "150" - -CMD_OK = "200.1" -TYPE_SET_OK = "200.2" -ENTERING_PORT_MODE = "200.3" -CMD_NOT_IMPLMNTD_SUPERFLUOUS = "202" -SYS_STATUS_OR_HELP_REPLY = "211" -DIR_STATUS = "212" -FILE_STATUS = "213" -HELP_MSG = "214" -NAME_SYS_TYPE = "215" -SVC_READY_FOR_NEW_USER = "220.1" -WELCOME_MSG = "220.2" -SVC_CLOSING_CTRL_CNX = "221" -GOODBYE_MSG = "221" -DATA_CNX_OPEN_NO_XFR_IN_PROGRESS = "225" -CLOSING_DATA_CNX = "226" -TXFR_COMPLETE_OK = "226" -ENTERING_PASV_MODE = "227" -ENTERING_EPSV_MODE = "229" -USR_LOGGED_IN_PROCEED = "230.1" # v1 of code 230 -GUEST_LOGGED_IN_PROCEED = "230.2" # v2 of code 230 -REQ_FILE_ACTN_COMPLETED_OK = "250" -PWD_REPLY = "257.1" -MKD_REPLY = "257.2" - -USR_NAME_OK_NEED_PASS = "331.1" # v1 of Code 331 -GUEST_NAME_OK_NEED_EMAIL = "331.2" # v2 of code 331 -NEED_ACCT_FOR_LOGIN = "332" -REQ_FILE_ACTN_PENDING_FURTHER_INFO = "350" - -SVC_NOT_AVAIL_CLOSING_CTRL_CNX = "421.1" -TOO_MANY_CONNECTIONS = "421.2" -CANT_OPEN_DATA_CNX = "425" -CNX_CLOSED_TXFR_ABORTED = "426" -REQ_ACTN_ABRTD_FILE_UNAVAIL = "450" -REQ_ACTN_ABRTD_LOCAL_ERR = "451" -REQ_ACTN_ABRTD_INSUFF_STORAGE = "452" - -SYNTAX_ERR = "500" -SYNTAX_ERR_IN_ARGS = "501" -CMD_NOT_IMPLMNTD = "502" -BAD_CMD_SEQ = "503" -CMD_NOT_IMPLMNTD_FOR_PARAM = "504" -NOT_LOGGED_IN = "530.1" # v1 of code 530 - please log in -AUTH_FAILURE = "530.2" # v2 of code 530 - authorization failure -NEED_ACCT_FOR_STOR = "532" -FILE_NOT_FOUND = "550.1" # no such file or directory -PERMISSION_DENIED = "550.2" # permission denied -ANON_USER_DENIED = "550.3" # anonymous users can't alter filesystem -IS_NOT_A_DIR = "550.4" # rmd called on a path that is not a directory -REQ_ACTN_NOT_TAKEN = "550.5" -FILE_EXISTS = "550.6" -IS_A_DIR = "550.7" -PAGE_TYPE_UNK = "551" -EXCEEDED_STORAGE_ALLOC = "552" -FILENAME_NOT_ALLOWED = "553" - - -RESPONSE = { - # -- 100's -- - RESTART_MARKER_REPLY: '110 MARK yyyy-mmmm', # TODO: this must be fixed - SERVICE_READY_IN_N_MINUTES: '120 service ready in %s minutes', - DATA_CNX_ALREADY_OPEN_START_XFR: '125 Data connection already open, starting transfer', - FILE_STATUS_OK_OPEN_DATA_CNX: '150 File status okay; about to open data connection.', - - # -- 200's -- - CMD_OK: '200 Command OK', - TYPE_SET_OK: '200 Type set to %s.', - ENTERING_PORT_MODE: '200 PORT OK', - CMD_NOT_IMPLMNTD_SUPERFLUOUS: '202 Command not implemented, superfluous at this site', - SYS_STATUS_OR_HELP_REPLY: '211 System status reply', - DIR_STATUS: '212 %s', - FILE_STATUS: '213 %s', - HELP_MSG: '214 help: %s', - NAME_SYS_TYPE: '215 UNIX Type: L8', - WELCOME_MSG: "220 %s", - SVC_READY_FOR_NEW_USER: '220 Service ready', - GOODBYE_MSG: '221 Goodbye.', - DATA_CNX_OPEN_NO_XFR_IN_PROGRESS: '225 data connection open, no transfer in progress', - CLOSING_DATA_CNX: '226 Abort successful', - TXFR_COMPLETE_OK: '226 Transfer Complete.', - ENTERING_PASV_MODE: '227 Entering Passive Mode (%s).', - ENTERING_EPSV_MODE: '229 Entering Extended Passive Mode (|||%s|).', # where is epsv defined in the rfc's? - USR_LOGGED_IN_PROCEED: '230 User logged in, proceed', - GUEST_LOGGED_IN_PROCEED: '230 Anonymous login ok, access restrictions apply.', - REQ_FILE_ACTN_COMPLETED_OK: '250 Requested File Action Completed OK', #i.e. CWD completed ok - PWD_REPLY: '257 "%s"', - MKD_REPLY: '257 "%s" created', - - # -- 300's -- - 'userotp': '331 Response to %s.', # ??? - USR_NAME_OK_NEED_PASS: '331 Password required for %s.', - GUEST_NAME_OK_NEED_EMAIL: '331 Guest login ok, type your email address as password.', - - REQ_FILE_ACTN_PENDING_FURTHER_INFO: '350 Requested file action pending further information.', - -# -- 400's -- - SVC_NOT_AVAIL_CLOSING_CTRL_CNX: '421 Service not available, closing control connection.', - TOO_MANY_CONNECTIONS: '421 Too many users right now, try again in a few minutes.', - CANT_OPEN_DATA_CNX: "425 Can't open data connection.", - CNX_CLOSED_TXFR_ABORTED: '426 Transfer aborted. Data connection closed.', - - REQ_ACTN_ABRTD_LOCAL_ERR: '451 Requested action aborted. Local error in processing.', - - - # -- 500's -- - SYNTAX_ERR: "500 Syntax error: %s", - SYNTAX_ERR_IN_ARGS: '501 syntax error in argument(s) %s.', - CMD_NOT_IMPLMNTD: "502 Command '%s' not implemented", - BAD_CMD_SEQ: '503 Incorrect sequence of commands: %s', - CMD_NOT_IMPLMNTD_FOR_PARAM: "504 Not implemented for parameter '%s'.", - NOT_LOGGED_IN: '530 Please login with USER and PASS.', - AUTH_FAILURE: '530 Sorry, Authentication failed.', - NEED_ACCT_FOR_STOR: '532 Need an account for storing files', - FILE_NOT_FOUND: '550 %s: No such file or directory.', - PERMISSION_DENIED: '550 %s: Permission denied.', - ANON_USER_DENIED: '550 Anonymous users are forbidden to change the filesystem', - IS_NOT_A_DIR: '550 Cannot rmd, %s is not a directory', - FILE_EXISTS: '550 %s: File exists', - IS_A_DIR: '550 %s: is a directory', - REQ_ACTN_NOT_TAKEN: '550 Requested action not taken: %s', - EXCEEDED_STORAGE_ALLOC: '552 Requested file action aborted, exceeded file storage allocation', - FILENAME_NOT_ALLOWED: '553 Requested action not taken, file name not allowed' -} - - - -class InvalidPath(Exception): - """ - Internal exception used to signify an error during parsing a path. - """ - - - -def toSegments(cwd, path): - """ - Normalize a path, as represented by a list of strings each - representing one segment of the path. - """ - if path.startswith('/'): - segs = [] - else: - segs = cwd[:] - - for s in path.split('/'): - if s == '.' or s == '': - continue - elif s == '..': - if segs: - segs.pop() - else: - raise InvalidPath(cwd, path) - elif '\0' in s or '/' in s: - raise InvalidPath(cwd, path) - else: - segs.append(s) - return segs - - -def errnoToFailure(e, path): - """ - Map C{OSError} and C{IOError} to standard FTP errors. - """ - if e == errno.ENOENT: - return defer.fail(FileNotFoundError(path)) - elif e == errno.EACCES or e == errno.EPERM: - return defer.fail(PermissionDeniedError(path)) - elif e == errno.ENOTDIR: - return defer.fail(IsNotADirectoryError(path)) - elif e == errno.EEXIST: - return defer.fail(FileExistsError(path)) - elif e == errno.EISDIR: - return defer.fail(IsADirectoryError(path)) - else: - return defer.fail() - - - -class FTPCmdError(Exception): - """ - Generic exception for FTP commands. - """ - def __init__(self, *msg): - Exception.__init__(self, *msg) - self.errorMessage = msg - - - def response(self): - """ - Generate a FTP response message for this error. - """ - return RESPONSE[self.errorCode] % self.errorMessage - - - -class FileNotFoundError(FTPCmdError): - """ - Raised when trying to access a non existent file or directory. - """ - errorCode = FILE_NOT_FOUND - - - -class AnonUserDeniedError(FTPCmdError): - """ - Raised when an anonymous user issues a command that will alter the - filesystem - """ - def __init__(self): - # No message - FTPCmdError.__init__(self, None) - - errorCode = ANON_USER_DENIED - - - -class PermissionDeniedError(FTPCmdError): - """ - Raised when access is attempted to a resource to which access is - not allowed. - """ - errorCode = PERMISSION_DENIED - - - -class IsNotADirectoryError(FTPCmdError): - """ - Raised when RMD is called on a path that isn't a directory. - """ - errorCode = IS_NOT_A_DIR - - - -class FileExistsError(FTPCmdError): - """ - Raised when attempted to override an existing resource. - """ - errorCode = FILE_EXISTS - - - -class IsADirectoryError(FTPCmdError): - """ - Raised when DELE is called on a path that is a directory. - """ - errorCode = IS_A_DIR - - - -class CmdSyntaxError(FTPCmdError): - """ - Raised when a command syntax is wrong. - """ - errorCode = SYNTAX_ERR - - - -class CmdArgSyntaxError(FTPCmdError): - """ - Raised when a command is called with wrong value or a wrong number of - arguments. - """ - errorCode = SYNTAX_ERR_IN_ARGS - - - -class CmdNotImplementedError(FTPCmdError): - """ - Raised when an unimplemented command is given to the server. - """ - errorCode = CMD_NOT_IMPLMNTD - - - -class CmdNotImplementedForArgError(FTPCmdError): - """ - Raised when the handling of a parameter for a command is not implemented by - the server. - """ - errorCode = CMD_NOT_IMPLMNTD_FOR_PARAM - - - -class FTPError(Exception): - pass - - - -class PortConnectionError(Exception): - pass - - - -class BadCmdSequenceError(FTPCmdError): - """ - Raised when a client sends a series of commands in an illogical sequence. - """ - errorCode = BAD_CMD_SEQ - - - -class AuthorizationError(FTPCmdError): - """ - Raised when client authentication fails. - """ - errorCode = AUTH_FAILURE - - - -def debugDeferred(self, *_): - log.msg('debugDeferred(): %s' % str(_), debug=True) - - -# -- DTP Protocol -- - - -_months = [ - None, - 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', - 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] - - -class DTP(object, protocol.Protocol): - implements(interfaces.IConsumer) - - isConnected = False - - _cons = None - _onConnLost = None - _buffer = None - - def connectionMade(self): - self.isConnected = True - self.factory.deferred.callback(None) - self._buffer = [] - - def connectionLost(self, reason): - self.isConnected = False - if self._onConnLost is not None: - self._onConnLost.callback(None) - - def sendLine(self, line): - self.transport.write(line + '\r\n') - - - def _formatOneListResponse(self, name, size, directory, permissions, hardlinks, modified, owner, group): - def formatMode(mode): - return ''.join([mode & (256 >> n) and 'rwx'[n % 3] or '-' for n in range(9)]) - - def formatDate(mtime): - now = time.gmtime() - info = { - 'month': _months[mtime.tm_mon], - 'day': mtime.tm_mday, - 'year': mtime.tm_year, - 'hour': mtime.tm_hour, - 'minute': mtime.tm_min - } - if now.tm_year != mtime.tm_year: - return '%(month)s %(day)02d %(year)5d' % info - else: - return '%(month)s %(day)02d %(hour)02d:%(minute)02d' % info - - format = ('%(directory)s%(permissions)s%(hardlinks)4d ' - '%(owner)-9s %(group)-9s %(size)15d %(date)12s ' - '%(name)s') - - return format % { - 'directory': directory and 'd' or '-', - 'permissions': formatMode(permissions), - 'hardlinks': hardlinks, - 'owner': owner[:8], - 'group': group[:8], - 'size': size, - 'date': formatDate(time.gmtime(modified)), - 'name': name} - - def sendListResponse(self, name, response): - self.sendLine(self._formatOneListResponse(name, *response)) - - - # Proxy IConsumer to our transport - def registerProducer(self, producer, streaming): - return self.transport.registerProducer(producer, streaming) - - def unregisterProducer(self): - self.transport.unregisterProducer() - self.transport.loseConnection() - - def write(self, data): - if self.isConnected: - return self.transport.write(data) - raise Exception("Crap damn crap damn crap damn") - - - # Pretend to be a producer, too. - def _conswrite(self, bytes): - try: - self._cons.write(bytes) - except: - self._onConnLost.errback() - - def dataReceived(self, bytes): - if self._cons is not None: - self._conswrite(bytes) - else: - self._buffer.append(bytes) - - def _unregConsumer(self, ignored): - self._cons.unregisterProducer() - self._cons = None - del self._onConnLost - return ignored - - def registerConsumer(self, cons): - assert self._cons is None - self._cons = cons - self._cons.registerProducer(self, True) - for chunk in self._buffer: - self._conswrite(chunk) - self._buffer = None - if self.isConnected: - self._onConnLost = d = defer.Deferred() - d.addBoth(self._unregConsumer) - return d - else: - self._cons.unregisterProducer() - self._cons = None - return defer.succeed(None) - - def resumeProducing(self): - self.transport.resumeProducing() - - def pauseProducing(self): - self.transport.pauseProducing() - - def stopProducing(self): - self.transport.stopProducing() - -class DTPFactory(protocol.ClientFactory): - """ - DTP protocol factory. - - @ivar peerCheck: perform checks to make sure the ftp-pi's peer is the same - as the dtp's - @ivar pi: a reference to this factory's protocol interpreter - """ - - # -- configuration variables -- - peerCheck = False - - # -- class variables -- - def __init__(self, pi, peerHost=None): - """Constructor - @param pi: this factory's protocol interpreter - @param peerHost: if peerCheck is True, this is the tuple that the - generated instance will use to perform security checks - """ - self.pi = pi # the protocol interpreter that is using this factory - self.peerHost = peerHost # the from FTP.transport.peerHost() - self.deferred = defer.Deferred() # deferred will fire when instance is connected - self.deferred.addBoth(lambda ign: (delattr(self, 'deferred'), ign)[1]) - self.delayedCall = None - - def buildProtocol(self, addr): - log.msg('DTPFactory.buildProtocol', debug=True) - self.cancelTimeout() - if self.pi.dtpInstance: # only create one instance - return - p = DTP() - p.factory = self - p.pi = self.pi - self.pi.dtpInstance = p - return p - - def stopFactory(self): - log.msg('dtpFactory.stopFactory', debug=True) - self.cancelTimeout() - - def timeoutFactory(self): - log.msg('timed out waiting for DTP connection') - if self.deferred: - d, self.deferred = self.deferred, None - - # TODO: LEFT OFF HERE! - - d.addErrback(debugDeferred, 'timeoutFactory firing errback') - d.errback(defer.TimeoutError()) - self.stopFactory() - - def cancelTimeout(self): - if not self.delayedCall.called and not self.delayedCall.cancelled: - log.msg('cancelling DTP timeout', debug=True) - self.delayedCall.cancel() - assert self.delayedCall.cancelled - log.msg('timeout has been cancelled', debug=True) - - def setTimeout(self, seconds): - log.msg('DTPFactory.setTimeout set to %s seconds' % seconds) - self.delayedCall = reactor.callLater(seconds, self.timeoutFactory) - - def clientConnectionFailed(self, connector, reason): - self.deferred.errback(PortConnectionError(reason)) - -# -- FTP-PI (Protocol Interpreter) -- - -class ASCIIConsumerWrapper(object): - def __init__(self, cons): - self.cons = cons - self.registerProducer = cons.registerProducer - self.unregisterProducer = cons.unregisterProducer - - assert os.linesep == "\r\n" or len(os.linesep) == 1, "Unsupported platform (yea right like this even exists)" - - if os.linesep == "\r\n": - self.write = cons.write - - def write(self, bytes): - return self.cons.write(bytes.replace(os.linesep, "\r\n")) - - - -class FileConsumer(object): - """ - A consumer for FTP input that writes data to a file. - - @ivar fObj: a file object opened for writing, used to write data received. - @type fObj: C{file} - """ - - implements(interfaces.IConsumer) - - def __init__(self, fObj): - self.fObj = fObj - - - def registerProducer(self, producer, streaming): - self.producer = producer - assert streaming - - - def unregisterProducer(self): - self.producer = None - self.fObj.close() - - - def write(self, bytes): - self.fObj.write(bytes) - - - -class FTPOverflowProtocol(basic.LineReceiver): - """FTP mini-protocol for when there are too many connections.""" - def connectionMade(self): - self.sendLine(RESPONSE[TOO_MANY_CONNECTIONS]) - self.transport.loseConnection() - - -class FTP(object, basic.LineReceiver, policies.TimeoutMixin): - """ - Protocol Interpreter for the File Transfer Protocol - - @ivar state: The current server state. One of L{UNAUTH}, - L{INAUTH}, L{AUTHED}, L{RENAMING}. - - @ivar shell: The connected avatar - @ivar binary: The transfer mode. If false, ASCII. - @ivar dtpFactory: Generates a single DTP for this session - @ivar dtpPort: Port returned from listenTCP - @ivar listenFactory: A callable with the signature of - L{twisted.internet.interfaces.IReactorTCP.listenTCP} which will be used - to create Ports for passive connections (mainly for testing). - - @ivar passivePortRange: iterator used as source of passive port numbers. - @type passivePortRange: C{iterator} - """ - - disconnected = False - - # States an FTP can be in - UNAUTH, INAUTH, AUTHED, RENAMING = range(4) - - # how long the DTP waits for a connection - dtpTimeout = 10 - - portal = None - shell = None - dtpFactory = None - dtpPort = None - dtpInstance = None - binary = True - - passivePortRange = xrange(0, 1) - - listenFactory = reactor.listenTCP - - def reply(self, key, *args): - msg = RESPONSE[key] % args - self.sendLine(msg) - - - def connectionMade(self): - self.state = self.UNAUTH - self.setTimeout(self.timeOut) - self.reply(WELCOME_MSG, self.factory.welcomeMessage) - - def connectionLost(self, reason): - # if we have a DTP protocol instance running and - # we lose connection to the client's PI, kill the - # DTP connection and close the port - if self.dtpFactory: - self.cleanupDTP() - self.setTimeout(None) - if hasattr(self.shell, 'logout') and self.shell.logout is not None: - self.shell.logout() - self.shell = None - self.transport = None - - def timeoutConnection(self): - self.transport.loseConnection() - - def lineReceived(self, line): - self.resetTimeout() - self.pauseProducing() - - def processFailed(err): - if err.check(FTPCmdError): - self.sendLine(err.value.response()) - elif (err.check(TypeError) and - err.value.args[0].find('takes exactly') != -1): - self.reply(SYNTAX_ERR, "%s requires an argument." % (cmd,)) - else: - log.msg("Unexpected FTP error") - log.err(err) - self.reply(REQ_ACTN_NOT_TAKEN, "internal server error") - - def processSucceeded(result): - if isinstance(result, tuple): - self.reply(*result) - elif result is not None: - self.reply(result) - - def allDone(ignored): - if not self.disconnected: - self.resumeProducing() - - spaceIndex = line.find(' ') - if spaceIndex != -1: - cmd = line[:spaceIndex] - args = (line[spaceIndex + 1:],) - else: - cmd = line - args = () - d = defer.maybeDeferred(self.processCommand, cmd, *args) - d.addCallbacks(processSucceeded, processFailed) - d.addErrback(log.err) - - # XXX It burnsss - # LineReceiver doesn't let you resumeProducing inside - # lineReceived atm - from twisted.internet import reactor - reactor.callLater(0, d.addBoth, allDone) - - - def processCommand(self, cmd, *params): - cmd = cmd.upper() - - if self.state == self.UNAUTH: - if cmd == 'USER': - return self.ftp_USER(*params) - elif cmd == 'PASS': - return BAD_CMD_SEQ, "USER required before PASS" - else: - return NOT_LOGGED_IN - - elif self.state == self.INAUTH: - if cmd == 'PASS': - return self.ftp_PASS(*params) - else: - return BAD_CMD_SEQ, "PASS required after USER" - - elif self.state == self.AUTHED: - method = getattr(self, "ftp_" + cmd, None) - if method is not None: - return method(*params) - return defer.fail(CmdNotImplementedError(cmd)) - - elif self.state == self.RENAMING: - if cmd == 'RNTO': - return self.ftp_RNTO(*params) - else: - return BAD_CMD_SEQ, "RNTO required after RNFR" - - - def getDTPPort(self, factory): - """ - Return a port for passive access, using C{self.passivePortRange} - attribute. - """ - for portn in self.passivePortRange: - try: - dtpPort = self.listenFactory(portn, factory) - except error.CannotListenError: - continue - else: - return dtpPort - raise error.CannotListenError('', portn, - "No port available in range %s" % - (self.passivePortRange,)) - - - def ftp_USER(self, username): - """ - First part of login. Get the username the peer wants to - authenticate as. - """ - if not username: - return defer.fail(CmdSyntaxError('USER requires an argument')) - - self._user = username - self.state = self.INAUTH - if self.factory.allowAnonymous and self._user == self.factory.userAnonymous: - return GUEST_NAME_OK_NEED_EMAIL - else: - return (USR_NAME_OK_NEED_PASS, username) - - # TODO: add max auth try before timeout from ip... - # TODO: need to implement minimal ABOR command - - def ftp_PASS(self, password): - """ - Second part of login. Get the password the peer wants to - authenticate with. - """ - if self.factory.allowAnonymous and self._user == self.factory.userAnonymous: - # anonymous login - creds = credentials.Anonymous() - reply = GUEST_LOGGED_IN_PROCEED - else: - # user login - creds = credentials.UsernamePassword(self._user, password) - reply = USR_LOGGED_IN_PROCEED - del self._user - - def _cbLogin((interface, avatar, logout)): - assert interface is IFTPShell, "The realm is busted, jerk." - self.shell = avatar - self.logout = logout - self.workingDirectory = [] - self.state = self.AUTHED - return reply - - def _ebLogin(failure): - failure.trap(cred_error.UnauthorizedLogin, cred_error.UnhandledCredentials) - self.state = self.UNAUTH - raise AuthorizationError - - d = self.portal.login(creds, None, IFTPShell) - d.addCallbacks(_cbLogin, _ebLogin) - return d - - - def ftp_PASV(self): - """Request for a passive connection - - from the rfc:: - - This command requests the server-DTP to \"listen\" on a data port - (which is not its default data port) and to wait for a connection - rather than initiate one upon receipt of a transfer command. The - response to this command includes the host and port address this - server is listening on. - """ - # if we have a DTP port set up, lose it. - if self.dtpFactory is not None: - # cleanupDTP sets dtpFactory to none. Later we'll do - # cleanup here or something. - self.cleanupDTP() - self.dtpFactory = DTPFactory(pi=self) - self.dtpFactory.setTimeout(self.dtpTimeout) - self.dtpPort = self.getDTPPort(self.dtpFactory) - - host = self.transport.getHost().host - port = self.dtpPort.getHost().port - self.reply(ENTERING_PASV_MODE, encodeHostPort(host, port)) - return self.dtpFactory.deferred.addCallback(lambda ign: None) - - - def ftp_PORT(self, address): - addr = map(int, address.split(',')) - ip = '%d.%d.%d.%d' % tuple(addr[:4]) - port = addr[4] << 8 | addr[5] - - # if we have a DTP port set up, lose it. - if self.dtpFactory is not None: - self.cleanupDTP() - - self.dtpFactory = DTPFactory(pi=self, peerHost=self.transport.getPeer().host) - self.dtpFactory.setTimeout(self.dtpTimeout) - self.dtpPort = reactor.connectTCP(ip, port, self.dtpFactory) - - def connected(ignored): - return ENTERING_PORT_MODE - def connFailed(err): - err.trap(PortConnectionError) - return CANT_OPEN_DATA_CNX - return self.dtpFactory.deferred.addCallbacks(connected, connFailed) - - - def ftp_LIST(self, path=''): - """ This command causes a list to be sent from the server to the - passive DTP. If the pathname specifies a directory or other - group of files, the server should transfer a list of files - in the specified directory. If the pathname specifies a - file then the server should send current information on the - file. A null argument implies the user's current working or - default directory. - """ - # Uh, for now, do this retarded thing. - if self.dtpInstance is None or not self.dtpInstance.isConnected: - return defer.fail(BadCmdSequenceError('must send PORT or PASV before RETR')) - - # bug in konqueror - if path == "-a": - path = '' - # bug in gFTP 2.0.15 - if path == "-aL": - path = '' - # bug in Nautilus 2.10.0 - if path == "-L": - path = '' - # bug in ange-ftp - if path == "-la": - path = '' - - def gotListing(results): - self.reply(DATA_CNX_ALREADY_OPEN_START_XFR) - for (name, attrs) in results: - self.dtpInstance.sendListResponse(name, attrs) - self.dtpInstance.transport.loseConnection() - return (TXFR_COMPLETE_OK,) - - try: - segments = toSegments(self.workingDirectory, path) - except InvalidPath, e: - return defer.fail(FileNotFoundError(path)) - - d = self.shell.list( - segments, - ('size', 'directory', 'permissions', 'hardlinks', - 'modified', 'owner', 'group')) - d.addCallback(gotListing) - return d - - - def ftp_NLST(self, path): - # XXX: why is this check different to ftp_RETR/ftp_STOR? - if self.dtpInstance is None or not self.dtpInstance.isConnected: - return defer.fail(BadCmdSequenceError('must send PORT or PASV before RETR')) - - try: - segments = toSegments(self.workingDirectory, path) - except InvalidPath, e: - return defer.fail(FileNotFoundError(path)) - - def cbList(results): - self.reply(DATA_CNX_ALREADY_OPEN_START_XFR) - for (name, ignored) in results: - self.dtpInstance.sendLine(name) - self.dtpInstance.transport.loseConnection() - return (TXFR_COMPLETE_OK,) - - def cbGlob(results): - self.reply(DATA_CNX_ALREADY_OPEN_START_XFR) - for (name, ignored) in results: - if fnmatch.fnmatch(name, segments[-1]): - self.dtpInstance.sendLine(name) - self.dtpInstance.transport.loseConnection() - return (TXFR_COMPLETE_OK,) - - # XXX Maybe this globbing is incomplete, but who cares. - # Stupid people probably. - if segments and ( - '*' in segments[-1] or '?' in segments[-1] or - ('[' in segments[-1] and ']' in segments[-1])): - d = self.shell.list(segments[:-1]) - d.addCallback(cbGlob) - else: - d = self.shell.list(segments) - d.addCallback(cbList) - return d - - - def ftp_CWD(self, path): - try: - segments = toSegments(self.workingDirectory, path) - except InvalidPath, e: - # XXX Eh, what to fail with here? - return defer.fail(FileNotFoundError(path)) - - def accessGranted(result): - self.workingDirectory = segments - return (REQ_FILE_ACTN_COMPLETED_OK,) - - return self.shell.access(segments).addCallback(accessGranted) - - - def ftp_CDUP(self): - return self.ftp_CWD('..') - - - def ftp_PWD(self): - return (PWD_REPLY, '/' + '/'.join(self.workingDirectory)) - - - def ftp_RETR(self, path): - if self.dtpInstance is None: - raise BadCmdSequenceError('PORT or PASV required before RETR') - - try: - newsegs = toSegments(self.workingDirectory, path) - except InvalidPath: - return defer.fail(FileNotFoundError(path)) - - # XXX For now, just disable the timeout. Later we'll want to - # leave it active and have the DTP connection reset it - # periodically. - self.setTimeout(None) - - # Put it back later - def enableTimeout(result): - self.setTimeout(self.factory.timeOut) - return result - - # And away she goes - if not self.binary: - cons = ASCIIConsumerWrapper(self.dtpInstance) - else: - cons = self.dtpInstance - - def cbSent(result): - return (TXFR_COMPLETE_OK,) - - def ebSent(err): - log.msg("Unexpected error attempting to transmit file to client:") - log.err(err) - return (CNX_CLOSED_TXFR_ABORTED,) - - def cbOpened(file): - # Tell them what to doooo - if self.dtpInstance.isConnected: - self.reply(DATA_CNX_ALREADY_OPEN_START_XFR) - else: - self.reply(FILE_STATUS_OK_OPEN_DATA_CNX) - - d = file.send(cons) - d.addCallbacks(cbSent, ebSent) - return d - - def ebOpened(err): - if not err.check(PermissionDeniedError, FileNotFoundError, IsNotADirectoryError): - log.msg("Unexpected error attempting to open file for transmission:") - log.err(err) - if err.check(FTPCmdError): - return (err.value.errorCode, '/'.join(newsegs)) - return (FILE_NOT_FOUND, '/'.join(newsegs)) - - d = self.shell.openForReading(newsegs) - d.addCallbacks(cbOpened, ebOpened) - d.addBoth(enableTimeout) - - # Pass back Deferred that fires when the transfer is done - return d - - - def ftp_STOR(self, path): - if self.dtpInstance is None: - raise BadCmdSequenceError('PORT or PASV required before STOR') - - try: - newsegs = toSegments(self.workingDirectory, path) - except InvalidPath: - return defer.fail(FileNotFoundError(path)) - - # XXX For now, just disable the timeout. Later we'll want to - # leave it active and have the DTP connection reset it - # periodically. - self.setTimeout(None) - - # Put it back later - def enableTimeout(result): - self.setTimeout(self.factory.timeOut) - return result - - def cbSent(result): - return (TXFR_COMPLETE_OK,) - - def ebSent(err): - log.msg("Unexpected error receiving file from client:") - log.err(err) - return (CNX_CLOSED_TXFR_ABORTED,) - - def cbConsumer(cons): - if not self.binary: - cons = ASCIIConsumerWrapper(cons) - - d = self.dtpInstance.registerConsumer(cons) - d.addCallbacks(cbSent, ebSent) - - # Tell them what to doooo - if self.dtpInstance.isConnected: - self.reply(DATA_CNX_ALREADY_OPEN_START_XFR) - else: - self.reply(FILE_STATUS_OK_OPEN_DATA_CNX) - - return d - - def cbOpened(file): - d = file.receive() - d.addCallback(cbConsumer) - return d - - def ebOpened(err): - if not err.check(PermissionDeniedError, FileNotFoundError, IsNotADirectoryError): - log.msg("Unexpected error attempting to open file for upload:") - log.err(err) - if isinstance(err.value, FTPCmdError): - return (err.value.errorCode, '/'.join(newsegs)) - return (FILE_NOT_FOUND, '/'.join(newsegs)) - - d = self.shell.openForWriting(newsegs) - d.addCallbacks(cbOpened, ebOpened) - d.addBoth(enableTimeout) - - # Pass back Deferred that fires when the transfer is done - return d - - - def ftp_SIZE(self, path): - try: - newsegs = toSegments(self.workingDirectory, path) - except InvalidPath: - return defer.fail(FileNotFoundError(path)) - - def cbStat((size,)): - return (FILE_STATUS, str(size)) - - return self.shell.stat(newsegs, ('size',)).addCallback(cbStat) - - - def ftp_MDTM(self, path): - try: - newsegs = toSegments(self.workingDirectory, path) - except InvalidPath: - return defer.fail(FileNotFoundError(path)) - - def cbStat((modified,)): - return (FILE_STATUS, time.strftime('%Y%m%d%H%M%S', time.gmtime(modified))) - - return self.shell.stat(newsegs, ('modified',)).addCallback(cbStat) - - - def ftp_TYPE(self, type): - p = type.upper() - if p: - f = getattr(self, 'type_' + p[0], None) - if f is not None: - return f(p[1:]) - return self.type_UNKNOWN(p) - return (SYNTAX_ERR,) - - def type_A(self, code): - if code == '' or code == 'N': - self.binary = False - return (TYPE_SET_OK, 'A' + code) - else: - return defer.fail(CmdArgSyntaxError(code)) - - def type_I(self, code): - if code == '': - self.binary = True - return (TYPE_SET_OK, 'I') - else: - return defer.fail(CmdArgSyntaxError(code)) - - def type_UNKNOWN(self, code): - return defer.fail(CmdNotImplementedForArgError(code)) - - - - def ftp_SYST(self): - return NAME_SYS_TYPE - - - def ftp_STRU(self, structure): - p = structure.upper() - if p == 'F': - return (CMD_OK,) - return defer.fail(CmdNotImplementedForArgError(structure)) - - - def ftp_MODE(self, mode): - p = mode.upper() - if p == 'S': - return (CMD_OK,) - return defer.fail(CmdNotImplementedForArgError(mode)) - - - def ftp_MKD(self, path): - try: - newsegs = toSegments(self.workingDirectory, path) - except InvalidPath: - return defer.fail(FileNotFoundError(path)) - return self.shell.makeDirectory(newsegs).addCallback(lambda ign: (MKD_REPLY, path)) - - - def ftp_RMD(self, path): - try: - newsegs = toSegments(self.workingDirectory, path) - except InvalidPath: - return defer.fail(FileNotFoundError(path)) - return self.shell.removeDirectory(newsegs).addCallback(lambda ign: (REQ_FILE_ACTN_COMPLETED_OK,)) - - - def ftp_DELE(self, path): - try: - newsegs = toSegments(self.workingDirectory, path) - except InvalidPath: - return defer.fail(FileNotFoundError(path)) - return self.shell.removeFile(newsegs).addCallback(lambda ign: (REQ_FILE_ACTN_COMPLETED_OK,)) - - - def ftp_NOOP(self): - return (CMD_OK,) - - - def ftp_RNFR(self, fromName): - self._fromName = fromName - self.state = self.RENAMING - return (REQ_FILE_ACTN_PENDING_FURTHER_INFO,) - - - def ftp_RNTO(self, toName): - fromName = self._fromName - del self._fromName - self.state = self.AUTHED - - try: - fromsegs = toSegments(self.workingDirectory, fromName) - tosegs = toSegments(self.workingDirectory, toName) - except InvalidPath: - return defer.fail(FileNotFoundError(fromName)) - return self.shell.rename(fromsegs, tosegs).addCallback(lambda ign: (REQ_FILE_ACTN_COMPLETED_OK,)) - - - def ftp_QUIT(self): - self.reply(GOODBYE_MSG) - self.transport.loseConnection() - self.disconnected = True - - - def cleanupDTP(self): - """call when DTP connection exits - """ - log.msg('cleanupDTP', debug=True) - - log.msg(self.dtpPort) - dtpPort, self.dtpPort = self.dtpPort, None - if interfaces.IListeningPort.providedBy(dtpPort): - dtpPort.stopListening() - elif interfaces.IConnector.providedBy(dtpPort): - dtpPort.disconnect() - else: - assert False, "dtpPort should be an IListeningPort or IConnector, instead is %r" % (dtpPort,) - - self.dtpFactory.stopFactory() - self.dtpFactory = None - - if self.dtpInstance is not None: - self.dtpInstance = None - - -class FTPFactory(policies.LimitTotalConnectionsFactory): - """ - A factory for producing ftp protocol instances - - @ivar timeOut: the protocol interpreter's idle timeout time in seconds, - default is 600 seconds. - - @ivar passivePortRange: value forwarded to C{protocol.passivePortRange}. - @type passivePortRange: C{iterator} - """ - protocol = FTP - overflowProtocol = FTPOverflowProtocol - allowAnonymous = True - userAnonymous = 'anonymous' - timeOut = 600 - - welcomeMessage = "Twisted %s FTP Server" % (copyright.version,) - - passivePortRange = xrange(0, 1) - - def __init__(self, portal=None, userAnonymous='anonymous'): - self.portal = portal - self.userAnonymous = 'anonymous' - self.instances = [] - - def buildProtocol(self, addr): - p = policies.LimitTotalConnectionsFactory.buildProtocol(self, addr) - if p is not None: - p.wrappedProtocol.portal = self.portal - p.wrappedProtocol.timeOut = self.timeOut - p.passivePortRange = self.passivePortRange - return p - - def stopFactory(self): - # make sure ftp instance's timeouts are set to None - # to avoid reactor complaints - [p.setTimeout(None) for p in self.instances if p.timeOut is not None] - policies.LimitTotalConnectionsFactory.stopFactory(self) - -# -- Cred Objects -- - - -class IFTPShell(Interface): - """ - An abstraction of the shell commands used by the FTP protocol for - a given user account. - - All path names must be absolute. - """ - - def makeDirectory(path): - """ - Create a directory. - - @param path: The path, as a list of segments, to create - @type path: C{list} of C{unicode} - - @return: A Deferred which fires when the directory has been - created, or which fails if the directory cannot be created. - """ - - - def removeDirectory(path): - """ - Remove a directory. - - @param path: The path, as a list of segments, to remove - @type path: C{list} of C{unicode} - - @return: A Deferred which fires when the directory has been - removed, or which fails if the directory cannot be removed. - """ - - - def removeFile(path): - """ - Remove a file. - - @param path: The path, as a list of segments, to remove - @type path: C{list} of C{unicode} - - @return: A Deferred which fires when the file has been - removed, or which fails if the file cannot be removed. - """ - - - def rename(fromPath, toPath): - """ - Rename a file or directory. - - @param fromPath: The current name of the path. - @type fromPath: C{list} of C{unicode} - - @param toPath: The desired new name of the path. - @type toPath: C{list} of C{unicode} - - @return: A Deferred which fires when the path has been - renamed, or which fails if the path cannot be renamed. - """ - - - def access(path): - """ - Determine whether access to the given path is allowed. - - @param path: The path, as a list of segments - - @return: A Deferred which fires with None if access is allowed - or which fails with a specific exception type if access is - denied. - """ - - - def stat(path, keys=()): - """ - Retrieve information about the given path. - - This is like list, except it will never return results about - child paths. - """ - - - def list(path, keys=()): - """ - Retrieve information about the given path. - - If the path represents a non-directory, the result list should - have only one entry with information about that non-directory. - Otherwise, the result list should have an element for each - child of the directory. - - @param path: The path, as a list of segments, to list - @type path: C{list} of C{unicode} - - @param keys: A tuple of keys desired in the resulting - dictionaries. - - @return: A Deferred which fires with a list of (name, list), - where the name is the name of the entry as a unicode string - and each list contains values corresponding to the requested - keys. The following are possible elements of keys, and the - values which should be returned for them: - - - C{'size'}: size in bytes, as an integer (this is kinda required) - - - C{'directory'}: boolean indicating the type of this entry - - - C{'permissions'}: a bitvector (see os.stat(foo).st_mode) - - - C{'hardlinks'}: Number of hard links to this entry - - - C{'modified'}: number of seconds since the epoch since entry was - modified - - - C{'owner'}: string indicating the user owner of this entry - - - C{'group'}: string indicating the group owner of this entry - """ - - - def openForReading(path): - """ - @param path: The path, as a list of segments, to open - @type path: C{list} of C{unicode} - - @rtype: C{Deferred} which will fire with L{IReadFile} - """ - - - def openForWriting(path): - """ - @param path: The path, as a list of segments, to open - @type path: C{list} of C{unicode} - - @rtype: C{Deferred} which will fire with L{IWriteFile} - """ - - - -class IReadFile(Interface): - """ - A file out of which bytes may be read. - """ - - def send(consumer): - """ - Produce the contents of the given path to the given consumer. This - method may only be invoked once on each provider. - - @type consumer: C{IConsumer} - - @return: A Deferred which fires when the file has been - consumed completely. - """ - - - -class IWriteFile(Interface): - """ - A file into which bytes may be written. - """ - - def receive(): - """ - Create a consumer which will write to this file. This method may - only be invoked once on each provider. - - @rtype: C{Deferred} of C{IConsumer} - """ - - - -def _getgroups(uid): - """Return the primary and supplementary groups for the given UID. - - @type uid: C{int} - """ - result = [] - pwent = pwd.getpwuid(uid) - - result.append(pwent.pw_gid) - - for grent in grp.getgrall(): - if pwent.pw_name in grent.gr_mem: - result.append(grent.gr_gid) - - return result - - -def _testPermissions(uid, gid, spath, mode='r'): - """ - checks to see if uid has proper permissions to access path with mode - - @type uid: C{int} - @param uid: numeric user id - - @type gid: C{int} - @param gid: numeric group id - - @type spath: C{str} - @param spath: the path on the server to test - - @type mode: C{str} - @param mode: 'r' or 'w' (read or write) - - @rtype: C{bool} - @return: True if the given credentials have the specified form of - access to the given path - """ - if mode == 'r': - usr = stat.S_IRUSR - grp = stat.S_IRGRP - oth = stat.S_IROTH - amode = os.R_OK - elif mode == 'w': - usr = stat.S_IWUSR - grp = stat.S_IWGRP - oth = stat.S_IWOTH - amode = os.W_OK - else: - raise ValueError("Invalid mode %r: must specify 'r' or 'w'" % (mode,)) - - access = False - if os.path.exists(spath): - if uid == 0: - access = True - else: - s = os.stat(spath) - if usr & s.st_mode and uid == s.st_uid: - access = True - elif grp & s.st_mode and gid in _getgroups(uid): - access = True - elif oth & s.st_mode: - access = True - - if access: - if not os.access(spath, amode): - access = False - log.msg("Filesystem grants permission to UID %d but it is inaccessible to me running as UID %d" % ( - uid, os.getuid())) - return access - - - -class FTPAnonymousShell(object): - """ - An anonymous implementation of IFTPShell - - @type filesystemRoot: L{twisted.python.filepath.FilePath} - @ivar filesystemRoot: The path which is considered the root of - this shell. - """ - implements(IFTPShell) - - def __init__(self, filesystemRoot): - self.filesystemRoot = filesystemRoot - - - def _path(self, path): - return reduce(filepath.FilePath.child, path, self.filesystemRoot) - - - def makeDirectory(self, path): - return defer.fail(AnonUserDeniedError()) - - - def removeDirectory(self, path): - return defer.fail(AnonUserDeniedError()) - - - def removeFile(self, path): - return defer.fail(AnonUserDeniedError()) - - - def rename(self, fromPath, toPath): - return defer.fail(AnonUserDeniedError()) - - - def receive(self, path): - path = self._path(path) - return defer.fail(AnonUserDeniedError()) - - - def openForReading(self, path): - p = self._path(path) - if p.isdir(): - # Normally, we would only check for EISDIR in open, but win32 - # returns EACCES in this case, so we check before - return defer.fail(IsADirectoryError(path)) - try: - f = p.open('rb') - except (IOError, OSError), e: - return errnoToFailure(e.errno, path) - except: - return defer.fail() - else: - return defer.succeed(_FileReader(f)) - - - def openForWriting(self, path): - """ - Reject write attempts by anonymous users with - L{PermissionDeniedError}. - """ - return defer.fail(PermissionDeniedError("STOR not allowed")) - - - def access(self, path): - p = self._path(path) - if not p.exists(): - # Again, win32 doesn't report a sane error after, so let's fail - # early if we can - return defer.fail(FileNotFoundError(path)) - # For now, just see if we can os.listdir() it - try: - p.listdir() - except (IOError, OSError), e: - return errnoToFailure(e.errno, path) - except: - return defer.fail() - else: - return defer.succeed(None) - - - def stat(self, path, keys=()): - p = self._path(path) - if p.isdir(): - try: - statResult = self._statNode(p, keys) - except (IOError, OSError), e: - return errnoToFailure(e.errno, path) - except: - return defer.fail() - else: - return defer.succeed(statResult) - else: - return self.list(path, keys).addCallback(lambda res: res[0][1]) - - - def list(self, path, keys=()): - """ - Return the list of files at given C{path}, adding C{keys} stat - informations if specified. - - @param path: the directory or file to check. - @type path: C{str} - - @param keys: the list of desired metadata - @type keys: C{list} of C{str} - """ - filePath = self._path(path) - if filePath.isdir(): - entries = filePath.listdir() - fileEntries = [filePath.child(p) for p in entries] - elif filePath.isfile(): - entries = [os.path.join(*filePath.segmentsFrom(self.filesystemRoot))] - fileEntries = [filePath] - else: - return defer.fail(FileNotFoundError(path)) - - results = [] - for fileName, filePath in zip(entries, fileEntries): - ent = [] - results.append((fileName, ent)) - if keys: - try: - ent.extend(self._statNode(filePath, keys)) - except (IOError, OSError), e: - return errnoToFailure(e.errno, fileName) - except: - return defer.fail() - - return defer.succeed(results) - - - def _statNode(self, filePath, keys): - """ - Shortcut method to get stat info on a node. - - @param filePath: the node to stat. - @type filePath: C{filepath.FilePath} - - @param keys: the stat keys to get. - @type keys: C{iterable} - """ - filePath.restat() - return [getattr(self, '_stat_' + k)(filePath.statinfo) for k in keys] - - _stat_size = operator.attrgetter('st_size') - _stat_permissions = operator.attrgetter('st_mode') - _stat_hardlinks = operator.attrgetter('st_nlink') - _stat_modified = operator.attrgetter('st_mtime') - - - def _stat_owner(self, st): - if pwd is not None: - try: - return pwd.getpwuid(st.st_uid)[0] - except KeyError: - pass - return str(st.st_uid) - - - def _stat_group(self, st): - if grp is not None: - try: - return grp.getgrgid(st.st_gid)[0] - except KeyError: - pass - return str(st.st_gid) - - - def _stat_directory(self, st): - return bool(st.st_mode & stat.S_IFDIR) - - - -class _FileReader(object): - implements(IReadFile) - - def __init__(self, fObj): - self.fObj = fObj - self._send = False - - def _close(self, passthrough): - self._send = True - self.fObj.close() - return passthrough - - def send(self, consumer): - assert not self._send, "Can only call IReadFile.send *once* per instance" - self._send = True - d = basic.FileSender().beginFileTransfer(self.fObj, consumer) - d.addBoth(self._close) - return d - - - -class FTPShell(FTPAnonymousShell): - """ - An authenticated implementation of L{IFTPShell}. - """ - - def makeDirectory(self, path): - p = self._path(path) - try: - p.makedirs() - except (IOError, OSError), e: - return errnoToFailure(e.errno, path) - except: - return defer.fail() - else: - return defer.succeed(None) - - - def removeDirectory(self, path): - p = self._path(path) - if p.isfile(): - # Win32 returns the wrong errno when rmdir is called on a file - # instead of a directory, so as we have the info here, let's fail - # early with a pertinent error - return defer.fail(IsNotADirectoryError(path)) - try: - os.rmdir(p.path) - except (IOError, OSError), e: - return errnoToFailure(e.errno, path) - except: - return defer.fail() - else: - return defer.succeed(None) - - - def removeFile(self, path): - p = self._path(path) - if p.isdir(): - # Win32 returns the wrong errno when remove is called on a - # directory instead of a file, so as we have the info here, - # let's fail early with a pertinent error - return defer.fail(IsADirectoryError(path)) - try: - p.remove() - except (IOError, OSError), e: - return errnoToFailure(e.errno, path) - except: - return defer.fail() - else: - return defer.succeed(None) - - - def rename(self, fromPath, toPath): - fp = self._path(fromPath) - tp = self._path(toPath) - try: - os.rename(fp.path, tp.path) - except (IOError, OSError), e: - return errnoToFailure(e.errno, fromPath) - except: - return defer.fail() - else: - return defer.succeed(None) - - - def openForWriting(self, path): - p = self._path(path) - if p.isdir(): - # Normally, we would only check for EISDIR in open, but win32 - # returns EACCES in this case, so we check before - return defer.fail(IsADirectoryError(path)) - try: - fObj = p.open('wb') - except (IOError, OSError), e: - return errnoToFailure(e.errno, path) - except: - return defer.fail() - return defer.succeed(_FileWriter(fObj)) - - - -class _FileWriter(object): - implements(IWriteFile) - - def __init__(self, fObj): - self.fObj = fObj - self._receive = False - - def receive(self): - assert not self._receive, "Can only call IWriteFile.receive *once* per instance" - self._receive = True - # FileConsumer will close the file object - return defer.succeed(FileConsumer(self.fObj)) - - - -class FTPRealm: - """ - @type anonymousRoot: L{twisted.python.filepath.FilePath} - @ivar anonymousRoot: Root of the filesystem to which anonymous - users will be granted access. - """ - implements(portal.IRealm) - - def __init__(self, anonymousRoot): - self.anonymousRoot = filepath.FilePath(anonymousRoot) - - def requestAvatar(self, avatarId, mind, *interfaces): - for iface in interfaces: - if iface is IFTPShell: - if avatarId is checkers.ANONYMOUS: - avatar = FTPAnonymousShell(self.anonymousRoot) - else: - avatar = FTPShell(filepath.FilePath("/home/" + avatarId)) - return IFTPShell, avatar, getattr(avatar, 'logout', lambda: None) - raise NotImplementedError("Only IFTPShell interface is supported by this realm") - -# --- FTP CLIENT ------------------------------------------------------------- - -#### -# And now for the client... - -# Notes: -# * Reference: http://cr.yp.to/ftp.html -# * FIXME: Does not support pipelining (which is not supported by all -# servers anyway). This isn't a functionality limitation, just a -# small performance issue. -# * Only has a rudimentary understanding of FTP response codes (although -# the full response is passed to the caller if they so choose). -# * Assumes that USER and PASS should always be sent -# * Always sets TYPE I (binary mode) -# * Doesn't understand any of the weird, obscure TELNET stuff (\377...) -# * FIXME: Doesn't share any code with the FTPServer - -class ConnectionLost(FTPError): - pass - -class CommandFailed(FTPError): - pass - -class BadResponse(FTPError): - pass - -class UnexpectedResponse(FTPError): - pass - -class UnexpectedData(FTPError): - pass - -class FTPCommand: - def __init__(self, text=None, public=0): - self.text = text - self.deferred = defer.Deferred() - self.ready = 1 - self.public = public - self.transferDeferred = None - - def fail(self, failure): - if self.public: - self.deferred.errback(failure) - - -class ProtocolWrapper(protocol.Protocol): - def __init__(self, original, deferred): - self.original = original - self.deferred = deferred - def makeConnection(self, transport): - self.original.makeConnection(transport) - def dataReceived(self, data): - self.original.dataReceived(data) - def connectionLost(self, reason): - self.original.connectionLost(reason) - # Signal that transfer has completed - self.deferred.callback(None) - - -class SenderProtocol(protocol.Protocol): - implements(interfaces.IFinishableConsumer) - - def __init__(self): - # Fired upon connection - self.connectedDeferred = defer.Deferred() - - # Fired upon disconnection - self.deferred = defer.Deferred() - - #Protocol stuff - def dataReceived(self, data): - raise UnexpectedData( - "Received data from the server on a " - "send-only data-connection" - ) - - def makeConnection(self, transport): - protocol.Protocol.makeConnection(self, transport) - self.connectedDeferred.callback(self) - - def connectionLost(self, reason): - if reason.check(error.ConnectionDone): - self.deferred.callback('connection done') - else: - self.deferred.errback(reason) - - #IFinishableConsumer stuff - def write(self, data): - self.transport.write(data) - - def registerProducer(self, producer, streaming): - """ - Register the given producer with our transport. - """ - self.transport.registerProducer(producer, streaming) - - def unregisterProducer(self): - """ - Unregister the previously registered producer. - """ - self.transport.unregisterProducer() - - def finish(self): - self.transport.loseConnection() - - -def decodeHostPort(line): - """Decode an FTP response specifying a host and port. - - @return: a 2-tuple of (host, port). - """ - abcdef = re.sub('[^0-9, ]', '', line) - parsed = [int(p.strip()) for p in abcdef.split(',')] - for x in parsed: - if x < 0 or x > 255: - raise ValueError("Out of range", line, x) - a, b, c, d, e, f = parsed - host = "%s.%s.%s.%s" % (a, b, c, d) - port = (int(e) << 8) + int(f) - return host, port - -def encodeHostPort(host, port): - numbers = host.split('.') + [str(port >> 8), str(port % 256)] - return ','.join(numbers) - -def _unwrapFirstError(failure): - failure.trap(defer.FirstError) - return failure.value.subFailure - -class FTPDataPortFactory(protocol.ServerFactory): - """Factory for data connections that use the PORT command - - (i.e. "active" transfers) - """ - noisy = 0 - def buildProtocol(self, addr): - # This is a bit hackish -- we already have a Protocol instance, - # so just return it instead of making a new one - # FIXME: Reject connections from the wrong address/port - # (potential security problem) - self.protocol.factory = self - self.port.loseConnection() - return self.protocol - - -class FTPClientBasic(basic.LineReceiver): - """ - Foundations of an FTP client. - """ - debug = False - - def __init__(self): - self.actionQueue = [] - self.greeting = None - self.nextDeferred = defer.Deferred().addCallback(self._cb_greeting) - self.nextDeferred.addErrback(self.fail) - self.response = [] - self._failed = 0 - - def fail(self, error): - """ - Give an error to any queued deferreds. - """ - self._fail(error) - - def _fail(self, error): - """ - Errback all queued deferreds. - """ - if self._failed: - # We're recursing; bail out here for simplicity - return error - self._failed = 1 - if self.nextDeferred: - try: - self.nextDeferred.errback(failure.Failure(ConnectionLost('FTP connection lost', error))) - except defer.AlreadyCalledError: - pass - for ftpCommand in self.actionQueue: - ftpCommand.fail(failure.Failure(ConnectionLost('FTP connection lost', error))) - return error - - def _cb_greeting(self, greeting): - self.greeting = greeting - - def sendLine(self, line): - """ - (Private) Sends a line, unless line is None. - """ - if line is None: - return - basic.LineReceiver.sendLine(self, line) - - def sendNextCommand(self): - """ - (Private) Processes the next command in the queue. - """ - ftpCommand = self.popCommandQueue() - if ftpCommand is None: - self.nextDeferred = None - return - if not ftpCommand.ready: - self.actionQueue.insert(0, ftpCommand) - reactor.callLater(1.0, self.sendNextCommand) - self.nextDeferred = None - return - - # FIXME: this if block doesn't belong in FTPClientBasic, it belongs in - # FTPClient. - if ftpCommand.text == 'PORT': - self.generatePortCommand(ftpCommand) - - if self.debug: - log.msg('<-- %s' % ftpCommand.text) - self.nextDeferred = ftpCommand.deferred - self.sendLine(ftpCommand.text) - - def queueCommand(self, ftpCommand): - """ - Add an FTPCommand object to the queue. - - If it's the only thing in the queue, and we are connected and we aren't - waiting for a response of an earlier command, the command will be sent - immediately. - - @param ftpCommand: an L{FTPCommand} - """ - self.actionQueue.append(ftpCommand) - if (len(self.actionQueue) == 1 and self.transport is not None and - self.nextDeferred is None): - self.sendNextCommand() - - def queueStringCommand(self, command, public=1): - """ - Queues a string to be issued as an FTP command - - @param command: string of an FTP command to queue - @param public: a flag intended for internal use by FTPClient. Don't - change it unless you know what you're doing. - - @return: a L{Deferred} that will be called when the response to the - command has been received. - """ - ftpCommand = FTPCommand(command, public) - self.queueCommand(ftpCommand) - return ftpCommand.deferred - - def popCommandQueue(self): - """ - Return the front element of the command queue, or None if empty. - """ - if self.actionQueue: - return self.actionQueue.pop(0) - else: - return None - - def queueLogin(self, username, password): - """ - Login: send the username, send the password. - - If the password is C{None}, the PASS command won't be sent. Also, if - the response to the USER command has a response code of 230 (User logged - in), then PASS won't be sent either. - """ - # Prepare the USER command - deferreds = [] - userDeferred = self.queueStringCommand('USER ' + username, public=0) - deferreds.append(userDeferred) - - # Prepare the PASS command (if a password is given) - if password is not None: - passwordCmd = FTPCommand('PASS ' + password, public=0) - self.queueCommand(passwordCmd) - deferreds.append(passwordCmd.deferred) - - # Avoid sending PASS if the response to USER is 230. - # (ref: http://cr.yp.to/ftp/user.html#user) - def cancelPasswordIfNotNeeded(response): - if response[0].startswith('230'): - # No password needed! - self.actionQueue.remove(passwordCmd) - return response - userDeferred.addCallback(cancelPasswordIfNotNeeded) - - # Error handling. - for deferred in deferreds: - # If something goes wrong, call fail - deferred.addErrback(self.fail) - # But also swallow the error, so we don't cause spurious errors - deferred.addErrback(lambda x: None) - - def lineReceived(self, line): - """ - (Private) Parses the response messages from the FTP server. - """ - # Add this line to the current response - if self.debug: - log.msg('--> %s' % line) - self.response.append(line) - - # Bail out if this isn't the last line of a response - # The last line of response starts with 3 digits followed by a space - codeIsValid = re.match(r'\d{3} ', line) - if not codeIsValid: - return - - code = line[0:3] - - # Ignore marks - if code[0] == '1': - return - - # Check that we were expecting a response - if self.nextDeferred is None: - self.fail(UnexpectedResponse(self.response)) - return - - # Reset the response - response = self.response - self.response = [] - - # Look for a success or error code, and call the appropriate callback - if code[0] in ('2', '3'): - # Success - self.nextDeferred.callback(response) - elif code[0] in ('4', '5'): - # Failure - self.nextDeferred.errback(failure.Failure(CommandFailed(response))) - else: - # This shouldn't happen unless something screwed up. - log.msg('Server sent invalid response code %s' % (code,)) - self.nextDeferred.errback(failure.Failure(BadResponse(response))) - - # Run the next command - self.sendNextCommand() - - def connectionLost(self, reason): - self._fail(reason) - - - -class _PassiveConnectionFactory(protocol.ClientFactory): - noisy = False - - def __init__(self, protoInstance): - self.protoInstance = protoInstance - - def buildProtocol(self, ignored): - self.protoInstance.factory = self - return self.protoInstance - - def clientConnectionFailed(self, connector, reason): - e = FTPError('Connection Failed', reason) - self.protoInstance.deferred.errback(e) - - - -class FTPClient(FTPClientBasic): - """ - A Twisted FTP Client - - Supports active and passive transfers. - - @ivar passive: See description in __init__. - """ - connectFactory = reactor.connectTCP - - def __init__(self, username='anonymous', - password='twisted@twistedmatrix.com', - passive=1): - """ - Constructor. - - I will login as soon as I receive the welcome message from the server. - - @param username: FTP username - @param password: FTP password - @param passive: flag that controls if I use active or passive data - connections. You can also change this after construction by - assigning to self.passive. - """ - FTPClientBasic.__init__(self) - self.queueLogin(username, password) - - self.passive = passive - - def fail(self, error): - """ - Disconnect, and also give an error to any queued deferreds. - """ - self.transport.loseConnection() - self._fail(error) - - def receiveFromConnection(self, commands, protocol): - """ - Retrieves a file or listing generated by the given command, - feeding it to the given protocol. - - @param command: list of strings of FTP commands to execute then receive - the results of (e.g. LIST, RETR) - @param protocol: A L{Protocol} *instance* e.g. an - L{FTPFileListProtocol}, or something that can be adapted to one. - Typically this will be an L{IConsumer} implemenation. - - @return: L{Deferred}. - """ - protocol = interfaces.IProtocol(protocol) - wrapper = ProtocolWrapper(protocol, defer.Deferred()) - return self._openDataConnection(commands, wrapper) - - def queueLogin(self, username, password): - """ - Login: send the username, send the password, and - set retrieval mode to binary - """ - FTPClientBasic.queueLogin(self, username, password) - d = self.queueStringCommand('TYPE I', public=0) - # If something goes wrong, call fail - d.addErrback(self.fail) - # But also swallow the error, so we don't cause spurious errors - d.addErrback(lambda x: None) - - def sendToConnection(self, commands): - """ - XXX - - @return: A tuple of two L{Deferred}s: - - L{Deferred} L{IFinishableConsumer}. You must call - the C{finish} method on the IFinishableConsumer when the file - is completely transferred. - - L{Deferred} list of control-connection responses. - """ - s = SenderProtocol() - r = self._openDataConnection(commands, s) - return (s.connectedDeferred, r) - - def _openDataConnection(self, commands, protocol): - """ - This method returns a DeferredList. - """ - cmds = [FTPCommand(command, public=1) for command in commands] - cmdsDeferred = defer.DeferredList([cmd.deferred for cmd in cmds], - fireOnOneErrback=True, consumeErrors=True) - cmdsDeferred.addErrback(_unwrapFirstError) - - if self.passive: - # Hack: use a mutable object to sneak a variable out of the - # scope of doPassive - _mutable = [None] - def doPassive(response): - """Connect to the port specified in the response to PASV""" - host, port = decodeHostPort(response[-1][4:]) - - f = _PassiveConnectionFactory(protocol) - _mutable[0] = self.connectFactory(host, port, f) - - pasvCmd = FTPCommand('PASV') - self.queueCommand(pasvCmd) - pasvCmd.deferred.addCallback(doPassive).addErrback(self.fail) - - results = [cmdsDeferred, pasvCmd.deferred, protocol.deferred] - d = defer.DeferredList(results, fireOnOneErrback=True, consumeErrors=True) - d.addErrback(_unwrapFirstError) - - # Ensure the connection is always closed - def close(x, m=_mutable): - m[0] and m[0].disconnect() - return x - d.addBoth(close) - - else: - # We just place a marker command in the queue, and will fill in - # the host and port numbers later (see generatePortCommand) - portCmd = FTPCommand('PORT') - - # Ok, now we jump through a few hoops here. - # This is the problem: a transfer is not to be trusted as complete - # until we get both the "226 Transfer complete" message on the - # control connection, and the data socket is closed. Thus, we use - # a DeferredList to make sure we only fire the callback at the - # right time. - - portCmd.transferDeferred = protocol.deferred - portCmd.protocol = protocol - portCmd.deferred.addErrback(portCmd.transferDeferred.errback) - self.queueCommand(portCmd) - - # Create dummy functions for the next callback to call. - # These will also be replaced with real functions in - # generatePortCommand. - portCmd.loseConnection = lambda result: result - portCmd.fail = lambda error: error - - # Ensure that the connection always gets closed - cmdsDeferred.addErrback(lambda e, pc=portCmd: pc.fail(e) or e) - - results = [cmdsDeferred, portCmd.deferred, portCmd.transferDeferred] - d = defer.DeferredList(results, fireOnOneErrback=True, consumeErrors=True) - d.addErrback(_unwrapFirstError) - - for cmd in cmds: - self.queueCommand(cmd) - return d - - def generatePortCommand(self, portCmd): - """ - (Private) Generates the text of a given PORT command. - """ - - # The problem is that we don't create the listening port until we need - # it for various reasons, and so we have to muck about to figure out - # what interface and port it's listening on, and then finally we can - # create the text of the PORT command to send to the FTP server. - - # FIXME: This method is far too ugly. - - # FIXME: The best solution is probably to only create the data port - # once per FTPClient, and just recycle it for each new download. - # This should be ok, because we don't pipeline commands. - - # Start listening on a port - factory = FTPDataPortFactory() - factory.protocol = portCmd.protocol - listener = reactor.listenTCP(0, factory) - factory.port = listener - - # Ensure we close the listening port if something goes wrong - def listenerFail(error, listener=listener): - if listener.connected: - listener.loseConnection() - return error - portCmd.fail = listenerFail - - # Construct crufty FTP magic numbers that represent host & port - host = self.transport.getHost().host - port = listener.getHost().port - portCmd.text = 'PORT ' + encodeHostPort(host, port) - - def escapePath(self, path): - """ - Returns a FTP escaped path (replace newlines with nulls). - """ - # Escape newline characters - return path.replace('\n', '\0') - - def retrieveFile(self, path, protocol, offset=0): - """ - Retrieve a file from the given path - - This method issues the 'RETR' FTP command. - - The file is fed into the given Protocol instance. The data connection - will be passive if self.passive is set. - - @param path: path to file that you wish to receive. - @param protocol: a L{Protocol} instance. - @param offset: offset to start downloading from - - @return: L{Deferred} - """ - cmds = ['RETR ' + self.escapePath(path)] - if offset: - cmds.insert(0, ('REST ' + str(offset))) - return self.receiveFromConnection(cmds, protocol) - - retr = retrieveFile - - def storeFile(self, path, offset=0): - """ - Store a file at the given path. - - This method issues the 'STOR' FTP command. - - @return: A tuple of two L{Deferred}s: - - L{Deferred} L{IFinishableConsumer}. You must call - the C{finish} method on the IFinishableConsumer when the file - is completely transferred. - - L{Deferred} list of control-connection responses. - """ - cmds = ['STOR ' + self.escapePath(path)] - if offset: - cmds.insert(0, ('REST ' + str(offset))) - return self.sendToConnection(cmds) - - stor = storeFile - - def list(self, path, protocol): - """ - Retrieve a file listing into the given protocol instance. - - This method issues the 'LIST' FTP command. - - @param path: path to get a file listing for. - @param protocol: a L{Protocol} instance, probably a - L{FTPFileListProtocol} instance. It can cope with most common file - listing formats. - - @return: L{Deferred} - """ - if path is None: - path = '' - return self.receiveFromConnection(['LIST ' + self.escapePath(path)], protocol) - - def nlst(self, path, protocol): - """ - Retrieve a short file listing into the given protocol instance. - - This method issues the 'NLST' FTP command. - - NLST (should) return a list of filenames, one per line. - - @param path: path to get short file listing for. - @param protocol: a L{Protocol} instance. - """ - if path is None: - path = '' - return self.receiveFromConnection(['NLST ' + self.escapePath(path)], protocol) - - def cwd(self, path): - """ - Issues the CWD (Change Working Directory) command. It's also - available as changeDirectory, which parses the result. - - @return: a L{Deferred} that will be called when done. - """ - return self.queueStringCommand('CWD ' + self.escapePath(path)) - - def changeDirectory(self, path): - """ - Change the directory on the server and parse the result to determine - if it was successful or not. - - @type path: C{str} - @param path: The path to which to change. - - @return: a L{Deferred} which will be called back when the directory - change has succeeded or and errbacked if an error occurrs. - """ - def cbParse(result): - try: - # The only valid code is 250 - if int(result[0].split(' ', 1)[0]) == 250: - return True - else: - raise ValueError - except (IndexError, ValueError), e: - return failure.Failure(CommandFailed(result)) - return self.cwd(path).addCallback(cbParse) - - def cdup(self): - """ - Issues the CDUP (Change Directory UP) command. - - @return: a L{Deferred} that will be called when done. - """ - return self.queueStringCommand('CDUP') - - def pwd(self): - """ - Issues the PWD (Print Working Directory) command. - - The L{getDirectory} does the same job but automatically parses the - result. - - @return: a L{Deferred} that will be called when done. It is up to the - caller to interpret the response, but the L{parsePWDResponse} method - in this module should work. - """ - return self.queueStringCommand('PWD') - - def getDirectory(self): - """ - Returns the current remote directory. - - @return: a L{Deferred} that will be called back with a C{str} giving - the remote directory or which will errback with L{CommandFailed} - if an error response is returned. - """ - def cbParse(result): - try: - # The only valid code is 257 - if int(result[0].split(' ', 1)[0]) != 257: - raise ValueError - except (IndexError, ValueError), e: - return failure.Failure(CommandFailed(result)) - path = parsePWDResponse(result[0]) - if path is None: - return failure.Failure(CommandFailed(result)) - return path - return self.pwd().addCallback(cbParse) - - def quit(self): - """ - Issues the QUIT command. - """ - return self.queueStringCommand('QUIT') - - -class FTPFileListProtocol(basic.LineReceiver): - """Parser for standard FTP file listings - - This is the evil required to match:: - - -rw-r--r-- 1 root other 531 Jan 29 03:26 README - - If you need different evil for a wacky FTP server, you can - override either C{fileLinePattern} or C{parseDirectoryLine()}. - - It populates the instance attribute self.files, which is a list containing - dicts with the following keys (examples from the above line): - - filetype: e.g. 'd' for directories, or '-' for an ordinary file - - perms: e.g. 'rw-r--r--' - - nlinks: e.g. 1 - - owner: e.g. 'root' - - group: e.g. 'other' - - size: e.g. 531 - - date: e.g. 'Jan 29 03:26' - - filename: e.g. 'README' - - linktarget: e.g. 'some/file' - - Note that the 'date' value will be formatted differently depending on the - date. Check U{http://cr.yp.to/ftp.html} if you really want to try to parse - it. - - @ivar files: list of dicts describing the files in this listing - """ - fileLinePattern = re.compile( - r'^(?P.)(?P.{9})\s+(?P\d*)\s*' - r'(?P\S+)\s+(?P\S+)\s+(?P\d+)\s+' - r'(?P...\s+\d+\s+[\d:]+)\s+(?P([^ ]|\\ )*?)' - r'( -> (?P[^\r]*))?\r?$' - ) - delimiter = '\n' - - def __init__(self): - self.files = [] - - def lineReceived(self, line): - d = self.parseDirectoryLine(line) - if d is None: - self.unknownLine(line) - else: - self.addFile(d) - - def parseDirectoryLine(self, line): - """Return a dictionary of fields, or None if line cannot be parsed. - - @param line: line of text expected to contain a directory entry - @type line: str - - @return: dict - """ - match = self.fileLinePattern.match(line) - if match is None: - return None - else: - d = match.groupdict() - d['filename'] = d['filename'].replace(r'\ ', ' ') - d['nlinks'] = int(d['nlinks']) - d['size'] = int(d['size']) - if d['linktarget']: - d['linktarget'] = d['linktarget'].replace(r'\ ', ' ') - return d - - def addFile(self, info): - """Append file information dictionary to the list of known files. - - Subclasses can override or extend this method to handle file - information differently without affecting the parsing of data - from the server. - - @param info: dictionary containing the parsed representation - of the file information - @type info: dict - """ - self.files.append(info) - - def unknownLine(self, line): - """Deal with received lines which could not be parsed as file - information. - - Subclasses can override this to perform any special processing - needed. - - @param line: unparsable line as received - @type line: str - """ - pass - -def parsePWDResponse(response): - """Returns the path from a response to a PWD command. - - Responses typically look like:: - - 257 "/home/andrew" is current directory. - - For this example, I will return C{'/home/andrew'}. - - If I can't find the path, I return C{None}. - """ - match = re.search('"(.*)"', response) - if match: - return match.groups()[0] - else: - return None diff --git a/tools/buildbot/pylibs/twisted/protocols/gps/__init__.py b/tools/buildbot/pylibs/twisted/protocols/gps/__init__.py deleted file mode 100644 index 278648c..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/gps/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Global Positioning System protocols.""" diff --git a/tools/buildbot/pylibs/twisted/protocols/gps/nmea.py b/tools/buildbot/pylibs/twisted/protocols/gps/nmea.py deleted file mode 100644 index 74e487e..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/gps/nmea.py +++ /dev/null @@ -1,208 +0,0 @@ -# -*- test-case-name: twisted.test.test_nmea -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -"""NMEA 0183 implementation - -Maintainer: U{Bob Ippolito} - -The following NMEA 0183 sentences are currently understood:: - GPGGA (fix) - GPGLL (position) - GPRMC (position and time) - GPGSA (active satellites) - -The following NMEA 0183 sentences require implementation:: - None really, the others aren't generally useful or implemented in most devices anyhow - -Other desired features:: - - A NMEA 0183 producer to emulate GPS devices (?) -""" - -import operator -from twisted.protocols import basic - -POSFIX_INVALID, POSFIX_SPS, POSFIX_DGPS, POSFIX_PPS = 0, 1, 2, 3 -MODE_AUTO, MODE_FORCED = 'A', 'M' -MODE_NOFIX, MODE_2D, MODE_3D = 1, 2, 3 - -class InvalidSentence(Exception): - pass - -class InvalidChecksum(Exception): - pass - -class NMEAReceiver(basic.LineReceiver): - """This parses most common NMEA-0183 messages, presumably from a serial GPS device at 4800 bps - """ - delimiter = '\r\n' - dispatch = { - 'GPGGA': 'fix', - 'GPGLL': 'position', - 'GPGSA': 'activesatellites', - 'GPRMC': 'positiontime', - 'GPGSV': 'viewsatellites', # not implemented - 'GPVTG': 'course', # not implemented - 'GPALM': 'almanac', # not implemented - 'GPGRS': 'range', # not implemented - 'GPGST': 'noise', # not implemented - 'GPMSS': 'beacon', # not implemented - 'GPZDA': 'time', # not implemented - } - # generally you may miss the beginning of the first message - ignore_invalid_sentence = 1 - # checksums shouldn't be invalid - ignore_checksum_mismatch = 0 - # ignore unknown sentence types - ignore_unknown_sentencetypes = 0 - # do we want to even bother checking to see if it's from the 20th century? - convert_dates_before_y2k = 1 - - def lineReceived(self, line): - if not line.startswith('$'): - if self.ignore_invalid_sentence: - return - raise InvalidSentence("%r does not begin with $" % (line,)) - # message is everything between $ and *, checksum is xor of all ASCII values of the message - strmessage, checksum = line[1:].strip().split('*') - message = strmessage.split(',') - sentencetype, message = message[0], message[1:] - dispatch = self.dispatch.get(sentencetype, None) - if (not dispatch) and (not self.ignore_unknown_sentencetypes): - raise InvalidSentence("sentencetype %r" % (sentencetype,)) - if not self.ignore_checksum_mismatch: - checksum, calculated_checksum = int(checksum, 16), reduce(operator.xor, map(ord, strmessage)) - if checksum != calculated_checksum: - raise InvalidChecksum("Given 0x%02X != 0x%02X" % (checksum, calculated_checksum)) - handler = getattr(self, "handle_%s" % dispatch, None) - decoder = getattr(self, "decode_%s" % dispatch, None) - if not (dispatch and handler and decoder): - # missing dispatch, handler, or decoder - return - # return handler(*decoder(*message)) - try: - decoded = decoder(*message) - except Exception, e: - raise InvalidSentence("%r is not a valid %s (%s) sentence" % (line, sentencetype, dispatch)) - return handler(*decoded) - - def decode_position(self, latitude, ns, longitude, ew, utc, status): - latitude, longitude = self._decode_latlon(latitude, ns, longitude, ew) - utc = self._decode_utc(utc) - if status == 'A': - status = 1 - else: - status = 0 - return ( - latitude, - longitude, - utc, - status, - ) - - def decode_positiontime(self, utc, status, latitude, ns, longitude, ew, speed, course, utcdate, magvar, magdir): - utc = self._decode_utc(utc) - latitude, longitude = self._decode_latlon(latitude, ns, longitude, ew) - if speed != '': - speed = float(speed) - else: - speed = None - if course != '': - course = float(course) - else: - course = None - utcdate = 2000+int(utcdate[4:6]), int(utcdate[2:4]), int(utcdate[0:2]) - if self.convert_dates_before_y2k and utcdate[0] > 2073: - # GPS was invented by the US DoD in 1973, but NMEA uses 2 digit year. - # Highly unlikely that we'll be using NMEA or this twisted module in 70 years, - # but remotely possible that you'll be using it to play back data from the 20th century. - utcdate = (utcdate[0] - 100, utcdate[1], utcdate[2]) - if magvar != '': - magvar = float(magvar) - if magdir == 'W': - magvar = -magvar - else: - magvar = None - return ( - latitude, - longitude, - speed, - course, - # UTC seconds past utcdate - utc, - # UTC (year, month, day) - utcdate, - # None or magnetic variation in degrees (west is negative) - magvar, - ) - - def _decode_utc(self, utc): - utc_hh, utc_mm, utc_ss = map(float, (utc[:2], utc[2:4], utc[4:])) - return utc_hh * 3600.0 + utc_mm * 60.0 + utc_ss - - def _decode_latlon(self, latitude, ns, longitude, ew): - latitude = float(latitude[:2]) + float(latitude[2:])/60.0 - if ns == 'S': - latitude = -latitude - longitude = float(longitude[:3]) + float(longitude[3:])/60.0 - if ew == 'W': - longitude = -longitude - return (latitude, longitude) - - def decode_activesatellites(self, mode1, mode2, *args): - satellites, (pdop, hdop, vdop) = args[:12], map(float, args[12:]) - satlist = [] - for n in satellites: - if n: - satlist.append(int(n)) - else: - satlist.append(None) - mode = (mode1, int(mode2)) - return ( - # satellite list by channel - tuple(satlist), - # (MODE_AUTO/MODE_FORCED, MODE_NOFIX/MODE_2DFIX/MODE_3DFIX) - mode, - # position dilution of precision - pdop, - # horizontal dilution of precision - hdop, - # vertical dilution of precision - vdop, - ) - - def decode_fix(self, utc, latitude, ns, longitude, ew, posfix, satellites, hdop, altitude, altitude_units, geoid_separation, geoid_separation_units, dgps_age, dgps_station_id): - latitude, longitude = self._decode_latlon(latitude, ns, longitude, ew) - utc = self._decode_utc(utc) - posfix = int(posfix) - satellites = int(satellites) - hdop = float(hdop) - altitude = (float(altitude), altitude_units) - if geoid_separation != '': - geoid = (float(geoid_separation), geoid_separation_units) - else: - geoid = None - if dgps_age != '': - dgps = (float(dgps_age), dgps_station_id) - else: - dgps = None - return ( - # seconds since 00:00 UTC - utc, - # latitude (degrees) - latitude, - # longitude (degrees) - longitude, - # position fix status (POSFIX_INVALID, POSFIX_SPS, POSFIX_DGPS, POSFIX_PPS) - posfix, - # number of satellites used for fix 0 <= satellites <= 12 - satellites, - # horizontal dilution of precision - hdop, - # None or (altitude according to WGS-84 ellipsoid, units (typically 'M' for meters)) - altitude, - # None or (geoid separation according to WGS-84 ellipsoid, units (typically 'M' for meters)) - geoid, - # (age of dgps data in seconds, dgps station id) - dgps, - ) diff --git a/tools/buildbot/pylibs/twisted/protocols/gps/rockwell.py b/tools/buildbot/pylibs/twisted/protocols/gps/rockwell.py deleted file mode 100644 index e946995..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/gps/rockwell.py +++ /dev/null @@ -1,268 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Rockwell Semiconductor Zodiac Serial Protocol -Coded from official protocol specs (Order No. GPS-25, 09/24/1996, Revision 11) - -Maintainer: U{Bob Ippolito} - -The following Rockwell Zodiac messages are currently understood:: - EARTHA\\r\\n (a hack to "turn on" a DeLorme Earthmate) - 1000 (Geodesic Position Status Output) - 1002 (Channel Summary) - 1003 (Visible Satellites) - 1011 (Receiver ID) - -The following Rockwell Zodiac messages require implementation:: - None really, the others aren't quite so useful and require bidirectional communication w/ the device - -Other desired features:: - - Compatability with the DeLorme Tripmate and other devices with this chipset (?) -""" - -import struct, operator, math -from twisted.internet import protocol -from twisted.python import log - -DEBUG = 1 - -class ZodiacParseError(ValueError): - pass - -class Zodiac(protocol.Protocol): - dispatch = { - # Output Messages (* means they get sent by the receiver by default periodically) - 1000: 'fix', # *Geodesic Position Status Output - 1001: 'ecef', # ECEF Position Status Output - 1002: 'channels', # *Channel Summary - 1003: 'satellites', # *Visible Satellites - 1005: 'dgps', # Differential GPS Status - 1007: 'channelmeas', # Channel Measurement - 1011: 'id', # *Receiver ID - 1012: 'usersettings', # User-Settings Output - 1100: 'testresults', # Built-In Test Results - 1102: 'meastimemark', # Measurement Time Mark - 1108: 'utctimemark', # UTC Time Mark Pulse Output - 1130: 'serial', # Serial Port Communication Parameters In Use - 1135: 'eepromupdate', # EEPROM Update - 1136: 'eepromstatus', # EEPROM Status - } - # these aren't used for anything yet, just sitting here for reference - messages = { - # Input Messages - 'fix': 1200, # Geodesic Position and Velocity Initialization - 'udatum': 1210, # User-Defined Datum Definition - 'mdatum': 1211, # Map Datum Select - 'smask': 1212, # Satellite Elevation Mask Control - 'sselect': 1213, # Satellite Candidate Select - 'dgpsc': 1214, # Differential GPS Control - 'startc': 1216, # Cold Start Control - 'svalid': 1217, # Solution Validity Control - 'antenna': 1218, # Antenna Type Select - 'altinput': 1219, # User-Entered Altitude Input - 'appctl': 1220, # Application Platform Control - 'navcfg': 1221, # Nav Configuration - 'test': 1300, # Perform Built-In Test Command - 'restart': 1303, # Restart Command - 'serial': 1330, # Serial Port Communications Parameters - 'msgctl': 1331, # Message Protocol Control - 'dgpsd': 1351, # Raw DGPS RTCM SC-104 Data - } - MAX_LENGTH = 296 - allow_earthmate_hack = 1 - recvd = "" - - def dataReceived(self, recd): - self.recvd = self.recvd + recd - while len(self.recvd) >= 10: - - # hack for DeLorme EarthMate - if self.recvd[:8] == 'EARTHA\r\n': - if self.allow_earthmate_hack: - self.allow_earthmate_hack = 0 - self.transport.write('EARTHA\r\n') - self.recvd = self.recvd[8:] - continue - - if self.recvd[0:2] != '\xFF\x81': - if DEBUG: - raise ZodiacParseError('Invalid Sync %r' % self.recvd) - else: - raise ZodiacParseError - sync, msg_id, length, acknak, checksum = struct.unpack(' self.MAX_LENGTH: - raise ZodiacParseError("Invalid Header??") - - # empty messages pass empty strings - message = '' - - # does this message have data ? - if length: - message, checksum = self.recvd[10:10+length], struct.unpack(' 0 - minimize_ram = (options_list & 0x02) > 0 - # (version info), (options info) - return ((software_version, software_date), (minimize_rom, minimize_ram)) - - def decode_channels(self, message): - assert len(message) == 90, "Channel Summary Message should be 51 words total (90 byte message)" - ticks, msgseq, satseq, gpswk, gpsws, gpsns = struct.unpack('}. - -@seealso: U{HTB Linux queuing discipline manual - user guide - } -@seealso: U{Token Bucket Filter in Linux Advanced Routing & Traffic Control - HOWTO} -@author: U{Kevin Turner} -""" - -from __future__ import nested_scopes - -__version__ = '$Revision: 1.5 $'[11:-2] - - -# TODO: Investigate whether we should be using os.times()[-1] instead of -# time.time. time.time, it has been pointed out, can go backwards. Is -# the same true of os.times? -from time import time -from zope.interface import implements, Interface - -from twisted.protocols import pcp - - -class Bucket: - """Token bucket, or something like it. - - I can hold up to a certain number of tokens, and I drain over time. - - @cvar maxburst: Size of the bucket, in bytes. If None, the bucket is - never full. - @type maxburst: int - @cvar rate: Rate the bucket drains, in bytes per second. If None, - the bucket drains instantaneously. - @type rate: int - """ - - maxburst = None - rate = None - - _refcount = 0 - - def __init__(self, parentBucket=None): - self.content = 0 - self.parentBucket=parentBucket - self.lastDrip = time() - - def add(self, amount): - """Add tokens to me. - - @param amount: A quanity of tokens to add. - @type amount: int - - @returns: The number of tokens that fit. - @returntype: int - """ - self.drip() - if self.maxburst is None: - allowable = amount - else: - allowable = min(amount, self.maxburst - self.content) - - if self.parentBucket is not None: - allowable = self.parentBucket.add(allowable) - self.content += allowable - return allowable - - def drip(self): - """Let some of the bucket drain. - - How much of the bucket drains depends on how long it has been - since I was last called. - - @returns: True if I am now empty. - @returntype: bool - """ - if self.parentBucket is not None: - self.parentBucket.drip() - - if self.rate is None: - self.content = 0 - return True - else: - now = time() - deltaT = now - self.lastDrip - self.content = long(max(0, self.content - deltaT * self.rate)) - self.lastDrip = now - return False - - -class IBucketFilter(Interface): - def getBucketFor(*somethings, **some_kw): - """I'll give you a bucket for something. - - @returntype: L{Bucket} - """ - -class HierarchicalBucketFilter: - """I filter things into buckets, and I am nestable. - - @cvar bucketFactory: Class of buckets to make. - @type bucketFactory: L{Bucket} class - @cvar sweepInterval: Seconds between sweeping out the bucket cache. - @type sweepInterval: int - """ - - implements(IBucketFilter) - - bucketFactory = Bucket - sweepInterval = None - - def __init__(self, parentFilter=None): - self.buckets = {} - self.parentFilter = parentFilter - self.lastSweep = time() - - def getBucketFor(self, *a, **kw): - """You want a bucket for that? I'll give you a bucket. - - Any parameters are passed on to L{getBucketKey}, from them it - decides which bucket you get. - - @returntype: L{Bucket} - """ - if ((self.sweepInterval is not None) - and ((time() - self.lastSweep) > self.sweepInterval)): - self.sweep() - - if self.parentFilter: - parentBucket = self.parentFilter.getBucketFor(self, *a, **kw) - else: - parentBucket = None - - key = self.getBucketKey(*a, **kw) - bucket = self.buckets.get(key) - if bucket is None: - bucket = self.bucketFactory(parentBucket) - self.buckets[key] = bucket - return bucket - - def getBucketKey(self, *a, **kw): - """I determine who gets which bucket. - - Unless I'm overridden, everything gets the same bucket. - - @returns: something to be used as a key in the bucket cache. - """ - return None - - def sweep(self): - """I throw away references to empty buckets.""" - for key, bucket in self.buckets.items(): - if (bucket._refcount == 0) and bucket.drip(): - del self.buckets[key] - - self.lastSweep = time() - - -class FilterByHost(HierarchicalBucketFilter): - """A bucket filter with a bucket for each host. - """ - sweepInterval = 60 * 20 - - def getBucketKey(self, transport): - return transport.getPeer()[1] - - -class FilterByServer(HierarchicalBucketFilter): - """A bucket filter with a bucket for each service. - """ - sweepInterval = None - - def getBucketKey(self, transport): - return transport.getHost()[2] - - -class ShapedConsumer(pcp.ProducerConsumerProxy): - """I wrap a Consumer and shape the rate at which it receives data. - """ - # Providing a Pull interface means I don't have to try to schedule - # traffic with callLaters. - iAmStreaming = False - - def __init__(self, consumer, bucket): - pcp.ProducerConsumerProxy.__init__(self, consumer) - self.bucket = bucket - self.bucket._refcount += 1 - - def _writeSomeData(self, data): - # In practice, this actually results in obscene amounts of - # overhead, as a result of generating lots and lots of packets - # with twelve-byte payloads. We may need to do a version of - # this with scheduled writes after all. - amount = self.bucket.add(len(data)) - return pcp.ProducerConsumerProxy._writeSomeData(self, data[:amount]) - - def stopProducing(self): - pcp.ProducerConsumerProxy.stopProducing(self) - self.bucket._refcount -= 1 - - -class ShapedTransport(ShapedConsumer): - """I wrap a Transport and shape the rate at which it receives data. - - I am a L{ShapedConsumer} with a little bit of magic to provide for - the case where the consumer I wrap is also a Transport and people - will be attempting to access attributes I do not proxy as a - Consumer (e.g. loseConnection). - """ - # Ugh. We only wanted to filter IConsumer, not ITransport. - - iAmStreaming = False - def __getattr__(self, name): - # Because people will be doing things like .getPeer and - # .loseConnection on me. - return getattr(self.consumer, name) - - -class ShapedProtocolFactory: - """I dispense Protocols with traffic shaping on their transports. - - Usage:: - - myserver = SomeFactory() - myserver.protocol = ShapedProtocolFactory(myserver.protocol, - bucketFilter) - - Where SomeServerFactory is a L{twisted.internet.protocol.Factory}, and - bucketFilter is an instance of L{HierarchicalBucketFilter}. - """ - def __init__(self, protoClass, bucketFilter): - """Tell me what to wrap and where to get buckets. - - @param protoClass: The class of Protocol I will generate - wrapped instances of. - @type protoClass: L{Protocol} - class - @param bucketFilter: The filter which will determine how - traffic is shaped. - @type bucketFilter: L{HierarchicalBucketFilter}. - """ - # More precisely, protoClass can be any callable that will return - # instances of something that implements IProtocol. - self.protocol = protoClass - self.bucketFilter = bucketFilter - - def __call__(self, *a, **kw): - """Make a Protocol instance with a shaped transport. - - Any parameters will be passed on to the protocol's initializer. - - @returns: a Protocol instance with a L{ShapedTransport}. - """ - proto = self.protocol(*a, **kw) - origMakeConnection = proto.makeConnection - def makeConnection(transport): - bucket = self.bucketFilter.getBucketFor(transport) - shapedTransport = ShapedTransport(transport, bucket) - return origMakeConnection(shapedTransport) - proto.makeConnection = makeConnection - return proto diff --git a/tools/buildbot/pylibs/twisted/protocols/http.py b/tools/buildbot/pylibs/twisted/protocols/http.py deleted file mode 100644 index 9a801f6..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/http.py +++ /dev/null @@ -1,7 +0,0 @@ -from twisted.python import util - -util.moduleMovedForSplit('twisted.protocols.http', 'twisted.web.http', - 'HTTP protocol support', 'Web', - 'http://twistedmatrix.com/projects/web', - globals()) - diff --git a/tools/buildbot/pylibs/twisted/protocols/ident.py b/tools/buildbot/pylibs/twisted/protocols/ident.py deleted file mode 100644 index 4c86786..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/ident.py +++ /dev/null @@ -1,227 +0,0 @@ -# -*- test-case-name: twisted.test.test_ident -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Ident protocol implementation. - -@author: U{Jp Calderone} -""" - -from __future__ import generators - -import struct - -from twisted.internet import defer -from twisted.protocols import basic -from twisted.python import log, failure - -_MIN_PORT = 1 -_MAX_PORT = 2 ** 16 - 1 - -class IdentError(Exception): - """ - Can't determine connection owner; reason unknown. - """ - - identDescription = 'UNKNOWN-ERROR' - - def __str__(self): - return self.identDescription - - -class NoUser(IdentError): - """ - The connection specified by the port pair is not currently in use or - currently not owned by an identifiable entity. - """ - identDescription = 'NO-USER' - - -class InvalidPort(IdentError): - """ - Either the local or foreign port was improperly specified. This should - be returned if either or both of the port ids were out of range (TCP - port numbers are from 1-65535), negative integers, reals or in any - fashion not recognized as a non-negative integer. - """ - identDescription = 'INVALID-PORT' - - -class HiddenUser(IdentError): - """ - The server was able to identify the user of this port, but the - information was not returned at the request of the user. - """ - identDescription = 'HIDDEN-USER' - - -class IdentServer(basic.LineOnlyReceiver): - """ - The Identification Protocol (a.k.a., "ident", a.k.a., "the Ident - Protocol") provides a means to determine the identity of a user of a - particular TCP connection. Given a TCP port number pair, it returns a - character string which identifies the owner of that connection on the - server's system. - - Server authors should subclass this class and override the lookup method. - The default implementation returns an UNKNOWN-ERROR response for every - query. - """ - - def lineReceived(self, line): - parts = line.split(',') - if len(parts) != 2: - self.invalidQuery() - else: - try: - portOnServer, portOnClient = map(int, parts) - except ValueError: - self.invalidQuery() - else: - if _MIN_PORT <= portOnServer <= _MAX_PORT and _MIN_PORT <= portOnClient <= _MAX_PORT: - self.validQuery(portOnServer, portOnClient) - else: - self._ebLookup(failure.Failure(InvalidPort()), portOnServer, portOnClient) - - def invalidQuery(self): - self.transport.loseConnection() - - def validQuery(self, portOnServer, portOnClient): - serverAddr = self.transport.getHost()[1], portOnServer - clientAddr = self.transport.getPeer()[1], portOnClient - defer.maybeDeferred(self.lookup, serverAddr, clientAddr - ).addCallback(self._cbLookup, portOnServer, portOnClient - ).addErrback(self._ebLookup, portOnServer, portOnClient - ) - - def _cbLookup(self, (sysName, userId), sport, cport): - self.sendLine('%d, %d : USERID : %s : %s' % (sport, cport, sysName, userId)) - - def _ebLookup(self, failure, sport, cport): - if failure.check(IdentError): - self.sendLine('%d, %d : ERROR : %s' % (sport, cport, failure.value)) - else: - log.err(failure) - self.sendLine('%d, %d : ERROR : %s' % (sport, cport, IdentError(failure.value))) - - def lookup(self, serverAddress, clientAddress): - """Lookup user information about the specified address pair. - - Return value should be a two-tuple of system name and username. - Acceptable values for the system name may be found online at:: - - U{http://www.iana.org/assignments/operating-system-names} - - This method may also raise any IdentError subclass (or IdentError - itself) to indicate user information will not be provided for the - given query. - - A Deferred may also be returned. - - @param serverAddress: A two-tuple representing the server endpoint - of the address being queried. The first element is a string holding - a dotted-quad IP address. The second element is an integer - representing the port. - - @param clientAddress: Like L{serverAddress}, but represents the - client endpoint of the address being queried. - """ - raise IdentError() - -class ProcServerMixin: - """Implements lookup() to grab entries for responses from /proc/net/tcp - """ - - SYSTEM_NAME = 'LINUX' - - try: - from pwd import getpwuid - def getUsername(self, uid, getpwuid=getpwuid): - return getpwuid(uid)[0] - del getpwuid - except ImportError: - def getUsername(self, uid): - raise IdentError() - - def entries(self): - f = file('/proc/net/tcp') - f.readline() - for L in f: - yield L.strip() - - def dottedQuadFromHexString(self, hexstr): - return '.'.join(map(str, struct.unpack('4B', struct.pack('=L', int(hexstr, 16))))) - - def unpackAddress(self, packed): - addr, port = packed.split(':') - addr = self.dottedQuadFromHexString(addr) - port = int(port, 16) - return addr, port - - def parseLine(self, line): - parts = line.strip().split() - localAddr, localPort = self.unpackAddress(parts[1]) - remoteAddr, remotePort = self.unpackAddress(parts[2]) - uid = int(parts[7]) - return (localAddr, localPort), (remoteAddr, remotePort), uid - - def lookup(self, serverAddress, clientAddress): - for ent in self.entries(): - localAddr, remoteAddr, uid = self.parseLine(ent) - if remoteAddr == clientAddress and localAddr[1] == serverAddress[1]: - return (self.SYSTEM_NAME, self.getUsername(uid)) - - raise NoUser() - - -class IdentClient(basic.LineOnlyReceiver): - - errorTypes = (IdentError, NoUser, InvalidPort, HiddenUser) - - def __init__(self): - self.queries = [] - - def lookup(self, portOnServer, portOnClient): - """Lookup user information about the specified address pair. - """ - self.queries.append((defer.Deferred(), portOnServer, portOnClient)) - if len(self.queries) > 1: - return self.queries[-1][0] - - self.sendLine('%d, %d' % (portOnServer, portOnClient)) - return self.queries[-1][0] - - def lineReceived(self, line): - if not self.queries: - log.msg("Unexpected server response: %r" % (line,)) - else: - d, _, _ = self.queries.pop(0) - self.parseResponse(d, line) - if self.queries: - self.sendLine('%d, %d' % (self.queries[0][1], self.queries[0][2])) - - def connectionLost(self, reason): - for q in self.queries: - q[0].errback(IdentError(reason)) - self.queries = [] - - def parseResponse(self, deferred, line): - parts = line.split(':', 2) - if len(parts) != 3: - deferred.errback(IdentError(line)) - else: - ports, type, addInfo = map(str.strip, parts) - if type == 'ERROR': - for et in self.errorTypes: - if et.identDescription == addInfo: - deferred.errback(et(line)) - return - deferred.errback(IdentError(line)) - else: - deferred.callback((type, addInfo)) - -__all__ = ['IdentError', 'NoUser', 'InvalidPort', 'HiddenUser', - 'IdentServer', 'IdentClient', - 'ProcServerMixin'] diff --git a/tools/buildbot/pylibs/twisted/protocols/imap4.py b/tools/buildbot/pylibs/twisted/protocols/imap4.py deleted file mode 100644 index 9d2498e..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/imap4.py +++ /dev/null @@ -1,7 +0,0 @@ -from twisted.python import util - -util.moduleMovedForSplit('twisted.protocols.imap4', 'twisted.mail.imap4', - 'IMAP4 protocol support', 'Mail', - 'http://twistedmatrix.com/projects/mail', - globals()) - diff --git a/tools/buildbot/pylibs/twisted/protocols/ip.py b/tools/buildbot/pylibs/twisted/protocols/ip.py deleted file mode 100644 index f496733..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/ip.py +++ /dev/null @@ -1,7 +0,0 @@ -from twisted.python import util - -util.moduleMovedForSplit('twisted.protocols.ip', 'twisted.pair.ip', - 'Internet Protocol', 'Pair', - 'http://twistedmatrix.com/projects/pair', - globals()) - diff --git a/tools/buildbot/pylibs/twisted/protocols/irc.py b/tools/buildbot/pylibs/twisted/protocols/irc.py deleted file mode 100644 index 3165eb3..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/irc.py +++ /dev/null @@ -1,7 +0,0 @@ -from twisted.python import util - -util.moduleMovedForSplit('twisted.protocols.irc', 'twisted.words.protocols.irc', - 'IRC protocol support', 'Words', - 'http://twistedmatrix.com/projects/words', - globals()) - diff --git a/tools/buildbot/pylibs/twisted/protocols/jabber.py b/tools/buildbot/pylibs/twisted/protocols/jabber.py deleted file mode 100644 index 311b5e3..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/jabber.py +++ /dev/null @@ -1,7 +0,0 @@ -from twisted.python import util - -util.moduleMovedForSplit('twisted.protocols.jabber', 'twisted.words.protocols.jabber', - 'Jabber protocol support', 'Words', - 'http://twistedmatrix.com/projects/words', - globals()) - diff --git a/tools/buildbot/pylibs/twisted/protocols/loopback.py b/tools/buildbot/pylibs/twisted/protocols/loopback.py deleted file mode 100644 index bbf42a3..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/loopback.py +++ /dev/null @@ -1,335 +0,0 @@ -# -*- test-case-name: twisted.test.test_loopback -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Testing support for protocols -- loopback between client and server. -""" - -# system imports -import tempfile -from zope.interface import implements - -# Twisted Imports -from twisted.protocols import policies -from twisted.internet import interfaces, protocol, main, defer -from twisted.python import failure -from twisted.internet.interfaces import IAddress - - -class _LoopbackQueue(object): - """ - Trivial wrapper around a list to give it an interface like a queue, which - the addition of also sending notifications by way of a Deferred whenever - the list has something added to it. - """ - - _notificationDeferred = None - disconnect = False - - def __init__(self): - self._queue = [] - - - def put(self, v): - self._queue.append(v) - if self._notificationDeferred is not None: - d, self._notificationDeferred = self._notificationDeferred, None - d.callback(None) - - - def __nonzero__(self): - return bool(self._queue) - - - def get(self): - return self._queue.pop(0) - - - -class _LoopbackAddress(object): - implements(IAddress) - - -class _LoopbackTransport(object): - implements(interfaces.ITransport, interfaces.IConsumer) - - disconnecting = False - producer = None - - # ITransport - def __init__(self, q): - self.q = q - - def write(self, bytes): - self.q.put(bytes) - - def writeSequence(self, iovec): - self.q.put(''.join(iovec)) - - def loseConnection(self): - self.q.disconnect = True - self.q.put('') - - def getPeer(self): - return _LoopbackAddress() - - def getHost(self): - return _LoopbackAddress() - - # IConsumer - def registerProducer(self, producer, streaming): - assert self.producer is None - self.producer = producer - self.streamingProducer = streaming - self._pollProducer() - - def unregisterProducer(self): - assert self.producer is not None - self.producer = None - - def _pollProducer(self): - if self.producer is not None and not self.streamingProducer: - self.producer.resumeProducing() - - - -def loopbackAsync(server, client): - """ - Establish a connection between C{server} and C{client} then transfer data - between them until the connection is closed. This is often useful for - testing a protocol. - - @param server: The protocol instance representing the server-side of this - connection. - - @param client: The protocol instance representing the client-side of this - connection. - - @return: A L{Deferred} which fires when the connection has been closed and - both sides have received notification of this. - """ - serverToClient = _LoopbackQueue() - clientToServer = _LoopbackQueue() - - server.makeConnection(_LoopbackTransport(serverToClient)) - client.makeConnection(_LoopbackTransport(clientToServer)) - - return _loopbackAsyncBody(server, serverToClient, client, clientToServer) - - - -def _loopbackAsyncBody(server, serverToClient, client, clientToServer): - """ - Transfer bytes from the output queue of each protocol to the input of the other. - - @param server: The protocol instance representing the server-side of this - connection. - - @param serverToClient: The L{_LoopbackQueue} holding the server's output. - - @param client: The protocol instance representing the client-side of this - connection. - - @param clientToServer: The L{_LoopbackQueue} holding the client's output. - - @return: A L{Deferred} which fires when the connection has been closed and - both sides have received notification of this. - """ - def pump(source, q, target): - sent = False - while q: - sent = True - bytes = q.get() - if bytes: - target.dataReceived(bytes) - - # A write buffer has now been emptied. Give any producer on that side - # an opportunity to produce more data. - source.transport._pollProducer() - - return sent - - while 1: - disconnect = clientSent = serverSent = False - - # Deliver the data which has been written. - serverSent = pump(server, serverToClient, client) - clientSent = pump(client, clientToServer, server) - - if not clientSent and not serverSent: - # Neither side wrote any data. Wait for some new data to be added - # before trying to do anything further. - d = clientToServer._notificationDeferred = serverToClient._notificationDeferred = defer.Deferred() - d.addCallback(_loopbackAsyncContinue, server, serverToClient, client, clientToServer) - return d - if serverToClient.disconnect: - # The server wants to drop the connection. Flush any remaining - # data it has. - disconnect = True - pump(server, serverToClient, client) - elif clientToServer.disconnect: - # The client wants to drop the connection. Flush any remaining - # data it has. - disconnect = True - pump(client, clientToServer, server) - if disconnect: - # Someone wanted to disconnect, so okay, the connection is gone. - server.connectionLost(failure.Failure(main.CONNECTION_DONE)) - client.connectionLost(failure.Failure(main.CONNECTION_DONE)) - return defer.succeed(None) - - - -def _loopbackAsyncContinue(ignored, server, serverToClient, client, clientToServer): - # Clear the Deferred from each message queue, since it has already fired - # and cannot be used again. - clientToServer._notificationDeferred = serverToClient._notificationDeferred = None - - # Push some more bytes around. - return _loopbackAsyncBody(server, serverToClient, client, clientToServer) - - - -class LoopbackRelay: - - implements(interfaces.ITransport, interfaces.IConsumer) - - buffer = '' - shouldLose = 0 - disconnecting = 0 - producer = None - - def __init__(self, target, logFile=None): - self.target = target - self.logFile = logFile - - def write(self, data): - self.buffer = self.buffer + data - if self.logFile: - self.logFile.write("loopback writing %s\n" % repr(data)) - - def writeSequence(self, iovec): - self.write("".join(iovec)) - - def clearBuffer(self): - if self.shouldLose == -1: - return - - if self.producer: - self.producer.resumeProducing() - if self.buffer: - if self.logFile: - self.logFile.write("loopback receiving %s\n" % repr(self.buffer)) - buffer = self.buffer - self.buffer = '' - self.target.dataReceived(buffer) - if self.shouldLose == 1: - self.shouldLose = -1 - self.target.connectionLost(failure.Failure(main.CONNECTION_DONE)) - - def loseConnection(self): - if self.shouldLose != -1: - self.shouldLose = 1 - - def getHost(self): - return 'loopback' - - def getPeer(self): - return 'loopback' - - def registerProducer(self, producer, streaming): - self.producer = producer - - def unregisterProducer(self): - self.producer = None - - def logPrefix(self): - return 'Loopback(%r)' % (self.target.__class__.__name__,) - -def loopback(server, client, logFile=None): - """Run session between server and client. - DEPRECATED in Twisted 2.5. Use loopbackAsync instead. - """ - import warnings - warnings.warn('loopback() is deprecated (since Twisted 2.5). ' - 'Use loopbackAsync() instead.', - stacklevel=2, category=DeprecationWarning) - from twisted.internet import reactor - serverToClient = LoopbackRelay(client, logFile) - clientToServer = LoopbackRelay(server, logFile) - server.makeConnection(serverToClient) - client.makeConnection(clientToServer) - while 1: - reactor.iterate(0.01) # this is to clear any deferreds - serverToClient.clearBuffer() - clientToServer.clearBuffer() - if serverToClient.shouldLose: - serverToClient.clearBuffer() - server.connectionLost(failure.Failure(main.CONNECTION_DONE)) - break - elif clientToServer.shouldLose: - client.connectionLost(failure.Failure(main.CONNECTION_DONE)) - break - reactor.iterate() # last gasp before I go away - - -class LoopbackClientFactory(protocol.ClientFactory): - - def __init__(self, protocol): - self.disconnected = 0 - self.deferred = defer.Deferred() - self.protocol = protocol - - def buildProtocol(self, addr): - return self.protocol - - def clientConnectionLost(self, connector, reason): - self.disconnected = 1 - self.deferred.callback(None) - - -class _FireOnClose(policies.ProtocolWrapper): - def __init__(self, protocol, factory): - policies.ProtocolWrapper.__init__(self, protocol, factory) - self.deferred = defer.Deferred() - - def connectionLost(self, reason): - policies.ProtocolWrapper.connectionLost(self, reason) - self.deferred.callback(None) - - -def loopbackTCP(server, client, port=0, noisy=True): - """Run session between server and client protocol instances over TCP.""" - from twisted.internet import reactor - f = policies.WrappingFactory(protocol.Factory()) - serverWrapper = _FireOnClose(f, server) - f.noisy = noisy - f.buildProtocol = lambda addr: serverWrapper - serverPort = reactor.listenTCP(port, f, interface='127.0.0.1') - clientF = LoopbackClientFactory(client) - clientF.noisy = noisy - reactor.connectTCP('127.0.0.1', serverPort.getHost().port, clientF) - d = clientF.deferred - d.addCallback(lambda x: serverWrapper.deferred) - d.addCallback(lambda x: serverPort.stopListening()) - return d - - -def loopbackUNIX(server, client, noisy=True): - """Run session between server and client protocol instances over UNIX socket.""" - path = tempfile.mktemp() - from twisted.internet import reactor - f = policies.WrappingFactory(protocol.Factory()) - serverWrapper = _FireOnClose(f, server) - f.noisy = noisy - f.buildProtocol = lambda addr: serverWrapper - serverPort = reactor.listenUNIX(path, f) - clientF = LoopbackClientFactory(client) - clientF.noisy = noisy - reactor.connectUNIX(path, clientF) - d = clientF.deferred - d.addCallback(lambda x: serverWrapper.deferred) - d.addCallback(lambda x: serverPort.stopListening()) - return d diff --git a/tools/buildbot/pylibs/twisted/protocols/memcache.py b/tools/buildbot/pylibs/twisted/protocols/memcache.py deleted file mode 100644 index 4862cd5..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/memcache.py +++ /dev/null @@ -1,657 +0,0 @@ -# -*- test-case-name: twisted.test.test_memcache -*- -# Copyright (c) 2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Memcache client protocol. Memcached is a caching server, storing data in the -form of pairs key/value, and memcache is the protocol to talk with it. - -To connect to a server, create a factory for L{MemCacheProtocol}:: - - from twisted.internet import reactor, protocol - from twisted.protocols.memcache import MemCacheProtocol, DEFAULT_PORT - d = protocol.ClientCreator(reactor, MemCacheProtocol - ).connectTCP("localhost", DEFAULT_PORT) - def doSomething(proto): - # Here you call the memcache operations - return proto.set("mykey", "a lot of data") - d.addCallback(doSomething) - reactor.run() - -All the operations of the memcache protocol are present, but -L{MemCacheProtocol.set} and L{MemCacheProtocol.get} are the more important. - -See U{http://code.sixapart.com/svn/memcached/trunk/server/doc/protocol.txt} for -more information about the protocol. -""" - -try: - from collections import deque -except ImportError: - class deque(list): - def popleft(self): - return self.pop(0) - - -from twisted.protocols.basic import LineReceiver -from twisted.protocols.policies import TimeoutMixin -from twisted.internet.defer import Deferred, fail, TimeoutError -from twisted.python import log - - - -DEFAULT_PORT = 11211 - - - -class NoSuchCommand(Exception): - """ - Exception raised when a non existent command is called. - """ - - - -class ClientError(Exception): - """ - Error caused by an invalid client call. - """ - - - -class ServerError(Exception): - """ - Problem happening on the server. - """ - - - -class Command(object): - """ - Wrap a client action into an object, that holds the values used in the - protocol. - - @ivar _deferred: the L{Deferred} object that will be fired when the result - arrives. - @type _deferred: L{Deferred} - - @ivar command: name of the command sent to the server. - @type command: C{str} - """ - - def __init__(self, command, **kwargs): - """ - Create a command. - - @param command: the name of the command. - @type command: C{str} - - @param kwargs: this values will be stored as attributes of the object - for future use - """ - self.command = command - self._deferred = Deferred() - for k, v in kwargs.items(): - setattr(self, k, v) - - - def success(self, value): - """ - Shortcut method to fire the underlying deferred. - """ - self._deferred.callback(value) - - - def fail(self, error): - """ - Make the underlying deferred fails. - """ - self._deferred.errback(error) - - - -class MemCacheProtocol(LineReceiver, TimeoutMixin): - """ - MemCache protocol: connect to a memcached server to store/retrieve values. - - @ivar persistentTimeOut: the timeout period used to wait for a response. - @type persistentTimeOut: C{int} - - @ivar _current: current list of requests waiting for an answer from the - server. - @type _current: C{deque} of L{Command} - - @ivar _lenExpected: amount of data expected in raw mode, when reading for - a value. - @type _lenExpected: C{int} - - @ivar _getBuffer: current buffer of data, used to store temporary data - when reading in raw mode. - @type _getBuffer: C{list} - - @ivar _bufferLength: the total amount of bytes in C{_getBuffer}. - @type _bufferLength: C{int} - """ - MAX_KEY_LENGTH = 250 - - def __init__(self, timeOut=60): - """ - Create the protocol. - - @param timeOut: the timeout to wait before detecting that the - connection is dead and close it. It's expressed in seconds. - @type timeOut: C{int} - """ - self._current = deque() - self._lenExpected = None - self._getBuffer = None - self._bufferLength = None - self.persistentTimeOut = self.timeOut = timeOut - - - def timeoutConnection(self): - """ - Close the connection in case of timeout. - """ - for cmd in self._current: - cmd.fail(TimeoutError("Connection timeout")) - self.transport.loseConnection() - - - def sendLine(self, line): - """ - Override sendLine to add a timeout to response. - """ - if not self._current: - self.setTimeout(self.persistentTimeOut) - LineReceiver.sendLine(self, line) - - - def rawDataReceived(self, data): - """ - Collect data for a get. - """ - self.resetTimeout() - self._getBuffer.append(data) - self._bufferLength += len(data) - if self._bufferLength >= self._lenExpected + 2: - data = "".join(self._getBuffer) - buf = data[:self._lenExpected] - rem = data[self._lenExpected + 2:] - val = buf - self._lenExpected = None - self._getBuffer = None - self._bufferLength = None - cmd = self._current[0] - cmd.value = val - self.setLineMode(rem) - - - def cmd_STORED(self): - """ - Manage a success response to a set operation. - """ - self._current.popleft().success(True) - - - def cmd_NOT_STORED(self): - """ - Manage a specific 'not stored' response to a set operation: this is not - an error, but some condition wasn't met. - """ - self._current.popleft().success(False) - - - def cmd_END(self): - """ - This the end token to a get or a stat operation. - """ - cmd = self._current.popleft() - if cmd.command == "get": - cmd.success((cmd.flags, cmd.value)) - elif cmd.command == "gets": - cmd.success((cmd.flags, cmd.cas, cmd.value)) - elif cmd.command == "stats": - cmd.success(cmd.values) - - - def cmd_NOT_FOUND(self): - """ - Manage error response for incr/decr/delete. - """ - self._current.popleft().success(False) - - - def cmd_VALUE(self, line): - """ - Prepare the reading a value after a get. - """ - cmd = self._current[0] - if cmd.command == "get": - key, flags, length = line.split() - cas = "" - else: - key, flags, length, cas = line.split() - self._lenExpected = int(length) - self._getBuffer = [] - self._bufferLength = 0 - if cmd.key != key: - raise RuntimeError("Unexpected commands answer.") - cmd.flags = int(flags) - cmd.length = self._lenExpected - cmd.cas = cas - self.setRawMode() - - - def cmd_STAT(self, line): - """ - Reception of one stat line. - """ - cmd = self._current[0] - key, val = line.split(" ", 1) - cmd.values[key] = val - - - def cmd_VERSION(self, versionData): - """ - Read version token. - """ - self._current.popleft().success(versionData) - - - def cmd_ERROR(self): - """ - An non-existent command has been sent. - """ - log.err("Non-existent command sent.") - cmd = self._current.popleft() - cmd.fail(NoSuchCommand()) - - - def cmd_CLIENT_ERROR(self, errText): - """ - An invalid input as been sent. - """ - log.err("Invalid input: %s" % (errText,)) - cmd = self._current.popleft() - cmd.fail(ClientError(errText)) - - - def cmd_SERVER_ERROR(self, errText): - """ - An error has happened server-side. - """ - log.err("Server error: %s" % (errText,)) - cmd = self._current.popleft() - cmd.fail(ServerError(errText)) - - - def cmd_DELETED(self): - """ - A delete command has completed successfully. - """ - self._current.popleft().success(True) - - - def cmd_OK(self): - """ - The last command has been completed. - """ - self._current.popleft().success(True) - - - def cmd_EXISTS(self): - """ - A C{checkAndSet} update has failed. - """ - self._current.popleft().success(False) - - - def lineReceived(self, line): - """ - Receive line commands from the server. - """ - self.resetTimeout() - token = line.split(" ", 1)[0] - # First manage standard commands without space - cmd = getattr(self, "cmd_%s" % (token,), None) - if cmd is not None: - args = line.split(" ", 1)[1:] - if args: - cmd(args[0]) - else: - cmd() - else: - # Then manage commands with space in it - line = line.replace(" ", "_") - cmd = getattr(self, "cmd_%s" % (line,), None) - if cmd is not None: - cmd() - else: - # Increment/Decrement response - cmd = self._current.popleft() - val = int(line) - cmd.success(val) - if not self._current: - # No pending request, remove timeout - self.setTimeout(None) - - - def increment(self, key, val=1): - """ - Increment the value of C{key} by given value (default to 1). - C{key} must be consistent with an int. Return the new value. - - @param key: the key to modify. - @type key: C{str} - - @param val: the value to increment. - @type val: C{int} - - @return: a deferred with will be called back with the new value - associated with the key (after the increment). - @rtype: L{Deferred} - """ - return self._incrdecr("incr", key, val) - - - def decrement(self, key, val=1): - """ - Decrement the value of C{key} by given value (default to 1). - C{key} must be consistent with an int. Return the new value, coerced to - 0 if negative. - - @param key: the key to modify. - @type key: C{str} - - @param val: the value to decrement. - @type val: C{int} - - @return: a deferred with will be called back with the new value - associated with the key (after the decrement). - @rtype: L{Deferred} - """ - return self._incrdecr("decr", key, val) - - - def _incrdecr(self, cmd, key, val): - """ - Internal wrapper for incr/decr. - """ - if not isinstance(key, str): - return fail(ClientError( - "Invalid type for key: %s, expecting a string" % (type(key),))) - if len(key) > self.MAX_KEY_LENGTH: - return fail(ClientError("Key too long")) - fullcmd = "%s %s %d" % (cmd, key, int(val)) - self.sendLine(fullcmd) - cmdObj = Command(cmd, key=key) - self._current.append(cmdObj) - return cmdObj._deferred - - - def replace(self, key, val, flags=0, expireTime=0): - """ - Replace the given C{key}. It must already exist in the server. - - @param key: the key to replace. - @type key: C{str} - - @param val: the new value associated with the key. - @type val: C{str} - - @param flags: the flags to store with the key. - @type flags: C{int} - - @param expireTime: if different from 0, the relative time in seconds - when the key will be deleted from the store. - @type expireTime: C{int} - - @return: a deferred that will fire with C{True} if the operation has - succeeded, and C{False} with the key didn't previously exist. - @rtype: L{Deferred} - """ - return self._set("replace", key, val, flags, expireTime, "") - - - def add(self, key, val, flags=0, expireTime=0): - """ - Add the given C{key}. It must not exist in the server. - - @param key: the key to add. - @type key: C{str} - - @param val: the value associated with the key. - @type val: C{str} - - @param flags: the flags to store with the key. - @type flags: C{int} - - @param expireTime: if different from 0, the relative time in seconds - when the key will be deleted from the store. - @type expireTime: C{int} - - @return: a deferred that will fire with C{True} if the operation has - succeeded, and C{False} with the key already exists. - @rtype: L{Deferred} - """ - return self._set("add", key, val, flags, expireTime, "") - - - def set(self, key, val, flags=0, expireTime=0): - """ - Set the given C{key}. - - @param key: the key to set. - @type key: C{str} - - @param val: the value associated with the key. - @type val: C{str} - - @param flags: the flags to store with the key. - @type flags: C{int} - - @param expireTime: if different from 0, the relative time in seconds - when the key will be deleted from the store. - @type expireTime: C{int} - - @return: a deferred that will fire with C{True} if the operation has - succeeded. - @rtype: L{Deferred} - """ - return self._set("set", key, val, flags, expireTime, "") - - - def checkAndSet(self, key, val, cas, flags=0, expireTime=0): - """ - Change the content of C{key} only if the C{cas} value matches the - current one associated with the key. Use this to store a value which - hasn't been modified since last time you fetched it. - - @param key: The key to set. - @type key: C{str} - - @param val: The value associated with the key. - @type val: C{str} - - @param cas: Unique 64-bit value returned by previous call of C{get}. - @type cas: C{str} - - @param flags: The flags to store with the key. - @type flags: C{int} - - @param expireTime: If different from 0, the relative time in seconds - when the key will be deleted from the store. - @type expireTime: C{int} - - @return: A deferred that will fire with C{True} if the operation has - succeeded, C{False} otherwise. - @rtype: L{Deferred} - """ - return self._set("cas", key, val, flags, expireTime, cas) - - - def _set(self, cmd, key, val, flags, expireTime, cas): - """ - Internal wrapper for setting values. - """ - if not isinstance(key, str): - return fail(ClientError( - "Invalid type for key: %s, expecting a string" % (type(key),))) - if len(key) > self.MAX_KEY_LENGTH: - return fail(ClientError("Key too long")) - if not isinstance(val, str): - return fail(ClientError( - "Invalid type for value: %s, expecting a string" % - (type(val),))) - if cas: - cas = " " + cas - length = len(val) - fullcmd = "%s %s %d %d %d%s" % ( - cmd, key, flags, expireTime, length, cas) - self.sendLine(fullcmd) - self.sendLine(val) - cmdObj = Command(cmd, key=key, flags=flags, length=length) - self._current.append(cmdObj) - return cmdObj._deferred - - - def append(self, key, val): - """ - Append given data to the value of an existing key. - - @param key: The key to modify. - @type key: C{str} - - @param val: The value to append to the current value associated with - the key. - @type val: C{str} - - @return: A deferred that will fire with C{True} if the operation has - succeeded, C{False} otherwise. - @rtype: L{Deferred} - """ - # Even if flags and expTime values are ignored, we have to pass them - return self._set("append", key, val, 0, 0, "") - - - def prepend(self, key, val): - """ - Prepend given data to the value of an existing key. - - @param key: The key to modify. - @type key: C{str} - - @param val: The value to prepend to the current value associated with - the key. - @type val: C{str} - - @return: A deferred that will fire with C{True} if the operation has - succeeded, C{False} otherwise. - @rtype: L{Deferred} - """ - # Even if flags and expTime values are ignored, we have to pass them - return self._set("prepend", key, val, 0, 0, "") - - - def get(self, key, withIdentifier=False): - """ - Get the given C{key}. It doesn't support multiple keys. If - C{withIdentifier} is set to C{True}, the command issued is a C{gets}, - that will return the current identifier associated with the value. This - identifier has to be used when issuing C{checkAndSet} update later, - using the corresponding method. - - @param key: The key to retrieve. - @type key: C{str} - - @param withIdentifier: If set to C{True}, retrieve the current - identifier along with the value and the flags. - @type withIdentifier: C{bool} - - @return: A deferred that will fire with the tuple (flags, value) if - C{withIdentifier} is C{False}, or (flags, cas identifier, value) - if C{True}. - @rtype: L{Deferred} - """ - if not isinstance(key, str): - return fail(ClientError( - "Invalid type for key: %s, expecting a string" % (type(key),))) - if len(key) > self.MAX_KEY_LENGTH: - return fail(ClientError("Key too long")) - if withIdentifier: - cmd = "gets" - else: - cmd = "get" - fullcmd = "%s %s" % (cmd, key) - self.sendLine(fullcmd) - cmdObj = Command(cmd, key=key, value=None, flags=0, cas="") - self._current.append(cmdObj) - return cmdObj._deferred - - - def stats(self): - """ - Get some stats from the server. It will be available as a dict. - - @return: a deferred that will fire with a C{dict} of the available - statistics. - @rtype: L{Deferred} - """ - self.sendLine("stats") - cmdObj = Command("stats", values={}) - self._current.append(cmdObj) - return cmdObj._deferred - - - def version(self): - """ - Get the version of the server. - - @return: a deferred that will fire with the string value of the - version. - @rtype: L{Deferred} - """ - self.sendLine("version") - cmdObj = Command("version") - self._current.append(cmdObj) - return cmdObj._deferred - - - def delete(self, key): - """ - Delete an existing C{key}. - - @param key: the key to delete. - @type key: C{str} - - @return: a deferred that will be called back with C{True} if the key - was successfully deleted, or C{False} if not. - @rtype: L{Deferred} - """ - if not isinstance(key, str): - return fail(ClientError( - "Invalid type for key: %s, expecting a string" % (type(key),))) - self.sendLine("delete %s" % key) - cmdObj = Command("delete", key=key) - self._current.append(cmdObj) - return cmdObj._deferred - - - def flushAll(self): - """ - Flush all cached values. - - @return: a deferred that will be called back with C{True} when the - operation has succeeded. - @rtype: L{Deferred} - """ - self.sendLine("flush_all") - cmdObj = Command("flush_all") - self._current.append(cmdObj) - return cmdObj._deferred - - - -__all__ = ["MemCacheProtocol", "DEFAULT_PORT", "NoSuchCommand", "ClientError", - "ServerError"] - diff --git a/tools/buildbot/pylibs/twisted/protocols/mice/__init__.py b/tools/buildbot/pylibs/twisted/protocols/mice/__init__.py deleted file mode 100644 index fda89c5..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/mice/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Mice Protocols.""" diff --git a/tools/buildbot/pylibs/twisted/protocols/mice/mouseman.py b/tools/buildbot/pylibs/twisted/protocols/mice/mouseman.py deleted file mode 100644 index d22c48a..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/mice/mouseman.py +++ /dev/null @@ -1,127 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -"""Logictech MouseMan serial protocol. - -http://www.softnco.demon.co.uk/SerialMouse.txt -""" - -from twisted.internet import protocol - -class MouseMan(protocol.Protocol): - """ - - Parser for Logitech MouseMan serial mouse protocol (compatible - with Microsoft Serial Mouse). - - """ - - state = 'initial' - - leftbutton=None - rightbutton=None - middlebutton=None - - leftold=None - rightold=None - middleold=None - - horiz=None - vert=None - horizold=None - vertold=None - - def down_left(self): - pass - - def up_left(self): - pass - - def down_middle(self): - pass - - def up_middle(self): - pass - - def down_right(self): - pass - - def up_right(self): - pass - - def move(self, x, y): - pass - - horiz=None - vert=None - - def state_initial(self, byte): - if byte & 1<<6: - self.word1=byte - self.leftbutton = byte & 1<<5 - self.rightbutton = byte & 1<<4 - return 'horiz' - else: - return 'initial' - - def state_horiz(self, byte): - if byte & 1<<6: - return self.state_initial(byte) - else: - x=(self.word1 & 0x03)<<6 | (byte & 0x3f) - if x>=128: - x=-256+x - self.horiz = x - return 'vert' - - def state_vert(self, byte): - if byte & 1<<6: - # short packet - return self.state_initial(byte) - else: - x = (self.word1 & 0x0c)<<4 | (byte & 0x3f) - if x>=128: - x=-256+x - self.vert = x - self.snapshot() - return 'maybemiddle' - - def state_maybemiddle(self, byte): - if byte & 1<<6: - self.snapshot() - return self.state_initial(byte) - else: - self.middlebutton=byte & 1<<5 - self.snapshot() - return 'initial' - - def snapshot(self): - if self.leftbutton and not self.leftold: - self.down_left() - self.leftold=1 - if not self.leftbutton and self.leftold: - self.up_left() - self.leftold=0 - - if self.middlebutton and not self.middleold: - self.down_middle() - self.middleold=1 - if not self.middlebutton and self.middleold: - self.up_middle() - self.middleold=0 - - if self.rightbutton and not self.rightold: - self.down_right() - self.rightold=1 - if not self.rightbutton and self.rightold: - self.up_right() - self.rightold=0 - - if self.horiz or self.vert: - self.move(self.horiz, self.vert) - - def dataReceived(self, data): - for c in data: - byte = ord(c) - self.state = getattr(self, 'state_'+self.state)(byte) diff --git a/tools/buildbot/pylibs/twisted/protocols/msn.py b/tools/buildbot/pylibs/twisted/protocols/msn.py deleted file mode 100644 index a96298d..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/msn.py +++ /dev/null @@ -1,7 +0,0 @@ -from twisted.python import util - -util.moduleMovedForSplit('twisted.protocols.msn', 'twisted.words.protocols.msn', - 'MSN protocol support', 'Words', - 'http://twistedmatrix.com/projects/words', - globals()) - diff --git a/tools/buildbot/pylibs/twisted/protocols/nntp.py b/tools/buildbot/pylibs/twisted/protocols/nntp.py deleted file mode 100644 index f3ea295..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/nntp.py +++ /dev/null @@ -1,7 +0,0 @@ -from twisted.python import util - -util.moduleMovedForSplit('twisted.protocols.nntp', 'twisted.news.nntp', - 'NNTP protocol support', 'News', - 'http://twistedmatrix.com/projects/news', - globals()) - diff --git a/tools/buildbot/pylibs/twisted/protocols/oscar.py b/tools/buildbot/pylibs/twisted/protocols/oscar.py deleted file mode 100644 index 07f5208..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/oscar.py +++ /dev/null @@ -1,7 +0,0 @@ -from twisted.python import util - -util.moduleMovedForSplit('twisted.protocols.oscar', 'twisted.words.protocols.oscar', - 'OSCAR protocol support', 'Words', - 'http://twistedmatrix.com/projects/words', - globals()) - diff --git a/tools/buildbot/pylibs/twisted/protocols/pcp.py b/tools/buildbot/pylibs/twisted/protocols/pcp.py deleted file mode 100644 index 00a1342..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/pcp.py +++ /dev/null @@ -1,209 +0,0 @@ -# -*- test-case-name: twisted.test.test_pcp -*- -# -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Producer-Consumer Proxy.""" - -__version__ = '$Revision: 1.4 $'[11:-2] - -import operator - -from zope.interface import implements - -from twisted.internet import interfaces - - -class BasicProducerConsumerProxy: - """ I can act as a man in the middle between any Producer and Consumer. - - @ivar producer: the Producer I subscribe to. - @type producer: L{IProducer} - @ivar consumer: the Consumer I publish to. - @type consumer: L{IConsumer} - @ivar paused: As a Producer, am I paused? - @type paused: bool - """ - implements(interfaces.IProducer, interfaces.IConsumer) - - consumer = None - producer = None - producerIsStreaming = None - iAmStreaming = True - outstandingPull = False - paused = False - stopped = False - - def __init__(self, consumer): - self._buffer = [] - if consumer is not None: - self.consumer = consumer - consumer.registerProducer(self, self.iAmStreaming) - - # Producer methods: - - def pauseProducing(self): - self.paused = True - if self.producer: - self.producer.pauseProducing() - - def resumeProducing(self): - self.paused = False - if self._buffer: - # TODO: Check to see if consumer supports writeSeq. - self.consumer.write(''.join(self._buffer)) - self._buffer[:] = [] - else: - if not self.iAmStreaming: - self.outstandingPull = True - - if self.producer is not None: - self.producer.resumeProducing() - - def stopProducing(self): - if self.producer is not None: - self.producer.stopProducing() - if self.consumer is not None: - del self.consumer - - # Consumer methods: - - def write(self, data): - if self.paused or (not self.iAmStreaming and not self.outstandingPull): - # We could use that fifo queue here. - self._buffer.append(data) - - elif self.consumer is not None: - self.consumer.write(data) - self.outstandingPull = False - - def finish(self): - if self.consumer is not None: - self.consumer.finish() - self.unregisterProducer() - - def registerProducer(self, producer, streaming): - self.producer = producer - self.producerIsStreaming = streaming - - def unregisterProducer(self): - if self.producer is not None: - del self.producer - del self.producerIsStreaming - if self.consumer: - self.consumer.unregisterProducer() - - def __repr__(self): - return '<%s@%x around %s>' % (self.__class__, id(self), self.consumer) - - -class ProducerConsumerProxy(BasicProducerConsumerProxy): - """ProducerConsumerProxy with a finite buffer. - - When my buffer fills up, I have my parent Producer pause until my buffer - has room in it again. - """ - # Copies much from abstract.FileDescriptor - bufferSize = 2**2**2**2 - - producerPaused = False - unregistered = False - - def pauseProducing(self): - # Does *not* call up to ProducerConsumerProxy to relay the pause - # message through to my parent Producer. - self.paused = True - - def resumeProducing(self): - self.paused = False - if self._buffer: - data = ''.join(self._buffer) - bytesSent = self._writeSomeData(data) - if bytesSent < len(data): - unsent = data[bytesSent:] - assert not self.iAmStreaming, ( - "Streaming producer did not write all its data.") - self._buffer[:] = [unsent] - else: - self._buffer[:] = [] - else: - bytesSent = 0 - - if (self.unregistered and bytesSent and not self._buffer and - self.consumer is not None): - self.consumer.unregisterProducer() - - if not self.iAmStreaming: - self.outstandingPull = not bytesSent - - if self.producer is not None: - bytesBuffered = reduce(operator.add, - [len(s) for s in self._buffer], 0) - # TODO: You can see here the potential for high and low - # watermarks, where bufferSize would be the high mark when we - # ask the upstream producer to pause, and we wouldn't have - # it resume again until it hit the low mark. Or if producer - # is Pull, maybe we'd like to pull from it as much as necessary - # to keep our buffer full to the low mark, so we're never caught - # without something to send. - if self.producerPaused and (bytesBuffered < self.bufferSize): - # Now that our buffer is empty, - self.producerPaused = False - self.producer.resumeProducing() - elif self.outstandingPull: - # I did not have any data to write in response to a pull, - # so I'd better pull some myself. - self.producer.resumeProducing() - - def write(self, data): - if self.paused or (not self.iAmStreaming and not self.outstandingPull): - # We could use that fifo queue here. - self._buffer.append(data) - - elif self.consumer is not None: - assert not self._buffer, ( - "Writing fresh data to consumer before my buffer is empty!") - # I'm going to use _writeSomeData here so that there is only one - # path to self.consumer.write. But it doesn't actually make sense, - # if I am streaming, for some data to not be all data. But maybe I - # am not streaming, but I am writing here anyway, because there was - # an earlier request for data which was not answered. - bytesSent = self._writeSomeData(data) - self.outstandingPull = False - if not bytesSent == len(data): - assert not self.iAmStreaming, ( - "Streaming producer did not write all its data.") - self._buffer.append(data[bytesSent:]) - - if (self.producer is not None) and self.producerIsStreaming: - bytesBuffered = reduce(operator.add, - [len(s) for s in self._buffer], 0) - if bytesBuffered >= self.bufferSize: - - self.producer.pauseProducing() - self.producerPaused = True - - def registerProducer(self, producer, streaming): - self.unregistered = False - BasicProducerConsumerProxy.registerProducer(self, producer, streaming) - if not streaming: - producer.resumeProducing() - - def unregisterProducer(self): - if self.producer is not None: - del self.producer - del self.producerIsStreaming - self.unregistered = True - if self.consumer and not self._buffer: - self.consumer.unregisterProducer() - - def _writeSomeData(self, data): - """Write as much of this data as possible. - - @returns: The number of bytes written. - """ - if self.consumer is None: - return 0 - self.consumer.write(data) - return len(data) diff --git a/tools/buildbot/pylibs/twisted/protocols/policies.py b/tools/buildbot/pylibs/twisted/protocols/policies.py deleted file mode 100644 index ff99ddd..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/policies.py +++ /dev/null @@ -1,631 +0,0 @@ -# -*- test-case-name: twisted.test.test_policies -*- -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Resource limiting policies. - -@seealso: See also L{twisted.protocols.htb} for rate limiting. -""" - -# system imports -import sys, operator - -# twisted imports -from twisted.internet.protocol import ServerFactory, Protocol, ClientFactory -from twisted.internet import reactor, error -from twisted.python import log -from zope.interface import providedBy, directlyProvides - - -class ProtocolWrapper(Protocol): - """Wraps protocol instances and acts as their transport as well.""" - - disconnecting = 0 - - def __init__(self, factory, wrappedProtocol): - self.wrappedProtocol = wrappedProtocol - self.factory = factory - - def makeConnection(self, transport): - directlyProvides(self, *providedBy(self) + providedBy(transport)) - Protocol.makeConnection(self, transport) - - # Transport relaying - - def write(self, data): - self.transport.write(data) - - def writeSequence(self, data): - self.transport.writeSequence(data) - - def loseConnection(self): - self.disconnecting = 1 - self.transport.loseConnection() - - def getPeer(self): - return self.transport.getPeer() - - def getHost(self): - return self.transport.getHost() - - def registerProducer(self, producer, streaming): - self.transport.registerProducer(producer, streaming) - - def unregisterProducer(self): - self.transport.unregisterProducer() - - def stopConsuming(self): - self.transport.stopConsuming() - - def __getattr__(self, name): - return getattr(self.transport, name) - - # Protocol relaying - - def connectionMade(self): - self.factory.registerProtocol(self) - self.wrappedProtocol.makeConnection(self) - - def dataReceived(self, data): - self.wrappedProtocol.dataReceived(data) - - def connectionLost(self, reason): - self.factory.unregisterProtocol(self) - self.wrappedProtocol.connectionLost(reason) - - -class WrappingFactory(ClientFactory): - """Wraps a factory and its protocols, and keeps track of them.""" - - protocol = ProtocolWrapper - - def __init__(self, wrappedFactory): - self.wrappedFactory = wrappedFactory - self.protocols = {} - - def doStart(self): - self.wrappedFactory.doStart() - ClientFactory.doStart(self) - - def doStop(self): - self.wrappedFactory.doStop() - ClientFactory.doStop(self) - - def startedConnecting(self, connector): - self.wrappedFactory.startedConnecting(connector) - - def clientConnectionFailed(self, connector, reason): - self.wrappedFactory.clientConnectionFailed(connector, reason) - - def clientConnectionLost(self, connector, reason): - self.wrappedFactory.clientConnectionLost(connector, reason) - - def buildProtocol(self, addr): - return self.protocol(self, self.wrappedFactory.buildProtocol(addr)) - - def registerProtocol(self, p): - """Called by protocol to register itself.""" - self.protocols[p] = 1 - - def unregisterProtocol(self, p): - """Called by protocols when they go away.""" - del self.protocols[p] - - -class ThrottlingProtocol(ProtocolWrapper): - """Protocol for ThrottlingFactory.""" - - # wrap API for tracking bandwidth - - def write(self, data): - self.factory.registerWritten(len(data)) - ProtocolWrapper.write(self, data) - - def writeSequence(self, seq): - self.factory.registerWritten(reduce(operator.add, map(len, seq))) - ProtocolWrapper.writeSequence(self, seq) - - def dataReceived(self, data): - self.factory.registerRead(len(data)) - ProtocolWrapper.dataReceived(self, data) - - def registerProducer(self, producer, streaming): - self.producer = producer - ProtocolWrapper.registerProducer(self, producer, streaming) - - def unregisterProducer(self): - del self.producer - ProtocolWrapper.unregisterProducer(self) - - - def throttleReads(self): - self.transport.pauseProducing() - - def unthrottleReads(self): - self.transport.resumeProducing() - - def throttleWrites(self): - if hasattr(self, "producer"): - self.producer.pauseProducing() - - def unthrottleWrites(self): - if hasattr(self, "producer"): - self.producer.resumeProducing() - - -class ThrottlingFactory(WrappingFactory): - """ - Throttles bandwidth and number of connections. - - Write bandwidth will only be throttled if there is a producer - registered. - """ - - protocol = ThrottlingProtocol - - def __init__(self, wrappedFactory, maxConnectionCount=sys.maxint, - readLimit=None, writeLimit=None): - WrappingFactory.__init__(self, wrappedFactory) - self.connectionCount = 0 - self.maxConnectionCount = maxConnectionCount - self.readLimit = readLimit # max bytes we should read per second - self.writeLimit = writeLimit # max bytes we should write per second - self.readThisSecond = 0 - self.writtenThisSecond = 0 - self.unthrottleReadsID = None - self.checkReadBandwidthID = None - self.unthrottleWritesID = None - self.checkWriteBandwidthID = None - - - def callLater(self, period, func): - """ - Wrapper around L{reactor.callLater} for test purpose. - """ - return reactor.callLater(period, func) - - - def registerWritten(self, length): - """ - Called by protocol to tell us more bytes were written. - """ - self.writtenThisSecond += length - - - def registerRead(self, length): - """ - Called by protocol to tell us more bytes were read. - """ - self.readThisSecond += length - - - def checkReadBandwidth(self): - """ - Checks if we've passed bandwidth limits. - """ - if self.readThisSecond > self.readLimit: - self.throttleReads() - throttleTime = (float(self.readThisSecond) / self.readLimit) - 1.0 - self.unthrottleReadsID = self.callLater(throttleTime, - self.unthrottleReads) - self.readThisSecond = 0 - self.checkReadBandwidthID = self.callLater(1, self.checkReadBandwidth) - - - def checkWriteBandwidth(self): - if self.writtenThisSecond > self.writeLimit: - self.throttleWrites() - throttleTime = (float(self.writtenThisSecond) / self.writeLimit) - 1.0 - self.unthrottleWritesID = self.callLater(throttleTime, - self.unthrottleWrites) - # reset for next round - self.writtenThisSecond = 0 - self.checkWriteBandwidthID = self.callLater(1, self.checkWriteBandwidth) - - - def throttleReads(self): - """ - Throttle reads on all protocols. - """ - log.msg("Throttling reads on %s" % self) - for p in self.protocols.keys(): - p.throttleReads() - - - def unthrottleReads(self): - """ - Stop throttling reads on all protocols. - """ - self.unthrottleReadsID = None - log.msg("Stopped throttling reads on %s" % self) - for p in self.protocols.keys(): - p.unthrottleReads() - - - def throttleWrites(self): - """ - Throttle writes on all protocols. - """ - log.msg("Throttling writes on %s" % self) - for p in self.protocols.keys(): - p.throttleWrites() - - - def unthrottleWrites(self): - """ - Stop throttling writes on all protocols. - """ - self.unthrottleWritesID = None - log.msg("Stopped throttling writes on %s" % self) - for p in self.protocols.keys(): - p.unthrottleWrites() - - - def buildProtocol(self, addr): - if self.connectionCount == 0: - if self.readLimit is not None: - self.checkReadBandwidth() - if self.writeLimit is not None: - self.checkWriteBandwidth() - - if self.connectionCount < self.maxConnectionCount: - self.connectionCount += 1 - return WrappingFactory.buildProtocol(self, addr) - else: - log.msg("Max connection count reached!") - return None - - - def unregisterProtocol(self, p): - WrappingFactory.unregisterProtocol(self, p) - self.connectionCount -= 1 - if self.connectionCount == 0: - if self.unthrottleReadsID is not None: - self.unthrottleReadsID.cancel() - if self.checkReadBandwidthID is not None: - self.checkReadBandwidthID.cancel() - if self.unthrottleWritesID is not None: - self.unthrottleWritesID.cancel() - if self.checkWriteBandwidthID is not None: - self.checkWriteBandwidthID.cancel() - - - -class SpewingProtocol(ProtocolWrapper): - def dataReceived(self, data): - log.msg("Received: %r" % data) - ProtocolWrapper.dataReceived(self,data) - - def write(self, data): - log.msg("Sending: %r" % data) - ProtocolWrapper.write(self,data) - - - -class SpewingFactory(WrappingFactory): - protocol = SpewingProtocol - - - -class LimitConnectionsByPeer(WrappingFactory): - - maxConnectionsPerPeer = 5 - - def startFactory(self): - self.peerConnections = {} - - def buildProtocol(self, addr): - peerHost = addr[0] - connectionCount = self.peerConnections.get(peerHost, 0) - if connectionCount >= self.maxConnectionsPerPeer: - return None - self.peerConnections[peerHost] = connectionCount + 1 - return WrappingFactory.buildProtocol(self, addr) - - def unregisterProtocol(self, p): - peerHost = p.getPeer()[1] - self.peerConnections[peerHost] -= 1 - if self.peerConnections[peerHost] == 0: - del self.peerConnections[peerHost] - - -class LimitTotalConnectionsFactory(ServerFactory): - """ - Factory that limits the number of simultaneous connections. - - @type connectionCount: C{int} - @ivar connectionCount: number of current connections. - @type connectionLimit: C{int} or C{None} - @cvar connectionLimit: maximum number of connections. - @type overflowProtocol: L{Protocol} or C{None} - @cvar overflowProtocol: Protocol to use for new connections when - connectionLimit is exceeded. If C{None} (the default value), excess - connections will be closed immediately. - """ - connectionCount = 0 - connectionLimit = None - overflowProtocol = None - - def buildProtocol(self, addr): - if (self.connectionLimit is None or - self.connectionCount < self.connectionLimit): - # Build the normal protocol - wrappedProtocol = self.protocol() - elif self.overflowProtocol is None: - # Just drop the connection - return None - else: - # Too many connections, so build the overflow protocol - wrappedProtocol = self.overflowProtocol() - - wrappedProtocol.factory = self - protocol = ProtocolWrapper(self, wrappedProtocol) - self.connectionCount += 1 - return protocol - - def registerProtocol(self, p): - pass - - def unregisterProtocol(self, p): - self.connectionCount -= 1 - - - -class TimeoutProtocol(ProtocolWrapper): - """ - Protocol that automatically disconnects when the connection is idle. - """ - - def __init__(self, factory, wrappedProtocol, timeoutPeriod): - """ - Constructor. - - @param factory: An L{IFactory}. - @param wrappedProtocol: A L{Protocol} to wrapp. - @param timeoutPeriod: Number of seconds to wait for activity before - timing out. - """ - ProtocolWrapper.__init__(self, factory, wrappedProtocol) - self.timeoutCall = None - self.setTimeout(timeoutPeriod) - - - def setTimeout(self, timeoutPeriod=None): - """ - Set a timeout. - - This will cancel any existing timeouts. - - @param timeoutPeriod: If not C{None}, change the timeout period. - Otherwise, use the existing value. - """ - self.cancelTimeout() - if timeoutPeriod is not None: - self.timeoutPeriod = timeoutPeriod - self.timeoutCall = self.factory.callLater(self.timeoutPeriod, self.timeoutFunc) - - - def cancelTimeout(self): - """ - Cancel the timeout. - - If the timeout was already cancelled, this does nothing. - """ - if self.timeoutCall: - try: - self.timeoutCall.cancel() - except error.AlreadyCalled: - pass - self.timeoutCall = None - - - def resetTimeout(self): - """ - Reset the timeout, usually because some activity just happened. - """ - if self.timeoutCall: - self.timeoutCall.reset(self.timeoutPeriod) - - - def write(self, data): - self.resetTimeout() - ProtocolWrapper.write(self, data) - - - def writeSequence(self, seq): - self.resetTimeout() - ProtocolWrapper.writeSequence(self, seq) - - - def dataReceived(self, data): - self.resetTimeout() - ProtocolWrapper.dataReceived(self, data) - - - def connectionLost(self, reason): - self.cancelTimeout() - ProtocolWrapper.connectionLost(self, reason) - - - def timeoutFunc(self): - """ - This method is called when the timeout is triggered. - - By default it calls L{loseConnection}. Override this if you want - something else to happen. - """ - self.loseConnection() - - - -class TimeoutFactory(WrappingFactory): - """ - Factory for TimeoutWrapper. - """ - protocol = TimeoutProtocol - - - def __init__(self, wrappedFactory, timeoutPeriod=30*60): - self.timeoutPeriod = timeoutPeriod - WrappingFactory.__init__(self, wrappedFactory) - - - def buildProtocol(self, addr): - return self.protocol(self, self.wrappedFactory.buildProtocol(addr), - timeoutPeriod=self.timeoutPeriod) - - - def callLater(self, period, func): - """ - Wrapper around L{reactor.callLater} for test purpose. - """ - return reactor.callLater(period, func) - - - -class TrafficLoggingProtocol(ProtocolWrapper): - - def __init__(self, factory, wrappedProtocol, logfile, lengthLimit=None, - number=0): - """ - @param factory: factory which created this protocol. - @type factory: C{protocol.Factory}. - @param wrappedProtocol: the underlying protocol. - @type wrappedProtocol: C{protocol.Protocol}. - @param logfile: file opened for writing used to write log messages. - @type logfile: C{file} - @param lengthLimit: maximum size of the datareceived logged. - @type lengthLimit: C{int} - @param number: identifier of the connection. - @type number: C{int}. - """ - ProtocolWrapper.__init__(self, factory, wrappedProtocol) - self.logfile = logfile - self.lengthLimit = lengthLimit - self._number = number - - - def _log(self, line): - self.logfile.write(line + '\n') - self.logfile.flush() - - - def _mungeData(self, data): - if self.lengthLimit and len(data) > self.lengthLimit: - data = data[:self.lengthLimit - 12] + '<... elided>' - return data - - - # IProtocol - def connectionMade(self): - self._log('*') - return ProtocolWrapper.connectionMade(self) - - - def dataReceived(self, data): - self._log('C %d: %r' % (self._number, self._mungeData(data))) - return ProtocolWrapper.dataReceived(self, data) - - - def connectionLost(self, reason): - self._log('C %d: %r' % (self._number, reason)) - return ProtocolWrapper.connectionLost(self, reason) - - - # ITransport - def write(self, data): - self._log('S %d: %r' % (self._number, self._mungeData(data))) - return ProtocolWrapper.write(self, data) - - - def writeSequence(self, iovec): - self._log('SV %d: %r' % (self._number, [self._mungeData(d) for d in iovec])) - return ProtocolWrapper.writeSequence(self, iovec) - - - def loseConnection(self): - self._log('S %d: *' % (self._number,)) - return ProtocolWrapper.loseConnection(self) - - - -class TrafficLoggingFactory(WrappingFactory): - protocol = TrafficLoggingProtocol - - _counter = 0 - - def __init__(self, wrappedFactory, logfilePrefix, lengthLimit=None): - self.logfilePrefix = logfilePrefix - self.lengthLimit = lengthLimit - WrappingFactory.__init__(self, wrappedFactory) - - - def open(self, name): - return file(name, 'w') - - - def buildProtocol(self, addr): - self._counter += 1 - logfile = self.open(self.logfilePrefix + '-' + str(self._counter)) - return self.protocol(self, self.wrappedFactory.buildProtocol(addr), - logfile, self.lengthLimit, self._counter) - - - def resetCounter(self): - """ - Reset the value of the counter used to identify connections. - """ - self._counter = 0 - - - -class TimeoutMixin: - """Mixin for protocols which wish to timeout connections - - @cvar timeOut: The number of seconds after which to timeout the connection. - """ - timeOut = None - - __timeoutCall = None - - def callLater(self, period, func): - return reactor.callLater(period, func) - - - def resetTimeout(self): - """Reset the timeout count down""" - if self.__timeoutCall is not None and self.timeOut is not None: - self.__timeoutCall.reset(self.timeOut) - - def setTimeout(self, period): - """Change the timeout period - - @type period: C{int} or C{NoneType} - @param period: The period, in seconds, to change the timeout to, or - C{None} to disable the timeout. - """ - prev = self.timeOut - self.timeOut = period - - if self.__timeoutCall is not None: - if period is None: - self.__timeoutCall.cancel() - self.__timeoutCall = None - else: - self.__timeoutCall.reset(period) - elif period is not None: - self.__timeoutCall = self.callLater(period, self.__timedOut) - - return prev - - def __timedOut(self): - self.__timeoutCall = None - self.timeoutConnection() - - def timeoutConnection(self): - """Called when the connection times out. - Override to define behavior other than dropping the connection. - """ - self.transport.loseConnection() diff --git a/tools/buildbot/pylibs/twisted/protocols/pop3.py b/tools/buildbot/pylibs/twisted/protocols/pop3.py deleted file mode 100644 index 45d7f3ac..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/pop3.py +++ /dev/null @@ -1,6 +0,0 @@ -from twisted.python import util - -util.moduleMovedForSplit('twisted.protocols.pop3', 'twisted.mail.pop3', - 'POP3 protocol support', 'Mail', - 'http://twistedmatrix.com/projects/mail', - globals()) diff --git a/tools/buildbot/pylibs/twisted/protocols/portforward.py b/tools/buildbot/pylibs/twisted/protocols/portforward.py deleted file mode 100644 index 62f2aa3..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/portforward.py +++ /dev/null @@ -1,76 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -A simple port forwarder. -""" - -# Twisted imports -from twisted.internet import protocol -from twisted.python import log - -class Proxy(protocol.Protocol): - noisy = True - - peer = None - - def setPeer(self, peer): - self.peer = peer - - def connectionLost(self, reason): - if self.peer is not None: - self.peer.transport.loseConnection() - self.peer = None - elif self.noisy: - log.msg("Unable to connect to peer: %s" % (reason,)) - - def dataReceived(self, data): - self.peer.transport.write(data) - -class ProxyClient(Proxy): - def connectionMade(self): - self.peer.setPeer(self) - # We're connected, everybody can read to their hearts content. - self.peer.transport.resumeProducing() - -class ProxyClientFactory(protocol.ClientFactory): - - protocol = ProxyClient - - def setServer(self, server): - self.server = server - - def buildProtocol(self, *args, **kw): - prot = protocol.ClientFactory.buildProtocol(self, *args, **kw) - prot.setPeer(self.server) - return prot - - def clientConnectionFailed(self, connector, reason): - self.server.transport.loseConnection() - - -class ProxyServer(Proxy): - - clientProtocolFactory = ProxyClientFactory - - def connectionMade(self): - # Don't read anything from the connecting client until we have - # somewhere to send it to. - self.transport.pauseProducing() - - client = self.clientProtocolFactory() - client.setServer(self) - - from twisted.internet import reactor - reactor.connectTCP(self.factory.host, self.factory.port, client) - - -class ProxyFactory(protocol.Factory): - """Factory for port forwarder.""" - - protocol = ProxyServer - - def __init__(self, host, port): - self.host = host - self.port = port diff --git a/tools/buildbot/pylibs/twisted/protocols/postfix.py b/tools/buildbot/pylibs/twisted/protocols/postfix.py deleted file mode 100644 index ef85e50..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/postfix.py +++ /dev/null @@ -1,132 +0,0 @@ -# -*- test-case-name: twisted.test.test_postfix -*- -# -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -"""Postfix mail transport agent related protocols.""" - -import sys - -# Twisted imports -from twisted.protocols import basic -from twisted.protocols import policies -from twisted.internet import protocol, defer -from twisted.python import log -import UserDict -import urllib - -# urllib's quote functions just happen to match -# the postfix semantics. - -def quote(s): - return urllib.quote(s) - -def unquote(s): - return urllib.unquote(s) - -class PostfixTCPMapServer(basic.LineReceiver, policies.TimeoutMixin): - """Postfix mail transport agent TCP map protocol implementation. - - Receive requests for data matching given key via lineReceived, - asks it's factory for the data with self.factory.get(key), and - returns the data to the requester. None means no entry found. - - You can use postfix's postmap to test the map service:: - - /usr/sbin/postmap -q KEY tcp:localhost:4242 - - """ - - timeout = 600 - delimiter = '\n' - - def connectionMade(self): - self.setTimeout(self.timeout) - - def sendCode(self, code, message=''): - "Send an SMTP-like code with a message." - self.sendLine('%3.3d %s' % (code, message or '')) - - def lineReceived(self, line): - self.resetTimeout() - try: - request, params = line.split(None, 1) - except ValueError: - request = line - params = None - try: - f = getattr(self, 'do_' + request) - except AttributeError: - self.sendCode(400, 'unknown command') - else: - try: - f(params) - except: - self.sendCode(400, 'Command %r failed: %s.' % (request, sys.exc_info()[1])) - - def do_get(self, key): - if key is None: - self.sendCode(400, 'Command %r takes 1 parameters.' % 'get') - else: - d = defer.maybeDeferred(self.factory.get, key) - d.addCallbacks(self._cbGot, self._cbNot) - d.addErrback(log.err) - - def _cbNot(self, fail): - self.sendCode(400, fail.getErrorMessage()) - - def _cbGot(self, value): - if value is None: - self.sendCode(500) - else: - self.sendCode(200, quote(value)) - - def do_put(self, keyAndValue): - if keyAndValue is None: - self.sendCode(400, 'Command %r takes 2 parameters.' % 'put') - else: - try: - key, value = keyAndValue.split(None, 1) - except ValueError: - self.sendCode(400, 'Command %r takes 2 parameters.' % 'put') - else: - self.sendCode(500, 'put is not implemented yet.') - - -class PostfixTCPMapDictServerFactory(protocol.ServerFactory, - UserDict.UserDict): - """An in-memory dictionary factory for PostfixTCPMapServer.""" - - protocol = PostfixTCPMapServer - -class PostfixTCPMapDeferringDictServerFactory(protocol.ServerFactory): - """An in-memory dictionary factory for PostfixTCPMapServer.""" - - protocol = PostfixTCPMapServer - - def __init__(self, data=None): - self.data = {} - if data is not None: - self.data.update(data) - - def get(self, key): - return defer.succeed(self.data.get(key)) - -if __name__ == '__main__': - """Test app for PostfixTCPMapServer. Call with parameters - KEY1=VAL1 KEY2=VAL2 ...""" - from twisted.internet import reactor - log.startLogging(sys.stdout) - d = {} - for arg in sys.argv[1:]: - try: - k,v = arg.split('=', 1) - except ValueError: - k = arg - v = '' - d[k]=v - f=PostfixTCPMapDictServerFactory(d) - port = reactor.listenTCP(4242, f, interface='127.0.0.1') - reactor.run() diff --git a/tools/buildbot/pylibs/twisted/protocols/raw.py b/tools/buildbot/pylibs/twisted/protocols/raw.py deleted file mode 100644 index e01d613..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/raw.py +++ /dev/null @@ -1,7 +0,0 @@ -from twisted.python import util - -util.moduleMovedForSplit('twisted.protocols.raw', 'twisted.pair.raw', - 'Interfaces for raw packets', 'Pair', - 'http://twistedmatrix.com/projects/pair', - globals()) - diff --git a/tools/buildbot/pylibs/twisted/protocols/rawudp.py b/tools/buildbot/pylibs/twisted/protocols/rawudp.py deleted file mode 100644 index fec0ec0..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/rawudp.py +++ /dev/null @@ -1,7 +0,0 @@ -from twisted.python import util - -util.moduleMovedForSplit('twisted.protocols.rawudp', 'twisted.pair.rawudp', - 'Raw UDP', 'Pair', - 'http://twistedmatrix.com/projects/pair', - globals()) - diff --git a/tools/buildbot/pylibs/twisted/protocols/shoutcast.py b/tools/buildbot/pylibs/twisted/protocols/shoutcast.py deleted file mode 100644 index 553ec09..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/shoutcast.py +++ /dev/null @@ -1,120 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Chop up shoutcast stream into MP3s and metadata, if available.""" - -from twisted.web import http -from twisted import copyright - - -class ShoutcastClient(http.HTTPClient): - """Shoutcast HTTP stream. - - Modes can be 'length', 'meta' and 'mp3'. - - See http://www.smackfu.com/stuff/programming/shoutcast.html - for details on the protocol. - """ - - userAgent = "Twisted Shoutcast client " + copyright.version - - def __init__(self, path="/"): - self.path = path - self.got_metadata = False - self.metaint = None - self.metamode = "mp3" - self.databuffer = "" - - def connectionMade(self): - self.sendCommand("GET", self.path) - self.sendHeader("User-Agent", self.userAgent) - self.sendHeader("Icy-MetaData", "1") - self.endHeaders() - - def lineReceived(self, line): - # fix shoutcast crappiness - if not self.firstLine and line: - if len(line.split(": ", 1)) == 1: - line = line.replace(":", ": ", 1) - http.HTTPClient.lineReceived(self, line) - - def handleHeader(self, key, value): - if key.lower() == 'icy-metaint': - self.metaint = int(value) - self.got_metadata = True - - def handleEndHeaders(self): - # Lets check if we got metadata, and set the - # appropriate handleResponsePart method. - if self.got_metadata: - # if we have metadata, then it has to be parsed out of the data stream - self.handleResponsePart = self.handleResponsePart_with_metadata - else: - # otherwise, all the data is MP3 data - self.handleResponsePart = self.gotMP3Data - - def handleResponsePart_with_metadata(self, data): - self.databuffer += data - while self.databuffer: - stop = getattr(self, "handle_%s" % self.metamode)() - if stop: - return - - def handle_length(self): - self.remaining = ord(self.databuffer[0]) * 16 - self.databuffer = self.databuffer[1:] - self.metamode = "meta" - - def handle_mp3(self): - if len(self.databuffer) > self.metaint: - self.gotMP3Data(self.databuffer[:self.metaint]) - self.databuffer = self.databuffer[self.metaint:] - self.metamode = "length" - else: - return 1 - - def handle_meta(self): - if len(self.databuffer) >= self.remaining: - if self.remaining: - data = self.databuffer[:self.remaining] - self.gotMetaData(self.parseMetadata(data)) - self.databuffer = self.databuffer[self.remaining:] - self.metamode = "mp3" - else: - return 1 - - def parseMetadata(self, data): - meta = [] - for chunk in data.split(';'): - chunk = chunk.strip().replace("\x00", "") - if not chunk: - continue - key, value = chunk.split('=', 1) - if value.startswith("'") and value.endswith("'"): - value = value[1:-1] - meta.append((key, value)) - return meta - - def gotMetaData(self, metadata): - """Called with a list of (key, value) pairs of metadata, - if metadata is available on the server. - - Will only be called on non-empty metadata. - """ - raise NotImplementedError, "implement in subclass" - - def gotMP3Data(self, data): - """Called with chunk of MP3 data.""" - raise NotImplementedError, "implement in subclass" - - -if __name__ == '__main__': - class Test(ShoutcastClient): - def gotMetaData(self, data): print "meta:", data - def gotMP3Data(self, data): pass - - from twisted.internet import protocol, reactor - import sys - protocol.ClientCreator(reactor, Test).connectTCP(sys.argv[1], int(sys.argv[2])) - reactor.run() diff --git a/tools/buildbot/pylibs/twisted/protocols/sip.py b/tools/buildbot/pylibs/twisted/protocols/sip.py deleted file mode 100644 index 857c3fb..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/sip.py +++ /dev/null @@ -1,1190 +0,0 @@ -# -*- test-case-name: twisted.test.test_sip -*- - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Session Initialization Protocol. - -Documented in RFC 2543. -[Superceded by 3261] -""" - -# system imports -import socket -import random -import time -import md5 -import sys -from zope.interface import implements, Interface - -# twisted imports -from twisted.python import log, util -from twisted.internet import protocol, defer, reactor - -from twisted import cred -import twisted.cred.credentials -import twisted.cred.error - -# sibling imports -from twisted.protocols import basic - -PORT = 5060 - -# SIP headers have short forms -shortHeaders = {"call-id": "i", - "contact": "m", - "content-encoding": "e", - "content-length": "l", - "content-type": "c", - "from": "f", - "subject": "s", - "to": "t", - "via": "v", - } - -longHeaders = {} -for k, v in shortHeaders.items(): - longHeaders[v] = k -del k, v - -statusCodes = { - 100: "Trying", - 180: "Ringing", - 181: "Call Is Being Forwarded", - 182: "Queued", - 183: "Session Progress", - - 200: "OK", - - 300: "Multiple Choices", - 301: "Moved Permanently", - 302: "Moved Temporarily", - 303: "See Other", - 305: "Use Proxy", - 380: "Alternative Service", - - 400: "Bad Request", - 401: "Unauthorized", - 402: "Payment Required", - 403: "Forbidden", - 404: "Not Found", - 405: "Method Not Allowed", - 406: "Not Acceptable", - 407: "Proxy Authentication Required", - 408: "Request Timeout", - 409: "Conflict", # Not in RFC3261 - 410: "Gone", - 411: "Length Required", # Not in RFC3261 - 413: "Request Entity Too Large", - 414: "Request-URI Too Large", - 415: "Unsupported Media Type", - 416: "Unsupported URI Scheme", - 420: "Bad Extension", - 421: "Extension Required", - 423: "Interval Too Brief", - 480: "Temporarily Unavailable", - 481: "Call/Transaction Does Not Exist", - 482: "Loop Detected", - 483: "Too Many Hops", - 484: "Address Incomplete", - 485: "Ambiguous", - 486: "Busy Here", - 487: "Request Terminated", - 488: "Not Acceptable Here", - 491: "Request Pending", - 493: "Undecipherable", - - 500: "Internal Server Error", - 501: "Not Implemented", - 502: "Bad Gateway", # no donut - 503: "Service Unavailable", - 504: "Server Time-out", - 505: "SIP Version not supported", - 513: "Message Too Large", - - 600: "Busy Everywhere", - 603: "Decline", - 604: "Does not exist anywhere", - 606: "Not Acceptable", -} - -specialCases = { - 'cseq': 'CSeq', - 'call-id': 'Call-ID', - 'www-authenticate': 'WWW-Authenticate', -} - -def dashCapitalize(s): - ''' Capitalize a string, making sure to treat - as a word seperator ''' - return '-'.join([ x.capitalize() for x in s.split('-')]) - -def unq(s): - if s[0] == s[-1] == '"': - return s[1:-1] - return s - -def DigestCalcHA1( - pszAlg, - pszUserName, - pszRealm, - pszPassword, - pszNonce, - pszCNonce, -): - m = md5.md5() - m.update(pszUserName) - m.update(":") - m.update(pszRealm) - m.update(":") - m.update(pszPassword) - HA1 = m.digest() - if pszAlg == "md5-sess": - m = md5.md5() - m.update(HA1) - m.update(":") - m.update(pszNonce) - m.update(":") - m.update(pszCNonce) - HA1 = m.digest() - return HA1.encode('hex') - -def DigestCalcResponse( - HA1, - pszNonce, - pszNonceCount, - pszCNonce, - pszQop, - pszMethod, - pszDigestUri, - pszHEntity, -): - m = md5.md5() - m.update(pszMethod) - m.update(":") - m.update(pszDigestUri) - if pszQop == "auth-int": - m.update(":") - m.update(pszHEntity) - HA2 = m.digest().encode('hex') - - m = md5.md5() - m.update(HA1) - m.update(":") - m.update(pszNonce) - m.update(":") - if pszNonceCount and pszCNonce: # pszQop: - m.update(pszNonceCount) - m.update(":") - m.update(pszCNonce) - m.update(":") - m.update(pszQop) - m.update(":") - m.update(HA2) - hash = m.digest().encode('hex') - return hash - -class Via: - """A SIP Via header.""" - - def __init__(self, host, port=PORT, transport="UDP", ttl=None, hidden=False, - received=None, rport=None, branch=None, maddr=None): - self.transport = transport - self.host = host - self.port = port - self.ttl = ttl - self.hidden = hidden - self.received = received - self.rport = rport - self.branch = branch - self.maddr = maddr - - def toString(self): - s = "SIP/2.0/%s %s:%s" % (self.transport, self.host, self.port) - if self.hidden: - s += ";hidden" - for n in "ttl", "branch", "maddr", "received", "rport": - value = getattr(self, n) - if value == True: - s += ";" + n - elif value != None: - s += ";%s=%s" % (n, value) - return s - - -def parseViaHeader(value): - """Parse a Via header, returning Via class instance.""" - parts = value.split(";") - sent, params = parts[0], parts[1:] - protocolinfo, by = sent.split(" ", 1) - by = by.strip() - result = {} - pname, pversion, transport = protocolinfo.split("/") - if pname != "SIP" or pversion != "2.0": - raise ValueError, "wrong protocol or version: %r" % value - result["transport"] = transport - if ":" in by: - host, port = by.split(":") - result["port"] = int(port) - result["host"] = host - else: - result["host"] = by - for p in params: - # it's the comment-striping dance! - p = p.strip().split(" ", 1) - if len(p) == 1: - p, comment = p[0], "" - else: - p, comment = p - if p == "hidden": - result["hidden"] = True - continue - parts = p.split("=", 1) - if len(parts) == 1: - name, value = parts[0], True - else: - name, value = parts - if name in ("rport", "ttl"): - value = int(value) - result[name] = value - return Via(**result) - - -class URL: - """A SIP URL.""" - - def __init__(self, host, username=None, password=None, port=None, - transport=None, usertype=None, method=None, - ttl=None, maddr=None, tag=None, other=None, headers=None): - self.username = username - self.host = host - self.password = password - self.port = port - self.transport = transport - self.usertype = usertype - self.method = method - self.tag = tag - self.ttl = ttl - self.maddr = maddr - if other == None: - self.other = [] - else: - self.other = other - if headers == None: - self.headers = {} - else: - self.headers = headers - - def toString(self): - l = []; w = l.append - w("sip:") - if self.username != None: - w(self.username) - if self.password != None: - w(":%s" % self.password) - w("@") - w(self.host) - if self.port != None: - w(":%d" % self.port) - if self.usertype != None: - w(";user=%s" % self.usertype) - for n in ("transport", "ttl", "maddr", "method", "tag"): - v = getattr(self, n) - if v != None: - w(";%s=%s" % (n, v)) - for v in self.other: - w(";%s" % v) - if self.headers: - w("?") - w("&".join([("%s=%s" % (specialCases.get(h) or dashCapitalize(h), v)) for (h, v) in self.headers.items()])) - return "".join(l) - - def __str__(self): - return self.toString() - - def __repr__(self): - return '' % (self.username, self.password, self.host, self.port, self.transport) - - -def parseURL(url, host=None, port=None): - """Return string into URL object. - - URIs are of of form 'sip:user@example.com'. - """ - d = {} - if not url.startswith("sip:"): - raise ValueError("unsupported scheme: " + url[:4]) - parts = url[4:].split(";") - userdomain, params = parts[0], parts[1:] - udparts = userdomain.split("@", 1) - if len(udparts) == 2: - userpass, hostport = udparts - upparts = userpass.split(":", 1) - if len(upparts) == 1: - d["username"] = upparts[0] - else: - d["username"] = upparts[0] - d["password"] = upparts[1] - else: - hostport = udparts[0] - hpparts = hostport.split(":", 1) - if len(hpparts) == 1: - d["host"] = hpparts[0] - else: - d["host"] = hpparts[0] - d["port"] = int(hpparts[1]) - if host != None: - d["host"] = host - if port != None: - d["port"] = port - for p in params: - if p == params[-1] and "?" in p: - d["headers"] = h = {} - p, headers = p.split("?", 1) - for header in headers.split("&"): - k, v = header.split("=") - h[k] = v - nv = p.split("=", 1) - if len(nv) == 1: - d.setdefault("other", []).append(p) - continue - name, value = nv - if name == "user": - d["usertype"] = value - elif name in ("transport", "ttl", "maddr", "method", "tag"): - if name == "ttl": - value = int(value) - d[name] = value - else: - d.setdefault("other", []).append(p) - return URL(**d) - - -def cleanRequestURL(url): - """Clean a URL from a Request line.""" - url.transport = None - url.maddr = None - url.ttl = None - url.headers = {} - - -def parseAddress(address, host=None, port=None, clean=0): - """Return (name, uri, params) for From/To/Contact header. - - @param clean: remove unnecessary info, usually for From and To headers. - """ - address = address.strip() - # simple 'sip:foo' case - if address.startswith("sip:"): - return "", parseURL(address, host=host, port=port), {} - params = {} - name, url = address.split("<", 1) - name = name.strip() - if name.startswith('"'): - name = name[1:] - if name.endswith('"'): - name = name[:-1] - url, paramstring = url.split(">", 1) - url = parseURL(url, host=host, port=port) - paramstring = paramstring.strip() - if paramstring: - for l in paramstring.split(";"): - if not l: - continue - k, v = l.split("=") - params[k] = v - if clean: - # rfc 2543 6.21 - url.ttl = None - url.headers = {} - url.transport = None - url.maddr = None - return name, url, params - - -class SIPError(Exception): - def __init__(self, code, phrase=None): - if phrase is None: - phrase = statusCodes[code] - Exception.__init__(self, "SIP error (%d): %s" % (code, phrase)) - self.code = code - self.phrase = phrase - - -class RegistrationError(SIPError): - """Registration was not possible.""" - - -class Message: - """A SIP message.""" - - length = None - - def __init__(self): - self.headers = util.OrderedDict() # map name to list of values - self.body = "" - self.finished = 0 - - def addHeader(self, name, value): - name = name.lower() - name = longHeaders.get(name, name) - if name == "content-length": - self.length = int(value) - self.headers.setdefault(name,[]).append(value) - - def bodyDataReceived(self, data): - self.body += data - - def creationFinished(self): - if (self.length != None) and (self.length != len(self.body)): - raise ValueError, "wrong body length" - self.finished = 1 - - def toString(self): - s = "%s\r\n" % self._getHeaderLine() - for n, vs in self.headers.items(): - for v in vs: - s += "%s: %s\r\n" % (specialCases.get(n) or dashCapitalize(n), v) - s += "\r\n" - s += self.body - return s - - def _getHeaderLine(self): - raise NotImplementedError - - -class Request(Message): - """A Request for a URI""" - - - def __init__(self, method, uri, version="SIP/2.0"): - Message.__init__(self) - self.method = method - if isinstance(uri, URL): - self.uri = uri - else: - self.uri = parseURL(uri) - cleanRequestURL(self.uri) - - def __repr__(self): - return "" % (id(self), self.method, self.uri.toString()) - - def _getHeaderLine(self): - return "%s %s SIP/2.0" % (self.method, self.uri.toString()) - - -class Response(Message): - """A Response to a URI Request""" - - def __init__(self, code, phrase=None, version="SIP/2.0"): - Message.__init__(self) - self.code = code - if phrase == None: - phrase = statusCodes[code] - self.phrase = phrase - - def __repr__(self): - return "" % (id(self), self.code) - - def _getHeaderLine(self): - return "SIP/2.0 %s %s" % (self.code, self.phrase) - - -class MessagesParser(basic.LineReceiver): - """A SIP messages parser. - - Expects dataReceived, dataDone repeatedly, - in that order. Shouldn't be connected to actual transport. - """ - - version = "SIP/2.0" - acceptResponses = 1 - acceptRequests = 1 - state = "firstline" # or "headers", "body" or "invalid" - - debug = 0 - - def __init__(self, messageReceivedCallback): - self.messageReceived = messageReceivedCallback - self.reset() - - def reset(self, remainingData=""): - self.state = "firstline" - self.length = None # body length - self.bodyReceived = 0 # how much of the body we received - self.message = None - self.setLineMode(remainingData) - - def invalidMessage(self): - self.state = "invalid" - self.setRawMode() - - def dataDone(self): - # clear out any buffered data that may be hanging around - self.clearLineBuffer() - if self.state == "firstline": - return - if self.state != "body": - self.reset() - return - if self.length == None: - # no content-length header, so end of data signals message done - self.messageDone() - elif self.length < self.bodyReceived: - # aborted in the middle - self.reset() - else: - # we have enough data and message wasn't finished? something is wrong - raise RuntimeError, "this should never happen" - - def dataReceived(self, data): - try: - basic.LineReceiver.dataReceived(self, data) - except: - log.err() - self.invalidMessage() - - def handleFirstLine(self, line): - """Expected to create self.message.""" - raise NotImplementedError - - def lineLengthExceeded(self, line): - self.invalidMessage() - - def lineReceived(self, line): - if self.state == "firstline": - while line.startswith("\n") or line.startswith("\r"): - line = line[1:] - if not line: - return - try: - a, b, c = line.split(" ", 2) - except ValueError: - self.invalidMessage() - return - if a == "SIP/2.0" and self.acceptResponses: - # response - try: - code = int(b) - except ValueError: - self.invalidMessage() - return - self.message = Response(code, c) - elif c == "SIP/2.0" and self.acceptRequests: - self.message = Request(a, b) - else: - self.invalidMessage() - return - self.state = "headers" - return - else: - assert self.state == "headers" - if line: - # XXX support multi-line headers - try: - name, value = line.split(":", 1) - except ValueError: - self.invalidMessage() - return - self.message.addHeader(name, value.lstrip()) - if name.lower() == "content-length": - try: - self.length = int(value.lstrip()) - except ValueError: - self.invalidMessage() - return - else: - # CRLF, we now have message body until self.length bytes, - # or if no length was given, until there is no more data - # from the connection sending us data. - self.state = "body" - if self.length == 0: - self.messageDone() - return - self.setRawMode() - - def messageDone(self, remainingData=""): - assert self.state == "body" - self.message.creationFinished() - self.messageReceived(self.message) - self.reset(remainingData) - - def rawDataReceived(self, data): - assert self.state in ("body", "invalid") - if self.state == "invalid": - return - if self.length == None: - self.message.bodyDataReceived(data) - else: - dataLen = len(data) - expectedLen = self.length - self.bodyReceived - if dataLen > expectedLen: - self.message.bodyDataReceived(data[:expectedLen]) - self.messageDone(data[expectedLen:]) - return - else: - self.bodyReceived += dataLen - self.message.bodyDataReceived(data) - if self.bodyReceived == self.length: - self.messageDone() - - -class Base(protocol.DatagramProtocol): - """Base class for SIP clients and servers.""" - - PORT = PORT - debug = False - - def __init__(self): - self.messages = [] - self.parser = MessagesParser(self.addMessage) - - def addMessage(self, msg): - self.messages.append(msg) - - def datagramReceived(self, data, addr): - self.parser.dataReceived(data) - self.parser.dataDone() - for m in self.messages: - self._fixupNAT(m, addr) - if self.debug: - log.msg("Received %r from %r" % (m.toString(), addr)) - if isinstance(m, Request): - self.handle_request(m, addr) - else: - self.handle_response(m, addr) - self.messages[:] = [] - - def _fixupNAT(self, message, (srcHost, srcPort)): - # RFC 2543 6.40.2, - senderVia = parseViaHeader(message.headers["via"][0]) - if senderVia.host != srcHost: - senderVia.received = srcHost - if senderVia.port != srcPort: - senderVia.rport = srcPort - message.headers["via"][0] = senderVia.toString() - elif senderVia.rport == True: - senderVia.received = srcHost - senderVia.rport = srcPort - message.headers["via"][0] = senderVia.toString() - - def deliverResponse(self, responseMessage): - """Deliver response. - - Destination is based on topmost Via header.""" - destVia = parseViaHeader(responseMessage.headers["via"][0]) - # XXX we don't do multicast yet - host = destVia.received or destVia.host - port = destVia.rport or destVia.port or self.PORT - destAddr = URL(host=host, port=port) - self.sendMessage(destAddr, responseMessage) - - def responseFromRequest(self, code, request): - """Create a response to a request message.""" - response = Response(code) - for name in ("via", "to", "from", "call-id", "cseq"): - response.headers[name] = request.headers.get(name, [])[:] - - return response - - def sendMessage(self, destURL, message): - """Send a message. - - @param destURL: C{URL}. This should be a *physical* URL, not a logical one. - @param message: The message to send. - """ - if destURL.transport not in ("udp", None): - raise RuntimeError, "only UDP currently supported" - if self.debug: - log.msg("Sending %r to %r" % (message.toString(), destURL)) - self.transport.write(message.toString(), (destURL.host, destURL.port or self.PORT)) - - def handle_request(self, message, addr): - """Override to define behavior for requests received - - @type message: C{Message} - @type addr: C{tuple} - """ - raise NotImplementedError - - def handle_response(self, message, addr): - """Override to define behavior for responses received. - - @type message: C{Message} - @type addr: C{tuple} - """ - raise NotImplementedError - - -class IContact(Interface): - """A user of a registrar or proxy""" - - -class Registration: - def __init__(self, secondsToExpiry, contactURL): - self.secondsToExpiry = secondsToExpiry - self.contactURL = contactURL - -class IRegistry(Interface): - """Allows registration of logical->physical URL mapping.""" - - def registerAddress(domainURL, logicalURL, physicalURL): - """Register the physical address of a logical URL. - - @return: Deferred of C{Registration} or failure with RegistrationError. - """ - - def unregisterAddress(domainURL, logicalURL, physicalURL): - """Unregister the physical address of a logical URL. - - @return: Deferred of C{Registration} or failure with RegistrationError. - """ - - def getRegistrationInfo(logicalURL): - """Get registration info for logical URL. - - @return: Deferred of C{Registration} object or failure of LookupError. - """ - - -class ILocator(Interface): - """Allow looking up physical address for logical URL.""" - - def getAddress(logicalURL): - """Return physical URL of server for logical URL of user. - - @param logicalURL: a logical C{URL}. - @return: Deferred which becomes URL or fails with LookupError. - """ - - -class Proxy(Base): - """SIP proxy.""" - - PORT = PORT - - locator = None # object implementing ILocator - - def __init__(self, host=None, port=PORT): - """Create new instance. - - @param host: our hostname/IP as set in Via headers. - @param port: our port as set in Via headers. - """ - self.host = host or socket.getfqdn() - self.port = port - Base.__init__(self) - - def getVia(self): - """Return value of Via header for this proxy.""" - return Via(host=self.host, port=self.port) - - def handle_request(self, message, addr): - # send immediate 100/trying message before processing - #self.deliverResponse(self.responseFromRequest(100, message)) - f = getattr(self, "handle_%s_request" % message.method, None) - if f is None: - f = self.handle_request_default - try: - d = f(message, addr) - except SIPError, e: - self.deliverResponse(self.responseFromRequest(e.code, message)) - except: - log.err() - self.deliverResponse(self.responseFromRequest(500, message)) - else: - if d is not None: - d.addErrback(lambda e: - self.deliverResponse(self.responseFromRequest(e.code, message)) - ) - - def handle_request_default(self, message, (srcHost, srcPort)): - """Default request handler. - - Default behaviour for OPTIONS and unknown methods for proxies - is to forward message on to the client. - - Since at the moment we are stateless proxy, thats basically - everything. - """ - def _mungContactHeader(uri, message): - message.headers['contact'][0] = uri.toString() - return self.sendMessage(uri, message) - - viaHeader = self.getVia() - if viaHeader.toString() in message.headers["via"]: - # must be a loop, so drop message - log.msg("Dropping looped message.") - return - - message.headers["via"].insert(0, viaHeader.toString()) - name, uri, tags = parseAddress(message.headers["to"][0], clean=1) - - # this is broken and needs refactoring to use cred - d = self.locator.getAddress(uri) - d.addCallback(self.sendMessage, message) - d.addErrback(self._cantForwardRequest, message) - - def _cantForwardRequest(self, error, message): - error.trap(LookupError) - del message.headers["via"][0] # this'll be us - self.deliverResponse(self.responseFromRequest(404, message)) - - def deliverResponse(self, responseMessage): - """Deliver response. - - Destination is based on topmost Via header.""" - destVia = parseViaHeader(responseMessage.headers["via"][0]) - # XXX we don't do multicast yet - host = destVia.received or destVia.host - port = destVia.rport or destVia.port or self.PORT - - destAddr = URL(host=host, port=port) - self.sendMessage(destAddr, responseMessage) - - def responseFromRequest(self, code, request): - """Create a response to a request message.""" - response = Response(code) - for name in ("via", "to", "from", "call-id", "cseq"): - response.headers[name] = request.headers.get(name, [])[:] - return response - - def handle_response(self, message, addr): - """Default response handler.""" - v = parseViaHeader(message.headers["via"][0]) - if (v.host, v.port) != (self.host, self.port): - # we got a message not intended for us? - # XXX note this check breaks if we have multiple external IPs - # yay for suck protocols - log.msg("Dropping incorrectly addressed message") - return - del message.headers["via"][0] - if not message.headers["via"]: - # this message is addressed to us - self.gotResponse(message, addr) - return - self.deliverResponse(message) - - def gotResponse(self, message, addr): - """Called with responses that are addressed at this server.""" - pass - -class IAuthorizer(Interface): - def getChallenge(peer): - """Generate a challenge the client may respond to. - - @type peer: C{tuple} - @param peer: The client's address - - @rtype: C{str} - @return: The challenge string - """ - - def decode(response): - """Create a credentials object from the given response. - - @type response: C{str} - """ - -class BasicAuthorizer: - """Authorizer for insecure Basic (base64-encoded plaintext) authentication. - - This form of authentication is broken and insecure. Do not use it. - """ - - implements(IAuthorizer) - - def getChallenge(self, peer): - return None - - def decode(self, response): - # At least one SIP client improperly pads its Base64 encoded messages - for i in range(3): - try: - creds = (response + ('=' * i)).decode('base64') - except: - pass - else: - break - else: - # Totally bogus - raise SIPError(400) - p = creds.split(':', 1) - if len(p) == 2: - return cred.credentials.UsernamePassword(*p) - raise SIPError(400) - - -class DigestedCredentials(cred.credentials.UsernameHashedPassword): - """Yet Another Simple Digest-MD5 authentication scheme""" - - def __init__(self, username, fields, challenges): - self.username = username - self.fields = fields - self.challenges = challenges - - def checkPassword(self, password): - method = 'REGISTER' - response = self.fields.get('response') - uri = self.fields.get('uri') - nonce = self.fields.get('nonce') - cnonce = self.fields.get('cnonce') - nc = self.fields.get('nc') - algo = self.fields.get('algorithm', 'MD5') - qop = self.fields.get('qop-options', 'auth') - opaque = self.fields.get('opaque') - - if opaque not in self.challenges: - return False - del self.challenges[opaque] - - user, domain = self.username.split('@', 1) - if uri is None: - uri = 'sip:' + domain - - expected = DigestCalcResponse( - DigestCalcHA1(algo, user, domain, password, nonce, cnonce), - nonce, nc, cnonce, qop, method, uri, None, - ) - - return expected == response - -class DigestAuthorizer: - CHALLENGE_LIFETIME = 15 - - implements(IAuthorizer) - - def __init__(self): - self.outstanding = {} - - def generateNonce(self): - c = tuple([random.randrange(sys.maxint) for _ in range(3)]) - c = '%d%d%d' % c - return c - - def generateOpaque(self): - return str(random.randrange(sys.maxint)) - - def getChallenge(self, peer): - c = self.generateNonce() - o = self.generateOpaque() - self.outstanding[o] = c - return ','.join(( - 'nonce="%s"' % c, - 'opaque="%s"' % o, - 'qop-options="auth"', - 'algorithm="MD5"', - )) - - def decode(self, response): - response = ' '.join(response.splitlines()) - parts = response.split(',') - auth = dict([(k.strip(), unq(v.strip())) for (k, v) in [p.split('=', 1) for p in parts]]) - try: - username = auth['username'] - except KeyError: - raise SIPError(401) - try: - return DigestedCredentials(username, auth, self.outstanding) - except: - raise SIPError(400) - - -class RegisterProxy(Proxy): - """A proxy that allows registration for a specific domain. - - Unregistered users won't be handled. - """ - - portal = None - - registry = None # should implement IRegistry - - authorizers = { - 'digest': DigestAuthorizer(), - } - - def __init__(self, *args, **kw): - Proxy.__init__(self, *args, **kw) - self.liveChallenges = {} - - def handle_ACK_request(self, message, (host, port)): - # XXX - # ACKs are a client's way of indicating they got the last message - # Responding to them is not a good idea. - # However, we should keep track of terminal messages and re-transmit - # if no ACK is received. - pass - - def handle_REGISTER_request(self, message, (host, port)): - """Handle a registration request. - - Currently registration is not proxied. - """ - if self.portal is None: - # There is no portal. Let anyone in. - self.register(message, host, port) - else: - # There is a portal. Check for credentials. - if not message.headers.has_key("authorization"): - return self.unauthorized(message, host, port) - else: - return self.login(message, host, port) - - def unauthorized(self, message, host, port): - m = self.responseFromRequest(401, message) - for (scheme, auth) in self.authorizers.iteritems(): - chal = auth.getChallenge((host, port)) - if chal is None: - value = '%s realm="%s"' % (scheme.title(), self.host) - else: - value = '%s %s,realm="%s"' % (scheme.title(), chal, self.host) - m.headers.setdefault('www-authenticate', []).append(value) - self.deliverResponse(m) - - - def login(self, message, host, port): - parts = message.headers['authorization'][0].split(None, 1) - a = self.authorizers.get(parts[0].lower()) - if a: - try: - c = a.decode(parts[1]) - except SIPError: - raise - except: - log.err() - self.deliverResponse(self.responseFromRequest(500, message)) - else: - c.username += '@' + self.host - self.portal.login(c, None, IContact - ).addCallback(self._cbLogin, message, host, port - ).addErrback(self._ebLogin, message, host, port - ).addErrback(log.err - ) - else: - self.deliverResponse(self.responseFromRequest(501, message)) - - def _cbLogin(self, (i, a, l), message, host, port): - # It's stateless, matey. What a joke. - self.register(message, host, port) - - def _ebLogin(self, failure, message, host, port): - failure.trap(cred.error.UnauthorizedLogin) - self.unauthorized(message, host, port) - - def register(self, message, host, port): - """Allow all users to register""" - name, toURL, params = parseAddress(message.headers["to"][0], clean=1) - contact = None - if message.headers.has_key("contact"): - contact = message.headers["contact"][0] - - if message.headers.get("expires", [None])[0] == "0": - self.unregister(message, toURL, contact) - else: - # XXX Check expires on appropriate URL, and pass it to registry - # instead of having registry hardcode it. - if contact is not None: - name, contactURL, params = parseAddress(contact, host=host, port=port) - d = self.registry.registerAddress(message.uri, toURL, contactURL) - else: - d = self.registry.getRegistrationInfo(toURL) - d.addCallbacks(self._cbRegister, self._ebRegister, - callbackArgs=(message,), - errbackArgs=(message,) - ) - - def _cbRegister(self, registration, message): - response = self.responseFromRequest(200, message) - if registration.contactURL != None: - response.addHeader("contact", registration.contactURL.toString()) - response.addHeader("expires", "%d" % registration.secondsToExpiry) - response.addHeader("content-length", "0") - self.deliverResponse(response) - - def _ebRegister(self, error, message): - error.trap(RegistrationError, LookupError) - # XXX return error message, and alter tests to deal with - # this, currently tests assume no message sent on failure - - def unregister(self, message, toURL, contact): - try: - expires = int(message.headers["expires"][0]) - except ValueError: - self.deliverResponse(self.responseFromRequest(400, message)) - else: - if expires == 0: - if contact == "*": - contactURL = "*" - else: - name, contactURL, params = parseAddress(contact) - d = self.registry.unregisterAddress(message.uri, toURL, contactURL) - d.addCallback(self._cbUnregister, message - ).addErrback(self._ebUnregister, message - ) - - def _cbUnregister(self, registration, message): - msg = self.responseFromRequest(200, message) - msg.headers.setdefault('contact', []).append(registration.contactURL.toString()) - msg.addHeader("expires", "0") - self.deliverResponse(msg) - - def _ebUnregister(self, registration, message): - pass - - -class InMemoryRegistry: - """A simplistic registry for a specific domain.""" - - implements(IRegistry, ILocator) - - def __init__(self, domain): - self.domain = domain # the domain we handle registration for - self.users = {} # map username to (IDelayedCall for expiry, address URI) - - def getAddress(self, userURI): - if userURI.host != self.domain: - return defer.fail(LookupError("unknown domain")) - if self.users.has_key(userURI.username): - dc, url = self.users[userURI.username] - return defer.succeed(url) - else: - return defer.fail(LookupError("no such user")) - - def getRegistrationInfo(self, userURI): - if userURI.host != self.domain: - return defer.fail(LookupError("unknown domain")) - if self.users.has_key(userURI.username): - dc, url = self.users[userURI.username] - return defer.succeed(Registration(int(dc.getTime() - time.time()), url)) - else: - return defer.fail(LookupError("no such user")) - - def _expireRegistration(self, username): - try: - dc, url = self.users[username] - except KeyError: - return defer.fail(LookupError("no such user")) - else: - dc.cancel() - del self.users[username] - return defer.succeed(Registration(0, url)) - - def registerAddress(self, domainURL, logicalURL, physicalURL): - if domainURL.host != self.domain: - log.msg("Registration for domain we don't handle.") - return defer.fail(RegistrationError(404)) - if logicalURL.host != self.domain: - log.msg("Registration for domain we don't handle.") - return defer.fail(RegistrationError(404)) - if self.users.has_key(logicalURL.username): - dc, old = self.users[logicalURL.username] - dc.reset(3600) - else: - dc = reactor.callLater(3600, self._expireRegistration, logicalURL.username) - log.msg("Registered %s at %s" % (logicalURL.toString(), physicalURL.toString())) - self.users[logicalURL.username] = (dc, physicalURL) - return defer.succeed(Registration(int(dc.getTime() - time.time()), physicalURL)) - - def unregisterAddress(self, domainURL, logicalURL, physicalURL): - return self._expireRegistration(logicalURL.username) diff --git a/tools/buildbot/pylibs/twisted/protocols/smtp.py b/tools/buildbot/pylibs/twisted/protocols/smtp.py deleted file mode 100644 index c6bd37a..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/smtp.py +++ /dev/null @@ -1,6 +0,0 @@ -from twisted.python import util - -util.moduleMovedForSplit('twisted.protocols.smtp', 'twisted.mail.smtp', - 'SMTP protocol support', 'Mail', - 'http://twistedmatrix.com/projects/mail', - globals()) diff --git a/tools/buildbot/pylibs/twisted/protocols/socks.py b/tools/buildbot/pylibs/twisted/protocols/socks.py deleted file mode 100644 index eda2e97..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/socks.py +++ /dev/null @@ -1,173 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Implementation of the SOCKSv4 protocol. -""" - -# twisted imports -from twisted.internet import reactor, protocol, defer -from twisted.python import log - -# python imports -import struct -import string -import socket -import time - - -class SOCKSv4Outgoing(protocol.Protocol): - - def __init__(self,socks): - self.socks=socks - - def connectionMade(self): - peer = self.transport.getPeer() - self.socks.makeReply(90, 0, port=peer.port, ip=peer.host) - self.socks.otherConn=self - - def connectionLost(self, reason): - self.socks.transport.loseConnection() - - def dataReceived(self,data): - self.socks.write(data) - - def write(self,data): - self.socks.log(self,data) - self.transport.write(data) - - -class SOCKSv4Incoming(protocol.Protocol): - - def __init__(self,socks): - self.socks=socks - self.socks.otherConn=self - - def connectionLost(self, reason): - self.socks.transport.loseConnection() - - def dataReceived(self,data): - self.socks.write(data) - - def write(self,data): - self.socks.log(self,data) - self.transport.write(data) - - -class SOCKSv4(protocol.Protocol): - - def __init__(self,logging=None): - self.logging=logging - - def connectionMade(self): - self.buf="" - self.otherConn=None - - def dataReceived(self,data): - if self.otherConn: - self.otherConn.write(data) - return - self.buf=self.buf+data - if '\000' in self.buf[8:]: - head,self.buf=self.buf[:8],self.buf[8:] - try: - version,code,port=struct.unpack("!BBH",head[:4]) - except struct.error: - raise RuntimeError, "struct error with head='%s' and buf='%s'"%(repr(head),repr(self.buf)) - user,self.buf=string.split(self.buf,"\000",1) - if head[4:7]=="\000\000\000": # domain is after - server,self.buf=string.split(self.buf,'\000',1) - #server=gethostbyname(server) - else: - server=socket.inet_ntoa(head[4:8]) - assert version==4, "Bad version code: %s"%version - if not self.authorize(code,server,port,user): - self.makeReply(91) - return - if code==1: # CONNECT - d = self.connectClass(server, port, SOCKSv4Outgoing, self) - d.addErrback(lambda result, self=self: self.makeReply(91)) - elif code==2: # BIND - ip = socket.gethostbyname(server) - d = self.listenClass(0, SOCKSv4IncomingFactory, self, ip) - d.addCallback(lambda (h, p), self=self: self.makeReply(90, 0, p, h)) - else: - raise RuntimeError, "Bad Connect Code: %s" % code - assert self.buf=="","hmm, still stuff in buffer... %s" % repr(self.buf) - - def connectionLost(self, reason): - if self.otherConn: - self.otherConn.transport.loseConnection() - - def authorize(self,code,server,port,user): - log.msg("code %s connection to %s:%s (user %s) authorized" % (code,server,port,user)) - return 1 - - def connectClass(self, host, port, klass, *args): - return protocol.ClientCreator(reactor, klass, *args).connectTCP(host,port) - - def listenClass(self, port, klass, *args): - serv = reactor.listenTCP(port, klass(*args)) - return defer.succeed(serv.getHost()[1:]) - - def makeReply(self,reply,version=0,port=0,ip="0.0.0.0"): - self.transport.write(struct.pack("!BBH",version,reply,port)+socket.inet_aton(ip)) - if reply!=90: self.transport.loseConnection() - - def write(self,data): - self.log(self,data) - self.transport.write(data) - - def log(self,proto,data): - if not self.logging: return - peer = self.transport.getPeer() - their_peer = self.otherConn.transport.getPeer() - f=open(self.logging,"a") - f.write("%s\t%s:%d %s %s:%d\n"%(time.ctime(), - peer.host,peer.port, - ((proto==self and '<') or '>'), - their_peer.host,their_peer.port)) - while data: - p,data=data[:16],data[16:] - f.write(string.join(map(lambda x:'%02X'%ord(x),p),' ')+' ') - f.write((16-len(p))*3*' ') - for c in p: - if len(repr(c))>3: f.write('.') - else: f.write(c) - f.write('\n') - f.write('\n') - f.close() - - -class SOCKSv4Factory(protocol.Factory): - """A factory for a SOCKSv4 proxy. - - Constructor accepts one argument, a log file name. - """ - - def __init__(self, log): - self.logging = log - - def buildProtocol(self, addr): - return SOCKSv4(self.logging) - - -class SOCKSv4IncomingFactory(protocol.Factory): - """A utility class for building protocols for incoming connections.""" - - def __init__(self, socks, ip): - self.socks = socks - self.ip = ip - - def buildProtocol(self, addr): - if addr[0] == self.ip: - self.ip = "" - self.socks.makeReply(90, 0) - return SOCKSv4Incoming(self.socks) - elif self.ip == "": - return None - else: - self.socks.makeReply(91, 0) - self.ip = "" - return None diff --git a/tools/buildbot/pylibs/twisted/protocols/stateful.py b/tools/buildbot/pylibs/twisted/protocols/stateful.py deleted file mode 100644 index 75313f6..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/stateful.py +++ /dev/null @@ -1,52 +0,0 @@ -# -*- test-case-name: twisted.test.test_stateful -*- - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -from twisted.internet import protocol - -try: - from cStringIO import StringIO -except ImportError: - from StringIO import StringIO - -class StatefulProtocol(protocol.Protocol): - """A Protocol that stores state for you. - - state is a pair (function, num_bytes). When num_bytes bytes of data arrives - from the network, function is called. It is expected to return the next - state or None to keep same state. Initial state is returned by - getInitialState (override it). - """ - _sful_data = None, None, 0 - - def makeConnection(self, transport): - protocol.Protocol.makeConnection(self, transport) - self._sful_data = self.getInitialState(), StringIO(), 0 - - def getInitialState(self): - raise NotImplementedError - - def dataReceived(self, data): - state, buffer, offset = self._sful_data - buffer.seek(0, 2) - buffer.write(data) - blen = buffer.tell() # how many bytes total is in the buffer - buffer.seek(offset) - while blen - offset >= state[1]: - d = buffer.read(state[1]) - offset += state[1] - next = state[0](d) - if self.transport.disconnecting: # XXX: argh stupid hack borrowed right from LineReceiver - return # dataReceived won't be called again, so who cares about consistent state - if next: - state = next - if offset != 0: - b = buffer.read() - buffer.reset() - buffer.truncate() - buffer.write(b) - offset = 0 - self._sful_data = state, buffer, offset - diff --git a/tools/buildbot/pylibs/twisted/protocols/sux.py b/tools/buildbot/pylibs/twisted/protocols/sux.py deleted file mode 100644 index eae965d..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/sux.py +++ /dev/null @@ -1,7 +0,0 @@ -from twisted.python import util - -util.moduleMovedForSplit('twisted.protocols.sux', 'twisted.web.sux', - 'SAX-like XML parser', 'Web', - 'http://twistedmatrix.com/projects/web', - globals()) - diff --git a/tools/buildbot/pylibs/twisted/protocols/telnet.py b/tools/buildbot/pylibs/twisted/protocols/telnet.py deleted file mode 100644 index 592d93a..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/telnet.py +++ /dev/null @@ -1,325 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""TELNET implementation, with line-oriented command handling. -""" - -import warnings -warnings.warn( - "As of Twisted 2.1, twisted.protocols.telnet is deprecated. " - "See twisted.conch.telnet for the current, supported API.", - DeprecationWarning, - stacklevel=2) - - -# System Imports -try: - from cStringIO import StringIO -except ImportError: - from StringIO import StringIO - -# Twisted Imports -from twisted import copyright -from twisted.internet import protocol - -# Some utility chars. -ESC = chr(27) # ESC for doing fanciness -BOLD_MODE_ON = ESC+"[1m" # turn bold on -BOLD_MODE_OFF= ESC+"[m" # no char attributes - - -# Characters gleaned from the various (and conflicting) RFCs. Not all of these are correct. - -NULL = chr(0) # No operation. -LF = chr(10) # Moves the printer to the - # next print line, keeping the - # same horizontal position. -CR = chr(13) # Moves the printer to the left - # margin of the current line. -BEL = chr(7) # Produces an audible or - # visible signal (which does - # NOT move the print head). -BS = chr(8) # Moves the print head one - # character position towards - # the left margin. -HT = chr(9) # Moves the printer to the - # next horizontal tab stop. - # It remains unspecified how - # either party determines or - # establishes where such tab - # stops are located. -VT = chr(11) # Moves the printer to the - # next vertical tab stop. It - # remains unspecified how - # either party determines or - # establishes where such tab - # stops are located. -FF = chr(12) # Moves the printer to the top - # of the next page, keeping - # the same horizontal position. -SE = chr(240) # End of subnegotiation parameters. -NOP= chr(241) # No operation. -DM = chr(242) # "Data Mark": The data stream portion - # of a Synch. This should always be - # accompanied by a TCP Urgent - # notification. -BRK= chr(243) # NVT character Break. -IP = chr(244) # The function Interrupt Process. -AO = chr(245) # The function Abort Output -AYT= chr(246) # The function Are You There. -EC = chr(247) # The function Erase Character. -EL = chr(248) # The function Erase Line -GA = chr(249) # The Go Ahead signal. -SB = chr(250) # Indicates that what follows is - # subnegotiation of the indicated - # option. -WILL = chr(251) # Indicates the desire to begin - # performing, or confirmation that - # you are now performing, the - # indicated option. -WONT = chr(252) # Indicates the refusal to perform, - # or continue performing, the - # indicated option. -DO = chr(253) # Indicates the request that the - # other party perform, or - # confirmation that you are expecting - # the other party to perform, the - # indicated option. -DONT = chr(254) # Indicates the demand that the - # other party stop performing, - # or confirmation that you are no - # longer expecting the other party - # to perform, the indicated option. -IAC = chr(255) # Data Byte 255. - -# features - -ECHO = chr(1) # User-to-Server: Asks the server to send - # Echos of the transmitted data. - - # Server-to User: States that the server is - # sending echos of the transmitted data. - # Sent only as a reply to ECHO or NO ECHO. - -SUPGA = chr(3) # Supress Go Ahead...? "Modern" telnet servers - # are supposed to do this. - -LINEMODE = chr(34) # I don't care that Jon Postel is dead. - -HIDE = chr(133) # The intention is that a server will send - # this signal to a user system which is - # echoing locally (to the user) when the user - # is about to type something secret (e.g. a - # password). In this case, the user system - # is to suppress local echoing or overprint - # the input (or something) until the server - # sends a NOECHO signal. In situations where - # the user system is not echoing locally, - # this signal must not be sent by the server. - - -NOECHO= chr(131) # User-to-Server: Asks the server not to - # return Echos of the transmitted data. - # - # Server-to-User: States that the server is - # not sending echos of the transmitted data. - # Sent only as a reply to ECHO or NO ECHO, - # or to end the hide your input. - - - -iacBytes = { - DO: 'DO', - DONT: 'DONT', - WILL: 'WILL', - WONT: 'WONT', - IP: 'IP' - } - -def multireplace(st, dct): - for k, v in dct.items(): - st = st.replace(k, v) - return st - -class Telnet(protocol.Protocol): - """I am a Protocol for handling Telnet connections. I have two - sets of special methods, telnet_* and iac_*. - - telnet_* methods get called on every line sent to me. The method - to call is decided by the current mode. The initial mode is 'User'; - this means that telnet_User is the first telnet_* method to be called. - All telnet_* methods should return a string which specifies the mode - to go into next; thus dictating which telnet_* method to call next. - For example, the default telnet_User method returns 'Password' to go - into Password mode, and the default telnet_Password method returns - 'Command' to go into Command mode. - - The iac_* methods are less-used; they are called when an IAC telnet - byte is received. You can define iac_DO, iac_DONT, iac_WILL, iac_WONT, - and iac_IP methods to do what you want when one of these bytes is - received.""" - - - gotIAC = 0 - iacByte = None - lastLine = None - buffer = '' - echo = 0 - delimiters = ['\r\n', '\r\000'] - mode = "User" - - def write(self, data): - """Send the given data over my transport.""" - self.transport.write(data) - - - def connectionMade(self): - """I will write a welcomeMessage and loginPrompt to the client.""" - self.write(self.welcomeMessage() + self.loginPrompt()) - - def welcomeMessage(self): - """Override me to return a string which will be sent to the client - before login.""" - x = self.factory.__class__ - return ("\r\n" + x.__module__ + '.' + x.__name__ + - '\r\nTwisted %s\r\n' % copyright.version - ) - - def loginPrompt(self): - """Override me to return a 'login:'-type prompt.""" - return "username: " - - def iacSBchunk(self, chunk): - pass - - def iac_DO(self, feature): - pass - - def iac_DONT(self, feature): - pass - - def iac_WILL(self, feature): - pass - - def iac_WONT(self, feature): - pass - - def iac_IP(self, feature): - pass - - def processLine(self, line): - """I call a method that looks like 'telnet_*' where '*' is filled - in by the current mode. telnet_* methods should return a string which - will become the new mode. If None is returned, the mode will not change. - """ - mode = getattr(self, "telnet_"+self.mode)(line) - if mode is not None: - self.mode = mode - - def telnet_User(self, user): - """I take a username, set it to the 'self.username' attribute, - print out a password prompt, and switch to 'Password' mode. If - you want to do something else when the username is received (ie, - create a new user if the user doesn't exist), override me.""" - self.username = user - self.write(IAC+WILL+ECHO+"password: ") - return "Password" - - def telnet_Password(self, paswd): - """I accept a password as an argument, and check it with the - checkUserAndPass method. If the login is successful, I call - loggedIn().""" - self.write(IAC+WONT+ECHO+"*****\r\n") - try: - checked = self.checkUserAndPass(self.username, paswd) - except: - return "Done" - if not checked: - return "Done" - self.loggedIn() - return "Command" - - def telnet_Command(self, cmd): - """The default 'command processing' mode. You probably want to - override me.""" - return "Command" - - def processChunk(self, chunk): - """I take a chunk of data and delegate out to telnet_* methods - by way of processLine. If the current mode is 'Done', I'll close - the connection. """ - self.buffer = self.buffer + chunk - - #yech. - for delim in self.delimiters: - idx = self.buffer.find(delim) - if idx != -1: - break - - while idx != -1: - buf, self.buffer = self.buffer[:idx], self.buffer[idx+2:] - self.processLine(buf) - if self.mode == 'Done': - self.transport.loseConnection() - - for delim in self.delimiters: - idx = self.buffer.find(delim) - if idx != -1: - break - - def dataReceived(self, data): - chunk = StringIO() - # silly little IAC state-machine - for char in data: - if self.gotIAC: - # working on an IAC request state - if self.iacByte: - # we're in SB mode, getting a chunk - if self.iacByte == SB: - if char == SE: - self.iacSBchunk(chunk.getvalue()) - chunk = StringIO() - del self.iacByte - del self.gotIAC - else: - chunk.write(char) - else: - # got all I need to know state - try: - getattr(self, 'iac_%s' % iacBytes[self.iacByte])(char) - except KeyError: - pass - del self.iacByte - del self.gotIAC - else: - # got IAC, this is my W/W/D/D (or perhaps sb) - self.iacByte = char - elif char == IAC: - # Process what I've got so far before going into - # the IAC state; don't want to process characters - # in an inconsistent state with what they were - # received in. - c = chunk.getvalue() - if c: - why = self.processChunk(c) - if why: - return why - chunk = StringIO() - self.gotIAC = 1 - else: - chunk.write(char) - # chunks are of a relatively indeterminate size. - c = chunk.getvalue() - if c: - why = self.processChunk(c) - if why: - return why - - def loggedIn(self): - """Called after the user succesfully logged in. - - Override in subclasses. - """ - pass diff --git a/tools/buildbot/pylibs/twisted/protocols/toc.py b/tools/buildbot/pylibs/twisted/protocols/toc.py deleted file mode 100644 index 8beaa2c..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/toc.py +++ /dev/null @@ -1,7 +0,0 @@ -from twisted.python import util - -util.moduleMovedForSplit('twisted.protocols.toc', 'twisted.words.protocols.toc', - 'TOC protocol support', 'Words', - 'http://twistedmatrix.com/projects/words', - globals()) - diff --git a/tools/buildbot/pylibs/twisted/protocols/wire.py b/tools/buildbot/pylibs/twisted/protocols/wire.py deleted file mode 100644 index 3bcbec1..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/wire.py +++ /dev/null @@ -1,90 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -"""Implement standard (and unused) TCP protocols. - -These protocols are either provided by inetd, or are not provided at all. -""" - -# system imports -import time, struct -from zope.interface import implements - -# twisted import -from twisted.internet import protocol, interfaces - - -class Echo(protocol.Protocol): - """As soon as any data is received, write it back (RFC 862)""" - - def dataReceived(self, data): - self.transport.write(data) - - -class Discard(protocol.Protocol): - """Discard any received data (RFC 863)""" - - def dataReceived(self, data): - # I'm ignoring you, nyah-nyah - pass - - -class Chargen(protocol.Protocol): - """Generate repeating noise (RFC 864)""" - noise = r'@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&?' - - implements(interfaces.IProducer) - - def connectionMade(self): - self.transport.registerProducer(self, 0) - - def resumeProducing(self): - self.transport.write(self.noise) - - def pauseProducing(self): - pass - - def stopProducing(self): - pass - - -class QOTD(protocol.Protocol): - """Return a quote of the day (RFC 865)""" - - def connectionMade(self): - self.transport.write(self.getQuote()) - self.transport.loseConnection() - - def getQuote(self): - """Return a quote. May be overrriden in subclasses.""" - return "An apple a day keeps the doctor away.\r\n" - -class Who(protocol.Protocol): - """Return list of active users (RFC 866)""" - - def connectionMade(self): - self.transport.write(self.getUsers()) - self.transport.loseConnection() - - def getUsers(self): - """Return active users. Override in subclasses.""" - return "root\r\n" - - -class Daytime(protocol.Protocol): - """Send back the daytime in ASCII form (RFC 867)""" - - def connectionMade(self): - self.transport.write(time.asctime(time.gmtime(time.time())) + '\r\n') - self.transport.loseConnection() - - -class Time(protocol.Protocol): - """Send back the time in machine readable form (RFC 868)""" - - def connectionMade(self): - # is this correct only for 32-bit machines? - result = struct.pack("!i", int(time.time())) - self.transport.write(result) - self.transport.loseConnection() - diff --git a/tools/buildbot/pylibs/twisted/protocols/xmlstream.py b/tools/buildbot/pylibs/twisted/protocols/xmlstream.py deleted file mode 100644 index a567cbf..0000000 --- a/tools/buildbot/pylibs/twisted/protocols/xmlstream.py +++ /dev/null @@ -1,5 +0,0 @@ -import warnings -warnings.warn("twisted.protocols.xmlstream is DEPRECATED. import twisted.words.xish.xmlstream instead.", - DeprecationWarning, stacklevel=2) - -from twisted.words.xish.xmlstream import * diff --git a/tools/buildbot/pylibs/twisted/python/__init__.py b/tools/buildbot/pylibs/twisted/python/__init__.py deleted file mode 100644 index 6fc1955..0000000 --- a/tools/buildbot/pylibs/twisted/python/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" - -Twisted Python: Utilities and Enhancements for Python. - -""" - - - diff --git a/tools/buildbot/pylibs/twisted/python/_epoll.c b/tools/buildbot/pylibs/twisted/python/_epoll.c deleted file mode 100644 index 00300c6..0000000 --- a/tools/buildbot/pylibs/twisted/python/_epoll.c +++ /dev/null @@ -1,925 +0,0 @@ -/* Generated by Pyrex 0.9.4.1 on Sun Oct 15 15:04:09 2006 */ - -#define PY_SSIZE_T_CLEAN -#include "Python.h" -#include "structmember.h" -#ifndef PY_LONG_LONG - #define PY_LONG_LONG LONG_LONG -#endif -#if PY_VERSION_HEX < 0x02050000 - typedef int Py_ssize_t; - #define PY_SSIZE_T_MAX INT_MAX - #define PY_SSIZE_T_MIN INT_MIN - #define PyInt_FromSsize_t(z) PyInt_FromLong(z) - #define PyInt_AsSsize_t(o) PyInt_AsLong(o) -#endif -#ifdef __cplusplus -#define __PYX_EXTERN_C extern "C" -#else -#define __PYX_EXTERN_C extern -#endif -__PYX_EXTERN_C double pow(double, double); -#include "stdio.h" -#include "errno.h" -#include "string.h" -#include "stdint.h" -#include "sys/epoll.h" - - -typedef struct {const char *s; const void **p;} __Pyx_CApiTabEntry; /*proto*/ -typedef struct {PyObject **p; char *s;} __Pyx_InternTabEntry; /*proto*/ -typedef struct {PyObject **p; char *s; long n;} __Pyx_StringTabEntry; /*proto*/ -static PyObject *__Pyx_UnpackItem(PyObject *, Py_ssize_t); /*proto*/ -static int __Pyx_EndUnpack(PyObject *, Py_ssize_t); /*proto*/ -static int __Pyx_PrintItem(PyObject *); /*proto*/ -static int __Pyx_PrintNewline(void); /*proto*/ -static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb); /*proto*/ -static void __Pyx_ReRaise(void); /*proto*/ -static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list); /*proto*/ -static PyObject *__Pyx_GetExcValue(void); /*proto*/ -static int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, int none_allowed, char *name); /*proto*/ -static int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); /*proto*/ -static int __Pyx_GetStarArgs(PyObject **args, PyObject **kwds, char *kwd_list[], Py_ssize_t nargs, PyObject **args2, PyObject **kwds2); /*proto*/ -static void __Pyx_WriteUnraisable(char *name); /*proto*/ -static void __Pyx_AddTraceback(char *funcname); /*proto*/ -static PyTypeObject *__Pyx_ImportType(char *module_name, char *class_name, long size); /*proto*/ -static int __Pyx_SetVtable(PyObject *dict, void *vtable); /*proto*/ -static int __Pyx_GetVtable(PyObject *dict, void *vtabptr); /*proto*/ -static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name, char *modname); /*proto*/ -static int __Pyx_InternStrings(__Pyx_InternTabEntry *t); /*proto*/ -static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); /*proto*/ -static int __Pyx_InitCApi(PyObject *module); /*proto*/ -static int __Pyx_ImportModuleCApi(__Pyx_CApiTabEntry *t); /*proto*/ -static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name); /*proto*/ - -static PyObject *__pyx_m; -static PyObject *__pyx_b; -static int __pyx_lineno; -static char *__pyx_filename; -static char **__pyx_f; - -static char __pyx_mdoc[] = "\nInterface to epoll I/O event notification facility.\n"; - -/* Declarations from _epoll */ - - -struct __pyx_obj_6_epoll_epoll { - PyObject_HEAD - int fd; - int initialized; -}; - -static PyTypeObject *__pyx_ptype_6_epoll_epoll = 0; - -/* Implementation of _epoll */ - -static PyObject *__pyx_n_CTL_ADD; -static PyObject *__pyx_n_CTL_DEL; -static PyObject *__pyx_n_CTL_MOD; -static PyObject *__pyx_n_IN; -static PyObject *__pyx_n_OUT; -static PyObject *__pyx_n_PRI; -static PyObject *__pyx_n_ERR; -static PyObject *__pyx_n_HUP; -static PyObject *__pyx_n_ET; -static PyObject *__pyx_n_RDNORM; -static PyObject *__pyx_n_RDBAND; -static PyObject *__pyx_n_WRNORM; -static PyObject *__pyx_n_WRBAND; -static PyObject *__pyx_n_MSG; - -static PyObject *__pyx_n_IOError; - -static int __pyx_f_6_epoll_5epoll___init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static int __pyx_f_6_epoll_5epoll___init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - int __pyx_v_size; - int __pyx_r; - int __pyx_1; - PyObject *__pyx_2 = 0; - PyObject *__pyx_3 = 0; - PyObject *__pyx_4 = 0; - PyObject *__pyx_5 = 0; - static char *__pyx_argnames[] = {"size",0}; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "i", __pyx_argnames, &__pyx_v_size)) return -1; - Py_INCREF(__pyx_v_self); - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":77 */ - ((struct __pyx_obj_6_epoll_epoll *)__pyx_v_self)->fd = epoll_create(__pyx_v_size); - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":78 */ - __pyx_1 = (((struct __pyx_obj_6_epoll_epoll *)__pyx_v_self)->fd == (-1)); - if (__pyx_1) { - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":79 */ - __pyx_2 = __Pyx_GetName(__pyx_b, __pyx_n_IOError); if (!__pyx_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 79; goto __pyx_L1;} - __pyx_3 = PyInt_FromLong(errno); if (!__pyx_3) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 79; goto __pyx_L1;} - __pyx_4 = PyString_FromString(strerror(errno)); if (!__pyx_4) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 79; goto __pyx_L1;} - __pyx_5 = PyTuple_New(2); if (!__pyx_5) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 79; goto __pyx_L1;} - PyTuple_SET_ITEM(__pyx_5, 0, __pyx_3); - PyTuple_SET_ITEM(__pyx_5, 1, __pyx_4); - __pyx_3 = 0; - __pyx_4 = 0; - __pyx_3 = PyObject_Call(__pyx_2, __pyx_5, 0); if (!__pyx_3) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 79; goto __pyx_L1;} - Py_DECREF(__pyx_2); __pyx_2 = 0; - Py_DECREF(__pyx_5); __pyx_5 = 0; - __Pyx_Raise(__pyx_3, 0, 0); - Py_DECREF(__pyx_3); __pyx_3 = 0; - {__pyx_filename = __pyx_f[0]; __pyx_lineno = 79; goto __pyx_L1;} - goto __pyx_L2; - } - __pyx_L2:; - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":80 */ - ((struct __pyx_obj_6_epoll_epoll *)__pyx_v_self)->initialized = 1; - - __pyx_r = 0; - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_2); - Py_XDECREF(__pyx_3); - Py_XDECREF(__pyx_4); - Py_XDECREF(__pyx_5); - __Pyx_AddTraceback("_epoll.epoll.__init__"); - __pyx_r = -1; - __pyx_L0:; - Py_DECREF(__pyx_v_self); - return __pyx_r; -} - -static void __pyx_f_6_epoll_5epoll___dealloc__(PyObject *__pyx_v_self); /*proto*/ -static void __pyx_f_6_epoll_5epoll___dealloc__(PyObject *__pyx_v_self) { - int __pyx_1; - Py_INCREF(__pyx_v_self); - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":83 */ - __pyx_1 = ((struct __pyx_obj_6_epoll_epoll *)__pyx_v_self)->initialized; - if (__pyx_1) { - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":84 */ - close(((struct __pyx_obj_6_epoll_epoll *)__pyx_v_self)->fd); - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":85 */ - ((struct __pyx_obj_6_epoll_epoll *)__pyx_v_self)->initialized = 0; - goto __pyx_L2; - } - __pyx_L2:; - - goto __pyx_L0; - __pyx_L1:; - __Pyx_AddTraceback("_epoll.epoll.__dealloc__"); - __pyx_L0:; - Py_DECREF(__pyx_v_self); -} - -static PyObject *__pyx_f_6_epoll_5epoll_close(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static char __pyx_doc_6_epoll_5epoll_close[] = "\n Close the epoll file descriptor.\n "; -static PyObject *__pyx_f_6_epoll_5epoll_close(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_r; - int __pyx_1; - PyObject *__pyx_2 = 0; - PyObject *__pyx_3 = 0; - PyObject *__pyx_4 = 0; - PyObject *__pyx_5 = 0; - static char *__pyx_argnames[] = {0}; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "", __pyx_argnames)) return 0; - Py_INCREF(__pyx_v_self); - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":91 */ - __pyx_1 = ((struct __pyx_obj_6_epoll_epoll *)__pyx_v_self)->initialized; - if (__pyx_1) { - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":92 */ - __pyx_1 = (close(((struct __pyx_obj_6_epoll_epoll *)__pyx_v_self)->fd) == (-1)); - if (__pyx_1) { - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":93 */ - __pyx_2 = __Pyx_GetName(__pyx_b, __pyx_n_IOError); if (!__pyx_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 93; goto __pyx_L1;} - __pyx_3 = PyInt_FromLong(errno); if (!__pyx_3) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 93; goto __pyx_L1;} - __pyx_4 = PyString_FromString(strerror(errno)); if (!__pyx_4) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 93; goto __pyx_L1;} - __pyx_5 = PyTuple_New(2); if (!__pyx_5) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 93; goto __pyx_L1;} - PyTuple_SET_ITEM(__pyx_5, 0, __pyx_3); - PyTuple_SET_ITEM(__pyx_5, 1, __pyx_4); - __pyx_3 = 0; - __pyx_4 = 0; - __pyx_3 = PyObject_Call(__pyx_2, __pyx_5, 0); if (!__pyx_3) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 93; goto __pyx_L1;} - Py_DECREF(__pyx_2); __pyx_2 = 0; - Py_DECREF(__pyx_5); __pyx_5 = 0; - __Pyx_Raise(__pyx_3, 0, 0); - Py_DECREF(__pyx_3); __pyx_3 = 0; - {__pyx_filename = __pyx_f[0]; __pyx_lineno = 93; goto __pyx_L1;} - goto __pyx_L3; - } - __pyx_L3:; - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":94 */ - ((struct __pyx_obj_6_epoll_epoll *)__pyx_v_self)->initialized = 0; - goto __pyx_L2; - } - __pyx_L2:; - - __pyx_r = Py_None; Py_INCREF(Py_None); - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_2); - Py_XDECREF(__pyx_3); - Py_XDECREF(__pyx_4); - Py_XDECREF(__pyx_5); - __Pyx_AddTraceback("_epoll.epoll.close"); - __pyx_r = 0; - __pyx_L0:; - Py_DECREF(__pyx_v_self); - return __pyx_r; -} - -static PyObject *__pyx_f_6_epoll_5epoll_fileno(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static char __pyx_doc_6_epoll_5epoll_fileno[] = "\n Return the epoll file descriptor number.\n "; -static PyObject *__pyx_f_6_epoll_5epoll_fileno(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_r; - PyObject *__pyx_1 = 0; - static char *__pyx_argnames[] = {0}; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "", __pyx_argnames)) return 0; - Py_INCREF(__pyx_v_self); - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":100 */ - __pyx_1 = PyInt_FromLong(((struct __pyx_obj_6_epoll_epoll *)__pyx_v_self)->fd); if (!__pyx_1) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 100; goto __pyx_L1;} - __pyx_r = __pyx_1; - __pyx_1 = 0; - goto __pyx_L0; - - __pyx_r = Py_None; Py_INCREF(Py_None); - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_1); - __Pyx_AddTraceback("_epoll.epoll.fileno"); - __pyx_r = 0; - __pyx_L0:; - Py_DECREF(__pyx_v_self); - return __pyx_r; -} - -static PyObject *__pyx_f_6_epoll_5epoll__control(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static char __pyx_doc_6_epoll_5epoll__control[] = "\n Modify the monitored state of a particular file descriptor.\n \n Wrap epoll_ctl(2).\n\n @type op: C{int}\n @param op: One of CTL_ADD, CTL_DEL, or CTL_MOD\n\n @type fd: C{int}\n @param fd: File descriptor to modify\n\n @type events: C{int}\n @param events: A bit set of IN, OUT, PRI, ERR, HUP, and ET.\n\n @raise IOError: Raised if the underlying epoll_ctl() call fails.\n "; -static PyObject *__pyx_f_6_epoll_5epoll__control(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - int __pyx_v_op; - int __pyx_v_fd; - int __pyx_v_events; - int __pyx_v_result; - struct epoll_event __pyx_v_evt; - PyObject *__pyx_r; - int __pyx_1; - PyObject *__pyx_2 = 0; - PyObject *__pyx_3 = 0; - PyObject *__pyx_4 = 0; - PyObject *__pyx_5 = 0; - static char *__pyx_argnames[] = {"op","fd","events",0}; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "iii", __pyx_argnames, &__pyx_v_op, &__pyx_v_fd, &__pyx_v_events)) return 0; - Py_INCREF(__pyx_v_self); - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":121 */ - __pyx_v_evt.events = __pyx_v_events; - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":122 */ - __pyx_v_evt.data.fd = __pyx_v_fd; - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":123 */ - __pyx_v_result = epoll_ctl(((struct __pyx_obj_6_epoll_epoll *)__pyx_v_self)->fd,__pyx_v_op,__pyx_v_fd,(&__pyx_v_evt)); - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":124 */ - __pyx_1 = (__pyx_v_result == (-1)); - if (__pyx_1) { - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":125 */ - __pyx_2 = __Pyx_GetName(__pyx_b, __pyx_n_IOError); if (!__pyx_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 125; goto __pyx_L1;} - __pyx_3 = PyInt_FromLong(errno); if (!__pyx_3) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 125; goto __pyx_L1;} - __pyx_4 = PyString_FromString(strerror(errno)); if (!__pyx_4) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 125; goto __pyx_L1;} - __pyx_5 = PyTuple_New(2); if (!__pyx_5) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 125; goto __pyx_L1;} - PyTuple_SET_ITEM(__pyx_5, 0, __pyx_3); - PyTuple_SET_ITEM(__pyx_5, 1, __pyx_4); - __pyx_3 = 0; - __pyx_4 = 0; - __pyx_3 = PyObject_Call(__pyx_2, __pyx_5, 0); if (!__pyx_3) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 125; goto __pyx_L1;} - Py_DECREF(__pyx_2); __pyx_2 = 0; - Py_DECREF(__pyx_5); __pyx_5 = 0; - __Pyx_Raise(__pyx_3, 0, 0); - Py_DECREF(__pyx_3); __pyx_3 = 0; - {__pyx_filename = __pyx_f[0]; __pyx_lineno = 125; goto __pyx_L1;} - goto __pyx_L2; - } - __pyx_L2:; - - __pyx_r = Py_None; Py_INCREF(Py_None); - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_2); - Py_XDECREF(__pyx_3); - Py_XDECREF(__pyx_4); - Py_XDECREF(__pyx_5); - __Pyx_AddTraceback("_epoll.epoll._control"); - __pyx_r = 0; - __pyx_L0:; - Py_DECREF(__pyx_v_self); - return __pyx_r; -} - -static PyObject *__pyx_n_append; - -static PyObject *__pyx_f_6_epoll_5epoll_wait(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static char __pyx_doc_6_epoll_5epoll_wait[] = "\n Wait for an I/O event, wrap epoll_wait(2).\n\n @type maxevents: C{int}\n @param maxevents: Maximum number of events returned.\n\n @type timeout: C{int}\n @param timeout: Maximum time waiting for events. 0 makes it return\n immediately whereas -1 makes it wait indefinitely.\n \n @raise IOError: Raised if the underlying epoll_wait() call fails.\n "; -static PyObject *__pyx_f_6_epoll_5epoll_wait(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - unsigned int __pyx_v_maxevents; - int __pyx_v_timeout; - struct epoll_event (*__pyx_v_events); - int __pyx_v_result; - int __pyx_v_nbytes; - int __pyx_v_fd; - PyThreadState (*__pyx_v__save); - PyObject *__pyx_v_results; - PyObject *__pyx_v_i; - PyObject *__pyx_r; - int __pyx_1; - PyObject *__pyx_2 = 0; - PyObject *__pyx_3 = 0; - PyObject *__pyx_4 = 0; - PyObject *__pyx_5 = 0; - long __pyx_6; - Py_ssize_t __pyx_7; - static char *__pyx_argnames[] = {"maxevents","timeout",0}; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "Ii", __pyx_argnames, &__pyx_v_maxevents, &__pyx_v_timeout)) return 0; - Py_INCREF(__pyx_v_self); - __pyx_v_results = Py_None; Py_INCREF(Py_None); - __pyx_v_i = Py_None; Py_INCREF(Py_None); - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":146 */ - __pyx_v_nbytes = ((sizeof(struct epoll_event )) * __pyx_v_maxevents); - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":147 */ - __pyx_v_events = ((struct epoll_event (*))malloc(__pyx_v_nbytes)); - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":148 */ - memset(__pyx_v_events,0,__pyx_v_nbytes); - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":149 */ - /*try:*/ { - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":150 */ - __pyx_v_fd = ((struct __pyx_obj_6_epoll_epoll *)__pyx_v_self)->fd; - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":152 */ - __pyx_v__save = PyEval_SaveThread(); - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":153 */ - __pyx_v_result = epoll_wait(__pyx_v_fd,__pyx_v_events,__pyx_v_maxevents,__pyx_v_timeout); - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":154 */ - PyEval_RestoreThread(__pyx_v__save); - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":156 */ - __pyx_1 = (__pyx_v_result == (-1)); - if (__pyx_1) { - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":157 */ - __pyx_2 = __Pyx_GetName(__pyx_b, __pyx_n_IOError); if (!__pyx_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 157; goto __pyx_L3;} - __pyx_3 = PyInt_FromLong(errno); if (!__pyx_3) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 157; goto __pyx_L3;} - __pyx_4 = PyString_FromString(strerror(errno)); if (!__pyx_4) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 157; goto __pyx_L3;} - __pyx_5 = PyTuple_New(2); if (!__pyx_5) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 157; goto __pyx_L3;} - PyTuple_SET_ITEM(__pyx_5, 0, __pyx_3); - PyTuple_SET_ITEM(__pyx_5, 1, __pyx_4); - __pyx_3 = 0; - __pyx_4 = 0; - __pyx_3 = PyObject_Call(__pyx_2, __pyx_5, 0); if (!__pyx_3) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 157; goto __pyx_L3;} - Py_DECREF(__pyx_2); __pyx_2 = 0; - Py_DECREF(__pyx_5); __pyx_5 = 0; - __Pyx_Raise(__pyx_3, 0, 0); - Py_DECREF(__pyx_3); __pyx_3 = 0; - {__pyx_filename = __pyx_f[0]; __pyx_lineno = 157; goto __pyx_L3;} - goto __pyx_L5; - } - __pyx_L5:; - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":158 */ - __pyx_4 = PyList_New(0); if (!__pyx_4) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 158; goto __pyx_L3;} - Py_DECREF(__pyx_v_results); - __pyx_v_results = __pyx_4; - __pyx_4 = 0; - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":159 */ - for (__pyx_6 = 0; __pyx_6 < __pyx_v_result; ++__pyx_6) { - __pyx_2 = PyInt_FromLong(__pyx_6); if (!__pyx_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 159; goto __pyx_L3;} - Py_DECREF(__pyx_v_i); - __pyx_v_i = __pyx_2; - __pyx_2 = 0; - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":160 */ - __pyx_5 = PyObject_GetAttr(__pyx_v_results, __pyx_n_append); if (!__pyx_5) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 160; goto __pyx_L3;} - __pyx_7 = PyInt_AsSsize_t(__pyx_v_i); if (PyErr_Occurred()) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 160; goto __pyx_L3;} - __pyx_3 = PyInt_FromLong((__pyx_v_events[__pyx_7]).data.fd); if (!__pyx_3) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 160; goto __pyx_L3;} - __pyx_7 = PyInt_AsSsize_t(__pyx_v_i); if (PyErr_Occurred()) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 160; goto __pyx_L3;} - __pyx_4 = PyInt_FromLong(((int )(__pyx_v_events[__pyx_7]).events)); if (!__pyx_4) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 160; goto __pyx_L3;} - __pyx_2 = PyTuple_New(2); if (!__pyx_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 160; goto __pyx_L3;} - PyTuple_SET_ITEM(__pyx_2, 0, __pyx_3); - PyTuple_SET_ITEM(__pyx_2, 1, __pyx_4); - __pyx_3 = 0; - __pyx_4 = 0; - __pyx_3 = PyTuple_New(1); if (!__pyx_3) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 160; goto __pyx_L3;} - PyTuple_SET_ITEM(__pyx_3, 0, __pyx_2); - __pyx_2 = 0; - __pyx_4 = PyObject_Call(__pyx_5, __pyx_3, 0); if (!__pyx_4) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 160; goto __pyx_L3;} - Py_DECREF(__pyx_5); __pyx_5 = 0; - Py_DECREF(__pyx_3); __pyx_3 = 0; - Py_DECREF(__pyx_4); __pyx_4 = 0; - __pyx_L6:; - } - __pyx_L7:; - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":161 */ - Py_INCREF(__pyx_v_results); - __pyx_r = __pyx_v_results; - goto __pyx_L2; - } - /*finally:*/ { - int __pyx_why; - __pyx_why = 0; goto __pyx_L4; - __pyx_L2: __pyx_why = 3; goto __pyx_L4; - __pyx_L3: { - __pyx_why = 4; - Py_XDECREF(__pyx_2); __pyx_2 = 0; - Py_XDECREF(__pyx_5); __pyx_5 = 0; - Py_XDECREF(__pyx_3); __pyx_3 = 0; - Py_XDECREF(__pyx_4); __pyx_4 = 0; - PyErr_Fetch(&__pyx_2, &__pyx_5, &__pyx_3); - __pyx_1 = __pyx_lineno; - goto __pyx_L4; - } - __pyx_L4:; - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":163 */ - free(__pyx_v_events); - switch (__pyx_why) { - case 3: goto __pyx_L0; - case 4: { - PyErr_Restore(__pyx_2, __pyx_5, __pyx_3); - __pyx_lineno = __pyx_1; - __pyx_2 = 0; - __pyx_5 = 0; - __pyx_3 = 0; - goto __pyx_L1; - } - } - } - - __pyx_r = Py_None; Py_INCREF(Py_None); - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_2); - Py_XDECREF(__pyx_3); - Py_XDECREF(__pyx_4); - Py_XDECREF(__pyx_5); - __Pyx_AddTraceback("_epoll.epoll.wait"); - __pyx_r = 0; - __pyx_L0:; - Py_DECREF(__pyx_v_results); - Py_DECREF(__pyx_v_i); - Py_DECREF(__pyx_v_self); - return __pyx_r; -} - -static __Pyx_InternTabEntry __pyx_intern_tab[] = { - {&__pyx_n_CTL_ADD, "CTL_ADD"}, - {&__pyx_n_CTL_DEL, "CTL_DEL"}, - {&__pyx_n_CTL_MOD, "CTL_MOD"}, - {&__pyx_n_ERR, "ERR"}, - {&__pyx_n_ET, "ET"}, - {&__pyx_n_HUP, "HUP"}, - {&__pyx_n_IN, "IN"}, - {&__pyx_n_IOError, "IOError"}, - {&__pyx_n_MSG, "MSG"}, - {&__pyx_n_OUT, "OUT"}, - {&__pyx_n_PRI, "PRI"}, - {&__pyx_n_RDBAND, "RDBAND"}, - {&__pyx_n_RDNORM, "RDNORM"}, - {&__pyx_n_WRBAND, "WRBAND"}, - {&__pyx_n_WRNORM, "WRNORM"}, - {&__pyx_n_append, "append"}, - {0, 0} -}; - -static PyObject *__pyx_tp_new_6_epoll_epoll(PyTypeObject *t, PyObject *a, PyObject *k) { - PyObject *o = (*t->tp_alloc)(t, 0); - struct __pyx_obj_6_epoll_epoll *p = (struct __pyx_obj_6_epoll_epoll *)o; - return o; -} - -static void __pyx_tp_dealloc_6_epoll_epoll(PyObject *o) { - struct __pyx_obj_6_epoll_epoll *p = (struct __pyx_obj_6_epoll_epoll *)o; - { - PyObject *etype, *eval, *etb; - PyErr_Fetch(&etype, &eval, &etb); - ++o->ob_refcnt; - __pyx_f_6_epoll_5epoll___dealloc__(o); - if (PyErr_Occurred()) PyErr_WriteUnraisable(o); - --o->ob_refcnt; - PyErr_Restore(etype, eval, etb); - } - (*o->ob_type->tp_free)(o); -} - -static int __pyx_tp_traverse_6_epoll_epoll(PyObject *o, visitproc v, void *a) { - int e; - struct __pyx_obj_6_epoll_epoll *p = (struct __pyx_obj_6_epoll_epoll *)o; - return 0; -} - -static int __pyx_tp_clear_6_epoll_epoll(PyObject *o) { - struct __pyx_obj_6_epoll_epoll *p = (struct __pyx_obj_6_epoll_epoll *)o; - return 0; -} - -static struct PyMethodDef __pyx_methods_6_epoll_epoll[] = { - {"close", (PyCFunction)__pyx_f_6_epoll_5epoll_close, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6_epoll_5epoll_close}, - {"fileno", (PyCFunction)__pyx_f_6_epoll_5epoll_fileno, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6_epoll_5epoll_fileno}, - {"_control", (PyCFunction)__pyx_f_6_epoll_5epoll__control, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6_epoll_5epoll__control}, - {"wait", (PyCFunction)__pyx_f_6_epoll_5epoll_wait, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6_epoll_5epoll_wait}, - {0, 0, 0, 0} -}; - -static PyNumberMethods __pyx_tp_as_number_epoll = { - 0, /*nb_add*/ - 0, /*nb_subtract*/ - 0, /*nb_multiply*/ - 0, /*nb_divide*/ - 0, /*nb_remainder*/ - 0, /*nb_divmod*/ - 0, /*nb_power*/ - 0, /*nb_negative*/ - 0, /*nb_positive*/ - 0, /*nb_absolute*/ - 0, /*nb_nonzero*/ - 0, /*nb_invert*/ - 0, /*nb_lshift*/ - 0, /*nb_rshift*/ - 0, /*nb_and*/ - 0, /*nb_xor*/ - 0, /*nb_or*/ - 0, /*nb_coerce*/ - 0, /*nb_int*/ - 0, /*nb_long*/ - 0, /*nb_float*/ - 0, /*nb_oct*/ - 0, /*nb_hex*/ - 0, /*nb_inplace_add*/ - 0, /*nb_inplace_subtract*/ - 0, /*nb_inplace_multiply*/ - 0, /*nb_inplace_divide*/ - 0, /*nb_inplace_remainder*/ - 0, /*nb_inplace_power*/ - 0, /*nb_inplace_lshift*/ - 0, /*nb_inplace_rshift*/ - 0, /*nb_inplace_and*/ - 0, /*nb_inplace_xor*/ - 0, /*nb_inplace_or*/ - 0, /*nb_floor_divide*/ - 0, /*nb_true_divide*/ - 0, /*nb_inplace_floor_divide*/ - 0, /*nb_inplace_true_divide*/ -}; - -static PySequenceMethods __pyx_tp_as_sequence_epoll = { - 0, /*sq_length*/ - 0, /*sq_concat*/ - 0, /*sq_repeat*/ - 0, /*sq_item*/ - 0, /*sq_slice*/ - 0, /*sq_ass_item*/ - 0, /*sq_ass_slice*/ - 0, /*sq_contains*/ - 0, /*sq_inplace_concat*/ - 0, /*sq_inplace_repeat*/ -}; - -static PyMappingMethods __pyx_tp_as_mapping_epoll = { - 0, /*mp_length*/ - 0, /*mp_subscript*/ - 0, /*mp_ass_subscript*/ -}; - -static PyBufferProcs __pyx_tp_as_buffer_epoll = { - 0, /*bf_getreadbuffer*/ - 0, /*bf_getwritebuffer*/ - 0, /*bf_getsegcount*/ - 0, /*bf_getcharbuffer*/ -}; - -PyTypeObject __pyx_type_6_epoll_epoll = { - PyObject_HEAD_INIT(0) - 0, /*ob_size*/ - "_epoll.epoll", /*tp_name*/ - sizeof(struct __pyx_obj_6_epoll_epoll), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_6_epoll_epoll, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - &__pyx_tp_as_number_epoll, /*tp_as_number*/ - &__pyx_tp_as_sequence_epoll, /*tp_as_sequence*/ - &__pyx_tp_as_mapping_epoll, /*tp_as_mapping*/ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - &__pyx_tp_as_buffer_epoll, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/ - "\n Represent a set of file descriptors being monitored for events.\n ", /*tp_doc*/ - __pyx_tp_traverse_6_epoll_epoll, /*tp_traverse*/ - __pyx_tp_clear_6_epoll_epoll, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - __pyx_methods_6_epoll_epoll, /*tp_methods*/ - 0, /*tp_members*/ - 0, /*tp_getset*/ - 0, /*tp_base*/ - 0, /*tp_dict*/ - 0, /*tp_descr_get*/ - 0, /*tp_descr_set*/ - 0, /*tp_dictoffset*/ - __pyx_f_6_epoll_5epoll___init__, /*tp_init*/ - 0, /*tp_alloc*/ - __pyx_tp_new_6_epoll_epoll, /*tp_new*/ - 0, /*tp_free*/ - 0, /*tp_is_gc*/ - 0, /*tp_bases*/ - 0, /*tp_mro*/ - 0, /*tp_cache*/ - 0, /*tp_subclasses*/ - 0, /*tp_weaklist*/ -}; - -static struct PyMethodDef __pyx_methods[] = { - {0, 0, 0, 0} -}; - -static void __pyx_init_filenames(void); /*proto*/ - -PyMODINIT_FUNC init_epoll(void); /*proto*/ -PyMODINIT_FUNC init_epoll(void) { - PyObject *__pyx_1 = 0; - __pyx_init_filenames(); - __pyx_m = Py_InitModule4("_epoll", __pyx_methods, __pyx_mdoc, 0, PYTHON_API_VERSION); - if (!__pyx_m) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 4; goto __pyx_L1;}; - __pyx_b = PyImport_AddModule("__builtin__"); - if (!__pyx_b) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 4; goto __pyx_L1;}; - if (PyObject_SetAttrString(__pyx_m, "__builtins__", __pyx_b) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 4; goto __pyx_L1;}; - if (__Pyx_InternStrings(__pyx_intern_tab) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 4; goto __pyx_L1;}; - if (PyType_Ready(&__pyx_type_6_epoll_epoll) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 68; goto __pyx_L1;} - if (PyObject_SetAttrString(__pyx_m, "epoll", (PyObject *)&__pyx_type_6_epoll_epoll) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 68; goto __pyx_L1;} - __pyx_ptype_6_epoll_epoll = &__pyx_type_6_epoll_epoll; - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":165 */ - __pyx_1 = PyInt_FromLong(EPOLL_CTL_ADD); if (!__pyx_1) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 165; goto __pyx_L1;} - if (PyObject_SetAttr(__pyx_m, __pyx_n_CTL_ADD, __pyx_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 165; goto __pyx_L1;} - Py_DECREF(__pyx_1); __pyx_1 = 0; - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":166 */ - __pyx_1 = PyInt_FromLong(EPOLL_CTL_DEL); if (!__pyx_1) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 166; goto __pyx_L1;} - if (PyObject_SetAttr(__pyx_m, __pyx_n_CTL_DEL, __pyx_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 166; goto __pyx_L1;} - Py_DECREF(__pyx_1); __pyx_1 = 0; - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":167 */ - __pyx_1 = PyInt_FromLong(EPOLL_CTL_MOD); if (!__pyx_1) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 167; goto __pyx_L1;} - if (PyObject_SetAttr(__pyx_m, __pyx_n_CTL_MOD, __pyx_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 167; goto __pyx_L1;} - Py_DECREF(__pyx_1); __pyx_1 = 0; - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":169 */ - __pyx_1 = PyInt_FromLong(EPOLLIN); if (!__pyx_1) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 169; goto __pyx_L1;} - if (PyObject_SetAttr(__pyx_m, __pyx_n_IN, __pyx_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 169; goto __pyx_L1;} - Py_DECREF(__pyx_1); __pyx_1 = 0; - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":170 */ - __pyx_1 = PyInt_FromLong(EPOLLOUT); if (!__pyx_1) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 170; goto __pyx_L1;} - if (PyObject_SetAttr(__pyx_m, __pyx_n_OUT, __pyx_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 170; goto __pyx_L1;} - Py_DECREF(__pyx_1); __pyx_1 = 0; - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":171 */ - __pyx_1 = PyInt_FromLong(EPOLLPRI); if (!__pyx_1) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 171; goto __pyx_L1;} - if (PyObject_SetAttr(__pyx_m, __pyx_n_PRI, __pyx_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 171; goto __pyx_L1;} - Py_DECREF(__pyx_1); __pyx_1 = 0; - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":172 */ - __pyx_1 = PyInt_FromLong(EPOLLERR); if (!__pyx_1) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 172; goto __pyx_L1;} - if (PyObject_SetAttr(__pyx_m, __pyx_n_ERR, __pyx_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 172; goto __pyx_L1;} - Py_DECREF(__pyx_1); __pyx_1 = 0; - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":173 */ - __pyx_1 = PyInt_FromLong(EPOLLHUP); if (!__pyx_1) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 173; goto __pyx_L1;} - if (PyObject_SetAttr(__pyx_m, __pyx_n_HUP, __pyx_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 173; goto __pyx_L1;} - Py_DECREF(__pyx_1); __pyx_1 = 0; - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":174 */ - __pyx_1 = PyInt_FromLong(EPOLLET); if (!__pyx_1) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 174; goto __pyx_L1;} - if (PyObject_SetAttr(__pyx_m, __pyx_n_ET, __pyx_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 174; goto __pyx_L1;} - Py_DECREF(__pyx_1); __pyx_1 = 0; - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":176 */ - __pyx_1 = PyInt_FromLong(EPOLLRDNORM); if (!__pyx_1) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 176; goto __pyx_L1;} - if (PyObject_SetAttr(__pyx_m, __pyx_n_RDNORM, __pyx_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 176; goto __pyx_L1;} - Py_DECREF(__pyx_1); __pyx_1 = 0; - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":177 */ - __pyx_1 = PyInt_FromLong(EPOLLRDBAND); if (!__pyx_1) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 177; goto __pyx_L1;} - if (PyObject_SetAttr(__pyx_m, __pyx_n_RDBAND, __pyx_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 177; goto __pyx_L1;} - Py_DECREF(__pyx_1); __pyx_1 = 0; - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":178 */ - __pyx_1 = PyInt_FromLong(EPOLLWRNORM); if (!__pyx_1) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 178; goto __pyx_L1;} - if (PyObject_SetAttr(__pyx_m, __pyx_n_WRNORM, __pyx_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 178; goto __pyx_L1;} - Py_DECREF(__pyx_1); __pyx_1 = 0; - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":179 */ - __pyx_1 = PyInt_FromLong(EPOLLWRBAND); if (!__pyx_1) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 179; goto __pyx_L1;} - if (PyObject_SetAttr(__pyx_m, __pyx_n_WRBAND, __pyx_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 179; goto __pyx_L1;} - Py_DECREF(__pyx_1); __pyx_1 = 0; - - /* "/home/exarkun/Projects/Twisted/branches/epollreactor-1953-2/twisted/python/_epoll.pyx":180 */ - __pyx_1 = PyInt_FromLong(EPOLLMSG); if (!__pyx_1) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 180; goto __pyx_L1;} - if (PyObject_SetAttr(__pyx_m, __pyx_n_MSG, __pyx_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 180; goto __pyx_L1;} - Py_DECREF(__pyx_1); __pyx_1 = 0; - return; - __pyx_L1:; - Py_XDECREF(__pyx_1); - __Pyx_AddTraceback("_epoll"); -} - -static char *__pyx_filenames[] = { - "_epoll.pyx", -}; - -/* Runtime support code */ - -static void __pyx_init_filenames(void) { - __pyx_f = __pyx_filenames; -} - -static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name) { - PyObject *result; - result = PyObject_GetAttr(dict, name); - if (!result) - PyErr_SetObject(PyExc_NameError, name); - return result; -} - -static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb) { - Py_XINCREF(type); - Py_XINCREF(value); - Py_XINCREF(tb); - /* First, check the traceback argument, replacing None with NULL. */ - if (tb == Py_None) { - Py_DECREF(tb); - tb = 0; - } - else if (tb != NULL && !PyTraceBack_Check(tb)) { - PyErr_SetString(PyExc_TypeError, - "raise: arg 3 must be a traceback or None"); - goto raise_error; - } - /* Next, replace a missing value with None */ - if (value == NULL) { - value = Py_None; - Py_INCREF(value); - } - /* Next, repeatedly, replace a tuple exception with its first item */ - while (PyTuple_Check(type) && PyTuple_Size(type) > 0) { - PyObject *tmp = type; - type = PyTuple_GET_ITEM(type, 0); - Py_INCREF(type); - Py_DECREF(tmp); - } - if (PyString_CheckExact(type)) { - /* Raising builtin string is deprecated but still allowed -- - * do nothing. Raising an instance of a new-style str - * subclass is right out. */ - if (PyErr_Warn(PyExc_DeprecationWarning, - "raising a string exception is deprecated")) - goto raise_error; - } - else if (PyType_Check(type) || PyClass_Check(type)) - ; /* PyErr_NormalizeException(&type, &value, &tb); */ - else if (PyInstance_Check(type)) { - /* Raising an instance. The value should be a dummy. */ - if (value != Py_None) { - PyErr_SetString(PyExc_TypeError, - "instance exception may not have a separate value"); - goto raise_error; - } - else { - /* Normalize to raise , */ - Py_DECREF(value); - value = type; - type = (PyObject*) ((PyInstanceObject*)type)->in_class; - Py_INCREF(type); - } - } - else if (PyType_IsSubtype(type->ob_type, (PyTypeObject*)PyExc_Exception)) { - /* Raising a new-style object (in Py2.5). - The value should be a dummy. */ - if (value != Py_None) { - PyErr_SetString(PyExc_TypeError, - "instance exception may not have a separate value"); - goto raise_error; - } - else { - /* Normalize to raise , */ - Py_DECREF(value); - value = type; - type = (PyObject*) type->ob_type; - Py_INCREF(type); - } - } - else { - /* Not something you can raise. You get an exception - anyway, just not what you specified :-) */ - PyErr_Format(PyExc_TypeError, - "exceptions must be classes, instances, or " - "strings (deprecated), not %s", - type->ob_type->tp_name); - goto raise_error; - } - PyErr_Restore(type, value, tb); - return; -raise_error: - Py_XDECREF(value); - Py_XDECREF(type); - Py_XDECREF(tb); - return; -} - -static int __Pyx_InternStrings(__Pyx_InternTabEntry *t) { - while (t->p) { - *t->p = PyString_InternFromString(t->s); - if (!*t->p) - return -1; - ++t; - } - return 0; -} - -#include "compile.h" -#include "frameobject.h" -#include "traceback.h" - -static void __Pyx_AddTraceback(char *funcname) { - PyObject *py_srcfile = 0; - PyObject *py_funcname = 0; - PyObject *py_globals = 0; - PyObject *empty_tuple = 0; - PyObject *empty_string = 0; - PyCodeObject *py_code = 0; - PyFrameObject *py_frame = 0; - - py_srcfile = PyString_FromString(__pyx_filename); - if (!py_srcfile) goto bad; - py_funcname = PyString_FromString(funcname); - if (!py_funcname) goto bad; - py_globals = PyModule_GetDict(__pyx_m); - if (!py_globals) goto bad; - empty_tuple = PyTuple_New(0); - if (!empty_tuple) goto bad; - empty_string = PyString_FromString(""); - if (!empty_string) goto bad; - py_code = PyCode_New( - 0, /*int argcount,*/ - 0, /*int nlocals,*/ - 0, /*int stacksize,*/ - 0, /*int flags,*/ - empty_string, /*PyObject *code,*/ - empty_tuple, /*PyObject *consts,*/ - empty_tuple, /*PyObject *names,*/ - empty_tuple, /*PyObject *varnames,*/ - empty_tuple, /*PyObject *freevars,*/ - empty_tuple, /*PyObject *cellvars,*/ - py_srcfile, /*PyObject *filename,*/ - py_funcname, /*PyObject *name,*/ - __pyx_lineno, /*int firstlineno,*/ - empty_string /*PyObject *lnotab*/ - ); - if (!py_code) goto bad; - py_frame = PyFrame_New( - PyThreadState_Get(), /*PyThreadState *tstate,*/ - py_code, /*PyCodeObject *code,*/ - py_globals, /*PyObject *globals,*/ - 0 /*PyObject *locals*/ - ); - if (!py_frame) goto bad; - py_frame->f_lineno = __pyx_lineno; - PyTraceBack_Here(py_frame); -bad: - Py_XDECREF(py_srcfile); - Py_XDECREF(py_funcname); - Py_XDECREF(empty_tuple); - Py_XDECREF(empty_string); - Py_XDECREF(py_code); - Py_XDECREF(py_frame); -} diff --git a/tools/buildbot/pylibs/twisted/python/_epoll.pyx b/tools/buildbot/pylibs/twisted/python/_epoll.pyx deleted file mode 100644 index 3a3b1ce..0000000 --- a/tools/buildbot/pylibs/twisted/python/_epoll.pyx +++ /dev/null @@ -1,181 +0,0 @@ -# Copyright (c) 2001-2006 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Interface to epoll I/O event notification facility. -""" - -# NOTE: The version of Pyrex you are using probably _does not work_ with -# Python 2.5. If you need to recompile this file, _make sure you are using -# a version of Pyrex which works with Python 2.5_. I am using 0.9.4.1 from -# . -exarkun - -cdef extern from "stdio.h": - cdef extern void *malloc(int) - cdef extern void free(void *) - cdef extern int close(int) - -cdef extern from "errno.h": - cdef extern int errno - cdef extern char *strerror(int) - -cdef extern from "string.h": - cdef extern void *memset(void* s, int c, int n) - -cdef extern from "stdint.h": - ctypedef unsigned long uint32_t - ctypedef unsigned long long uint64_t - -cdef extern from "sys/epoll.h": - - cdef enum: - EPOLL_CTL_ADD = 1 - EPOLL_CTL_DEL = 2 - EPOLL_CTL_MOD = 3 - - cdef enum EPOLL_EVENTS: - EPOLLIN = 0x001 - EPOLLPRI = 0x002 - EPOLLOUT = 0x004 - EPOLLRDNORM = 0x040 - EPOLLRDBAND = 0x080 - EPOLLWRNORM = 0x100 - EPOLLWRBAND = 0x200 - EPOLLMSG = 0x400 - EPOLLERR = 0x008 - EPOLLHUP = 0x010 - EPOLLET = (1 << 31) - - ctypedef union epoll_data_t: - void *ptr - int fd - uint32_t u32 - uint64_t u64 - - cdef struct epoll_event: - uint32_t events - epoll_data_t data - - int epoll_create(int size) - int epoll_ctl(int epfd, int op, int fd, epoll_event *event) - int epoll_wait(int epfd, epoll_event *events, int maxevents, int timeout) - -cdef extern from "Python.h": - ctypedef struct PyThreadState - cdef extern PyThreadState *PyEval_SaveThread() - cdef extern void PyEval_RestoreThread(PyThreadState*) - -cdef class epoll: - """ - Represent a set of file descriptors being monitored for events. - """ - - cdef int fd - cdef int initialized - - def __init__(self, int size): - self.fd = epoll_create(size) - if self.fd == -1: - raise IOError(errno, strerror(errno)) - self.initialized = 1 - - def __dealloc__(self): - if self.initialized: - close(self.fd) - self.initialized = 0 - - def close(self): - """ - Close the epoll file descriptor. - """ - if self.initialized: - if close(self.fd) == -1: - raise IOError(errno, strerror(errno)) - self.initialized = 0 - - def fileno(self): - """ - Return the epoll file descriptor number. - """ - return self.fd - - def _control(self, int op, int fd, int events): - """ - Modify the monitored state of a particular file descriptor. - - Wrap epoll_ctl(2). - - @type op: C{int} - @param op: One of CTL_ADD, CTL_DEL, or CTL_MOD - - @type fd: C{int} - @param fd: File descriptor to modify - - @type events: C{int} - @param events: A bit set of IN, OUT, PRI, ERR, HUP, and ET. - - @raise IOError: Raised if the underlying epoll_ctl() call fails. - """ - cdef int result - cdef epoll_event evt - evt.events = events - evt.data.fd = fd - result = epoll_ctl(self.fd, op, fd, &evt) - if result == -1: - raise IOError(errno, strerror(errno)) - - def wait(self, unsigned int maxevents, int timeout): - """ - Wait for an I/O event, wrap epoll_wait(2). - - @type maxevents: C{int} - @param maxevents: Maximum number of events returned. - - @type timeout: C{int} - @param timeout: Maximum time waiting for events. 0 makes it return - immediately whereas -1 makes it wait indefinitely. - - @raise IOError: Raised if the underlying epoll_wait() call fails. - """ - cdef epoll_event *events - cdef int result - cdef int nbytes - cdef int fd - cdef PyThreadState *_save - - nbytes = sizeof(epoll_event) * maxevents - events = malloc(nbytes) - memset(events, 0, nbytes) - try: - fd = self.fd - - _save = PyEval_SaveThread() - result = epoll_wait(fd, events, maxevents, timeout) - PyEval_RestoreThread(_save) - - if result == -1: - raise IOError(errno, strerror(errno)) - results = [] - for i from 0 <= i < result: - results.append((events[i].data.fd, events[i].events)) - return results - finally: - free(events) - -CTL_ADD = EPOLL_CTL_ADD -CTL_DEL = EPOLL_CTL_DEL -CTL_MOD = EPOLL_CTL_MOD - -IN = EPOLLIN -OUT = EPOLLOUT -PRI = EPOLLPRI -ERR = EPOLLERR -HUP = EPOLLHUP -ET = EPOLLET - -RDNORM = EPOLLRDNORM -RDBAND = EPOLLRDBAND -WRNORM = EPOLLWRNORM -WRBAND = EPOLLWRBAND -MSG = EPOLLMSG - diff --git a/tools/buildbot/pylibs/twisted/python/_release.py b/tools/buildbot/pylibs/twisted/python/_release.py deleted file mode 100644 index 875a94a..0000000 --- a/tools/buildbot/pylibs/twisted/python/_release.py +++ /dev/null @@ -1,803 +0,0 @@ -# -*- test-case-name: twisted.python.test.test_release -*- -# Copyright (c) 2007-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Twisted's automated release system. - -This module is only for use within Twisted's release system. If you are anyone -else, do not use it. The interface and behaviour will change without notice. -""" - -from datetime import date -import os -from tempfile import mkdtemp -import tarfile - -# Popen4 isn't available on Windows. BookBuilder won't work on Windows, but -# we don't care. -exarkun -try: - from popen2 import Popen4 -except ImportError: - Popen4 = None - -from twisted.python.versions import Version -from twisted.python.filepath import FilePath - -# This import is an example of why you shouldn't use this module unless you're -# radix -try: - from twisted.lore.scripts import lore -except ImportError: - pass - -# The offset between a year and the corresponding major version number. -VERSION_OFFSET = 2000 - - -class CommandFailed(Exception): - """ - Raised when a child process exits unsuccessfully. - - @type exitCode: C{int} - @ivar exitCode: The exit code for the child process. - - @type output: C{str} - @ivar output: The bytes read from stdout and stderr of the child process. - """ - def __init__(self, exitCode, output): - Exception.__init__(self, exitCode, output) - self.exitCode = exitCode - self.output = output - - - -def _changeVersionInFile(old, new, filename): - """ - Replace the C{old} version number with the C{new} one in the given - C{filename}. - """ - replaceInFile(filename, {old.base(): new.base()}) - - - -def getNextVersion(version, now=None): - """ - Calculate the version number for a new release of Twisted based on - the previous version number. - - @param version: The previous version number. - @param now: (optional) The current date. - """ - # XXX: This has no way of incrementing the patch number. Currently, we - # don't need it. See bug 2915. Jonathan Lange, 2007-11-20. - if now is None: - now = date.today() - major = now.year - VERSION_OFFSET - if major != version.major: - minor = 0 - else: - minor = version.minor + 1 - return Version(version.package, major, minor, 0) - - - -class Project(object): - """ - A representation of a project that has a version. - - @ivar directory: A L{twisted.python.filepath.FilePath} pointing to the base - directory of a Twisted-style Python package. The package should contain - a C{_version.py} file and a C{topfiles} directory that contains a - C{README} file. - """ - - def __init__(self, directory): - self.directory = directory - - - def __repr__(self): - return '%s(%r)' % ( - self.__class__.__name__, self.directory) - - - def getVersion(self): - """ - @return: A L{Version} specifying the version number of the project - based on live python modules. - """ - namespace = {} - execfile(self.directory.child("_version.py").path, namespace) - return namespace["version"] - - - def updateVersion(self, version): - """ - Replace the existing version numbers in _version.py and README files - with the specified version. - """ - oldVersion = self.getVersion() - replaceProjectVersion(oldVersion.package, - self.directory.child("_version.py").path, - version) - _changeVersionInFile( - oldVersion, version, - self.directory.child("topfiles").child("README").path) - - - -def findTwistedProjects(baseDirectory): - """ - Find all Twisted-style projects beneath a base directory. - - @param baseDirectory: A L{twisted.python.filepath.FilePath} to look inside. - @return: A list of L{Project}. - """ - projects = [] - for filePath in baseDirectory.walk(): - if filePath.basename() == 'topfiles': - projectDirectory = filePath.parent() - projects.append(Project(projectDirectory)) - return projects - - - -def updateTwistedVersionInformation(baseDirectory, now): - """ - Update the version information for Twisted and all subprojects to the - date-based version number. - - @param baseDirectory: Where to look for Twisted. If None, the function - infers the information from C{twisted.__file__}. - @param now: The current date (as L{datetime.date}). If None, it defaults - to today. - """ - for project in findTwistedProjects(baseDirectory): - project.updateVersion(getNextVersion(project.getVersion(), now=now)) - - - -def replaceProjectVersion(name, filename, newversion): - """ - Write version specification code into the given filename, which - sets the version to the given version number. - - @param filename: A filename which is most likely a "_version.py" - under some Twisted project. - @param newversion: A version object. - """ - # XXX - this should be moved to Project and renamed to writeVersionFile. - # jml, 2007-11-15. - f = open(filename, 'w') - if newversion.prerelease is not None: - prerelease = ", prerelease=%r" % (newversion.prerelease,) - else: - prerelease = "" - f.write('''\ -# This is an auto-generated file. Do not edit it. -from twisted.python import versions -version = versions.Version(%r, %s, %s, %s%s) -''' % (name, newversion.major, newversion.minor, newversion.micro, prerelease)) - f.close() - - - -def replaceInFile(filename, oldToNew): - """ - I replace the text `oldstr' with `newstr' in `filename' using science. - """ - os.rename(filename, filename+'.bak') - f = open(filename+'.bak') - d = f.read() - f.close() - for k,v in oldToNew.items(): - d = d.replace(k, v) - f = open(filename + '.new', 'w') - f.write(d) - f.close() - os.rename(filename+'.new', filename) - os.unlink(filename+'.bak') - - - -class NoDocumentsFound(Exception): - """ - Raised when no input documents are found. - """ - - - -class LoreBuilderMixin(object): - """ - Base class for builders which invoke lore. - """ - def lore(self, arguments): - """ - Run lore with the given arguments. - - @param arguments: A C{list} of C{str} giving command line arguments to - lore which should be used. - """ - options = lore.Options() - options.parseOptions(["--null"] + arguments) - lore.runGivenOptions(options) - - - -class DocBuilder(LoreBuilderMixin): - """ - Generate HTML documentation for projects. - """ - - def build(self, version, resourceDir, docDir, template, apiBaseURL=None, deleteInput=False): - """ - Build the documentation in C{docDir} with Lore. - - Input files ending in .xhtml will be considered. Output will written as - .html files. - - @param version: the version of the documentation to pass to lore. - @type version: C{str} - - @param resourceDir: The directory which contains the toplevel index and - stylesheet file for this section of documentation. - @type resourceDir: L{twisted.python.filepath.FilePath} - - @param docDir: The directory of the documentation. - @type docDir: L{twisted.python.filepath.FilePath} - - @param template: The template used to generate the documentation. - @type template: L{twisted.python.filepath.FilePath} - - @type apiBaseURL: C{str} or C{NoneType} - @param apiBaseURL: A format string which will be interpolated with the - fully-qualified Python name for each API link. For example, to - generate the Twisted 8.0.0 documentation, pass - C{"http://twistedmatrix.com/documents/8.0.0/api/%s.html"}. - - @param deleteInput: If True, the input documents will be deleted after - their output is generated. - @type deleteInput: C{bool} - - @raise NoDocumentsFound: When there are no .xhtml files in the given - C{docDir}. - """ - linkrel = self.getLinkrel(resourceDir, docDir) - inputFiles = docDir.globChildren("*.xhtml") - filenames = [x.path for x in inputFiles] - if not filenames: - raise NoDocumentsFound("No input documents found in %s" % (docDir,)) - if apiBaseURL is not None: - arguments = ["--config", "baseurl=" + apiBaseURL] - else: - arguments = [] - arguments.extend(["--config", "template=%s" % (template.path,), - "--config", "ext=.html", - "--config", "version=%s" % (version,), - "--linkrel", linkrel] + filenames) - self.lore(arguments) - if deleteInput: - for inputFile in inputFiles: - inputFile.remove() - - - def getLinkrel(self, resourceDir, docDir): - """ - Calculate a value appropriate for Lore's --linkrel option. - - Lore's --linkrel option defines how to 'find' documents that are - linked to from TEMPLATE files (NOT document bodies). That is, it's a - prefix for links ('a' and 'link') in the template. - - @param resourceDir: The directory which contains the toplevel index and - stylesheet file for this section of documentation. - @type resourceDir: L{twisted.python.filepath.FilePath} - - @param docDir: The directory containing documents that must link to - C{resourceDir}. - @type docDir: L{twisted.python.filepath.FilePath} - """ - if resourceDir != docDir: - return '/'.join(filePathDelta(docDir, resourceDir)) + "/" - else: - return "" - - - -class ManBuilder(LoreBuilderMixin): - """ - Generate man pages of the different existing scripts. - """ - - def build(self, manDir): - """ - Generate Lore input files from the man pages in C{manDir}. - - Input files ending in .1 will be considered. Output will written as - -man.xhtml files. - - @param manDir: The directory of the man pages. - @type manDir: L{twisted.python.filepath.FilePath} - - @raise NoDocumentsFound: When there are no .1 files in the given - C{manDir}. - """ - inputFiles = manDir.globChildren("*.1") - filenames = [x.path for x in inputFiles] - if not filenames: - raise NoDocumentsFound("No manual pages found in %s" % (manDir,)) - arguments = ["--input", "man", - "--output", "lore", - "--config", "ext=-man.xhtml"] + filenames - self.lore(arguments) - - - -class APIBuilder(object): - """ - Generate API documentation from source files using - U{pydoctor}. This requires - pydoctor to be installed and usable (which means you won't be able to - use it with Python 2.3). - """ - def build(self, projectName, projectURL, sourceURL, packagePath, outputPath): - """ - Call pydoctor's entry point with options which will generate HTML - documentation for the specified package's API. - - @type projectName: C{str} - @param projectName: The name of the package for which to generate - documentation. - - @type projectURL: C{str} - @param projectURL: The location (probably an HTTP URL) of the project - on the web. - - @type sourceURL: C{str} - @param sourceURL: The location (probably an HTTP URL) of the root of - the source browser for the project. - - @type packagePath: L{FilePath} - @param packagePath: The path to the top-level of the package named by - C{projectName}. - - @type outputPath: L{FilePath} - @param outputPath: An existing directory to which the generated API - documentation will be written. - """ - from pydoctor.driver import main - main( - ["--project-name", projectName, - "--project-url", projectURL, - "--system-class", "pydoctor.twistedmodel.TwistedSystem", - "--project-base-dir", packagePath.parent().path, - "--html-viewsource-base", sourceURL, - "--add-package", packagePath.path, - "--html-output", outputPath.path, - "--quiet", "--make-html"]) - - - -class BookBuilder(LoreBuilderMixin): - """ - Generate the LaTeX and PDF documentation. - - The book is built by assembling a number of LaTeX documents. Only the - overall document which describes how to assemble the documents is stored - in LaTeX in the source. The rest of the documentation is generated from - Lore input files. These are primarily XHTML files (of the particular - Lore subset), but man pages are stored in GROFF format. BookBuilder - expects all of its input to be Lore XHTML format, so L{ManBuilder} - should be invoked first if the man pages are to be included in the - result (this is determined by the book LaTeX definition file). - Therefore, a sample usage of BookBuilder may look something like this: - - man = ManBuilder() - man.build(FilePath("doc/core/man")) - book = BookBuilder() - book.build( - FilePath('doc/core/howto'), - [FilePath('doc/core/howto'), FilePath('doc/core/howto/tutorial'), - FilePath('doc/core/man'), FilePath('doc/core/specifications')], - FilePath('doc/core/howto/book.tex'), FilePath('/tmp/book.pdf')) - """ - def run(self, command): - """ - Execute a command in a child process and return the output. - - @type command C{str} - @param command: The shell command to run. - - @raise L{RuntimeError}: If the child process exits with an error. - """ - process = Popen4(command) - stdout = process.fromchild.read() - exitCode = process.wait() - if os.WIFSIGNALED(exitCode) or os.WEXITSTATUS(exitCode): - raise CommandFailed(exitCode, stdout) - return stdout - - - def buildTeX(self, howtoDir): - """ - Build LaTeX files for lore input files in the given directory. - - Input files ending in .xhtml will be considered. Output will written as - .tex files. - - @type howtoDir: L{FilePath} - @param howtoDir: A directory containing lore input files. - - @raise ValueError: If C{howtoDir} does not exist. - """ - if not howtoDir.exists(): - raise ValueError("%r does not exist." % (howtoDir.path,)) - self.lore( - ["--output", "latex", - "--config", "section"] + - [child.path for child in howtoDir.globChildren("*.xhtml")]) - - - def buildPDF(self, bookPath, inputDirectory, outputPath): - """ - Build a PDF from the given a LaTeX book document. - - @type bookPath: L{FilePath} - @param bookPath: The location of a LaTeX document defining a book. - - @type inputDirectory: L{FilePath} - @param inputDirectory: The directory which the inputs of the book are - relative to. - - @type outputPath: L{FilePath} - @param outputPath: The location to which to write the resulting book. - """ - if not bookPath.basename().endswith(".tex"): - raise ValueError("Book filename must end with .tex") - - workPath = FilePath(mkdtemp()) - try: - startDir = os.getcwd() - try: - os.chdir(inputDirectory.path) - - texToDVI = ( - "latex -interaction=nonstopmode " - "-output-directory=%s %s") % ( - workPath.path, bookPath.path) - - # What I tell you three times is true! - # The first two invocations of latex on the book file allows it - # correctly create page numbers for in-text references. Why this is - # the case, I could not tell you. -exarkun - for i in range(3): - self.run(texToDVI) - - bookBaseWithoutExtension = bookPath.basename()[:-4] - dviPath = workPath.child(bookBaseWithoutExtension + ".dvi") - psPath = workPath.child(bookBaseWithoutExtension + ".ps") - pdfPath = workPath.child(bookBaseWithoutExtension + ".pdf") - self.run( - "dvips -o %(postscript)s -t letter -Ppdf %(dvi)s" % { - 'postscript': psPath.path, - 'dvi': dviPath.path}) - self.run("ps2pdf13 %(postscript)s %(pdf)s" % { - 'postscript': psPath.path, - 'pdf': pdfPath.path}) - pdfPath.moveTo(outputPath) - workPath.remove() - finally: - os.chdir(startDir) - except: - workPath.moveTo(bookPath.parent().child(workPath.basename())) - raise - - - def build(self, baseDirectory, inputDirectories, bookPath, outputPath): - """ - Build a PDF book from the given TeX book definition and directories - containing lore inputs. - - @type baseDirectory: L{FilePath} - @param baseDirectory: The directory which the inputs of the book are - relative to. - - @type inputDirectories: C{list} of L{FilePath} - @param inputDirectories: The paths which contain lore inputs to be - converted to LaTeX. - - @type bookPath: L{FilePath} - @param bookPath: The location of a LaTeX document defining a book. - - @type outputPath: L{FilePath} - @param outputPath: The location to which to write the resulting book. - """ - for inputDir in inputDirectories: - self.buildTeX(inputDir) - self.buildPDF(bookPath, baseDirectory, outputPath) - for inputDirectory in inputDirectories: - for child in inputDirectory.children(): - if child.splitext()[1] == ".tex" and child != bookPath: - child.remove() - - - -def filePathDelta(origin, destination): - """ - Return a list of strings that represent C{destination} as a path relative - to C{origin}. - - It is assumed that both paths represent directories, not files. That is to - say, the delta of L{twisted.python.filepath.FilePath} /foo/bar to - L{twisted.python.filepath.FilePath} /foo/baz will be C{../baz}, - not C{baz}. - - @type origin: L{twisted.python.filepath.FilePath} - @param origin: The origin of the relative path. - - @type destination: L{twisted.python.filepath.FilePath} - @param destination: The destination of the relative path. - """ - commonItems = 0 - path1 = origin.path.split(os.sep) - path2 = destination.path.split(os.sep) - for elem1, elem2 in zip(path1, path2): - if elem1 == elem2: - commonItems += 1 - path = [".."] * (len(path1) - commonItems) - return path + path2[commonItems:] - - - -class DistributionBuilder(object): - """ - A builder of Twisted distributions. - - This knows how to build tarballs for Twisted and all of its subprojects. - """ - - from twisted.python.dist import twisted_subprojects as subprojects - blacklist = ["vfs", "web2"] - - def __init__(self, rootDirectory, outputDirectory, apiBaseURL=None): - """ - Create a distribution builder. - - @param rootDirectory: root of a Twisted export which will populate - subsequent tarballs. - @type rootDirectory: L{FilePath}. - - @param outputDirectory: The directory in which to create the tarballs. - @type outputDirectory: L{FilePath} - - @type apiBaseURL: C{str} or C{NoneType} - @param apiBaseURL: A format string which will be interpolated with the - fully-qualified Python name for each API link. For example, to - generate the Twisted 8.0.0 documentation, pass - C{"http://twistedmatrix.com/documents/8.0.0/api/%s.html"}. - """ - self.rootDirectory = rootDirectory - self.outputDirectory = outputDirectory - self.apiBaseURL = apiBaseURL - self.manBuilder = ManBuilder() - self.docBuilder = DocBuilder() - - - def _buildDocInDir(self, path, version, howtoPath): - """ - Generate documentation in the given path, building man pages first if - necessary and swallowing errors (so that directories without lore - documentation in them are ignored). - - @param path: The path containing documentation to build. - @type path: L{FilePath} - @param version: The version of the project to include in all generated - pages. - @type version: C{str} - @param howtoPath: The "resource path" as L{DocBuilder} describes it. - @type howtoPath: L{FilePath} - """ - templatePath = self.rootDirectory.child("doc").child("core" - ).child("howto").child("template.tpl") - if path.basename() == "man": - self.manBuilder.build(path) - if path.isdir(): - try: - self.docBuilder.build(version, howtoPath, path, - templatePath, self.apiBaseURL, True) - except NoDocumentsFound: - pass - - - def buildTwisted(self, version): - """ - Build the main Twisted distribution in C{Twisted-.tar.bz2}. - - @type version: C{str} - @param version: The version of Twisted to build. - - @return: The tarball file. - @rtype: L{FilePath}. - """ - releaseName = "Twisted-%s" % (version,) - buildPath = lambda *args: '/'.join((releaseName,) + args) - - outputFile = self.outputDirectory.child(releaseName + ".tar.bz2") - tarball = tarfile.TarFile.open(outputFile.path, 'w:bz2') - - docPath = self.rootDirectory.child("doc") - - # Generate docs! - if docPath.isdir(): - for subProjectDir in docPath.children(): - if (subProjectDir.isdir() - and subProjectDir.basename() not in self.blacklist): - for child in subProjectDir.walk(): - self._buildDocInDir(child, version, - subProjectDir.child("howto")) - - # Now, this part is nasty. We need to exclude blacklisted subprojects - # from the main Twisted distribution. This means we need to exclude - # their bin directories, their documentation directories, their - # plugins, and their python packages. Given that there's no "add all - # but exclude these particular paths" functionality in tarfile, we have - # to walk through all these directories and add things that *aren't* - # part of the blacklisted projects. - - for binthing in self.rootDirectory.child("bin").children(): - if binthing.basename() not in self.blacklist: - tarball.add(binthing.path, - buildPath("bin", binthing.basename())) - - bad_plugins = ["twisted_%s.py" % (blacklisted,) - for blacklisted in self.blacklist] - - for submodule in self.rootDirectory.child("twisted").children(): - if submodule.basename() == "plugins": - for plugin in submodule.children(): - if plugin.basename() not in bad_plugins: - tarball.add(plugin.path, buildPath("twisted", "plugins", - plugin.basename())) - elif submodule.basename() not in self.blacklist: - tarball.add(submodule.path, buildPath("twisted", - submodule.basename())) - - for docDir in self.rootDirectory.child("doc").children(): - if docDir.basename() not in self.blacklist: - tarball.add(docDir.path, buildPath("doc", docDir.basename())) - - for toplevel in self.rootDirectory.children(): - if not toplevel.isdir(): - tarball.add(toplevel.path, buildPath(toplevel.basename())) - - tarball.close() - - return outputFile - - - def buildCore(self, version): - """ - Build a core distribution in C{TwistedCore-.tar.bz2}. - - This is very similar to L{buildSubProject}, but core tarballs and the - input are laid out slightly differently. - - - scripts are in the top level of the C{bin} directory. - - code is included directly from the C{twisted} directory, excluding - subprojects. - - all plugins except the subproject plugins are included. - - @type version: C{str} - @param version: The version of Twisted to build. - - @return: The tarball file. - @rtype: L{FilePath}. - """ - releaseName = "TwistedCore-%s" % (version,) - outputFile = self.outputDirectory.child(releaseName + ".tar.bz2") - buildPath = lambda *args: '/'.join((releaseName,) + args) - tarball = self._createBasicSubprojectTarball( - "core", version, outputFile) - - # Include the bin directory for the subproject. - for path in self.rootDirectory.child("bin").children(): - if not path.isdir(): - tarball.add(path.path, buildPath("bin", path.basename())) - - # Include all files within twisted/ that aren't part of a subproject. - for path in self.rootDirectory.child("twisted").children(): - if path.basename() == "plugins": - for plugin in path.children(): - for subproject in self.subprojects: - if plugin.basename() == "twisted_%s.py" % (subproject,): - break - else: - tarball.add(plugin.path, - buildPath("twisted", "plugins", - plugin.basename())) - elif not path.basename() in self.subprojects + ["topfiles"]: - tarball.add(path.path, buildPath("twisted", path.basename())) - - tarball.add(self.rootDirectory.child("twisted").child("topfiles").path, - releaseName) - tarball.close() - - return outputFile - - - def buildSubProject(self, projectName, version): - """ - Build a subproject distribution in - C{Twisted-.tar.bz2}. - - @type projectName: C{str} - @param projectName: The lowercase name of the subproject to build. - @type version: C{str} - @param version: The version of Twisted to build. - - @return: The tarball file. - @rtype: L{FilePath}. - """ - releaseName = "Twisted%s-%s" % (projectName.capitalize(), version) - outputFile = self.outputDirectory.child(releaseName + ".tar.bz2") - buildPath = lambda *args: '/'.join((releaseName,) + args) - subProjectDir = self.rootDirectory.child("twisted").child(projectName) - - tarball = self._createBasicSubprojectTarball(projectName, version, - outputFile) - - tarball.add(subProjectDir.child("topfiles").path, releaseName) - - # Include all files in the subproject package except for topfiles. - for child in subProjectDir.children(): - name = child.basename() - if name != "topfiles": - tarball.add( - child.path, - buildPath("twisted", projectName, name)) - - pluginsDir = self.rootDirectory.child("twisted").child("plugins") - # Include the plugin for the subproject. - pluginFileName = "twisted_%s.py" % (projectName,) - pluginFile = pluginsDir.child(pluginFileName) - if pluginFile.exists(): - tarball.add(pluginFile.path, - buildPath("twisted", "plugins", pluginFileName)) - - # Include the bin directory for the subproject. - binPath = self.rootDirectory.child("bin").child(projectName) - if binPath.isdir(): - tarball.add(binPath.path, buildPath("bin")) - tarball.close() - - return outputFile - - - def _createBasicSubprojectTarball(self, projectName, version, outputFile): - """ - Helper method to create and fill a tarball with things common between - subprojects and core. - - @param projectName: The subproject's name. - @type projectName: C{str} - @param version: The version of the release. - @type version: C{str} - @param outputFile: The location of the tar file to create. - @type outputFile: L{FilePath} - """ - releaseName = "Twisted%s-%s" % (projectName.capitalize(), version) - buildPath = lambda *args: '/'.join((releaseName,) + args) - - tarball = tarfile.TarFile.open(outputFile.path, 'w:bz2') - - tarball.add(self.rootDirectory.child("LICENSE").path, - buildPath("LICENSE")) - - docPath = self.rootDirectory.child("doc").child(projectName) - - if docPath.isdir(): - for child in docPath.walk(): - self._buildDocInDir(child, version, docPath.child("howto")) - tarball.add(docPath.path, buildPath("doc")) - - return tarball diff --git a/tools/buildbot/pylibs/twisted/python/_twisted_zsh_stub b/tools/buildbot/pylibs/twisted/python/_twisted_zsh_stub deleted file mode 100644 index dd2fc64..0000000 --- a/tools/buildbot/pylibs/twisted/python/_twisted_zsh_stub +++ /dev/null @@ -1,89 +0,0 @@ -#compdef trial conch mktap cftp tapconvert twistd ckeygen lore pyhtmlizer tap2deb tkconch manhole tap2rpm - -# Copyright (c) 2005 Eric Mangold -# See LICENSE for details. -# -# Maintainer: Eric Mangold - -# This file is meant to be in your zsh function path. i.e. in one of those -# directories listed in your $fpath variable. -# -# e.g. /usr/local/share/zsh/site-functions/ -# -# It is responsible for passing completion control to the correct -# completion function for the version of Twisted that is -# currently in use. -# -# Goals: -# -# We want to detect any changes to PYTHONPATH since the last time we ran. -# That way we can re-locate the completion functions so that we are sure -# to be completing for the right version of twisted. - -local dir old_fpath python_code run shebang - -function debug () { - echo $@ >> /tmp/debug -} - -#debug "START _twisted_stub" - -function load_twisted_completions() { - [[ -z $commands[twistd] ]] && echo 'ERROR: test command "twistd" not found in path' && return 1 - shebang=$(head -1 $commands[twistd]) - [[ $shebang != \#\!* ]] && echo 'ERROR: invalid shebang line for test script "twistd"' && return 1 - PYTHON=$shebang[3,-1] - PYTHON=${PYTHON# *} - - #debug PYTHON -$PYTHON- - python_code=' -import twisted, os.path -dir = os.path.dirname(twisted.__file__) -print dir + os.sep + os.path.join("python", "zsh") -' - dir=$($PYTHON -c "$python_code") - #debug "Trying to load twisted functions from $dir" - if [[ -r $dir/_twistd ]]; then - old_fpath=($fpath) - fpath=( $dir $fpath ) - autoload +X _trial _conch _mktap _cftp _tapconvert _twistd _ckeygen - autoload +X _lore _pyhtmlizer _tap2deb _tkconch - autoload +X _manhole _tap2rpm - fpath=($old_fpath) - else - echo 'ERROR: Cannot find twisted completion function files in:' - echo "$dir" - return 1 - fi -} - -function twisted_run () { - # run completion function for current command - # the :t modifier strips off any leading pathname components - eval _$words[1]:t -} - -function twisted_save_load_run () { - # save PYTHONPATH, load twisted completions, and run the completion - # function for the current command - load_twisted_completions && twisted_run && PYTHONPATH_last=$PYTHONPATH -} - - -if [[ -n $PYTHONPATH_last ]]; then - #debug "PYTHONPATH_last is set to $PYTHONPATH_last" - #check if it's the same as the last time we ran - if [[ $PYTHONPATH == $PYTHONPATH_last ]]; then - #debug "PYTHONPATH == PYTHONPATH_last" - # it's the same, which means we've already loaded completion - # functions and nothing has changed. - twisted_run - else - twisted_save_load_run - fi -else - twisted_save_load_run -fi - -#debug "END _twisted_stub" -# diff --git a/tools/buildbot/pylibs/twisted/python/compat.py b/tools/buildbot/pylibs/twisted/python/compat.py deleted file mode 100644 index f8eb5ed..0000000 --- a/tools/buildbot/pylibs/twisted/python/compat.py +++ /dev/null @@ -1,168 +0,0 @@ -# -*- test-case-name: twisted.test.test_compat -*- -# -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Compatibility module to provide backwards compatibility for useful Python -features. - -This is mainly for use of internal Twisted code. We encourage you to use -the latest version of Python directly from your code, if possible. -""" - -import sys, string, socket, struct - -def inet_pton(af, addr): - if af == socket.AF_INET: - return socket.inet_aton(addr) - elif af == getattr(socket, 'AF_INET6', 'AF_INET6'): - if [x for x in addr if x not in string.hexdigits + ':.']: - raise ValueError("Illegal characters: %r" % (''.join(x),)) - - parts = addr.split(':') - elided = parts.count('') - ipv4Component = '.' in parts[-1] - - if len(parts) > (8 - ipv4Component) or elided > 3: - raise ValueError("Syntactically invalid address") - - if elided == 3: - return '\x00' * 16 - - if elided: - zeros = ['0'] * (8 - len(parts) - ipv4Component + elided) - - if addr.startswith('::'): - parts[:2] = zeros - elif addr.endswith('::'): - parts[-2:] = zeros - else: - idx = parts.index('') - parts[idx:idx+1] = zeros - - if len(parts) != 8 - ipv4Component: - raise ValueError("Syntactically invalid address") - else: - if len(parts) != (8 - ipv4Component): - raise ValueError("Syntactically invalid address") - - if ipv4Component: - if parts[-1].count('.') != 3: - raise ValueError("Syntactically invalid address") - rawipv4 = socket.inet_aton(parts[-1]) - unpackedipv4 = struct.unpack('!HH', rawipv4) - parts[-1:] = [hex(x)[2:] for x in unpackedipv4] - - parts = [int(x, 16) for x in parts] - return struct.pack('!8H', *parts) - else: - raise socket.error(97, 'Address family not supported by protocol') - -def inet_ntop(af, addr): - if af == socket.AF_INET: - return socket.inet_ntoa(addr) - elif af == socket.AF_INET6: - if len(addr) != 16: - raise ValueError("address length incorrect") - parts = struct.unpack('!8H', addr) - curBase = bestBase = None - for i in range(8): - if not parts[i]: - if curBase is None: - curBase = i - curLen = 0 - curLen += 1 - else: - if curBase is not None: - if bestBase is None or curLen > bestLen: - bestBase = curBase - bestLen = curLen - curBase = None - if curBase is not None and (bestBase is None or curLen > bestLen): - bestBase = curBase - bestLen = curLen - parts = [hex(x)[2:] for x in parts] - if bestBase is not None: - parts[bestBase:bestBase + bestLen] = [''] - if parts[0] == '': - parts.insert(0, '') - if parts[-1] == '': - parts.insert(len(parts) - 1, '') - return ':'.join(parts) - else: - raise socket.error(97, 'Address family not supported by protocol') - -try: - socket.inet_pton(socket.AF_INET6, "::") -except (AttributeError, NameError, socket.error): - socket.inet_pton = inet_pton - socket.inet_ntop = inet_ntop - socket.AF_INET6 = 'AF_INET6' - -adict = dict - -# OpenSSL/__init__.py imports OpenSSL.tsafe. OpenSSL/tsafe.py imports -# threading. threading imports thread. All to make this stupid threadsafe -# version of its Connection class. We don't even care about threadsafe -# Connections. In the interest of not screwing over some crazy person -# calling into OpenSSL from another thread and trying to use Twisted's SSL -# support, we don't totally destroy OpenSSL.tsafe, but we will replace it -# with our own version which imports threading as late as possible. - -class tsafe(object): - class Connection: - """ - OpenSSL.tsafe.Connection, defined in such a way as to not blow. - """ - __module__ = 'OpenSSL.tsafe' - - def __init__(self, *args): - from OpenSSL import SSL as _ssl - self._ssl_conn = apply(_ssl.Connection, args) - from threading import _RLock - self._lock = _RLock() - - for f in ('get_context', 'pending', 'send', 'write', 'recv', - 'read', 'renegotiate', 'bind', 'listen', 'connect', - 'accept', 'setblocking', 'fileno', 'shutdown', - 'close', 'get_cipher_list', 'getpeername', - 'getsockname', 'getsockopt', 'setsockopt', - 'makefile', 'get_app_data', 'set_app_data', - 'state_string', 'sock_shutdown', - 'get_peer_certificate', 'want_read', 'want_write', - 'set_connect_state', 'set_accept_state', - 'connect_ex', 'sendall'): - - exec """def %s(self, *args): - self._lock.acquire() - try: - return apply(self._ssl_conn.%s, args) - finally: - self._lock.release()\n""" % (f, f) -sys.modules['OpenSSL.tsafe'] = tsafe - -import operator -try: - operator.attrgetter -except AttributeError: - class attrgetter(object): - def __init__(self, name): - self.name = name - def __call__(self, obj): - return getattr(obj, self.name) - operator.attrgetter = attrgetter - - -try: - set = set -except NameError: - from sets import Set as set - - -try: - frozenset = frozenset -except NameError: - from sets import ImmutableSet as frozenset - diff --git a/tools/buildbot/pylibs/twisted/python/components.py b/tools/buildbot/pylibs/twisted/python/components.py deleted file mode 100644 index 54af395..0000000 --- a/tools/buildbot/pylibs/twisted/python/components.py +++ /dev/null @@ -1,445 +0,0 @@ -# -*- test-case-name: twisted.python.test.test_components -*- - -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Component architecture for Twisted, based on Zope3 components. - -Using the Zope3 API directly is strongly recommended. Everything -you need is in the top-level of the zope.interface package, e.g.:: - - from zope.interface import Interface, implements - - class IFoo(Interface): - pass - - class Foo: - implements(IFoo) - - print IFoo.implementedBy(Foo) # True - print IFoo.providedBy(Foo()) # True - -The one exception is L{twisted.python.components.registerAdapter}, which is -still the way to register adapters (at least, if you want Twisted's global -adapter registry). -""" - -# twisted imports -from twisted.python import reflect -from twisted.persisted import styles - -# system imports -import warnings - -# zope3 imports -from zope.interface import directlyProvides, interface, declarations -from zope.interface.adapter import AdapterRegistry - - - -class ComponentsDeprecationWarning(DeprecationWarning): - """Nothing emits this warning anymore.""" - pass - -# Twisted's global adapter registry -globalRegistry = AdapterRegistry() - -# Attribute that registerAdapter looks at. Is this supposed to be public? -ALLOW_DUPLICATES = 0 - -# Define a function to find the registered adapter factory, using either a -# version of Zope Interface which has the `registered' method or an older -# version which does not. -if getattr(AdapterRegistry, 'registered', None) is None: - def _registered(registry, required, provided): - """ - Return the adapter factory for the given parameters in the given - registry, or None if there is not one. - """ - return registry.get(required).selfImplied.get(provided, {}).get('') -else: - def _registered(registry, required, provided): - """ - Return the adapter factory for the given parameters in the given - registry, or None if there is not one. - """ - return registry.registered([required], provided) - - -def registerAdapter(adapterFactory, origInterface, *interfaceClasses): - """Register an adapter class. - - An adapter class is expected to implement the given interface, by - adapting instances implementing 'origInterface'. An adapter class's - __init__ method should accept one parameter, an instance implementing - 'origInterface'. - """ - self = globalRegistry - assert interfaceClasses, "You need to pass an Interface" - global ALLOW_DUPLICATES - - # deal with class->interface adapters: - if not isinstance(origInterface, interface.InterfaceClass): - origInterface = declarations.implementedBy(origInterface) - - for interfaceClass in interfaceClasses: - factory = _registered(self, origInterface, interfaceClass) - if factory is not None and not ALLOW_DUPLICATES: - raise ValueError("an adapter (%s) was already registered." % (factory, )) - for interfaceClass in interfaceClasses: - self.register([origInterface], interfaceClass, '', adapterFactory) - - -def getAdapterFactory(fromInterface, toInterface, default): - """Return registered adapter for a given class and interface. - - Note that is tied to the *Twisted* global registry, and will - thus not find adapters registered elsewhere. - """ - self = globalRegistry - if not isinstance(fromInterface, interface.InterfaceClass): - fromInterface = declarations.implementedBy(fromInterface) - factory = self.lookup1(fromInterface, toInterface) - if factory is None: - factory = default - return factory - - -# add global adapter lookup hook for our newly created registry -def _hook(iface, ob, lookup=globalRegistry.lookup1): - factory = lookup(declarations.providedBy(ob), iface) - if factory is None: - return None - else: - return factory(ob) -interface.adapter_hooks.append(_hook) - -## backwardsCompatImplements and fixClassImplements should probably stick around for another -## release cycle. No harm doing so in any case. - -def backwardsCompatImplements(klass): - """DEPRECATED. - - Does nothing. Previously handled backwards compat from a - zope.interface using class to a class wanting old twisted - components interface behaviors. - """ - warnings.warn("components.backwardsCompatImplements doesn't do anything in Twisted 2.3, stop calling it.", ComponentsDeprecationWarning, stacklevel=2) - -def fixClassImplements(klass): - """DEPRECATED. - - Does nothing. Previously converted class from __implements__ to - zope implementation. - """ - warnings.warn("components.fixClassImplements doesn't do anything in Twisted 2.3, stop calling it.", ComponentsDeprecationWarning, stacklevel=2) - - -def getRegistry(): - """Returns the Twisted global - C{zope.interface.adapter.AdapterRegistry} instance. - """ - return globalRegistry - -# FIXME: deprecate attribute somehow? -CannotAdapt = TypeError - -class Adapter: - """I am the default implementation of an Adapter for some interface. - - This docstring contains a limerick, by popular demand:: - - Subclassing made Zope and TR - much harder to work with by far. - So before you inherit, - be sure to declare it - Adapter, not PyObject* - - @cvar temporaryAdapter: If this is True, the adapter will not be - persisted on the Componentized. - @cvar multiComponent: If this adapter is persistent, should it be - automatically registered for all appropriate interfaces. - """ - - # These attributes are used with Componentized. - - temporaryAdapter = 0 - multiComponent = 1 - - def __init__(self, original): - """Set my 'original' attribute to be the object I am adapting. - """ - self.original = original - - def __conform__(self, interface): - """ - I forward __conform__ to self.original if it has it, otherwise I - simply return None. - """ - if hasattr(self.original, "__conform__"): - return self.original.__conform__(interface) - return None - - def isuper(self, iface, adapter): - """ - Forward isuper to self.original - """ - return self.original.isuper(iface, adapter) - - -class Componentized(styles.Versioned): - """I am a mixin to allow you to be adapted in various ways persistently. - - I define a list of persistent adapters. This is to allow adapter classes - to store system-specific state, and initialized on demand. The - getComponent method implements this. You must also register adapters for - this class for the interfaces that you wish to pass to getComponent. - - Many other classes and utilities listed here are present in Zope3; this one - is specific to Twisted. - """ - - persistenceVersion = 1 - - def __init__(self): - self._adapterCache = {} - - def locateAdapterClass(self, klass, interfaceClass, default): - return getAdapterFactory(klass, interfaceClass, default) - - def setAdapter(self, interfaceClass, adapterClass): - self.setComponent(interfaceClass, adapterClass(self)) - - def addAdapter(self, adapterClass, ignoreClass=0): - """Utility method that calls addComponent. I take an adapter class and - instantiate it with myself as the first argument. - - @return: The adapter instantiated. - """ - adapt = adapterClass(self) - self.addComponent(adapt, ignoreClass) - return adapt - - def setComponent(self, interfaceClass, component): - """ - """ - self._adapterCache[reflect.qual(interfaceClass)] = component - - def addComponent(self, component, ignoreClass=0): - """ - Add a component to me, for all appropriate interfaces. - - In order to determine which interfaces are appropriate, the component's - provided interfaces will be scanned. - - If the argument 'ignoreClass' is True, then all interfaces are - considered appropriate. - - Otherwise, an 'appropriate' interface is one for which its class has - been registered as an adapter for my class according to the rules of - getComponent. - - @return: the list of appropriate interfaces - """ - for iface in declarations.providedBy(component): - if (ignoreClass or - (self.locateAdapterClass(self.__class__, iface, None) - == component.__class__)): - self._adapterCache[reflect.qual(iface)] = component - - def unsetComponent(self, interfaceClass): - """Remove my component specified by the given interface class.""" - del self._adapterCache[reflect.qual(interfaceClass)] - - def removeComponent(self, component): - """ - Remove the given component from me entirely, for all interfaces for which - it has been registered. - - @return: a list of the interfaces that were removed. - """ - l = [] - for k, v in self._adapterCache.items(): - if v is component: - del self._adapterCache[k] - l.append(reflect.namedObject(k)) - return l - - def getComponent(self, interface, default=None): - """Create or retrieve an adapter for the given interface. - - If such an adapter has already been created, retrieve it from the cache - that this instance keeps of all its adapters. Adapters created through - this mechanism may safely store system-specific state. - - If you want to register an adapter that will be created through - getComponent, but you don't require (or don't want) your adapter to be - cached and kept alive for the lifetime of this Componentized object, - set the attribute 'temporaryAdapter' to True on your adapter class. - - If you want to automatically register an adapter for all appropriate - interfaces (with addComponent), set the attribute 'multiComponent' to - True on your adapter class. - """ - k = reflect.qual(interface) - if self._adapterCache.has_key(k): - return self._adapterCache[k] - else: - adapter = interface.__adapt__(self) - if adapter is not None and not ( - hasattr(adapter, "temporaryAdapter") and - adapter.temporaryAdapter): - self._adapterCache[k] = adapter - if (hasattr(adapter, "multiComponent") and - adapter.multiComponent): - self.addComponent(adapter) - if adapter is None: - return default - return adapter - - - def __conform__(self, interface): - return self.getComponent(interface) - - -class ReprableComponentized(Componentized): - def __init__(self): - Componentized.__init__(self) - - def __repr__(self): - from cStringIO import StringIO - from pprint import pprint - sio = StringIO() - pprint(self._adapterCache, sio) - return sio.getvalue() - - - -def proxyForInterface(iface, originalAttribute='original'): - """ - Create a class which proxies all method calls which adhere to an interface - to another provider of that interface. - - This function is intended for creating specialized proxies. The typical way - to use it is by subclassing the result:: - - class MySpecializedProxy(proxyForInterface(IFoo)): - def someInterfaceMethod(self, arg): - if arg == 3: - return 3 - return self.original.someInterfaceMethod(arg) - - @param iface: The Interface to which the resulting object will conform, and - which the wrapped object must provide. - - @param originalAttribute: name of the attribute used to save the original - object in the resulting class. Default to C{original}. - @type originalAttribute: C{str} - - @return: A class whose constructor takes the original object as its only - argument. Constructing the class creates the proxy. - """ - def __init__(self, original): - setattr(self, originalAttribute, original) - contents = {"__init__": __init__} - for name in iface: - contents[name] = _ProxyDescriptor(name, originalAttribute) - proxy = type("(Proxy for %s)" - % (reflect.qual(iface),), (object,), contents) - directlyProvides(proxy, iface) - return proxy - - - -class _ProxiedClassMethod(object): - """ - A proxied class method. - - @ivar methodName: the name of the method which this should invoke when - called. - @type methodName: C{str} - - @ivar originalAttribute: name of the attribute of the proxy where the - original object is stored. - @type orginalAttribute: C{str} - """ - def __init__(self, methodName, originalAttribute): - self.methodName = methodName - self.originalAttribute = originalAttribute - - - def __call__(self, oself, *args, **kw): - """ - Invoke the specified L{methodName} method of the C{original} attribute - for proxyForInterface. - - @param oself: an instance of a L{proxyForInterface} object. - - @return: the result of the underlying method. - """ - original = getattr(oself, self.originalAttribute) - actualMethod = getattr(original, self.methodName) - return actualMethod(*args, **kw) - - - -class _ProxyDescriptor(object): - """ - A descriptor which will proxy attribute access, mutation, and - deletion to the L{original} attribute of the object it is being accessed - from. - - @ivar attributeName: the name of the attribute which this descriptor will - retrieve from instances' C{original} attribute. - @type attributeName: C{str} - - @ivar originalAttribute: name of the attribute of the proxy where the - original object is stored. - @type orginalAttribute: C{str} - """ - def __init__(self, attributeName, originalAttribute): - self.attributeName = attributeName - self.originalAttribute = originalAttribute - - - def __get__(self, oself, type=None): - """ - Retrieve the C{self.attributeName} property from L{oself}. - """ - if oself is None: - return _ProxiedClassMethod(self.attributeName, - self.originalAttribute) - original = getattr(oself, self.originalAttribute) - return getattr(original, self.attributeName) - - - def __set__(self, oself, value): - """ - Set the C{self.attributeName} property of L{oself}. - """ - original = getattr(oself, self.originalAttribute) - setattr(original, self.attributeName, value) - - - def __delete__(self, oself): - """ - Delete the C{self.attributeName} property of L{oself}. - """ - original = getattr(oself, self.originalAttribute) - delattr(original, self.attributeName) - - - -__all__ = [ - # Sticking around: - "ComponentsDeprecationWarning", - "registerAdapter", "getAdapterFactory", - "Adapter", "Componentized", "ReprableComponentized", "getRegistry", - "proxyForInterface", - - # Deprecated: - "backwardsCompatImplements", - "fixClassImplements", -] diff --git a/tools/buildbot/pylibs/twisted/python/context.py b/tools/buildbot/pylibs/twisted/python/context.py deleted file mode 100644 index e4f7e9f..0000000 --- a/tools/buildbot/pylibs/twisted/python/context.py +++ /dev/null @@ -1,90 +0,0 @@ -# -*- test-case-name: twisted.test.test_context -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -""" -Dynamic pseudo-scoping for Python. - -Call functions with context.call({key: value}, func); func and -functions that it calls will be able to use 'context.get(key)' to -retrieve 'value'. - -This is thread-safe. -""" - -try: - from threading import local -except ImportError: - local = None - -from twisted.python import threadable - -defaultContextDict = {} - -setDefault = defaultContextDict.__setitem__ - -class ContextTracker: - def __init__(self): - self.contexts = [defaultContextDict] - - def callWithContext(self, ctx, func, *args, **kw): - newContext = self.contexts[-1].copy() - newContext.update(ctx) - self.contexts.append(newContext) - try: - return func(*args,**kw) - finally: - self.contexts.pop() - - def getContext(self, key, default=None): - return self.contexts[-1].get(key, default) - - -class _ThreadedContextTracker: - def __init__(self): - self.threadId = threadable.getThreadID - self.contextPerThread = {} - - def currentContext(self): - tkey = self.threadId() - try: - return self.contextPerThread[tkey] - except KeyError: - ct = self.contextPerThread[tkey] = ContextTracker() - return ct - - def callWithContext(self, ctx, func, *args, **kw): - return self.currentContext().callWithContext(ctx, func, *args, **kw) - - def getContext(self, key, default=None): - return self.currentContext().getContext(key, default) - - -class _TLSContextTracker(_ThreadedContextTracker): - def __init__(self): - self.storage = local() - - def currentContext(self): - try: - return self.storage.ct - except AttributeError: - ct = self.storage.ct = ContextTracker() - return ct - -if local is None: - ThreadedContextTracker = _ThreadedContextTracker -else: - ThreadedContextTracker = _TLSContextTracker - -def installContextTracker(ctr): - global theContextTracker - global call - global get - - theContextTracker = ctr - call = theContextTracker.callWithContext - get = theContextTracker.getContext - -installContextTracker(ThreadedContextTracker()) diff --git a/tools/buildbot/pylibs/twisted/python/deprecate.py b/tools/buildbot/pylibs/twisted/python/deprecate.py deleted file mode 100644 index d05c946..0000000 --- a/tools/buildbot/pylibs/twisted/python/deprecate.py +++ /dev/null @@ -1,134 +0,0 @@ -# -*- test-case-name: twisted.python.test.test_deprecate -*- - -# Copyright (c) 2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Deprecation framework for Twisted. - -To mark a method or function as being deprecated do this:: - - def badAPI(self, first, second): - ''' - Docstring for badAPI. - ''' - ... - badAPI = deprecate(Version("Twisted", 8, 0, 0))(badAPI) - -The newly-decorated badAPI will issue a warning when called. It will also have -a deprecation notice appended to its docstring. - -See also L{Version}. -""" - - -__all__ = [ - 'deprecated', - 'getDeprecationWarningString', - 'getWarningMethod', - 'setWarningMethod', - ] - - -from warnings import warn - -from twisted.python.versions import getVersionString, Version -from twisted.python.reflect import qual -from twisted.python.util import mergeFunctionMetadata - - -def getWarningMethod(): - """ - Return the warning method currently used to record deprecation warnings. - """ - return warn - - - -def setWarningMethod(newMethod): - """ - Set the warning method to use to record deprecation warnings. - - The callable should take message, category and stacklevel. The return - value is ignored. - """ - global warn - warn = newMethod - - - -def _getDeprecationDocstring(version): - return "Deprecated in %s." % getVersionString(version) - - - -def getDeprecationWarningString(callableThing, version): - """ - Return a string indicating that the callable was deprecated in the given - version. - - @param callableThing: A callable to be deprecated. - @param version: The L{twisted.python.versions.Version} that the callable - was deprecated in. - @return: A string describing the deprecation. - """ - return "%s was deprecated in %s" % ( - qual(callableThing), getVersionString(version)) - - - -def deprecated(version): - """ - Return a decorator that marks callables as deprecated. - """ - - def deprecationDecorator(function): - """ - Decorator that marks C{function} as deprecated. - """ - - warningString = getDeprecationWarningString(function, version) - - def deprecatedFunction(*args, **kwargs): - warn( - warningString, - DeprecationWarning, - stacklevel=2) - return function(*args, **kwargs) - - deprecatedFunction = mergeFunctionMetadata( - function, deprecatedFunction) - _appendToDocstring(deprecatedFunction, - _getDeprecationDocstring(version)) - deprecatedFunction.deprecatedVersion = version - return deprecatedFunction - - return deprecationDecorator - - - -def _appendToDocstring(thingWithDoc, textToAppend): - """ - Append the given text to the docstring of C{thingWithDoc}. - - If C{thingWithDoc} has no docstring, then the text just replaces the - docstring. If it has a single-line docstring then it appends a blank line - and the message text. If it has a multi-line docstring, then in appends a - blank line a the message text, and also does the indentation correctly. - """ - if thingWithDoc.__doc__: - docstringLines = thingWithDoc.__doc__.splitlines() - else: - docstringLines = [] - - if len(docstringLines) == 0: - docstringLines.append(textToAppend) - elif len(docstringLines) == 1: - docstringLines.extend(['', textToAppend, '']) - else: - spaces = docstringLines.pop() - docstringLines.extend(['', - spaces + textToAppend, - spaces]) - thingWithDoc.__doc__ = '\n'.join(docstringLines) diff --git a/tools/buildbot/pylibs/twisted/python/dispatch.py b/tools/buildbot/pylibs/twisted/python/dispatch.py deleted file mode 100644 index 4e28632..0000000 --- a/tools/buildbot/pylibs/twisted/python/dispatch.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -import warnings -warnings.warn( - "Create your own event dispatching mechanism, " - "twisted.python.dispatch will soon be no more.", - DeprecationWarning, 2) - - -class EventDispatcher: - """ - A global event dispatcher for events. - I'm used for any events that need to span disparate objects in the client. - - I should only be used when one object needs to signal an object that it's - not got a direct reference to (unless you really want to pass it through - here, in which case I won't mind). - - I'm mainly useful for complex GUIs. - """ - - def __init__(self, prefix="event_"): - self.prefix = prefix - self.callbacks = {} - - - def registerHandler(self, name, meth): - self.callbacks.setdefault(name, []).append(meth) - - - def autoRegister(self, obj): - from twisted.python import reflect - d = {} - reflect.accumulateMethods(obj, d, self.prefix) - for k,v in d.items(): - self.registerHandler(k, v) - - - def publishEvent(self, name, *args, **kwargs): - for cb in self.callbacks[name]: - cb(*args, **kwargs) diff --git a/tools/buildbot/pylibs/twisted/python/dist.py b/tools/buildbot/pylibs/twisted/python/dist.py deleted file mode 100644 index 4fe86f6..0000000 --- a/tools/buildbot/pylibs/twisted/python/dist.py +++ /dev/null @@ -1,361 +0,0 @@ -""" -Distutils convenience functionality. - -Don't use this outside of Twisted. - -Maintainer: U{Christopher Armstrong} -""" - -import sys, os -from distutils.command import build_scripts, install_data, build_ext, build_py -from distutils.errors import CompileError -from distutils import core -from distutils.core import Extension - -twisted_subprojects = ["conch", "flow", "lore", "mail", "names", - "news", "pair", "runner", "web", "web2", - "words", "vfs"] - - -class ConditionalExtension(Extension): - """ - An extension module that will only be compiled if certain conditions are - met. - - @param condition: A callable of one argument which returns True or False to - indicate whether the extension should be built. The argument is an - instance of L{build_ext_twisted}, which has useful methods for checking - things about the platform. - """ - def __init__(self, *args, **kwargs): - self.condition = kwargs.pop("condition", lambda builder: True) - Extension.__init__(self, *args, **kwargs) - - - -def setup(**kw): - """ - An alternative to distutils' setup() which is specially designed - for Twisted subprojects. - - Pass twisted_subproject=projname if you want package and data - files to automatically be found for you. - - @param conditionalExtensions: Extensions to optionally build. - @type conditionalExtensions: C{list} of L{ConditionalExtension} - """ - return core.setup(**get_setup_args(**kw)) - -def get_setup_args(**kw): - if 'twisted_subproject' in kw: - if 'twisted' not in os.listdir('.'): - raise RuntimeError("Sorry, you need to run setup.py from the " - "toplevel source directory.") - projname = kw['twisted_subproject'] - projdir = os.path.join('twisted', projname) - - kw['packages'] = getPackages(projdir, parent='twisted') - kw['version'] = getVersion(projname) - - plugin = "twisted/plugins/twisted_" + projname + ".py" - if os.path.exists(plugin): - kw.setdefault('py_modules', []).append( - plugin.replace("/", ".")[:-3]) - - kw['data_files'] = getDataFiles(projdir, parent='twisted') - - del kw['twisted_subproject'] - else: - if 'plugins' in kw: - py_modules = [] - for plg in kw['plugins']: - py_modules.append("twisted.plugins." + plg) - kw.setdefault('py_modules', []).extend(py_modules) - del kw['plugins'] - - if 'cmdclass' not in kw: - kw['cmdclass'] = { - 'install_data': install_data_twisted, - 'build_scripts': build_scripts_twisted} - if sys.version_info[:3] < (2, 3, 0): - kw['cmdclass']['build_py'] = build_py_twisted - - if "conditionalExtensions" in kw: - extensions = kw["conditionalExtensions"] - del kw["conditionalExtensions"] - - if 'ext_modules' not in kw: - # This is a workaround for distutils behavior; ext_modules isn't - # actually used by our custom builder. distutils deep-down checks - # to see if there are any ext_modules defined before invoking - # the build_ext command. We need to trigger build_ext regardless - # because it is the thing that does the conditional checks to see - # if it should build any extensions. The reason we have to delay - # the conditional checks until then is that the compiler objects - # are not yet set up when this code is executed. - kw["ext_modules"] = extensions - - class my_build_ext(build_ext_twisted): - conditionalExtensions = extensions - kw.setdefault('cmdclass', {})['build_ext'] = my_build_ext - return kw - -def getVersion(proj, base="twisted"): - """ - Extract the version number for a given project. - - @param proj: the name of the project. Examples are "core", - "conch", "words", "mail". - - @rtype: str - @returns: The version number of the project, as a string like - "2.0.0". - """ - if proj == 'core': - vfile = os.path.join(base, '_version.py') - else: - vfile = os.path.join(base, proj, '_version.py') - ns = {'__name__': 'Nothing to see here'} - execfile(vfile, ns) - return ns['version'].base() - - -# Names that are exluded from globbing results: -EXCLUDE_NAMES = ["{arch}", "CVS", ".cvsignore", "_darcs", - "RCS", "SCCS", ".svn"] -EXCLUDE_PATTERNS = ["*.py[cdo]", "*.s[ol]", ".#*", "*~", "*.py"] - -import fnmatch - -def _filterNames(names): - """Given a list of file names, return those names that should be copied. - """ - names = [n for n in names - if n not in EXCLUDE_NAMES] - # This is needed when building a distro from a working - # copy (likely a checkout) rather than a pristine export: - for pattern in EXCLUDE_PATTERNS: - names = [n for n in names - if (not fnmatch.fnmatch(n, pattern)) - and (not n.endswith('.py'))] - return names - -def relativeTo(base, relativee): - """ - Gets 'relativee' relative to 'basepath'. - - i.e., - - >>> relativeTo('/home/', '/home/radix/') - 'radix' - >>> relativeTo('.', '/home/radix/Projects/Twisted') # curdir is /home/radix - 'Projects/Twisted' - - The 'relativee' must be a child of 'basepath'. - """ - basepath = os.path.abspath(base) - relativee = os.path.abspath(relativee) - if relativee.startswith(basepath): - relative = relativee[len(basepath):] - if relative.startswith(os.sep): - relative = relative[1:] - return os.path.join(base, relative) - raise ValueError("%s is not a subpath of %s" % (relativee, basepath)) - - -def getDataFiles(dname, ignore=None, parent=None): - """ - Get all the data files that should be included in this distutils Project. - - 'dname' should be the path to the package that you're distributing. - - 'ignore' is a list of sub-packages to ignore. This facilitates - disparate package hierarchies. That's a fancy way of saying that - the 'twisted' package doesn't want to include the 'twisted.conch' - package, so it will pass ['conch'] as the value. - - 'parent' is necessary if you're distributing a subpackage like - twisted.conch. 'dname' should point to 'twisted/conch' and 'parent' - should point to 'twisted'. This ensures that your data_files are - generated correctly, only using relative paths for the first element - of the tuple ('twisted/conch/*'). - The default 'parent' is the current working directory. - """ - parent = parent or "." - ignore = ignore or [] - result = [] - for directory, subdirectories, filenames in os.walk(dname): - resultfiles = [] - for exname in EXCLUDE_NAMES: - if exname in subdirectories: - subdirectories.remove(exname) - for ig in ignore: - if ig in subdirectories: - subdirectories.remove(ig) - for filename in _filterNames(filenames): - resultfiles.append(filename) - if resultfiles: - result.append((relativeTo(parent, directory), - [relativeTo(parent, - os.path.join(directory, filename)) - for filename in resultfiles])) - return result - -def getPackages(dname, pkgname=None, results=None, ignore=None, parent=None): - """ - Get all packages which are under dname. This is necessary for - Python 2.2's distutils. Pretty similar arguments to getDataFiles, - including 'parent'. - """ - parent = parent or "" - prefix = [] - if parent: - prefix = [parent] - bname = os.path.basename(dname) - ignore = ignore or [] - if bname in ignore: - return [] - if results is None: - results = [] - if pkgname is None: - pkgname = [] - subfiles = os.listdir(dname) - abssubfiles = [os.path.join(dname, x) for x in subfiles] - if '__init__.py' in subfiles: - results.append(prefix + pkgname + [bname]) - for subdir in filter(os.path.isdir, abssubfiles): - getPackages(subdir, pkgname=pkgname + [bname], - results=results, ignore=ignore, - parent=parent) - res = ['.'.join(result) for result in results] - return res - - - -def getScripts(projname, basedir=''): - """ - Returns a list of scripts for a Twisted subproject; this works in - any of an SVN checkout, a project-specific tarball. - """ - scriptdir = os.path.join(basedir, 'bin', projname) - if not os.path.isdir(scriptdir): - # Probably a project-specific tarball, in which case only this - # project's bins are included in 'bin' - scriptdir = os.path.join(basedir, 'bin') - if not os.path.isdir(scriptdir): - return [] - thingies = os.listdir(scriptdir) - if '.svn' in thingies: - thingies.remove('.svn') - return filter(os.path.isfile, - [os.path.join(scriptdir, x) for x in thingies]) - - -## Helpers and distutil tweaks - -class build_py_twisted(build_py.build_py): - """ - Changes behavior in Python 2.2 to support simultaneous specification of - `packages' and `py_modules'. - """ - def run(self): - if self.py_modules: - self.build_modules() - if self.packages: - self.build_packages() - self.byte_compile(self.get_outputs(include_bytecode=0)) - - - -class build_scripts_twisted(build_scripts.build_scripts): - """Renames scripts so they end with '.py' on Windows.""" - - def run(self): - build_scripts.build_scripts.run(self) - if not os.name == "nt": - return - for f in os.listdir(self.build_dir): - fpath=os.path.join(self.build_dir, f) - if not fpath.endswith(".py"): - try: - os.unlink(fpath + ".py") - except EnvironmentError, e: - if e.args[1]=='No such file or directory': - pass - os.rename(fpath, fpath + ".py") - - - -class install_data_twisted(install_data.install_data): - """I make sure data files are installed in the package directory.""" - def finalize_options(self): - self.set_undefined_options('install', - ('install_lib', 'install_dir') - ) - install_data.install_data.finalize_options(self) - - - -class build_ext_twisted(build_ext.build_ext): - """ - Allow subclasses to easily detect and customize Extensions to - build at install-time. - """ - - def prepare_extensions(self): - """ - Prepare the C{self.extensions} attribute (used by - L{build_ext.build_ext}) by checking which extensions in - L{conditionalExtensions} should be built. In addition, if we are - building on NT, define the WIN32 macro to 1. - """ - # always define WIN32 under Windows - if os.name == 'nt': - self.define_macros = [("WIN32", 1)] - else: - self.define_macros = [] - self.extensions = [x for x in self.conditionalExtensions - if x.condition(self)] - for ext in self.extensions: - ext.define_macros.extend(self.define_macros) - - - def build_extensions(self): - """ - Check to see which extension modules to build and then build them. - """ - self.prepare_extensions() - build_ext.build_ext.build_extensions(self) - - - def _remove_conftest(self): - for filename in ("conftest.c", "conftest.o", "conftest.obj"): - try: - os.unlink(filename) - except EnvironmentError: - pass - - - def _compile_helper(self, content): - conftest = open("conftest.c", "w") - try: - conftest.write(content) - conftest.close() - - try: - self.compiler.compile(["conftest.c"], output_dir='') - except CompileError: - return False - return True - finally: - self._remove_conftest() - - - def _check_header(self, header_name): - """ - Check if the given header can be included by trying to compile a file - that contains only an #include line. - """ - self.compiler.announce("checking for %s ..." % header_name, 0) - return self._compile_helper("#include <%s>\n" % header_name) - diff --git a/tools/buildbot/pylibs/twisted/python/dxprofile.py b/tools/buildbot/pylibs/twisted/python/dxprofile.py deleted file mode 100644 index 1939893..0000000 --- a/tools/buildbot/pylibs/twisted/python/dxprofile.py +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -DEPRECATED since Twisted 8.0. - -Utility functions for reporting bytecode frequencies to Skip Montanaro's -stat collector. - -This module requires a version of Python build with DYNAMIC_EXCUTION_PROFILE, -and optionally DXPAIRS, defined to be useful. -""" - -import sys, types, xmlrpclib, warnings - - -warnings.warn("twisted.python.dxprofile is deprecated since Twisted 8.0.", - category=DeprecationWarning) - - -def rle(iterable): - """ - Run length encode a list. - """ - iterable = iter(iterable) - runlen = 1 - result = [] - try: - previous = iterable.next() - except StopIteration: - return [] - for element in iterable: - if element == previous: - runlen = runlen + 1 - continue - else: - if isinstance(previous, (types.ListType, types.TupleType)): - previous = rle(previous) - result.append([previous, runlen]) - previous = element - runlen = 1 - if isinstance(previous, (types.ListType, types.TupleType)): - previous = rle(previous) - result.append([previous, runlen]) - return result - - - -def report(email, appname): - """ - Send an RLE encoded version of sys.getdxp() off to our Top Men (tm) - for analysis. - """ - if hasattr(sys, 'getdxp') and appname: - dxp = xmlrpclib.ServerProxy("http://manatee.mojam.com:7304") - dxp.add_dx_info(appname, email, sys.version_info[:3], rle(sys.getdxp())) diff --git a/tools/buildbot/pylibs/twisted/python/failure.py b/tools/buildbot/pylibs/twisted/python/failure.py deleted file mode 100644 index 76d5b7f..0000000 --- a/tools/buildbot/pylibs/twisted/python/failure.py +++ /dev/null @@ -1,550 +0,0 @@ -# -*- test-case-name: twisted.test.test_failure -*- -# See also test suite twisted.test.test_pbfailure - -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Asynchronous-friendly error mechanism. - -See L{Failure}. -""" - -# System Imports -import sys -import linecache -import inspect -import opcode -from cStringIO import StringIO - -from twisted.python import reflect - -count = 0 -traceupLength = 4 - -class DefaultException(Exception): - pass - -def format_frames(frames, write, detail="default"): - """Format and write frames. - - @param frames: is a list of frames as used by Failure.frames, with - each frame being a list of - (funcName, fileName, lineNumber, locals.items(), globals.items()) - @type frames: list - @param write: this will be called with formatted strings. - @type write: callable - @param detail: Three detail levels are available: - default, brief, and verbose. - @type detail: string - """ - if detail not in ('default', 'brief', 'verbose'): - raise ValueError, "Detail must be default, brief, or verbose. (not %r)" % (detail,) - w = write - if detail == "brief": - for method, filename, lineno, localVars, globalVars in frames: - w('%s:%s:%s\n' % (filename, lineno, method)) - elif detail == "default": - for method, filename, lineno, localVars, globalVars in frames: - w( ' File "%s", line %s, in %s\n' % (filename, lineno, method)) - w( ' %s\n' % linecache.getline(filename, lineno).strip()) - elif detail == "verbose": - for method, filename, lineno, localVars, globalVars in frames: - w("%s:%d: %s(...)\n" % (filename, lineno, method)) - w(' [ Locals ]\n') - # Note: the repr(val) was (self.pickled and val) or repr(val))) - for name, val in localVars: - w(" %s : %s\n" % (name, repr(val))) - w(' ( Globals )\n') - for name, val in globalVars: - w(" %s : %s\n" % (name, repr(val))) - -# slyphon: i have a need to check for this value in trial -# so I made it a module-level constant -EXCEPTION_CAUGHT_HERE = "--- ---" - - - -class NoCurrentExceptionError(Exception): - """ - Raised when trying to create a Failure from the current interpreter - exception state and there is no current exception state. - """ - - -class _Traceback(object): - """ - Fake traceback object which can be passed to functions in the standard - library L{traceback} module. - """ - - def __init__(self, frames): - """ - Construct a fake traceback object using a list of frames. Note that - although frames generally include locals and globals, this information - is not kept by this object, since locals and globals are not used in - standard tracebacks. - - @param frames: [(methodname, filename, lineno, locals, globals), ...] - """ - assert len(frames) > 0, "Must pass some frames" - head, frames = frames[0], frames[1:] - name, filename, lineno, localz, globalz = head - self.tb_frame = _Frame(name, filename) - self.tb_lineno = lineno - if len(frames) == 0: - self.tb_next = None - else: - self.tb_next = _Traceback(frames) - - -class _Frame(object): - """ - A fake frame object, used by L{_Traceback}. - """ - - def __init__(self, name, filename): - self.f_code = _Code(name, filename) - self.f_globals = {} - - -class _Code(object): - """ - A fake code object, used by L{_Traceback} via L{_Frame}. - """ - def __init__(self, name, filename): - self.co_name = name - self.co_filename = filename - - -class Failure: - """A basic abstraction for an error that has occurred. - - This is necessary because Python's built-in error mechanisms are - inconvenient for asynchronous communication. - - @ivar value: The exception instance responsible for this failure. - @ivar type: The exception's class. - """ - - pickled = 0 - stack = None - - # The opcode of "yield" in Python bytecode. We need this in _findFailure in - # order to identify whether an exception was thrown by a - # throwExceptionIntoGenerator. - _yieldOpcode = chr(opcode.opmap["YIELD_VALUE"]) - - def __init__(self, exc_value=None, exc_type=None, exc_tb=None): - """Initialize me with an explanation of the error. - - By default, this will use the current X{exception} - (L{sys.exc_info}()). However, if you want to specify a - particular kind of failure, you can pass an exception as an - argument. - - If no C{exc_value} is passed, then an "original" Failure will - be searched for. If the current exception handler that this - Failure is being constructed in is handling an exception - raised by L{raiseException}, then this Failure will act like - the original Failure. - """ - global count - count = count + 1 - self.count = count - self.type = self.value = tb = None - - #strings Exceptions/Failures are bad, mmkay? - if isinstance(exc_value, (str, unicode)) and exc_type is None: - import warnings - warnings.warn( - "Don't pass strings (like %r) to failure.Failure (replacing with a DefaultException)." % - exc_value, DeprecationWarning, stacklevel=2) - exc_value = DefaultException(exc_value) - - stackOffset = 0 - - if exc_value is None: - exc_value = self._findFailure() - - if exc_value is None: - self.type, self.value, tb = sys.exc_info() - if self.type is None: - raise NoCurrentExceptionError() - stackOffset = 1 - elif exc_type is None: - if isinstance(exc_value, Exception): - self.type = exc_value.__class__ - else: #allow arbitrary objects. - self.type = type(exc_value) - self.value = exc_value - else: - self.type = exc_type - self.value = exc_value - if isinstance(self.value, Failure): - self.__dict__ = self.value.__dict__ - return - if tb is None: - if exc_tb: - tb = exc_tb -# else: -# log.msg("Erf, %r created with no traceback, %s %s." % ( -# repr(self), repr(exc_value), repr(exc_type))) -# for s in traceback.format_stack(): -# log.msg(s) - - frames = self.frames = [] - stack = self.stack = [] - - # added 2003-06-23 by Chris Armstrong. Yes, I actually have a - # use case where I need this traceback object, and I've made - # sure that it'll be cleaned up. - self.tb = tb - - if tb: - f = tb.tb_frame - elif not isinstance(self.value, Failure): - # we don't do frame introspection since it's expensive, - # and if we were passed a plain exception with no - # traceback, it's not useful anyway - f = stackOffset = None - - while stackOffset and f: - # This excludes this Failure.__init__ frame from the - # stack, leaving it to start with our caller instead. - f = f.f_back - stackOffset -= 1 - - # Keeps the *full* stack. Formerly in spread.pb.print_excFullStack: - # - # The need for this function arises from the fact that several - # PB classes have the peculiar habit of discarding exceptions - # with bareword "except:"s. This premature exception - # catching means tracebacks generated here don't tend to show - # what called upon the PB object. - - while f: - localz = f.f_locals.copy() - if f.f_locals is f.f_globals: - globalz = {} - else: - globalz = f.f_globals.copy() - for d in globalz, localz: - if d.has_key("__builtins__"): - del d["__builtins__"] - stack.insert(0, [ - f.f_code.co_name, - f.f_code.co_filename, - f.f_lineno, - localz.items(), - globalz.items(), - ]) - f = f.f_back - - while tb is not None: - f = tb.tb_frame - localz = f.f_locals.copy() - if f.f_locals is f.f_globals: - globalz = {} - else: - globalz = f.f_globals.copy() - for d in globalz, localz: - if d.has_key("__builtins__"): - del d["__builtins__"] - - frames.append([ - f.f_code.co_name, - f.f_code.co_filename, - tb.tb_lineno, - localz.items(), - globalz.items(), - ]) - tb = tb.tb_next - if inspect.isclass(self.type) and issubclass(self.type, Exception): - parentCs = reflect.allYourBase(self.type) - self.parents = map(reflect.qual, parentCs) - self.parents.append(reflect.qual(self.type)) - else: - self.parents = [self.type] - - def trap(self, *errorTypes): - """Trap this failure if its type is in a predetermined list. - - This allows you to trap a Failure in an error callback. It will be - automatically re-raised if it is not a type that you expect. - - The reason for having this particular API is because it's very useful - in Deferred errback chains: - - | def _ebFoo(self, failure): - | r = failure.trap(Spam, Eggs) - | print 'The Failure is due to either Spam or Eggs!' - | if r == Spam: - | print 'Spam did it!' - | elif r == Eggs: - | print 'Eggs did it!' - - If the failure is not a Spam or an Eggs, then the Failure - will be 'passed on' to the next errback. - - @type errorTypes: L{Exception} - """ - error = self.check(*errorTypes) - if not error: - raise self - return error - - def check(self, *errorTypes): - """Check if this failure's type is in a predetermined list. - - @type errorTypes: list of L{Exception} classes or - fully-qualified class names. - @returns: the matching L{Exception} type, or None if no match. - """ - for error in errorTypes: - err = error - if inspect.isclass(error) and issubclass(error, Exception): - err = reflect.qual(error) - if err in self.parents: - return error - return None - - - def raiseException(self): - """ - raise the original exception, preserving traceback - information if available. - """ - raise self.type, self.value, self.tb - - - def throwExceptionIntoGenerator(self, g): - """ - Throw the original exception into the given generator, - preserving traceback information if available. - - @return: The next value yielded from the generator. - @raise StopIteration: If there are no more values in the generator. - @raise anything else: Anything that the generator raises. - """ - return g.throw(self.type, self.value, self.tb) - - - def _findFailure(cls): - """ - Find the failure that represents the exception currently in context. - """ - tb = sys.exc_info()[-1] - if not tb: - return - - secondLastTb = None - lastTb = tb - while lastTb.tb_next: - secondLastTb = lastTb - lastTb = lastTb.tb_next - - lastFrame = lastTb.tb_frame - - # NOTE: f_locals.get('self') is used rather than - # f_locals['self'] because psyco frames do not contain - # anything in their locals() dicts. psyco makes debugging - # difficult anyhow, so losing the Failure objects (and thus - # the tracebacks) here when it is used is not that big a deal. - - # handle raiseException-originated exceptions - if lastFrame.f_code is cls.raiseException.func_code: - return lastFrame.f_locals.get('self') - - # handle throwExceptionIntoGenerator-originated exceptions - # this is tricky, and differs if the exception was caught - # inside the generator, or above it: - - # it is only really originating from - # throwExceptionIntoGenerator if the bottom of the traceback - # is a yield. - # Pyrex and Cython extensions create traceback frames - # with no co_code, but they can't yield so we know it's okay to just return here. - if ((not lastFrame.f_code.co_code) or - lastFrame.f_code.co_code[lastTb.tb_lasti] != cls._yieldOpcode): - return - - # if the exception was caught above the generator.throw - # (outside the generator), it will appear in the tb (as the - # second last item): - if secondLastTb: - frame = secondLastTb.tb_frame - if frame.f_code is cls.throwExceptionIntoGenerator.func_code: - return frame.f_locals.get('self') - - # if the exception was caught below the generator.throw - # (inside the generator), it will appear in the frames' linked - # list, above the top-level traceback item (which must be the - # generator frame itself, thus its caller is - # throwExceptionIntoGenerator). - frame = tb.tb_frame.f_back - if frame and frame.f_code is cls.throwExceptionIntoGenerator.func_code: - return frame.f_locals.get('self') - - _findFailure = classmethod(_findFailure) - - def __repr__(self): - return "<%s %s>" % (self.__class__, self.type) - - def __str__(self): - return "[Failure instance: %s]" % self.getBriefTraceback() - - def __getstate__(self): - """Avoid pickling objects in the traceback. - """ - if self.pickled: - return self.__dict__ - c = self.__dict__.copy() - - c['frames'] = [ - [ - v[0], v[1], v[2], - [(j[0], reflect.safe_repr(j[1])) for j in v[3]], - [(j[0], reflect.safe_repr(j[1])) for j in v[4]] - ] for v in self.frames - ] - - # added 2003-06-23. See comment above in __init__ - c['tb'] = None - - if self.stack is not None: - # XXX: This is a band-aid. I can't figure out where these - # (failure.stack is None) instances are coming from. - c['stack'] = [ - [ - v[0], v[1], v[2], - [(j[0], reflect.safe_repr(j[1])) for j in v[3]], - [(j[0], reflect.safe_repr(j[1])) for j in v[4]] - ] for v in self.stack - ] - - c['pickled'] = 1 - return c - - def cleanFailure(self): - """Remove references to other objects, replacing them with strings. - """ - self.__dict__ = self.__getstate__() - - def getTracebackObject(self): - """ - Get an object that represents this Failure's stack that can be passed - to traceback.extract_tb. - - If the original traceback object is still present, return that. If this - traceback object has been lost but we still have the information, - return a fake traceback object (see L{_Traceback}). If there is no - traceback information at all, return None. - """ - if self.tb is not None: - return self.tb - elif len(self.frames) > 0: - return _Traceback(self.frames) - else: - return None - - def getErrorMessage(self): - """Get a string of the exception which caused this Failure.""" - if isinstance(self.value, Failure): - return self.value.getErrorMessage() - return reflect.safe_str(self.value) - - def getBriefTraceback(self): - io = StringIO() - self.printBriefTraceback(file=io) - return io.getvalue() - - def getTraceback(self, elideFrameworkCode=0, detail='default'): - io = StringIO() - self.printTraceback(file=io, elideFrameworkCode=elideFrameworkCode, detail=detail) - return io.getvalue() - - def printTraceback(self, file=None, elideFrameworkCode=0, detail='default'): - """Emulate Python's standard error reporting mechanism. - """ - if file is None: - file = log.logerr - w = file.write - - # Preamble - if detail == 'verbose': - w( '*--- Failure #%d%s---\n' % - (self.count, - (self.pickled and ' (pickled) ') or ' ')) - elif detail == 'brief': - if self.frames: - hasFrames = 'Traceback' - else: - hasFrames = 'Traceback (failure with no frames)' - w("%s: %s: %s\n" % (hasFrames, self.type, self.value)) - else: - w( 'Traceback (most recent call last):\n') - - # Frames, formatted in appropriate style - if self.frames: - if not elideFrameworkCode: - format_frames(self.stack[-traceupLength:], w, detail) - w("%s\n" % (EXCEPTION_CAUGHT_HERE,)) - format_frames(self.frames, w, detail) - elif not detail == 'brief': - # Yeah, it's not really a traceback, despite looking like one... - w("Failure: ") - - # postamble, if any - if not detail == 'brief': - # Unfortunately, self.type will not be a class object if this - # Failure was created implicitly from a string exception. - # qual() doesn't make any sense on a string, so check for this - # case here and just write out the string if that's what we - # have. - if isinstance(self.type, (str, unicode)): - w(self.type + "\n") - else: - w("%s: %s\n" % (reflect.qual(self.type), - reflect.safe_str(self.value))) - # chaining - if isinstance(self.value, Failure): - # TODO: indentation for chained failures? - file.write(" (chained Failure)\n") - self.value.printTraceback(file, elideFrameworkCode, detail) - if detail == 'verbose': - w('*--- End of Failure #%d ---\n' % self.count) - - def printBriefTraceback(self, file=None, elideFrameworkCode=0): - """Print a traceback as densely as possible. - """ - self.printTraceback(file, elideFrameworkCode, detail='brief') - - def printDetailedTraceback(self, file=None, elideFrameworkCode=0): - """Print a traceback with detailed locals and globals information. - """ - self.printTraceback(file, elideFrameworkCode, detail='verbose') - -# slyphon: make post-morteming exceptions tweakable - -DO_POST_MORTEM = True - -def _debuginit(self, exc_value=None, exc_type=None, exc_tb=None, - Failure__init__=Failure.__init__.im_func): - if (exc_value, exc_type, exc_tb) == (None, None, None): - exc = sys.exc_info() - if not exc[0] == self.__class__ and DO_POST_MORTEM: - print "Jumping into debugger for post-mortem of exception '%s':" % exc[1] - import pdb - pdb.post_mortem(exc[2]) - Failure__init__(self, exc_value, exc_type, exc_tb) - -def startDebugMode(): - """Enable debug hooks for Failures.""" - Failure.__init__ = _debuginit - - -# Sibling imports - at the bottom and unqualified to avoid unresolvable -# circularity -import log diff --git a/tools/buildbot/pylibs/twisted/python/filepath.py b/tools/buildbot/pylibs/twisted/python/filepath.py deleted file mode 100644 index a31f2e8..0000000 --- a/tools/buildbot/pylibs/twisted/python/filepath.py +++ /dev/null @@ -1,675 +0,0 @@ -# -*- test-case-name: twisted.test.test_paths -*- -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Object-oriented filesystem path representation. -""" - -import os -import errno -import random -import sha -import base64 - -from os.path import isabs, exists, normpath, abspath, splitext -from os.path import basename, dirname -from os.path import join as joinpath -from os import sep as slash -from os import listdir, utime, stat - -from stat import S_ISREG, S_ISDIR - -# Please keep this as light as possible on other Twisted imports; many, many -# things import this module, and it would be good if it could easily be -# modified for inclusion in the standard library. --glyph - -from twisted.python.runtime import platform - -from twisted.python.win32 import ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND -from twisted.python.win32 import ERROR_INVALID_NAME, ERROR_DIRECTORY -from twisted.python.win32 import WindowsError - -def _stub_islink(path): - """ - Always return 'false' if the operating system does not support symlinks. - - @param path: a path string. - @type path: L{str} - @return: false - """ - return False - - -def _stub_urandom(n): - """ - Provide random data in versions of Python prior to 2.4. This is an - effectively compatible replacement for 'os.urandom'. - - @type n: L{int} - @param n: the number of bytes of data to return - @return: C{n} bytes of random data. - @rtype: str - """ - randomData = [random.randrange(256) for n in xrange(n)] - return ''.join(map(chr, randomData)) - - -def _stub_armor(s): - """ - ASCII-armor for random data. This uses a hex encoding, although we will - prefer url-safe base64 encoding for features in this module if it is - available. - """ - return s.encode('hex') - -islink = getattr(os.path, 'islink', _stub_islink) -randomBytes = getattr(os, 'urandom', _stub_urandom) -armor = getattr(base64, 'urlsafe_b64encode', _stub_armor) - -class InsecurePath(Exception): - pass - - -class UnlistableError(OSError): - """ - An exception which is used to distinguish between errors which mean 'this - is not a directory you can list' and other, more catastrophic errors. - - This error will try to look as much like the original error as possible, - while still being catchable as an independent type. - - @ivar originalException: the actual original exception instance, either an - L{OSError} or a L{WindowsError}. - """ - def __init__(self, originalException): - """ - Create an UnlistableError exception. - - @param originalException: an instance of OSError. - """ - self.__dict__.update(originalException.__dict__) - self.originalException = originalException - - - -class _WindowsUnlistableError(UnlistableError, WindowsError): - """ - This exception is raised on Windows, for compatibility with previous - releases of FilePath where unportable programs may have done "except - WindowsError:" around a call to children(). - - It is private because all application code may portably catch - L{UnlistableError} instead. - """ - - - -def _secureEnoughString(): - """ - Create a pseudorandom, 16-character string for use in secure filenames. - """ - return armor(sha.new(randomBytes(64)).digest())[:16] - -class _PathHelper: - """ - Abstract helper class also used by ZipPath; implements certain utility methods. - """ - - def getContent(self): - return self.open().read() - - def children(self): - """ - List the chilren of this path object. - - @raise OSError: If an error occurs while listing the directory. If the - error is 'serious', meaning that the operation failed due to an access - violation, exhaustion of some kind of resource (file descriptors or - memory), OSError or a platform-specific variant will be raised. - - @raise UnlistableError: If the inability to list the directory is due - to this path not existing or not being a directory, the more specific - OSError subclass L{UnlistableError} is raised instead. - - @return: an iterable of all currently-existing children of this object - accessible with L{_PathHelper.child}. - """ - try: - subnames = self.listdir() - except WindowsError, winErrObj: - # WindowsError is an OSError subclass, so if not for this clause - # the OSError clause below would be handling these. Windows error - # codes aren't the same as POSIX error codes, so we need to handle - # them differently. - - # Under Python 2.5 on Windows, WindowsError has a winerror - # attribute and an errno attribute. The winerror attribute is - # bound to the Windows error code while the errno attribute is - # bound to a translation of that code to a perhaps equivalent POSIX - # error number. - - # Under Python 2.4 on Windows, WindowsError only has an errno - # attribute. It is bound to the Windows error code. - - # For simplicity of code and to keep the number of paths through - # this suite minimal, we grab the Windows error code under either - # version. - - # Furthermore, attempting to use os.listdir on a non-existent path - # in Python 2.4 will result in a Windows error code of - # ERROR_PATH_NOT_FOUND. However, in Python 2.5, - # ERROR_FILE_NOT_FOUND results instead. -exarkun - winerror = getattr(winErrObj, 'winerror', winErrObj.errno) - if winerror not in (ERROR_PATH_NOT_FOUND, - ERROR_FILE_NOT_FOUND, - ERROR_INVALID_NAME, - ERROR_DIRECTORY): - raise - raise _WindowsUnlistableError(winErrObj) - except OSError, ose: - if ose.errno not in (errno.ENOENT, errno.ENOTDIR): - # Other possible errors here, according to linux manpages: - # EACCES, EMIFLE, ENFILE, ENOMEM. None of these seem like the - # sort of thing which should be handled normally. -glyph - raise - raise UnlistableError(ose) - return map(self.child, subnames) - - def walk(self): - """ - Yield myself, then each of my children, and each of those children's - children in turn. - - @return: a generator yielding FilePath-like objects. - """ - yield self - if self.isdir(): - for c in self.children(): - for subc in c.walk(): - yield subc - - def sibling(self, path): - return self.parent().child(path) - - def segmentsFrom(self, ancestor): - """ - Return a list of segments between a child and its ancestor. - - For example, in the case of a path X representing /a/b/c/d and a path Y - representing /a/b, C{Y.segmentsFrom(X)} will return C{['c', - 'd']}. - - @param ancestor: an instance of the same class as self, ostensibly an - ancestor of self. - - @raise: ValueError if the 'ancestor' parameter is not actually an - ancestor, i.e. a path for /x/y/z is passed as an ancestor for /a/b/c/d. - - @return: a list of strs - """ - # this might be an unnecessarily inefficient implementation but it will - # work on win32 and for zipfiles; later I will deterimine if the - # obvious fast implemenation does the right thing too - f = self - p = f.parent() - segments = [] - while f != ancestor and p != f: - segments[0:0] = [f.basename()] - f = p - p = p.parent() - if f == ancestor and segments: - return segments - raise ValueError("%r not parent of %r" % (ancestor, self)) - - - # new in 8.0 - def __hash__(self): - """ - Hash the same as another FilePath with the same path as mine. - """ - return hash((self.__class__, self.path)) - - - # pending deprecation in 8.0 - def getmtime(self): - """ - Deprecated. Use getModificationTime instead. - """ - return int(self.getModificationTime()) - - - def getatime(self): - """ - Deprecated. Use getAccessTime instead. - """ - return int(self.getAccessTime()) - - - def getctime(self): - """ - Deprecated. Use getStatusChangeTime instead. - """ - return int(self.getStatusChangeTime()) - - - -class FilePath(_PathHelper): - """ - I am a path on the filesystem that only permits 'downwards' access. - - Instantiate me with a pathname (for example, - FilePath('/home/myuser/public_html')) and I will attempt to only provide - access to files which reside inside that path. I may be a path to a file, - a directory, or a file which does not exist. - - The correct way to use me is to instantiate me, and then do ALL filesystem - access through me. In other words, do not import the 'os' module; if you - need to open a file, call my 'open' method. If you need to list a - directory, call my 'path' method. - - Even if you pass me a relative path, I will convert that to an absolute - path internally. - - Note: although time-related methods do return floating-point results, they - may still be only second resolution depending on the platform and the last - value passed to L{os.stat_float_times}. If you want greater-than-second - precision, call C{os.stat_float_times(True)}, or use Python 2.5. - Greater-than-second precision is only available in Windows on Python2.5 and - later. - - @type alwaysCreate: C{bool} - @ivar alwaysCreate: When opening this file, only succeed if the file does not - already exist. - """ - - statinfo = None - path = None - - def __init__(self, path, alwaysCreate=False): - self.path = abspath(path) - self.alwaysCreate = alwaysCreate - - def __getstate__(self): - d = self.__dict__.copy() - if d.has_key('statinfo'): - del d['statinfo'] - return d - - def child(self, path): - if platform.isWindows() and path.count(":"): - # Catch paths like C:blah that don't have a slash - raise InsecurePath("%r contains a colon." % (path,)) - norm = normpath(path) - if slash in norm: - raise InsecurePath("%r contains one or more directory separators" % (path,)) - newpath = abspath(joinpath(self.path, norm)) - if not newpath.startswith(self.path): - raise InsecurePath("%r is not a child of %s" % (newpath, self.path)) - return self.clonePath(newpath) - - def preauthChild(self, path): - """ - Use me if `path' might have slashes in it, but you know they're safe. - - (NOT slashes at the beginning. It still needs to be a _child_). - """ - newpath = abspath(joinpath(self.path, normpath(path))) - if not newpath.startswith(self.path): - raise InsecurePath("%s is not a child of %s" % (newpath, self.path)) - return self.clonePath(newpath) - - def childSearchPreauth(self, *paths): - """Return my first existing child with a name in 'paths'. - - paths is expected to be a list of *pre-secured* path fragments; in most - cases this will be specified by a system administrator and not an - arbitrary user. - - If no appropriately-named children exist, this will return None. - """ - p = self.path - for child in paths: - jp = joinpath(p, child) - if exists(jp): - return self.clonePath(jp) - - def siblingExtensionSearch(self, *exts): - """Attempt to return a path with my name, given multiple possible - extensions. - - Each extension in exts will be tested and the first path which exists - will be returned. If no path exists, None will be returned. If '' is - in exts, then if the file referred to by this path exists, 'self' will - be returned. - - The extension '*' has a magic meaning, which means "any path that - begins with self.path+'.' is acceptable". - """ - p = self.path - for ext in exts: - if not ext and self.exists(): - return self - if ext == '*': - basedot = basename(p)+'.' - for fn in listdir(dirname(p)): - if fn.startswith(basedot): - return self.clonePath(joinpath(dirname(p), fn)) - p2 = p + ext - if exists(p2): - return self.clonePath(p2) - - def siblingExtension(self, ext): - return self.clonePath(self.path+ext) - - - def linkTo(self, linkFilePath): - """ - Creates a symlink to self to at the path in the L{FilePath} - C{linkFilePath}. Only works on posix systems due to its dependence on - C{os.symlink}. Propagates C{OSError}s up from C{os.symlink} if - C{linkFilePath.parent()} does not exist, or C{linkFilePath} already - exists. - - @param linkFilePath: a FilePath representing the link to be created - @type linkFilePath: L{FilePath} - """ - os.symlink(self.path, linkFilePath.path) - - - def open(self, mode='r'): - if self.alwaysCreate: - assert 'a' not in mode, "Appending not supported when alwaysCreate == True" - return self.create() - return open(self.path, mode+'b') - - # stat methods below - - def restat(self, reraise=True): - """ - Re-calculate cached effects of 'stat'. To refresh information on this path - after you know the filesystem may have changed, call this method. - - @param reraise: a boolean. If true, re-raise exceptions from - L{os.stat}; otherwise, mark this path as not existing, and remove any - cached stat information. - """ - try: - self.statinfo = stat(self.path) - except OSError: - self.statinfo = 0 - if reraise: - raise - - - def chmod(self, mode): - """ - Changes the permissions on self, if possible. Propagates errors from - C{os.chmod} up. - - @param mode: integer representing the new permissions desired (same as - the command line chmod) - @type mode: C{int} - """ - os.chmod(self.path, mode) - - - def getsize(self): - st = self.statinfo - if not st: - self.restat() - st = self.statinfo - return st.st_size - - - def getModificationTime(self): - """ - Retrieve the time of last access from this file. - - @return: a number of seconds from the epoch. - @rtype: float - """ - st = self.statinfo - if not st: - self.restat() - st = self.statinfo - return float(st.st_mtime) - - - def getStatusChangeTime(self): - """ - Retrieve the time of the last status change for this file. - - @return: a number of seconds from the epoch. - @rtype: float - """ - st = self.statinfo - if not st: - self.restat() - st = self.statinfo - return float(st.st_ctime) - - - def getAccessTime(self): - """ - Retrieve the time that this file was last accessed. - - @return: a number of seconds from the epoch. - @rtype: float - """ - st = self.statinfo - if not st: - self.restat() - st = self.statinfo - return float(st.st_atime) - - - def exists(self): - """ - Check if the C{path} exists. - - @return: C{True} if the stats of C{path} can be retrieved successfully, - C{False} in the other cases. - @rtype: C{bool} - """ - if self.statinfo: - return True - else: - self.restat(False) - if self.statinfo: - return True - else: - return False - - - def isdir(self): - st = self.statinfo - if not st: - self.restat(False) - st = self.statinfo - if not st: - return False - return S_ISDIR(st.st_mode) - - def isfile(self): - st = self.statinfo - if not st: - self.restat(False) - st = self.statinfo - if not st: - return False - return S_ISREG(st.st_mode) - - def islink(self): - # We can't use cached stat results here, because that is the stat of - # the destination - (see #1773) which in *every case* but this one is - # the right thing to use. We could call lstat here and use that, but - # it seems unlikely we'd actually save any work that way. -glyph - return islink(self.path) - - def isabs(self): - return isabs(self.path) - - def listdir(self): - return listdir(self.path) - - def splitext(self): - return splitext(self.path) - - def __repr__(self): - return 'FilePath(%r)' % (self.path,) - - def touch(self): - try: - self.open('a').close() - except IOError: - pass - utime(self.path, None) - - def remove(self): - """ - Removes the file or directory that is represented by self. If - C{self.path} is a directory, recursively remove all its children - before removing the directory. If it's a file or link, just delete - it. - """ - if self.isdir() and not self.islink(): - for child in self.children(): - child.remove() - os.rmdir(self.path) - else: - os.remove(self.path) - self.restat(False) - - - def makedirs(self): - """ - Create all directories not yet existing in C{path} segments, using - C{os.makedirs}. - """ - return os.makedirs(self.path) - - - def globChildren(self, pattern): - """ - Assuming I am representing a directory, return a list of - FilePaths representing my children that match the given - pattern. - """ - import glob - path = self.path[-1] == '/' and self.path + pattern or slash.join([self.path, pattern]) - return map(self.clonePath, glob.glob(path)) - - def basename(self): - return basename(self.path) - - def dirname(self): - return dirname(self.path) - - def parent(self): - return self.clonePath(self.dirname()) - - def setContent(self, content, ext='.new'): - sib = self.siblingExtension(ext) - sib.open('w').write(content) - if platform.isWindows() and exists(self.path): - os.unlink(self.path) - os.rename(sib.path, self.path) - - # new in 2.2.0 - - def __cmp__(self, other): - if not isinstance(other, FilePath): - return NotImplemented - return cmp(self.path, other.path) - - def createDirectory(self): - os.mkdir(self.path) - - def requireCreate(self, val=1): - self.alwaysCreate = val - - def create(self): - """Exclusively create a file, only if this file previously did not exist. - """ - fdint = os.open(self.path, (os.O_EXCL | - os.O_CREAT | - os.O_RDWR)) - - # XXX TODO: 'name' attribute of returned files is not mutable or - # settable via fdopen, so this file is slighly less functional than the - # one returned from 'open' by default. send a patch to Python... - - return os.fdopen(fdint, 'w+b') - - def temporarySibling(self): - """ - Create a path naming a temporary sibling of this path in a secure fashion. - """ - sib = self.sibling(_secureEnoughString() + self.basename()) - sib.requireCreate() - return sib - - _chunkSize = 2 ** 2 ** 2 ** 2 - - def copyTo(self, destination): - # XXX TODO: *thorough* audit and documentation of the exact desired - # semantics of this code. Right now the behavior of existent - # destination symlinks is convenient, and quite possibly correct, but - # its security properties need to be explained. - if self.isdir(): - if not destination.exists(): - destination.createDirectory() - for child in self.children(): - destChild = destination.child(child.basename()) - child.copyTo(destChild) - elif self.isfile(): - writefile = destination.open('w') - readfile = self.open() - while 1: - # XXX TODO: optionally use os.open, os.read and O_DIRECT and - # use os.fstatvfs to determine chunk sizes and make - # *****sure**** copy is page-atomic; the following is good - # enough for 99.9% of everybody and won't take a week to audit - # though. - chunk = readfile.read(self._chunkSize) - writefile.write(chunk) - if len(chunk) < self._chunkSize: - break - writefile.close() - readfile.close() - else: - # If you see the following message because you want to copy - # symlinks, fifos, block devices, character devices, or unix - # sockets, please feel free to add support to do sensible things in - # reaction to those types! - raise NotImplementedError( - "Only copying of files and directories supported") - - def moveTo(self, destination): - try: - os.rename(self.path, destination.path) - self.restat(False) - except OSError, ose: - if ose.errno == errno.EXDEV: - # man 2 rename, ubuntu linux 5.10 "breezy": - - # oldpath and newpath are not on the same mounted filesystem. - # (Linux permits a filesystem to be mounted at multiple - # points, but rename(2) does not work across different mount - # points, even if the same filesystem is mounted on both.) - - # that means it's time to copy trees of directories! - secsib = destination.temporarySibling() - self.copyTo(secsib) # slow - secsib.moveTo(destination) # visible - - # done creating new stuff. let's clean me up. - mysecsib = self.temporarySibling() - self.moveTo(mysecsib) # visible - mysecsib.remove() # slow - else: - raise - - -FilePath.clonePath = FilePath diff --git a/tools/buildbot/pylibs/twisted/python/finalize.py b/tools/buildbot/pylibs/twisted/python/finalize.py deleted file mode 100644 index 8b99bf6..0000000 --- a/tools/buildbot/pylibs/twisted/python/finalize.py +++ /dev/null @@ -1,46 +0,0 @@ - -""" -A module for externalized finalizers. -""" - -import weakref - -garbageKey = 0 - -def callbackFactory(num, fins): - def _cb(w): - del refs[num] - for fx in fins: - fx() - return _cb - -refs = {} - -def register(inst): - global garbageKey - garbageKey += 1 - r = weakref.ref(inst, callbackFactory(garbageKey, inst.__finalizers__())) - refs[garbageKey] = r - -if __name__ == '__main__': - def fin(): - print 'I am _so_ dead.' - - class Finalizeable: - """ - An un-sucky __del__ - """ - - def __finalizers__(self): - """ - I'm going away. - """ - return [fin] - - f = Finalizeable() - f.f2 = f - register(f) - del f - import gc - gc.collect() - print 'deled' diff --git a/tools/buildbot/pylibs/twisted/python/formmethod.py b/tools/buildbot/pylibs/twisted/python/formmethod.py deleted file mode 100644 index 69b0edf..0000000 --- a/tools/buildbot/pylibs/twisted/python/formmethod.py +++ /dev/null @@ -1,363 +0,0 @@ -# -*- test-case-name: twisted.test.test_formmethod -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Form-based method objects. - -This module contains support for descriptive method signatures that can be used -to format methods. Currently this is only used by woven. -""" - -import calendar - -class FormException(Exception): - """An error occurred calling the form method. - """ - def __init__(self, *args, **kwargs): - Exception.__init__(self, *args) - self.descriptions = kwargs - - -class InputError(FormException): - """ - An error occurred with some input. - """ - - -class Argument: - """Base class for form arguments.""" - - # default value for argument, if no other default is given - defaultDefault = None - - def __init__(self, name, default=None, shortDesc=None, - longDesc=None, hints=None, allowNone=1): - self.name = name - self.allowNone = allowNone - if default is None: - default = self.defaultDefault - self.default = default - self.shortDesc = shortDesc - self.longDesc = longDesc - if not hints: - hints = {} - self.hints = hints - - def addHints(self, **kwargs): - self.hints.update(kwargs) - - def getHint(self, name, default=None): - return self.hints.get(name, default) - - def getShortDescription(self): - return self.shortDesc or self.name.capitalize() - - def getLongDescription(self): - return self.longDesc or '' #self.shortDesc or "The %s." % self.name - - def coerce(self, val): - """Convert the value to the correct format.""" - raise NotImplementedError, "implement in subclass" - - -class String(Argument): - """A single string. - """ - defaultDefault = '' - min = 0 - max = None - - def __init__(self, name, default=None, shortDesc=None, - longDesc=None, hints=None, allowNone=1, min=0, max=None): - Argument.__init__(self, name, default=default, shortDesc=shortDesc, - longDesc=longDesc, hints=hints, allowNone=allowNone) - self.min = min - self.max = max - - def coerce(self, val): - s = str(val) - if len(s) < self.min: - raise InputError, "Value must be at least %s characters long" % self.min - if self.max != None and len(s) > self.max: - raise InputError, "Value must be at most %s characters long" % self.max - return str(val) - - -class Text(String): - """A long string. - """ - - -class Password(String): - """A string which should be obscured when input. - """ - - -class VerifiedPassword(String): - """A string that should be obscured when input and needs verification.""" - - def coerce(self, vals): - if len(vals) != 2 or vals[0] != vals[1]: - raise InputError, "Please enter the same password twice." - s = str(vals[0]) - if len(s) < self.min: - raise InputError, "Value must be at least %s characters long" % self.min - if self.max != None and len(s) > self.max: - raise InputError, "Value must be at most %s characters long" % self.max - return s - - -class Hidden(String): - """A string which is not displayed. - - The passed default is used as the value. - """ - - -class Integer(Argument): - """A single integer. - """ - defaultDefault = None - - def __init__(self, name, allowNone=1, default=None, shortDesc=None, - longDesc=None, hints=None): - #although Argument now has allowNone, that was recently added, and - #putting it at the end kept things which relied on argument order - #from breaking. However, allowNone originally was in here, so - #I have to keep the same order, to prevent breaking code that - #depends on argument order only - Argument.__init__(self, name, default, shortDesc, longDesc, hints, - allowNone) - - def coerce(self, val): - if not val.strip() and self.allowNone: - return None - try: - return int(val) - except ValueError: - raise InputError, "%s is not valid, please enter a whole number, e.g. 10" % val - - -class IntegerRange(Integer): - - def __init__(self, name, min, max, allowNone=1, default=None, shortDesc=None, - longDesc=None, hints=None): - self.min = min - self.max = max - Integer.__init__(self, name, allowNone=allowNone, default=default, shortDesc=shortDesc, - longDesc=longDesc, hints=hints) - - def coerce(self, val): - result = Integer.coerce(self, val) - if self.allowNone and result == None: - return result - if result < self.min: - raise InputError, "Value %s is too small, it should be at least %s" % (result, self.min) - if result > self.max: - raise InputError, "Value %s is too large, it should be at most %s" % (result, self.max) - return result - - -class Float(Argument): - - defaultDefault = None - - def __init__(self, name, allowNone=1, default=None, shortDesc=None, - longDesc=None, hints=None): - #although Argument now has allowNone, that was recently added, and - #putting it at the end kept things which relied on argument order - #from breaking. However, allowNone originally was in here, so - #I have to keep the same order, to prevent breaking code that - #depends on argument order only - Argument.__init__(self, name, default, shortDesc, longDesc, hints, - allowNone) - - - def coerce(self, val): - if not val.strip() and self.allowNone: - return None - try: - return float(val) - except ValueError: - raise InputError, "Invalid float: %s" % val - - -class Choice(Argument): - """ - The result of a choice between enumerated types. The choices should - be a list of tuples of tag, value, and description. The tag will be - the value returned if the user hits "Submit", and the description - is the bale for the enumerated type. default is a list of all the - values (seconds element in choices). If no defaults are specified, - initially the first item will be selected. Only one item can (should) - be selected at once. - """ - def __init__(self, name, choices=[], default=[], shortDesc=None, - longDesc=None, hints=None, allowNone=1): - self.choices = choices - if choices and not default: - default.append(choices[0][1]) - Argument.__init__(self, name, default, shortDesc, longDesc, hints, allowNone=allowNone) - - def coerce(self, inIdent): - for ident, val, desc in self.choices: - if ident == inIdent: - return val - else: - raise InputError("Invalid Choice: %s" % inIdent) - - -class Flags(Argument): - """ - The result of a checkbox group or multi-menu. The flags should be a - list of tuples of tag, value, and description. The tag will be - the value returned if the user hits "Submit", and the description - is the bale for the enumerated type. default is a list of all the - values (second elements in flags). If no defaults are specified, - initially nothing will be selected. Several items may be selected at - once. - """ - def __init__(self, name, flags=(), default=(), shortDesc=None, - longDesc=None, hints=None, allowNone=1): - self.flags = flags - Argument.__init__(self, name, default, shortDesc, longDesc, hints, allowNone=allowNone) - - def coerce(self, inFlagKeys): - if not inFlagKeys: - return [] - outFlags = [] - for inFlagKey in inFlagKeys: - for flagKey, flagVal, flagDesc in self.flags: - if inFlagKey == flagKey: - outFlags.append(flagVal) - break - else: - raise InputError("Invalid Flag: %s" % inFlagKey) - return outFlags - - -class CheckGroup(Flags): - pass - - -class RadioGroup(Choice): - pass - - -class Boolean(Argument): - def coerce(self, inVal): - if not inVal: - return 0 - lInVal = str(inVal).lower() - if lInVal in ('no', 'n', 'f', 'false', '0'): - return 0 - return 1 - -class File(Argument): - def __init__(self, name, allowNone=1, shortDesc=None, longDesc=None, - hints=None): - self.allowNone = allowNone - Argument.__init__(self, name, None, shortDesc, longDesc, hints) - - def coerce(self, file): - if not file and self.allowNone: - return None - elif file: - return file - else: - raise InputError, "Invalid File" - -def positiveInt(x): - x = int(x) - if x <= 0: raise ValueError - return x - -class Date(Argument): - """A date -- (year, month, day) tuple.""" - - defaultDefault = None - - def __init__(self, name, allowNone=1, default=None, shortDesc=None, - longDesc=None, hints=None): - Argument.__init__(self, name, default, shortDesc, longDesc, hints) - self.allowNone = allowNone - if not allowNone: - self.defaultDefault = (1970, 1, 1) - - def coerce(self, args): - """Return tuple of ints (year, month, day).""" - if tuple(args) == ("", "", "") and self.allowNone: - return None - - try: - year, month, day = map(positiveInt, args) - except ValueError: - raise InputError, "Invalid date" - if (month, day) == (2, 29): - if not calendar.isleap(year): - raise InputError, "%d was not a leap year" % year - else: - return year, month, day - try: - mdays = calendar.mdays[month] - except IndexError: - raise InputError, "Invalid date" - if day > mdays: - raise InputError, "Invalid date" - return year, month, day - - -class Submit(Choice): - """Submit button or a reasonable facsimile thereof.""" - - def __init__(self, name, choices=[("Submit", "submit", "Submit form")], - reset=0, shortDesc=None, longDesc=None, allowNone=0, hints=None): - Choice.__init__(self, name, choices=choices, shortDesc=shortDesc, - longDesc=longDesc, hints=hints) - self.allowNone = allowNone - self.reset = reset - - def coerce(self, value): - if self.allowNone and not value: - return None - else: - return Choice.coerce(self, value) - - -class PresentationHint: - """ - A hint to a particular system. - """ - - -class MethodSignature: - - def __init__(self, *sigList): - """ - """ - self.methodSignature = sigList - - def getArgument(self, name): - for a in self.methodSignature: - if a.name == name: - return a - - def method(self, callable, takesRequest=False): - return FormMethod(self, callable, takesRequest) - - -class FormMethod: - """A callable object with a signature.""" - - def __init__(self, signature, callable, takesRequest=False): - self.signature = signature - self.callable = callable - self.takesRequest = takesRequest - - def getArgs(self): - return tuple(self.signature.methodSignature) - - def call(self,*args,**kw): - return self.callable(*args,**kw) diff --git a/tools/buildbot/pylibs/twisted/python/hook.py b/tools/buildbot/pylibs/twisted/python/hook.py deleted file mode 100644 index 3c85ca7..0000000 --- a/tools/buildbot/pylibs/twisted/python/hook.py +++ /dev/null @@ -1,177 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - - -""" -I define support for hookable instance methods. - -These are methods which you can register pre-call and post-call external -functions to augment their functionality. People familiar with more esoteric -languages may think of these as \"method combinations\". - -This could be used to add optional preconditions, user-extensible callbacks -(a-la emacs) or a thread-safety mechanism. - -The four exported calls are: - - - L{addPre} - - L{addPost} - - L{removePre} - - L{removePost} - -All have the signature (class, methodName, callable), and the callable they -take must always have the signature (instance, *args, **kw) unless the -particular signature of the method they hook is known. - -Hooks should typically not throw exceptions, however, no effort will be made by -this module to prevent them from doing so. Pre-hooks will always be called, -but post-hooks will only be called if the pre-hooks do not raise any exceptions -(they will still be called if the main method raises an exception). The return -values and exception status of the main method will be propogated (assuming -none of the hooks raise an exception). Hooks will be executed in the order in -which they are added. - -""" - -# System Imports -import string - -### Public Interface - -class HookError(Exception): - "An error which will fire when an invariant is violated." - -def addPre(klass, name, func): - """hook.addPre(klass, name, func) -> None - - Add a function to be called before the method klass.name is invoked. - """ - - _addHook(klass, name, PRE, func) - -def addPost(klass, name, func): - """hook.addPost(klass, name, func) -> None - - Add a function to be called after the method klass.name is invoked. - """ - _addHook(klass, name, POST, func) - -def removePre(klass, name, func): - """hook.removePre(klass, name, func) -> None - - Remove a function (previously registered with addPre) so that it - is no longer executed before klass.name. - """ - - _removeHook(klass, name, PRE, func) - -def removePost(klass, name, func): - """hook.removePre(klass, name, func) -> None - - Remove a function (previously registered with addPost) so that it - is no longer executed after klass.name. - """ - _removeHook(klass, name, POST, func) - -### "Helper" functions. - -hooked_func = """ - -import %(module)s - -def %(name)s(*args, **kw): - klazz = %(module)s.%(klass)s - for preMethod in klazz.%(preName)s: - preMethod(*args, **kw) - try: - return klazz.%(originalName)s(*args, **kw) - finally: - for postMethod in klazz.%(postName)s: - postMethod(*args, **kw) -""" - -_PRE = '__hook_pre_%s_%s_%s__' -_POST = '__hook_post_%s_%s_%s__' -_ORIG = '__hook_orig_%s_%s_%s__' - - -def _XXX(k,n,s): - "string manipulation garbage" - x = s % (string.replace(k.__module__,'.','_'), k.__name__, n) - return x - -def PRE(k,n): - "(private) munging to turn a method name into a pre-hook-method-name" - return _XXX(k,n,_PRE) - -def POST(k,n): - "(private) munging to turn a method name into a post-hook-method-name" - return _XXX(k,n,_POST) - -def ORIG(k,n): - "(private) munging to turn a method name into an `original' identifier" - return _XXX(k,n,_ORIG) - - -def _addHook(klass, name, phase, func): - "(private) adds a hook to a method on a class" - _enhook(klass, name) - - if not hasattr(klass, phase(klass, name)): - setattr(klass, phase(klass, name), []) - - phaselist = getattr(klass, phase(klass, name)) - phaselist.append(func) - - -def _removeHook(klass, name, phase, func): - "(private) removes a hook from a method on a class" - phaselistname = phase(klass, name) - if not hasattr(klass, ORIG(klass,name)): - raise HookError("no hooks present!") - - phaselist = getattr(klass, phase(klass, name)) - try: phaselist.remove(func) - except ValueError: - raise HookError("hook %s not found in removal list for %s"% - (name,klass)) - - if not getattr(klass, PRE(klass,name)) and not getattr(klass, POST(klass, name)): - _dehook(klass, name) - -def _enhook(klass, name): - "(private) causes a certain method name to be hooked on a class" - if hasattr(klass, ORIG(klass, name)): - return - - def newfunc(*args, **kw): - for preMethod in getattr(klass, PRE(klass, name)): - preMethod(*args, **kw) - try: - return getattr(klass, ORIG(klass, name))(*args, **kw) - finally: - for postMethod in getattr(klass, POST(klass, name)): - postMethod(*args, **kw) - try: - newfunc.func_name = name - except TypeError: - # Older python's don't let you do this - pass - - oldfunc = getattr(klass, name).im_func - setattr(klass, ORIG(klass, name), oldfunc) - setattr(klass, PRE(klass, name), []) - setattr(klass, POST(klass, name), []) - setattr(klass, name, newfunc) - -def _dehook(klass, name): - "(private) causes a certain method name no longer to be hooked on a class" - - if not hasattr(klass, ORIG(klass, name)): - raise HookError("Cannot unhook!") - setattr(klass, name, getattr(klass, ORIG(klass,name))) - delattr(klass, PRE(klass,name)) - delattr(klass, POST(klass,name)) - delattr(klass, ORIG(klass,name)) diff --git a/tools/buildbot/pylibs/twisted/python/htmlizer.py b/tools/buildbot/pylibs/twisted/python/htmlizer.py deleted file mode 100644 index bdb31e6..0000000 --- a/tools/buildbot/pylibs/twisted/python/htmlizer.py +++ /dev/null @@ -1,87 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -import tokenize, cgi, keyword -import reflect - -class TokenPrinter: - - currentCol, currentLine = 0, 1 - lastIdentifier = parameters = 0 - - def __init__(self, writer): - self.writer = writer - - def printtoken(self, type, token, (srow, scol), (erow, ecol), line): - #print "printtoken(%r,%r,%r,(%r,%r),(%r,%r),%r), row=%r,col=%r" % ( - # self, type, token, srow,scol, erow,ecol, line, - # self.currentLine, self.currentCol) - if self.currentLine < srow: - self.writer('\n'*(srow-self.currentLine)) - self.currentLine, self.currentCol = srow, 0 - self.writer(' '*(scol-self.currentCol)) - if self.lastIdentifier: - type = "identifier" - self.parameters = 1 - elif type == tokenize.NAME: - if keyword.iskeyword(token): - type = 'keyword' - else: - if self.parameters: - type = 'parameter' - else: - type = 'variable' - else: - type = tokenize.tok_name.get(type).lower() - self.writer(token, type) - self.currentCol = ecol - self.currentLine += token.count('\n') - if self.currentLine != erow: - self.currentCol = 0 - self.lastIdentifier = token in ('def', 'class') - if token == ':': - self.parameters = 0 - - -class HTMLWriter: - - noSpan = [] - - def __init__(self, writer): - self.writer = writer - noSpan = [] - reflect.accumulateClassList(self.__class__, "noSpan", noSpan) - self.noSpan = noSpan - - def write(self, token, type=None): - token = cgi.escape(token) - if (type is None) or (type in self.noSpan): - self.writer(token) - else: - self.writer('%s' % - (type, token)) - - -class SmallerHTMLWriter(HTMLWriter): - """HTMLWriter that doesn't generate spans for some junk. - - Results in much smaller HTML output. - """ - noSpan = ["endmarker", "indent", "dedent", "op", "newline", "nl"] - -def filter(inp, out, writer=HTMLWriter): - out.write('
                  \n')
                  -    printer = TokenPrinter(writer(out.write).write).printtoken
                  -    try:
                  -        tokenize.tokenize(inp.readline, printer)
                  -    except tokenize.TokenError:
                  -        pass
                  -    out.write('
                  \n') - -def main(): - import sys - filter(open(sys.argv[1]), sys.stdout) - -if __name__ == '__main__': - main() diff --git a/tools/buildbot/pylibs/twisted/python/lockfile.py b/tools/buildbot/pylibs/twisted/python/lockfile.py deleted file mode 100644 index a6750d7..0000000 --- a/tools/buildbot/pylibs/twisted/python/lockfile.py +++ /dev/null @@ -1,143 +0,0 @@ -# -*- test-case-name: twisted.test.test_lockfile -*- -# Copyright (c) 2005 Divmod, Inc. -# See LICENSE for details. - - -""" -Lock files. -""" - -__metaclass__ = type - -import errno, os - -from time import time as _uniquefloat - -def unique(): - return str(long(_uniquefloat() * 1000)) - -try: - from os import symlink - from os import readlink - from os import remove as rmlink - from os import rename as mvlink -except: - # XXX Implement an atomic thingamajig for win32 - import shutil - def symlink(value, filename): - newlinkname = filename+"."+unique()+'.newlink' - newvalname = os.path.join(newlinkname,"symlink") - os.mkdir(newlinkname) - f = open(newvalname,'wb') - f.write(value) - f.flush() - f.close() - try: - os.rename(newlinkname, filename) - except: - os.remove(newvalname) - os.rmdir(newlinkname) - raise - - def readlink(filename): - return open(os.path.join(filename,'symlink'),'rb').read() - - def rmlink(filename): - shutil.rmtree(filename) - - def mvlink(src, dest): - try: - shutil.rmtree(dest) - except: - pass - os.rename(src,dest) - - -class FilesystemLock: - """A mutex. - - This relies on the filesystem property that creating - a symlink is an atomic operation and that it will - fail if the symlink already exists. Deleting the - symlink will release the lock. - - @ivar name: The name of the file associated with this lock. - @ivar clean: Indicates whether this lock was released cleanly by its - last owner. Only meaningful after C{lock} has been called and returns - True. - """ - - clean = None - locked = False - - def __init__(self, name): - self.name = name - - def lock(self): - """Acquire this lock. - - @rtype: C{bool} - @return: True if the lock is acquired, false otherwise. - - @raise: Any exception os.symlink() may raise, other than - EEXIST. - """ - try: - pid = readlink(self.name) - except (OSError, IOError), e: - if e.errno != errno.ENOENT: - raise - self.clean = True - else: - if not hasattr(os, 'kill'): - return False - try: - os.kill(int(pid), 0) - except (OSError, IOError), e: - if e.errno != errno.ESRCH: - raise - rmlink(self.name) - self.clean = False - else: - return False - - symlink(str(os.getpid()), self.name) - self.locked = True - return True - - def unlock(self): - """Release this lock. - - This deletes the directory with the given name. - - @raise: Any exception os.readlink() may raise, or - ValueError if the lock is not owned by this process. - """ - pid = readlink(self.name) - if int(pid) != os.getpid(): - raise ValueError("Lock %r not owned by this process" % (self.name,)) - rmlink(self.name) - self.locked = False - - -def isLocked(name): - """Determine if the lock of the given name is held or not. - - @type name: C{str} - @param name: The filesystem path to the lock to test - - @rtype: C{bool} - @return: True if the lock is held, False otherwise. - """ - l = FilesystemLock(name) - result = None - try: - result = l.lock() - finally: - if result: - l.unlock() - return not result - - -__all__ = ['FilesystemLock', 'isLocked'] - diff --git a/tools/buildbot/pylibs/twisted/python/log.py b/tools/buildbot/pylibs/twisted/python/log.py deleted file mode 100644 index 37514f4..0000000 --- a/tools/buildbot/pylibs/twisted/python/log.py +++ /dev/null @@ -1,584 +0,0 @@ -# -*- test-case-name: twisted.test.test_log -*- -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Logging and metrics infrastructure. -""" - -from __future__ import division - -# System Imports -import sys -import time -import warnings -from datetime import datetime -import logging - -# Sibling Imports -from twisted.python import util, context, reflect - -class ILogContext: - """ - Actually, this interface is just a synoym for the dictionary interface, - but it serves as a key for the default information in a log. - - I do not inherit from Interface because the world is a cruel place. - """ - -context.setDefault(ILogContext, - {"isError": 0, - "system": "-"}) - -def callWithContext(ctx, func, *args, **kw): - newCtx = context.get(ILogContext).copy() - newCtx.update(ctx) - return context.call({ILogContext: newCtx}, func, *args, **kw) - -def callWithLogger(logger, func, *args, **kw): - """ - Utility method which wraps a function in a try:/except:, logs a failure if - one occurrs, and uses the system's logPrefix. - """ - try: - lp = logger.logPrefix() - except KeyboardInterrupt: - raise - except: - lp = '(buggy logPrefix method)' - err(system=lp) - try: - return callWithContext({"system": lp}, func, *args, **kw) - except KeyboardInterrupt: - raise - except: - err(system=lp) - -def showwarning(message, category, filename, lineno, file=None): - if file is None: - msg(warning=message, category=reflect.qual(category), filename=filename, lineno=lineno, - format="%(filename)s:%(lineno)s: %(category)s: %(warning)s") - else: - _oldshowwarning(message, category, filename, lineno, file) - -_keepErrors = 0 -_keptErrors = [] -_ignoreErrors = [] - -def startKeepingErrors(): - """ - DEPRECATED in Twisted 2.5. - - Support function for testing frameworks. - - Start keeping errors in a buffer which can be retrieved (and emptied) with - flushErrors. - """ - warnings.warn("log.startKeepingErrors is deprecated since Twisted 2.5", - category=DeprecationWarning, stacklevel=2) - global _keepErrors - _keepErrors = 1 - - -def flushErrors(*errorTypes): - """ - DEPRECATED in Twisted 2.5. See L{TestCase.flushLoggedErrors}. - - Support function for testing frameworks. - - Return a list of errors that occurred since the last call to flushErrors(). - (This will return None unless startKeepingErrors has been called.) - """ - - warnings.warn("log.flushErrors is deprecated since Twisted 2.5. " - "If you need to flush errors from within a unittest, " - "use TestCase.flushLoggedErrors instead.", - category=DeprecationWarning, stacklevel=2) - return _flushErrors(*errorTypes) - - -def _flushErrors(*errorTypes): - """ - PRIVATE. DEPRECATED. DON'T USE. - """ - global _keptErrors - k = _keptErrors - _keptErrors = [] - if errorTypes: - for erk in k: - shouldReLog = 1 - for errT in errorTypes: - if erk.check(errT): - shouldReLog = 0 - if shouldReLog: - err(erk) - return k - -def ignoreErrors(*types): - """ - DEPRECATED - """ - warnings.warn("log.ignoreErrors is deprecated since Twisted 2.5", - category=DeprecationWarning, stacklevel=2) - _ignore(*types) - -def _ignore(*types): - """ - PRIVATE. DEPRECATED. DON'T USE. - """ - for type in types: - _ignoreErrors.append(type) - -def clearIgnores(): - """ - DEPRECATED - """ - warnings.warn("log.clearIgnores is deprecated since Twisted 2.5", - category=DeprecationWarning, stacklevel=2) - _clearIgnores() - -def _clearIgnores(): - """ - PRIVATE. DEPRECATED. DON'T USE. - """ - global _ignoreErrors - _ignoreErrors = [] - - -def err(_stuff=None, _why=None, **kw): - """ - Write a failure to the log. - """ - if _stuff is None: - _stuff = failure.Failure() - if isinstance(_stuff, failure.Failure): - if _keepErrors: - if _ignoreErrors: - keep = 0 - for err in _ignoreErrors: - r = _stuff.check(err) - if r: - keep = 0 - break - else: - keep = 1 - if keep: - _keptErrors.append(_stuff) - else: - _keptErrors.append(_stuff) - msg(failure=_stuff, why=_why, isError=1, **kw) - elif isinstance(_stuff, Exception): - msg(failure=failure.Failure(_stuff), why=_why, isError=1, **kw) - else: - msg(repr(_stuff), why=_why, isError=1, **kw) - -deferr = err - - -class Logger: - """ - This represents a class which may 'own' a log. Used by subclassing. - """ - def logPrefix(self): - """ - Override this method to insert custom logging behavior. Its - return value will be inserted in front of every line. It may - be called more times than the number of output lines. - """ - return '-' - - -class LogPublisher: - """ - Class for singleton log message publishing. - """ - - synchronized = ['msg'] - - def __init__(self): - self.observers = [] - - def addObserver(self, other): - """ - Add a new observer. - - Observers are callable objects that will be called with each new log - message (a dict). - """ - assert callable(other) - self.observers.append(other) - - def removeObserver(self, other): - """ - Remove an observer. - """ - self.observers.remove(other) - - def msg(self, *message, **kw): - """ - Log a new message. - - For example:: - - >>> log.msg('Hello, world.') - - In particular, you MUST avoid the forms:: - - >>> log.msg(u'Hello, world.') - >>> log.msg('Hello ', 'world.') - - These forms work (sometimes) by accident and will be disabled - entirely in the future. - """ - actualEventDict = (context.get(ILogContext) or {}).copy() - actualEventDict.update(kw) - actualEventDict['message'] = message - actualEventDict['time'] = time.time() - for i in xrange(len(self.observers) - 1, -1, -1): - try: - self.observers[i](actualEventDict) - except KeyboardInterrupt: - # Don't swallow keyboard interrupt! - raise - except UnicodeEncodeError: - raise - except: - o = self.observers.pop(i) - err(failure.Failure(), - "Log observer %s failed, removing from observer list." % (o,)) - - -try: - theLogPublisher -except NameError: - theLogPublisher = LogPublisher() - addObserver = theLogPublisher.addObserver - removeObserver = theLogPublisher.removeObserver - msg = theLogPublisher.msg - - -def _safeFormat(fmtString, fmtDict): - """ - Try to format the string C{fmtString} using C{fmtDict} arguments, - swallowing all errors to always return a string. - """ - # There's a way we could make this if not safer at least more - # informative: perhaps some sort of str/repr wrapper objects - # could be wrapped around the things inside of C{fmtDict}. That way - # if the event dict contains an object with a bad __repr__, we - # can only cry about that individual object instead of the - # entire event dict. - try: - text = fmtString % fmtDict - except KeyboardInterrupt: - raise - except: - try: - text = ('Invalid format string or unformattable object in log message: %r, %s' % (fmtString, fmtDict)) - except: - try: - text = 'UNFORMATTABLE OBJECT WRITTEN TO LOG with fmt %r, MESSAGE LOST' % (fmtString,) - except: - text = 'PATHOLOGICAL ERROR IN BOTH FORMAT STRING AND MESSAGE DETAILS, MESSAGE LOST' - return text - - -def textFromEventDict(eventDict): - """ - Extract text from an event dict passed to a log observer. If it cannot - handle the dict, it returns None. - - The possible keys of eventDict are: - - C{message}: by default, it holds the final text. It's required, but can - be empty if either C{isError} or C{format} is provided (the first - having the priority). - - C{isError}: boolean indicating the nature of the event. - - C{failure}: L{failure.Failure} instance, required if the event is an - error. - - C{why}: if defined, used as header of the traceback in case of errors. - - C{format}: string format used in place of C{message} to customize - the event. It uses all keys present in C{eventDict} to format - the text. - Other keys will be used when applying the C{format}, or ignored. - """ - edm = eventDict['message'] - if not edm: - if eventDict['isError'] and 'failure' in eventDict: - text = ((eventDict.get('why') or 'Unhandled Error') - + '\n' + eventDict['failure'].getTraceback()) - elif 'format' in eventDict: - text = _safeFormat(eventDict['format'], eventDict) - else: - # we don't know how to log this - return - else: - text = ' '.join(map(reflect.safe_str, edm)) - return text - - -class FileLogObserver: - """ - Log observer that writes to a file-like object. - - @type timeFormat: C{str} or C{NoneType} - @ivar timeFormat: If not C{None}, the format string passed to strftime(). - """ - timeFormat = None - - def __init__(self, f): - self.write = f.write - self.flush = f.flush - - def getTimezoneOffset(self, when): - """ - Return the current local timezone offset from UTC. - - @type when: C{int} - @param when: POSIX (ie, UTC) timestamp for which to find the offset. - - @rtype: C{int} - @return: The number of seconds offset from UTC. West is positive, - east is negative. - """ - offset = datetime.utcfromtimestamp(when) - datetime.fromtimestamp(when) - return offset.days * (60 * 60 * 24) + offset.seconds - - def formatTime(self, when): - """ - Format the given UTC value as a string representing that time in the - local timezone. - - By default it's formatted as a ISO8601-like string (ISO8601 date and - ISO8601 time separated by a space). It can be customized using the - C{timeFormat} attribute, which will be used as input for the underlying - C{time.strftime} call. - - @type when: C{int} - @param when: POSIX (ie, UTC) timestamp for which to find the offset. - - @rtype: C{str} - """ - if self.timeFormat is not None: - return time.strftime(self.timeFormat, time.localtime(when)) - - tzOffset = -self.getTimezoneOffset(when) - when = datetime.utcfromtimestamp(when + tzOffset) - tzHour = int(tzOffset / 60 / 60) - tzMin = int(tzOffset / 60 % 60) - return '%d-%02d-%02d %02d:%02d:%02d%+03d%02d' % ( - when.year, when.month, when.day, - when.hour, when.minute, when.second, - tzHour, tzMin) - - def emit(self, eventDict): - text = textFromEventDict(eventDict) - if text is None: - return - - timeStr = self.formatTime(eventDict['time']) - fmtDict = {'system': eventDict['system'], 'text': text.replace("\n", "\n\t")} - msgStr = _safeFormat("[%(system)s] %(text)s\n", fmtDict) - - util.untilConcludes(self.write, timeStr + " " + msgStr) - util.untilConcludes(self.flush) # Hoorj! - - def start(self): - """ - Start observing log events. - """ - addObserver(self.emit) - - def stop(self): - """ - Stop observing log events. - """ - removeObserver(self.emit) - - -class PythonLoggingObserver(object): - """ - Output twisted messages to Python standard library L{logging} module. - - WARNING: specific logging configurations (example: network) can lead to - a blocking system. Nothing is done here to prevent that, so be sure to not - use this: code within Twisted, such as twisted.web, assumes that logging - does not block. - """ - - def __init__(self, loggerName="twisted"): - """ - @param loggerName: identifier used for getting logger. - @type loggerName: C{str} - """ - self.logger = logging.getLogger(loggerName) - - def emit(self, eventDict): - """ - Receive a twisted log entry, format it and bridge it to python. - - By default the logging level used is info; log.err produces error - level, and you can customize the level by using the C{logLevel} key:: - - >>> log.msg('debugging', logLevel=logging.DEBUG) - - """ - if 'logLevel' in eventDict: - level = eventDict['logLevel'] - elif eventDict['isError']: - level = logging.ERROR - else: - level = logging.INFO - text = textFromEventDict(eventDict) - if text is None: - return - self.logger.log(level, text) - - def start(self): - """ - Start observing log events. - """ - addObserver(self.emit) - - def stop(self): - """ - Stop observing log events. - """ - removeObserver(self.emit) - - -class StdioOnnaStick: - """ - Class that pretends to be stout/err. - """ - - closed = 0 - softspace = 0 - mode = 'wb' - name = '' - - def __init__(self, isError=0): - self.isError = isError - self.buf = '' - - def close(self): - pass - - def fileno(self): - return -1 - - def flush(self): - pass - - def read(self): - raise IOError("can't read from the log!") - - readline = read - readlines = read - seek = read - tell = read - - def write(self, data): - d = (self.buf + data).split('\n') - self.buf = d[-1] - messages = d[0:-1] - for message in messages: - msg(message, printed=1, isError=self.isError) - - def writelines(self, lines): - for line in lines: - msg(line, printed=1, isError=self.isError) - - -try: - _oldshowwarning -except NameError: - _oldshowwarning = None - - -def startLogging(file, *a, **kw): - """ - Initialize logging to a specified file. - """ - flo = FileLogObserver(file) - startLoggingWithObserver(flo.emit, *a, **kw) - -def startLoggingWithObserver(observer, setStdout=1): - """ - Initialize logging to a specified observer. If setStdout is true - (defaults to yes), also redirect sys.stdout and sys.stderr - to the specified file. - """ - global defaultObserver, _oldshowwarning - if not _oldshowwarning: - _oldshowwarning = warnings.showwarning - warnings.showwarning = showwarning - if defaultObserver: - defaultObserver.stop() - defaultObserver = None - addObserver(observer) - msg("Log opened.") - if setStdout: - sys.stdout = logfile - sys.stderr = logerr - - -class NullFile: - softspace = 0 - def read(self): pass - def write(self, bytes): pass - def flush(self): pass - def close(self): pass - - -def discardLogs(): - """ - Throw away all logs. - """ - global logfile - logfile = NullFile() - - -# Prevent logfile from being erased on reload. This only works in cpython. -try: - logfile -except NameError: - logfile = StdioOnnaStick(0) - logerr = StdioOnnaStick(1) - - -class DefaultObserver: - """ - Default observer. - - Will ignore all non-error messages and send error messages to sys.stderr. - Will be removed when startLogging() is called for the first time. - """ - - def _emit(self, eventDict): - if eventDict["isError"]: - if 'failure' in eventDict: - text = eventDict['failure'].getTraceback() - else: - text = " ".join([str(m) for m in eventDict["message"]]) + "\n" - sys.stderr.write(text) - sys.stderr.flush() - - def start(self): - addObserver(self._emit) - - def stop(self): - removeObserver(self._emit) - - -# Some more sibling imports, at the bottom and unqualified to avoid -# unresolvable circularity -import threadable, failure -threadable.synchronize(LogPublisher) - - -try: - defaultObserver -except NameError: - defaultObserver = DefaultObserver() - defaultObserver.start() - diff --git a/tools/buildbot/pylibs/twisted/python/logfile.py b/tools/buildbot/pylibs/twisted/python/logfile.py deleted file mode 100644 index c19dc62..0000000 --- a/tools/buildbot/pylibs/twisted/python/logfile.py +++ /dev/null @@ -1,309 +0,0 @@ -# -*- test-case-name: twisted.test.test_logfile -*- - -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -A rotating, browsable log file. -""" - -# System Imports -import os, glob, time, stat - -from twisted.python import threadable - -class BaseLogFile: - """ - The base class for a log file that can be rotated. - """ - - synchronized = ["write", "rotate"] - - def __init__(self, name, directory, defaultMode=None): - """ - Create a log file. - - @param name: name of the file - @param directory: directory holding the file - @param defaultMode: permissions used to create the file. Default to - current permissions of the file if the file exists. - """ - self.directory = directory - assert os.path.isdir(self.directory) - self.name = name - self.path = os.path.join(directory, name) - if defaultMode is None and os.path.exists(self.path): - self.defaultMode = stat.S_IMODE(os.stat(self.path)[stat.ST_MODE]) - else: - self.defaultMode = defaultMode - self._openFile() - - def fromFullPath(cls, filename, *args, **kwargs): - """ - Construct a log file from a full file path. - """ - logPath = os.path.abspath(filename) - return cls(os.path.basename(logPath), - os.path.dirname(logPath), *args, **kwargs) - fromFullPath = classmethod(fromFullPath) - - def shouldRotate(self): - """ - Override with a method to that returns true if the log - should be rotated. - """ - raise NotImplementedError - - def _openFile(self): - """ - Open the log file. - """ - self.closed = False - if os.path.exists(self.path): - self._file = file(self.path, "r+", 1) - self._file.seek(0, 2) - else: - if self.defaultMode is not None: - # Set the lowest permissions - oldUmask = os.umask(0777) - try: - self._file = file(self.path, "w+", 1) - finally: - os.umask(oldUmask) - else: - self._file = file(self.path, "w+", 1) - if self.defaultMode is not None: - try: - os.chmod(self.path, self.defaultMode) - except OSError: - # Probably /dev/null or something? - pass - - def __getstate__(self): - state = self.__dict__.copy() - del state["_file"] - return state - - def __setstate__(self, state): - self.__dict__ = state - self._openFile() - - def write(self, data): - """ - Write some data to the file. - """ - if self.shouldRotate(): - self.flush() - self.rotate() - self._file.write(data) - - def flush(self): - """ - Flush the file. - """ - self._file.flush() - - def close(self): - """ - Close the file. - - The file cannot be used once it has been closed. - """ - self.closed = True - self._file.close() - self._file = None - - def getCurrentLog(self): - """ - Return a LogReader for the current log file. - """ - return LogReader(self.path) - - -class LogFile(BaseLogFile): - """ - A log file that can be rotated. - - A rotateLength of None disables automatic log rotation. - """ - def __init__(self, name, directory, rotateLength=1000000, defaultMode=None, - maxRotatedFiles=None): - """ - Create a log file rotating on length. - - @param name: file name. - @type name: C{str} - @param directory: path of the log file. - @type directory: C{str} - @param rotateLength: size of the log file where it rotates. Default to - 1M. - @type rotateLength: C{int} - @param defaultMode: mode used to create the file. - @type defaultMode: C{int} - @param maxRotatedFiles: if not None, max number of log files the class - creates. Warning: it removes all log files above this number. - @type maxRotatedFiles: C{int} - """ - BaseLogFile.__init__(self, name, directory, defaultMode) - self.rotateLength = rotateLength - self.maxRotatedFiles = maxRotatedFiles - - def _openFile(self): - BaseLogFile._openFile(self) - self.size = self._file.tell() - - def shouldRotate(self): - """ - Rotate when the log file size is larger than rotateLength. - """ - return self.rotateLength and self.size >= self.rotateLength - - def getLog(self, identifier): - """ - Given an integer, return a LogReader for an old log file. - """ - filename = "%s.%d" % (self.path, identifier) - if not os.path.exists(filename): - raise ValueError, "no such logfile exists" - return LogReader(filename) - - def write(self, data): - """ - Write some data to the file. - """ - BaseLogFile.write(self, data) - self.size += len(data) - - def rotate(self): - """ - Rotate the file and create a new one. - - If it's not possible to open new logfile, this will fail silently, - and continue logging to old logfile. - """ - if not (os.access(self.directory, os.W_OK) and os.access(self.path, os.W_OK)): - return - logs = self.listLogs() - logs.reverse() - for i in logs: - if self.maxRotatedFiles is not None and i >= self.maxRotatedFiles: - os.remove("%s.%d" % (self.path, i)) - else: - os.rename("%s.%d" % (self.path, i), "%s.%d" % (self.path, i + 1)) - self._file.close() - os.rename(self.path, "%s.1" % self.path) - self._openFile() - - def listLogs(self): - """ - Return sorted list of integers - the old logs' identifiers. - """ - result = [] - for name in glob.glob("%s.*" % self.path): - try: - counter = int(name.split('.')[-1]) - if counter: - result.append(counter) - except ValueError: - pass - result.sort() - return result - - def __getstate__(self): - state = BaseLogFile.__getstate__(self) - del state["size"] - return state - -threadable.synchronize(LogFile) - - -class DailyLogFile(BaseLogFile): - """A log file that is rotated daily (at or after midnight localtime) - """ - def _openFile(self): - BaseLogFile._openFile(self) - self.lastDate = self.toDate(os.stat(self.path)[8]) - - def shouldRotate(self): - """Rotate when the date has changed since last write""" - return self.toDate() > self.lastDate - - def toDate(self, *args): - """Convert a unixtime to (year, month, day) localtime tuple, - or return the current (year, month, day) localtime tuple. - - This function primarily exists so you may overload it with - gmtime, or some cruft to make unit testing possible. - """ - # primarily so this can be unit tested easily - return time.localtime(*args)[:3] - - def suffix(self, tupledate): - """Return the suffix given a (year, month, day) tuple or unixtime""" - try: - return '_'.join(map(str, tupledate)) - except: - # try taking a float unixtime - return '_'.join(map(str, self.toDate(tupledate))) - - def getLog(self, identifier): - """Given a unix time, return a LogReader for an old log file.""" - if self.toDate(identifier) == self.lastDate: - return self.getCurrentLog() - filename = "%s.%s" % (self.path, self.suffix(identifier)) - if not os.path.exists(filename): - raise ValueError, "no such logfile exists" - return LogReader(filename) - - def write(self, data): - """Write some data to the log file""" - BaseLogFile.write(self, data) - # Guard against a corner case where time.time() - # could potentially run backwards to yesterday. - # Primarily due to network time. - self.lastDate = max(self.lastDate, self.toDate()) - - def rotate(self): - """Rotate the file and create a new one. - - If it's not possible to open new logfile, this will fail silently, - and continue logging to old logfile. - """ - if not (os.access(self.directory, os.W_OK) and os.access(self.path, os.W_OK)): - return - newpath = "%s.%s" % (self.path, self.suffix(self.lastDate)) - if os.path.exists(newpath): - return - self._file.close() - os.rename(self.path, newpath) - self._openFile() - - def __getstate__(self): - state = BaseLogFile.__getstate__(self) - del state["lastDate"] - return state - -threadable.synchronize(DailyLogFile) - - -class LogReader: - """Read from a log file.""" - - def __init__(self, name): - self._file = file(name, "r") - - def readLines(self, lines=10): - """Read a list of lines from the log file. - - This doesn't returns all of the files lines - call it multiple times. - """ - result = [] - for i in range(lines): - line = self._file.readline() - if not line: - break - result.append(line) - return result - - def close(self): - self._file.close() diff --git a/tools/buildbot/pylibs/twisted/python/modules.py b/tools/buildbot/pylibs/twisted/python/modules.py deleted file mode 100644 index 0d6555d..0000000 --- a/tools/buildbot/pylibs/twisted/python/modules.py +++ /dev/null @@ -1,759 +0,0 @@ -# -*- test-case-name: twisted.test.test_modules -*- -# Copyright (c) 2006-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -This module aims to provide a unified, object-oriented view of Python's -runtime hierarchy. - -Python is a very dynamic language with wide variety of introspection utilities. -However, these utilities can be hard to use, because there is no consistent -API. The introspection API in python is made up of attributes (__name__, -__module__, func_name, etc) on instances, modules, classes and functions which -vary between those four types, utility modules such as 'inspect' which provide -some functionality, the 'imp' module, the "compiler" module, the semantics of -PEP 302 support, and setuptools, among other things. - -At the top, you have "PythonPath", an abstract representation of sys.path which -includes methods to locate top-level modules, with or without loading them. -The top-level exposed functions in this module for accessing the system path -are "walkModules", "iterModules", and "getModule". - -From most to least specific, here are the objects provided:: - - PythonPath # sys.path - | - v - PathEntry # one entry on sys.path: an importer - | - v - PythonModule # a module or package that can be loaded - | - v - PythonAttribute # an attribute of a module (function or class) - | - v - PythonAttribute # an attribute of a function or class - | - v - ... - -Here's an example of idiomatic usage: this is what you would do to list all of -the modules outside the standard library's python-files directory:: - - import os - stdlibdir = os.path.dirname(os.__file__) - - from twisted.python.modules import iterModules - - for modinfo in iterModules(): - if (modinfo.pathEntry.filePath.path != stdlibdir - and not modinfo.isPackage()): - print 'unpackaged: %s: %s' % ( - modinfo.name, modinfo.filePath.path) -""" - -__metaclass__ = type - -# let's try to keep path imports to a minimum... -from os.path import dirname, split as splitpath - -import sys -import zipimport -import inspect -from zope.interface import Interface, implements - -from twisted.python.components import registerAdapter -from twisted.python.filepath import FilePath, UnlistableError -from twisted.python.zippath import ZipArchive -from twisted.python.reflect import namedAny - -_nothing = object() - -PYTHON_EXTENSIONS = ['.py'] -OPTIMIZED_MODE = __doc__ is None -if OPTIMIZED_MODE: - PYTHON_EXTENSIONS.append('.pyo') -else: - PYTHON_EXTENSIONS.append('.pyc') - -def _isPythonIdentifier(string): - """ - cheezy fake test for proper identifier-ness. - - @param string: a str which might or might not be a valid python identifier. - - @return: True or False - """ - return (' ' not in string and - '.' not in string and - '-' not in string) - - - -def _isPackagePath(fpath): - # Determine if a FilePath-like object is a Python package. TODO: deal with - # __init__module.(so|dll|pyd)? - extless = fpath.splitext()[0] - basend = splitpath(extless)[1] - return basend == "__init__" - - - -class _ModuleIteratorHelper: - """ - This mixin provides common behavior between python module and path entries, - since the mechanism for searching sys.path and __path__ attributes is - remarkably similar. - """ - - def iterModules(self): - """ - Loop over the modules present below this entry or package on PYTHONPATH. - - For modules which are not packages, this will yield nothing. - - For packages and path entries, this will only yield modules one level - down; i.e. if there is a package a.b.c, iterModules on a will only - return a.b. If you want to descend deeply, use walkModules. - - @return: a generator which yields PythonModule instances that describe - modules which can be, or have been, imported. - """ - yielded = {} - if not self.filePath.exists(): - return - - for placeToLook in self._packagePaths(): - try: - children = placeToLook.children() - except UnlistableError: - continue - - children.sort() - for potentialTopLevel in children: - ext = potentialTopLevel.splitext()[1] - potentialBasename = potentialTopLevel.basename()[:-len(ext)] - if ext in PYTHON_EXTENSIONS: - # TODO: this should be a little choosier about which path entry - # it selects first, and it should do all the .so checking and - # crud - if not _isPythonIdentifier(potentialBasename): - continue - modname = self._subModuleName(potentialBasename) - if modname.split(".")[-1] == '__init__': - # This marks the directory as a package so it can't be - # a module. - continue - if modname not in yielded: - yielded[modname] = True - pm = PythonModule(modname, potentialTopLevel, self._getEntry()) - assert pm != self - yield pm - else: - if (ext or not _isPythonIdentifier(potentialBasename) - or not potentialTopLevel.isdir()): - continue - modname = self._subModuleName(potentialTopLevel.basename()) - for ext in PYTHON_EXTENSIONS: - initpy = potentialTopLevel.child("__init__"+ext) - if initpy.exists(): - yielded[modname] = True - pm = PythonModule(modname, initpy, self._getEntry()) - assert pm != self - yield pm - break - - def walkModules(self, importPackages=False): - """ - Similar to L{iterModules}, this yields self, and then every module in my - package or entry, and every submodule in each package or entry. - - In other words, this is deep, and L{iterModules} is shallow. - """ - yield self - for package in self.iterModules(): - for module in package.walkModules(importPackages=importPackages): - yield module - - def _subModuleName(self, mn): - """ - This is a hook to provide packages with the ability to specify their names - as a prefix to submodules here. - """ - return mn - - def _packagePaths(self): - """ - Implement in subclasses to specify where to look for modules. - - @return: iterable of FilePath-like objects. - """ - raise NotImplementedError() - - def _getEntry(self): - """ - Implement in subclasses to specify what path entry submodules will come - from. - - @return: a PathEntry instance. - """ - raise NotImplementedError() - - - def __getitem__(self, modname): - """ - Retrieve a module from below this path or package. - - @param modname: a str naming a module to be loaded. For entries, this - is a top-level, undotted package name, and for packages it is the name - of the module without the package prefix. For example, if you have a - PythonModule representing the 'twisted' package, you could use: - - twistedPackageObj['python']['modules'] - - to retrieve this module. - - @raise: KeyError if the module is not found. - - @return: a PythonModule. - """ - for module in self.iterModules(): - if module.name == self._subModuleName(modname): - return module - raise KeyError(modname) - - def __iter__(self): - """ - Implemented to raise NotImplementedError for clarity, so that attempting to - loop over this object won't call __getitem__. - - Note: in the future there might be some sensible default for iteration, - like 'walkEverything', so this is deliberately untested and undefined - behavior. - """ - raise NotImplementedError() - -class PythonAttribute: - """ - I represent a function, class, or other object that is present. - - @ivar name: the fully-qualified python name of this attribute. - - @ivar onObject: a reference to a PythonModule or other PythonAttribute that - is this attribute's logical parent. - - @ivar name: the fully qualified python name of the attribute represented by - this class. - """ - def __init__(self, name, onObject, loaded, pythonValue): - """ - Create a PythonAttribute. This is a private constructor. Do not construct - me directly, use PythonModule.iterAttributes. - - @param name: the FQPN - @param onObject: see ivar - @param loaded: always True, for now - @param pythonValue: the value of the attribute we're pointing to. - """ - self.name = name - self.onObject = onObject - self._loaded = loaded - self.pythonValue = pythonValue - - def __repr__(self): - return 'PythonAttribute<%r>'%(self.name,) - - def isLoaded(self): - """ - Return a boolean describing whether the attribute this describes has - actually been loaded into memory by importing its module. - - Note: this currently always returns true; there is no Python parser - support in this module yet. - """ - return self._loaded - - def load(self, default=_nothing): - """ - Load the value associated with this attribute. - - @return: an arbitrary Python object, or 'default' if there is an error - loading it. - """ - return self.pythonValue - - def iterAttributes(self): - for name, val in inspect.getmembers(self.load()): - yield PythonAttribute(self.name+'.'+name, self, True, val) - -class PythonModule(_ModuleIteratorHelper): - """ - Representation of a module which could be imported from sys.path. - - @ivar name: the fully qualified python name of this module. - - @ivar filePath: a FilePath-like object which points to the location of this - module. - - @ivar pathEntry: a L{PathEntry} instance which this module was located - from. - """ - - def __init__(self, name, filePath, pathEntry): - """ - Create a PythonModule. Do not construct this directly, instead inspect a - PythonPath or other PythonModule instances. - - @param name: see ivar - @param filePath: see ivar - @param pathEntry: see ivar - """ - assert not name.endswith(".__init__") - self.name = name - self.filePath = filePath - self.parentPath = filePath.parent() - self.pathEntry = pathEntry - - def _getEntry(self): - return self.pathEntry - - def __repr__(self): - """ - Return a string representation including the module name. - """ - return 'PythonModule<%r>' % (self.name,) - - def isLoaded(self): - """ - Determine if the module is loaded into sys.modules. - - @return: a boolean: true if loaded, false if not. - """ - return self.name in self.pathEntry.pythonPath.moduleDict - - def iterAttributes(self): - """ - List all the attributes defined in this module. - - Note: Future work is planned here to make it possible to list python - attributes on a module without loading the module by inspecting ASTs or - bytecode, but currently any iteration of PythonModule objects insists - they must be loaded, and will use inspect.getmodule. - - @raise NotImplementedError: if this module is not loaded. - - @return: a generator yielding PythonAttribute instances describing the - attributes of this module. - """ - if not self.isLoaded(): - raise NotImplementedError( - "You can't load attributes from non-loaded modules yet.") - for name, val in inspect.getmembers(self.load()): - yield PythonAttribute(self.name+'.'+name, self, True, val) - - def isPackage(self): - """ - Returns true if this module is also a package, and might yield something - from iterModules. - """ - return _isPackagePath(self.filePath) - - def load(self, default=_nothing): - """ - Load this module. - - @param default: if specified, the value to return in case of an error. - - @return: a genuine python module. - - @raise: any type of exception. Importing modules is a risky business; - the erorrs of any code run at module scope may be raised from here, as - well as ImportError if something bizarre happened to the system path - between the discovery of this PythonModule object and the attempt to - import it. If you specify a default, the error will be swallowed - entirely, and not logged. - - @rtype: types.ModuleType. - """ - try: - return self.pathEntry.pythonPath.moduleLoader(self.name) - except: # this needs more thought... - if default is not _nothing: - return default - raise - - def __eq__(self, other): - """ - PythonModules with the same name are equal. - """ - if not isinstance(other, PythonModule): - return False - return other.name == self.name - - def __ne__(self, other): - """ - PythonModules with different names are not equal. - """ - if not isinstance(other, PythonModule): - return True - return other.name != self.name - - def walkModules(self, importPackages=False): - if importPackages and self.isPackage(): - self.load() - return super(PythonModule, self).walkModules(importPackages=importPackages) - - def _subModuleName(self, mn): - """ - submodules of this module are prefixed with our name. - """ - return self.name + '.' + mn - - def _packagePaths(self): - """ - Yield a sequence of FilePath-like objects which represent path segments. - """ - if not self.isPackage(): - return - if self.isLoaded(): - load = self.load() - if hasattr(load, '__path__'): - for fn in load.__path__: - if fn == self.parentPath.path: - # this should _really_ exist. - assert self.parentPath.exists() - yield self.parentPath - else: - smp = self.pathEntry.pythonPath._smartPath(fn) - if smp.exists(): - yield smp - else: - yield self.parentPath - - -class PathEntry(_ModuleIteratorHelper): - """ - I am a proxy for a single entry on sys.path. - - @ivar filePath: a FilePath-like object pointing at the filesystem location - or archive file where this path entry is stored. - - @ivar pythonPath: a PythonPath instance. - """ - def __init__(self, filePath, pythonPath): - """ - Create a PathEntry. This is a private constructor. - """ - self.filePath = filePath - self.pythonPath = pythonPath - - def _getEntry(self): - return self - - def __repr__(self): - return 'PathEntry<%r>' % (self.filePath,) - - def _packagePaths(self): - yield self.filePath - -class IPathImportMapper(Interface): - """ - This is an internal interface, used to map importers to factories for - FilePath-like objects. - """ - def mapPath(self, pathLikeString): - """ - Return a FilePath-like object. - - @param pathLikeString: a path-like string, like one that might be - passed to an import hook. - - @return: a L{FilePath}, or something like it (currently only a - L{ZipPath}, but more might be added later). - """ - -class _DefaultMapImpl: - """ Wrapper for the default importer, i.e. None. """ - implements(IPathImportMapper) - def mapPath(self, fsPathString): - return FilePath(fsPathString) -_theDefaultMapper = _DefaultMapImpl() - -class _ZipMapImpl: - """ IPathImportMapper implementation for zipimport.ZipImporter. """ - implements(IPathImportMapper) - def __init__(self, importer): - self.importer = importer - - def mapPath(self, fsPathString): - """ - Map the given FS path to a ZipPath, by looking at the ZipImporter's - "archive" attribute and using it as our ZipArchive root, then walking - down into the archive from there. - - @return: a L{zippath.ZipPath} or L{zippath.ZipArchive} instance. - """ - za = ZipArchive(self.importer.archive) - myPath = FilePath(self.importer.archive) - itsPath = FilePath(fsPathString) - if myPath == itsPath: - return za - # This is NOT a general-purpose rule for sys.path or __file__: - # zipimport specifically uses regular OS path syntax in its pathnames, - # even though zip files specify that slashes are always the separator, - # regardless of platform. - segs = itsPath.segmentsFrom(myPath) - zp = za - for seg in segs: - zp = zp.child(seg) - return zp - -registerAdapter(_ZipMapImpl, zipimport.zipimporter, IPathImportMapper) - -def _defaultSysPathFactory(): - """ - Provide the default behavior of PythonPath's sys.path factory, which is to - return the current value of sys.path. - - @return: L{sys.path} - """ - return sys.path - - -class PythonPath: - """ - I represent the very top of the Python object-space, the module list in - sys.path and the modules list in sys.modules. - - @ivar sysPath: a sequence of strings like sys.path. This attribute is - read-only. - - @ivar moduleDict: a dictionary mapping string module names to module - objects, like sys.modules. - - @ivar sysPathHooks: a list of PEP-302 path hooks, like sys.path_hooks. - - @ivar moduleLoader: a function that takes a fully-qualified python name and - returns a module, like twisted.python.reflect.namedAny. - """ - - def __init__(self, - sysPath=None, - moduleDict=sys.modules, - sysPathHooks=sys.path_hooks, - importerCache=sys.path_importer_cache, - moduleLoader=namedAny, - sysPathFactory=None): - """ - Create a PythonPath. You almost certainly want to use - modules.theSystemPath, or its aliased methods, rather than creating a - new instance yourself, though. - - All parameters are optional, and if unspecified, will use 'system' - equivalents that makes this PythonPath like the global L{theSystemPath} - instance. - - @param sysPath: a sys.path-like list to use for this PythonPath, to - specify where to load modules from. - - @param moduleDict: a sys.modules-like dictionary to use for keeping - track of what modules this PythonPath has loaded. - - @param sysPathHooks: sys.path_hooks-like list of PEP-302 path hooks to - be used for this PythonPath, to determie which importers should be - used. - - @param importerCache: a sys.path_importer_cache-like list of PEP-302 - importers. This will be used in conjunction with the given - sysPathHooks. - - @param moduleLoader: a module loader function which takes a string and - returns a module. That is to say, it is like L{namedAny} - *not* like - L{__import__}. - - @param sysPathFactory: a 0-argument callable which returns the current - value of a sys.path-like list of strings. Specify either this, or - sysPath, not both. This alternative interface is provided because the - way the Python import mechanism works, you can re-bind the 'sys.path' - name and that is what is used for current imports, so it must be a - factory rather than a value to deal with modification by rebinding - rather than modification by mutation. Note: it is not recommended to - rebind sys.path. Although this mechanism can deal with that, it is a - subtle point which some tools that it is easy for tools which interact - with sys.path to miss. - """ - if sysPath is not None: - sysPathFactory = lambda : sysPath - elif sysPathFactory is None: - sysPathFactory = _defaultSysPathFactory - self._sysPathFactory = sysPathFactory - self._sysPath = sysPath - self.moduleDict = moduleDict - self.sysPathHooks = sysPathHooks - self.importerCache = importerCache - self._moduleLoader = moduleLoader - - - def _getSysPath(self): - """ - Retrieve the current value of sys.path. - """ - return self._sysPathFactory() - - sysPath = property(_getSysPath) - - def moduleLoader(self, modname): - """ - Replicate python2.4+ sys.modules preservation behavior. - - @param modname: a str module name. - - @return: an imported module. - - @raise: any type of exception that may arise from importing. - """ - freezeModules = self.moduleDict.copy() - try: - return self._moduleLoader(modname) - except: - self.moduleDict.clear() - self.moduleDict.update(freezeModules) - raise - - def _findEntryPathString(self, modobj): - """ - Determine where a given Python module object came from by looking at path - entries. - """ - topPackageObj = modobj - while '.' in topPackageObj.__name__: - topPackageObj = self.moduleDict['.'.join( - topPackageObj.__name__.split('.')[:-1])] - if _isPackagePath(FilePath(topPackageObj.__file__)): - # if package 'foo' is on sys.path at /a/b/foo, package 'foo's - # __file__ will be /a/b/foo/__init__.py, and we are looking for - # /a/b here, the path-entry; so go up two steps. - rval = dirname(dirname(topPackageObj.__file__)) - else: - # the module is completely top-level, not within any packages. The - # path entry it's on is just its dirname. - rval = dirname(topPackageObj.__file__) - # There are probably some awful tricks that an importer could pull - # which would break this, so let's just make sure... it's a loaded - # module after all, which means that its path MUST be in - # path_importer_cache according to PEP 302 -glyph - from pprint import pformat - assert rval in self.importerCache, '%r for %r not in import cache %s' % ( - rval, modobj, pformat(self.importerCache)) - return rval - - def _smartPath(self, pathName): - """ - Given a path entry from sys.path which may refer to an importer, - return the appropriate FilePath-like instance. - - @param pathName: a str describing the path. - - @return: a FilePath-like object. - """ - importr = self.importerCache.get(pathName, _nothing) - if importr is _nothing: - for hook in self.sysPathHooks: - try: - importr = hook(pathName) - except ImportError, ie: - pass - if importr is _nothing: # still - importr = None - return IPathImportMapper(importr, _theDefaultMapper).mapPath(pathName) - - def iterEntries(self): - """ - Iterate the entries on my sysPath. - - @return: a generator yielding PathEntry objects - """ - for pathName in self.sysPath: - fp = self._smartPath(pathName) - yield PathEntry(fp, self) - - def __getitem__(self, modname): - """ - Get a python module by a given fully-qualified name. - - @return: a PythonModule object. - - @raise: KeyError, if the module name is a module name. - """ - # See if the module is already somewhere in Python-land. - if modname in self.moduleDict: - # we need 2 paths; one of the path entry and one for the module. - moduleObject = self.moduleDict[modname] - pe = PathEntry( - self._smartPath( - self._findEntryPathString(moduleObject)), - self) - mp = self._smartPath(moduleObject.__file__) - return PythonModule(modname, mp, pe) - - # Recurse if we're trying to get a submodule. - if '.' in modname: - pkg = self - for name in modname.split('.'): - pkg = pkg[name] - return pkg - - # Finally do the slowest possible thing and iterate - for module in self.iterModules(): - if module.name == modname: - return module - raise KeyError(modname) - - def __repr__(self): - """ - Display my sysPath and moduleDict in a string representation. - """ - return "PythonPath(%r,%r)" % (self.sysPath, self.moduleDict) - - def iterModules(self): - """ - Yield all top-level modules on my sysPath. - """ - for entry in self.iterEntries(): - for module in entry.iterModules(): - yield module - - def walkModules(self, importPackages=False): - """ - Similar to L{iterModules}, this yields every module on the path, then every - submodule in each package or entry. - """ - for package in self.iterModules(): - for module in package.walkModules(importPackages=False): - yield module - -theSystemPath = PythonPath() - -def walkModules(importPackages=False): - """ - Deeply iterate all modules on the global python path. - - @param importPackages: Import packages as they are seen. - """ - return theSystemPath.walkModules(importPackages=importPackages) - -def iterModules(): - """ - Iterate all modules and top-level packages on the global Python path, but - do not descend into packages. - - @param importPackages: Import packages as they are seen. - """ - return theSystemPath.iterModules() - -def getModule(moduleName): - """ - Retrieve a module from the system path. - """ - return theSystemPath[moduleName] diff --git a/tools/buildbot/pylibs/twisted/python/monkey.py b/tools/buildbot/pylibs/twisted/python/monkey.py deleted file mode 100644 index 4c1a507..0000000 --- a/tools/buildbot/pylibs/twisted/python/monkey.py +++ /dev/null @@ -1,73 +0,0 @@ -# -*- test-case-name: twisted.test.test_monkey -*- - -# Copyright (c) 2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -class MonkeyPatcher(object): - """ - Cover up attributes with new objects. Neat for monkey-patching things for - unit-testing purposes. - """ - - def __init__(self, *patches): - # List of patches to apply in (obj, name, value). - self._patchesToApply = [] - # List of the original values for things that have been patched. - # (obj, name, value) format. - self._originals = [] - for patch in patches: - self.addPatch(*patch) - - - def addPatch(self, obj, name, value): - """ - Add a patch so that the attribute C{name} on C{obj} will be assigned to - C{value} when C{patch} is called or during C{runWithPatches}. - - You can restore the original values with a call to restore(). - """ - self._patchesToApply.append((obj, name, value)) - - - def _alreadyPatched(self, obj, name): - """ - Has the C{name} attribute of C{obj} already been patched by this - patcher? - """ - for o, n, v in self._originals: - if (o, n) == (obj, name): - return True - return False - - - def patch(self): - """ - Apply all of the patches that have been specified with L{addPatch}. - Reverse this operation using L{restore}. - """ - for obj, name, value in self._patchesToApply: - if not self._alreadyPatched(obj, name): - self._originals.append((obj, name, getattr(obj, name))) - setattr(obj, name, value) - - - def restore(self): - """ - Restore all original values to any patched objects. - """ - while self._originals: - obj, name, value = self._originals.pop() - setattr(obj, name, value) - - - def runWithPatches(self, f, *args, **kw): - """ - Apply each patch already specified. Then run the function f with the - given args and kwargs. Restore everything when done. - """ - self.patch() - try: - return f(*args, **kw) - finally: - self.restore() diff --git a/tools/buildbot/pylibs/twisted/python/otp.py b/tools/buildbot/pylibs/twisted/python/otp.py deleted file mode 100644 index 87ce5ad..0000000 --- a/tools/buildbot/pylibs/twisted/python/otp.py +++ /dev/null @@ -1,481 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" A One-Time Password System based on RFC 2289 - -The class Authenticator contains the hashing-logic, and the parser for the -readable output. It also contains challenge which returns a string describing -the authentication scheme for a client. - -OTP is a password container for an user on a server. - -NOTE: Does not take care of transmitting the shared secret password. - -At the end there's a dict called dict which is dictionary contain 2048 -words for storing pronouncable 11-bit values. Taken from RFC 1760. - -Uses the MD5- and SHA-algorithms for hashing - -Todo: RFC2444, SASL (perhaps), parsing hex-responses -""" - -import string -import random - -def stringToLong(s): - """ Convert digest to long """ - result = 0L - for byte in s: - result = (256 * result) + ord(byte) - return result - -def stringToDWords(s): - """ Convert digest to a list of four 32-bits words """ - result = [] - for a in xrange(len(s) / 4): - tmp = 0L - for byte in s[-4:]: - tmp = (256 * tmp) + ord(byte) - result.append(tmp) - s = s[:-4] - return result - -def longToString(l): - """ Convert long to digest """ - result = "" - while l > 0L: - result = chr(l % 256) + result - l = l / 256L - return result - -import md5, sha -hashid = {md5: 'md5', sha: 'sha1'} - -INITIALSEQUENCE = 1000 -MINIMUMSEQUENCE = 50 - -class Unauthorized(Exception): - """the Unauthorized exception - - This exception is raised when an action is not allowed, or a user is not - authenticated properly. - """ - -class OTPAuthenticator: - """A One Time Password System - - Based on RFC 2289, which is based on a the S/KEY Authentication-scheme. - It uses the MD5- and SHA-algorithms for hashing - - The variable OTP is at all times a 64bit string""" - - def __init__(self, hash = md5): - "Set the hash to either md5 or sha1" - self.hash = hash - pass - - def generateSeed(self): - "Return a 10 char random seed, with 6 lowercase chars and 4 digits" - seed = '' - for x in range(6): - seed = seed + chr(random.randrange(97,122)) - for x in range(4): - seed = seed + chr(random.randrange(48,57)) - return seed - - def foldDigest(self, otp): - if self.hash == md5: - return self.foldDigest128(otp) - if self.hash == sha: - return self.foldDigest160(otp) - - def foldDigest128(self, otp128): - "Fold a 128 bit digest to 64 bit" - regs = stringToDWords(otp128) - p0 = regs[0] ^ regs[2] - p1 = regs[1] ^ regs[3] - S = '' - for a in xrange(4): - S = chr(p0 & 0xFF) + S - p0 = p0 >> 8 - for a in xrange(4): - S = chr(p1 & 0xFF) + S - p1 = p1 >> 8 - return S - - def foldDigest160(self, otp160): - "Fold a 160 bit digest to 64 bit" - regs = stringToDWords(otp160) - p0 = regs[0] ^ regs[2] - p1 = regs[1] ^ regs[3] - p0 = regs[0] ^ regs[4] - S = '' - for a in xrange(4): - S = chr(p0 & 0xFF) + S - p0 = p0 >> 8 - for a in xrange(4): - S = chr(p1 & 0xFF) + S - p1 = p1 >> 8 - return S - - def hashUpdate(self, digest): - "Run through the hash and fold to 64 bit" - h = self.hash.new(digest) - return self.foldDigest(h.digest()) - - def generateOTP(self, seed, passwd, sequence): - """Return a 64 bit OTP based on inputs - Run through makeReadable to get a 6 word pass-phrase""" - seed = string.lower(seed) - otp = self.hashUpdate(seed + passwd) - for a in xrange(sequence): - otp = self.hashUpdate(otp) - return otp - - def calculateParity(self, otp): - "Calculate the parity from a 64bit OTP" - parity = 0 - for i in xrange(0, 64, 2): - parity = parity + otp & 0x3 - otp = otp >> 2 - return parity - - def makeReadable(self, otp): - "Returns a 6 word pass-phrase from a 64bit OTP" - digest = stringToLong(otp) - list = [] - parity = self.calculateParity(digest) - for i in xrange(4,-1, -1): - list.append(dict[(digest >> (i * 11 + 9)) & 0x7FF]) - list.append(dict[(digest << 2) & 0x7FC | (parity & 0x03)]) - return string.join(list) - - def challenge(self, seed, sequence): - """Return a challenge in the format otp- """ - return "otp-%s %i %s" % (hashid[self.hash], sequence, seed) - - def parsePhrase(self, phrase): - """Decode the phrase, and return a 64bit OTP - I will raise Unauthorized if the parity is wrong - TODO: Add support for hex (MUST) and the '2nd scheme'(SHOULD)""" - words = string.split(phrase) - for i in xrange(len(words)): - words[i] = string.upper(words[i]) - b = 0L - for i in xrange(0,5): - b = b | ((long(dict.index(words[i])) << ((4-i)*11L+9L))) - tmp = dict.index(words[5]) - b = b | (tmp & 0x7FC ) >> 2 - if (tmp & 3) <> self.calculateParity(b): - raise Unauthorized("Parity error") - digest = longToString(b) - return digest - -class OTP(OTPAuthenticator): - """An automatic version of the OTP-Authenticator - - Updates the sequence and the keeps last approved password on success - On the next authentication, the stored password is hashed and checked - up against the one given by the user. If they match, the sequencecounter - is decreased and the circle is closed. - - This object should be glued to each user - - Note: - It does NOT reset the sequence when the combinations left approach zero, - This has to be done manuelly by instancing a new object - """ - seed = None - sequence = 0 - lastotp = None - - def __init__(self, passwd, sequence = INITIALSEQUENCE, hash=md5): - """Initialize the OTP-Sequence, and discard the password""" - OTPAuthenticator.__init__(self, hash) - seed = self.generateSeed() - # Generate the 'last' password - self.lastotp = OTPAuthenticator.generateOTP(self, seed, passwd, sequence+1) - self.seed = seed - self.sequence = sequence - - def challenge(self): - """Return a challenge string""" - result = OTPAuthenticator.challenge(self, self.seed, self.sequence) - return result - - def authenticate(self, phrase): - """Test the phrase against the last challenge issued""" - try: - digest = self.parsePhrase(phrase) - hasheddigest = self.hashUpdate(digest) - if (self.lastotp == hasheddigest): - self.lastotp = digest - if self.sequence > MINIMUMSEQUENCE: - self.sequence = self.sequence - 1 - return "ok" - else: - raise Unauthorized("Failed") - except Unauthorized, msg: - raise Unauthorized(msg) - -# -# The 2048 word standard dictionary from RFC 1760 -# -dict = ["A", "ABE", "ACE", "ACT", "AD", "ADA", "ADD", -"AGO", "AID", "AIM", "AIR", "ALL", "ALP", "AM", "AMY", -"AN", "ANA", "AND", "ANN", "ANT", "ANY", "APE", "APS", -"APT", "ARC", "ARE", "ARK", "ARM", "ART", "AS", "ASH", -"ASK", "AT", "ATE", "AUG", "AUK", "AVE", "AWE", "AWK", -"AWL", "AWN", "AX", "AYE", "BAD", "BAG", "BAH", "BAM", -"BAN", "BAR", "BAT", "BAY", "BE", "BED", "BEE", "BEG", -"BEN", "BET", "BEY", "BIB", "BID", "BIG", "BIN", "BIT", -"BOB", "BOG", "BON", "BOO", "BOP", "BOW", "BOY", "BUB", -"BUD", "BUG", "BUM", "BUN", "BUS", "BUT", "BUY", "BY", -"BYE", "CAB", "CAL", "CAM", "CAN", "CAP", "CAR", "CAT", -"CAW", "COD", "COG", "COL", "CON", "COO", "COP", "COT", -"COW", "COY", "CRY", "CUB", "CUE", "CUP", "CUR", "CUT", -"DAB", "DAD", "DAM", "DAN", "DAR", "DAY", "DEE", "DEL", -"DEN", "DES", "DEW", "DID", "DIE", "DIG", "DIN", "DIP", -"DO", "DOE", "DOG", "DON", "DOT", "DOW", "DRY", "DUB", -"DUD", "DUE", "DUG", "DUN", "EAR", "EAT", "ED", "EEL", -"EGG", "EGO", "ELI", "ELK", "ELM", "ELY", "EM", "END", -"EST", "ETC", "EVA", "EVE", "EWE", "EYE", "FAD", "FAN", -"FAR", "FAT", "FAY", "FED", "FEE", "FEW", "FIB", "FIG", -"FIN", "FIR", "FIT", "FLO", "FLY", "FOE", "FOG", "FOR", -"FRY", "FUM", "FUN", "FUR", "GAB", "GAD", "GAG", "GAL", -"GAM", "GAP", "GAS", "GAY", "GEE", "GEL", "GEM", "GET", -"GIG", "GIL", "GIN", "GO", "GOT", "GUM", "GUN", "GUS", -"GUT", "GUY", "GYM", "GYP", "HA", "HAD", "HAL", "HAM", -"HAN", "HAP", "HAS", "HAT", "HAW", "HAY", "HE", "HEM", -"HEN", "HER", "HEW", "HEY", "HI", "HID", "HIM", "HIP", -"HIS", "HIT", "HO", "HOB", "HOC", "HOE", "HOG", "HOP", -"HOT", "HOW", "HUB", "HUE", "HUG", "HUH", "HUM", "HUT", -"I", "ICY", "IDA", "IF", "IKE", "ILL", "INK", "INN", -"IO", "ION", "IQ", "IRA", "IRE", "IRK", "IS", "IT", -"ITS", "IVY", "JAB", "JAG", "JAM", "JAN", "JAR", "JAW", -"JAY", "JET", "JIG", "JIM", "JO", "JOB", "JOE", "JOG", -"JOT", "JOY", "JUG", "JUT", "KAY", "KEG", "KEN", "KEY", -"KID", "KIM", "KIN", "KIT", "LA", "LAB", "LAC", "LAD", -"LAG", "LAM", "LAP", "LAW", "LAY", "LEA", "LED", "LEE", -"LEG", "LEN", "LEO", "LET", "LEW", "LID", "LIE", "LIN", -"LIP", "LIT", "LO", "LOB", "LOG", "LOP", "LOS", "LOT", -"LOU", "LOW", "LOY", "LUG", "LYE", "MA", "MAC", "MAD", -"MAE", "MAN", "MAO", "MAP", "MAT", "MAW", "MAY", "ME", -"MEG", "MEL", "MEN", "MET", "MEW", "MID", "MIN", "MIT", -"MOB", "MOD", "MOE", "MOO", "MOP", "MOS", "MOT", "MOW", -"MUD", "MUG", "MUM", "MY", "NAB", "NAG", "NAN", "NAP", -"NAT", "NAY", "NE", "NED", "NEE", "NET", "NEW", "NIB", -"NIL", "NIP", "NIT", "NO", "NOB", "NOD", "NON", "NOR", -"NOT", "NOV", "NOW", "NU", "NUN", "NUT", "O", "OAF", -"OAK", "OAR", "OAT", "ODD", "ODE", "OF", "OFF", "OFT", -"OH", "OIL", "OK", "OLD", "ON", "ONE", "OR", "ORB", -"ORE", "ORR", "OS", "OTT", "OUR", "OUT", "OVA", "OW", -"OWE", "OWL", "OWN", "OX", "PA", "PAD", "PAL", "PAM", -"PAN", "PAP", "PAR", "PAT", "PAW", "PAY", "PEA", "PEG", -"PEN", "PEP", "PER", "PET", "PEW", "PHI", "PI", "PIE", -"PIN", "PIT", "PLY", "PO", "POD", "POE", "POP", "POT", -"POW", "PRO", "PRY", "PUB", "PUG", "PUN", "PUP", "PUT", -"QUO", "RAG", "RAM", "RAN", "RAP", "RAT", "RAW", "RAY", -"REB", "RED", "REP", "RET", "RIB", "RID", "RIG", "RIM", -"RIO", "RIP", "ROB", "ROD", "ROE", "RON", "ROT", "ROW", -"ROY", "RUB", "RUE", "RUG", "RUM", "RUN", "RYE", "SAC", -"SAD", "SAG", "SAL", "SAM", "SAN", "SAP", "SAT", "SAW", -"SAY", "SEA", "SEC", "SEE", "SEN", "SET", "SEW", "SHE", -"SHY", "SIN", "SIP", "SIR", "SIS", "SIT", "SKI", "SKY", -"SLY", "SO", "SOB", "SOD", "SON", "SOP", "SOW", "SOY", -"SPA", "SPY", "SUB", "SUD", "SUE", "SUM", "SUN", "SUP", -"TAB", "TAD", "TAG", "TAN", "TAP", "TAR", "TEA", "TED", -"TEE", "TEN", "THE", "THY", "TIC", "TIE", "TIM", "TIN", -"TIP", "TO", "TOE", "TOG", "TOM", "TON", "TOO", "TOP", -"TOW", "TOY", "TRY", "TUB", "TUG", "TUM", "TUN", "TWO", -"UN", "UP", "US", "USE", "VAN", "VAT", "VET", "VIE", -"WAD", "WAG", "WAR", "WAS", "WAY", "WE", "WEB", "WED", -"WEE", "WET", "WHO", "WHY", "WIN", "WIT", "WOK", "WON", -"WOO", "WOW", "WRY", "WU", "YAM", "YAP", "YAW", "YE", -"YEA", "YES", "YET", "YOU", "ABED", "ABEL", "ABET", "ABLE", -"ABUT", "ACHE", "ACID", "ACME", "ACRE", "ACTA", "ACTS", "ADAM", -"ADDS", "ADEN", "AFAR", "AFRO", "AGEE", "AHEM", "AHOY", "AIDA", -"AIDE", "AIDS", "AIRY", "AJAR", "AKIN", "ALAN", "ALEC", "ALGA", -"ALIA", "ALLY", "ALMA", "ALOE", "ALSO", "ALTO", "ALUM", "ALVA", -"AMEN", "AMES", "AMID", "AMMO", "AMOK", "AMOS", "AMRA", "ANDY", -"ANEW", "ANNA", "ANNE", "ANTE", "ANTI", "AQUA", "ARAB", "ARCH", -"AREA", "ARGO", "ARID", "ARMY", "ARTS", "ARTY", "ASIA", "ASKS", -"ATOM", "AUNT", "AURA", "AUTO", "AVER", "AVID", "AVIS", "AVON", -"AVOW", "AWAY", "AWRY", "BABE", "BABY", "BACH", "BACK", "BADE", -"BAIL", "BAIT", "BAKE", "BALD", "BALE", "BALI", "BALK", "BALL", -"BALM", "BAND", "BANE", "BANG", "BANK", "BARB", "BARD", "BARE", -"BARK", "BARN", "BARR", "BASE", "BASH", "BASK", "BASS", "BATE", -"BATH", "BAWD", "BAWL", "BEAD", "BEAK", "BEAM", "BEAN", "BEAR", -"BEAT", "BEAU", "BECK", "BEEF", "BEEN", "BEER", "BEET", "BELA", -"BELL", "BELT", "BEND", "BENT", "BERG", "BERN", "BERT", "BESS", -"BEST", "BETA", "BETH", "BHOY", "BIAS", "BIDE", "BIEN", "BILE", -"BILK", "BILL", "BIND", "BING", "BIRD", "BITE", "BITS", "BLAB", -"BLAT", "BLED", "BLEW", "BLOB", "BLOC", "BLOT", "BLOW", "BLUE", -"BLUM", "BLUR", "BOAR", "BOAT", "BOCA", "BOCK", "BODE", "BODY", -"BOGY", "BOHR", "BOIL", "BOLD", "BOLO", "BOLT", "BOMB", "BONA", -"BOND", "BONE", "BONG", "BONN", "BONY", "BOOK", "BOOM", "BOON", -"BOOT", "BORE", "BORG", "BORN", "BOSE", "BOSS", "BOTH", "BOUT", -"BOWL", "BOYD", "BRAD", "BRAE", "BRAG", "BRAN", "BRAY", "BRED", -"BREW", "BRIG", "BRIM", "BROW", "BUCK", "BUDD", "BUFF", "BULB", -"BULK", "BULL", "BUNK", "BUNT", "BUOY", "BURG", "BURL", "BURN", -"BURR", "BURT", "BURY", "BUSH", "BUSS", "BUST", "BUSY", "BYTE", -"CADY", "CAFE", "CAGE", "CAIN", "CAKE", "CALF", "CALL", "CALM", -"CAME", "CANE", "CANT", "CARD", "CARE", "CARL", "CARR", "CART", -"CASE", "CASH", "CASK", "CAST", "CAVE", "CEIL", "CELL", "CENT", -"CERN", "CHAD", "CHAR", "CHAT", "CHAW", "CHEF", "CHEN", "CHEW", -"CHIC", "CHIN", "CHOU", "CHOW", "CHUB", "CHUG", "CHUM", "CITE", -"CITY", "CLAD", "CLAM", "CLAN", "CLAW", "CLAY", "CLOD", "CLOG", -"CLOT", "CLUB", "CLUE", "COAL", "COAT", "COCA", "COCK", "COCO", -"CODA", "CODE", "CODY", "COED", "COIL", "COIN", "COKE", "COLA", -"COLD", "COLT", "COMA", "COMB", "COME", "COOK", "COOL", "COON", -"COOT", "CORD", "CORE", "CORK", "CORN", "COST", "COVE", "COWL", -"CRAB", "CRAG", "CRAM", "CRAY", "CREW", "CRIB", "CROW", "CRUD", -"CUBA", "CUBE", "CUFF", "CULL", "CULT", "CUNY", "CURB", "CURD", -"CURE", "CURL", "CURT", "CUTS", "DADE", "DALE", "DAME", "DANA", -"DANE", "DANG", "DANK", "DARE", "DARK", "DARN", "DART", "DASH", -"DATA", "DATE", "DAVE", "DAVY", "DAWN", "DAYS", "DEAD", "DEAF", -"DEAL", "DEAN", "DEAR", "DEBT", "DECK", "DEED", "DEEM", "DEER", -"DEFT", "DEFY", "DELL", "DENT", "DENY", "DESK", "DIAL", "DICE", -"DIED", "DIET", "DIME", "DINE", "DING", "DINT", "DIRE", "DIRT", -"DISC", "DISH", "DISK", "DIVE", "DOCK", "DOES", "DOLE", "DOLL", -"DOLT", "DOME", "DONE", "DOOM", "DOOR", "DORA", "DOSE", "DOTE", -"DOUG", "DOUR", "DOVE", "DOWN", "DRAB", "DRAG", "DRAM", "DRAW", -"DREW", "DRUB", "DRUG", "DRUM", "DUAL", "DUCK", "DUCT", "DUEL", -"DUET", "DUKE", "DULL", "DUMB", "DUNE", "DUNK", "DUSK", "DUST", -"DUTY", "EACH", "EARL", "EARN", "EASE", "EAST", "EASY", "EBEN", -"ECHO", "EDDY", "EDEN", "EDGE", "EDGY", "EDIT", "EDNA", "EGAN", -"ELAN", "ELBA", "ELLA", "ELSE", "EMIL", "EMIT", "EMMA", "ENDS", -"ERIC", "EROS", "EVEN", "EVER", "EVIL", "EYED", "FACE", "FACT", -"FADE", "FAIL", "FAIN", "FAIR", "FAKE", "FALL", "FAME", "FANG", -"FARM", "FAST", "FATE", "FAWN", "FEAR", "FEAT", "FEED", "FEEL", -"FEET", "FELL", "FELT", "FEND", "FERN", "FEST", "FEUD", "FIEF", -"FIGS", "FILE", "FILL", "FILM", "FIND", "FINE", "FINK", "FIRE", -"FIRM", "FISH", "FISK", "FIST", "FITS", "FIVE", "FLAG", "FLAK", -"FLAM", "FLAT", "FLAW", "FLEA", "FLED", "FLEW", "FLIT", "FLOC", -"FLOG", "FLOW", "FLUB", "FLUE", "FOAL", "FOAM", "FOGY", "FOIL", -"FOLD", "FOLK", "FOND", "FONT", "FOOD", "FOOL", "FOOT", "FORD", -"FORE", "FORK", "FORM", "FORT", "FOSS", "FOUL", "FOUR", "FOWL", -"FRAU", "FRAY", "FRED", "FREE", "FRET", "FREY", "FROG", "FROM", -"FUEL", "FULL", "FUME", "FUND", "FUNK", "FURY", "FUSE", "FUSS", -"GAFF", "GAGE", "GAIL", "GAIN", "GAIT", "GALA", "GALE", "GALL", -"GALT", "GAME", "GANG", "GARB", "GARY", "GASH", "GATE", "GAUL", -"GAUR", "GAVE", "GAWK", "GEAR", "GELD", "GENE", "GENT", "GERM", -"GETS", "GIBE", "GIFT", "GILD", "GILL", "GILT", "GINA", "GIRD", -"GIRL", "GIST", "GIVE", "GLAD", "GLEE", "GLEN", "GLIB", "GLOB", -"GLOM", "GLOW", "GLUE", "GLUM", "GLUT", "GOAD", "GOAL", "GOAT", -"GOER", "GOES", "GOLD", "GOLF", "GONE", "GONG", "GOOD", "GOOF", -"GORE", "GORY", "GOSH", "GOUT", "GOWN", "GRAB", "GRAD", "GRAY", -"GREG", "GREW", "GREY", "GRID", "GRIM", "GRIN", "GRIT", "GROW", -"GRUB", "GULF", "GULL", "GUNK", "GURU", "GUSH", "GUST", "GWEN", -"GWYN", "HAAG", "HAAS", "HACK", "HAIL", "HAIR", "HALE", "HALF", -"HALL", "HALO", "HALT", "HAND", "HANG", "HANK", "HANS", "HARD", -"HARK", "HARM", "HART", "HASH", "HAST", "HATE", "HATH", "HAUL", -"HAVE", "HAWK", "HAYS", "HEAD", "HEAL", "HEAR", "HEAT", "HEBE", -"HECK", "HEED", "HEEL", "HEFT", "HELD", "HELL", "HELM", "HERB", -"HERD", "HERE", "HERO", "HERS", "HESS", "HEWN", "HICK", "HIDE", -"HIGH", "HIKE", "HILL", "HILT", "HIND", "HINT", "HIRE", "HISS", -"HIVE", "HOBO", "HOCK", "HOFF", "HOLD", "HOLE", "HOLM", "HOLT", -"HOME", "HONE", "HONK", "HOOD", "HOOF", "HOOK", "HOOT", "HORN", -"HOSE", "HOST", "HOUR", "HOVE", "HOWE", "HOWL", "HOYT", "HUCK", -"HUED", "HUFF", "HUGE", "HUGH", "HUGO", "HULK", "HULL", "HUNK", -"HUNT", "HURD", "HURL", "HURT", "HUSH", "HYDE", "HYMN", "IBIS", -"ICON", "IDEA", "IDLE", "IFFY", "INCA", "INCH", "INTO", "IONS", -"IOTA", "IOWA", "IRIS", "IRMA", "IRON", "ISLE", "ITCH", "ITEM", -"IVAN", "JACK", "JADE", "JAIL", "JAKE", "JANE", "JAVA", "JEAN", -"JEFF", "JERK", "JESS", "JEST", "JIBE", "JILL", "JILT", "JIVE", -"JOAN", "JOBS", "JOCK", "JOEL", "JOEY", "JOHN", "JOIN", "JOKE", -"JOLT", "JOVE", "JUDD", "JUDE", "JUDO", "JUDY", "JUJU", "JUKE", -"JULY", "JUNE", "JUNK", "JUNO", "JURY", "JUST", "JUTE", "KAHN", -"KALE", "KANE", "KANT", "KARL", "KATE", "KEEL", "KEEN", "KENO", -"KENT", "KERN", "KERR", "KEYS", "KICK", "KILL", "KIND", "KING", -"KIRK", "KISS", "KITE", "KLAN", "KNEE", "KNEW", "KNIT", "KNOB", -"KNOT", "KNOW", "KOCH", "KONG", "KUDO", "KURD", "KURT", "KYLE", -"LACE", "LACK", "LACY", "LADY", "LAID", "LAIN", "LAIR", "LAKE", -"LAMB", "LAME", "LAND", "LANE", "LANG", "LARD", "LARK", "LASS", -"LAST", "LATE", "LAUD", "LAVA", "LAWN", "LAWS", "LAYS", "LEAD", -"LEAF", "LEAK", "LEAN", "LEAR", "LEEK", "LEER", "LEFT", "LEND", -"LENS", "LENT", "LEON", "LESK", "LESS", "LEST", "LETS", "LIAR", -"LICE", "LICK", "LIED", "LIEN", "LIES", "LIEU", "LIFE", "LIFT", -"LIKE", "LILA", "LILT", "LILY", "LIMA", "LIMB", "LIME", "LIND", -"LINE", "LINK", "LINT", "LION", "LISA", "LIST", "LIVE", "LOAD", -"LOAF", "LOAM", "LOAN", "LOCK", "LOFT", "LOGE", "LOIS", "LOLA", -"LONE", "LONG", "LOOK", "LOON", "LOOT", "LORD", "LORE", "LOSE", -"LOSS", "LOST", "LOUD", "LOVE", "LOWE", "LUCK", "LUCY", "LUGE", -"LUKE", "LULU", "LUND", "LUNG", "LURA", "LURE", "LURK", "LUSH", -"LUST", "LYLE", "LYNN", "LYON", "LYRA", "MACE", "MADE", "MAGI", -"MAID", "MAIL", "MAIN", "MAKE", "MALE", "MALI", "MALL", "MALT", -"MANA", "MANN", "MANY", "MARC", "MARE", "MARK", "MARS", "MART", -"MARY", "MASH", "MASK", "MASS", "MAST", "MATE", "MATH", "MAUL", -"MAYO", "MEAD", "MEAL", "MEAN", "MEAT", "MEEK", "MEET", "MELD", -"MELT", "MEMO", "MEND", "MENU", "MERT", "MESH", "MESS", "MICE", -"MIKE", "MILD", "MILE", "MILK", "MILL", "MILT", "MIMI", "MIND", -"MINE", "MINI", "MINK", "MINT", "MIRE", "MISS", "MIST", "MITE", -"MITT", "MOAN", "MOAT", "MOCK", "MODE", "MOLD", "MOLE", "MOLL", -"MOLT", "MONA", "MONK", "MONT", "MOOD", "MOON", "MOOR", "MOOT", -"MORE", "MORN", "MORT", "MOSS", "MOST", "MOTH", "MOVE", "MUCH", -"MUCK", "MUDD", "MUFF", "MULE", "MULL", "MURK", "MUSH", "MUST", -"MUTE", "MUTT", "MYRA", "MYTH", "NAGY", "NAIL", "NAIR", "NAME", -"NARY", "NASH", "NAVE", "NAVY", "NEAL", "NEAR", "NEAT", "NECK", -"NEED", "NEIL", "NELL", "NEON", "NERO", "NESS", "NEST", "NEWS", -"NEWT", "NIBS", "NICE", "NICK", "NILE", "NINA", "NINE", "NOAH", -"NODE", "NOEL", "NOLL", "NONE", "NOOK", "NOON", "NORM", "NOSE", -"NOTE", "NOUN", "NOVA", "NUDE", "NULL", "NUMB", "OATH", "OBEY", -"OBOE", "ODIN", "OHIO", "OILY", "OINT", "OKAY", "OLAF", "OLDY", -"OLGA", "OLIN", "OMAN", "OMEN", "OMIT", "ONCE", "ONES", "ONLY", -"ONTO", "ONUS", "ORAL", "ORGY", "OSLO", "OTIS", "OTTO", "OUCH", -"OUST", "OUTS", "OVAL", "OVEN", "OVER", "OWLY", "OWNS", "QUAD", -"QUIT", "QUOD", "RACE", "RACK", "RACY", "RAFT", "RAGE", "RAID", -"RAIL", "RAIN", "RAKE", "RANK", "RANT", "RARE", "RASH", "RATE", -"RAVE", "RAYS", "READ", "REAL", "REAM", "REAR", "RECK", "REED", -"REEF", "REEK", "REEL", "REID", "REIN", "RENA", "REND", "RENT", -"REST", "RICE", "RICH", "RICK", "RIDE", "RIFT", "RILL", "RIME", -"RING", "RINK", "RISE", "RISK", "RITE", "ROAD", "ROAM", "ROAR", -"ROBE", "ROCK", "RODE", "ROIL", "ROLL", "ROME", "ROOD", "ROOF", -"ROOK", "ROOM", "ROOT", "ROSA", "ROSE", "ROSS", "ROSY", "ROTH", -"ROUT", "ROVE", "ROWE", "ROWS", "RUBE", "RUBY", "RUDE", "RUDY", -"RUIN", "RULE", "RUNG", "RUNS", "RUNT", "RUSE", "RUSH", "RUSK", -"RUSS", "RUST", "RUTH", "SACK", "SAFE", "SAGE", "SAID", "SAIL", -"SALE", "SALK", "SALT", "SAME", "SAND", "SANE", "SANG", "SANK", -"SARA", "SAUL", "SAVE", "SAYS", "SCAN", "SCAR", "SCAT", "SCOT", -"SEAL", "SEAM", "SEAR", "SEAT", "SEED", "SEEK", "SEEM", "SEEN", -"SEES", "SELF", "SELL", "SEND", "SENT", "SETS", "SEWN", "SHAG", -"SHAM", "SHAW", "SHAY", "SHED", "SHIM", "SHIN", "SHOD", "SHOE", -"SHOT", "SHOW", "SHUN", "SHUT", "SICK", "SIDE", "SIFT", "SIGH", -"SIGN", "SILK", "SILL", "SILO", "SILT", "SINE", "SING", "SINK", -"SIRE", "SITE", "SITS", "SITU", "SKAT", "SKEW", "SKID", "SKIM", -"SKIN", "SKIT", "SLAB", "SLAM", "SLAT", "SLAY", "SLED", "SLEW", -"SLID", "SLIM", "SLIT", "SLOB", "SLOG", "SLOT", "SLOW", "SLUG", -"SLUM", "SLUR", "SMOG", "SMUG", "SNAG", "SNOB", "SNOW", "SNUB", -"SNUG", "SOAK", "SOAR", "SOCK", "SODA", "SOFA", "SOFT", "SOIL", -"SOLD", "SOME", "SONG", "SOON", "SOOT", "SORE", "SORT", "SOUL", -"SOUR", "SOWN", "STAB", "STAG", "STAN", "STAR", "STAY", "STEM", -"STEW", "STIR", "STOW", "STUB", "STUN", "SUCH", "SUDS", "SUIT", -"SULK", "SUMS", "SUNG", "SUNK", "SURE", "SURF", "SWAB", "SWAG", -"SWAM", "SWAN", "SWAT", "SWAY", "SWIM", "SWUM", "TACK", "TACT", -"TAIL", "TAKE", "TALE", "TALK", "TALL", "TANK", "TASK", "TATE", -"TAUT", "TEAL", "TEAM", "TEAR", "TECH", "TEEM", "TEEN", "TEET", -"TELL", "TEND", "TENT", "TERM", "TERN", "TESS", "TEST", "THAN", -"THAT", "THEE", "THEM", "THEN", "THEY", "THIN", "THIS", "THUD", -"THUG", "TICK", "TIDE", "TIDY", "TIED", "TIER", "TILE", "TILL", -"TILT", "TIME", "TINA", "TINE", "TINT", "TINY", "TIRE", "TOAD", -"TOGO", "TOIL", "TOLD", "TOLL", "TONE", "TONG", "TONY", "TOOK", -"TOOL", "TOOT", "TORE", "TORN", "TOTE", "TOUR", "TOUT", "TOWN", -"TRAG", "TRAM", "TRAY", "TREE", "TREK", "TRIG", "TRIM", "TRIO", -"TROD", "TROT", "TROY", "TRUE", "TUBA", "TUBE", "TUCK", "TUFT", -"TUNA", "TUNE", "TUNG", "TURF", "TURN", "TUSK", "TWIG", "TWIN", -"TWIT", "ULAN", "UNIT", "URGE", "USED", "USER", "USES", "UTAH", -"VAIL", "VAIN", "VALE", "VARY", "VASE", "VAST", "VEAL", "VEDA", -"VEIL", "VEIN", "VEND", "VENT", "VERB", "VERY", "VETO", "VICE", -"VIEW", "VINE", "VISE", "VOID", "VOLT", "VOTE", "WACK", "WADE", -"WAGE", "WAIL", "WAIT", "WAKE", "WALE", "WALK", "WALL", "WALT", -"WAND", "WANE", "WANG", "WANT", "WARD", "WARM", "WARN", "WART", -"WASH", "WAST", "WATS", "WATT", "WAVE", "WAVY", "WAYS", "WEAK", -"WEAL", "WEAN", "WEAR", "WEED", "WEEK", "WEIR", "WELD", "WELL", -"WELT", "WENT", "WERE", "WERT", "WEST", "WHAM", "WHAT", "WHEE", -"WHEN", "WHET", "WHOA", "WHOM", "WICK", "WIFE", "WILD", "WILL", -"WIND", "WINE", "WING", "WINK", "WINO", "WIRE", "WISE", "WISH", -"WITH", "WOLF", "WONT", "WOOD", "WOOL", "WORD", "WORE", "WORK", -"WORM", "WORN", "WOVE", "WRIT", "WYNN", "YALE", "YANG", "YANK", -"YARD", "YARN", "YAWL", "YAWN", "YEAH", "YEAR", "YELL", "YOGA", -"YOKE"] - diff --git a/tools/buildbot/pylibs/twisted/python/plugin.py b/tools/buildbot/pylibs/twisted/python/plugin.py deleted file mode 100644 index 971d389..0000000 --- a/tools/buildbot/pylibs/twisted/python/plugin.py +++ /dev/null @@ -1,332 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -from __future__ import nested_scopes - -# System Imports -import sys -import os -import errno -import types -import warnings - -# Twisted imports -from twisted.python import util - -# Sibling Imports -from reflect import namedModule - -try: - from os.path import realpath as cacheTransform -except ImportError: - from os.path import abspath as cacheTransform - -class PlugIn: - """I am a Python module registered in a plugins.tml file. - """ - def __init__(self, name, module, **kw): - self.name = name - self.module = module - for key, value in kw.items(): - setattr(self, key, value) - - def isLoaded(self): - """Check to see if the module for this plugin has been imported yet. - - @rtype: C{int} - @return: A true value if the module for this plugin has been loaded, - false otherwise. - """ - return sys.modules.has_key(self.module) - - def load(self): - """Load the module for this plugin. - - @rtype: C{ModuleType} - @return: The module object that is loaded. - """ - return namedModule(self.module) - - def __repr__(self): - if self.isLoaded(): - loaded = ' loaded' - else: - loaded = '' - return "" % (repr(self.name), self.module, loaded) - -class DropIn: - """I am a Python package containing plugins.tml. - """ - def __init__(self, name): - self.name = name - self.plugins = [] - - def register(self, name, module, **kw): - """Register a new plug-in. - """ - warnings.warn("The twisted.python.plugin system is deprecated. " - "See twisted.plugin for the revised edition.", - DeprecationWarning, 2) - self.plugins.append(PlugIn(name, module, **kw)) - - def __repr__(self): - return "" % (self.name, self.plugins) - - -def _prepCallbacks(debug, progress): - if debug: - try: - debug('Looking for plugin.tml files') - except: - debug = lambda x: sys.stdout.write(x + '\n') - debug('Looking for plugin.tml files') - else: - debug = lambda x: None - if progress: - try: - progress(0.0) - except: - pb = util.makeStatusBar(76) - progress = lambda x, pb=pb: sys.stdout.write(pb(x) + '\r') - progress(0.0) - else: - progress = lambda x: None - return debug, progress - -def getPluginFileList(debugInspection=None, showProgress=None): - """Find plugin.tml files in subdirectories of paths in C{sys.path} - - @type debugInspection: C{None} or a callable taking one argument - @param debugInspection: If not None, this is invoked with strings containing - debug information about the loading process. If it is any other true value, - this debug information is written to stdout (This behavior is deprecated). - - @type showProgress: C{None} or a callable taking one argument. - @param showProgress: If not None, this is invoked with floating point - values between 0 and 1 describing the progress of the loading process. - If it is any other true value, this progress information is written to - stdout. (This behavior is deprecated). - - @rtype: C{list} of C{str} - @return: A list of the plugin.tml files found. - """ - if isinstance(debugInspection, types.IntType): - warnings.warn( - "int parameter for debugInspection is deprecated, pass None or " - "a function that takes a single argument instead.", - DeprecationWarning, 2 - ) - if isinstance(showProgress, types.IntType): - warnings.warn( - "int parameter for showProgress is deprecated, pass None or " - "a function that takes a single argument instead.", - DeprecationWarning, 2 - ) - debugInspection, showProgress = _prepCallbacks(debugInspection, showProgress) - exists = os.path.exists - join = os.sep.join - result = [] - loaded = {} - seenNames = {} - - # XXX Some people claim to have found non-strings in sys.path (an empty - # list, in particular). Instead of tracking down the cause for their - # presence, they decided it was better to discard them unconditionally - # without further investigation. At some point, someone should track - # down where non-strings are coming from and do something about them. - paths = [cacheTransform(p) for p in sys.path - if isinstance(p, str) and os.path.isdir(p)] - - # special case for commonly used directories we *know* shouldn't be checked - # and really slow down mktap and such-like in real installations - for p in ("/usr/bin", "/usr/local/bin"): - try: - paths.remove(p) - except ValueError: - pass - progress = 0.0 - increments = 1.0 / len(paths) - - for (index, d) in zip(range(len(paths)), paths): - showProgress(progress) - if loaded.has_key(d): - debugInspection('Already saw ' + d) - continue - else: - debugInspection('Recursing through ' + d) - try: - subDirs = os.listdir(d) - except OSError, (err, s): - # Permission denied, carry on - if err == errno.EACCES: - debugInspection('Permission denied on ' + d) - else: - raise - else: - # filter out files we obviously don't need to check - ones with '.' in them - subDirs = [s for s in subDirs if "." not in s] - if not subDirs: - continue - incr = increments * (1.0 / len(subDirs)) - for plugindir in subDirs: - if seenNames.has_key(plugindir): - debugInspection('Seen %s already' % plugindir) - continue - tmlname = join((d, plugindir, "plugins.tml")) - if isAModule(join((d,plugindir))): - seenNames[plugindir] = 1 - if exists(tmlname): - result.append(tmlname) - debugInspection('Found ' + tmlname) - else: - debugInspection('Failed ' + tmlname) - else: - debugInspection('Not a module ' + tmlname) - progress = progress + incr - showProgress(progress) - - showProgress(1.0) - return result - -def loadPlugins(plugInType, fileList, debugInspection=None, showProgress=None): - """Traverse the given list of files and attempt to load plugins from them. - - @type plugInType: C{str} - @param plugInType: The type of plugin to search for. This is tested - against the C{type} argument to the C{register} function in the - plugin.tml files. - - @type fileList: C{list} of C{str} - @param fileList: A list of the files to attempt to load plugin - information from. One name is put in their scope, the C{register} - function. - - @type debugInspection: C{None} or a callable taking one argument - @param debugInspection: If not None, this is invoked with strings containing - debug information about the loading process. If it is any other true value, - this debug information is written to stdout (This behavior is deprecated). - - @type showProgress: C{None} or a callable taking one argument. - @param showProgress: If not None, this is invoked with floating point - values between 0 and 1 describing the progress of the loading process. - If it is any other true value, this progress information is written to - stdout. (This behavior is deprecated). - - @rtype: C{list} - @return: A list of the C{PlugIn} objects found. - """ - if isinstance(debugInspection, types.IntType): - warnings.warn( - "int parameter for debugInspection is deprecated, pass None or " - "a function that takes a single argument instead.", - DeprecationWarning, 4 - ) - if isinstance(showProgress, types.IntType): - warnings.warn( - "int parameter for showProgress is deprecated, pass None or " - "a function that takes a single argument instead.", - DeprecationWarning, 4 - ) - result = [] - debugInspection, showProgress = _prepCallbacks(debugInspection, showProgress) - - if not fileList: - raise ValueError("No plugins passed to loadPlugins") - - increments = 1.0 / len(fileList) - progress = 0.0 - - for (index, tmlFile) in zip(range(len(fileList)), fileList): - showProgress(progress) - debugInspection("Loading from " + tmlFile) - pname = os.path.split(os.path.abspath(tmlFile))[-2] - dropin = DropIn(pname) - ns = {'register': dropin.register, '__file__': tmlFile} - try: - execfile(tmlFile, ns) - except (IOError, OSError), e: - # guess we don't have permissions for that - debugInspection("Error loading: %s" % e) - continue - - ldp = len(dropin.plugins) or 1.0 - incr = increments * (1.0 / ldp) - for plugin in dropin.plugins: - if plugInType == plugin.type: - result.append(plugin) - debugInspection("Found %r" % (plugin,)) - else: - debugInspection("Disqualified %r" % (plugin,)) - progress = progress + incr - showProgress(progress) - debugInspection("Finished loading from %s!" % tmlFile) - - showProgress(1.0) - debugInspection("Returning %r" % (result,)) - return result - -def getPlugIns(plugInType, debugInspection=None, showProgress=None): - """Helper function to get all the plugins of a particular type. - - @type plugInType: C{str} - @param plugInType: The type of plugin to search for. This is tested - against the C{type} argument to the C{register} function in the - plugin.tml files. - - @type debugInspection: C{None} or a callable taking one argument - @param debugInspection: If not None, this is invoked with strings containing - debug information about the loading process. If it is any other true value, - this debug information is written to stdout (This behavior is deprecated). - - @type showProgress: C{None} or a callable taking one argument. - @param showProgress: If not None, this is invoked with floating point - values between 0 and 1 describing the progress of the loading process. - If it is any other true value, this progress information is written to - stdout. (This behavior is deprecated). - - @rtype: C{list} - @return: A list of C{PlugIn} objects that were found. - """ - warnings.warn("The twisted.python.plugin system is deprecated. " - "See twisted.plugin for the revised edition.", - DeprecationWarning, 2) - return _getPlugIns(plugInType, debugInspection, showProgress) - -def _getPlugIns(plugInType, debugInspection=None, showProgress=None): - if isinstance(debugInspection, types.IntType): - warnings.warn( - "int parameter for debugInspection is deprecated, pass None or " - "a function that takes a single argument instead.", - DeprecationWarning, 3 - ) - if isinstance(showProgress, types.IntType): - warnings.warn( - "int parameter for showProgress is deprecated, pass None or " - "a function that takes a single argument instead.", - DeprecationWarning, 3 - ) - debugInspection, showProgress = _prepCallbacks(debugInspection, showProgress) - - firstHalf = secondHalf = lambda x: None - if showProgress: - firstHalf = lambda x: showProgress(x / 2.0) - secondHalf = lambda x: showProgress(x / 2.0 + 0.5) - - tmlFiles = getPluginFileList(debugInspection, firstHalf) - if not tmlFiles: - return [] - return loadPlugins(plugInType, tmlFiles, debugInspection, secondHalf) - -def isAModule(d): - """This function checks the directory for __init__ files. - """ - suffixes = ['py', 'pyc', 'pyo', 'so', 'pyd', 'dll'] - exists = os.path.exists - join = os.sep.join - for s in suffixes: # bad algorithm, but probably works - if exists(join((d,'__init__.%s' % s))): - return 1 - return 0 - -__all__ = ['PlugIn', 'DropIn', 'getPluginFileList', 'loadPlugins', 'getPlugIns'] diff --git a/tools/buildbot/pylibs/twisted/python/procutils.py b/tools/buildbot/pylibs/twisted/python/procutils.py deleted file mode 100644 index c96a1604..0000000 --- a/tools/buildbot/pylibs/twisted/python/procutils.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Utilities for dealing with processes. -""" - -import os - -def which(name, flags=os.X_OK): - """Search PATH for executable files with the given name. - - On newer versions of MS-Windows, the PATHEXT environment variable will be - set to the list of file extensions for files considered executable. This - will normally include things like ".EXE". This fuction will also find files - with the given name ending with any of these extensions. - - On MS-Windows the only flag that has any meaning is os.F_OK. Any other - flags will be ignored. - - @type name: C{str} - @param name: The name for which to search. - - @type flags: C{int} - @param flags: Arguments to L{os.access}. - - @rtype: C{list} - @param: A list of the full paths to files found, in the - order in which they were found. - """ - result = [] - exts = filter(None, os.environ.get('PATHEXT', '').split(os.pathsep)) - path = os.environ.get('PATH', None) - if path is None: - return [] - for p in os.environ.get('PATH', '').split(os.pathsep): - p = os.path.join(p, name) - if os.access(p, flags): - result.append(p) - for e in exts: - pext = p + e - if os.access(pext, flags): - result.append(pext) - return result - diff --git a/tools/buildbot/pylibs/twisted/python/randbytes.py b/tools/buildbot/pylibs/twisted/python/randbytes.py deleted file mode 100644 index 319363d..0000000 --- a/tools/buildbot/pylibs/twisted/python/randbytes.py +++ /dev/null @@ -1,177 +0,0 @@ -# -*- test-case-name: twisted.test.test_randbytes -*- -# Copyright (c) 2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Cryptographically secure random implementation, with fallback on normal random. -""" - -# System imports -import warnings, os, random - -getrandbits = getattr(random, 'getrandbits', None) - -try: - from Crypto.Util import randpool -except ImportError: - randpool = None - - - -class SecureRandomNotAvailable(RuntimeError): - """ - Exception raised when no secure random algorithm is found. - """ - - - -class SourceNotAvailable(RuntimeError): - """ - Internal exception used when a specific random source is not available. - """ - - - -class RandomFactory(object): - """ - Factory providing L{secureRandom} and L{insecureRandom} methods. - - You shouldn't have to instantiate this class, use the module level - functions instead: it is an implementation detail and could be removed or - changed arbitrarily. - - @ivar randomPool: pool of random data. - @type randomPool: C{randpool.RandomPool} - - @cvar randomSources: list of file sources used when os.urandom is not - available. - @type randomSources: C{tuple} - """ - randpool = randpool - randomPool = None - randomSources = ('/dev/urandom',) - getrandbits = getrandbits - - - def _osUrandom(self, nbytes): - """ - Wrapper around C{os.urandom} that cleanly manage its absence. - """ - try: - return os.urandom(nbytes) - except (AttributeError, NotImplementedError), e: - raise SourceNotAvailable(e) - - - def _fileUrandom(self, nbytes): - """ - Wrapper around random file sources. - - This method isn't meant to be call out of the class and could be - removed arbitrarily. - """ - for src in self.randomSources: - try: - f = file(src, 'rb') - except (IOError, OSError): - pass - else: - bytes = f.read(nbytes) - f.close() - return bytes - raise SourceNotAvailable("File sources not available: %s" % - (self.randomSources,)) - - - def _cryptoRandom(self, nbytes): - """ - Wrapper around Crypo random pool. - """ - if self.randpool is not None: - if self.randomPool is None: - self.randomPool = self.randpool.RandomPool() - self.randomPool.stir() - return self.randomPool.get_bytes(nbytes) - raise SourceNotAvailable("PyCrypto isn't installed") - - - def secureRandom(self, nbytes, fallback=False): - """ - Return a number of secure random bytes. - - @param nbytes: number of bytes to generate. - @type nbytes: C{int}. - @param fallback: whether the function should fallback on non secure - random or not. Default to C{false}. - @type fallback: C{bool} - - @return: a string of random bytes. - @rtype: C{str}. - """ - for src in ("_osUrandom", "_fileUrandom", "_cryptoRandom"): - try: - return getattr(self, src)(nbytes) - except SourceNotAvailable: - pass - if fallback: - warnings.warn( - "Neither PyCrypto nor urandom available - " - "proceeding with non-cryptographically secure random source", - category=RuntimeWarning, - stacklevel=2 - ) - return self.insecureRandom(nbytes) - else: - raise SecureRandomNotAvailable("No secure random source available") - - - def _randBits(self, nbytes): - """ - Wrapper around C{os.getrandbits}. - """ - if self.getrandbits is not None: - n = self.getrandbits(nbytes * 8) - hexBytes = ("%%0%dx" % (nbytes * 2)) % n - return hexBytes.decode('hex') - raise SourceNotAvailable("random.getrandbits is not available") - - - def _randRange(self, nbytes): - """ - Wrapper around C{random.randrange}. - """ - bytes = "" - for i in xrange(nbytes): - bytes += chr(random.randrange(0, 255)) - return bytes - - - def insecureRandom(self, nbytes): - """ - Return a number of non secure random bytes. - - @param nbytes: number of bytes to generate. - @type nbytes: C{int}. - - @return: a string of random bytes. - @rtype: C{str}. - """ - for src in ("_randBits", "_randRange"): - try: - return getattr(self, src)(nbytes) - except SourceNotAvailable: - pass - - - -factory = RandomFactory() - -secureRandom = factory.secureRandom - -insecureRandom = factory.insecureRandom - -del factory - - -__all__ = ["secureRandom", "insecureRandom", "SecureRandomNotAvailable"] - diff --git a/tools/buildbot/pylibs/twisted/python/rebuild.py b/tools/buildbot/pylibs/twisted/python/rebuild.py deleted file mode 100644 index 4f53657..0000000 --- a/tools/buildbot/pylibs/twisted/python/rebuild.py +++ /dev/null @@ -1,264 +0,0 @@ -# -*- test-case-name: twisted.test.test_rebuild -*- -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -*Real* reloading support for Python. -""" - -# System Imports -import sys -import types -import time -import linecache - -# Sibling Imports -from twisted.python import log, reflect - -lastRebuild = time.time() - - -class Sensitive: - """ - A utility mixin that's sensitive to rebuilds. - - This is a mixin for classes (usually those which represent collections of - callbacks) to make sure that their code is up-to-date before running. - """ - - lastRebuild = lastRebuild - - def needRebuildUpdate(self): - yn = (self.lastRebuild < lastRebuild) - return yn - - def rebuildUpToDate(self): - self.lastRebuild = time.time() - - def latestVersionOf(self, anObject): - """ - Get the latest version of an object. - - This can handle just about anything callable; instances, functions, - methods, and classes. - """ - t = type(anObject) - if t == types.FunctionType: - return latestFunction(anObject) - elif t == types.MethodType: - if anObject.im_self is None: - return getattr(anObject.im_class, anObject.__name__) - else: - return getattr(anObject.im_self, anObject.__name__) - elif t == types.InstanceType: - # Kick it, if it's out of date. - getattr(anObject, 'nothing', None) - return anObject - elif t == types.ClassType: - return latestClass(anObject) - else: - log.msg('warning returning anObject!') - return anObject - -_modDictIDMap = {} - -def latestFunction(oldFunc): - """ - Get the latest version of a function. - """ - # This may be CPython specific, since I believe jython instantiates a new - # module upon reload. - dictID = id(oldFunc.func_globals) - module = _modDictIDMap.get(dictID) - if module is None: - return oldFunc - return getattr(module, oldFunc.__name__) - - -def latestClass(oldClass): - """ - Get the latest version of a class. - """ - module = reflect.namedModule(oldClass.__module__) - newClass = getattr(module, oldClass.__name__) - newBases = [latestClass(base) for base in newClass.__bases__] - - try: - # This makes old-style stuff work - newClass.__bases__ = tuple(newBases) - return newClass - except TypeError: - if newClass.__module__ == "__builtin__": - # __builtin__ members can't be reloaded sanely - return newClass - ctor = getattr(newClass, '__metaclass__', type) - return ctor(newClass.__name__, tuple(newBases), dict(newClass.__dict__)) - - -class RebuildError(Exception): - """ - Exception raised when trying to rebuild a class whereas it's not possible. - """ - - -def updateInstance(self): - """ - Updates an instance to be current. - """ - try: - self.__class__ = latestClass(self.__class__) - except TypeError: - if hasattr(self.__class__, '__slots__'): - raise RebuildError("Can't rebuild class with __slots__ on Python < 2.6") - else: - raise - - -def __getattr__(self, name): - """ - A getattr method to cause a class to be refreshed. - """ - if name == '__del__': - raise AttributeError("Without this, Python segfaults.") - updateInstance(self) - log.msg("(rebuilding stale %s instance (%s))" % (reflect.qual(self.__class__), name)) - result = getattr(self, name) - return result - - -def rebuild(module, doLog=1): - """ - Reload a module and do as much as possible to replace its references. - """ - global lastRebuild - lastRebuild = time.time() - if hasattr(module, 'ALLOW_TWISTED_REBUILD'): - # Is this module allowed to be rebuilt? - if not module.ALLOW_TWISTED_REBUILD: - raise RuntimeError("I am not allowed to be rebuilt.") - if doLog: - log.msg('Rebuilding %s...' % str(module.__name__)) - - ## Safely handle adapter re-registration - from twisted.python import components - components.ALLOW_DUPLICATES = True - - d = module.__dict__ - _modDictIDMap[id(d)] = module - newclasses = {} - classes = {} - functions = {} - values = {} - if doLog: - log.msg(' (scanning %s): ' % str(module.__name__)) - for k, v in d.items(): - if type(v) == types.ClassType: - # Failure condition -- instances of classes with buggy - # __hash__/__cmp__ methods referenced at the module level... - if v.__module__ == module.__name__: - classes[v] = 1 - if doLog: - log.logfile.write("c") - log.logfile.flush() - elif type(v) == types.FunctionType: - if v.func_globals is module.__dict__: - functions[v] = 1 - if doLog: - log.logfile.write("f") - log.logfile.flush() - elif isinstance(v, type): - if v.__module__ == module.__name__: - newclasses[v] = 1 - if doLog: - log.logfile.write("o") - log.logfile.flush() - - values.update(classes) - values.update(functions) - fromOldModule = values.has_key - newclasses = newclasses.keys() - classes = classes.keys() - functions = functions.keys() - - if doLog: - log.msg('') - log.msg(' (reload %s)' % str(module.__name__)) - - # Boom. - reload(module) - # Make sure that my traceback printing will at least be recent... - linecache.clearcache() - - if doLog: - log.msg(' (cleaning %s): ' % str(module.__name__)) - - for clazz in classes: - if getattr(module, clazz.__name__) is clazz: - log.msg("WARNING: class %s not replaced by reload!" % reflect.qual(clazz)) - else: - if doLog: - log.logfile.write("x") - log.logfile.flush() - clazz.__bases__ = () - clazz.__dict__.clear() - clazz.__getattr__ = __getattr__ - clazz.__module__ = module.__name__ - if newclasses: - import gc - for nclass in newclasses: - ga = getattr(module, nclass.__name__) - if ga is nclass: - log.msg("WARNING: new-class %s not replaced by reload!" % reflect.qual(nclass)) - else: - for r in gc.get_referrers(nclass): - if getattr(r, '__class__', None) is nclass: - r.__class__ = ga - if doLog: - log.msg('') - log.msg(' (fixing %s): ' % str(module.__name__)) - modcount = 0 - for mk, mod in sys.modules.items(): - modcount = modcount + 1 - if mod == module or mod is None: - continue - - if not hasattr(mod, '__file__'): - # It's a builtin module; nothing to replace here. - continue - changed = 0 - - for k, v in mod.__dict__.items(): - try: - hash(v) - except TypeError: - continue - if fromOldModule(v): - if type(v) == types.ClassType: - if doLog: - log.logfile.write("c") - log.logfile.flush() - nv = latestClass(v) - else: - if doLog: - log.logfile.write("f") - log.logfile.flush() - nv = latestFunction(v) - changed = 1 - setattr(mod, k, nv) - else: - # Replace bases of non-module classes just to be sure. - if type(v) == types.ClassType: - for base in v.__bases__: - if fromOldModule(base): - latestClass(v) - if doLog and not changed and ((modcount % 10) ==0) : - log.logfile.write(".") - log.logfile.flush() - - components.ALLOW_DUPLICATES = False - if doLog: - log.msg('') - log.msg(' Rebuilt %s.' % str(module.__name__)) - return module - diff --git a/tools/buildbot/pylibs/twisted/python/reflect.py b/tools/buildbot/pylibs/twisted/python/reflect.py deleted file mode 100644 index 522ec9b..0000000 --- a/tools/buildbot/pylibs/twisted/python/reflect.py +++ /dev/null @@ -1,745 +0,0 @@ -# -*- test-case-name: twisted.test.test_reflect -*- - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Standardized versions of various cool and/or strange things that you can do -with Python's reflection capabilities. -""" - -from __future__ import nested_scopes - - -# System Imports -import sys -import os -import types -import string -import pickle -import new -import traceback -import weakref -import re -import warnings -try: - from collections import deque -except ImportError: - deque = list - -RegexType = type(re.compile("")) - - -try: - import cStringIO as StringIO -except ImportError: - import StringIO - -class Settable: - """ - A mixin class for syntactic sugar. Lets you assign attributes by - calling with keyword arguments; for example, C{x(a=b,c=d,y=z)} is the - same as C{x.a=b;x.c=d;x.y=z}. The most useful place for this is - where you don't want to name a variable, but you do want to set - some attributes; for example, C{X()(y=z,a=b)}. - """ - def __init__(self, **kw): - self(**kw) - - def __call__(self,**kw): - for key,val in kw.items(): - setattr(self,key,val) - return self - - -class AccessorType(type): - """Metaclass that generates properties automatically. - - This is for Python 2.2 and up. - - Using this metaclass for your class will give you explicit accessor - methods; a method called set_foo, will automatically create a property - 'foo' that uses set_foo as a setter method. Same for get_foo and del_foo. - - Note that this will only work on methods that are present on class - creation. If you add methods after the class is defined they will not - automatically become properties. Likewise, class attributes will only - be used if they are present upon class creation, and no getter function - was set - if a getter is present, the class attribute will be ignored. - - This is a 2.2-only alternative to the Accessor mixin - just set in your - class definition:: - - __metaclass__ = AccessorType - - """ - - def __init__(self, name, bases, d): - type.__init__(self, name, bases, d) - accessors = {} - prefixs = ["get_", "set_", "del_"] - for k in d.keys(): - v = getattr(self, k) - for i in range(3): - if k.startswith(prefixs[i]): - accessors.setdefault(k[4:], [None, None, None])[i] = v - for name, (getter, setter, deler) in accessors.items(): - # create default behaviours for the property - if we leave - # the getter as None we won't be able to getattr, etc.. - if getter is None: - if hasattr(self, name): - value = getattr(self, name) - def getter(this, value=value, name=name): - if this.__dict__.has_key(name): - return this.__dict__[name] - else: - return value - else: - def getter(this, name=name): - if this.__dict__.has_key(name): - return this.__dict__[name] - else: - raise AttributeError, "no such attribute %r" % name - if setter is None: - def setter(this, value, name=name): - this.__dict__[name] = value - if deler is None: - def deler(this, name=name): - del this.__dict__[name] - setattr(self, name, property(getter, setter, deler, "")) - - -class PropertyAccessor(object): - """A mixin class for Python 2.2 that uses AccessorType. - - This provides compatability with the pre-2.2 Accessor mixin, up - to a point. - - Extending this class will give you explicit accessor methods; a - method called set_foo, for example, is the same as an if statement - in __setattr__ looking for 'foo'. Same for get_foo and del_foo. - - There are also reallyDel and reallySet methods, so you can - override specifics in subclasses without clobbering __setattr__ - and __getattr__, or using non-2.1 compatible code. - - There is are incompatibilities with Accessor - accessor - methods added after class creation will *not* be detected. OTOH, - this method is probably way faster. - - In addition, class attributes will only be used if no getter - was defined, and instance attributes will not override getter methods - whereas in original Accessor the class attribute or instance attribute - would override the getter method. - """ - # addendum to above: - # The behaviour of Accessor is wrong IMHO, and I've found bugs - # caused by it. - # -- itamar - - __metaclass__ = AccessorType - - def reallySet(self, k, v): - self.__dict__[k] = v - - def reallyDel(self, k): - del self.__dict__[k] - - -class Accessor: - """ - Extending this class will give you explicit accessor methods; a - method called C{set_foo}, for example, is the same as an if statement - in L{__setattr__} looking for C{'foo'}. Same for C{get_foo} and - C{del_foo}. There are also L{reallyDel} and L{reallySet} methods, - so you can override specifics in subclasses without clobbering - L{__setattr__} and L{__getattr__}. - - This implementation is for Python 2.1. - """ - - def __setattr__(self, k,v): - kstring='set_%s'%k - if hasattr(self.__class__,kstring): - return getattr(self,kstring)(v) - else: - self.reallySet(k,v) - - def __getattr__(self, k): - kstring='get_%s'%k - if hasattr(self.__class__,kstring): - return getattr(self,kstring)() - raise AttributeError("%s instance has no accessor for: %s" % (qual(self.__class__),k)) - - def __delattr__(self, k): - kstring='del_%s'%k - if hasattr(self.__class__,kstring): - getattr(self,kstring)() - return - self.reallyDel(k) - - def reallySet(self, k,v): - """ - *actually* set self.k to v without incurring side-effects. - This is a hook to be overridden by subclasses. - """ - if k == "__dict__": - self.__dict__.clear() - self.__dict__.update(v) - else: - self.__dict__[k]=v - - def reallyDel(self, k): - """ - *actually* del self.k without incurring side-effects. This is a - hook to be overridden by subclasses. - """ - del self.__dict__[k] - -# just in case -OriginalAccessor = Accessor - - -class Summer(Accessor): - """ - Extend from this class to get the capability to maintain 'related - sums'. Have a tuple in your class like the following:: - - sums=(('amount','credit','credit_total'), - ('amount','debit','debit_total')) - - and the 'credit_total' member of the 'credit' member of self will - always be incremented when the 'amount' member of self is - incremented, similiarly for the debit versions. - """ - - def reallySet(self, k,v): - "This method does the work." - for sum in self.sums: - attr=sum[0] - obj=sum[1] - objattr=sum[2] - if k == attr: - try: - oldval=getattr(self, attr) - except: - oldval=0 - diff=v-oldval - if hasattr(self, obj): - ob=getattr(self,obj) - if ob is not None: - try:oldobjval=getattr(ob, objattr) - except:oldobjval=0.0 - setattr(ob,objattr,oldobjval+diff) - - elif k == obj: - if hasattr(self, attr): - x=getattr(self,attr) - setattr(self,attr,0) - y=getattr(self,k) - Accessor.reallySet(self,k,v) - setattr(self,attr,x) - Accessor.reallySet(self,y,v) - Accessor.reallySet(self,k,v) - -class QueueMethod: - """ I represent a method that doesn't exist yet.""" - def __init__(self, name, calls): - self.name = name - self.calls = calls - def __call__(self, *args): - self.calls.append((self.name, args)) - - -def funcinfo(function): - """ - this is more documentation for myself than useful code. - """ - warnings.warn( - "[v2.5] Use inspect.getargspec instead of twisted.python.reflect.funcinfo", - DeprecationWarning, - stacklevel=2) - code=function.func_code - name=function.func_name - argc=code.co_argcount - argv=code.co_varnames[:argc] - defaults=function.func_defaults - - out = [] - - out.append('The function %s accepts %s arguments' % (name ,argc)) - if defaults: - required=argc-len(defaults) - out.append('It requires %s arguments' % required) - out.append('The arguments required are: %s' % argv[:required]) - out.append('additional arguments are:') - for i in range(argc-required): - j=i+required - out.append('%s which has a default of' % (argv[j], defaults[i])) - return out - - -ISNT=0 -WAS=1 -IS=2 - - -def fullFuncName(func): - qualName = (str(pickle.whichmodule(func, func.__name__)) + '.' + func.__name__) - if namedObject(qualName) is not func: - raise Exception("Couldn't find %s as %s." % (func, qualName)) - return qualName - -def qual(clazz): - """Return full import path of a class.""" - return clazz.__module__ + '.' + clazz.__name__ - -def getcurrent(clazz): - assert type(clazz) == types.ClassType, 'must be a class...' - module = namedModule(clazz.__module__) - currclass = getattr(module, clazz.__name__, None) - if currclass is None: - return clazz - return currclass - -def getClass(obj): - """Return the class or type of object 'obj'. - Returns sensible result for oldstyle and newstyle instances and types.""" - if hasattr(obj, '__class__'): - return obj.__class__ - else: - return type(obj) - -# class graph nonsense - -# I should really have a better name for this... -def isinst(inst,clazz): - if type(inst) != types.InstanceType or type(clazz)!= types.ClassType: - return isinstance(inst,clazz) - cl = inst.__class__ - cl2 = getcurrent(cl) - clazz = getcurrent(clazz) - if issubclass(cl2,clazz): - if cl == cl2: - return WAS - else: - inst.__class__ = cl2 - return IS - else: - return ISNT - - -def namedModule(name): - """Return a module given its name.""" - topLevel = __import__(name) - packages = name.split(".")[1:] - m = topLevel - for p in packages: - m = getattr(m, p) - return m - - -def namedObject(name): - """Get a fully named module-global object. - """ - classSplit = string.split(name, '.') - module = namedModule(string.join(classSplit[:-1], '.')) - return getattr(module, classSplit[-1]) - -namedClass = namedObject # backwards compat - - - -class _NoModuleFound(Exception): - """ - No module was found because none exists. - """ - - - -def _importAndCheckStack(importName): - """ - Import the given name as a module, then walk the stack to determine whether - the failure was the module not existing, or some code in the module (for - example a dependent import) failing. This can be helpful to determine - whether any actual application code was run. For example, to distiguish - administrative error (entering the wrong module name), from programmer - error (writing buggy code in a module that fails to import). - - @raise Exception: if something bad happens. This can be any type of - exception, since nobody knows what loading some arbitrary code might do. - - @raise _NoModuleFound: if no module was found. - """ - try: - try: - return __import__(importName) - except ImportError: - excType, excValue, excTraceback = sys.exc_info() - while excTraceback: - execName = excTraceback.tb_frame.f_globals["__name__"] - if (execName is None or # python 2.4+, post-cleanup - execName == importName): # python 2.3, no cleanup - raise excType, excValue, excTraceback - excTraceback = excTraceback.tb_next - raise _NoModuleFound() - except: - # Necessary for cleaning up modules in 2.3. - sys.modules.pop(importName, None) - raise - - - -def namedAny(name): - """ - Retrieve a Python object from the global Python module namespace, by its - fully qualified name. The first part of the name, that describes a module, - will be discovered and imported. - - @param name: the fully qualified name of a Python object, which is a - dot-separated list of python objects accessible via a name. This includes - packages, modules, and any Python object which has attributes. For - example, a fully-qualified name of this object is - 'twisted.python.reflect.namedAny'. - - @type name: L{str} - - @return: the Python object identified by 'name'. - - @raise ValueError: if the top level dotted name that is passed is not a - valid Python identifier, or the top level dotted name that is passed is not - a valid python module. - - @raise AttributeError: if an attribute of an object along the way cannot be - accessed, or a module along the way is not found. - - @raise ImportError: if any module involved cannot be imported for some - reason. - """ - names = name.split('.') - topLevelPackage = None - moduleNames = names[:] - while not topLevelPackage: - trialname = '.'.join(moduleNames) - try: - topLevelPackage = _importAndCheckStack(trialname) - except _NoModuleFound: - moduleNames.pop() - - obj = topLevelPackage - for n in names[1:]: - obj = getattr(obj, n) - - return obj - -def _reclass(clazz): - clazz = getattr(namedModule(clazz.__module__),clazz.__name__) - clazz.__bases__ = tuple(map(_reclass, clazz.__bases__)) - return clazz - - - - -def macro(name, filename, source, **identifiers): - """macro(name, source, **identifiers) - - This allows you to create macro-like behaviors in python. See - twisted.python.hook for an example of its usage. - """ - if not identifiers.has_key('name'): - identifiers['name'] = name - source = source % identifiers - codeplace = "<%s (macro)>" % filename - code = compile(source, codeplace, 'exec') - - # shield your eyes! - sm = sys.modules - tprm = "twisted.python.reflect.macros" - if not sm.has_key(tprm): - macros = new.module(tprm) - sm[tprm] = macros - macros.count = 0 - macros = sm[tprm] - macros.count += 1 - macroname = 'macro_' + str(macros.count) - tprmm = tprm + '.' + macroname - mymod = new.module(tprmm) - sys.modules[tprmm] = mymod - setattr(macros, macroname, mymod) - dict = mymod.__dict__ - - # Before we go on, I guess I should explain why I just did that. Basically - # it's a gross hack to get epydoc to work right, but the general idea is - # that it will be a useful aid in debugging in _any_ app which expects - # sys.modules to have the same globals as some function. For example, it - # would be useful if you were foolishly trying to pickle a wrapped function - # directly from a class that had been hooked. - - exec code in dict, dict - return dict[name] - -def _determineClass(x): - try: - return x.__class__ - except: - return type(x) - -def _determineClassName(x): - c = _determineClass(x) - try: - return c.__name__ - except: - try: - return str(c) - except: - return '' % id(c) - -def safe_repr(o): - """safe_repr(anything) -> string - - Returns a string representation of an object, or a string containing a - traceback, if that object's __repr__ raised an exception. - """ - - try: - return repr(o) - except: - io = StringIO.StringIO() - traceback.print_stack(file=io) - whati = _determineClassName(o) - swron = io.getvalue() - gwith = id(o) - you ='<%s instance at %s with repr error %s>' % ( - whati,swron,gwith) - return you - -def safe_str(o): - """safe_str(anything) -> string - - Returns a string representation of an object, or a string containing a - traceback, if that object's __str__ raised an exception. - """ - - try: - return str(o) - except: - strExc = '\n'.join(traceback.format_exception(*sys.exc_info())) - clsName = _determineClassName(o) - obId = id(o) - return '<%s instance at %s with str error %s>' % ( - clsName, obId, strExc) - - -##the following were factored out of usage - -def allYourBase(classObj, baseClass=None): - """allYourBase(classObj, baseClass=None) -> list of all base - classes that are subclasses of baseClass, unless it is None, - in which case all bases will be added. - """ - l = [] - accumulateBases(classObj, l, baseClass) - return l - - -def accumulateBases(classObj, l, baseClass=None): - for base in classObj.__bases__: - if baseClass is None or issubclass(base, baseClass): - l.append(base) - accumulateBases(base, l, baseClass) - - -def prefixedMethodNames(classObj, prefix): - """A list of method names with a given prefix in a given class. - """ - dct = {} - addMethodNamesToDict(classObj, dct, prefix) - return dct.keys() - - -def addMethodNamesToDict(classObj, dict, prefix, baseClass=None): - """ - addMethodNamesToDict(classObj, dict, prefix, baseClass=None) -> dict - this goes through 'classObj' (and its bases) and puts method names - starting with 'prefix' in 'dict' with a value of 1. if baseClass isn't - None, methods will only be added if classObj is-a baseClass - - If the class in question has the methods 'prefix_methodname' and - 'prefix_methodname2', the resulting dict should look something like: - {"methodname": 1, "methodname2": 1}. - """ - for base in classObj.__bases__: - addMethodNamesToDict(base, dict, prefix, baseClass) - - if baseClass is None or baseClass in classObj.__bases__: - for name, method in classObj.__dict__.items(): - optName = name[len(prefix):] - if ((type(method) is types.FunctionType) - and (name[:len(prefix)] == prefix) - and (len(optName))): - dict[optName] = 1 - -def prefixedMethods(obj, prefix=''): - """A list of methods with a given prefix on a given instance. - """ - dct = {} - accumulateMethods(obj, dct, prefix) - return dct.values() - -def accumulateMethods(obj, dict, prefix='', curClass=None): - """accumulateMethods(instance, dict, prefix) - I recurse through the bases of instance.__class__, and add methods - beginning with 'prefix' to 'dict', in the form of - {'methodname':*instance*method_object}. - """ - if not curClass: - curClass = obj.__class__ - for base in curClass.__bases__: - accumulateMethods(obj, dict, prefix, base) - - for name, method in curClass.__dict__.items(): - optName = name[len(prefix):] - if ((type(method) is types.FunctionType) - and (name[:len(prefix)] == prefix) - and (len(optName))): - dict[optName] = getattr(obj, name) - -def accumulateClassDict(classObj, attr, adict, baseClass=None): - """Accumulate all attributes of a given name in a class heirarchy into a single dictionary. - - Assuming all class attributes of this name are dictionaries. - If any of the dictionaries being accumulated have the same key, the - one highest in the class heirarchy wins. - (XXX: If \"higest\" means \"closest to the starting class\".) - - Ex:: - - | class Soy: - | properties = {\"taste\": \"bland\"} - | - | class Plant: - | properties = {\"colour\": \"green\"} - | - | class Seaweed(Plant): - | pass - | - | class Lunch(Soy, Seaweed): - | properties = {\"vegan\": 1 } - | - | dct = {} - | - | accumulateClassDict(Lunch, \"properties\", dct) - | - | print dct - - {\"taste\": \"bland\", \"colour\": \"green\", \"vegan\": 1} - """ - for base in classObj.__bases__: - accumulateClassDict(base, attr, adict) - if baseClass is None or baseClass in classObj.__bases__: - adict.update(classObj.__dict__.get(attr, {})) - - -def accumulateClassList(classObj, attr, listObj, baseClass=None): - """Accumulate all attributes of a given name in a class heirarchy into a single list. - - Assuming all class attributes of this name are lists. - """ - for base in classObj.__bases__: - accumulateClassList(base, attr, listObj) - if baseClass is None or baseClass in classObj.__bases__: - listObj.extend(classObj.__dict__.get(attr, [])) - - -def isSame(a, b): - return (a is b) - -def isLike(a, b): - return (a == b) - -def modgrep(goal): - return objgrep(sys.modules, goal, isLike, 'sys.modules') - -def isOfType(start, goal): - return ((type(start) is goal) or - (isinstance(start, types.InstanceType) and - start.__class__ is goal)) - - -def findInstances(start, t): - return objgrep(start, t, isOfType) - -def objgrep(start, goal, eq=isLike, path='', paths=None, seen=None, showUnknowns=0, maxDepth=None): - '''An insanely CPU-intensive process for finding stuff. - ''' - if paths is None: - paths = [] - if seen is None: - seen = {} - if eq(start, goal): - paths.append(path) - if seen.has_key(id(start)): - if seen[id(start)] is start: - return - if maxDepth is not None: - if maxDepth == 0: - return - maxDepth -= 1 - seen[id(start)] = start - if isinstance(start, types.DictionaryType): - r = [] - for k, v in start.items(): - objgrep(k, goal, eq, path+'{'+repr(v)+'}', paths, seen, showUnknowns, maxDepth) - objgrep(v, goal, eq, path+'['+repr(k)+']', paths, seen, showUnknowns, maxDepth) - elif isinstance(start, (list, tuple, deque)): - for idx in xrange(len(start)): - objgrep(start[idx], goal, eq, path+'['+str(idx)+']', paths, seen, showUnknowns, maxDepth) - elif isinstance(start, types.MethodType): - objgrep(start.im_self, goal, eq, path+'.im_self', paths, seen, showUnknowns, maxDepth) - objgrep(start.im_func, goal, eq, path+'.im_func', paths, seen, showUnknowns, maxDepth) - objgrep(start.im_class, goal, eq, path+'.im_class', paths, seen, showUnknowns, maxDepth) - elif hasattr(start, '__dict__'): - for k, v in start.__dict__.items(): - objgrep(v, goal, eq, path+'.'+k, paths, seen, showUnknowns, maxDepth) - if isinstance(start, types.InstanceType): - objgrep(start.__class__, goal, eq, path+'.__class__', paths, seen, showUnknowns, maxDepth) - elif isinstance(start, weakref.ReferenceType): - objgrep(start(), goal, eq, path+'()', paths, seen, showUnknowns, maxDepth) - elif (isinstance(start, types.StringTypes+ - (types.IntType, types.FunctionType, - types.BuiltinMethodType, RegexType, types.FloatType, - types.NoneType, types.FileType)) or - type(start).__name__ in ('wrapper_descriptor', 'method_descriptor', - 'member_descriptor', 'getset_descriptor')): - pass - elif showUnknowns: - print 'unknown type', type(start), start - return paths - - -def filenameToModuleName(fn): - """ - Convert a name in the filesystem to the name of the Python module it is. - - This is agressive about getting a module name back from a file; it will - always return a string. Agressive means 'sometimes wrong'; it won't look - at the Python path or try to do any error checking: don't use this method - unless you already know that the filename you're talking about is a Python - module. - """ - fullName = os.path.abspath(fn) - base = os.path.basename(fn) - if not base: - # this happens when fn ends with a path separator, just skit it - base = os.path.basename(fn[:-1]) - modName = os.path.splitext(base)[0] - while 1: - fullName = os.path.dirname(fullName) - if os.path.exists(os.path.join(fullName, "__init__.py")): - modName = "%s.%s" % (os.path.basename(fullName), modName) - else: - break - return modName - -#boo python diff --git a/tools/buildbot/pylibs/twisted/python/release.py b/tools/buildbot/pylibs/twisted/python/release.py deleted file mode 100644 index 8c1e676..0000000 --- a/tools/buildbot/pylibs/twisted/python/release.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -A release-automation toolkit. - -Don't use this outside of Twisted. - -Maintainer: U{Christopher Armstrong} -""" - -import os -import re - - -# errors - -class DirectoryExists(OSError): - """Some directory exists when it shouldn't.""" - pass - - - -class DirectoryDoesntExist(OSError): - """Some directory doesn't exist when it should.""" - pass - - - -class CommandFailed(OSError): - pass - - - -# utilities - -def sh(command, null=True, prompt=False): - """ - I'll try to execute `command', and if `prompt' is true, I'll - ask before running it. If the command returns something other - than 0, I'll raise CommandFailed(command). - """ - print "--$", command - - if prompt: - if raw_input("run ?? ").startswith('n'): - return - if null: - command = "%s > /dev/null" % command - if os.system(command) != 0: - raise CommandFailed(command) - - - -def runChdirSafe(f, *args, **kw): - origdir = os.path.abspath('.') - try: - return f(*args, **kw) - finally: - os.chdir(origdir) diff --git a/tools/buildbot/pylibs/twisted/python/roots.py b/tools/buildbot/pylibs/twisted/python/roots.py deleted file mode 100644 index c2ee39d..0000000 --- a/tools/buildbot/pylibs/twisted/python/roots.py +++ /dev/null @@ -1,257 +0,0 @@ -# -*- test-case-name: twisted.test.test_roots -*- -# -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Twisted Python Roots: an abstract hierarchy representation for Twisted. - -Maintainer: Glyph Lefkowitz - -Future Plans: Removing distinction between 'static' and 'dynamic' entities, -which never made much sense anyway and bloats the API horribly. This probably -involves updating all of Coil to have tree widgets that can be dynamically -expanded, which probably involves porting all of Coil to Woven, so it might not -happen for a while. - -""" - -# System imports -import types -from twisted.python import reflect - -class NotSupportedError(NotImplementedError): - """ - An exception meaning that the tree-manipulation operation - you're attempting to perform is not supported. - """ - - -class Request: - """I am an abstract representation of a request for an entity. - - I also function as the response. The request is responded to by calling - self.write(data) until there is no data left and then calling - self.finish(). - """ - # This attribute should be set to the string name of the protocol being - # responded to (e.g. HTTP or FTP) - wireProtocol = None - def write(self, data): - """Add some data to the response to this request. - """ - raise NotImplementedError("%s.write" % reflect.qual(self.__class__)) - - def finish(self): - """The response to this request is finished; flush all data to the network stream. - """ - raise NotImplementedError("%s.finish" % reflect.qual(self.__class__)) - - -class Entity: - """I am a terminal object in a hierarchy, with no children. - - I represent a null interface; certain non-instance objects (strings and - integers, notably) are Entities. - - Methods on this class are suggested to be implemented, but are not - required, and will be emulated on a per-protocol basis for types which do - not handle them. - """ - def render(self, request): - """ - I produce a stream of bytes for the request, by calling request.write() - and request.finish(). - """ - raise NotImplementedError("%s.render" % reflect.qual(self.__class__)) - - -class Collection: - """I represent a static collection of entities. - - I contain methods designed to represent collections that can be dynamically - created. - """ - - def __init__(self, entities=None): - """Initialize me. - """ - if entities is not None: - self.entities = entities - else: - self.entities = {} - - def getStaticEntity(self, name): - """Get an entity that was added to me using putEntity. - - This method will return 'None' if it fails. - """ - return self.entities.get(name) - - def getDynamicEntity(self, name, request): - """Subclass this to generate an entity on demand. - - This method should return 'None' if it fails. - """ - - def getEntity(self, name, request): - """Retrieve an entity from me. - - I will first attempt to retrieve an entity statically; static entities - will obscure dynamic ones. If that fails, I will retrieve the entity - dynamically. - - If I cannot retrieve an entity, I will return 'None'. - """ - ent = self.getStaticEntity(name) - if ent is not None: - return ent - ent = self.getDynamicEntity(name, request) - if ent is not None: - return ent - return None - - def putEntity(self, name, entity): - """Store a static reference on 'name' for 'entity'. - - Raises a KeyError if the operation fails. - """ - self.entities[name] = entity - - def delEntity(self, name): - """Remove a static reference for 'name'. - - Raises a KeyError if the operation fails. - """ - del self.entities[name] - - def storeEntity(self, name, request): - """Store an entity for 'name', based on the content of 'request'. - """ - raise NotSupportedError("%s.storeEntity" % reflect.qual(self.__class__)) - - def removeEntity(self, name, request): - """Remove an entity for 'name', based on the content of 'request'. - """ - raise NotSupportedError("%s.removeEntity" % reflect.qual(self.__class__)) - - def listStaticEntities(self): - """Retrieve a list of all name, entity pairs that I store references to. - - See getStaticEntity. - """ - return self.entities.items() - - def listDynamicEntities(self, request): - """A list of all name, entity that I can generate on demand. - - See getDynamicEntity. - """ - return [] - - def listEntities(self, request): - """Retrieve a list of all name, entity pairs I contain. - - See getEntity. - """ - return self.listStaticEntities() + self.listDynamicEntities(request) - - def listStaticNames(self): - """Retrieve a list of the names of entities that I store references to. - - See getStaticEntity. - """ - return self.entities.keys() - - - def listDynamicNames(self): - """Retrieve a list of the names of entities that I store references to. - - See getDynamicEntity. - """ - return [] - - - def listNames(self, request): - """Retrieve a list of all names for entities that I contain. - - See getEntity. - """ - return self.listStaticNames() - - -class ConstraintViolation(Exception): - """An exception raised when a constraint is violated. - """ - - -class Constrained(Collection): - """A collection that has constraints on its names and/or entities.""" - - def nameConstraint(self, name): - """A method that determines whether an entity may be added to me with a given name. - - If the constraint is satisfied, return 1; if the constraint is not - satisfied, either return 0 or raise a descriptive ConstraintViolation. - """ - return 1 - - def entityConstraint(self, entity): - """A method that determines whether an entity may be added to me. - - If the constraint is satisfied, return 1; if the constraint is not - satisfied, either return 0 or raise a descriptive ConstraintViolation. - """ - return 1 - - def reallyPutEntity(self, name, entity): - Collection.putEntity(self, name, entity) - - def putEntity(self, name, entity): - """Store an entity if it meets both constraints. - - Otherwise raise a ConstraintViolation. - """ - if self.nameConstraint(name): - if self.entityConstraint(entity): - self.reallyPutEntity(name, entity) - else: - raise ConstraintViolation("Entity constraint violated.") - else: - raise ConstraintViolation("Name constraint violated.") - - -class Locked(Constrained): - """A collection that can be locked from adding entities.""" - - locked = 0 - - def lock(self): - self.locked = 1 - - def entityConstraint(self, entity): - return not self.locked - - -class Homogenous(Constrained): - """A homogenous collection of entities. - - I will only contain entities that are an instance of the class or type - specified by my 'entityType' attribute. - """ - - entityType = types.InstanceType - - def entityConstraint(self, entity): - if isinstance(entity, self.entityType): - return 1 - else: - raise ConstraintViolation("%s of incorrect type (%s)" % - (entity, self.entityType)) - - def getNameType(self): - return "Name" - - def getEntityType(self): - return self.entityType.__name__ diff --git a/tools/buildbot/pylibs/twisted/python/runtime.py b/tools/buildbot/pylibs/twisted/python/runtime.py deleted file mode 100644 index acea6fa..0000000 --- a/tools/buildbot/pylibs/twisted/python/runtime.py +++ /dev/null @@ -1,82 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -# System imports -import os -import sys -import time -import imp - -def shortPythonVersion(): - hv = sys.hexversion - major = (hv & 0xff000000L) >> 24 - minor = (hv & 0x00ff0000L) >> 16 - teeny = (hv & 0x0000ff00L) >> 8 - return "%s.%s.%s" % (major,minor,teeny) - -knownPlatforms = { - 'nt': 'win32', - 'ce': 'win32', - 'posix': 'posix', - 'java': 'java', - 'org.python.modules.os': 'java', - } - -_timeFunctions = { - #'win32': time.clock, - 'win32': time.time, - } - -class Platform: - """Gives us information about the platform we're running on""" - - type = knownPlatforms.get(os.name) - seconds = staticmethod(_timeFunctions.get(type, time.time)) - - def __init__(self, name=None): - if name is not None: - self.type = knownPlatforms.get(name) - self.seconds = _timeFunctions.get(self.type, time.time) - - def isKnown(self): - """Do we know about this platform?""" - return self.type != None - - def getType(self): - """Return 'posix', 'win32' or 'java'""" - return self.type - - def isMacOSX(self): - """Return if we are runnng on Mac OS X.""" - return sys.platform == "darwin" - - def isWinNT(self): - """Are we running in Windows NT?""" - if self.getType() == 'win32': - import _winreg - try: - k=_winreg.OpenKeyEx(_winreg.HKEY_LOCAL_MACHINE, - r'Software\Microsoft\Windows NT\CurrentVersion') - _winreg.QueryValueEx(k, 'SystemRoot') - return 1 - except WindowsError: - return 0 - # not windows NT - return 0 - - def isWindows(self): - return self.getType() == 'win32' - - def supportsThreads(self): - """Can threads be created? - """ - try: - return imp.find_module('thread')[0] is None - except ImportError: - return False - -platform = Platform() -platformType = platform.getType() -seconds = platform.seconds diff --git a/tools/buildbot/pylibs/twisted/python/shortcut.py b/tools/buildbot/pylibs/twisted/python/shortcut.py deleted file mode 100644 index 5465d86..0000000 --- a/tools/buildbot/pylibs/twisted/python/shortcut.py +++ /dev/null @@ -1,76 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Creation of Windows shortcuts. - -Requires win32all. -""" - -from win32com.shell import shell -import pythoncom -import os - - -def open(filename): - """Open an existing shortcut for reading. - - @return: The shortcut object - @rtype: Shortcut - """ - sc=Shortcut() - sc.load(filename) - return sc - - -class Shortcut: - """A shortcut on Win32. - >>> sc=Shortcut(path, arguments, description, workingdir, iconpath, iconidx) - @param path: Location of the target - @param arguments: If path points to an executable, optional arguments to - pass - @param description: Human-readable decription of target - @param workingdir: Directory from which target is launched - @param iconpath: Filename that contains an icon for the shortcut - @param iconidx: If iconpath is set, optional index of the icon desired - """ - - def __init__(self, - path=None, - arguments=None, - description=None, - workingdir=None, - iconpath=None, - iconidx=0): - self._base = pythoncom.CoCreateInstance( - shell.CLSID_ShellLink, None, - pythoncom.CLSCTX_INPROC_SERVER, shell.IID_IShellLink - ) - data = map(None, - ['"%s"' % os.path.abspath(path), arguments, description, - os.path.abspath(workingdir), os.path.abspath(iconpath)], - ("SetPath", "SetArguments", "SetDescription", - "SetWorkingDirectory") ) - for value, function in data: - if value and function: - # call function on each non-null value - getattr(self, function)(value) - if iconpath: - self.SetIconLocation(iconpath, iconidx) - - def load( self, filename ): - """Read a shortcut file from disk.""" - self._base.QueryInterface(pythoncom.IID_IPersistFile).Load(filename) - - def save( self, filename ): - """Write the shortcut to disk. - - The file should be named something.lnk. - """ - self._base.QueryInterface(pythoncom.IID_IPersistFile).Save(filename, 0) - - def __getattr__( self, name ): - if name != "_base": - return getattr(self._base, name) - raise AttributeError, "%s instance has no attribute %s" % \ - (self.__class__.__name__, name) diff --git a/tools/buildbot/pylibs/twisted/python/syslog.py b/tools/buildbot/pylibs/twisted/python/syslog.py deleted file mode 100644 index 53b8a96..0000000 --- a/tools/buildbot/pylibs/twisted/python/syslog.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -syslog = __import__('syslog') - -import log - -class SyslogObserver: - def __init__(self, prefix): - syslog.openlog(prefix) - - def emit(self, eventDict): - edm = eventDict['message'] - if not edm: - if eventDict['isError'] and eventDict.has_key('failure'): - text = eventDict['failure'].getTraceback() - elif eventDict.has_key('format'): - text = eventDict['format'] % eventDict - else: - # we don't know how to log this - return - else: - text = ' '.join(map(str, edm)) - - lines = text.split('\n') - while lines[-1:] == ['']: - lines.pop() - - firstLine = 1 - for line in lines: - if firstLine: - firstLine=0 - else: - line = '\t%s' % line - syslog.syslog('[%s] %s' % (eventDict['system'], line)) - -def startLogging(prefix='Twisted', setStdout=1): - obs = SyslogObserver(prefix) - log.startLoggingWithObserver(obs.emit, setStdout=setStdout) diff --git a/tools/buildbot/pylibs/twisted/python/test/__init__.py b/tools/buildbot/pylibs/twisted/python/test/__init__.py deleted file mode 100644 index cfdc40d..0000000 --- a/tools/buildbot/pylibs/twisted/python/test/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -""" -Unit tests for L{twisted.python}. -""" diff --git a/tools/buildbot/pylibs/twisted/python/test/test_components.py b/tools/buildbot/pylibs/twisted/python/test/test_components.py deleted file mode 100644 index 426923b..0000000 --- a/tools/buildbot/pylibs/twisted/python/test/test_components.py +++ /dev/null @@ -1,741 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Test cases for Twisted component architecture. -""" - -from zope.interface import Interface, implements, Attribute - -from twisted.trial import unittest -from twisted.python import components -from twisted.python.components import proxyForInterface - - -class InterfacesTestCase(unittest.TestCase): - """Test interfaces.""" - -class Compo(components.Componentized): - num = 0 - def inc(self): - self.num = self.num + 1 - return self.num - -class IAdept(Interface): - def adaptorFunc(): - raise NotImplementedError() - -class IElapsed(Interface): - def elapsedFunc(): - """ - 1! - """ - -class Adept(components.Adapter): - implements(IAdept) - def __init__(self, orig): - self.original = orig - self.num = 0 - def adaptorFunc(self): - self.num = self.num + 1 - return self.num, self.original.inc() - -class Elapsed(components.Adapter): - implements(IElapsed) - def elapsedFunc(self): - return 1 - -components.registerAdapter(Adept, Compo, IAdept) -components.registerAdapter(Elapsed, Compo, IElapsed) - -class AComp(components.Componentized): - pass -class BComp(AComp): - pass -class CComp(BComp): - pass - -class ITest(Interface): - pass -class ITest2(Interface): - pass -class ITest3(Interface): - pass -class ITest4(Interface): - pass -class Test(components.Adapter): - implements(ITest, ITest3, ITest4) - def __init__(self, orig): - pass -class Test2: - implements(ITest2) - temporaryAdapter = 1 - def __init__(self, orig): - pass - -components.registerAdapter(Test, AComp, ITest) -components.registerAdapter(Test, AComp, ITest3) -components.registerAdapter(Test2, AComp, ITest2) - - - - -class ComponentizedTestCase(unittest.TestCase): - """Simple test case for caching in Componentized. - """ - def testComponentized(self): - c = Compo() - assert c.getComponent(IAdept).adaptorFunc() == (1, 1) - assert c.getComponent(IAdept).adaptorFunc() == (2, 2) - assert IElapsed(IAdept(c)).elapsedFunc() == 1 - - def testInheritanceAdaptation(self): - c = CComp() - co1 = c.getComponent(ITest) - co2 = c.getComponent(ITest) - co3 = c.getComponent(ITest2) - co4 = c.getComponent(ITest2) - assert co1 is co2 - assert co3 is not co4 - c.removeComponent(co1) - co5 = c.getComponent(ITest) - co6 = c.getComponent(ITest) - assert co5 is co6 - assert co1 is not co5 - - def testMultiAdapter(self): - c = CComp() - co1 = c.getComponent(ITest) - co2 = c.getComponent(ITest2) - co3 = c.getComponent(ITest3) - co4 = c.getComponent(ITest4) - assert co4 == None - assert co1 is co3 - - - def test_getComponentDefaults(self): - """ - Test that a default value specified to Componentized.getComponent if - there is no component for the requested interface. - """ - componentized = components.Componentized() - default = object() - self.assertIdentical( - componentized.getComponent(ITest, default), - default) - self.assertIdentical( - componentized.getComponent(ITest, default=default), - default) - self.assertIdentical( - componentized.getComponent(ITest), - None) - - - -class AdapterTestCase(unittest.TestCase): - """Test adapters.""" - - def testAdapterGetComponent(self): - o = object() - a = Adept(o) - self.assertRaises(components.CannotAdapt, ITest, a) - self.assertEquals(ITest(a, None), None) - - - -class IMeta(Interface): - pass - -class MetaAdder(components.Adapter): - implements(IMeta) - def add(self, num): - return self.original.num + num - -class BackwardsAdder(components.Adapter): - implements(IMeta) - def add(self, num): - return self.original.num - num - -class MetaNumber: - def __init__(self, num): - self.num = num - -class FakeAdder: - def add(self, num): - return num + 5 - -class FakeNumber: - num = 3 - -class ComponentNumber(components.Componentized): - def __init__(self): - self.num = 0 - components.Componentized.__init__(self) - -class ComponentMeta(components.Adapter): - implements(IMeta) - def __init__(self, original): - components.Adapter.__init__(self, original) - self.num = self.original.num - -class ComponentAdder(ComponentMeta): - def add(self, num): - self.num += num - return self.num - -class ComponentDoubler(ComponentMeta): - def add(self, num): - self.num += (num * 2) - return self.original.num - -components.registerAdapter(MetaAdder, MetaNumber, IMeta) -components.registerAdapter(ComponentAdder, ComponentNumber, IMeta) - -class IAttrX(Interface): - def x(): - pass - -class IAttrXX(Interface): - def xx(): - pass - -class Xcellent: - implements(IAttrX) - def x(self): - return 'x!' - -class DoubleXAdapter: - num = 42 - def __init__(self, original): - self.original = original - def xx(self): - return (self.original.x(), self.original.x()) - def __cmp__(self, other): - return cmp(self.num, other.num) - -components.registerAdapter(DoubleXAdapter, IAttrX, IAttrXX) - -class TestMetaInterface(unittest.TestCase): - - def testBasic(self): - n = MetaNumber(1) - self.assertEquals(IMeta(n).add(1), 2) - - def testComponentizedInteraction(self): - c = ComponentNumber() - IMeta(c).add(1) - IMeta(c).add(1) - self.assertEquals(IMeta(c).add(1), 3) - - def testAdapterWithCmp(self): - # Make sure that a __cmp__ on an adapter doesn't break anything - xx = IAttrXX(Xcellent()) - self.assertEqual(('x!', 'x!'), xx.xx()) - - -class RegistrationTestCase(unittest.TestCase): - """ - Tests for adapter registration. - """ - def _registerAdapterForClassOrInterface(self, original): - adapter = lambda o: None - class TheInterface(Interface): - pass - components.registerAdapter(adapter, original, TheInterface) - self.assertIdentical( - components.getAdapterFactory(original, TheInterface, None), - adapter) - - - def test_registerAdapterForClass(self): - """ - Test that an adapter from a class can be registered and then looked - up. - """ - class TheOriginal(object): - pass - return self._registerAdapterForClassOrInterface(TheOriginal) - - - def test_registerAdapterForInterface(self): - """ - Test that an adapter from an interface can be registered and then - looked up. - """ - class TheOriginal(Interface): - pass - return self._registerAdapterForClassOrInterface(TheOriginal) - - - def _duplicateAdapterForClassOrInterface(self, original): - firstAdapter = lambda o: False - secondAdapter = lambda o: True - class TheInterface(Interface): - pass - components.registerAdapter(firstAdapter, original, TheInterface) - self.assertRaises( - ValueError, - components.registerAdapter, - secondAdapter, original, TheInterface) - # Make sure that the original adapter is still around as well - self.assertIdentical( - components.getAdapterFactory(original, TheInterface, None), - firstAdapter) - - - def test_duplicateAdapterForClass(self): - """ - Test that attempting to register a second adapter from a class - raises the appropriate exception. - """ - class TheOriginal(object): - pass - return self._duplicateAdapterForClassOrInterface(TheOriginal) - - - def test_duplicateAdapterForInterface(self): - """ - Test that attempting to register a second adapter from an interface - raises the appropriate exception. - """ - class TheOriginal(Interface): - pass - return self._duplicateAdapterForClassOrInterface(TheOriginal) - - - def _duplicateAdapterForClassOrInterfaceAllowed(self, original): - firstAdapter = lambda o: False - secondAdapter = lambda o: True - class TheInterface(Interface): - pass - components.registerAdapter(firstAdapter, original, TheInterface) - components.ALLOW_DUPLICATES = True - try: - components.registerAdapter(secondAdapter, original, TheInterface) - self.assertIdentical( - components.getAdapterFactory(original, TheInterface, None), - secondAdapter) - finally: - components.ALLOW_DUPLICATES = False - - # It should be rejected again at this point - self.assertRaises( - ValueError, - components.registerAdapter, - firstAdapter, original, TheInterface) - - self.assertIdentical( - components.getAdapterFactory(original, TheInterface, None), - secondAdapter) - - def test_duplicateAdapterForClassAllowed(self): - """ - Test that when L{components.ALLOW_DUPLICATES} is set to a true - value, duplicate registrations from classes are allowed to override - the original registration. - """ - class TheOriginal(object): - pass - return self._duplicateAdapterForClassOrInterfaceAllowed(TheOriginal) - - - def test_duplicateAdapterForInterfaceAllowed(self): - """ - Test that when L{components.ALLOW_DUPLICATES} is set to a true - value, duplicate registrations from interfaces are allowed to - override the original registration. - """ - class TheOriginal(Interface): - pass - return self._duplicateAdapterForClassOrInterfaceAllowed(TheOriginal) - - - def _multipleInterfacesForClassOrInterface(self, original): - adapter = lambda o: None - class FirstInterface(Interface): - pass - class SecondInterface(Interface): - pass - components.registerAdapter(adapter, original, FirstInterface, SecondInterface) - self.assertIdentical( - components.getAdapterFactory(original, FirstInterface, None), - adapter) - self.assertIdentical( - components.getAdapterFactory(original, SecondInterface, None), - adapter) - - - def test_multipleInterfacesForClass(self): - """ - Test the registration of an adapter from a class to several - interfaces at once. - """ - class TheOriginal(object): - pass - return self._multipleInterfacesForClassOrInterface(TheOriginal) - - - def test_multipleInterfacesForInterface(self): - """ - Test the registration of an adapter from an interface to several - interfaces at once. - """ - class TheOriginal(Interface): - pass - return self._multipleInterfacesForClassOrInterface(TheOriginal) - - - def _subclassAdapterRegistrationForClassOrInterface(self, original): - firstAdapter = lambda o: True - secondAdapter = lambda o: False - class TheSubclass(original): - pass - class TheInterface(Interface): - pass - components.registerAdapter(firstAdapter, original, TheInterface) - components.registerAdapter(secondAdapter, TheSubclass, TheInterface) - self.assertIdentical( - components.getAdapterFactory(original, TheInterface, None), - firstAdapter) - self.assertIdentical( - components.getAdapterFactory(TheSubclass, TheInterface, None), - secondAdapter) - - - def test_subclassAdapterRegistrationForClass(self): - """ - Test that an adapter to a particular interface can be registered - from both a class and its subclass. - """ - class TheOriginal(object): - pass - return self._subclassAdapterRegistrationForClassOrInterface(TheOriginal) - - - def test_subclassAdapterRegistrationForInterface(self): - """ - Test that an adapter to a particular interface can be registered - from both an interface and its subclass. - """ - class TheOriginal(Interface): - pass - return self._subclassAdapterRegistrationForClassOrInterface(TheOriginal) - - - -class IProxiedInterface(Interface): - """ - An interface class for use by L{proxyForInterface}. - """ - - ifaceAttribute = Attribute(""" - An example declared attribute, which should be proxied.""") - - def yay(*a, **kw): - """ - A sample method which should be proxied. - """ - -class IProxiedSubInterface(IProxiedInterface): - """ - An interface that derives from another for use with L{proxyForInterface}. - """ - - def boo(self): - """ - A different sample method which should be proxied. - """ - - - -class Yayable(object): - """ - A provider of L{IProxiedInterface} which increments a counter for - every call to C{yay}. - - @ivar yays: The number of times C{yay} has been called. - """ - implements(IProxiedInterface) - - def __init__(self): - self.yays = 0 - self.yayArgs = [] - - def yay(self, *a, **kw): - """ - Increment C{self.yays}. - """ - self.yays += 1 - self.yayArgs.append((a, kw)) - return self.yays - - -class Booable(object): - """ - An implementation of IProxiedSubInterface - """ - implements(IProxiedSubInterface) - yayed = False - booed = False - def yay(self): - """ - Mark the fact that 'yay' has been called. - """ - self.yayed = True - - - def boo(self): - """ - Mark the fact that 'boo' has been called.1 - """ - self.booed = True - - - -class IMultipleMethods(Interface): - """ - An interface with multiple methods. - """ - - def methodOne(): - """ - The first method. Should return 1. - """ - - def methodTwo(): - """ - The second method. Should return 2. - """ - - - -class MultipleMethodImplementor(object): - """ - A precise implementation of L{IMultipleMethods}. - """ - - def methodOne(self): - """ - @return: 1 - """ - return 1 - - - def methodTwo(self): - """ - @return: 2 - """ - return 2 - - - -class ProxyForInterfaceTests(unittest.TestCase): - """ - Tests for L{proxyForInterface}. - """ - - def test_original(self): - """ - Proxy objects should have an C{original} attribute which refers to the - original object passed to the constructor. - """ - original = object() - proxy = proxyForInterface(IProxiedInterface)(original) - self.assertIdentical(proxy.original, original) - - - def test_proxyMethod(self): - """ - The class created from L{proxyForInterface} passes methods on an - interface to the object which is passed to its constructor. - """ - klass = proxyForInterface(IProxiedInterface) - yayable = Yayable() - proxy = klass(yayable) - proxy.yay() - self.assertEquals(proxy.yay(), 2) - self.assertEquals(yayable.yays, 2) - - - def test_proxyAttribute(self): - """ - Proxy objects should proxy declared attributes, but not other - attributes. - """ - yayable = Yayable() - yayable.ifaceAttribute = object() - proxy = proxyForInterface(IProxiedInterface)(yayable) - self.assertIdentical(proxy.ifaceAttribute, yayable.ifaceAttribute) - self.assertRaises(AttributeError, lambda: proxy.yays) - - - def test_proxySetAttribute(self): - """ - The attributes that proxy objects proxy should be assignable and affect - the original object. - """ - yayable = Yayable() - proxy = proxyForInterface(IProxiedInterface)(yayable) - thingy = object() - proxy.ifaceAttribute = thingy - self.assertIdentical(yayable.ifaceAttribute, thingy) - - - def test_proxyDeleteAttribute(self): - """ - The attributes that proxy objects proxy should be deletable and affect - the original object. - """ - yayable = Yayable() - yayable.ifaceAttribute = None - proxy = proxyForInterface(IProxiedInterface)(yayable) - del proxy.ifaceAttribute - self.assertFalse(hasattr(yayable, 'ifaceAttribute')) - - - def test_multipleMethods(self): - """ - [Regression test] The proxy should send its method calls to the correct - method, not the incorrect one. - """ - multi = MultipleMethodImplementor() - proxy = proxyForInterface(IMultipleMethods)(multi) - self.assertEquals(proxy.methodOne(), 1) - self.assertEquals(proxy.methodTwo(), 2) - - - def test_subclassing(self): - """ - It is possible to subclass the result of L{proxyForInterface}. - """ - - class SpecializedProxy(proxyForInterface(IProxiedInterface)): - """ - A specialized proxy which can decrement the number of yays. - """ - def boo(self): - """ - Decrement the number of yays. - """ - self.original.yays -= 1 - - yayable = Yayable() - special = SpecializedProxy(yayable) - self.assertEquals(yayable.yays, 0) - special.boo() - self.assertEquals(yayable.yays, -1) - - - def test_proxyName(self): - """ - The name of a proxy class indicates which interface it proxies. - """ - proxy = proxyForInterface(IProxiedInterface) - self.assertEquals( - proxy.__name__, - "(Proxy for " - "twisted.python.test.test_components.IProxiedInterface)") - - - def test_provides(self): - """ - The resulting proxy provides the Interface that it proxies. - """ - proxy = proxyForInterface(IProxiedInterface) - self.assertTrue(IProxiedInterface.providedBy(proxy)) - - - def test_proxyDescriptorGet(self): - """ - _ProxyDescriptor's __get__ method should return the appropriate - attribute of its argument's 'original' attribute if it is invoked with - an object. If it is invoked with None, it should return a false - class-method emulator instead. - - For some reason, Python's documentation recommends to define - descriptors' __get__ methods with the 'type' parameter as optional, - despite the fact that Python itself never actually calls the descriptor - that way. This is probably do to support 'foo.__get__(bar)' as an - idiom. Let's make sure that the behavior is correct. Since we don't - actually use the 'type' argument at all, this test calls it the - idiomatic way to ensure that signature works; test_proxyInheritance - verifies the how-Python-actually-calls-it signature. - """ - class Sample: - called = False - def hello(self): - self.called = True - fakeProxy = Sample() - testObject = Sample() - fakeProxy.original = testObject - pd = components._ProxyDescriptor("hello", "original") - self.assertEquals(pd.__get__(fakeProxy), testObject.hello) - fakeClassMethod = pd.__get__(None) - fakeClassMethod(fakeProxy) - self.failUnless(testObject.called) - - - def test_proxyInheritance(self): - """ - Subclasses of the class returned from L{proxyForInterface} should be - able to upcall methods by reference to their superclass, as any normal - Python class can. - """ - class YayableWrapper(proxyForInterface(IProxiedInterface)): - """ - This class does not override any functionality. - """ - - class EnhancedWrapper(YayableWrapper): - """ - This class overrides the 'yay' method. - """ - wrappedYays = 1 - def yay(self, *a, **k): - self.wrappedYays += 1 - return YayableWrapper.yay(self, *a, **k) + 7 - - yayable = Yayable() - wrapper = EnhancedWrapper(yayable) - self.assertEquals(wrapper.yay(3, 4, x=5, y=6), 8) - self.assertEquals(yayable.yayArgs, - [((3, 4), dict(x=5, y=6))]) - - - def test_interfaceInheritance(self): - """ - Proxies of subinterfaces generated with proxyForInterface should allow - access to attributes of both the child and the base interfaces. - """ - proxyClass = proxyForInterface(IProxiedSubInterface) - booable = Booable() - proxy = proxyClass(booable) - proxy.yay() - proxy.boo() - self.failUnless(booable.yayed) - self.failUnless(booable.booed) - - - def test_attributeCustomization(self): - """ - The original attribute name can be customized via the - C{originalAttribute} argument of L{proxyForInterface}: the attribute - should change, but the methods of the original object should still be - callable, and the attributes still accessible. - """ - yayable = Yayable() - yayable.ifaceAttribute = object() - proxy = proxyForInterface( - IProxiedInterface, originalAttribute='foo')(yayable) - self.assertIdentical(proxy.foo, yayable) - - # Check the behavior - self.assertEquals(proxy.yay(), 1) - self.assertIdentical(proxy.ifaceAttribute, yayable.ifaceAttribute) - thingy = object() - proxy.ifaceAttribute = thingy - self.assertIdentical(yayable.ifaceAttribute, thingy) - del proxy.ifaceAttribute - self.assertFalse(hasattr(yayable, 'ifaceAttribute')) - diff --git a/tools/buildbot/pylibs/twisted/python/test/test_deprecate.py b/tools/buildbot/pylibs/twisted/python/test/test_deprecate.py deleted file mode 100644 index 7e85bc5..0000000 --- a/tools/buildbot/pylibs/twisted/python/test/test_deprecate.py +++ /dev/null @@ -1,173 +0,0 @@ -# Copyright (c) 2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Tests for Twisted's deprecation framework. -""" - - -from twisted.trial.unittest import TestCase - -from twisted.python.deprecate import _appendToDocstring -from twisted.python.deprecate import _getDeprecationDocstring -from twisted.python.deprecate import deprecated, getDeprecationWarningString -from twisted.python.reflect import qual -from twisted.python.versions import getVersionString, Version - - - -def dummyCallable(): - """ - Do nothing. - - This is used to test the deprecation decorators. - """ - - - -class TestDeprecationWarnings(TestCase): - - def test_getDeprecationWarningString(self): - """ - L{getDeprecationWarningString} returns a string that tells us that a - callable was deprecated at a certain released version of Twisted. - """ - version = Version('Twisted', 8, 0, 0) - self.assertEqual( - getDeprecationWarningString(self.test_getDeprecationWarningString, version), - "%s was deprecated in Twisted 8.0.0" % ( - qual(self.test_getDeprecationWarningString))) - - - def test_deprecateEmitsWarning(self): - """ - Decorating a callable with L{deprecated} emits a warning. - """ - version = Version('Twisted', 8, 0, 0) - dummy = deprecated(version)(dummyCallable) - def add_a_stack_level(): - dummy() - self.assertWarns( - DeprecationWarning, - getDeprecationWarningString(dummyCallable, version), - __file__, - add_a_stack_level) - - - def test_deprecatedPreservesName(self): - """ - The decorated function has the same name as the original. - """ - version = Version('Twisted', 8, 0, 0) - dummy = deprecated(version)(dummyCallable) - self.assertEqual(dummyCallable.__name__, dummy.__name__) - self.assertEqual(qual(dummyCallable), qual(dummy)) - - - def test_getDeprecationDocstring(self): - """ - L{_getDeprecationDocstring} returns a note about the deprecation to go - into a docstring. - """ - version = Version('Twisted', 8, 0, 0) - self.assertEqual( - "Deprecated in Twisted 8.0.0.", _getDeprecationDocstring(version)) - - - def test_deprecatedUpdatesDocstring(self): - """ - The docstring of the deprecated function is appended with information - about the deprecation. - """ - - version = Version('Twisted', 8, 0, 0) - dummy = deprecated(version)(dummyCallable) - - _appendToDocstring( - dummyCallable, - _getDeprecationDocstring(version)) - - self.assertEqual(dummyCallable.__doc__, dummy.__doc__) - - - def test_versionMetadata(self): - """ - Deprecating a function adds version information to the decorated - version of that function. - """ - # XXX - Is this a YAGNI? - - version = Version('Twisted', 8, 0, 0) - dummy = deprecated(version)(dummyCallable) - - self.assertEqual(version, dummy.deprecatedVersion) - - - -class TestAppendToDocstring(TestCase): - """ - Test the _appendToDocstring function. - - _appendToDocstring is used to add text to a docstring. - """ - - def test_appendToEmptyDocstring(self): - """ - Appending to an empty docstring simply replaces the docstring. - """ - - def noDocstring(): - pass - - _appendToDocstring(noDocstring, "Appended text.") - self.assertEqual("Appended text.", noDocstring.__doc__) - - - def test_appendToSingleLineDocstring(self): - """ - Appending to a single line docstring places the message on a new line, - with a blank line separating it from the rest of the docstring. - - The docstring ends with a newline, conforming to Twisted and PEP 8 - standards. Unfortunately, the indentation is incorrect, since the - existing docstring doesn't have enough info to help us indent - properly. - """ - - def singleLineDocstring(): - """This doesn't comply with standards, but is here for a test.""" - - _appendToDocstring(singleLineDocstring, "Appended text.") - self.assertEqual( - ["This doesn't comply with standards, but is here for a test.", - "", - "Appended text."], - singleLineDocstring.__doc__.splitlines()) - self.assertTrue(singleLineDocstring.__doc__.endswith('\n')) - - - def test_appendToMultilineDocstring(self): - """ - Appending to a multi-line docstring places the messade on a new line, - with a blank line separating it from the rest of the docstring. - - Because we have multiple lines, we have enough information to do - indentation. - """ - - def multiLineDocstring(): - """ - This is a multi-line docstring. - """ - - def expectedDocstring(): - """ - This is a multi-line docstring. - - Appended text. - """ - - _appendToDocstring(multiLineDocstring, "Appended text.") - self.assertEqual( - expectedDocstring.__doc__, multiLineDocstring.__doc__) diff --git a/tools/buildbot/pylibs/twisted/python/test/test_dist.py b/tools/buildbot/pylibs/twisted/python/test/test_dist.py deleted file mode 100644 index c69717d..0000000 --- a/tools/buildbot/pylibs/twisted/python/test/test_dist.py +++ /dev/null @@ -1,173 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for parts of our release automation system. -""" - - -import os - -from distutils.core import Distribution - -from twisted.trial.unittest import TestCase - -from twisted.python import dist -from twisted.python.dist import get_setup_args, ConditionalExtension -from twisted.python.filepath import FilePath - - -class SetupTest(TestCase): - """ - Tests for L{get_setup_args}. - """ - def test_conditionalExtensions(self): - """ - Passing C{conditionalExtensions} as a list of L{ConditionalExtension} - objects to get_setup_args inserts a custom build_ext into the result - which knows how to check whether they should be - """ - good_ext = ConditionalExtension("whatever", ["whatever.c"], - condition=lambda b: True) - bad_ext = ConditionalExtension("whatever", ["whatever.c"], - condition=lambda b: False) - args = get_setup_args(conditionalExtensions=[good_ext, bad_ext]) - # ext_modules should be set even though it's not used. See comment - # in get_setup_args - self.assertEquals(args["ext_modules"], [good_ext, bad_ext]) - cmdclass = args["cmdclass"] - build_ext = cmdclass["build_ext"] - builder = build_ext(Distribution()) - builder.prepare_extensions() - self.assertEquals(builder.extensions, [good_ext]) - - - def test_win32Definition(self): - """ - When building on Windows NT, the WIN32 macro will be defined as 1. - """ - ext = ConditionalExtension("whatever", ["whatever.c"], - define_macros=[("whatever", 2)]) - args = get_setup_args(conditionalExtensions=[ext]) - builder = args["cmdclass"]["build_ext"](Distribution()) - self.patch(os, "name", "nt") - builder.prepare_extensions() - self.assertEquals(ext.define_macros, [("whatever", 2), ("WIN32", 1)]) - - - -class GetVersionTest(TestCase): - """ - Tests for L{dist.getVersion}. - """ - - def setUp(self): - self.dirname = self.mktemp() - os.mkdir(self.dirname) - - def test_getVersionCore(self): - """ - Test that getting the version of core reads from the - [base]/_version.py file. - """ - f = open(os.path.join(self.dirname, "_version.py"), "w") - f.write(""" -from twisted.python import versions -version = versions.Version("twisted", 0, 1, 2) -""") - f.close() - self.assertEquals(dist.getVersion("core", base=self.dirname), "0.1.2") - - def test_getVersionOther(self): - """ - Test that getting the version of a non-core project reads from - the [base]/[projname]/_version.py file. - """ - os.mkdir(os.path.join(self.dirname, "blat")) - f = open(os.path.join(self.dirname, "blat", "_version.py"), "w") - f.write(""" -from twisted.python import versions -version = versions.Version("twisted.blat", 9, 8, 10) -""") - f.close() - self.assertEquals(dist.getVersion("blat", base=self.dirname), "9.8.10") - - -class GetScriptsTest(TestCase): - - def test_scriptsInSVN(self): - """ - getScripts should return the scripts associated with a project - in the context of Twisted SVN. - """ - basedir = self.mktemp() - os.mkdir(basedir) - os.mkdir(os.path.join(basedir, 'bin')) - os.mkdir(os.path.join(basedir, 'bin', 'proj')) - f = open(os.path.join(basedir, 'bin', 'proj', 'exy'), 'w') - f.write('yay') - f.close() - scripts = dist.getScripts('proj', basedir=basedir) - self.assertEquals(len(scripts), 1) - self.assertEquals(os.path.basename(scripts[0]), 'exy') - - - def test_scriptsInRelease(self): - """ - getScripts should return the scripts associated with a project - in the context of a released subproject tarball. - """ - basedir = self.mktemp() - os.mkdir(basedir) - os.mkdir(os.path.join(basedir, 'bin')) - f = open(os.path.join(basedir, 'bin', 'exy'), 'w') - f.write('yay') - f.close() - scripts = dist.getScripts('proj', basedir=basedir) - self.assertEquals(len(scripts), 1) - self.assertEquals(os.path.basename(scripts[0]), 'exy') - - - def test_noScriptsInSVN(self): - """ - When calling getScripts for a project which doesn't actually - have any scripts, in the context of an SVN checkout, an - empty list should be returned. - """ - basedir = self.mktemp() - os.mkdir(basedir) - os.mkdir(os.path.join(basedir, 'bin')) - os.mkdir(os.path.join(basedir, 'bin', 'otherproj')) - scripts = dist.getScripts('noscripts', basedir=basedir) - self.assertEquals(scripts, []) - - - def test_getScriptsTopLevel(self): - """ - Passing the empty string to getScripts returns scripts that are (only) - in the top level bin directory. - """ - basedir = FilePath(self.mktemp()) - basedir.createDirectory() - bindir = basedir.child("bin") - bindir.createDirectory() - included = bindir.child("included") - included.setContent("yay included") - subdir = bindir.child("subdir") - subdir.createDirectory() - subdir.child("not-included").setContent("not included") - - scripts = dist.getScripts("", basedir=basedir.path) - self.assertEquals(scripts, [included.path]) - - - def test_noScriptsInSubproject(self): - """ - When calling getScripts for a project which doesn't actually - have any scripts in the context of that project's individual - project structure, an empty list should be returned. - """ - basedir = self.mktemp() - os.mkdir(basedir) - scripts = dist.getScripts('noscripts', basedir=basedir) - self.assertEquals(scripts, []) diff --git a/tools/buildbot/pylibs/twisted/python/test/test_release.py b/tools/buildbot/pylibs/twisted/python/test/test_release.py deleted file mode 100644 index a12eeae..0000000 --- a/tools/buildbot/pylibs/twisted/python/test/test_release.py +++ /dev/null @@ -1,1516 +0,0 @@ -# Copyright (c) 2007-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.python.release} and L{twisted.python._release}. -""" - -import warnings -import operator -import os, sys, signal -from StringIO import StringIO -import tarfile - -from datetime import date - -try: - import pydoctor.driver - # it might not be installed, or it might use syntax not available in - # this version of Python. -except (ImportError, SyntaxError): - pydoctor = None - -from twisted.trial.unittest import TestCase - -from twisted.python.compat import set -from twisted.python.procutils import which -from twisted.python import release -from twisted.python.filepath import FilePath -from twisted.python.util import dsu -from twisted.python.versions import Version -from twisted.python._release import _changeVersionInFile, getNextVersion -from twisted.python._release import findTwistedProjects, replaceInFile -from twisted.python._release import replaceProjectVersion -from twisted.python._release import updateTwistedVersionInformation, Project -from twisted.python._release import VERSION_OFFSET, DocBuilder, ManBuilder -from twisted.python._release import NoDocumentsFound, filePathDelta -from twisted.python._release import CommandFailed, BookBuilder -from twisted.python._release import DistributionBuilder, APIBuilder - -try: - from twisted.lore.scripts import lore -except ImportError: - lore = None - - - -class ChangeVersionTest(TestCase): - """ - Twisted has the ability to change versions. - """ - - def makeFile(self, relativePath, content): - """ - Create a file with the given content relative to a temporary directory. - - @param relativePath: The basename of the file to create. - @param content: The content that the file will have. - @return: The filename. - """ - baseDirectory = FilePath(self.mktemp()) - directory, filename = os.path.split(relativePath) - directory = baseDirectory.preauthChild(directory) - directory.makedirs() - file = directory.child(filename) - directory.child(filename).setContent(content) - return file - - - def test_getNextVersion(self): - """ - When calculating the next version to release when a release is - happening in the same year as the last release, the minor version - number is incremented. - """ - now = date.today() - major = now.year - VERSION_OFFSET - version = Version("twisted", major, 9, 0) - self.assertEquals(getNextVersion(version, now=now), - Version("twisted", major, 10, 0)) - - - def test_getNextVersionAfterYearChange(self): - """ - When calculating the next version to release when a release is - happening in a later year, the minor version number is reset to 0. - """ - now = date.today() - major = now.year - VERSION_OFFSET - version = Version("twisted", major - 1, 9, 0) - self.assertEquals(getNextVersion(version, now=now), - Version("twisted", major, 0, 0)) - - - def test_changeVersionInFile(self): - """ - _changeVersionInFile replaces the old version information in a file - with the given new version information. - """ - # The version numbers are arbitrary, the name is only kind of - # arbitrary. - packageName = 'foo' - oldVersion = Version(packageName, 2, 5, 0) - file = self.makeFile('README', - "Hello and welcome to %s." % oldVersion.base()) - - newVersion = Version(packageName, 7, 6, 0) - _changeVersionInFile(oldVersion, newVersion, file.path) - - self.assertEqual(file.getContent(), - "Hello and welcome to %s." % newVersion.base()) - - - -class ProjectTest(TestCase): - """ - There is a first-class representation of a project. - """ - - def assertProjectsEqual(self, observedProjects, expectedProjects): - """ - Assert that two lists of L{Project}s are equal. - """ - self.assertEqual(len(observedProjects), len(expectedProjects)) - observedProjects = dsu(observedProjects, - key=operator.attrgetter('directory')) - expectedProjects = dsu(expectedProjects, - key=operator.attrgetter('directory')) - for observed, expected in zip(observedProjects, expectedProjects): - self.assertEqual(observed.directory, expected.directory) - - - def makeProject(self, version, baseDirectory=None): - """ - Make a Twisted-style project in the given base directory. - - @param baseDirectory: The directory to create files in - (as a L{FilePath). - @param version: The version information for the project. - @return: L{Project} pointing to the created project. - """ - if baseDirectory is None: - baseDirectory = FilePath(self.mktemp()) - baseDirectory.createDirectory() - segments = version.package.split('.') - directory = baseDirectory - for segment in segments: - directory = directory.child(segment) - if not directory.exists(): - directory.createDirectory() - directory.child('__init__.py').setContent('') - directory.child('topfiles').createDirectory() - directory.child('topfiles').child('README').setContent(version.base()) - replaceProjectVersion( - version.package, directory.child('_version.py').path, - version) - return Project(directory) - - - def makeProjects(self, *versions): - """ - Create a series of projects underneath a temporary base directory. - - @return: A L{FilePath} for the base directory. - """ - baseDirectory = FilePath(self.mktemp()) - baseDirectory.createDirectory() - for version in versions: - self.makeProject(version, baseDirectory) - return baseDirectory - - - def test_getVersion(self): - """ - Project objects know their version. - """ - version = Version('foo', 2, 1, 0) - project = self.makeProject(version) - self.assertEquals(project.getVersion(), version) - - - def test_updateVersion(self): - """ - Project objects know how to update the version numbers in those - projects. - """ - project = self.makeProject(Version("bar", 2, 1, 0)) - newVersion = Version("bar", 3, 2, 9) - project.updateVersion(newVersion) - self.assertEquals(project.getVersion(), newVersion) - self.assertEquals( - project.directory.child("topfiles").child("README").getContent(), - "3.2.9") - - - def test_repr(self): - """ - The representation of a Project is Project(directory). - """ - foo = Project(FilePath('bar')) - self.assertEqual( - repr(foo), 'Project(%r)' % (foo.directory)) - - - def test_findTwistedStyleProjects(self): - """ - findTwistedStyleProjects finds all projects underneath a particular - directory. A 'project' is defined by the existence of a 'topfiles' - directory and is returned as a Project object. - """ - baseDirectory = self.makeProjects( - Version('foo', 2, 3, 0), Version('foo.bar', 0, 7, 4)) - projects = findTwistedProjects(baseDirectory) - self.assertProjectsEqual( - projects, - [Project(baseDirectory.child('foo')), - Project(baseDirectory.child('foo').child('bar'))]) - - - def test_updateTwistedVersionInformation(self): - """ - Update Twisted version information in the top-level project and all of - the subprojects. - """ - baseDirectory = FilePath(self.mktemp()) - baseDirectory.createDirectory() - now = date.today() - - projectName = 'foo' - oldVersion = Version(projectName, 2, 5, 0) - newVersion = getNextVersion(oldVersion, now=now) - - project = self.makeProject(oldVersion, baseDirectory) - - updateTwistedVersionInformation(baseDirectory, now=now) - - self.assertEqual(project.getVersion(), newVersion) - self.assertEqual( - project.directory.child('topfiles').child('README').getContent(), - newVersion.base()) - - - -class UtilityTest(TestCase): - """ - Tests for various utility functions for releasing. - """ - - def test_chdir(self): - """ - Test that the runChdirSafe is actually safe, i.e., it still - changes back to the original directory even if an error is - raised. - """ - cwd = os.getcwd() - def chAndBreak(): - os.mkdir('releaseCh') - os.chdir('releaseCh') - 1/0 - self.assertRaises(ZeroDivisionError, - release.runChdirSafe, chAndBreak) - self.assertEquals(cwd, os.getcwd()) - - - - def test_replaceInFile(self): - """ - L{replaceInFile} replaces data in a file based on a dict. A key from - the dict that is found in the file is replaced with the corresponding - value. - """ - in_ = 'foo\nhey hey $VER\nbar\n' - outf = open('release.replace', 'w') - outf.write(in_) - outf.close() - - expected = in_.replace('$VER', '2.0.0') - replaceInFile('release.replace', {'$VER': '2.0.0'}) - self.assertEquals(open('release.replace').read(), expected) - - - expected = expected.replace('2.0.0', '3.0.0') - replaceInFile('release.replace', {'2.0.0': '3.0.0'}) - self.assertEquals(open('release.replace').read(), expected) - - - -class VersionWritingTest(TestCase): - """ - Tests for L{replaceProjectVersion}. - """ - - def test_replaceProjectVersion(self): - """ - L{replaceProjectVersion} writes a Python file that defines a - C{version} variable that corresponds to the given name and version - number. - """ - replaceProjectVersion("twisted.test_project", - "test_project", Version("whatever", 0, 82, 7)) - ns = {'__name___': 'twisted.test_project'} - execfile("test_project", ns) - self.assertEquals(ns["version"].base(), "0.82.7") - - - def test_replaceProjectVersionWithPrerelease(self): - """ - L{replaceProjectVersion} will write a Version instantiation that - includes a prerelease parameter if necessary. - """ - replaceProjectVersion("twisted.test_project", - "test_project", Version("whatever", 0, 82, 7, - prerelease=8)) - ns = {'__name___': 'twisted.test_project'} - execfile("test_project", ns) - self.assertEquals(ns["version"].base(), "0.82.7pre8") - - - -class BuilderTestsMixin(object): - """ - A mixin class which provides various methods for creating sample Lore input - and output. - - @cvar template: The lore template that will be used to prepare sample - output. - @type template: C{str} - - @ivar docCounter: A counter which is incremented every time input is - generated and which is included in the documents. - @type docCounter: C{int} - """ - template = ''' - - Yo: - -
                  - Index - Version: - - - ''' - - def setUp(self): - """ - Initialize the doc counter which ensures documents are unique. - """ - self.docCounter = 0 - - - def getArbitraryOutput(self, version, counter, prefix=""): - """ - Get the correct HTML output for the arbitrary input returned by - L{getArbitraryLoreInput} for the given parameters. - - @param version: The version string to include in the output. - @type version: C{str} - @param counter: A counter to include in the output. - @type counter: C{int} - """ - document = ('' - 'Yo:Hi! Title: %(count)s' - '
                  Hi! %(count)s' - '
                  ' - 'IndexVersion: %(version)s' - '') - return document % {"count": counter, "prefix": prefix, - "version": version} - - - def getArbitraryLoreInput(self, counter): - """ - Get an arbitrary, unique (for this test case) string of lore input. - - @param counter: A counter to include in the input. - @type counter: C{int} - """ - template = ( - '' - 'Hi! Title: %(count)s' - '' - 'Hi! %(count)s' - '
                  foobar
                  ' - '' - '') - return template % {"count": counter} - - - def getArbitraryLoreInputAndOutput(self, version, prefix=""): - """ - Get an input document along with expected output for lore run on that - output document, assuming an appropriately-specified C{self.template}. - - @param version: A version string to include in the input and output. - @type version: C{str} - @param prefix: The prefix to include in the link to the index. - @type prefix: C{str} - - @return: A two-tuple of input and expected output. - @rtype: C{(str, str)}. - """ - self.docCounter += 1 - return (self.getArbitraryLoreInput(self.docCounter), - self.getArbitraryOutput(version, self.docCounter, - prefix=prefix)) - - - def getArbitraryManInput(self): - """ - Get an arbitrary man page content. - """ - return """.TH MANHOLE "1" "August 2001" "" "" -.SH NAME -manhole \- Connect to a Twisted Manhole service -.SH SYNOPSIS -.B manhole -.SH DESCRIPTION -manhole is a GTK interface to Twisted Manhole services. You can execute python -code as if at an interactive Python console inside a running Twisted process -with this.""" - - - def getArbitraryManLoreOutput(self): - """ - Get an arbitrary lore input document which represents man-to-lore - output based on the man page returned from L{getArbitraryManInput} - """ - return ("\nMANHOLE.1" - "\n\n\n

                  MANHOLE.1

                  \n\n

                  NAME

                  \n\n" - "

                  manhole - Connect to a Twisted Manhole service\n

                  \n\n" - "

                  SYNOPSIS

                  \n\n

                  manhole

                  \n\n" - "

                  DESCRIPTION

                  \n\n

                  manhole is a GTK interface to Twisted " - "Manhole services. You can execute python\ncode as if at an " - "interactive Python console inside a running Twisted process\nwith" - " this.

                  \n\n\n\n") - - - def getArbitraryManHTMLOutput(self, version, prefix=""): - """ - Get an arbitrary lore output document which represents the lore HTML - output based on the input document returned from - L{getArbitraryManLoreOutput}. - - @param version: A version string to include in the document. - @type version: C{str} - @param prefix: The prefix to include in the link to the index. - @type prefix: C{str} - """ - return ('' - 'Yo:MANHOLE.1
                  ' - '

                  NAME

                  manhole - ' - 'Connect to a Twisted Manhole service\n

                  SYNOPSIS

                  manhole

                  ' - 'DESCRIPTION

                  manhole is a GTK ' - 'interface to Twisted Manhole services. You can execute ' - 'python\ncode as if at an interactive Python console inside a ' - 'running Twisted process\nwith this.

                  IndexVersion: ' - '%s' % (prefix, version)) - - - - -class DocBuilderTestCase(TestCase, BuilderTestsMixin): - """ - Tests for L{DocBuilder}. - - Note for future maintainers: The exact byte equality assertions throughout - this suite may need to be updated due to minor differences in lore. They - should not be taken to mean that Lore must maintain the same byte format - forever. Feel free to update the tests when Lore changes, but please be - careful. - """ - - def setUp(self): - """ - Set up a few instance variables that will be useful. - - @ivar builder: A plain L{DocBuilder}. - @ivar docCounter: An integer to be used as a counter by the - C{getArbitrary...} methods. - @ivar howtoDir: A L{FilePath} representing a directory to be used for - containing Lore documents. - @ivar templateFile: A L{FilePath} representing a file with - C{self.template} as its content. - """ - BuilderTestsMixin.setUp(self) - self.builder = DocBuilder() - self.howtoDir = FilePath(self.mktemp()) - self.howtoDir.createDirectory() - self.templateFile = self.howtoDir.child("template.tpl") - self.templateFile.setContent(self.template) - - - def test_build(self): - """ - The L{DocBuilder} runs lore on all .xhtml files within a directory. - """ - version = "1.2.3" - input1, output1 = self.getArbitraryLoreInputAndOutput(version) - input2, output2 = self.getArbitraryLoreInputAndOutput(version) - - self.howtoDir.child("one.xhtml").setContent(input1) - self.howtoDir.child("two.xhtml").setContent(input2) - - self.builder.build(version, self.howtoDir, self.howtoDir, - self.templateFile) - out1 = self.howtoDir.child('one.html') - out2 = self.howtoDir.child('two.html') - self.assertEquals(out1.getContent(), output1) - self.assertEquals(out2.getContent(), output2) - - - def test_noDocumentsFound(self): - """ - The C{build} method raises L{NoDocumentsFound} if there are no - .xhtml files in the given directory. - """ - self.assertRaises( - NoDocumentsFound, - self.builder.build, "1.2.3", self.howtoDir, self.howtoDir, - self.templateFile) - - - def test_parentDocumentLinking(self): - """ - The L{DocBuilder} generates correct links from documents to - template-generated links like stylesheets and index backreferences. - """ - input = self.getArbitraryLoreInput(0) - tutoDir = self.howtoDir.child("tutorial") - tutoDir.createDirectory() - tutoDir.child("child.xhtml").setContent(input) - self.builder.build("1.2.3", self.howtoDir, tutoDir, self.templateFile) - outFile = tutoDir.child('child.html') - self.assertIn('Index', - outFile.getContent()) - - - def test_siblingDirectoryDocumentLinking(self): - """ - It is necessary to generate documentation in a directory foo/bar where - stylesheet and indexes are located in foo/baz. Such resources should be - appropriately linked to. - """ - input = self.getArbitraryLoreInput(0) - resourceDir = self.howtoDir.child("resources") - docDir = self.howtoDir.child("docs") - docDir.createDirectory() - docDir.child("child.xhtml").setContent(input) - self.builder.build("1.2.3", resourceDir, docDir, self.templateFile) - outFile = docDir.child('child.html') - self.assertIn('Index', - outFile.getContent()) - - - def test_apiLinking(self): - """ - The L{DocBuilder} generates correct links from documents to API - documentation. - """ - version = "1.2.3" - input, output = self.getArbitraryLoreInputAndOutput(version) - self.howtoDir.child("one.xhtml").setContent(input) - - self.builder.build(version, self.howtoDir, self.howtoDir, - self.templateFile, "scheme:apilinks/%s.ext") - out = self.howtoDir.child('one.html') - self.assertIn( - 'foobar', - out.getContent()) - - - def test_deleteInput(self): - """ - L{DocBuilder.build} can be instructed to delete the input files after - generating the output based on them. - """ - input1 = self.getArbitraryLoreInput(0) - self.howtoDir.child("one.xhtml").setContent(input1) - self.builder.build("whatever", self.howtoDir, self.howtoDir, - self.templateFile, deleteInput=True) - self.assertTrue(self.howtoDir.child('one.html').exists()) - self.assertFalse(self.howtoDir.child('one.xhtml').exists()) - - - def test_doNotDeleteInput(self): - """ - Input will not be deleted by default. - """ - input1 = self.getArbitraryLoreInput(0) - self.howtoDir.child("one.xhtml").setContent(input1) - self.builder.build("whatever", self.howtoDir, self.howtoDir, - self.templateFile) - self.assertTrue(self.howtoDir.child('one.html').exists()) - self.assertTrue(self.howtoDir.child('one.xhtml').exists()) - - - def test_getLinkrelToSameDirectory(self): - """ - If the doc and resource directories are the same, the linkrel should be - an empty string. - """ - linkrel = self.builder.getLinkrel(FilePath("/foo/bar"), - FilePath("/foo/bar")) - self.assertEquals(linkrel, "") - - - def test_getLinkrelToParentDirectory(self): - """ - If the doc directory is a child of the resource directory, the linkrel - should make use of '..'. - """ - linkrel = self.builder.getLinkrel(FilePath("/foo"), - FilePath("/foo/bar")) - self.assertEquals(linkrel, "../") - - - def test_getLinkrelToSibling(self): - """ - If the doc directory is a sibling of the resource directory, the - linkrel should make use of '..' and a named segment. - """ - linkrel = self.builder.getLinkrel(FilePath("/foo/howto"), - FilePath("/foo/examples")) - self.assertEquals(linkrel, "../howto/") - - - def test_getLinkrelToUncle(self): - """ - If the doc directory is a sibling of the parent of the resource - directory, the linkrel should make use of multiple '..'s and a named - segment. - """ - linkrel = self.builder.getLinkrel(FilePath("/foo/howto"), - FilePath("/foo/examples/quotes")) - self.assertEquals(linkrel, "../../howto/") - - - -class APIBuilderTestCase(TestCase): - """ - Tests for L{APIBuilder}. - """ - if pydoctor is None or getattr(pydoctor, "version_info", (0,)) < (0, 1): - skip = "APIBuilder requires Pydoctor 0.1 or newer" - - def test_build(self): - """ - L{APIBuilder.build} writes an index file which includes the name of the - project specified. - """ - stdout = StringIO() - self.patch(sys, 'stdout', stdout) - - projectName = "Foobar" - packageName = "quux" - projectURL = "scheme:project" - sourceURL = "scheme:source" - docstring = "text in docstring" - badDocstring = "should not appear in output" - - inputPath = FilePath(self.mktemp()).child(packageName) - inputPath.makedirs() - inputPath.child("__init__.py").setContent( - "def foo():\n" - " '%s'\n" - "def _bar():\n" - " '%s'" % (docstring, badDocstring)) - - outputPath = FilePath(self.mktemp()) - outputPath.makedirs() - - builder = APIBuilder() - builder.build(projectName, projectURL, sourceURL, inputPath, outputPath) - - indexPath = outputPath.child("index.html") - self.assertTrue( - indexPath.exists(), - "API index %r did not exist." % (outputPath.path,)) - self.assertIn( - '%s' % (projectURL, projectName), - indexPath.getContent(), - "Project name/location not in file contents.") - - quuxPath = outputPath.child("quux.html") - self.assertTrue( - quuxPath.exists(), - "Package documentation file %r did not exist." % (quuxPath.path,)) - self.assertIn( - docstring, quuxPath.getContent(), - "Docstring not in package documentation file.") - self.assertIn( - 'View Source' % (sourceURL, packageName), - quuxPath.getContent()) - self.assertIn( - 'View Source' % (sourceURL, packageName), - quuxPath.getContent()) - self.assertIn( - '' % ( - sourceURL, packageName), - quuxPath.getContent()) - self.assertNotIn(badDocstring, quuxPath.getContent()) - - self.assertEqual(stdout.getvalue(), '') - - - -class ManBuilderTestCase(TestCase, BuilderTestsMixin): - """ - Tests for L{ManBuilder}. - """ - - def setUp(self): - """ - Set up a few instance variables that will be useful. - - @ivar builder: A plain L{ManBuilder}. - @ivar manDir: A L{FilePath} representing a directory to be used for - containing man pages. - """ - BuilderTestsMixin.setUp(self) - self.builder = ManBuilder() - self.manDir = FilePath(self.mktemp()) - self.manDir.createDirectory() - - - def test_noDocumentsFound(self): - """ - L{ManBuilder.build} raises L{NoDocumentsFound} if there are no - .1 files in the given directory. - """ - self.assertRaises(NoDocumentsFound, self.builder.build, self.manDir) - - - def test_build(self): - """ - Check that L{ManBuilder.build} find the man page in the directory, and - successfully produce a Lore content. - """ - manContent = self.getArbitraryManInput() - self.manDir.child('test1.1').setContent(manContent) - self.builder.build(self.manDir) - output = self.manDir.child('test1-man.xhtml').getContent() - expected = self.getArbitraryManLoreOutput() - # No-op on *nix, fix for windows - expected = expected.replace('\n', os.linesep) - self.assertEquals(output, expected) - - - def test_toHTML(self): - """ - Check that the content output by C{build} is compatible as input of - L{DocBuilder.build}. - """ - manContent = self.getArbitraryManInput() - self.manDir.child('test1.1').setContent(manContent) - self.builder.build(self.manDir) - - templateFile = self.manDir.child("template.tpl") - templateFile.setContent(DocBuilderTestCase.template) - docBuilder = DocBuilder() - docBuilder.build("1.2.3", self.manDir, self.manDir, - templateFile) - output = self.manDir.child('test1-man.html').getContent() - self.assertEquals(output, '' - 'Yo:MANHOLE.1
                  ' - '

                  NAME

                  manhole - ' - 'Connect to a Twisted Manhole service\n

                  SYNOPSIS

                  manhole

                  ' - 'DESCRIPTION

                  manhole is a GTK ' - 'interface to Twisted Manhole services. You can execute ' - 'python\ncode as if at an interactive Python console inside a ' - 'running Twisted process\nwith this.

                  IndexVersion: ' - '1.2.3') - - - -class BookBuilderTests(TestCase, BuilderTestsMixin): - """ - Tests for L{BookBuilder}. - """ - if not (which("latex") and which("dvips") and which("ps2pdf13")): - skip = "Book Builder tests require latex." - try: - from popen2 import Popen4 - except ImportError: - skip = "Book Builder requires popen2.Popen4." - else: - del Popen4 - - def setUp(self): - """ - Make a directory into which to place temporary files. - """ - self.docCounter = 0 - self.howtoDir = FilePath(self.mktemp()) - self.howtoDir.makedirs() - - - def getArbitraryOutput(self, version, counter, prefix=""): - """ - Create and return a C{str} containing the LaTeX document which is - expected as the output for processing the result of the document - returned by C{self.getArbitraryLoreInput(counter)}. - """ - path = self.howtoDir.child("%d.xhtml" % (counter,)).path - path = path[len(os.getcwd()) + 1:] - return ( - r'\section{Hi! Title: %(count)s\label{%(path)s}}' - '\n' - r'Hi! %(count)sfoobar') % {'count': counter, 'path': path} - - - def test_runSuccess(self): - """ - L{BookBuilder.run} executes the command it is passed and returns a - string giving the stdout and stderr of the command if it completes - successfully. - """ - builder = BookBuilder() - self.assertEqual(builder.run("echo hi; echo bye 1>&2"), "hi\nbye\n") - - - def test_runFailed(self): - """ - L{BookBuilder.run} executes the command it is passed and raises - L{CommandFailed} if it completes unsuccessfully. - """ - builder = BookBuilder() - exc = self.assertRaises(CommandFailed, builder.run, "echo hi; false") - self.assertNotEqual(os.WEXITSTATUS(exc.exitCode), 0) - self.assertEqual(exc.output, "hi\n") - - - def test_runSignaled(self): - """ - L{BookBuilder.run} executes the command it is passed and raises - L{CommandFailed} if it exits due to a signal. - """ - builder = BookBuilder() - exc = self.assertRaises( - # This is only a little bit too tricky. - CommandFailed, builder.run, "echo hi; exec kill -9 $$") - self.assertTrue(os.WIFSIGNALED(exc.exitCode)) - self.assertEqual(os.WTERMSIG(exc.exitCode), signal.SIGKILL) - self.assertEqual(exc.output, "hi\n") - - - def test_buildTeX(self): - """ - L{BookBuilder.buildTeX} writes intermediate TeX files for all lore - input files in a directory. - """ - version = "3.2.1" - input1, output1 = self.getArbitraryLoreInputAndOutput(version) - input2, output2 = self.getArbitraryLoreInputAndOutput(version) - - # Filenames are chosen by getArbitraryOutput to match the counter used - # by getArbitraryLoreInputAndOutput. - self.howtoDir.child("1.xhtml").setContent(input1) - self.howtoDir.child("2.xhtml").setContent(input2) - - builder = BookBuilder() - builder.buildTeX(self.howtoDir) - self.assertEqual(self.howtoDir.child("1.tex").getContent(), output1) - self.assertEqual(self.howtoDir.child("2.tex").getContent(), output2) - - - def test_buildTeXRejectsInvalidDirectory(self): - """ - L{BookBuilder.buildTeX} raises L{ValueError} if passed a directory - which does not exist. - """ - builder = BookBuilder() - self.assertRaises( - ValueError, builder.buildTeX, self.howtoDir.temporarySibling()) - - - def test_buildTeXOnlyBuildsXHTML(self): - """ - L{BookBuilder.buildTeX} ignores files which which don't end with - ".xhtml". - """ - # Hopefully ">" is always a parse error from microdom! - self.howtoDir.child("not-input.dat").setContent(">") - self.test_buildTeX() - - - def test_stdout(self): - """ - L{BookBuilder.buildTeX} does not write to stdout. - """ - stdout = StringIO() - self.patch(sys, 'stdout', stdout) - - # Suppress warnings so that if there are any old-style plugins that - # lore queries for don't confuse the assertion below. See #3070. - self.patch(warnings, 'warn', lambda *a, **kw: None) - self.test_buildTeX() - self.assertEqual(stdout.getvalue(), '') - - - def test_buildPDFRejectsInvalidBookFilename(self): - """ - L{BookBuilder.buildPDF} raises L{ValueError} if the book filename does - not end with ".tex". - """ - builder = BookBuilder() - self.assertRaises( - ValueError, - builder.buildPDF, - FilePath(self.mktemp()).child("foo"), - None, - None) - - - def _setupTeXFiles(self): - sections = range(3) - self._setupTeXSections(sections) - return self._setupTeXBook(sections) - - - def _setupTeXSections(self, sections): - for texSectionNumber in sections: - texPath = self.howtoDir.child("%d.tex" % (texSectionNumber,)) - texPath.setContent(self.getArbitraryOutput( - "1.2.3", texSectionNumber)) - - - def _setupTeXBook(self, sections): - bookTeX = self.howtoDir.child("book.tex") - bookTeX.setContent( - r"\documentclass{book}" "\n" - r"\begin{document}" "\n" + - "\n".join([r"\input{%d.tex}" % (n,) for n in sections]) + - r"\end{document}" "\n") - return bookTeX - - - def test_buildPDF(self): - """ - L{BookBuilder.buildPDF} creates a PDF given an index tex file and a - directory containing .tex files. - """ - bookPath = self._setupTeXFiles() - outputPath = FilePath(self.mktemp()) - - builder = BookBuilder() - builder.buildPDF(bookPath, self.howtoDir, outputPath) - - self.assertTrue(outputPath.exists()) - - - def test_buildPDFLongPath(self): - """ - L{BookBuilder.buildPDF} succeeds even if the paths it is operating on - are very long. - - C{ps2pdf13} seems to have problems when path names are long. This test - verifies that even if inputs have long paths, generation still - succeeds. - """ - # Make it long. - self.howtoDir = self.howtoDir.child("x" * 128).child("x" * 128).child("x" * 128) - self.howtoDir.makedirs() - - # This will use the above long path. - bookPath = self._setupTeXFiles() - outputPath = FilePath(self.mktemp()) - - builder = BookBuilder() - builder.buildPDF(bookPath, self.howtoDir, outputPath) - - self.assertTrue(outputPath.exists()) - - - def test_buildPDFRunsLaTeXThreeTimes(self): - """ - L{BookBuilder.buildPDF} runs C{latex} three times. - """ - class InspectableBookBuilder(BookBuilder): - def __init__(self): - BookBuilder.__init__(self) - self.commands = [] - - def run(self, command): - """ - Record the command and then execute it. - """ - self.commands.append(command) - return BookBuilder.run(self, command) - - bookPath = self._setupTeXFiles() - outputPath = FilePath(self.mktemp()) - - builder = InspectableBookBuilder() - builder.buildPDF(bookPath, self.howtoDir, outputPath) - - # These string comparisons are very fragile. It would be better to - # have a test which asserted the correctness of the contents of the - # output files. I don't know how one could do that, though. -exarkun - latex1, latex2, latex3, dvips, ps2pdf13 = builder.commands - self.assertEqual(latex1, latex2) - self.assertEqual(latex2, latex3) - self.assertTrue( - latex1.startswith("latex "), - "LaTeX command %r does not start with 'latex '" % (latex1,)) - self.assertTrue( - latex1.endswith(" " + bookPath.path), - "LaTeX command %r does not end with the book path (%r)." % ( - latex1, bookPath.path)) - - self.assertTrue( - dvips.startswith("dvips "), - "dvips command %r does not start with 'dvips '" % (dvips,)) - self.assertTrue( - ps2pdf13.startswith("ps2pdf13 "), - "ps2pdf13 command %r does not start with 'ps2pdf13 '" % ( - ps2pdf13,)) - - - def test_noSideEffects(self): - """ - The working directory is the same before and after a call to - L{BookBuilder.buildPDF}. Also the contents of the directory containing - the input book are the same before and after the call. - """ - startDir = os.getcwd() - bookTeX = self._setupTeXFiles() - startTeXSiblings = bookTeX.parent().children() - startHowtoChildren = self.howtoDir.children() - - builder = BookBuilder() - builder.buildPDF(bookTeX, self.howtoDir, FilePath(self.mktemp())) - - self.assertEqual(startDir, os.getcwd()) - self.assertEqual(startTeXSiblings, bookTeX.parent().children()) - self.assertEqual(startHowtoChildren, self.howtoDir.children()) - - - def test_failedCommandProvidesOutput(self): - """ - If a subprocess fails, L{BookBuilder.buildPDF} raises L{CommandFailed} - with the subprocess's output and leaves the temporary directory as a - sibling of the book path. - """ - bookTeX = FilePath(self.mktemp() + ".tex") - builder = BookBuilder() - inputState = bookTeX.parent().children() - exc = self.assertRaises( - CommandFailed, - builder.buildPDF, - bookTeX, self.howtoDir, FilePath(self.mktemp())) - self.assertTrue(exc.output) - newOutputState = set(bookTeX.parent().children()) - set(inputState) - self.assertEqual(len(newOutputState), 1) - workPath = newOutputState.pop() - self.assertTrue( - workPath.isdir(), - "Expected work path %r was not a directory." % (workPath.path,)) - - - def test_build(self): - """ - L{BookBuilder.build} generates a pdf book file from some lore input - files. - """ - sections = range(1, 4) - for sectionNumber in sections: - self.howtoDir.child("%d.xhtml" % (sectionNumber,)).setContent( - self.getArbitraryLoreInput(sectionNumber)) - bookTeX = self._setupTeXBook(sections) - bookPDF = FilePath(self.mktemp()) - - builder = BookBuilder() - builder.build(self.howtoDir, [self.howtoDir], bookTeX, bookPDF) - - self.assertTrue(bookPDF.exists()) - - - def test_buildRemovesTemporaryLaTeXFiles(self): - """ - L{BookBuilder.build} removes the intermediate LaTeX files it creates. - """ - sections = range(1, 4) - for sectionNumber in sections: - self.howtoDir.child("%d.xhtml" % (sectionNumber,)).setContent( - self.getArbitraryLoreInput(sectionNumber)) - bookTeX = self._setupTeXBook(sections) - bookPDF = FilePath(self.mktemp()) - - builder = BookBuilder() - builder.build(self.howtoDir, [self.howtoDir], bookTeX, bookPDF) - - self.assertEqual( - set(self.howtoDir.listdir()), - set([bookTeX.basename()] + ["%d.xhtml" % (n,) for n in sections])) - - - -class FilePathDeltaTest(TestCase): - """ - Tests for L{filePathDelta}. - """ - - def test_filePathDeltaSubdir(self): - """ - L{filePathDelta} can create a simple relative path to a child path. - """ - self.assertEquals(filePathDelta(FilePath("/foo/bar"), - FilePath("/foo/bar/baz")), - ["baz"]) - - - def test_filePathDeltaSiblingDir(self): - """ - L{filePathDelta} can traverse upwards to create relative paths to - siblings. - """ - self.assertEquals(filePathDelta(FilePath("/foo/bar"), - FilePath("/foo/baz")), - ["..", "baz"]) - - - def test_filePathNoCommonElements(self): - """ - L{filePathDelta} can create relative paths to totally unrelated paths - for maximum portability. - """ - self.assertEquals(filePathDelta(FilePath("/foo/bar"), - FilePath("/baz/quux")), - ["..", "..", "baz", "quux"]) - - - -class DistributionBuilderTests(BuilderTestsMixin, TestCase): - """ - Tests for L{DistributionBuilder}. - """ - - def setUp(self): - BuilderTestsMixin.setUp(self) - - self.rootDir = FilePath(self.mktemp()) - self.rootDir.createDirectory() - - outputDir = FilePath(self.mktemp()) - outputDir.createDirectory() - self.builder = DistributionBuilder(self.rootDir, outputDir) - - - def createStructure(self, root, dirDict): - """ - Create a set of directories and files given a dict defining their - structure. - - @param root: The directory in which to create the structure. - @type root: L{FilePath} - - @param dirDict: The dict defining the structure. Keys should be strings - naming files, values should be strings describing file contents OR - dicts describing subdirectories. For example: C{{"foofile": - "foocontents", "bardir": {"barfile": "barcontents"}}} - @type dirDict: C{dict} - """ - for x in dirDict: - child = root.child(x) - if isinstance(dirDict[x], dict): - child.createDirectory() - self.createStructure(child, dirDict[x]) - else: - child.setContent(dirDict[x]) - - - def assertExtractedStructure(self, outputFile, dirDict): - """ - Assert that a tarfile content is equivalent to one described by a dict. - - @param outputFile: The tar file built by L{DistributionBuilder}. - @type outputFile: L{FilePath}. - @param dirDict: The dict that should describe the contents of the - directory. It should be the same structure as the C{dirDict} - parameter to L{createStructure}. - @type dirDict: C{dict} - """ - tarFile = tarfile.TarFile.open(outputFile.path, "r:bz2") - extracted = FilePath(self.mktemp()) - extracted.createDirectory() - for info in tarFile: - tarFile.extract(info, path=extracted.path) - self.assertStructure(extracted.children()[0], dirDict) - - - def assertStructure(self, root, dirDict): - """ - Assert that a directory is equivalent to one described by a dict. - - @param root: The filesystem directory to compare. - @type root: L{FilePath} - @param dirDict: The dict that should describe the contents of the - directory. It should be the same structure as the C{dirDict} - parameter to L{createStructure}. - @type dirDict: C{dict} - """ - children = [x.basename() for x in root.children()] - for x in dirDict: - child = root.child(x) - if isinstance(dirDict[x], dict): - self.assertTrue(child.isdir(), "%s is not a dir!" - % (child.path,)) - self.assertStructure(child, dirDict[x]) - else: - a = child.getContent() - self.assertEquals(a, dirDict[x], child.path) - children.remove(x) - if children: - self.fail("There were extra children in %s: %s" - % (root.path, children)) - - - def test_twistedDistribution(self): - """ - The Twisted tarball contains everything in the source checkout, with - built documentation. - """ - loreInput, loreOutput = self.getArbitraryLoreInputAndOutput("10.0.0") - manInput1 = self.getArbitraryManInput() - manOutput1 = self.getArbitraryManHTMLOutput("10.0.0", "../howto/") - manInput2 = self.getArbitraryManInput() - manOutput2 = self.getArbitraryManHTMLOutput("10.0.0", "../howto/") - coreIndexInput, coreIndexOutput = self.getArbitraryLoreInputAndOutput( - "10.0.0", prefix="howto/") - - structure = { - "README": "Twisted", - "unrelated": "x", - "LICENSE": "copyright!", - "setup.py": "import toplevel", - "bin": {"web": {"websetroot": "SET ROOT"}, - "twistd": "TWISTD"}, - "twisted": - {"web": - {"__init__.py": "import WEB", - "topfiles": {"setup.py": "import WEBINSTALL", - "README": "WEB!"}}, - "words": {"__init__.py": "import WORDS"}, - "plugins": {"twisted_web.py": "import WEBPLUG", - "twisted_words.py": "import WORDPLUG"}}, - "doc": {"web": {"howto": {"index.xhtml": loreInput}, - "man": {"websetroot.1": manInput2}}, - "core": {"howto": {"template.tpl": self.template}, - "man": {"twistd.1": manInput1}, - "index.xhtml": coreIndexInput}}} - - outStructure = { - "README": "Twisted", - "unrelated": "x", - "LICENSE": "copyright!", - "setup.py": "import toplevel", - "bin": {"web": {"websetroot": "SET ROOT"}, - "twistd": "TWISTD"}, - "twisted": - {"web": {"__init__.py": "import WEB", - "topfiles": {"setup.py": "import WEBINSTALL", - "README": "WEB!"}}, - "words": {"__init__.py": "import WORDS"}, - "plugins": {"twisted_web.py": "import WEBPLUG", - "twisted_words.py": "import WORDPLUG"}}, - "doc": {"web": {"howto": {"index.html": loreOutput}, - "man": {"websetroot.1": manInput2, - "websetroot-man.html": manOutput2}}, - "core": {"howto": {"template.tpl": self.template}, - "man": {"twistd.1": manInput1, - "twistd-man.html": manOutput1}, - "index.html": coreIndexOutput}}} - - self.createStructure(self.rootDir, structure) - - outputFile = self.builder.buildTwisted("10.0.0") - - self.assertExtractedStructure(outputFile, outStructure) - - def test_twistedDistributionExcludesWeb2AndVFS(self): - """ - The main Twisted distribution does not include web2 or vfs. - """ - loreInput, loreOutput = self.getArbitraryLoreInputAndOutput("10.0.0") - coreIndexInput, coreIndexOutput = self.getArbitraryLoreInputAndOutput( - "10.0.0", prefix="howto/") - - structure = { - "README": "Twisted", - "unrelated": "x", - "LICENSE": "copyright!", - "setup.py": "import toplevel", - "bin": {"web2": {"websetroot": "SET ROOT"}, - "vfs": {"vfsitup": "hee hee"}, - "twistd": "TWISTD"}, - "twisted": - {"web2": - {"__init__.py": "import WEB", - "topfiles": {"setup.py": "import WEBINSTALL", - "README": "WEB!"}}, - "vfs": - {"__init__.py": "import VFS", - "blah blah": "blah blah"}, - "words": {"__init__.py": "import WORDS"}, - "plugins": {"twisted_web.py": "import WEBPLUG", - "twisted_words.py": "import WORDPLUG", - "twisted_web2.py": "import WEB2", - "twisted_vfs.py": "import VFS"}}, - "doc": {"web2": {"excluded!": "yay"}, - "vfs": {"unrelated": "whatever"}, - "core": {"howto": {"template.tpl": self.template}, - "index.xhtml": coreIndexInput}}} - - outStructure = { - "README": "Twisted", - "unrelated": "x", - "LICENSE": "copyright!", - "setup.py": "import toplevel", - "bin": {"twistd": "TWISTD"}, - "twisted": - {"words": {"__init__.py": "import WORDS"}, - "plugins": {"twisted_web.py": "import WEBPLUG", - "twisted_words.py": "import WORDPLUG"}}, - "doc": {"core": {"howto": {"template.tpl": self.template}, - "index.html": coreIndexOutput}}} - self.createStructure(self.rootDir, structure) - - outputFile = self.builder.buildTwisted("10.0.0") - - self.assertExtractedStructure(outputFile, outStructure) - - - def test_subProjectLayout(self): - """ - The subproject tarball includes files like so: - - 1. twisted//topfiles defines the files that will be in the - top level in the tarball, except LICENSE, which comes from the real - top-level directory. - 2. twisted/ is included, but without the topfiles entry - in that directory. No other twisted subpackages are included. - 3. twisted/plugins/twisted_.py is included, but nothing - else in plugins is. - """ - structure = { - "README": "HI!@", - "unrelated": "x", - "LICENSE": "copyright!", - "setup.py": "import toplevel", - "bin": {"web": {"websetroot": "SET ROOT"}, - "words": {"im": "#!im"}}, - "twisted": - {"web": - {"__init__.py": "import WEB", - "topfiles": {"setup.py": "import WEBINSTALL", - "README": "WEB!"}}, - "words": {"__init__.py": "import WORDS"}, - "plugins": {"twisted_web.py": "import WEBPLUG", - "twisted_words.py": "import WORDPLUG"}}} - - outStructure = { - "README": "WEB!", - "LICENSE": "copyright!", - "setup.py": "import WEBINSTALL", - "bin": {"websetroot": "SET ROOT"}, - "twisted": {"web": {"__init__.py": "import WEB"}, - "plugins": {"twisted_web.py": "import WEBPLUG"}}} - - self.createStructure(self.rootDir, structure) - - outputFile = self.builder.buildSubProject("web", "0.3.0") - - self.assertExtractedStructure(outputFile, outStructure) - - - def test_minimalSubProjectLayout(self): - """ - buildSubProject should work with minimal subprojects. - """ - structure = { - "LICENSE": "copyright!", - "bin": {}, - "twisted": - {"web": {"__init__.py": "import WEB", - "topfiles": {"setup.py": "import WEBINSTALL"}}, - "plugins": {}}} - - outStructure = { - "setup.py": "import WEBINSTALL", - "LICENSE": "copyright!", - "twisted": {"web": {"__init__.py": "import WEB"}}} - - self.createStructure(self.rootDir, structure) - - outputFile = self.builder.buildSubProject("web", "0.3.0") - - self.assertExtractedStructure(outputFile, outStructure) - - - def test_subProjectDocBuilding(self): - """ - When building a subproject release, documentation should be built with - lore. - """ - loreInput, loreOutput = self.getArbitraryLoreInputAndOutput("0.3.0") - manInput = self.getArbitraryManInput() - manOutput = self.getArbitraryManHTMLOutput("0.3.0", "../howto/") - structure = { - "LICENSE": "copyright!", - "twisted": {"web": {"__init__.py": "import WEB", - "topfiles": {"setup.py": "import WEBINST"}}}, - "doc": {"web": {"howto": {"index.xhtml": loreInput}, - "man": {"twistd.1": manInput}}, - "core": {"howto": {"template.tpl": self.template}} - } - } - - outStructure = { - "LICENSE": "copyright!", - "setup.py": "import WEBINST", - "twisted": {"web": {"__init__.py": "import WEB"}}, - "doc": {"howto": {"index.html": loreOutput}, - "man": {"twistd.1": manInput, - "twistd-man.html": manOutput}}} - - self.createStructure(self.rootDir, structure) - - outputFile = self.builder.buildSubProject("web", "0.3.0") - - self.assertExtractedStructure(outputFile, outStructure) - - - def test_coreProjectLayout(self): - """ - The core tarball looks a lot like a subproject tarball, except it - doesn't include: - - - Python packages from other subprojects - - plugins from other subprojects - - scripts from other subprojects - """ - indexInput, indexOutput = self.getArbitraryLoreInputAndOutput( - "8.0.0", prefix="howto/") - howtoInput, howtoOutput = self.getArbitraryLoreInputAndOutput("8.0.0") - specInput, specOutput = self.getArbitraryLoreInputAndOutput( - "8.0.0", prefix="../howto/") - upgradeInput, upgradeOutput = self.getArbitraryLoreInputAndOutput( - "8.0.0", prefix="../howto/") - tutorialInput, tutorialOutput = self.getArbitraryLoreInputAndOutput( - "8.0.0", prefix="../") - - structure = { - "LICENSE": "copyright!", - "twisted": {"__init__.py": "twisted", - "python": {"__init__.py": "python", - "roots.py": "roots!"}, - "conch": {"__init__.py": "conch", - "unrelated.py": "import conch"}, - "plugin.py": "plugin", - "plugins": {"twisted_web.py": "webplug", - "twisted_whatever.py": "include!", - "cred.py": "include!"}, - "topfiles": {"setup.py": "import CORE", - "README": "core readme"}}, - "doc": {"core": {"howto": {"template.tpl": self.template, - "index.xhtml": howtoInput, - "tutorial": - {"index.xhtml": tutorialInput}}, - "specifications": {"index.xhtml": specInput}, - "upgrades": {"index.xhtml": upgradeInput}, - "examples": {"foo.py": "foo.py"}, - "index.xhtml": indexInput}, - "web": {"howto": {"index.xhtml": "webindex"}}}, - "bin": {"twistd": "TWISTD", - "web": {"websetroot": "websetroot"}} - } - - outStructure = { - "LICENSE": "copyright!", - "setup.py": "import CORE", - "README": "core readme", - "twisted": {"__init__.py": "twisted", - "python": {"__init__.py": "python", - "roots.py": "roots!"}, - "plugin.py": "plugin", - "plugins": {"twisted_whatever.py": "include!", - "cred.py": "include!"}}, - "doc": {"howto": {"template.tpl": self.template, - "index.html": howtoOutput, - "tutorial": {"index.html": tutorialOutput}}, - "specifications": {"index.html": specOutput}, - "upgrades": {"index.html": upgradeOutput}, - "examples": {"foo.py": "foo.py"}, - "index.html": indexOutput}, - "bin": {"twistd": "TWISTD"}, - } - - self.createStructure(self.rootDir, structure) - - outputFile = self.builder.buildCore("8.0.0") - - self.assertExtractedStructure(outputFile, outStructure) - - - -if lore is None: - skipMessage = "Lore is not present." - BookBuilderTests.skip = skipMessage - DocBuilderTestCase.skip = skipMessage - ManBuilderTestCase.skip = skipMessage - DistributionBuilderTests.skip = skipMessage diff --git a/tools/buildbot/pylibs/twisted/python/test/test_util.py b/tools/buildbot/pylibs/twisted/python/test/test_util.py deleted file mode 100644 index a680d82..0000000 --- a/tools/buildbot/pylibs/twisted/python/test/test_util.py +++ /dev/null @@ -1,597 +0,0 @@ -# -*- test-case-name: twisted.test.test_util -*- -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -import os.path, sys -import shutil, errno -try: - import pwd, grp -except ImportError: - pwd = grp = None - -from twisted.trial import unittest - -from twisted.python import util -from twisted.internet import reactor -from twisted.internet.interfaces import IReactorProcess -from twisted.internet.protocol import ProcessProtocol -from twisted.internet.defer import Deferred -from twisted.internet.error import ProcessDone - - -class UtilTestCase(unittest.TestCase): - - def testUniq(self): - l = ["a", 1, "ab", "a", 3, 4, 1, 2, 2, 4, 6] - self.assertEquals(util.uniquify(l), ["a", 1, "ab", 3, 4, 2, 6]) - - def testRaises(self): - self.failUnless(util.raises(ZeroDivisionError, divmod, 1, 0)) - self.failIf(util.raises(ZeroDivisionError, divmod, 0, 1)) - - try: - util.raises(TypeError, divmod, 1, 0) - except ZeroDivisionError: - pass - else: - raise unittest.FailTest, "util.raises didn't raise when it should have" - - def testUninterruptably(self): - def f(a, b): - self.calls += 1 - exc = self.exceptions.pop() - if exc is not None: - raise exc(errno.EINTR, "Interrupted system call!") - return a + b - - self.exceptions = [None] - self.calls = 0 - self.assertEquals(util.untilConcludes(f, 1, 2), 3) - self.assertEquals(self.calls, 1) - - self.exceptions = [None, OSError, IOError] - self.calls = 0 - self.assertEquals(util.untilConcludes(f, 2, 3), 5) - self.assertEquals(self.calls, 3) - - def testUnsignedID(self): - util.id = lambda x: x - try: - for i in range(1, 100): - self.assertEquals(util.unsignedID(i), i) - top = (sys.maxint + 1L) * 2L - for i in range(-100, -1): - self.assertEquals(util.unsignedID(i), top + i) - finally: - del util.id - - def testNameToLabel(self): - """ - Test the various kinds of inputs L{nameToLabel} supports. - """ - nameData = [ - ('f', 'F'), - ('fo', 'Fo'), - ('foo', 'Foo'), - ('fooBar', 'Foo Bar'), - ('fooBarBaz', 'Foo Bar Baz'), - ] - for inp, out in nameData: - got = util.nameToLabel(inp) - self.assertEquals( - got, out, - "nameToLabel(%r) == %r != %r" % (inp, got, out)) - - - def test_uidFromNumericString(self): - """ - When L{uidFromString} is called with a base-ten string representation - of an integer, it returns the integer. - """ - self.assertEqual(util.uidFromString("100"), 100) - - - def test_uidFromUsernameString(self): - """ - When L{uidFromString} is called with a base-ten string representation - of an integer, it returns the integer. - """ - pwent = pwd.getpwuid(os.getuid()) - self.assertEqual(util.uidFromString(pwent.pw_name), pwent.pw_uid) - if pwd is None: - test_uidFromUsernameString.skip = ( - "Username/UID conversion requires the pwd module.") - - - def test_gidFromNumericString(self): - """ - When L{gidFromString} is called with a base-ten string representation - of an integer, it returns the integer. - """ - self.assertEqual(util.gidFromString("100"), 100) - - - def test_gidFromGroupnameString(self): - """ - When L{gidFromString} is called with a base-ten string representation - of an integer, it returns the integer. - """ - grent = grp.getgrgid(os.getgid()) - self.assertEqual(util.gidFromString(grent.gr_name), grent.gr_gid) - if grp is None: - test_gidFromGroupnameString.skip = ( - "Group Name/GID conversion requires the grp module.") - - - -class TestMergeFunctionMetadata(unittest.TestCase): - """ - Tests for L{mergeFunctionMetadata}. - """ - - def test_mergedFunctionBehavesLikeMergeTarget(self): - """ - After merging C{foo}'s data into C{bar}, the returned function behaves - as if it is C{bar}. - """ - foo_object = object() - bar_object = object() - - def foo(): - return foo_object - - def bar(x, y, (a, b), c=10, *d, **e): - return bar_object - - baz = util.mergeFunctionMetadata(foo, bar) - self.assertIdentical(baz(1, 2, (3, 4), quux=10), bar_object) - - - def test_moduleIsMerged(self): - """ - Merging C{foo} into C{bar} returns a function with C{foo}'s - C{__module__}. - """ - def foo(): - pass - - def bar(): - pass - bar.__module__ = 'somewhere.else' - - baz = util.mergeFunctionMetadata(foo, bar) - self.assertEqual(baz.__module__, foo.__module__) - - - def test_docstringIsMerged(self): - """ - Merging C{foo} into C{bar} returns a function with C{foo}'s docstring. - """ - - def foo(): - """ - This is foo. - """ - - def bar(): - """ - This is bar. - """ - - baz = util.mergeFunctionMetadata(foo, bar) - self.assertEqual(baz.__doc__, foo.__doc__) - - - def test_nameIsMerged(self): - """ - Merging C{foo} into C{bar} returns a function with C{foo}'s name. - """ - - def foo(): - pass - - def bar(): - pass - - baz = util.mergeFunctionMetadata(foo, bar) - self.assertEqual(baz.__name__, foo.__name__) - - - def test_instanceDictionaryIsMerged(self): - """ - Merging C{foo} into C{bar} returns a function with C{bar}'s - dictionary, updated by C{foo}'s. - """ - - def foo(): - pass - foo.a = 1 - foo.b = 2 - - def bar(): - pass - bar.b = 3 - bar.c = 4 - - baz = util.mergeFunctionMetadata(foo, bar) - self.assertEqual(foo.a, baz.a) - self.assertEqual(foo.b, baz.b) - self.assertEqual(bar.c, baz.c) - - - -class OrderedDictTest(unittest.TestCase): - def testOrderedDict(self): - d = util.OrderedDict() - d['a'] = 'b' - d['b'] = 'a' - d[3] = 12 - d[1234] = 4321 - self.assertEquals(repr(d), "{'a': 'b', 'b': 'a', 3: 12, 1234: 4321}") - self.assertEquals(d.values(), ['b', 'a', 12, 4321]) - del d[3] - self.assertEquals(repr(d), "{'a': 'b', 'b': 'a', 1234: 4321}") - self.assertEquals(d, {'a': 'b', 'b': 'a', 1234:4321}) - self.assertEquals(d.keys(), ['a', 'b', 1234]) - self.assertEquals(list(d.iteritems()), - [('a', 'b'), ('b','a'), (1234, 4321)]) - item = d.popitem() - self.assertEquals(item, (1234, 4321)) - - def testInitialization(self): - d = util.OrderedDict({'monkey': 'ook', - 'apple': 'red'}) - self.failUnless(d._order) - - d = util.OrderedDict(((1,1),(3,3),(2,2),(0,0))) - self.assertEquals(repr(d), "{1: 1, 3: 3, 2: 2, 0: 0}") - -class InsensitiveDictTest(unittest.TestCase): - def testPreserve(self): - InsensitiveDict=util.InsensitiveDict - dct=InsensitiveDict({'Foo':'bar', 1:2, 'fnz':{1:2}}, preserve=1) - self.assertEquals(dct['fnz'], {1:2}) - self.assertEquals(dct['foo'], 'bar') - self.assertEquals(dct.copy(), dct) - self.assertEquals(dct['foo'], dct.get('Foo')) - assert 1 in dct and 'foo' in dct - self.assertEquals(eval(repr(dct)), dct) - keys=['Foo', 'fnz', 1] - for x in keys: - assert x in dct.keys() - assert (x, dct[x]) in dct.items() - self.assertEquals(len(keys), len(dct)) - del dct[1] - del dct['foo'] - - def testNoPreserve(self): - InsensitiveDict=util.InsensitiveDict - dct=InsensitiveDict({'Foo':'bar', 1:2, 'fnz':{1:2}}, preserve=0) - keys=['foo', 'fnz', 1] - for x in keys: - assert x in dct.keys() - assert (x, dct[x]) in dct.items() - self.assertEquals(len(keys), len(dct)) - del dct[1] - del dct['foo'] - - - - -class PasswordTestingProcessProtocol(ProcessProtocol): - """ - Write the string C{"secret\n"} to a subprocess and then collect all of - its output and fire a Deferred with it when the process ends. - """ - def connectionMade(self): - self.output = [] - self.transport.write('secret\n') - - def childDataReceived(self, fd, output): - self.output.append((fd, output)) - - def processEnded(self, reason): - self.finished.callback((reason, self.output)) - - -class GetPasswordTest(unittest.TestCase): - if not IReactorProcess.providedBy(reactor): - skip = "Process support required to test getPassword" - - def test_stdin(self): - """ - Making sure getPassword accepts a password from standard input by - running a child process which uses getPassword to read in a string - which it then writes it out again. Write a string to the child - process and then read one and make sure it is the right string. - """ - p = PasswordTestingProcessProtocol() - p.finished = Deferred() - reactor.spawnProcess( - p, - sys.executable, - [sys.executable, - '-c', - ('import sys\n' - 'from twisted.python.util import getPassword\n' - 'sys.stdout.write(getPassword())\n' - 'sys.stdout.flush()\n')], - env={'PYTHONPATH': os.pathsep.join(sys.path)}) - - def processFinished((reason, output)): - reason.trap(ProcessDone) - self.assertIn((1, 'secret'), output) - - return p.finished.addCallback(processFinished) - - - -class SearchUpwardsTest(unittest.TestCase): - def testSearchupwards(self): - os.makedirs('searchupwards/a/b/c') - file('searchupwards/foo.txt', 'w').close() - file('searchupwards/a/foo.txt', 'w').close() - file('searchupwards/a/b/c/foo.txt', 'w').close() - os.mkdir('searchupwards/bar') - os.mkdir('searchupwards/bam') - os.mkdir('searchupwards/a/bar') - os.mkdir('searchupwards/a/b/bam') - actual=util.searchupwards('searchupwards/a/b/c', - files=['foo.txt'], - dirs=['bar', 'bam']) - expected=os.path.abspath('searchupwards') + os.sep - self.assertEqual(actual, expected) - shutil.rmtree('searchupwards') - actual=util.searchupwards('searchupwards/a/b/c', - files=['foo.txt'], - dirs=['bar', 'bam']) - expected=None - self.assertEqual(actual, expected) - -class Foo: - def __init__(self, x): - self.x = x - -class DSU(unittest.TestCase): - def testDSU(self): - L = [Foo(x) for x in range(20, 9, -1)] - L2 = util.dsu(L, lambda o: o.x) - self.assertEquals(range(10, 21), [o.x for o in L2]) - -class IntervalDifferentialTestCase(unittest.TestCase): - def testDefault(self): - d = iter(util.IntervalDifferential([], 10)) - for i in range(100): - self.assertEquals(d.next(), (10, None)) - - def testSingle(self): - d = iter(util.IntervalDifferential([5], 10)) - for i in range(100): - self.assertEquals(d.next(), (5, 0)) - - def testPair(self): - d = iter(util.IntervalDifferential([5, 7], 10)) - for i in range(100): - self.assertEquals(d.next(), (5, 0)) - self.assertEquals(d.next(), (2, 1)) - self.assertEquals(d.next(), (3, 0)) - self.assertEquals(d.next(), (4, 1)) - self.assertEquals(d.next(), (1, 0)) - self.assertEquals(d.next(), (5, 0)) - self.assertEquals(d.next(), (1, 1)) - self.assertEquals(d.next(), (4, 0)) - self.assertEquals(d.next(), (3, 1)) - self.assertEquals(d.next(), (2, 0)) - self.assertEquals(d.next(), (5, 0)) - self.assertEquals(d.next(), (0, 1)) - - def testTriple(self): - d = iter(util.IntervalDifferential([2, 4, 5], 10)) - for i in range(100): - self.assertEquals(d.next(), (2, 0)) - self.assertEquals(d.next(), (2, 0)) - self.assertEquals(d.next(), (0, 1)) - self.assertEquals(d.next(), (1, 2)) - self.assertEquals(d.next(), (1, 0)) - self.assertEquals(d.next(), (2, 0)) - self.assertEquals(d.next(), (0, 1)) - self.assertEquals(d.next(), (2, 0)) - self.assertEquals(d.next(), (0, 2)) - self.assertEquals(d.next(), (2, 0)) - self.assertEquals(d.next(), (0, 1)) - self.assertEquals(d.next(), (2, 0)) - self.assertEquals(d.next(), (1, 2)) - self.assertEquals(d.next(), (1, 0)) - self.assertEquals(d.next(), (0, 1)) - self.assertEquals(d.next(), (2, 0)) - self.assertEquals(d.next(), (2, 0)) - self.assertEquals(d.next(), (0, 1)) - self.assertEquals(d.next(), (0, 2)) - - def testInsert(self): - d = iter(util.IntervalDifferential([], 10)) - self.assertEquals(d.next(), (10, None)) - d.addInterval(3) - self.assertEquals(d.next(), (3, 0)) - self.assertEquals(d.next(), (3, 0)) - d.addInterval(6) - self.assertEquals(d.next(), (3, 0)) - self.assertEquals(d.next(), (3, 0)) - self.assertEquals(d.next(), (0, 1)) - self.assertEquals(d.next(), (3, 0)) - self.assertEquals(d.next(), (3, 0)) - self.assertEquals(d.next(), (0, 1)) - - def testRemove(self): - d = iter(util.IntervalDifferential([3, 5], 10)) - self.assertEquals(d.next(), (3, 0)) - self.assertEquals(d.next(), (2, 1)) - self.assertEquals(d.next(), (1, 0)) - d.removeInterval(3) - self.assertEquals(d.next(), (4, 0)) - self.assertEquals(d.next(), (5, 0)) - d.removeInterval(5) - self.assertEquals(d.next(), (10, None)) - self.assertRaises(ValueError, d.removeInterval, 10) - - - -class Record(util.FancyEqMixin): - """ - Trivial user of L{FancyEqMixin} used by tests. - """ - compareAttributes = ('a', 'b') - - def __init__(self, a, b): - self.a = a - self.b = b - - - -class DifferentRecord(util.FancyEqMixin): - """ - Trivial user of L{FancyEqMixin} which is not related to L{Record}. - """ - compareAttributes = ('a', 'b') - - def __init__(self, a, b): - self.a = a - self.b = b - - - -class DerivedRecord(Record): - """ - A class with an inheritance relationship to L{Record}. - """ - - - -class EqualToEverything(object): - """ - A class the instances of which consider themselves equal to everything. - """ - def __eq__(self, other): - return True - - - def __ne__(self, other): - return False - - - -class EqualToNothing(object): - """ - A class the instances of which consider themselves equal to nothing. - """ - def __eq__(self, other): - return False - - - def __ne__(self, other): - return True - - - -class EqualityTests(unittest.TestCase): - """ - Tests for L{FancyEqMixin}. - """ - def test_identity(self): - """ - Instances of a class which mixes in L{FancyEqMixin} but which - defines no comparison attributes compare by identity. - """ - class Empty(util.FancyEqMixin): - pass - - self.assertFalse(Empty() == Empty()) - self.assertTrue(Empty() != Empty()) - empty = Empty() - self.assertTrue(empty == empty) - self.assertFalse(empty != empty) - - - def test_equality(self): - """ - Instances of a class which mixes in L{FancyEqMixin} should compare - equal if all of their attributes compare equal. They should not - compare equal if any of their attributes do not compare equal. - """ - self.assertTrue(Record(1, 2) == Record(1, 2)) - self.assertFalse(Record(1, 2) == Record(1, 3)) - self.assertFalse(Record(1, 2) == Record(2, 2)) - self.assertFalse(Record(1, 2) == Record(3, 4)) - - - def test_unequality(self): - """ - Unequality between instances of a particular L{record} should be - defined as the negation of equality. - """ - self.assertFalse(Record(1, 2) != Record(1, 2)) - self.assertTrue(Record(1, 2) != Record(1, 3)) - self.assertTrue(Record(1, 2) != Record(2, 2)) - self.assertTrue(Record(1, 2) != Record(3, 4)) - - - def test_differentClassesEquality(self): - """ - Instances of different classes which mix in L{FancyEqMixin} should not - compare equal. - """ - self.assertFalse(Record(1, 2) == DifferentRecord(1, 2)) - - - def test_differentClassesInequality(self): - """ - Instances of different classes which mix in L{FancyEqMixin} should - compare unequal. - """ - self.assertTrue(Record(1, 2) != DifferentRecord(1, 2)) - - - def test_inheritedClassesEquality(self): - """ - An instance of a class which derives from a class which mixes in - L{FancyEqMixin} should compare equal to an instance of the base class - if and only if all of their attributes compare equal. - """ - self.assertTrue(Record(1, 2) == DerivedRecord(1, 2)) - self.assertFalse(Record(1, 2) == DerivedRecord(1, 3)) - self.assertFalse(Record(1, 2) == DerivedRecord(2, 2)) - self.assertFalse(Record(1, 2) == DerivedRecord(3, 4)) - - - def test_inheritedClassesInequality(self): - """ - An instance of a class which derives from a class which mixes in - L{FancyEqMixin} should compare unequal to an instance of the base - class if any of their attributes compare unequal. - """ - self.assertFalse(Record(1, 2) != DerivedRecord(1, 2)) - self.assertTrue(Record(1, 2) != DerivedRecord(1, 3)) - self.assertTrue(Record(1, 2) != DerivedRecord(2, 2)) - self.assertTrue(Record(1, 2) != DerivedRecord(3, 4)) - - - def test_rightHandArgumentImplementsEquality(self): - """ - The right-hand argument to the equality operator is given a chance - to determine the result of the operation if it is of a type - unrelated to the L{FancyEqMixin}-based instance on the left-hand - side. - """ - self.assertTrue(Record(1, 2) == EqualToEverything()) - self.assertFalse(Record(1, 2) == EqualToNothing()) - - - def test_rightHandArgumentImplementsUnequality(self): - """ - The right-hand argument to the non-equality operator is given a - chance to determine the result of the operation if it is of a type - unrelated to the L{FancyEqMixin}-based instance on the left-hand - side. - """ - self.assertFalse(Record(1, 2) != EqualToEverything()) - self.assertTrue(Record(1, 2) != EqualToNothing()) diff --git a/tools/buildbot/pylibs/twisted/python/test/test_versions.py b/tools/buildbot/pylibs/twisted/python/test/test_versions.py deleted file mode 100644 index 368bae1..0000000 --- a/tools/buildbot/pylibs/twisted/python/test/test_versions.py +++ /dev/null @@ -1,269 +0,0 @@ -# Copyright (c) 2006-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -import sys -from cStringIO import StringIO - -from twisted.python.versions import getVersionString, IncomparableVersions -from twisted.python.versions import Version, _inf -from twisted.python.filepath import FilePath - -from twisted.trial import unittest - - - -VERSION_4_ENTRIES = """\ - - - - -""" - - - -VERSION_8_ENTRIES = """\ -8 - -dir -22715 -svn+ssh://svn.twistedmatrix.com/svn/Twisted/trunk -""" - - - -class VersionsTest(unittest.TestCase): - - def test_versionComparison(self): - """ - Versions can be compared for equality and order. - """ - va = Version("dummy", 1, 0, 0) - vb = Version("dummy", 0, 1, 0) - self.failUnless(va > vb) - self.failUnless(vb < va) - self.failUnless(va >= vb) - self.failUnless(vb <= va) - self.failUnless(va != vb) - self.failUnless(vb == Version("dummy", 0, 1, 0)) - self.failUnless(vb == vb) - - # BREAK IT DOWN@!! - self.failIf(va < vb) - self.failIf(vb > va) - self.failIf(va <= vb) - self.failIf(vb >= va) - self.failIf(va == vb) - self.failIf(vb != Version("dummy", 0, 1, 0)) - self.failIf(vb != vb) - - - def test_comparingPrereleasesWithReleases(self): - """ - Prereleases are always less than versions without prereleases. - """ - va = Version("whatever", 1, 0, 0, prerelease=1) - vb = Version("whatever", 1, 0, 0) - self.assertTrue(va < vb) - self.assertFalse(va > vb) - self.assertNotEquals(vb, va) - - - def test_comparingPrereleases(self): - """ - The value specified as the prerelease is used in version comparisons. - """ - va = Version("whatever", 1, 0, 0, prerelease=1) - vb = Version("whatever", 1, 0, 0, prerelease=2) - self.assertTrue(va < vb) - self.assertFalse(va > vb) - self.assertNotEqual(va, vb) - - - def test_infComparison(self): - """ - L{_inf} is equal to L{_inf}. - - This is a regression test. - """ - self.assertEquals(_inf, _inf) - - - def testDontAllowBuggyComparisons(self): - self.assertRaises(IncomparableVersions, - cmp, - Version("dummy", 1, 0, 0), - Version("dumym", 1, 0, 0)) - - - def test_repr(self): - """ - Calling C{repr} on a version returns a human-readable string - representation of the version. - """ - self.assertEquals(repr(Version("dummy", 1, 2, 3)), - "Version('dummy', 1, 2, 3)") - - - def test_reprWithPrerelease(self): - """ - Calling C{repr} on a version with a prerelease returns a human-readable - string representation of the version including the prerelease. - """ - self.assertEquals(repr(Version("dummy", 1, 2, 3, prerelease=4)), - "Version('dummy', 1, 2, 3, prerelease=4)") - - - def test_str(self): - """ - Calling C{str} on a version returns a human-readable string - representation of the version. - """ - self.assertEquals(str(Version("dummy", 1, 2, 3)), - "[dummy, version 1.2.3]") - - - def test_strWithPrerelease(self): - """ - Calling C{str} on a version with a prerelease includes the prerelease. - """ - self.assertEquals(str(Version("dummy", 1, 0, 0, prerelease=1)), - "[dummy, version 1.0.0pre1]") - - - def testShort(self): - self.assertEquals(Version('dummy', 1, 2, 3).short(), '1.2.3') - - - def test_goodSVNEntries_4(self): - """ - Version should be able to parse an SVN format 4 entries file. - """ - version = Version("dummy", 1, 0, 0) - self.assertEquals( - version._parseSVNEntries_4(StringIO(VERSION_4_ENTRIES)), '18211') - - - def test_goodSVNEntries_8(self): - """ - Version should be able to parse an SVN format 8 entries file. - """ - version = Version("dummy", 1, 0, 0) - self.assertEqual( - version._parseSVNEntries_8(StringIO(VERSION_8_ENTRIES)), '22715') - - - def test_getVersionString(self): - """ - L{getVersionString} returns a string with the package name and the - short version number. - """ - self.assertEqual( - 'Twisted 8.0.0', getVersionString(Version('Twisted', 8, 0, 0))) - - - def test_getVersionStringWithPrerelease(self): - """ - L{getVersionString} includes the prerelease, if any. - """ - self.assertEqual( - getVersionString(Version("whatever", 8, 0, 0, prerelease=1)), - "whatever 8.0.0pre1") - - - def test_base(self): - """ - The L{base} method returns a very simple representation of the version. - """ - self.assertEquals(Version("foo", 1, 0, 0).base(), "1.0.0") - - - def test_baseWithPrerelease(self): - """ - The base version includes 'preX' for versions with prereleases. - """ - self.assertEquals(Version("foo", 1, 0, 0, prerelease=8).base(), - "1.0.0pre8") - - - -class FormatDiscoveryTests(unittest.TestCase): - """ - Tests which discover the parsing method based on the imported module name. - """ - - def setUp(self): - """ - Create a temporary directory with a package structure in it. - """ - self.entry = FilePath(self.mktemp()) - self.preTestModules = sys.modules.copy() - sys.path.append(self.entry.path) - pkg = self.entry.child("twisted_python_versions_package") - pkg.makedirs() - pkg.child("__init__.py").setContent( - "from twisted.python.versions import Version\n" - "version = Version('twisted_python_versions_package', 1, 0, 0)\n") - self.svnEntries = pkg.child(".svn") - self.svnEntries.makedirs() - - - def tearDown(self): - """ - Remove the imported modules and sys.path modifications. - """ - sys.modules.clear() - sys.modules.update(self.preTestModules) - sys.path.remove(self.entry.path) - - - def checkSVNFormat(self, formatVersion, entriesText, expectedRevision): - """ - Check for the given revision being detected after setting the SVN - entries text and format version of the test directory structure. - """ - self.svnEntries.child("format").setContent(formatVersion+"\n") - self.svnEntries.child("entries").setContent(entriesText) - self.assertEqual(self.getVersion()._getSVNVersion(), expectedRevision) - - - def getVersion(self): - """ - Import and retrieve the Version object from our dynamically created - package. - """ - import twisted_python_versions_package - return twisted_python_versions_package.version - - - def test_detectVersion4(self): - """ - Verify that version 4 format file will be properly detected and parsed. - """ - self.checkSVNFormat("4", VERSION_4_ENTRIES, '18211') - - - def test_detectVersion8(self): - """ - Verify that version 8 format files will be properly detected and - parsed. - """ - self.checkSVNFormat("8", VERSION_8_ENTRIES, '22715') - - - def test_detectUnknownVersion(self): - """ - Verify that a new version of SVN will result in the revision 'Unknown'. - """ - self.checkSVNFormat("some-random-new-version", "ooga booga!", 'Unknown') - - diff --git a/tools/buildbot/pylibs/twisted/python/test/test_zipstream.py b/tools/buildbot/pylibs/twisted/python/test/test_zipstream.py deleted file mode 100644 index 5ccb033..0000000 --- a/tools/buildbot/pylibs/twisted/python/test/test_zipstream.py +++ /dev/null @@ -1,396 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.python.zipstream} -""" -import sys -import random -import md5 -import zipfile - -from twisted.python import zipstream, filepath -from twisted.trial import unittest - -class FileEntryMixin: - """ - File entry classes should behave as file-like objects - """ - def getFileEntry(self, contents): - """ - Return an appropriate zip file entry - """ - filename = self.mktemp() - z = zipfile.ZipFile(filename, 'w', self.compression) - z.writestr('content', contents) - z.close() - z = zipstream.ChunkingZipFile(filename, 'r') - return z.readfile('content') - - - def test_isatty(self): - """ - zip files should not be ttys, so isatty() should be false - """ - self.assertEquals(self.getFileEntry('').isatty(), False) - - - def test_closed(self): - """ - The C{closed} attribute should reflect whether C{close()} has been - called. - """ - fileEntry = self.getFileEntry('') - self.assertEquals(fileEntry.closed, False) - fileEntry.close() - self.assertEquals(fileEntry.closed, True) - - - def test_readline(self): - """ - C{readline()} should mirror L{file.readline} and return up to a single - deliminter. - """ - fileEntry = self.getFileEntry('hoho\nho') - self.assertEquals(fileEntry.readline(), 'hoho\n') - self.assertEquals(fileEntry.readline(), 'ho') - self.assertEquals(fileEntry.readline(), '') - - - def test_next(self): - """ - Zip file entries should implement the iterator protocol as files do. - """ - fileEntry = self.getFileEntry('ho\nhoho') - self.assertEquals(fileEntry.next(), 'ho\n') - self.assertEquals(fileEntry.next(), 'hoho') - self.assertRaises(StopIteration, fileEntry.next) - - - def test_readlines(self): - """ - C{readlines()} should return a list of all the lines. - """ - fileEntry = self.getFileEntry('ho\nho\nho') - self.assertEquals(fileEntry.readlines(), ['ho\n', 'ho\n', 'ho']) - - - def test_iteration(self): - """ - C{__iter__()} and C{xreadlines()} should return C{self}. - """ - fileEntry = self.getFileEntry('') - self.assertIdentical(iter(fileEntry), fileEntry) - self.assertIdentical(fileEntry.xreadlines(), fileEntry) - - - def test_readWhole(self): - """ - C{.read()} should read the entire file. - """ - contents = "Hello, world!" - entry = self.getFileEntry(contents) - self.assertEquals(entry.read(), contents) - - - def test_readPartial(self): - """ - C{.read(num)} should read num bytes from the file. - """ - contents = "0123456789" - entry = self.getFileEntry(contents) - one = entry.read(4) - two = entry.read(200) - self.assertEquals(one, "0123") - self.assertEquals(two, "456789") - - - def test_tell(self): - """ - C{.tell()} should return the number of bytes that have been read so - far. - """ - contents = "x" * 100 - entry = self.getFileEntry(contents) - entry.read(2) - self.assertEquals(entry.tell(), 2) - entry.read(4) - self.assertEquals(entry.tell(), 6) - - - -class DeflatedZipFileEntryTest(FileEntryMixin, unittest.TestCase): - """ - DeflatedZipFileEntry should be file-like - """ - compression = zipfile.ZIP_DEFLATED - - - -class ZipFileEntryTest(FileEntryMixin, unittest.TestCase): - """ - ZipFileEntry should be file-like - """ - compression = zipfile.ZIP_STORED - - - -class ZipstreamTest(unittest.TestCase): - """ - Tests for twisted.python.zipstream - """ - def setUp(self): - """ - Creates junk data that can be compressed and a test directory for any - files that will be created - """ - self.testdir = filepath.FilePath(self.mktemp()) - self.testdir.makedirs() - self.unzipdir = self.testdir.child('unzipped') - self.unzipdir.makedirs() - - - def makeZipFile(self, contents, directory=''): - """ - Makes a zip file archive containing len(contents) files. Contents - should be a list of strings, each string being the content of one file. - """ - zpfilename = self.testdir.child('zipfile.zip').path - zpfile = zipfile.ZipFile(zpfilename, 'w') - for i, content in enumerate(contents): - filename = str(i) - if directory: - filename = directory + "/" + filename - zpfile.writestr(filename, content) - zpfile.close() - return zpfilename - - - def test_countEntries(self): - """ - Make sure the deprecated L{countZipFileEntries} returns the correct - number of entries for a zip file. - """ - name = self.makeZipFile(["one", "two", "three", "four", "five"]) - result = self.assertWarns(DeprecationWarning, - "countZipFileEntries is deprecated.", - __file__, lambda : - zipstream.countZipFileEntries(name)) - self.assertEquals(result, 5) - - - def test_invalidMode(self): - """ - A ChunkingZipFile opened in write-mode should not allow .readfile(), - and raise a RuntimeError instead. - """ - czf = zipstream.ChunkingZipFile(self.mktemp(), "w") - self.assertRaises(RuntimeError, czf.readfile, "something") - - - def test_closedArchive(self): - """ - A closed ChunkingZipFile should raise a L{RuntimeError} when - .readfile() is invoked. - """ - czf = zipstream.ChunkingZipFile(self.makeZipFile(["something"]), "r") - czf.close() - self.assertRaises(RuntimeError, czf.readfile, "something") - - - def test_invalidHeader(self): - """ - A zipfile entry with the wrong magic number should raise BadZipfile for - readfile(), but that should not affect other files in the archive. - """ - fn = self.makeZipFile(["test contents", - "more contents"]) - zf = zipfile.ZipFile(fn, "r") - zeroOffset = zf.getinfo("0").header_offset - zf.close() - # Zero out just the one header. - scribble = file(fn, "r+b") - scribble.seek(zeroOffset, 0) - scribble.write(chr(0) * 4) - scribble.close() - czf = zipstream.ChunkingZipFile(fn) - self.assertRaises(zipfile.BadZipfile, czf.readfile, "0") - self.assertEquals(czf.readfile("1").read(), "more contents") - - - def test_filenameMismatch(self): - """ - A zipfile entry with a different filename than is found in the central - directory should raise BadZipfile. - """ - fn = self.makeZipFile(["test contents", - "more contents"]) - zf = zipfile.ZipFile(fn, "r") - info = zf.getinfo("0") - info.filename = "not zero" - zf.close() - scribble = file(fn, "r+b") - scribble.seek(info.header_offset, 0) - scribble.write(info.FileHeader()) - scribble.close() - - czf = zipstream.ChunkingZipFile(fn) - self.assertRaises(zipfile.BadZipfile, czf.readfile, "0") - self.assertEquals(czf.readfile("1").read(), "more contents") - - - if sys.version_info < (2, 5): - # In python 2.4 and earlier, consistency between the directory and the - # file header are verified at archive-opening time. In python 2.5 - # (and, presumably, later) it is readzipfile's responsibility. - message = "Consistency-checking only necessary in 2.5." - test_invalidHeader.skip = message - test_filenameMismatch.skip = message - - - - def test_unsupportedCompression(self): - """ - A zipfile which describes an unsupported compression mechanism should - raise BadZipfile. - """ - fn = self.mktemp() - zf = zipfile.ZipFile(fn, "w") - zi = zipfile.ZipInfo("0") - zf.writestr(zi, "some data") - # Mangle its compression type in the central directory; can't do this - # before the writestr call or zipfile will (correctly) tell us not to - # pass bad compression types :) - zi.compress_type = 1234 - zf.close() - - czf = zipstream.ChunkingZipFile(fn) - self.assertRaises(zipfile.BadZipfile, czf.readfile, "0") - - - def test_extraData(self): - """ - readfile() should skip over 'extra' data present in the zip metadata. - """ - fn = self.mktemp() - zf = zipfile.ZipFile(fn, 'w') - zi = zipfile.ZipInfo("0") - zi.extra = "hello, extra" - zf.writestr(zi, "the real data") - zf.close() - czf = zipstream.ChunkingZipFile(fn) - self.assertEquals(czf.readfile("0").read(), "the real data") - - - def test_unzipIter(self): - """ - L{twisted.python.zipstream.unzipIter} should unzip a file for each - iteration and yield the number of files left to unzip after that - iteration - """ - numfiles = 10 - contents = ['This is test file %d!' % i for i in range(numfiles)] - zpfilename = self.makeZipFile(contents) - uziter = zipstream.unzipIter(zpfilename, self.unzipdir.path) - for i in range(numfiles): - self.assertEquals(len(list(self.unzipdir.children())), i) - self.assertEquals(uziter.next(), numfiles - i - 1) - self.assertEquals(len(list(self.unzipdir.children())), numfiles) - - for child in self.unzipdir.children(): - num = int(child.basename()) - self.assertEquals(child.open().read(), contents[num]) - - - def test_unzip(self): - """ - L{twisted.python.zipstream.unzip} should extract all files from a zip - archive - """ - numfiles = 3 - zpfilename = self.makeZipFile([''] * numfiles) - zipstream.unzip(zpfilename, self.unzipdir.path) - self.assertEquals(len(list(self.unzipdir.children())), numfiles) - - - def test_overwrite(self): - """ - L{twisted.python.zipstream.unzip} and - L{twisted.python.zipstream.unzipIter} shouldn't overwrite files unless - the 'overwrite' flag is passed - """ - testfile = self.unzipdir.child('0') - zpfilename = self.makeZipFile(['OVERWRITTEN']) - - testfile.setContent('NOT OVERWRITTEN') - zipstream.unzip(zpfilename, self.unzipdir.path) - self.assertEquals(testfile.open().read(), 'NOT OVERWRITTEN') - zipstream.unzip(zpfilename, self.unzipdir.path, overwrite=True) - self.assertEquals(testfile.open().read(), 'OVERWRITTEN') - - testfile.setContent('NOT OVERWRITTEN') - uziter = zipstream.unzipIter(zpfilename, self.unzipdir.path) - uziter.next() - self.assertEquals(testfile.open().read(), 'NOT OVERWRITTEN') - uziter = zipstream.unzipIter(zpfilename, self.unzipdir.path, - overwrite=True) - uziter.next() - self.assertEquals(testfile.open().read(), 'OVERWRITTEN') - - - # XXX these tests are kind of gross and old, but I think unzipIterChunky is - # kind of a gross function anyway. We should really write an abstract - # copyTo/moveTo that operates on FilePath and make sure ZipPath can support - # it, then just deprecate / remove this stuff. - def _unzipIterChunkyTest(self, compression, chunksize, lower, upper): - """ - unzipIterChunky should unzip the given number of bytes per iteration. - """ - junk = ' '.join([str(random.random()) for n in xrange(1000)]) - junkmd5 = md5.new(junk).hexdigest() - - tempdir = filepath.FilePath(self.mktemp()) - tempdir.makedirs() - zfpath = tempdir.child('bigfile.zip').path - self._makebigfile(zfpath, compression, junk) - uziter = zipstream.unzipIterChunky(zfpath, tempdir.path, - chunksize=chunksize) - r = uziter.next() - # test that the number of chunks is in the right ballpark; - # this could theoretically be any number but statistically it - # should always be in this range - approx = lower < r < upper - self.failUnless(approx) - for r in uziter: - pass - self.assertEqual(r, 0) - newmd5 = md5.new( - tempdir.child("zipstreamjunk").open().read()).hexdigest() - self.assertEqual(newmd5, junkmd5) - - def test_unzipIterChunkyStored(self): - """ - unzipIterChunky should unzip the given number of bytes per iteration on - a stored archive. - """ - self._unzipIterChunkyTest(zipfile.ZIP_STORED, 500, 35, 45) - - - def test_chunkyDeflated(self): - """ - unzipIterChunky should unzip the given number of bytes per iteration on - a deflated archive. - """ - self._unzipIterChunkyTest(zipfile.ZIP_DEFLATED, 972, 23, 27) - - - def _makebigfile(self, filename, compression, junk): - """ - Create a zip file with the given file name and compression scheme. - """ - zf = zipfile.ZipFile(filename, 'w', compression) - for i in range(10): - fn = 'zipstream%d' % i - zf.writestr(fn, "") - zf.writestr('zipstreamjunk', junk) - zf.close() diff --git a/tools/buildbot/pylibs/twisted/python/text.py b/tools/buildbot/pylibs/twisted/python/text.py deleted file mode 100644 index b502870..0000000 --- a/tools/buildbot/pylibs/twisted/python/text.py +++ /dev/null @@ -1,227 +0,0 @@ -# -*- test-case-name: twisted.test.test_text -*- -# -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Miscellany of text-munging functions. -""" - -import string, types - -def stringyString(object, indentation=''): - """Expansive string formatting for sequence types. - - list.__str__ and dict.__str__ use repr() to display their - elements. This function also turns these sequence types - into strings, but uses str() on their elements instead. - - Sequence elements are also displayed on seperate lines, - and nested sequences have nested indentation. - """ - braces = '' - sl = [] - - if type(object) is types.DictType: - braces = '{}' - for key, value in object.items(): - value = stringyString(value, indentation + ' ') - if isMultiline(value): - if endsInNewline(value): - value = value[:-len('\n')] - sl.append("%s %s:\n%s" % (indentation, key, value)) - else: - # Oops. Will have to move that indentation. - sl.append("%s %s: %s" % (indentation, key, - value[len(indentation) + 3:])) - - elif type(object) in (types.TupleType, types.ListType): - if type(object) is types.TupleType: - braces = '()' - else: - braces = '[]' - - for element in object: - element = stringyString(element, indentation + ' ') - sl.append(string.rstrip(element) + ',') - else: - sl[:] = map(lambda s, i=indentation: i+s, - string.split(str(object),'\n')) - - if not sl: - sl.append(indentation) - - if braces: - sl[0] = indentation + braces[0] + sl[0][len(indentation) + 1:] - sl[-1] = sl[-1] + braces[-1] - - s = string.join(sl, "\n") - - if isMultiline(s) and not endsInNewline(s): - s = s + '\n' - - return s - -def isMultiline(s): - """Returns True if this string has a newline in it.""" - return (string.find(s, '\n') != -1) - -def endsInNewline(s): - """Returns True if this string ends in a newline.""" - return (s[-len('\n'):] == '\n') - -def docstringLStrip(docstring): - """Gets rid of unsightly lefthand docstring whitespace residue. - - You'd think someone would have done this already, but apparently - not in 1.5.2. - - BUT since we're all using Python 2.1 now, use L{inspect.getdoc} - instead. I{This function should go away soon.} - """ - - if not docstring: - return docstring - - docstring = string.replace(docstring, '\t', ' ' * 8) - lines = string.split(docstring,'\n') - - leading = 0 - for l in xrange(1,len(lines)): - line = lines[l] - if string.strip(line): - while 1: - if line[leading] == ' ': - leading = leading + 1 - else: - break - if leading: - break - - outlines = lines[0:1] - for l in xrange(1,len(lines)): - outlines.append(lines[l][leading:]) - - return string.join(outlines, '\n') - -def greedyWrap(inString, width=80): - """Given a string and a column width, return a list of lines. - - Caveat: I'm use a stupid greedy word-wrapping - algorythm. I won't put two spaces at the end - of a sentence. I don't do full justification. - And no, I've never even *heard* of hypenation. - """ - - outLines = [] - - #eww, evil hacks to allow paragraphs delimited by two \ns :( - if inString.find('\n\n') >= 0: - paragraphs = string.split(inString, '\n\n') - for para in paragraphs: - outLines.extend(greedyWrap(para) + ['']) - return outLines - inWords = string.split(inString) - - column = 0 - ptr_line = 0 - while inWords: - column = column + len(inWords[ptr_line]) - ptr_line = ptr_line + 1 - - if (column > width): - if ptr_line == 1: - # This single word is too long, it will be the whole line. - pass - else: - # We've gone too far, stop the line one word back. - ptr_line = ptr_line - 1 - (l, inWords) = (inWords[0:ptr_line], inWords[ptr_line:]) - outLines.append(string.join(l,' ')) - - ptr_line = 0 - column = 0 - elif not (len(inWords) > ptr_line): - # Clean up the last bit. - outLines.append(string.join(inWords, ' ')) - del inWords[:] - else: - # Space - column = column + 1 - # next word - - return outLines - - -wordWrap = greedyWrap - -def removeLeadingBlanks(lines): - ret = [] - for line in lines: - if ret or line.strip(): - ret.append(line) - return ret - -def removeLeadingTrailingBlanks(s): - lines = removeLeadingBlanks(s.split('\n')) - lines.reverse() - lines = removeLeadingBlanks(lines) - lines.reverse() - return '\n'.join(lines)+'\n' - -def splitQuoted(s): - """Like string.split, but don't break substrings inside quotes. - - >>> splitQuoted('the \"hairy monkey\" likes pie') - ['the', 'hairy monkey', 'likes', 'pie'] - - Another one of those \"someone must have a better solution for - this\" things. This implementation is a VERY DUMB hack done too - quickly. - """ - out = [] - quot = None - phrase = None - for word in s.split(): - if phrase is None: - if word and (word[0] in ("\"", "'")): - quot = word[0] - word = word[1:] - phrase = [] - - if phrase is None: - out.append(word) - else: - if word and (word[-1] == quot): - word = word[:-1] - phrase.append(word) - out.append(" ".join(phrase)) - phrase = None - else: - phrase.append(word) - - return out - -def strFile(p, f, caseSensitive=True): - """Find whether string p occurs in a read()able object f - @rtype: C{bool} - """ - buf = "" - buf_len = max(len(p), 2**2**2**2) - if not caseSensitive: - p = p.lower() - while 1: - r = f.read(buf_len-len(p)) - if not caseSensitive: - r = r.lower() - bytes_read = len(r) - if bytes_read == 0: - return False - l = len(buf)+bytes_read-buf_len - if l <= 0: - buf = buf + r - else: - buf = buf[l:] + r - if buf.find(p) != -1: - return True - diff --git a/tools/buildbot/pylibs/twisted/python/threadable.py b/tools/buildbot/pylibs/twisted/python/threadable.py deleted file mode 100644 index 9330320..0000000 --- a/tools/buildbot/pylibs/twisted/python/threadable.py +++ /dev/null @@ -1,120 +0,0 @@ -# -*- test-case-name: twisted.python.threadable -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -A module that will allow your program to be multi-threaded, -micro-threaded, and single-threaded. Currently microthreads are -unimplemented. The idea is to abstract away some commonly used -functionality so that I don't have to special-case it in all programs. -""" - -import warnings - -from twisted.python import hook - -class DummyLock(object): - """ - Hack to allow locks to be unpickled on an unthreaded system. - """ - - def __reduce__(self): - return (unpickle_lock, ()) - -def unpickle_lock(): - if threadingmodule is not None: - return XLock() - else: - return DummyLock() -unpickle_lock.__safe_for_unpickling__ = True - -def _synchPre(self, *a, **b): - if '_threadable_lock' not in self.__dict__: - _synchLockCreator.acquire() - if '_threadable_lock' not in self.__dict__: - self.__dict__['_threadable_lock'] = XLock() - _synchLockCreator.release() - self._threadable_lock.acquire() - -def _synchPost(self, *a, **b): - self._threadable_lock.release() - -def synchronize(*klasses): - """Make all methods listed in each class' synchronized attribute synchronized. - - The synchronized attribute should be a list of strings, consisting of the - names of methods that must be synchronized. If we are running in threaded - mode these methods will be wrapped with a lock. - """ - if threadmodule is not None: - for klass in klasses: - for methodName in klass.synchronized: - hook.addPre(klass, methodName, _synchPre) - hook.addPost(klass, methodName, _synchPost) - -def init(with_threads=1): - """Initialize threading. - - Don't bother calling this. If it needs to happen, it will happen. - """ - global threaded, _synchLockCreator, XLock - - if with_threads: - if not threaded: - if threadmodule is not None: - threaded = True - - class XLock(threadingmodule._RLock, object): - def __reduce__(self): - return (unpickle_lock, ()) - - _synchLockCreator = XLock() - else: - raise RuntimeError("Cannot initialize threading, platform lacks thread support") - else: - if threaded: - raise RuntimeError("Cannot uninitialize threads") - else: - pass - -_dummyID = object() -def getThreadID(): - if threadmodule is None: - return _dummyID - return threadmodule.get_ident() - - -def isInIOThread(): - """Are we in the thread responsable for I/O requests (the event loop)? - """ - return ioThread == getThreadID() - - -def registerAsIOThread(): - """Mark the current thread as responsable for I/O requests. - """ - global ioThread - ioThread = getThreadID() - - -ioThread = None -threaded = False - -def whenThreaded(cb): - warnings.warn("threadable.whenThreaded is deprecated. " - "Use application-level logic instead.", - DeprecationWarning, stacklevel=2) - cb() - -try: - import thread as threadmodule - import threading as threadingmodule -except ImportError: - threadmodule = None - threadingmodule = None -else: - init(True) - -__all__ = ['isInIOThread', 'registerAsIOThread', 'getThreadID', 'XLock', - 'whenThreaded'] diff --git a/tools/buildbot/pylibs/twisted/python/threadpool.py b/tools/buildbot/pylibs/twisted/python/threadpool.py deleted file mode 100644 index e7f6f93..0000000 --- a/tools/buildbot/pylibs/twisted/python/threadpool.py +++ /dev/null @@ -1,242 +0,0 @@ -# -*- test-case-name: twisted.test.test_threadpool -*- -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -twisted.threadpool: a pool of threads to which we dispatch tasks. - -In most cases you can just use reactor.callInThread and friends -instead of creating a thread pool directly. -""" - -# System Imports -import Queue -import threading -import copy -import sys -import warnings - - -# Twisted Imports -from twisted.python import log, runtime, context, threadable - -WorkerStop = object() - - -class ThreadPool: - """ - This class (hopefully) generalizes the functionality of a pool of - threads to which work can be dispatched. - - callInThread() and stop() should only be called from - a single thread, unless you make a subclass where stop() and - _startSomeWorkers() are synchronized. - """ - min = 5 - max = 20 - joined = False - started = False - workers = 0 - name = None - - threadFactory = threading.Thread - currentThread = staticmethod(threading.currentThread) - - def __init__(self, minthreads=5, maxthreads=20, name=None): - """ - Create a new threadpool. - - @param minthreads: minimum number of threads in the pool - - @param maxthreads: maximum number of threads in the pool - """ - assert minthreads >= 0, 'minimum is negative' - assert minthreads <= maxthreads, 'minimum is greater than maximum' - self.q = Queue.Queue(0) - self.min = minthreads - self.max = maxthreads - self.name = name - if runtime.platform.getType() != "java": - self.waiters = [] - self.threads = [] - self.working = [] - else: - self.waiters = ThreadSafeList() - self.threads = ThreadSafeList() - self.working = ThreadSafeList() - - def start(self): - """ - Start the threadpool. - """ - self.joined = False - self.started = True - # Start some threads. - self.adjustPoolsize() - - def startAWorker(self): - self.workers += 1 - name = "PoolThread-%s-%s" % (self.name or id(self), self.workers) - newThread = self.threadFactory(target=self._worker, name=name) - self.threads.append(newThread) - newThread.start() - - def stopAWorker(self): - self.q.put(WorkerStop) - self.workers -= 1 - - def __setstate__(self, state): - self.__dict__ = state - ThreadPool.__init__(self, self.min, self.max) - - def __getstate__(self): - state = {} - state['min'] = self.min - state['max'] = self.max - return state - - def _startSomeWorkers(self): - neededSize = self.q.qsize() + len(self.working) - # Create enough, but not too many - while self.workers < min(self.max, neededSize): - self.startAWorker() - - def dispatch(self, owner, func, *args, **kw): - """ - DEPRECATED: use L{callInThread} instead. - - Dispatch a function to be a run in a thread. - """ - warnings.warn("dispatch() is deprecated since Twisted 8.0, " - "use callInThread() instead", - DeprecationWarning, stacklevel=2) - self.callInThread(func, *args, **kw) - - def callInThread(self, func, *args, **kw): - if self.joined: - return - ctx = context.theContextTracker.currentContext().contexts[-1] - o = (ctx, func, args, kw) - self.q.put(o) - if self.started: - self._startSomeWorkers() - - def _runWithCallback(self, callback, errback, func, args, kwargs): - try: - result = apply(func, args, kwargs) - except: - errback(sys.exc_info()[1]) - else: - callback(result) - - def dispatchWithCallback(self, owner, callback, errback, func, *args, **kw): - """ - DEPRECATED: use L{twisted.internet.threads.deferToThread} instead. - - Dispatch a function, returning the result to a callback function. - - The callback function will be called in the thread - make sure it is - thread-safe. - """ - warnings.warn("dispatchWithCallback() is deprecated since Twisted 8.0, " - "use twisted.internet.threads.deferToThread() instead.", - DeprecationWarning, stacklevel=2) - self.callInThread( - self._runWithCallback, callback, errback, func, args, kw - ) - - def _worker(self): - """ - Method used as target of the created threads: retrieve task to run - from the threadpool, run it, and proceed to the next task until - threadpool is stopped. - """ - ct = self.currentThread() - o = self.q.get() - while o is not WorkerStop: - self.working.append(ct) - ctx, function, args, kwargs = o - try: - context.call(ctx, function, *args, **kwargs) - except: - context.call(ctx, log.err) - self.working.remove(ct) - del o, ctx, function, args, kwargs - self.waiters.append(ct) - o = self.q.get() - self.waiters.remove(ct) - - self.threads.remove(ct) - - def stop(self): - """ - Shutdown the threads in the threadpool. - """ - self.joined = True - threads = copy.copy(self.threads) - while self.workers: - self.q.put(WorkerStop) - self.workers -= 1 - - # and let's just make sure - # FIXME: threads that have died before calling stop() are not joined. - for thread in threads: - thread.join() - - def adjustPoolsize(self, minthreads=None, maxthreads=None): - if minthreads is None: - minthreads = self.min - if maxthreads is None: - maxthreads = self.max - - assert minthreads >= 0, 'minimum is negative' - assert minthreads <= maxthreads, 'minimum is greater than maximum' - - self.min = minthreads - self.max = maxthreads - if not self.started: - return - - # Kill of some threads if we have too many. - while self.workers > self.max: - self.stopAWorker() - # Start some threads if we have too few. - while self.workers < self.min: - self.startAWorker() - # Start some threads if there is a need. - self._startSomeWorkers() - - def dumpStats(self): - log.msg('queue: %s' % self.q.queue) - log.msg('waiters: %s' % self.waiters) - log.msg('workers: %s' % self.working) - log.msg('total: %s' % self.threads) - - -class ThreadSafeList: - """ - In Jython 2.1 lists aren't thread-safe, so this wraps it. - """ - - def __init__(self): - self.lock = threading.Lock() - self.l = [] - - def append(self, i): - self.lock.acquire() - try: - self.l.append(i) - finally: - self.lock.release() - - def remove(self, i): - self.lock.acquire() - try: - self.l.remove(i) - finally: - self.lock.release() - - def __len__(self): - return len(self.l) - diff --git a/tools/buildbot/pylibs/twisted/python/timeoutqueue.py b/tools/buildbot/pylibs/twisted/python/timeoutqueue.py deleted file mode 100644 index 9252dc3..0000000 --- a/tools/buildbot/pylibs/twisted/python/timeoutqueue.py +++ /dev/null @@ -1,49 +0,0 @@ -# -*- test-case-name: twisted.test.test_timeoutqueue -*- -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -A Queue subclass that supports timeouts. -""" - -# System Imports -import Queue, time, warnings - - -_time = time.time -_sleep = time.sleep - - -class TimedOut(Exception): - pass - - -class TimeoutQueue(Queue.Queue): - """ - A thread-safe queue that supports timeouts. - """ - - def __init__(self, max=0): - warnings.warn("timeoutqueue is deprecated since Twisted 8.0", - category=DeprecationWarning, stacklevel=2) - Queue.Queue.__init__(self, max) - - def wait(self, timeout): - """ - Wait until the queue isn't empty. Raises TimedOut if still empty. - """ - endtime = _time() + timeout - delay = 0.0005 # 500 us -> initial delay of 1 ms - while 1: - gotit = not self.empty() - if gotit: - break - remaining = endtime - _time() - if remaining <= 0: - raise TimedOut, "timed out." - delay = min(delay * 2, remaining, .05) - _sleep(delay) - - -__all__ = ["TimeoutQueue", "TimedOut"] - diff --git a/tools/buildbot/pylibs/twisted/python/urlpath.py b/tools/buildbot/pylibs/twisted/python/urlpath.py deleted file mode 100644 index bee8357..0000000 --- a/tools/buildbot/pylibs/twisted/python/urlpath.py +++ /dev/null @@ -1,122 +0,0 @@ -# -*- test-case-name: twisted.test.test_paths -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -import urlparse -import urllib - -class URLPath: - def __init__(self, scheme='', netloc='localhost', path='', - query='', fragment=''): - self.scheme = scheme or 'http' - self.netloc = netloc - self.path = path or '/' - self.query = query - self.fragment = fragment - - _qpathlist = None - _uqpathlist = None - - def pathList(self, unquote=0, copy=1): - if self._qpathlist is None: - self._qpathlist = self.path.split('/') - self._uqpathlist = map(urllib.unquote, self._qpathlist) - if unquote: - result = self._uqpathlist - else: - result = self._qpathlist - if copy: - return result[:] - else: - return result - - def fromString(klass, st): - t = urlparse.urlsplit(st) - u = klass(*t) - return u - - fromString = classmethod(fromString) - - def fromRequest(klass, request): - return klass.fromString(request.prePathURL()) - - fromRequest = classmethod(fromRequest) - - def _pathMod(self, newpathsegs, keepQuery): - if keepQuery: - query = self.query - else: - query = '' - return URLPath(self.scheme, - self.netloc, - '/'.join(newpathsegs), - query) - - def sibling(self, path, keepQuery=0): - l = self.pathList() - l[-1] = path - return self._pathMod(l, keepQuery) - - def child(self, path, keepQuery=0): - l = self.pathList() - if l[-1] == '': - l[-1] = path - else: - l.append(path) - return self._pathMod(l, keepQuery) - - def parent(self, keepQuery=0): - l = self.pathList() - if l[-1] == '': - del l[-2] - else: - # We are a file, such as http://example.com/foo/bar - # our parent directory is http://example.com/ - l.pop() - l[-1] = '' - return self._pathMod(l, keepQuery) - - def here(self, keepQuery=0): - l = self.pathList() - if l[-1] != '': - l[-1] = '' - return self._pathMod(l, keepQuery) - - def click(self, st): - """Return a path which is the URL where a browser would presumably take - you if you clicked on a link with an HREF as given. - """ - scheme, netloc, path, query, fragment = urlparse.urlsplit(st) - if not scheme: - scheme = self.scheme - if not netloc: - netloc = self.netloc - if not path: - path = self.path - if not query: - query = self.query - elif path[0] != '/': - l = self.pathList() - l[-1] = path - path = '/'.join(l) - - return URLPath(scheme, - netloc, - path, - query, - fragment) - - - - def __str__(self): - x = urlparse.urlunsplit(( - self.scheme, self.netloc, self.path, - self.query, self.fragment)) - return x - - def __repr__(self): - return ('URLPath(scheme=%r, netloc=%r, path=%r, query=%r, fragment=%r)' - % (self.scheme, self.netloc, self.path, self.query, self.fragment)) - diff --git a/tools/buildbot/pylibs/twisted/python/usage.py b/tools/buildbot/pylibs/twisted/python/usage.py deleted file mode 100644 index 7abe355..0000000 --- a/tools/buildbot/pylibs/twisted/python/usage.py +++ /dev/null @@ -1,631 +0,0 @@ -# -*- test-case-name: twisted.test.test_usage -*- -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -twisted.python.usage is a module for parsing/handling the -command line of your program. - -For information on how to use it, see -U{http://twistedmatrix.com/projects/core/documentation/howto/options.html}, -or doc/howto/options.html in your Twisted directory. -""" - -# System Imports -import os -import sys -import getopt -from os import path - -# Sibling Imports -from twisted.python import reflect, text, util - - -class UsageError(Exception): - pass - - -error = UsageError - - -class CoerceParameter(object): - """ - Utility class that can corce a parameter before storing it. - """ - def __init__(self, options, coerce): - """ - @param options: parent Options object - @param coerce: callable used to coerce the value. - """ - self.options = options - self.coerce = coerce - self.doc = getattr(self.coerce, 'coerceDoc', '') - - def dispatch(self, parameterName, value): - """ - When called in dispatch, do the coerce for C{value} and save the - returned value. - """ - if value is None: - raise UsageError("Parameter '%s' requires an argument." - % (parameterName,)) - try: - value = self.coerce(value) - except ValueError, e: - raise UsageError("Parameter type enforcement failed: %s" % (e,)) - - self.options.opts[parameterName] = value - - -class Options(dict): - """ - An option list parser class - - C{optFlags} and C{optParameters} are lists of available parameters - which your program can handle. The difference between the two - is the 'flags' have an on(1) or off(0) state (off by default) - whereas 'parameters' have an assigned value, with an optional - default. (Compare '--verbose' and '--verbosity=2') - - optFlags is assigned a list of lists. Each list represents - a flag parameter, as so:: - - | optFlags = [['verbose', 'v', 'Makes it tell you what it doing.'], - | ['quiet', 'q', 'Be vewy vewy quiet.']] - - As you can see, the first item is the long option name - (prefixed with '--' on the command line), followed by the - short option name (prefixed with '-'), and the description. - The description is used for the built-in handling of the - --help switch, which prints a usage summary. - - C{optParameters} is much the same, except the list also contains - a default value:: - - | optParameters = [['outfile', 'O', 'outfile.log', 'Description...']] - - A coerce function can also be specified as the last element: it will be - called with the argument and should return the value that will be stored - for the option. This function can have a C{coerceDoc} attribute which - will be appended to the documentation of the option. - - subCommands is a list of 4-tuples of (command name, command shortcut, - parser class, documentation). If the first non-option argument found is - one of the given command names, an instance of the given parser class is - instantiated and given the remainder of the arguments to parse and - self.opts[command] is set to the command name. For example:: - - | subCommands = [ - | ['inquisition', 'inquest', InquisitionOptions, - | 'Perform an inquisition'], - | ['holyquest', 'quest', HolyQuestOptions, - | 'Embark upon a holy quest'] - | ] - - In this case, C{" holyquest --horseback --for-grail"} will cause - C{HolyQuestOptions} to be instantiated and asked to parse - C{['--horseback', '--for-grail']}. Currently, only the first sub-command - is parsed, and all options following it are passed to its parser. If a - subcommand is found, the subCommand attribute is set to its name and the - subOptions attribute is set to the Option instance that parses the - remaining options. If a subcommand is not given to parseOptions, - the subCommand attribute will be None. You can also mark one of - the subCommands to be the default. - - | defaultSubCommand = 'holyquest' - - In this case, the subCommand attribute will never be None, and - the subOptions attribute will always be set. - - If you want to handle your own options, define a method named - C{opt_paramname} that takes C{(self, option)} as arguments. C{option} - will be whatever immediately follows the parameter on the - command line. Options fully supports the mapping interface, so you - can do things like C{'self["option"] = val'} in these methods. - - Advanced functionality is covered in the howto documentation, - available at - U{http://twistedmatrix.com/projects/core/documentation/howto/options.html}, - or doc/howto/options.html in your Twisted directory. - """ - - subCommand = None - defaultSubCommand = None - parent = None - def __init__(self): - super(Options, self).__init__() - - self.opts = self - self.defaults = {} - - # These are strings/lists we will pass to getopt - self.longOpt = [] - self.shortOpt = '' - self.docs = {} - self.synonyms = {} - self._dispatch = {} - - - collectors = [ - self._gather_flags, - self._gather_parameters, - self._gather_handlers, - ] - - for c in collectors: - (longOpt, shortOpt, docs, settings, synonyms, dispatch) = c() - self.longOpt.extend(longOpt) - self.shortOpt = self.shortOpt + shortOpt - self.docs.update(docs) - - self.opts.update(settings) - self.defaults.update(settings) - - self.synonyms.update(synonyms) - self._dispatch.update(dispatch) - - def __hash__(self): - """ - Define a custom hash function so that Options instances can be used - as dictionary keys. This is an internal feature used to implement - the parser. Do not rely on it in application code. - """ - return int(id(self) % sys.maxint) - - def opt_help(self): - """ - Display this help and exit. - """ - print self.__str__() - sys.exit(0) - - def opt_version(self): - from twisted import copyright - print "Twisted version:", copyright.version - sys.exit(0) - - #opt_h = opt_help # this conflicted with existing 'host' options. - - def parseOptions(self, options=None): - """ - The guts of the command-line parser. - """ - - if options is None: - options = sys.argv[1:] - try: - opts, args = getopt.getopt(options, - self.shortOpt, self.longOpt) - except getopt.error, e: - raise UsageError(str(e)) - - for opt, arg in opts: - if opt[1] == '-': - opt = opt[2:] - else: - opt = opt[1:] - - optMangled = opt - if optMangled not in self.synonyms: - optMangled = opt.replace("-", "_") - if optMangled not in self.synonyms: - raise UsageError("No such option '%s'" % (opt,)) - - optMangled = self.synonyms[optMangled] - if isinstance(self._dispatch[optMangled], CoerceParameter): - self._dispatch[optMangled].dispatch(optMangled, arg) - else: - self._dispatch[optMangled](optMangled, arg) - - if (getattr(self, 'subCommands', None) - and (args or self.defaultSubCommand is not None)): - if not args: - args = [self.defaultSubCommand] - sub, rest = args[0], args[1:] - for (cmd, short, parser, doc) in self.subCommands: - if sub == cmd or sub == short: - self.subCommand = cmd - self.subOptions = parser() - self.subOptions.parent = self - self.subOptions.parseOptions(rest) - break - else: - raise UsageError("Unknown command: %s" % sub) - else: - try: - self.parseArgs(*args) - except TypeError: - raise UsageError("Wrong number of arguments.") - - self.postOptions() - - def postOptions(self): - """ - I am called after the options are parsed. - - Override this method in your subclass to do something after - the options have been parsed and assigned, like validate that - all options are sane. - """ - - def parseArgs(self): - """ - I am called with any leftover arguments which were not options. - - Override me to do something with the remaining arguments on - the command line, those which were not flags or options. e.g. - interpret them as a list of files to operate on. - - Note that if there more arguments on the command line - than this method accepts, parseArgs will blow up with - a getopt.error. This means if you don't override me, - parseArgs will blow up if I am passed any arguments at - all! - """ - - def _generic_flag(self, flagName, value=None): - if value not in ('', None): - raise UsageError("Flag '%s' takes no argument." - " Not even \"%s\"." % (flagName, value)) - - self.opts[flagName] = 1 - - def _gather_flags(self): - """ - Gather up boolean (flag) options. - """ - - longOpt, shortOpt = [], '' - docs, settings, synonyms, dispatch = {}, {}, {}, {} - - flags = [] - reflect.accumulateClassList(self.__class__, 'optFlags', flags) - - for flag in flags: - long, short, doc = util.padTo(3, flag) - if not long: - raise ValueError("A flag cannot be without a name.") - - docs[long] = doc - settings[long] = 0 - if short: - shortOpt = shortOpt + short - synonyms[short] = long - longOpt.append(long) - synonyms[long] = long - dispatch[long] = self._generic_flag - - return longOpt, shortOpt, docs, settings, synonyms, dispatch - - def _gather_parameters(self): - """ - Gather options which take a value. - """ - longOpt, shortOpt = [], '' - docs, settings, synonyms, dispatch = {}, {}, {}, {} - - parameters = [] - - reflect.accumulateClassList(self.__class__, 'optStrings', - parameters) - if parameters: - import warnings - warnings.warn("Options.optStrings is deprecated, " - "please use optParameters instead.", stacklevel=2) - - reflect.accumulateClassList(self.__class__, 'optParameters', - parameters) - - synonyms = {} - - for parameter in parameters: - long, short, default, doc, paramType = util.padTo(5, parameter) - if not long: - raise ValueError("A parameter cannot be without a name.") - - docs[long] = doc - settings[long] = default - if short: - shortOpt = shortOpt + short + ':' - synonyms[short] = long - longOpt.append(long + '=') - synonyms[long] = long - if paramType is not None: - dispatch[long] = CoerceParameter(self, paramType) - else: - dispatch[long] = CoerceParameter(self, str) - - return longOpt, shortOpt, docs, settings, synonyms, dispatch - - - def _gather_handlers(self): - """ - Gather up options with their own handler methods. - """ - - longOpt, shortOpt = [], '' - docs, settings, synonyms, dispatch = {}, {}, {}, {} - - dct = {} - reflect.addMethodNamesToDict(self.__class__, dct, "opt_") - - for name in dct.keys(): - method = getattr(self, 'opt_'+name) - - takesArg = not flagFunction(method, name) - - prettyName = name.replace('_', '-') - doc = getattr(method, '__doc__', None) - if doc: - ## Only use the first line. - #docs[name] = doc.split('\n')[0] - docs[prettyName] = doc - else: - docs[prettyName] = self.docs.get(prettyName) - - synonyms[prettyName] = prettyName - - # A little slight-of-hand here makes dispatching much easier - # in parseOptions, as it makes all option-methods have the - # same signature. - if takesArg: - fn = lambda name, value, m=method: m(value) - else: - # XXX: This won't raise a TypeError if it's called - # with a value when it shouldn't be. - fn = lambda name, value=None, m=method: m() - - dispatch[prettyName] = fn - - if len(name) == 1: - shortOpt = shortOpt + name - if takesArg: - shortOpt = shortOpt + ':' - else: - if takesArg: - prettyName = prettyName + '=' - longOpt.append(prettyName) - - reverse_dct = {} - # Map synonyms - for name in dct.keys(): - method = getattr(self, 'opt_' + name) - if method not in reverse_dct: - reverse_dct[method] = [] - reverse_dct[method].append(name) - - cmpLength = lambda a, b: cmp(len(a), len(b)) - - for method, names in reverse_dct.items(): - if len(names) < 2: - continue - names_ = names[:] - names_.sort(cmpLength) - longest = names_.pop() - for name in names_: - synonyms[name] = longest - - return longOpt, shortOpt, docs, settings, synonyms, dispatch - - - def __str__(self): - return self.getSynopsis() + '\n' + self.getUsage(width=None) - - def getSynopsis(self): - """ - Returns a string containing a description of these options and how to - pass them to the executed file. - """ - - default = "%s%s" % (path.basename(sys.argv[0]), - (self.longOpt and " [options]") or '') - if self.parent is None: - default = "Usage: %s%s" % (path.basename(sys.argv[0]), - (self.longOpt and " [options]") or '') - else: - default = '%s' % ((self.longOpt and "[options]") or '') - synopsis = getattr(self, "synopsis", default) - - synopsis = synopsis.rstrip() - - if self.parent is not None: - synopsis = ' '.join((self.parent.getSynopsis(), - self.parent.subCommand, synopsis)) - - return synopsis - - def getUsage(self, width=None): - # If subOptions exists by now, then there was probably an error while - # parsing its options. - if hasattr(self, 'subOptions'): - return self.subOptions.getUsage(width=width) - - if not width: - width = int(os.environ.get('COLUMNS', '80')) - - if hasattr(self, 'subCommands'): - cmdDicts = [] - for (cmd, short, parser, desc) in self.subCommands: - cmdDicts.append( - {'long': cmd, - 'short': short, - 'doc': desc, - 'optType': 'command', - 'default': None - }) - chunks = docMakeChunks(cmdDicts, width) - commands = 'Commands:\n' + ''.join(chunks) - else: - commands = '' - - longToShort = {} - for key, value in self.synonyms.items(): - longname = value - if (key != longname) and (len(key) == 1): - longToShort[longname] = key - else: - if longname not in longToShort: - longToShort[longname] = None - else: - pass - - optDicts = [] - for opt in self.longOpt: - if opt[-1] == '=': - optType = 'parameter' - opt = opt[:-1] - else: - optType = 'flag' - - optDicts.append( - {'long': opt, - 'short': longToShort[opt], - 'doc': self.docs[opt], - 'optType': optType, - 'default': self.defaults.get(opt, None), - 'dispatch': self._dispatch.get(opt, None) - }) - - if not (getattr(self, "longdesc", None) is None): - longdesc = self.longdesc - else: - import __main__ - if getattr(__main__, '__doc__', None): - longdesc = __main__.__doc__ - else: - longdesc = '' - - if longdesc: - longdesc = ('\n' + - '\n'.join(text.wordWrap(longdesc, width)).strip() - + '\n') - - if optDicts: - chunks = docMakeChunks(optDicts, width) - s = "Options:\n%s" % (''.join(chunks)) - else: - s = "Options: None\n" - - return s + longdesc + commands - - #def __repr__(self): - # XXX: It'd be cool if we could return a succinct representation - # of which flags and options are set here. - - -def docMakeChunks(optList, width=80): - """ - Makes doc chunks for option declarations. - - Takes a list of dictionaries, each of which may have one or more - of the keys 'long', 'short', 'doc', 'default', 'optType'. - - Returns a list of strings. - The strings may be multiple lines, - all of them end with a newline. - """ - - # XXX: sanity check to make sure we have a sane combination of keys. - - maxOptLen = 0 - for opt in optList: - optLen = len(opt.get('long', '')) - if optLen: - if opt.get('optType', None) == "parameter": - # these take up an extra character - optLen = optLen + 1 - maxOptLen = max(optLen, maxOptLen) - - colWidth1 = maxOptLen + len(" -s, -- ") - colWidth2 = width - colWidth1 - # XXX - impose some sane minimum limit. - # Then if we don't have enough room for the option and the doc - # to share one line, they can take turns on alternating lines. - - colFiller1 = " " * colWidth1 - - optChunks = [] - seen = {} - for opt in optList: - if opt.get('short', None) in seen or opt.get('long', None) in seen: - continue - for x in opt.get('short', None), opt.get('long', None): - if x is not None: - seen[x] = 1 - - optLines = [] - comma = " " - if opt.get('short', None): - short = "-%c" % (opt['short'],) - else: - short = '' - - if opt.get('long', None): - long = opt['long'] - if opt.get("optType", None) == "parameter": - long = long + '=' - - long = "%-*s" % (maxOptLen, long) - if short: - comma = "," - else: - long = " " * (maxOptLen + len('--')) - - if opt.get('optType', None) == 'command': - column1 = ' %s ' % long - else: - column1 = " %2s%c --%s " % (short, comma, long) - - if opt.get('doc', ''): - doc = opt['doc'].strip() - else: - doc = '' - - if (opt.get("optType", None) == "parameter") \ - and not (opt.get('default', None) is None): - doc = "%s [default: %s]" % (doc, opt['default']) - - if (opt.get("optType", None) == "parameter") \ - and opt.get('dispatch', None) is not None: - d = opt['dispatch'] - if isinstance(d, CoerceParameter) and d.doc: - doc = "%s. %s" % (doc, d.doc) - - if doc: - column2_l = text.wordWrap(doc, colWidth2) - else: - column2_l = [''] - - optLines.append("%s%s\n" % (column1, column2_l.pop(0))) - - for line in column2_l: - optLines.append("%s%s\n" % (colFiller1, line)) - - optChunks.append(''.join(optLines)) - - return optChunks - - -def flagFunction(method, name=None): - reqArgs = method.im_func.func_code.co_argcount - if reqArgs > 2: - raise UsageError('Invalid Option function for %s' % - (name or method.func_name)) - if reqArgs == 2: - # argName = method.im_func.func_code.co_varnames[1] - return 0 - return 1 - - -def portCoerce(value): - """ - Coerce a string value to an int port number, and checks the validity. - """ - value = int(value) - if value < 0 or value > 65535: - raise ValueError("Port number not in range: %s" % (value,)) - return value -portCoerce.coerceDoc = "Must be an int between 0 and 65535." - - diff --git a/tools/buildbot/pylibs/twisted/python/util.py b/tools/buildbot/pylibs/twisted/python/util.py deleted file mode 100644 index 82180521..0000000 --- a/tools/buildbot/pylibs/twisted/python/util.py +++ /dev/null @@ -1,915 +0,0 @@ -# -*- test-case-name: twisted.python.test.test_util -*- -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -import os, sys, hmac, errno, new, inspect -try: - import pwd, grp -except ImportError: - pwd = grp = None -try: - from os import setgroups, getgroups -except ImportError: - setgroups = getgroups = None -from UserDict import UserDict - - -class InsensitiveDict: - """Dictionary, that has case-insensitive keys. - - Normally keys are retained in their original form when queried with - .keys() or .items(). If initialized with preserveCase=0, keys are both - looked up in lowercase and returned in lowercase by .keys() and .items(). - """ - """ - Modified recipe at - http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66315 originally - contributed by Sami Hangaslammi. - """ - - def __init__(self, dict=None, preserve=1): - """Create an empty dictionary, or update from 'dict'.""" - self.data = {} - self.preserve=preserve - if dict: - self.update(dict) - - def __delitem__(self, key): - k=self._lowerOrReturn(key) - del self.data[k] - - def _lowerOrReturn(self, key): - if isinstance(key, str) or isinstance(key, unicode): - return key.lower() - else: - return key - - def __getitem__(self, key): - """Retrieve the value associated with 'key' (in any case).""" - k = self._lowerOrReturn(key) - return self.data[k][1] - - def __setitem__(self, key, value): - """Associate 'value' with 'key'. If 'key' already exists, but - in different case, it will be replaced.""" - k = self._lowerOrReturn(key) - self.data[k] = (key, value) - - def has_key(self, key): - """Case insensitive test whether 'key' exists.""" - k = self._lowerOrReturn(key) - return self.data.has_key(k) - __contains__=has_key - - def _doPreserve(self, key): - if not self.preserve and (isinstance(key, str) - or isinstance(key, unicode)): - return key.lower() - else: - return key - - def keys(self): - """List of keys in their original case.""" - return list(self.iterkeys()) - - def values(self): - """List of values.""" - return list(self.itervalues()) - - def items(self): - """List of (key,value) pairs.""" - return list(self.iteritems()) - - def get(self, key, default=None): - """Retrieve value associated with 'key' or return default value - if 'key' doesn't exist.""" - try: - return self[key] - except KeyError: - return default - - def setdefault(self, key, default): - """If 'key' doesn't exists, associate it with the 'default' value. - Return value associated with 'key'.""" - if not self.has_key(key): - self[key] = default - return self[key] - - def update(self, dict): - """Copy (key,value) pairs from 'dict'.""" - for k,v in dict.items(): - self[k] = v - - def __repr__(self): - """String representation of the dictionary.""" - items = ", ".join([("%r: %r" % (k,v)) for k,v in self.items()]) - return "InsensitiveDict({%s})" % items - - def iterkeys(self): - for v in self.data.itervalues(): - yield self._doPreserve(v[0]) - - def itervalues(self): - for v in self.data.itervalues(): - yield v[1] - - def iteritems(self): - for (k, v) in self.data.itervalues(): - yield self._doPreserve(k), v - - def popitem(self): - i=self.items()[0] - del self[i[0]] - return i - - def clear(self): - for k in self.keys(): - del self[k] - - def copy(self): - return InsensitiveDict(self, self.preserve) - - def __len__(self): - return len(self.data) - - def __eq__(self, other): - for k,v in self.items(): - if not (k in other) or not (other[k]==v): - return 0 - return len(self)==len(other) - -class OrderedDict(UserDict): - """A UserDict that preserves insert order whenever possible.""" - def __init__(self, dict=None, **kwargs): - self._order = [] - self.data = {} - if dict is not None: - if hasattr(dict,'keys'): - self.update(dict) - else: - for k,v in dict: # sequence - self[k] = v - if len(kwargs): - self.update(kwargs) - def __repr__(self): - return '{'+', '.join([('%r: %r' % item) for item in self.items()])+'}' - - def __setitem__(self, key, value): - if not self.has_key(key): - self._order.append(key) - UserDict.__setitem__(self, key, value) - - def copy(self): - return self.__class__(self) - - def __delitem__(self, key): - UserDict.__delitem__(self, key) - self._order.remove(key) - - def iteritems(self): - for item in self._order: - yield (item, self[item]) - - def items(self): - return list(self.iteritems()) - - def itervalues(self): - for item in self._order: - yield self[item] - - def values(self): - return list(self.itervalues()) - - def iterkeys(self): - return iter(self._order) - - def keys(self): - return list(self._order) - - def popitem(self): - key = self._order[-1] - value = self[key] - del self[key] - return (key, value) - - def setdefault(self, item, default): - if self.has_key(item): - return self[item] - self[item] = default - return default - - def update(self, d): - for k, v in d.items(): - self[k] = v - -def uniquify(lst): - """Make the elements of a list unique by inserting them into a dictionary. - This must not change the order of the input lst. - """ - dct = {} - result = [] - for k in lst: - if not dct.has_key(k): result.append(k) - dct[k] = 1 - return result - -def padTo(n, seq, default=None): - """Pads a sequence out to n elements, - - filling in with a default value if it is not long enough. - - If the input sequence is longer than n, raises ValueError. - - Details, details: - This returns a new list; it does not extend the original sequence. - The new list contains the values of the original sequence, not copies. - """ - - if len(seq) > n: - raise ValueError, "%d elements is more than %d." % (len(seq), n) - - blank = [default] * n - - blank[:len(seq)] = list(seq) - - return blank - -def getPluginDirs(): - import twisted - systemPlugins = os.path.join(os.path.dirname(os.path.dirname( - os.path.abspath(twisted.__file__))), 'plugins') - userPlugins = os.path.expanduser("~/TwistedPlugins") - confPlugins = os.path.expanduser("~/.twisted") - allPlugins = filter(os.path.isdir, [systemPlugins, userPlugins, confPlugins]) - return allPlugins - -def addPluginDir(): - sys.path.extend(getPluginDirs()) - -def sibpath(path, sibling): - """Return the path to a sibling of a file in the filesystem. - - This is useful in conjunction with the special __file__ attribute - that Python provides for modules, so modules can load associated - resource files. - """ - return os.path.join(os.path.dirname(os.path.abspath(path)), sibling) - - -def _getpass(prompt): - """Helper to turn IOErrors into KeyboardInterrupts""" - import getpass - try: - return getpass.getpass(prompt) - except IOError, e: - if e.errno == errno.EINTR: - raise KeyboardInterrupt - raise - except EOFError: - raise KeyboardInterrupt - -def getPassword(prompt = 'Password: ', confirm = 0, forceTTY = 0, - confirmPrompt = 'Confirm password: ', - mismatchMessage = "Passwords don't match."): - """Obtain a password by prompting or from stdin. - - If stdin is a terminal, prompt for a new password, and confirm (if - C{confirm} is true) by asking again to make sure the user typed the same - thing, as keystrokes will not be echoed. - - If stdin is not a terminal, and C{forceTTY} is not true, read in a line - and use it as the password, less the trailing newline, if any. If - C{forceTTY} is true, attempt to open a tty and prompt for the password - using it. Raise a RuntimeError if this is not possible. - - @returns: C{str} - """ - isaTTY = hasattr(sys.stdin, 'isatty') and sys.stdin.isatty() - - old = None - try: - if not isaTTY: - if forceTTY: - try: - old = sys.stdin, sys.stdout - sys.stdin = sys.stdout = open('/dev/tty', 'r+') - except: - raise RuntimeError("Cannot obtain a TTY") - else: - password = sys.stdin.readline() - if password[-1] == '\n': - password = password[:-1] - return password - - while 1: - try1 = _getpass(prompt) - if not confirm: - return try1 - try2 = _getpass(confirmPrompt) - if try1 == try2: - return try1 - else: - sys.stderr.write(mismatchMessage + "\n") - finally: - if old: - sys.stdin.close() - sys.stdin, sys.stdout = old - - -def dict(*a, **k): - import warnings - import __builtin__ - warnings.warn('twisted.python.util.dict is deprecated. Use __builtin__.dict instead') - return __builtin__.dict(*a, **k) - -def println(*a): - sys.stdout.write(' '.join(map(str, a))+'\n') - -# XXX -# This does not belong here -# But where does it belong? - -def str_xor(s, b): - return ''.join([chr(ord(c) ^ b) for c in s]) - -def keyed_md5(secret, challenge): - """Create the keyed MD5 string for the given secret and challenge.""" - import warnings - warnings.warn( - "keyed_md5() is deprecated. Use the stdlib module hmac instead.", - DeprecationWarning, stacklevel=2 - ) - return hmac.HMAC(secret, challenge).hexdigest() - -def makeStatBar(width, maxPosition, doneChar = '=', undoneChar = '-', currentChar = '>'): - """Creates a function that will return a string representing a progress bar. - """ - aValue = width / float(maxPosition) - def statBar(position, force = 0, last = ['']): - assert len(last) == 1, "Don't mess with the last parameter." - done = int(aValue * position) - toDo = width - done - 2 - result = "[%s%s%s]" % (doneChar * done, currentChar, undoneChar * toDo) - if force: - last[0] = result - return result - if result == last[0]: - return '' - last[0] = result - return result - - statBar.__doc__ = """statBar(position, force = 0) -> '[%s%s%s]'-style progress bar - - returned string is %d characters long, and the range goes from 0..%d. - The 'position' argument is where the '%s' will be drawn. If force is false, - '' will be returned instead if the resulting progress bar is identical to the - previously returned progress bar. -""" % (doneChar * 3, currentChar, undoneChar * 3, width, maxPosition, currentChar) - return statBar - -def spewer(frame, s, ignored): - """A trace function for sys.settrace that prints every function or method call.""" - from twisted.python import reflect - if frame.f_locals.has_key('self'): - se = frame.f_locals['self'] - if hasattr(se, '__class__'): - k = reflect.qual(se.__class__) - else: - k = reflect.qual(type(se)) - print 'method %s of %s at %s' % ( - frame.f_code.co_name, k, id(se) - ) - else: - print 'function %s in %s, line %s' % ( - frame.f_code.co_name, - frame.f_code.co_filename, - frame.f_lineno) - -def searchupwards(start, files=[], dirs=[]): - """Walk upwards from start, looking for a directory containing - all files and directories given as arguments:: - >>> searchupwards('.', ['foo.txt'], ['bar', 'bam']) - - If not found, return None - """ - start=os.path.abspath(start) - parents=start.split(os.sep) - exists=os.path.exists; join=os.sep.join; isdir=os.path.isdir - while len(parents): - candidate=join(parents)+os.sep - allpresent=1 - for f in files: - if not exists("%s%s" % (candidate, f)): - allpresent=0 - break - if allpresent: - for d in dirs: - if not isdir("%s%s" % (candidate, d)): - allpresent=0 - break - if allpresent: return candidate - parents.pop(-1) - return None - - -class LineLog: - """ - A limited-size line-based log, useful for logging line-based - protocols such as SMTP. - - When the log fills up, old entries drop off the end. - """ - def __init__(self, size=10): - """ - Create a new log, with size lines of storage (default 10). - A log size of 0 (or less) means an infinite log. - """ - if size < 0: - size = 0 - self.log = [None]*size - self.size = size - - def append(self,line): - if self.size: - self.log[:-1] = self.log[1:] - self.log[-1] = line - else: - self.log.append(line) - - def str(self): - return '\n'.join(filter(None,self.log)) - - def __getitem__(self, item): - return filter(None,self.log)[item] - - def clear(self): - """Empty the log""" - self.log = [None]*self.size - -def raises(exception, f, *args, **kwargs): - """Determine whether the given call raises the given exception""" - try: - f(*args, **kwargs) - except exception: - return 1 - return 0 - -class IntervalDifferential: - """ - Given a list of intervals, generate the amount of time to sleep between - \"instants\". - - For example, given 7, 11 and 13, the three (infinite) sequences:: - - 7 14 21 28 35 ... - 11 22 33 44 ... - 13 26 39 52 ... - - will be generated, merged, and used to produce:: - - (7, 0) (4, 1) (2, 2) (1, 0) (7, 0) (1, 1) (4, 2) (2, 0) (5, 1) (2, 0) - - New intervals may be added or removed as iteration proceeds using the - proper methods. - """ - - def __init__(self, intervals, default=60): - """ - @type intervals: C{list} of C{int}, C{long}, or C{float} param - @param intervals: The intervals between instants. - - @type default: C{int}, C{long}, or C{float} - @param default: The duration to generate if the intervals list - becomes empty. - """ - self.intervals = intervals[:] - self.default = default - - def __iter__(self): - return _IntervalDifferentialIterator(self.intervals, self.default) - -class _IntervalDifferentialIterator: - def __init__(self, i, d): - - self.intervals = [[e, e, n] for (e, n) in zip(i, range(len(i)))] - self.default = d - self.last = 0 - - def next(self): - if not self.intervals: - return (self.default, None) - last, index = self.intervals[0][0], self.intervals[0][2] - self.intervals[0][0] += self.intervals[0][1] - self.intervals.sort() - result = last - self.last - self.last = last - return result, index - - def addInterval(self, i): - if self.intervals: - delay = self.intervals[0][0] - self.intervals[0][1] - self.intervals.append([delay + i, i, len(self.intervals)]) - self.intervals.sort() - else: - self.intervals.append([i, i, 0]) - - def removeInterval(self, interval): - for i in range(len(self.intervals)): - if self.intervals[i][1] == interval: - index = self.intervals[i][2] - del self.intervals[i] - for i in self.intervals: - if i[2] > index: - i[2] -= 1 - return - raise ValueError, "Specified interval not in IntervalDifferential" - - -class FancyStrMixin: - """ - Set showAttributes to a sequence of strings naming attributes, OR - sequences of (attributeName, displayName, formatCharacter) - """ - showAttributes = () - def __str__(self): - r = ['<', hasattr(self, 'fancybasename') and self.fancybasename or self.__class__.__name__] - for attr in self.showAttributes: - if isinstance(attr, str): - r.append(' %s=%r' % (attr, getattr(self, attr))) - else: - r.append((' %s=' + attr[2]) % (attr[1], getattr(self, attr[0]))) - r.append('>') - return ''.join(r) - __repr__ = __str__ - - - -class FancyEqMixin: - compareAttributes = () - def __eq__(self, other): - if not self.compareAttributes: - return self is other - if isinstance(self, other.__class__): - return ( - [getattr(self, name) for name in self.compareAttributes] == - [getattr(other, name) for name in self.compareAttributes]) - return NotImplemented - - - def __ne__(self, other): - result = self.__eq__(other) - if result is NotImplemented: - return result - return not result - - - -def dsu(list, key): - L2 = [(key(e), i, e) for (i, e) in zip(range(len(list)), list)] - L2.sort() - return [e[2] for e in L2] - -if pwd is None or grp is None or setgroups is None or getgroups is None: - def initgroups(uid, primaryGid): - """ - Do nothing. - - Underlying platform support require to manipulate groups is missing. - """ -else: - def _setgroups_until_success(l): - while(1): - # NASTY NASTY HACK (but glibc does it so it must be okay): - # In case sysconfig didn't give the right answer, find the limit - # on max groups by just looping, trying to set fewer and fewer - # groups each time until it succeeds. - try: - setgroups(l) - except ValueError: - # This exception comes from python itself restricting - # number of groups allowed. - if len(l) > 1: - del l[-1] - else: - raise - except OSError, e: - if e.errno == errno.EINVAL and len(l) > 1: - # This comes from the OS saying too many groups - del l[-1] - else: - raise - else: - # Success, yay! - return - - def initgroups(uid, primaryGid): - """ - Initializes the group access list. - - This is done by reading the group database /etc/group and using all - groups of which C{uid} is a member. The additional group - C{primaryGid} is also added to the list. - - If the given user is a member of more than C{NGROUPS}, arbitrary - groups will be silently discarded to bring the number below that - limit. - - @type uid: C{int} - @param uid: The UID for which to look up group information. - - @type primaryGid: C{int} or C{NoneType} - @param primaryGid: If provided, an additional GID to include when - setting the groups. - """ - try: - # Try to get the maximum number of groups - max_groups = os.sysconf("SC_NGROUPS_MAX") - except: - # No predefined limit - max_groups = 0 - - username = pwd.getpwuid(uid)[0] - l = [] - if primaryGid is not None: - l.append(primaryGid) - for groupname, password, gid, userlist in grp.getgrall(): - if username in userlist: - l.append(gid) - if len(l) == max_groups: - break # No more groups, ignore any more - try: - _setgroups_until_success(l) - except OSError, e: - # We might be able to remove this code now that we - # don't try to setgid/setuid even when not asked to. - if e.errno == errno.EPERM: - for g in getgroups(): - if g not in l: - raise - else: - raise - - - -def switchUID(uid, gid, euid=False): - if euid: - setuid = os.seteuid - setgid = os.setegid - else: - setuid = os.setuid - setgid = os.setgid - if gid is not None: - setgid(gid) - if uid is not None: - initgroups(uid, gid) - setuid(uid) - - -class SubclassableCStringIO(object): - """A wrapper around cStringIO to allow for subclassing""" - __csio = None - - def __init__(self, *a, **kw): - from cStringIO import StringIO - self.__csio = StringIO(*a, **kw) - - def __iter__(self): - return self.__csio.__iter__() - - def next(self): - return self.__csio.next() - - def close(self): - return self.__csio.close() - - def isatty(self): - return self.__csio.isatty() - - def seek(self, pos, mode=0): - return self.__csio.seek(pos, mode) - - def tell(self): - return self.__csio.tell() - - def read(self, n=-1): - return self.__csio.read(n) - - def readline(self, length=None): - return self.__csio.readline(length) - - def readlines(self, sizehint=0): - return self.__csio.readlines(sizehint) - - def truncate(self, size=None): - return self.__csio.truncate(size) - - def write(self, s): - return self.__csio.write(s) - - def writelines(self, list): - return self.__csio.writelines(list) - - def flush(self): - return self.__csio.flush() - - def getvalue(self): - return self.__csio.getvalue() - -def moduleMovedForSplit(origModuleName, newModuleName, moduleDesc, - projectName, projectURL, globDict): - from twisted.python import reflect - modoc = """ -%(moduleDesc)s - -This module is DEPRECATED. It has been split off into a third party -package, Twisted %(projectName)s. Please see %(projectURL)s. - -This is just a place-holder that imports from the third-party %(projectName)s -package for backwards compatibility. To use it, you need to install -that package. -""" % {'moduleDesc': moduleDesc, - 'projectName': projectName, - 'projectURL': projectURL} - - #origModule = reflect.namedModule(origModuleName) - try: - newModule = reflect.namedModule(newModuleName) - except ImportError: - raise ImportError("You need to have the Twisted %s " - "package installed to use %s. " - "See %s." - % (projectName, origModuleName, projectURL)) - - # Populate the old module with the new module's contents - for k,v in vars(newModule).items(): - globDict[k] = v - globDict['__doc__'] = modoc - import warnings - warnings.warn("%s has moved to %s. See %s." % (origModuleName, newModuleName, - projectURL), - DeprecationWarning, stacklevel=3) - return - - -def untilConcludes(f, *a, **kw): - while True: - try: - return f(*a, **kw) - except (IOError, OSError), e: - if e.args[0] == errno.EINTR: - continue - raise - -# A value about twice as large as any Python int, to which negative values -# from id() will be added, moving them into a range which should begin just -# above where positive values from id() leave off. -_HUGEINT = (sys.maxint + 1L) * 2L -def unsignedID(obj): - """ - Return the id of an object as an unsigned number so that its hex - representation makes sense - """ - rval = id(obj) - if rval < 0: - rval += _HUGEINT - return rval - -def mergeFunctionMetadata(f, g): - """ - Overwrite C{g}'s name and docstring with values from C{f}. Update - C{g}'s instance dictionary with C{f}'s. - - To use this function safely you must use the return value. In Python 2.3, - L{mergeFunctionMetadata} will create a new function. In later versions of - Python, C{g} will be mutated and returned. - - @return: A function that has C{g}'s behavior and metadata merged from - C{f}. - """ - try: - g.__name__ = f.__name__ - except TypeError: - try: - merged = new.function( - g.func_code, g.func_globals, - f.__name__, inspect.getargspec(g)[-1], - g.func_closure) - except TypeError: - pass - else: - merged = g - try: - merged.__doc__ = f.__doc__ - except (TypeError, AttributeError): - pass - try: - merged.__dict__.update(g.__dict__) - merged.__dict__.update(f.__dict__) - except (TypeError, AttributeError): - pass - merged.__module__ = f.__module__ - return merged - - -def nameToLabel(mname): - """ - Convert a string like a variable name into a slightly more human-friendly - string with spaces and capitalized letters. - - @type mname: C{str} - @param mname: The name to convert to a label. This must be a string - which could be used as a Python identifier. Strings which do not take - this form will result in unpredictable behavior. - - @rtype: C{str} - """ - labelList = [] - word = '' - lastWasUpper = False - for letter in mname: - if letter.isupper() == lastWasUpper: - # Continuing a word. - word += letter - else: - # breaking a word OR beginning a word - if lastWasUpper: - # could be either - if len(word) == 1: - # keep going - word += letter - else: - # acronym - # we're processing the lowercase letter after the acronym-then-capital - lastWord = word[:-1] - firstLetter = word[-1] - labelList.append(lastWord) - word = firstLetter + letter - else: - # definitely breaking: lower to upper - labelList.append(word) - word = letter - lastWasUpper = letter.isupper() - if labelList: - labelList[0] = labelList[0].capitalize() - else: - return mname.capitalize() - labelList.append(word) - return ' '.join(labelList) - - - -def uidFromString(uidString): - """ - Convert a user identifier, as a string, into an integer UID. - - @type uid: C{str} - @param uid: A string giving the base-ten representation of a UID or the - name of a user which can be converted to a UID via L{pwd.getpwnam}. - - @rtype: C{int} - @return: The integer UID corresponding to the given string. - - @raise ValueError: If the user name is supplied and L{pwd} is not - available. - """ - try: - return int(uidString) - except ValueError: - if pwd is None: - raise - return pwd.getpwnam(uidString)[2] - - - -def gidFromString(gidString): - """ - Convert a group identifier, as a string, into an integer GID. - - @type uid: C{str} - @param uid: A string giving the base-ten representation of a GID or the - name of a group which can be converted to a GID via L{grp.getgrnam}. - - @rtype: C{int} - @return: The integer GID corresponding to the given string. - - @raise ValueError: If the group name is supplied and L{grp} is not - available. - """ - try: - return int(gidString) - except ValueError: - if grp is None: - raise - return grp.getgrnam(gidString)[2] - - - -__all__ = [ - "uniquify", "padTo", "getPluginDirs", "addPluginDir", "sibpath", - "getPassword", "dict", "println", "keyed_md5", "makeStatBar", - "OrderedDict", "InsensitiveDict", "spewer", "searchupwards", "LineLog", - "raises", "IntervalDifferential", "FancyStrMixin", "FancyEqMixin", - "dsu", "switchUID", "SubclassableCStringIO", "moduleMovedForSplit", - "unsignedID", "mergeFunctionMetadata", "nameToLabel", "uidFromString", - "gidFromString", -] diff --git a/tools/buildbot/pylibs/twisted/python/versions.py b/tools/buildbot/pylibs/twisted/python/versions.py deleted file mode 100644 index 806784d..0000000 --- a/tools/buildbot/pylibs/twisted/python/versions.py +++ /dev/null @@ -1,235 +0,0 @@ -# -*- test-case-name: twisted.python.test.test_versions -*- -# Copyright (c) 2006-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Versions for Python packages. - -See L{Version}. -""" - -import sys, os - - -class _inf(object): - """ - An object that is bigger than all other objects. - """ - def __cmp__(self, other): - """ - @param other: Another object. - @type other: any - - @return: 0 if other is inf, 1 otherwise. - @rtype: C{int} - """ - if other is _inf: - return 0 - return 1 - -_inf = _inf() - - -class IncomparableVersions(TypeError): - """ - Two versions could not be compared. - """ - -class Version(object): - """ - An object that represents a three-part version number. - - If running from an svn checkout, include the revision number in - the version string. - """ - def __init__(self, package, major, minor, micro, prerelease=None): - """ - @param package: Name of the package that this is a version of. - @type package: C{str} - @param major: The major version number. - @type major: C{int} - @param minor: The minor version number. - @type minor: C{int} - @param micro: The micro version number. - @type micro: C{int} - @param prerelease: The prerelease number. - @type prerelease: C{int} - """ - self.package = package - self.major = major - self.minor = minor - self.micro = micro - self.prerelease = prerelease - - - def short(self): - """ - Return a string in canonical short version format, - ..[+rSVNVer]. - """ - s = self.base() - svnver = self._getSVNVersion() - if svnver: - s += '+r' + str(svnver) - return s - - - def base(self): - """ - Like L{short}, but without the +rSVNVer. - """ - if self.prerelease is None: - pre = "" - else: - pre = "pre%s" % (self.prerelease,) - return '%d.%d.%d%s' % (self.major, - self.minor, - self.micro, - pre) - - - def __repr__(self): - svnver = self._formatSVNVersion() - if svnver: - svnver = ' #' + svnver - if self.prerelease is None: - prerelease = "" - else: - prerelease = ", prerelease=%r" % (self.prerelease,) - return '%s(%r, %d, %d, %d%s)%s' % ( - self.__class__.__name__, - self.package, - self.major, - self.minor, - self.micro, - prerelease, - svnver) - - - def __str__(self): - return '[%s, version %s]' % ( - self.package, - self.short()) - - - def __cmp__(self, other): - """ - Compare two versions, considering major versions, minor versions, micro - versions, then prereleases. - - A version with a prerelease is always less than a version without a - prerelease. If both versions have prereleases, they will be included in - the comparison. - - @param other: Another version. - @type other: L{Version} - - @return: NotImplemented when the other object is not a Version, or one - of -1, 0, or 1. - - @raise IncomparableVersions: when the package names of the versions - differ. - """ - if not isinstance(other, self.__class__): - return NotImplemented - if self.package != other.package: - raise IncomparableVersions("%r != %r" - % (self.package, other.package)) - - if self.prerelease is None: - prerelease = _inf - else: - prerelease = self.prerelease - - if other.prerelease is None: - otherpre = _inf - else: - otherpre = other.prerelease - - x = cmp((self.major, - self.minor, - self.micro, - prerelease), - (other.major, - other.minor, - other.micro, - otherpre)) - return x - - - def _parseSVNEntries_4(self, entriesFile): - """ - Given a readable file object which represents a .svn/entries file in - format version 4, return the revision as a string. We do this by - reading first XML element in the document that has a 'revision' - attribute. - """ - from xml.dom.minidom import parse - doc = parse(entriesFile).documentElement - for node in doc.childNodes: - if hasattr(node, 'getAttribute'): - rev = node.getAttribute('revision') - if rev is not None: - return rev.encode('ascii') - - - def _parseSVNEntries_8(self, entriesFile): - """ - Given a readable file object which represents a .svn/entries file in - format version 8, return the revision as a string. - """ - entriesFile.readline() - entriesFile.readline() - entriesFile.readline() - return entriesFile.readline().strip() - - - def _getSVNVersion(self): - """ - Figure out the SVN revision number based on the existance of - /.svn/entries, and its contents. This requires discovering the - format version from the 'format' file and parsing the entries file - accordingly. - - @return: None or string containing SVN Revision number. - """ - mod = sys.modules.get(self.package) - if mod: - svn = os.path.join(os.path.dirname(mod.__file__), '.svn') - formatFile = os.path.join(svn, 'format') - if not os.path.exists(formatFile): - return None - format = file(formatFile).read().strip() - ent = os.path.join(svn, 'entries') - if not os.path.exists(ent): - return None - parser = getattr(self, '_parseSVNEntries_' + format, None) - if parser is None: - return 'Unknown' - entries = file(ent) - try: - try: - return parser(entries) - finally: - entries.close() - except: - return 'Unknown' - - - def _formatSVNVersion(self): - ver = self._getSVNVersion() - if ver is None: - return '' - return ' (SVN r%s)' % (ver,) - - - -def getVersionString(version): - """ - Get a friendly string for the given version object. - - @param version: A L{Version} object. - @return: A string containing the package and short version number. - """ - result = '%s %s' % (version.package, version.short()) - return result diff --git a/tools/buildbot/pylibs/twisted/python/win32.py b/tools/buildbot/pylibs/twisted/python/win32.py deleted file mode 100644 index c409f0d..0000000 --- a/tools/buildbot/pylibs/twisted/python/win32.py +++ /dev/null @@ -1,160 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Win32 utilities. - -See also twisted.python.shortcut. -""" - -import re -import exceptions -import os - -try: - import win32api - import win32con -except ImportError: - pass - -from twisted.python.runtime import platform - -# http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/system_error_codes.asp -ERROR_FILE_NOT_FOUND = 2 -ERROR_PATH_NOT_FOUND = 3 -ERROR_INVALID_NAME = 123 -ERROR_DIRECTORY = 267 - -def _determineWindowsError(): - """ - Determine which WindowsError name to export. - """ - return getattr(exceptions, 'WindowsError', FakeWindowsError) - -class FakeWindowsError(OSError): - """ - Stand-in for sometimes-builtin exception on platforms for which it - is missing. - """ - -WindowsError = _determineWindowsError() - -# XXX fix this to use python's builtin _winreg? - -def getProgramsMenuPath(): - """Get the path to the Programs menu. - - Probably will break on non-US Windows. - - @returns: the filesystem location of the common Start Menu->Programs. - """ - if not platform.isWinNT(): - return "C:\\Windows\\Start Menu\\Programs" - keyname = 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders' - hShellFolders = win32api.RegOpenKeyEx(win32con.HKEY_LOCAL_MACHINE, - keyname, 0, win32con.KEY_READ) - return win32api.RegQueryValueEx(hShellFolders, 'Common Programs')[0] - - -def getProgramFilesPath(): - """Get the path to the Program Files folder.""" - keyname = 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion' - currentV = win32api.RegOpenKeyEx(win32con.HKEY_LOCAL_MACHINE, - keyname, 0, win32con.KEY_READ) - return win32api.RegQueryValueEx(currentV, 'ProgramFilesDir')[0] - -_cmdLineQuoteRe = re.compile(r'(\\*)"') -_cmdLineQuoteRe2 = re.compile(r'(\\+)\Z') -def cmdLineQuote(s): - """ - Internal method for quoting a single command-line argument. - - @param s: an unquoted string that you want to quote so that something that - does cmd.exe-style unquoting will interpret it as a single argument, even - if it contains spaces. - - @return: a quoted string. - """ - quote = ((" " in s) or ("\t" in s) or ('"' in s)) and '"' or '' - return quote + _cmdLineQuoteRe2.sub(r"\1\1", _cmdLineQuoteRe.sub(r'\1\1\\"', s)) + quote - -def quoteArguments(arguments): - """ - Quote an iterable of command-line arguments for passing to CreateProcess or - a similar API. This allows the list passed to C{reactor.spawnProcess} to - match the child process's C{sys.argv} properly. - - @param arglist: an iterable of C{str}, each unquoted. - - @return: a single string, with the given sequence quoted as necessary. - """ - return ' '.join([cmdLineQuote(a) for a in arguments]) - - -class _ErrorFormatter(object): - """ - Formatter for Windows error messages. - - @ivar winError: A callable which takes one integer error number argument - and returns an L{exceptions.WindowsError} instance for that error (like - L{ctypes.WinError}). - - @ivar formatMessage: A callable which takes one integer error number - argument and returns a C{str} giving the message for that error (like - L{win32api.FormatMessage}). - - @ivar errorTab: A mapping from integer error numbers to C{str} messages - which correspond to those erorrs (like L{socket.errorTab}). - """ - def __init__(self, WinError, FormatMessage, errorTab): - self.winError = WinError - self.formatMessage = FormatMessage - self.errorTab = errorTab - - def fromEnvironment(cls): - """ - Get as many of the platform-specific error translation objects as - possible and return an instance of C{cls} created with them. - """ - try: - from ctypes import WinError - except ImportError: - WinError = None - try: - from win32api import FormatMessage - except ImportError: - FormatMessage = None - try: - from socket import errorTab - except ImportError: - errorTab = None - return cls(WinError, FormatMessage, errorTab) - fromEnvironment = classmethod(fromEnvironment) - - - def formatError(self, errorcode): - """ - Returns the string associated with a Windows error message, such as the - ones found in socket.error. - - Attempts direct lookup against the win32 API via ctypes and then - pywin32 if available), then in the error table in the socket module, - then finally defaulting to C{os.strerror}. - - @param errorcode: the Windows error code - @type errorcode: C{int} - - @return: The error message string - @rtype: C{str} - """ - if self.winError is not None: - return self.winError(errorcode)[1] - if self.formatMessage is not None: - return self.formatMessage(errorcode) - if self.errorTab is not None: - result = self.errorTab.get(errorcode) - if result is not None: - return result - return os.strerror(errorcode) - -formatError = _ErrorFormatter.fromEnvironment().formatError diff --git a/tools/buildbot/pylibs/twisted/python/zippath.py b/tools/buildbot/pylibs/twisted/python/zippath.py deleted file mode 100644 index 2bf29bde..0000000 --- a/tools/buildbot/pylibs/twisted/python/zippath.py +++ /dev/null @@ -1,215 +0,0 @@ -# -*- test-case-name: twisted.test.test_paths.ZipFilePathTestCase -*- - -""" - -This module contains partial re-implementations of FilePath, pending some -specification of formal interfaces it is a duck-typing attempt to emulate them -for certain restricted uses. - -See the constructor for ZipArchive for use. - -""" - -__metaclass__ = type - -import os -import time -import errno - -from twisted.python.zipstream import ChunkingZipFile - -from twisted.python.filepath import FilePath, _PathHelper - -# using FilePath here exclusively rather than os to make sure that we don't do -# anything OS-path-specific here. - -ZIP_PATH_SEP = '/' # In zipfiles, "/" is universally used as the - # path separator, regardless of platform. - - -class ZipPath(_PathHelper): - """ - I represent a file or directory contained within a zip file. - """ - def __init__(self, archive, pathInArchive): - """ - Don't construct me directly. Use ZipArchive.child(). - - @param archive: a ZipArchive instance. - - @param pathInArchive: a ZIP_PATH_SEP-separated string. - """ - self.archive = archive - self.pathInArchive = pathInArchive - # self.path pretends to be os-specific because that's the way the - # 'zipimport' module does it. - self.path = os.path.join(archive.zipfile.filename, - *(self.pathInArchive.split(ZIP_PATH_SEP))) - - def __cmp__(self, other): - if not isinstance(other, ZipPath): - return NotImplemented - return cmp((self.archive, self.pathInArchive), - (other.archive, other.pathInArchive)) - - def __repr__(self): - return 'ZipPath(%r)' % (self.path,) - - def parent(self): - splitup = self.pathInArchive.split(ZIP_PATH_SEP) - if len(splitup) == 1: - return self.archive - return ZipPath(self.archive, ZIP_PATH_SEP.join(splitup[:-1])) - - def child(self, path): - return ZipPath(self.archive, ZIP_PATH_SEP.join([self.pathInArchive, path])) - - def sibling(self, path): - return self.parent().child(path) - - # preauthChild = child - - def exists(self): - return self.isdir() or self.isfile() - - def isdir(self): - return self.pathInArchive in self.archive.childmap - - def isfile(self): - return self.pathInArchive in self.archive.zipfile.NameToInfo - - def islink(self): - return False - - def listdir(self): - if self.exists(): - if self.isdir(): - return self.archive.childmap[self.pathInArchive].keys() - else: - raise OSError(errno.ENOTDIR, "Leaf zip entry listed") - else: - raise OSError(errno.ENOENT, "Non-existent zip entry listed") - - - def splitext(self): - """ - Return a value similar to that returned by os.path.splitext. - """ - # This happens to work out because of the fact that we use OS-specific - # path separators in the constructor to construct our fake 'path' - # attribute. - return os.path.splitext(self.path) - - - def basename(self): - return self.pathInArchive.split(ZIP_PATH_SEP)[-1] - - def dirname(self): - # XXX NOTE: This API isn't a very good idea on filepath, but it's even - # less meaningful here. - return self.parent().path - - def open(self): - return self.archive.zipfile.readfile(self.pathInArchive) - - def restat(self): - pass - - - def getAccessTime(self): - """ - Retrieve this file's last access-time. This is the same as the last access - time for the archive. - - @return: a number of seconds since the epoch - """ - return self.archive.getAccessTime() - - - def getModificationTime(self): - """ - Retrieve this file's last modification time. This is the time of - modification recorded in the zipfile. - - @return: a number of seconds since the epoch. - """ - return time.mktime( - self.archive.zipfile.NameToInfo[self.pathInArchive].date_time - + (0, 0, 0)) - - - def getStatusChangeTime(self): - """ - Retrieve this file's last modification time. This name is provided for - compatibility, and returns the same value as getmtime. - - @return: a number of seconds since the epoch. - """ - return self.getModificationTime() - - - -class ZipArchive(ZipPath): - """ I am a FilePath-like object which can wrap a zip archive as if it were a - directory. - """ - archive = property(lambda self: self) - def __init__(self, archivePathname): - """Create a ZipArchive, treating the archive at archivePathname as a zip file. - - @param archivePathname: a str, naming a path in the filesystem. - """ - self.zipfile = ChunkingZipFile(archivePathname) - self.path = archivePathname - self.pathInArchive = '' - # zipfile is already wasting O(N) memory on cached ZipInfo instances, - # so there's no sense in trying to do this lazily or intelligently - self.childmap = {} # map parent: list of children - - for name in self.zipfile.namelist(): - name = name.split(ZIP_PATH_SEP) - for x in range(len(name)): - child = name[-x] - parent = ZIP_PATH_SEP.join(name[:-x]) - if parent not in self.childmap: - self.childmap[parent] = {} - self.childmap[parent][child] = 1 - parent = '' - - def child(self, path): - """ - Create a ZipPath pointing at a path within the archive. - - @param path: a str with no path separators in it, either '/' or the - system path separator, if it's different. - """ - return ZipPath(self, path) - - def exists(self): - """ - Returns true if the underlying archive exists. - """ - return FilePath(self.zipfile.filename).exists() - - - def getAccessTime(self): - """ - Return the archive file's last access time. - """ - return FilePath(self.zipfile.filename).getAccessTime() - - - def getModificationTime(self): - """ - Return the archive file's modification time. - """ - return FilePath(self.zipfile.filename).getModificationTime() - - - def getStatusChangeTime(self): - """ - Return the archive file's status change time. - """ - return FilePath(self.zipfile.filename).getStatusChangeTime() - - diff --git a/tools/buildbot/pylibs/twisted/python/zipstream.py b/tools/buildbot/pylibs/twisted/python/zipstream.py deleted file mode 100644 index b0e72cc..0000000 --- a/tools/buildbot/pylibs/twisted/python/zipstream.py +++ /dev/null @@ -1,377 +0,0 @@ -# -*- test-case-name: twisted.python.test.test_zipstream -*- -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -An incremental approach to unzipping files. This allows you to unzip a little -bit of a file at a time, which means you can report progress as a file unzips. -""" - -import warnings -import zipfile -import os.path -import zlib -import struct - -_fileHeaderSize = struct.calcsize(zipfile.structFileHeader) - -class ChunkingZipFile(zipfile.ZipFile): - """ - A ZipFile object which, with readfile(), also gives you access to a - filelike object for each entry. - """ - - def readfile(self, name): - """ - Return file-like object for name. - """ - if self.mode not in ("r", "a"): - raise RuntimeError('read() requires mode "r" or "a"') - if not self.fp: - raise RuntimeError( - "Attempt to read ZIP archive that was already closed") - zinfo = self.getinfo(name) - - self.fp.seek(zinfo.header_offset, 0) - - fheader = self.fp.read(_fileHeaderSize) - if fheader[0:4] != zipfile.stringFileHeader: - raise zipfile.BadZipfile("Bad magic number for file header") - - fheader = struct.unpack(zipfile.structFileHeader, fheader) - fname = self.fp.read(fheader[zipfile._FH_FILENAME_LENGTH]) - - if fheader[zipfile._FH_EXTRA_FIELD_LENGTH]: - self.fp.read(fheader[zipfile._FH_EXTRA_FIELD_LENGTH]) - - if fname != zinfo.orig_filename: - raise zipfile.BadZipfile( - 'File name in directory "%s" and header "%s" differ.' % ( - zinfo.orig_filename, fname)) - - if zinfo.compress_type == zipfile.ZIP_STORED: - return ZipFileEntry(self, zinfo.compress_size) - elif zinfo.compress_type == zipfile.ZIP_DEFLATED: - return DeflatedZipFileEntry(self, zinfo.compress_size) - else: - raise zipfile.BadZipfile( - "Unsupported compression method %d for file %s" % - (zinfo.compress_type, name)) - - - -class _FileEntry(object): - """ - Abstract superclass of both compressed and uncompressed variants of - file-like objects within a zip archive. - - @ivar chunkingZipFile: a chunking zip file. - @type chunkingZipFile: L{ChunkingZipFile} - - @ivar length: The number of bytes within the zip file that represent this - file. (This is the size on disk, not the number of decompressed bytes - which will result from reading it.) - - @ivar fp: the underlying file object (that contains pkzip data). Do not - touch this, please. It will quite likely move or go away. - - @ivar closed: File-like 'closed' attribute; True before this file has been - closed, False after. - @type closed: L{bool} - - @ivar finished: An older, broken synonym for 'closed'. Do not touch this, - please. - @type finished: L{int} - """ - def __init__(self, chunkingZipFile, length): - """ - Create a L{_FileEntry} from a L{ChunkingZipFile}. - """ - self.chunkingZipFile = chunkingZipFile - self.fp = self.chunkingZipFile.fp - self.length = length - self.finished = 0 - self.closed = False - - - def isatty(self): - """ - Returns false because zip files should not be ttys - """ - return False - - - def close(self): - """ - Close self (file-like object) - """ - self.closed = True - self.finished = 1 - del self.fp - - - def readline(self): - """ - Read a line. - """ - bytes = "" - for byte in iter(lambda : self.read(1), ""): - bytes += byte - if byte == "\n": - break - return bytes - - - def next(self): - """ - Implement next as file does (like readline, except raises StopIteration - at EOF) - """ - nextline = self.readline() - if nextline: - return nextline - raise StopIteration() - - - def readlines(self): - """ - Returns a list of all the lines - """ - return list(self) - - - def xreadlines(self): - """ - Returns an iterator (so self) - """ - return self - - - def __iter__(self): - """ - Returns an iterator (so self) - """ - return self - - - -class ZipFileEntry(_FileEntry): - """ - File-like object used to read an uncompressed entry in a ZipFile - """ - - def __init__(self, chunkingZipFile, length): - _FileEntry.__init__(self, chunkingZipFile, length) - self.readBytes = 0 - - - def tell(self): - return self.readBytes - - - def read(self, n=None): - if n is None: - n = self.length - self.readBytes - if n == 0 or self.finished: - return '' - data = self.chunkingZipFile.fp.read( - min(n, self.length - self.readBytes)) - self.readBytes += len(data) - if self.readBytes == self.length or len(data) < n: - self.finished = 1 - return data - - - -class DeflatedZipFileEntry(_FileEntry): - """ - File-like object used to read a deflated entry in a ZipFile - """ - - def __init__(self, chunkingZipFile, length): - _FileEntry.__init__(self, chunkingZipFile, length) - self.returnedBytes = 0 - self.readBytes = 0 - self.decomp = zlib.decompressobj(-15) - self.buffer = "" - - - def tell(self): - return self.returnedBytes - - - def read(self, n=None): - if self.finished: - return "" - if n is None: - result = [self.buffer,] - result.append( - self.decomp.decompress( - self.chunkingZipFile.fp.read( - self.length - self.readBytes))) - result.append(self.decomp.decompress("Z")) - result.append(self.decomp.flush()) - self.buffer = "" - self.finished = 1 - result = "".join(result) - self.returnedBytes += len(result) - return result - else: - while len(self.buffer) < n: - data = self.chunkingZipFile.fp.read( - min(n, 1024, self.length - self.readBytes)) - self.readBytes += len(data) - if not data: - result = (self.buffer - + self.decomp.decompress("Z") - + self.decomp.flush()) - self.finished = 1 - self.buffer = "" - self.returnedBytes += len(result) - return result - else: - self.buffer += self.decomp.decompress(data) - result = self.buffer[:n] - self.buffer = self.buffer[n:] - self.returnedBytes += len(result) - return result - - - -def unzip(filename, directory=".", overwrite=0): - """ - Unzip the file - - @param filename: the name of the zip file - @param directory: the directory into which the files will be - extracted - @param overwrite: if on, overwrite files when they exist. You can - still get an error if you try to create a directory over a file - with the same name or vice-versa. - """ - for i in unzipIter(filename, directory, overwrite): - pass - -DIR_BIT = 16 - -def unzipIter(filename, directory='.', overwrite=0): - """ - Return a generator for the zipfile. This implementation will yield - after every file. - - The value it yields is the number of files left to unzip. - """ - zf = zipfile.ZipFile(filename, 'r') - names = zf.namelist() - if not os.path.exists(directory): - os.makedirs(directory) - remaining = len(zf.namelist()) - for entry in names: - remaining -= 1 - isdir = zf.getinfo(entry).external_attr & DIR_BIT - f = os.path.join(directory, entry) - if isdir: - # overwrite flag only applies to files - if not os.path.exists(f): - os.makedirs(f) - else: - # create the directory the file will be in first, - # since we can't guarantee it exists - fdir = os.path.split(f)[0] - if not os.path.exists(fdir): - os.makedirs(f) - if overwrite or not os.path.exists(f): - outfile = file(f, 'wb') - outfile.write(zf.read(entry)) - outfile.close() - yield remaining - - -def countZipFileChunks(filename, chunksize): - """ - Predict the number of chunks that will be extracted from the entire - zipfile, given chunksize blocks. - """ - totalchunks = 0 - zf = ChunkingZipFile(filename) - for info in zf.infolist(): - totalchunks += countFileChunks(info, chunksize) - return totalchunks - - -def countFileChunks(zipinfo, chunksize): - """ - Count the number of chunks that will result from the given L{ZipInfo}. - - @param zipinfo: a L{zipfile.ZipInfo} instance describing an entry in a zip - archive to be counted. - - @return: the number of chunks present in the zip file. (Even an empty file - counts as one chunk.) - @rtype: L{int} - """ - count, extra = divmod(zipinfo.file_size, chunksize) - if extra > 0: - count += 1 - return count or 1 - - -def countZipFileEntries(filename): - """ - Count the number of entries in a zip archive. (Don't use this function.) - - @param filename: The filename of a zip archive. - @type filename: L{str} - """ - warnings.warn("countZipFileEntries is deprecated.", - DeprecationWarning, 2) - zf = zipfile.ZipFile(filename) - return len(zf.namelist()) - - -def unzipIterChunky(filename, directory='.', overwrite=0, - chunksize=4096): - """ - Return a generator for the zipfile. This implementation will yield after - every chunksize uncompressed bytes, or at the end of a file, whichever - comes first. - - The value it yields is the number of chunks left to unzip. - """ - czf = ChunkingZipFile(filename, 'r') - if not os.path.exists(directory): - os.makedirs(directory) - remaining = countZipFileChunks(filename, chunksize) - names = czf.namelist() - infos = czf.infolist() - - for entry, info in zip(names, infos): - isdir = info.external_attr & DIR_BIT - f = os.path.join(directory, entry) - if isdir: - # overwrite flag only applies to files - if not os.path.exists(f): - os.makedirs(f) - remaining -= 1 - yield remaining - else: - # create the directory the file will be in first, - # since we can't guarantee it exists - fdir = os.path.split(f)[0] - if not os.path.exists(fdir): - os.makedirs(f) - if overwrite or not os.path.exists(f): - outfile = file(f, 'wb') - fp = czf.readfile(entry) - if info.file_size == 0: - remaining -= 1 - yield remaining - while fp.tell() < info.file_size: - hunk = fp.read(chunksize) - outfile.write(hunk) - remaining -= 1 - yield remaining - outfile.close() - else: - remaining -= countFileChunks(info, chunksize) - yield remaining diff --git a/tools/buildbot/pylibs/twisted/python/zsh/README b/tools/buildbot/pylibs/twisted/python/zsh/README deleted file mode 100644 index b076ed4..0000000 --- a/tools/buildbot/pylibs/twisted/python/zsh/README +++ /dev/null @@ -1,8 +0,0 @@ -This directory holds the auto-generated zsh completion -functions for twisted commands. Re-generate with -python zshcomp.py path/to/this/dir - -This directory needs to be under the twisted package so -that is can be dynamically located on the filesystem -by _twisted_zsh_stub - diff --git a/tools/buildbot/pylibs/twisted/python/zsh/_cftp b/tools/buildbot/pylibs/twisted/python/zsh/_cftp deleted file mode 100644 index 342bbf8..0000000 --- a/tools/buildbot/pylibs/twisted/python/zsh/_cftp +++ /dev/null @@ -1,48 +0,0 @@ -#compdef cftp -_arguments -s -A "-*" \ -'1:host | user@host:{_ssh;if compset -P "*@"; then _wanted hosts expl "remote host name" _ssh_hosts && ret=0 elif compset -S "@*"; then _wanted users expl "login name" _ssh_users -S "" && ret=0 else if (( $+opt_args[-l] )); then tmp=() else tmp=( "users:login name:_ssh_users -qS@" ) fi; _alternative "hosts:remote host name:_ssh_hosts" "$tmp[@]" && ret=0 fi}' \ -'2::localfile:{if [[ $words[1] == *:* ]]; then; _files; fi}' \ -'(--noagent -a --agent)-A[Enable authentication agent forwarding]' \ -'(--noagent -a -A)--agent[Enable authentication agent forwarding]' \ -"(--batchfile)-b[File to read commands from, or '-' for stdin.]:batchfile:_files" \ -"(-b)--batchfile=[File to read commands from, or '-' for stdin.]:batchfile:_files" \ -'(--buffersize)-B[Size of send/receive buffer (default: 32768)]:buffersize:_files' \ -'(-B)--buffersize=[Size of send/receive buffer (default: 32768)]:buffersize:_files' \ -"(--ciphers)-c[Select encryption algorithms]:ciphers:_values -s , 'ciphers to choose from' idea-ctr blowfish-ctr none arcfour aes256-ctr cast128-ctr idea-cbc blowfish-cbc 3des-cbc aes256-cbc 3des-ctr cast128-cbc aes128-ctr aes192-cbc aes192-ctr aes128-cbc" \ -"(-c)--ciphers=[Select encryption algorithms]:ciphers:_values -s , 'ciphers to choose from' idea-ctr blowfish-ctr none arcfour aes256-ctr cast128-ctr idea-cbc blowfish-cbc 3des-cbc aes256-cbc 3des-ctr cast128-cbc aes128-ctr aes192-cbc aes192-ctr aes128-cbc" \ -'(--compress)-C[Enable compression.]' \ -'(-C)--compress[Enable compression.]' \ -"(--connection-usage)-K[Connection types to use]:connection-usage:_values -s , 'connection types to choose from' unix direct" \ -"(-K)--connection-usage=[Connection types to use]:connection-usage:_values -s , 'connection types to choose from' unix direct" \ -'--help[Display this help and exit.]' \ -"--host-key-algorithms=[Select host key algorithms]:host-key-algorithms:_values -s , 'host key algorithms to choose from' ssh-rsa ssh-dss" \ -'(--identity)-i[Identity for public-key authentication]:identity:_files' \ -'(-i)--identity=[Identity for public-key authentication]:identity:_files' \ -'--known-hosts=[File to check for host keys]:known-hosts:_files' \ -'(--log)-v[Enable logging (defaults to stderr)]' \ -'(-v)--log[Enable logging (defaults to stderr)]' \ -'--logfile=[File to log to, or - for stdout]:logfile:_files' \ -"(--macs)-m[Specify MAC algorithms]:macs:_values -s , 'macs to choose from' hmac-sha1 none hmac-md5" \ -"(-m)--macs=[Specify MAC algorithms]:macs:_values -s , 'macs to choose from' hmac-sha1 none hmac-md5" \ -'(--agent -A --noagent)-a[Disable authentication agent forwarding (default)]' \ -'(--agent -A -a)--noagent[Disable authentication agent forwarding (default)]' \ -'(--nocache)-I[Do not allow connection sharing over this connection.]' \ -'(-I)--nocache[Do not allow connection sharing over this connection.]' \ -'(--nox11)-x[Disable X11 connection forwarding (default)]' \ -'(-x)--nox11[Disable X11 connection forwarding (default)]' \ -'(--option)-o[Ignored OpenSSH options]:option:_files' \ -'(-o)--option=[Ignored OpenSSH options]:option:_files' \ -'(--port)-p[Connect to this port. Server must be on the same port.]:port:_files' \ -'(-p)--port=[Connect to this port. Server must be on the same port.]:port:_files' \ -'(--reconnect)-r[Reconnect to the server if the connection is lost.]' \ -'(-r)--reconnect[Reconnect to the server if the connection is lost.]' \ -'(--requests)-R[Number of requests to make before waiting for a reply.]:requests:_files' \ -'(-R)--requests=[Number of requests to make before waiting for a reply.]:requests:_files' \ -'(--subsystem)-s[Subsystem/server program to connect to.]:subsystem:_files' \ -'(-s)--subsystem=[Subsystem/server program to connect to.]:subsystem:_files' \ -'(--user)-l[Log in using this user name.]:user:_users' \ -'(-l)--user=[Log in using this user name.]:user:_users' \ -'--user-authentications=[Types of user authentications to use.]:user-authentications:_files' \ -'(--version)-V[Display version number only.]' \ -'(-V)--version[Display version number only.]' \ -&& return 0 diff --git a/tools/buildbot/pylibs/twisted/python/zsh/_ckeygen b/tools/buildbot/pylibs/twisted/python/zsh/_ckeygen deleted file mode 100644 index 7842b50..0000000 --- a/tools/buildbot/pylibs/twisted/python/zsh/_ckeygen +++ /dev/null @@ -1,25 +0,0 @@ -#compdef ckeygen -_arguments -s -A "-*" \ -'(--bits)-b[Number of bits in the key to create.]:bits:_files' \ -'(-b)--bits=[Number of bits in the key to create.]:bits:_files' \ -'(--changepass)-p[Change passphrase of private key file.]' \ -'(-p)--changepass[Change passphrase of private key file.]' \ -'(--comment)-C[Provide new comment.]:comment:_files' \ -'(-C)--comment=[Provide new comment.]:comment:_files' \ -'(--filename)-f[Filename of the key file.]:filename:_files' \ -'(-f)--filename=[Filename of the key file.]:filename:_files' \ -'(--fingerprint)-l[Show fingerprint of key file.]' \ -'(-l)--fingerprint[Show fingerprint of key file.]' \ -'--help[Display this help and exit.]' \ -'(--newpass)-N[Provide new passphrase.]:newpass:_files' \ -'(-N)--newpass=[Provide new passphrase.]:newpass:_files' \ -'(--pass)-P[Provide old passphrase]:pass:_files' \ -'(-P)--pass=[Provide old passphrase]:pass:_files' \ -'(--quiet)-q[Quiet.]' \ -'(-q)--quiet[Quiet.]' \ -'(--showpub)-y[Read private key file and print public key.]' \ -'(-y)--showpub[Read private key file and print public key.]' \ -'(--type)-t[Specify type of key to create.]:type:(rsa dsa)' \ -'(-t)--type=[Specify type of key to create.]:type:(rsa dsa)' \ -'--version[version]' \ -&& return 0 diff --git a/tools/buildbot/pylibs/twisted/python/zsh/_conch b/tools/buildbot/pylibs/twisted/python/zsh/_conch deleted file mode 100644 index b68088a..0000000 --- a/tools/buildbot/pylibs/twisted/python/zsh/_conch +++ /dev/null @@ -1,58 +0,0 @@ -#compdef conch -_arguments -s -A "-*" \ -'1:host | user@host:{_ssh;if compset -P "*@"; then _wanted hosts expl "remote host name" _ssh_hosts && ret=0 elif compset -S "@*"; then _wanted users expl "login name" _ssh_users -S "" && ret=0 else if (( $+opt_args[-l] )); then tmp=() else tmp=( "users:login name:_ssh_users -qS@" ) fi; _alternative "hosts:remote host name:_ssh_hosts" "$tmp[@]" && ret=0 fi}' \ -'*:command: ' \ -'(--noagent -a --agent)-A[Enable authentication agent forwarding]' \ -'(--noagent -a -A)--agent[Enable authentication agent forwarding]' \ -"(--ciphers)-c[Select encryption algorithms]:ciphers:_values -s , 'ciphers to choose from' idea-ctr blowfish-ctr none arcfour aes256-ctr cast128-ctr idea-cbc blowfish-cbc 3des-cbc aes256-cbc 3des-ctr cast128-cbc aes128-ctr aes192-cbc aes192-ctr aes128-cbc" \ -"(-c)--ciphers=[Select encryption algorithms]:ciphers:_values -s , 'ciphers to choose from' idea-ctr blowfish-ctr none arcfour aes256-ctr cast128-ctr idea-cbc blowfish-cbc 3des-cbc aes256-cbc 3des-ctr cast128-cbc aes128-ctr aes192-cbc aes192-ctr aes128-cbc" \ -'(--compress)-C[Enable compression.]' \ -'(-C)--compress[Enable compression.]' \ -"(--connection-usage)-K[Connection types to use]:connection-usage:_values -s , 'connection types to choose from' unix direct" \ -"(-K)--connection-usage=[Connection types to use]:connection-usage:_values -s , 'connection types to choose from' unix direct" \ -"(--escape)-e[Set escape character; \`\`none'' = disable]:escape:_files" \ -"(-e)--escape=[Set escape character; \`\`none'' = disable]:escape:_files" \ -'(--fork)-f[Fork to background after authentication.]' \ -'(-f)--fork[Fork to background after authentication.]' \ -'--help[Display this help and exit.]' \ -"--host-key-algorithms=[Select host key algorithms]:host-key-algorithms:_values -s , 'host key algorithms to choose from' ssh-rsa ssh-dss" \ -'(--identity)-i[Identity for public-key authentication]:identity:_files' \ -'(-i)--identity=[Identity for public-key authentication]:identity:_files' \ -'--known-hosts=[File to check for host keys]:known-hosts:_files' \ -'(--localforward)-L[listen-port:host:port Forward local port to remote address]:listen-port:host:port:_files' \ -'(-L)--localforward=[listen-port:host:port Forward local port to remote address]:listen-port:host:port:_files' \ -'(--log)-v[Enable logging (defaults to stderr)]' \ -'(-v)--log[Enable logging (defaults to stderr)]' \ -'--logfile=[File to log to, or - for stdout]:logfile:_files' \ -"(--macs)-m[Specify MAC algorithms]:macs:_values -s , 'macs to choose from' hmac-sha1 none hmac-md5" \ -"(-m)--macs=[Specify MAC algorithms]:macs:_values -s , 'macs to choose from' hmac-sha1 none hmac-md5" \ -'(--agent -A --noagent)-a[Disable authentication agent forwarding (default)]' \ -'(--agent -A -a)--noagent[Disable authentication agent forwarding (default)]' \ -'(--nocache)-I[Do not allow connection sharing over this connection.]' \ -'(-I)--nocache[Do not allow connection sharing over this connection.]' \ -'(--noshell)-N[Do not execute a shell or command.]' \ -'(-N)--noshell[Do not execute a shell or command.]' \ -'(--notty)-T[Do not allocate a tty.]' \ -'(-T)--notty[Do not allocate a tty.]' \ -'(--nox11)-x[Disable X11 connection forwarding (default)]' \ -'(-x)--nox11[Disable X11 connection forwarding (default)]' \ -'(--null)-n[Redirect input from /dev/null.]' \ -'(-n)--null[Redirect input from /dev/null.]' \ -'(--option)-o[Ignored OpenSSH options]:option:_files' \ -'(-o)--option=[Ignored OpenSSH options]:option:_files' \ -'(--port)-p[Connect to this port. Server must be on the same port.]:port:_files' \ -'(-p)--port=[Connect to this port. Server must be on the same port.]:port:_files' \ -'(--reconnect)-r[Reconnect to the server if the connection is lost.]' \ -'(-r)--reconnect[Reconnect to the server if the connection is lost.]' \ -'(--remoteforward)-R[listen-port:host:port Forward remote port to local address]:listen-port:host:port:_files' \ -'(-R)--remoteforward=[listen-port:host:port Forward remote port to local address]:listen-port:host:port:_files' \ -'(--subsystem)-s[Invoke command (mandatory) as SSH2 subsystem.]' \ -'(-s)--subsystem[Invoke command (mandatory) as SSH2 subsystem.]' \ -'(--tty)-t[Tty; allocate a tty even if command is given.]' \ -'(-t)--tty[Tty; allocate a tty even if command is given.]' \ -'(--user)-l[Log in using this user name.]:user:_users' \ -'(-l)--user=[Log in using this user name.]:user:_users' \ -'--user-authentications=[Types of user authentications to use.]:user-authentications:_files' \ -'(--version)-V[Display version number only.]' \ -'(-V)--version[Display version number only.]' \ -&& return 0 diff --git a/tools/buildbot/pylibs/twisted/python/zsh/_lore b/tools/buildbot/pylibs/twisted/python/zsh/_lore deleted file mode 100644 index 012790c..0000000 --- a/tools/buildbot/pylibs/twisted/python/zsh/_lore +++ /dev/null @@ -1,28 +0,0 @@ -#compdef lore -_arguments -s -A "-*" \ -'*:files:_files' \ -'(--book)-b[The book file to generate a book from]:book:_files' \ -'(-b)--book=[The book file to generate a book from]:book:_files' \ -'--config=[config]:config:_files' \ -'(--docsdir)-d[docsdir]:docsdir:_files' \ -'(-d)--docsdir=[docsdir]:docsdir:_files' \ -'--help[Display this help and exit.]' \ -'(--index)-x[The base filename you want to give your index file]:index:_files' \ -'(-x)--index=[The base filename you want to give your index file]:index:_files' \ -'(--input)-i[input]:input:_files' \ -'(-i)--input=[input]:input:_files' \ -'(--inputext)-e[The extension that your Lore input files have]:inputext:_files' \ -'(-e)--inputext=[The extension that your Lore input files have]:inputext:_files' \ -'(--linkrel)-l[linkrel]:linkrel:_files' \ -'(-l)--linkrel=[linkrel]:linkrel:_files' \ -'(--null)-n[Do not report filenames]' \ -'(-n)--null[Do not report filenames]' \ -'(--number)-N[Add chapter/section numbers to section headings]' \ -'(-N)--number[Add chapter/section numbers to section headings]' \ -'(--output)-o[output]:output:_files' \ -'(-o)--output=[output]:output:_files' \ -'(--plain)-p[Report filenames without progress bar]' \ -'(-p)--plain[Report filenames without progress bar]' \ -'--prefixurl=[The prefix to stick on to relative links; only useful when processing directories]:prefixurl:_files' \ -'--version[version]' \ -&& return 0 diff --git a/tools/buildbot/pylibs/twisted/python/zsh/_manhole b/tools/buildbot/pylibs/twisted/python/zsh/_manhole deleted file mode 100644 index fffeef0..0000000 --- a/tools/buildbot/pylibs/twisted/python/zsh/_manhole +++ /dev/null @@ -1,19 +0,0 @@ -#compdef manhole -_arguments -s -A "-*" \ -'--help[Display this help and exit.]' \ -'(--host)-h[host]:host:_hosts' \ -'(-h)--host=[host]:host:_hosts' \ -'(--password)-w[password]:password:_files' \ -'(-w)--password=[password]:password:_files' \ -'(--perspective)-P[PB Perspective to ask for (if different than username)]:perspective:_files' \ -'(-P)--perspective=[PB Perspective to ask for (if different than username)]:perspective:_files' \ -'(--port)-p[port]:port:_files' \ -'(-p)--port=[port]:port:_files' \ -'(--service)-s[PB Service]:service:_files' \ -'(-s)--service=[PB Service]:service:_files' \ -'(--toolkit)-t[Front-end to use; one of gtk2]:toolkit:(gtk1 gtk2)' \ -'(-t)--toolkit=[Front-end to use; one of gtk2]:toolkit:(gtk1 gtk2)' \ -'(--user)-u[username]:user:_files' \ -'(-u)--user=[username]:user:_files' \ -'--version[version]' \ -&& return 0 diff --git a/tools/buildbot/pylibs/twisted/python/zsh/_mktap b/tools/buildbot/pylibs/twisted/python/zsh/_mktap deleted file mode 100644 index 152fc9c..0000000 --- a/tools/buildbot/pylibs/twisted/python/zsh/_mktap +++ /dev/null @@ -1,304 +0,0 @@ -#compdef mktap -local _zsh_subcmds_array -_zsh_subcmds_array=( -"web2:An HTTP/1.1 web server that can serve from a filesystem or application resource." -"ftp:An FTP server." -"telnet:A simple, telnet-based remote debugging service." -"socks:A SOCKSv4 proxy service." -"manhole-old:An interactive remote debugger service." -"portforward:A simple port-forwarder." -"web:A general-purpose web server which can serve from a filesystem or application resource." -"inetd:An inetd(8) replacement." -"news:A news server." -"words:A modern words server" -"toc:An AIM TOC service." -"dns:A domain name server." -"mail:An email service" -"manhole:An interactive remote debugger service accessible via telnet and ssh and providing syntax coloring and basic line editing functionality." -"conch:A Conch SSH service." -) - -_arguments -s -A "-*" \ -'*::subcmd:->subcmd' \ -'(--append)-a[An existing .tap file to append the plugin to, rather than creating a new one.]:tap file to append to:_files -g "*.tap"' \ -'(-a)--append=[An existing .tap file to append the plugin to, rather than creating a new one.]:tap file to append to:_files -g "*.tap"' \ -'(--appname)-n[The process name to use for this application.]:appname:_files' \ -'(-n)--appname=[The process name to use for this application.]:appname:_files' \ -'(--debug)-d[Show debug information for plugin loading]' \ -'(-d)--debug[Show debug information for plugin loading]' \ -"(--encrypted)-e[Encrypt file before writing (will make the extension of the resultant file begin with 'e')]" \ -"(-e)--encrypted[Encrypt file before writing (will make the extension of the resultant file begin with 'e')]" \ -'(--gid)-g[The gid to run as.]:gid to run as:_files' \ -'(-g)--gid=[The gid to run as.]:gid to run as:_files' \ -'(--help)-h[Display this message]' \ -'(-h)--help[Display this message]' \ -'(--progress)-p[Show progress information for plugin loading]' \ -'(-p)--progress[Show progress information for plugin loading]' \ -"(--type)-t[The output format to use; this can be 'pickle', 'xml', or 'source'.]:output format:(pickle xml source)" \ -"(-t)--type=[The output format to use; this can be 'pickle', 'xml', or 'source'.]:output format:(pickle xml source)" \ -'(--uid)-u[The uid to run as.]:uid to run as:_files' \ -'(-u)--uid=[The uid to run as.]:uid to run as:_files' \ -'--version[version]' \ -&& return 0 -if (( CURRENT == 1 )); then - _describe "tap to build" _zsh_subcmds_array && ret=0 -fi -(( ret )) || return 0 - -service="$words[1]" - -case $service in -web2) -_arguments -s -A "-*" \ -"--allow-ignore-ext[Specify whether or not a request for 'foo' should return 'foo.ext']" \ -"(--certificate)-c[SSL certificate to use for HTTPS.]:certificate:_files -g '*.pem'" \ -"(-c)--certificate=[SSL certificate to use for HTTPS.]:certificate:_files -g '*.pem'" \ -'--class=[A class that will be used to serve the root resource. Must implement twisted.web2.iweb.IResource and take no arguments.]:class:_files' \ -'--dav=[A path that will be used to serve the root resource as a DAV Collection.]:dav:_files' \ -'--help[Display this help and exit.]' \ -'--https=[Port to listen on for Secure HTTP.]:https:_files' \ -'--ignore-ext=[Specify an extension to ignore. These will be processed in order.]:ignore-ext:_files' \ -'(--index)-i[Add the name of a file used to check for directory indexes.]:index:_files' \ -'(-i)--index=[Add the name of a file used to check for directory indexes.]:index:_files' \ -'(--logfile)-l[Common Access Logging Format file to write to if unspecified access log information will be written to the standard twisted log file.]:logfile:_files' \ -'(-l)--logfile=[Common Access Logging Format file to write to if unspecified access log information will be written to the standard twisted log file.]:logfile:_files' \ -"--mimetype=[Mapping from file extension to MIME Type in the form of 'ext=type'.]:mimetype:_files" \ -'--path=[A path that will be used to serve the root resource as a raw file]:path:_files' \ -'(--port)-p[Port to start the server on.]:port:_files' \ -'(-p)--port=[Port to start the server on.]:port:_files' \ -"(--privkey)-k[SSL certificate to use for HTTPS.]:privkey:_files -g '*.pem'" \ -"(-k)--privkey=[SSL certificate to use for HTTPS.]:privkey:_files -g '*.pem'" \ -"--processor=[\`ext=class' where \`class' is added as a Processor for files ending]:processor:_files" \ -'--version[version]' \ -'--vhost-class=[Specify a virtual host in the form of domain=class,]:vhost-class:_files' \ -'--vhost-dav=[Specify a virtual host in the form of domain=path,]:vhost-dav:_files' \ -'--vhost-path=[Specify a directory to use for automatic named virtual hosts.]:vhost-path:_files' \ -'--vhost-static=[Specify a virtual host in the form of domain=path to be served as]:vhost-static:_files' \ -&& return 0 -;; -ftp) -_arguments -s -A "-*" \ -'--help[Display this help and exit.]' \ -'--password-file=[username:password-style credentials database]:password-file:_files' \ -'(--port)-p[set the port number]:port:_files' \ -'(-p)--port=[set the port number]:port:_files' \ -'(--root)-r[define the root of the ftp-site.]:root:_files' \ -'(-r)--root=[define the root of the ftp-site.]:root:_files' \ -'--userAnonymous=[Name of the anonymous user.]:userAnonymous:_files' \ -'--version[version]' \ -&& return 0 -;; -telnet) -_arguments -s -A "-*" \ -'--help[Display this help and exit.]' \ -'(--password)-w[set the password]:password:_files' \ -'(-w)--password=[set the password]:password:_files' \ -'(--port)-p[port to listen on]:port:_files' \ -'(-p)--port=[port to listen on]:port:_files' \ -'(--username)-u[set the login username]:username:_users' \ -'(-u)--username=[set the login username]:username:_users' \ -'--version[version]' \ -&& return 0 -;; -socks) -_arguments -s -A "-*" \ -'--help[Display this help and exit.]' \ -'(--interface)-i[local interface to which we listen]:interface:_files' \ -'(-i)--interface=[local interface to which we listen]:interface:_files' \ -"(--log)-l[file to log connection data to]:log:_files -g '*.log'" \ -"(-l)--log=[file to log connection data to]:log:_files -g '*.log'" \ -'(--port)-p[Port on which to listen]:port:_files' \ -'(-p)--port=[Port on which to listen]:port:_files' \ -'--version[version]' \ -&& return 0 -;; -manhole-old) -_arguments -s -A "-*" \ -'--help[Display this help and exit.]' \ -"(--password)-w[Required. '-' will prompt or read a password from stdin.]:password:_files" \ -"(-w)--password=[Required. '-' will prompt or read a password from stdin.]:password:_files" \ -'(--port)-p[Port to listen on]:port:_files' \ -'(-p)--port=[Port to listen on]:port:_files' \ -'(--tracebacks)-T[Allow tracebacks to be sent over the network]' \ -'(-T)--tracebacks[Allow tracebacks to be sent over the network]' \ -'(--user)-u[Name of user to allow to log in]:user:_users' \ -'(-u)--user=[Name of user to allow to log in]:user:_users' \ -'--version[version]' \ -&& return 0 -;; -portforward) -_arguments -s -A "-*" \ -'(--dest_port)-d[Set the destination port.]:dest_port:_files' \ -'(-d)--dest_port=[Set the destination port.]:dest_port:_files' \ -'--help[Display this help and exit.]' \ -'(--host)-h[Set the host.]:host:_hosts' \ -'(-h)--host=[Set the host.]:host:_hosts' \ -'(--port)-p[Set the port number.]:port:_files' \ -'(-p)--port=[Set the port number.]:port:_files' \ -'--version[version]' \ -&& return 0 -;; -web) -_arguments -s -A "-*" \ -"--allow-ignore-ext[Specify whether or not a request for 'foo' should return 'foo.ext']" \ -"(--certificate)-c[SSL certificate to use for HTTPS. ]:certificate:_files -g '*.pem'" \ -"(-c)--certificate=[SSL certificate to use for HTTPS. ]:certificate:_files -g '*.pem'" \ -'--class=[Create a Resource subclass with a zero-argument constructor.]:class:_files' \ -'--flashconduit=[Start a flashconduit on the specified port.]:flashconduit:_files' \ -'--help[Display this help and exit.]' \ -'--https=[Port to listen on for Secure HTTP.]:https:_files' \ -'--ignore-ext=[Specify an extension to ignore. These will be processed in order.]:ignore-ext:_files' \ -'(--index)-i[Add the name of a file used to check for directory indexes.]:index:_files' \ -'(-i)--index=[Add the name of a file used to check for directory indexes.]:index:_files' \ -"(--logfile)-l[Path to web CLF (Combined Log Format) log file.]:logfile:_files -g '*.log'" \ -"(-l)--logfile=[Path to web CLF (Combined Log Format) log file.]:logfile:_files -g '*.log'" \ -'(--mime-type)-m[Specify the default mime-type for static files.]:mime-type:_files' \ -'(-m)--mime-type=[Specify the default mime-type for static files.]:mime-type:_files' \ -'(--notracebacks)-n[Display tracebacks in broken web pages. Displaying tracebacks to users may be security risk!]' \ -'(-n)--notracebacks[Display tracebacks in broken web pages. Displaying tracebacks to users may be security risk!]' \ -'--path=[ is either a specific file or a directory to]:path:_files' \ -'--personal[Instead of generating a webserver, generate a ResourcePublisher which listens on ~/.twistd-web-pb]' \ -'(--port)-p[Port to start the server on.]:port:_files' \ -'(-p)--port=[Port to start the server on.]:port:_files' \ -"(--privkey)-k[SSL certificate to use for HTTPS.]:privkey:_files -g '*.pem'" \ -"(-k)--privkey=[SSL certificate to use for HTTPS.]:privkey:_files -g '*.pem'" \ -"--processor=[\`ext=class' where \`class' is added as a Processor for files ending]:processor:_files" \ -'--resource-script=[An .rpy file to be used as the root resource of the webserver.]:resource-script:_files' \ -'(--static)-s[Same as --path, this is deprecated and will be removed in a]:static:_files' \ -'(-s)--static=[Same as --path, this is deprecated and will be removed in a]:static:_files' \ -'(--user)-u[Makes a server with ~/public_html and ~/.twistd-web-pb support for]' \ -'(-u)--user[Makes a server with ~/public_html and ~/.twistd-web-pb support for]' \ -'--version[version]' \ -&& return 0 -;; -inetd) -_arguments -s -A "-*" \ -"(--file)-f[Service configuration file]:file:_files -g '*.conf'" \ -"(-f)--file=[Service configuration file]:file:_files -g '*.conf'" \ -'--help[Display this help and exit.]' \ -"(--nointernal)-i[Don't run internal services]" \ -"(-i)--nointernal[Don't run internal services]" \ -'(--rpc)-r[RPC procedure table file]:rpc:_files' \ -'(-r)--rpc=[RPC procedure table file]:rpc:_files' \ -'--version[version]' \ -&& return 0 -;; -news) -_arguments -s -A "-*" \ -'(--datadir)-d[Root data storage path]:datadir:_dirs' \ -'(-d)--datadir=[Root data storage path]:datadir:_dirs' \ -'--group=[The name of a newsgroup to carry.]:group:_files' \ -'--help[Display this help and exit.]' \ -'(--interface)-i[Interface to which to bind]:interface:_files' \ -'(-i)--interface=[Interface to which to bind]:interface:_files' \ -'(--mailhost)-m[Host of SMTP server to use]:mailhost:_hosts' \ -'(-m)--mailhost=[Host of SMTP server to use]:mailhost:_hosts' \ -'--moderator=[The email of the moderator for the most recently passed group.]:moderator:_files' \ -'(--port)-p[Listen port]:port:_files' \ -'(-p)--port=[Listen port]:port:_files' \ -'--server=[The address of a Usenet server to pass messages to and receive messages from.]:server:_files' \ -'--subscription=[A newsgroup to list as a recommended subscription.]:subscription:_files' \ -'--version[version]' \ -&& return 0 -;; -words) -_arguments -s -A "-*" \ -'--group=[Specify a group which should exist]:group:_files' \ -'--help[Display this help and exit.]' \ -'--hostname=[Name of this server; purely an informative]:hostname:_files' \ -'--irc-port=[strports description of the port to bind for the irc server]:irc-port:_files' \ -'--passwd=[Name of a passwd-style password file. (REQUIRED)]:passwd:_files' \ -'--pb-port=[strports description of the port to bind for the pb server]:pb-port:_files' \ -'--version[version]' \ -&& return 0 -;; -toc) -_arguments -s -A "-*" \ -'--help[Display this help and exit.]' \ -'(--port)-p[port]:port:_files' \ -'(-p)--port=[port]:port:_files' \ -'--version[version]' \ -&& return 0 -;; -dns) -_arguments -s -A "-*" \ -'--bindzone=[Specify the filename of a BIND9 syntax zone definition]:bindzone:_files' \ -'(--cache)-c[Enable record caching]' \ -'(-c)--cache[Enable record caching]' \ -'--help[Display this help and exit.]' \ -'--hosts-file=[Perform lookups with a hosts file]:hosts-file:_files' \ -'(--interface)-i[The interface to which to bind]:interface:_files' \ -'(-i)--interface=[The interface to which to bind]:interface:_files' \ -'(--port)-p[The port on which to listen]:port:_files' \ -'(-p)--port=[The port on which to listen]:port:_files' \ -'--pyzone=[Specify the filename of a Python syntax zone definition]:pyzone:_files' \ -'(--recursive)-r[Perform recursive lookups]' \ -'(-r)--recursive[Perform recursive lookups]' \ -'--resolv-conf=[Override location of resolv.conf (implies --recursive)]:resolv-conf:_files' \ -'--secondary=[Act as secondary for the specified domain, performing]:secondary:_files' \ -'(--verbose)-v[Log verbosely]' \ -'(-v)--verbose[Log verbosely]' \ -'--version[version]' \ -&& return 0 -;; -mail) -_arguments -s -A "-*" \ -'(--aliases)-A[Specify an aliases(5) file to use for this domain]:aliases:_files' \ -'(-A)--aliases=[Specify an aliases(5) file to use for this domain]:aliases:_files' \ -'(--bounce-to-postmaster)-b[undelivered mails are sent to the postmaster]' \ -'(-b)--bounce-to-postmaster[undelivered mails are sent to the postmaster]' \ -'(--certificate)-c[Certificate file to use for SSL connections]:certificate:_files' \ -'(-c)--certificate=[Certificate file to use for SSL connections]:certificate:_files' \ -'(--default)-D[Make the most recently specified domain the default domain.]' \ -'(-D)--default[Make the most recently specified domain the default domain.]' \ -'--disable-anonymous[Disallow non-authenticated SMTP connections]' \ -'(--esmtp)-E[Use RFC 1425/1869 SMTP extensions]' \ -'(-E)--esmtp[Use RFC 1425/1869 SMTP extensions]' \ -'--help[Display this help and exit.]' \ -'(--hostname)-H[The hostname by which to identify this server.]:hostname:_hosts' \ -'(-H)--hostname=[The hostname by which to identify this server.]:hostname:_hosts' \ -'(--maildirdbmdomain)-d[generate an SMTP/POP3 virtual domain which saves to "path"]:maildirdbmdomain:_files' \ -'(-d)--maildirdbmdomain=[generate an SMTP/POP3 virtual domain which saves to "path"]:maildirdbmdomain:_files' \ -'(--passwordfile)-P[Specify a file containing username:password login info for authenticated ESMTP connections.]:passwordfile:_files' \ -'(-P)--passwordfile=[Specify a file containing username:password login info for authenticated ESMTP connections.]:passwordfile:_files' \ -'(--pop3)-p[Port to start the POP3 server on (0 to disable).]:pop3:_files' \ -'(-p)--pop3=[Port to start the POP3 server on (0 to disable).]:pop3:_files' \ -'(--pop3s)-S[Port to start the POP3-over-SSL server on (0 to disable).]:pop3s:_files' \ -'(-S)--pop3s=[Port to start the POP3-over-SSL server on (0 to disable).]:pop3s:_files' \ -"(--relay)-R[Relay messages according to their envelope 'To', using the givenpath as a queue directory.]:relay:_files" \ -"(-R)--relay=[Relay messages according to their envelope 'To', using the givenpath as a queue directory.]:relay:_files" \ -'(--smtp)-s[Port to start the SMTP server on (0 to disable).]:smtp:_files' \ -'(-s)--smtp=[Port to start the SMTP server on (0 to disable).]:smtp:_files' \ -'(--user)-u[add a user/password to the last specified domains]:user:_files' \ -'(-u)--user=[add a user/password to the last specified domains]:user:_files' \ -'--version[version]' \ -&& return 0 -;; -manhole) -_arguments -s -A "-*" \ -'--help[Display this help and exit.]' \ -'(--passwd)-p[name of a passwd(5)-format username/password file]:passwd:_files' \ -'(-p)--passwd=[name of a passwd(5)-format username/password file]:passwd:_files' \ -'(--sshPort)-s[strports description of the address on which to listen for ssh connections]:sshPort:_files' \ -'(-s)--sshPort=[strports description of the address on which to listen for ssh connections]:sshPort:_files' \ -'(--telnetPort)-t[strports description of the address on which to listen for telnet connections]:telnetPort:_files' \ -'(-t)--telnetPort=[strports description of the address on which to listen for telnet connections]:telnetPort:_files' \ -'--user=[user]:user:_files' \ -'--version[version]' \ -&& return 0 -;; -conch) -_arguments -s -A "-*" \ -'(--data)-d[directory to look for host keys in]:data:_dirs' \ -'(-d)--data=[directory to look for host keys in]:data:_dirs' \ -'--help[Display this help and exit.]' \ -'(--interface)-i[local interface to which we listen]:interface:_files' \ -'(-i)--interface=[local interface to which we listen]:interface:_files' \ -'--moduli=[directory to look for moduli in (if different from --data)]:moduli:_dirs' \ -'(--port)-p[Port on which to listen]:port:_files' \ -'(-p)--port=[Port on which to listen]:port:_files' \ -'--version[version]' \ -&& return 0 -;; -*) _message "don't know how to complete $service";; -esac \ No newline at end of file diff --git a/tools/buildbot/pylibs/twisted/python/zsh/_pyhtmlizer b/tools/buildbot/pylibs/twisted/python/zsh/_pyhtmlizer deleted file mode 100644 index 8bbfc83..0000000 --- a/tools/buildbot/pylibs/twisted/python/zsh/_pyhtmlizer +++ /dev/null @@ -1,8 +0,0 @@ -#compdef pyhtmlizer -_arguments -s -A "-*" \ -"1:source python file:_files -g '*.py'" \ -'--help[Display this help and exit.]' \ -'(--stylesheet)-s[URL of stylesheet to link to.]:stylesheet:_files' \ -'(-s)--stylesheet=[URL of stylesheet to link to.]:stylesheet:_files' \ -'--version[version]' \ -&& return 0 diff --git a/tools/buildbot/pylibs/twisted/python/zsh/_tap2deb b/tools/buildbot/pylibs/twisted/python/zsh/_tap2deb deleted file mode 100644 index 4c5f6da..0000000 --- a/tools/buildbot/pylibs/twisted/python/zsh/_tap2deb +++ /dev/null @@ -1,23 +0,0 @@ -#compdef tap2deb -_arguments -s -A "-*" \ -'(--debfile)-d[debfile]:debfile:_files' \ -'(-d)--debfile=[debfile]:debfile:_files' \ -'(--description)-e[description]:description:_files' \ -'(-e)--description=[description]:description:_files' \ -'--help[Display this help and exit.]' \ -'(--long_description)-l[long_description]:long_description:_files' \ -'(-l)--long_description=[long_description]:long_description:_files' \ -"(--maintainer)-m[The maintainer's name and email in a specific format: 'John Doe ']:maintainer:_files" \ -"(-m)--maintainer=[The maintainer's name and email in a specific format: 'John Doe ']:maintainer:_files" \ -'(--protocol)-p[protocol]:protocol:_files' \ -'(-p)--protocol=[protocol]:protocol:_files' \ -'(--set-version)-V[set-version]:set-version:_files' \ -'(-V)--set-version=[set-version]:set-version:_files' \ -'(--tapfile)-t[tapfile]:tapfile:_files' \ -'(-t)--tapfile=[tapfile]:tapfile:_files' \ -"(--type)-y[type of configuration: 'tap', 'xml, 'source' or 'python' for .tac files]:type:(tap xml source python)" \ -"(-y)--type=[type of configuration: 'tap', 'xml, 'source' or 'python' for .tac files]:type:(tap xml source python)" \ -'(--unsigned)-u[unsigned]' \ -'(-u)--unsigned[unsigned]' \ -'--version[version]' \ -&& return 0 diff --git a/tools/buildbot/pylibs/twisted/python/zsh/_tap2rpm b/tools/buildbot/pylibs/twisted/python/zsh/_tap2rpm deleted file mode 100644 index e3f289f..0000000 --- a/tools/buildbot/pylibs/twisted/python/zsh/_tap2rpm +++ /dev/null @@ -1,23 +0,0 @@ -#compdef tap2rpm -_arguments -s -A "-*" \ -'(--description)-e[description]:description:_files' \ -'(-e)--description=[description]:description:_files' \ -'--help[Display this help and exit.]' \ -'(--long_description)-l[long_description]:long_description:_files' \ -'(-l)--long_description=[long_description]:long_description:_files' \ -'(--maintainer)-m[maintainer]:maintainer:_files' \ -'(-m)--maintainer=[maintainer]:maintainer:_files' \ -'(--protocol)-p[protocol]:protocol:_files' \ -'(-p)--protocol=[protocol]:protocol:_files' \ -'(--rpmfile)-r[rpmfile]:rpmfile:_files -g "*.rpm"' \ -'(-r)--rpmfile=[rpmfile]:rpmfile:_files -g "*.rpm"' \ -'(--set-version)-V[set-version]:set-version:_files' \ -'(-V)--set-version=[set-version]:set-version:_files' \ -'(--tapfile)-t[tapfile]:tapfile:_files' \ -'(-t)--tapfile=[tapfile]:tapfile:_files' \ -"(--type)-y[type of configuration: 'tap', 'xml, 'source' or 'python']:type:(tap xml source python)" \ -"(-y)--type=[type of configuration: 'tap', 'xml, 'source' or 'python']:type:(tap xml source python)" \ -'(--unsigned)-u[unsigned]' \ -'(-u)--unsigned[unsigned]' \ -'--version[version]' \ -&& return 0 diff --git a/tools/buildbot/pylibs/twisted/python/zsh/_tapconvert b/tools/buildbot/pylibs/twisted/python/zsh/_tapconvert deleted file mode 100644 index 82d2fac..0000000 --- a/tools/buildbot/pylibs/twisted/python/zsh/_tapconvert +++ /dev/null @@ -1,17 +0,0 @@ -#compdef tapconvert -_arguments -s -A "-*" \ -'(--decrypt)-d[The specified tap/aos/xml file is encrypted.]' \ -'(-d)--decrypt[The specified tap/aos/xml file is encrypted.]' \ -'(--encrypt)-e[Encrypt file before writing]' \ -'(-e)--encrypt[Encrypt file before writing]' \ -'--help[Display this help and exit.]' \ -'(--in)-i[The filename of the tap to read from]:tap file to read from:_files' \ -'(-i)--in=[The filename of the tap to read from]:tap file to read from:_files' \ -'(--out)-o[A filename to write the tap to]:tap file to write to:_files' \ -'(-o)--out=[A filename to write the tap to]:tap file to write to:_files' \ -"(--typein)-f[The format to use; this can be 'guess', 'python', 'pickle', 'xml', or 'source'.]:typein:(guess python pickle xml source)" \ -"(-f)--typein=[The format to use; this can be 'guess', 'python', 'pickle', 'xml', or 'source'.]:typein:(guess python pickle xml source)" \ -"(--typeout)-t[The output format to use; this can be 'pickle', 'xml', or 'source'.]:typeout:(pickle xml source)" \ -"(-t)--typeout=[The output format to use; this can be 'pickle', 'xml', or 'source'.]:typeout:(pickle xml source)" \ -'--version[version]' \ -&& return 0 diff --git a/tools/buildbot/pylibs/twisted/python/zsh/_tkconch b/tools/buildbot/pylibs/twisted/python/zsh/_tkconch deleted file mode 100644 index 81a1643..0000000 --- a/tools/buildbot/pylibs/twisted/python/zsh/_tkconch +++ /dev/null @@ -1,38 +0,0 @@ -#compdef tkconch -_arguments -s -A "-*" \ -'1:host | user@host:{_ssh;if compset -P "*@"; then _wanted hosts expl "remote host name" _ssh_hosts && ret=0 elif compset -S "@*"; then _wanted users expl "login name" _ssh_users -S "" && ret=0 else if (( $+opt_args[-l] )); then tmp=() else tmp=( "users:login name:_ssh_users -qS@" ) fi; _alternative "hosts:remote host name:_ssh_hosts" "$tmp[@]" && ret=0 fi}' \ -'*:command: ' \ -'(--ansilog)-a[Print the receieved data to stdout]' \ -'(-a)--ansilog[Print the receieved data to stdout]' \ -'(--cipher)-c[Select encryption algorithm.]:cipher:(aes256-ctr aes256-cbc aes192-ctr aes192-cbc aes128-ctr aes128-cbc cast128-ctr cast128-cbc blowfish-ctr blowfish idea-ctridea-cbc 3des-ctr 3des-cbc)' \ -'(-c)--cipher=[Select encryption algorithm.]:cipher:(aes256-ctr aes256-cbc aes192-ctr aes192-cbc aes128-ctr aes128-cbc cast128-ctr cast128-cbc blowfish-ctr blowfish idea-ctridea-cbc 3des-ctr 3des-cbc)' \ -'(--compress)-C[Enable compression.]' \ -'(-C)--compress[Enable compression.]' \ -"(--escape)-e[Set escape character; \`\`none'' = disable]:escape:_files" \ -"(-e)--escape=[Set escape character; \`\`none'' = disable]:escape:_files" \ -'--help[Display this help and exit.]' \ -'(--identity)-i[Identity for public key authentication]:identity:_files' \ -'(-i)--identity=[Identity for public key authentication]:identity:_files' \ -'(--localforward)-L[listen-port:host:port Forward local port to remote address]:listen-port:host:port:_files' \ -'(-L)--localforward=[listen-port:host:port Forward local port to remote address]:listen-port:host:port:_files' \ -'(--log)-v[Log to stderr]' \ -'(-v)--log[Log to stderr]' \ -'(--macs)-m[Specify MAC algorithms for protocol version 2.]:macs:(hmac-sha1 hmac-md5)' \ -'(-m)--macs=[Specify MAC algorithms for protocol version 2.]:macs:(hmac-sha1 hmac-md5)' \ -'(--noshell)-N[Do not execute a shell or command.]' \ -'(-N)--noshell[Do not execute a shell or command.]' \ -'(--tty -t --notty)-T[Do not allocate a tty.]' \ -'(--tty -t -T)--notty[Do not allocate a tty.]' \ -'(--port)-p[Connect to this port. Server must be on the same port.]:port:_files' \ -'(-p)--port=[Connect to this port. Server must be on the same port.]:port:_files' \ -'(--remoteforward)-R[listen-port:host:port Forward remote port to local address]:listen-port:host:port:_files' \ -'(-R)--remoteforward=[listen-port:host:port Forward remote port to local address]:listen-port:host:port:_files' \ -'(--subsystem)-s[Invoke command (mandatory) as SSH2 subsystem.]' \ -'(-s)--subsystem[Invoke command (mandatory) as SSH2 subsystem.]' \ -'(--notty -T --tty)-t[Tty; allocate a tty even if command is given.]' \ -'(--notty -T -t)--tty[Tty; allocate a tty even if command is given.]' \ -'(--user)-l[Log in using this user name.]:user:_files' \ -'(-l)--user=[Log in using this user name.]:user:_files' \ -'(--version)-V[Display version number only.]' \ -'(-V)--version[Display version number only.]' \ -&& return 0 diff --git a/tools/buildbot/pylibs/twisted/python/zsh/_tkmktap b/tools/buildbot/pylibs/twisted/python/zsh/_tkmktap deleted file mode 100644 index e69de29..0000000 diff --git a/tools/buildbot/pylibs/twisted/python/zsh/_trial b/tools/buildbot/pylibs/twisted/python/zsh/_trial deleted file mode 100644 index 01547aec..0000000 --- a/tools/buildbot/pylibs/twisted/python/zsh/_trial +++ /dev/null @@ -1,40 +0,0 @@ -#compdef trial -_arguments -s -A "-*" \ -"*:file|module|package|TestCase|testMethod:_files -g '*.py'" \ -'--coverage[Generate coverage information in the given directory (relative to]' \ -"(--debug)-b[Run tests in the Python debugger. Will load '.pdbrc' from current directory if it exists.]" \ -"(-b)--debug[Run tests in the Python debugger. Will load '.pdbrc' from current directory if it exists.]" \ -'(--debug-stacktraces)-B[Report Deferred creation and callback stack traces]' \ -'(-B)--debug-stacktraces[Report Deferred creation and callback stack traces]' \ -'--disablegc[Disable the garbage collector]' \ -'(--dry-run)-n[do everything but run the tests]' \ -'(-n)--dry-run[do everything but run the tests]' \ -'(--extra)-x[Add an extra argument. (This is a hack necessary for interfacing with]:extra:_files' \ -'(-x)--extra=[Add an extra argument. (This is a hack necessary for interfacing with]:extra:_files' \ -'--force-gc[Have Trial run gc.collect() before and after each test case.]' \ -'(--help)-h[Display this help and exit.]' \ -'(-h)--help[Display this help and exit.]' \ -'--help-reactors[Display a list of possibly available reactor names.]' \ -'--help-reporters[Help on available output plugins (reporters)]' \ -'(--logfile)-l[log file name]:log file name:_files' \ -'(-l)--logfile=[log file name]:log file name:_files' \ -"(--no-recurse)-N[Don't recurse into packages]" \ -"(-N)--no-recurse[Don't recurse into packages]" \ -"--nopm[don't automatically jump into debugger for postmorteming of exceptions]" \ -'--profile[Run tests under the Python profiler]' \ -'(--random)-z[Run tests in random order using the specified seed]:random seed:_files' \ -'(-z)--random=[Run tests in random order using the specified seed]:random seed:_files' \ -'(--reactor)-r[Which reactor to use (see --help-reactors for a list of possibilities)]:reactor:(kqueue win32 epoll iocp gtk cf gtk2 default debug-gui poll glib2 select wx)' \ -'(-r)--reactor=[Which reactor to use (see --help-reactors for a list of possibilities)]:reactor:(kqueue win32 epoll iocp gtk cf gtk2 default debug-gui poll glib2 select wx)' \ -'--recursionlimit=[see sys.setrecursionlimit()]:recursionlimit:_files' \ -'--reporter=[The reporter to use for this test run. See --help-reporters for more info.]:reporter:(bwverbose text verbose timing summary)' \ -'(--rterrors)-e[realtime errors, print out tracebacks as soon as they occur]' \ -'(-e)--rterrors[realtime errors, print out tracebacks as soon as they occur]' \ -'--spew[Print an insanely verbose log of everything that happens. Useful]' \ -'--tbformat=[Specify the format to display tracebacks with. Valid formats are]:tbformat:(plain emacs cgitb)' \ -'--temp-directory=[Path to use as working directory for tests.]:temp-directory:_files' \ -'--testmodule=[Filename to grep for test cases (-*- test-case-name)]:testmodule:_files' \ -'(--until-failure)-u[Repeat test until it fails]' \ -'(-u)--until-failure[Repeat test until it fails]' \ -'--version[version]' \ -&& return 0 diff --git a/tools/buildbot/pylibs/twisted/python/zsh/_twistd b/tools/buildbot/pylibs/twisted/python/zsh/_twistd deleted file mode 100644 index f55996b..0000000 --- a/tools/buildbot/pylibs/twisted/python/zsh/_twistd +++ /dev/null @@ -1,328 +0,0 @@ -#compdef twistd -local _zsh_subcmds_array -_zsh_subcmds_array=( -"web2:An HTTP/1.1 web server that can serve from a filesystem or application resource." -"ftp:An FTP server." -"telnet:A simple, telnet-based remote debugging service." -"socks:A SOCKSv4 proxy service." -"manhole-old:An interactive remote debugger service." -"portforward:A simple port-forwarder." -"web:A general-purpose web server which can serve from a filesystem or application resource." -"inetd:An inetd(8) replacement." -"news:A news server." -"words:A modern words server" -"toc:An AIM TOC service." -"dns:A domain name server." -"mail:An email service" -"manhole:An interactive remote debugger service accessible via telnet and ssh and providing syntax coloring and basic line editing functionality." -"conch:A Conch SSH service." -) - -_arguments -s -A "-*" \ -'*::subcmd:->subcmd' \ -'--chroot=[Chroot to a supplied directory before running]:chroot directory:_dirs' \ -'(--debug)-b[run the application in the Python Debugger (implies nodaemon),]' \ -'(-b)--debug[run the application in the Python Debugger (implies nodaemon),]' \ -'(--encrypted)-e[The specified tap/aos/xml file is encrypted.]' \ -'(-e)--encrypted[The specified tap/aos/xml file is encrypted.]' \ -'--euid[Set only effective user-id rather than real user-id. (This option has no effect unless the server is running as root, in which case it means not to shed all privileges after binding ports, retaining the option to regain privileges in cases such as spawning processes. Use with caution.)]' \ -'(--python --xml --source -y -x -s --file)-f[read the given .tap file]:file:_files -g "*.tap"' \ -'(--python --xml --source -y -x -s -f)--file=[read the given .tap file]:file:_files -g "*.tap"' \ -'(--gid)-g[The gid to run as.]:gid:_files' \ -'(-g)--gid=[The gid to run as.]:gid:_files' \ -'--help[Display this help and exit.]' \ -'--help-reactors[Display a list of possibly available reactor names.]' \ -'(--logfile)-l[log to a specified file, - for stdout]:logfile:_files' \ -'(-l)--logfile=[log to a specified file, - for stdout]:logfile:_files' \ -'(--no_save)-o[do not save state on shutdown]' \ -'(-o)--no_save[do not save state on shutdown]' \ -"(--nodaemon)-n[don't daemonize]" \ -"(-n)--nodaemon[don't daemonize]" \ -"--nothotshot[Don't use the 'hotshot' profiler even if it's available.]" \ -"--originalname[Don't try to change the process name]" \ -'--pidfile=[Name of the pidfile (default: twistd.pid)]:pidfile:_files -g "*.pid"' \ -'--prefix=[Use the given prefix when syslogging (default: twisted)]:prefix:_files' \ -'(--profile)-p[Run in profile mode, dumping results to specified file]:profile:_files' \ -'(-p)--profile=[Run in profile mode, dumping results to specified file]:profile:_files' \ -'(--file --xml --source -f -x -s --python)-y[read an application from within a Python file (implies -o)]:python:_files -g "*.(tac|py)"' \ -'(--file --xml --source -f -x -s -y)--python=[read an application from within a Python file (implies -o)]:python:_files -g "*.(tac|py)"' \ -'(--quiet)-q[No-op for backwards compatability.]' \ -'(-q)--quiet[No-op for backwards compatability.]' \ -'(--reactor)-r[Which reactor to use (see --help-reactors for a list of possibilities)]:reactor:(kqueue win32 epoll iocp gtk cf gtk2 default debug-gui poll glib2 select wx)' \ -'(-r)--reactor=[Which reactor to use (see --help-reactors for a list of possibilities)]:reactor:(kqueue win32 epoll iocp gtk cf gtk2 default debug-gui poll glib2 select wx)' \ -'--report-profile=[E-mail address to use when reporting dynamic execution profiler stats. This should not be combined with other profiling options. This will only take effect if the application to be run has an application name.]:report-profile:_files' \ -'(--rundir)-d[Change to a supplied directory before running]:rundir:_dirs' \ -'(-d)--rundir=[Change to a supplied directory before running]:rundir:_dirs' \ -'--savestats[save the Stats object rather than the text output of the profiler.]' \ -'(--file --python --xml -f -y -x --source)-s[Read an application from a .tas file (AOT format).]:source:_files -g "*.tas"' \ -'(--file --python --xml -f -y -x -s)--source=[Read an application from a .tas file (AOT format).]:source:_files -g "*.tas"' \ -'--spew[Print an insanely verbose log of everything that happens.]' \ -'--syslog[Log to syslog, not to file]' \ -'(--uid)-u[The uid to run as.]:uid:_files' \ -'(-u)--uid=[The uid to run as.]:uid:_files' \ -'--version[Print version information and exit.]' \ -'(--file --python --source -f -y -s --xml)-x[Read an application from a .tax file (Marmalade format).]:xml:_files -g "*.tax"' \ -'(--file --python --source -f -y -s -x)--xml=[Read an application from a .tax file (Marmalade format).]:xml:_files -g "*.tax"' \ -&& return 0 -if (( CURRENT == 1 )); then - _describe "service to run" _zsh_subcmds_array && ret=0 -fi -(( ret )) || return 0 - -service="$words[1]" - -case $service in -web2) -_arguments -s -A "-*" \ -"--allow-ignore-ext[Specify whether or not a request for 'foo' should return 'foo.ext']" \ -"(--certificate)-c[SSL certificate to use for HTTPS.]:certificate:_files -g '*.pem'" \ -"(-c)--certificate=[SSL certificate to use for HTTPS.]:certificate:_files -g '*.pem'" \ -'--class=[A class that will be used to serve the root resource. Must implement twisted.web2.iweb.IResource and take no arguments.]:class:_files' \ -'--dav=[A path that will be used to serve the root resource as a DAV Collection.]:dav:_files' \ -'--help[Display this help and exit.]' \ -'--https=[Port to listen on for Secure HTTP.]:https:_files' \ -'--ignore-ext=[Specify an extension to ignore. These will be processed in order.]:ignore-ext:_files' \ -'(--index)-i[Add the name of a file used to check for directory indexes.]:index:_files' \ -'(-i)--index=[Add the name of a file used to check for directory indexes.]:index:_files' \ -'(--logfile)-l[Common Access Logging Format file to write to if unspecified access log information will be written to the standard twisted log file.]:logfile:_files' \ -'(-l)--logfile=[Common Access Logging Format file to write to if unspecified access log information will be written to the standard twisted log file.]:logfile:_files' \ -"--mimetype=[Mapping from file extension to MIME Type in the form of 'ext=type'.]:mimetype:_files" \ -'--path=[A path that will be used to serve the root resource as a raw file]:path:_files' \ -'(--port)-p[Port to start the server on.]:port:_files' \ -'(-p)--port=[Port to start the server on.]:port:_files' \ -"(--privkey)-k[SSL certificate to use for HTTPS.]:privkey:_files -g '*.pem'" \ -"(-k)--privkey=[SSL certificate to use for HTTPS.]:privkey:_files -g '*.pem'" \ -"--processor=[\`ext=class' where \`class' is added as a Processor for files ending]:processor:_files" \ -'--version[version]' \ -'--vhost-class=[Specify a virtual host in the form of domain=class,]:vhost-class:_files' \ -'--vhost-dav=[Specify a virtual host in the form of domain=path,]:vhost-dav:_files' \ -'--vhost-path=[Specify a directory to use for automatic named virtual hosts.]:vhost-path:_files' \ -'--vhost-static=[Specify a virtual host in the form of domain=path to be served as]:vhost-static:_files' \ -&& return 0 -;; -ftp) -_arguments -s -A "-*" \ -'--help[Display this help and exit.]' \ -'--password-file=[username:password-style credentials database]:password-file:_files' \ -'(--port)-p[set the port number]:port:_files' \ -'(-p)--port=[set the port number]:port:_files' \ -'(--root)-r[define the root of the ftp-site.]:root:_files' \ -'(-r)--root=[define the root of the ftp-site.]:root:_files' \ -'--userAnonymous=[Name of the anonymous user.]:userAnonymous:_files' \ -'--version[version]' \ -&& return 0 -;; -telnet) -_arguments -s -A "-*" \ -'--help[Display this help and exit.]' \ -'(--password)-w[set the password]:password:_files' \ -'(-w)--password=[set the password]:password:_files' \ -'(--port)-p[port to listen on]:port:_files' \ -'(-p)--port=[port to listen on]:port:_files' \ -'(--username)-u[set the login username]:username:_users' \ -'(-u)--username=[set the login username]:username:_users' \ -'--version[version]' \ -&& return 0 -;; -socks) -_arguments -s -A "-*" \ -'--help[Display this help and exit.]' \ -'(--interface)-i[local interface to which we listen]:interface:_files' \ -'(-i)--interface=[local interface to which we listen]:interface:_files' \ -"(--log)-l[file to log connection data to]:log:_files -g '*.log'" \ -"(-l)--log=[file to log connection data to]:log:_files -g '*.log'" \ -'(--port)-p[Port on which to listen]:port:_files' \ -'(-p)--port=[Port on which to listen]:port:_files' \ -'--version[version]' \ -&& return 0 -;; -manhole-old) -_arguments -s -A "-*" \ -'--help[Display this help and exit.]' \ -"(--password)-w[Required. '-' will prompt or read a password from stdin.]:password:_files" \ -"(-w)--password=[Required. '-' will prompt or read a password from stdin.]:password:_files" \ -'(--port)-p[Port to listen on]:port:_files' \ -'(-p)--port=[Port to listen on]:port:_files' \ -'(--tracebacks)-T[Allow tracebacks to be sent over the network]' \ -'(-T)--tracebacks[Allow tracebacks to be sent over the network]' \ -'(--user)-u[Name of user to allow to log in]:user:_users' \ -'(-u)--user=[Name of user to allow to log in]:user:_users' \ -'--version[version]' \ -&& return 0 -;; -portforward) -_arguments -s -A "-*" \ -'(--dest_port)-d[Set the destination port.]:dest_port:_files' \ -'(-d)--dest_port=[Set the destination port.]:dest_port:_files' \ -'--help[Display this help and exit.]' \ -'(--host)-h[Set the host.]:host:_hosts' \ -'(-h)--host=[Set the host.]:host:_hosts' \ -'(--port)-p[Set the port number.]:port:_files' \ -'(-p)--port=[Set the port number.]:port:_files' \ -'--version[version]' \ -&& return 0 -;; -web) -_arguments -s -A "-*" \ -"--allow-ignore-ext[Specify whether or not a request for 'foo' should return 'foo.ext']" \ -"(--certificate)-c[SSL certificate to use for HTTPS. ]:certificate:_files -g '*.pem'" \ -"(-c)--certificate=[SSL certificate to use for HTTPS. ]:certificate:_files -g '*.pem'" \ -'--class=[Create a Resource subclass with a zero-argument constructor.]:class:_files' \ -'--flashconduit=[Start a flashconduit on the specified port.]:flashconduit:_files' \ -'--help[Display this help and exit.]' \ -'--https=[Port to listen on for Secure HTTP.]:https:_files' \ -'--ignore-ext=[Specify an extension to ignore. These will be processed in order.]:ignore-ext:_files' \ -'(--index)-i[Add the name of a file used to check for directory indexes.]:index:_files' \ -'(-i)--index=[Add the name of a file used to check for directory indexes.]:index:_files' \ -"(--logfile)-l[Path to web CLF (Combined Log Format) log file.]:logfile:_files -g '*.log'" \ -"(-l)--logfile=[Path to web CLF (Combined Log Format) log file.]:logfile:_files -g '*.log'" \ -'(--mime-type)-m[Specify the default mime-type for static files.]:mime-type:_files' \ -'(-m)--mime-type=[Specify the default mime-type for static files.]:mime-type:_files' \ -'(--notracebacks)-n[Display tracebacks in broken web pages. Displaying tracebacks to users may be security risk!]' \ -'(-n)--notracebacks[Display tracebacks in broken web pages. Displaying tracebacks to users may be security risk!]' \ -'--path=[ is either a specific file or a directory to]:path:_files' \ -'--personal[Instead of generating a webserver, generate a ResourcePublisher which listens on ~/.twistd-web-pb]' \ -'(--port)-p[Port to start the server on.]:port:_files' \ -'(-p)--port=[Port to start the server on.]:port:_files' \ -"(--privkey)-k[SSL certificate to use for HTTPS.]:privkey:_files -g '*.pem'" \ -"(-k)--privkey=[SSL certificate to use for HTTPS.]:privkey:_files -g '*.pem'" \ -"--processor=[\`ext=class' where \`class' is added as a Processor for files ending]:processor:_files" \ -'--resource-script=[An .rpy file to be used as the root resource of the webserver.]:resource-script:_files' \ -'(--static)-s[Same as --path, this is deprecated and will be removed in a]:static:_files' \ -'(-s)--static=[Same as --path, this is deprecated and will be removed in a]:static:_files' \ -'(--user)-u[Makes a server with ~/public_html and ~/.twistd-web-pb support for]' \ -'(-u)--user[Makes a server with ~/public_html and ~/.twistd-web-pb support for]' \ -'--version[version]' \ -&& return 0 -;; -inetd) -_arguments -s -A "-*" \ -"(--file)-f[Service configuration file]:file:_files -g '*.conf'" \ -"(-f)--file=[Service configuration file]:file:_files -g '*.conf'" \ -'--help[Display this help and exit.]' \ -"(--nointernal)-i[Don't run internal services]" \ -"(-i)--nointernal[Don't run internal services]" \ -'(--rpc)-r[RPC procedure table file]:rpc:_files' \ -'(-r)--rpc=[RPC procedure table file]:rpc:_files' \ -'--version[version]' \ -&& return 0 -;; -news) -_arguments -s -A "-*" \ -'(--datadir)-d[Root data storage path]:datadir:_dirs' \ -'(-d)--datadir=[Root data storage path]:datadir:_dirs' \ -'--group=[The name of a newsgroup to carry.]:group:_files' \ -'--help[Display this help and exit.]' \ -'(--interface)-i[Interface to which to bind]:interface:_files' \ -'(-i)--interface=[Interface to which to bind]:interface:_files' \ -'(--mailhost)-m[Host of SMTP server to use]:mailhost:_hosts' \ -'(-m)--mailhost=[Host of SMTP server to use]:mailhost:_hosts' \ -'--moderator=[The email of the moderator for the most recently passed group.]:moderator:_files' \ -'(--port)-p[Listen port]:port:_files' \ -'(-p)--port=[Listen port]:port:_files' \ -'--server=[The address of a Usenet server to pass messages to and receive messages from.]:server:_files' \ -'--subscription=[A newsgroup to list as a recommended subscription.]:subscription:_files' \ -'--version[version]' \ -&& return 0 -;; -words) -_arguments -s -A "-*" \ -'--group=[Specify a group which should exist]:group:_files' \ -'--help[Display this help and exit.]' \ -'--hostname=[Name of this server; purely an informative]:hostname:_files' \ -'--irc-port=[strports description of the port to bind for the irc server]:irc-port:_files' \ -'--passwd=[Name of a passwd-style password file. (REQUIRED)]:passwd:_files' \ -'--pb-port=[strports description of the port to bind for the pb server]:pb-port:_files' \ -'--version[version]' \ -&& return 0 -;; -toc) -_arguments -s -A "-*" \ -'--help[Display this help and exit.]' \ -'(--port)-p[port]:port:_files' \ -'(-p)--port=[port]:port:_files' \ -'--version[version]' \ -&& return 0 -;; -dns) -_arguments -s -A "-*" \ -'--bindzone=[Specify the filename of a BIND9 syntax zone definition]:bindzone:_files' \ -'(--cache)-c[Enable record caching]' \ -'(-c)--cache[Enable record caching]' \ -'--help[Display this help and exit.]' \ -'--hosts-file=[Perform lookups with a hosts file]:hosts-file:_files' \ -'(--interface)-i[The interface to which to bind]:interface:_files' \ -'(-i)--interface=[The interface to which to bind]:interface:_files' \ -'(--port)-p[The port on which to listen]:port:_files' \ -'(-p)--port=[The port on which to listen]:port:_files' \ -'--pyzone=[Specify the filename of a Python syntax zone definition]:pyzone:_files' \ -'(--recursive)-r[Perform recursive lookups]' \ -'(-r)--recursive[Perform recursive lookups]' \ -'--resolv-conf=[Override location of resolv.conf (implies --recursive)]:resolv-conf:_files' \ -'--secondary=[Act as secondary for the specified domain, performing]:secondary:_files' \ -'(--verbose)-v[Log verbosely]' \ -'(-v)--verbose[Log verbosely]' \ -'--version[version]' \ -&& return 0 -;; -mail) -_arguments -s -A "-*" \ -'(--aliases)-A[Specify an aliases(5) file to use for this domain]:aliases:_files' \ -'(-A)--aliases=[Specify an aliases(5) file to use for this domain]:aliases:_files' \ -'(--bounce-to-postmaster)-b[undelivered mails are sent to the postmaster]' \ -'(-b)--bounce-to-postmaster[undelivered mails are sent to the postmaster]' \ -'(--certificate)-c[Certificate file to use for SSL connections]:certificate:_files' \ -'(-c)--certificate=[Certificate file to use for SSL connections]:certificate:_files' \ -'(--default)-D[Make the most recently specified domain the default domain.]' \ -'(-D)--default[Make the most recently specified domain the default domain.]' \ -'--disable-anonymous[Disallow non-authenticated SMTP connections]' \ -'(--esmtp)-E[Use RFC 1425/1869 SMTP extensions]' \ -'(-E)--esmtp[Use RFC 1425/1869 SMTP extensions]' \ -'--help[Display this help and exit.]' \ -'(--hostname)-H[The hostname by which to identify this server.]:hostname:_hosts' \ -'(-H)--hostname=[The hostname by which to identify this server.]:hostname:_hosts' \ -'(--maildirdbmdomain)-d[generate an SMTP/POP3 virtual domain which saves to "path"]:maildirdbmdomain:_files' \ -'(-d)--maildirdbmdomain=[generate an SMTP/POP3 virtual domain which saves to "path"]:maildirdbmdomain:_files' \ -'(--passwordfile)-P[Specify a file containing username:password login info for authenticated ESMTP connections.]:passwordfile:_files' \ -'(-P)--passwordfile=[Specify a file containing username:password login info for authenticated ESMTP connections.]:passwordfile:_files' \ -'(--pop3)-p[Port to start the POP3 server on (0 to disable).]:pop3:_files' \ -'(-p)--pop3=[Port to start the POP3 server on (0 to disable).]:pop3:_files' \ -'(--pop3s)-S[Port to start the POP3-over-SSL server on (0 to disable).]:pop3s:_files' \ -'(-S)--pop3s=[Port to start the POP3-over-SSL server on (0 to disable).]:pop3s:_files' \ -"(--relay)-R[Relay messages according to their envelope 'To', using the givenpath as a queue directory.]:relay:_files" \ -"(-R)--relay=[Relay messages according to their envelope 'To', using the givenpath as a queue directory.]:relay:_files" \ -'(--smtp)-s[Port to start the SMTP server on (0 to disable).]:smtp:_files' \ -'(-s)--smtp=[Port to start the SMTP server on (0 to disable).]:smtp:_files' \ -'(--user)-u[add a user/password to the last specified domains]:user:_files' \ -'(-u)--user=[add a user/password to the last specified domains]:user:_files' \ -'--version[version]' \ -&& return 0 -;; -manhole) -_arguments -s -A "-*" \ -'--help[Display this help and exit.]' \ -'(--passwd)-p[name of a passwd(5)-format username/password file]:passwd:_files' \ -'(-p)--passwd=[name of a passwd(5)-format username/password file]:passwd:_files' \ -'(--sshPort)-s[strports description of the address on which to listen for ssh connections]:sshPort:_files' \ -'(-s)--sshPort=[strports description of the address on which to listen for ssh connections]:sshPort:_files' \ -'(--telnetPort)-t[strports description of the address on which to listen for telnet connections]:telnetPort:_files' \ -'(-t)--telnetPort=[strports description of the address on which to listen for telnet connections]:telnetPort:_files' \ -'--user=[user]:user:_files' \ -'--version[version]' \ -&& return 0 -;; -conch) -_arguments -s -A "-*" \ -'(--data)-d[directory to look for host keys in]:data:_dirs' \ -'(-d)--data=[directory to look for host keys in]:data:_dirs' \ -'--help[Display this help and exit.]' \ -'(--interface)-i[local interface to which we listen]:interface:_files' \ -'(-i)--interface=[local interface to which we listen]:interface:_files' \ -'--moduli=[directory to look for moduli in (if different from --data)]:moduli:_dirs' \ -'(--port)-p[Port on which to listen]:port:_files' \ -'(-p)--port=[Port on which to listen]:port:_files' \ -'--version[version]' \ -&& return 0 -;; -*) _message "don't know how to complete $service";; -esac \ No newline at end of file diff --git a/tools/buildbot/pylibs/twisted/python/zsh/_websetroot b/tools/buildbot/pylibs/twisted/python/zsh/_websetroot deleted file mode 100644 index e69de29..0000000 diff --git a/tools/buildbot/pylibs/twisted/python/zshcomp.py b/tools/buildbot/pylibs/twisted/python/zshcomp.py deleted file mode 100644 index 4910cfd..0000000 --- a/tools/buildbot/pylibs/twisted/python/zshcomp.py +++ /dev/null @@ -1,780 +0,0 @@ -# -*- test-case-name: twisted.test.test_zshcomp -*- -# Copyright (c) 2006 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Rebuild the completion functions for the currently active version of Twisted:: - $ python zshcomp.py -i - -This module implements a zsh code generator which generates completion code for -commands that use twisted.python.usage. This is the stuff that makes pressing -Tab at the command line work. - -Maintainer: Eric Mangold - -To build completion functions for your own commands, and not Twisted commands, -then just do something like this:: - - o = mymodule.MyOptions() - f = file('_mycommand', 'w') - Builder("mycommand", o, f).write() - -Then all you have to do is place the generated file somewhere in your -C{$fpath}, and restart zsh. Note the "site-functions" directory in your -C{$fpath} where you may install 3rd-party completion functions (like the one -you're building). Call C{siteFunctionsPath} to locate this directory -programmatically. - -SPECIAL CLASS VARIABLES. You may set these on your usage.Options subclass:: - - zsh_altArgDescr - zsh_multiUse - zsh_mutuallyExclusive - zsh_actions - zsh_actionDescr - zsh_extras - -Here is what they mean (with examples):: - - zsh_altArgDescr = {"foo":"use this description for foo instead"} - A dict mapping long option names to alternate descriptions. When this - variable is present, the descriptions contained here will override - those descriptions provided in the optFlags and optParameters - variables. - - zsh_multiUse = ["foo", "bar"] - A sequence containing those long option names which may appear on the - command line more than once. By default, options will only be completed - one time. - - zsh_mutuallyExclusive = [("foo", "bar"), ("bar", "baz")] - A sequence of sequences, with each sub-sequence containing those long - option names that are mutually exclusive. That is, those options that - cannot appear on the command line together. - - zsh_actions = {"foo":'_files -g "*.foo"', "bar":"(one two three)", - "colors":"_values -s , 'colors to use' red green blue"} - A dict mapping long option names to Zsh "actions". These actions - define what will be completed as the argument to the given option. By - default, all files/dirs will be completed if no action is given. - - Callables may instead be given for the values in this dict. The - callable should accept no arguments, and return a string that will be - used as the zsh "action" in the same way as the literal strings in the - examples above. - - As you can see in the example above. The "foo" option will have files - that end in .foo completed when the user presses Tab. The "bar" - option will have either of the strings "one", "two", or "three" - completed when the user presses Tab. - - "colors" will allow multiple arguments to be completed, seperated by - commas. The possible arguments are red, green, and blue. Examples:: - - my_command --foo some-file.foo --colors=red,green - my_command --colors=green - my_command --colors=green,blue - - Actions may take many forms, and it is beyond the scope of this - document to illustrate them all. Please refer to the documention for - the Zsh _arguments function. zshcomp is basically a front-end to Zsh's - _arguments completion function. - - That documentation is available on the zsh web site at this URL: - U{http://zsh.sunsite.dk/Doc/Release/zsh_19.html#SEC124} - - zsh_actionDescr = {"logfile":"log file name", "random":"random seed"} - A dict mapping long option names to a description for the corresponding - zsh "action". These descriptions are show above the generated matches - when the user is doing completions for this option. - - Normally Zsh does not show these descriptions unless you have - "verbose" completion turned on. Turn on verbosity with this in your - ~/.zshrc:: - - zstyle ':completion:*' verbose yes - zstyle ':completion:*:descriptions' format '%B%d%b' - - zsh_extras = [":file to read from:action", ":file to write to:action"] - A sequence of extra arguments that will be passed verbatim to Zsh's - _arguments completion function. The _arguments function does all the - hard work of doing command line completions. You can see how zshcomp - invokes the _arguments call by looking at the generated completion - files that this module creates. - - *** NOTE *** - - You will need to use this variable to describe completions for normal - command line arguments. That is, those arguments that are not - associated with an option. That is, the arguments that are given to the - parseArgs method of your usage.Options subclass. - - In the example above, the 1st non-option argument will be described as - "file to read from" and completion options will be generated in - accordance with the "action". (See above about zsh "actions") The - 2nd non-option argument will be described as "file to write to" and - the action will be interpreted likewise. - - Things you can put here are all documented under the _arguments - function here: U{http://zsh.sunsite.dk/Doc/Release/zsh_19.html#SEC124} - -Zsh Notes: - -To enable advanced completion add something like this to your ~/.zshrc:: - - autoload -U compinit - compinit - -For some extra verbosity, and general niceness add these lines too:: - - zstyle ':completion:*' verbose yes - zstyle ':completion:*:descriptions' format '%B%d%b' - zstyle ':completion:*:messages' format '%d' - zstyle ':completion:*:warnings' format 'No matches for: %d' - -Have fun! -""" -import itertools, sys, commands, os.path - -from twisted.python import reflect, util, usage -from twisted.scripts.mktap import IServiceMaker - -class MyOptions(usage.Options): - """ - Options for this file - """ - longdesc = "" - synopsis = "Usage: python zshcomp.py [--install | -i] | " - optFlags = [["install", "i", - 'Output files to the "installation" directory ' \ - '(twisted/python/zsh in the currently active ' \ - 'Twisted package)']] - optParameters = [["directory", "d", None, - "Output files to this directory"]] - def postOptions(self): - if self['install'] and self['directory']: - raise usage.UsageError, "Can't have --install and " \ - "--directory at the same time" - if not self['install'] and not self['directory']: - raise usage.UsageError, "Not enough arguments" - if self['directory'] and not os.path.isdir(self['directory']): - raise usage.UsageError, "%s is not a directory" % self['directory'] - -class Builder: - def __init__(self, cmd_name, options, file): - """ - @type cmd_name: C{str} - @param cmd_name: The name of the command - - @type options: C{twisted.usage.Options} - @param options: The C{twisted.usage.Options} instance defined for - this command - - @type file: C{file} - @param file: The C{file} to write the completion function to - """ - - self.cmd_name = cmd_name - self.options = options - self.file = file - - def write(self): - """ - Write the completion function to the file given to __init__ - @return: C{None} - """ - # by default, we just write out a single call to _arguments - self.file.write('#compdef %s\n' % (self.cmd_name,)) - gen = ArgumentsGenerator(self.cmd_name, self.options, self.file) - gen.write() - -class SubcommandBuilder(Builder): - """ - Use this builder for commands that have sub-commands. twisted.python.usage - has the notion of sub-commands that are defined using an entirely seperate - Options class. - """ - interface = None - subcmdLabel = None - - def write(self): - """ - Write the completion function to the file given to __init__ - @return: C{None} - """ - self.file.write('#compdef %s\n' % (self.cmd_name,)) - self.file.write('local _zsh_subcmds_array\n_zsh_subcmds_array=(\n') - from twisted import plugin as newplugin - plugins = newplugin.getPlugins(self.interface) - - for p in plugins: - self.file.write('"%s:%s"\n' % (p.tapname, p.description)) - self.file.write(")\n\n") - - self.options.__class__.zsh_extras = ['*::subcmd:->subcmd'] - gen = ArgumentsGenerator(self.cmd_name, self.options, self.file) - gen.write() - - self.file.write("""if (( CURRENT == 1 )); then - _describe "%s" _zsh_subcmds_array && ret=0 -fi -(( ret )) || return 0 - -service="$words[1]" - -case $service in\n""" % (self.subcmdLabel,)) - - plugins = newplugin.getPlugins(self.interface) - for p in plugins: - self.file.write(p.tapname + ")\n") - gen = ArgumentsGenerator(p.tapname, p.options(), self.file) - gen.write() - self.file.write(";;\n") - self.file.write("*) _message \"don't know how to" \ - " complete $service\";;\nesac") - -class MktapBuilder(SubcommandBuilder): - """ - Builder for the mktap command - """ - interface = IServiceMaker - subcmdLabel = 'tap to build' - -class TwistdBuilder(SubcommandBuilder): - """ - Builder for the twistd command - """ - interface = IServiceMaker - subcmdLabel = 'service to run' - -class ArgumentsGenerator: - """ - Generate a call to the zsh _arguments completion function - based on data in a usage.Options subclass - """ - def __init__(self, cmd_name, options, file): - """ - @type cmd_name: C{str} - @param cmd_name: The name of the command - - @type options: C{twisted.usage.Options} - @param options: The C{twisted.usage.Options} instance defined - for this command - - @type file: C{file} - @param file: The C{file} to write the completion function to - """ - self.cmd_name = cmd_name - self.options = options - self.file = file - - self.altArgDescr = {} - self.actionDescr = {} - self.multiUse = [] - self.mutuallyExclusive = [] - self.actions = {} - self.extras = [] - - aCL = reflect.accumulateClassList - aCD = reflect.accumulateClassDict - - aCD(options.__class__, 'zsh_altArgDescr', self.altArgDescr) - aCD(options.__class__, 'zsh_actionDescr', self.actionDescr) - aCL(options.__class__, 'zsh_multiUse', self.multiUse) - aCL(options.__class__, 'zsh_mutuallyExclusive', - self.mutuallyExclusive) - aCD(options.__class__, 'zsh_actions', self.actions) - aCL(options.__class__, 'zsh_extras', self.extras) - - optFlags = [] - optParams = [] - - aCL(options.__class__, 'optFlags', optFlags) - aCL(options.__class__, 'optParameters', optParams) - - for i, optList in enumerate(optFlags): - if len(optList) != 3: - optFlags[i] = util.padTo(3, optList) - - for i, optList in enumerate(optParams): - if len(optList) != 4: - optParams[i] = util.padTo(4, optList) - - - self.optFlags = optFlags - self.optParams = optParams - - optParams_d = {} - for optList in optParams: - optParams_d[optList[0]] = optList[1:] - self.optParams_d = optParams_d - - optFlags_d = {} - for optList in optFlags: - optFlags_d[optList[0]] = optList[1:] - self.optFlags_d = optFlags_d - - optAll_d = {} - optAll_d.update(optParams_d) - optAll_d.update(optFlags_d) - self.optAll_d = optAll_d - - self.addAdditionalOptions() - - # makes sure none of the zsh_ data structures reference option - # names that don't exist. (great for catching typos) - self.verifyZshNames() - - self.excludes = self.makeExcludesDict() - - def write(self): - """ - Write the zsh completion code to the file given to __init__ - @return: C{None} - """ - self.writeHeader() - self.writeExtras() - self.writeOptions() - self.writeFooter() - - def writeHeader(self): - """ - This is the start of the code that calls _arguments - @return: C{None} - """ - self.file.write('_arguments -s -A "-*" \\\n') - - def writeOptions(self): - """ - Write out zsh code for each option in this command - @return: C{None} - """ - optNames = self.optAll_d.keys() - optNames.sort() - for long in optNames: - self.writeOpt(long) - - def writeExtras(self): - """ - Write out the "extras" list. These are just passed verbatim to the - _arguments call - @return: C{None} - """ - for s in self.extras: - self.file.write(escape(s)) - self.file.write(' \\\n') - - def writeFooter(self): - """ - Write the last bit of code that finishes the call to _arguments - @return: C{None} - """ - self.file.write('&& return 0\n') - - def verifyZshNames(self): - """ - Ensure that none of the names given in zsh_* variables are typoed - @return: C{None} - @raise ValueError: Raised if unknown option names have been given in - zsh_* variables - """ - def err(name): - raise ValueError, "Unknown option name \"%s\" found while\n" \ - "examining zsh_ attributes for the %s command" % ( - name, self.cmd_name) - - for name in itertools.chain(self.altArgDescr, self.actionDescr, - self.actions, self.multiUse): - if name not in self.optAll_d: - err(name) - - for seq in self.mutuallyExclusive: - for name in seq: - if name not in self.optAll_d: - err(name) - - def excludeStr(self, long, buildShort=False): - """ - Generate an "exclusion string" for the given option - - @type long: C{str} - @param long: The long name of the option - (i.e. "verbose" instead of "v") - - @type buildShort: C{bool} - @param buildShort: May be True to indicate we're building an excludes - string for the short option that correspondes to - the given long opt - - @return: The generated C{str} - """ - if long in self.excludes: - exclusions = self.excludes[long][:] - else: - exclusions = [] - - # if long isn't a multiUse option (can't appear on the cmd line more - # than once), then we have to exclude the short option if we're - # building for the long option, and vice versa. - if long not in self.multiUse: - if buildShort is False: - short = self.getShortOption(long) - if short is not None: - exclusions.append(short) - else: - exclusions.append(long) - - if not exclusions: - return '' - - strings = [] - for optName in exclusions: - if len(optName) == 1: - # short option - strings.append("-" + optName) - else: - strings.append("--" + optName) - return "(%s)" % " ".join(strings) - - def makeExcludesDict(self): - """ - @return: A C{dict} that maps each option name appearing in - self.mutuallyExclusive to a list of those option names that - is it mutually exclusive with (can't appear on the cmd line with) - """ - - #create a mapping of long option name -> single character name - longToShort = {} - for optList in itertools.chain(self.optParams, self.optFlags): - try: - if optList[1] != None: - longToShort[optList[0]] = optList[1] - except IndexError: - pass - - excludes = {} - for lst in self.mutuallyExclusive: - for i, long in enumerate(lst): - tmp = [] - tmp.extend(lst[:i]) - tmp.extend(lst[i+1:]) - for name in tmp[:]: - if name in longToShort: - tmp.append(longToShort[name]) - - if long in excludes: - excludes[long].extend(tmp) - else: - excludes[long] = tmp - return excludes - - def writeOpt(self, long): - """ - Write out the zsh code for the given argument. This is just part of the - one big call to _arguments - - @type long: C{str} - @param long: The long name of the option - (i.e. "verbose" instead of "v") - - @return: C{None} - """ - if long in self.optFlags_d: - # It's a flag option. Not one that takes a parameter. - long_field = "--%s" % long - else: - long_field = "--%s=" % long - - short = self.getShortOption(long) - if short != None: - short_field = "-" + short - else: - short_field = '' - - descr = self.getDescription(long) - descr_field = descr.replace("[", "\[") - descr_field = descr_field.replace("]", "\]") - descr_field = '[%s]' % descr_field - - if long in self.actionDescr: - actionDescr_field = self.actionDescr[long] - else: - actionDescr_field = descr - - action_field = self.getAction(long) - if long in self.multiUse: - multi_field = '*' - else: - multi_field = '' - - longExclusions_field = self.excludeStr(long) - - if short: - #we have to write an extra line for the short option if we have one - shortExclusions_field = self.excludeStr(long, buildShort=True) - self.file.write(escape('%s%s%s%s%s' % (shortExclusions_field, - multi_field, short_field, descr_field, action_field))) - self.file.write(' \\\n') - - self.file.write(escape('%s%s%s%s%s' % (longExclusions_field, - multi_field, long_field, descr_field, action_field))) - self.file.write(' \\\n') - - def getAction(self, long): - """ - Return a zsh "action" string for the given argument - @return: C{str} - """ - if long in self.actions: - if callable(self.actions[long]): - action = self.actions[long]() - else: - action = self.actions[long] - return ":%s:%s" % (self.getActionDescr(long), action) - if long in self.optParams_d: - return ':%s:_files' % self.getActionDescr(long) - return '' - - def getActionDescr(self, long): - """ - Return the description to be used when this argument is completed - @return: C{str} - """ - if long in self.actionDescr: - return self.actionDescr[long] - else: - return long - - def getDescription(self, long): - """ - Return the description to be used for this argument - @return: C{str} - """ - #check if we have an alternate descr for this arg, and if so use it - if long in self.altArgDescr: - return self.altArgDescr[long] - - #otherwise we have to get it from the optFlags or optParams - try: - descr = self.optFlags_d[long][1] - except KeyError: - try: - descr = self.optParams_d[long][2] - except KeyError: - descr = None - - if descr is not None: - return descr - - # lets try to get it from the opt_foo method doc string if there is one - longMangled = long.replace('-', '_') # this is what t.p.usage does - obj = getattr(self.options, 'opt_%s' % longMangled, None) - if obj: - descr = descrFromDoc(obj) - if descr is not None: - return descr - - return long # we really ought to have a good description to use - - def getShortOption(self, long): - """ - Return the short option letter or None - @return: C{str} or C{None} - """ - optList = self.optAll_d[long] - try: - return optList[0] or None - except IndexError: - pass - - def addAdditionalOptions(self): - """ - Add additional options to the optFlags and optParams lists. - These will be defined by 'opt_foo' methods of the Options subclass - @return: C{None} - """ - methodsDict = {} - reflect.accumulateMethods(self.options, methodsDict, 'opt_') - methodToShort = {} - for name in methodsDict.copy(): - if len(name) == 1: - methodToShort[methodsDict[name]] = name - del methodsDict[name] - - for methodName, methodObj in methodsDict.items(): - long = methodName.replace('_', '-') # t.p.usage does this - # if this option is already defined by the optFlags or - # optParameters then we don't want to override that data - if long in self.optAll_d: - continue - - descr = self.getDescription(long) - - short = None - if methodObj in methodToShort: - short = methodToShort[methodObj] - - reqArgs = methodObj.im_func.func_code.co_argcount - if reqArgs == 2: - self.optParams.append([long, short, None, descr]) - self.optParams_d[long] = [short, None, descr] - self.optAll_d[long] = [short, None, descr] - elif reqArgs == 1: - self.optFlags.append([long, short, descr]) - self.optFlags_d[long] = [short, descr] - self.optAll_d[long] = [short, None, descr] - else: - raise TypeError, '%r has wrong number ' \ - 'of arguments' % (methodObj,) - -def descrFromDoc(obj): - """ - Generate an appropriate description from docstring of the given object - """ - if obj.__doc__ is None: - return None - - lines = obj.__doc__.split("\n") - descr = None - try: - if lines[0] != "" and not lines[0].isspace(): - descr = lines[0].lstrip() - # skip first line if it's blank - elif lines[1] != "" and not lines[1].isspace(): - descr = lines[1].lstrip() - except IndexError: - pass - return descr - -def firstLine(s): - """ - Return the first line of the given string - """ - try: - i = s.index('\n') - return s[:i] - except ValueError: - return s - -def escape(str): - """ - Shell escape the given string - """ - return commands.mkarg(str)[1:] - -def siteFunctionsPath(): - """ - Return the path to the system-wide site-functions directory or - C{None} if it cannot be determined - """ - try: - cmd = "zsh -f -c 'echo ${(M)fpath:#/*/site-functions}'" - output = commands.getoutput(cmd) - if os.path.isdir(output): - return output - except: - pass - -generateFor = [('conch', 'twisted.conch.scripts.conch', 'ClientOptions'), - ('mktap', 'twisted.scripts.mktap', 'FirstPassOptions'), - ('trial', 'twisted.scripts.trial', 'Options'), - ('cftp', 'twisted.conch.scripts.cftp', 'ClientOptions'), - ('tapconvert', 'twisted.scripts.tapconvert', 'ConvertOptions'), - ('twistd', 'twisted.scripts.twistd', 'ServerOptions'), - ('ckeygen', 'twisted.conch.scripts.ckeygen', 'GeneralOptions'), - ('lore', 'twisted.lore.scripts.lore', 'Options'), - ('pyhtmlizer', 'twisted.scripts.htmlizer', 'Options'), - ('tap2deb', 'twisted.scripts.tap2deb', 'MyOptions'), - ('tkconch', 'twisted.conch.scripts.tkconch', 'GeneralOptions'), - ('manhole', 'twisted.scripts.manhole', 'MyOptions'), - ('tap2rpm', 'twisted.scripts.tap2rpm', 'MyOptions'), - ('websetroot', None, None), - ('tkmktap', None, None), - ] -# NOTE: the commands using None above are no longer included in Twisted. -# However due to limitations in zsh's completion system the version of -# _twisted_zsh_stub shipped with zsh contains a static list of Twisted's -# commands. It will display errors if completion functions for these missing -# commands are not found :( So we just include dummy (empty) completion -# function files - -specialBuilders = {'mktap' : MktapBuilder, - 'twistd' : TwistdBuilder} - -def makeCompFunctionFiles(out_path, generateFor=generateFor, - specialBuilders=specialBuilders): - """ - Generate completion function files in the given directory for all - twisted commands - - @type out_path: C{str} - @param out_path: The path to the directory to generate completion function - fils in - - @param generateFor: Sequence in the form of the 'generateFor' top-level - variable as defined in this module. Indicates what - commands to build completion files for. - - @param specialBuilders: Sequence in the form of the 'specialBuilders' - top-level variable as defined in this module. - Indicates what commands require a special - Builder class. - - @return: C{list} of 2-tuples of the form (cmd_name, error) indicating - commands that we skipped building completions for. cmd_name - is the name of the skipped command, and error is the Exception - that was raised when trying to import the script module. - Commands are usually skipped due to a missing dependency, - e.g. Tkinter. - """ - skips = [] - for cmd_name, module_name, class_name in generateFor: - if module_name is None: - # create empty file - f = _openCmdFile(out_path, cmd_name) - f.close() - continue - try: - m = __import__('%s' % (module_name,), None, None, (class_name)) - f = _openCmdFile(out_path, cmd_name) - o = getattr(m, class_name)() # instantiate Options class - - if cmd_name in specialBuilders: - b = specialBuilders[cmd_name](cmd_name, o, f) - b.write() - else: - b = Builder(cmd_name, o, f) - b.write() - except Exception, e: - skips.append( (cmd_name, e) ) - continue - return skips - -def _openCmdFile(out_path, cmd_name): - return file(os.path.join(out_path, '_'+cmd_name), 'w') - -def run(): - options = MyOptions() - try: - options.parseOptions(sys.argv[1:]) - except usage.UsageError, e: - print e - print options.getUsage() - sys.exit(2) - - if options['install']: - import twisted - dir = os.path.join(os.path.dirname(twisted.__file__), "python", "zsh") - skips = makeCompFunctionFiles(dir) - else: - skips = makeCompFunctionFiles(options['directory']) - - for cmd_name, error in skips: - sys.stderr.write("zshcomp: Skipped building for %s. Script module " \ - "could not be imported:\n" % (cmd_name,)) - sys.stderr.write(str(error)+'\n') - if skips: - sys.exit(3) - -if __name__ == '__main__': - run() diff --git a/tools/buildbot/pylibs/twisted/runner/__init__.py b/tools/buildbot/pylibs/twisted/runner/__init__.py deleted file mode 100644 index 43ce469..0000000 --- a/tools/buildbot/pylibs/twisted/runner/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -""" -Twisted runer: run and monitor processes - -Maintainer: U{Andrew Bennetts} - -classic inetd(8) support: -Future Plans: The basic design should be final. There are some bugs that need -fixing regarding UDP and Sun-RPC support. Perhaps some day xinetd -compatibility will be added. - -procmon:monitor and restart processes -""" - -from twisted.runner._version import version -__version__ = version.short() diff --git a/tools/buildbot/pylibs/twisted/runner/_version.py b/tools/buildbot/pylibs/twisted/runner/_version.py deleted file mode 100644 index 42f001f..0000000 --- a/tools/buildbot/pylibs/twisted/runner/_version.py +++ /dev/null @@ -1,3 +0,0 @@ -# This is an auto-generated file. Do not edit it. -from twisted.python import versions -version = versions.Version('twisted.runner', 8, 0, 0) diff --git a/tools/buildbot/pylibs/twisted/runner/inetd.py b/tools/buildbot/pylibs/twisted/runner/inetd.py deleted file mode 100644 index ddcb2a2..0000000 --- a/tools/buildbot/pylibs/twisted/runner/inetd.py +++ /dev/null @@ -1,70 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -""" -Twisted inetd. - -Maintainer: U{Andrew Bennetts} - -Future Plans: Bugfixes. Specifically for UDP and Sun-RPC, which don't work -correctly yet. -""" - -import os - -from twisted.internet import process, reactor, fdesc -from twisted.internet.protocol import Protocol, ServerFactory -from twisted.protocols import wire - -# A dict of known 'internal' services (i.e. those that don't involve spawning -# another process. -internalProtocols = { - 'echo': wire.Echo, - 'chargen': wire.Chargen, - 'discard': wire.Discard, - 'daytime': wire.Daytime, - 'time': wire.Time, -} - - -class InetdProtocol(Protocol): - """Forks a child process on connectionMade, passing the socket as fd 0.""" - def connectionMade(self): - sockFD = self.transport.fileno() - childFDs = {0: sockFD, 1: sockFD} - if self.factory.stderrFile: - childFDs[2] = self.factory.stderrFile.fileno() - - # processes run by inetd expect blocking sockets - # FIXME: maybe this should be done in process.py? are other uses of - # Process possibly affected by this? - fdesc.setBlocking(sockFD) - if childFDs.has_key(2): - fdesc.setBlocking(childFDs[2]) - - service = self.factory.service - uid = service.user - gid = service.group - - # don't tell Process to change our UID/GID if it's what we - # already are - if uid == os.getuid(): - uid = None - if gid == os.getgid(): - gid = None - - process.Process(None, service.program, service.programArgs, os.environ, - None, None, uid, gid, childFDs) - - reactor.removeReader(self.transport) - reactor.removeWriter(self.transport) - - -class InetdFactory(ServerFactory): - protocol = InetdProtocol - stderrFile = None - - def __init__(self, service): - self.service = service diff --git a/tools/buildbot/pylibs/twisted/runner/inetdconf.py b/tools/buildbot/pylibs/twisted/runner/inetdconf.py deleted file mode 100644 index 9df90dc..0000000 --- a/tools/buildbot/pylibs/twisted/runner/inetdconf.py +++ /dev/null @@ -1,194 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -""" -Parser for inetd.conf files - -Maintainer: U{Andrew Bennetts} - -Future Plans: xinetd configuration file support? -""" - -# Various exceptions -class InvalidConfError(Exception): - """Invalid configuration file""" - - -class InvalidInetdConfError(InvalidConfError): - """Invalid inetd.conf file""" - - -class InvalidServicesConfError(InvalidConfError): - """Invalid services file""" - - -class InvalidRPCServicesConfError(InvalidConfError): - """Invalid rpc services file""" - - -class UnknownService(Exception): - """Unknown service name""" - - -class SimpleConfFile: - """Simple configuration file parser superclass. - - Filters out comments and empty lines (which includes lines that only - contain comments). - - To use this class, override parseLine or parseFields. - """ - - commentChar = '#' - defaultFilename = None - - def parseFile(self, file=None): - """Parse a configuration file - - If file is None and self.defaultFilename is set, it will open - defaultFilename and use it. - """ - if file is None and self.defaultFilename: - file = open(self.defaultFilename,'r') - - for line in file.readlines(): - # Strip out comments - comment = line.find(self.commentChar) - if comment != -1: - line = line[:comment] - - # Strip whitespace - line = line.strip() - - # Skip empty lines (and lines which only contain comments) - if not line: - continue - - self.parseLine(line) - - def parseLine(self, line): - """Override this. - - By default, this will split the line on whitespace and call - self.parseFields (catching any errors). - """ - try: - self.parseFields(*line.split()) - except ValueError: - raise InvalidInetdConfError, 'Invalid line: ' + repr(line) - - def parseFields(self, *fields): - """Override this.""" - - -class InetdService: - """A simple description of an inetd service.""" - name = None - port = None - socketType = None - protocol = None - wait = None - user = None - group = None - program = None - programArgs = None - - def __init__(self, name, port, socketType, protocol, wait, user, group, - program, programArgs): - self.name = name - self.port = port - self.socketType = socketType - self.protocol = protocol - self.wait = wait - self.user = user - self.group = group - self.program = program - self.programArgs = programArgs - - -class InetdConf(SimpleConfFile): - """Configuration parser for a traditional UNIX inetd(8)""" - - defaultFilename = '/etc/inetd.conf' - - def __init__(self, knownServices=None): - self.services = [] - - if knownServices is None: - knownServices = ServicesConf() - knownServices.parseFile() - self.knownServices = knownServices - - def parseFields(self, serviceName, socketType, protocol, wait, user, - program, *programArgs): - """Parse an inetd.conf file. - - Implemented from the description in the Debian inetd.conf man page. - """ - # Extract user (and optional group) - user, group = (user.split('.') + [None])[:2] - - # Find the port for a service - port = self.knownServices.services.get((serviceName, protocol), None) - if not port and not protocol.startswith('rpc/'): - # FIXME: Should this be discarded/ignored, rather than throwing - # an exception? - try: - port = int(serviceName) - serviceName = 'unknown' - except: - raise UnknownService, "Unknown service: %s (%s)" \ - % (serviceName, protocol) - - self.services.append(InetdService(serviceName, port, socketType, - protocol, wait, user, group, program, - programArgs)) - - -class ServicesConf(SimpleConfFile): - """/etc/services parser - - @ivar services: dict mapping service names to (port, protocol) tuples. - """ - - defaultFilename = '/etc/services' - - def __init__(self): - self.services = {} - - def parseFields(self, name, portAndProtocol, *aliases): - try: - port, protocol = portAndProtocol.split('/') - port = long(port) - except: - raise InvalidServicesConfError, 'Invalid port/protocol:' + \ - repr(portAndProtocol) - - self.services[(name, protocol)] = port - for alias in aliases: - self.services[(alias, protocol)] = port - - -class RPCServicesConf(SimpleConfFile): - """/etc/rpc parser - - @ivar self.services: dict mapping rpc service names to rpc ports. - """ - - defaultFilename = '/etc/rpc' - - def __init__(self): - self.services = {} - - def parseFields(self, name, port, *aliases): - try: - port = long(port) - except: - raise InvalidRPCServicesConfError, 'Invalid port:' + repr(port) - - self.services[name] = port - for alias in aliases: - self.services[alias] = port - - diff --git a/tools/buildbot/pylibs/twisted/runner/inetdtap.py b/tools/buildbot/pylibs/twisted/runner/inetdtap.py deleted file mode 100644 index fc0f676..0000000 --- a/tools/buildbot/pylibs/twisted/runner/inetdtap.py +++ /dev/null @@ -1,160 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -""" -Twisted inetd TAP support - -Maintainer: U{Andrew Bennetts} - -Future Plans: more configurability. -""" - -import os, pwd, grp, socket - -from twisted.runner import inetd, inetdconf -from twisted.python import log, usage -from twisted.internet.protocol import ServerFactory -from twisted.application import internet, service as appservice - -try: - import portmap - rpcOk = 1 -except ImportError: - rpcOk = 0 - - -# Protocol map -protocolDict = {'tcp': socket.IPPROTO_TCP, 'udp': socket.IPPROTO_UDP} - - -class Options(usage.Options): - - optParameters = [ - ['rpc', 'r', '/etc/rpc', 'RPC procedure table file'], - ['file', 'f', '/etc/inetd.conf', 'Service configuration file'] - ] - - optFlags = [['nointernal', 'i', "Don't run internal services"]] - zsh_actions = {"file" : "_files -g '*.conf'"} - -class RPCServer(internet.TCPServer): - - def __init__(self, rpcVersions, rpcConf, proto, service): - internet.TCPServer.__init__(0, ServerFactory()) - self.rpcConf = rpcConf - self.proto = proto - self.service = service - - def startService(self): - internet.TCPServer.startService(self) - import portmap - portNo = self._port.getHost()[2] - service = self.service - for version in rpcVersions: - portmap.set(self.rpcConf.services[name], version, self.proto, - portNo) - inetd.forkPassingFD(service.program, service.programArgs, - os.environ, service.user, service.group, p) - -def makeService(config): - s = appservice.MultiService() - conf = inetdconf.InetdConf() - conf.parseFile(open(config['file'])) - - rpcConf = inetdconf.RPCServicesConf() - try: - rpcConf.parseFile(open(config['rpc'])) - except: - # We'll survive even if we can't read /etc/rpc - log.deferr() - - for service in conf.services: - rpc = service.protocol.startswith('rpc/') - protocol = service.protocol - - if rpc and not rpcOk: - log.msg('Skipping rpc service due to lack of rpc support') - continue - - if rpc: - # RPC has extra options, so extract that - protocol = protocol[4:] # trim 'rpc/' - if not protocolDict.has_key(protocol): - log.msg('Bad protocol: ' + protocol) - continue - - try: - name, rpcVersions = service.name.split('/') - except ValueError: - log.msg('Bad RPC service/version: ' + service.name) - continue - - if not rpcConf.services.has_key(name): - log.msg('Unknown RPC service: ' + repr(service.name)) - continue - - try: - if '-' in rpcVersions: - start, end = map(int, rpcVersions.split('-')) - rpcVersions = range(start, end+1) - else: - rpcVersions = [int(rpcVersions)] - except ValueError: - log.msg('Bad RPC versions: ' + str(rpcVersions)) - continue - - if (protocol, service.socketType) not in [('tcp', 'stream'), - ('udp', 'dgram')]: - log.msg('Skipping unsupported type/protocol: %s/%s' - % (service.socketType, service.protocol)) - continue - - # Convert the username into a uid (if necessary) - try: - service.user = int(service.user) - except ValueError: - try: - service.user = pwd.getpwnam(service.user)[2] - except KeyError: - log.msg('Unknown user: ' + service.user) - continue - - # Convert the group name into a gid (if necessary) - if service.group is None: - # If no group was specified, use the user's primary group - service.group = pwd.getpwuid(service.user)[3] - else: - try: - service.group = int(service.group) - except ValueError: - try: - service.group = grp.getgrnam(service.group)[2] - except KeyError: - log.msg('Unknown group: ' + service.group) - continue - - if service.program == 'internal': - if config['nointernal']: - continue - - # Internal services can use a standard ServerFactory - if not inetd.internalProtocols.has_key(service.name): - log.msg('Unknown internal service: ' + service.name) - continue - factory = ServerFactory() - factory.protocol = inetd.internalProtocols[service.name] - elif rpc: - i = RPCServer(rpcVersions, rpcConf, proto, service) - i.setServiceParent(s) - continue - else: - # Non-internal non-rpc services use InetdFactory - factory = inetd.InetdFactory(service) - - if protocol == 'tcp': - internet.TCPServer(service.port, factory).setServiceParent(s) - elif protocol == 'udp': - raise RuntimeError("not supporting UDP") - return s diff --git a/tools/buildbot/pylibs/twisted/runner/portmap.c b/tools/buildbot/pylibs/twisted/runner/portmap.c deleted file mode 100644 index ca0c1c9..0000000 --- a/tools/buildbot/pylibs/twisted/runner/portmap.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2001-2004 Twisted Matrix Laboratories. - * See LICENSE for details. - - * - */ - -/* portmap.c: A simple Python wrapper for pmap_set(3) and pmap_unset(3) */ - -#include -#include -#include - -static PyObject * portmap_set(PyObject *self, PyObject *args) -{ - unsigned long program, version; - int protocol; - unsigned short port; - - if (!PyArg_ParseTuple(args, "llih:set", - &program, &version, &protocol, &port)) - return NULL; - - pmap_unset(program, version); - pmap_set(program, version, protocol, port); - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject * portmap_unset(PyObject *self, PyObject *args) -{ - unsigned long program, version; - - if (!PyArg_ParseTuple(args, "ll:unset", - &program, &version)) - return NULL; - - pmap_unset(program, version); - - Py_INCREF(Py_None); - return Py_None; -} - -static PyMethodDef PortmapMethods[] = { - {"set", portmap_set, METH_VARARGS, - "Set an entry in the portmapper."}, - {"unset", portmap_unset, METH_VARARGS, - "Unset an entry in the portmapper."}, - {NULL, NULL, 0, NULL} -}; - -void initportmap(void) -{ - (void) Py_InitModule("portmap", PortmapMethods); -} - diff --git a/tools/buildbot/pylibs/twisted/runner/procmon.py b/tools/buildbot/pylibs/twisted/runner/procmon.py deleted file mode 100644 index 5bd8428..0000000 --- a/tools/buildbot/pylibs/twisted/runner/procmon.py +++ /dev/null @@ -1,235 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -""" -ProcessMonitor: run processes, monitor progress, and restart when -they die. - -The ProcessMonitor will not attempt to restart a process that appears -to die instantly -- with each "instant" death (less than 1 second, by -default), it will delay approximately twice as long before restarting -it. A successful run will reset the counter. - -The primary interface is "addProcess" and "removeProcess". When the -service is active (that is, when the application it is attached to -is running), adding a process automatically starts it. - -Each process has a name (a string). This string must uniquely identify -the process. In particular, attempting to add two processes with the -same name will result in a key error. - -The arguments to addProcess are: - - name -- a string, uniquely specifying the process - - args -- a list of arguments. the first will be used to determine the - executable - - optionally, the uid and gid this process should be run as (by default, - it does not change uid/gid before running processes). - -Note that args are passed to the system call, not to the shell. If running -the shell is desired, the common idiom is to use -.addProcess("name", ['/bin/sh', '-c', shell_script]) - -removeProcess takes just the name argument. If the process is started, it -kills it, and will never restart it. - -The "restartAll" method restarts all processes. This is useful for 3rd -parties management services to allow a user to restart servers because -of an outside circumstances change -- for example, a new version of a library -which is installed. - -The following attributes on the monitor can be set to configure behaviour - - threshold -- how long a process has to live before the death is considered - instant (default 1, measured in seconds) - - killTime -- how long a process being killed has to get its affairs in - order before it gets killed with an unmaskable signal - (default 5, measured in seconds) - - consistencyDelay -- time between consistency checks - (default 60, measured in seconds) -""" - -import os, time -from signal import SIGTERM, SIGKILL -from twisted.python import log -from twisted.internet import protocol, reactor, process -from twisted.application import service -from twisted.protocols import basic - -class DummyTransport: - - disconnecting = 0 - -transport = DummyTransport() - -class LineLogger(basic.LineReceiver): - - tag = None - delimiter = '\n' - - def lineReceived(self, line): - log.msg('[%s] %s' % (self.tag, line)) - -class LoggingProtocol(protocol.ProcessProtocol): - - service = None - name = None - empty = 1 - - def connectionMade(self): - self.output = LineLogger() - self.output.tag = self.name - self.output.makeConnection(transport) - - def outReceived(self, data): - self.output.dataReceived(data) - self.empty = data[-1] == '\n' - - errReceived = outReceived - - def processEnded(self, reason): - if not self.empty: - self.output.dataReceived('\n') - self.service.connectionLost(self.name) - - -class ProcessMonitor(service.Service): - - threshold = 1 - active = 0 - killTime = 5 - consistency = None - consistencyDelay = 60 - - def __init__(self): - self.processes = {} - self.protocols = {} - self.delay = {} - self.timeStarted = {} - self.murder = {} - - def __getstate__(self): - dct = service.Service.__getstate__(self) - for k in ('active', 'consistency'): - if dct.has_key(k): - del dct[k] - dct['protocols'] = {} - dct['delay'] = {} - dct['timeStarted'] = {} - dct['murder'] = {} - return dct - - def _checkConsistency(self): - for name, protocol in self.protocols.items(): - proc = protocol.transport - try: - proc.signalProcess(0) - except (OSError, process.ProcessExitedAlready): - log.msg("Lost process %r somehow, restarting." % name) - del self.protocols[name] - self.startProcess(name) - self.consistency = reactor.callLater(self.consistencyDelay, - self._checkConsistency) - - def addProcess(self, name, args, uid=None, gid=None): - if self.processes.has_key(name): - raise KeyError("remove %s first" % name) - self.processes[name] = args, uid, gid - if self.active: - self.startProcess(name) - - def removeProcess(self, name): - del self.processes[name] - self.stopProcess(name) - - def startService(self): - service.Service.startService(self) - self.active = 1 - for name in self.processes.keys(): - reactor.callLater(0, self.startProcess, name) - self.consistency = reactor.callLater(self.consistencyDelay, - self._checkConsistency) - - def stopService(self): - service.Service.stopService(self) - self.active = 0 - for name in self.processes.keys(): - self.stopProcess(name) - self.consistency.cancel() - - def connectionLost(self, name): - if self.murder.has_key(name): - self.murder[name].cancel() - del self.murder[name] - if self.protocols.has_key(name): - del self.protocols[name] - if time.time()-self.timeStarted[name]') - -def main(): - mon = ProcessMonitor() - mon.addProcess('foo', ['/bin/sh', '-c', 'sleep 2;echo hello']) - mon.addProcess('qux', ['/bin/sh', '-c', 'sleep 2;printf pilim']) - mon.addProcess('bar', ['/bin/sh', '-c', 'echo goodbye']) - mon.addProcess('baz', ['/bin/sh', '-c', - 'echo welcome;while :;do echo blah;sleep 5;done']) - reactor.callLater(30, lambda mon=mon: - os.kill(mon.protocols['baz'].transport.pid, SIGTERM)) - reactor.callLater(60, mon.restartAll) - mon.startService() - reactor.addSystemEventTrigger('before', 'shutdown', mon.stopService) - reactor.run() - -if __name__ == '__main__': - main() diff --git a/tools/buildbot/pylibs/twisted/runner/procutils.py b/tools/buildbot/pylibs/twisted/runner/procutils.py deleted file mode 100644 index 2b6bc2f..0000000 --- a/tools/buildbot/pylibs/twisted/runner/procutils.py +++ /dev/null @@ -1,5 +0,0 @@ -import warnings -warnings.warn("twisted.runner.procutils is DEPRECATED. import twisted.python.procutils instead.", - DeprecationWarning, stacklevel=2) - -from twisted.python.procutils import which diff --git a/tools/buildbot/pylibs/twisted/runner/topfiles/NEWS b/tools/buildbot/pylibs/twisted/runner/topfiles/NEWS deleted file mode 100644 index 8ee59ce..0000000 --- a/tools/buildbot/pylibs/twisted/runner/topfiles/NEWS +++ /dev/null @@ -1,20 +0,0 @@ -8.0.0 (2008-03-17) -================== - -Misc ----- - - Remove all "API Stability" markers (#2847) - - -0.2.0 (2006-05-24) -================== - -Fixes ------ - - Fix a bug that broke inetdtap.RPCServer. - - Misc: #1142 - - -0.1.0 -===== - - Pass *blocking* sockets to subprocesses run by inetd diff --git a/tools/buildbot/pylibs/twisted/runner/topfiles/README b/tools/buildbot/pylibs/twisted/runner/topfiles/README deleted file mode 100644 index 68840f4..0000000 --- a/tools/buildbot/pylibs/twisted/runner/topfiles/README +++ /dev/null @@ -1,2 +0,0 @@ -Twisted Runner 8.0.0 - diff --git a/tools/buildbot/pylibs/twisted/runner/topfiles/setup.py b/tools/buildbot/pylibs/twisted/runner/topfiles/setup.py deleted file mode 100644 index bb52eba..0000000 --- a/tools/buildbot/pylibs/twisted/runner/topfiles/setup.py +++ /dev/null @@ -1,33 +0,0 @@ -try: - from twisted.python.dist import setup, ConditionalExtension as Extension -except ImportError: - raise SystemExit("twisted.python.dist module not found. Make sure you " - "have installed the Twisted core package before " - "attempting to install any other Twisted projects.") - -extensions = [ - Extension("twisted.runner.portmap", - ["twisted/runner/portmap.c"], - condition=lambda builder: builder._check_header("rpc/rpc.h")), -] - -if __name__ == '__main__': - setup( - twisted_subproject="runner", - # metadata - name="Twisted Runner", - description="Twisted Runner is a process management library and inetd " - "replacement.", - author="Twisted Matrix Laboratories", - author_email="twisted-python@twistedmatrix.com", - maintainer="Andrew Bennetts", - maintainer_email="spiv@twistedmatrix.com", - url="http://twistedmatrix.com/trac/wiki/TwistedRunner", - license="MIT", - long_description="""\ -Twisted Runner contains code useful for persistent process management -with Python and Twisted, and has an almost full replacement for inetd. -""", - # build stuff - conditionalExtensions=extensions, - ) diff --git a/tools/buildbot/pylibs/twisted/scripts/__init__.py b/tools/buildbot/pylibs/twisted/scripts/__init__.py deleted file mode 100644 index 28ce5b6..0000000 --- a/tools/buildbot/pylibs/twisted/scripts/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -# $Id: __init__.py,v 1.1 2002/03/18 23:33:48 jh Exp $ - -__doc__ = ''' -Subpackage containing the modules that implement the command line tools. -Note that these are imported by script stubs generated by "setup.py". -''' - diff --git a/tools/buildbot/pylibs/twisted/scripts/_twistd_unix.py b/tools/buildbot/pylibs/twisted/scripts/_twistd_unix.py deleted file mode 100644 index 36f4f78..0000000 --- a/tools/buildbot/pylibs/twisted/scripts/_twistd_unix.py +++ /dev/null @@ -1,313 +0,0 @@ -# -*- test-case-name: twisted.test.test_twistd -*- -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -import warnings -import os, errno, sys - -from twisted.python import log, syslog, logfile -from twisted.python.util import switchUID, uidFromString, gidFromString -from twisted.application import app, service -from twisted import copyright - - -class ServerOptions(app.ServerOptions): - synopsis = "Usage: twistd [options]" - - optFlags = [['nodaemon','n', "don't daemonize"], - ['quiet', 'q', "No-op for backwards compatibility."], - ['originalname', None, "Don't try to change the process name"], - ['syslog', None, "Log to syslog, not to file"], - ['euid', '', - "Set only effective user-id rather than real user-id. " - "(This option has no effect unless the server is running as " - "root, in which case it means not to shed all privileges " - "after binding ports, retaining the option to regain " - "privileges in cases such as spawning processes. " - "Use with caution.)"], - ] - - optParameters = [ - ['prefix', None,'twisted', - "use the given prefix when syslogging"], - ['pidfile','','twistd.pid', - "Name of the pidfile"], - ['chroot', None, None, - 'Chroot to a supplied directory before running'], - ['uid', 'u', None, "The uid to run as.", uidFromString], - ['gid', 'g', None, "The gid to run as.", gidFromString], - ] - zsh_altArgDescr = {"prefix":"Use the given prefix when syslogging (default: twisted)", - "pidfile":"Name of the pidfile (default: twistd.pid)",} - #zsh_multiUse = ["foo", "bar"] - #zsh_mutuallyExclusive = [("foo", "bar"), ("bar", "baz")] - zsh_actions = {"pidfile":'_files -g "*.pid"', "chroot":'_dirs'} - zsh_actionDescr = {"chroot":"chroot directory"} - - def opt_version(self): - """Print version information and exit. - """ - print 'twistd (the Twisted daemon) %s' % copyright.version - print copyright.copyright - sys.exit() - - - def postOptions(self): - app.ServerOptions.postOptions(self) - if self['pidfile']: - self['pidfile'] = os.path.abspath(self['pidfile']) - - -def checkPID(pidfile): - if not pidfile: - return - if os.path.exists(pidfile): - try: - pid = int(open(pidfile).read()) - except ValueError: - sys.exit('Pidfile %s contains non-numeric value' % pidfile) - try: - os.kill(pid, 0) - except OSError, why: - if why[0] == errno.ESRCH: - # The pid doesnt exists. - log.msg('Removing stale pidfile %s' % pidfile, isError=True) - os.remove(pidfile) - else: - sys.exit("Can't check status of PID %s from pidfile %s: %s" % - (pid, pidfile, why[1])) - else: - sys.exit("""\ -Another twistd server is running, PID %s\n -This could either be a previously started instance of your application or a -different application entirely. To start a new one, either run it in some other -directory, or use the --pidfile and --logfile parameters to avoid clashes. -""" % pid) - -def _getLogObserver(logfilename, sysLog, prefix, nodaemon): - """ - Create and return a suitable log observer for the given configuration. - - The observer will go to syslog using the prefix C{prefix} if C{sysLog} is - true. Otherwise, it will go to the file named C{logfilename} or, if - C{nodaemon} is true and C{logfilename} is C{"-"}, to stdout. - - @type logfilename: C{str} - @param logfilename: The name of the file to which to log, if other than the - default. - - @type sysLog: C{bool} - @param sysLog: A flag indicating whether to use syslog instead of file - logging. - - @type prefix: C{str} - @param prefix: If C{sysLog} is C{True}, the string prefix to use for syslog - messages. - - @type nodaemon: C{bool} - @param nodaemon: A flag indicating the process will not be daemonizing. - - @return: An object suitable to be passed to C{log.addObserver}. - """ - if sysLog: - observer = syslog.SyslogObserver(prefix).emit - else: - if logfilename == '-': - if not nodaemon: - print 'daemons cannot log to stdout' - os._exit(1) - logFile = sys.stdout - elif nodaemon and not logfilename: - logFile = sys.stdout - else: - logFile = logfile.LogFile.fromFullPath(logfilename or 'twistd.log') - try: - import signal - except ImportError: - pass - else: - def rotateLog(signal, frame): - from twisted.internet import reactor - reactor.callFromThread(logFile.rotate) - signal.signal(signal.SIGUSR1, rotateLog) - observer = log.FileLogObserver(logFile).emit - return observer - - -def startLogging(*args, **kw): - warnings.warn( - """ - Use ApplicationRunner instead of startLogging. - """, - category=PendingDeprecationWarning, - stacklevel=2) - observer = _getLogObserver(*args, **kw) - log.startLoggingWithObserver(observer) - sys.stdout.flush() - - -def daemonize(): - # See http://www.erlenstar.demon.co.uk/unix/faq_toc.html#TOC16 - if os.fork(): # launch child and... - os._exit(0) # kill off parent - os.setsid() - if os.fork(): # launch child and... - os._exit(0) # kill off parent again. - os.umask(077) - null = os.open('/dev/null', os.O_RDWR) - for i in range(3): - try: - os.dup2(null, i) - except OSError, e: - if e.errno != errno.EBADF: - raise - os.close(null) - - -def launchWithName(name): - if name and name != sys.argv[0]: - exe = os.path.realpath(sys.executable) - log.msg('Changing process name to ' + name) - os.execv(exe, [name, sys.argv[0], '--originalname'] + sys.argv[1:]) - - -class UnixApplicationRunner(app.ApplicationRunner): - """ - An ApplicationRunner which does Unix-specific things, like fork, - shed privileges, and maintain a PID file. - """ - - def preApplication(self): - """ - Do pre-application-creation setup. - """ - checkPID(self.config['pidfile']) - self.config['nodaemon'] = (self.config['nodaemon'] - or self.config['debug']) - self.oldstdout = sys.stdout - self.oldstderr = sys.stderr - - - def getLogObserver(self): - """ - Override to supply a log observer suitable for POSIX based on the given - arguments. - """ - return _getLogObserver( - self.config['logfile'], self.config['syslog'], - self.config['prefix'], self.config['nodaemon']) - - - def postApplication(self): - """ - To be called after the application is created: start the - application and run the reactor. After the reactor stops, - clean up PID files and such. - """ - self.startApplication(self.application) - self.startReactor(None, self.oldstdout, self.oldstderr) - self.removePID(self.config['pidfile']) - log.msg("Server Shut Down.") - - - def removePID(self, pidfile): - """ - Remove the specified PID file, if possible. Errors are logged, not - raised. - - @type pidfile: C{str} - @param pidfile: The path to the PID tracking file. - """ - if not pidfile: - return - try: - os.unlink(pidfile) - except OSError, e: - if e.errno == errno.EACCES or e.errno == errno.EPERM: - log.msg("Warning: No permission to delete pid file") - else: - log.msg("Failed to unlink PID file:") - log.deferr() - except: - log.msg("Failed to unlink PID file:") - log.deferr() - - - def setupEnvironment(self, chroot, rundir, nodaemon, pidfile): - """ - Set the filesystem root, the working directory, and daemonize. - - @type chroot: C{str} or L{NoneType} - @param chroot: If not None, a path to use as the filesystem root (using - L{os.chroot}). - - @type rundir: C{str} - @param rundir: The path to set as the working directory. - - @type nodaemon: C{bool} - @param nodaemon: A flag which, if set, indicates that daemonization - should not be done. - - @type pidfile: C{str} or C{NoneType} - @param pidfile: If not C{None}, the path to a file into which to put - the PID of this process. - """ - if chroot is not None: - os.chroot(chroot) - if rundir == '.': - rundir = '/' - os.chdir(rundir) - if not nodaemon: - daemonize() - if pidfile: - open(pidfile,'wb').write(str(os.getpid())) - - - def shedPrivileges(self, euid, uid, gid): - """ - Change the UID and GID or the EUID and EGID of this process. - - @type euid: C{bool} - @param euid: A flag which, if set, indicates that only the I{effective} - UID and GID should be set. - - @type uid: C{int} or C{NoneType} - @param uid: If not C{None}, the UID to which to switch. - - @type gid: C{int} or C{NoneType} - @param gid: If not C{None}, the GID to which to switch. - """ - if uid is not None or gid is not None: - switchUID(uid, gid, euid) - extra = euid and 'e' or '' - log.msg('set %suid/%sgid %s/%s' % (extra, extra, uid, gid)) - - - def startApplication(self, application): - """ - Configure global process state based on the given application and run - the application. - - @param application: An object which can be adapted to - L{service.IProcess} and L{service.IService}. - """ - process = service.IProcess(application) - if not self.config['originalname']: - launchWithName(process.processName) - self.setupEnvironment( - self.config['chroot'], self.config['rundir'], - self.config['nodaemon'], self.config['pidfile']) - - service.IService(application).privilegedStartService() - - uid, gid = self.config['uid'], self.config['gid'] - if uid is None: - uid = process.uid - if gid is None: - gid = process.gid - - self.shedPrivileges(self.config['euid'], uid, gid) - app.startApplication(application, not self.config['no_save']) - - - diff --git a/tools/buildbot/pylibs/twisted/scripts/_twistw.py b/tools/buildbot/pylibs/twisted/scripts/_twistw.py deleted file mode 100644 index e90ceaa..0000000 --- a/tools/buildbot/pylibs/twisted/scripts/_twistw.py +++ /dev/null @@ -1,88 +0,0 @@ -# -*- test-case-name: twisted.test.test_twistd -*- -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -import warnings - -from twisted.python import log, logfile -from twisted.application import app, service, internet -from twisted import copyright -import sys, os - -class ServerOptions(app.ServerOptions): - synopsis = "Usage: twistd [options]" - - optFlags = [['nodaemon','n', "(for backwards compatability)."], - ] - - def opt_version(self): - """Print version information and exit. - """ - print 'twistd (the Twisted Windows runner) %s' % copyright.version - print copyright.copyright - sys.exit() - - -def _getLogObserver(logfilename): - """ - Create and return a suitable log observer for the given configuration. - - The observer will go to stdout if C{logfilename} is empty or equal to - C{"-"}. Otherwise, it will go to a file with that name. - - @type logfilename: C{str} - @param logfilename: The name of the file to which to log, if other than the - default. - - @return: An object suitable to be passed to C{log.addObserver}. - """ - if logfilename == '-' or not logfilename: - logFile = sys.stdout - else: - logFile = logfile.LogFile.fromFullPath(logfilename) - return log.FileLogObserver(logFile).emit - - -def startLogging(*args, **kw): - warnings.warn( - """ - Use ApplicationRunner instead of startLogging." - """, - category=PendingDeprecationWarning, - stacklevel=2) - observer = _getLogObserver(*args, **kw) - log.startLoggingWithObserver(observer) - sys.stdout.flush() - - -class WindowsApplicationRunner(app.ApplicationRunner): - """ - An ApplicationRunner which avoids unix-specific things. No - forking, no PID files, no privileges. - """ - def preApplication(self): - """ - Do pre-application-creation setup. - """ - self.oldstdout = sys.stdout - self.oldstderr = sys.stderr - os.chdir(self.config['rundir']) - - - def getLogObserver(self): - """ - Override to supply a log observer suitable for Windows based on the - given arguments. - """ - return _getLogObserver(self.config['logfile']) - - - def postApplication(self): - """ - Start the application and run the reactor. - """ - service.IService(self.application).privilegedStartService() - app.startApplication(self.application, not self.config['no_save']) - app.startApplication(internet.TimerService(0.1, lambda:None), 0) - self.startReactor(None, self.oldstdout, self.oldstderr) - log.msg("Server Shut Down.") diff --git a/tools/buildbot/pylibs/twisted/scripts/htmlizer.py b/tools/buildbot/pylibs/twisted/scripts/htmlizer.py deleted file mode 100644 index 5bbc1e9..0000000 --- a/tools/buildbot/pylibs/twisted/scripts/htmlizer.py +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -"""HTML pretty-printing for Python source code.""" - -__version__ = '$Revision: 1.8 $'[11:-2] - -from twisted.python import htmlizer, usage -from twisted import copyright - -import os, sys - -header = ''' -%(title)s - -%(alternate)s -%(stylesheet)s - - -''' -footer = """""" - -styleLink = '' -alternateLink = '' - -class Options(usage.Options): - synopsis = """%s [options] source.py - """ % ( - os.path.basename(sys.argv[0]),) - - optParameters = [ - ('stylesheet', 's', None, "URL of stylesheet to link to."), - ] - zsh_extras = ["1:source python file:_files -g '*.py'"] - - def parseArgs(self, filename): - self['filename'] = filename - -def run(): - options = Options() - try: - options.parseOptions() - except usage.UsageError, e: - print str(e) - sys.exit(1) - filename = options['filename'] - if options.get('stylesheet') is not None: - stylesheet = styleLink % (options['stylesheet'],) - else: - stylesheet = '' - - output = open(filename + '.html', 'w') - try: - output.write(header % { - 'title': filename, - 'generator': 'htmlizer/%s' % (copyright.longversion,), - 'alternate': alternateLink % {'source': filename}, - 'stylesheet': stylesheet - }) - htmlizer.filter(open(filename), output, - htmlizer.SmallerHTMLWriter) - output.write(footer) - finally: - output.close() diff --git a/tools/buildbot/pylibs/twisted/scripts/manhole.py b/tools/buildbot/pylibs/twisted/scripts/manhole.py deleted file mode 100644 index 624c320..0000000 --- a/tools/buildbot/pylibs/twisted/scripts/manhole.py +++ /dev/null @@ -1,185 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Start a L{twisted.manhole} client. - -@var toolkitPreference: A list of all toolkits we have front-ends for, with - the ones we most prefer to use listed first. -@type toolkitPreference: list of strings -""" - -import sys - -from twisted.python import usage - -# Prefer gtk2 because it is the way of the future! -toolkitPreference = ('gtk2', 'gtk1') - -class NoToolkitError(usage.UsageError): - wantToolkits = toolkitPreference - def __str__(self): - return ( - "I couldn't find any of these toolkits installed, and I need " - "one of them to run: %s" % (', '.join(self.wantToolkits),)) - -def bestToolkit(): - """The most-preferred available toolkit. - - @returntype: string - """ - avail = getAvailableToolkits() - for v in toolkitPreference: - if v in avail: - return v - else: - raise NoToolkitError - -_availableToolkits = None -def getAvailableToolkits(): - """Autodetect available toolkits. - - @returns: A list of usable toolkits. - @returntype: list of strings - """ - global _availableToolkits - # use cached result - if _availableToolkits is not None: - return _availableToolkits - - avail = [] - - # Recent GTK. - try: - import pygtk - except: - pass - else: - gtkvers = pygtk._get_available_versions().keys() - for v in gtkvers: - frontend = {'1.2': 'gtk1', - '2.0': 'gtk2'}.get(v) - if frontend is not None: - avail.append(frontend) - - if not avail: - # Older GTK - try: - # WARNING: It's entirely possible that this does something crappy, - # such as running gtk_init, which may have undesirable side - # effects if that's not the toolkit we end up using. - import gtk - except: - pass - else: - avail.append('gtk1') - - # There may be some "middle gtk" that got left out -- that is, a - # version of pygtk 1.99.x that happened before the pygtk module - # with its _get_available_versions was introduced. Chances are - # that the gtk2 front-end wouldn't work with it anyway, but it may - # get mis-identified it as gtk1. :( - - _availableToolkits = avail - return avail - - -def run(): - config = MyOptions() - try: - config.parseOptions() - except usage.UsageError, e: - print str(e) - print str(config) - sys.exit(1) - - try: - run = getattr(sys.modules[__name__], 'run_' + config.opts['toolkit']) - except AttributeError: - print "Sorry, no support for toolkit %r." % (config.opts['toolkit'],) - sys.exit(1) - - run(config) - - from twisted.internet import reactor - reactor.run() - -def run_gtk1(config): - # Put these off until after we parse options, so we know what reactor - # to install. - from twisted.internet import gtkreactor - gtkreactor.install() - from twisted.spread.ui import gtkutil - - # Put this off until after we parse options, or else gnome eats them. - # (http://www.daa.com.au/pipermail/pygtk/2002-December/004051.html) - sys.argv[:] = ['manhole'] - from twisted.manhole.ui import gtkmanhole - - i = gtkmanhole.Interaction() - lw = gtkutil.Login(i.connected, - i.client, - initialUser=config.opts['user'], - initialPassword=config.opts['password'], - initialService=config.opts['service'], - initialHostname=config.opts['host'], - initialPortno=config.opts['port'], - initialPerspective=config.opts['perspective']) - - i.loginWindow = lw - - lw.show_all() - - -def run_gtk2(config): - # Put these off until after we parse options, so we know what reactor - # to load. - from twisted.internet import gtk2reactor - gtk2reactor.install() - from twisted.spread.ui import gtk2util - - # Put this off until after we parse options, or else gnome eats them. - sys.argv[:] = ['manhole'] - from twisted.manhole.ui import gtk2manhole - - o = config.opts - defaults = { - 'host': o['host'], - 'port': o['port'], - 'identityName': o['user'], - 'password': o['password'], - 'serviceName': o['service'], - 'perspectiveName': o['perspective'] - } - w = gtk2manhole.ManholeWindow() - w.setDefaults(defaults) - w.login() - - -# from twisted.spread import pb -# can't do that, it installs a reactor. grr. -pbportno = 8787 - -class MyOptions(usage.Options): - optParameters=[("user", "u", "guest", "username"), - ("password", "w", "guest"), - ("service", "s", "twisted.manhole", "PB Service"), - ("host", "h", "localhost"), - ("port", "p", str(pbportno)), - ("perspective", "P", "", - "PB Perspective to ask for " - "(if different than username)"), - ("toolkit", "t", bestToolkit(), - "Front-end to use; one of %s" - % (' '.join(getAvailableToolkits()),)), - ] - - #zsh_altArgDescr = {"foo":"use this description for foo instead"} - #zsh_multiUse = ["foo", "bar"] - #zsh_mutuallyExclusive = [("foo", "bar"), ("bar", "baz")] - zsh_actions = {"host":"_hosts", - "toolkit":"(gtk1 gtk2)"} - #zsh_actionDescr = {"logfile":"log file name", "random":"random seed"} - -if __name__ == '__main__': - run() diff --git a/tools/buildbot/pylibs/twisted/scripts/mktap.py b/tools/buildbot/pylibs/twisted/scripts/mktap.py deleted file mode 100644 index 9a7ea9d..0000000 --- a/tools/buildbot/pylibs/twisted/scripts/mktap.py +++ /dev/null @@ -1,190 +0,0 @@ -# -*- test-case-name: twisted.scripts.test.test_mktap -*- -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -import warnings, sys, os - - -from twisted.application import service, app -from twisted.persisted import sob -from twisted.python import usage, util, plugin as oldplugin -from twisted import plugin as newplugin -from twisted.python.util import uidFromString, gidFromString - -# API COMPATIBILITY -IServiceMaker = service.IServiceMaker -_tapHelper = service.ServiceMaker - -warnings.warn( - "mktap and related support modules are deprecated as of Twisted 8.0. " - "Use Twisted Application Plugins with the 'twistd' command directly, " - "as described in 'Writing a Twisted Application Plugin for twistd' " - "chapter of the Developer Guide.", DeprecationWarning, stacklevel=2) - - - -def getid(uid, gid): - """ - Convert one or both of a string representation of a UID and GID into - integer form. On platforms where L{pwd} and L{grp} is available, user and - group names can be converted. - - @type uid: C{str} or C{NoneType} - @param uid: A string giving the base-ten representation of a UID or the - name of a user which can be converted to a UID via L{pwd.getpwnam}, - or None if no UID value is to be obtained. - - @type gid: C{str} or C{NoneType} - @param uid: A string giving the base-ten representation of a GID or the - name of a group which can be converted to a GID via - L{grp.getgrnam}, or None if no UID value is to be obtained. - - @return: A two-tuple giving integer UID and GID information for - whichever (or both) parameter is provided with a non-C{None} value. - - @raise ValueError: If a user or group name is supplied and L{pwd} or L{grp} - is not available. - """ - if uid is not None: - uid = uidFromString(uid) - if gid is not None: - gid = gidFromString(gid) - return (uid, gid) - - - -def loadPlugins(debug = None, progress = None): - tapLookup = {} - - plugins = oldplugin._getPlugIns("tap", debug, progress) - for plug in plugins: - if hasattr(plug, 'tapname'): - shortTapName = plug.tapname - else: - shortTapName = plug.module.split('.')[-1] - tapLookup[shortTapName] = plug - - plugins = newplugin.getPlugins(IServiceMaker) - for plug in plugins: - tapLookup[plug.tapname] = plug - - return tapLookup - -def addToApplication(ser, name, append, procname, type, encrypted, uid, gid): - if append and os.path.exists(append): - a = service.loadApplication(append, 'pickle', None) - else: - a = service.Application(name, uid, gid) - if procname: - service.IProcess(a).processName = procname - ser.setServiceParent(service.IServiceCollection(a)) - sob.IPersistable(a).setStyle(type) - passphrase = app.getSavePassphrase(encrypted) - if passphrase: - append = None - sob.IPersistable(a).save(filename=append, passphrase=passphrase) - -class FirstPassOptions(usage.Options): - synopsis = """Usage: mktap [options] [command options] """ - - recursing = 0 - params = () - - optParameters = [ - ['uid', 'u', None, "The uid to run as.", uidFromString], - ['gid', 'g', None, "The gid to run as.", gidFromString], - ['append', 'a', None, - "An existing .tap file to append the plugin to, rather than " - "creating a new one."], - ['type', 't', 'pickle', - "The output format to use; this can be 'pickle', 'xml', " - "or 'source'."], - ['appname', 'n', None, "The process name to use for this application."] - ] - - optFlags = [ - ['encrypted', 'e', "Encrypt file before writing " - "(will make the extension of the resultant " - "file begin with 'e')"], - ['debug', 'd', "Show debug information for plugin loading"], - ['progress', 'p', "Show progress information for plugin loading"], - ['help', 'h', "Display this message"], - ] - #zsh_altArgDescr = {"foo":"use this description for foo instead"} - #zsh_multiUse = ["foo", "bar"] - #zsh_mutuallyExclusive = [("foo", "bar"), ("bar", "baz")] - zsh_actions = {"append":'_files -g "*.tap"', - "type":"(pickle xml source)"} - zsh_actionDescr = {"append":"tap file to append to", "uid":"uid to run as", - "gid":"gid to run as", "type":"output format"} - - def init(self, tapLookup): - sc = [] - for (name, module) in tapLookup.iteritems(): - if IServiceMaker.providedBy(module): - sc.append(( - name, None, lambda m=module: m.options(), module.description)) - else: - sc.append(( - name, None, lambda obj=module: obj.load().Options(), - getattr(module, 'description', ''))) - - sc.sort() - self.subCommands = sc - - def parseArgs(self, *rest): - self.params += rest - - def _reportDebug(self, info): - print 'Debug: ', info - - def _reportProgress(self, info): - s = self.pb(info) - if s: - print '\rProgress: ', s, - if info == 1.0: - print '\r' + (' ' * 79) + '\r', - - def postOptions(self): - if self.recursing: - return - debug = progress = None - if self['debug']: - debug = self._reportDebug - if self['progress']: - progress = self._reportProgress - self.pb = util.makeStatBar(60, 1.0) - try: - self.tapLookup = loadPlugins(debug, progress) - except IOError: - raise usage.UsageError("Couldn't load the plugins file!") - self.init(self.tapLookup) - self.recursing = 1 - self.parseOptions(self.params) - if not hasattr(self, 'subOptions') or self['help']: - raise usage.UsageError(str(self)) - if hasattr(self, 'subOptions') and self.subOptions.get('help'): - raise usage.UsageError(str(self.subOptions)) - if not self.tapLookup.has_key(self.subCommand): - raise usage.UsageError("Please select one of: "+ - ' '.join(self.tapLookup)) - - -def run(): - options = FirstPassOptions() - try: - options.parseOptions(sys.argv[1:]) - except usage.UsageError, e: - print e - sys.exit(2) - except KeyboardInterrupt: - sys.exit(1) - - plg = options.tapLookup[options.subCommand] - if not IServiceMaker.providedBy(plg): - plg = plg.load() - ser = plg.makeService(options.subOptions) - addToApplication(ser, - options.subCommand, options['append'], options['appname'], - options['type'], options['encrypted'], - options['uid'], options['gid']) diff --git a/tools/buildbot/pylibs/twisted/scripts/tap2deb.py b/tools/buildbot/pylibs/twisted/scripts/tap2deb.py deleted file mode 100644 index 7f66952..0000000 --- a/tools/buildbot/pylibs/twisted/scripts/tap2deb.py +++ /dev/null @@ -1,279 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - - -import sys, os, string, shutil - -from twisted.python import usage - -class MyOptions(usage.Options): - optFlags = [["unsigned", "u"]] - optParameters = [["tapfile", "t", "twistd.tap"], - ["maintainer", "m", "", "The maintainer's name and email in a specific format: " - "'John Doe '"], - ["protocol", "p", ""], - ["description", "e", ""], - ["long_description", "l", ""], - ["set-version", "V", "1.0"], - ["debfile", "d", None], - ["type", "y", "tap", "type of configuration: 'tap', 'xml, 'source' or 'python' for .tac files"]] - - #zsh_altArgDescr = {"foo":"use this description for foo instead"} - #zsh_multiUse = ["foo", "bar"] - #zsh_mutuallyExclusive = [("foo", "bar"), ("bar", "baz")] - zsh_actions = {"type":"(tap xml source python)"} - #zsh_actionDescr = {"logfile":"log file name", "random":"random seed"} - - def postOptions(self): - if not self["maintainer"]: - raise usage.UsageError, "maintainer must be specified." - - -type_dict = { -'tap': 'file', -'python': 'python', -'source': 'source', -'xml': 'xml', -} - -def save_to_file(file, text): - open(file, 'w').write(text) - - -def run(): - - try: - config = MyOptions() - config.parseOptions() - except usage.error, ue: - sys.exit("%s: %s" % (sys.argv[0], ue)) - - tap_file = config['tapfile'] - base_tap_file = os.path.basename(config['tapfile']) - protocol = (config['protocol'] or os.path.splitext(base_tap_file)[0]) - deb_file = config['debfile'] or 'twisted-'+protocol - version = config['set-version'] - maintainer = config['maintainer'] - description = config['description'] or ('A Twisted-based server for %(protocol)s' % - vars()) - long_description = config['long_description'] or 'Automatically created by tap2deb' - twistd_option = type_dict[config['type']] - date = string.strip(os.popen('822-date').read()) - directory = deb_file + '-' + version - python_version = '%s.%s' % sys.version_info[:2] - - if os.path.exists(os.path.join('.build', directory)): - os.system('rm -rf %s' % os.path.join('.build', directory)) - os.makedirs(os.path.join('.build', directory, 'debian')) - - shutil.copy(tap_file, os.path.join('.build', directory)) - - save_to_file(os.path.join('.build', directory, 'debian', 'README.Debian'), - '''This package was auto-generated by tap2deb\n''') - - save_to_file(os.path.join('.build', directory, 'debian', 'conffiles'), - '''\ -/etc/init.d/%(deb_file)s -/etc/default/%(deb_file)s -/etc/%(base_tap_file)s -''' % vars()) - - save_to_file(os.path.join('.build', directory, 'debian', 'default'), - '''\ -pidfile=/var/run/%(deb_file)s.pid -rundir=/var/lib/%(deb_file)s/ -file=/etc/%(tap_file)s -logfile=/var/log/%(deb_file)s.log - ''' % vars()) - - save_to_file(os.path.join('.build', directory, 'debian', 'init.d'), - '''\ -#!/bin/sh - -PATH=/sbin:/bin:/usr/sbin:/usr/bin - -pidfile=/var/run/%(deb_file)s.pid \ -rundir=/var/lib/%(deb_file)s/ \ -file=/etc/%(tap_file)s \ -logfile=/var/log/%(deb_file)s.log - -[ -r /etc/default/%(deb_file)s ] && . /etc/default/%(deb_file)s - -test -x /usr/bin/twistd%(python_version)s || exit 0 -test -r $file || exit 0 -test -r /usr/share/%(deb_file)s/package-installed || exit 0 - - -case "$1" in - start) - echo -n "Starting %(deb_file)s: twistd" - start-stop-daemon --start --quiet --exec /usr/bin/twistd%(python_version)s -- \ - --pidfile=$pidfile \ - --rundir=$rundir \ - --%(twistd_option)s=$file \ - --logfile=$logfile - echo "." - ;; - - stop) - echo -n "Stopping %(deb_file)s: twistd" - start-stop-daemon --stop --quiet \ - --pidfile $pidfile - echo "." - ;; - - restart) - $0 stop - $0 start - ;; - - force-reload) - $0 restart - ;; - - *) - echo "Usage: /etc/init.d/%(deb_file)s {start|stop|restart|force-reload}" >&2 - exit 1 - ;; -esac - -exit 0 -''' % vars()) - - os.chmod(os.path.join('.build', directory, 'debian', 'init.d'), 0755) - - save_to_file(os.path.join('.build', directory, 'debian', 'postinst'), - '''\ -#!/bin/sh -update-rc.d %(deb_file)s defaults >/dev/null -invoke-rc.d %(deb_file)s start -''' % vars()) - - save_to_file(os.path.join('.build', directory, 'debian', 'prerm'), - '''\ -#!/bin/sh -invoke-rc.d %(deb_file)s stop -''' % vars()) - - save_to_file(os.path.join('.build', directory, 'debian', 'postrm'), - '''\ -#!/bin/sh -if [ "$1" = purge ]; then - update-rc.d %(deb_file)s remove >/dev/null -fi -''' % vars()) - - save_to_file(os.path.join('.build', directory, 'debian', 'changelog'), - '''\ -%(deb_file)s (%(version)s) unstable; urgency=low - - * Created by tap2deb - - -- %(maintainer)s %(date)s - -''' % vars()) - - save_to_file(os.path.join('.build', directory, 'debian', 'control'), - '''\ -Source: %(deb_file)s -Section: net -Priority: extra -Maintainer: %(maintainer)s -Build-Depends-Indep: debhelper -Standards-Version: 3.5.6 - -Package: %(deb_file)s -Architecture: all -Depends: python%(python_version)s-twisted -Description: %(description)s - %(long_description)s -''' % vars()) - - save_to_file(os.path.join('.build', directory, 'debian', 'copyright'), - '''\ -This package was auto-debianized by %(maintainer)s on -%(date)s - -It was auto-generated by tap2deb - -Upstream Author(s): -Moshe Zadka -- tap2deb author - -Copyright: - -Insert copyright here. -''' % vars()) - - save_to_file(os.path.join('.build', directory, 'debian', 'dirs'), - '''\ -etc/init.d -etc/default -var/lib/%(deb_file)s -usr/share/doc/%(deb_file)s -usr/share/%(deb_file)s -''' % vars()) - - save_to_file(os.path.join('.build', directory, 'debian', 'rules'), - '''\ -#!/usr/bin/make -f - -export DH_COMPAT=1 - -build: build-stamp -build-stamp: - dh_testdir - touch build-stamp - -clean: - dh_testdir - dh_testroot - rm -f build-stamp install-stamp - dh_clean - -install: install-stamp -install-stamp: build-stamp - dh_testdir - dh_testroot - dh_clean -k - dh_installdirs - - # Add here commands to install the package into debian/tmp. - cp %(base_tap_file)s debian/tmp/etc/ - cp debian/init.d debian/tmp/etc/init.d/%(deb_file)s - cp debian/default debian/tmp/etc/default/%(deb_file)s - cp debian/copyright debian/tmp/usr/share/doc/%(deb_file)s/ - cp debian/README.Debian debian/tmp/usr/share/doc/%(deb_file)s/ - touch debian/tmp/usr/share/%(deb_file)s/package-installed - touch install-stamp - -binary-arch: build install - -binary-indep: build install - dh_testdir - dh_testroot - dh_strip - dh_compress - dh_installchangelogs - dh_fixperms - dh_installdeb - dh_shlibdeps - dh_gencontrol - dh_md5sums - dh_builddeb - -source diff: - @echo >&2 'source and diff are obsolete - use dpkg-source -b'; false - -binary: binary-indep binary-arch -.PHONY: build clean binary-indep binary-arch binary install -''' % vars()) - - os.chmod(os.path.join('.build', directory, 'debian', 'rules'), 0755) - - os.chdir('.build/%(directory)s' % vars()) - os.system('dpkg-buildpackage -rfakeroot'+ ['', ' -uc -us'][config['unsigned']]) - -if __name__ == '__main__': - run() - diff --git a/tools/buildbot/pylibs/twisted/scripts/tap2rpm.py b/tools/buildbot/pylibs/twisted/scripts/tap2rpm.py deleted file mode 100644 index 601555d..0000000 --- a/tools/buildbot/pylibs/twisted/scripts/tap2rpm.py +++ /dev/null @@ -1,273 +0,0 @@ -# based off the tap2deb.py file -# tap2rpm.py built by Sean Reifschneider, - -# TODO: need to implement log-file rotation - -import sys, os, shutil, time, glob - -from twisted.python import usage -from twisted.scripts import tap2deb - - -################################# -# data that goes in /etc/inittab -initFileData = '''\ -#!/bin/sh -# -# Startup script for a Twisted service. -# -# chkconfig: - 85 15 -# description: Start-up script for the Twisted service "%(tap_file)s". - -PATH=/usr/bin:/bin:/usr/sbin:/sbin - -pidfile=/var/run/%(rpm_file)s.pid -rundir=/var/lib/twisted-taps/%(rpm_file)s/ -file=/etc/twisted-taps/%(tap_file)s -logfile=/var/log/%(rpm_file)s.log - -# load init function library -. /etc/init.d/functions - -[ -r /etc/default/%(rpm_file)s ] && . /etc/default/%(rpm_file)s - -# check for required files -if [ ! -x /usr/bin/twistd ] -then - echo "$0: Aborting, no /usr/bin/twistd found" - exit 0 -fi -if [ ! -r "$file" ] -then - echo "$0: Aborting, no file $file found." - exit 0 -fi - -# set up run directory if necessary -if [ ! -d "${rundir}" ] -then - mkdir -p "${rundir}" -fi - - -case "$1" in - start) - echo -n "Starting %(rpm_file)s: twistd" - daemon twistd \\ - --pidfile=$pidfile \\ - --rundir=$rundir \\ - --%(twistd_option)s=$file \\ - --logfile=$logfile - status %(rpm_file)s - ;; - - stop) - echo -n "Stopping %(rpm_file)s: twistd" - kill `cat "${pidfile}"` - status %(rpm_file)s - ;; - - restart) - "${0}" stop - "${0}" start - ;; - - *) - echo "Usage: ${0} {start|stop|restart|}" >&2 - exit 1 - ;; -esac - -exit 0 -''' - -####################################### -# the data for creating the spec file -specFileData = '''\ -Summary: %(description)s -Name: %(rpm_file)s -Version: %(version)s -Release: 1 -Copyright: Unknown -Group: Networking/Daemons -Source: %(tarfile_basename)s -BuildRoot: /var/tmp/%%{name}-%%{version}-root -Requires: /usr/bin/twistd -BuildArch: noarch - -%%description -%(long_description)s - -%%prep -%%setup -%%build - -%%install -[ ! -z "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != '/' ] \ - && rm -rf "$RPM_BUILD_ROOT" -mkdir -p "$RPM_BUILD_ROOT"/etc/twisted-taps -mkdir -p "$RPM_BUILD_ROOT"/etc/init.d -mkdir -p "$RPM_BUILD_ROOT"/var/lib/twisted-taps -cp "%(tap_file)s" "$RPM_BUILD_ROOT"/etc/twisted-taps/ -cp "%(rpm_file)s.init" "$RPM_BUILD_ROOT"/etc/init.d/"%(rpm_file)s" - -%%clean -[ ! -z "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != '/' ] \ - && rm -rf "$RPM_BUILD_ROOT" - -%%post -/sbin/chkconfig --add %(rpm_file)s -/sbin/chkconfig --level 35 %(rpm_file)s -/etc/init.d/%(rpm_file)s start - -%%preun -/etc/init.d/%(rpm_file)s stop -/sbin/chkconfig --del %(rpm_file)s - -%%files -%%defattr(-,root,root) -%%attr(0755,root,root) /etc/init.d/%(rpm_file)s -%%attr(0660,root,root) /etc/twisted-taps/%(tap_file)s - -%%changelog -* %(date)s %(maintainer)s -- Created by tap2rpm: %(rpm_file)s (%(version)s) -''' - -############################### -class MyOptions(usage.Options): - optFlags = [["unsigned", "u"]] - optParameters = [ - ["tapfile", "t", "twistd.tap"], - ["maintainer", "m", ""], - ["protocol", "p", ""], - ["description", "e", ""], - ["long_description", "l", ""], - ["set-version", "V", "1.0"], - ["rpmfile", "r", None], - ["type", "y", "tap", "type of configuration: 'tap', 'xml, " - "'source' or 'python'"], - ] - - #zsh_altArgDescr = {"foo":"use this description for foo instead"} - #zsh_multiUse = ["foo", "bar"] - #zsh_mutuallyExclusive = [("foo", "bar"), ("bar", "baz")] - zsh_actions = {"type":"(tap xml source python)", - "rpmfile":'_files -g "*.rpm"'} - #zsh_actionDescr = {"logfile":"log file name", "random":"random seed"} - - -type_dict = { - 'tap': 'file', - 'python': 'python', - 'source': 'source', - 'xml': 'xml', -} - - -########################## -def makeBuildDir(baseDir): - '''Set up the temporary directory for building RPMs. - Returns: Tuple: ( buildDir, rpmrcFile ) - ''' - import random, string - - # make top directory - oldMask = os.umask(0077) - while 1: - tmpDir = os.path.join(baseDir, 'tap2rpm-%s-%s' % ( os.getpid(), - random.randint(0, 999999999) )) - if not os.path.exists(tmpDir): - os.makedirs(tmpDir) - break - os.umask(oldMask) - - # set up initial directory contents - os.makedirs(os.path.join(tmpDir, 'RPMS', 'noarch')) - os.makedirs(os.path.join(tmpDir, 'SPECS')) - os.makedirs(os.path.join(tmpDir, 'BUILD')) - os.makedirs(os.path.join(tmpDir, 'SOURCES')) - os.makedirs(os.path.join(tmpDir, 'SRPMS')) - - # set up rpmmacros file - macroFile = os.path.join(tmpDir, 'rpmmacros') - rcFile = os.path.join(tmpDir, 'rpmrc') - rpmrcData = open('/usr/lib/rpm/rpmrc', 'r').read() - rpmrcData = string.replace(rpmrcData, '~/.rpmmacros', macroFile) - fp = open(macroFile, 'w') - fp.write('%%_topdir %s\n' % tmpDir) - fp.close() - - # set up the rpmrc file - fp = open(rcFile, 'w') - fp.write(rpmrcData) - fp.close() - - return(( tmpDir, rcFile )) - - -########## -def run(): - # parse options - try: - config = MyOptions() - config.parseOptions() - except usage.error, ue: - sys.exit("%s: %s" % (sys.argv[0], ue)) - - # set up some useful local variables - tap_file = config['tapfile'] - base_tap_file = os.path.basename(config['tapfile']) - protocol = (config['protocol'] or os.path.splitext(base_tap_file)[0]) - rpm_file = config['rpmfile'] or 'twisted-'+protocol - version = config['set-version'] - maintainer = config['maintainer'] - description = config['description'] or ('A TCP server for %(protocol)s' % - vars()) - long_description = (config['long_description'] - or 'Automatically created by tap2deb') - twistd_option = type_dict[config['type']] - date = time.strftime('%a %b %d %Y', time.localtime(time.time())) - directory = rpm_file + '-' + version - python_version = '%s.%s' % sys.version_info[:2] - - # set up a blank maintainer if not present - if not maintainer: - maintainer = 'tap2rpm' - - # create source archive directory - tmp_dir, rpmrc_file = makeBuildDir('/var/tmp') - source_dir = os.path.join(tmp_dir, directory) - os.makedirs(source_dir) - - # populate source directory - tarfile_name = source_dir + '.tar.gz' - tarfile_basename = os.path.basename(tarfile_name) - tap2deb.save_to_file(os.path.join(source_dir, '%s.spec' % rpm_file), - specFileData % vars()) - tap2deb.save_to_file(os.path.join(source_dir, '%s.init' % rpm_file), - initFileData % vars()) - shutil.copy(tap_file, source_dir) - - # create source tar - os.system('cd "%(tmp_dir)s"; tar cfz "%(tarfile_name)s" "%(directory)s"' - % vars()) - - # build rpm - print 'Starting build...' - print '=' * 70 - sys.stdout.flush() - os.system('rpmbuild -ta --rcfile "%s" %s' % ( rpmrc_file, tarfile_name )) - print 'Done with build...' - print '=' * 70 - - # copy the RPMs to the local directory - rpm_path = glob.glob(os.path.join(tmp_dir, 'RPMS', 'noarch', '*'))[0] - srpm_path = glob.glob(os.path.join(tmp_dir, 'SRPMS', '*'))[0] - print 'Writing "%s"...' % os.path.basename(rpm_path) - shutil.copy(rpm_path, '.') - print 'Writing "%s"...' % os.path.basename(srpm_path) - shutil.copy(srpm_path, '.') - - # remove the build directory - shutil.rmtree(tmp_dir) diff --git a/tools/buildbot/pylibs/twisted/scripts/tapconvert.py b/tools/buildbot/pylibs/twisted/scripts/tapconvert.py deleted file mode 100644 index 4616e6d..0000000 --- a/tools/buildbot/pylibs/twisted/scripts/tapconvert.py +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.python import usage -from twisted.application import app -from twisted.persisted import sob -import sys, getpass - -class ConvertOptions(usage.Options): - synopsis = "Usage: tapconvert [options]" - optParameters = [ - ['in', 'i', None, "The filename of the tap to read from"], - ['out', 'o', None, "A filename to write the tap to"], - ['typein', 'f', 'guess', - "The format to use; this can be 'guess', 'python', " - "'pickle', 'xml', or 'source'."], - ['typeout', 't', 'source', - "The output format to use; this can be 'pickle', 'xml', or 'source'."], - ] - - optFlags = [ - ['decrypt', 'd', "The specified tap/aos/xml file is encrypted."], - ['encrypt', 'e', "Encrypt file before writing"] - ] - #zsh_altArgDescr = {"foo":"use this description for foo instead"} - #zsh_multiUse = ["foo", "bar"] - #zsh_mutuallyExclusive = [("foo", "bar"), ("bar", "baz")] - zsh_actions = {"typein":"(guess python pickle xml source)", - "typeout":"(pickle xml source)"} - zsh_actionDescr = {"in":"tap file to read from", - "out":"tap file to write to"} - - def postOptions(self): - if self['in'] is None: - raise usage.UsageError("%s\nYou must specify the input filename." - % self) - if self["typein"] == "guess": - try: - self["typein"] = sob.guessType(self["in"]) - except KeyError: - raise usage.UsageError("Could not guess type for '%s'" % - self["typein"]) - -def run(): - options = ConvertOptions() - try: - options.parseOptions(sys.argv[1:]) - except usage.UsageError, e: - print e - else: - app.convertStyle(options["in"], options["typein"], - options.opts['decrypt'] or getpass.getpass('Passphrase: '), - options["out"], options['typeout'], options["encrypt"]) diff --git a/tools/buildbot/pylibs/twisted/scripts/test/__init__.py b/tools/buildbot/pylibs/twisted/scripts/test/__init__.py deleted file mode 100644 index d903f60..0000000 --- a/tools/buildbot/pylibs/twisted/scripts/test/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright (c) 2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test package for L{twisted.scripts}. -""" diff --git a/tools/buildbot/pylibs/twisted/scripts/test/test_mktap.py b/tools/buildbot/pylibs/twisted/scripts/test/test_mktap.py deleted file mode 100644 index 96dcb39..0000000 --- a/tools/buildbot/pylibs/twisted/scripts/test/test_mktap.py +++ /dev/null @@ -1,107 +0,0 @@ -# Copyright (c) 2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.scripts.mktap}. -""" - -import sys -try: - import pwd, grp -except ImportError: - pwd = None - -from twisted.trial.unittest import TestCase - -from twisted.scripts.mktap import run, getid -from twisted.application.service import IProcess, loadApplication -from twisted.test.test_twistd import patchUserDatabase - - -class RunTests(TestCase): - """ - Tests for L{twisted.scripts.mktap.run}. - """ - def setUp(self): - """ - Save the original value of L{sys.argv} so that tests can change it - as necessary. - """ - self.argv = sys.argv[:] - - - def tearDown(self): - """ - Restore the original value of L{sys.argv}. - """ - sys.argv[:] = self.argv - - - def _saveConfiguredIDTest(self, argv, uid, gid): - """ - Test that when L{run} is invoked and L{sys.argv} has the given - value, the resulting application has the specified UID and GID. - - @type argv: C{list} of C{str} - @param argv: The value to which to set L{sys.argv} before calling L{run}. - - @type uid: C{int} - @param uid: The expected value for the resulting application's - L{IProcess.uid}. - - @type gid: C{int} - @param gid: The expected value for the resulting application's - L{IProcess.gid}. - """ - sys.argv = argv - run() - app = loadApplication("ftp.tap", "pickle", None) - process = IProcess(app) - self.assertEqual(process.uid, uid) - self.assertEqual(process.gid, gid) - - - def test_getNumericID(self): - """ - L{run} extracts numeric UID and GID information from the command - line and persists it with the application object. - """ - uid = 1234 - gid = 4321 - self._saveConfiguredIDTest( - ["mktap", "--uid", str(uid), "--gid", str(gid), "ftp"], - uid, gid) - - - def test_getNameID(self): - """ - L{run} extracts name UID and GID information from the command - line and persists it with the application object. - """ - user = "foo" - uid = 1234 - group = "bar" - gid = 4321 - patchUserDatabase(self.patch, user, uid, group, gid) - self._saveConfiguredIDTest( - ["mktap", "--uid", user, "--gid", group, "ftp"], - uid, gid) - if pwd is None: - test_getNameID.skip = ( - "Username/UID Group name/GID translation requires pwd and grp " - "modules.") - - - -class HelperTests(TestCase): - """ - Tests for miscellaneous utility functions related to mktap. - """ - def test_getid(self): - """ - L{getid} returns a two-tuple of integers giving the numeric values of - the strings it is passed. - """ - uid = 1234 - gid = 4321 - self.assertEqual(getid(str(uid), str(gid)), (uid, gid)) diff --git a/tools/buildbot/pylibs/twisted/scripts/tkunzip.py b/tools/buildbot/pylibs/twisted/scripts/tkunzip.py deleted file mode 100644 index 6332c12..0000000 --- a/tools/buildbot/pylibs/twisted/scripts/tkunzip.py +++ /dev/null @@ -1,286 +0,0 @@ -"""Post-install GUI to compile to pyc and unpack twisted doco""" - -from __future__ import generators - -import sys -import zipfile -import py_compile - -# we're going to ignore failures to import tkinter and fall back -# to using the console if the required dll is not found - -# Scary kludge to work around tk84.dll bug: -# https://sourceforge.net/tracker/index.php?func=detail&aid=814654&group_id=5470&atid=105470 -# Without which(): you get a windows missing-dll popup message -from twisted.python.procutils import which -tkdll='tk84.dll' -if which(tkdll) or which('DLLs/%s' % tkdll): - try: - import Tkinter - from Tkinter import * - from twisted.internet import tksupport - except ImportError: - pass - -# twisted -from twisted.internet import reactor, defer -from twisted.python import failure, log, zipstream, util, usage, log -# local -import os.path - -class ProgressBar: - def __init__(self, master=None, orientation="horizontal", - min=0, max=100, width=100, height=18, - doLabel=1, appearance="sunken", - fillColor="blue", background="gray", - labelColor="yellow", labelFont="Arial", - labelText="", labelFormat="%d%%", - value=0, bd=2): - # preserve various values - self.master=master - self.orientation=orientation - self.min=min - self.max=max - self.width=width - self.height=height - self.doLabel=doLabel - self.fillColor=fillColor - self.labelFont= labelFont - self.labelColor=labelColor - self.background=background - self.labelText=labelText - self.labelFormat=labelFormat - self.value=value - self.frame=Frame(master, relief=appearance, bd=bd) - self.canvas=Canvas(self.frame, height=height, width=width, bd=0, - highlightthickness=0, background=background) - self.scale=self.canvas.create_rectangle(0, 0, width, height, - fill=fillColor) - self.label=self.canvas.create_text(self.canvas.winfo_reqwidth() / 2, - height / 2, text=labelText, - anchor="c", fill=labelColor, - font=self.labelFont) - self.update() - self.canvas.pack(side='top', fill='x', expand='no') - - def pack(self, *args, **kwargs): - self.frame.pack(*args, **kwargs) - - def updateProgress(self, newValue, newMax=None): - if newMax: - self.max = newMax - self.value = newValue - self.update() - - def update(self): - # Trim the values to be between min and max - value=self.value - if value > self.max: - value = self.max - if value < self.min: - value = self.min - # Adjust the rectangle - if self.orientation == "horizontal": - self.canvas.coords(self.scale, 0, 0, - float(value) / self.max * self.width, self.height) - else: - self.canvas.coords(self.scale, 0, - self.height - (float(value) / - self.max*self.height), - self.width, self.height) - # Now update the colors - self.canvas.itemconfig(self.scale, fill=self.fillColor) - self.canvas.itemconfig(self.label, fill=self.labelColor) - # And update the label - if self.doLabel: - if value: - if value >= 0: - pvalue = int((float(value) / float(self.max)) * - 100.0) - else: - pvalue = 0 - self.canvas.itemconfig(self.label, text=self.labelFormat - % pvalue) - else: - self.canvas.itemconfig(self.label, text='') - else: - self.canvas.itemconfig(self.label, text=self.labelFormat % - self.labelText) - self.canvas.update_idletasks() - - -class Progressor: - """A base class to make it simple to hook a progress bar up to a process. - """ - def __init__(self, title, *args, **kwargs): - self.title=title - self.stopping=0 - self.bar=None - self.iterator=None - self.remaining=1000 - - def setBar(self, bar, max): - self.bar=bar - bar.updateProgress(0, max) - return self - - def setIterator(self, iterator): - self.iterator=iterator - return self - - def updateBar(self, deferred): - b=self.bar - try: - b.updateProgress(b.max - self.remaining) - except TclError: - self.stopping=1 - except: - deferred.errback(failure.Failure()) - - def processAll(self, root): - assert self.bar and self.iterator, "must setBar and setIterator" - self.root=root - root.title(self.title) - d=defer.Deferred() - d.addErrback(log.err) - reactor.callLater(0.1, self.processOne, d) - return d - - def processOne(self, deferred): - if self.stopping: - deferred.callback(self.root) - return - - try: - self.remaining=self.iterator.next() - except StopIteration: - self.stopping=1 - except: - deferred.errback(failure.Failure()) - - if self.remaining%10==0: - reactor.callLater(0, self.updateBar, deferred) - if self.remaining%100==0: - log.msg(self.remaining) - reactor.callLater(0, self.processOne, deferred) - -def compiler(path): - """A generator for compiling files to .pyc""" - def justlist(arg, directory, names): - pynames=[os.path.join(directory, n) for n in names - if n.endswith('.py')] - arg.extend(pynames) - all=[] - os.path.walk(path, justlist, all) - - remaining=len(all) - i=zip(all, range(remaining-1, -1, -1)) - for f, remaining in i: - py_compile.compile(f) - yield remaining - -class TkunzipOptions(usage.Options): - optParameters=[["zipfile", "z", "", "a zipfile"], - ["ziptargetdir", "t", ".", "where to extract zipfile"], - ["compiledir", "c", "", "a directory to compile"], - ] - optFlags=[["use-console", "C", "show in the console, not graphically"], - ["shell-exec", "x", """\ -spawn a new console to show output (implies -C)"""], - ] - -def countPys(countl, directory, names): - sofar=countl[0] - sofar=sofar+len([f for f in names if f.endswith('.py')]) - countl[0]=sofar - return sofar - -def countPysRecursive(path): - countl=[0] - os.path.walk(path, countPys, countl) - return countl[0] - -def run(argv=sys.argv): - log.startLogging(file('tkunzip.log', 'w')) - opt=TkunzipOptions() - try: - opt.parseOptions(argv[1:]) - except usage.UsageError, e: - print str(opt) - print str(e) - sys.exit(1) - - if opt['use-console']: - # this should come before shell-exec to prevent infinite loop - return doItConsolicious(opt) - if opt['shell-exec'] or not 'Tkinter' in sys.modules: - from distutils import sysconfig - from twisted.scripts import tkunzip - myfile=tkunzip.__file__ - exe=os.path.join(sysconfig.get_config_var('prefix'), 'python.exe') - return os.system('%s %s --use-console %s' % (exe, myfile, - ' '.join(argv[1:]))) - return doItTkinterly(opt) - -def doItConsolicious(opt): - # reclaim stdout/stderr from log - sys.stdout = sys.__stdout__ - sys.stderr = sys.__stderr__ - if opt['zipfile']: - print 'Unpacking documentation...' - for n in zipstream.unzipIter(opt['zipfile'], opt['ziptargetdir']): - if n % 100 == 0: - print n, - if n % 1000 == 0: - print - print 'Done unpacking.' - - if opt['compiledir']: - print 'Compiling to pyc...' - import compileall - compileall.compile_dir(opt["compiledir"]) - print 'Done compiling.' - -def doItTkinterly(opt): - root=Tkinter.Tk() - root.withdraw() - root.title('One Moment.') - root.protocol('WM_DELETE_WINDOW', reactor.stop) - tksupport.install(root) - - prog=ProgressBar(root, value=0, labelColor="black", width=200) - prog.pack() - - # callback immediately - d=defer.succeed(root).addErrback(log.err) - - def deiconify(root): - root.deiconify() - return root - - d.addCallback(deiconify) - - if opt['zipfile']: - uz=Progressor('Unpacking documentation...') - max=zipstream.countZipFileChunks(opt['zipfile'], 4096) - uz.setBar(prog, max) - uz.setIterator(zipstream.unzipIterChunky(opt['zipfile'], - opt['ziptargetdir'])) - d.addCallback(uz.processAll) - - if opt['compiledir']: - comp=Progressor('Compiling to pyc...') - comp.setBar(prog, countPysRecursive(opt['compiledir'])) - comp.setIterator(compiler(opt['compiledir'])) - d.addCallback(comp.processAll) - - def stop(ignore): - reactor.stop() - root.destroy() - d.addCallback(stop) - - reactor.run() - - -if __name__=='__main__': - run() diff --git a/tools/buildbot/pylibs/twisted/scripts/trial.py b/tools/buildbot/pylibs/twisted/scripts/trial.py deleted file mode 100644 index 4476f4a..0000000 --- a/tools/buildbot/pylibs/twisted/scripts/trial.py +++ /dev/null @@ -1,368 +0,0 @@ -# -*- test-case-name: twisted.trial.test.test_script -*- - -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -import sys, os, random, gc, time, warnings - -from twisted.internet import defer -from twisted.application import app -from twisted.python import usage, reflect, failure -from twisted import plugin -from twisted.python.util import spewer -from twisted.python.compat import set -from twisted.trial import runner, itrial, reporter - - -# Yea, this is stupid. Leave it for for command-line compatibility for a -# while, though. -TBFORMAT_MAP = { - 'plain': 'default', - 'default': 'default', - 'emacs': 'brief', - 'brief': 'brief', - 'cgitb': 'verbose', - 'verbose': 'verbose' - } - - -def _parseLocalVariables(line): - """Accepts a single line in Emacs local variable declaration format and - returns a dict of all the variables {name: value}. - Raises ValueError if 'line' is in the wrong format. - - See http://www.gnu.org/software/emacs/manual/html_node/File-Variables.html - """ - paren = '-*-' - start = line.find(paren) + len(paren) - end = line.rfind(paren) - if start == -1 or end == -1: - raise ValueError("%r not a valid local variable declaration" % (line,)) - items = line[start:end].split(';') - localVars = {} - for item in items: - if len(item.strip()) == 0: - continue - split = item.split(':') - if len(split) != 2: - raise ValueError("%r contains invalid declaration %r" - % (line, item)) - localVars[split[0].strip()] = split[1].strip() - return localVars - - -def loadLocalVariables(filename): - """Accepts a filename and attempts to load the Emacs variable declarations - from that file, simulating what Emacs does. - - See http://www.gnu.org/software/emacs/manual/html_node/File-Variables.html - """ - f = file(filename, "r") - lines = [f.readline(), f.readline()] - f.close() - for line in lines: - try: - return _parseLocalVariables(line) - except ValueError: - pass - return {} - - -def getTestModules(filename): - testCaseVar = loadLocalVariables(filename).get('test-case-name', None) - if testCaseVar is None: - return [] - return testCaseVar.split(',') - - -def isTestFile(filename): - """Returns true if 'filename' looks like a file containing unit tests. - False otherwise. Doesn't care whether filename exists. - """ - basename = os.path.basename(filename) - return (basename.startswith('test_') - and os.path.splitext(basename)[1] == ('.py')) - - -def _zshReporterAction(): - return "(%s)" % (" ".join([p.longOpt for p in plugin.getPlugins(itrial.IReporter)]),) - -class Options(usage.Options, app.ReactorSelectionMixin): - synopsis = """%s [options] [[file|package|module|TestCase|testmethod]...] - """ % (os.path.basename(sys.argv[0]),) - - optFlags = [["help", "h"], - ["rterrors", "e", "realtime errors, print out tracebacks as " - "soon as they occur"], - ["debug", "b", "Run tests in the Python debugger. Will load " - "'.pdbrc' from current directory if it exists."], - ["debug-stacktraces", "B", "Report Deferred creation and " - "callback stack traces"], - ["nopm", None, "don't automatically jump into debugger for " - "postmorteming of exceptions"], - ["dry-run", 'n', "do everything but run the tests"], - ["force-gc", None, "Have Trial run gc.collect() before and " - "after each test case."], - ["profile", None, "Run tests under the Python profiler"], - ["unclean-warnings", None, - "Turn dirty reactor errors into warnings"], - ["until-failure", "u", "Repeat test until it fails"], - ["no-recurse", "N", "Don't recurse into packages"], - ['help-reporters', None, - "Help on available output plugins (reporters)"] - ] - - optParameters = [ - ["logfile", "l", "test.log", "log file name"], - ["random", "z", None, - "Run tests in random order using the specified seed"], - ['temp-directory', None, '_trial_temp', - 'Path to use as working directory for tests.'], - ['reporter', None, 'verbose', - 'The reporter to use for this test run. See --help-reporters for ' - 'more info.']] - - zsh_actions = {"tbformat":"(plain emacs cgitb)", - "reporter":_zshReporterAction} - zsh_actionDescr = {"logfile":"log file name", - "random":"random seed"} - zsh_extras = ["*:file|module|package|TestCase|testMethod:_files -g '*.py'"] - - fallbackReporter = reporter.TreeReporter - extra = None - tracer = None - - def __init__(self): - self['tests'] = set() - usage.Options.__init__(self) - - def opt_coverage(self): - """ - Generate coverage information in the _trial_temp/coverage. Requires - Python 2.3.3. - """ - coverdir = 'coverage' - print "Setting coverage directory to %s." % (coverdir,) - import trace - - # begin monkey patch --------------------------- - # Before Python 2.4, this function asserted that 'filename' had - # to end with '.py' This is wrong for at least two reasons: - # 1. We might be wanting to find executable line nos in a script - # 2. The implementation should use os.splitext - # This monkey patch is the same function as in the stdlib (v2.3) - # but with the assertion removed. - def find_executable_linenos(filename): - """Return dict where keys are line numbers in the line number - table. - """ - #assert filename.endswith('.py') # YOU BASTARDS - try: - prog = open(filename).read() - prog = '\n'.join(prog.splitlines()) + '\n' - except IOError, err: - sys.stderr.write("Not printing coverage data for %r: %s\n" - % (filename, err)) - sys.stderr.flush() - return {} - code = compile(prog, filename, "exec") - strs = trace.find_strings(filename) - return trace.find_lines(code, strs) - - trace.find_executable_linenos = find_executable_linenos - # end monkey patch ------------------------------ - - self.coverdir = os.path.abspath(os.path.join(self['temp-directory'], coverdir)) - self.tracer = trace.Trace(count=1, trace=0) - sys.settrace(self.tracer.globaltrace) - - def opt_testmodule(self, filename): - "Filename to grep for test cases (-*- test-case-name)" - # If the filename passed to this parameter looks like a test module - # we just add that to the test suite. - # - # If not, we inspect it for an Emacs buffer local variable called - # 'test-case-name'. If that variable is declared, we try to add its - # value to the test suite as a module. - # - # This parameter allows automated processes (like Buildbot) to pass - # a list of files to Trial with the general expectation of "these files, - # whatever they are, will get tested" - if not os.path.isfile(filename): - sys.stderr.write("File %r doesn't exist\n" % (filename,)) - return - filename = os.path.abspath(filename) - if isTestFile(filename): - self['tests'].add(filename) - else: - self['tests'].update(getTestModules(filename)) - - def opt_spew(self): - """Print an insanely verbose log of everything that happens. Useful - when debugging freezes or locks in complex code.""" - sys.settrace(spewer) - - - def opt_help_reporters(self): - synopsis = ("Trial's output can be customized using plugins called " - "Reporters. You can\nselect any of the following " - "reporters using --reporter=\n") - print synopsis - for p in plugin.getPlugins(itrial.IReporter): - print ' ', p.longOpt, '\t', p.description - print - sys.exit(0) - - def opt_disablegc(self): - """Disable the garbage collector""" - gc.disable() - - def opt_tbformat(self, opt): - """Specify the format to display tracebacks with. Valid formats are - 'plain', 'emacs', and 'cgitb' which uses the nicely verbose stdlib - cgitb.text function""" - try: - self['tbformat'] = TBFORMAT_MAP[opt] - except KeyError: - raise usage.UsageError( - "tbformat must be 'plain', 'emacs', or 'cgitb'.") - - def opt_extra(self, arg): - """ - Add an extra argument. (This is a hack necessary for interfacing with - emacs's `gud'.) - """ - if self.extra is None: - self.extra = [] - self.extra.append(arg) - opt_x = opt_extra - - def opt_recursionlimit(self, arg): - """see sys.setrecursionlimit()""" - try: - sys.setrecursionlimit(int(arg)) - except (TypeError, ValueError): - raise usage.UsageError( - "argument to recursionlimit must be an integer") - - def opt_random(self, option): - try: - self['random'] = long(option) - except ValueError: - raise usage.UsageError( - "Argument to --random must be a positive integer") - else: - if self['random'] < 0: - raise usage.UsageError( - "Argument to --random must be a positive integer") - elif self['random'] == 0: - self['random'] = long(time.time() * 100) - - def opt_without_module(self, option): - """ - Fake the lack of the specified modules, separated with commas. - """ - for module in option.split(","): - if module in sys.modules: - warnings.warn("Module '%s' already imported, " - "disabling anyway." % (module,), - category=RuntimeWarning) - sys.modules[module] = None - - def parseArgs(self, *args): - self['tests'].update(args) - if self.extra is not None: - self['tests'].update(self.extra) - - def _loadReporterByName(self, name): - for p in plugin.getPlugins(itrial.IReporter): - qual = "%s.%s" % (p.module, p.klass) - if p.longOpt == name: - return reflect.namedAny(qual) - raise usage.UsageError("Only pass names of Reporter plugins to " - "--reporter. See --help-reporters for " - "more info.") - - - def postOptions(self): - - # Only load reporters now, as opposed to any earlier, to avoid letting - # application-defined plugins muck up reactor selecting by importing - # t.i.reactor and causing the default to be installed. - self['reporter'] = self._loadReporterByName(self['reporter']) - - if 'tbformat' not in self: - self['tbformat'] = 'default' - if self['nopm']: - if not self['debug']: - raise usage.UsageError("you must specify --debug when using " - "--nopm ") - failure.DO_POST_MORTEM = False - - -def _initialDebugSetup(config): - # do this part of debug setup first for easy debugging of import failures - if config['debug']: - failure.startDebugMode() - if config['debug'] or config['debug-stacktraces']: - defer.setDebugging(True) - - -def _getSuite(config): - loader = _getLoader(config) - recurse = not config['no-recurse'] - return loader.loadByNames(config['tests'], recurse) - - -def _getLoader(config): - loader = runner.TestLoader() - if config['random']: - randomer = random.Random() - randomer.seed(config['random']) - loader.sorter = lambda x : randomer.random() - print 'Running tests shuffled with seed %d\n' % config['random'] - if not config['until-failure']: - loader.suiteFactory = runner.DestructiveTestSuite - return loader - - -def _makeRunner(config): - mode = None - if config['debug']: - mode = runner.TrialRunner.DEBUG - if config['dry-run']: - mode = runner.TrialRunner.DRY_RUN - return runner.TrialRunner(config['reporter'], - mode=mode, - profile=config['profile'], - logfile=config['logfile'], - tracebackFormat=config['tbformat'], - realTimeErrors=config['rterrors'], - uncleanWarnings=config['unclean-warnings'], - workingDirectory=config['temp-directory'], - forceGarbageCollection=config['force-gc']) - - -def run(): - if len(sys.argv) == 1: - sys.argv.append("--help") - config = Options() - try: - config.parseOptions() - except usage.error, ue: - raise SystemExit, "%s: %s" % (sys.argv[0], ue) - _initialDebugSetup(config) - trialRunner = _makeRunner(config) - suite = _getSuite(config) - if config['until-failure']: - test_result = trialRunner.runUntilFailure(suite) - else: - test_result = trialRunner.run(suite) - if config.tracer: - sys.settrace(None) - results = config.tracer.results() - results.write_results(show_missing=1, summary=False, - coverdir=config.coverdir) - sys.exit(not test_result.wasSuccessful()) - diff --git a/tools/buildbot/pylibs/twisted/scripts/twistd.py b/tools/buildbot/pylibs/twisted/scripts/twistd.py deleted file mode 100644 index 5847216..0000000 --- a/tools/buildbot/pylibs/twisted/scripts/twistd.py +++ /dev/null @@ -1,30 +0,0 @@ -# -*- test-case-name: twisted.test.test_twistd -*- -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -The Twisted Daemon: platform-independent interface. - -@author: U{Christopher Armstrong} -""" - -from twisted.application import app - -from twisted.python.runtime import platformType -if platformType == "win32": - from twisted.scripts._twistw import ServerOptions, \ - WindowsApplicationRunner as _SomeApplicationRunner -else: - from twisted.scripts._twistd_unix import ServerOptions, \ - UnixApplicationRunner as _SomeApplicationRunner - - -def runApp(config): - _SomeApplicationRunner(config).run() - - -def run(): - app.run(runApp, ServerOptions) - - -__all__ = ['run', 'runApp'] diff --git a/tools/buildbot/pylibs/twisted/spread/__init__.py b/tools/buildbot/pylibs/twisted/spread/__init__.py deleted file mode 100644 index a7ed489..0000000 --- a/tools/buildbot/pylibs/twisted/spread/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Twisted Spread: Spreadable (Distributed) Computing. - -Future Plans: PB, Jelly and Banana need to be optimized. - -@author: U{Glyph Lefkowitz} -""" diff --git a/tools/buildbot/pylibs/twisted/spread/banana.py b/tools/buildbot/pylibs/twisted/spread/banana.py deleted file mode 100644 index df34503..0000000 --- a/tools/buildbot/pylibs/twisted/spread/banana.py +++ /dev/null @@ -1,351 +0,0 @@ -# -*- test-case-name: twisted.test.test_banana -*- -# -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Banana -- s-exp based protocol. - -Future Plans: This module is almost entirely stable. The same caveat applies -to it as applies to L{twisted.spread.jelly}, however. Read its future plans -for more details. - -@author: U{Glyph Lefkowitz} -""" - -__version__ = "$Revision: 1.37 $"[11:-2] - -from twisted.internet import protocol -from twisted.persisted import styles -from twisted.python import log - -import copy, cStringIO, struct - -class BananaError(Exception): - pass - -def int2b128(integer, stream): - if integer == 0: - stream(chr(0)) - return - assert integer > 0, "can only encode positive integers" - while integer: - stream(chr(integer & 0x7f)) - integer = integer >> 7 - -def b1282int(st): - oneHundredAndTwentyEight = 128l - i = 0 - place = 0 - for char in st: - num = ord(char) - i = i + (num * (oneHundredAndTwentyEight ** place)) - place = place + 1 - if i <= 2147483647: - return int(i) - else: - return i - -# delimiter characters. -LIST = chr(0x80) -INT = chr(0x81) -STRING = chr(0x82) -NEG = chr(0x83) -FLOAT = chr(0x84) -# "optional" -- these might be refused by a low-level implementation. -LONGINT = chr(0x85) -LONGNEG = chr(0x86) -# really optional; this is is part of the 'pb' vocabulary -VOCAB = chr(0x87) - -HIGH_BIT_SET = chr(0x80) - -def setPrefixLimit(limit): - """ - Set the limit on the prefix length for all Banana connections - established after this call. - - The prefix length limit determines how many bytes of prefix a banana - decoder will allow before rejecting a potential object as too large. - - @type limit: C{int} - @param limit: The number of bytes of prefix for banana to allow when - decoding. - """ - global _PREFIX_LIMIT - _PREFIX_LIMIT = limit -setPrefixLimit(64) - -SIZE_LIMIT = 640 * 1024 # 640k is all you'll ever need :-) - -class Banana(protocol.Protocol, styles.Ephemeral): - knownDialects = ["pb", "none"] - - prefixLimit = None - sizeLimit = SIZE_LIMIT - - def setPrefixLimit(self, limit): - """ - Set the prefix limit for decoding done by this protocol instance. - - @see: L{setPrefixLimit} - """ - self.prefixLimit = limit - self._smallestLongInt = -2 ** (limit * 7) + 1 - self._smallestInt = -2 ** 31 - self._largestInt = 2 ** 31 - 1 - self._largestLongInt = 2 ** (limit * 7) - 1 - - - def connectionReady(self): - """Surrogate for connectionMade - Called after protocol negotiation. - """ - - def _selectDialect(self, dialect): - self.currentDialect = dialect - self.connectionReady() - - def callExpressionReceived(self, obj): - if self.currentDialect: - self.expressionReceived(obj) - else: - # this is the first message we've received - if self.isClient: - # if I'm a client I have to respond - for serverVer in obj: - if serverVer in self.knownDialects: - self.sendEncoded(serverVer) - self._selectDialect(serverVer) - break - else: - # I can't speak any of those dialects. - log.msg('error losing') - self.transport.loseConnection() - else: - if obj in self.knownDialects: - self._selectDialect(obj) - else: - # the client just selected a protocol that I did not suggest. - log.msg('freaky losing') - self.transport.loseConnection() - - - def connectionMade(self): - self.setPrefixLimit(_PREFIX_LIMIT) - self.currentDialect = None - if not self.isClient: - self.sendEncoded(self.knownDialects) - - - def gotItem(self, item): - l = self.listStack - if l: - l[-1][1].append(item) - else: - self.callExpressionReceived(item) - - buffer = '' - - def dataReceived(self, chunk): - buffer = self.buffer + chunk - listStack = self.listStack - gotItem = self.gotItem - while buffer: - assert self.buffer != buffer, "This ain't right: %s %s" % (repr(self.buffer), repr(buffer)) - self.buffer = buffer - pos = 0 - for ch in buffer: - if ch >= HIGH_BIT_SET: - break - pos = pos + 1 - else: - if pos > self.prefixLimit: - raise BananaError("Security precaution: more than %d bytes of prefix" % (self.prefixLimit,)) - return - num = buffer[:pos] - typebyte = buffer[pos] - rest = buffer[pos+1:] - if len(num) > self.prefixLimit: - raise BananaError("Security precaution: longer than %d bytes worth of prefix" % (self.prefixLimit,)) - if typebyte == LIST: - num = b1282int(num) - if num > SIZE_LIMIT: - raise BananaError("Security precaution: List too long.") - listStack.append((num, [])) - buffer = rest - elif typebyte == STRING: - num = b1282int(num) - if num > SIZE_LIMIT: - raise BananaError("Security precaution: String too long.") - if len(rest) >= num: - buffer = rest[num:] - gotItem(rest[:num]) - else: - return - elif typebyte == INT: - buffer = rest - num = b1282int(num) - gotItem(int(num)) - elif typebyte == LONGINT: - buffer = rest - num = b1282int(num) - gotItem(long(num)) - elif typebyte == LONGNEG: - buffer = rest - num = b1282int(num) - gotItem(-long(num)) - elif typebyte == NEG: - buffer = rest - num = -b1282int(num) - gotItem(num) - elif typebyte == VOCAB: - buffer = rest - num = b1282int(num) - gotItem(self.incomingVocabulary[num]) - elif typebyte == FLOAT: - if len(rest) >= 8: - buffer = rest[8:] - gotItem(struct.unpack("!d", rest[:8])[0]) - else: - return - else: - raise NotImplementedError(("Invalid Type Byte %r" % (typebyte,))) - while listStack and (len(listStack[-1][1]) == listStack[-1][0]): - item = listStack.pop()[1] - gotItem(item) - self.buffer = '' - - - def expressionReceived(self, lst): - """Called when an expression (list, string, or int) is received. - """ - raise NotImplementedError() - - - outgoingVocabulary = { - # Jelly Data Types - 'None' : 1, - 'class' : 2, - 'dereference' : 3, - 'reference' : 4, - 'dictionary' : 5, - 'function' : 6, - 'instance' : 7, - 'list' : 8, - 'module' : 9, - 'persistent' : 10, - 'tuple' : 11, - 'unpersistable' : 12, - - # PB Data Types - 'copy' : 13, - 'cache' : 14, - 'cached' : 15, - 'remote' : 16, - 'local' : 17, - 'lcache' : 18, - - # PB Protocol Messages - 'version' : 19, - 'login' : 20, - 'password' : 21, - 'challenge' : 22, - 'logged_in' : 23, - 'not_logged_in' : 24, - 'cachemessage' : 25, - 'message' : 26, - 'answer' : 27, - 'error' : 28, - 'decref' : 29, - 'decache' : 30, - 'uncache' : 31, - } - - incomingVocabulary = {} - for k, v in outgoingVocabulary.items(): - incomingVocabulary[v] = k - - def __init__(self, isClient=1): - self.listStack = [] - self.outgoingSymbols = copy.copy(self.outgoingVocabulary) - self.outgoingSymbolCount = 0 - self.isClient = isClient - - def sendEncoded(self, obj): - io = cStringIO.StringIO() - self._encode(obj, io.write) - value = io.getvalue() - self.transport.write(value) - - def _encode(self, obj, write): - if isinstance(obj, (list, tuple)): - if len(obj) > SIZE_LIMIT: - raise BananaError( - "list/tuple is too long to send (%d)" % (len(obj),)) - int2b128(len(obj), write) - write(LIST) - for elem in obj: - self._encode(elem, write) - elif isinstance(obj, (int, long)): - if obj < self._smallestLongInt or obj > self._largestLongInt: - raise BananaError( - "int/long is too large to send (%d)" % (obj,)) - if obj < self._smallestInt: - int2b128(-obj, write) - write(LONGNEG) - elif obj < 0: - int2b128(-obj, write) - write(NEG) - elif obj <= self._largestInt: - int2b128(obj, write) - write(INT) - else: - int2b128(obj, write) - write(LONGINT) - elif isinstance(obj, float): - write(FLOAT) - write(struct.pack("!d", obj)) - elif isinstance(obj, str): - # TODO: an API for extending banana... - if self.currentDialect == "pb" and obj in self.outgoingSymbols: - symbolID = self.outgoingSymbols[obj] - int2b128(symbolID, write) - write(VOCAB) - else: - if len(obj) > SIZE_LIMIT: - raise BananaError( - "string is too long to send (%d)" % (len(obj),)) - int2b128(len(obj), write) - write(STRING) - write(obj) - else: - raise BananaError("could not send object: %r" % (obj,)) - - -# For use from the interactive interpreter -_i = Banana() -_i.connectionMade() -_i._selectDialect("none") - - -def encode(lst): - """Encode a list s-expression.""" - io = cStringIO.StringIO() - _i.transport = io - _i.sendEncoded(lst) - return io.getvalue() - - -def decode(st): - """ - Decode a banana-encoded string. - """ - l = [] - _i.expressionReceived = l.append - try: - _i.dataReceived(st) - finally: - _i.buffer = '' - del _i.expressionReceived - return l[0] diff --git a/tools/buildbot/pylibs/twisted/spread/flavors.py b/tools/buildbot/pylibs/twisted/spread/flavors.py deleted file mode 100644 index f59f3fa..0000000 --- a/tools/buildbot/pylibs/twisted/spread/flavors.py +++ /dev/null @@ -1,603 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -This module represents flavors of remotely acessible objects. - -Currently this is only objects accessible through Perspective Broker, but will -hopefully encompass all forms of remote access which can emulate subsets of PB -(such as XMLRPC or SOAP). - -Future Plans: Optimization. Exploitation of new-style object model. -Optimizations to this module should not affect external-use semantics at all, -but may have a small impact on users who subclass and override methods. - -@author: U{Glyph Lefkowitz} -""" - -__version__ = "$Revision: 1.32 $"[11:-2] - -# NOTE: this module should NOT import pb; it is supposed to be a module which -# abstractly defines remotely accessible types. Many of these types expect to -# be serialized by Jelly, but they ought to be accessible through other -# mechanisms (like XMLRPC) - -# system imports -import sys -from zope.interface import implements, Interface - -# twisted imports -from twisted.python import log, reflect - -# sibling imports -from jelly import setUnjellyableForClass, setUnjellyableForClassTree, setUnjellyableFactoryForClass, unjellyableRegistry -from jelly import Jellyable, Unjellyable, _Dummy, _DummyNewStyle -from jelly import setInstanceState, getInstanceState - -# compatibility -setCopierForClass = setUnjellyableForClass -setCopierForClassTree = setUnjellyableForClassTree -setFactoryForClass = setUnjellyableFactoryForClass -copyTags = unjellyableRegistry - -copy_atom = "copy" -cache_atom = "cache" -cached_atom = "cached" -remote_atom = "remote" - - -class NoSuchMethod(AttributeError): - """Raised if there is no such remote method""" - - -class IPBRoot(Interface): - """Factory for root Referenceable objects for PB servers.""" - - def rootObject(broker): - """Return root Referenceable for broker.""" - - -class Serializable(Jellyable): - """An object that can be passed remotely. - - I am a style of object which can be serialized by Perspective - Broker. Objects which wish to be referenceable or copied remotely - have to subclass Serializable. However, clients of Perspective - Broker will probably not want to directly subclass Serializable; the - Flavors of transferable objects are listed below. - - What it means to be \"Serializable\" is that an object can be - passed to or returned from a remote method. Certain basic types - (dictionaries, lists, tuples, numbers, strings) are serializable by - default; however, classes need to choose a specific serialization - style: L{Referenceable}, L{Viewable}, L{Copyable} or L{Cacheable}. - - You may also pass C{[lists, dictionaries, tuples]} of L{Serializable} - instances to or return them from remote methods, as many levels deep - as you like. - """ - - def processUniqueID(self): - """Return an ID which uniquely represents this object for this process. - - By default, this uses the 'id' builtin, but can be overridden to - indicate that two values are identity-equivalent (such as proxies - for the same object). - """ - - return id(self) - -class Referenceable(Serializable): - perspective = None - """I am an object sent remotely as a direct reference. - - When one of my subclasses is sent as an argument to or returned - from a remote method call, I will be serialized by default as a - direct reference. - - This means that the peer will be able to call methods on me; - a method call xxx() from my peer will be resolved to methods - of the name remote_xxx. - """ - - def remoteMessageReceived(self, broker, message, args, kw): - """A remote message has been received. Dispatch it appropriately. - - The default implementation is to dispatch to a method called - 'remote_messagename' and call it with the same arguments. - """ - args = broker.unserialize(args) - kw = broker.unserialize(kw) - method = getattr(self, "remote_%s" % message, None) - if method is None: - raise NoSuchMethod("No such method: remote_%s" % (message,)) - try: - state = method(*args, **kw) - except TypeError: - log.msg("%s didn't accept %s and %s" % (method, args, kw)) - raise - return broker.serialize(state, self.perspective) - - def jellyFor(self, jellier): - """(internal) - - Return a tuple which will be used as the s-expression to - serialize this to a peer. - """ - - return "remote", jellier.invoker.registerReference(self) - - -class Root(Referenceable): - """I provide a root object to L{pb.Broker}s for a L{pb.BrokerFactory}. - - When a L{pb.BrokerFactory} produces a L{pb.Broker}, it supplies that - L{pb.Broker} with an object named \"root\". That object is obtained - by calling my rootObject method. - - See also: L{pb.getObjectAt} - """ - - implements(IPBRoot) - - def rootObject(self, broker): - """A L{pb.BrokerFactory} is requesting to publish me as a root object. - - When a L{pb.BrokerFactory} is sending me as the root object, this - method will be invoked to allow per-broker versions of an - object. By default I return myself. - """ - return self - - -class ViewPoint(Referenceable): - """ - I act as an indirect reference to an object accessed through a - L{pb.Perspective}. - - Simply put, I combine an object with a perspective so that when a - peer calls methods on the object I refer to, the method will be - invoked with that perspective as a first argument, so that it can - know who is calling it. - - While L{Viewable} objects will be converted to ViewPoints by default - when they are returned from or sent as arguments to a remote - method, any object may be manually proxied as well. (XXX: Now that - this class is no longer named C{Proxy}, this is the only occourance - of the term 'proxied' in this docstring, and may be unclear.) - - This can be useful when dealing with L{pb.Perspective}s, L{Copyable}s, - and L{Cacheable}s. It is legal to implement a method as such on - a perspective:: - - | def perspective_getViewPointForOther(self, name): - | defr = self.service.getPerspectiveRequest(name) - | defr.addCallbacks(lambda x, self=self: ViewPoint(self, x), log.msg) - | return defr - - This will allow you to have references to Perspective objects in two - different ways. One is through the initial 'attach' call -- each - peer will have a L{pb.RemoteReference} to their perspective directly. The - other is through this method; each peer can get a L{pb.RemoteReference} to - all other perspectives in the service; but that L{pb.RemoteReference} will - be to a L{ViewPoint}, not directly to the object. - - The practical offshoot of this is that you can implement 2 varieties - of remotely callable methods on this Perspective; view_xxx and - C{perspective_xxx}. C{view_xxx} methods will follow the rules for - ViewPoint methods (see ViewPoint.L{remoteMessageReceived}), and - C{perspective_xxx} methods will follow the rules for Perspective - methods. - """ - - def __init__(self, perspective, object): - """Initialize me with a Perspective and an Object. - """ - self.perspective = perspective - self.object = object - - def processUniqueID(self): - """Return an ID unique to a proxy for this perspective+object combination. - """ - return (id(self.perspective), id(self.object)) - - def remoteMessageReceived(self, broker, message, args, kw): - """A remote message has been received. Dispatch it appropriately. - - The default implementation is to dispatch to a method called - 'C{view_messagename}' to my Object and call it on my object with - the same arguments, modified by inserting my Perspective as - the first argument. - """ - args = broker.unserialize(args, self.perspective) - kw = broker.unserialize(kw, self.perspective) - method = getattr(self.object, "view_%s" % message) - try: - state = apply(method, (self.perspective,)+args, kw) - except TypeError: - log.msg("%s didn't accept %s and %s" % (method, args, kw)) - raise - rv = broker.serialize(state, self.perspective, method, args, kw) - return rv - - -class Viewable(Serializable): - """I will be converted to a L{ViewPoint} when passed to or returned from a remote method. - - The beginning of a peer's interaction with a PB Service is always - through a perspective. However, if a C{perspective_xxx} method returns - a Viewable, it will be serialized to the peer as a response to that - method. - """ - - def jellyFor(self, jellier): - """Serialize a L{ViewPoint} for me and the perspective of the given broker. - """ - return ViewPoint(jellier.invoker.serializingPerspective, self).jellyFor(jellier) - - - -class Copyable(Serializable): - """Subclass me to get copied each time you are returned from or passed to a remote method. - - When I am returned from or passed to a remote method call, I will be - converted into data via a set of callbacks (see my methods for more - info). That data will then be serialized using Jelly, and sent to - the peer. - - The peer will then look up the type to represent this with; see - L{RemoteCopy} for details. - """ - - def getStateToCopy(self): - """Gather state to send when I am serialized for a peer. - - I will default to returning self.__dict__. Override this to - customize this behavior. - """ - - return self.__dict__ - - def getStateToCopyFor(self, perspective): - """ - Gather state to send when I am serialized for a particular - perspective. - - I will default to calling L{getStateToCopy}. Override this to - customize this behavior. - """ - - return self.getStateToCopy() - - def getTypeToCopy(self): - """Determine what type tag to send for me. - - By default, send the string representation of my class - (package.module.Class); normally this is adequate, but - you may override this to change it. - """ - - return reflect.qual(self.__class__) - - def getTypeToCopyFor(self, perspective): - """Determine what type tag to send for me. - - By default, defer to self.L{getTypeToCopy}() normally this is - adequate, but you may override this to change it. - """ - - return self.getTypeToCopy() - - def jellyFor(self, jellier): - """Assemble type tag and state to copy for this broker. - - This will call L{getTypeToCopyFor} and L{getStateToCopy}, and - return an appropriate s-expression to represent me. - """ - - if jellier.invoker is None: - return getInstanceState(self, jellier) - p = jellier.invoker.serializingPerspective - t = self.getTypeToCopyFor(p) - state = self.getStateToCopyFor(p) - sxp = jellier.prepare(self) - sxp.extend([t, jellier.jelly(state)]) - return jellier.preserve(self, sxp) - - -class Cacheable(Copyable): - """A cached instance. - - This means that it's copied; but there is some logic to make sure - that it's only copied once. Additionally, when state is retrieved, - it is passed a "proto-reference" to the state as it will exist on - the client. - - XXX: The documentation for this class needs work, but it's the most - complex part of PB and it is inherently difficult to explain. - """ - - def getStateToCacheAndObserveFor(self, perspective, observer): - """ - Get state to cache on the client and client-cache reference - to observe locally. - - This is similiar to getStateToCopyFor, but it additionally - passes in a reference to the client-side RemoteCache instance - that will be created when it is unserialized. This allows - Cacheable instances to keep their RemoteCaches up to date when - they change, such that no changes can occur between the point - at which the state is initially copied and the client receives - it that are not propogated. - """ - - return self.getStateToCopyFor(perspective) - - def jellyFor(self, jellier): - """Return an appropriate tuple to serialize me. - - Depending on whether this broker has cached me or not, this may - return either a full state or a reference to an existing cache. - """ - if jellier.invoker is None: - return getInstanceState(self, jellier) - luid = jellier.invoker.cachedRemotelyAs(self, 1) - if luid is None: - luid = jellier.invoker.cacheRemotely(self) - p = jellier.invoker.serializingPerspective - type_ = self.getTypeToCopyFor(p) - observer = RemoteCacheObserver(jellier.invoker, self, p) - state = self.getStateToCacheAndObserveFor(p, observer) - l = jellier.prepare(self) - jstate = jellier.jelly(state) - l.extend([type_, luid, jstate]) - return jellier.preserve(self, l) - else: - return cached_atom, luid - - def stoppedObserving(self, perspective, observer): - """This method is called when a client has stopped observing me. - - The 'observer' argument is the same as that passed in to - getStateToCacheAndObserveFor. - """ - - - -class RemoteCopy(Unjellyable): - """I am a remote copy of a Copyable object. - - When the state from a L{Copyable} object is received, an instance will - be created based on the copy tags table (see setUnjellyableForClass) and - sent the L{setCopyableState} message. I provide a reasonable default - implementation of that message; subclass me if you wish to serve as - a copier for remote data. - - NOTE: copiers are invoked with no arguments. Do not implement a - constructor which requires args in a subclass of L{RemoteCopy}! - """ - - def setCopyableState(self, state): - """I will be invoked with the state to copy locally. - - 'state' is the data returned from the remote object's - 'getStateToCopyFor' method, which will often be the remote - object's dictionary (or a filtered approximation of it depending - on my peer's perspective). - """ - - self.__dict__ = state - - def unjellyFor(self, unjellier, jellyList): - if unjellier.invoker is None: - return setInstanceState(self, unjellier, jellyList) - self.setCopyableState(unjellier.unjelly(jellyList[1])) - return self - - - -class RemoteCache(RemoteCopy, Serializable): - """A cache is a local representation of a remote L{Cacheable} object. - - This represents the last known state of this object. It may - also have methods invoked on it -- in order to update caches, - the cached class generates a L{pb.RemoteReference} to this object as - it is originally sent. - - Much like copy, I will be invoked with no arguments. Do not - implement a constructor that requires arguments in one of my - subclasses. - """ - - def remoteMessageReceived(self, broker, message, args, kw): - """A remote message has been received. Dispatch it appropriately. - - The default implementation is to dispatch to a method called - 'C{observe_messagename}' and call it on my with the same arguments. - """ - - args = broker.unserialize(args) - kw = broker.unserialize(kw) - method = getattr(self, "observe_%s" % message) - try: - state = apply(method, args, kw) - except TypeError: - log.msg("%s didn't accept %s and %s" % (method, args, kw)) - raise - return broker.serialize(state, None, method, args, kw) - - def jellyFor(self, jellier): - """serialize me (only for the broker I'm for) as the original cached reference - """ - if jellier.invoker is None: - return getInstanceState(self, jellier) - assert jellier.invoker is self.broker, "You cannot exchange cached proxies between brokers." - return 'lcache', self.luid - - - def unjellyFor(self, unjellier, jellyList): - if unjellier.invoker is None: - return setInstanceState(self, unjellier, jellyList) - self.broker = unjellier.invoker - self.luid = jellyList[1] - if isinstance(self.__class__, type): #new-style class - cProxy = _DummyNewStyle() - else: - cProxy = _Dummy() - cProxy.__class__ = self.__class__ - cProxy.__dict__ = self.__dict__ - # XXX questionable whether this was a good design idea... - init = getattr(cProxy, "__init__", None) - if init: - init() - unjellier.invoker.cacheLocally(jellyList[1], self) - cProxy.setCopyableState(unjellier.unjelly(jellyList[2])) - # Might have changed due to setCopyableState method; we'll assume that - # it's bad form to do so afterwards. - self.__dict__ = cProxy.__dict__ - # chomp, chomp -- some existing code uses "self.__dict__ =", some uses - # "__dict__.update". This is here in order to handle both cases. - self.broker = unjellier.invoker - self.luid = jellyList[1] - return cProxy - -## def __really_del__(self): -## """Final finalization call, made after all remote references have been lost. -## """ - - def __cmp__(self, other): - """Compare me [to another RemoteCache. - """ - if isinstance(other, self.__class__): - return cmp(id(self.__dict__), id(other.__dict__)) - else: - return cmp(id(self.__dict__), other) - - def __hash__(self): - """Hash me. - """ - return int(id(self.__dict__) % sys.maxint) - - broker = None - luid = None - - def __del__(self): - """Do distributed reference counting on finalize. - """ - try: - # log.msg( ' --- decache: %s %s' % (self, self.luid) ) - if self.broker: - self.broker.decCacheRef(self.luid) - except: - log.deferr() - -def unjellyCached(unjellier, unjellyList): - luid = unjellyList[1] - cNotProxy = unjellier.invoker.cachedLocallyAs(luid) - - cProxy = _Dummy() - cProxy.__class__ = cNotProxy.__class__ - cProxy.__dict__ = cNotProxy.__dict__ - return cProxy - -setUnjellyableForClass("cached", unjellyCached) - -def unjellyLCache(unjellier, unjellyList): - luid = unjellyList[1] - obj = unjellier.invoker.remotelyCachedForLUID(luid) - return obj - -setUnjellyableForClass("lcache", unjellyLCache) - -def unjellyLocal(unjellier, unjellyList): - obj = unjellier.invoker.localObjectForID(unjellyList[1]) - return obj - -setUnjellyableForClass("local", unjellyLocal) - -class RemoteCacheMethod: - """A method on a reference to a L{RemoteCache}. - """ - - def __init__(self, name, broker, cached, perspective): - """(internal) initialize. - """ - self.name = name - self.broker = broker - self.perspective = perspective - self.cached = cached - - def __cmp__(self, other): - return cmp((self.name, self.broker, self.perspective, self.cached), other) - - def __hash__(self): - return hash((self.name, self.broker, self.perspective, self.cached)) - - def __call__(self, *args, **kw): - """(internal) action method. - """ - cacheID = self.broker.cachedRemotelyAs(self.cached) - if cacheID is None: - from pb import ProtocolError - raise ProtocolError("You can't call a cached method when the object hasn't been given to the peer yet.") - return self.broker._sendMessage('cache', self.perspective, cacheID, self.name, args, kw) - -class RemoteCacheObserver: - """I am a reverse-reference to the peer's L{RemoteCache}. - - I am generated automatically when a cache is serialized. I - represent a reference to the client's L{RemoteCache} object that - will represent a particular L{Cacheable}; I am the additional - object passed to getStateToCacheAndObserveFor. - """ - - def __init__(self, broker, cached, perspective): - """(internal) Initialize me. - - @param broker: a L{pb.Broker} instance. - - @param cached: a L{Cacheable} instance that this L{RemoteCacheObserver} - corresponds to. - - @param perspective: a reference to the perspective who is observing this. - """ - - self.broker = broker - self.cached = cached - self.perspective = perspective - - def __repr__(self): - return "" % ( - self.broker, self.cached, self.perspective, id(self)) - - def __hash__(self): - """Generate a hash unique to all L{RemoteCacheObserver}s for this broker/perspective/cached triplet - """ - - return ( (hash(self.broker) % 2**10) - + (hash(self.perspective) % 2**10) - + (hash(self.cached) % 2**10)) - - def __cmp__(self, other): - """Compare me to another L{RemoteCacheObserver}. - """ - - return cmp((self.broker, self.perspective, self.cached), other) - - def callRemote(self, _name, *args, **kw): - """(internal) action method. - """ - cacheID = self.broker.cachedRemotelyAs(self.cached) - if cacheID is None: - from pb import ProtocolError - raise ProtocolError("You can't call a cached method when the " - "object hasn't been given to the peer yet.") - return self.broker._sendMessage('cache', self.perspective, cacheID, - _name, args, kw) - - def remoteMethod(self, key): - """Get a L{pb.RemoteMethod} for this key. - """ - return RemoteCacheMethod(key, self.broker, self.cached, self.perspective) diff --git a/tools/buildbot/pylibs/twisted/spread/interfaces.py b/tools/buildbot/pylibs/twisted/spread/interfaces.py deleted file mode 100644 index 6d48d00..0000000 --- a/tools/buildbot/pylibs/twisted/spread/interfaces.py +++ /dev/null @@ -1,28 +0,0 @@ -""" -Twisted Spread Interfaces. - -This module is unused so far. It's also undecided whether this module -will remain monolithic. -""" - -from zope.interface import Interface - -class IJellyable(Interface): - def jellyFor(jellier): - """ - Jelly myself for jellier. - """ - -class IUnjellyable(Interface): - def unjellyFor(jellier, jellyList): - """ - Unjelly myself for the jellier. - - @param jellier: A stateful object which exists for the lifetime of a - single call to L{unjelly}. - - @param jellyList: The C{list} which represents the jellied state of the - object to be unjellied. - - @return: The object which results from unjellying. - """ diff --git a/tools/buildbot/pylibs/twisted/spread/jelly.py b/tools/buildbot/pylibs/twisted/spread/jelly.py deleted file mode 100644 index 25602b8..0000000 --- a/tools/buildbot/pylibs/twisted/spread/jelly.py +++ /dev/null @@ -1,1136 +0,0 @@ -# -*- test-case-name: twisted.test.test_jelly -*- - -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -S-expression-based persistence of python objects. - -It does something very much like L{Pickle}; however, pickle's main goal -seems to be efficiency (both in space and time); jelly's main goals are -security, human readability, and portability to other environments. - -This is how Jelly converts various objects to s-expressions. - -Boolean:: - True --> ['boolean', 'true'] - -Integer:: - 1 --> 1 - -List:: - [1, 2] --> ['list', 1, 2] - -String:: - \"hello\" --> \"hello\" - -Float:: - 2.3 --> 2.3 - -Dictionary:: - {'a': 1, 'b': 'c'} --> ['dictionary', ['b', 'c'], ['a', 1]] - -Module:: - UserString --> ['module', 'UserString'] - -Class:: - UserString.UserString --> ['class', ['module', 'UserString'], 'UserString'] - -Function:: - string.join --> ['function', 'join', ['module', 'string']] - -Instance: s is an instance of UserString.UserString, with a __dict__ -{'data': 'hello'}:: - [\"UserString.UserString\", ['dictionary', ['data', 'hello']]] - -Class Method: UserString.UserString.center:: - ['method', 'center', ['None'], ['class', ['module', 'UserString'], - 'UserString']] - -Instance Method: s.center, where s is an instance of UserString.UserString:: - ['method', 'center', ['instance', ['reference', 1, ['class', - ['module', 'UserString'], 'UserString']], ['dictionary', ['data', 'd']]], - ['dereference', 1]] - -The C{set} builtin and the C{sets.Set} class are serialized to the same -thing, and unserialized to C{set} if available, else to C{sets.Set}. It means -that there's a possibility of type switching in the serialization process. The -solution is to always use C{set} if possible, and only use C{sets.Set} under -Python 2.3; this can be accomplished by using L{twisted.python.compat.set}. - -The same rule applies for C{frozenset} and C{sets.ImmutableSet}. - -@author: U{Glyph Lefkowitz} -""" - -__version__ = "$Revision: 1.48 $"[11:-2] - -# System Imports -import pickle -import types -import warnings -from types import StringType -from types import UnicodeType -from types import IntType -from types import TupleType -from types import ListType -from types import LongType -from types import FloatType -from types import FunctionType -from types import MethodType -from types import ModuleType -from types import DictionaryType -from types import InstanceType -from types import NoneType -from types import ClassType -import copy - -import datetime -from types import BooleanType - -try: - import decimal -except ImportError: - decimal = None - -try: - _set = set -except NameError: - _set = None - -try: - # Filter out deprecation warning for Python >= 2.6 - warnings.filterwarnings("ignore", category=DeprecationWarning, - message="the sets module is deprecated", append=True) - import sets as _sets -finally: - warnings.filters.pop() - - -from new import instance -from new import instancemethod -from zope.interface import implements - -# Twisted Imports -from twisted.python.reflect import namedObject, qual -from twisted.persisted.crefutil import NotKnown, _Tuple, _InstanceMethod -from twisted.persisted.crefutil import _DictKeyAndValue, _Dereference -from twisted.persisted.crefutil import _Container -from twisted.python import runtime - -from twisted.spread.interfaces import IJellyable, IUnjellyable - - -if runtime.platform.getType() == "java": - from org.python.core import PyStringMap - DictTypes = (DictionaryType, PyStringMap) -else: - DictTypes = (DictionaryType,) - - -None_atom = "None" # N -# code -class_atom = "class" # c -module_atom = "module" # m -function_atom = "function" # f - -# references -dereference_atom = 'dereference' # D -persistent_atom = 'persistent' # p -reference_atom = 'reference' # r - -# mutable collections -dictionary_atom = "dictionary" # d -list_atom = 'list' # l -set_atom = 'set' - -# immutable collections -# (assignment to __dict__ and __class__ still might go away!) -tuple_atom = "tuple" # t -instance_atom = 'instance' # i -frozenset_atom = 'frozenset' - - -# errors -unpersistable_atom = "unpersistable"# u -unjellyableRegistry = {} -unjellyableFactoryRegistry = {} - - - -def _newInstance(cls, state): - """ - Make a new instance of a class without calling its __init__ method. - 'state' will be used to update inst.__dict__ . Supports both new- and - old-style classes. - """ - if not isinstance(cls, types.ClassType): - # new-style - inst = cls.__new__(cls) - inst.__dict__.update(state) # Copy 'instance' behaviour - else: - inst = instance(cls, state) - return inst - - - -def _maybeClass(classnamep): - try: - object - except NameError: - isObject = 0 - else: - isObject = isinstance(classnamep, type) - if isinstance(classnamep, ClassType) or isObject: - return qual(classnamep) - return classnamep - - - -def setUnjellyableForClass(classname, unjellyable): - """ - Set which local class will represent a remote type. - - If you have written a Copyable class that you expect your client to be - receiving, write a local "copy" class to represent it, then call:: - - jellier.setUnjellyableForClass('module.package.Class', MyJellier). - - Call this at the module level immediately after its class - definition. MyCopier should be a subclass of RemoteCopy. - - The classname may be a special tag returned by - 'Copyable.getTypeToCopyFor' rather than an actual classname. - - This call is also for cached classes, since there will be no - overlap. The rules are the same. - """ - - global unjellyableRegistry - classname = _maybeClass(classname) - unjellyableRegistry[classname] = unjellyable - globalSecurity.allowTypes(classname) - - - -def setUnjellyableFactoryForClass(classname, copyFactory): - """ - Set the factory to construct a remote instance of a type:: - - jellier.setFactoryForClass('module.package.Class', MyFactory) - - Call this at the module level immediately after its class definition. - C{copyFactory} should return an instance or subclass of - L{RemoteCopy}. - - Similar to L{setUnjellyableForClass} except it uses a factory instead - of creating an instance. - """ - - global unjellyableFactoryRegistry - classname = _maybeClass(classname) - unjellyableFactoryRegistry[classname] = copyFactory - globalSecurity.allowTypes(classname) - - - -def setUnjellyableForClassTree(module, baseClass, prefix=None): - """ - Set all classes in a module derived from C{baseClass} as copiers for - a corresponding remote class. - - When you have a heirarchy of Copyable (or Cacheable) classes on - one side, and a mirror structure of Copied (or RemoteCache) - classes on the other, use this to setCopierForClass all your - Copieds for the Copyables. - - Each copyTag (the \"classname\" argument to getTypeToCopyFor, and - what the Copyable's getTypeToCopyFor returns) is formed from - adding a prefix to the Copied's class name. The prefix defaults - to module.__name__. If you wish the copy tag to consist of solely - the classname, pass the empty string \'\'. - - @param module: a module object from which to pull the Copied classes. - (passing sys.modules[__name__] might be useful) - - @param baseClass: the base class from which all your Copied classes derive. - - @param prefix: the string prefixed to classnames to form the - unjellyableRegistry. - """ - if prefix is None: - prefix = module.__name__ - - if prefix: - prefix = "%s." % prefix - - for i in dir(module): - i_ = getattr(module, i) - if type(i_) == types.ClassType: - if issubclass(i_, baseClass): - setUnjellyableForClass('%s%s' % (prefix, i), i_) - - - -def getInstanceState(inst, jellier): - """ - Utility method to default to 'normal' state rules in serialization. - """ - if hasattr(inst, "__getstate__"): - state = inst.__getstate__() - else: - state = inst.__dict__ - sxp = jellier.prepare(inst) - sxp.extend([qual(inst.__class__), jellier.jelly(state)]) - return jellier.preserve(inst, sxp) - - - -def setInstanceState(inst, unjellier, jellyList): - """ - Utility method to default to 'normal' state rules in unserialization. - """ - state = unjellier.unjelly(jellyList[1]) - if hasattr(inst, "__setstate__"): - inst.__setstate__(state) - else: - inst.__dict__ = state - return inst - - - -class Unpersistable: - """ - This is an instance of a class that comes back when something couldn't be - unpersisted. - """ - - def __init__(self, reason): - """ - Initialize an unpersistable object with a descriptive C{reason} string. - """ - self.reason = reason - - - def __repr__(self): - return "Unpersistable(%s)" % repr(self.reason) - - - -class Jellyable: - """ - Inherit from me to Jelly yourself directly with the `getStateFor' - convenience method. - """ - implements(IJellyable) - - def getStateFor(self, jellier): - return self.__dict__ - - - def jellyFor(self, jellier): - """ - @see: L{twisted.spread.interfaces.IJellyable.jellyFor} - """ - sxp = jellier.prepare(self) - sxp.extend([ - qual(self.__class__), - jellier.jelly(self.getStateFor(jellier))]) - return jellier.preserve(self, sxp) - - - -class Unjellyable: - """ - Inherit from me to Unjelly yourself directly with the - C{setStateFor} convenience method. - """ - implements(IUnjellyable) - - def setStateFor(self, unjellier, state): - self.__dict__ = state - - - def unjellyFor(self, unjellier, jellyList): - """ - Perform the inverse operation of L{Jellyable.jellyFor}. - - @see: L{twisted.spread.interfaces.IUnjellyable.unjellyFor} - """ - state = unjellier.unjelly(jellyList[1]) - self.setStateFor(unjellier, state) - return self - - - -class _Jellier: - """ - (Internal) This class manages state for a call to jelly() - """ - - def __init__(self, taster, persistentStore, invoker): - """ - Initialize. - """ - self.taster = taster - # `preserved' is a dict of previously seen instances. - self.preserved = {} - # `cooked' is a dict of previously backreferenced instances to their - # `ref' lists. - self.cooked = {} - self.cooker = {} - self._ref_id = 1 - self.persistentStore = persistentStore - self.invoker = invoker - - - def _cook(self, object): - """ - (internal) Backreference an object. - - Notes on this method for the hapless future maintainer: If I've already - gone through the prepare/preserve cycle on the specified object (it is - being referenced after the serializer is \"done with\" it, e.g. this - reference is NOT circular), the copy-in-place of aList is relevant, - since the list being modified is the actual, pre-existing jelly - expression that was returned for that object. If not, it's technically - superfluous, since the value in self.preserved didn't need to be set, - but the invariant that self.preserved[id(object)] is a list is - convenient because that means we don't have to test and create it or - not create it here, creating fewer code-paths. that's why - self.preserved is always set to a list. - - Sorry that this code is so hard to follow, but Python objects are - tricky to persist correctly. -glyph - """ - aList = self.preserved[id(object)] - newList = copy.copy(aList) - # make a new reference ID - refid = self._ref_id - self._ref_id = self._ref_id + 1 - # replace the old list in-place, so that we don't have to track the - # previous reference to it. - aList[:] = [reference_atom, refid, newList] - self.cooked[id(object)] = [dereference_atom, refid] - return aList - - - def prepare(self, object): - """ - (internal) Create a list for persisting an object to. This will allow - backreferences to be made internal to the object. (circular - references). - - The reason this needs to happen is that we don't generate an ID for - every object, so we won't necessarily know which ID the object will - have in the future. When it is 'cooked' ( see _cook ), it will be - assigned an ID, and the temporary placeholder list created here will be - modified in-place to create an expression that gives this object an ID: - [reference id# [object-jelly]]. - """ - - # create a placeholder list to be preserved - self.preserved[id(object)] = [] - # keep a reference to this object around, so it doesn't disappear! - # (This isn't always necessary, but for cases where the objects are - # dynamically generated by __getstate__ or getStateToCopyFor calls, it - # is; id() will return the same value for a different object if it gets - # garbage collected. This may be optimized later.) - self.cooker[id(object)] = object - return [] - - - def preserve(self, object, sexp): - """ - (internal) Mark an object's persistent list for later referral. - """ - # if I've been cooked in the meanwhile, - if id(object) in self.cooked: - # replace the placeholder empty list with the real one - self.preserved[id(object)][2] = sexp - # but give this one back. - sexp = self.preserved[id(object)] - else: - self.preserved[id(object)] = sexp - return sexp - - constantTypes = {types.StringType : 1, types.IntType : 1, - types.FloatType : 1, types.LongType : 1} - - - def _checkMutable(self,obj): - objId = id(obj) - if objId in self.cooked: - return self.cooked[objId] - if objId in self.preserved: - self._cook(obj) - return self.cooked[objId] - - - def jelly(self, obj): - if isinstance(obj, Jellyable): - preRef = self._checkMutable(obj) - if preRef: - return preRef - return obj.jellyFor(self) - objType = type(obj) - if self.taster.isTypeAllowed(qual(objType)): - # "Immutable" Types - if ((objType is StringType) or - (objType is IntType) or - (objType is LongType) or - (objType is FloatType)): - return obj - elif objType is MethodType: - return ["method", - obj.im_func.__name__, - self.jelly(obj.im_self), - self.jelly(obj.im_class)] - - elif UnicodeType and objType is UnicodeType: - return ['unicode', obj.encode('UTF-8')] - elif objType is NoneType: - return ['None'] - elif objType is FunctionType: - name = obj.__name__ - return ['function', str(pickle.whichmodule(obj, obj.__name__)) - + '.' + - name] - elif objType is ModuleType: - return ['module', obj.__name__] - elif objType is BooleanType: - return ['boolean', obj and 'true' or 'false'] - elif objType is datetime.datetime: - if obj.tzinfo: - raise NotImplementedError( - "Currently can't jelly datetime objects with tzinfo") - return ['datetime', '%s %s %s %s %s %s %s' % ( - obj.year, obj.month, obj.day, obj.hour, - obj.minute, obj.second, obj.microsecond)] - elif objType is datetime.time: - if obj.tzinfo: - raise NotImplementedError( - "Currently can't jelly datetime objects with tzinfo") - return ['time', '%s %s %s %s' % (obj.hour, obj.minute, - obj.second, obj.microsecond)] - elif objType is datetime.date: - return ['date', '%s %s %s' % (obj.year, obj.month, obj.day)] - elif objType is datetime.timedelta: - return ['timedelta', '%s %s %s' % (obj.days, obj.seconds, - obj.microseconds)] - elif objType is ClassType or issubclass(objType, type): - return ['class', qual(obj)] - elif decimal is not None and objType is decimal.Decimal: - return self.jelly_decimal(obj) - else: - preRef = self._checkMutable(obj) - if preRef: - return preRef - # "Mutable" Types - sxp = self.prepare(obj) - if objType is ListType: - sxp.extend(self._jellyIterable(list_atom, obj)) - elif objType is TupleType: - sxp.extend(self._jellyIterable(tuple_atom, obj)) - elif objType in DictTypes: - sxp.append(dictionary_atom) - for key, val in obj.items(): - sxp.append([self.jelly(key), self.jelly(val)]) - elif (_set is not None and objType is set or - objType is _sets.Set): - sxp.extend(self._jellyIterable(set_atom, obj)) - elif (_set is not None and objType is frozenset or - objType is _sets.ImmutableSet): - sxp.extend(self._jellyIterable(frozenset_atom, obj)) - else: - className = qual(obj.__class__) - persistent = None - if self.persistentStore: - persistent = self.persistentStore(obj, self) - if persistent is not None: - sxp.append(persistent_atom) - sxp.append(persistent) - elif self.taster.isClassAllowed(obj.__class__): - sxp.append(className) - if hasattr(obj, "__getstate__"): - state = obj.__getstate__() - else: - state = obj.__dict__ - sxp.append(self.jelly(state)) - else: - self.unpersistable( - "instance of class %s deemed insecure" % - qual(obj.__class__), sxp) - return self.preserve(obj, sxp) - else: - if objType is InstanceType: - raise InsecureJelly("Class not allowed for instance: %s %s" % - (obj.__class__, obj)) - raise InsecureJelly("Type not allowed for object: %s %s" % - (objType, obj)) - - - def _jellyIterable(self, atom, obj): - """ - Jelly an iterable object. - - @param atom: the identifier atom of the object. - @type atom: C{str} - - @param obj: any iterable object. - @type obj: C{iterable} - - @return: a generator of jellied data. - @rtype: C{generator} - """ - yield atom - for item in obj: - yield self.jelly(item) - - - def jelly_decimal(self, d): - """ - Jelly a decimal object. - - @param d: a decimal object to serialize. - @type d: C{decimal.Decimal} - - @return: jelly for the decimal object. - @rtype: C{list} - """ - sign, guts, exponent = d.as_tuple() - value = reduce(lambda left, right: left * 10 + right, guts) - if sign: - value = -value - return ['decimal', value, exponent] - - - def unpersistable(self, reason, sxp=None): - """ - (internal) Returns an sexp: (unpersistable "reason"). Utility method - for making note that a particular object could not be serialized. - """ - if sxp is None: - sxp = [] - sxp.append(unpersistable_atom) - sxp.append(reason) - return sxp - - - -class _Unjellier: - - def __init__(self, taster, persistentLoad, invoker): - self.taster = taster - self.persistentLoad = persistentLoad - self.references = {} - self.postCallbacks = [] - self.invoker = invoker - - - def unjellyFull(self, obj): - o = self.unjelly(obj) - for m in self.postCallbacks: - m() - return o - - - def unjelly(self, obj): - if type(obj) is not types.ListType: - return obj - jelType = obj[0] - if not self.taster.isTypeAllowed(jelType): - raise InsecureJelly(jelType) - regClass = unjellyableRegistry.get(jelType) - if regClass is not None: - if isinstance(regClass, ClassType): - inst = _Dummy() # XXX chomp, chomp - inst.__class__ = regClass - method = inst.unjellyFor - elif isinstance(regClass, type): - # regClass.__new__ does not call regClass.__init__ - inst = regClass.__new__(regClass) - method = inst.unjellyFor - else: - method = regClass # this is how it ought to be done - val = method(self, obj) - if hasattr(val, 'postUnjelly'): - self.postCallbacks.append(inst.postUnjelly) - return val - regFactory = unjellyableFactoryRegistry.get(jelType) - if regFactory is not None: - state = self.unjelly(obj[1]) - inst = regFactory(state) - if hasattr(inst, 'postUnjelly'): - self.postCallbacks.append(inst.postUnjelly) - return inst - thunk = getattr(self, '_unjelly_%s'%jelType, None) - if thunk is not None: - ret = thunk(obj[1:]) - else: - nameSplit = jelType.split('.') - modName = '.'.join(nameSplit[:-1]) - if not self.taster.isModuleAllowed(modName): - raise InsecureJelly( - "Module %s not allowed (in type %s)." % (modName, jelType)) - clz = namedObject(jelType) - if not self.taster.isClassAllowed(clz): - raise InsecureJelly("Class %s not allowed." % jelType) - if hasattr(clz, "__setstate__"): - ret = _newInstance(clz, {}) - state = self.unjelly(obj[1]) - ret.__setstate__(state) - else: - state = self.unjelly(obj[1]) - ret = _newInstance(clz, state) - if hasattr(clz, 'postUnjelly'): - self.postCallbacks.append(ret.postUnjelly) - return ret - - - def _unjelly_None(self, exp): - return None - - - def _unjelly_unicode(self, exp): - if UnicodeType: - return unicode(exp[0], "UTF-8") - else: - return Unpersistable("Could not unpersist unicode: %s" % (exp[0],)) - - - def _unjelly_decimal(self, exp): - """ - Unjelly decimal objects, if decimal is available. If not, return a - L{Unpersistable} object instead. - """ - if decimal is None: - return Unpersistable( - "Could not unpersist decimal: %s" % (exp[0] * (10**exp[1]),)) - value = exp[0] - exponent = exp[1] - if value < 0: - sign = 1 - else: - sign = 0 - guts = decimal.Decimal(value).as_tuple()[1] - return decimal.Decimal((sign, guts, exponent)) - - - def _unjelly_boolean(self, exp): - if BooleanType: - assert exp[0] in ('true', 'false') - return exp[0] == 'true' - else: - return Unpersistable("Could not unpersist boolean: %s" % (exp[0],)) - - - def _unjelly_datetime(self, exp): - return datetime.datetime(*map(int, exp[0].split())) - - - def _unjelly_date(self, exp): - return datetime.date(*map(int, exp[0].split())) - - - def _unjelly_time(self, exp): - return datetime.time(*map(int, exp[0].split())) - - - def _unjelly_timedelta(self, exp): - days, seconds, microseconds = map(int, exp[0].split()) - return datetime.timedelta( - days=days, seconds=seconds, microseconds=microseconds) - - - def unjellyInto(self, obj, loc, jel): - o = self.unjelly(jel) - if isinstance(o, NotKnown): - o.addDependant(obj, loc) - obj[loc] = o - return o - - - def _unjelly_dereference(self, lst): - refid = lst[0] - x = self.references.get(refid) - if x is not None: - return x - der = _Dereference(refid) - self.references[refid] = der - return der - - - def _unjelly_reference(self, lst): - refid = lst[0] - exp = lst[1] - o = self.unjelly(exp) - ref = self.references.get(refid) - if (ref is None): - self.references[refid] = o - elif isinstance(ref, NotKnown): - ref.resolveDependants(o) - self.references[refid] = o - else: - assert 0, "Multiple references with same ID!" - return o - - - def _unjelly_tuple(self, lst): - l = range(len(lst)) - finished = 1 - for elem in l: - if isinstance(self.unjellyInto(l, elem, lst[elem]), NotKnown): - finished = 0 - if finished: - return tuple(l) - else: - return _Tuple(l) - - - def _unjelly_list(self, lst): - l = range(len(lst)) - for elem in l: - self.unjellyInto(l, elem, lst[elem]) - return l - - - def _unjellySetOrFrozenset(self, lst, containerType): - """ - Helper method to unjelly set or frozenset. - - @param lst: the content of the set. - @type lst: C{list} - - @param containerType: the type of C{set} to use. - """ - l = range(len(lst)) - finished = True - for elem in l: - data = self.unjellyInto(l, elem, lst[elem]) - if isinstance(data, NotKnown): - finished = False - if not finished: - return _Container(l, containerType) - else: - return containerType(l) - - - def _unjelly_set(self, lst): - """ - Unjelly set using either the C{set} builtin if available, or - C{sets.Set} as fallback. - """ - if _set is not None: - containerType = set - else: - containerType = _sets.Set - return self._unjellySetOrFrozenset(lst, containerType) - - - def _unjelly_frozenset(self, lst): - """ - Unjelly frozenset using either the C{frozenset} builtin if available, - or C{sets.ImmutableSet} as fallback. - """ - if _set is not None: - containerType = frozenset - else: - containerType = _sets.ImmutableSet - return self._unjellySetOrFrozenset(lst, containerType) - - - def _unjelly_dictionary(self, lst): - d = {} - for k, v in lst: - kvd = _DictKeyAndValue(d) - self.unjellyInto(kvd, 0, k) - self.unjellyInto(kvd, 1, v) - return d - - - def _unjelly_module(self, rest): - moduleName = rest[0] - if type(moduleName) != types.StringType: - raise InsecureJelly( - "Attempted to unjelly a module with a non-string name.") - if not self.taster.isModuleAllowed(moduleName): - raise InsecureJelly( - "Attempted to unjelly module named %r" % (moduleName,)) - mod = __import__(moduleName, {}, {},"x") - return mod - - - def _unjelly_class(self, rest): - clist = rest[0].split('.') - modName = '.'.join(clist[:-1]) - if not self.taster.isModuleAllowed(modName): - raise InsecureJelly("module %s not allowed" % modName) - klaus = namedObject(rest[0]) - if type(klaus) is not types.ClassType: - raise InsecureJelly( - "class %r unjellied to something that isn't a class: %r" % ( - rest[0], klaus)) - if not self.taster.isClassAllowed(klaus): - raise InsecureJelly("class not allowed: %s" % qual(klaus)) - return klaus - - - def _unjelly_function(self, rest): - modSplit = rest[0].split('.') - modName = '.'.join(modSplit[:-1]) - if not self.taster.isModuleAllowed(modName): - raise InsecureJelly("Module not allowed: %s"% modName) - # XXX do I need an isFunctionAllowed? - function = namedObject(rest[0]) - return function - - - def _unjelly_persistent(self, rest): - if self.persistentLoad: - pload = self.persistentLoad(rest[0], self) - return pload - else: - return Unpersistable("Persistent callback not found") - - - def _unjelly_instance(self, rest): - clz = self.unjelly(rest[0]) - if type(clz) is not types.ClassType: - raise InsecureJelly("Instance found with non-class class.") - if hasattr(clz, "__setstate__"): - inst = _newInstance(clz, {}) - state = self.unjelly(rest[1]) - inst.__setstate__(state) - else: - state = self.unjelly(rest[1]) - inst = _newInstance(clz, state) - if hasattr(clz, 'postUnjelly'): - self.postCallbacks.append(inst.postUnjelly) - return inst - - - def _unjelly_unpersistable(self, rest): - return Unpersistable("Unpersistable data: %s" % (rest[0],)) - - - def _unjelly_method(self, rest): - """ - (internal) Unjelly a method. - """ - im_name = rest[0] - im_self = self.unjelly(rest[1]) - im_class = self.unjelly(rest[2]) - if type(im_class) is not types.ClassType: - raise InsecureJelly("Method found with non-class class.") - if im_name in im_class.__dict__: - if im_self is None: - im = getattr(im_class, im_name) - elif isinstance(im_self, NotKnown): - im = _InstanceMethod(im_name, im_self, im_class) - else: - im = instancemethod(im_class.__dict__[im_name], - im_self, - im_class) - else: - raise TypeError('instance method changed') - return im - - - -class _Dummy: - """ - (Internal) Dummy class, used for unserializing instances. - """ - - - -class _DummyNewStyle(object): - """ - (Internal) Dummy class, used for unserializing instances of new-style - classes. - """ - - - -#### Published Interface. - - -class InsecureJelly(Exception): - """ - This exception will be raised when a jelly is deemed `insecure'; e.g. it - contains a type, class, or module disallowed by the specified `taster' - """ - - - -class DummySecurityOptions: - """ - DummySecurityOptions() -> insecure security options - Dummy security options -- this class will allow anything. - """ - - def isModuleAllowed(self, moduleName): - """ - DummySecurityOptions.isModuleAllowed(moduleName) -> boolean - returns 1 if a module by that name is allowed, 0 otherwise - """ - return 1 - - - def isClassAllowed(self, klass): - """ - DummySecurityOptions.isClassAllowed(class) -> boolean - Assumes the module has already been allowed. Returns 1 if the given - class is allowed, 0 otherwise. - """ - return 1 - - - def isTypeAllowed(self, typeName): - """ - DummySecurityOptions.isTypeAllowed(typeName) -> boolean - Returns 1 if the given type is allowed, 0 otherwise. - """ - return 1 - - - -class SecurityOptions: - """ - This will by default disallow everything, except for 'none'. - """ - - basicTypes = ["dictionary", "list", "tuple", - "reference", "dereference", "unpersistable", - "persistent", "long_int", "long", "dict"] - - def __init__(self): - """ - SecurityOptions() initialize. - """ - # I don't believe any of these types can ever pose a security hazard, - # except perhaps "reference"... - self.allowedTypes = {"None": 1, - "bool": 1, - "boolean": 1, - "string": 1, - "str": 1, - "int": 1, - "float": 1, - "datetime": 1, - "time": 1, - "date": 1, - "timedelta": 1, - "NoneType": 1} - if hasattr(types, 'UnicodeType'): - self.allowedTypes['unicode'] = 1 - if decimal is not None: - self.allowedTypes['decimal'] = 1 - self.allowedTypes['set'] = 1 - self.allowedTypes['frozenset'] = 1 - self.allowedModules = {} - self.allowedClasses = {} - - - def allowBasicTypes(self): - """ - Allow all `basic' types. (Dictionary and list. Int, string, and float - are implicitly allowed.) - """ - self.allowTypes(*self.basicTypes) - - - def allowTypes(self, *types): - """ - SecurityOptions.allowTypes(typeString): Allow a particular type, by its - name. - """ - for typ in types: - if not isinstance(typ, str): - typ = qual(typ) - self.allowedTypes[typ] = 1 - - - def allowInstancesOf(self, *classes): - """ - SecurityOptions.allowInstances(klass, klass, ...): allow instances - of the specified classes - - This will also allow the 'instance', 'class' (renamed 'classobj' in - Python 2.3), and 'module' types, as well as basic types. - """ - self.allowBasicTypes() - self.allowTypes("instance", "class", "classobj", "module") - for klass in classes: - self.allowTypes(qual(klass)) - self.allowModules(klass.__module__) - self.allowedClasses[klass] = 1 - - - def allowModules(self, *modules): - """ - SecurityOptions.allowModules(module, module, ...): allow modules by - name. This will also allow the 'module' type. - """ - for module in modules: - if type(module) == types.ModuleType: - module = module.__name__ - self.allowedModules[module] = 1 - - - def isModuleAllowed(self, moduleName): - """ - SecurityOptions.isModuleAllowed(moduleName) -> boolean - returns 1 if a module by that name is allowed, 0 otherwise - """ - return moduleName in self.allowedModules - - - def isClassAllowed(self, klass): - """ - SecurityOptions.isClassAllowed(class) -> boolean - Assumes the module has already been allowed. Returns 1 if the given - class is allowed, 0 otherwise. - """ - return klass in self.allowedClasses - - - def isTypeAllowed(self, typeName): - """ - SecurityOptions.isTypeAllowed(typeName) -> boolean - Returns 1 if the given type is allowed, 0 otherwise. - """ - return (typeName in self.allowedTypes or '.' in typeName) - - -globalSecurity = SecurityOptions() -globalSecurity.allowBasicTypes() - - - -def jelly(object, taster=DummySecurityOptions(), persistentStore=None, - invoker=None): - """ - Serialize to s-expression. - - Returns a list which is the serialized representation of an object. An - optional 'taster' argument takes a SecurityOptions and will mark any - insecure objects as unpersistable rather than serializing them. - """ - return _Jellier(taster, persistentStore, invoker).jelly(object) - - - -def unjelly(sexp, taster=DummySecurityOptions(), persistentLoad=None, - invoker=None): - """ - Unserialize from s-expression. - - Takes an list that was the result from a call to jelly() and unserializes - an arbitrary object from it. The optional 'taster' argument, an instance - of SecurityOptions, will cause an InsecureJelly exception to be raised if a - disallowed type, module, or class attempted to unserialize. - """ - return _Unjellier(taster, persistentLoad, invoker).unjellyFull(sexp) diff --git a/tools/buildbot/pylibs/twisted/spread/pb.py b/tools/buildbot/pylibs/twisted/spread/pb.py deleted file mode 100644 index 8c2dc1f..0000000 --- a/tools/buildbot/pylibs/twisted/spread/pb.py +++ /dev/null @@ -1,1349 +0,0 @@ -# -*- test-case-name: twisted.test.test_pb -*- -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Perspective Broker - -\"This isn\'t a professional opinion, but it's probably got enough -internet to kill you.\" --glyph - -Future Plans: The connection APIs will be extended with support for -URLs, that will be able to extend resource location and discovery -conversations and specify different authentication mechanisms besides -username/password. This should only add to, and not change, the -existing protocol. - - -Important Changes -================= - -New APIs have been added for serving and connecting. On the client -side, use PBClientFactory.getPerspective() instead of connect(), and -PBClientFactory.getRootObject() instead of getObjectAt(). Server side -should switch to updated cred APIs by using PBServerFactory, at which -point clients would switch to PBClientFactory.login(). - -The new cred support means a different method is sent for login, -although the protocol is compatible on the binary level. When we -switch to pluggable credentials this will introduce another change, -although the current change will still be supported. - -The Perspective class is now deprecated, and has been replaced with -Avatar, which does not rely on the old cred APIs. - - -Introduction -============ - -This is a broker for proxies for and copies of objects. It provides a -translucent interface layer to those proxies. - -The protocol is not opaque, because it provides objects which -represent the remote proxies and require no context (server -references, IDs) to operate on. - -It is not transparent because it does I{not} attempt to make remote -objects behave identically, or even similiarly, to local objects. -Method calls are invoked asynchronously, and specific rules are -applied when serializing arguments. - -@author: U{Glyph Lefkowitz} -""" - -__version__ = "$Revision: 1.157 $"[11:-2] - - -# System Imports -try: - import cStringIO as StringIO -except ImportError: - import StringIO - -import md5 -import random -import new -import types - -from zope.interface import implements, Interface - -# Twisted Imports -from twisted.python import log, failure, reflect -from twisted.internet import defer, protocol -from twisted.cred.portal import Portal -from twisted.cred.credentials import IAnonymous, ICredentials -from twisted.cred.credentials import IUsernameHashedPassword, Anonymous -from twisted.persisted import styles -from twisted.python.components import registerAdapter - -from twisted.spread.interfaces import IJellyable, IUnjellyable -from twisted.spread.jelly import jelly, unjelly, globalSecurity -from twisted.spread import banana - -from twisted.spread.flavors import Serializable -from twisted.spread.flavors import Referenceable, NoSuchMethod -from twisted.spread.flavors import Root, IPBRoot -from twisted.spread.flavors import ViewPoint -from twisted.spread.flavors import Viewable -from twisted.spread.flavors import Copyable -from twisted.spread.flavors import Jellyable -from twisted.spread.flavors import Cacheable -from twisted.spread.flavors import RemoteCopy -from twisted.spread.flavors import RemoteCache -from twisted.spread.flavors import RemoteCacheObserver -from twisted.spread.flavors import copyTags -from twisted.spread.flavors import setCopierForClass, setUnjellyableForClass -from twisted.spread.flavors import setFactoryForClass -from twisted.spread.flavors import setCopierForClassTree - -MAX_BROKER_REFS = 1024 - -portno = 8787 - - -class ProtocolError(Exception): - """ - This error is raised when an invalid protocol statement is received. - """ - -class DeadReferenceError(ProtocolError): - """ - This error is raised when a method is called on a dead reference (one whose - broker has been disconnected). - """ - -class Error(Exception): - """ - This error can be raised to generate known error conditions. - - When a PB callable method (perspective_, remote_, view_) raises - this error, it indicates that a traceback should not be printed, - but instead, the string representation of the exception should be - sent. - """ - -class RemoteMethod: - """This is a translucent reference to a remote message. - """ - def __init__(self, obj, name): - """Initialize with a L{RemoteReference} and the name of this message. - """ - self.obj = obj - self.name = name - - def __cmp__(self, other): - return cmp((self.obj, self.name), other) - - def __hash__(self): - return hash((self.obj, self.name)) - - def __call__(self, *args, **kw): - """Asynchronously invoke a remote method. - """ - return self.obj.broker._sendMessage('',self.obj.perspective, self.obj.luid, self.name, args, kw) - -def noOperation(*args, **kw): - """Do nothing. - - Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, - consectetur, adipisci velit... - """ - -class PBConnectionLost(Exception): - pass - -def printTraceback(tb): - """Print a traceback (string) to the standard log. - """ - - log.msg('Perspective Broker Traceback:' ) - log.msg(tb) - -class IPerspective(Interface): - """ - per*spec*tive, n. : The relationship of aspects of a subject to each - other and to a whole: 'a perspective of history'; 'a need to view - the problem in the proper perspective'. - - This is a Perspective Broker-specific wrapper for an avatar. That - is to say, a PB-published view on to the business logic for the - system's concept of a 'user'. - - The concept of attached/detached is no longer implemented by the - framework. The realm is expected to implement such semantics if - needed. - """ - - def perspectiveMessageReceived(broker, message, args, kwargs): - """ - This method is called when a network message is received. - - @arg broker: The Perspective Broker. - - @type message: str - @arg message: The name of the method called by the other end. - - @type args: list in jelly format - @arg args: The arguments that were passed by the other end. It - is recommend that you use the `unserialize' method of the - broker to decode this. - - @type kwargs: dict in jelly format - @arg kwargs: The keyword arguments that were passed by the - other end. It is recommended that you use the - `unserialize' method of the broker to decode this. - - @rtype: A jelly list. - @return: It is recommended that you use the `serialize' method - of the broker on whatever object you need to return to - generate the return value. - """ - - - -class Avatar: - """A default IPerspective implementor. - - This class is intended to be subclassed, and a realm should return - an instance of such a subclass when IPerspective is requested of - it. - - A peer requesting a perspective will receive only a - L{RemoteReference} to a pb.Avatar. When a method is called on - that L{RemoteReference}, it will translate to a method on the - remote perspective named 'perspective_methodname'. (For more - information on invoking methods on other objects, see - L{flavors.ViewPoint}.) - """ - - implements(IPerspective) - - def perspectiveMessageReceived(self, broker, message, args, kw): - """This method is called when a network message is received. - - I will call:: - - | self.perspective_%(message)s(*broker.unserialize(args), - | **broker.unserialize(kw)) - - to handle the method; subclasses of Avatar are expected to - implement methods of this naming convention. - """ - - args = broker.unserialize(args, self) - kw = broker.unserialize(kw, self) - method = getattr(self, "perspective_%s" % message) - try: - state = method(*args, **kw) - except TypeError: - log.msg("%s didn't accept %s and %s" % (method, args, kw)) - raise - return broker.serialize(state, self, method, args, kw) - - - -class AsReferenceable(Referenceable): - """AsReferenceable: a reference directed towards another object. - """ - - def __init__(self, object, messageType="remote"): - """Initialize me with an object. - """ - self.remoteMessageReceived = getattr(object, messageType + "MessageReceived") - - - -class RemoteReference(Serializable, styles.Ephemeral): - """This is a translucent reference to a remote object. - - I may be a reference to a L{flavors.ViewPoint}, a - L{flavors.Referenceable}, or an L{IPerspective} implementor (e.g., - pb.Avatar). From the client's perspective, it is not possible to - tell which except by convention. - - I am a \"translucent\" reference because although no additional - bookkeeping overhead is given to the application programmer for - manipulating a reference, return values are asynchronous. - - See also L{twisted.internet.defer}. - - @ivar broker: The broker I am obtained through. - @type broker: L{Broker} - """ - - implements(IUnjellyable) - - def __init__(self, perspective, broker, luid, doRefCount): - """(internal) Initialize me with a broker and a locally-unique ID. - - The ID is unique only to the particular Perspective Broker - instance. - """ - self.luid = luid - self.broker = broker - self.doRefCount = doRefCount - self.perspective = perspective - self.disconnectCallbacks = [] - - def notifyOnDisconnect(self, callback): - """Register a callback to be called if our broker gets disconnected. - - This callback will be called with one argument, this instance. - """ - assert callable(callback) - self.disconnectCallbacks.append(callback) - if len(self.disconnectCallbacks) == 1: - self.broker.notifyOnDisconnect(self._disconnected) - - def dontNotifyOnDisconnect(self, callback): - """Remove a callback that was registered with notifyOnDisconnect.""" - self.disconnectCallbacks.remove(callback) - if not self.disconnectCallbacks: - self.broker.dontNotifyOnDisconnect(self._disconnected) - - def _disconnected(self): - """Called if we are disconnected and have callbacks registered.""" - for callback in self.disconnectCallbacks: - callback(self) - self.disconnectCallbacks = None - - def jellyFor(self, jellier): - """If I am being sent back to where I came from, serialize as a local backreference. - """ - if jellier.invoker: - assert self.broker == jellier.invoker, "Can't send references to brokers other than their own." - return "local", self.luid - else: - return "unpersistable", "References cannot be serialized" - - def unjellyFor(self, unjellier, unjellyList): - self.__init__(unjellier.invoker.unserializingPerspective, unjellier.invoker, unjellyList[1], 1) - return self - - def callRemote(self, _name, *args, **kw): - """Asynchronously invoke a remote method. - - @type _name: C{string} - @param _name: the name of the remote method to invoke - @param args: arguments to serialize for the remote function - @param kw: keyword arguments to serialize for the remote function. - @rtype: L{twisted.internet.defer.Deferred} - @returns: a Deferred which will be fired when the result of - this remote call is received. - """ - # note that we use '_name' instead of 'name' so the user can call - # remote methods with 'name' as a keyword parameter, like this: - # ref.callRemote("getPeopleNamed", count=12, name="Bob") - - return self.broker._sendMessage('',self.perspective, self.luid, - _name, args, kw) - - def remoteMethod(self, key): - """Get a L{RemoteMethod} for this key. - """ - return RemoteMethod(self, key) - - def __cmp__(self,other): - """Compare me [to another L{RemoteReference}]. - """ - if isinstance(other, RemoteReference): - if other.broker == self.broker: - return cmp(self.luid, other.luid) - return cmp(self.broker, other) - - def __hash__(self): - """Hash me. - """ - return self.luid - - def __del__(self): - """Do distributed reference counting on finalization. - """ - if self.doRefCount: - self.broker.sendDecRef(self.luid) - -setUnjellyableForClass("remote", RemoteReference) - -class Local: - """(internal) A reference to a local object. - """ - - def __init__(self, object, perspective=None): - """Initialize. - """ - self.object = object - self.perspective = perspective - self.refcount = 1 - - def __repr__(self): - return "" % (self.object, self.refcount) - - def incref(self): - """Increment and return my reference count. - """ - self.refcount = self.refcount + 1 - return self.refcount - - def decref(self): - """Decrement and return my reference count. - """ - self.refcount = self.refcount - 1 - return self.refcount - - -class _RemoteCacheDummy: - """Ignore. - """ - -## -# Failure -## - -class CopyableFailure(failure.Failure, Copyable): - """ - A L{flavors.RemoteCopy} and L{flavors.Copyable} version of - L{twisted.python.failure.Failure} for serialization. - """ - - unsafeTracebacks = 0 - - def getStateToCopy(self): - """ - Collect state related to the exception which occurred, discarding - state which cannot reasonably be serialized. - """ - state = self.__dict__.copy() - state['tb'] = None - state['frames'] = [] - state['stack'] = [] - if isinstance(self.value, failure.Failure): - state['value'] = failure2Copyable(self.value, self.unsafeTracebacks) - else: - state['value'] = str(self.value) # Exception instance - if isinstance(self.type, str): - state['type'] = self.type - else: - state['type'] = reflect.qual(self.type) # Exception class - if self.unsafeTracebacks: - io = StringIO.StringIO() - self.printTraceback(io) - state['traceback'] = io.getvalue() - else: - state['traceback'] = 'Traceback unavailable\n' - return state - - -class CopiedFailure(RemoteCopy, failure.Failure): - def printTraceback(self, file=None, elideFrameworkCode=0, detail='default'): - if file is None: - file = log.logfile - file.write("Traceback from remote host -- ") - file.write(self.traceback) - - printBriefTraceback = printTraceback - printDetailedTraceback = printTraceback - -setUnjellyableForClass(CopyableFailure, CopiedFailure) - -def failure2Copyable(fail, unsafeTracebacks=0): - f = new.instance(CopyableFailure, fail.__dict__) - f.unsafeTracebacks = unsafeTracebacks - return f - -class Broker(banana.Banana): - """I am a broker for objects. - """ - - version = 6 - username = None - factory = None - - def __init__(self, isClient=1, security=globalSecurity): - banana.Banana.__init__(self, isClient) - self.disconnected = 0 - self.disconnects = [] - self.failures = [] - self.connects = [] - self.localObjects = {} - self.security = security - self.pageProducers = [] - self.currentRequestID = 0 - self.currentLocalID = 0 - # Some terms: - # PUID: process unique ID; return value of id() function. type "int". - # LUID: locally unique ID; an ID unique to an object mapped over this - # connection. type "int" - # GUID: (not used yet) globally unique ID; an ID for an object which - # may be on a redirected or meta server. Type as yet undecided. - # Dictionary mapping LUIDs to local objects. - # set above to allow root object to be assigned before connection is made - # self.localObjects = {} - # Dictionary mapping PUIDs to LUIDs. - self.luids = {} - # Dictionary mapping LUIDs to local (remotely cached) objects. Remotely - # cached means that they're objects which originate here, and were - # copied remotely. - self.remotelyCachedObjects = {} - # Dictionary mapping PUIDs to (cached) LUIDs - self.remotelyCachedLUIDs = {} - # Dictionary mapping (remote) LUIDs to (locally cached) objects. - self.locallyCachedObjects = {} - self.waitingForAnswers = {} - - def resumeProducing(self): - """Called when the consumer attached to me runs out of buffer. - """ - # Go backwards over the list so we can remove indexes from it as we go - for pageridx in xrange(len(self.pageProducers)-1, -1, -1): - pager = self.pageProducers[pageridx] - pager.sendNextPage() - if not pager.stillPaging(): - del self.pageProducers[pageridx] - if not self.pageProducers: - self.transport.unregisterProducer() - - # Streaming producer methods; not necessary to implement. - def pauseProducing(self): - pass - - def stopProducing(self): - pass - - def registerPageProducer(self, pager): - self.pageProducers.append(pager) - if len(self.pageProducers) == 1: - self.transport.registerProducer(self, 0) - - def expressionReceived(self, sexp): - """Evaluate an expression as it's received. - """ - if isinstance(sexp, types.ListType): - command = sexp[0] - methodName = "proto_%s" % command - method = getattr(self, methodName, None) - if method: - method(*sexp[1:]) - else: - self.sendCall("didNotUnderstand", command) - else: - raise ProtocolError("Non-list expression received.") - - - def proto_version(self, vnum): - """Protocol message: (version version-number) - - Check to make sure that both ends of the protocol are speaking - the same version dialect. - """ - - if vnum != self.version: - raise ProtocolError("Version Incompatibility: %s %s" % (self.version, vnum)) - - - def sendCall(self, *exp): - """Utility method to send an expression to the other side of the connection. - """ - self.sendEncoded(exp) - - def proto_didNotUnderstand(self, command): - """Respond to stock 'C{didNotUnderstand}' message. - - Log the command that was not understood and continue. (Note: - this will probably be changed to close the connection or raise - an exception in the future.) - """ - log.msg("Didn't understand command: %r" % command) - - def connectionReady(self): - """Initialize. Called after Banana negotiation is done. - """ - self.sendCall("version", self.version) - for notifier in self.connects: - try: - notifier() - except: - log.deferr() - self.connects = None - if self.factory: # in tests we won't have factory - self.factory.clientConnectionMade(self) - - def connectionFailed(self): - # XXX should never get called anymore? check! - for notifier in self.failures: - try: - notifier() - except: - log.deferr() - self.failures = None - - waitingForAnswers = None - - def connectionLost(self, reason): - """The connection was lost. - """ - self.disconnected = 1 - # nuke potential circular references. - self.luids = None - if self.waitingForAnswers: - for d in self.waitingForAnswers.values(): - try: - d.errback(failure.Failure(PBConnectionLost(reason))) - except: - log.deferr() - # Assure all Cacheable.stoppedObserving are called - for lobj in self.remotelyCachedObjects.values(): - cacheable = lobj.object - perspective = lobj.perspective - try: - cacheable.stoppedObserving(perspective, RemoteCacheObserver(self, cacheable, perspective)) - except: - log.deferr() - # Loop on a copy to prevent notifiers to mixup - # the list by calling dontNotifyOnDisconnect - for notifier in self.disconnects[:]: - try: - notifier() - except: - log.deferr() - self.disconnects = None - self.waitingForAnswers = None - self.localSecurity = None - self.remoteSecurity = None - self.remotelyCachedObjects = None - self.remotelyCachedLUIDs = None - self.locallyCachedObjects = None - self.localObjects = None - - def notifyOnDisconnect(self, notifier): - """Call the given callback when the Broker disconnects.""" - assert callable(notifier) - self.disconnects.append(notifier) - - def notifyOnFail(self, notifier): - """Call the given callback if the Broker fails to connect.""" - assert callable(notifier) - self.failures.append(notifier) - - def notifyOnConnect(self, notifier): - """Call the given callback when the Broker connects.""" - assert callable(notifier) - if self.connects is None: - try: - notifier() - except: - log.err() - else: - self.connects.append(notifier) - - def dontNotifyOnDisconnect(self, notifier): - """Remove a callback from list of disconnect callbacks.""" - try: - self.disconnects.remove(notifier) - except ValueError: - pass - - def localObjectForID(self, luid): - """Get a local object for a locally unique ID. - - I will return an object previously stored with - self.L{registerReference}, or C{None} if XXX:Unfinished thought:XXX - """ - - lob = self.localObjects.get(luid) - if lob is None: - return - return lob.object - - maxBrokerRefsViolations = 0 - - def registerReference(self, object): - """Get an ID for a local object. - - Store a persistent reference to a local object and map its id() - to a generated, session-unique ID and return that ID. - """ - - assert object is not None - puid = object.processUniqueID() - luid = self.luids.get(puid) - if luid is None: - if len(self.localObjects) > MAX_BROKER_REFS: - self.maxBrokerRefsViolations = self.maxBrokerRefsViolations + 1 - if self.maxBrokerRefsViolations > 3: - self.transport.loseConnection() - raise Error("Maximum PB reference count exceeded. " - "Goodbye.") - raise Error("Maximum PB reference count exceeded.") - - luid = self.newLocalID() - self.localObjects[luid] = Local(object) - self.luids[puid] = luid - else: - self.localObjects[luid].incref() - return luid - - def setNameForLocal(self, name, object): - """Store a special (string) ID for this object. - - This is how you specify a 'base' set of objects that the remote - protocol can connect to. - """ - assert object is not None - self.localObjects[name] = Local(object) - - def remoteForName(self, name): - """Returns an object from the remote name mapping. - - Note that this does not check the validity of the name, only - creates a translucent reference for it. - """ - return RemoteReference(None, self, name, 0) - - def cachedRemotelyAs(self, instance, incref=0): - """Returns an ID that says what this instance is cached as remotely, or C{None} if it's not. - """ - - puid = instance.processUniqueID() - luid = self.remotelyCachedLUIDs.get(puid) - if (luid is not None) and (incref): - self.remotelyCachedObjects[luid].incref() - return luid - - def remotelyCachedForLUID(self, luid): - """Returns an instance which is cached remotely, with this LUID. - """ - return self.remotelyCachedObjects[luid].object - - def cacheRemotely(self, instance): - """ - XXX""" - puid = instance.processUniqueID() - luid = self.newLocalID() - if len(self.remotelyCachedObjects) > MAX_BROKER_REFS: - self.maxBrokerRefsViolations = self.maxBrokerRefsViolations + 1 - if self.maxBrokerRefsViolations > 3: - self.transport.loseConnection() - raise Error("Maximum PB cache count exceeded. " - "Goodbye.") - raise Error("Maximum PB cache count exceeded.") - - self.remotelyCachedLUIDs[puid] = luid - # This table may not be necessary -- for now, it's to make sure that no - # monkey business happens with id(instance) - self.remotelyCachedObjects[luid] = Local(instance, self.serializingPerspective) - return luid - - def cacheLocally(self, cid, instance): - """(internal) - - Store a non-filled-out cached instance locally. - """ - self.locallyCachedObjects[cid] = instance - - def cachedLocallyAs(self, cid): - instance = self.locallyCachedObjects[cid] - return instance - - def serialize(self, object, perspective=None, method=None, args=None, kw=None): - """Jelly an object according to the remote security rules for this broker. - """ - - if isinstance(object, defer.Deferred): - object.addCallbacks(self.serialize, lambda x: x, - callbackKeywords={ - 'perspective': perspective, - 'method': method, - 'args': args, - 'kw': kw - }) - return object - - # XXX This call is NOT REENTRANT and testing for reentrancy is just - # crazy, so it likely won't be. Don't ever write methods that call the - # broker's serialize() method recursively (e.g. sending a method call - # from within a getState (this causes concurrency problems anyway so - # you really, really shouldn't do it)) - - # self.jellier = _NetJellier(self) - self.serializingPerspective = perspective - self.jellyMethod = method - self.jellyArgs = args - self.jellyKw = kw - try: - return jelly(object, self.security, None, self) - finally: - self.serializingPerspective = None - self.jellyMethod = None - self.jellyArgs = None - self.jellyKw = None - - def unserialize(self, sexp, perspective = None): - """Unjelly an sexp according to the local security rules for this broker. - """ - - self.unserializingPerspective = perspective - try: - return unjelly(sexp, self.security, None, self) - finally: - self.unserializingPerspective = None - - def newLocalID(self): - """Generate a new LUID. - """ - self.currentLocalID = self.currentLocalID + 1 - return self.currentLocalID - - def newRequestID(self): - """Generate a new request ID. - """ - self.currentRequestID = self.currentRequestID + 1 - return self.currentRequestID - - def _sendMessage(self, prefix, perspective, objectID, message, args, kw): - pbc = None - pbe = None - answerRequired = 1 - if kw.has_key('pbcallback'): - pbc = kw['pbcallback'] - del kw['pbcallback'] - if kw.has_key('pberrback'): - pbe = kw['pberrback'] - del kw['pberrback'] - if kw.has_key('pbanswer'): - assert (not pbe) and (not pbc), "You can't specify a no-answer requirement." - answerRequired = kw['pbanswer'] - del kw['pbanswer'] - if self.disconnected: - raise DeadReferenceError("Calling Stale Broker") - try: - netArgs = self.serialize(args, perspective=perspective, method=message) - netKw = self.serialize(kw, perspective=perspective, method=message) - except: - return defer.fail(failure.Failure()) - requestID = self.newRequestID() - if answerRequired: - rval = defer.Deferred() - self.waitingForAnswers[requestID] = rval - if pbc or pbe: - log.msg('warning! using deprecated "pbcallback"') - rval.addCallbacks(pbc, pbe) - else: - rval = None - self.sendCall(prefix+"message", requestID, objectID, message, answerRequired, netArgs, netKw) - return rval - - def proto_message(self, requestID, objectID, message, answerRequired, netArgs, netKw): - self._recvMessage(self.localObjectForID, requestID, objectID, message, answerRequired, netArgs, netKw) - def proto_cachemessage(self, requestID, objectID, message, answerRequired, netArgs, netKw): - self._recvMessage(self.cachedLocallyAs, requestID, objectID, message, answerRequired, netArgs, netKw) - - def _recvMessage(self, findObjMethod, requestID, objectID, message, answerRequired, netArgs, netKw): - """Received a message-send. - - Look up message based on object, unserialize the arguments, and - invoke it with args, and send an 'answer' or 'error' response. - """ - try: - object = findObjMethod(objectID) - if object is None: - raise Error("Invalid Object ID") - netResult = object.remoteMessageReceived(self, message, netArgs, netKw) - except Error, e: - if answerRequired: - # If the error is Jellyable or explicitly allowed via our - # security options, send it back and let the code on the - # other end deal with unjellying. If it isn't Jellyable, - # wrap it in a CopyableFailure, which ensures it can be - # unjellied on the other end. We have to do this because - # all errors must be sent back. - if isinstance(e, Jellyable) or self.security.isClassAllowed(e.__class__): - self._sendError(e, requestID) - else: - self._sendError(CopyableFailure(e), requestID) - except: - if answerRequired: - log.msg("Peer will receive following PB traceback:", isError=True) - f = CopyableFailure() - self._sendError(f, requestID) - log.err() - else: - if answerRequired: - if isinstance(netResult, defer.Deferred): - args = (requestID,) - netResult.addCallbacks(self._sendAnswer, self._sendFailureOrError, - callbackArgs=args, errbackArgs=args) - # XXX Should this be done somewhere else? - else: - self._sendAnswer(netResult, requestID) - ## - # success - ## - - def _sendAnswer(self, netResult, requestID): - """(internal) Send an answer to a previously sent message. - """ - self.sendCall("answer", requestID, netResult) - - def proto_answer(self, requestID, netResult): - """(internal) Got an answer to a previously sent message. - - Look up the appropriate callback and call it. - """ - d = self.waitingForAnswers[requestID] - del self.waitingForAnswers[requestID] - d.callback(self.unserialize(netResult)) - - ## - # failure - ## - def _sendFailureOrError(self, fail, requestID): - """ - Call L{_sendError} or L{_sendFailure}, depending on whether C{fail} - represents an L{Error} subclass or not. - """ - if fail.check(Error) is None: - self._sendFailure(fail, requestID) - else: - self._sendError(fail, requestID) - - - def _sendFailure(self, fail, requestID): - """Log error and then send it.""" - log.msg("Peer will receive following PB traceback:") - log.err(fail) - self._sendError(fail, requestID) - - def _sendError(self, fail, requestID): - """(internal) Send an error for a previously sent message. - """ - if isinstance(fail, failure.Failure): - # If the failures value is jellyable or allowed through security, - # send the value - if (isinstance(fail.value, Jellyable) or - self.security.isClassAllowed(fail.value.__class__)): - fail = fail.value - elif not isinstance(fail, CopyableFailure): - fail = failure2Copyable(fail, self.factory.unsafeTracebacks) - if isinstance(fail, CopyableFailure): - fail.unsafeTracebacks = self.factory.unsafeTracebacks - self.sendCall("error", requestID, self.serialize(fail)) - - def proto_error(self, requestID, fail): - """(internal) Deal with an error. - """ - d = self.waitingForAnswers[requestID] - del self.waitingForAnswers[requestID] - d.errback(self.unserialize(fail)) - - ## - # refcounts - ## - - def sendDecRef(self, objectID): - """(internal) Send a DECREF directive. - """ - self.sendCall("decref", objectID) - - def proto_decref(self, objectID): - """(internal) Decrement the reference count of an object. - - If the reference count is zero, it will free the reference to this - object. - """ - refs = self.localObjects[objectID].decref() - if refs == 0: - puid = self.localObjects[objectID].object.processUniqueID() - del self.luids[puid] - del self.localObjects[objectID] - - ## - # caching - ## - - def decCacheRef(self, objectID): - """(internal) Send a DECACHE directive. - """ - self.sendCall("decache", objectID) - - def proto_decache(self, objectID): - """(internal) Decrement the reference count of a cached object. - - If the reference count is zero, free the reference, then send an - 'uncached' directive. - """ - refs = self.remotelyCachedObjects[objectID].decref() - # log.msg('decaching: %s #refs: %s' % (objectID, refs)) - if refs == 0: - lobj = self.remotelyCachedObjects[objectID] - cacheable = lobj.object - perspective = lobj.perspective - # TODO: force_decache needs to be able to force-invalidate a - # cacheable reference. - try: - cacheable.stoppedObserving(perspective, RemoteCacheObserver(self, cacheable, perspective)) - except: - log.deferr() - puid = cacheable.processUniqueID() - del self.remotelyCachedLUIDs[puid] - del self.remotelyCachedObjects[objectID] - self.sendCall("uncache", objectID) - - def proto_uncache(self, objectID): - """(internal) Tell the client it is now OK to uncache an object. - """ - # log.msg("uncaching locally %d" % objectID) - obj = self.locallyCachedObjects[objectID] - obj.broker = None -## def reallyDel(obj=obj): -## obj.__really_del__() -## obj.__del__ = reallyDel - del self.locallyCachedObjects[objectID] - - - -def respond(challenge, password): - """Respond to a challenge. - - This is useful for challenge/response authentication. - """ - m = md5.new() - m.update(password) - hashedPassword = m.digest() - m = md5.new() - m.update(hashedPassword) - m.update(challenge) - doubleHashedPassword = m.digest() - return doubleHashedPassword - -def challenge(): - """I return some random data.""" - crap = '' - for x in range(random.randrange(15,25)): - crap = crap + chr(random.randint(65,90)) - crap = md5.new(crap).digest() - return crap - - -class PBClientFactory(protocol.ClientFactory): - """ - Client factory for PB brokers. - - As with all client factories, use with reactor.connectTCP/SSL/etc.. - getPerspective and getRootObject can be called either before or - after the connect. - """ - - protocol = Broker - unsafeTracebacks = False - - def __init__(self, unsafeTracebacks=False, security=globalSecurity): - """ - @param unsafeTracebacks: if set, tracebacks for exceptions will be sent - over the wire. - @type unsafeTracebacks: C{bool} - - @param security: security options used by the broker, default to - C{globalSecurity}. - @type security: L{twisted.spread.jelly.SecurityOptions} - """ - self.unsafeTracebacks = unsafeTracebacks - self.security = security - self._reset() - - - def buildProtocol(self, addr): - """ - Build the broker instance, passing the security options to it. - """ - p = self.protocol(isClient=True, security=self.security) - p.factory = self - return p - - - def _reset(self): - self.rootObjectRequests = [] # list of deferred - self._broker = None - self._root = None - - def _failAll(self, reason): - deferreds = self.rootObjectRequests - self._reset() - for d in deferreds: - d.errback(reason) - - def clientConnectionFailed(self, connector, reason): - self._failAll(reason) - - def clientConnectionLost(self, connector, reason, reconnecting=0): - """Reconnecting subclasses should call with reconnecting=1.""" - if reconnecting: - # any pending requests will go to next connection attempt - # so we don't fail them. - self._broker = None - self._root = None - else: - self._failAll(reason) - - def clientConnectionMade(self, broker): - self._broker = broker - self._root = broker.remoteForName("root") - ds = self.rootObjectRequests - self.rootObjectRequests = [] - for d in ds: - d.callback(self._root) - - def getRootObject(self): - """Get root object of remote PB server. - - @return: Deferred of the root object. - """ - if self._broker and not self._broker.disconnected: - return defer.succeed(self._root) - d = defer.Deferred() - self.rootObjectRequests.append(d) - return d - - def disconnect(self): - """If the factory is connected, close the connection. - - Note that if you set up the factory to reconnect, you will need to - implement extra logic to prevent automatic reconnection after this - is called. - """ - if self._broker: - self._broker.transport.loseConnection() - - def _cbSendUsername(self, root, username, password, client): - return root.callRemote("login", username).addCallback( - self._cbResponse, password, client) - - def _cbResponse(self, (challenge, challenger), password, client): - return challenger.callRemote("respond", respond(challenge, password), client) - - - def _cbLoginAnonymous(self, root, client): - """ - Attempt an anonymous login on the given remote root object. - - @type root: L{RemoteReference} - @param root: The object on which to attempt the login, most likely - returned by a call to L{PBClientFactory.getRootObject}. - - @param client: A jellyable object which will be used as the I{mind} - parameter for the login attempt. - - @rtype: L{Deferred} - @return: A L{Deferred} which will be called back with a - L{RemoteReference} to an avatar when anonymous login succeeds, or - which will errback if anonymous login fails. - """ - return root.callRemote("loginAnonymous", client) - - - def login(self, credentials, client=None): - """ - Login and get perspective from remote PB server. - - Currently the following credentials are supported:: - - L{twisted.cred.credentials.IUsernamePassword} - L{twisted.cred.credentials.IAnonymous} - - @rtype: L{Deferred} - @return: A L{Deferred} which will be called back with a - L{RemoteReference} for the avatar logged in to, or which will - errback if login fails. - """ - d = self.getRootObject() - - if IAnonymous.providedBy(credentials): - d.addCallback(self._cbLoginAnonymous, client) - else: - d.addCallback( - self._cbSendUsername, credentials.username, - credentials.password, client) - return d - - - -class PBServerFactory(protocol.ServerFactory): - """ - Server factory for perspective broker. - - Login is done using a Portal object, whose realm is expected to return - avatars implementing IPerspective. The credential checkers in the portal - should accept IUsernameHashedPassword or IUsernameMD5Password. - - Alternatively, any object providing or adaptable to L{IPBRoot} can be - used instead of a portal to provide the root object of the PB server. - """ - - unsafeTracebacks = False - - # object broker factory - protocol = Broker - - def __init__(self, root, unsafeTracebacks=False, security=globalSecurity): - """ - @param root: factory providing the root Referenceable used by the broker. - @type root: object providing or adaptable to L{IPBRoot}. - - @param unsafeTracebacks: if set, tracebacks for exceptions will be sent - over the wire. - @type unsafeTracebacks: C{bool} - - @param security: security options used by the broker, default to - C{globalSecurity}. - @type security: L{twisted.spread.jelly.SecurityOptions} - """ - self.root = IPBRoot(root) - self.unsafeTracebacks = unsafeTracebacks - self.security = security - - - def buildProtocol(self, addr): - """ - Return a Broker attached to the factory (as the service provider). - """ - proto = self.protocol(isClient=False, security=self.security) - proto.factory = self - proto.setNameForLocal("root", self.root.rootObject(proto)) - return proto - - def clientConnectionMade(self, protocol): - # XXX does this method make any sense? - pass - - -class IUsernameMD5Password(ICredentials): - """I encapsulate a username and a hashed password. - - This credential is used for username/password over - PB. CredentialCheckers which check this kind of credential must - store the passwords in plaintext form or as a MD5 digest. - - @type username: C{str} or C{Deferred} - @ivar username: The username associated with these credentials. - """ - - def checkPassword(password): - """Validate these credentials against the correct password. - - @param password: The correct, plaintext password against which to - check. - - @return: a deferred which becomes, or a boolean indicating if the - password matches. - """ - - def checkMD5Password(password): - """Validate these credentials against the correct MD5 digest of password. - - @param password: The correct, plaintext password against which to - check. - - @return: a deferred which becomes, or a boolean indicating if the - password matches. - """ - - -class _PortalRoot: - """Root object, used to login to portal.""" - - implements(IPBRoot) - - def __init__(self, portal): - self.portal = portal - - def rootObject(self, broker): - return _PortalWrapper(self.portal, broker) - -registerAdapter(_PortalRoot, Portal, IPBRoot) - - - -class _JellyableAvatarMixin: - """ - Helper class for code which deals with avatars which PB must be capable of - sending to a peer. - """ - def _cbLogin(self, (interface, avatar, logout)): - """ - Ensure that the avatar to be returned to the client is jellyable and - set up disconnection notification to call the realm's logout object. - """ - if not IJellyable.providedBy(avatar): - avatar = AsReferenceable(avatar, "perspective") - self.broker.notifyOnDisconnect(logout) - return avatar - - - -class _PortalWrapper(Referenceable, _JellyableAvatarMixin): - """ - Root Referenceable object, used to login to portal. - """ - - def __init__(self, portal, broker): - self.portal = portal - self.broker = broker - - - def remote_login(self, username): - """ - Start of username/password login. - """ - c = challenge() - return c, _PortalAuthChallenger(self.portal, self.broker, username, c) - - - def remote_loginAnonymous(self, mind): - """ - Attempt an anonymous login. - - @param mind: An object to use as the mind parameter to the portal login - call (possibly None). - - @rtype: L{Deferred} - @return: A Deferred which will be called back with an avatar when login - succeeds or which will be errbacked if login fails somehow. - """ - d = self.portal.login(Anonymous(), mind, IPerspective) - d.addCallback(self._cbLogin) - return d - - - -class _PortalAuthChallenger(Referenceable, _JellyableAvatarMixin): - """ - Called with response to password challenge. - """ - implements(IUsernameHashedPassword, IUsernameMD5Password) - - def __init__(self, portal, broker, username, challenge): - self.portal = portal - self.broker = broker - self.username = username - self.challenge = challenge - - - def remote_respond(self, response, mind): - self.response = response - d = self.portal.login(self, mind, IPerspective) - d.addCallback(self._cbLogin) - return d - - - # IUsernameHashedPassword: - def checkPassword(self, password): - return self.checkMD5Password(md5.md5(password).digest()) - - - # IUsernameMD5Password - def checkMD5Password(self, md5Password): - md = md5.new() - md.update(md5Password) - md.update(self.challenge) - correct = md.digest() - return self.response == correct diff --git a/tools/buildbot/pylibs/twisted/spread/publish.py b/tools/buildbot/pylibs/twisted/spread/publish.py deleted file mode 100644 index 0f031fd..0000000 --- a/tools/buildbot/pylibs/twisted/spread/publish.py +++ /dev/null @@ -1,142 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Persistently cached objects for PB. - -Maintainer: U{Glyph Lefkowitz} - -Future Plans: None known. -""" - -# Twisted imports -from twisted.internet import defer - -# sibling imports -import jelly -import banana -import flavors - -# System Imports -import time - -class Publishable(flavors.Cacheable): - """An object whose cached state persists across sessions. - """ - def __init__(self, publishedID): - self.republish() - self.publishedID = publishedID - - def republish(self): - """Set the timestamp to current and (TODO) update all observers. - """ - self.timestamp = time.time() - - def view_getStateToPublish(self, perspective): - '(internal)' - return self.getStateToPublishFor(perspective) - - def getStateToPublishFor(self, perspective): - """Implement me to special-case your state for a perspective. - """ - return self.getStateToPublish() - - def getStateToPublish(self): - """Implement me to return state to copy as part of the publish phase. - """ - raise NotImplementedError("%s.getStateToPublishFor" % self.__class__) - - def getStateToCacheAndObserveFor(self, perspective, observer): - """Get all necessary metadata to keep a clientside cache. - """ - if perspective: - pname = perspective.perspectiveName - sname = perspective.getService().serviceName - else: - pname = "None" - sname = "None" - - return {"remote": flavors.ViewPoint(perspective, self), - "publishedID": self.publishedID, - "perspective": pname, - "service": sname, - "timestamp": self.timestamp} - -class RemotePublished(flavors.RemoteCache): - """The local representation of remote Publishable object. - """ - isActivated = 0 - _wasCleanWhenLoaded = 0 - def getFileName(self, ext='pub'): - return ("%s-%s-%s.%s" % - (self.service, self.perspective, str(self.publishedID), ext)) - - def setCopyableState(self, state): - self.__dict__.update(state) - self._activationListeners = [] - try: - data = open(self.getFileName()).read() - except IOError: - recent = 0 - else: - newself = jelly.unjelly(banana.decode(data)) - recent = (newself.timestamp == self.timestamp) - if recent: - self._cbGotUpdate(newself.__dict__) - self._wasCleanWhenLoaded = 1 - else: - self.remote.callRemote('getStateToPublish').addCallbacks(self._cbGotUpdate) - - def __getstate__(self): - other = self.__dict__.copy() - # Remove PB-specific attributes - del other['broker'] - del other['remote'] - del other['luid'] - # remove my own runtime-tracking stuff - del other['_activationListeners'] - del other['isActivated'] - return other - - def _cbGotUpdate(self, newState): - self.__dict__.update(newState) - self.isActivated = 1 - # send out notifications - for listener in self._activationListeners: - listener(self) - self._activationListeners = [] - self.activated() - open(self.getFileName(), "wb").write(banana.encode(jelly.jelly(self))) - - def activated(self): - """Implement this method if you want to be notified when your - publishable subclass is activated. - """ - - def callWhenActivated(self, callback): - """Externally register for notification when this publishable has received all relevant data. - """ - if self.isActivated: - callback(self) - else: - self._activationListeners.append(callback) - -def whenReady(d): - """ - Wrap a deferred returned from a pb method in another deferred that - expects a RemotePublished as a result. This will allow you to wait until - the result is really available. - - Idiomatic usage would look like:: - - publish.whenReady(serverObject.getMeAPublishable()).addCallback(lookAtThePublishable) - """ - d2 = defer.Deferred() - d.addCallbacks(_pubReady, d2.errback, - callbackArgs=(d2,)) - return d2 - -def _pubReady(result, d2): - '(internal)' - result.callWhenActivated(d2.callback) diff --git a/tools/buildbot/pylibs/twisted/spread/refpath.py b/tools/buildbot/pylibs/twisted/spread/refpath.py deleted file mode 100644 index e83dc8d..0000000 --- a/tools/buildbot/pylibs/twisted/spread/refpath.py +++ /dev/null @@ -1,99 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -__version__ = "$Revision: 1.17 $"[11:-2] - -""" -Path-based references for PB, and other reference-based protocols. - -Maintainer: U{Glyph Lefkowitz} - -Future Plans: None at this point besides a final overview and finalization -pass. -""" - - -from twisted.python import log - -from flavors import Referenceable, Viewable -from copy import copy -import os - - - -### "Server"-side objects - -class PathReferenceContext: - def __init__(self, path, root): - self.metadata = {} - self.path = path - self.root = root - - def __setitem__(self, key, item): - self.metadata[key] = item - - def __getitem__(self, key): - return self.metadata[key] - - def getObject(self): - o = self.root - for p in self.path: - o = o.getChild(p, self) - return o - -class PathReference: - def __init__(self): - self.children = {} - def getChild(self, child, ctx): - return self.children[child] - -class PathReferenceDirectory(Referenceable): - def __init__(self, root, prefix="remote"): - self.root = root - self.prefix = prefix - def remote_callPath(self, path, name, *args, **kw): - ctx = PathReferenceContext(path, self) - obj = ctx.getObject() - return apply(getattr(obj, "%s_%s" % (self.prefix, name)), args, kw) - -class PathReferenceContextDirectory(Referenceable): - def __init__(self, root, prefix="remote"): - self.root = root - self.prefix = prefix - def remote_callPath(self, path, name, *args, **kw): - ctx = PathReferenceContext(path, self) - obj = ctx.getObject() - return apply(getattr(obj, "%s_%s" % (self.prefix, name)), - (ctx,)+args, kw) - -class PathViewDirectory(Viewable): - def __init__(self, root, prefix="view"): - self.root = root - self.prefix = prefix - def view_callPath(self, perspective, path, name, *args, **kw): - ctx = PathReferenceContext(path, self) - obj = ctx.getObject() - return apply(getattr(obj, "%s_%s" % (self.prefix, name)), - (perspective,)+args, kw) - -class PathViewContextDirectory(Viewable): - def __init__(self, root, prefix="view"): - self.root = root - self.prefix = prefix - def view_callPath(self, perspective, path, name, *args, **kw): - ctx = PathReferenceContext(path, self) - obj = ctx.getObject() - return apply(getattr(obj, "%s_%s" % (self.prefix, name)), - (perspective,ctx)+args, kw) - -### "Client"-side objects - -class RemotePathReference: - def __init__(self, ref, path): - self.ref = ref - self.path = path - - def callRemote(self, name, *args, **kw): - apply(self.ref.callRemote, - ("callPath", self.path, name)+args, kw) diff --git a/tools/buildbot/pylibs/twisted/spread/ui/__init__.py b/tools/buildbot/pylibs/twisted/spread/ui/__init__.py deleted file mode 100644 index 4dfc589..0000000 --- a/tools/buildbot/pylibs/twisted/spread/ui/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Twisted Spread UI: UI utilities for various toolkits connecting to PB. -""" - -# Undeprecating this until someone figures out a real plan for alternatives to spread.ui. -##import warnings -##warnings.warn("twisted.spread.ui is deprecated. Please do not use.", DeprecationWarning) diff --git a/tools/buildbot/pylibs/twisted/spread/ui/gtk2util.py b/tools/buildbot/pylibs/twisted/spread/ui/gtk2util.py deleted file mode 100644 index 07e7ef6..0000000 --- a/tools/buildbot/pylibs/twisted/spread/ui/gtk2util.py +++ /dev/null @@ -1,215 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -from __future__ import nested_scopes - -import gtk - -from twisted import copyright -from twisted.internet import defer -from twisted.python import failure, log, util -from twisted.spread import pb -from twisted.cred.credentials import UsernamePassword - -from twisted.internet import error as netError - -def login(client=None, **defaults): - """ - @param host: - @param port: - @param identityName: - @param password: - @param serviceName: - @param perspectiveName: - - @returntype: Deferred RemoteReference of Perspective - """ - d = defer.Deferred() - LoginDialog(client, d, defaults) - return d - -class GladeKeeper: - """ - @cvar gladefile: The file in which the glade GUI definition is kept. - @type gladefile: str - - @cvar _widgets: Widgets that should be attached to me as attributes. - @type _widgets: list of strings - """ - - gladefile = None - _widgets = () - - def __init__(self): - from gtk import glade - self.glade = glade.XML(self.gladefile) - - # mold can go away when we get a newer pygtk (post 1.99.14) - mold = {} - for k in dir(self): - mold[k] = getattr(self, k) - self.glade.signal_autoconnect(mold) - self._setWidgets() - - def _setWidgets(self): - get_widget = self.glade.get_widget - for widgetName in self._widgets: - setattr(self, "_" + widgetName, get_widget(widgetName)) - - -class LoginDialog(GladeKeeper): - # IdentityConnector host port identityName password - # requestLogin -> identityWrapper or login failure - # requestService serviceName perspectiveName client - - # window killed - # cancel button pressed - # login button activated - - fields = ['host','port','identityName','password', - 'perspectiveName'] - - _widgets = ("hostEntry", "portEntry", "identityNameEntry", "passwordEntry", - "perspectiveNameEntry", "statusBar", - "loginDialog") - - _advancedControls = ['perspectiveLabel', 'perspectiveNameEntry', - 'protocolLabel', 'versionLabel'] - - gladefile = util.sibpath(__file__, "login2.glade") - - def __init__(self, client, deferred, defaults): - self.client = client - self.deferredResult = deferred - - GladeKeeper.__init__(self) - - self.setDefaults(defaults) - self._loginDialog.show() - - - def setDefaults(self, defaults): - if not defaults.has_key('port'): - defaults['port'] = str(pb.portno) - elif isinstance(defaults['port'], (int, long)): - defaults['port'] = str(defaults['port']) - - for k, v in defaults.iteritems(): - if k in self.fields: - widget = getattr(self, "_%sEntry" % (k,)) - widget.set_text(v) - - def _setWidgets(self): - GladeKeeper._setWidgets(self) - self._statusContext = self._statusBar.get_context_id("Login dialog.") - get_widget = self.glade.get_widget - get_widget("versionLabel").set_text(copyright.longversion) - get_widget("protocolLabel").set_text("Protocol PB-%s" % - (pb.Broker.version,)) - - def _on_loginDialog_response(self, widget, response): - handlers = {gtk.RESPONSE_NONE: self._windowClosed, - gtk.RESPONSE_DELETE_EVENT: self._windowClosed, - gtk.RESPONSE_OK: self._doLogin, - gtk.RESPONSE_CANCEL: self._cancelled} - handler = handlers.get(response) - if handler is not None: - handler() - else: - log.msg("Unexpected dialog response %r from %s" % (response, - widget)) - - def _on_loginDialog_close(self, widget, userdata=None): - self._windowClosed() - - def _on_loginDialog_destroy_event(self, widget, userdata=None): - self._windowClosed() - - def _cancelled(self): - if not self.deferredResult.called: - self.deferredResult.errback(netError.UserError("User hit Cancel.")) - self._loginDialog.destroy() - - def _windowClosed(self, reason=None): - if not self.deferredResult.called: - self.deferredResult.errback(netError.UserError("Window closed.")) - - def _doLogin(self): - idParams = {} - - idParams['host'] = self._hostEntry.get_text() - idParams['port'] = self._portEntry.get_text() - idParams['identityName'] = self._identityNameEntry.get_text() - idParams['password'] = self._passwordEntry.get_text() - - try: - idParams['port'] = int(idParams['port']) - except ValueError: - pass - - f = pb.PBClientFactory() - from twisted.internet import reactor - reactor.connectTCP(idParams['host'], idParams['port'], f) - creds = UsernamePassword(idParams['identityName'], idParams['password']) - f.login(creds, self.client - ).addCallbacks(self._cbGotPerspective, self._ebFailedLogin - ).setTimeout(30 - ) - self.statusMsg("Contacting server...") - - # serviceName = self._serviceNameEntry.get_text() - # perspectiveName = self._perspectiveNameEntry.get_text() - # if not perspectiveName: - # perspectiveName = idParams['identityName'] - - # d = _identityConnector.requestService(serviceName, perspectiveName, - # self.client) - # d.addCallbacks(self._cbGotPerspective, self._ebFailedLogin) - # setCursor to waiting - - def _cbGotPerspective(self, perspective): - self.statusMsg("Connected to server.") - self.deferredResult.callback(perspective) - # clear waiting cursor - self._loginDialog.destroy() - - def _ebFailedLogin(self, reason): - if isinstance(reason, failure.Failure): - reason = reason.value - self.statusMsg(reason) - if isinstance(reason, (unicode, str)): - text = reason - else: - text = unicode(reason) - msg = gtk.MessageDialog(self._loginDialog, - gtk.DIALOG_DESTROY_WITH_PARENT, - gtk.MESSAGE_ERROR, - gtk.BUTTONS_CLOSE, - text) - msg.show_all() - msg.connect("response", lambda *a: msg.destroy()) - - # hostname not found - # host unreachable - # connection refused - # authentication failed - # no such service - # no such perspective - # internal server error - - def _on_advancedButton_toggled(self, widget, userdata=None): - active = widget.get_active() - if active: - op = "show" - else: - op = "hide" - for widgetName in self._advancedControls: - widget = self.glade.get_widget(widgetName) - getattr(widget, op)() - - def statusMsg(self, text): - if not isinstance(text, (unicode, str)): - text = unicode(text) - return self._statusBar.push(self._statusContext, text) diff --git a/tools/buildbot/pylibs/twisted/spread/ui/gtkutil.py b/tools/buildbot/pylibs/twisted/spread/ui/gtkutil.py deleted file mode 100644 index 90a10f0..0000000 --- a/tools/buildbot/pylibs/twisted/spread/ui/gtkutil.py +++ /dev/null @@ -1,204 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -import gtk -import string - -from twisted.spread import pb -from twisted import copyright -from twisted.python import reflect -from twisted.cred.credentials import UsernamePassword - -normalFont = gtk.load_font("-adobe-courier-medium-r-normal-*-*-120-*-*-m-*-iso8859-1") -boldFont = gtk.load_font("-adobe-courier-bold-r-normal-*-*-120-*-*-m-*-iso8859-1") -errorFont = gtk.load_font("-adobe-courier-medium-o-normal-*-*-120-*-*-m-*-iso8859-1") - - -def selectAll(widget,event): - widget.select_region(0,-1) - -def cbutton(name, callback): - b = gtk.GtkButton(name) - b.connect('clicked', callback) - return b - -class ButtonBar: - barButtons = None - def getButtonList(self, prefix='button_', container=None): - result = [] - buttons = self.barButtons or \ - reflect.prefixedMethodNames(self.__class__, prefix) - for b in buttons: - bName = string.replace(b, '_', ' ') - result.append(cbutton(bName, getattr(self,prefix+b))) - if container: - map(container.add, result) - return result - -def scrollify(widget): - #widget.set_word_wrap(gtk.TRUE) - scrl=gtk.GtkScrolledWindow() - scrl.add(widget) - scrl.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS) - # scrl.set_update_policy(gtk.POLICY_AUTOMATIC) - return scrl - -def defocusify(widget): - widget.unset_flags(gtk.CAN_FOCUS) - -class GetString(gtk.GtkWindow): - def __init__(self, im, desc): - gtk.GtkWindow.__init__(self, gtk.WINDOW_TOPLEVEL) - self.set_title(desc) - self.im = im - button = cbutton(desc, self.clicked) - self.entry = gtk.GtkEntry() - self.entry.connect('activate', self.clicked) - hb = gtk.GtkHBox() - hb.add(self.entry) - hb.add(button) - self.add(hb) - self.show_all() - - def clicked(self, btn): - raise NotImplementedError - - -class Login(gtk.GtkWindow): - - _resetTimeout = None - - def __init__(self, callback, - referenceable=None, - initialUser="guest", initialPassword="guest", - initialHostname="localhost",initialPortno=str(pb.portno), - initialService="", initialPerspective=""): - gtk.GtkWindow.__init__(self,gtk.WINDOW_TOPLEVEL) - version_label = gtk.GtkLabel("Twisted v%s" % copyright.version) - self.pbReferenceable = referenceable - self.pbCallback = callback - # version_label.show() - self.username = gtk.GtkEntry() - self.password = gtk.GtkEntry() - self.service = gtk.GtkEntry() - self.perspective = gtk.GtkEntry() - self.hostname = gtk.GtkEntry() - self.port = gtk.GtkEntry() - self.password.set_visibility(gtk.FALSE) - - self.username.set_text(initialUser) - self.password.set_text(initialPassword) - self.service.set_text(initialService) - self.perspective.set_text(initialPerspective) - self.hostname.set_text(initialHostname) - self.port.set_text(str(initialPortno)) - - userlbl=gtk.GtkLabel("Username:") - passlbl=gtk.GtkLabel("Password:") - servicelbl=gtk.GtkLabel("Service:") - perspeclbl=gtk.GtkLabel("Perspective:") - hostlbl=gtk.GtkLabel("Hostname:") - portlbl=gtk.GtkLabel("Port #:") - self.allLabels = [ - userlbl, passlbl, servicelbl, perspeclbl, hostlbl, portlbl - ] - self.logstat = gtk.GtkLabel("Protocol PB-%s" % pb.Broker.version) - self.okbutton = cbutton("Log In", self.login) - self.okbutton["can_default"] = 1 - self.okbutton["receives_default"] = 1 - - okbtnbx = gtk.GtkHButtonBox() - okbtnbx.add(self.okbutton) - - vbox = gtk.GtkVBox() - vbox.add(version_label) - table = gtk.GtkTable(2,6) - row=0 - for label, entry in [(userlbl, self.username), - (passlbl, self.password), - (hostlbl, self.hostname), - (servicelbl, self.service), - (perspeclbl, self.perspective), - (portlbl, self.port)]: - table.attach(label, 0, 1, row, row+1) - table.attach(entry, 1, 2, row, row+1) - row = row+1 - - vbox.add(table) - vbox.add(self.logstat) - vbox.add(okbtnbx) - self.add(vbox) - self.username.grab_focus() - self.okbutton.grab_default() - for fld in self.username, self.password, self.hostname, self.service, self.perspective: - fld.signal_connect('activate',self.login) - fld.signal_connect('focus_in_event',selectAll) - self.signal_connect('destroy',gtk.mainquit,None) - - def loginReset(self): - print 'doing login reset' - self.logstat.set_text("Idle.") - self._resetTimeout = None - return 0 - - def loginReport(self, txt): - print 'setting login report',repr(txt) - self.logstat.set_text(txt) - if not (self._resetTimeout is None): - gtk.timeout_remove(self._resetTimeout) - - self._resetTimeout = gtk.timeout_add(59000, self.loginReset) - - def login(self, btn): - host = self.hostname.get_text() - port = self.port.get_text() - service = self.service.get_text() - perspective = self.perspective.get_text() - # Maybe we're connecting to a unix socket, so don't make any - # assumptions - try: - port = int(port) - except: - pass - user = self.username.get_text() - pswd = self.password.get_text() - self.loginReport("connecting...") - # putting this off to avoid a stupid bug in gtk where it won't redraw - # if you input_add a connecting socket (!??) - self.user_tx = user - self.pswd_tx = pswd - self.host_tx = host - self.port_tx = port - self.service_tx = service - self.perspective_tx = perspective or user - afterOneTimeout(10, self.__actuallyConnect) - - def __actuallyConnect(self): - from twisted.application import internet - - f = pb.PBClientFactory() - internet.TCPClient(self.host_tx, self.port_tx, f) - creds = UsernamePassword(self.user_tx, self.pswd_tx) - f.login(creds, self.pbReferenceable - ).addCallbacks(self.pbCallback, self.couldNotConnect - ).setTimeout(30 - ) - - def couldNotConnect(self, msg): - self.loginReport("couldn't connect: %s" % str(msg)) - - -class _TimerOuter: - def __init__(self, timeout, cmd, args): - self.args = args - self.cmd = cmd - self.tid = gtk.timeout_add(timeout, self.doIt) - - def doIt(self): - gtk.timeout_remove(self.tid) - apply(self.cmd, self.args) - -def afterOneTimeout(timeout, cmd, *args): - _TimerOuter(timeout, cmd, args) diff --git a/tools/buildbot/pylibs/twisted/spread/ui/login2.glade b/tools/buildbot/pylibs/twisted/spread/ui/login2.glade deleted file mode 100644 index af8c53d..0000000 --- a/tools/buildbot/pylibs/twisted/spread/ui/login2.glade +++ /dev/null @@ -1,461 +0,0 @@ - - - - - - - Login - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - True - True - True - - - - - - True - False - 0 - - - - True - GTK_BUTTONBOX_END - - - - True - True - True - gtk-cancel - True - GTK_RELIEF_NORMAL - -6 - - - - - - True - True - True - True - GTK_RELIEF_NORMAL - -5 - - - - True - 0.5 - 0.5 - 0 - 0 - - - - True - False - 2 - - - - True - gtk-ok - 4 - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - True - _Login - True - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - - - - - - 0 - False - True - GTK_PACK_END - - - - - - True - False - - - 0 - False - False - GTK_PACK_END - - - - - - True - 6 - 2 - False - 2 - 0 - - - - True - _Host: - True - False - GTK_JUSTIFY_LEFT - False - False - 0.9 - 0.5 - 0 - 0 - hostEntry - - - - - - - 0 - 1 - 0 - 1 - fill - - - - - - - True - False - 0 - - - - True - The name of a host to connect to. - True - True - True - True - 0 - localhost - True - * - True - - - - - - 0 - True - True - - - - - - True - The number of a port to connect on. - True - True - True - 0 - 8787 - True - * - True - 5 - - - 0 - False - True - - - - - 1 - 2 - 0 - 1 - fill - - - - - - True - _Name: - True - False - GTK_JUSTIFY_LEFT - False - False - 0.9 - 0.5 - 0 - 0 - identityNameEntry - - - 0 - 1 - 1 - 2 - fill - - - - - - - True - An identity to log in as. - True - True - True - 0 - - True - * - True - - - 1 - 2 - 1 - 2 - - - - - - - True - The Identity's log-in password. - True - True - False - 0 - - True - * - True - - - 1 - 2 - 2 - 3 - - - - - - - True - _Password: - True - False - GTK_JUSTIFY_LEFT - False - False - 0.9 - 0.5 - 0 - 0 - passwordEntry - - - 0 - 1 - 2 - 3 - fill - - - - - - - Perspective: - False - False - GTK_JUSTIFY_LEFT - False - False - 0.9 - 0.5 - 0 - 0 - - - 0 - 1 - 5 - 6 - fill - - - - - - - The name of a Perspective to request. - True - True - True - 0 - - True - * - False - - - 1 - 2 - 5 - 6 - - - - - - - True - False - 0 - - - - Insert Protocol Version Here - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - Insert Twisted Version Here - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - 0 - 2 - 4 - 5 - fill - fill - - - - - - True - 1 - 0.5 - 0 - 1 - - - - True - Advanced options. - True - Advanced >> - True - GTK_RELIEF_NORMAL - False - False - - - - - - 0 - 2 - 3 - 4 - - - - - - 0 - False - False - - - - - - - diff --git a/tools/buildbot/pylibs/twisted/spread/ui/tktree.py b/tools/buildbot/pylibs/twisted/spread/ui/tktree.py deleted file mode 100644 index 1b34e0e..0000000 --- a/tools/buildbot/pylibs/twisted/spread/ui/tktree.py +++ /dev/null @@ -1,204 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -What I want it to look like: - -+- One -| \- Two -| |- Three -| |- Four -| +- Five -| | \- Six -| |- Seven -+- Eight -| \- Nine -""" - -import os -from Tkinter import * - -class Node: - def __init__(self): - """ - Do whatever you want here. - """ - self.item=None - def getName(self): - """ - Return the name of this node in the tree. - """ - pass - def isExpandable(self): - """ - Return true if this node is expandable. - """ - return len(self.getSubNodes())>0 - def getSubNodes(self): - """ - Return the sub nodes of this node. - """ - return [] - def gotDoubleClick(self): - """ - Called when we are double clicked. - """ - pass - def updateMe(self): - """ - Call me when something about me changes, so that my representation - changes. - """ - if self.item: - self.item.update() - -class FileNode(Node): - def __init__(self,name): - Node.__init__(self) - self.name=name - def getName(self): - return os.path.basename(self.name) - def isExpandable(self): - return os.path.isdir(self.name) - def getSubNodes(self): - names=map(lambda x,n=self.name:os.path.join(n,x),os.listdir(self.name)) - return map(FileNode,names) - -class TreeItem: - def __init__(self,widget,parent,node): - self.widget=widget - self.node=node - node.item=self - if self.node.isExpandable(): - self.expand=0 - else: - self.expand=None - self.parent=parent - if parent: - self.level=self.parent.level+1 - else: - self.level=0 - self.first=0 # gets set in Tree.expand() - self.subitems=[] - def __del__(self): - del self.node - del self.widget - def __repr__(self): - return ""%(self.node.getName(),self.level) - def render(self): - """ - Override in a subclass. - """ - raise NotImplementedError - def update(self): - self.widget.update(self) - -class ListboxTreeItem(TreeItem): - def render(self): - start=self.level*"| " - if self.expand==None and not self.first: - start=start+"|" - elif self.expand==0: - start=start+"L" - elif self.expand==1: - start=start+"+" - else: - start=start+"\\" - r=[start+"- "+self.node.getName()] - if self.expand: - for i in self.subitems: - r.extend(i.render()) - return r - -class ListboxTree: - def __init__(self,parent=None,**options): - self.box=apply(Listbox,[parent],options) - self.box.bind("",self.flip) - self.roots=[] - self.items=[] - def pack(self,*args,**kw): - """ - for packing. - """ - apply(self.box.pack,args,kw) - def grid(self,*args,**kw): - """ - for gridding. - """ - apply(self.box.grid,args,kw) - def yview(self,*args,**kw): - """ - for scrolling. - """ - apply(self.box.yview,args,kw) - def addRoot(self,node): - r=ListboxTreeItem(self,None,node) - self.roots.append(r) - self.items.append(r) - self.box.insert(END,r.render()[0]) - return r - def curselection(self): - c=self.box.curselection() - if not c: return - return self.items[int(c[0])] - def flip(self,*foo): - if not self.box.curselection(): return - item=self.items[int(self.box.curselection()[0])] - if item.expand==None: return - if not item.expand: - self.expand(item) - else: - self.close(item) - item.node.gotDoubleClick() - def expand(self,item): - if item.expand or item.expand==None: return - item.expand=1 - item.subitems=map(lambda x,i=item,s=self:ListboxTreeItem(s,i,x),item.node.getSubNodes()) - if item.subitems: - item.subitems[0].first=1 - i=self.items.index(item) - self.items,after=self.items[:i+1],self.items[i+1:] - self.items=self.items+item.subitems+after - c=self.items.index(item) - self.box.delete(c) - r=item.render() - for i in r: - self.box.insert(c,i) - c=c+1 - def close(self,item): - if not item.expand: return - item.expand=0 - length=len(item.subitems) - for i in item.subitems: - self.close(i) - c=self.items.index(item) - del self.items[c+1:c+1+length] - for i in range(length+1): - self.box.delete(c) - self.box.insert(c,item.render()[0]) - def remove(self,item): - if item.expand: - self.close(item) - c=self.items.index(item) - del self.items[c] - if item.parent: - item.parent.subitems.remove(item) - self.box.delete(c) - def update(self,item): - if item.expand==None: - c=self.items.index(item) - self.box.delete(c) - self.box.insert(c,item.render()[0]) - elif item.expand: - self.close(item) - self.expand(item) - -if __name__=="__main__": - tk=Tk() - s=Scrollbar() - t=ListboxTree(tk,yscrollcommand=s.set) - t.pack(side=LEFT,fill=BOTH) - s.config(command=t.yview) - s.pack(side=RIGHT,fill=Y) - t.addRoot(FileNode("C:/")) - #mainloop() diff --git a/tools/buildbot/pylibs/twisted/spread/ui/tkutil.py b/tools/buildbot/pylibs/twisted/spread/ui/tkutil.py deleted file mode 100644 index dd9902c9..0000000 --- a/tools/buildbot/pylibs/twisted/spread/ui/tkutil.py +++ /dev/null @@ -1,397 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -"""Utilities for building L{PB} clients with L{Tkinter}. -""" -from Tkinter import * -from tkSimpleDialog import _QueryString -from tkFileDialog import _Dialog -from twisted.spread import pb -from twisted.internet import reactor -from twisted import copyright - -import string - -#normalFont = Font("-adobe-courier-medium-r-normal-*-*-120-*-*-m-*-iso8859-1") -#boldFont = Font("-adobe-courier-bold-r-normal-*-*-120-*-*-m-*-iso8859-1") -#errorFont = Font("-adobe-courier-medium-o-normal-*-*-120-*-*-m-*-iso8859-1") - -class _QueryPassword(_QueryString): - def body(self, master): - - w = Label(master, text=self.prompt, justify=LEFT) - w.grid(row=0, padx=5, sticky=W) - - self.entry = Entry(master, name="entry",show="*") - self.entry.grid(row=1, padx=5, sticky=W+E) - - if self.initialvalue: - self.entry.insert(0, self.initialvalue) - self.entry.select_range(0, END) - - return self.entry - -def askpassword(title, prompt, **kw): - '''get a password from the user - - @param title: the dialog title - @param prompt: the label text - @param **kw: see L{SimpleDialog} class - - @returns: a string - ''' - d = apply(_QueryPassword, (title, prompt), kw) - return d.result - -def grid_setexpand(widget): - cols,rows=widget.grid_size() - for i in range(cols): - widget.columnconfigure(i,weight=1) - for i in range(rows): - widget.rowconfigure(i,weight=1) - -class CList(Frame): - def __init__(self,parent,labels,disablesorting=0,**kw): - Frame.__init__(self,parent) - self.labels=labels - self.lists=[] - self.disablesorting=disablesorting - kw["exportselection"]=0 - for i in range(len(labels)): - b=Button(self,text=labels[i],anchor=W,height=1,pady=0) - b.config(command=lambda s=self,i=i:s.setSort(i)) - b.grid(column=i,row=0,sticky=N+E+W) - box=apply(Listbox,(self,),kw) - box.grid(column=i,row=1,sticky=N+E+S+W) - self.lists.append(box) - grid_setexpand(self) - self.rowconfigure(0,weight=0) - self._callall("bind",'',self.Button1) - self._callall("bind",'',self.Button1) - self.bind('',self.UpKey) - self.bind('',self.DownKey) - self.sort=None - - def _callall(self,funcname,*args,**kw): - rets=[] - for l in self.lists: - func=getattr(l,funcname) - ret=apply(func,args,kw) - if ret!=None: rets.append(ret) - if rets: return rets - - def Button1(self,e): - index=self.nearest(e.y) - self.select_clear(0,END) - self.select_set(index) - self.activate(index) - return "break" - - def UpKey(self,e): - index=self.index(ACTIVE) - if index: - self.select_clear(0,END) - self.select_set(index-1) - return "break" - - def DownKey(self,e): - index=self.index(ACTIVE) - if index!=self.size()-1: - self.select_clear(0,END) - self.select_set(index+1) - return "break" - - def setSort(self,index): - if self.sort==None: - self.sort=[index,1] - elif self.sort[0]==index: - self.sort[1]=-self.sort[1] - else: - self.sort=[index,1] - self._sort() - - def _sort(self): - if self.disablesorting: - return - if self.sort==None: - return - ind,direc=self.sort - li=list(self.get(0,END)) - li.sort(lambda x,y,i=ind,d=direc:d*cmp(x[i],y[i])) - self.delete(0,END) - for l in li: - self._insert(END,l) - def activate(self,index): - self._callall("activate",index) - - # def bbox(self,index): - # return self._callall("bbox",index) - - def curselection(self): - return self.lists[0].curselection() - - def delete(self,*args): - apply(self._callall,("delete",)+args) - - def get(self,*args): - bad=apply(self._callall,("get",)+args) - if len(args)==1: - return bad - ret=[] - for i in range(len(bad[0])): - r=[] - for j in range(len(bad)): - r.append(bad[j][i]) - ret.append(r) - return ret - - def index(self,index): - return self.lists[0].index(index) - - def insert(self,index,items): - self._insert(index,items) - self._sort() - - def _insert(self,index,items): - for i in range(len(items)): - self.lists[i].insert(index,items[i]) - - def nearest(self,y): - return self.lists[0].nearest(y) - - def see(self,index): - self._callall("see",index) - - def size(self): - return self.lists[0].size() - - def selection_anchor(self,index): - self._callall("selection_anchor",index) - - select_anchor=selection_anchor - - def selection_clear(self,*args): - apply(self._callall,("selection_clear",)+args) - - select_clear=selection_clear - - def selection_includes(self,index): - return self.lists[0].select_includes(index) - - select_includes=selection_includes - - def selection_set(self,*args): - apply(self._callall,("selection_set",)+args) - - select_set=selection_set - - def xview(self,*args): - if not args: return self.lists[0].xview() - apply(self._callall,("xview",)+args) - - def yview(self,*args): - if not args: return self.lists[0].yview() - apply(self._callall,("yview",)+args) - -class ProgressBar: - def __init__(self, master=None, orientation="horizontal", - min=0, max=100, width=100, height=18, - doLabel=1, appearance="sunken", - fillColor="blue", background="gray", - labelColor="yellow", labelFont="Verdana", - labelText="", labelFormat="%d%%", - value=0, bd=2): - # preserve various values - self.master=master - self.orientation=orientation - self.min=min - self.max=max - self.width=width - self.height=height - self.doLabel=doLabel - self.fillColor=fillColor - self.labelFont= labelFont - self.labelColor=labelColor - self.background=background - self.labelText=labelText - self.labelFormat=labelFormat - self.value=value - self.frame=Frame(master, relief=appearance, bd=bd) - self.canvas=Canvas(self.frame, height=height, width=width, bd=0, - highlightthickness=0, background=background) - self.scale=self.canvas.create_rectangle(0, 0, width, height, - fill=fillColor) - self.label=self.canvas.create_text(self.canvas.winfo_reqwidth() / 2, - height / 2, text=labelText, - anchor="c", fill=labelColor, - font=self.labelFont) - self.update() - self.canvas.pack(side='top', fill='x', expand='no') - - def updateProgress(self, newValue, newMax=None): - if newMax: - self.max = newMax - self.value = newValue - self.update() - - def update(self): - # Trim the values to be between min and max - value=self.value - if value > self.max: - value = self.max - if value < self.min: - value = self.min - # Adjust the rectangle - if self.orientation == "horizontal": - self.canvas.coords(self.scale, 0, 0, - float(value) / self.max * self.width, self.height) - else: - self.canvas.coords(self.scale, 0, - self.height - (float(value) / - self.max*self.height), - self.width, self.height) - # Now update the colors - self.canvas.itemconfig(self.scale, fill=self.fillColor) - self.canvas.itemconfig(self.label, fill=self.labelColor) - # And update the label - if self.doLabel: - if value: - if value >= 0: - pvalue = int((float(value) / float(self.max)) * - 100.0) - else: - pvalue = 0 - self.canvas.itemconfig(self.label, text=self.labelFormat - % pvalue) - else: - self.canvas.itemconfig(self.label, text='') - else: - self.canvas.itemconfig(self.label, text=self.labelFormat % - self.labelText) - self.canvas.update_idletasks() - -class DirectoryBrowser(_Dialog): - command = "tk_chooseDirectory" - -def askdirectory(**options): - "Ask for a directory to save to." - - return apply(DirectoryBrowser, (), options).show() - -class GenericLogin(Toplevel): - def __init__(self,callback,buttons): - Toplevel.__init__(self) - self.callback=callback - Label(self,text="Twisted v%s"%copyright.version).grid(column=0,row=0,columnspan=2) - self.entries={} - row=1 - for stuff in buttons: - label,value=stuff[:2] - if len(stuff)==3: - dict=stuff[2] - else: dict={} - Label(self,text=label+": ").grid(column=0,row=row) - e=apply(Entry,(self,),dict) - e.grid(column=1,row=row) - e.insert(0,value) - self.entries[label]=e - row=row+1 - Button(self,text="Login",command=self.doLogin).grid(column=0,row=row) - Button(self,text="Cancel",command=self.close).grid(column=1,row=row) - self.protocol('WM_DELETE_WINDOW',self.close) - - def close(self): - self.tk.quit() - self.destroy() - - def doLogin(self): - values={} - for k in self.entries.keys(): - values[string.lower(k)]=self.entries[k].get() - self.callback(values) - self.destroy() - -class Login(Toplevel): - def __init__(self, - callback, - referenced = None, - initialUser = "guest", - initialPassword = "guest", - initialHostname = "localhost", - initialService = "", - initialPortno = pb.portno): - Toplevel.__init__(self) - version_label = Label(self,text="Twisted v%s" % copyright.version) - self.pbReferenceable = referenced - self.pbCallback = callback - # version_label.show() - self.username = Entry(self) - self.password = Entry(self,show='*') - self.hostname = Entry(self) - self.service = Entry(self) - self.port = Entry(self) - - self.username.insert(0,initialUser) - self.password.insert(0,initialPassword) - self.service.insert(0,initialService) - self.hostname.insert(0,initialHostname) - self.port.insert(0,str(initialPortno)) - - userlbl=Label(self,text="Username:") - passlbl=Label(self,text="Password:") - servicelbl=Label(self,text="Service:") - hostlbl=Label(self,text="Hostname:") - portlbl=Label(self,text="Port #:") - self.logvar=StringVar() - self.logvar.set("Protocol PB-%s"%pb.Broker.version) - self.logstat = Label(self,textvariable=self.logvar) - self.okbutton = Button(self,text="Log In", command=self.login) - - version_label.grid(column=0,row=0,columnspan=2) - z=0 - for i in [[userlbl,self.username], - [passlbl,self.password], - [hostlbl,self.hostname], - [servicelbl,self.service], - [portlbl,self.port]]: - i[0].grid(column=0,row=z+1) - i[1].grid(column=1,row=z+1) - z = z+1 - - self.logstat.grid(column=0,row=6,columnspan=2) - self.okbutton.grid(column=0,row=7,columnspan=2) - - self.protocol('WM_DELETE_WINDOW',self.tk.quit) - - def loginReset(self): - self.logvar.set("Idle.") - - def loginReport(self, txt): - self.logvar.set(txt) - self.after(30000, self.loginReset) - - def login(self): - host = self.hostname.get() - port = self.port.get() - service = self.service.get() - try: - port = int(port) - except: - pass - user = self.username.get() - pswd = self.password.get() - pb.connect(host, port, user, pswd, service, - client=self.pbReferenceable).addCallback(self.pbCallback).addErrback( - self.couldNotConnect) - - def couldNotConnect(self,f): - self.loginReport("could not connect:"+f.getErrorMessage()) - -if __name__=="__main__": - root=Tk() - o=CList(root,["Username","Online","Auto-Logon","Gateway"]) - o.pack() - for i in range(0,16,4): - o.insert(END,[i,i+1,i+2,i+3]) - mainloop() diff --git a/tools/buildbot/pylibs/twisted/spread/util.py b/tools/buildbot/pylibs/twisted/spread/util.py deleted file mode 100644 index d4f44d5..0000000 --- a/tools/buildbot/pylibs/twisted/spread/util.py +++ /dev/null @@ -1,215 +0,0 @@ -# -*- test-case-name: twisted.test.test_pb -*- - -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Utility classes for spread. -""" - -from twisted.internet import defer -from twisted.python.failure import Failure -from twisted.spread import pb -from twisted.protocols import basic -from twisted.internet import interfaces - -from zope.interface import implements - - -class LocalMethod: - def __init__(self, local, name): - self.local = local - self.name = name - - def __call__(self, *args, **kw): - return self.local.callRemote(self.name, *args, **kw) - - -class LocalAsRemote: - """ - A class useful for emulating the effects of remote behavior locally. - """ - reportAllTracebacks = 1 - - def callRemote(self, name, *args, **kw): - """ - Call a specially-designated local method. - - self.callRemote('x') will first try to invoke a method named - sync_x and return its result (which should probably be a - Deferred). Second, it will look for a method called async_x, - which will be called and then have its result (or Failure) - automatically wrapped in a Deferred. - """ - if hasattr(self, 'sync_'+name): - return getattr(self, 'sync_'+name)(*args, **kw) - try: - method = getattr(self, "async_" + name) - return defer.succeed(method(*args, **kw)) - except: - f = Failure() - if self.reportAllTracebacks: - f.printTraceback() - return defer.fail(f) - - def remoteMethod(self, name): - return LocalMethod(self, name) - - -class LocalAsyncForwarder: - """ - A class useful for forwarding a locally-defined interface. - """ - - def __init__(self, forwarded, interfaceClass, failWhenNotImplemented=0): - assert interfaceClass.providedBy(forwarded) - self.forwarded = forwarded - self.interfaceClass = interfaceClass - self.failWhenNotImplemented = failWhenNotImplemented - - def _callMethod(self, method, *args, **kw): - return getattr(self.forwarded, method)(*args, **kw) - - def callRemote(self, method, *args, **kw): - if self.interfaceClass.queryDescriptionFor(method): - result = defer.maybeDeferred(self._callMethod, method, *args, **kw) - return result - elif self.failWhenNotImplemented: - return defer.fail( - Failure(NotImplementedError, - "No Such Method in Interface: %s" % method)) - else: - return defer.succeed(None) - - -class Pager: - """ - I am an object which pages out information. - """ - def __init__(self, collector, callback=None, *args, **kw): - """ - Create a pager with a Reference to a remote collector and - an optional callable to invoke upon completion. - """ - if callable(callback): - self.callback = callback - self.callbackArgs = args - self.callbackKeyword = kw - else: - self.callback = None - self._stillPaging = 1 - self.collector = collector - collector.broker.registerPageProducer(self) - - def stillPaging(self): - """ - (internal) Method called by Broker. - """ - if not self._stillPaging: - self.collector.callRemote("endedPaging") - if self.callback is not None: - self.callback(*self.callbackArgs, **self.callbackKeyword) - return self._stillPaging - - def sendNextPage(self): - """ - (internal) Method called by Broker. - """ - self.collector.callRemote("gotPage", self.nextPage()) - - def nextPage(self): - """ - Override this to return an object to be sent to my collector. - """ - raise NotImplementedError() - - def stopPaging(self): - """ - Call this when you're done paging. - """ - self._stillPaging = 0 - - -class StringPager(Pager): - """ - A simple pager that splits a string into chunks. - """ - def __init__(self, collector, st, chunkSize=8192, callback=None, *args, **kw): - self.string = st - self.pointer = 0 - self.chunkSize = chunkSize - Pager.__init__(self, collector, callback, *args, **kw) - - def nextPage(self): - val = self.string[self.pointer:self.pointer+self.chunkSize] - self.pointer += self.chunkSize - if self.pointer >= len(self.string): - self.stopPaging() - return val - - -class FilePager(Pager): - """ - Reads a file in chunks and sends the chunks as they come. - """ - implements(interfaces.IConsumer) - - def __init__(self, collector, fd, callback=None, *args, **kw): - self.chunks = [] - Pager.__init__(self, collector, callback, *args, **kw) - self.startProducing(fd) - - def startProducing(self, fd): - self.deferred = basic.FileSender().beginFileTransfer(fd, self) - self.deferred.addBoth(lambda x : self.stopPaging()) - - def registerProducer(self, producer, streaming): - self.producer = producer - if not streaming: - self.producer.resumeProducing() - - def unregisterProducer(self): - self.producer = None - - def write(self, chunk): - self.chunks.append(chunk) - - def sendNextPage(self): - """ - Get the first chunk read and send it to collector. - """ - if not self.chunks: - return - val = self.chunks.pop(0) - self.producer.resumeProducing() - self.collector.callRemote("gotPage", val) - - -# Utility paging stuff. -class CallbackPageCollector(pb.Referenceable): - """ - I receive pages from the peer. You may instantiate a Pager with a - remote reference to me. I will call the callback with a list of pages - once they are all received. - """ - def __init__(self, callback): - self.pages = [] - self.callback = callback - - def remote_gotPage(self, page): - self.pages.append(page) - - def remote_endedPaging(self): - self.callback(self.pages) - - -def getAllPages(referenceable, methodName, *args, **kw): - """ - A utility method that will call a remote method which expects a - PageCollector as the first argument. - """ - d = defer.Deferred() - referenceable.callRemote(methodName, CallbackPageCollector(d.callback), *args, **kw) - return d - diff --git a/tools/buildbot/pylibs/twisted/tap/__init__.py b/tools/buildbot/pylibs/twisted/tap/__init__.py deleted file mode 100644 index 2428714..0000000 --- a/tools/buildbot/pylibs/twisted/tap/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" - -Twisted TAP: Twisted Application Persistence builders for other Twisted servers. - -""" diff --git a/tools/buildbot/pylibs/twisted/tap/ftp.py b/tools/buildbot/pylibs/twisted/tap/ftp.py deleted file mode 100644 index ae60955..0000000 --- a/tools/buildbot/pylibs/twisted/tap/ftp.py +++ /dev/null @@ -1,51 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -I am the support module for making a ftp server with mktap. -""" - -from twisted.protocols import ftp -from twisted.python import usage -from twisted.application import internet -from twisted.cred import error, portal, checkers, credentials - -import os.path - - -class Options(usage.Options): - synopsis = """Usage: mktap ftp [options]. - WARNING: This FTP server is probably INSECURE do not use it. - """ - optParameters = [ - ["port", "p", "2121", "set the port number"], - ["root", "r", "/usr/local/ftp", "define the root of the ftp-site."], - ["userAnonymous", "", "anonymous", "Name of the anonymous user."], - ["password-file", "", None, "username:password-style credentials database"], - ] - - longdesc = '' - - -def makeService(config): - f = ftp.FTPFactory() - - r = ftp.FTPRealm(config['root']) - p = portal.Portal(r) - p.registerChecker(checkers.AllowAnonymousAccess(), credentials.IAnonymous) - - if config['password-file'] is not None: - p.registerChecker(checkers.FilePasswordDB(config['password-file'], cache=True)) - - f.tld = config['root'] - f.userAnonymous = config['userAnonymous'] - f.portal = p - f.protocol = ftp.FTP - - try: - portno = int(config['port']) - except KeyError: - portno = 2121 - return internet.TCPServer(portno, f) diff --git a/tools/buildbot/pylibs/twisted/tap/manhole.py b/tools/buildbot/pylibs/twisted/tap/manhole.py deleted file mode 100644 index 33e8b11..0000000 --- a/tools/buildbot/pylibs/twisted/tap/manhole.py +++ /dev/null @@ -1,51 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -I am the support module for making a manhole server with mktap. -""" - -from twisted.manhole import service -from twisted.spread import pb -from twisted.python import usage, util -from twisted.cred import portal, checkers -from twisted.application import strports -import os, sys - -class Options(usage.Options): - synopsis = "mktap manhole [options]" - optParameters = [ - ["user", "u", "admin", "Name of user to allow to log in"], - ["port", "p", str(pb.portno), "Port to listen on"], - ] - - optFlags = [ - ["tracebacks", "T", "Allow tracebacks to be sent over the network"], - ] - zsh_actions = {"user" : "_users"} - - def opt_password(self, password): - """Required. '-' will prompt or read a password from stdin. - """ - # If standard input is a terminal, I prompt for a password and - # confirm it. Otherwise, I use the first line from standard - # input, stripping off a trailing newline if there is one. - if password in ('', '-'): - self['password'] = util.getPassword(confirm=1) - else: - self['password'] = password - opt_w = opt_password - - def postOptions(self): - if not self.has_key('password'): - self.opt_password('-') - -def makeService(config): - port, user, password = config['port'], config['user'], config['password'] - p = portal.Portal( - service.Realm(service.Service(config["tracebacks"], config.get('namespace'))), - [checkers.InMemoryUsernamePasswordDatabaseDontUse(**{user: password})] - ) - return strports.service(port, pb.PBServerFactory(p, config["tracebacks"])) diff --git a/tools/buildbot/pylibs/twisted/tap/portforward.py b/tools/buildbot/pylibs/twisted/tap/portforward.py deleted file mode 100644 index 3f07116..0000000 --- a/tools/buildbot/pylibs/twisted/tap/portforward.py +++ /dev/null @@ -1,24 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Support module for making a port forwarder with mktap. -""" -from twisted.protocols import portforward -from twisted.python import usage -from twisted.application import strports - -class Options(usage.Options): - synopsis = "Usage: mktap portforward [options]" - longdesc = 'Port Forwarder.' - optParameters = [ - ["port", "p", "6666","Set the port number."], - ["host", "h", "localhost","Set the host."], - ["dest_port", "d", 6665,"Set the destination port."], - ] - zsh_actions = {"host" : "_hosts"} - -def makeService(config): - f = portforward.ProxyFactory(config['host'], int(config['dest_port'])) - return strports.service(config['port'], f) diff --git a/tools/buildbot/pylibs/twisted/tap/socks.py b/tools/buildbot/pylibs/twisted/tap/socks.py deleted file mode 100644 index 57b2866..0000000 --- a/tools/buildbot/pylibs/twisted/tap/socks.py +++ /dev/null @@ -1,34 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -I am a support module for making SOCKSv4 servers with mktap. -""" - -from twisted.protocols import socks -from twisted.python import usage -from twisted.application import internet -import sys - -class Options(usage.Options): - synopsis = "Usage: mktap socks [-i ] [-p ] [-l ]" - optParameters = [["interface", "i", "127.0.0.1", "local interface to which we listen"], - ["port", "p", 1080, "Port on which to listen"], - ["log", "l", None, "file to log connection data to"]] - zsh_actions = {"log" : "_files -g '*.log'"} - - longdesc = "Makes a SOCKSv4 server." - -def makeService(config): - if config["interface"] != "127.0.0.1": - print - print "WARNING:" - print " You have chosen to listen on a non-local interface." - print " This may allow intruders to access your local network" - print " if you run this on a firewall." - print - t = socks.SOCKSv4Factory(config['log']) - portno = int(config['port']) - return internet.TCPServer(portno, t, interface=config['interface']) diff --git a/tools/buildbot/pylibs/twisted/tap/telnet.py b/tools/buildbot/pylibs/twisted/tap/telnet.py deleted file mode 100644 index c27235e..0000000 --- a/tools/buildbot/pylibs/twisted/tap/telnet.py +++ /dev/null @@ -1,29 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Support module for making a telnet server with mktap. -""" - -from twisted.manhole import telnet -from twisted.python import usage -from twisted.application import strports - -class Options(usage.Options): - synopsis = "Usage: mktap telnet [options]" - longdesc = "Makes a telnet server to a Python shell." - optParameters = [ - ["username", "u", "admin","set the login username"], - ["password", "w", "changeme","set the password"], - ["port", "p", "4040", "port to listen on"], - ] - zsh_actions = {"username":"_users"} - -def makeService(config): - t = telnet.ShellFactory() - t.username, t.password = config['username'], config['password'] - s = strports.service(config['port'], t) - t.setService(s) - return s diff --git a/tools/buildbot/pylibs/twisted/test/__init__.py b/tools/buildbot/pylibs/twisted/test/__init__.py deleted file mode 100644 index 85a53c7..0000000 --- a/tools/buildbot/pylibs/twisted/test/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" - -Twisted Test: Unit Tests for Twisted. - -""" diff --git a/tools/buildbot/pylibs/twisted/test/app_qtstub.py b/tools/buildbot/pylibs/twisted/test/app_qtstub.py deleted file mode 100644 index aa0c527..0000000 --- a/tools/buildbot/pylibs/twisted/test/app_qtstub.py +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright (c) 2006 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -L{twisted.test.test_application.PluggableReactorTestCase.test_qtStub} uses -this helper program to test that when the QT reactor plugin is not -available, an attempt to select it via the deprecated name C{qt} fails -appropriately. - -When installation fails, no output is produced. When it succeeds, a message -is printed. -""" - -import sys - -from twisted.application import reactors - - -class QTNotImporter: - """ - Import hook which unilaterally rejects any attempt to import - C{qtreactor} so that we can reliably test the behavior of attempting to - install it when it is not present. - """ - def find_module(self, fullname, path): - """ - Reject attempts to import C{qtreactor}. Ignore everything else. - """ - if fullname == 'qtreactor': - raise ImportError('qtreactor does not exist!') - - - -def main(): - """ - Try to install the reactor named C{qt}. Expect it to not work. Print - diagnostics to stdout if something goes wrong, print nothing otherwise. - """ - sys.meta_path.insert(0, QTNotImporter()) - try: - reactors.installReactor('qt') - except reactors.NoSuchReactor, e: - if e.args != ('qt',): - print 'Wrong arguments to NoSuchReactor:', e.args - else: - # Do nothing to indicate success. - pass - else: - print 'installed qtreactor succesfully' - sys.stdout.flush() - -if __name__ == '__main__': - main() diff --git a/tools/buildbot/pylibs/twisted/test/crash_test_dummy.py b/tools/buildbot/pylibs/twisted/test/crash_test_dummy.py deleted file mode 100644 index a508c60..0000000 --- a/tools/buildbot/pylibs/twisted/test/crash_test_dummy.py +++ /dev/null @@ -1,34 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -from twisted.python import components -from zope.interface import implements, Interface - -def foo(): - return 2 - -class X: - def __init__(self, x): - self.x = x - - def do(self): - #print 'X',self.x,'doing!' - pass - - -class XComponent(components.Componentized): - pass - -class IX(Interface): - pass - -class XA(components.Adapter): - implements(IX) - - def method(self): - # Kick start :( - pass - -components.registerAdapter(XA, X, IX) diff --git a/tools/buildbot/pylibs/twisted/test/generator_failure_tests.py b/tools/buildbot/pylibs/twisted/test/generator_failure_tests.py deleted file mode 100644 index 8c31c27..0000000 --- a/tools/buildbot/pylibs/twisted/test/generator_failure_tests.py +++ /dev/null @@ -1,169 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Python 2.5 test cases for failures thrown into generators. -""" - -import sys -import traceback - -from twisted.trial.unittest import TestCase - -from twisted.python.failure import Failure -from twisted.test.test_failure import getDivisionFailure -from twisted.internet import defer - - -class TwoPointFiveFailureTests(TestCase): - - def test_inlineCallbacksTracebacks(self): - """ - inlineCallbacks that re-raise tracebacks into their deferred - should not lose their tracebacsk. - """ - f = getDivisionFailure() - d = defer.Deferred() - try: - f.raiseException() - except: - d.errback() - - failures = [] - def collect_error(result): - failures.append(result) - - def ic(d): - yield d - ic = defer.inlineCallbacks(ic) - ic(d).addErrback(collect_error) - - newFailure, = failures - self.assertEquals( - traceback.extract_tb(newFailure.getTracebackObject())[-1][-1], - "1/0" - ) - - - def _throwIntoGenerator(self, f, g): - try: - f.throwExceptionIntoGenerator(g) - except StopIteration: - pass - else: - self.fail("throwExceptionIntoGenerator should have raised " - "StopIteration") - - def test_throwExceptionIntoGenerator(self): - """ - It should be possible to throw the exception that a Failure - represents into a generator. - """ - stuff = [] - def generator(): - try: - yield - except: - stuff.append(sys.exc_info()) - else: - self.fail("Yield should have yielded exception.") - g = generator() - f = getDivisionFailure() - g.next() - self._throwIntoGenerator(f, g) - - self.assertEquals(stuff[0][0], ZeroDivisionError) - self.assertTrue(isinstance(stuff[0][1], ZeroDivisionError)) - - self.assertEquals(traceback.extract_tb(stuff[0][2])[-1][-1], "1/0") - - - def test_findFailureInGenerator(self): - """ - Within an exception handler, it should be possible to find the - original Failure that caused the current exception (if it was - caused by throwExceptionIntoGenerator). - """ - f = getDivisionFailure() - f.cleanFailure() - - foundFailures = [] - def generator(): - try: - yield - except: - foundFailures.append(Failure._findFailure()) - else: - self.fail("No exception sent to generator") - - g = generator() - g.next() - self._throwIntoGenerator(f, g) - - self.assertEqual(foundFailures, [f]) - - - def test_failureConstructionFindsOriginalFailure(self): - """ - When a Failure is constructed in the context of an exception - handler that is handling an exception raised by - throwExceptionIntoGenerator, the new Failure should be chained to that - original Failure. - """ - f = getDivisionFailure() - f.cleanFailure() - - newFailures = [] - - def generator(): - try: - yield - except: - newFailures.append(Failure()) - else: - self.fail("No exception sent to generator") - g = generator() - g.next() - self._throwIntoGenerator(f, g) - - self.assertEqual(len(newFailures), 1) - self.assertEqual(newFailures[0].getTraceback(), f.getTraceback()) - - def test_ambiguousFailureInGenerator(self): - """ - When a generator reraises a different exception, - L{Failure._findFailure} inside the generator should find the reraised - exception rather than original one. - """ - def generator(): - try: - try: - yield - except: - [][1] - except: - self.assertIsInstance(Failure().value, IndexError) - g = generator() - g.next() - f = getDivisionFailure() - self._throwIntoGenerator(f, g) - - def test_ambiguousFailureFromGenerator(self): - """ - When a generator reraises a different exception, - L{Failure._findFailure} above the generator should find the reraised - exception rather than original one. - """ - def generator(): - try: - yield - except: - [][1] - g = generator() - g.next() - f = getDivisionFailure() - try: - self._throwIntoGenerator(f, g) - except: - self.assertIsInstance(Failure().value, IndexError) diff --git a/tools/buildbot/pylibs/twisted/test/iosim.py b/tools/buildbot/pylibs/twisted/test/iosim.py deleted file mode 100644 index e420661..0000000 --- a/tools/buildbot/pylibs/twisted/test/iosim.py +++ /dev/null @@ -1,275 +0,0 @@ -# -*- test-case-name: twisted.test.test_amp.TLSTest -*- -"""Utilities and helpers for simulating a network -""" - -import itertools - - -from zope.interface import implements, directlyProvides - -from twisted.internet import error -from twisted.internet import interfaces -from OpenSSL.SSL import Error as NativeOpenSSLError - -from twisted.internet._sslverify import OpenSSLVerifyError - -class TLSNegotiation: - def __init__(self, obj, connectState): - self.obj = obj - self.connectState = connectState - self.sent = False - self.readyToSend = connectState - - def __repr__(self): - return 'TLSNegotiation(%r)' % (self.obj,) - - def pretendToVerify(self, other, tpt): - # Set the transport problems list here? disconnections? - # hmmmmm... need some negative path tests. - - if not self.obj.iosimVerify(other.obj): - tpt.problems.append(OpenSSLVerifyError("fake cert", "fake errno", "fake depth")) - tpt.disconnectReason = NativeOpenSSLError() - tpt.loseConnection() - - -class FakeTransport: - """A wrapper around a file-like object to make it behave as a Transport. - - This doesn't actually stream the file to the attached protocol, - and is thus useful mainly as a utility for debugging protocols. - """ - - implements(interfaces.ITransport, - interfaces.ITLSTransport) # ha ha not really - - _nextserial = itertools.count().next - closed = 0 - disconnecting = 0 - disconnected = 0 - disconnectReason = error.ConnectionDone("Connection done") - producer = None - streamingProducer = 0 - tls = None - - def __init__(self): - self.stream = [] - self.problems = [] - self.serial = self._nextserial() - - def __repr__(self): - return 'FakeTransport<%s,%s,%s>' % ( - self.isServer and 'S' or 'C', self.serial, - self.protocol.__class__.__name__) - - def write(self, data): - if self.tls is not None: - self.tlsbuf.append(data) - else: - self.stream.append(data) - - def _checkProducer(self): - # Cheating; this is called at "idle" times to allow producers to be - # found and dealt with - if self.producer: - self.producer.resumeProducing() - - def registerProducer(self, producer, streaming): - """From abstract.FileDescriptor - """ - self.producer = producer - self.streamingProducer = streaming - if not streaming: - producer.resumeProducing() - - def unregisterProducer(self): - self.producer = None - - def stopConsuming(self): - self.unregisterProducer() - self.loseConnection() - - def writeSequence(self, iovec): - self.write("".join(iovec)) - - def loseConnection(self): - self.disconnecting = True - - def reportDisconnect(self): - if self.tls is not None: - # We were in the middle of negotiating! Must have been a TLS problem. - err = NativeOpenSSLError() - else: - err = self.disconnectReason - self.protocol.connectionLost(err) - - def getPeer(self): - # XXX: According to ITransport, this should return an IAddress! - return 'file', 'file' - - def getHost(self): - # XXX: According to ITransport, this should return an IAddress! - return 'file' - - def resumeProducing(self): - # Never sends data anyways - pass - - def pauseProducing(self): - # Never sends data anyways - pass - - def stopProducing(self): - self.loseConnection() - - def startTLS(self, contextFactory, beNormal=True): - # Nothing's using this feature yet, but startTLS has an undocumented - # second argument which defaults to true; if set to False, servers will - # behave like clients and clients will behave like servers. - connectState = self.isServer ^ beNormal - self.tls = TLSNegotiation(contextFactory, connectState) - self.tlsbuf = [] - - def getOutBuffer(self): - S = self.stream - if S: - self.stream = [] - return ''.join(S) - elif self.tls is not None: - if self.tls.readyToSend: - # Only _send_ the TLS negotiation "packet" if I'm ready to. - self.tls.sent = True - return self.tls - else: - return None - else: - return None - - def bufferReceived(self, buf): - if isinstance(buf, TLSNegotiation): - assert self.tls is not None # By the time you're receiving a - # negotiation, you have to have called - # startTLS already. - if self.tls.sent: - self.tls.pretendToVerify(buf, self) - self.tls = None # we're done with the handshake if we've gotten - # this far... although maybe it failed...? - # TLS started! Unbuffer... - b, self.tlsbuf = self.tlsbuf, None - self.writeSequence(b) - directlyProvides(self, interfaces.ISSLTransport) - else: - # We haven't sent our own TLS negotiation: time to do that! - self.tls.readyToSend = True - else: - self.protocol.dataReceived(buf) - - - # this next bit is just to fake out problemsFromTransport, which is an - # ultra-shitty API anyway. remove it when we manage to remove that. -glyph - def getHandle(self): - return self - - get_context = getHandle - get_app_data = getHandle - - # end of gross problemsFromTransport stuff - -def makeFakeClient(c): - ft = FakeTransport() - ft.isServer = False - ft.protocol = c - return ft - -def makeFakeServer(s): - ft = FakeTransport() - ft.isServer = True - ft.protocol = s - return ft - -class IOPump: - """Utility to pump data between clients and servers for protocol testing. - - Perhaps this is a utility worthy of being in protocol.py? - """ - def __init__(self, client, server, clientIO, serverIO, debug): - self.client = client - self.server = server - self.clientIO = clientIO - self.serverIO = serverIO - self.debug = debug - - def flush(self, debug=False): - """Pump until there is no more input or output. - - Returns whether any data was moved. - """ - result = False - for x in range(1000): - if self.pump(debug): - result = True - else: - break - else: - assert 0, "Too long" - return result - - - def pump(self, debug=False): - """Move data back and forth. - - Returns whether any data was moved. - """ - if self.debug or debug: - print '-- GLUG --' - sData = self.serverIO.getOutBuffer() - cData = self.clientIO.getOutBuffer() - self.clientIO._checkProducer() - self.serverIO._checkProducer() - if self.debug or debug: - print '.' - # XXX slightly buggy in the face of incremental output - if cData: - print 'C: '+repr(cData) - if sData: - print 'S: '+repr(sData) - if cData: - self.serverIO.bufferReceived(cData) - if sData: - self.clientIO.bufferReceived(sData) - if cData or sData: - return True - if (self.serverIO.disconnecting and - not self.serverIO.disconnected): - if self.debug or debug: - print '* C' - self.serverIO.disconnected = True - self.clientIO.disconnecting = True - self.clientIO.reportDisconnect() - return True - if self.clientIO.disconnecting and not self.clientIO.disconnected: - if self.debug or debug: - print '* S' - self.clientIO.disconnected = True - self.serverIO.disconnecting = True - self.serverIO.reportDisconnect() - return True - return False - - -def connectedServerAndClient(ServerClass, ClientClass, - clientTransportFactory=makeFakeClient, - serverTransportFactory=makeFakeServer, - debug=False): - """Returns a 3-tuple: (client, server, pump) - """ - c = ClientClass() - s = ServerClass() - cio = clientTransportFactory(c) - sio = serverTransportFactory(s) - c.makeConnection(cio) - s.makeConnection(sio) - pump = IOPump(c, s, cio, sio, debug) - # kick off server greeting, etc - pump.flush() - return c, s, pump diff --git a/tools/buildbot/pylibs/twisted/test/mock_win32process.py b/tools/buildbot/pylibs/twisted/test/mock_win32process.py deleted file mode 100644 index 49ed953..0000000 --- a/tools/buildbot/pylibs/twisted/test/mock_win32process.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright (c) 2007-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -This is a mock win32process module. - -The purpose of this module is mock process creation for the PID test. - -CreateProcess(...) will spawn a process, and always return a PID of 42. -""" - -import win32process -GetExitCodeProcess = win32process.GetExitCodeProcess -STARTUPINFO = win32process.STARTUPINFO - -STARTF_USESTDHANDLES = win32process.STARTF_USESTDHANDLES - - -def CreateProcess(appName, - cmdline, - procSecurity, - threadSecurity, - inheritHandles, - newEnvironment, - env, - workingDir, - startupInfo): - """ - This function mocks the generated pid aspect of the win32.CreateProcess - function. - - the true win32process.CreateProcess is called - - return values are harvested in a tuple. - - all return values from createProcess are passed back to the calling - function except for the pid, the returned pid is hardcoded to 42 - """ - - hProcess, hThread, dwPid, dwTid = win32process.CreateProcess( - appName, - cmdline, - procSecurity, - threadSecurity, - inheritHandles, - newEnvironment, - env, - workingDir, - startupInfo) - dwPid = 42 - return (hProcess, hThread, dwPid, dwTid) diff --git a/tools/buildbot/pylibs/twisted/test/myrebuilder1.py b/tools/buildbot/pylibs/twisted/test/myrebuilder1.py deleted file mode 100644 index f53e8c7..0000000 --- a/tools/buildbot/pylibs/twisted/test/myrebuilder1.py +++ /dev/null @@ -1,15 +0,0 @@ - -class A: - def a(self): - return 'a' -try: - object -except NameError: - pass -else: - class B(object, A): - def b(self): - return 'b' -class Inherit(A): - def a(self): - return 'c' diff --git a/tools/buildbot/pylibs/twisted/test/myrebuilder2.py b/tools/buildbot/pylibs/twisted/test/myrebuilder2.py deleted file mode 100644 index d2a0d10..0000000 --- a/tools/buildbot/pylibs/twisted/test/myrebuilder2.py +++ /dev/null @@ -1,16 +0,0 @@ - -class A: - def a(self): - return 'b' -try: - object -except NameError: - pass -else: - class B(A, object): - def b(self): - return 'c' - -class Inherit(A): - def a(self): - return 'd' diff --git a/tools/buildbot/pylibs/twisted/test/plugin_basic.py b/tools/buildbot/pylibs/twisted/test/plugin_basic.py deleted file mode 100644 index 343a3c5..0000000 --- a/tools/buildbot/pylibs/twisted/test/plugin_basic.py +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright (c) 2005 Divmod, Inc. -# Copyright (c) 2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -# Don't change the docstring, it's part of the tests -""" -I'm a test drop-in. The plugin system's unit tests use me. No one -else should. -""" - -from zope.interface import classProvides - -from twisted.plugin import IPlugin -from twisted.test.test_plugin import ITestPlugin, ITestPlugin2 - - - -class TestPlugin: - """ - A plugin used solely for testing purposes. - """ - - classProvides(ITestPlugin, - IPlugin) - - def test1(): - pass - test1 = staticmethod(test1) - - - -class AnotherTestPlugin: - """ - Another plugin used solely for testing purposes. - """ - - classProvides(ITestPlugin2, - IPlugin) - - def test(): - pass - test = staticmethod(test) - - - -class ThirdTestPlugin: - """ - Another plugin used solely for testing purposes. - """ - - classProvides(ITestPlugin2, - IPlugin) - - def test(): - pass - test = staticmethod(test) - diff --git a/tools/buildbot/pylibs/twisted/test/plugin_extra1.py b/tools/buildbot/pylibs/twisted/test/plugin_extra1.py deleted file mode 100644 index bc1b3c0..0000000 --- a/tools/buildbot/pylibs/twisted/test/plugin_extra1.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (c) 2005 Divmod, Inc. -# Copyright (c) 2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test plugin used in L{twisted.test.test_plugin}. -""" - -from zope.interface import classProvides - -from twisted.plugin import IPlugin -from twisted.test.test_plugin import ITestPlugin - - - -class FourthTestPlugin: - classProvides(ITestPlugin, - IPlugin) - - def test1(): - pass - test1 = staticmethod(test1) - diff --git a/tools/buildbot/pylibs/twisted/test/plugin_extra2.py b/tools/buildbot/pylibs/twisted/test/plugin_extra2.py deleted file mode 100644 index 05ff992..0000000 --- a/tools/buildbot/pylibs/twisted/test/plugin_extra2.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright (c) 2005 Divmod, Inc. -# Copyright (c) 2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test plugin used in L{twisted.test.test_plugin}. -""" - -from zope.interface import classProvides - -from twisted.plugin import IPlugin -from twisted.test.test_plugin import ITestPlugin - - - -class FourthTestPlugin: - classProvides(ITestPlugin, - IPlugin) - - def test1(): - pass - test1 = staticmethod(test1) - - - -class FifthTestPlugin: - """ - More documentation: I hate you. - """ - classProvides(ITestPlugin, - IPlugin) - - def test1(): - pass - test1 = staticmethod(test1) diff --git a/tools/buildbot/pylibs/twisted/test/process_cmdline.py b/tools/buildbot/pylibs/twisted/test/process_cmdline.py deleted file mode 100644 index bd250de..0000000 --- a/tools/buildbot/pylibs/twisted/test/process_cmdline.py +++ /dev/null @@ -1,5 +0,0 @@ -"""Write to stdout the command line args it received, one per line.""" - -import sys -for x in sys.argv[1:]: - print x diff --git a/tools/buildbot/pylibs/twisted/test/process_echoer.py b/tools/buildbot/pylibs/twisted/test/process_echoer.py deleted file mode 100644 index 2f640bf..0000000 --- a/tools/buildbot/pylibs/twisted/test/process_echoer.py +++ /dev/null @@ -1,10 +0,0 @@ -"""Write back all data it receives.""" - -import sys - -data = sys.stdin.read(1) -while data: - sys.stdout.write(data) - data = sys.stdin.read(1) -sys.stderr.write("byebye") -sys.stderr.flush() diff --git a/tools/buildbot/pylibs/twisted/test/process_fds.py b/tools/buildbot/pylibs/twisted/test/process_fds.py deleted file mode 100644 index e2273c1..0000000 --- a/tools/buildbot/pylibs/twisted/test/process_fds.py +++ /dev/null @@ -1,40 +0,0 @@ - -"""Write to a handful of file descriptors, to test the childFDs= argument of -reactor.spawnProcess() -""" - -import os, sys - -debug = 0 - -if debug: stderr = os.fdopen(2, "w") - -if debug: print >>stderr, "this is stderr" - -abcd = os.read(0, 4) -if debug: print >>stderr, "read(0):", abcd -if abcd != "abcd": - sys.exit(1) - -if debug: print >>stderr, "os.write(1, righto)" - -os.write(1, "righto") - -efgh = os.read(3, 4) -if debug: print >>stderr, "read(3):", efgh -if efgh != "efgh": - sys.exit(2) - -if debug: print >>stderr, "os.close(4)" -os.close(4) - -eof = os.read(5, 4) -if debug: print >>stderr, "read(5):", eof -if eof != "": - sys.exit(3) - -if debug: print >>stderr, "os.write(1, closed)" -os.write(1, "closed") - -if debug: print >>stderr, "sys.exit(0)" -sys.exit(0) diff --git a/tools/buildbot/pylibs/twisted/test/process_linger.py b/tools/buildbot/pylibs/twisted/test/process_linger.py deleted file mode 100644 index a95a8d2..0000000 --- a/tools/buildbot/pylibs/twisted/test/process_linger.py +++ /dev/null @@ -1,17 +0,0 @@ - -"""Write to a file descriptor and then close it, waiting a few seconds before -quitting. This serves to make sure SIGCHLD is actually being noticed. -""" - -import os, sys, time - -print "here is some text" -time.sleep(1) -print "goodbye" -os.close(1) -os.close(2) - -time.sleep(2) - -sys.exit(0) - diff --git a/tools/buildbot/pylibs/twisted/test/process_reader.py b/tools/buildbot/pylibs/twisted/test/process_reader.py deleted file mode 100644 index be37a7c..0000000 --- a/tools/buildbot/pylibs/twisted/test/process_reader.py +++ /dev/null @@ -1,12 +0,0 @@ -"""Script used by test_process.TestTwoProcesses""" - -# run until stdin is closed, then quit - -import sys - -while 1: - d = sys.stdin.read() - if len(d) == 0: - sys.exit(0) - - diff --git a/tools/buildbot/pylibs/twisted/test/process_signal.py b/tools/buildbot/pylibs/twisted/test/process_signal.py deleted file mode 100644 index f2ff108..0000000 --- a/tools/buildbot/pylibs/twisted/test/process_signal.py +++ /dev/null @@ -1,8 +0,0 @@ -import sys, signal - -signal.signal(signal.SIGINT, signal.SIG_DFL) -if getattr(signal, "SIGHUP", None) is not None: - signal.signal(signal.SIGHUP, signal.SIG_DFL) -print 'ok, signal us' -sys.stdin.read() -sys.exit(1) diff --git a/tools/buildbot/pylibs/twisted/test/process_stdinreader.py b/tools/buildbot/pylibs/twisted/test/process_stdinreader.py deleted file mode 100644 index 9de453d8..0000000 --- a/tools/buildbot/pylibs/twisted/test/process_stdinreader.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -"""Script used by twisted.test.test_process on win32.""" - -import sys, time, os, msvcrt -msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) -msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY) - - -sys.stdout.write("out\n") -sys.stdout.flush() -sys.stderr.write("err\n") -sys.stderr.flush() - -data = sys.stdin.read() - -sys.stdout.write(data) -sys.stdout.write("\nout\n") -sys.stderr.write("err\n") - -sys.stdout.flush() -sys.stderr.flush() diff --git a/tools/buildbot/pylibs/twisted/test/process_tester.py b/tools/buildbot/pylibs/twisted/test/process_tester.py deleted file mode 100644 index d9779b1..0000000 --- a/tools/buildbot/pylibs/twisted/test/process_tester.py +++ /dev/null @@ -1,37 +0,0 @@ -"""Test program for processes.""" - -import sys, os - -test_file_match = "process_test.log.*" -test_file = "process_test.log.%d" % os.getpid() - -def main(): - f = open(test_file, 'wb') - - # stage 1 - bytes = sys.stdin.read(4) - f.write("one: %r\n" % bytes) - # stage 2 - sys.stdout.write(bytes) - sys.stdout.flush() - os.close(sys.stdout.fileno()) - - # and a one, and a two, and a... - bytes = sys.stdin.read(4) - f.write("two: %r\n" % bytes) - - # stage 3 - sys.stderr.write(bytes) - sys.stderr.flush() - os.close(sys.stderr.fileno()) - - # stage 4 - bytes = sys.stdin.read(4) - f.write("three: %r\n" % bytes) - - # exit with status code 23 - sys.exit(23) - - -if __name__ == '__main__': - main() diff --git a/tools/buildbot/pylibs/twisted/test/process_tty.py b/tools/buildbot/pylibs/twisted/test/process_tty.py deleted file mode 100644 index 9dab638..0000000 --- a/tools/buildbot/pylibs/twisted/test/process_tty.py +++ /dev/null @@ -1,6 +0,0 @@ -"""Test to make sure we can open /dev/tty""" - -f = open("/dev/tty", "r+") -a = f.readline() -f.write(a) -f.close() diff --git a/tools/buildbot/pylibs/twisted/test/process_twisted.py b/tools/buildbot/pylibs/twisted/test/process_twisted.py deleted file mode 100644 index e31c7e2..0000000 --- a/tools/buildbot/pylibs/twisted/test/process_twisted.py +++ /dev/null @@ -1,43 +0,0 @@ -"""A process that reads from stdin and out using Twisted.""" - -### Twisted Preamble -# This makes sure that users don't have to set up their environment -# specially in order to run these programs from bin/. -import sys, os, string -pos = string.find(os.path.abspath(sys.argv[0]), os.sep+'Twisted') -if pos != -1: - sys.path.insert(0, os.path.abspath(sys.argv[0])[:pos+8]) -sys.path.insert(0, os.curdir) -### end of preamble - - -from twisted.python import log -from zope.interface import implements -from twisted.internet import interfaces - -log.startLogging(sys.stderr) - -from twisted.internet import protocol, reactor, stdio - - -class Echo(protocol.Protocol): - implements(interfaces.IHalfCloseableProtocol) - - def connectionMade(self): - print "connection made" - - def dataReceived(self, data): - self.transport.write(data) - - def readConnectionLost(self): - print "readConnectionLost" - self.transport.loseConnection() - def writeConnectionLost(self): - print "writeConnectionLost" - - def connectionLost(self, reason): - print "connectionLost", reason - reactor.stop() - -stdio.StandardIO(Echo()) -reactor.run() diff --git a/tools/buildbot/pylibs/twisted/test/proto_helpers.py b/tools/buildbot/pylibs/twisted/test/proto_helpers.py deleted file mode 100644 index c0bd3de..0000000 --- a/tools/buildbot/pylibs/twisted/test/proto_helpers.py +++ /dev/null @@ -1,93 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -try: - from cStringIO import StringIO -except ImportError: - from StringIO import StringIO - -from twisted.protocols import basic -from twisted.internet import error - - -class LineSendingProtocol(basic.LineReceiver): - lostConn = False - - def __init__(self, lines, start = True): - self.lines = lines[:] - self.response = [] - self.start = start - - def connectionMade(self): - if self.start: - map(self.sendLine, self.lines) - - def lineReceived(self, line): - if not self.start: - map(self.sendLine, self.lines) - self.lines = [] - self.response.append(line) - - def connectionLost(self, reason): - self.lostConn = True - - -class FakeDatagramTransport: - noAddr = object() - - def __init__(self): - self.written = [] - - def write(self, packet, addr=noAddr): - self.written.append((packet, addr)) - - -class StringTransport: - disconnecting = 0 - - hostAddr = None - peerAddr = None - - def __init__(self, hostAddress=None, peerAddress=None): - self.clear() - if hostAddress is not None: - self.hostAddr = hostAddress - if peerAddress is not None: - self.peerAddr = peerAddress - self.connected = True - - def clear(self): - self.io = StringIO() - - def value(self): - return self.io.getvalue() - - def write(self, data): - if isinstance(data, unicode): # no, really, I mean it - raise TypeError("Data must not be unicode") - self.io.write(data) - - def writeSequence(self, data): - self.io.write(''.join(data)) - - def loseConnection(self): - pass - - def getPeer(self): - if self.peerAddr is None: - return ('StringIO', repr(self.io)) - return self.peerAddr - - def getHost(self): - if self.hostAddr is None: - return ('StringIO', repr(self.io)) - return self.hostAddr - - -class StringTransportWithDisconnection(StringTransport): - def loseConnection(self): - if self.connected: - self.connected = False - self.protocol.connectionLost(error.ConnectionDone("Bye.")) - diff --git a/tools/buildbot/pylibs/twisted/test/raiser.c b/tools/buildbot/pylibs/twisted/test/raiser.c deleted file mode 100644 index d4c800c..0000000 --- a/tools/buildbot/pylibs/twisted/test/raiser.c +++ /dev/null @@ -1,316 +0,0 @@ -/* Generated by Pyrex 0.9.5.1a on Wed Apr 9 19:55:33 2008 */ - -#include "Python.h" -#include "structmember.h" -#ifndef PY_LONG_LONG - #define PY_LONG_LONG LONG_LONG -#endif -#ifdef __cplusplus -#define __PYX_EXTERN_C extern "C" -#else -#define __PYX_EXTERN_C extern -#endif -__PYX_EXTERN_C double pow(double, double); - - -typedef struct {PyObject **p; char *s;} __Pyx_InternTabEntry; /*proto*/ -typedef struct {PyObject **p; char *s; long n;} __Pyx_StringTabEntry; /*proto*/ - -static PyObject *__pyx_m; -static PyObject *__pyx_b; -static int __pyx_lineno; -static char *__pyx_filename; -static char **__pyx_f; - -static char __pyx_mdoc[] = "\nA trivial extension that just raises an exception.\nSee L{twisted.test.test_failure.test_failureConstructionWithMungedStackSucceeds}.\n"; - -static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name); /*proto*/ - -static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name, char *modname); /*proto*/ - -static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb); /*proto*/ - -static int __Pyx_InternStrings(__Pyx_InternTabEntry *t); /*proto*/ - -static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); /*proto*/ - -static void __Pyx_AddTraceback(char *funcname); /*proto*/ - -/* Declarations from raiser */ - - - -/* Implementation of raiser */ - -static char (__pyx_k2[]) = "\n A speficic exception only used to be identified in tests.\n "; - -static PyObject *__pyx_n_RaiserException; -static PyObject *__pyx_n_raiseException; -static PyObject *__pyx_n_Exception; - -static PyObject *__pyx_k2p; - -static PyObject *__pyx_k3p; - -static char (__pyx_k3[]) = "This function is intentionally broken"; - -static PyObject *__pyx_f_6raiser_raiseException(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static char __pyx_doc_6raiser_raiseException[] = "\n Raise L{RaiserException}.\n "; -static PyObject *__pyx_f_6raiser_raiseException(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_r; - PyObject *__pyx_1 = 0; - PyObject *__pyx_2 = 0; - PyObject *__pyx_3 = 0; - static char *__pyx_argnames[] = {0}; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "", __pyx_argnames)) return 0; - - /* "/home/therve/Projects/Twisted/branches/failure-c-extension-3132/twisted/test/raiser.pyx":21 */ - __pyx_1 = __Pyx_GetName(__pyx_m, __pyx_n_RaiserException); if (!__pyx_1) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 21; goto __pyx_L1;} - __pyx_2 = PyTuple_New(1); if (!__pyx_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 21; goto __pyx_L1;} - Py_INCREF(__pyx_k3p); - PyTuple_SET_ITEM(__pyx_2, 0, __pyx_k3p); - __pyx_3 = PyObject_CallObject(__pyx_1, __pyx_2); if (!__pyx_3) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 21; goto __pyx_L1;} - Py_DECREF(__pyx_1); __pyx_1 = 0; - Py_DECREF(__pyx_2); __pyx_2 = 0; - __Pyx_Raise(__pyx_3, 0, 0); - Py_DECREF(__pyx_3); __pyx_3 = 0; - {__pyx_filename = __pyx_f[0]; __pyx_lineno = 21; goto __pyx_L1;} - - __pyx_r = Py_None; Py_INCREF(Py_None); - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_1); - Py_XDECREF(__pyx_2); - Py_XDECREF(__pyx_3); - __Pyx_AddTraceback("raiser.raiseException"); - __pyx_r = 0; - __pyx_L0:; - return __pyx_r; -} - -static __Pyx_InternTabEntry __pyx_intern_tab[] = { - {&__pyx_n_Exception, "Exception"}, - {&__pyx_n_RaiserException, "RaiserException"}, - {&__pyx_n_raiseException, "raiseException"}, - {0, 0} -}; - -static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_k2p, __pyx_k2, sizeof(__pyx_k2)}, - {&__pyx_k3p, __pyx_k3, sizeof(__pyx_k3)}, - {0, 0, 0} -}; - -static struct PyMethodDef __pyx_methods[] = { - {"raiseException", (PyCFunction)__pyx_f_6raiser_raiseException, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6raiser_raiseException}, - {0, 0, 0, 0} -}; - -static void __pyx_init_filenames(void); /*proto*/ - -PyMODINIT_FUNC initraiser(void); /*proto*/ -PyMODINIT_FUNC initraiser(void) { - PyObject *__pyx_1 = 0; - PyObject *__pyx_2 = 0; - PyObject *__pyx_3 = 0; - __pyx_init_filenames(); - __pyx_m = Py_InitModule4("raiser", __pyx_methods, __pyx_mdoc, 0, PYTHON_API_VERSION); - if (!__pyx_m) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 4; goto __pyx_L1;}; - __pyx_b = PyImport_AddModule("__builtin__"); - if (!__pyx_b) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 4; goto __pyx_L1;}; - if (PyObject_SetAttrString(__pyx_m, "__builtins__", __pyx_b) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 4; goto __pyx_L1;}; - if (__Pyx_InternStrings(__pyx_intern_tab) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 4; goto __pyx_L1;}; - if (__Pyx_InitStrings(__pyx_string_tab) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 4; goto __pyx_L1;}; - - /* "/home/therve/Projects/Twisted/branches/failure-c-extension-3132/twisted/test/raiser.pyx":11 */ - __pyx_1 = PyDict_New(); if (!__pyx_1) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 11; goto __pyx_L1;} - __pyx_2 = __Pyx_GetName(__pyx_b, __pyx_n_Exception); if (!__pyx_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 11; goto __pyx_L1;} - __pyx_3 = PyTuple_New(1); if (!__pyx_3) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 11; goto __pyx_L1;} - PyTuple_SET_ITEM(__pyx_3, 0, __pyx_2); - __pyx_2 = 0; - if (PyDict_SetItemString(__pyx_1, "__doc__", __pyx_k2p) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 11; goto __pyx_L1;} - __pyx_2 = __Pyx_CreateClass(__pyx_3, __pyx_1, __pyx_n_RaiserException, "raiser"); if (!__pyx_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 11; goto __pyx_L1;} - Py_DECREF(__pyx_3); __pyx_3 = 0; - if (PyObject_SetAttr(__pyx_m, __pyx_n_RaiserException, __pyx_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 11; goto __pyx_L1;} - Py_DECREF(__pyx_2); __pyx_2 = 0; - Py_DECREF(__pyx_1); __pyx_1 = 0; - - /* "/home/therve/Projects/Twisted/branches/failure-c-extension-3132/twisted/test/raiser.pyx":17 */ - return; - __pyx_L1:; - Py_XDECREF(__pyx_1); - Py_XDECREF(__pyx_2); - Py_XDECREF(__pyx_3); - __Pyx_AddTraceback("raiser"); -} - -static char *__pyx_filenames[] = { - "raiser.pyx", -}; - -/* Runtime support code */ - -static void __pyx_init_filenames(void) { - __pyx_f = __pyx_filenames; -} - -static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name) { - PyObject *result; - result = PyObject_GetAttr(dict, name); - if (!result) - PyErr_SetObject(PyExc_NameError, name); - return result; -} - -static PyObject *__Pyx_CreateClass( - PyObject *bases, PyObject *dict, PyObject *name, char *modname) -{ - PyObject *py_modname; - PyObject *result = 0; - - py_modname = PyString_FromString(modname); - if (!py_modname) - goto bad; - if (PyDict_SetItemString(dict, "__module__", py_modname) < 0) - goto bad; - result = PyClass_New(bases, dict, name); -bad: - Py_XDECREF(py_modname); - return result; -} - -static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb) { - Py_XINCREF(type); - Py_XINCREF(value); - Py_XINCREF(tb); - /* First, check the traceback argument, replacing None with NULL. */ - if (tb == Py_None) { - Py_DECREF(tb); - tb = 0; - } - else if (tb != NULL && !PyTraceBack_Check(tb)) { - PyErr_SetString(PyExc_TypeError, - "raise: arg 3 must be a traceback or None"); - goto raise_error; - } - /* Next, replace a missing value with None */ - if (value == NULL) { - value = Py_None; - Py_INCREF(value); - } - /* Next, repeatedly, replace a tuple exception with its first item */ - while (PyTuple_Check(type) && PyTuple_Size(type) > 0) { - PyObject *tmp = type; - type = PyTuple_GET_ITEM(type, 0); - Py_INCREF(type); - Py_DECREF(tmp); - } - if (PyString_Check(type)) { - if (PyErr_Warn(PyExc_DeprecationWarning, - "raising a string exception is deprecated")) - goto raise_error; - } - else if (PyType_Check(type) || PyClass_Check(type)) - ; /*PyErr_NormalizeException(&type, &value, &tb);*/ - else { - /* Raising an instance. The value should be a dummy. */ - if (value != Py_None) { - PyErr_SetString(PyExc_TypeError, - "instance exception may not have a separate value"); - goto raise_error; - } - /* Normalize to raise , */ - Py_DECREF(value); - value = type; - if (PyInstance_Check(type)) - type = (PyObject*) ((PyInstanceObject*)type)->in_class; - else - type = (PyObject*) type->ob_type; - Py_INCREF(type); - } - PyErr_Restore(type, value, tb); - return; -raise_error: - Py_XDECREF(value); - Py_XDECREF(type); - Py_XDECREF(tb); - return; -} - -static int __Pyx_InternStrings(__Pyx_InternTabEntry *t) { - while (t->p) { - *t->p = PyString_InternFromString(t->s); - if (!*t->p) - return -1; - ++t; - } - return 0; -} - -static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) { - while (t->p) { - *t->p = PyString_FromStringAndSize(t->s, t->n - 1); - if (!*t->p) - return -1; - ++t; - } - return 0; -} - -#include "compile.h" -#include "frameobject.h" -#include "traceback.h" - -static void __Pyx_AddTraceback(char *funcname) { - PyObject *py_srcfile = 0; - PyObject *py_funcname = 0; - PyObject *py_globals = 0; - PyObject *empty_tuple = 0; - PyObject *empty_string = 0; - PyCodeObject *py_code = 0; - PyFrameObject *py_frame = 0; - - py_srcfile = PyString_FromString(__pyx_filename); - if (!py_srcfile) goto bad; - py_funcname = PyString_FromString(funcname); - if (!py_funcname) goto bad; - py_globals = PyModule_GetDict(__pyx_m); - if (!py_globals) goto bad; - empty_tuple = PyTuple_New(0); - if (!empty_tuple) goto bad; - empty_string = PyString_FromString(""); - if (!empty_string) goto bad; - py_code = PyCode_New( - 0, /*int argcount,*/ - 0, /*int nlocals,*/ - 0, /*int stacksize,*/ - 0, /*int flags,*/ - empty_string, /*PyObject *code,*/ - empty_tuple, /*PyObject *consts,*/ - empty_tuple, /*PyObject *names,*/ - empty_tuple, /*PyObject *varnames,*/ - empty_tuple, /*PyObject *freevars,*/ - empty_tuple, /*PyObject *cellvars,*/ - py_srcfile, /*PyObject *filename,*/ - py_funcname, /*PyObject *name,*/ - __pyx_lineno, /*int firstlineno,*/ - empty_string /*PyObject *lnotab*/ - ); - if (!py_code) goto bad; - py_frame = PyFrame_New( - PyThreadState_Get(), /*PyThreadState *tstate,*/ - py_code, /*PyCodeObject *code,*/ - py_globals, /*PyObject *globals,*/ - 0 /*PyObject *locals*/ - ); - if (!py_frame) goto bad; - py_frame->f_lineno = __pyx_lineno; - PyTraceBack_Here(py_frame); -bad: - Py_XDECREF(py_srcfile); - Py_XDECREF(py_funcname); - Py_XDECREF(empty_tuple); - Py_XDECREF(empty_string); - Py_XDECREF(py_code); - Py_XDECREF(py_frame); -} diff --git a/tools/buildbot/pylibs/twisted/test/raiser.pyx b/tools/buildbot/pylibs/twisted/test/raiser.pyx deleted file mode 100644 index a21ce09..0000000 --- a/tools/buildbot/pylibs/twisted/test/raiser.pyx +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright (c) 2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -A trivial extension that just raises an exception. -See L{twisted.test.test_failure.test_failureConstructionWithMungedStackSucceeds}. -""" - - - -class RaiserException(Exception): - """ - A speficic exception only used to be identified in tests. - """ - - -def raiseException(): - """ - Raise L{RaiserException}. - """ - raise RaiserException("This function is intentionally broken") diff --git a/tools/buildbot/pylibs/twisted/test/reflect_helper_IE.py b/tools/buildbot/pylibs/twisted/test/reflect_helper_IE.py deleted file mode 100644 index 614d9483..0000000 --- a/tools/buildbot/pylibs/twisted/test/reflect_helper_IE.py +++ /dev/null @@ -1,4 +0,0 @@ - -# Helper for a test_reflect test - -import idonotexist diff --git a/tools/buildbot/pylibs/twisted/test/reflect_helper_VE.py b/tools/buildbot/pylibs/twisted/test/reflect_helper_VE.py deleted file mode 100644 index e19507f..0000000 --- a/tools/buildbot/pylibs/twisted/test/reflect_helper_VE.py +++ /dev/null @@ -1,4 +0,0 @@ - -# Helper for a test_reflect test - -raise ValueError("Stuff is broken and things") diff --git a/tools/buildbot/pylibs/twisted/test/reflect_helper_ZDE.py b/tools/buildbot/pylibs/twisted/test/reflect_helper_ZDE.py deleted file mode 100644 index bd05fbca..0000000 --- a/tools/buildbot/pylibs/twisted/test/reflect_helper_ZDE.py +++ /dev/null @@ -1,4 +0,0 @@ - -# Helper module for a test_reflect test - -1/0 diff --git a/tools/buildbot/pylibs/twisted/test/server.pem b/tools/buildbot/pylibs/twisted/test/server.pem deleted file mode 100644 index 80ef9dcf..0000000 --- a/tools/buildbot/pylibs/twisted/test/server.pem +++ /dev/null @@ -1,36 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDBjCCAm+gAwIBAgIBATANBgkqhkiG9w0BAQQFADB7MQswCQYDVQQGEwJTRzER -MA8GA1UEChMITTJDcnlwdG8xFDASBgNVBAsTC00yQ3J5cHRvIENBMSQwIgYDVQQD -ExtNMkNyeXB0byBDZXJ0aWZpY2F0ZSBNYXN0ZXIxHTAbBgkqhkiG9w0BCQEWDm5n -cHNAcG9zdDEuY29tMB4XDTAwMDkxMDA5NTEzMFoXDTAyMDkxMDA5NTEzMFowUzEL -MAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRIwEAYDVQQDEwlsb2NhbGhv -c3QxHTAbBgkqhkiG9w0BCQEWDm5ncHNAcG9zdDEuY29tMFwwDQYJKoZIhvcNAQEB -BQADSwAwSAJBAKy+e3dulvXzV7zoTZWc5TzgApr8DmeQHTYC8ydfzH7EECe4R1Xh -5kwIzOuuFfn178FBiS84gngaNcrFi0Z5fAkCAwEAAaOCAQQwggEAMAkGA1UdEwQC -MAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRl -MB0GA1UdDgQWBBTPhIKSvnsmYsBVNWjj0m3M2z0qVTCBpQYDVR0jBIGdMIGagBT7 -hyNp65w6kxXlxb8pUU/+7Sg4AaF/pH0wezELMAkGA1UEBhMCU0cxETAPBgNVBAoT -CE0yQ3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UEAxMbTTJDcnlw -dG8gQ2VydGlmaWNhdGUgTWFzdGVyMR0wGwYJKoZIhvcNAQkBFg5uZ3BzQHBvc3Qx -LmNvbYIBADANBgkqhkiG9w0BAQQFAAOBgQA7/CqT6PoHycTdhEStWNZde7M/2Yc6 -BoJuVwnW8YxGO8Sn6UJ4FeffZNcYZddSDKosw8LtPOeWoK3JINjAk5jiPQ2cww++ -7QGG/g5NDjxFZNDJP1dGiLAxPW6JXwov4v0FmdzfLOZ01jDcgQQZqEpYlgpuI5JE -WUQ9Ho4EzbYCOQ== ------END CERTIFICATE----- ------BEGIN RSA PRIVATE KEY----- -MIIBPAIBAAJBAKy+e3dulvXzV7zoTZWc5TzgApr8DmeQHTYC8ydfzH7EECe4R1Xh -5kwIzOuuFfn178FBiS84gngaNcrFi0Z5fAkCAwEAAQJBAIqm/bz4NA1H++Vx5Ewx -OcKp3w19QSaZAwlGRtsUxrP7436QjnREM3Bm8ygU11BjkPVmtrKm6AayQfCHqJoT -ZIECIQDW0BoMoL0HOYM/mrTLhaykYAVqgIeJsPjvkEhTFXWBuQIhAM3deFAvWNu4 -nklUQ37XsCT2c9tmNt1LAT+slG2JOTTRAiAuXDtC/m3NYVwyHfFm+zKHRzHkClk2 -HjubeEgjpj32AQIhAJqMGTaZVOwevTXvvHwNEH+vRWsAYU/gbx+OQB+7VOcBAiEA -oolb6NMg/R3enNPvS1O4UU1H8wpaF77L4yiSWlE0p4w= ------END RSA PRIVATE KEY----- ------BEGIN CERTIFICATE REQUEST----- -MIIBDTCBuAIBADBTMQswCQYDVQQGEwJTRzERMA8GA1UEChMITTJDcnlwdG8xEjAQ -BgNVBAMTCWxvY2FsaG9zdDEdMBsGCSqGSIb3DQEJARYObmdwc0Bwb3N0MS5jb20w -XDANBgkqhkiG9w0BAQEFAANLADBIAkEArL57d26W9fNXvOhNlZzlPOACmvwOZ5Ad -NgLzJ1/MfsQQJ7hHVeHmTAjM664V+fXvwUGJLziCeBo1ysWLRnl8CQIDAQABoAAw -DQYJKoZIhvcNAQEEBQADQQA7uqbrNTjVWpF6By5ZNPvhZ4YdFgkeXFVWi5ao/TaP -Vq4BG021fJ9nlHRtr4rotpgHDX1rr+iWeHKsx4+5DRSy ------END CERTIFICATE REQUEST----- diff --git a/tools/buildbot/pylibs/twisted/test/ssl_helpers.py b/tools/buildbot/pylibs/twisted/test/ssl_helpers.py deleted file mode 100644 index aa609a8..0000000 --- a/tools/buildbot/pylibs/twisted/test/ssl_helpers.py +++ /dev/null @@ -1,26 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -from twisted.internet import ssl -from twisted.python.util import sibpath - -from OpenSSL import SSL - -class ClientTLSContext(ssl.ClientContextFactory): - isClient = 1 - def getContext(self): - return SSL.Context(SSL.TLSv1_METHOD) - -class ServerTLSContext: - isClient = 0 - - def __init__(self, filename = sibpath(__file__, 'server.pem')): - self.filename = filename - - def getContext(self): - ctx = SSL.Context(SSL.TLSv1_METHOD) - ctx.use_certificate_file(self.filename) - ctx.use_privatekey_file(self.filename) - return ctx diff --git a/tools/buildbot/pylibs/twisted/test/stdio_test_consumer.py b/tools/buildbot/pylibs/twisted/test/stdio_test_consumer.py deleted file mode 100644 index 97ddca2..0000000 --- a/tools/buildbot/pylibs/twisted/test/stdio_test_consumer.py +++ /dev/null @@ -1,39 +0,0 @@ -# -*- test-case-name: twisted.test.test_stdio.StandardInputOutputTestCase.test_consumer -*- -# Copyright (c) 2006-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Main program for the child process run by -L{twisted.test.test_stdio.StandardInputOutputTestCase.test_consumer} to test -that process transports implement IConsumer properly. -""" - -import sys - -from twisted.python import log, reflect -from twisted.internet import stdio, protocol -from twisted.protocols import basic - -def failed(err): - log.startLogging(sys.stderr) - log.err(err) - -class ConsumerChild(protocol.Protocol): - def __init__(self, junkPath): - self.junkPath = junkPath - - def connectionMade(self): - d = basic.FileSender().beginFileTransfer(file(self.junkPath), self.transport) - d.addErrback(failed) - d.addCallback(lambda ign: self.transport.loseConnection()) - - - def connectionLost(self, reason): - reactor.stop() - - -if __name__ == '__main__': - reflect.namedAny(sys.argv[1]).install() - from twisted.internet import reactor - stdio.StandardIO(ConsumerChild(sys.argv[2])) - reactor.run() diff --git a/tools/buildbot/pylibs/twisted/test/stdio_test_hostpeer.py b/tools/buildbot/pylibs/twisted/test/stdio_test_hostpeer.py deleted file mode 100644 index fb2937c..0000000 --- a/tools/buildbot/pylibs/twisted/test/stdio_test_hostpeer.py +++ /dev/null @@ -1,32 +0,0 @@ -# -*- test-case-name: twisted.test.test_stdio.StandardInputOutputTestCase.test_hostAndPeer -*- -# Copyright (c) 2006-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Main program for the child process run by -L{twisted.test.test_stdio.StandardInputOutputTestCase.test_hostAndPeer} to test -that ITransport.getHost() and ITransport.getPeer() work for process transports. -""" - -import sys - -from twisted.internet import stdio, protocol -from twisted.python import reflect - -class HostPeerChild(protocol.Protocol): - def connectionMade(self): - self.transport.write('\n'.join([ - str(self.transport.getHost()), - str(self.transport.getPeer())])) - self.transport.loseConnection() - - - def connectionLost(self, reason): - reactor.stop() - - -if __name__ == '__main__': - reflect.namedAny(sys.argv[1]).install() - from twisted.internet import reactor - stdio.StandardIO(HostPeerChild()) - reactor.run() diff --git a/tools/buildbot/pylibs/twisted/test/stdio_test_lastwrite.py b/tools/buildbot/pylibs/twisted/test/stdio_test_lastwrite.py deleted file mode 100644 index d9da17a..0000000 --- a/tools/buildbot/pylibs/twisted/test/stdio_test_lastwrite.py +++ /dev/null @@ -1,45 +0,0 @@ -# -*- test-case-name: twisted.test.test_stdio.StandardInputOutputTestCase.test_lastWriteReceived -*- -# Copyright (c) 2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Main program for the child process run by -L{twisted.test.test_stdio.StandardInputOutputTestCase.test_lastWriteReceived} -to test that L{os.write} can be reliably used after -L{twisted.internet.stdio.StandardIO} has finished. -""" - -import sys - -from twisted.internet.protocol import Protocol -from twisted.internet.stdio import StandardIO -from twisted.python.reflect import namedAny - - -class LastWriteChild(Protocol): - def __init__(self, reactor, magicString): - self.reactor = reactor - self.magicString = magicString - - - def connectionMade(self): - self.transport.write(self.magicString) - self.transport.loseConnection() - - - def connectionLost(self, reason): - self.reactor.stop() - - - -def main(reactor, magicString): - p = LastWriteChild(reactor, magicString) - StandardIO(p) - reactor.run() - - - -if __name__ == '__main__': - namedAny(sys.argv[1]).install() - from twisted.internet import reactor - main(reactor, sys.argv[2]) diff --git a/tools/buildbot/pylibs/twisted/test/stdio_test_loseconn.py b/tools/buildbot/pylibs/twisted/test/stdio_test_loseconn.py deleted file mode 100644 index e039275..0000000 --- a/tools/buildbot/pylibs/twisted/test/stdio_test_loseconn.py +++ /dev/null @@ -1,29 +0,0 @@ -# -*- test-case-name: twisted.test.test_stdio.StandardInputOutputTestCase.test_loseConnection -*- -# Copyright (c) 2006-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Main program for the child process run by -L{twisted.test.test_stdio.StandardInputOutputTestCase.test_loseConnection} to -test that ITransport.loseConnection() works for process transports. -""" - -import sys - -from twisted.internet import stdio, protocol -from twisted.python import reflect - -class LoseConnChild(protocol.Protocol): - def connectionMade(self): - self.transport.loseConnection() - - - def connectionLost(self, reason): - reactor.stop() - - -if __name__ == '__main__': - reflect.namedAny(sys.argv[1]).install() - from twisted.internet import reactor - stdio.StandardIO(LoseConnChild()) - reactor.run() diff --git a/tools/buildbot/pylibs/twisted/test/stdio_test_producer.py b/tools/buildbot/pylibs/twisted/test/stdio_test_producer.py deleted file mode 100644 index 00db9f7..0000000 --- a/tools/buildbot/pylibs/twisted/test/stdio_test_producer.py +++ /dev/null @@ -1,55 +0,0 @@ -# -*- test-case-name: twisted.test.test_stdio.StandardInputOutputTestCase.test_producer -*- -# Copyright (c) 2006-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Main program for the child process run by -L{twisted.test.test_stdio.StandardInputOutputTestCase.test_producer} to test -that process transports implement IProducer properly. -""" - -import sys - -from twisted.internet import stdio, protocol -from twisted.python import log, reflect - -class ProducerChild(protocol.Protocol): - _paused = False - buf = '' - - def connectionLost(self, reason): - log.msg("*****OVER*****") - reactor.callLater(1, reactor.stop) - # reactor.stop() - - - def dataReceived(self, bytes): - self.buf += bytes - if self._paused: - log.startLogging(sys.stderr) - log.msg("dataReceived while transport paused!") - self.transport.loseConnection() - else: - self.transport.write(bytes) - if self.buf.endswith('\n0\n'): - self.transport.loseConnection() - else: - self.pause() - - - def pause(self): - self._paused = True - self.transport.pauseProducing() - reactor.callLater(0.01, self.unpause) - - - def unpause(self): - self._paused = False - self.transport.resumeProducing() - - -if __name__ == '__main__': - reflect.namedAny(sys.argv[1]).install() - from twisted.internet import reactor - stdio.StandardIO(ProducerChild()) - reactor.run() diff --git a/tools/buildbot/pylibs/twisted/test/stdio_test_write.py b/tools/buildbot/pylibs/twisted/test/stdio_test_write.py deleted file mode 100644 index e152331..0000000 --- a/tools/buildbot/pylibs/twisted/test/stdio_test_write.py +++ /dev/null @@ -1,32 +0,0 @@ -# -*- test-case-name: twisted.test.test_stdio.StandardInputOutputTestCase.test_write -*- -# Copyright (c) 2006-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Main program for the child process run by -L{twisted.test.test_stdio.StandardInputOutputTestCase.test_write} to test that -ITransport.write() works for process transports. -""" - -import sys - -from twisted.internet import stdio, protocol -from twisted.python import reflect - -class WriteChild(protocol.Protocol): - def connectionMade(self): - for ch in 'ok!': - self.transport.write(ch) - self.transport.loseConnection() - - - def connectionLost(self, reason): - reactor.stop() - - -if __name__ == '__main__': - reflect.namedAny(sys.argv[1]).install() - from twisted.internet import reactor - stdio.StandardIO(WriteChild()) - reactor.run() - diff --git a/tools/buildbot/pylibs/twisted/test/stdio_test_writeseq.py b/tools/buildbot/pylibs/twisted/test/stdio_test_writeseq.py deleted file mode 100644 index 5a499ba..0000000 --- a/tools/buildbot/pylibs/twisted/test/stdio_test_writeseq.py +++ /dev/null @@ -1,30 +0,0 @@ -# -*- test-case-name: twisted.test.test_stdio.StandardInputOutputTestCase.test_writeSequence -*- -# Copyright (c) 2006-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Main program for the child process run by -L{twisted.test.test_stdio.StandardInputOutputTestCase.test_writeSequence} to test that -ITransport.writeSequence() works for process transports. -""" - -import sys - -from twisted.internet import stdio, protocol -from twisted.python import reflect - -class WriteSequenceChild(protocol.Protocol): - def connectionMade(self): - self.transport.writeSequence(list('ok!')) - self.transport.loseConnection() - - - def connectionLost(self, reason): - reactor.stop() - - -if __name__ == '__main__': - reflect.namedAny(sys.argv[1]).install() - from twisted.internet import reactor - stdio.StandardIO(WriteSequenceChild()) - reactor.run() diff --git a/tools/buildbot/pylibs/twisted/test/test_abstract.py b/tools/buildbot/pylibs/twisted/test/test_abstract.py deleted file mode 100644 index 44b4646..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_abstract.py +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright (c) 2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for generic file descriptor based reactor support code. -""" - -from twisted.trial.unittest import TestCase - -from twisted.internet.abstract import isIPAddress - - -class AddressTests(TestCase): - """ - Tests for address-related functionality. - """ - def test_decimalDotted(self): - """ - L{isIPAddress} should return C{True} for any decimal dotted - representation of an IPv4 address. - """ - self.assertTrue(isIPAddress('0.1.2.3')) - self.assertTrue(isIPAddress('252.253.254.255')) - - - def test_shortDecimalDotted(self): - """ - L{isIPAddress} should return C{False} for a dotted decimal - representation with fewer or more than four octets. - """ - self.assertFalse(isIPAddress('0')) - self.assertFalse(isIPAddress('0.1')) - self.assertFalse(isIPAddress('0.1.2')) - self.assertFalse(isIPAddress('0.1.2.3.4')) - - - def test_invalidLetters(self): - """ - L{isIPAddress} should return C{False} for any non-decimal dotted - representation including letters. - """ - self.assertFalse(isIPAddress('a.2.3.4')) - self.assertFalse(isIPAddress('1.b.3.4')) - - - def test_invalidPunctuation(self): - """ - L{isIPAddress} should return C{False} for a string containing - strange punctuation. - """ - self.assertFalse(isIPAddress(',')) - self.assertFalse(isIPAddress('1,2')) - self.assertFalse(isIPAddress('1,2,3')) - self.assertFalse(isIPAddress('1.,.3,4')) - - - def test_emptyString(self): - """ - L{isIPAddress} should return C{False} for the empty string. - """ - self.assertFalse(isIPAddress('')) - - - def test_invalidNegative(self): - """ - L{isIPAddress} should return C{False} for negative decimal values. - """ - self.assertFalse(isIPAddress('-1')) - self.assertFalse(isIPAddress('1.-2')) - self.assertFalse(isIPAddress('1.2.-3')) - self.assertFalse(isIPAddress('1.2.-3.4')) - - - def test_invalidPositive(self): - """ - L{isIPAddress} should return C{False} for a string containing - positive decimal values greater than 255. - """ - self.assertFalse(isIPAddress('256.0.0.0')) - self.assertFalse(isIPAddress('0.256.0.0')) - self.assertFalse(isIPAddress('0.0.256.0')) - self.assertFalse(isIPAddress('0.0.0.256')) - self.assertFalse(isIPAddress('256.256.256.256')) diff --git a/tools/buildbot/pylibs/twisted/test/test_adbapi.py b/tools/buildbot/pylibs/twisted/test/test_adbapi.py deleted file mode 100644 index fcda19a..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_adbapi.py +++ /dev/null @@ -1,575 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Tests for twisted.enterprise.adbapi. -""" - -from twisted.trial import unittest - -import os, stat - -from twisted.enterprise.adbapi import ConnectionPool, ConnectionLost, safe -from twisted.enterprise.adbapi import _unreleasedVersion -from twisted.internet import reactor, defer, interfaces - - -simple_table_schema = """ -CREATE TABLE simple ( - x integer -) -""" - - -class ADBAPITestBase: - """Test the asynchronous DB-API code.""" - - openfun_called = {} - - if interfaces.IReactorThreads(reactor, None) is None: - skip = "ADB-API requires threads, no way to test without them" - - def setUp(self): - self.startDB() - self.dbpool = self.makePool(cp_openfun=self.openfun) - self.dbpool.start() - - def tearDown(self): - d = self.dbpool.runOperation('DROP TABLE simple') - d.addCallback(lambda res: self.dbpool.close()) - d.addCallback(lambda res: self.stopDB()) - return d - - def openfun(self, conn): - self.openfun_called[conn] = True - - def checkOpenfunCalled(self, conn=None): - if not conn: - self.failUnless(self.openfun_called) - else: - self.failUnless(self.openfun_called.has_key(conn)) - - def testPool(self): - d = self.dbpool.runOperation(simple_table_schema) - if self.test_failures: - d.addCallback(self._testPool_1_1) - d.addCallback(self._testPool_1_2) - d.addCallback(self._testPool_1_3) - d.addCallback(self._testPool_1_4) - d.addCallback(lambda res: self.flushLoggedErrors()) - d.addCallback(self._testPool_2) - d.addCallback(self._testPool_3) - d.addCallback(self._testPool_4) - d.addCallback(self._testPool_5) - d.addCallback(self._testPool_6) - d.addCallback(self._testPool_7) - d.addCallback(self._testPool_8) - d.addCallback(self._testPool_9) - return d - - def _testPool_1_1(self, res): - d = defer.maybeDeferred(self.dbpool.runQuery, "select * from NOTABLE") - d.addCallbacks(lambda res: self.fail('no exception'), - lambda f: None) - return d - - def _testPool_1_2(self, res): - d = defer.maybeDeferred(self.dbpool.runOperation, - "deletexxx from NOTABLE") - d.addCallbacks(lambda res: self.fail('no exception'), - lambda f: None) - return d - - def _testPool_1_3(self, res): - d = defer.maybeDeferred(self.dbpool.runInteraction, - self.bad_interaction) - d.addCallbacks(lambda res: self.fail('no exception'), - lambda f: None) - return d - - def _testPool_1_4(self, res): - d = defer.maybeDeferred(self.dbpool.runWithConnection, - self.bad_withConnection) - d.addCallbacks(lambda res: self.fail('no exception'), - lambda f: None) - return d - - def _testPool_2(self, res): - # verify simple table is empty - sql = "select count(1) from simple" - d = self.dbpool.runQuery(sql) - def _check(row): - self.failUnless(int(row[0][0]) == 0, "Interaction not rolled back") - self.checkOpenfunCalled() - d.addCallback(_check) - return d - - def _testPool_3(self, res): - sql = "select count(1) from simple" - inserts = [] - # add some rows to simple table (runOperation) - for i in range(self.num_iterations): - sql = "insert into simple(x) values(%d)" % i - inserts.append(self.dbpool.runOperation(sql)) - d = defer.gatherResults(inserts) - - def _select(res): - # make sure they were added (runQuery) - sql = "select x from simple order by x"; - d = self.dbpool.runQuery(sql) - return d - d.addCallback(_select) - - def _check(rows): - self.failUnless(len(rows) == self.num_iterations, - "Wrong number of rows") - for i in range(self.num_iterations): - self.failUnless(len(rows[i]) == 1, "Wrong size row") - self.failUnless(rows[i][0] == i, "Values not returned.") - d.addCallback(_check) - - return d - - def _testPool_4(self, res): - # runInteraction - d = self.dbpool.runInteraction(self.interaction) - d.addCallback(lambda res: self.assertEquals(res, "done")) - return d - - def _testPool_5(self, res): - # withConnection - d = self.dbpool.runWithConnection(self.withConnection) - d.addCallback(lambda res: self.assertEquals(res, "done")) - return d - - def _testPool_6(self, res): - # Test a withConnection cannot be closed - d = self.dbpool.runWithConnection(self.close_withConnection) - return d - - def _testPool_7(self, res): - # give the pool a workout - ds = [] - for i in range(self.num_iterations): - sql = "select x from simple where x = %d" % i - ds.append(self.dbpool.runQuery(sql)) - dlist = defer.DeferredList(ds, fireOnOneErrback=True) - def _check(result): - for i in range(self.num_iterations): - self.failUnless(result[i][1][0][0] == i, "Value not returned") - dlist.addCallback(_check) - return dlist - - def _testPool_8(self, res): - # now delete everything - ds = [] - for i in range(self.num_iterations): - sql = "delete from simple where x = %d" % i - ds.append(self.dbpool.runOperation(sql)) - dlist = defer.DeferredList(ds, fireOnOneErrback=True) - return dlist - - def _testPool_9(self, res): - # verify simple table is empty - sql = "select count(1) from simple" - d = self.dbpool.runQuery(sql) - def _check(row): - self.failUnless(int(row[0][0]) == 0, - "Didn't successfully delete table contents") - self.checkConnect() - d.addCallback(_check) - return d - - def checkConnect(self): - """Check the connect/disconnect synchronous calls.""" - conn = self.dbpool.connect() - self.checkOpenfunCalled(conn) - curs = conn.cursor() - curs.execute("insert into simple(x) values(1)") - curs.execute("select x from simple") - res = curs.fetchall() - self.failUnlessEqual(len(res), 1) - self.failUnlessEqual(len(res[0]), 1) - self.failUnlessEqual(res[0][0], 1) - curs.execute("delete from simple") - curs.execute("select x from simple") - self.failUnlessEqual(len(curs.fetchall()), 0) - curs.close() - self.dbpool.disconnect(conn) - - def interaction(self, transaction): - transaction.execute("select x from simple order by x") - for i in range(self.num_iterations): - row = transaction.fetchone() - self.failUnless(len(row) == 1, "Wrong size row") - self.failUnless(row[0] == i, "Value not returned.") - # should test this, but gadfly throws an exception instead - #self.failUnless(transaction.fetchone() is None, "Too many rows") - return "done" - - def bad_interaction(self, transaction): - if self.can_rollback: - transaction.execute("insert into simple(x) values(0)") - - transaction.execute("select * from NOTABLE") - - def withConnection(self, conn): - curs = conn.cursor() - try: - curs.execute("select x from simple order by x") - for i in range(self.num_iterations): - row = curs.fetchone() - self.failUnless(len(row) == 1, "Wrong size row") - self.failUnless(row[0] == i, "Value not returned.") - # should test this, but gadfly throws an exception instead - #self.failUnless(transaction.fetchone() is None, "Too many rows") - finally: - curs.close() - return "done" - - def close_withConnection(self, conn): - conn.close() - - def bad_withConnection(self, conn): - curs = conn.cursor() - try: - curs.execute("select * from NOTABLE") - finally: - curs.close() - - -class ReconnectTestBase: - """Test the asynchronous DB-API code with reconnect.""" - - if interfaces.IReactorThreads(reactor, None) is None: - skip = "ADB-API requires threads, no way to test without them" - - def setUp(self): - if self.good_sql is None: - raise unittest.SkipTest('no good sql for reconnect test') - self.startDB() - self.dbpool = self.makePool(cp_max=1, cp_reconnect=True, - cp_good_sql=self.good_sql) - self.dbpool.start() - return self.dbpool.runOperation(simple_table_schema) - - def tearDown(self): - d = self.dbpool.runOperation('DROP TABLE simple') - d.addCallback(lambda res: self.dbpool.close()) - d.addCallback(lambda res: self.stopDB()) - return d - - def testPool(self): - d = defer.succeed(None) - d.addCallback(self._testPool_1) - d.addCallback(self._testPool_2) - if not self.early_reconnect: - d.addCallback(self._testPool_3) - d.addCallback(self._testPool_4) - d.addCallback(self._testPool_5) - return d - - def _testPool_1(self, res): - sql = "select count(1) from simple" - d = self.dbpool.runQuery(sql) - def _check(row): - self.failUnless(int(row[0][0]) == 0, "Table not empty") - d.addCallback(_check) - return d - - def _testPool_2(self, res): - # reach in and close the connection manually - self.dbpool.connections.values()[0].close() - - def _testPool_3(self, res): - sql = "select count(1) from simple" - d = defer.maybeDeferred(self.dbpool.runQuery, sql) - d.addCallbacks(lambda res: self.fail('no exception'), - lambda f: f.trap(ConnectionLost)) - return d - - def _testPool_4(self, res): - sql = "select count(1) from simple" - d = self.dbpool.runQuery(sql) - def _check(row): - self.failUnless(int(row[0][0]) == 0, "Table not empty") - d.addCallback(_check) - return d - - def _testPool_5(self, res): - sql = "select * from NOTABLE" # bad sql - d = defer.maybeDeferred(self.dbpool.runQuery, sql) - d.addCallbacks(lambda res: self.fail('no exception'), - lambda f: self.failIf(f.check(ConnectionLost))) - return d - - -class DBTestConnector: - """A class which knows how to test for the presence of - and establish a connection to a relational database. - - To enable test cases which use a central, system database, - you must create a database named DB_NAME with a user DB_USER - and password DB_PASS with full access rights to database DB_NAME. - """ - - TEST_PREFIX = None # used for creating new test cases - - DB_NAME = "twisted_test" - DB_USER = 'twisted_test' - DB_PASS = 'twisted_test' - - DB_DIR = None # directory for database storage - - nulls_ok = True # nulls supported - trailing_spaces_ok = True # trailing spaces in strings preserved - can_rollback = True # rollback supported - test_failures = True # test bad sql? - escape_slashes = True # escape \ in sql? - good_sql = ConnectionPool.good_sql - early_reconnect = True # cursor() will fail on closed connection - can_clear = True # can try to clear out tables when starting - needs_dbdir = False # if a temporary directory is needed for the db - - num_iterations = 50 # number of iterations for test loops - # (lower this for slow db's) - - def setUpClass(self): - if self.needs_dbdir: - self.DB_DIR = self.mktemp() - os.mkdir(self.DB_DIR) - - if not self.can_connect(): - raise unittest.SkipTest('%s: Cannot access db' % self.TEST_PREFIX) - - def can_connect(self): - """Return true if this database is present on the system - and can be used in a test.""" - raise NotImplementedError() - - def startDB(self): - """Take any steps needed to bring database up.""" - pass - - def stopDB(self): - """Bring database down, if needed.""" - pass - - def makePool(self, **newkw): - """Create a connection pool with additional keyword arguments.""" - args, kw = self.getPoolArgs() - kw = kw.copy() - kw.update(newkw) - return ConnectionPool(*args, **kw) - - def getPoolArgs(self): - """Return a tuple (args, kw) of list and keyword arguments - that need to be passed to ConnectionPool to create a connection - to this database.""" - raise NotImplementedError() - -class GadflyConnector(DBTestConnector): - TEST_PREFIX = 'Gadfly' - - nulls_ok = False - can_rollback = False - escape_slashes = False - good_sql = 'select * from simple where 1=0' - needs_dbdir = True - - num_iterations = 1 # slow - - def can_connect(self): - try: import gadfly - except: return False - if not getattr(gadfly, 'connect', None): - gadfly.connect = gadfly.gadfly - return True - - def startDB(self): - import gadfly - conn = gadfly.gadfly() - conn.startup(self.DB_NAME, self.DB_DIR) - - # gadfly seems to want us to create something to get the db going - cursor = conn.cursor() - cursor.execute("create table x (x integer)") - conn.commit() - conn.close() - - def getPoolArgs(self): - args = ('gadfly', self.DB_NAME, self.DB_DIR) - kw = {'cp_max': 1} - return args, kw - -class SQLiteConnector(DBTestConnector): - TEST_PREFIX = 'SQLite' - - escape_slashes = False - needs_dbdir = True - - num_iterations = 1 # slow - - def can_connect(self): - try: import sqlite - except: return False - return True - - def startDB(self): - self.database = os.path.join(self.DB_DIR, self.DB_NAME) - if os.path.exists(self.database): - os.unlink(self.database) - - def getPoolArgs(self): - args = ('sqlite',) - kw = {'database': self.database, 'cp_max': 1} - return args, kw - -class PyPgSQLConnector(DBTestConnector): - TEST_PREFIX = "PyPgSQL" - - def can_connect(self): - try: from pyPgSQL import PgSQL - except: return False - try: - conn = PgSQL.connect(database=self.DB_NAME, user=self.DB_USER, - password=self.DB_PASS) - conn.close() - return True - except: - return False - - def getPoolArgs(self): - args = ('pyPgSQL.PgSQL',) - kw = {'database': self.DB_NAME, 'user': self.DB_USER, - 'password': self.DB_PASS, 'cp_min': 0} - return args, kw - -class PsycopgConnector(DBTestConnector): - TEST_PREFIX = 'Psycopg' - - def can_connect(self): - try: import psycopg - except: return False - try: - conn = psycopg.connect(database=self.DB_NAME, user=self.DB_USER, - password=self.DB_PASS) - conn.close() - return True - except: - return False - - def getPoolArgs(self): - args = ('psycopg',) - kw = {'database': self.DB_NAME, 'user': self.DB_USER, - 'password': self.DB_PASS, 'cp_min': 0} - return args, kw - -class MySQLConnector(DBTestConnector): - TEST_PREFIX = 'MySQL' - - trailing_spaces_ok = False - can_rollback = False - early_reconnect = False - - def can_connect(self): - try: import MySQLdb - except: return False - try: - conn = MySQLdb.connect(db=self.DB_NAME, user=self.DB_USER, - passwd=self.DB_PASS) - conn.close() - return True - except: - return False - - def getPoolArgs(self): - args = ('MySQLdb',) - kw = {'db': self.DB_NAME, 'user': self.DB_USER, 'passwd': self.DB_PASS} - return args, kw - -class FirebirdConnector(DBTestConnector): - TEST_PREFIX = 'Firebird' - - test_failures = False # failure testing causes problems - escape_slashes = False - good_sql = None # firebird doesn't handle failed sql well - can_clear = False # firebird is not so good - needs_dbdir = True - - num_iterations = 5 # slow - - def can_connect(self): - try: import kinterbasdb - except: return False - try: - self.startDB() - self.stopDB() - return True - except: - return False - - def startDB(self): - import kinterbasdb - self.DB_NAME = os.path.join(self.DB_DIR, DBTestConnector.DB_NAME) - os.chmod(self.DB_DIR, stat.S_IRWXU + stat.S_IRWXG + stat.S_IRWXO) - sql = 'create database "%s" user "%s" password "%s"' - sql %= (self.DB_NAME, self.DB_USER, self.DB_PASS); - conn = kinterbasdb.create_database(sql) - conn.close() - - def getPoolArgs(self): - args = ('kinterbasdb',) - kw = {'database': self.DB_NAME, 'host': '127.0.0.1', - 'user': self.DB_USER, 'password': self.DB_PASS} - return args, kw - - def stopDB(self): - import kinterbasdb - conn = kinterbasdb.connect(database=self.DB_NAME, - host='127.0.0.1', user=self.DB_USER, - password=self.DB_PASS) - conn.drop_database() - -def makeSQLTests(base, suffix, globals): - """ - Make a test case for every db connector which can connect. - - @param base: Base class for test case. Additional base classes - will be a DBConnector subclass and unittest.TestCase - @param suffix: A suffix used to create test case names. Prefixes - are defined in the DBConnector subclasses. - """ - connectors = [GadflyConnector, SQLiteConnector, PyPgSQLConnector, - PsycopgConnector, MySQLConnector, FirebirdConnector] - for connclass in connectors: - name = connclass.TEST_PREFIX + suffix - import new - klass = new.classobj(name, (connclass, base, unittest.TestCase), base.__dict__) - globals[name] = klass - -# GadflyADBAPITestCase SQLiteADBAPITestCase PyPgSQLADBAPITestCase -# PsycopgADBAPITestCase MySQLADBAPITestCase FirebirdADBAPITestCase -makeSQLTests(ADBAPITestBase, 'ADBAPITestCase', globals()) - -# GadflyReconnectTestCase SQLiteReconnectTestCase PyPgSQLReconnectTestCase -# PsycopgReconnectTestCase MySQLReconnectTestCase FirebirdReconnectTestCase -makeSQLTests(ReconnectTestBase, 'ReconnectTestCase', globals()) - - - -class DeprecationTestCase(unittest.TestCase): - """ - Test deprecations in twisted.enterprise.adbapi - """ - - def test_safe(self): - """ - Test deprecation of twisted.enterprise.adbapi.safe() - """ - result = self.callDeprecated(_unreleasedVersion, - safe, "test'") - - # make sure safe still behaves like the original - self.assertEqual(result, "test''") diff --git a/tools/buildbot/pylibs/twisted/test/test_amp.py b/tools/buildbot/pylibs/twisted/test/test_amp.py deleted file mode 100644 index 5027122..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_amp.py +++ /dev/null @@ -1,2115 +0,0 @@ -# Copyright (c) 2005 Divmod, Inc. -# Copyright (c) 2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.python import filepath -from twisted.python.failure import Failure -from twisted.protocols import amp -from twisted.test import iosim -from twisted.trial import unittest -from twisted.internet import protocol, defer, error, reactor, interfaces - - -class TestProto(protocol.Protocol): - def __init__(self, onConnLost, dataToSend): - self.onConnLost = onConnLost - self.dataToSend = dataToSend - - def connectionMade(self): - self.data = [] - self.transport.write(self.dataToSend) - - def dataReceived(self, bytes): - self.data.append(bytes) - # self.transport.loseConnection() - - def connectionLost(self, reason): - self.onConnLost.callback(self.data) - - - -class SimpleSymmetricProtocol(amp.AMP): - - def sendHello(self, text): - return self.callRemoteString( - "hello", - hello=text) - - def amp_HELLO(self, box): - return amp.Box(hello=box['hello']) - - def amp_HOWDOYOUDO(self, box): - return amp.QuitBox(howdoyoudo='world') - - - -class UnfriendlyGreeting(Exception): - """Greeting was insufficiently kind. - """ - -class DeathThreat(Exception): - """Greeting was insufficiently kind. - """ - -class UnknownProtocol(Exception): - """Asked to switch to the wrong protocol. - """ - - -class TransportPeer(amp.Argument): - # this serves as some informal documentation for how to get variables from - # the protocol or your environment and pass them to methods as arguments. - def retrieve(self, d, name, proto): - return '' - - def fromStringProto(self, notAString, proto): - return proto.transport.getPeer() - - def toBox(self, name, strings, objects, proto): - return - - - -class Hello(amp.Command): - - commandName = 'hello' - - arguments = [('hello', amp.String()), - ('optional', amp.Boolean(optional=True)), - ('print', amp.Unicode(optional=True)), - ('from', TransportPeer(optional=True)), - ('mixedCase', amp.String(optional=True)), - ('dash-arg', amp.String(optional=True)), - ('underscore_arg', amp.String(optional=True))] - - response = [('hello', amp.String()), - ('print', amp.Unicode(optional=True))] - - errors = {UnfriendlyGreeting: 'UNFRIENDLY'} - - fatalErrors = {DeathThreat: 'DEAD'} - -class NoAnswerHello(Hello): - commandName = Hello.commandName - requiresAnswer = False - -class FutureHello(amp.Command): - commandName = 'hello' - - arguments = [('hello', amp.String()), - ('optional', amp.Boolean(optional=True)), - ('print', amp.Unicode(optional=True)), - ('from', TransportPeer(optional=True)), - ('bonus', amp.String(optional=True)), # addt'l arguments - # should generally be - # added at the end, and - # be optional... - ] - - response = [('hello', amp.String()), - ('print', amp.Unicode(optional=True))] - - errors = {UnfriendlyGreeting: 'UNFRIENDLY'} - -class WTF(amp.Command): - """ - An example of an invalid command. - """ - - -class BrokenReturn(amp.Command): - """ An example of a perfectly good command, but the handler is going to return - None... - """ - - commandName = 'broken_return' - -class Goodbye(amp.Command): - # commandName left blank on purpose: this tests implicit command names. - response = [('goodbye', amp.String())] - responseType = amp.QuitBox - -class Howdoyoudo(amp.Command): - commandName = 'howdoyoudo' - # responseType = amp.QuitBox - -class WaitForever(amp.Command): - commandName = 'wait_forever' - -class GetList(amp.Command): - commandName = 'getlist' - arguments = [('length', amp.Integer())] - response = [('body', amp.AmpList([('x', amp.Integer())]))] - -class SecuredPing(amp.Command): - # XXX TODO: actually make this refuse to send over an insecure connection - response = [('pinged', amp.Boolean())] - -class TestSwitchProto(amp.ProtocolSwitchCommand): - commandName = 'Switch-Proto' - - arguments = [ - ('name', amp.String()), - ] - errors = {UnknownProtocol: 'UNKNOWN'} - -class SingleUseFactory(protocol.ClientFactory): - def __init__(self, proto): - self.proto = proto - self.proto.factory = self - - def buildProtocol(self, addr): - p, self.proto = self.proto, None - return p - - reasonFailed = None - - def clientConnectionFailed(self, connector, reason): - self.reasonFailed = reason - return - -THING_I_DONT_UNDERSTAND = 'gwebol nargo' -class ThingIDontUnderstandError(Exception): - pass - -class FactoryNotifier(amp.AMP): - factory = None - def connectionMade(self): - if self.factory is not None: - self.factory.theProto = self - if hasattr(self.factory, 'onMade'): - self.factory.onMade.callback(None) - - def emitpong(self): - from twisted.internet.interfaces import ISSLTransport - if not ISSLTransport.providedBy(self.transport): - raise DeathThreat("only send secure pings over secure channels") - return {'pinged': True} - SecuredPing.responder(emitpong) - - -class SimpleSymmetricCommandProtocol(FactoryNotifier): - maybeLater = None - def __init__(self, onConnLost=None): - amp.AMP.__init__(self) - self.onConnLost = onConnLost - - def sendHello(self, text): - return self.callRemote(Hello, hello=text) - - def sendUnicodeHello(self, text, translation): - return self.callRemote(Hello, hello=text, Print=translation) - - greeted = False - - def cmdHello(self, hello, From, optional=None, Print=None, - mixedCase=None, dash_arg=None, underscore_arg=None): - assert From == self.transport.getPeer() - if hello == THING_I_DONT_UNDERSTAND: - raise ThingIDontUnderstandError() - if hello.startswith('fuck'): - raise UnfriendlyGreeting("Don't be a dick.") - if hello == 'die': - raise DeathThreat("aieeeeeeeee") - result = dict(hello=hello) - if Print is not None: - result.update(dict(Print=Print)) - self.greeted = True - return result - Hello.responder(cmdHello) - - def cmdGetlist(self, length): - return {'body': [dict(x=1)] * length} - GetList.responder(cmdGetlist) - - def waitforit(self): - self.waiting = defer.Deferred() - return self.waiting - WaitForever.responder(waitforit) - - def howdo(self): - return dict(howdoyoudo='world') - Howdoyoudo.responder(howdo) - - def saybye(self): - return dict(goodbye="everyone") - Goodbye.responder(saybye) - - def switchToTestProtocol(self, fail=False): - if fail: - name = 'no-proto' - else: - name = 'test-proto' - p = TestProto(self.onConnLost, SWITCH_CLIENT_DATA) - return self.callRemote( - TestSwitchProto, - SingleUseFactory(p), name=name).addCallback(lambda ign: p) - - def switchit(self, name): - if name == 'test-proto': - return TestProto(self.onConnLost, SWITCH_SERVER_DATA) - raise UnknownProtocol(name) - TestSwitchProto.responder(switchit) - - def donothing(self): - return None - BrokenReturn.responder(donothing) - - -class DeferredSymmetricCommandProtocol(SimpleSymmetricCommandProtocol): - def switchit(self, name): - if name == 'test-proto': - self.maybeLaterProto = TestProto(self.onConnLost, SWITCH_SERVER_DATA) - self.maybeLater = defer.Deferred() - return self.maybeLater - raise UnknownProtocol(name) - TestSwitchProto.responder(switchit) - -class BadNoAnswerCommandProtocol(SimpleSymmetricCommandProtocol): - def badResponder(self, hello, From, optional=None, Print=None, - mixedCase=None, dash_arg=None, underscore_arg=None): - """ - This responder does nothing and forgets to return a dictionary. - """ - NoAnswerHello.responder(badResponder) - -class NoAnswerCommandProtocol(SimpleSymmetricCommandProtocol): - def goodNoAnswerResponder(self, hello, From, optional=None, Print=None, - mixedCase=None, dash_arg=None, underscore_arg=None): - return dict(hello=hello+"-noanswer") - NoAnswerHello.responder(goodNoAnswerResponder) - -def connectedServerAndClient(ServerClass=SimpleSymmetricProtocol, - ClientClass=SimpleSymmetricProtocol, - *a, **kw): - """Returns a 3-tuple: (client, server, pump) - """ - return iosim.connectedServerAndClient( - ServerClass, ClientClass, - *a, **kw) - -class TotallyDumbProtocol(protocol.Protocol): - buf = '' - def dataReceived(self, data): - self.buf += data - -class LiteralAmp(amp.AMP): - def __init__(self): - self.boxes = [] - - def ampBoxReceived(self, box): - self.boxes.append(box) - return - -class ParsingTest(unittest.TestCase): - - def test_booleanValues(self): - """ - Verify that the Boolean parser parses 'True' and 'False', but nothing - else. - """ - b = amp.Boolean() - self.assertEquals(b.fromString("True"), True) - self.assertEquals(b.fromString("False"), False) - self.assertRaises(TypeError, b.fromString, "ninja") - self.assertRaises(TypeError, b.fromString, "true") - self.assertRaises(TypeError, b.fromString, "TRUE") - self.assertEquals(b.toString(True), 'True') - self.assertEquals(b.toString(False), 'False') - - def test_pathValueRoundTrip(self): - """ - Verify the 'Path' argument can parse and emit a file path. - """ - fp = filepath.FilePath(self.mktemp()) - p = amp.Path() - s = p.toString(fp) - v = p.fromString(s) - self.assertNotIdentical(fp, v) # sanity check - self.assertEquals(fp, v) - - - def test_sillyEmptyThing(self): - """ - Test that empty boxes raise an error; they aren't supposed to be sent - on purpose. - """ - a = amp.AMP() - return self.assertRaises(amp.NoEmptyBoxes, a.ampBoxReceived, amp.Box()) - - - def test_ParsingRoundTrip(self): - """ - Verify that various kinds of data make it through the encode/parse - round-trip unharmed. - """ - c, s, p = connectedServerAndClient(ClientClass=LiteralAmp, - ServerClass=LiteralAmp) - - SIMPLE = ('simple', 'test') - CE = ('ceq', ': ') - CR = ('crtest', 'test\r') - LF = ('lftest', 'hello\n') - NEWLINE = ('newline', 'test\r\none\r\ntwo') - NEWLINE2 = ('newline2', 'test\r\none\r\n two') - BLANKLINE = ('newline3', 'test\r\n\r\nblank\r\n\r\nline') - BODYTEST = ('body', 'blah\r\n\r\ntesttest') - - testData = [ - [SIMPLE], - [SIMPLE, BODYTEST], - [SIMPLE, CE], - [SIMPLE, CR], - [SIMPLE, CE, CR, LF], - [CE, CR, LF], - [SIMPLE, NEWLINE, CE, NEWLINE2], - [BODYTEST, SIMPLE, NEWLINE] - ] - - for test in testData: - jb = amp.Box() - jb.update(dict(test)) - jb._sendTo(c) - p.flush() - self.assertEquals(s.boxes[-1], jb) - - - -class FakeLocator(object): - """ - This is a fake implementation of the interface implied by - L{CommandLocator}. - """ - def __init__(self): - """ - Remember the given keyword arguments as a set of responders. - """ - self.commands = {} - - - def locateResponder(self, commandName): - """ - Look up and return a function passed as a keyword argument of the given - name to the constructor. - """ - return self.commands[commandName] - - -class FakeSender: - """ - This is a fake implementation of the 'box sender' interface implied by - L{AMP}. - """ - def __init__(self): - """ - Create a fake sender and initialize the list of received boxes and - unhandled errors. - """ - self.sentBoxes = [] - self.unhandledErrors = [] - self.expectedErrors = 0 - - - def expectError(self): - """ - Expect one error, so that the test doesn't fail. - """ - self.expectedErrors += 1 - - - def sendBox(self, box): - """ - Accept a box, but don't do anything. - """ - self.sentBoxes.append(box) - - - def unhandledError(self, failure): - """ - Deal with failures by instantly re-raising them for easier debugging. - """ - self.expectedErrors -= 1 - if self.expectedErrors < 0: - failure.raiseException() - else: - self.unhandledErrors.append(failure) - - - -class CommandDispatchTests(unittest.TestCase): - """ - The AMP CommandDispatcher class dispatches converts AMP boxes into commands - and responses using Command.responder decorator. - - Note: Originally, AMP's factoring was such that many tests for this - functionality are now implemented as full round-trip tests in L{AMPTest}. - Future tests should be written at this level instead, to ensure API - compatibility and to provide more granular, readable units of test - coverage. - """ - - def setUp(self): - """ - Create a dispatcher to use. - """ - self.locator = FakeLocator() - self.sender = FakeSender() - self.dispatcher = amp.BoxDispatcher(self.locator) - self.dispatcher.startReceivingBoxes(self.sender) - - - def test_receivedAsk(self): - """ - L{CommandDispatcher.ampBoxReceived} should locate the appropriate - command in its responder lookup, based on the '_ask' key. - """ - received = [] - def thunk(box): - received.append(box) - return amp.Box({"hello": "goodbye"}) - input = amp.Box(_command="hello", - _ask="test-command-id", - hello="world") - self.locator.commands['hello'] = thunk - self.dispatcher.ampBoxReceived(input) - self.assertEquals(received, [input]) - - - def test_sendUnhandledError(self): - """ - L{CommandDispatcher} should relay its unhandled errors in responding to - boxes to its boxSender. - """ - err = RuntimeError("something went wrong, oh no") - self.sender.expectError() - self.dispatcher.unhandledError(Failure(err)) - self.assertEqual(len(self.sender.unhandledErrors), 1) - self.assertEqual(self.sender.unhandledErrors[0].value, err) - - - def test_unhandledSerializationError(self): - """ - Errors during serialization ought to be relayed to the sender's - unhandledError method. - """ - err = RuntimeError("something undefined went wrong") - def thunk(result): - class BrokenBox(amp.Box): - def _sendTo(self, proto): - raise err - return BrokenBox() - self.locator.commands['hello'] = thunk - input = amp.Box(_command="hello", - _ask="test-command-id", - hello="world") - self.sender.expectError() - self.dispatcher.ampBoxReceived(input) - self.assertEquals(len(self.sender.unhandledErrors), 1) - self.assertEquals(self.sender.unhandledErrors[0].value, err) - - - def test_callRemote(self): - """ - L{CommandDispatcher.callRemote} should emit a properly formatted '_ask' - box to its boxSender and record an outstanding L{Deferred}. When a - corresponding '_answer' packet is received, the L{Deferred} should be - fired, and the results translated via the given L{Command}'s response - de-serialization. - """ - D = self.dispatcher.callRemote(Hello, hello='world') - self.assertEquals(self.sender.sentBoxes, - [amp.AmpBox(_command="hello", - _ask="1", - hello="world")]) - answers = [] - D.addCallback(answers.append) - self.assertEquals(answers, []) - self.dispatcher.ampBoxReceived(amp.AmpBox({'hello': "yay", - 'print': "ignored", - '_answer': "1"})) - self.assertEquals(answers, [dict(hello="yay", - Print=u"ignored")]) - - -class SimpleGreeting(amp.Command): - """ - A very simple greeting command that uses a few basic argument types. - """ - commandName = 'simple' - arguments = [('greeting', amp.Unicode()), - ('cookie', amp.Integer())] - response = [('cookieplus', amp.Integer())] - - -class TestLocator(amp.CommandLocator): - """ - A locator which implements a responder to a 'hello' command. - """ - def __init__(self): - self.greetings = [] - - - def greetingResponder(self, greeting, cookie): - self.greetings.append((greeting, cookie)) - return dict(cookieplus=cookie + 3) - greetingResponder = SimpleGreeting.responder(greetingResponder) - - - -class OverrideLocatorAMP(amp.AMP): - def __init__(self): - amp.AMP.__init__(self) - self.customResponder = object() - self.expectations = {"custom": self.customResponder} - self.greetings = [] - - - def lookupFunction(self, name): - """ - Override the deprecated lookupFunction function. - """ - if name in self.expectations: - result = self.expectations[name] - return result - else: - return super(OverrideLocatorAMP, self).lookupFunction(name) - - - def greetingResponder(self, greeting, cookie): - self.greetings.append((greeting, cookie)) - return dict(cookieplus=cookie + 3) - greetingResponder = SimpleGreeting.responder(greetingResponder) - - - - -class CommandLocatorTests(unittest.TestCase): - """ - The CommandLocator should enable users to specify responders to commands as - functions that take structured objects, annotated with metadata. - """ - - def test_responderDecorator(self): - """ - A method on a L{CommandLocator} subclass decorated with a L{Command} - subclass's L{responder} decorator should be returned from - locateResponder, wrapped in logic to serialize and deserialize its - arguments. - """ - locator = TestLocator() - responderCallable = locator.locateResponder("simple") - result = responderCallable(amp.Box(greeting="ni hao", cookie="5")) - def done(values): - self.assertEquals(values, amp.AmpBox(cookieplus='8')) - return result.addCallback(done) - - - def test_lookupFunctionDeprecatedOverride(self): - """ - Subclasses which override locateResponder under its old name, - lookupFunction, should have the override invoked instead. (This tests - an AMP subclass, because in the version of the code that could invoke - this deprecated code path, there was no L{CommandLocator}.) - """ - locator = OverrideLocatorAMP() - customResponderObject = self.assertWarns( - PendingDeprecationWarning, - "Override locateResponder, not lookupFunction.", - __file__, lambda : locator.locateResponder("custom")) - self.assertEquals(locator.customResponder, customResponderObject) - # Make sure upcalling works too - normalResponderObject = self.assertWarns( - PendingDeprecationWarning, - "Override locateResponder, not lookupFunction.", - __file__, lambda : locator.locateResponder("simple")) - result = normalResponderObject(amp.Box(greeting="ni hao", cookie="5")) - def done(values): - self.assertEquals(values, amp.AmpBox(cookieplus='8')) - return result.addCallback(done) - - - def test_lookupFunctionDeprecatedInvoke(self): - """ - Invoking locateResponder under its old name, lookupFunction, should - emit a deprecation warning, but do the same thing. - """ - locator = TestLocator() - responderCallable = self.assertWarns( - PendingDeprecationWarning, - "Call locateResponder, not lookupFunction.", __file__, - lambda : locator.lookupFunction("simple")) - result = responderCallable(amp.Box(greeting="ni hao", cookie="5")) - def done(values): - self.assertEquals(values, amp.AmpBox(cookieplus='8')) - return result.addCallback(done) - - - -SWITCH_CLIENT_DATA = 'Success!' -SWITCH_SERVER_DATA = 'No, really. Success.' - - -class BinaryProtocolTests(unittest.TestCase): - """ - Tests for L{amp.BinaryBoxProtocol}. - """ - - def setUp(self): - """ - Keep track of all boxes received by this test in its capacity as an - L{IBoxReceiver} implementor. - """ - self.boxes = [] - self.data = [] - - - def startReceivingBoxes(self, sender): - """ - Implement L{IBoxReceiver.startReceivingBoxes} to do nothing. - """ - - - def ampBoxReceived(self, box): - """ - A box was received by the protocol. - """ - self.boxes.append(box) - - stopReason = None - def stopReceivingBoxes(self, reason): - """ - Record the reason that we stopped receiving boxes. - """ - self.stopReason = reason - - - # fake ITransport - def getPeer(self): - return 'no peer' - - - def getHost(self): - return 'no host' - - - def write(self, data): - self.data.append(data) - - - def test_receiveBoxStateMachine(self): - """ - When a binary box protocol receives: - * a key - * a value - * an empty string - it should emit a box and send it to its boxReceiver. - """ - a = amp.BinaryBoxProtocol(self) - a.stringReceived("hello") - a.stringReceived("world") - a.stringReceived("") - self.assertEquals(self.boxes, [amp.AmpBox(hello="world")]) - - - def test_receiveBoxData(self): - """ - When a binary box protocol receives the serialized form of an AMP box, - it should emit a similar box to its boxReceiver. - """ - a = amp.BinaryBoxProtocol(self) - a.dataReceived(amp.Box({"testKey": "valueTest", - "anotherKey": "anotherValue"}).serialize()) - self.assertEquals(self.boxes, - [amp.Box({"testKey": "valueTest", - "anotherKey": "anotherValue"})]) - - - def test_sendBox(self): - """ - When a binary box protocol sends a box, it should emit the serialized - bytes of that box to its transport. - """ - a = amp.BinaryBoxProtocol(self) - a.makeConnection(self) - aBox = amp.Box({"testKey": "valueTest", - "someData": "hello"}) - a.makeConnection(self) - a.sendBox(aBox) - self.assertEquals(''.join(self.data), aBox.serialize()) - - - def test_connectionLostStopSendingBoxes(self): - """ - When a binary box protocol loses its connection, it should notify its - box receiver that it has stopped receiving boxes. - """ - a = amp.BinaryBoxProtocol(self) - a.makeConnection(self) - aBox = amp.Box({"sample": "data"}) - a.makeConnection(self) - connectionFailure = Failure(RuntimeError()) - a.connectionLost(connectionFailure) - self.assertIdentical(self.stopReason, connectionFailure) - - - def test_protocolSwitch(self): - """ - L{BinaryBoxProtocol} has the capacity to switch to a different protocol - on a box boundary. When a protocol is in the process of switching, it - cannot receive traffic. - """ - otherProto = TestProto(None, "outgoing data") - test = self - class SwitchyReceiver: - switched = False - def startReceivingBoxes(self, sender): - pass - def ampBoxReceived(self, box): - test.assertFalse(self.switched, - "Should only receive one box!") - self.switched = True - a._lockForSwitch() - a._switchTo(otherProto) - a = amp.BinaryBoxProtocol(SwitchyReceiver()) - anyOldBox = amp.Box({"include": "lots", - "of": "data"}) - a.makeConnection(self) - # Include a 0-length box at the beginning of the next protocol's data, - # to make sure that AMP doesn't eat the data or try to deliver extra - # boxes either... - moreThanOneBox = anyOldBox.serialize() + "\x00\x00Hello, world!" - a.dataReceived(moreThanOneBox) - self.assertIdentical(otherProto.transport, self) - self.assertEquals("".join(otherProto.data), "\x00\x00Hello, world!") - self.assertEquals(self.data, ["outgoing data"]) - a.dataReceived("more data") - self.assertEquals("".join(otherProto.data), - "\x00\x00Hello, world!more data") - self.assertRaises(amp.ProtocolSwitched, a.sendBox, anyOldBox) - - - def test_protocolSwitchInvalidStates(self): - """ - In order to make sure the protocol never gets any invalid data sent - into the middle of a box, it must be locked for switching before it is - switched. It can only be unlocked if the switch failed, and attempting - to send a box while it is locked should raise an exception. - """ - a = amp.BinaryBoxProtocol(self) - a.makeConnection(self) - sampleBox = amp.Box({"some": "data"}) - a._lockForSwitch() - self.assertRaises(amp.ProtocolSwitched, a.sendBox, sampleBox) - a._unlockFromSwitch() - a.sendBox(sampleBox) - self.assertEquals(''.join(self.data), sampleBox.serialize()) - a._lockForSwitch() - otherProto = TestProto(None, "outgoing data") - a._switchTo(otherProto) - self.assertRaises(amp.ProtocolSwitched, a._unlockFromSwitch) - - - def test_protocolSwitchLoseConnection(self): - """ - When the protocol is switched, it should notify its nested protocol of - disconnection. - """ - class Loser(protocol.Protocol): - reason = None - def connectionLost(self, reason): - self.reason = reason - connectionLoser = Loser() - a = amp.BinaryBoxProtocol(self) - a.makeConnection(self) - a._lockForSwitch() - a._switchTo(connectionLoser) - connectionFailure = Failure(RuntimeError()) - a.connectionLost(connectionFailure) - self.assertEquals(connectionLoser.reason, connectionFailure) - - - def test_protocolSwitchLoseClientConnection(self): - """ - When the protocol is switched, it should notify its nested client - protocol factory of disconnection. - """ - class ClientLoser: - reason = None - def clientConnectionLost(self, connector, reason): - self.reason = reason - a = amp.BinaryBoxProtocol(self) - connectionLoser = protocol.Protocol() - clientLoser = ClientLoser() - a.makeConnection(self) - a._lockForSwitch() - a._switchTo(connectionLoser, clientLoser) - connectionFailure = Failure(RuntimeError()) - a.connectionLost(connectionFailure) - self.assertEquals(clientLoser.reason, connectionFailure) - - - -class AMPTest(unittest.TestCase): - - def test_interfaceDeclarations(self): - """ - The classes in the amp module ought to implement the interfaces that - are declared for their benefit. - """ - for interface, implementation in [(amp.IBoxSender, amp.BinaryBoxProtocol), - (amp.IBoxReceiver, amp.BoxDispatcher), - (amp.IResponderLocator, amp.CommandLocator), - (amp.IResponderLocator, amp.SimpleStringLocator), - (amp.IBoxSender, amp.AMP), - (amp.IBoxReceiver, amp.AMP), - (amp.IResponderLocator, amp.AMP)]: - self.failUnless(interface.implementedBy(implementation), - "%s does not implements(%s)" % (implementation, interface)) - - - def test_helloWorld(self): - """ - Verify that a simple command can be sent and its response received with - the simple low-level string-based API. - """ - c, s, p = connectedServerAndClient() - L = [] - HELLO = 'world' - c.sendHello(HELLO).addCallback(L.append) - p.flush() - self.assertEquals(L[0]['hello'], HELLO) - - - def test_wireFormatRoundTrip(self): - """ - Verify that mixed-case, underscored and dashed arguments are mapped to - their python names properly. - """ - c, s, p = connectedServerAndClient() - L = [] - HELLO = 'world' - c.sendHello(HELLO).addCallback(L.append) - p.flush() - self.assertEquals(L[0]['hello'], HELLO) - - - def test_helloWorldUnicode(self): - """ - Verify that unicode arguments can be encoded and decoded. - """ - c, s, p = connectedServerAndClient( - ServerClass=SimpleSymmetricCommandProtocol, - ClientClass=SimpleSymmetricCommandProtocol) - L = [] - HELLO = 'world' - HELLO_UNICODE = 'wor\u1234ld' - c.sendUnicodeHello(HELLO, HELLO_UNICODE).addCallback(L.append) - p.flush() - self.assertEquals(L[0]['hello'], HELLO) - self.assertEquals(L[0]['Print'], HELLO_UNICODE) - - - def test_unknownCommandLow(self): - """ - Verify that unknown commands using low-level APIs will be rejected with an - error, but will NOT terminate the connection. - """ - c, s, p = connectedServerAndClient() - L = [] - def clearAndAdd(e): - """ - You can't propagate the error... - """ - e.trap(amp.UnhandledCommand) - return "OK" - c.callRemoteString("WTF").addErrback(clearAndAdd).addCallback(L.append) - p.flush() - self.assertEquals(L.pop(), "OK") - HELLO = 'world' - c.sendHello(HELLO).addCallback(L.append) - p.flush() - self.assertEquals(L[0]['hello'], HELLO) - - - def test_unknownCommandHigh(self): - """ - Verify that unknown commands using high-level APIs will be rejected with an - error, but will NOT terminate the connection. - """ - c, s, p = connectedServerAndClient() - L = [] - def clearAndAdd(e): - """ - You can't propagate the error... - """ - e.trap(amp.UnhandledCommand) - return "OK" - c.callRemote(WTF).addErrback(clearAndAdd).addCallback(L.append) - p.flush() - self.assertEquals(L.pop(), "OK") - HELLO = 'world' - c.sendHello(HELLO).addCallback(L.append) - p.flush() - self.assertEquals(L[0]['hello'], HELLO) - - - def test_brokenReturnValue(self): - """ - It can be very confusing if you write some code which responds to a - command, but gets the return value wrong. Most commonly you end up - returning None instead of a dictionary. - - Verify that if that happens, the framework logs a useful error. - """ - L = [] - SimpleSymmetricCommandProtocol().dispatchCommand( - amp.AmpBox(_command=BrokenReturn.commandName)).addErrback(L.append) - blr = L[0].trap(amp.BadLocalReturn) - self.failUnlessIn('None', repr(L[0].value)) - - - - def test_unknownArgument(self): - """ - Verify that unknown arguments are ignored, and not passed to a Python - function which can't accept them. - """ - c, s, p = connectedServerAndClient( - ServerClass=SimpleSymmetricCommandProtocol, - ClientClass=SimpleSymmetricCommandProtocol) - L = [] - HELLO = 'world' - # c.sendHello(HELLO).addCallback(L.append) - c.callRemote(FutureHello, - hello=HELLO, - bonus="I'm not in the book!").addCallback( - L.append) - p.flush() - self.assertEquals(L[0]['hello'], HELLO) - - - def test_simpleReprs(self): - """ - Verify that the various Box objects repr properly, for debugging. - """ - self.assertEquals(type(repr(amp._TLSBox())), str) - self.assertEquals(type(repr(amp._SwitchBox('a'))), str) - self.assertEquals(type(repr(amp.QuitBox())), str) - self.assertEquals(type(repr(amp.AmpBox())), str) - self.failUnless("AmpBox" in repr(amp.AmpBox())) - - def test_keyTooLong(self): - """ - Verify that a key that is too long will immediately raise a synchronous - exception. - """ - c, s, p = connectedServerAndClient() - L = [] - x = "H" * (0xff+1) - tl = self.assertRaises(amp.TooLong, - c.callRemoteString, "Hello", - **{x: "hi"}) - self.failUnless(tl.isKey) - self.failUnless(tl.isLocal) - self.failUnlessIdentical(tl.keyName, None) - self.failUnlessIdentical(tl.value, x) - self.failUnless(str(len(x)) in repr(tl)) - self.failUnless("key" in repr(tl)) - - - def test_valueTooLong(self): - """ - Verify that attempting to send value longer than 64k will immediately - raise an exception. - """ - c, s, p = connectedServerAndClient() - L = [] - x = "H" * (0xffff+1) - tl = self.assertRaises(amp.TooLong, c.sendHello, x) - p.flush() - self.failIf(tl.isKey) - self.failUnless(tl.isLocal) - self.failUnlessIdentical(tl.keyName, 'hello') - self.failUnlessIdentical(tl.value, x) - self.failUnless(str(len(x)) in repr(tl)) - self.failUnless("value" in repr(tl)) - self.failUnless('hello' in repr(tl)) - - - def test_helloWorldCommand(self): - """ - Verify that a simple command can be sent and its response received with - the high-level value parsing API. - """ - c, s, p = connectedServerAndClient( - ServerClass=SimpleSymmetricCommandProtocol, - ClientClass=SimpleSymmetricCommandProtocol) - L = [] - HELLO = 'world' - c.sendHello(HELLO).addCallback(L.append) - p.flush() - self.assertEquals(L[0]['hello'], HELLO) - - - def test_helloErrorHandling(self): - """ - Verify that if a known error type is raised and handled, it will be - properly relayed to the other end of the connection and translated into - an exception, and no error will be logged. - """ - L=[] - c, s, p = connectedServerAndClient( - ServerClass=SimpleSymmetricCommandProtocol, - ClientClass=SimpleSymmetricCommandProtocol) - HELLO = 'fuck you' - c.sendHello(HELLO).addErrback(L.append) - p.flush() - L[0].trap(UnfriendlyGreeting) - self.assertEquals(str(L[0].value), "Don't be a dick.") - - - def test_helloFatalErrorHandling(self): - """ - Verify that if a known, fatal error type is raised and handled, it will - be properly relayed to the other end of the connection and translated - into an exception, no error will be logged, and the connection will be - terminated. - """ - L=[] - c, s, p = connectedServerAndClient( - ServerClass=SimpleSymmetricCommandProtocol, - ClientClass=SimpleSymmetricCommandProtocol) - HELLO = 'die' - c.sendHello(HELLO).addErrback(L.append) - p.flush() - L.pop().trap(DeathThreat) - c.sendHello(HELLO).addErrback(L.append) - p.flush() - L.pop().trap(error.ConnectionDone) - - - - def test_helloNoErrorHandling(self): - """ - Verify that if an unknown error type is raised, it will be relayed to - the other end of the connection and translated into an exception, it - will be logged, and then the connection will be dropped. - """ - L=[] - c, s, p = connectedServerAndClient( - ServerClass=SimpleSymmetricCommandProtocol, - ClientClass=SimpleSymmetricCommandProtocol) - HELLO = THING_I_DONT_UNDERSTAND - c.sendHello(HELLO).addErrback(L.append) - p.flush() - ure = L.pop() - ure.trap(amp.UnknownRemoteError) - c.sendHello(HELLO).addErrback(L.append) - cl = L.pop() - cl.trap(error.ConnectionDone) - # The exception should have been logged. - self.failUnless(self.flushLoggedErrors(ThingIDontUnderstandError)) - - - - def test_lateAnswer(self): - """ - Verify that a command that does not get answered until after the - connection terminates will not cause any errors. - """ - c, s, p = connectedServerAndClient( - ServerClass=SimpleSymmetricCommandProtocol, - ClientClass=SimpleSymmetricCommandProtocol) - L = [] - HELLO = 'world' - c.callRemote(WaitForever).addErrback(L.append) - p.flush() - self.assertEquals(L, []) - s.transport.loseConnection() - p.flush() - L.pop().trap(error.ConnectionDone) - # Just make sure that it doesn't error... - s.waiting.callback({}) - return s.waiting - - - def test_requiresNoAnswer(self): - """ - Verify that a command that requires no answer is run. - """ - L=[] - c, s, p = connectedServerAndClient( - ServerClass=SimpleSymmetricCommandProtocol, - ClientClass=SimpleSymmetricCommandProtocol) - HELLO = 'world' - c.callRemote(NoAnswerHello, hello=HELLO) - p.flush() - self.failUnless(s.greeted) - - - def test_requiresNoAnswerFail(self): - """ - Verify that commands sent after a failed no-answer request do not complete. - """ - L=[] - c, s, p = connectedServerAndClient( - ServerClass=SimpleSymmetricCommandProtocol, - ClientClass=SimpleSymmetricCommandProtocol) - HELLO = 'fuck you' - c.callRemote(NoAnswerHello, hello=HELLO) - p.flush() - # This should be logged locally. - self.failUnless(self.flushLoggedErrors(amp.RemoteAmpError)) - HELLO = 'world' - c.callRemote(Hello, hello=HELLO).addErrback(L.append) - p.flush() - L.pop().trap(error.ConnectionDone) - self.failIf(s.greeted) - - - def test_noAnswerResponderBadAnswer(self): - """ - Verify that responders of requiresAnswer=False commands have to return - a dictionary anyway. - - (requiresAnswer is a hint from the _client_ - the server may be called - upon to answer commands in any case, if the client wants to know when - they complete.) - """ - c, s, p = connectedServerAndClient( - ServerClass=BadNoAnswerCommandProtocol, - ClientClass=SimpleSymmetricCommandProtocol) - c.callRemote(NoAnswerHello, hello="hello") - p.flush() - le = self.flushLoggedErrors(amp.BadLocalReturn) - self.assertEquals(len(le), 1) - - - def test_noAnswerResponderAskedForAnswer(self): - """ - Verify that responders with requiresAnswer=False will actually respond - if the client sets requiresAnswer=True. In other words, verify that - requiresAnswer is a hint honored only by the client. - """ - c, s, p = connectedServerAndClient( - ServerClass=NoAnswerCommandProtocol, - ClientClass=SimpleSymmetricCommandProtocol) - L = [] - c.callRemote(Hello, hello="Hello!").addCallback(L.append) - p.flush() - self.assertEquals(len(L), 1) - self.assertEquals(L, [dict(hello="Hello!-noanswer", - Print=None)]) # Optional response argument - - - def test_ampListCommand(self): - """ - Test encoding of an argument that uses the AmpList encoding. - """ - c, s, p = connectedServerAndClient( - ServerClass=SimpleSymmetricCommandProtocol, - ClientClass=SimpleSymmetricCommandProtocol) - L = [] - c.callRemote(GetList, length=10).addCallback(L.append) - p.flush() - values = L.pop().get('body') - self.assertEquals(values, [{'x': 1}] * 10) - - - def test_failEarlyOnArgSending(self): - """ - Verify that if we pass an invalid argument list (omitting an argument), an - exception will be raised. - """ - okayCommand = Hello(hello="What?") - self.assertRaises(amp.InvalidSignature, Hello) - - - def test_doubleProtocolSwitch(self): - """ - As a debugging aid, a protocol system should raise a - L{ProtocolSwitched} exception when asked to switch a protocol that is - already switched. - """ - serverDeferred = defer.Deferred() - serverProto = SimpleSymmetricCommandProtocol(serverDeferred) - clientDeferred = defer.Deferred() - clientProto = SimpleSymmetricCommandProtocol(clientDeferred) - c, s, p = connectedServerAndClient(ServerClass=lambda: serverProto, - ClientClass=lambda: clientProto) - def switched(result): - self.assertRaises(amp.ProtocolSwitched, c.switchToTestProtocol) - self.testSucceeded = True - c.switchToTestProtocol().addCallback(switched) - p.flush() - self.failUnless(self.testSucceeded) - - - def test_protocolSwitch(self, switcher=SimpleSymmetricCommandProtocol, - spuriousTraffic=False, - spuriousError=False): - """ - Verify that it is possible to switch to another protocol mid-connection and - send data to it successfully. - """ - self.testSucceeded = False - - serverDeferred = defer.Deferred() - serverProto = switcher(serverDeferred) - clientDeferred = defer.Deferred() - clientProto = switcher(clientDeferred) - c, s, p = connectedServerAndClient(ServerClass=lambda: serverProto, - ClientClass=lambda: clientProto) - - if spuriousTraffic: - wfdr = [] # remote - wfd = c.callRemote(WaitForever).addErrback(wfdr.append) - switchDeferred = c.switchToTestProtocol() - if spuriousTraffic: - self.assertRaises(amp.ProtocolSwitched, c.sendHello, 'world') - - def cbConnsLost(((serverSuccess, serverData), - (clientSuccess, clientData))): - self.failUnless(serverSuccess) - self.failUnless(clientSuccess) - self.assertEquals(''.join(serverData), SWITCH_CLIENT_DATA) - self.assertEquals(''.join(clientData), SWITCH_SERVER_DATA) - self.testSucceeded = True - - def cbSwitch(proto): - return defer.DeferredList( - [serverDeferred, clientDeferred]).addCallback(cbConnsLost) - - switchDeferred.addCallback(cbSwitch) - p.flush() - if serverProto.maybeLater is not None: - serverProto.maybeLater.callback(serverProto.maybeLaterProto) - p.flush() - if spuriousTraffic: - # switch is done here; do this here to make sure that if we're - # going to corrupt the connection, we do it before it's closed. - if spuriousError: - s.waiting.errback(amp.RemoteAmpError( - "SPURIOUS", - "Here's some traffic in the form of an error.")) - else: - s.waiting.callback({}) - p.flush() - c.transport.loseConnection() # close it - p.flush() - self.failUnless(self.testSucceeded) - - - def test_protocolSwitchDeferred(self): - """ - Verify that protocol-switching even works if the value returned from - the command that does the switch is deferred. - """ - return self.test_protocolSwitch(switcher=DeferredSymmetricCommandProtocol) - - - def test_protocolSwitchFail(self, switcher=SimpleSymmetricCommandProtocol): - """ - Verify that if we try to switch protocols and it fails, the connection - stays up and we can go back to speaking AMP. - """ - self.testSucceeded = False - - serverDeferred = defer.Deferred() - serverProto = switcher(serverDeferred) - clientDeferred = defer.Deferred() - clientProto = switcher(clientDeferred) - c, s, p = connectedServerAndClient(ServerClass=lambda: serverProto, - ClientClass=lambda: clientProto) - L = [] - switchDeferred = c.switchToTestProtocol(fail=True).addErrback(L.append) - p.flush() - L.pop().trap(UnknownProtocol) - self.failIf(self.testSucceeded) - # It's a known error, so let's send a "hello" on the same connection; - # it should work. - c.sendHello('world').addCallback(L.append) - p.flush() - self.assertEqual(L.pop()['hello'], 'world') - - - def test_trafficAfterSwitch(self): - """ - Verify that attempts to send traffic after a switch will not corrupt - the nested protocol. - """ - return self.test_protocolSwitch(spuriousTraffic=True) - - - def test_errorAfterSwitch(self): - """ - Returning an error after a protocol switch should record the underlying - error. - """ - return self.test_protocolSwitch(spuriousTraffic=True, - spuriousError=True) - - - def test_quitBoxQuits(self): - """ - Verify that commands with a responseType of QuitBox will in fact - terminate the connection. - """ - c, s, p = connectedServerAndClient( - ServerClass=SimpleSymmetricCommandProtocol, - ClientClass=SimpleSymmetricCommandProtocol) - - L = [] - HELLO = 'world' - GOODBYE = 'everyone' - c.sendHello(HELLO).addCallback(L.append) - p.flush() - self.assertEquals(L.pop()['hello'], HELLO) - c.callRemote(Goodbye).addCallback(L.append) - p.flush() - self.assertEquals(L.pop()['goodbye'], GOODBYE) - c.sendHello(HELLO).addErrback(L.append) - L.pop().trap(error.ConnectionDone) - - - def test_basicLiteralEmit(self): - """ - Verify that the command dictionaries for a callRemoteN look correct - after being serialized and parsed. - """ - c, s, p = connectedServerAndClient() - L = [] - s.ampBoxReceived = L.append - c.callRemote(Hello, hello='hello test', mixedCase='mixed case arg test', - dash_arg='x', underscore_arg='y') - p.flush() - self.assertEquals(len(L), 1) - for k, v in [('_command', Hello.commandName), - ('hello', 'hello test'), - ('mixedCase', 'mixed case arg test'), - ('dash-arg', 'x'), - ('underscore_arg', 'y')]: - self.assertEquals(L[-1].pop(k), v) - L[-1].pop('_ask') - self.assertEquals(L[-1], {}) - - - def test_basicStructuredEmit(self): - """ - Verify that a call similar to basicLiteralEmit's is handled properly with - high-level quoting and passing to Python methods, and that argument - names are correctly handled. - """ - L = [] - class StructuredHello(amp.AMP): - def h(self, *a, **k): - L.append((a, k)) - return dict(hello='aaa') - Hello.responder(h) - c, s, p = connectedServerAndClient(ServerClass=StructuredHello) - c.callRemote(Hello, hello='hello test', mixedCase='mixed case arg test', - dash_arg='x', underscore_arg='y').addCallback(L.append) - p.flush() - self.assertEquals(len(L), 2) - self.assertEquals(L[0], - ((), dict( - hello='hello test', - mixedCase='mixed case arg test', - dash_arg='x', - underscore_arg='y', - - # XXX - should optional arguments just not be passed? - # passing None seems a little odd, looking at the way it - # turns out here... -glyph - From=('file', 'file'), - Print=None, - optional=None, - ))) - self.assertEquals(L[1], dict(Print=None, hello='aaa')) - -class PretendRemoteCertificateAuthority: - def checkIsPretendRemote(self): - return True - -class IOSimCert: - verifyCount = 0 - - def options(self, *ign): - return self - - def iosimVerify(self, otherCert): - """ - This isn't a real certificate, and wouldn't work on a real socket, but - iosim specifies a different API so that we don't have to do any crypto - math to demonstrate that the right functions get called in the right - places. - """ - assert otherCert is self - self.verifyCount += 1 - return True - -class OKCert(IOSimCert): - def options(self, x): - assert x.checkIsPretendRemote() - return self - -class GrumpyCert(IOSimCert): - def iosimVerify(self, otherCert): - self.verifyCount += 1 - return False - -class DroppyCert(IOSimCert): - def __init__(self, toDrop): - self.toDrop = toDrop - - def iosimVerify(self, otherCert): - self.verifyCount += 1 - self.toDrop.loseConnection() - return True - -class SecurableProto(FactoryNotifier): - - factory = None - - def verifyFactory(self): - return [PretendRemoteCertificateAuthority()] - - def getTLSVars(self): - cert = self.certFactory() - verify = self.verifyFactory() - return dict( - tls_localCertificate=cert, - tls_verifyAuthorities=verify) - amp.StartTLS.responder(getTLSVars) - - - -class TLSTest(unittest.TestCase): - def test_startingTLS(self): - """ - Verify that starting TLS and succeeding at handshaking sends all the - notifications to all the right places. - """ - cli, svr, p = connectedServerAndClient( - ServerClass=SecurableProto, - ClientClass=SecurableProto) - - okc = OKCert() - svr.certFactory = lambda : okc - - cli.callRemote( - amp.StartTLS, tls_localCertificate=okc, - tls_verifyAuthorities=[PretendRemoteCertificateAuthority()]) - - # let's buffer something to be delivered securely - L = [] - d = cli.callRemote(SecuredPing).addCallback(L.append) - p.flush() - # once for client once for server - self.assertEquals(okc.verifyCount, 2) - L = [] - d = cli.callRemote(SecuredPing).addCallback(L.append) - p.flush() - self.assertEqual(L[0], {'pinged': True}) - - - def test_startTooManyTimes(self): - """ - Verify that the protocol will complain if we attempt to renegotiate TLS, - which we don't support. - """ - cli, svr, p = connectedServerAndClient( - ServerClass=SecurableProto, - ClientClass=SecurableProto) - - okc = OKCert() - svr.certFactory = lambda : okc - - cli.callRemote(amp.StartTLS, - tls_localCertificate=okc, - tls_verifyAuthorities=[PretendRemoteCertificateAuthority()]) - p.flush() - cli.noPeerCertificate = True # this is totally fake - self.assertRaises( - amp.OnlyOneTLS, - cli.callRemote, - amp.StartTLS, - tls_localCertificate=okc, - tls_verifyAuthorities=[PretendRemoteCertificateAuthority()]) - - - def test_negotiationFailed(self): - """ - Verify that starting TLS and failing on both sides at handshaking sends - notifications to all the right places and terminates the connection. - """ - - badCert = GrumpyCert() - - cli, svr, p = connectedServerAndClient( - ServerClass=SecurableProto, - ClientClass=SecurableProto) - svr.certFactory = lambda : badCert - - cli.callRemote(amp.StartTLS, - tls_localCertificate=badCert) - - p.flush() - # once for client once for server - but both fail - self.assertEquals(badCert.verifyCount, 2) - d = cli.callRemote(SecuredPing) - p.flush() - self.assertFailure(d, iosim.OpenSSLVerifyError) - - - def test_negotiationFailedByClosing(self): - """ - Verify that starting TLS and failing by way of a lost connection - notices that it is probably an SSL problem. - """ - - cli, svr, p = connectedServerAndClient( - ServerClass=SecurableProto, - ClientClass=SecurableProto) - droppyCert = DroppyCert(svr.transport) - svr.certFactory = lambda : droppyCert - - secure = cli.callRemote(amp.StartTLS, - tls_localCertificate=droppyCert) - - p.flush() - - self.assertEquals(droppyCert.verifyCount, 2) - - d = cli.callRemote(SecuredPing) - p.flush() - - # it might be a good idea to move this exception somewhere more - # reasonable. - self.assertFailure(d, error.PeerVerifyError) - - - -class InheritedError(Exception): - """ - This error is used to check inheritance. - """ - - - -class OtherInheritedError(Exception): - """ - This is a distinct error for checking inheritance. - """ - - - -class BaseCommand(amp.Command): - """ - This provides a command that will be subclassed. - """ - errors = {InheritedError: 'INHERITED_ERROR'} - - - -class InheritedCommand(BaseCommand): - """ - This is a command which subclasses another command but does not override - anything. - """ - - - -class AddErrorsCommand(BaseCommand): - """ - This is a command which subclasses another command but adds errors to the - list. - """ - arguments = [('other', amp.Boolean())] - errors = {OtherInheritedError: 'OTHER_INHERITED_ERROR'} - - - -class NormalCommandProtocol(amp.AMP): - """ - This is a protocol which responds to L{BaseCommand}, and is used to test - that inheritance does not interfere with the normal handling of errors. - """ - def resp(self): - raise InheritedError() - BaseCommand.responder(resp) - - - -class InheritedCommandProtocol(amp.AMP): - """ - This is a protocol which responds to L{InheritedCommand}, and is used to - test that inherited commands inherit their bases' errors if they do not - respond to any of their own. - """ - def resp(self): - raise InheritedError() - InheritedCommand.responder(resp) - - - -class AddedCommandProtocol(amp.AMP): - """ - This is a protocol which responds to L{AddErrorsCommand}, and is used to - test that inherited commands can add their own new types of errors, but - still respond in the same way to their parents types of errors. - """ - def resp(self, other): - if other: - raise OtherInheritedError() - else: - raise InheritedError() - AddErrorsCommand.responder(resp) - - - -class CommandInheritanceTests(unittest.TestCase): - """ - These tests verify that commands inherit error conditions properly. - """ - - def errorCheck(self, err, proto, cmd, **kw): - """ - Check that the appropriate kind of error is raised when a given command - is sent to a given protocol. - """ - c, s, p = connectedServerAndClient(ServerClass=proto, - ClientClass=proto) - d = c.callRemote(cmd, **kw) - d2 = self.failUnlessFailure(d, err) - p.flush() - return d2 - - - def test_basicErrorPropagation(self): - """ - Verify that errors specified in a superclass are respected normally - even if it has subclasses. - """ - return self.errorCheck( - InheritedError, NormalCommandProtocol, BaseCommand) - - - def test_inheritedErrorPropagation(self): - """ - Verify that errors specified in a superclass command are propagated to - its subclasses. - """ - return self.errorCheck( - InheritedError, InheritedCommandProtocol, InheritedCommand) - - - def test_inheritedErrorAddition(self): - """ - Verify that new errors specified in a subclass of an existing command - are honored even if the superclass defines some errors. - """ - return self.errorCheck( - OtherInheritedError, AddedCommandProtocol, AddErrorsCommand, other=True) - - - def test_additionWithOriginalError(self): - """ - Verify that errors specified in a command's superclass are respected - even if that command defines new errors itself. - """ - return self.errorCheck( - InheritedError, AddedCommandProtocol, AddErrorsCommand, other=False) - - -def _loseAndPass(err, proto): - # be specific, pass on the error to the client. - err.trap(error.ConnectionLost, error.ConnectionDone) - del proto.connectionLost - proto.connectionLost(err) - - -class LiveFireBase: - """ - Utility for connected reactor-using tests. - """ - - def setUp(self): - """ - Create an amp server and connect a client to it. - """ - from twisted.internet import reactor - self.serverFactory = protocol.ServerFactory() - self.serverFactory.protocol = self.serverProto - self.clientFactory = protocol.ClientFactory() - self.clientFactory.protocol = self.clientProto - self.clientFactory.onMade = defer.Deferred() - self.serverFactory.onMade = defer.Deferred() - self.serverPort = reactor.listenTCP(0, self.serverFactory) - self.addCleanup(self.serverPort.stopListening) - self.clientConn = reactor.connectTCP( - '127.0.0.1', self.serverPort.getHost().port, - self.clientFactory) - self.addCleanup(self.clientConn.disconnect) - def getProtos(rlst): - self.cli = self.clientFactory.theProto - self.svr = self.serverFactory.theProto - dl = defer.DeferredList([self.clientFactory.onMade, - self.serverFactory.onMade]) - return dl.addCallback(getProtos) - - def tearDown(self): - """ - Cleanup client and server connections, and check the error got at - C{connectionLost}. - """ - L = [] - for conn in self.cli, self.svr: - if conn.transport is not None: - # depend on amp's function connection-dropping behavior - d = defer.Deferred().addErrback(_loseAndPass, conn) - conn.connectionLost = d.errback - conn.transport.loseConnection() - L.append(d) - return defer.gatherResults(L - ).addErrback(lambda first: first.value.subFailure) - - -def show(x): - import sys - sys.stdout.write(x+'\n') - sys.stdout.flush() - - -def tempSelfSigned(): - from twisted.internet import ssl - - sharedDN = ssl.DN(CN='shared') - key = ssl.KeyPair.generate() - cr = key.certificateRequest(sharedDN) - sscrd = key.signCertificateRequest( - sharedDN, cr, lambda dn: True, 1234567) - cert = key.newCertificate(sscrd) - return cert - -tempcert = tempSelfSigned() - - -class LiveFireTLSTestCase(LiveFireBase, unittest.TestCase): - clientProto = SecurableProto - serverProto = SecurableProto - def test_liveFireCustomTLS(self): - """ - Using real, live TLS, actually negotiate a connection. - - This also looks at the 'peerCertificate' attribute's correctness, since - that's actually loaded using OpenSSL calls, but the main purpose is to - make sure that we didn't miss anything obvious in iosim about TLS - negotiations. - """ - - cert = tempcert - - self.svr.verifyFactory = lambda : [cert] - self.svr.certFactory = lambda : cert - # only needed on the server, we specify the client below. - - def secured(rslt): - x = cert.digest() - def pinged(rslt2): - # Interesting. OpenSSL won't even _tell_ us about the peer - # cert until we negotiate. we should be able to do this in - # 'secured' instead, but it looks like we can't. I think this - # is a bug somewhere far deeper than here. - self.failUnlessEqual(x, self.cli.hostCertificate.digest()) - self.failUnlessEqual(x, self.cli.peerCertificate.digest()) - self.failUnlessEqual(x, self.svr.hostCertificate.digest()) - self.failUnlessEqual(x, self.svr.peerCertificate.digest()) - return self.cli.callRemote(SecuredPing).addCallback(pinged) - return self.cli.callRemote(amp.StartTLS, - tls_localCertificate=cert, - tls_verifyAuthorities=[cert]).addCallback(secured) - - -class SlightlySmartTLS(SimpleSymmetricCommandProtocol): - """ - Specific implementation of server side protocol with different - management of TLS. - """ - def getTLSVars(self): - """ - @return: the global C{tempcert} certificate as local certificate. - """ - return dict(tls_localCertificate=tempcert) - amp.StartTLS.responder(getTLSVars) - - -class PlainVanillaLiveFire(LiveFireBase, unittest.TestCase): - - clientProto = SimpleSymmetricCommandProtocol - serverProto = SimpleSymmetricCommandProtocol - - def test_liveFireDefaultTLS(self): - """ - Verify that out of the box, we can start TLS to at least encrypt the - connection, even if we don't have any certificates to use. - """ - def secured(result): - return self.cli.callRemote(SecuredPing) - return self.cli.callRemote(amp.StartTLS).addCallback(secured) - - -class WithServerTLSVerification(LiveFireBase, unittest.TestCase): - clientProto = SimpleSymmetricCommandProtocol - serverProto = SlightlySmartTLS - - def test_anonymousVerifyingClient(self): - """ - Verify that anonymous clients can verify server certificates. - """ - def secured(result): - return self.cli.callRemote(SecuredPing) - return self.cli.callRemote(amp.StartTLS, - tls_verifyAuthorities=[tempcert] - ).addCallback(secured) - - - -class ProtocolIncludingArgument(amp.Argument): - """ - An L{amp.Argument} which encodes its parser and serializer - arguments *including the protocol* into its parsed and serialized - forms. - """ - - def fromStringProto(self, string, protocol): - """ - Don't decode anything; just return all possible information. - - @return: A two-tuple of the input string and the protocol. - """ - return (string, protocol) - - def toStringProto(self, obj, protocol): - """ - Encode identifying information about L{object} and protocol - into a string for later verification. - - @type obj: L{object} - @type protocol: L{amp.AMP} - """ - return "%s:%s" % (id(obj), id(protocol)) - - - -class ProtocolIncludingCommand(amp.Command): - """ - A command that has argument and response schemas which use - L{ProtocolIncludingArgument}. - """ - arguments = [('weird', ProtocolIncludingArgument())] - response = [('weird', ProtocolIncludingArgument())] - - - -class MagicSchemaCommand(amp.Command): - """ - A command which overrides L{parseResponse}, L{parseArguments}, and - L{makeResponse}. - """ - def parseResponse(self, strings, protocol): - """ - Don't do any parsing, just jam the input strings and protocol - onto the C{protocol.parseResponseArguments} attribute as a - two-tuple. Return the original strings. - """ - protocol.parseResponseArguments = (strings, protocol) - return strings - parseResponse = classmethod(parseResponse) - - - def parseArguments(cls, strings, protocol): - """ - Don't do any parsing, just jam the input strings and protocol - onto the C{protocol.parseArgumentsArguments} attribute as a - two-tuple. Return the original strings. - """ - protocol.parseArgumentsArguments = (strings, protocol) - return strings - parseArguments = classmethod(parseArguments) - - - def makeArguments(cls, objects, protocol): - """ - Don't do any serializing, just jam the input strings and protocol - onto the C{protocol.makeArgumentsArguments} attribute as a - two-tuple. Return the original strings. - """ - protocol.makeArgumentsArguments = (objects, protocol) - return objects - makeArguments = classmethod(makeArguments) - - - -class NoNetworkProtocol(amp.AMP): - """ - An L{amp.AMP} subclass which overrides private methods to avoid - testing the network. It also provides a responder for - L{MagicSchemaCommand} that does nothing, so that tests can test - aspects of the interaction of L{amp.Command}s and L{amp.AMP}. - - @ivar parseArgumentsArguments: Arguments that have been passed to any - L{MagicSchemaCommand}, if L{MagicSchemaCommand} has been handled by - this protocol. - - @ivar parseResponseArguments: Responses that have been returned from a - L{MagicSchemaCommand}, if L{MagicSchemaCommand} has been handled by - this protocol. - - @ivar makeArgumentsArguments: Arguments that have been serialized by any - L{MagicSchemaCommand}, if L{MagicSchemaCommand} has been handled by - this protocol. - """ - def _sendBoxCommand(self, commandName, strings, requiresAnswer): - """ - Return a Deferred which fires with the original strings. - """ - return defer.succeed(strings) - - MagicSchemaCommand.responder(lambda s, weird: {}) - - - -class MyBox(dict): - """ - A unique dict subclass. - """ - - - -class ProtocolIncludingCommandWithDifferentCommandType( - ProtocolIncludingCommand): - """ - A L{ProtocolIncludingCommand} subclass whose commandType is L{MyBox} - """ - commandType = MyBox - - - -class CommandTestCase(unittest.TestCase): - """ - Tests for L{amp.Command}. - """ - - def test_parseResponse(self): - """ - There should be a class method of Command which accepts a - mapping of argument names to serialized forms and returns a - similar mapping whose values have been parsed via the - Command's response schema. - """ - protocol = object() - result = 'whatever' - strings = {'weird': result} - self.assertEqual( - ProtocolIncludingCommand.parseResponse(strings, protocol), - {'weird': (result, protocol)}) - - - def test_callRemoteCallsParseResponse(self): - """ - Making a remote call on a L{amp.Command} subclass which - overrides the C{parseResponse} method should call that - C{parseResponse} method to get the response. - """ - client = NoNetworkProtocol() - thingy = "weeoo" - response = client.callRemote(MagicSchemaCommand, weird=thingy) - def gotResponse(ign): - self.assertEquals(client.parseResponseArguments, - ({"weird": thingy}, client)) - response.addCallback(gotResponse) - return response - - - def test_parseArguments(self): - """ - There should be a class method of L{amp.Command} which accepts - a mapping of argument names to serialized forms and returns a - similar mapping whose values have been parsed via the - command's argument schema. - """ - protocol = object() - result = 'whatever' - strings = {'weird': result} - self.assertEqual( - ProtocolIncludingCommand.parseArguments(strings, protocol), - {'weird': (result, protocol)}) - - - def test_responderCallsParseArguments(self): - """ - Making a remote call on a L{amp.Command} subclass which - overrides the C{parseArguments} method should call that - C{parseArguments} method to get the arguments. - """ - protocol = NoNetworkProtocol() - responder = protocol.locateResponder(MagicSchemaCommand.commandName) - argument = object() - response = responder(dict(weird=argument)) - response.addCallback( - lambda ign: self.assertEqual(protocol.parseArgumentsArguments, - ({"weird": argument}, protocol))) - return response - - - def test_makeArguments(self): - """ - There should be a class method of L{amp.Command} which accepts - a mapping of argument names to objects and returns a similar - mapping whose values have been serialized via the command's - argument schema. - """ - protocol = object() - argument = object() - objects = {'weird': argument} - self.assertEqual( - ProtocolIncludingCommand.makeArguments(objects, protocol), - {'weird': "%d:%d" % (id(argument), id(protocol))}) - - - def test_makeArgumentsUsesCommandType(self): - """ - L{amp.Command.makeArguments}'s return type should be the type - of the result of L{amp.Command.commandType}. - """ - protocol = object() - objects = {"weird": "whatever"} - - result = ProtocolIncludingCommandWithDifferentCommandType.makeArguments( - objects, protocol) - self.assertIdentical(type(result), MyBox) - - - def test_callRemoteCallsMakeArguments(self): - """ - Making a remote call on a L{amp.Command} subclass which - overrides the C{makeArguments} method should call that - C{makeArguments} method to get the response. - """ - client = NoNetworkProtocol() - argument = object() - response = client.callRemote(MagicSchemaCommand, weird=argument) - def gotResponse(ign): - self.assertEqual(client.makeArgumentsArguments, - ({"weird": argument}, client)) - response.addCallback(gotResponse) - return response - -if not interfaces.IReactorSSL.providedBy(reactor): - skipMsg = 'This test case requires SSL support in the reactor' - TLSTest.skip = skipMsg - LiveFireTLSTestCase.skip = skipMsg - PlainVanillaLiveFire.skip = skipMsg - WithServerTLSVerification.skip = skipMsg - diff --git a/tools/buildbot/pylibs/twisted/test/test_application.py b/tools/buildbot/pylibs/twisted/test/test_application.py deleted file mode 100644 index 41d916d5..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_application.py +++ /dev/null @@ -1,899 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -import sys, copy, os, pickle, warnings -from StringIO import StringIO - - -from twisted.trial import unittest, util -from twisted.application import service, internet, app -from twisted.persisted import sob -from twisted.python import usage -from twisted.python.util import sibpath -from twisted.internet import interfaces, defer -from twisted.protocols import wire, basic -from twisted.internet import protocol, reactor -from twisted.internet.utils import getProcessOutputAndValue -from twisted.application import reactors - -try: - from twisted.web import microdom - gotMicrodom = True -except ImportError: - warnings.warn("Not testing xml persistence as twisted.web.microdom " - "not available") - gotMicrodom = False - - -oldAppSuppressions = [util.suppress(message='twisted.internet.app is deprecated', - category=DeprecationWarning)] - -class Dummy: - processName=None - -class TestService(unittest.TestCase): - - def testName(self): - s = service.Service() - s.setName("hello") - self.failUnlessEqual(s.name, "hello") - - def testParent(self): - s = service.Service() - p = service.MultiService() - s.setServiceParent(p) - self.failUnlessEqual(list(p), [s]) - self.failUnlessEqual(s.parent, p) - - def testApplicationAsParent(self): - s = service.Service() - p = service.Application("") - s.setServiceParent(p) - self.failUnlessEqual(list(service.IServiceCollection(p)), [s]) - self.failUnlessEqual(s.parent, service.IServiceCollection(p)) - - def testNamedChild(self): - s = service.Service() - p = service.MultiService() - s.setName("hello") - s.setServiceParent(p) - self.failUnlessEqual(list(p), [s]) - self.failUnlessEqual(s.parent, p) - self.failUnlessEqual(p.getServiceNamed("hello"), s) - - def testDoublyNamedChild(self): - s = service.Service() - p = service.MultiService() - s.setName("hello") - s.setServiceParent(p) - self.failUnlessRaises(RuntimeError, s.setName, "lala") - - def testDuplicateNamedChild(self): - s = service.Service() - p = service.MultiService() - s.setName("hello") - s.setServiceParent(p) - s = service.Service() - s.setName("hello") - self.failUnlessRaises(RuntimeError, s.setServiceParent, p) - - def testDisowning(self): - s = service.Service() - p = service.MultiService() - s.setServiceParent(p) - self.failUnlessEqual(list(p), [s]) - self.failUnlessEqual(s.parent, p) - s.disownServiceParent() - self.failUnlessEqual(list(p), []) - self.failUnlessEqual(s.parent, None) - - def testRunning(self): - s = service.Service() - self.assert_(not s.running) - s.startService() - self.assert_(s.running) - s.stopService() - self.assert_(not s.running) - - def testRunningChildren1(self): - s = service.Service() - p = service.MultiService() - s.setServiceParent(p) - self.assert_(not s.running) - self.assert_(not p.running) - p.startService() - self.assert_(s.running) - self.assert_(p.running) - p.stopService() - self.assert_(not s.running) - self.assert_(not p.running) - - def testRunningChildren2(self): - s = service.Service() - def checkRunning(): - self.assert_(s.running) - t = service.Service() - t.stopService = checkRunning - t.startService = checkRunning - p = service.MultiService() - s.setServiceParent(p) - t.setServiceParent(p) - p.startService() - p.stopService() - - def testAddingIntoRunning(self): - p = service.MultiService() - p.startService() - s = service.Service() - self.assert_(not s.running) - s.setServiceParent(p) - self.assert_(s.running) - s.disownServiceParent() - self.assert_(not s.running) - - def testPrivileged(self): - s = service.Service() - def pss(): - s.privilegedStarted = 1 - s.privilegedStartService = pss - s1 = service.Service() - p = service.MultiService() - s.setServiceParent(p) - s1.setServiceParent(p) - p.privilegedStartService() - self.assert_(s.privilegedStarted) - - def testCopying(self): - s = service.Service() - s.startService() - s1 = copy.copy(s) - self.assert_(not s1.running) - self.assert_(s.running) - - -if hasattr(os, "getuid"): - curuid = os.getuid() - curgid = os.getgid() -else: - curuid = curgid = 0 - - -class TestProcess(unittest.TestCase): - - def testID(self): - p = service.Process(5, 6) - self.assertEqual(p.uid, 5) - self.assertEqual(p.gid, 6) - - def testDefaults(self): - p = service.Process(5) - self.assertEqual(p.uid, 5) - self.assertEqual(p.gid, None) - p = service.Process(gid=5) - self.assertEqual(p.uid, None) - self.assertEqual(p.gid, 5) - p = service.Process() - self.assertEqual(p.uid, None) - self.assertEqual(p.gid, None) - - def testProcessName(self): - p = service.Process() - self.assertEqual(p.processName, None) - p.processName = 'hello' - self.assertEqual(p.processName, 'hello') - - -class TestInterfaces(unittest.TestCase): - - def testService(self): - self.assert_(service.IService.providedBy(service.Service())) - - def testMultiService(self): - self.assert_(service.IService.providedBy(service.MultiService())) - self.assert_(service.IServiceCollection.providedBy(service.MultiService())) - - def testProcess(self): - self.assert_(service.IProcess.providedBy(service.Process())) - - -class TestApplication(unittest.TestCase): - - def testConstructor(self): - service.Application("hello") - service.Application("hello", 5) - service.Application("hello", 5, 6) - - def testProcessComponent(self): - a = service.Application("hello") - self.assertEqual(service.IProcess(a).uid, None) - self.assertEqual(service.IProcess(a).gid, None) - a = service.Application("hello", 5) - self.assertEqual(service.IProcess(a).uid, 5) - self.assertEqual(service.IProcess(a).gid, None) - a = service.Application("hello", 5, 6) - self.assertEqual(service.IProcess(a).uid, 5) - self.assertEqual(service.IProcess(a).gid, 6) - - def testServiceComponent(self): - a = service.Application("hello") - self.assert_(service.IService(a) is service.IServiceCollection(a)) - self.assertEqual(service.IService(a).name, "hello") - self.assertEqual(service.IService(a).parent, None) - - def testPersistableComponent(self): - a = service.Application("hello") - p = sob.IPersistable(a) - self.assertEqual(p.style, 'pickle') - self.assertEqual(p.name, 'hello') - self.assert_(p.original is a) - -class TestLoading(unittest.TestCase): - - def test_simpleStoreAndLoad(self): - a = service.Application("hello") - p = sob.IPersistable(a) - for style in 'xml source pickle'.split(): - if style == 'xml' and not gotMicrodom: - continue - p.setStyle(style) - p.save() - a1 = service.loadApplication("hello.ta"+style[0], style) - self.assertEqual(service.IService(a1).name, "hello") - open("hello.tac", 'w').writelines([ - "from twisted.application import service\n", - "application = service.Application('hello')\n", - ]) - a1 = service.loadApplication("hello.tac", 'python') - self.assertEqual(service.IService(a1).name, "hello") - - - -class TestAppSupport(unittest.TestCase): - - def testPassphrase(self): - self.assertEqual(app.getPassphrase(0), None) - - def testLoadApplication(self): - """ - Test loading an application file in different dump format. - """ - a = service.Application("hello") - baseconfig = {'file': None, 'xml': None, 'source': None, 'python':None} - for style in 'source xml pickle'.split(): - if style == 'xml' and not gotMicrodom: - continue - config = baseconfig.copy() - config[{'pickle': 'file'}.get(style, style)] = 'helloapplication' - sob.IPersistable(a).setStyle(style) - sob.IPersistable(a).save(filename='helloapplication') - a1 = app.getApplication(config, None) - self.assertEqual(service.IService(a1).name, "hello") - config = baseconfig.copy() - config['python'] = 'helloapplication' - open("helloapplication", 'w').writelines([ - "from twisted.application import service\n", - "application = service.Application('hello')\n", - ]) - a1 = app.getApplication(config, None) - self.assertEqual(service.IService(a1).name, "hello") - - testLoadApplication.suppress = [ - util.suppress(message="twisted.persisted.marmalade is deprecated", - category=DeprecationWarning)] - - def test_convertStyle(self): - appl = service.Application("lala") - for instyle in 'xml source pickle'.split(): - if instyle == 'xml' and not gotMicrodom: - continue - for outstyle in 'xml source pickle'.split(): - if outstyle == 'xml' and not gotMicrodom: - continue - sob.IPersistable(appl).setStyle(instyle) - sob.IPersistable(appl).save(filename="converttest") - app.convertStyle("converttest", instyle, None, - "converttest.out", outstyle, 0) - appl2 = service.loadApplication("converttest.out", outstyle) - self.assertEqual(service.IService(appl2).name, "lala") - - def test_getLogFile(self): - """ - Test L{app.getLogFile}, veryfying the LogFile instance it returns. - """ - os.mkdir("logfiledir") - l = app.getLogFile(os.path.join("logfiledir", "lala")) - self.assertEqual(l.path, - os.path.abspath(os.path.join("logfiledir", "lala"))) - self.assertEqual(l.name, "lala") - self.assertEqual(l.directory, os.path.abspath("logfiledir")) - - test_getLogFile.suppress = [ - util.suppress(message="app.getLogFile is deprecated. Use " - "twisted.python.logfile.LogFile.fromFullPath instead", - category=DeprecationWarning)] - - def test_startApplication(self): - appl = service.Application("lala") - app.startApplication(appl, 0) - self.assert_(service.IService(appl).running) - - -class Foo(basic.LineReceiver): - def connectionMade(self): - self.transport.write('lalala\r\n') - def lineReceived(self, line): - self.factory.line = line - self.transport.loseConnection() - def connectionLost(self, reason): - self.factory.d.callback(self.factory.line) - - -class DummyApp: - processName = None - def addService(self, service): - self.services[service.name] = service - def removeService(self, service): - del self.services[service.name] - - -class TimerTarget: - def __init__(self): - self.l = [] - def append(self, what): - self.l.append(what) - -class TestEcho(wire.Echo): - def connectionLost(self, reason): - self.d.callback(True) - -class TestInternet2(unittest.TestCase): - - def testTCP(self): - s = service.MultiService() - s.startService() - factory = protocol.ServerFactory() - factory.protocol = TestEcho - TestEcho.d = defer.Deferred() - t = internet.TCPServer(0, factory) - t.setServiceParent(s) - num = t._port.getHost().port - factory = protocol.ClientFactory() - factory.d = defer.Deferred() - factory.protocol = Foo - factory.line = None - internet.TCPClient('127.0.0.1', num, factory).setServiceParent(s) - factory.d.addCallback(self.assertEqual, 'lalala') - factory.d.addCallback(lambda x : s.stopService()) - factory.d.addCallback(lambda x : TestEcho.d) - return factory.d - - - def test_UDP(self): - """ - Test L{internet.UDPServer} with a random port: starting the service - should give it valid port, and stopService should free it so that we - can start a server on the same port again. - """ - if not interfaces.IReactorUDP(reactor, None): - raise unittest.SkipTest("This reactor does not support UDP sockets") - p = protocol.DatagramProtocol() - t = internet.UDPServer(0, p) - t.startService() - num = t._port.getHost().port - self.assertNotEquals(num, 0) - def onStop(ignored): - t = internet.UDPServer(num, p) - t.startService() - return t.stopService() - return defer.maybeDeferred(t.stopService).addCallback(onStop) - - - def testPrivileged(self): - factory = protocol.ServerFactory() - factory.protocol = TestEcho - TestEcho.d = defer.Deferred() - t = internet.TCPServer(0, factory) - t.privileged = 1 - t.privilegedStartService() - num = t._port.getHost().port - factory = protocol.ClientFactory() - factory.d = defer.Deferred() - factory.protocol = Foo - factory.line = None - c = internet.TCPClient('127.0.0.1', num, factory) - c.startService() - factory.d.addCallback(self.assertEqual, 'lalala') - factory.d.addCallback(lambda x : c.stopService()) - factory.d.addCallback(lambda x : t.stopService()) - factory.d.addCallback(lambda x : TestEcho.d) - return factory.d - - def testConnectionGettingRefused(self): - factory = protocol.ServerFactory() - factory.protocol = wire.Echo - t = internet.TCPServer(0, factory) - t.startService() - num = t._port.getHost().port - t.stopService() - d = defer.Deferred() - factory = protocol.ClientFactory() - factory.clientConnectionFailed = lambda *args: d.callback(None) - c = internet.TCPClient('127.0.0.1', num, factory) - c.startService() - return d - - def testUNIX(self): - # FIXME: This test is far too dense. It needs comments. - # -- spiv, 2004-11-07 - if not interfaces.IReactorUNIX(reactor, None): - raise unittest.SkipTest, "This reactor does not support UNIX domain sockets" - s = service.MultiService() - s.startService() - factory = protocol.ServerFactory() - factory.protocol = TestEcho - TestEcho.d = defer.Deferred() - t = internet.UNIXServer('echo.skt', factory) - t.setServiceParent(s) - factory = protocol.ClientFactory() - factory.protocol = Foo - factory.d = defer.Deferred() - factory.line = None - internet.UNIXClient('echo.skt', factory).setServiceParent(s) - factory.d.addCallback(self.assertEqual, 'lalala') - factory.d.addCallback(lambda x : s.stopService()) - factory.d.addCallback(lambda x : TestEcho.d) - factory.d.addCallback(self._cbTestUnix, factory, s) - return factory.d - - def _cbTestUnix(self, ignored, factory, s): - TestEcho.d = defer.Deferred() - factory.line = None - factory.d = defer.Deferred() - s.startService() - factory.d.addCallback(self.assertEqual, 'lalala') - factory.d.addCallback(lambda x : s.stopService()) - factory.d.addCallback(lambda x : TestEcho.d) - return factory.d - - def testVolatile(self): - if not interfaces.IReactorUNIX(reactor, None): - raise unittest.SkipTest, "This reactor does not support UNIX domain sockets" - factory = protocol.ServerFactory() - factory.protocol = wire.Echo - t = internet.UNIXServer('echo.skt', factory) - t.startService() - self.failIfIdentical(t._port, None) - t1 = copy.copy(t) - self.assertIdentical(t1._port, None) - t.stopService() - self.assertIdentical(t._port, None) - self.failIf(t.running) - - factory = protocol.ClientFactory() - factory.protocol = wire.Echo - t = internet.UNIXClient('echo.skt', factory) - t.startService() - self.failIfIdentical(t._connection, None) - t1 = copy.copy(t) - self.assertIdentical(t1._connection, None) - t.stopService() - self.assertIdentical(t._connection, None) - self.failIf(t.running) - - def testStoppingServer(self): - if not interfaces.IReactorUNIX(reactor, None): - raise unittest.SkipTest, "This reactor does not support UNIX domain sockets" - factory = protocol.ServerFactory() - factory.protocol = wire.Echo - t = internet.UNIXServer('echo.skt', factory) - t.startService() - t.stopService() - self.failIf(t.running) - factory = protocol.ClientFactory() - d = defer.Deferred() - factory.clientConnectionFailed = lambda *args: d.callback(None) - reactor.connectUNIX('echo.skt', factory) - return d - - def testPickledTimer(self): - target = TimerTarget() - t0 = internet.TimerService(1, target.append, "hello") - t0.startService() - s = pickle.dumps(t0) - t0.stopService() - - t = pickle.loads(s) - self.failIf(t.running) - - def testBrokenTimer(self): - d = defer.Deferred() - t = internet.TimerService(1, lambda: 1 / 0) - oldFailed = t._failed - def _failed(why): - oldFailed(why) - d.callback(None) - t._failed = _failed - t.startService() - d.addCallback(lambda x : t.stopService) - d.addCallback(lambda x : self.assertEqual( - [ZeroDivisionError], - [o.value.__class__ for o in self.flushLoggedErrors(ZeroDivisionError)])) - return d - - def testEverythingThere(self): - trans = 'TCP UNIX SSL UDP UNIXDatagram Multicast'.split() - for tran in trans[:]: - if not getattr(interfaces, "IReactor"+tran)(reactor, None): - trans.remove(tran) - if interfaces.IReactorArbitrary(reactor, None) is not None: - trans.insert(0, "Generic") - for tran in trans: - for side in 'Server Client'.split(): - if tran == "Multicast" and side == "Client": - continue - self.assert_(hasattr(internet, tran+side)) - method = getattr(internet, tran+side).method - prefix = {'Server': 'listen', 'Client': 'connect'}[side] - self.assert_(hasattr(reactor, prefix+method) or - (prefix == "connect" and method == "UDP")) - o = getattr(internet, tran+side)() - self.assertEqual(service.IService(o), o) - - - def test_reactorParametrizationInServer(self): - """ - L{internet._AbstractServer} supports a C{reactor} keyword argument - that can be used to parametrize the reactor used to listen for - connections. - """ - listen = [] - class FakeReactor(object): - def listenTCP(self, portNumber, factory): - listen.append((portNumber, factory)) - reactor = FakeReactor() - - factory = object() - t = internet.TCPServer(1234, factory, reactor=reactor) - t.startService() - self.assertEquals(listen, [(1234, factory)]) - - - def test_reactorParametrizationInClient(self): - """ - L{internet._AbstractClient} supports a C{reactor} keyword arguments - that can be used to parametrize the reactor used to create new client - connections. - """ - connect = [] - class FakeReactor(object): - def connectTCP(self, ip, portNumber, factory): - connect.append((ip, portNumber, factory)) - reactor = FakeReactor() - - factory = object() - t = internet.TCPClient('127.0.0.1', 1234, factory, reactor=reactor) - t.startService() - self.assertEquals(connect, [('127.0.0.1', 1234, factory)]) - - - def test_reactorParametrizationInServerMultipleStart(self): - """ - Like L{test_reactorParametrizationInServer}, but stop and restart the - service and check that the given reactor is still used. - """ - listen = [] - class FakeReactor(object): - def listenTCP(self, portNumber, factory): - listen.append((portNumber, factory)) - reactor = FakeReactor() - - factory = object() - t = internet.TCPServer(1234, factory, reactor=reactor) - t.startService() - self.assertEquals(listen, [(1234, factory)]) - t.stopService() - t.startService() - self.assertEquals(listen, [(1234, factory), (1234, factory)]) - - - def test_reactorParametrizationInClientMultipleStart(self): - """ - Like L{test_reactorParametrizationInClient}, but stop and restart the - service and check that the given reactor is still used. - """ - connect = [] - class FakeReactor(object): - def connectTCP(self, ip, portNumber, factory): - connect.append((ip, portNumber, factory)) - reactor = FakeReactor() - - factory = object() - t = internet.TCPClient('127.0.0.1', 1234, factory, reactor=reactor) - t.startService() - self.assertEquals(connect, [('127.0.0.1', 1234, factory)]) - t.stopService() - t.startService() - self.assertEquals(connect, [('127.0.0.1', 1234, factory), - ('127.0.0.1', 1234, factory)]) - - - -class TestTimerBasic(unittest.TestCase): - - def testTimerRuns(self): - d = defer.Deferred() - self.t = internet.TimerService(1, d.callback, 'hello') - self.t.startService() - d.addCallback(self.assertEqual, 'hello') - d.addCallback(lambda x : self.t.stopService()) - d.addCallback(lambda x : self.failIf(self.t.running)) - return d - - def tearDown(self): - return self.t.stopService() - - def testTimerRestart(self): - # restart the same TimerService - d1 = defer.Deferred() - d2 = defer.Deferred() - work = [(d2, "bar"), (d1, "foo")] - def trigger(): - d, arg = work.pop() - d.callback(arg) - self.t = internet.TimerService(1, trigger) - self.t.startService() - def onFirstResult(result): - self.assertEqual(result, 'foo') - return self.t.stopService() - def onFirstStop(ignored): - self.failIf(self.t.running) - self.t.startService() - return d2 - def onSecondResult(result): - self.assertEqual(result, 'bar') - self.t.stopService() - d1.addCallback(onFirstResult) - d1.addCallback(onFirstStop) - d1.addCallback(onSecondResult) - return d1 - - def testTimerLoops(self): - l = [] - def trigger(data, number, d): - l.append(data) - if len(l) == number: - d.callback(l) - d = defer.Deferred() - self.t = internet.TimerService(0.01, trigger, "hello", 10, d) - self.t.startService() - d.addCallback(self.assertEqual, ['hello'] * 10) - d.addCallback(lambda x : self.t.stopService()) - return d - - -class FakeReactor(reactors.Reactor): - """ - A fake reactor with a hooked install method. - """ - - def __init__(self, install, *args, **kwargs): - """ - @param install: any callable that will be used as install method. - @type install: C{callable} - """ - reactors.Reactor.__init__(self, *args, **kwargs) - self.install = install - - - -class PluggableReactorTestCase(unittest.TestCase): - """ - Tests for the reactor discovery/inspection APIs. - """ - - def setUp(self): - """ - Override the L{reactors.getPlugins} function, normally bound to - L{twisted.plugin.getPlugins}, in order to control which - L{IReactorInstaller} plugins are seen as available. - - C{self.pluginResults} can be customized and will be used as the - result of calls to C{reactors.getPlugins}. - """ - self.pluginCalls = [] - self.pluginResults = [] - self.originalFunction = reactors.getPlugins - reactors.getPlugins = self._getPlugins - - - def tearDown(self): - """ - Restore the original L{reactors.getPlugins}. - """ - reactors.getPlugins = self.originalFunction - - - def _getPlugins(self, interface, package=None): - """ - Stand-in for the real getPlugins method which records its arguments - and returns a fixed result. - """ - self.pluginCalls.append((interface, package)) - return list(self.pluginResults) - - - def test_getPluginReactorTypes(self): - """ - Test that reactor plugins are returned from L{getReactorTypes} - """ - name = 'fakereactortest' - package = __name__ + '.fakereactor' - description = 'description' - self.pluginResults = [reactors.Reactor(name, package, description)] - reactorTypes = reactors.getReactorTypes() - - self.assertEqual( - self.pluginCalls, - [(reactors.IReactorInstaller, None)]) - - for r in reactorTypes: - if r.shortName == name: - self.assertEqual(r.description, description) - break - else: - self.fail("Reactor plugin not present in getReactorTypes() result") - - - def test_reactorInstallation(self): - """ - Test that L{reactors.Reactor.install} loads the correct module and - calls its install attribute. - """ - installed = [] - def install(): - installed.append(True) - installer = FakeReactor(install, - 'fakereactortest', __name__, 'described') - installer.install() - self.assertEqual(installed, [True]) - - - def test_installReactor(self): - """ - Test that the L{reactors.installReactor} function correctly installs - the specified reactor. - """ - installed = [] - def install(): - installed.append(True) - name = 'fakereactortest' - package = __name__ - description = 'description' - self.pluginResults = [FakeReactor(install, name, package, description)] - reactors.installReactor(name) - self.assertEqual(installed, [True]) - - - def test_installNonExistentReactor(self): - """ - Test that L{reactors.installReactor} raises L{reactors.NoSuchReactor} - when asked to install a reactor which it cannot find. - """ - self.pluginResults = [] - self.assertRaises( - reactors.NoSuchReactor, - reactors.installReactor, 'somereactor') - - - def test_installNotAvailableReactor(self): - """ - Test that L{reactors.installReactor} raises an exception when asked to - install a reactor which doesn't work in this environment. - """ - def install(): - raise ImportError("Missing foo bar") - name = 'fakereactortest' - package = __name__ - description = 'description' - self.pluginResults = [FakeReactor(install, name, package, description)] - self.assertRaises(ImportError, reactors.installReactor, name) - - - def test_reactorSelectionMixin(self): - """ - Test that the reactor selected is installed as soon as possible, ie - when the option is parsed. - """ - executed = [] - INSTALL_EVENT = 'reactor installed' - SUBCOMMAND_EVENT = 'subcommands loaded' - - class ReactorSelectionOptions(usage.Options, app.ReactorSelectionMixin): - def subCommands(self): - executed.append(SUBCOMMAND_EVENT) - return [('subcommand', None, lambda: self, 'test subcommand')] - subCommands = property(subCommands) - - def install(): - executed.append(INSTALL_EVENT) - self.pluginResults = [ - FakeReactor(install, 'fakereactortest', __name__, 'described') - ] - - options = ReactorSelectionOptions() - options.parseOptions(['--reactor', 'fakereactortest', 'subcommand']) - self.assertEqual(executed[0], INSTALL_EVENT) - self.assertEqual(executed.count(INSTALL_EVENT), 1) - - - def test_reactorSelectionMixinNonExistent(self): - """ - Test that the usage mixin exits when trying to use a non existent - reactor (the name not matching to any reactor), giving an error - message. - """ - class ReactorSelectionOptions(usage.Options, app.ReactorSelectionMixin): - pass - self.pluginResults = [] - - options = ReactorSelectionOptions() - options.messageOutput = StringIO() - e = self.assertRaises(usage.UsageError, options.parseOptions, - ['--reactor', 'fakereactortest', 'subcommand']) - self.assertIn("fakereactortest", e.args[0]) - self.assertIn("help-reactors", e.args[0]) - - - def test_reactorSelectionMixinNotAvailable(self): - """ - Test that the usage mixin exits when trying to use a reactor not - available (the reactor raises an error at installation), giving an - error message. - """ - class ReactorSelectionOptions(usage.Options, app.ReactorSelectionMixin): - pass - message = "Missing foo bar" - def install(): - raise ImportError(message) - - name = 'fakereactortest' - package = __name__ - description = 'description' - self.pluginResults = [FakeReactor(install, name, package, description)] - - options = ReactorSelectionOptions() - options.messageOutput = StringIO() - e = self.assertRaises(usage.UsageError, options.parseOptions, - ['--reactor', 'fakereactortest', 'subcommand']) - self.assertIn(message, e.args[0]) - self.assertIn("help-reactors", e.args[0]) - - - def test_qtStub(self): - """ - Test that installing qtreactor when it's absent fails properly. - """ - scriptPath = sibpath(__file__, "app_qtstub.py") - def _checkOutput((output, err, code)): - self.failIf(output, output) - result = getProcessOutputAndValue( - sys.executable, - args=(sys.executable, scriptPath), - env=None) - result.addCallback(_checkOutput) - return result - - - -class ReportProfileTestCase(unittest.TestCase): - """ - Tests for L{app.reportProfile}. - """ - - def test_deprecation(self): - """ - Check that L{app.reportProfile} prints a warning and does nothing else. - """ - self.assertWarns(DeprecationWarning, - "reportProfile is deprecated and a no-op since Twisted 8.0.", - app.__file__, app.reportProfile, None, None) diff --git a/tools/buildbot/pylibs/twisted/test/test_assertions.py b/tools/buildbot/pylibs/twisted/test/test_assertions.py deleted file mode 100644 index 545e8b4..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_assertions.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- test-case-name: twisted.test.test_assertions -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.trial import unittest -from twisted.python import failure - -class Assertions(unittest.TestCase): - def testExceptions(self): - exc = self.assertRaises(ZeroDivisionError, lambda: 1/0) - assert isinstance(exc, ZeroDivisionError), "ZeroDivisionError instance not returned" - - for func in [lambda: 1/0, lambda: None]: - try: - self.assertRaises(ValueError, func) - except unittest.FailTest: - # Success! - pass - except: - raise unittest.FailTest("FailTest not raised", failure.Failure().getTraceback()) - else: - raise unittest.FailTest("FailTest not raised") diff --git a/tools/buildbot/pylibs/twisted/test/test_banana.py b/tools/buildbot/pylibs/twisted/test/test_banana.py deleted file mode 100644 index 2192d77..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_banana.py +++ /dev/null @@ -1,264 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -import StringIO -import sys - -# Twisted Imports -from twisted.trial import unittest -from twisted.spread import banana -from twisted.python import failure -from twisted.internet import protocol, main - - -class MathTestCase(unittest.TestCase): - def testInt2b128(self): - funkylist = range(0,100) + range(1000,1100) + range(1000000,1000100) + [1024 **10l] - for i in funkylist: - x = StringIO.StringIO() - banana.int2b128(i, x.write) - v = x.getvalue() - y = banana.b1282int(v) - assert y == i, "y = %s; i = %s" % (y,i) - -class BananaTestCase(unittest.TestCase): - - encClass = banana.Banana - - def setUp(self): - self.io = StringIO.StringIO() - self.enc = self.encClass() - self.enc.makeConnection(protocol.FileWrapper(self.io)) - self.enc._selectDialect("none") - self.enc.expressionReceived = self.putResult - - def putResult(self, result): - self.result = result - - def tearDown(self): - self.enc.connectionLost(failure.Failure(main.CONNECTION_DONE)) - del self.enc - - def testString(self): - self.enc.sendEncoded("hello") - l = [] - self.enc.dataReceived(self.io.getvalue()) - assert self.result == 'hello' - - def testLong(self): - self.enc.sendEncoded(1015l) - self.enc.dataReceived(self.io.getvalue()) - assert self.result == 1015l, "should be 1015l, got %s" % self.result - - - def test_largeLong(self): - """ - Test that various longs greater than 2 ** 32 - 1 round-trip through - banana properly. - """ - for exp in (32, 64, 128, 256): - for add in (0, 1): - n = 2 ** exp + add - self.io.truncate(0) - self.enc.sendEncoded(n) - self.enc.dataReceived(self.io.getvalue()) - self.assertEqual(self.result, n) - - - def _getSmallest(self): - # How many bytes of prefix our implementation allows - bytes = self.enc.prefixLimit - # How many useful bits we can extract from that based on Banana's - # base-128 representation. - bits = bytes * 7 - # The largest number we _should_ be able to encode - largest = 2 ** bits - 1 - # The smallest number we _shouldn't_ be able to encode - smallest = largest + 1 - return smallest - - - def test_encodeTooLargeLong(self): - """ - Test that a long above the implementation-specific limit is rejected - as too large to be encoded. - """ - smallest = self._getSmallest() - self.assertRaises(banana.BananaError, self.enc.sendEncoded, smallest) - - - def test_decodeTooLargeLong(self): - """ - Test that a long above the implementation specific limit is rejected - as too large to be decoded. - """ - smallest = self._getSmallest() - self.enc.setPrefixLimit(self.enc.prefixLimit * 2) - self.enc.sendEncoded(smallest) - encoded = self.io.getvalue() - self.io.truncate(0) - self.enc.setPrefixLimit(self.enc.prefixLimit / 2) - - self.assertRaises(banana.BananaError, self.enc.dataReceived, encoded) - - - def _getLargest(self): - return -self._getSmallest() - - - def test_encodeTooSmallLong(self): - """ - Test that a negative long below the implementation-specific limit is - rejected as too small to be encoded. - """ - largest = self._getLargest() - self.assertRaises(banana.BananaError, self.enc.sendEncoded, largest) - - - def test_decodeTooSmallLong(self): - """ - Test that a negative long below the implementation specific limit is - rejected as too small to be decoded. - """ - largest = self._getLargest() - self.enc.setPrefixLimit(self.enc.prefixLimit * 2) - self.enc.sendEncoded(largest) - encoded = self.io.getvalue() - self.io.truncate(0) - self.enc.setPrefixLimit(self.enc.prefixLimit / 2) - - self.assertRaises(banana.BananaError, self.enc.dataReceived, encoded) - - - def testNegativeLong(self): - self.enc.sendEncoded(-1015l) - self.enc.dataReceived(self.io.getvalue()) - assert self.result == -1015l, "should be -1015l, got %s" % self.result - - def testInteger(self): - self.enc.sendEncoded(1015) - self.enc.dataReceived(self.io.getvalue()) - assert self.result == 1015, "should be 1015, got %s" % self.result - - def testNegative(self): - self.enc.sendEncoded(-1015) - self.enc.dataReceived(self.io.getvalue()) - assert self.result == -1015, "should be -1015, got %s" % self.result - - def testFloat(self): - self.enc.sendEncoded(1015.) - self.enc.dataReceived(self.io.getvalue()) - assert self.result == 1015. - - def testList(self): - foo = [1, 2, [3, 4], [30.5, 40.2], 5, ["six", "seven", ["eight", 9]], [10], []] - self.enc.sendEncoded(foo) - self.enc.dataReceived(self.io.getvalue()) - assert self.result == foo, "%s!=%s" % (repr(self.result), repr(self.result)) - - def testPartial(self): - foo = [1, 2, [3, 4], [30.5, 40.2], 5, - ["six", "seven", ["eight", 9]], [10], - # TODO: currently the C implementation's a bit buggy... - sys.maxint * 3l, sys.maxint * 2l, sys.maxint * -2l] - self.enc.sendEncoded(foo) - for byte in self.io.getvalue(): - self.enc.dataReceived(byte) - assert self.result == foo, "%s!=%s" % (repr(self.result), repr(foo)) - - def feed(self, data): - for byte in data: - self.enc.dataReceived(byte) - def testOversizedList(self): - data = '\x02\x01\x01\x01\x01\x80' - # list(size=0x0101010102, about 4.3e9) - self.failUnlessRaises(banana.BananaError, self.feed, data) - def testOversizedString(self): - data = '\x02\x01\x01\x01\x01\x82' - # string(size=0x0101010102, about 4.3e9) - self.failUnlessRaises(banana.BananaError, self.feed, data) - - def testCrashString(self): - crashString = '\x00\x00\x00\x00\x04\x80' - # string(size=0x0400000000, about 17.2e9) - - # cBanana would fold that into a 32-bit 'int', then try to allocate - # a list with PyList_New(). cBanana ignored the NULL return value, - # so it would segfault when trying to free the imaginary list. - - # This variant doesn't segfault straight out in my environment. - # Instead, it takes up large amounts of CPU and memory... - #crashString = '\x00\x00\x00\x00\x01\x80' - # print repr(crashString) - #self.failUnlessRaises(Exception, self.enc.dataReceived, crashString) - try: - # should now raise MemoryError - self.enc.dataReceived(crashString) - except banana.BananaError: - pass - - def testCrashNegativeLong(self): - # There was a bug in cBanana which relied on negating a negative integer - # always giving a postive result, but for the lowest possible number in - # 2s-complement arithmetic, that's not true, i.e. - # long x = -2147483648; - # long y = -x; - # x == y; /* true! */ - # (assuming 32-bit longs) - self.enc.sendEncoded(-2147483648) - self.enc.dataReceived(self.io.getvalue()) - assert self.result == -2147483648, "should be -2147483648, got %s" % self.result - - - def test_sizedIntegerTypes(self): - """ - Test that integers below the maximum C{INT} token size cutoff are - serialized as C{INT} or C{NEG} and that larger integers are - serialized as C{LONGINT} or C{LONGNEG}. - """ - def encoded(n): - self.io.seek(0) - self.io.truncate() - self.enc.sendEncoded(n) - return self.io.getvalue() - - baseIntIn = +2147483647 - baseNegIn = -2147483648 - - baseIntOut = '\x7f\x7f\x7f\x07\x81' - self.assertEqual(encoded(baseIntIn - 2), '\x7d' + baseIntOut) - self.assertEqual(encoded(baseIntIn - 1), '\x7e' + baseIntOut) - self.assertEqual(encoded(baseIntIn - 0), '\x7f' + baseIntOut) - - baseLongIntOut = '\x00\x00\x00\x08\x85' - self.assertEqual(encoded(baseIntIn + 1), '\x00' + baseLongIntOut) - self.assertEqual(encoded(baseIntIn + 2), '\x01' + baseLongIntOut) - self.assertEqual(encoded(baseIntIn + 3), '\x02' + baseLongIntOut) - - baseNegOut = '\x7f\x7f\x7f\x07\x83' - self.assertEqual(encoded(baseNegIn + 2), '\x7e' + baseNegOut) - self.assertEqual(encoded(baseNegIn + 1), '\x7f' + baseNegOut) - self.assertEqual(encoded(baseNegIn + 0), '\x00\x00\x00\x00\x08\x83') - - baseLongNegOut = '\x00\x00\x00\x08\x86' - self.assertEqual(encoded(baseNegIn - 1), '\x01' + baseLongNegOut) - self.assertEqual(encoded(baseNegIn - 2), '\x02' + baseLongNegOut) - self.assertEqual(encoded(baseNegIn - 3), '\x03' + baseLongNegOut) - - - -class GlobalCoderTests(unittest.TestCase): - """ - Tests for the free functions L{banana.encode} and L{banana.decode}. - """ - def test_statelessDecode(self): - """ - Test that state doesn't carry over between calls to L{banana.decode}. - """ - # Banana encoding of 2 ** 449 - undecodable = '\x7f' * 65 + '\x85' - self.assertRaises(banana.BananaError, banana.decode, undecodable) - - # Banana encoding of 1 - decodable = '\x01\x81' - self.assertEqual(banana.decode(decodable), 1) diff --git a/tools/buildbot/pylibs/twisted/test/test_compat.py b/tools/buildbot/pylibs/twisted/test/test_compat.py deleted file mode 100644 index 29b8ba7..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_compat.py +++ /dev/null @@ -1,192 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Tests for L{twisted.python.compat}. -""" - -import types, socket - -from twisted.trial import unittest - -from twisted.python.compat import set, frozenset - - - -class IterableCounter: - def __init__(self, lim=0): - self.lim = lim - self.i = -1 - - def __iter__(self): - return self - - def next(self): - self.i += 1 - if self.i >= self.lim: - raise StopIteration - return self.i - -class CompatTestCase(unittest.TestCase): - def testDict(self): - d1 = {'a': 'b'} - d2 = dict(d1) - self.assertEquals(d1, d2) - d1['a'] = 'c' - self.assertNotEquals(d1, d2) - d2 = dict(d1.items()) - self.assertEquals(d1, d2) - - def testBool(self): - self.assertEquals(bool('hi'), True) - self.assertEquals(bool(True), True) - self.assertEquals(bool(''), False) - self.assertEquals(bool(False), False) - - def testIteration(self): - lst1, lst2 = range(10), [] - - for i in iter(lst1): - lst2.append(i) - self.assertEquals(lst1, lst2) - del lst2[:] - - try: - iterable = iter(lst1) - while 1: - lst2.append(iterable.next()) - except StopIteration: - pass - self.assertEquals(lst1, lst2) - del lst2[:] - - for i in iter(IterableCounter(10)): - lst2.append(i) - self.assertEquals(lst1, lst2) - del lst2[:] - - try: - iterable = iter(IterableCounter(10)) - while 1: - lst2.append(iterable.next()) - except StopIteration: - pass - self.assertEquals(lst1, lst2) - del lst2[:] - - for i in iter(IterableCounter(20).next, 10): - lst2.append(i) - self.assertEquals(lst1, lst2) - - def testIsinstance(self): - self.assert_(isinstance(u'hi', types.StringTypes)) - self.assert_(isinstance(self, unittest.TestCase)) - # I'm pretty sure it's impossible to implement this - # without replacing isinstance on 2.2 as well :( - # self.assert_(isinstance({}, dict)) - - def testStrip(self): - self.assertEquals(' x '.lstrip(' '), 'x ') - self.assertEquals(' x x'.lstrip(' '), 'x x') - self.assertEquals(' x '.rstrip(' '), ' x') - self.assertEquals('x x '.rstrip(' '), 'x x') - - self.assertEquals('\t x '.lstrip('\t '), 'x ') - self.assertEquals(' \tx x'.lstrip('\t '), 'x x') - self.assertEquals(' x\t '.rstrip(' \t'), ' x') - self.assertEquals('x x \t'.rstrip(' \t'), 'x x') - - self.assertEquals('\t x '.strip('\t '), 'x') - self.assertEquals(' \tx x'.strip('\t '), 'x x') - self.assertEquals(' x\t '.strip(' \t'), 'x') - self.assertEquals('x x \t'.strip(' \t'), 'x x') - - def testNToP(self): - from twisted.python.compat import inet_ntop - - f = lambda a: inet_ntop(socket.AF_INET6, a) - g = lambda a: inet_ntop(socket.AF_INET, a) - - self.assertEquals('::', f('\x00' * 16)) - self.assertEquals('::1', f('\x00' * 15 + '\x01')) - self.assertEquals( - 'aef:b01:506:1001:ffff:9997:55:170', - f('\x0a\xef\x0b\x01\x05\x06\x10\x01\xff\xff\x99\x97\x00\x55\x01\x70')) - - self.assertEquals('1.0.1.0', g('\x01\x00\x01\x00')) - self.assertEquals('170.85.170.85', g('\xaa\x55\xaa\x55')) - self.assertEquals('255.255.255.255', g('\xff\xff\xff\xff')) - - self.assertEquals('100::', f('\x01' + '\x00' * 15)) - self.assertEquals('100::1', f('\x01' + '\x00' * 14 + '\x01')) - - def testPToN(self): - from twisted.python.compat import inet_pton - - f = lambda a: inet_pton(socket.AF_INET6, a) - g = lambda a: inet_pton(socket.AF_INET, a) - - self.assertEquals('\x00\x00\x00\x00', g('0.0.0.0')) - self.assertEquals('\xff\x00\xff\x00', g('255.0.255.0')) - self.assertEquals('\xaa\xaa\xaa\xaa', g('170.170.170.170')) - - self.assertEquals('\x00' * 16, f('::')) - self.assertEquals('\x00' * 16, f('0::0')) - self.assertEquals('\x00\x01' + '\x00' * 14, f('1::')) - self.assertEquals( - '\x45\xef\x76\xcb\x00\x1a\x56\xef\xaf\xeb\x0b\xac\x19\x24\xae\xae', - f('45ef:76cb:1a:56ef:afeb:bac:1924:aeae')) - - self.assertEquals('\x00' * 14 + '\x00\x01', f('::1')) - self.assertEquals('\x00' * 12 + '\x01\x02\x03\x04', f('::1.2.3.4')) - self.assertEquals( - '\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06\x01\x02\x03\xff', - f('1:2:3:4:5:6:1.2.3.255')) - - for badaddr in ['1:2:3:4:5:6:7:8:', ':1:2:3:4:5:6:7:8', '1::2::3', - '1:::3', ':::', '1:2', '::1.2', '1.2.3.4::', - 'abcd:1.2.3.4:abcd:abcd:abcd:abcd:abcd', - '1234:1.2.3.4:1234:1234:1234:1234:1234:1234', - '1.2.3.4']: - self.assertRaises(ValueError, f, badaddr) - - def test_set(self): - """ - L{set} should behave like the expected set interface. - """ - a = set() - a.add('b') - a.add('c') - a.add('a') - b = list(a) - b.sort() - self.assertEquals(b, ['a', 'b', 'c']) - a.remove('b') - b = list(a) - b.sort() - self.assertEquals(b, ['a', 'c']) - - a.discard('d') - - b = set(['r', 's']) - d = a.union(b) - b = list(d) - b.sort() - self.assertEquals(b, ['a', 'c', 'r', 's']) - - - def test_frozenset(self): - """ - L{frozenset} should behave like the expected frozenset interface. - """ - a = frozenset(['a', 'b']) - self.assertRaises(AttributeError, getattr, a, "add") - self.assertEquals(list(a), ['a', 'b']) - - b = frozenset(['r', 's']) - d = a.union(b) - b = list(d) - b.sort() - self.assertEquals(b, ['a', 'b', 'r', 's']) - diff --git a/tools/buildbot/pylibs/twisted/test/test_context.py b/tools/buildbot/pylibs/twisted/test/test_context.py deleted file mode 100644 index 1f03dae..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_context.py +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -from twisted.trial.unittest import TestCase - -from twisted.python import context - -class ContextTest(TestCase): - - def testBasicContext(self): - self.assertEquals(context.get("x"), None) - self.assertEquals(context.call({"x": "y"}, context.get, "x"), "y") - self.assertEquals(context.get("x"), None) diff --git a/tools/buildbot/pylibs/twisted/test/test_cooperator.py b/tools/buildbot/pylibs/twisted/test/test_cooperator.py deleted file mode 100644 index b696a8d..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_cooperator.py +++ /dev/null @@ -1,189 +0,0 @@ - -from twisted.internet import reactor, defer, task -from twisted.trial import unittest - - -class TestCooperator(unittest.TestCase): - RESULT = 'done' - - def ebIter(self, err): - err.trap(task.SchedulerStopped) - return self.RESULT - - - def cbIter(self, ign): - self.fail() - - - def testStoppedRejectsNewTasks(self): - """ - Test that Cooperators refuse new tasks when they have been stopped. - """ - def testwith(stuff): - c = task.Cooperator() - c.stop() - d = c.coiterate(iter(()), stuff) - d.addCallback(self.cbIter) - d.addErrback(self.ebIter) - return d.addCallback(lambda result: - self.assertEquals(result, self.RESULT)) - return testwith(None).addCallback(lambda ign: testwith(defer.Deferred())) - - - def testStopRunning(self): - """ - Test that a running iterator will not run to completion when the - cooperator is stopped. - """ - c = task.Cooperator() - def myiter(): - for myiter.value in range(3): - yield myiter.value - myiter.value = -1 - d = c.coiterate(myiter()) - d.addCallback(self.cbIter) - d.addErrback(self.ebIter) - c.stop() - def doasserts(result): - self.assertEquals(result, self.RESULT) - self.assertEquals(myiter.value, -1) - d.addCallback(doasserts) - return d - - - def testStopOutstanding(self): - """ - Test that a running iterator paused on a third-party Deferred will - properly stop when .stop() is called. - """ - testControlD = defer.Deferred() - outstandingD = defer.Deferred() - def myiter(): - reactor.callLater(0, testControlD.callback, None) - yield outstandingD - self.fail() - c = task.Cooperator() - d = c.coiterate(myiter()) - def stopAndGo(ign): - c.stop() - outstandingD.callback('arglebargle') - - testControlD.addCallback(stopAndGo) - d.addCallback(self.cbIter) - d.addErrback(self.ebIter) - - return d.addCallback(lambda result: self.assertEquals(result, self.RESULT)) - - - def testUnexpectedError(self): - c = task.Cooperator() - def myiter(): - if 0: - yield None - else: - raise RuntimeError() - d = c.coiterate(myiter()) - return self.assertFailure(d, RuntimeError) - - - def testUnexpectedErrorActuallyLater(self): - def myiter(): - D = defer.Deferred() - reactor.callLater(0, D.errback, RuntimeError()) - yield D - - c = task.Cooperator() - d = c.coiterate(myiter()) - return self.assertFailure(d, RuntimeError) - - - def testUnexpectedErrorNotActuallyLater(self): - def myiter(): - yield defer.fail(RuntimeError()) - - c = task.Cooperator() - d = c.coiterate(myiter()) - return self.assertFailure(d, RuntimeError) - - - def testCooperation(self): - L = [] - def myiter(things): - for th in things: - L.append(th) - yield None - - groupsOfThings = ['abc', (1, 2, 3), 'def', (4, 5, 6)] - - c = task.Cooperator() - tasks = [] - for stuff in groupsOfThings: - tasks.append(c.coiterate(myiter(stuff))) - - return defer.DeferredList(tasks).addCallback( - lambda ign: self.assertEquals(tuple(L), sum(zip(*groupsOfThings), ()))) - - - def testResourceExhaustion(self): - output = [] - def myiter(): - for i in range(100): - output.append(i) - if i == 9: - _TPF.stopped = True - yield i - - class _TPF: - stopped = False - def __call__(self): - return self.stopped - - c = task.Cooperator(terminationPredicateFactory=_TPF) - c.coiterate(myiter()).addErrback(self.ebIter) - c._delayedCall.cancel() - # testing a private method because only the test case will ever care - # about this, so we have to carefully clean up after ourselves. - c._tick() - c.stop() - self.failUnless(_TPF.stopped) - self.assertEquals(output, range(10)) - - - def testCallbackReCoiterate(self): - """ - If a callback to a deferred returned by coiterate calls coiterate on - the same Cooperator, we should make sure to only do the minimal amount - of scheduling work. (This test was added to demonstrate a specific bug - that was found while writing the scheduler.) - """ - calls = [] - - class FakeCall: - def __init__(self, func): - self.func = func - - def __repr__(self): - return '' % (self.func,) - - def sched(f): - self.failIf(calls, repr(calls)) - calls.append(FakeCall(f)) - return calls[-1] - - c = task.Cooperator(scheduler=sched, terminationPredicateFactory=lambda: lambda: True) - d = c.coiterate(iter(())) - - done = [] - def anotherTask(ign): - c.coiterate(iter(())).addBoth(done.append) - - d.addCallback(anotherTask) - - work = 0 - while not done: - work += 1 - while calls: - calls.pop(0).func() - work += 1 - if work > 50: - self.fail("Cooperator took too long") diff --git a/tools/buildbot/pylibs/twisted/test/test_defer.py b/tools/buildbot/pylibs/twisted/test/test_defer.py deleted file mode 100644 index d67542e..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_defer.py +++ /dev/null @@ -1,899 +0,0 @@ - -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Test cases for defer module. -""" - -import gc - -from twisted.trial import unittest, util -from twisted.internet import reactor, defer -from twisted.python import failure, log - -from twisted.internet.task import Clock - -class GenericError(Exception): - pass - - -_setTimeoutSuppression = util.suppress( - message="Deferred.setTimeout is deprecated. Look for timeout " - "support specific to the API you are using instead.", - category=DeprecationWarning) - -_firstErrorSuppression = util.suppress( - message="FirstError.__getitem__ is deprecated. Use attributes instead.", - category=DeprecationWarning) - - -class DeferredTestCase(unittest.TestCase): - - def setUp(self): - self.callback_results = None - self.errback_results = None - self.callback2_results = None - - def _callback(self, *args, **kw): - self.callback_results = args, kw - return args[0] - - def _callback2(self, *args, **kw): - self.callback2_results = args, kw - - def _errback(self, *args, **kw): - self.errback_results = args, kw - - def testCallbackWithoutArgs(self): - deferred = defer.Deferred() - deferred.addCallback(self._callback) - deferred.callback("hello") - self.failUnlessEqual(self.errback_results, None) - self.failUnlessEqual(self.callback_results, (('hello',), {})) - - def testCallbackWithArgs(self): - deferred = defer.Deferred() - deferred.addCallback(self._callback, "world") - deferred.callback("hello") - self.failUnlessEqual(self.errback_results, None) - self.failUnlessEqual(self.callback_results, (('hello', 'world'), {})) - - def testCallbackWithKwArgs(self): - deferred = defer.Deferred() - deferred.addCallback(self._callback, world="world") - deferred.callback("hello") - self.failUnlessEqual(self.errback_results, None) - self.failUnlessEqual(self.callback_results, - (('hello',), {'world': 'world'})) - - def testTwoCallbacks(self): - deferred = defer.Deferred() - deferred.addCallback(self._callback) - deferred.addCallback(self._callback2) - deferred.callback("hello") - self.failUnlessEqual(self.errback_results, None) - self.failUnlessEqual(self.callback_results, - (('hello',), {})) - self.failUnlessEqual(self.callback2_results, - (('hello',), {})) - - def testDeferredList(self): - defr1 = defer.Deferred() - defr2 = defer.Deferred() - defr3 = defer.Deferred() - dl = defer.DeferredList([defr1, defr2, defr3]) - result = [] - def cb(resultList, result=result): - result.extend(resultList) - def catch(err): - return None - dl.addCallbacks(cb, cb) - defr1.callback("1") - defr2.addErrback(catch) - # "catch" is added to eat the GenericError that will be passed on by - # the DeferredList's callback on defr2. If left unhandled, the - # Failure object would cause a log.err() warning about "Unhandled - # error in Deferred". Twisted's pyunit watches for log.err calls and - # treats them as failures. So "catch" must eat the error to prevent - # it from flunking the test. - defr2.errback(GenericError("2")) - defr3.callback("3") - self.failUnlessEqual([result[0], - #result[1][1] is now a Failure instead of an Exception - (result[1][0], str(result[1][1].value)), - result[2]], - - [(defer.SUCCESS, "1"), - (defer.FAILURE, "2"), - (defer.SUCCESS, "3")]) - - def testEmptyDeferredList(self): - result = [] - def cb(resultList, result=result): - result.append(resultList) - - dl = defer.DeferredList([]) - dl.addCallbacks(cb) - self.failUnlessEqual(result, [[]]) - - result[:] = [] - dl = defer.DeferredList([], fireOnOneCallback=1) - dl.addCallbacks(cb) - self.failUnlessEqual(result, []) - - def testDeferredListFireOnOneError(self): - defr1 = defer.Deferred() - defr2 = defer.Deferred() - defr3 = defer.Deferred() - dl = defer.DeferredList([defr1, defr2, defr3], fireOnOneErrback=1) - result = [] - dl.addErrback(result.append) - - # consume errors after they pass through the DeferredList (to avoid - # 'Unhandled error in Deferred'. - def catch(err): - return None - defr2.addErrback(catch) - - # fire one Deferred's callback, no result yet - defr1.callback("1") - self.failUnlessEqual(result, []) - - # fire one Deferred's errback -- now we have a result - defr2.errback(GenericError("from def2")) - self.failUnlessEqual(len(result), 1) - - # extract the result from the list - failure = result[0] - - # the type of the failure is a FirstError - self.failUnless(issubclass(failure.type, defer.FirstError), - 'issubclass(failure.type, defer.FirstError) failed: ' - 'failure.type is %r' % (failure.type,) - ) - - firstError = failure.value - - # check that the GenericError("2") from the deferred at index 1 - # (defr2) is intact inside failure.value - self.failUnlessEqual(firstError.subFailure.type, GenericError) - self.failUnlessEqual(firstError.subFailure.value.args, ("from def2",)) - self.failUnlessEqual(firstError.index, 1) - - - def test_indexingFirstError(self): - """ - L{FirstError} behaves a little like a tuple, for backwards - compatibility. Test that it can actually be indexed to retrieve - information about the failure. - """ - subFailure = object() - index = object() - firstError = defer.FirstError(subFailure, index) - self.assertIdentical(firstError[0], firstError.subFailure) - self.assertIdentical(firstError[1], firstError.index) - test_indexingFirstError.suppress = [_firstErrorSuppression] - - - def testDeferredListDontConsumeErrors(self): - d1 = defer.Deferred() - dl = defer.DeferredList([d1]) - - errorTrap = [] - d1.addErrback(errorTrap.append) - - result = [] - dl.addCallback(result.append) - - d1.errback(GenericError('Bang')) - self.failUnlessEqual('Bang', errorTrap[0].value.args[0]) - self.failUnlessEqual(1, len(result)) - self.failUnlessEqual('Bang', result[0][0][1].value.args[0]) - - def testDeferredListConsumeErrors(self): - d1 = defer.Deferred() - dl = defer.DeferredList([d1], consumeErrors=True) - - errorTrap = [] - d1.addErrback(errorTrap.append) - - result = [] - dl.addCallback(result.append) - - d1.errback(GenericError('Bang')) - self.failUnlessEqual([], errorTrap) - self.failUnlessEqual(1, len(result)) - self.failUnlessEqual('Bang', result[0][0][1].value.args[0]) - - def testDeferredListFireOnOneErrorWithAlreadyFiredDeferreds(self): - # Create some deferreds, and errback one - d1 = defer.Deferred() - d2 = defer.Deferred() - d1.errback(GenericError('Bang')) - - # *Then* build the DeferredList, with fireOnOneErrback=True - dl = defer.DeferredList([d1, d2], fireOnOneErrback=True) - result = [] - dl.addErrback(result.append) - self.failUnlessEqual(1, len(result)) - - d1.addErrback(lambda e: None) # Swallow error - - def testDeferredListWithAlreadyFiredDeferreds(self): - # Create some deferreds, and err one, call the other - d1 = defer.Deferred() - d2 = defer.Deferred() - d1.errback(GenericError('Bang')) - d2.callback(2) - - # *Then* build the DeferredList - dl = defer.DeferredList([d1, d2]) - - result = [] - dl.addCallback(result.append) - - self.failUnlessEqual(1, len(result)) - - d1.addErrback(lambda e: None) # Swallow error - - def testTimeOut(self): - """ - Test that a Deferred which has setTimeout called on it and never has - C{callback} or C{errback} called on it eventually fails with a - L{error.TimeoutError}. - """ - L = [] - d = defer.Deferred() - d.setTimeout(0.01) - self.assertFailure(d, defer.TimeoutError) - d.addCallback(L.append) - self.failIf(L, "Deferred failed too soon.") - return d - testTimeOut.suppress = [_setTimeoutSuppression] - - - def testImmediateSuccess(self): - l = [] - d = defer.succeed("success") - d.addCallback(l.append) - self.assertEquals(l, ["success"]) - - - def test_immediateSuccessBeforeTimeout(self): - """ - Test that a synchronously successful Deferred is not affected by a - C{setTimeout} call. - """ - l = [] - d = defer.succeed("success") - d.setTimeout(1.0) - d.addCallback(l.append) - self.assertEquals(l, ["success"]) - test_immediateSuccessBeforeTimeout.suppress = [_setTimeoutSuppression] - - - def testImmediateFailure(self): - l = [] - d = defer.fail(GenericError("fail")) - d.addErrback(l.append) - self.assertEquals(str(l[0].value), "fail") - - def testPausedFailure(self): - l = [] - d = defer.fail(GenericError("fail")) - d.pause() - d.addErrback(l.append) - self.assertEquals(l, []) - d.unpause() - self.assertEquals(str(l[0].value), "fail") - - def testCallbackErrors(self): - l = [] - d = defer.Deferred().addCallback(lambda _: 1/0).addErrback(l.append) - d.callback(1) - self.assert_(isinstance(l[0].value, ZeroDivisionError)) - l = [] - d = defer.Deferred().addCallback( - lambda _: failure.Failure(ZeroDivisionError())).addErrback(l.append) - d.callback(1) - self.assert_(isinstance(l[0].value, ZeroDivisionError)) - - def testUnpauseBeforeCallback(self): - d = defer.Deferred() - d.pause() - d.addCallback(self._callback) - d.unpause() - - def testReturnDeferred(self): - d = defer.Deferred() - d2 = defer.Deferred() - d2.pause() - d.addCallback(lambda r, d2=d2: d2) - d.addCallback(self._callback) - d.callback(1) - assert self.callback_results is None, "Should not have been called yet." - d2.callback(2) - assert self.callback_results is None, "Still should not have been called yet." - d2.unpause() - assert self.callback_results[0][0] == 2, "Result should have been from second deferred:%s"% (self.callback_results,) - - def testGatherResults(self): - # test successful list of deferreds - l = [] - defer.gatherResults([defer.succeed(1), defer.succeed(2)]).addCallback(l.append) - self.assertEquals(l, [[1, 2]]) - # test failing list of deferreds - l = [] - dl = [defer.succeed(1), defer.fail(ValueError)] - defer.gatherResults(dl).addErrback(l.append) - self.assertEquals(len(l), 1) - self.assert_(isinstance(l[0], failure.Failure)) - # get rid of error - dl[1].addErrback(lambda e: 1) - - - def test_maybeDeferredSync(self): - """ - L{defer.maybeDeferred} should retrieve the result of a synchronous - function and pass it to its resulting L{defer.Deferred}. - """ - S, E = [], [] - d = defer.maybeDeferred((lambda x: x + 5), 10) - d.addCallbacks(S.append, E.append) - self.assertEquals(E, []) - self.assertEquals(S, [15]) - return d - - - def test_maybeDeferredSyncError(self): - """ - L{defer.maybeDeferred} should catch exception raised by a synchronous - function and errback its resulting L{defer.Deferred} with it. - """ - S, E = [], [] - try: - '10' + 5 - except TypeError, e: - expected = str(e) - d = defer.maybeDeferred((lambda x: x + 5), '10') - d.addCallbacks(S.append, E.append) - self.assertEquals(S, []) - self.assertEquals(len(E), 1) - self.assertEquals(str(E[0].value), expected) - return d - - - def test_maybeDeferredAsync(self): - """ - L{defer.maybeDeferred} should let L{defer.Deferred} instance pass by - so that original result is the same. - """ - d = defer.Deferred() - d2 = defer.maybeDeferred(lambda: d) - d.callback('Success') - return d2.addCallback(self.assertEquals, 'Success') - - - def test_maybeDeferredAsyncError(self): - """ - L{defer.maybeDeferred} should let L{defer.Deferred} instance pass by - so that L{failure.Failure} returned by the original instance is the - same. - """ - d = defer.Deferred() - d2 = defer.maybeDeferred(lambda: d) - d.errback(failure.Failure(RuntimeError())) - return self.assertFailure(d2, RuntimeError) - - - def test_reentrantRunCallbacks(self): - """ - A callback added to a L{Deferred} by a callback on that L{Deferred} - should be added to the end of the callback chain. - """ - deferred = defer.Deferred() - called = [] - def callback3(result): - called.append(3) - def callback2(result): - called.append(2) - def callback1(result): - called.append(1) - deferred.addCallback(callback3) - deferred.addCallback(callback1) - deferred.addCallback(callback2) - deferred.callback(None) - self.assertEqual(called, [1, 2, 3]) - - - def test_nonReentrantCallbacks(self): - """ - A callback added to a L{Deferred} by a callback on that L{Deferred} - should not be executed until the running callback returns. - """ - deferred = defer.Deferred() - called = [] - def callback2(result): - called.append(2) - def callback1(result): - called.append(1) - deferred.addCallback(callback2) - self.assertEquals(called, [1]) - deferred.addCallback(callback1) - deferred.callback(None) - self.assertEqual(called, [1, 2]) - - - def test_reentrantRunCallbacksWithFailure(self): - """ - After an exception is raised by a callback which was added to a - L{Deferred} by a callback on that L{Deferred}, the L{Deferred} should - call the first errback with a L{Failure} wrapping that exception. - """ - exceptionMessage = "callback raised exception" - deferred = defer.Deferred() - def callback2(result): - raise Exception(exceptionMessage) - def callback1(result): - deferred.addCallback(callback2) - deferred.addCallback(callback1) - deferred.callback(None) - self.assertFailure(deferred, Exception) - def cbFailed(exception): - self.assertEqual(exception.args, (exceptionMessage,)) - deferred.addCallback(cbFailed) - return deferred - - - -class AlreadyCalledTestCase(unittest.TestCase): - def setUp(self): - self._deferredWasDebugging = defer.getDebugging() - defer.setDebugging(True) - - def tearDown(self): - defer.setDebugging(self._deferredWasDebugging) - - def _callback(self, *args, **kw): - pass - def _errback(self, *args, **kw): - pass - - def _call_1(self, d): - d.callback("hello") - def _call_2(self, d): - d.callback("twice") - def _err_1(self, d): - d.errback(failure.Failure(RuntimeError())) - def _err_2(self, d): - d.errback(failure.Failure(RuntimeError())) - - def testAlreadyCalled_CC(self): - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - self._call_1(d) - self.failUnlessRaises(defer.AlreadyCalledError, self._call_2, d) - - def testAlreadyCalled_CE(self): - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - self._call_1(d) - self.failUnlessRaises(defer.AlreadyCalledError, self._err_2, d) - - def testAlreadyCalled_EE(self): - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - self._err_1(d) - self.failUnlessRaises(defer.AlreadyCalledError, self._err_2, d) - - def testAlreadyCalled_EC(self): - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - self._err_1(d) - self.failUnlessRaises(defer.AlreadyCalledError, self._call_2, d) - - - def _count(self, linetype, func, lines, expected): - count = 0 - for line in lines: - if (line.startswith(' %s:' % linetype) and - line.endswith(' %s' % func)): - count += 1 - self.failUnless(count == expected) - - def _check(self, e, caller, invoker1, invoker2): - # make sure the debugging information is vaguely correct - lines = e.args[0].split("\n") - # the creator should list the creator (testAlreadyCalledDebug) but not - # _call_1 or _call_2 or other invokers - self._count('C', caller, lines, 1) - self._count('C', '_call_1', lines, 0) - self._count('C', '_call_2', lines, 0) - self._count('C', '_err_1', lines, 0) - self._count('C', '_err_2', lines, 0) - # invoker should list the first invoker but not the second - self._count('I', invoker1, lines, 1) - self._count('I', invoker2, lines, 0) - - def testAlreadyCalledDebug_CC(self): - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - self._call_1(d) - try: - self._call_2(d) - except defer.AlreadyCalledError, e: - self._check(e, "testAlreadyCalledDebug_CC", "_call_1", "_call_2") - else: - self.fail("second callback failed to raise AlreadyCalledError") - - def testAlreadyCalledDebug_CE(self): - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - self._call_1(d) - try: - self._err_2(d) - except defer.AlreadyCalledError, e: - self._check(e, "testAlreadyCalledDebug_CE", "_call_1", "_err_2") - else: - self.fail("second errback failed to raise AlreadyCalledError") - - def testAlreadyCalledDebug_EC(self): - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - self._err_1(d) - try: - self._call_2(d) - except defer.AlreadyCalledError, e: - self._check(e, "testAlreadyCalledDebug_EC", "_err_1", "_call_2") - else: - self.fail("second callback failed to raise AlreadyCalledError") - - def testAlreadyCalledDebug_EE(self): - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - self._err_1(d) - try: - self._err_2(d) - except defer.AlreadyCalledError, e: - self._check(e, "testAlreadyCalledDebug_EE", "_err_1", "_err_2") - else: - self.fail("second errback failed to raise AlreadyCalledError") - - def testNoDebugging(self): - defer.setDebugging(False) - d = defer.Deferred() - d.addCallbacks(self._callback, self._errback) - self._call_1(d) - try: - self._call_2(d) - except defer.AlreadyCalledError, e: - self.failIf(e.args) - else: - self.fail("second callback failed to raise AlreadyCalledError") - - - def testSwitchDebugging(self): - # Make sure Deferreds can deal with debug state flipping - # around randomly. This is covering a particular fixed bug. - defer.setDebugging(False) - d = defer.Deferred() - d.addBoth(lambda ign: None) - defer.setDebugging(True) - d.callback(None) - - defer.setDebugging(False) - d = defer.Deferred() - d.callback(None) - defer.setDebugging(True) - d.addBoth(lambda ign: None) - - - -class LogTestCase(unittest.TestCase): - """ - Test logging of unhandled errors. - """ - - def setUp(self): - """ - Add a custom observer to observer logging. - """ - self.c = [] - log.addObserver(self.c.append) - - def tearDown(self): - """ - Remove the observer. - """ - log.removeObserver(self.c.append) - - def _check(self): - """ - Check the output of the log observer to see if the error is present. - """ - c2 = [e for e in self.c if e["isError"]] - self.assertEquals(len(c2), 2) - c2[1]["failure"].trap(ZeroDivisionError) - self.flushLoggedErrors(ZeroDivisionError) - - def test_errorLog(self): - """ - Verify that when a Deferred with no references to it is fired, and its - final result (the one not handled by any callback) is an exception, - that exception will be logged immediately. - """ - defer.Deferred().addCallback(lambda x: 1/0).callback(1) - self._check() - - def test_errorLogWithInnerFrameRef(self): - """ - Same as L{test_errorLog}, but with an inner frame. - """ - def _subErrorLogWithInnerFrameRef(): - d = defer.Deferred() - d.addCallback(lambda x: 1/0) - d.callback(1) - - _subErrorLogWithInnerFrameRef() - gc.collect() - self._check() - - def test_errorLogWithInnerFrameCycle(self): - """ - Same as L{test_errorLogWithInnerFrameRef}, plus create a cycle. - """ - def _subErrorLogWithInnerFrameCycle(): - d = defer.Deferred() - d.addCallback(lambda x, d=d: 1/0) - d._d = d - d.callback(1) - - _subErrorLogWithInnerFrameCycle() - gc.collect() - self._check() - - -class DeferredTestCaseII(unittest.TestCase): - def setUp(self): - self.callbackRan = 0 - - def testDeferredListEmpty(self): - """Testing empty DeferredList.""" - dl = defer.DeferredList([]) - dl.addCallback(self.cb_empty) - - def cb_empty(self, res): - self.callbackRan = 1 - self.failUnlessEqual([], res) - - def tearDown(self): - self.failUnless(self.callbackRan, "Callback was never run.") - -class OtherPrimitives(unittest.TestCase): - def _incr(self, result): - self.counter += 1 - - def setUp(self): - self.counter = 0 - - def testLock(self): - lock = defer.DeferredLock() - lock.acquire().addCallback(self._incr) - self.failUnless(lock.locked) - self.assertEquals(self.counter, 1) - - lock.acquire().addCallback(self._incr) - self.failUnless(lock.locked) - self.assertEquals(self.counter, 1) - - lock.release() - self.failUnless(lock.locked) - self.assertEquals(self.counter, 2) - - lock.release() - self.failIf(lock.locked) - self.assertEquals(self.counter, 2) - - self.assertRaises(TypeError, lock.run) - - firstUnique = object() - secondUnique = object() - - controlDeferred = defer.Deferred() - def helper(self, b): - self.b = b - return controlDeferred - - resultDeferred = lock.run(helper, self=self, b=firstUnique) - self.failUnless(lock.locked) - self.assertEquals(self.b, firstUnique) - - resultDeferred.addCallback(lambda x: setattr(self, 'result', x)) - - lock.acquire().addCallback(self._incr) - self.failUnless(lock.locked) - self.assertEquals(self.counter, 2) - - controlDeferred.callback(secondUnique) - self.assertEquals(self.result, secondUnique) - self.failUnless(lock.locked) - self.assertEquals(self.counter, 3) - - lock.release() - self.failIf(lock.locked) - - def testSemaphore(self): - N = 13 - sem = defer.DeferredSemaphore(N) - - controlDeferred = defer.Deferred() - def helper(self, arg): - self.arg = arg - return controlDeferred - - results = [] - uniqueObject = object() - resultDeferred = sem.run(helper, self=self, arg=uniqueObject) - resultDeferred.addCallback(results.append) - resultDeferred.addCallback(self._incr) - self.assertEquals(results, []) - self.assertEquals(self.arg, uniqueObject) - controlDeferred.callback(None) - self.assertEquals(results.pop(), None) - self.assertEquals(self.counter, 1) - - self.counter = 0 - for i in range(1, 1 + N): - sem.acquire().addCallback(self._incr) - self.assertEquals(self.counter, i) - - sem.acquire().addCallback(self._incr) - self.assertEquals(self.counter, N) - - sem.release() - self.assertEquals(self.counter, N + 1) - - for i in range(1, 1 + N): - sem.release() - self.assertEquals(self.counter, N + 1) - - def testQueue(self): - N, M = 2, 2 - queue = defer.DeferredQueue(N, M) - - gotten = [] - - for i in range(M): - queue.get().addCallback(gotten.append) - self.assertRaises(defer.QueueUnderflow, queue.get) - - for i in range(M): - queue.put(i) - self.assertEquals(gotten, range(i + 1)) - for i in range(N): - queue.put(N + i) - self.assertEquals(gotten, range(M)) - self.assertRaises(defer.QueueOverflow, queue.put, None) - - gotten = [] - for i in range(N): - queue.get().addCallback(gotten.append) - self.assertEquals(gotten, range(N, N + i + 1)) - - queue = defer.DeferredQueue() - gotten = [] - for i in range(N): - queue.get().addCallback(gotten.append) - for i in range(N): - queue.put(i) - self.assertEquals(gotten, range(N)) - - queue = defer.DeferredQueue(size=0) - self.assertRaises(defer.QueueOverflow, queue.put, None) - - queue = defer.DeferredQueue(backlog=0) - self.assertRaises(defer.QueueUnderflow, queue.get) - - - -class DeferredFilesystemLockTestCase(unittest.TestCase): - """ - Test the behavior of L{DeferredFilesystemLock} - """ - def setUp(self): - self.clock = Clock() - self.lock = defer.DeferredFilesystemLock(self.mktemp(), - scheduler=self.clock) - - - def test_waitUntilLockedWithNoLock(self): - """ - Test that the lock can be acquired when no lock is held - """ - d = self.lock.deferUntilLocked(timeout=1) - - return d - - - def test_waitUntilLockedWithTimeoutLocked(self): - """ - Test that the lock can not be acquired when the lock is held - for longer than the timeout. - """ - self.failUnless(self.lock.lock()) - - d = self.lock.deferUntilLocked(timeout=5.5) - self.assertFailure(d, defer.TimeoutError) - - self.clock.pump([1]*10) - - return d - - - def test_waitUntilLockedWithTimeoutUnlocked(self): - """ - Test that a lock can be acquired while a lock is held - but the lock is unlocked before our timeout. - """ - def onTimeout(f): - f.trap(defer.TimeoutError) - self.fail("Should not have timed out") - - self.failUnless(self.lock.lock()) - - self.clock.callLater(1, self.lock.unlock) - d = self.lock.deferUntilLocked(timeout=10) - d.addErrback(onTimeout) - - self.clock.pump([1]*10) - - return d - - - def test_defaultScheduler(self): - """ - Test that the default scheduler is set up properly. - """ - lock = defer.DeferredFilesystemLock(self.mktemp()) - - self.assertEquals(lock._scheduler, reactor) - - - def test_concurrentUsage(self): - """ - Test that an appropriate exception is raised when attempting - to use deferUntilLocked concurrently. - """ - self.lock.lock() - self.clock.callLater(1, self.lock.unlock) - - d = self.lock.deferUntilLocked() - d2 = self.lock.deferUntilLocked() - - self.assertFailure(d2, defer.AlreadyTryingToLockError) - - self.clock.advance(1) - - return d - - - def test_multipleUsages(self): - """ - Test that a DeferredFilesystemLock can be used multiple times - """ - def lockAquired(ign): - self.lock.unlock() - d = self.lock.deferUntilLocked() - return d - - self.lock.lock() - self.clock.callLater(1, self.lock.unlock) - - d = self.lock.deferUntilLocked() - d.addCallback(lockAquired) - - self.clock.advance(1) - - return d diff --git a/tools/buildbot/pylibs/twisted/test/test_defgen.py b/tools/buildbot/pylibs/twisted/test/test_defgen.py deleted file mode 100644 index 399e9dbc..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_defgen.py +++ /dev/null @@ -1,283 +0,0 @@ -from __future__ import generators, nested_scopes - -import sys - -from twisted.internet import reactor - -from twisted.trial import unittest, util - -from twisted.internet.defer import waitForDeferred, deferredGenerator, Deferred -from twisted.internet import defer - -def getThing(): - d = Deferred() - reactor.callLater(0, d.callback, "hi") - return d - -def getOwie(): - d = Deferred() - def CRAP(): - d.errback(ZeroDivisionError('OMG')) - reactor.callLater(0, CRAP) - return d - -# NOTE: most of the tests in DeferredGeneratorTests are duplicated -# with slightly different syntax for the InlineCallbacksTests below. - -class TerminalException(Exception): - pass - -class BaseDefgenTests: - """ - This class sets up a bunch of test cases which will test both - deferredGenerator and inlineCallbacks based generators. The subclasses - DeferredGeneratorTests and InlineCallbacksTests each provide the actual - generator implementations tested. - """ - - def testBasics(self): - """ - Test that a normal deferredGenerator works. Tests yielding a - deferred which callbacks, as well as a deferred errbacks. Also - ensures returning a final value works. - """ - - return self._genBasics().addCallback(self.assertEqual, 'WOOSH') - - def testBuggy(self): - """ - Ensure that a buggy generator properly signals a Failure - condition on result deferred. - """ - return self.assertFailure(self._genBuggy(), ZeroDivisionError) - - def testNothing(self): - """Test that a generator which never yields results in None.""" - - return self._genNothing().addCallback(self.assertEqual, None) - - def testHandledTerminalFailure(self): - """ - Create a Deferred Generator which yields a Deferred which fails and - handles the exception which results. Assert that the Deferred - Generator does not errback its Deferred. - """ - return self._genHandledTerminalFailure().addCallback(self.assertEqual, None) - - def testHandledTerminalAsyncFailure(self): - """ - Just like testHandledTerminalFailure, only with a Deferred which fires - asynchronously with an error. - """ - d = defer.Deferred() - deferredGeneratorResultDeferred = self._genHandledTerminalAsyncFailure(d) - d.errback(TerminalException("Handled Terminal Failure")) - return deferredGeneratorResultDeferred.addCallback( - self.assertEqual, None) - - def testStackUsage(self): - """ - Make sure we don't blow the stack when yielding immediately - available deferreds. - """ - return self._genStackUsage().addCallback(self.assertEqual, 0) - - def testStackUsage2(self): - """ - Make sure we don't blow the stack when yielding immediately - available values. - """ - return self._genStackUsage2().addCallback(self.assertEqual, 0) - - - - -class DeferredGeneratorTests(BaseDefgenTests, unittest.TestCase): - - # First provide all the generator impls necessary for BaseDefgenTests - def _genBasics(self): - - x = waitForDeferred(getThing()) - yield x - x = x.getResult() - - self.assertEquals(x, "hi") - - ow = waitForDeferred(getOwie()) - yield ow - try: - ow.getResult() - except ZeroDivisionError, e: - self.assertEquals(str(e), 'OMG') - yield "WOOSH" - return - _genBasics = deferredGenerator(_genBasics) - - def _genBuggy(self): - yield waitForDeferred(getThing()) - 1/0 - _genBuggy = deferredGenerator(_genBuggy) - - - def _genNothing(self): - if 0: yield 1 - _genNothing = deferredGenerator(_genNothing) - - def _genHandledTerminalFailure(self): - x = waitForDeferred(defer.fail(TerminalException("Handled Terminal Failure"))) - yield x - try: - x.getResult() - except TerminalException: - pass - _genHandledTerminalFailure = deferredGenerator(_genHandledTerminalFailure) - - - def _genHandledTerminalAsyncFailure(self, d): - x = waitForDeferred(d) - yield x - try: - x.getResult() - except TerminalException: - pass - _genHandledTerminalAsyncFailure = deferredGenerator(_genHandledTerminalAsyncFailure) - - - def _genStackUsage(self): - for x in range(5000): - # Test with yielding a deferred - x = waitForDeferred(defer.succeed(1)) - yield x - x = x.getResult() - yield 0 - _genStackUsage = deferredGenerator(_genStackUsage) - - def _genStackUsage2(self): - for x in range(5000): - # Test with yielding a random value - yield 1 - yield 0 - _genStackUsage2 = deferredGenerator(_genStackUsage2) - - # Tests unique to deferredGenerator - - def testDeferredYielding(self): - """ - Ensure that yielding a Deferred directly is trapped as an - error. - """ - # See the comment _deferGenerator about d.callback(Deferred). - def _genDeferred(): - yield getThing() - _genDeferred = deferredGenerator(_genDeferred) - - return self.assertFailure(_genDeferred(), TypeError) - - - -## This has to be in a string so the new yield syntax doesn't cause a -## syntax error in Python 2.4 and before. -inlineCallbacksTestsSource = ''' -from twisted.internet.defer import inlineCallbacks, returnValue - -class InlineCallbacksTests(BaseDefgenTests, unittest.TestCase): - # First provide all the generator impls necessary for BaseDefgenTests - - def _genBasics(self): - - x = yield getThing() - - self.assertEquals(x, "hi") - - try: - ow = yield getOwie() - except ZeroDivisionError, e: - self.assertEquals(str(e), 'OMG') - returnValue("WOOSH") - _genBasics = inlineCallbacks(_genBasics) - - def _genBuggy(self): - yield getThing() - 1/0 - _genBuggy = inlineCallbacks(_genBuggy) - - - def _genNothing(self): - if 0: yield 1 - _genNothing = inlineCallbacks(_genNothing) - - - def _genHandledTerminalFailure(self): - try: - x = yield defer.fail(TerminalException("Handled Terminal Failure")) - except TerminalException: - pass - _genHandledTerminalFailure = inlineCallbacks(_genHandledTerminalFailure) - - - def _genHandledTerminalAsyncFailure(self, d): - try: - x = yield d - except TerminalException: - pass - _genHandledTerminalAsyncFailure = inlineCallbacks( - _genHandledTerminalAsyncFailure) - - - def _genStackUsage(self): - for x in range(5000): - # Test with yielding a deferred - x = yield defer.succeed(1) - returnValue(0) - _genStackUsage = inlineCallbacks(_genStackUsage) - - def _genStackUsage2(self): - for x in range(5000): - # Test with yielding a random value - yield 1 - returnValue(0) - _genStackUsage2 = inlineCallbacks(_genStackUsage2) - - # Tests unique to inlineCallbacks - - def testYieldNonDeferrred(self): - """ - Ensure that yielding a non-deferred passes it back as the - result of the yield expression. - """ - def _test(): - x = yield 5 - returnValue(5) - _test = inlineCallbacks(_test) - - return _test().addCallback(self.assertEqual, 5) - - def testReturnNoValue(self): - """Ensure a standard python return results in a None result.""" - def _noReturn(): - yield 5 - return - _noReturn = inlineCallbacks(_noReturn) - - return _noReturn().addCallback(self.assertEqual, None) - - def testReturnValue(self): - """Ensure that returnValue works.""" - def _return(): - yield 5 - returnValue(6) - _return = inlineCallbacks(_return) - - return _return().addCallback(self.assertEqual, 6) - -''' - -if sys.version_info > (2, 5): - # Load tests - exec inlineCallbacksTestsSource -else: - # Make a placeholder test case - class InlineCallbacksTests(unittest.TestCase): - skip = "defer.defgen doesn't run on python < 2.5." - def test_everything(self): - pass diff --git a/tools/buildbot/pylibs/twisted/test/test_dict.py b/tools/buildbot/pylibs/twisted/test/test_dict.py deleted file mode 100644 index 154f66b..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_dict.py +++ /dev/null @@ -1,22 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -from twisted.trial import unittest -from twisted.protocols import dict - -paramString = "\"This is a dqstring \\w\\i\\t\\h boring stuff like: \\\"\" and t\\hes\\\"e are a\\to\\ms" -goodparams = ["This is a dqstring with boring stuff like: \"", "and", "thes\"e", "are", "atoms"] - -class ParamTest(unittest.TestCase): - def testParseParam(self): - """Testing command response handling""" - params = [] - rest = paramString - while 1: - (param, rest) = dict.parseParam(rest) - if param == None: - break - params.append(param) - self.failUnlessEqual(params, goodparams)#, "DictClient.parseParam returns unexpected results") diff --git a/tools/buildbot/pylibs/twisted/test/test_dirdbm.py b/tools/buildbot/pylibs/twisted/test/test_dirdbm.py deleted file mode 100644 index 12268bd..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_dirdbm.py +++ /dev/null @@ -1,174 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - - -""" -Test cases for dirdbm module. -""" - -from twisted.trial import unittest -from twisted.persisted import dirdbm -import os, shutil, glob - -class DirDbmTestCase(unittest.TestCase): - - def setUp(self): - self.path = self.mktemp() - self.dbm = dirdbm.open(self.path) - self.items = (('abc', 'foo'), ('/lalal', '\000\001'), ('\000\012', 'baz')) - - def tearDown(self): - shutil.rmtree(self.path) - - def testAll(self): - k = "//==".decode("base64") - self.dbm[k] = "a" - self.dbm[k] = "a" - self.assertEquals(self.dbm[k], "a") - - def testRebuildInteraction(self): - from twisted.persisted import dirdbm - from twisted.python import rebuild - - s = dirdbm.Shelf('dirdbm.rebuild.test') - s['key'] = 'value' - rebuild.rebuild(dirdbm) - # print s['key'] - - def testDbm(self): - d = self.dbm - - # insert keys - keys = [] - values = [] - for k, v in self.items: - d[k] = v - keys.append(k) - values.append(v) - keys.sort() - values.sort() - - # check they exist - for k, v in self.items: - assert d.has_key(k), "has_key() failed" - assert d[k] == v, "database has wrong value" - - # check non existent key - try: - d["XXX"] - except KeyError: - pass - else: - assert 0, "didn't raise KeyError on non-existent key" - - # check keys(), values() and items() - dbkeys = list(d.keys()) - dbvalues = list(d.values()) - dbitems = list(d.items()) - dbkeys.sort() - dbvalues.sort() - dbitems.sort() - items = list(self.items) - items.sort() - assert keys == dbkeys, ".keys() output didn't match: %s != %s" % (repr(keys), repr(dbkeys)) - assert values == dbvalues, ".values() output didn't match: %s != %s" % (repr(values), repr(dbvalues)) - assert items == dbitems, "items() didn't match: %s != %s" % (repr(items), repr(dbitems)) - - copyPath = self.mktemp() - d2 = d.copyTo(copyPath) - - copykeys = list(d.keys()) - copyvalues = list(d.values()) - copyitems = list(d.items()) - copykeys.sort() - copyvalues.sort() - copyitems.sort() - - assert dbkeys == copykeys, ".copyTo().keys() didn't match: %s != %s" % (repr(dbkeys), repr(copykeys)) - assert dbvalues == copyvalues, ".copyTo().values() didn't match: %s != %s" % (repr(dbvalues), repr(copyvalues)) - assert dbitems == copyitems, ".copyTo().items() didn't match: %s != %s" % (repr(dbkeys), repr(copyitems)) - - d2.clear() - assert len(d2.keys()) == len(d2.values()) == len(d2.items()) == 0, ".clear() failed" - shutil.rmtree(copyPath) - - # delete items - for k, v in self.items: - del d[k] - assert not d.has_key(k), "has_key() even though we deleted it" - assert len(d.keys()) == 0, "database has keys" - assert len(d.values()) == 0, "database has values" - assert len(d.items()) == 0, "database has items" - - - def testModificationTime(self): - import time - # the mtime value for files comes from a different place than the - # gettimeofday() system call. On linux, gettimeofday() can be - # slightly ahead (due to clock drift which gettimeofday() takes into - # account but which open()/write()/close() do not), and if we are - # close to the edge of the next second, time.time() can give a value - # which is larger than the mtime which results from a subsequent - # write(). I consider this a kernel bug, but it is beyond the scope - # of this test. Thus we keep the range of acceptability to 3 seconds time. - # -warner - self.dbm["k"] = "v" - self.assert_(abs(time.time() - self.dbm.getModificationTime("k")) <= 3) - - def testRecovery(self): - """DirDBM: test recovery from directory after a faked crash""" - k = self.dbm._encode("key1") - f = open(os.path.join(self.path, k + ".rpl"), "wb") - f.write("value") - f.close() - - k2 = self.dbm._encode("key2") - f = open(os.path.join(self.path, k2), "wb") - f.write("correct") - f.close() - f = open(os.path.join(self.path, k2 + ".rpl"), "wb") - f.write("wrong") - f.close() - - f = open(os.path.join(self.path, "aa.new"), "wb") - f.write("deleted") - f.close() - - dbm = dirdbm.DirDBM(self.path) - assert dbm["key1"] == "value" - assert dbm["key2"] == "correct" - assert not glob.glob(os.path.join(self.path, "*.new")) - assert not glob.glob(os.path.join(self.path, "*.rpl")) - - - def test_nonStringKeys(self): - """ - L{dirdbm.DirDBM} operations only support string keys: other types - should raise a C{AssertionError}. This really ought to be a - C{TypeError}, but it'll stay like this for backward compatibility. - """ - self.assertRaises(AssertionError, self.dbm.__setitem__, 2, "3") - try: - self.assertRaises(AssertionError, self.dbm.__setitem__, "2", 3) - except unittest.FailTest: - # dirdbm.Shelf.__setitem__ supports non-string values - self.assertIsInstance(self.dbm, dirdbm.Shelf) - self.assertRaises(AssertionError, self.dbm.__getitem__, 2) - self.assertRaises(AssertionError, self.dbm.__delitem__, 2) - self.assertRaises(AssertionError, self.dbm.has_key, 2) - self.assertRaises(AssertionError, self.dbm.__contains__, 2) - self.assertRaises(AssertionError, self.dbm.getModificationTime, 2) - - - -class ShelfTestCase(DirDbmTestCase): - - def setUp(self): - self.path = self.mktemp() - self.dbm = dirdbm.Shelf(self.path) - self.items = (('abc', 'foo'), ('/lalal', '\000\001'), ('\000\012', 'baz'), - ('int', 12), ('float', 12.0), ('tuple', (None, 12))) - - -testCases = [DirDbmTestCase, ShelfTestCase] diff --git a/tools/buildbot/pylibs/twisted/test/test_doc.py b/tools/buildbot/pylibs/twisted/test/test_doc.py deleted file mode 100644 index 1d4121b..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_doc.py +++ /dev/null @@ -1,92 +0,0 @@ -from twisted.trial import unittest -import inspect, glob, os -from os import path - -from twisted.python import reflect - -import twisted - -def errorInFile(f, line=17, name=''): - """Return a filename formatted so emacs will recognize it as an error point - - @param line: Line number in file. Defaults to 17 because that's about how - long the copyright headers are. - """ - return '%s:%d:%s' % (f, line, name) - # return 'File "%s", line %d, in %s' % (f, line, name) - -class DocCoverage(unittest.TestCase): - def setUp(self): - remove = len(os.path.dirname(os.path.dirname(twisted.__file__)))+1 - def visit(dirlist, directory, files): - if '__init__.py' in files: - d = directory[remove:].replace('/','.') - dirlist.append(d) - self.packageNames = [] - os.path.walk(os.path.dirname(twisted.__file__), - visit, self.packageNames) - - def testModules(self): - """Looking for docstrings in all modules.""" - docless = [] - for packageName in self.packageNames: - if packageName in ('twisted.test',): - # because some stuff in here behaves oddly when imported - continue - try: - package = reflect.namedModule(packageName) - except ImportError, e: - # This is testing doc coverage, not importability. - # (Really, I don't want to deal with the fact that I don't - # have pyserial installed.) - # print e - pass - else: - docless.extend(self.modulesInPackage(packageName, package)) - self.failIf(docless, "No docstrings in module files:\n" - "%s" % ('\n'.join(map(errorInFile, docless)),)) - - def modulesInPackage(self, packageName, package): - docless = [] - directory = path.dirname(package.__file__) - for modfile in glob.glob(path.join(directory, '*.py')): - moduleName = inspect.getmodulename(modfile) - if moduleName == '__init__': - # These are tested by test_packages. - continue - elif moduleName in ('spelunk_gnome','gtkmanhole'): - # argh special case pygtk evil argh. How does epydoc deal - # with this? - continue - try: - module = reflect.namedModule('.'.join([packageName, - moduleName])) - except Exception, e: - # print moduleName, "misbehaved:", e - pass - else: - if not inspect.getdoc(module): - docless.append(modfile) - return docless - - def testPackages(self): - """Looking for docstrings in all packages.""" - docless = [] - for packageName in self.packageNames: - try: - package = reflect.namedModule(packageName) - except Exception, e: - # This is testing doc coverage, not importability. - # (Really, I don't want to deal with the fact that I don't - # have pyserial installed.) - # print e - pass - else: - if not inspect.getdoc(package): - docless.append(package.__file__.replace('.pyc','.py')) - self.failIf(docless, "No docstrings for package files\n" - "%s" % ('\n'.join(map(errorInFile, docless),))) - - - # This test takes a while and doesn't come close to passing. :( - testModules.skip = "Activate me when you feel like writing docstrings, and fixing GTK crashing bugs." diff --git a/tools/buildbot/pylibs/twisted/test/test_enterprise.py b/tools/buildbot/pylibs/twisted/test/test_enterprise.py deleted file mode 100644 index 780c4fb..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_enterprise.py +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -General tests for twisted.enterprise. -""" - -from twisted.trial import unittest - -from twisted.enterprise import util - -class QuotingTestCase(unittest.TestCase): - - def testQuoting(self): - for value, typ, expected in [ - (12, "integer", "12"), - ("foo'd", "text", "'foo''d'"), - ("\x00abc\\s\xFF", "bytea", "'\\\\000abc\\\\\\\\s\\377'"), - (12, "text", "'12'"), - (u"123'456", "text", u"'123''456'") - ]: - self.assertEquals( - self.callDeprecated(util._deprecatedVersion, util.quote, value, - typ), - expected) - - - def test_safeDeprecation(self): - """ - L{safe} is deprecated. - """ - self.callDeprecated(util._deprecatedVersion, util.safe, "foo") - - - def test_getKeyColumnDeprecation(self): - """ - L{getKeyColumn} is deprecated. - """ - class Row(object): - rowKeyColumns = () - self.callDeprecated(util._deprecatedVersion, util.getKeyColumn, Row, "foo") diff --git a/tools/buildbot/pylibs/twisted/test/test_epoll.py b/tools/buildbot/pylibs/twisted/test/test_epoll.py deleted file mode 100644 index a5912a7..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_epoll.py +++ /dev/null @@ -1,159 +0,0 @@ -# Copyright (c) 2001-2006 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for epoll wrapper. -""" - -import socket, errno, time - -from twisted.trial import unittest -from twisted.python.util import untilConcludes - -try: - from twisted.python import _epoll -except ImportError: - _epoll = None - - -class EPoll(unittest.TestCase): - """ - Tests for the low-level epoll bindings. - """ - def setUp(self): - """ - Create a listening server port and a list with which to keep track - of created sockets. - """ - self.serverSocket = socket.socket() - self.serverSocket.bind(('127.0.0.1', 0)) - self.serverSocket.listen(1) - self.connections = [self.serverSocket] - - - def tearDown(self): - """ - Close any sockets which were opened by the test. - """ - for skt in self.connections: - skt.close() - - - def _connectedPair(self): - """ - Return the two sockets which make up a new TCP connection. - """ - client = socket.socket() - client.setblocking(False) - try: - client.connect(('127.0.0.1', self.serverSocket.getsockname()[1])) - except socket.error, e: - self.assertEquals(e.args[0], errno.EINPROGRESS) - else: - raise unittest.FailTest("Connect should have raised EINPROGRESS") - server, addr = self.serverSocket.accept() - - self.connections.extend((client, server)) - return client, server - - - def test_create(self): - """ - Test the creation of an epoll object. - """ - try: - p = _epoll.epoll(16) - except OSError, e: - raise unittest.FailTest(str(e)) - else: - p.close() - - - def test_badCreate(self): - """ - Test that attempting to create an epoll object with some random - objects raises a TypeError. - """ - self.assertRaises(TypeError, _epoll.epoll, 1, 2, 3) - self.assertRaises(TypeError, _epoll.epoll, 'foo') - self.assertRaises(TypeError, _epoll.epoll, None) - self.assertRaises(TypeError, _epoll.epoll, ()) - self.assertRaises(TypeError, _epoll.epoll, ['foo']) - self.assertRaises(TypeError, _epoll.epoll, {}) - self.assertRaises(TypeError, _epoll.epoll) - - - def test_add(self): - """ - Test adding a socket to an epoll object. - """ - server, client = self._connectedPair() - - p = _epoll.epoll(2) - try: - p._control(_epoll.CTL_ADD, server.fileno(), _epoll.IN | _epoll.OUT) - p._control(_epoll.CTL_ADD, client.fileno(), _epoll.IN | _epoll.OUT) - finally: - p.close() - - - def test_controlAndWait(self): - """ - Test waiting on an epoll object which has had some sockets added to - it. - """ - client, server = self._connectedPair() - - p = _epoll.epoll(16) - p._control(_epoll.CTL_ADD, client.fileno(), _epoll.IN | _epoll.OUT | - _epoll.ET) - p._control(_epoll.CTL_ADD, server.fileno(), _epoll.IN | _epoll.OUT | - _epoll.ET) - - now = time.time() - events = untilConcludes(p.wait, 4, 1000) - then = time.time() - self.failIf(then - now > 0.01) - - events.sort() - expected = [(client.fileno(), _epoll.OUT), - (server.fileno(), _epoll.OUT)] - expected.sort() - - self.assertEquals(events, expected) - - now = time.time() - events = untilConcludes(p.wait, 4, 200) - then = time.time() - self.failUnless(then - now > 0.1) - self.failIf(events) - - client.send("Hello!") - server.send("world!!!") - - now = time.time() - events = untilConcludes(p.wait, 4, 1000) - then = time.time() - self.failIf(then - now > 0.01) - - events.sort() - expected = [(client.fileno(), _epoll.IN | _epoll.OUT), - (server.fileno(), _epoll.IN | _epoll.OUT)] - expected.sort() - - self.assertEquals(events, expected) - -if _epoll is None: - EPoll.skip = "_epoll module unavailable" -else: - try: - e = _epoll.epoll(16) - except IOError, exc: - if exc.errno == errno.ENOSYS: - del exc - EPoll.skip = "epoll support missing from platform" - else: - raise - else: - e.close() - del e diff --git a/tools/buildbot/pylibs/twisted/test/test_error.py b/tools/buildbot/pylibs/twisted/test/test_error.py deleted file mode 100644 index d300c46..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_error.py +++ /dev/null @@ -1,170 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -from twisted.trial import unittest -from twisted.internet import error -import socket - -class TestStringification(unittest.TestCase): - """Test that the exceptions have useful stringifications. - """ - - listOfTests = [ - #(output, exception[, args[, kwargs]]), - - ("An error occurred binding to an interface.", - error.BindError), - - ("An error occurred binding to an interface: foo.", - error.BindError, ['foo']), - - ("An error occurred binding to an interface: foo bar.", - error.BindError, ['foo', 'bar']), - - ("Couldn't listen on eth0:4242: Foo.", - error.CannotListenError, - ('eth0', 4242, socket.error('Foo'))), - - ("Message is too long to send.", - error.MessageLengthError), - - ("Message is too long to send: foo bar.", - error.MessageLengthError, ['foo', 'bar']), - - ("DNS lookup failed.", - error.DNSLookupError), - - ("DNS lookup failed: foo bar.", - error.DNSLookupError, ['foo', 'bar']), - - ("An error occurred while connecting.", - error.ConnectError), - - ("An error occurred while connecting: someOsError.", - error.ConnectError, ['someOsError']), - - ("An error occurred while connecting: foo.", - error.ConnectError, [], {'string': 'foo'}), - - ("An error occurred while connecting: someOsError: foo.", - error.ConnectError, ['someOsError', 'foo']), - - ("Couldn't bind.", - error.ConnectBindError), - - ("Couldn't bind: someOsError.", - error.ConnectBindError, ['someOsError']), - - ("Couldn't bind: someOsError: foo.", - error.ConnectBindError, ['someOsError', 'foo']), - - ("Hostname couldn't be looked up.", - error.UnknownHostError), - - ("No route to host.", - error.NoRouteError), - - ("Connection was refused by other side.", - error.ConnectionRefusedError), - - ("TCP connection timed out.", - error.TCPTimedOutError), - - ("File used for UNIX socket is no good.", - error.BadFileError), - - ("Service name given as port is unknown.", - error.ServiceNameUnknownError), - - ("User aborted connection.", - error.UserError), - - ("User timeout caused connection failure.", - error.TimeoutError), - - ("An SSL error occurred.", - error.SSLError), - - ("Connection to the other side was lost in a non-clean fashion.", - error.ConnectionLost), - - ("Connection to the other side was lost in a non-clean fashion: foo bar.", - error.ConnectionLost, ['foo', 'bar']), - - ("Connection was closed cleanly.", - error.ConnectionDone), - - ("Connection was closed cleanly: foo bar.", - error.ConnectionDone, ['foo', 'bar']), - - ("Uh.", #TODO nice docstring, you've got there. - error.ConnectionFdescWentAway), - - ("Tried to cancel an already-called event.", - error.AlreadyCalled), - - ("Tried to cancel an already-called event: foo bar.", - error.AlreadyCalled, ['foo', 'bar']), - - ("Tried to cancel an already-cancelled event.", - error.AlreadyCancelled), - - ("A process has ended without apparent errors: process finished with exit code 0.", - error.ProcessDone, - [None]), - - ("A process has ended with a probable error condition: process ended.", - error.ProcessTerminated), - - ("A process has ended with a probable error condition: process ended with exit code 42.", - error.ProcessTerminated, - [], - {'exitCode': 42}), - - ("A process has ended with a probable error condition: process ended by signal SIGBUS.", - error.ProcessTerminated, - [], - {'signal': 'SIGBUS'}), - - ("The Connector was not connecting when it was asked to stop connecting.", - error.NotConnectingError), - - ("The Port was not listening when it was asked to stop listening.", - error.NotListeningError), - - ] - - def testThemAll(self): - for entry in self.listOfTests: - output = entry[0] - exception = entry[1] - try: - args = entry[2] - except IndexError: - args = () - try: - kwargs = entry[3] - except IndexError: - kwargs = {} - - self.failUnlessEqual( - str(exception(*args, **kwargs)), - output) - - - def test_connectionLostSubclassOfConnectionClosed(self): - """ - L{error.ConnectionClosed} is a superclass of L{error.ConnectionLost}. - """ - self.assertTrue(issubclass(error.ConnectionLost, - error.ConnectionClosed)) - - - def test_connectionDoneSubclassOfConnectionClosed(self): - """ - L{error.ConnectionClosed} is a superclass of L{error.ConnectionDone}. - """ - self.assertTrue(issubclass(error.ConnectionDone, - error.ConnectionClosed)) - diff --git a/tools/buildbot/pylibs/twisted/test/test_explorer.py b/tools/buildbot/pylibs/twisted/test/test_explorer.py deleted file mode 100644 index cf3bf96..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_explorer.py +++ /dev/null @@ -1,236 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Test cases for explorer -""" - -from twisted.trial import unittest - -from twisted.manhole import explorer - -import types, string - -""" -# Tests: - - Get an ObjectLink. Browse ObjectLink.identifier. Is it the same? - - Watch Object. Make sure an ObjectLink is received when: - Call a method. - Set an attribute. - - Have an Object with a setattr class. Watch it. - Do both the navite setattr and the watcher get called? - - Sequences with circular references. Does it blow up? -""" - -class SomeDohickey: - def __init__(self, *a): - self.__dict__['args'] = a - - def bip(self): - return self.args - - -class TestBrowser(unittest.TestCase): - def setUp(self): - self.pool = explorer.explorerPool - self.pool.clear() - self.testThing = ["How many stairs must a man climb down?", - SomeDohickey(42)] - - def test_chain(self): - "Following a chain of Explorers." - xplorer = self.pool.getExplorer(self.testThing, 'testThing') - self.failUnlessEqual(xplorer.id, id(self.testThing)) - self.failUnlessEqual(xplorer.identifier, 'testThing') - - dxplorer = xplorer.get_elements()[1] - self.failUnlessEqual(dxplorer.id, id(self.testThing[1])) - -class Watcher: - zero = 0 - def __init__(self): - self.links = [] - - def receiveBrowserObject(self, olink): - self.links.append(olink) - - def setZero(self): - self.zero = len(self.links) - - def len(self): - return len(self.links) - self.zero - - -class SetattrDohickey: - def __setattr__(self, k, v): - v = list(str(v)) - v.reverse() - self.__dict__[k] = string.join(v, '') - -class MiddleMan(SomeDohickey, SetattrDohickey): - pass - -# class TestWatch(unittest.TestCase): -class FIXME_Watch: - def setUp(self): - self.globalNS = globals().copy() - self.localNS = {} - self.browser = explorer.ObjectBrowser(self.globalNS, self.localNS) - self.watcher = Watcher() - - def test_setAttrPlain(self): - "Triggering a watcher response by setting an attribute." - - testThing = SomeDohickey('pencil') - self.browser.watchObject(testThing, 'testThing', - self.watcher.receiveBrowserObject) - self.watcher.setZero() - - testThing.someAttr = 'someValue' - - self.failUnlessEqual(testThing.someAttr, 'someValue') - self.failUnless(self.watcher.len()) - olink = self.watcher.links[-1] - self.failUnlessEqual(olink.id, id(testThing)) - - def test_setAttrChain(self): - "Setting an attribute on a watched object that has __setattr__" - testThing = MiddleMan('pencil') - - self.browser.watchObject(testThing, 'testThing', - self.watcher.receiveBrowserObject) - self.watcher.setZero() - - testThing.someAttr = 'ZORT' - - self.failUnlessEqual(testThing.someAttr, 'TROZ') - self.failUnless(self.watcher.len()) - olink = self.watcher.links[-1] - self.failUnlessEqual(olink.id, id(testThing)) - - - def test_method(self): - "Triggering a watcher response by invoking a method." - - for testThing in (SomeDohickey('pencil'), MiddleMan('pencil')): - self.browser.watchObject(testThing, 'testThing', - self.watcher.receiveBrowserObject) - self.watcher.setZero() - - rval = testThing.bip() - self.failUnlessEqual(rval, ('pencil',)) - - self.failUnless(self.watcher.len()) - olink = self.watcher.links[-1] - self.failUnlessEqual(olink.id, id(testThing)) - - -def function_noArgs(): - "A function which accepts no arguments at all." - return - -def function_simple(a, b, c): - "A function which accepts several arguments." - return a, b, c - -def function_variable(*a, **kw): - "A function which accepts a variable number of args and keywords." - return a, kw - -def function_crazy((alpha, beta), c, d=range(4), **kw): - "A function with a mad crazy signature." - return alpha, beta, c, d, kw - -class TestBrowseFunction(unittest.TestCase): - - def setUp(self): - self.pool = explorer.explorerPool - self.pool.clear() - - def test_sanity(self): - """Basic checks for browse_function. - - Was the proper type returned? Does it have the right name and ID? - """ - for f_name in ('function_noArgs', 'function_simple', - 'function_variable', 'function_crazy'): - f = eval(f_name) - - xplorer = self.pool.getExplorer(f, f_name) - - self.failUnlessEqual(xplorer.id, id(f)) - - self.failUnless(isinstance(xplorer, explorer.ExplorerFunction)) - - self.failUnlessEqual(xplorer.name, f_name) - - def test_signature_noArgs(self): - """Testing zero-argument function signature. - """ - - xplorer = self.pool.getExplorer(function_noArgs, 'function_noArgs') - - self.failUnlessEqual(len(xplorer.signature), 0) - - def test_signature_simple(self): - """Testing simple function signature. - """ - - xplorer = self.pool.getExplorer(function_simple, 'function_simple') - - expected_signature = ('a','b','c') - - self.failUnlessEqual(xplorer.signature.name, expected_signature) - - def test_signature_variable(self): - """Testing variable-argument function signature. - """ - - xplorer = self.pool.getExplorer(function_variable, - 'function_variable') - - expected_names = ('a','kw') - signature = xplorer.signature - - self.failUnlessEqual(signature.name, expected_names) - self.failUnless(signature.is_varlist(0)) - self.failUnless(signature.is_keyword(1)) - - def test_signature_crazy(self): - """Testing function with crazy signature. - """ - xplorer = self.pool.getExplorer(function_crazy, 'function_crazy') - - signature = xplorer.signature - - expected_signature = [{'name': 'c'}, - {'name': 'd', - 'default': range(4)}, - {'name': 'kw', - 'keywords': 1}] - - # The name of the first argument seems to be indecipherable, - # but make sure it has one (and no default). - self.failUnless(signature.get_name(0)) - self.failUnless(not signature.get_default(0)[0]) - - self.failUnlessEqual(signature.get_name(1), 'c') - - # Get a list of values from a list of ExplorerImmutables. - arg_2_default = map(lambda l: l.value, - signature.get_default(2)[1].get_elements()) - - self.failUnlessEqual(signature.get_name(2), 'd') - self.failUnlessEqual(arg_2_default, range(4)) - - self.failUnlessEqual(signature.get_name(3), 'kw') - self.failUnless(signature.is_keyword(3)) - -if __name__ == '__main__': - unittest.main() diff --git a/tools/buildbot/pylibs/twisted/test/test_extensions.py b/tools/buildbot/pylibs/twisted/test/test_extensions.py deleted file mode 100644 index e2ecd63..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_extensions.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -import os -from os.path import join as opj - -from twisted.trial import unittest - -from twisted.python import util - - -class CorrectComments(unittest.TestCase): - def testNoSlashSlashComments(self): - urlarg = util.sibpath(__file__, opj(os.pardir, 'protocols', '_c_urlarg.c')) - contents = file(urlarg).read() - self.assertEquals(contents.find('//'), -1) diff --git a/tools/buildbot/pylibs/twisted/test/test_factories.py b/tools/buildbot/pylibs/twisted/test/test_factories.py deleted file mode 100644 index 63cf210..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_factories.py +++ /dev/null @@ -1,122 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test code for basic Factory classes. -""" - -import pickle - -from twisted.trial import unittest - -from twisted.internet import reactor, defer -from twisted.internet.protocol import Factory, ReconnectingClientFactory -from twisted.protocols.basic import Int16StringReceiver - -class In(Int16StringReceiver): - def __init__(self): - self.msgs = {} - - def connectionMade(self): - self.factory.connections += 1 - - def stringReceived(self, msg): - n, msg = pickle.loads(msg) - self.msgs[n] = msg - self.sendString(pickle.dumps(n)) - - def connectionLost(self, reason): - self.factory.allMessages.append(self.msgs) - if len(self.factory.allMessages) >= self.factory.goal: - self.factory.d.callback(None) - -class Out(Int16StringReceiver): - msgs = dict([(x, 'X' * x) for x in range(10)]) - - def __init__(self): - self.msgs = Out.msgs.copy() - - def connectionMade(self): - for i in self.msgs.keys(): - self.sendString(pickle.dumps( (i, self.msgs[i]))) - - def stringReceived(self, msg): - n = pickle.loads(msg) - del self.msgs[n] - if not self.msgs: - self.transport.loseConnection() - self.factory.howManyTimes -= 1 - if self.factory.howManyTimes <= 0: - self.factory.stopTrying() - - - -class ReconnectingFactoryTestCase(unittest.TestCase): - """ - Tests for L{ReconnectingClientFactory}. - """ - def testStopTrying(self): - f = Factory() - f.protocol = In - f.connections = 0 - f.allMessages = [] - f.goal = 2 - f.d = defer.Deferred() - - c = ReconnectingClientFactory() - c.initialDelay = c.delay = 0.2 - c.protocol = Out - c.howManyTimes = 2 - - port = reactor.listenTCP(0, f) - self.addCleanup(port.stopListening) - PORT = port.getHost().port - reactor.connectTCP('127.0.0.1', PORT, c) - - f.d.addCallback(self._testStopTrying_1, f, c) - return f.d - testStopTrying.timeout = 10 - - - def _testStopTrying_1(self, res, f, c): - self.assertEquals(len(f.allMessages), 2, - "not enough messages -- %s" % f.allMessages) - self.assertEquals(f.connections, 2, - "Number of successful connections incorrect %d" % - f.connections) - self.assertEquals(f.allMessages, [Out.msgs] * 2) - self.failIf(c.continueTrying, "stopTrying never called or ineffective") - - - def test_serializeUnused(self): - """ - A L{ReconnectingClientFactory} which hasn't been used for anything - can be pickled and unpickled and end up with the same state. - """ - original = ReconnectingClientFactory() - reconstituted = pickle.loads(pickle.dumps(original)) - self.assertEqual(original.__dict__, reconstituted.__dict__) - - - def test_deserializationResetsParameters(self): - """ - A L{ReconnectingClientFactory} which is unpickled does not have an - L{IConnector} and has its reconnectioning timing parameters reset to - their initial values. - """ - class FakeConnector(object): - def stopConnecting(self): - pass - - factory = ReconnectingClientFactory() - factory.clientConnectionFailed(FakeConnector(), None) - try: - serialized = pickle.dumps(factory) - unserialized = pickle.loads(serialized) - self.assertEqual(unserialized.connector, None) - self.assertEqual(unserialized._callID, None) - self.assertEqual(unserialized.retries, 0) - self.assertEqual(unserialized.delay, factory.initialDelay) - self.assertEqual(unserialized.continueTrying, True) - finally: - factory.stopTrying() diff --git a/tools/buildbot/pylibs/twisted/test/test_failure.py b/tools/buildbot/pylibs/twisted/test/test_failure.py deleted file mode 100644 index 7dc0ab1..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_failure.py +++ /dev/null @@ -1,318 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Test cases for failure module. -""" - -import sys -import StringIO -import traceback - -from twisted.trial import unittest, util - -from twisted.python import failure - -try: - from twisted.test import raiser -except ImportError: - raiser = None - - -class BrokenStr(Exception): - def __str__(self): - raise self - - -def getDivisionFailure(): - try: - 1/0 - except: - f = failure.Failure() - return f - - -class FailureTestCase(unittest.TestCase): - - def testFailAndTrap(self): - """Trapping a failure.""" - try: - raise NotImplementedError('test') - except: - f = failure.Failure() - error = f.trap(SystemExit, RuntimeError) - self.assertEquals(error, RuntimeError) - self.assertEquals(f.type, NotImplementedError) - - def test_notTrapped(self): - """Making sure trap doesn't trap what it shouldn't.""" - try: - raise ValueError() - except: - f = failure.Failure() - self.assertRaises(failure.Failure, f.trap, OverflowError) - - def testPrinting(self): - out = StringIO.StringIO() - try: - 1/0 - except: - f = failure.Failure() - f.printDetailedTraceback(out) - f.printBriefTraceback(out) - f.printTraceback(out) - - def testExplictPass(self): - e = RuntimeError() - f = failure.Failure(e) - f.trap(RuntimeError) - self.assertEquals(f.value, e) - - - def _getInnermostFrameLine(self, f): - try: - f.raiseException() - except ZeroDivisionError: - tb = traceback.extract_tb(sys.exc_info()[2]) - return tb[-1][-1] - else: - raise Exception( - "f.raiseException() didn't raise ZeroDivisionError!?") - - - def testRaiseExceptionWithTB(self): - f = getDivisionFailure() - innerline = self._getInnermostFrameLine(f) - self.assertEquals(innerline, '1/0') - - - def testLackOfTB(self): - f = getDivisionFailure() - f.cleanFailure() - innerline = self._getInnermostFrameLine(f) - self.assertEquals(innerline, '1/0') - - testLackOfTB.todo = "the traceback is not preserved, exarkun said he'll try to fix this! god knows how" - - - _stringException = "bugger off" - def _getStringFailure(self): - try: - raise self._stringException - except: - f = failure.Failure() - return f - - def test_raiseStringExceptions(self): - # String exceptions used to totally bugged f.raiseException - f = self._getStringFailure() - try: - f.raiseException() - except: - self.assertEquals(sys.exc_info()[0], self._stringException) - else: - raise AssertionError("Should have raised") - test_raiseStringExceptions.suppress = [ - util.suppress(message='raising a string exception is deprecated')] - - - def test_printStringExceptions(self): - """ - L{Failure.printTraceback} should write out stack and exception - information, even for string exceptions. - """ - failure = self._getStringFailure() - output = StringIO.StringIO() - failure.printTraceback(file=output) - lines = output.getvalue().splitlines() - # The last line should be the value of the raised string - self.assertEqual(lines[-1], self._stringException) - - test_printStringExceptions.suppress = [ - util.suppress(message='raising a string exception is deprecated')] - - if sys.version_info[:2] >= (2, 6): - skipMsg = ("String exceptions aren't supported anymore starting " - "Python 2.6") - test_raiseStringExceptions.skip = skipMsg - test_printStringExceptions.skip = skipMsg - - - def testBrokenStr(self): - """ - Formatting a traceback of a Failure which refers to an object - that has a broken __str__ implementation should not cause - getTraceback to raise an exception. - """ - x = BrokenStr() - try: - str(x) - except: - f = failure.Failure() - self.assertEquals(f.value, x) - try: - f.getTraceback() - except: - self.fail("getTraceback() shouldn't raise an exception") - - - def testConstructionFails(self): - """ - Creating a Failure with no arguments causes it to try to discover the - current interpreter exception state. If no such state exists, creating - the Failure should raise a synchronous exception. - """ - self.assertRaises(failure.NoCurrentExceptionError, failure.Failure) - - def test_getTracebackObject(self): - """ - If the C{Failure} has not been cleaned, then C{getTracebackObject} - should return the traceback object that it was given in the - constructor. - """ - f = getDivisionFailure() - self.assertEqual(f.getTracebackObject(), f.tb) - - def test_getTracebackObjectFromClean(self): - """ - If the Failure has been cleaned, then C{getTracebackObject} should - return an object that looks the same to L{traceback.extract_tb}. - """ - f = getDivisionFailure() - expected = traceback.extract_tb(f.getTracebackObject()) - f.cleanFailure() - observed = traceback.extract_tb(f.getTracebackObject()) - self.assertEqual(expected, observed) - - def test_getTracebackObjectWithoutTraceback(self): - """ - L{failure.Failure}s need not be constructed with traceback objects. If - a C{Failure} has no traceback information at all, C{getTracebackObject} - should just return None. - - None is a good value, because traceback.extract_tb(None) -> []. - """ - f = failure.Failure(Exception("some error")) - self.assertEqual(f.getTracebackObject(), None) - -class FindFailureTests(unittest.TestCase): - """ - Tests for functionality related to L{Failure._findFailure}. - """ - - def test_findNoFailureInExceptionHandler(self): - """ - Within an exception handler, _findFailure should return - C{None} in case no Failure is associated with the current - exception. - """ - try: - 1/0 - except: - self.assertEqual(failure.Failure._findFailure(), None) - else: - self.fail("No exception raised from 1/0!?") - - - def test_findNoFailure(self): - """ - Outside of an exception handler, _findFailure should return None. - """ - self.assertEqual(sys.exc_info()[-1], None) #environment sanity check - self.assertEqual(failure.Failure._findFailure(), None) - - - def test_findFailure(self): - """ - Within an exception handler, it should be possible to find the - original Failure that caused the current exception (if it was - caused by raiseException). - """ - f = getDivisionFailure() - f.cleanFailure() - try: - f.raiseException() - except: - self.assertEqual(failure.Failure._findFailure(), f) - else: - self.fail("No exception raised from raiseException!?") - - - def test_failureConstructionFindsOriginalFailure(self): - """ - When a Failure is constructed in the context of an exception - handler that is handling an exception raised by - raiseException, the new Failure should be chained to that - original Failure. - """ - f = getDivisionFailure() - f.cleanFailure() - try: - f.raiseException() - except: - newF = failure.Failure() - self.assertEqual(f.getTraceback(), newF.getTraceback()) - else: - self.fail("No exception raised from raiseException!?") - - - def test_failureConstructionWithMungedStackSucceeds(self): - """ - Pyrex and Cython are known to insert fake stack frames so as to give - more Python-like tracebacks. These stack frames with empty code objects - should not break extraction of the exception. - """ - try: - raiser.raiseException() - except raiser.RaiserException: - f = failure.Failure() - self.assertTrue(f.check(raiser.RaiserException)) - else: - self.fail("No exception raised from extension?!") - - - if raiser is None: - skipMsg = "raiser extension not available" - test_failureConstructionWithMungedStackSucceeds.skip = skipMsg - - - -class TestFormattableTraceback(unittest.TestCase): - """ - Whitebox tests that show that L{failure._Traceback} constructs objects that - can be used by L{traceback.extract_tb}. - - If the objects can be used by L{traceback.extract_tb}, then they can be - formatted using L{traceback.format_tb} and friends. - """ - - def test_singleFrame(self): - """ - A C{_Traceback} object constructed with a single frame should be able - to be passed to L{traceback.extract_tb}, and we should get a singleton - list containing a (filename, lineno, methodname, line) tuple. - """ - tb = failure._Traceback([['method', 'filename.py', 123, {}, {}]]) - # Note that we don't need to test that extract_tb correctly extracts - # the line's contents. In this case, since filename.py doesn't exist, - # it will just use None. - self.assertEqual(traceback.extract_tb(tb), - [('filename.py', 123, 'method', None)]) - - def test_manyFrames(self): - """ - A C{_Traceback} object constructed with multiple frames should be able - to be passed to L{traceback.extract_tb}, and we should get a list - containing a tuple for each frame. - """ - tb = failure._Traceback([ - ['method1', 'filename.py', 123, {}, {}], - ['method2', 'filename.py', 235, {}, {}]]) - self.assertEqual(traceback.extract_tb(tb), - [('filename.py', 123, 'method1', None), - ('filename.py', 235, 'method2', None)]) - - -if sys.version_info[:2] >= (2, 5): - from twisted.test.generator_failure_tests import TwoPointFiveFailureTests diff --git a/tools/buildbot/pylibs/twisted/test/test_fdesc.py b/tools/buildbot/pylibs/twisted/test/test_fdesc.py deleted file mode 100644 index a88803c..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_fdesc.py +++ /dev/null @@ -1,176 +0,0 @@ -# Copyright (c) 2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.internet.fdesc}. -""" - -import os -import errno - -from twisted.trial import unittest - -try: - from twisted.internet import fdesc -except ImportError: - fdesc = None - - -class ReadWriteTestCase(unittest.TestCase): - """ - Tests for fdesc.readFromFD, fdesc.writeToFD. - """ - - def setUp(self): - """ - Create two non-blocking pipes that can be used in tests. - """ - self.r, self.w = os.pipe() - fdesc.setNonBlocking(self.r) - fdesc.setNonBlocking(self.w) - - - def tearDown(self): - """ - Close pipes. - """ - try: - os.close(self.w) - except OSError: - pass - try: - os.close(self.r) - except OSError: - pass - - - def write(self, d): - """ - Write data to the pipe. - """ - return fdesc.writeToFD(self.w, d) - - - def read(self): - """ - Read data from the pipe. - """ - l = [] - res = fdesc.readFromFD(self.r, l.append) - if res is None: - if l: - return l[0] - else: - return "" - else: - return res - - - def test_writeAndRead(self): - """ - Test that the number of bytes L{fdesc.writeToFD} reports as written - with its return value are seen by L{fdesc.readFromFD}. - """ - n = self.write("hello") - self.failUnless(n > 0) - s = self.read() - self.assertEquals(len(s), n) - self.assertEquals("hello"[:n], s) - - - def test_writeAndReadLarge(self): - """ - Similar to L{test_writeAndRead}, but use a much larger string to verify - the behavior for that case. - """ - orig = "0123456879" * 10000 - written = self.write(orig) - self.failUnless(written > 0) - result = [] - resultlength = 0 - i = 0 - while resultlength < written or i < 50: - result.append(self.read()) - resultlength += len(result[-1]) - # Increment a counter to be sure we'll exit at some point - i += 1 - result = "".join(result) - self.assertEquals(len(result), written) - self.assertEquals(orig[:written], result) - - - def test_readFromEmpty(self): - """ - Verify that reading from a file descriptor with no data does not raise - an exception and does not result in the callback function being called. - """ - l = [] - result = fdesc.readFromFD(self.r, l.append) - self.assertEquals(l, []) - self.assertEquals(result, None) - - - def test_readFromCleanClose(self): - """ - Test that using L{fdesc.readFromFD} on a cleanly closed file descriptor - returns a connection done indicator. - """ - os.close(self.w) - self.assertEquals(self.read(), fdesc.CONNECTION_DONE) - - - def test_writeToClosed(self): - """ - Verify that writing with L{fdesc.writeToFD} when the read end is closed - results in a connection lost indicator. - """ - os.close(self.r) - self.assertEquals(self.write("s"), fdesc.CONNECTION_LOST) - - - def test_readFromInvalid(self): - """ - Verify that reading with L{fdesc.readFromFD} when the read end is - closed results in a connection lost indicator. - """ - os.close(self.r) - self.assertEquals(self.read(), fdesc.CONNECTION_LOST) - - - def test_writeToInvalid(self): - """ - Verify that writing with L{fdesc.writeToFD} when the write end is - closed results in a connection lost indicator. - """ - os.close(self.w) - self.assertEquals(self.write("s"), fdesc.CONNECTION_LOST) - - - def test_writeErrors(self): - """ - Test error path for L{fdesc.writeTod}. - """ - oldOsWrite = os.write - def eagainWrite(fd, data): - err = OSError() - err.errno = errno.EAGAIN - raise err - os.write = eagainWrite - try: - self.assertEquals(self.write("s"), 0) - finally: - os.write = oldOsWrite - - def eintrWrite(fd, data): - err = OSError() - err.errno = errno.EINTR - raise err - os.write = eintrWrite - try: - self.assertEquals(self.write("s"), 0) - finally: - os.write = oldOsWrite - - -if fdesc is None: - ReadWriteTestCase.skip = "not supported on this platform" diff --git a/tools/buildbot/pylibs/twisted/test/test_finger.py b/tools/buildbot/pylibs/twisted/test/test_finger.py deleted file mode 100644 index 0d9366c..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_finger.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -from twisted.trial import unittest -from twisted.protocols import finger -from twisted.internet import reactor, protocol -from twisted.test import test_protocols - -class FingerTestCase(unittest.TestCase): - - def setUp(self): - self.t = test_protocols.StringIOWithoutClosing() - self.p = finger.Finger() - self.p.makeConnection(protocol.FileWrapper(self.t)) - - def testSimple(self): - self.p.dataReceived("moshez\r\n") - self.failUnlessEqual(self.t.getvalue(), - "Login: moshez\nNo such user\n") - - def testSimpleW(self): - self.p.dataReceived("/w moshez\r\n") - self.failUnlessEqual(self.t.getvalue(), - "Login: moshez\nNo such user\n") - - def testForwarding(self): - self.p.dataReceived("moshez@example.com\r\n") - self.failUnlessEqual(self.t.getvalue(), - "Finger forwarding service denied\n") - - def testList(self): - self.p.dataReceived("\r\n") - self.failUnlessEqual(self.t.getvalue(), - "Finger online list denied\n") diff --git a/tools/buildbot/pylibs/twisted/test/test_formmethod.py b/tools/buildbot/pylibs/twisted/test/test_formmethod.py deleted file mode 100644 index a28bb57..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_formmethod.py +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Test cases for formmethod module. -""" - -from twisted.trial import unittest - -from twisted.python import formmethod - - -class ArgumentTestCase(unittest.TestCase): - - def argTest(self, argKlass, testPairs, badValues, *args, **kwargs): - arg = argKlass("name", *args, **kwargs) - for val, result in testPairs: - self.assertEquals(arg.coerce(val), result) - for val in badValues: - self.assertRaises(formmethod.InputError, arg.coerce, val) - - def testString(self): - self.argTest(formmethod.String, [("a", "a"), (1, "1"), ("", "")], ()) - self.argTest(formmethod.String, [("ab", "ab"), ("abc", "abc")], ("2", ""), min=2) - self.argTest(formmethod.String, [("ab", "ab"), ("a", "a")], ("223213", "345x"), max=3) - self.argTest(formmethod.String, [("ab", "ab"), ("add", "add")], ("223213", "x"), min=2, max=3) - - def testInt(self): - self.argTest(formmethod.Integer, [("3", 3), ("-2", -2), ("", None)], ("q", "2.3")) - self.argTest(formmethod.Integer, [("3", 3), ("-2", -2)], ("q", "2.3", ""), allowNone=0) - - def testFloat(self): - self.argTest(formmethod.Float, [("3", 3.0), ("-2.3", -2.3), ("", None)], ("q", "2.3z")) - self.argTest(formmethod.Float, [("3", 3.0), ("-2.3", -2.3)], ("q", "2.3z", ""), - allowNone=0) - - def testChoice(self): - choices = [("a", "apple", "an apple"), - ("b", "banana", "ook")] - self.argTest(formmethod.Choice, [("a", "apple"), ("b", "banana")], - ("c", 1), choices=choices) - - def testFlags(self): - flags = [("a", "apple", "an apple"), - ("b", "banana", "ook")] - self.argTest(formmethod.Flags, - [(["a"], ["apple"]), (["b", "a"], ["banana", "apple"])], - (["a", "c"], ["fdfs"]), - flags=flags) - - def testBoolean(self): - tests = [("yes", 1), ("", 0), ("False", 0), ("no", 0)] - self.argTest(formmethod.Boolean, tests, ()) - - def testDate(self): - goodTests = { - ("2002", "12", "21"): (2002, 12, 21), - ("1996", "2", "29"): (1996, 2, 29), - ("", "", ""): None, - }.items() - badTests = [("2002", "2", "29"), ("xx", "2", "3"), - ("2002", "13", "1"), ("1999", "12","32"), - ("2002", "1"), ("2002", "2", "3", "4")] - self.argTest(formmethod.Date, goodTests, badTests) - - def testRangedInteger(self): - goodTests = {"0": 0, "12": 12, "3": 3}.items() - badTests = ["-1", "x", "13", "-2000", "3.4"] - self.argTest(formmethod.IntegerRange, goodTests, badTests, 0, 12) - - def testVerifiedPassword(self): - goodTests = {("foo", "foo"): "foo", ("ab", "ab"): "ab"}.items() - badTests = [("ab", "a"), ("12345", "12345"), ("", ""), ("a", "a"), ("a",), ("a", "a", "a")] - self.argTest(formmethod.VerifiedPassword, goodTests, badTests, min=2, max=4) - - diff --git a/tools/buildbot/pylibs/twisted/test/test_ftp.py b/tools/buildbot/pylibs/twisted/test/test_ftp.py deleted file mode 100644 index 92c36ed..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_ftp.py +++ /dev/null @@ -1,2253 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -FTP tests. - -Maintainer: U{Andrew Bennetts} -""" - -import os.path -from StringIO import StringIO -import shutil -import errno - -from zope.interface import implements - -from twisted.trial import unittest -from twisted.protocols import basic -from twisted.internet import reactor, protocol, defer, error -from twisted.internet.interfaces import IConsumer -from twisted.cred import portal, checkers, credentials -from twisted.python import failure, filepath -from twisted.test import proto_helpers - -from twisted.protocols import ftp, loopback - -class NonClosingStringIO(StringIO): - def close(self): - pass - -StringIOWithoutClosing = NonClosingStringIO - - - -class Dummy(basic.LineReceiver): - logname = None - def __init__(self): - self.lines = [] - self.rawData = [] - def connectionMade(self): - self.f = self.factory # to save typing in pdb :-) - def lineReceived(self,line): - self.lines.append(line) - def rawDataReceived(self, data): - self.rawData.append(data) - def lineLengthExceeded(self, line): - pass - - -class _BufferingProtocol(protocol.Protocol): - def connectionMade(self): - self.buffer = '' - self.d = defer.Deferred() - def dataReceived(self, data): - self.buffer += data - def connectionLost(self, reason): - self.d.callback(self) - - -class FTPServerTestCase(unittest.TestCase): - """ - Simple tests for an FTP server with the default settings. - - @ivar clientFactory: class used as ftp client. - """ - clientFactory = ftp.FTPClientBasic - - def setUp(self): - # Create a directory - self.directory = self.mktemp() - os.mkdir(self.directory) - - # Start the server - p = portal.Portal(ftp.FTPRealm(self.directory)) - p.registerChecker(checkers.AllowAnonymousAccess(), - credentials.IAnonymous) - self.factory = ftp.FTPFactory(portal=p) - self.port = reactor.listenTCP(0, self.factory, interface="127.0.0.1") - - # Hook the server's buildProtocol to make the protocol instance - # accessible to tests. - buildProtocol = self.factory.buildProtocol - d1 = defer.Deferred() - def _rememberProtocolInstance(addr): - protocol = buildProtocol(addr) - self.serverProtocol = protocol.wrappedProtocol - d1.callback(None) - return protocol - self.factory.buildProtocol = _rememberProtocolInstance - - # Connect a client to it - portNum = self.port.getHost().port - clientCreator = protocol.ClientCreator(reactor, self.clientFactory) - d2 = clientCreator.connectTCP("127.0.0.1", portNum) - def gotClient(client): - self.client = client - d2.addCallback(gotClient) - return defer.gatherResults([d1, d2]) - - def tearDown(self): - # Clean up sockets - self.client.transport.loseConnection() - d = defer.maybeDeferred(self.port.stopListening) - d.addCallback(self.ebTearDown) - return d - - def ebTearDown(self, ignore): - del self.serverProtocol - # Clean up temporary directory - shutil.rmtree(self.directory) - - def assertCommandResponse(self, command, expectedResponseLines, - chainDeferred=None): - """Asserts that a sending an FTP command receives the expected - response. - - Returns a Deferred. Optionally accepts a deferred to chain its actions - to. - """ - if chainDeferred is None: - chainDeferred = defer.succeed(None) - - def queueCommand(ignored): - d = self.client.queueStringCommand(command) - def gotResponse(responseLines): - self.assertEquals(expectedResponseLines, responseLines) - return d.addCallback(gotResponse) - return chainDeferred.addCallback(queueCommand) - - def assertCommandFailed(self, command, expectedResponse=None, - chainDeferred=None): - if chainDeferred is None: - chainDeferred = defer.succeed(None) - - def queueCommand(ignored): - return self.client.queueStringCommand(command) - chainDeferred.addCallback(queueCommand) - self.assertFailure(chainDeferred, ftp.CommandFailed) - def failed(exception): - if expectedResponse is not None: - self.failUnlessEqual( - expectedResponse, exception.args[0]) - return chainDeferred.addCallback(failed) - - def _anonymousLogin(self): - d = self.assertCommandResponse( - 'USER anonymous', - ['331 Guest login ok, type your email address as password.']) - return self.assertCommandResponse( - 'PASS test@twistedmatrix.com', - ['230 Anonymous login ok, access restrictions apply.'], - chainDeferred=d) - - -class BasicFTPServerTestCase(FTPServerTestCase): - def testNotLoggedInReply(self): - """When not logged in, all commands other than USER and PASS should - get NOT_LOGGED_IN errors. - """ - commandList = ['CDUP', 'CWD', 'LIST', 'MODE', 'PASV', - 'PWD', 'RETR', 'STRU', 'SYST', 'TYPE'] - - # Issue commands, check responses - def checkResponse(exception): - failureResponseLines = exception.args[0] - self.failUnless(failureResponseLines[-1].startswith("530"), - "Response didn't start with 530: %r" - % (failureResponseLines[-1],)) - deferreds = [] - for command in commandList: - deferred = self.client.queueStringCommand(command) - self.assertFailure(deferred, ftp.CommandFailed) - deferred.addCallback(checkResponse) - deferreds.append(deferred) - return defer.DeferredList(deferreds, fireOnOneErrback=True) - - def testPASSBeforeUSER(self): - """Issuing PASS before USER should give an error.""" - return self.assertCommandFailed( - 'PASS foo', - ["503 Incorrect sequence of commands: " - "USER required before PASS"]) - - def testNoParamsForUSER(self): - """Issuing USER without a username is a syntax error.""" - return self.assertCommandFailed( - 'USER', - ['500 Syntax error: USER requires an argument.']) - - def testNoParamsForPASS(self): - """Issuing PASS without a password is a syntax error.""" - d = self.client.queueStringCommand('USER foo') - return self.assertCommandFailed( - 'PASS', - ['500 Syntax error: PASS requires an argument.'], - chainDeferred=d) - - def testAnonymousLogin(self): - return self._anonymousLogin() - - def testQuit(self): - """Issuing QUIT should return a 221 message.""" - d = self._anonymousLogin() - return self.assertCommandResponse( - 'QUIT', - ['221 Goodbye.'], - chainDeferred=d) - - def testAnonymousLoginDenied(self): - # Reconfigure the server to disallow anonymous access, and to have an - # IUsernamePassword checker that always rejects. - self.factory.allowAnonymous = False - denyAlwaysChecker = checkers.InMemoryUsernamePasswordDatabaseDontUse() - self.factory.portal.registerChecker(denyAlwaysChecker, - credentials.IUsernamePassword) - - # Same response code as allowAnonymous=True, but different text. - d = self.assertCommandResponse( - 'USER anonymous', - ['331 Password required for anonymous.']) - - # It will be denied. No-one can login. - d = self.assertCommandFailed( - 'PASS test@twistedmatrix.com', - ['530 Sorry, Authentication failed.'], - chainDeferred=d) - - # It's not just saying that. You aren't logged in. - d = self.assertCommandFailed( - 'PWD', - ['530 Please login with USER and PASS.'], - chainDeferred=d) - return d - - def testUnknownCommand(self): - d = self._anonymousLogin() - return self.assertCommandFailed( - 'GIBBERISH', - ["502 Command 'GIBBERISH' not implemented"], - chainDeferred=d) - - def testRETRBeforePORT(self): - d = self._anonymousLogin() - return self.assertCommandFailed( - 'RETR foo', - ["503 Incorrect sequence of commands: " - "PORT or PASV required before RETR"], - chainDeferred=d) - - def testSTORBeforePORT(self): - d = self._anonymousLogin() - return self.assertCommandFailed( - 'STOR foo', - ["503 Incorrect sequence of commands: " - "PORT or PASV required before STOR"], - chainDeferred=d) - - def testBadCommandArgs(self): - d = self._anonymousLogin() - self.assertCommandFailed( - 'MODE z', - ["504 Not implemented for parameter 'z'."], - chainDeferred=d) - self.assertCommandFailed( - 'STRU I', - ["504 Not implemented for parameter 'I'."], - chainDeferred=d) - return d - - def testDecodeHostPort(self): - self.assertEquals(ftp.decodeHostPort('25,234,129,22,100,23'), - ('25.234.129.22', 25623)) - nums = range(6) - for i in range(6): - badValue = list(nums) - badValue[i] = 256 - s = ','.join(map(str, badValue)) - self.assertRaises(ValueError, ftp.decodeHostPort, s) - - def testPASV(self): - # Login - wfd = defer.waitForDeferred(self._anonymousLogin()) - yield wfd - wfd.getResult() - - # Issue a PASV command, and extract the host and port from the response - pasvCmd = defer.waitForDeferred(self.client.queueStringCommand('PASV')) - yield pasvCmd - responseLines = pasvCmd.getResult() - host, port = ftp.decodeHostPort(responseLines[-1][4:]) - - # Make sure the server is listening on the port it claims to be - self.assertEqual(port, self.serverProtocol.dtpPort.getHost().port) - - # Semi-reasonable way to force cleanup - self.serverProtocol.transport.loseConnection() - testPASV = defer.deferredGenerator(testPASV) - - def testSYST(self): - d = self._anonymousLogin() - self.assertCommandResponse('SYST', ["215 UNIX Type: L8"], - chainDeferred=d) - return d - - - def test_portRangeForwardError(self): - """ - Exceptions other than L{error.CannotListenError} which are raised by - C{listenFactory} should be raised to the caller of L{FTP.getDTPPort}. - """ - def listenFactory(portNumber, factory): - raise RuntimeError() - self.serverProtocol.listenFactory = listenFactory - - self.assertRaises(RuntimeError, self.serverProtocol.getDTPPort, - protocol.Factory()) - - - def test_portRange(self): - """ - L{FTP.passivePortRange} should determine the ports which - L{FTP.getDTPPort} attempts to bind. If no port from that iterator can - be bound, L{error.CannotListenError} should be raised, otherwise the - first successful result from L{FTP.listenFactory} should be returned. - """ - def listenFactory(portNumber, factory): - if portNumber in (22032, 22033, 22034): - raise error.CannotListenError('localhost', portNumber, 'error') - return portNumber - self.serverProtocol.listenFactory = listenFactory - - port = self.serverProtocol.getDTPPort(protocol.Factory()) - self.assertEquals(port, 0) - - self.serverProtocol.passivePortRange = xrange(22032, 65536) - port = self.serverProtocol.getDTPPort(protocol.Factory()) - self.assertEquals(port, 22035) - - self.serverProtocol.passivePortRange = xrange(22032, 22035) - self.assertRaises(error.CannotListenError, - self.serverProtocol.getDTPPort, - protocol.Factory()) - - - -class FTPServerTestCaseAdvancedClient(FTPServerTestCase): - """ - Test FTP server with the L{ftp.FTPClient} class. - """ - clientFactory = ftp.FTPClient - - def test_anonymousSTOR(self): - """ - Try to make an STOR as anonymous, and check that we got a permission - denied error. - """ - def eb(res): - res.trap(ftp.CommandFailed) - self.assertEquals(res.value.args[0][0], - '550 foo: Permission denied.') - d1, d2 = self.client.storeFile('foo') - d2.addErrback(eb) - return defer.gatherResults([d1, d2]) - - -class FTPServerPasvDataConnectionTestCase(FTPServerTestCase): - def _makeDataConnection(self, ignored=None): - # Establish a passive data connection (i.e. client connecting to - # server). - d = self.client.queueStringCommand('PASV') - def gotPASV(responseLines): - host, port = ftp.decodeHostPort(responseLines[-1][4:]) - cc = protocol.ClientCreator(reactor, _BufferingProtocol) - return cc.connectTCP('127.0.0.1', port) - return d.addCallback(gotPASV) - - def _download(self, command, chainDeferred=None): - if chainDeferred is None: - chainDeferred = defer.succeed(None) - - chainDeferred.addCallback(self._makeDataConnection) - def queueCommand(downloader): - # wait for the command to return, and the download connection to be - # closed. - d1 = self.client.queueStringCommand(command) - d2 = downloader.d - return defer.gatherResults([d1, d2]) - chainDeferred.addCallback(queueCommand) - - def downloadDone((ignored, downloader)): - return downloader.buffer - return chainDeferred.addCallback(downloadDone) - - def testEmptyLIST(self): - # Login - d = self._anonymousLogin() - - # No files, so the file listing should be empty - self._download('LIST', chainDeferred=d) - def checkEmpty(result): - self.assertEqual('', result) - return d.addCallback(checkEmpty) - - def testTwoDirLIST(self): - # Make some directories - os.mkdir(os.path.join(self.directory, 'foo')) - os.mkdir(os.path.join(self.directory, 'bar')) - - # Login - d = self._anonymousLogin() - - # We expect 2 lines because there are two files. - self._download('LIST', chainDeferred=d) - def checkDownload(download): - self.assertEqual(2, len(download[:-2].split('\r\n'))) - d.addCallback(checkDownload) - - # Download a names-only listing. - self._download('NLST ', chainDeferred=d) - def checkDownload(download): - filenames = download[:-2].split('\r\n') - filenames.sort() - self.assertEqual(['bar', 'foo'], filenames) - d.addCallback(checkDownload) - - # Download a listing of the 'foo' subdirectory. 'foo' has no files, so - # the file listing should be empty. - self._download('LIST foo', chainDeferred=d) - def checkDownload(download): - self.assertEqual('', download) - d.addCallback(checkDownload) - - # Change the current working directory to 'foo'. - def chdir(ignored): - return self.client.queueStringCommand('CWD foo') - d.addCallback(chdir) - - # Download a listing from within 'foo', and again it should be empty, - # because LIST uses the working directory by default. - self._download('LIST', chainDeferred=d) - def checkDownload(download): - self.assertEqual('', download) - return d.addCallback(checkDownload) - - def testManyLargeDownloads(self): - # Login - d = self._anonymousLogin() - - # Download a range of different size files - for size in range(100000, 110000, 500): - fObj = file(os.path.join(self.directory, '%d.txt' % (size,)), 'wb') - fObj.write('x' * size) - fObj.close() - - self._download('RETR %d.txt' % (size,), chainDeferred=d) - def checkDownload(download, size=size): - self.assertEqual('x' * size, download) - d.addCallback(checkDownload) - return d - - -class FTPServerPortDataConnectionTestCase(FTPServerPasvDataConnectionTestCase): - def setUp(self): - self.dataPorts = [] - return FTPServerPasvDataConnectionTestCase.setUp(self) - - def _makeDataConnection(self, ignored=None): - # Establish an active data connection (i.e. server connecting to - # client). - deferred = defer.Deferred() - class DataFactory(protocol.ServerFactory): - protocol = _BufferingProtocol - def buildProtocol(self, addr): - p = protocol.ServerFactory.buildProtocol(self, addr) - reactor.callLater(0, deferred.callback, p) - return p - dataPort = reactor.listenTCP(0, DataFactory(), interface='127.0.0.1') - self.dataPorts.append(dataPort) - cmd = 'PORT ' + ftp.encodeHostPort('127.0.0.1', dataPort.getHost().port) - self.client.queueStringCommand(cmd) - return deferred - - def tearDown(self): - l = [defer.maybeDeferred(port.stopListening) for port in self.dataPorts] - d = defer.maybeDeferred( - FTPServerPasvDataConnectionTestCase.tearDown, self) - l.append(d) - return defer.DeferredList(l, fireOnOneErrback=True) - - def testPORTCannotConnect(self): - # Login - d = self._anonymousLogin() - - # Listen on a port, and immediately stop listening as a way to find a - # port number that is definitely closed. - def loggedIn(ignored): - port = reactor.listenTCP(0, protocol.Factory(), - interface='127.0.0.1') - portNum = port.getHost().port - d = port.stopListening() - d.addCallback(lambda _: portNum) - return d - d.addCallback(loggedIn) - - # Tell the server to connect to that port with a PORT command, and - # verify that it fails with the right error. - def gotPortNum(portNum): - return self.assertCommandFailed( - 'PORT ' + ftp.encodeHostPort('127.0.0.1', portNum), - ["425 Can't open data connection."]) - return d.addCallback(gotPortNum) - - -# -- Client Tests ----------------------------------------------------------- - -class PrintLines(protocol.Protocol): - """Helper class used by FTPFileListingTests.""" - - def __init__(self, lines): - self._lines = lines - - def connectionMade(self): - for line in self._lines: - self.transport.write(line + "\r\n") - self.transport.loseConnection() - - -class MyFTPFileListProtocol(ftp.FTPFileListProtocol): - def __init__(self): - self.other = [] - ftp.FTPFileListProtocol.__init__(self) - - def unknownLine(self, line): - self.other.append(line) - - -class FTPFileListingTests(unittest.TestCase): - def getFilesForLines(self, lines): - fileList = MyFTPFileListProtocol() - d = loopback.loopbackAsync(PrintLines(lines), fileList) - d.addCallback(lambda _: (fileList.files, fileList.other)) - return d - - def testOneLine(self): - # This example line taken from the docstring for FTPFileListProtocol - line = '-rw-r--r-- 1 root other 531 Jan 29 03:26 README' - def check(((file,), other)): - self.failIf(other, 'unexpect unparsable lines: %s' % repr(other)) - self.failUnless(file['filetype'] == '-', 'misparsed fileitem') - self.failUnless(file['perms'] == 'rw-r--r--', 'misparsed perms') - self.failUnless(file['owner'] == 'root', 'misparsed fileitem') - self.failUnless(file['group'] == 'other', 'misparsed fileitem') - self.failUnless(file['size'] == 531, 'misparsed fileitem') - self.failUnless(file['date'] == 'Jan 29 03:26', 'misparsed fileitem') - self.failUnless(file['filename'] == 'README', 'misparsed fileitem') - self.failUnless(file['nlinks'] == 1, 'misparsed nlinks') - self.failIf(file['linktarget'], 'misparsed linktarget') - return self.getFilesForLines([line]).addCallback(check) - - def testVariantLines(self): - line1 = 'drw-r--r-- 2 root other 531 Jan 9 2003 A' - line2 = 'lrw-r--r-- 1 root other 1 Jan 29 03:26 B -> A' - line3 = 'woohoo! ' - def check(((file1, file2), (other,))): - self.failUnless(other == 'woohoo! \r', 'incorrect other line') - # file 1 - self.failUnless(file1['filetype'] == 'd', 'misparsed fileitem') - self.failUnless(file1['perms'] == 'rw-r--r--', 'misparsed perms') - self.failUnless(file1['owner'] == 'root', 'misparsed owner') - self.failUnless(file1['group'] == 'other', 'misparsed group') - self.failUnless(file1['size'] == 531, 'misparsed size') - self.failUnless(file1['date'] == 'Jan 9 2003', 'misparsed date') - self.failUnless(file1['filename'] == 'A', 'misparsed filename') - self.failUnless(file1['nlinks'] == 2, 'misparsed nlinks') - self.failIf(file1['linktarget'], 'misparsed linktarget') - # file 2 - self.failUnless(file2['filetype'] == 'l', 'misparsed fileitem') - self.failUnless(file2['perms'] == 'rw-r--r--', 'misparsed perms') - self.failUnless(file2['owner'] == 'root', 'misparsed owner') - self.failUnless(file2['group'] == 'other', 'misparsed group') - self.failUnless(file2['size'] == 1, 'misparsed size') - self.failUnless(file2['date'] == 'Jan 29 03:26', 'misparsed date') - self.failUnless(file2['filename'] == 'B', 'misparsed filename') - self.failUnless(file2['nlinks'] == 1, 'misparsed nlinks') - self.failUnless(file2['linktarget'] == 'A', 'misparsed linktarget') - return self.getFilesForLines([line1, line2, line3]).addCallback(check) - - def testUnknownLine(self): - def check((files, others)): - self.failIf(files, 'unexpected file entries') - self.failUnless(others == ['ABC\r', 'not a file\r'], - 'incorrect unparsable lines: %s' % repr(others)) - return self.getFilesForLines(['ABC', 'not a file']).addCallback(check) - - def testYear(self): - # This example derived from bug description in issue 514. - fileList = ftp.FTPFileListProtocol() - exampleLine = ( - '-rw-r--r-- 1 root other 531 Jan 29 2003 README\n') - class PrintLine(protocol.Protocol): - def connectionMade(self): - self.transport.write(exampleLine) - self.transport.loseConnection() - - def check(ignored): - file = fileList.files[0] - self.failUnless(file['size'] == 531, 'misparsed fileitem') - self.failUnless(file['date'] == 'Jan 29 2003', 'misparsed fileitem') - self.failUnless(file['filename'] == 'README', 'misparsed fileitem') - - d = loopback.loopbackAsync(PrintLine(), fileList) - return d.addCallback(check) - - -class FTPClientTests(unittest.TestCase): - def tearDown(self): - # Clean up self.port, if any. - port = getattr(self, 'port', None) - if port is not None: - return port.stopListening() - - def testFailedRETR(self): - f = protocol.Factory() - f.noisy = 0 - self.port = reactor.listenTCP(0, f, interface="127.0.0.1") - portNum = self.port.getHost().port - # This test data derived from a bug report by ranty on #twisted - responses = ['220 ready, dude (vsFTPd 1.0.0: beat me, break me)', - # USER anonymous - '331 Please specify the password.', - # PASS twisted@twistedmatrix.com - '230 Login successful. Have fun.', - # TYPE I - '200 Binary it is, then.', - # PASV - '227 Entering Passive Mode (127,0,0,1,%d,%d)' % - (portNum >> 8, portNum & 0xff), - # RETR /file/that/doesnt/exist - '550 Failed to open file.'] - f.buildProtocol = lambda addr: PrintLines(responses) - - client = ftp.FTPClient(passive=1) - cc = protocol.ClientCreator(reactor, ftp.FTPClient, passive=1) - d = cc.connectTCP('127.0.0.1', portNum) - def gotClient(client): - p = protocol.Protocol() - return client.retrieveFile('/file/that/doesnt/exist', p) - d.addCallback(gotClient) - return self.assertFailure(d, ftp.CommandFailed) - - def test_errbacksUponDisconnect(self): - """ - Test the ftp command errbacks when a connection lost happens during - the operation. - """ - ftpClient = ftp.FTPClient() - tr = proto_helpers.StringTransportWithDisconnection() - ftpClient.makeConnection(tr) - tr.protocol = ftpClient - d = ftpClient.list('some path', Dummy()) - m = [] - def _eb(failure): - m.append(failure) - return None - d.addErrback(_eb) - from twisted.internet.main import CONNECTION_LOST - ftpClient.connectionLost(failure.Failure(CONNECTION_LOST)) - self.failUnless(m, m) - return d - - - -class FTPClientTestCase(unittest.TestCase): - """ - Test advanced FTP client commands. - """ - def setUp(self): - """ - Create a FTP client and connect it to fake transport. - """ - self.client = ftp.FTPClient() - self.transport = proto_helpers.StringTransportWithDisconnection() - self.client.makeConnection(self.transport) - self.transport.protocol = self.client - - - def tearDown(self): - """ - Deliver disconnection notification to the client so that it can - perform any cleanup which may be required. - """ - self.client.connectionLost(error.ConnectionLost()) - - - def _testLogin(self): - """ - Test the login part. - """ - self.assertEquals(self.transport.value(), '') - self.client.lineReceived( - '331 Guest login ok, type your email address as password.') - self.assertEquals(self.transport.value(), 'USER anonymous\r\n') - self.transport.clear() - self.client.lineReceived( - '230 Anonymous login ok, access restrictions apply.') - self.assertEquals(self.transport.value(), 'TYPE I\r\n') - self.transport.clear() - self.client.lineReceived('200 Type set to I.') - - - def test_CDUP(self): - """ - Test the CDUP command. - - L{ftp.FTPClient.cdup} should return a Deferred which fires with a - sequence of one element which is the string the server sent - indicating that the command was executed successfully. - - (XXX - This is a bad API) - """ - def cbCdup(res): - self.assertEquals(res[0], '250 Requested File Action Completed OK') - - self._testLogin() - d = self.client.cdup().addCallback(cbCdup) - self.assertEquals(self.transport.value(), 'CDUP\r\n') - self.transport.clear() - self.client.lineReceived('250 Requested File Action Completed OK') - return d - - - def test_failedCDUP(self): - """ - Test L{ftp.FTPClient.cdup}'s handling of a failed CDUP command. - - When the CDUP command fails, the returned Deferred should errback - with L{ftp.CommandFailed}. - """ - self._testLogin() - d = self.client.cdup() - self.assertFailure(d, ftp.CommandFailed) - self.assertEquals(self.transport.value(), 'CDUP\r\n') - self.transport.clear() - self.client.lineReceived('550 ..: No such file or directory') - return d - - - def test_PWD(self): - """ - Test the PWD command. - - L{ftp.FTPClient.pwd} should return a Deferred which fires with a - sequence of one element which is a string representing the current - working directory on the server. - - (XXX - This is a bad API) - """ - def cbPwd(res): - self.assertEquals(ftp.parsePWDResponse(res[0]), "/bar/baz") - - self._testLogin() - d = self.client.pwd().addCallback(cbPwd) - self.assertEquals(self.transport.value(), 'PWD\r\n') - self.client.lineReceived('257 "/bar/baz"') - return d - - - def test_failedPWD(self): - """ - Test a failure in PWD command. - - When the PWD command fails, the returned Deferred should errback - with L{ftp.CommandFailed}. - """ - self._testLogin() - d = self.client.pwd() - self.assertFailure(d, ftp.CommandFailed) - self.assertEquals(self.transport.value(), 'PWD\r\n') - self.client.lineReceived('550 /bar/baz: No such file or directory') - return d - - - def test_CWD(self): - """ - Test the CWD command. - - L{ftp.FTPClient.cwd} should return a Deferred which fires with a - sequence of one element which is the string the server sent - indicating that the command was executed successfully. - - (XXX - This is a bad API) - """ - def cbCwd(res): - self.assertEquals(res[0], '250 Requested File Action Completed OK') - - self._testLogin() - d = self.client.cwd("bar/foo").addCallback(cbCwd) - self.assertEquals(self.transport.value(), 'CWD bar/foo\r\n') - self.client.lineReceived('250 Requested File Action Completed OK') - return d - - - def test_failedCWD(self): - """ - Test a failure in CWD command. - - When the PWD command fails, the returned Deferred should errback - with L{ftp.CommandFailed}. - """ - self._testLogin() - d = self.client.cwd("bar/foo") - self.assertFailure(d, ftp.CommandFailed) - self.assertEquals(self.transport.value(), 'CWD bar/foo\r\n') - self.client.lineReceived('550 bar/foo: No such file or directory') - return d - - - def test_passiveRETR(self): - """ - Test the RETR command in passive mode: get a file and verify its - content. - - L{ftp.FTPClient.retrieveFile} should return a Deferred which fires - with the protocol instance passed to it after the download has - completed. - - (XXX - This API should be based on producers and consumers) - """ - def cbRetr(res, proto): - self.assertEquals(proto.buffer, 'x' * 1000) - - def cbConnect(host, port, factory): - self.assertEquals(host, '127.0.0.1') - self.assertEquals(port, 12345) - proto = factory.buildProtocol((host, port)) - proto.makeConnection(proto_helpers.StringTransport()) - self.client.lineReceived( - '150 File status okay; about to open data connection.') - proto.dataReceived("x" * 1000) - proto.connectionLost(failure.Failure(error.ConnectionDone(""))) - - self.client.connectFactory = cbConnect - self._testLogin() - proto = _BufferingProtocol() - d = self.client.retrieveFile("spam", proto) - d.addCallback(cbRetr, proto) - self.assertEquals(self.transport.value(), 'PASV\r\n') - self.transport.clear() - self.client.lineReceived('227 Entering Passive Mode (%s).' % - (ftp.encodeHostPort('127.0.0.1', 12345),)) - self.assertEquals(self.transport.value(), 'RETR spam\r\n') - self.transport.clear() - self.client.lineReceived('226 Transfer Complete.') - return d - - - def test_RETR(self): - """ - Test the RETR command in non-passive mode. - - Like L{test_passiveRETR} but in the configuration where the server - establishes the data connection to the client, rather than the other - way around. - """ - self.client.passive = False - - def generatePort(portCmd): - portCmd.text = 'PORT %s' % (ftp.encodeHostPort('127.0.0.1', 9876),) - portCmd.protocol.makeConnection(proto_helpers.StringTransport()) - portCmd.protocol.dataReceived("x" * 1000) - portCmd.protocol.connectionLost( - failure.Failure(error.ConnectionDone(""))) - - def cbRetr(res, proto): - self.assertEquals(proto.buffer, 'x' * 1000) - - self.client.generatePortCommand = generatePort - self._testLogin() - proto = _BufferingProtocol() - d = self.client.retrieveFile("spam", proto) - d.addCallback(cbRetr, proto) - self.assertEquals(self.transport.value(), 'PORT %s\r\n' % - (ftp.encodeHostPort('127.0.0.1', 9876),)) - self.transport.clear() - self.client.lineReceived('200 PORT OK') - self.assertEquals(self.transport.value(), 'RETR spam\r\n') - self.transport.clear() - self.client.lineReceived('226 Transfer Complete.') - return d - - - def test_failedRETR(self): - """ - Try to RETR an unexisting file. - - L{ftp.FTPClient.retrieveFile} should return a Deferred which - errbacks with L{ftp.CommandFailed} if the server indicates the file - cannot be transferred for some reason. - """ - def cbConnect(host, port, factory): - self.assertEquals(host, '127.0.0.1') - self.assertEquals(port, 12345) - proto = factory.buildProtocol((host, port)) - proto.makeConnection(proto_helpers.StringTransport()) - self.client.lineReceived( - '150 File status okay; about to open data connection.') - proto.connectionLost(failure.Failure(error.ConnectionDone(""))) - - self.client.connectFactory = cbConnect - self._testLogin() - proto = _BufferingProtocol() - d = self.client.retrieveFile("spam", proto) - self.assertFailure(d, ftp.CommandFailed) - self.assertEquals(self.transport.value(), 'PASV\r\n') - self.transport.clear() - self.client.lineReceived('227 Entering Passive Mode (%s).' % - (ftp.encodeHostPort('127.0.0.1', 12345),)) - self.assertEquals(self.transport.value(), 'RETR spam\r\n') - self.transport.clear() - self.client.lineReceived('550 spam: No such file or directory') - return d - - - def test_lostRETR(self): - """ - Try a RETR, but disconnect during the transfer. - L{ftp.FTPClient.retrieveFile} should return a Deferred which - errbacks with L{ftp.ConnectionLost) - """ - self.client.passive = False - - l = [] - def generatePort(portCmd): - portCmd.text = 'PORT %s' % (ftp.encodeHostPort('127.0.0.1', 9876),) - tr = proto_helpers.StringTransportWithDisconnection() - portCmd.protocol.makeConnection(tr) - tr.protocol = portCmd.protocol - portCmd.protocol.dataReceived("x" * 500) - l.append(tr) - - self.client.generatePortCommand = generatePort - self._testLogin() - proto = _BufferingProtocol() - d = self.client.retrieveFile("spam", proto) - self.assertEquals(self.transport.value(), 'PORT %s\r\n' % - (ftp.encodeHostPort('127.0.0.1', 9876),)) - self.transport.clear() - self.client.lineReceived('200 PORT OK') - self.assertEquals(self.transport.value(), 'RETR spam\r\n') - - self.assert_(l) - l[0].loseConnection() - self.transport.loseConnection() - self.assertFailure(d, ftp.ConnectionLost) - return d - - - def test_passiveSTOR(self): - """ - Test the STOR command: send a file and verify its content. - - L{ftp.FTPClient.storeFile} should return a two-tuple of Deferreds. - The first of which should fire with a protocol instance when the - data connection has been established and is responsible for sending - the contents of the file. The second of which should fire when the - upload has completed, the data connection has been closed, and the - server has acknowledged receipt of the file. - - (XXX - storeFile should take a producer as an argument, instead, and - only return a Deferred which fires when the upload has succeeded or - failed). - """ - tr = proto_helpers.StringTransport() - def cbStore(sender): - self.client.lineReceived( - '150 File status okay; about to open data connection.') - sender.transport.write("x" * 1000) - sender.finish() - sender.connectionLost(failure.Failure(error.ConnectionDone(""))) - - def cbFinish(ign): - self.assertEquals(tr.value(), "x" * 1000) - - def cbConnect(host, port, factory): - self.assertEquals(host, '127.0.0.1') - self.assertEquals(port, 12345) - proto = factory.buildProtocol((host, port)) - proto.makeConnection(tr) - - self.client.connectFactory = cbConnect - self._testLogin() - d1, d2 = self.client.storeFile("spam") - d1.addCallback(cbStore) - d2.addCallback(cbFinish) - self.assertEquals(self.transport.value(), 'PASV\r\n') - self.transport.clear() - self.client.lineReceived('227 Entering Passive Mode (%s).' % - (ftp.encodeHostPort('127.0.0.1', 12345),)) - self.assertEquals(self.transport.value(), 'STOR spam\r\n') - self.transport.clear() - self.client.lineReceived('226 Transfer Complete.') - return defer.gatherResults([d1, d2]) - - - def test_failedSTOR(self): - """ - Test a failure in the STOR command. - - If the server does not acknowledge successful receipt of the - uploaded file, the second Deferred returned by - L{ftp.FTPClient.storeFile} should errback with L{ftp.CommandFailed}. - """ - tr = proto_helpers.StringTransport() - def cbStore(sender): - self.client.lineReceived( - '150 File status okay; about to open data connection.') - sender.transport.write("x" * 1000) - sender.finish() - sender.connectionLost(failure.Failure(error.ConnectionDone(""))) - - def cbConnect(host, port, factory): - self.assertEquals(host, '127.0.0.1') - self.assertEquals(port, 12345) - proto = factory.buildProtocol((host, port)) - proto.makeConnection(tr) - - self.client.connectFactory = cbConnect - self._testLogin() - d1, d2 = self.client.storeFile("spam") - d1.addCallback(cbStore) - self.assertFailure(d2, ftp.CommandFailed) - self.assertEquals(self.transport.value(), 'PASV\r\n') - self.transport.clear() - self.client.lineReceived('227 Entering Passive Mode (%s).' % - (ftp.encodeHostPort('127.0.0.1', 12345),)) - self.assertEquals(self.transport.value(), 'STOR spam\r\n') - self.transport.clear() - self.client.lineReceived( - '426 Transfer aborted. Data connection closed.') - return defer.gatherResults([d1, d2]) - - - def test_STOR(self): - """ - Test the STOR command in non-passive mode. - - Like L{test_passiveSTOR} but in the configuration where the server - establishes the data connection to the client, rather than the other - way around. - """ - tr = proto_helpers.StringTransport() - self.client.passive = False - def generatePort(portCmd): - portCmd.text = 'PORT %s' % ftp.encodeHostPort('127.0.0.1', 9876) - portCmd.protocol.makeConnection(tr) - - def cbStore(sender): - self.assertEquals(self.transport.value(), 'PORT %s\r\n' % - (ftp.encodeHostPort('127.0.0.1', 9876),)) - self.transport.clear() - self.client.lineReceived('200 PORT OK') - self.assertEquals(self.transport.value(), 'STOR spam\r\n') - self.transport.clear() - self.client.lineReceived( - '150 File status okay; about to open data connection.') - sender.transport.write("x" * 1000) - sender.finish() - sender.connectionLost(failure.Failure(error.ConnectionDone(""))) - self.client.lineReceived('226 Transfer Complete.') - - def cbFinish(ign): - self.assertEquals(tr.value(), "x" * 1000) - - self.client.generatePortCommand = generatePort - self._testLogin() - d1, d2 = self.client.storeFile("spam") - d1.addCallback(cbStore) - d2.addCallback(cbFinish) - return defer.gatherResults([d1, d2]) - - - def test_passiveLIST(self): - """ - Test the LIST command. - - L{ftp.FTPClient.list} should return a Deferred which fires with a - protocol instance which was passed to list after the command has - succeeded. - - (XXX - This is a very unfortunate API; if my understanding is - correct, the results are always at least line-oriented, so allowing - a per-line parser function to be specified would make this simpler, - but a default implementation should really be provided which knows - how to deal with all the formats used in real servers, so - application developers never have to care about this insanity. It - would also be nice to either get back a Deferred of a list of - filenames or to be able to consume the files as they are received - (which the current API does allow, but in a somewhat inconvenient - fashion) -exarkun) - """ - def cbList(res, fileList): - fls = [f["filename"] for f in fileList.files] - expected = ["foo", "bar", "baz"] - expected.sort() - fls.sort() - self.assertEquals(fls, expected) - - def cbConnect(host, port, factory): - self.assertEquals(host, '127.0.0.1') - self.assertEquals(port, 12345) - proto = factory.buildProtocol((host, port)) - proto.makeConnection(proto_helpers.StringTransport()) - self.client.lineReceived( - '150 File status okay; about to open data connection.') - sending = [ - '-rw-r--r-- 0 spam egg 100 Oct 10 2006 foo\r\n', - '-rw-r--r-- 3 spam egg 100 Oct 10 2006 bar\r\n', - '-rw-r--r-- 4 spam egg 100 Oct 10 2006 baz\r\n', - ] - for i in sending: - proto.dataReceived(i) - proto.connectionLost(failure.Failure(error.ConnectionDone(""))) - - self.client.connectFactory = cbConnect - self._testLogin() - fileList = ftp.FTPFileListProtocol() - d = self.client.list('foo/bar', fileList).addCallback(cbList, fileList) - self.assertEquals(self.transport.value(), 'PASV\r\n') - self.transport.clear() - self.client.lineReceived('227 Entering Passive Mode (%s).' % - (ftp.encodeHostPort('127.0.0.1', 12345),)) - self.assertEquals(self.transport.value(), 'LIST foo/bar\r\n') - self.client.lineReceived('226 Transfer Complete.') - return d - - - def test_LIST(self): - """ - Test the LIST command in non-passive mode. - - Like L{test_passiveLIST} but in the configuration where the server - establishes the data connection to the client, rather than the other - way around. - """ - self.client.passive = False - def generatePort(portCmd): - portCmd.text = 'PORT %s' % (ftp.encodeHostPort('127.0.0.1', 9876),) - portCmd.protocol.makeConnection(proto_helpers.StringTransport()) - self.client.lineReceived( - '150 File status okay; about to open data connection.') - sending = [ - '-rw-r--r-- 0 spam egg 100 Oct 10 2006 foo\r\n', - '-rw-r--r-- 3 spam egg 100 Oct 10 2006 bar\r\n', - '-rw-r--r-- 4 spam egg 100 Oct 10 2006 baz\r\n', - ] - for i in sending: - portCmd.protocol.dataReceived(i) - portCmd.protocol.connectionLost( - failure.Failure(error.ConnectionDone(""))) - - def cbList(res, fileList): - fls = [f["filename"] for f in fileList.files] - expected = ["foo", "bar", "baz"] - expected.sort() - fls.sort() - self.assertEquals(fls, expected) - - self.client.generatePortCommand = generatePort - self._testLogin() - fileList = ftp.FTPFileListProtocol() - d = self.client.list('foo/bar', fileList).addCallback(cbList, fileList) - self.assertEquals(self.transport.value(), 'PORT %s\r\n' % - (ftp.encodeHostPort('127.0.0.1', 9876),)) - self.transport.clear() - self.client.lineReceived('200 PORT OK') - self.assertEquals(self.transport.value(), 'LIST foo/bar\r\n') - self.transport.clear() - self.client.lineReceived('226 Transfer Complete.') - return d - - - def test_failedLIST(self): - """ - Test a failure in LIST command. - - L{ftp.FTPClient.list} should return a Deferred which fails with - L{ftp.CommandFailed} if the server indicates the indicated path is - invalid for some reason. - """ - def cbConnect(host, port, factory): - self.assertEquals(host, '127.0.0.1') - self.assertEquals(port, 12345) - proto = factory.buildProtocol((host, port)) - proto.makeConnection(proto_helpers.StringTransport()) - self.client.lineReceived( - '150 File status okay; about to open data connection.') - proto.connectionLost(failure.Failure(error.ConnectionDone(""))) - - self.client.connectFactory = cbConnect - self._testLogin() - fileList = ftp.FTPFileListProtocol() - d = self.client.list('foo/bar', fileList) - self.assertFailure(d, ftp.CommandFailed) - self.assertEquals(self.transport.value(), 'PASV\r\n') - self.transport.clear() - self.client.lineReceived('227 Entering Passive Mode (%s).' % - (ftp.encodeHostPort('127.0.0.1', 12345),)) - self.assertEquals(self.transport.value(), 'LIST foo/bar\r\n') - self.client.lineReceived('550 foo/bar: No such file or directory') - return d - - - def test_NLST(self): - """ - Test the NLST command in non-passive mode. - - L{ftp.FTPClient.nlst} should return a Deferred which fires with a - list of filenames when the list command has completed. - """ - self.client.passive = False - def generatePort(portCmd): - portCmd.text = 'PORT %s' % (ftp.encodeHostPort('127.0.0.1', 9876),) - portCmd.protocol.makeConnection(proto_helpers.StringTransport()) - self.client.lineReceived( - '150 File status okay; about to open data connection.') - portCmd.protocol.dataReceived('foo\r\n') - portCmd.protocol.dataReceived('bar\r\n') - portCmd.protocol.dataReceived('baz\r\n') - portCmd.protocol.connectionLost( - failure.Failure(error.ConnectionDone(""))) - - def cbList(res, proto): - fls = proto.buffer.splitlines() - expected = ["foo", "bar", "baz"] - expected.sort() - fls.sort() - self.assertEquals(fls, expected) - - self.client.generatePortCommand = generatePort - self._testLogin() - lstproto = _BufferingProtocol() - d = self.client.nlst('foo/bar', lstproto).addCallback(cbList, lstproto) - self.assertEquals(self.transport.value(), 'PORT %s\r\n' % - (ftp.encodeHostPort('127.0.0.1', 9876),)) - self.transport.clear() - self.client.lineReceived('200 PORT OK') - self.assertEquals(self.transport.value(), 'NLST foo/bar\r\n') - self.client.lineReceived('226 Transfer Complete.') - return d - - - def test_passiveNLST(self): - """ - Test the NLST command. - - Like L{test_passiveNLST} but in the configuration where the server - establishes the data connection to the client, rather than the other - way around. - """ - def cbList(res, proto): - fls = proto.buffer.splitlines() - expected = ["foo", "bar", "baz"] - expected.sort() - fls.sort() - self.assertEquals(fls, expected) - - def cbConnect(host, port, factory): - self.assertEquals(host, '127.0.0.1') - self.assertEquals(port, 12345) - proto = factory.buildProtocol((host, port)) - proto.makeConnection(proto_helpers.StringTransport()) - self.client.lineReceived( - '150 File status okay; about to open data connection.') - proto.dataReceived('foo\r\n') - proto.dataReceived('bar\r\n') - proto.dataReceived('baz\r\n') - proto.connectionLost(failure.Failure(error.ConnectionDone(""))) - - self.client.connectFactory = cbConnect - self._testLogin() - lstproto = _BufferingProtocol() - d = self.client.nlst('foo/bar', lstproto).addCallback(cbList, lstproto) - self.assertEquals(self.transport.value(), 'PASV\r\n') - self.transport.clear() - self.client.lineReceived('227 Entering Passive Mode (%s).' % - (ftp.encodeHostPort('127.0.0.1', 12345),)) - self.assertEquals(self.transport.value(), 'NLST foo/bar\r\n') - self.client.lineReceived('226 Transfer Complete.') - return d - - - def test_failedNLST(self): - """ - Test a failure in NLST command. - - L{ftp.FTPClient.nlst} should return a Deferred which fails with - L{ftp.CommandFailed} if the server indicates the indicated path is - invalid for some reason. - """ - tr = proto_helpers.StringTransport() - def cbConnect(host, port, factory): - self.assertEquals(host, '127.0.0.1') - self.assertEquals(port, 12345) - proto = factory.buildProtocol((host, port)) - proto.makeConnection(tr) - self.client.lineReceived( - '150 File status okay; about to open data connection.') - proto.connectionLost(failure.Failure(error.ConnectionDone(""))) - - self.client.connectFactory = cbConnect - self._testLogin() - lstproto = _BufferingProtocol() - d = self.client.nlst('foo/bar', lstproto) - self.assertFailure(d, ftp.CommandFailed) - self.assertEquals(self.transport.value(), 'PASV\r\n') - self.transport.clear() - self.client.lineReceived('227 Entering Passive Mode (%s).' % - (ftp.encodeHostPort('127.0.0.1', 12345),)) - self.assertEquals(self.transport.value(), 'NLST foo/bar\r\n') - self.client.lineReceived('550 foo/bar: No such file or directory') - return d - - - def test_changeDirectory(self): - """ - Test the changeDirectory method. - - L{ftp.FTPClient.changeDirectory} should return a Deferred which fires - with True if succeeded. - """ - def cbCd(res): - self.assertEquals(res, True) - - self._testLogin() - d = self.client.changeDirectory("bar/foo").addCallback(cbCd) - self.assertEquals(self.transport.value(), 'CWD bar/foo\r\n') - self.client.lineReceived('250 Requested File Action Completed OK') - return d - - - def test_failedChangeDirectory(self): - """ - Test a failure in the changeDirectory method. - - The behaviour here is the same as a failed CWD. - """ - self._testLogin() - d = self.client.changeDirectory("bar/foo") - self.assertFailure(d, ftp.CommandFailed) - self.assertEquals(self.transport.value(), 'CWD bar/foo\r\n') - self.client.lineReceived('550 bar/foo: No such file or directory') - return d - - - def test_strangeFailedChangeDirectory(self): - """ - Test a strange failure in changeDirectory method. - - L{ftp.FTPClient.changeDirectory} is stricter than CWD as it checks - code 250 for success. - """ - self._testLogin() - d = self.client.changeDirectory("bar/foo") - self.assertFailure(d, ftp.CommandFailed) - self.assertEquals(self.transport.value(), 'CWD bar/foo\r\n') - self.client.lineReceived('252 I do what I want !') - return d - - - def test_getDirectory(self): - """ - Test the getDirectory method. - - L{ftp.FTPClient.getDirectory} should return a Deferred which fires with - the current directory on the server. It wraps PWD command. - """ - def cbGet(res): - self.assertEquals(res, "/bar/baz") - - self._testLogin() - d = self.client.getDirectory().addCallback(cbGet) - self.assertEquals(self.transport.value(), 'PWD\r\n') - self.client.lineReceived('257 "/bar/baz"') - return d - - - def test_failedGetDirectory(self): - """ - Test a failure in getDirectory method. - - The behaviour should be the same as PWD. - """ - self._testLogin() - d = self.client.getDirectory() - self.assertFailure(d, ftp.CommandFailed) - self.assertEquals(self.transport.value(), 'PWD\r\n') - self.client.lineReceived('550 /bar/baz: No such file or directory') - return d - - - def test_anotherFailedGetDirectory(self): - """ - Test a different failure in getDirectory method. - - The response should be quoted to be parsed, so it returns an error - otherwise. - """ - self._testLogin() - d = self.client.getDirectory() - self.assertFailure(d, ftp.CommandFailed) - self.assertEquals(self.transport.value(), 'PWD\r\n') - self.client.lineReceived('257 /bar/baz') - return d - - - -class DummyTransport: - def write(self, bytes): - pass - -class BufferingTransport: - buffer = '' - def write(self, bytes): - self.buffer += bytes - - -class FTPClientBasicTests(unittest.TestCase): - - def testGreeting(self): - # The first response is captured as a greeting. - ftpClient = ftp.FTPClientBasic() - ftpClient.lineReceived('220 Imaginary FTP.') - self.failUnlessEqual(['220 Imaginary FTP.'], ftpClient.greeting) - - def testResponseWithNoMessage(self): - # Responses with no message are still valid, i.e. three digits followed - # by a space is complete response. - ftpClient = ftp.FTPClientBasic() - ftpClient.lineReceived('220 ') - self.failUnlessEqual(['220 '], ftpClient.greeting) - - def testMultilineResponse(self): - ftpClient = ftp.FTPClientBasic() - ftpClient.transport = DummyTransport() - ftpClient.lineReceived('220 Imaginary FTP.') - - # Queue (and send) a dummy command, and set up a callback to capture the - # result - deferred = ftpClient.queueStringCommand('BLAH') - result = [] - deferred.addCallback(result.append) - deferred.addErrback(self.fail) - - # Send the first line of a multiline response. - ftpClient.lineReceived('210-First line.') - self.failUnlessEqual([], result) - - # Send a second line, again prefixed with "nnn-". - ftpClient.lineReceived('123-Second line.') - self.failUnlessEqual([], result) - - # Send a plain line of text, no prefix. - ftpClient.lineReceived('Just some text.') - self.failUnlessEqual([], result) - - # Now send a short (less than 4 chars) line. - ftpClient.lineReceived('Hi') - self.failUnlessEqual([], result) - - # Now send an empty line. - ftpClient.lineReceived('') - self.failUnlessEqual([], result) - - # And a line with 3 digits in it, and nothing else. - ftpClient.lineReceived('321') - self.failUnlessEqual([], result) - - # Now finish it. - ftpClient.lineReceived('210 Done.') - self.failUnlessEqual( - ['210-First line.', - '123-Second line.', - 'Just some text.', - 'Hi', - '', - '321', - '210 Done.'], result[0]) - - def testNoPasswordGiven(self): - """Passing None as the password avoids sending the PASS command.""" - # Create a client, and give it a greeting. - ftpClient = ftp.FTPClientBasic() - ftpClient.transport = BufferingTransport() - ftpClient.lineReceived('220 Welcome to Imaginary FTP.') - - # Queue a login with no password - ftpClient.queueLogin('bob', None) - self.failUnlessEqual('USER bob\r\n', ftpClient.transport.buffer) - - # Clear the test buffer, acknowledge the USER command. - ftpClient.transport.buffer = '' - ftpClient.lineReceived('200 Hello bob.') - - # The client shouldn't have sent anything more (i.e. it shouldn't have - # sent a PASS command). - self.failUnlessEqual('', ftpClient.transport.buffer) - - def testNoPasswordNeeded(self): - """Receiving a 230 response to USER prevents PASS from being sent.""" - # Create a client, and give it a greeting. - ftpClient = ftp.FTPClientBasic() - ftpClient.transport = BufferingTransport() - ftpClient.lineReceived('220 Welcome to Imaginary FTP.') - - # Queue a login with no password - ftpClient.queueLogin('bob', 'secret') - self.failUnlessEqual('USER bob\r\n', ftpClient.transport.buffer) - - # Clear the test buffer, acknowledge the USER command with a 230 - # response code. - ftpClient.transport.buffer = '' - ftpClient.lineReceived('230 Hello bob. No password needed.') - - # The client shouldn't have sent anything more (i.e. it shouldn't have - # sent a PASS command). - self.failUnlessEqual('', ftpClient.transport.buffer) - - -class PathHandling(unittest.TestCase): - def testNormalizer(self): - for inp, outp in [('a', ['a']), - ('/a', ['a']), - ('/', []), - ('a/b/c', ['a', 'b', 'c']), - ('/a/b/c', ['a', 'b', 'c']), - ('/a/', ['a']), - ('a/', ['a'])]: - self.assertEquals(ftp.toSegments([], inp), outp) - - for inp, outp in [('b', ['a', 'b']), - ('b/', ['a', 'b']), - ('/b', ['b']), - ('/b/', ['b']), - ('b/c', ['a', 'b', 'c']), - ('b/c/', ['a', 'b', 'c']), - ('/b/c', ['b', 'c']), - ('/b/c/', ['b', 'c'])]: - self.assertEquals(ftp.toSegments(['a'], inp), outp) - - for inp, outp in [('//', []), - ('//a', ['a']), - ('a//', ['a']), - ('a//b', ['a', 'b'])]: - self.assertEquals(ftp.toSegments([], inp), outp) - - for inp, outp in [('//', []), - ('//b', ['b']), - ('b//c', ['a', 'b', 'c'])]: - self.assertEquals(ftp.toSegments(['a'], inp), outp) - - for inp, outp in [('..', []), - ('../', []), - ('a/..', ['x']), - ('/a/..', []), - ('/a/b/..', ['a']), - ('/a/b/../', ['a']), - ('/a/b/../c', ['a', 'c']), - ('/a/b/../c/', ['a', 'c']), - ('/a/b/../../c', ['c']), - ('/a/b/../../c/', ['c']), - ('/a/b/../../c/..', []), - ('/a/b/../../c/../', [])]: - self.assertEquals(ftp.toSegments(['x'], inp), outp) - - for inp in ['..', '../', 'a/../..', 'a/../../', - '/..', '/../', '/a/../..', '/a/../../', - '/a/b/../../..']: - self.assertRaises(ftp.InvalidPath, ftp.toSegments, [], inp) - - for inp in ['../..', '../../', '../a/../..']: - self.assertRaises(ftp.InvalidPath, ftp.toSegments, ['x'], inp) - - - -class ErrnoToFailureTestCase(unittest.TestCase): - """ - Tests for L{ftp.errnoToFailure} errno checking. - """ - - def test_notFound(self): - """ - C{errno.ENOENT} should be translated to L{ftp.FileNotFoundError}. - """ - d = ftp.errnoToFailure(errno.ENOENT, "foo") - return self.assertFailure(d, ftp.FileNotFoundError) - - - def test_permissionDenied(self): - """ - C{errno.EPERM} should be translated to L{ftp.PermissionDeniedError}. - """ - d = ftp.errnoToFailure(errno.EPERM, "foo") - return self.assertFailure(d, ftp.PermissionDeniedError) - - - def test_accessDenied(self): - """ - C{errno.EACCES} should be translated to L{ftp.PermissionDeniedError}. - """ - d = ftp.errnoToFailure(errno.EACCES, "foo") - return self.assertFailure(d, ftp.PermissionDeniedError) - - - def test_notDirectory(self): - """ - C{errno.ENOTDIR} should be translated to L{ftp.IsNotADirectoryError}. - """ - d = ftp.errnoToFailure(errno.ENOTDIR, "foo") - return self.assertFailure(d, ftp.IsNotADirectoryError) - - - def test_fileExists(self): - """ - C{errno.EEXIST} should be translated to L{ftp.FileExistsError}. - """ - d = ftp.errnoToFailure(errno.EEXIST, "foo") - return self.assertFailure(d, ftp.FileExistsError) - - - def test_isDirectory(self): - """ - C{errno.EISDIR} should be translated to L{ftp.IsADirectoryError}. - """ - d = ftp.errnoToFailure(errno.EISDIR, "foo") - return self.assertFailure(d, ftp.IsADirectoryError) - - - def test_passThrough(self): - """ - If an unknown errno is passed to L{ftp.errnoToFailure}, it should let - the originating exception pass through. - """ - try: - raise RuntimeError("bar") - except: - d = ftp.errnoToFailure(-1, "foo") - return self.assertFailure(d, RuntimeError) - - - -class AnonymousFTPShellTestCase(unittest.TestCase): - """ - Test anynomous shell properties. - """ - - def test_anonymousWrite(self): - """ - Check that L{ftp.FTPAnonymousShell} returns an error when trying to - open it in write mode. - """ - shell = ftp.FTPAnonymousShell('') - d = shell.openForWriting(('foo',)) - self.assertFailure(d, ftp.PermissionDeniedError) - return d - - - -class IFTPShellTestsMixin: - """ - Generic tests for the C{IFTPShell} interface. - """ - - def directoryExists(self, path): - """ - Test if the directory exists at C{path}. - - @param path: the relative path to check. - @type path: C{str}. - - @return: C{True} if C{path} exists and is a directory, C{False} if - it's not the case - @rtype: C{bool} - """ - raise NotImplementedError() - - - def createDirectory(self, path): - """ - Create a directory in C{path}. - - @param path: the relative path of the directory to create, with one - segment. - @type path: C{str} - """ - raise NotImplementedError() - - - def fileExists(self, path): - """ - Test if the file exists at C{path}. - - @param path: the relative path to check. - @type path: C{str}. - - @return: C{True} if C{path} exists and is a file, C{False} if it's not - the case. - @rtype: C{bool} - """ - raise NotImplementedError() - - - def createFile(self, path, fileContent=''): - """ - Create a file named C{path} with some content. - - @param path: the relative path of the file to create, without - directory. - @type path: C{str} - - @param fileContent: the content of the file. - @type fileContent: C{str} - """ - raise NotImplementedError() - - - def test_createDirectory(self): - """ - C{directoryExists} should report correctly about directory existence, - and C{createDirectory} should create a directory detectable by - C{directoryExists}. - """ - self.assertFalse(self.directoryExists('bar')) - self.createDirectory('bar') - self.assertTrue(self.directoryExists('bar')) - - - def test_createFile(self): - """ - C{fileExists} should report correctly about file existence, and - C{createFile} should create a file detectable by C{fileExists}. - """ - self.assertFalse(self.fileExists('file.txt')) - self.createFile('file.txt') - self.assertTrue(self.fileExists('file.txt')) - - - def test_makeDirectory(self): - """ - Create a directory and check it ends in the filesystem. - """ - d = self.shell.makeDirectory(('foo',)) - def cb(result): - self.assertTrue(self.directoryExists('foo')) - return d.addCallback(cb) - - - def test_makeDirectoryError(self): - """ - Creating a directory that already exists should fail with a - C{ftp.FileExistsError}. - """ - self.createDirectory('foo') - d = self.shell.makeDirectory(('foo',)) - return self.assertFailure(d, ftp.FileExistsError) - - - def test_removeDirectory(self): - """ - Try to remove a directory and check it's removed from the filesystem. - """ - self.createDirectory('bar') - d = self.shell.removeDirectory(('bar',)) - def cb(result): - self.assertFalse(self.directoryExists('bar')) - return d.addCallback(cb) - - - def test_removeDirectoryOnFile(self): - """ - removeDirectory should not work in file and fail with a - C{ftp.IsNotADirectoryError}. - """ - self.createFile('file.txt') - d = self.shell.removeDirectory(('file.txt',)) - return self.assertFailure(d, ftp.IsNotADirectoryError) - - - def test_removeNotExistingDirectory(self): - """ - Removing directory that doesn't exist should fail with a - C{ftp.FileNotFoundError}. - """ - d = self.shell.removeDirectory(('bar',)) - return self.assertFailure(d, ftp.FileNotFoundError) - - - def test_removeFile(self): - """ - Try to remove a file and check it's removed from the filesystem. - """ - self.createFile('file.txt') - d = self.shell.removeFile(('file.txt',)) - def cb(res): - self.assertFalse(self.fileExists('file.txt')) - d.addCallback(cb) - return d - - - def test_removeFileOnDirectory(self): - """ - removeFile should not work on directory. - """ - self.createDirectory('ned') - d = self.shell.removeFile(('ned',)) - return self.assertFailure(d, ftp.IsADirectoryError) - - - def test_removeNotExistingFile(self): - """ - Try to remove a non existent file, and check it raises a - L{ivfs.NotFoundError}. - """ - d = self.shell.removeFile(('foo',)) - return self.assertFailure(d, ftp.FileNotFoundError) - - - def test_list(self): - """ - Check the output of the list method. - """ - self.createDirectory('ned') - self.createFile('file.txt') - d = self.shell.list(('.',)) - def cb(l): - l.sort() - self.assertEquals(l, - [('file.txt', []), ('ned', [])]) - return d.addCallback(cb) - - - def test_listWithStat(self): - """ - Check the output of list with asked stats. - """ - self.createDirectory('ned') - self.createFile('file.txt') - d = self.shell.list(('.',), ('size', 'permissions',)) - def cb(l): - l.sort() - self.assertEquals(len(l), 2) - self.assertEquals(l[0][0], 'file.txt') - self.assertEquals(l[1][0], 'ned') - # Size and permissions are reported differently between platforms - # so just check they are present - self.assertEquals(len(l[0][1]), 2) - self.assertEquals(len(l[1][1]), 2) - return d.addCallback(cb) - - - def test_listWithInvalidStat(self): - """ - Querying an invalid stat should result to a C{AttributeError}. - """ - self.createDirectory('ned') - d = self.shell.list(('.',), ('size', 'whateverstat',)) - return self.assertFailure(d, AttributeError) - - - def test_listFile(self): - """ - Check the output of the list method on a file. - """ - self.createFile('file.txt') - d = self.shell.list(('file.txt',)) - def cb(l): - l.sort() - self.assertEquals(l, - [('file.txt', [])]) - return d.addCallback(cb) - - - def test_listNotExistingDirectory(self): - """ - list on a directory that doesn't exist should fail with a - L{ftp.FileNotFoundError}. - """ - d = self.shell.list(('foo',)) - return self.assertFailure(d, ftp.FileNotFoundError) - - - def test_access(self): - """ - Try to access a resource. - """ - self.createDirectory('ned') - d = self.shell.access(('ned',)) - return d - - - def test_accessNotFound(self): - """ - access should fail on a resource that doesn't exist. - """ - d = self.shell.access(('foo',)) - return self.assertFailure(d, ftp.FileNotFoundError) - - - def test_openForReading(self): - """ - Check that openForReading returns an object providing C{ftp.IReadFile}. - """ - self.createFile('file.txt') - d = self.shell.openForReading(('file.txt',)) - def cb(res): - self.assertTrue(ftp.IReadFile.providedBy(res)) - d.addCallback(cb) - return d - - - def test_openForReadingNotFound(self): - """ - openForReading should fail with a C{ftp.FileNotFoundError} on a file - that doesn't exist. - """ - d = self.shell.openForReading(('ned',)) - return self.assertFailure(d, ftp.FileNotFoundError) - - - def test_openForReadingOnDirectory(self): - """ - openForReading should not work on directory. - """ - self.createDirectory('ned') - d = self.shell.openForReading(('ned',)) - return self.assertFailure(d, ftp.IsADirectoryError) - - - def test_openForWriting(self): - """ - Check that openForWriting returns an object providing C{ftp.IWriteFile}. - """ - d = self.shell.openForWriting(('foo',)) - def cb1(res): - self.assertTrue(ftp.IWriteFile.providedBy(res)) - return res.receive().addCallback(cb2) - def cb2(res): - self.assertTrue(IConsumer.providedBy(res)) - d.addCallback(cb1) - return d - - - def test_openForWritingExistingDirectory(self): - """ - openForWriting should not be able to open a directory that already - exists. - """ - self.createDirectory('ned') - d = self.shell.openForWriting(('ned',)) - return self.assertFailure(d, ftp.IsADirectoryError) - - - def test_openForWritingInNotExistingDirectory(self): - """ - openForWring should fail with a L{ftp.FileNotFoundError} if you specify - a file in a directory that doesn't exist. - """ - self.createDirectory('ned') - d = self.shell.openForWriting(('ned', 'idonotexist', 'foo')) - return self.assertFailure(d, ftp.FileNotFoundError) - - - def test_statFile(self): - """ - Check the output of the stat method on a file. - """ - fileContent = 'wobble\n' - self.createFile('file.txt', fileContent) - d = self.shell.stat(('file.txt',), ('size', 'directory')) - def cb(res): - self.assertEquals(res[0], len(fileContent)) - self.assertFalse(res[1]) - d.addCallback(cb) - return d - - - def test_statDirectory(self): - """ - Check the output of the stat method on a directory. - """ - self.createDirectory('ned') - d = self.shell.stat(('ned',), ('size', 'directory')) - def cb(res): - self.assertTrue(res[1]) - d.addCallback(cb) - return d - - - def test_statOwnerGroup(self): - """ - Check the owner and groups stats. - """ - self.createDirectory('ned') - d = self.shell.stat(('ned',), ('owner', 'group')) - def cb(res): - self.assertEquals(len(res), 2) - d.addCallback(cb) - return d - - - def test_statNotExisting(self): - """ - stat should fail with L{ftp.FileNotFoundError} on a file that doesn't - exist. - """ - d = self.shell.stat(('foo',), ('size', 'directory')) - return self.assertFailure(d, ftp.FileNotFoundError) - - - def test_invalidStat(self): - """ - Querying an invalid stat should result to a C{AttributeError}. - """ - self.createDirectory('ned') - d = self.shell.stat(('ned',), ('size', 'whateverstat')) - return self.assertFailure(d, AttributeError) - - - def test_rename(self): - """ - Try to rename a directory. - """ - self.createDirectory('ned') - d = self.shell.rename(('ned',), ('foo',)) - def cb(res): - self.assertTrue(self.directoryExists('foo')) - self.assertFalse(self.directoryExists('ned')) - return d.addCallback(cb) - - - def test_renameNotExisting(self): - """ - Renaming a directory that doesn't exist should fail with - L{ftp.FileNotFoundError}. - """ - d = self.shell.rename(('foo',), ('bar',)) - return self.assertFailure(d, ftp.FileNotFoundError) - - - -class FTPShellTestCase(unittest.TestCase, IFTPShellTestsMixin): - """ - Tests for the C{ftp.FTPShell} object. - """ - - def setUp(self): - """ - Create a root directory and instantiate a shell. - """ - self.root = filepath.FilePath(self.mktemp()) - self.root.createDirectory() - self.shell = ftp.FTPShell(self.root) - - - def directoryExists(self, path): - """ - Test if the directory exists at C{path}. - """ - return self.root.child(path).isdir() - - - def createDirectory(self, path): - """ - Create a directory in C{path}. - """ - return self.root.child(path).createDirectory() - - - def fileExists(self, path): - """ - Test if the file exists at C{path}. - """ - return self.root.child(path).isfile() - - - def createFile(self, path, fileContent=''): - """ - Create a file named C{path} with some content. - """ - return self.root.child(path).setContent(fileContent) - - - -class TestConsumer(object): - """ - A simple consumer for tests. It only works with non-streaming producers. - - @ivar producer: an object providing - L{twisted.internet.interfaces.IPullProducer}. - """ - - implements(IConsumer) - producer = None - - def registerProducer(self, producer, streaming): - """ - Simple register of producer, checks that no register has happened - before. - """ - assert self.producer is None - self.buffer = [] - self.producer = producer - self.producer.resumeProducing() - - - def unregisterProducer(self): - """ - Unregister the producer, it should be done after a register. - """ - assert self.producer is not None - self.producer = None - - - def write(self, data): - """ - Save the data received. - """ - self.buffer.append(data) - self.producer.resumeProducing() - - - -class TestProducer(object): - """ - A dumb producer. - """ - - def __init__(self, toProduce, consumer): - """ - @param toProduce: data to write - @type toProduce: C{str} - @param consumer: the consumer of data. - @type consumer: C{IConsumer} - """ - self.toProduce = toProduce - self.consumer = consumer - - - def start(self): - """ - Send the data to consume. - """ - self.consumer.write(self.toProduce) - - - -class IReadWriteTestsMixin: - """ - Generic tests for the C{IReadFile} and C{IWriteFile} interfaces. - """ - - def getFileReader(self, content): - """ - Return an object providing C{IReadFile}, ready to send data C{content}. - """ - raise NotImplementedError() - - - def getFileWriter(self): - """ - Return an object providing C{IWriteFile}, ready to receive data. - """ - raise NotImplementedError() - - - def getFileContent(self): - """ - Return the content of the file used. - """ - raise NotImplementedError() - - - def test_read(self): - """ - Test L{ftp.IReadFile}: the implementation should have a send method - returning a C{Deferred} which fires when all the data has been sent - to the consumer, and the data should be correctly send to the consumer. - """ - content = 'wobble\n' - consumer = TestConsumer() - def cbGet(reader): - return reader.send(consumer).addCallback(cbSend) - def cbSend(res): - self.assertEquals("".join(consumer.buffer), content) - return self.getFileReader(content).addCallback(cbGet) - - - def test_write(self): - """ - Test L{ftp.IWriteFile}: the implementation should have a receive method - returning a C{Deferred} with fires with a consumer ready to receive - data to be written. - """ - content = 'elbbow\n' - def cbGet(writer): - return writer.receive().addCallback(cbReceive) - def cbReceive(consumer): - producer = TestProducer(content, consumer) - consumer.registerProducer(None, True) - producer.start() - consumer.unregisterProducer() - self.assertEquals(self.getFileContent(), content) - return self.getFileWriter().addCallback(cbGet) - - - -class FTPReadWriteTestCase(unittest.TestCase, IReadWriteTestsMixin): - """ - Tests for C{ftp._FileReader} and C{ftp._FileWriter}, the objects returned - by the shell in C{openForReading}/C{openForWriting}. - """ - - def setUp(self): - """ - Create a temporary file used later. - """ - self.root = filepath.FilePath(self.mktemp()) - self.root.createDirectory() - self.shell = ftp.FTPShell(self.root) - self.filename = "file.txt" - - - def getFileReader(self, content): - """ - Return a C{ftp._FileReader} instance with a file opened for reading. - """ - self.root.child(self.filename).setContent(content) - return self.shell.openForReading((self.filename,)) - - - def getFileWriter(self): - """ - Return a C{ftp._FileWriter} instance with a file opened for writing. - """ - return self.shell.openForWriting((self.filename,)) - - - def getFileContent(self): - """ - Return the content of the temporary file. - """ - return self.root.child(self.filename).getContent() - diff --git a/tools/buildbot/pylibs/twisted/test/test_hook.py b/tools/buildbot/pylibs/twisted/test/test_hook.py deleted file mode 100644 index 0118df1..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_hook.py +++ /dev/null @@ -1,150 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Test cases for twisted.hook module. -""" - -from twisted.python import hook -from twisted.trial import unittest - -class BaseClass: - """ - dummy class to help in testing. - """ - def __init__(self): - """ - dummy initializer - """ - self.calledBasePre = 0 - self.calledBasePost = 0 - self.calledBase = 0 - - def func(self, a, b): - """ - dummy method - """ - assert a == 1 - assert b == 2 - self.calledBase = self.calledBase + 1 - - -class SubClass(BaseClass): - """ - another dummy class - """ - def __init__(self): - """ - another dummy initializer - """ - BaseClass.__init__(self) - self.calledSubPre = 0 - self.calledSubPost = 0 - self.calledSub = 0 - - def func(self, a, b): - """ - another dummy function - """ - assert a == 1 - assert b == 2 - BaseClass.func(self, a, b) - self.calledSub = self.calledSub + 1 - -_clean_BaseClass = BaseClass.__dict__.copy() -_clean_SubClass = SubClass.__dict__.copy() - -def basePre(base, a, b): - """ - a pre-hook for the base class - """ - base.calledBasePre = base.calledBasePre + 1 - -def basePost(base, a, b): - """ - a post-hook for the base class - """ - base.calledBasePost = base.calledBasePost + 1 - -def subPre(sub, a, b): - """ - a pre-hook for the subclass - """ - sub.calledSubPre = sub.calledSubPre + 1 - -def subPost(sub, a, b): - """ - a post-hook for the subclass - """ - sub.calledSubPost = sub.calledSubPost + 1 - -class HookTestCase(unittest.TestCase): - """ - test case to make sure hooks are called - """ - def setUp(self): - """Make sure we have clean versions of our classes.""" - BaseClass.__dict__.clear() - BaseClass.__dict__.update(_clean_BaseClass) - SubClass.__dict__.clear() - SubClass.__dict__.update(_clean_SubClass) - - def testBaseHook(self): - """make sure that the base class's hook is called reliably - """ - base = BaseClass() - self.assertEquals(base.calledBase, 0) - self.assertEquals(base.calledBasePre, 0) - base.func(1,2) - self.assertEquals(base.calledBase, 1) - self.assertEquals(base.calledBasePre, 0) - hook.addPre(BaseClass, "func", basePre) - base.func(1, b=2) - self.assertEquals(base.calledBase, 2) - self.assertEquals(base.calledBasePre, 1) - hook.addPost(BaseClass, "func", basePost) - base.func(1, b=2) - self.assertEquals(base.calledBasePost, 1) - self.assertEquals(base.calledBase, 3) - self.assertEquals(base.calledBasePre, 2) - hook.removePre(BaseClass, "func", basePre) - hook.removePost(BaseClass, "func", basePost) - base.func(1, b=2) - self.assertEquals(base.calledBasePost, 1) - self.assertEquals(base.calledBase, 4) - self.assertEquals(base.calledBasePre, 2) - - def testSubHook(self): - """test interactions between base-class hooks and subclass hooks - """ - sub = SubClass() - self.assertEquals(sub.calledSub, 0) - self.assertEquals(sub.calledBase, 0) - sub.func(1, b=2) - self.assertEquals(sub.calledSub, 1) - self.assertEquals(sub.calledBase, 1) - hook.addPre(SubClass, 'func', subPre) - self.assertEquals(sub.calledSub, 1) - self.assertEquals(sub.calledBase, 1) - self.assertEquals(sub.calledSubPre, 0) - self.assertEquals(sub.calledBasePre, 0) - sub.func(1, b=2) - self.assertEquals(sub.calledSub, 2) - self.assertEquals(sub.calledBase, 2) - self.assertEquals(sub.calledSubPre, 1) - self.assertEquals(sub.calledBasePre, 0) - # let the pain begin - hook.addPre(BaseClass, 'func', basePre) - BaseClass.func(sub, 1, b=2) - # sub.func(1, b=2) - self.assertEquals(sub.calledBase, 3) - self.assertEquals(sub.calledBasePre, 1, str(sub.calledBasePre)) - sub.func(1, b=2) - self.assertEquals(sub.calledBasePre, 2) - self.assertEquals(sub.calledBase, 4) - self.assertEquals(sub.calledSubPre, 2) - self.assertEquals(sub.calledSub, 3) - -testCases = [HookTestCase] diff --git a/tools/buildbot/pylibs/twisted/test/test_htb.py b/tools/buildbot/pylibs/twisted/test/test_htb.py deleted file mode 100644 index 72dc513..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_htb.py +++ /dev/null @@ -1,96 +0,0 @@ -# -*- Python -*- - -__version__ = '$Revision: 1.3 $'[11:-2] - -from twisted.trial import unittest -from twisted.protocols import htb - -class DummyClock: - time = 0 - def set(self, when): - self.time = when - - def __call__(self): - return self.time - -class SomeBucket(htb.Bucket): - maxburst = 100 - rate = 2 - -class TestBucketBase(unittest.TestCase): - def setUp(self): - self._realTimeFunc = htb.time - self.clock = DummyClock() - htb.time = self.clock - - def tearDown(self): - htb.time = self._realTimeFunc - -class TestBucket(TestBucketBase): - def testBucketSize(self): - """Testing the size of the bucket.""" - b = SomeBucket() - fit = b.add(1000) - self.failUnlessEqual(100, fit) - - def testBucketDrian(self): - """Testing the bucket's drain rate.""" - b = SomeBucket() - fit = b.add(1000) - self.clock.set(10) - fit = b.add(1000) - self.failUnlessEqual(20, fit) - -class TestBucketNesting(TestBucketBase): - def setUp(self): - TestBucketBase.setUp(self) - self.parent = SomeBucket() - self.child1 = SomeBucket(self.parent) - self.child2 = SomeBucket(self.parent) - - def testBucketParentSize(self): - # Use up most of the parent bucket. - self.child1.add(90) - fit = self.child2.add(90) - self.failUnlessEqual(10, fit) - - def testBucketParentRate(self): - # Make the parent bucket drain slower. - self.parent.rate = 1 - # Fill both child1 and parent. - self.child1.add(100) - self.clock.set(10) - fit = self.child1.add(100) - # How much room was there? The child bucket would have had 20, - # but the parent bucket only ten (so no, it wouldn't make too much - # sense to have a child bucket draining faster than its parent in a real - # application.) - self.failUnlessEqual(10, fit) - - -# TODO: Test the Transport stuff? - -from test_pcp import DummyConsumer - -class ConsumerShaperTest(TestBucketBase): - def setUp(self): - TestBucketBase.setUp(self) - self.underlying = DummyConsumer() - self.bucket = SomeBucket() - self.shaped = htb.ShapedConsumer(self.underlying, self.bucket) - - def testRate(self): - # Start off with a full bucket, so the burst-size dosen't factor in - # to the calculations. - delta_t = 10 - self.bucket.add(100) - self.shaped.write("x" * 100) - self.clock.set(delta_t) - self.shaped.resumeProducing() - self.failUnlessEqual(len(self.underlying.getvalue()), - delta_t * self.bucket.rate) - - def testBucketRefs(self): - self.failUnlessEqual(self.bucket._refcount, 1) - self.shaped.stopProducing() - self.failUnlessEqual(self.bucket._refcount, 0) diff --git a/tools/buildbot/pylibs/twisted/test/test_ident.py b/tools/buildbot/pylibs/twisted/test/test_ident.py deleted file mode 100644 index 91f4243..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_ident.py +++ /dev/null @@ -1,194 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Test cases for twisted.protocols.ident module. -""" - -import struct - -from twisted.protocols import ident -from twisted.python import failure -from twisted.internet import error -from twisted.internet import defer - -from twisted.trial import unittest -from twisted.test.proto_helpers import StringTransport - - - -class ClassParserTestCase(unittest.TestCase): - """ - Test parsing of ident responses. - """ - - def setUp(self): - """ - Create a ident client used in tests. - """ - self.client = ident.IdentClient() - - - def test_indentError(self): - """ - 'UNKNOWN-ERROR' error should map to the L{ident.IdentError} exception. - """ - d = defer.Deferred() - self.client.queries.append((d, 123, 456)) - self.client.lineReceived('123, 456 : ERROR : UNKNOWN-ERROR') - return self.assertFailure(d, ident.IdentError) - - - def test_noUSerError(self): - """ - 'NO-USER' error should map to the L{ident.NoUser} exception. - """ - d = defer.Deferred() - self.client.queries.append((d, 234, 456)) - self.client.lineReceived('234, 456 : ERROR : NO-USER') - return self.assertFailure(d, ident.NoUser) - - - def test_invalidPortError(self): - """ - 'INVALID-PORT' error should map to the L{ident.InvalidPort} exception. - """ - d = defer.Deferred() - self.client.queries.append((d, 345, 567)) - self.client.lineReceived('345, 567 : ERROR : INVALID-PORT') - return self.assertFailure(d, ident.InvalidPort) - - - def test_hiddenUserError(self): - """ - 'HIDDEN-USER' error should map to the L{ident.HiddenUser} exception. - """ - d = defer.Deferred() - self.client.queries.append((d, 567, 789)) - self.client.lineReceived('567, 789 : ERROR : HIDDEN-USER') - return self.assertFailure(d, ident.HiddenUser) - - - def test_lostConnection(self): - """ - A pending query which failed because of a ConnectionLost should - receive an L{ident.IdentError}. - """ - d = defer.Deferred() - self.client.queries.append((d, 765, 432)) - self.client.connectionLost(failure.Failure(error.ConnectionLost())) - return self.assertFailure(d, ident.IdentError) - - - -class TestIdentServer(ident.IdentServer): - def lookup(self, serverAddress, clientAddress): - return self.resultValue - - -class TestErrorIdentServer(ident.IdentServer): - def lookup(self, serverAddress, clientAddress): - raise self.exceptionType() - - -class NewException(RuntimeError): - pass - - -class ServerParserTestCase(unittest.TestCase): - def testErrors(self): - p = TestErrorIdentServer() - p.makeConnection(StringTransport()) - L = [] - p.sendLine = L.append - - p.exceptionType = ident.IdentError - p.lineReceived('123, 345') - self.assertEquals(L[0], '123, 345 : ERROR : UNKNOWN-ERROR') - - p.exceptionType = ident.NoUser - p.lineReceived('432, 210') - self.assertEquals(L[1], '432, 210 : ERROR : NO-USER') - - p.exceptionType = ident.InvalidPort - p.lineReceived('987, 654') - self.assertEquals(L[2], '987, 654 : ERROR : INVALID-PORT') - - p.exceptionType = ident.HiddenUser - p.lineReceived('756, 827') - self.assertEquals(L[3], '756, 827 : ERROR : HIDDEN-USER') - - p.exceptionType = NewException - p.lineReceived('987, 789') - self.assertEquals(L[4], '987, 789 : ERROR : UNKNOWN-ERROR') - errs = self.flushLoggedErrors(NewException) - self.assertEquals(len(errs), 1) - - for port in -1, 0, 65536, 65537: - del L[:] - p.lineReceived('%d, 5' % (port,)) - p.lineReceived('5, %d' % (port,)) - self.assertEquals( - L, ['%d, 5 : ERROR : INVALID-PORT' % (port,), - '5, %d : ERROR : INVALID-PORT' % (port,)]) - - def testSuccess(self): - p = TestIdentServer() - p.makeConnection(StringTransport()) - L = [] - p.sendLine = L.append - - p.resultValue = ('SYS', 'USER') - p.lineReceived('123, 456') - self.assertEquals(L[0], '123, 456 : USERID : SYS : USER') - - -if struct.pack('=L', 1)[0] == '\x01': - _addr1 = '0100007F' - _addr2 = '04030201' -else: - _addr1 = '7F000001' - _addr2 = '01020304' - - -class ProcMixinTestCase(unittest.TestCase): - line = ('4: %s:0019 %s:02FA 0A 00000000:00000000 ' - '00:00000000 00000000 0 0 10927 1 f72a5b80 ' - '3000 0 0 2 -1') % (_addr1, _addr2) - - def testDottedQuadFromHexString(self): - p = ident.ProcServerMixin() - self.assertEquals(p.dottedQuadFromHexString(_addr1), '127.0.0.1') - - def testUnpackAddress(self): - p = ident.ProcServerMixin() - self.assertEquals(p.unpackAddress(_addr1 + ':0277'), - ('127.0.0.1', 631)) - - def testLineParser(self): - p = ident.ProcServerMixin() - self.assertEquals( - p.parseLine(self.line), - (('127.0.0.1', 25), ('1.2.3.4', 762), 0)) - - def testExistingAddress(self): - username = [] - p = ident.ProcServerMixin() - p.entries = lambda: iter([self.line]) - p.getUsername = lambda uid: (username.append(uid), 'root')[1] - self.assertEquals( - p.lookup(('127.0.0.1', 25), ('1.2.3.4', 762)), - (p.SYSTEM_NAME, 'root')) - self.assertEquals(username, [0]) - - def testNonExistingAddress(self): - p = ident.ProcServerMixin() - p.entries = lambda: iter([self.line]) - self.assertRaises(ident.NoUser, p.lookup, ('127.0.0.1', 26), - ('1.2.3.4', 762)) - self.assertRaises(ident.NoUser, p.lookup, ('127.0.0.1', 25), - ('1.2.3.5', 762)) - self.assertRaises(ident.NoUser, p.lookup, ('127.0.0.1', 25), - ('1.2.3.4', 763)) - diff --git a/tools/buildbot/pylibs/twisted/test/test_import.py b/tools/buildbot/pylibs/twisted/test/test_import.py deleted file mode 100644 index 3a417f7..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_import.py +++ /dev/null @@ -1,92 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -from twisted.trial import unittest -from twisted.python.runtime import platformType - -class AtLeastImportTestCase(unittest.TestCase): - - """I test that there are no syntax errors which will not allow importing. - """ - - failureException = ImportError - - def test_misc(self): - """Test importing other misc. modules - """ - from twisted import copyright - - def test_persisted(self): - """Test importing persisted - """ - from twisted.persisted import dirdbm - from twisted.persisted import styles - - def test_internet(self): - """Test importing internet - """ - from twisted.internet import tcp - from twisted.internet import main - # from twisted.internet import ssl - from twisted.internet import abstract - from twisted.internet import udp - from twisted.internet import protocol - from twisted.internet import defer - - def test_unix(self): - """internet modules for unix.""" - from twisted.internet import stdio - from twisted.internet import process - from twisted.internet import unix - - if platformType != "posix": - test_unix.skip = "UNIX-only modules" - - def test_spread(self): - """Test importing spreadables - """ - from twisted.spread import pb - from twisted.spread import jelly - from twisted.spread import banana - from twisted.spread import flavors - - def test_twistedPython(self): - """Test importing twisted.python - """ - from twisted.python import hook - from twisted.python import log - from twisted.python import reflect - # from twisted.python import threadable - # from twisted.python import threadpool - from twisted.python import usage - from twisted.python import otp - - def test_protocols(self): - """Test importing protocols - """ - from twisted.protocols import basic - from twisted.protocols import ftp - from twisted.protocols import telnet - from twisted.protocols import policies - - def test_enterprise(self): - from twisted.enterprise import adbapi - from twisted.enterprise import reflector - from twisted.enterprise import sqlreflector - from twisted.enterprise import row - - def test_test(self): - import os, sys - oldargv = sys.argv - sys.argv = sys.argv[:1] - try: - tests = os.listdir(os.path.dirname(__file__)) - for f in tests: - if f.startswith('test_') and f.endswith('.py'): - __import__('twisted.test.%s' % f[:-3]) - finally: - sys.argv = oldargv - -testCases = [AtLeastImportTestCase] diff --git a/tools/buildbot/pylibs/twisted/test/test_internet.py b/tools/buildbot/pylibs/twisted/test/test_internet.py deleted file mode 100644 index b877669..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_internet.py +++ /dev/null @@ -1,1653 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -from twisted.trial import unittest -from twisted.internet import reactor, protocol, error, abstract, defer -from twisted.internet import interfaces, base, task -from twisted.internet.tcp import Connection - -from twisted.test.time_helpers import Clock - -try: - from twisted.internet import ssl -except ImportError: - ssl = None -if ssl and not ssl.supported: - ssl = None - -from twisted.internet.defer import Deferred, maybeDeferred -from twisted.python import util, runtime - -import os -import sys -import time -import socket - - - -class ThreePhaseEventTests(unittest.TestCase): - """ - Tests for the private implementation helpers for system event triggers. - """ - def setUp(self): - """ - Create a trigger, an argument, and an event to be used by tests. - """ - self.trigger = lambda x: None - self.arg = object() - self.event = base._ThreePhaseEvent() - - - def test_addInvalidPhase(self): - """ - L{_ThreePhaseEvent.addTrigger} should raise L{KeyError} when called - with an invalid phase. - """ - self.assertRaises( - KeyError, - self.event.addTrigger, 'xxx', self.trigger, self.arg) - - - def test_addBeforeTrigger(self): - """ - L{_ThreePhaseEvent.addTrigger} should accept C{'before'} as a phase, a - callable, and some arguments and add the callable with the arguments to - the before list. - """ - self.event.addTrigger('before', self.trigger, self.arg) - self.assertEqual( - self.event.before, - [(self.trigger, (self.arg,), {})]) - - - def test_addDuringTrigger(self): - """ - L{_ThreePhaseEvent.addTrigger} should accept C{'during'} as a phase, a - callable, and some arguments and add the callable with the arguments to - the during list. - """ - self.event.addTrigger('during', self.trigger, self.arg) - self.assertEqual( - self.event.during, - [(self.trigger, (self.arg,), {})]) - - - def test_addAfterTrigger(self): - """ - L{_ThreePhaseEvent.addTrigger} should accept C{'after'} as a phase, a - callable, and some arguments and add the callable with the arguments to - the after list. - """ - self.event.addTrigger('after', self.trigger, self.arg) - self.assertEqual( - self.event.after, - [(self.trigger, (self.arg,), {})]) - - - def test_removeTrigger(self): - """ - L{_ThreePhaseEvent.removeTrigger} should accept an opaque object - previously returned by L{_ThreePhaseEvent.addTrigger} and remove the - associated trigger. - """ - handle = self.event.addTrigger('before', self.trigger, self.arg) - self.event.removeTrigger(handle) - self.assertEqual(self.event.before, []) - - - def test_removeNonexistentTrigger(self): - """ - L{_ThreePhaseEvent.removeTrigger} should raise L{ValueError} when given - an object not previously returned by L{_ThreePhaseEvent.addTrigger}. - """ - self.assertRaises(ValueError, self.event.removeTrigger, object()) - - - def test_removeRemovedTrigger(self): - """ - L{_ThreePhaseEvent.removeTrigger} should raise L{ValueError} the second - time it is called with an object returned by - L{_ThreePhaseEvent.addTrigger}. - """ - handle = self.event.addTrigger('before', self.trigger, self.arg) - self.event.removeTrigger(handle) - self.assertRaises(ValueError, self.event.removeTrigger, handle) - - - def test_removeAlmostValidTrigger(self): - """ - L{_ThreePhaseEvent.removeTrigger} should raise L{ValueError} if it is - given a trigger handle which resembles a valid trigger handle aside - from its phase being incorrect. - """ - self.assertRaises( - KeyError, - self.event.removeTrigger, ('xxx', self.trigger, (self.arg,), {})) - - - def test_fireEvent(self): - """ - L{_ThreePhaseEvent.fireEvent} should call I{before}, I{during}, and - I{after} phase triggers in that order. - """ - events = [] - self.event.addTrigger('after', events.append, ('first', 'after')) - self.event.addTrigger('during', events.append, ('first', 'during')) - self.event.addTrigger('before', events.append, ('first', 'before')) - self.event.addTrigger('before', events.append, ('second', 'before')) - self.event.addTrigger('during', events.append, ('second', 'during')) - self.event.addTrigger('after', events.append, ('second', 'after')) - - self.assertEqual(events, []) - self.event.fireEvent() - self.assertEqual(events, - [('first', 'before'), ('second', 'before'), - ('first', 'during'), ('second', 'during'), - ('first', 'after'), ('second', 'after')]) - - - def test_asynchronousBefore(self): - """ - L{_ThreePhaseEvent.fireEvent} should wait for any L{Deferred} returned - by a I{before} phase trigger before proceeding to I{during} events. - """ - events = [] - beforeResult = Deferred() - self.event.addTrigger('before', lambda: beforeResult) - self.event.addTrigger('during', events.append, 'during') - self.event.addTrigger('after', events.append, 'after') - - self.assertEqual(events, []) - self.event.fireEvent() - self.assertEqual(events, []) - beforeResult.callback(None) - self.assertEqual(events, ['during', 'after']) - - - def test_beforeTriggerException(self): - """ - If a before-phase trigger raises a synchronous exception, it should be - logged and the remaining triggers should be run. - """ - events = [] - - class DummyException(Exception): - pass - - def raisingTrigger(): - raise DummyException() - - self.event.addTrigger('before', raisingTrigger) - self.event.addTrigger('before', events.append, 'before') - self.event.addTrigger('during', events.append, 'during') - self.event.fireEvent() - self.assertEqual(events, ['before', 'during']) - errors = self.flushLoggedErrors(DummyException) - self.assertEqual(len(errors), 1) - - - def test_duringTriggerException(self): - """ - If a during-phase trigger raises a synchronous exception, it should be - logged and the remaining triggers should be run. - """ - events = [] - - class DummyException(Exception): - pass - - def raisingTrigger(): - raise DummyException() - - self.event.addTrigger('during', raisingTrigger) - self.event.addTrigger('during', events.append, 'during') - self.event.addTrigger('after', events.append, 'after') - self.event.fireEvent() - self.assertEqual(events, ['during', 'after']) - errors = self.flushLoggedErrors(DummyException) - self.assertEqual(len(errors), 1) - - - def test_synchronousRemoveAlreadyExecutedBefore(self): - """ - If a before-phase trigger tries to remove another before-phase trigger - which has already run, a warning should be emitted. - """ - events = [] - - def removeTrigger(): - self.event.removeTrigger(beforeHandle) - - beforeHandle = self.event.addTrigger('before', events.append, ('first', 'before')) - self.event.addTrigger('before', removeTrigger) - self.event.addTrigger('before', events.append, ('second', 'before')) - self.assertWarns( - DeprecationWarning, - "Removing already-fired system event triggers will raise an " - "exception in a future version of Twisted.", - __file__, - self.event.fireEvent) - self.assertEqual(events, [('first', 'before'), ('second', 'before')]) - - - def test_synchronousRemovePendingBefore(self): - """ - If a before-phase trigger removes another before-phase trigger which - has not yet run, the removed trigger should not be run. - """ - events = [] - self.event.addTrigger( - 'before', lambda: self.event.removeTrigger(beforeHandle)) - beforeHandle = self.event.addTrigger( - 'before', events.append, ('first', 'before')) - self.event.addTrigger('before', events.append, ('second', 'before')) - self.event.fireEvent() - self.assertEqual(events, [('second', 'before')]) - - - def test_synchronousBeforeRemovesDuring(self): - """ - If a before-phase trigger removes a during-phase trigger, the - during-phase trigger should not be run. - """ - events = [] - self.event.addTrigger( - 'before', lambda: self.event.removeTrigger(duringHandle)) - duringHandle = self.event.addTrigger('during', events.append, 'during') - self.event.addTrigger('after', events.append, 'after') - self.event.fireEvent() - self.assertEqual(events, ['after']) - - - def test_asynchronousBeforeRemovesDuring(self): - """ - If a before-phase trigger returns a L{Deferred} and later removes a - during-phase trigger before the L{Deferred} fires, the during-phase - trigger should not be run. - """ - events = [] - beforeResult = Deferred() - self.event.addTrigger('before', lambda: beforeResult) - duringHandle = self.event.addTrigger('during', events.append, 'during') - self.event.addTrigger('after', events.append, 'after') - self.event.fireEvent() - self.event.removeTrigger(duringHandle) - beforeResult.callback(None) - self.assertEqual(events, ['after']) - - - def test_synchronousBeforeRemovesConspicuouslySimilarDuring(self): - """ - If a before-phase trigger removes a during-phase trigger which is - identical to an already-executed before-phase trigger aside from their - phases, no warning should be emitted and the during-phase trigger - should not be run. - """ - events = [] - def trigger(): - events.append('trigger') - self.event.addTrigger('before', trigger) - self.event.addTrigger( - 'before', lambda: self.event.removeTrigger(duringTrigger)) - duringTrigger = self.event.addTrigger('during', trigger) - self.event.fireEvent() - self.assertEqual(events, ['trigger']) - - - def test_synchronousRemovePendingDuring(self): - """ - If a during-phase trigger removes another during-phase trigger which - has not yet run, the removed trigger should not be run. - """ - events = [] - self.event.addTrigger( - 'during', lambda: self.event.removeTrigger(duringHandle)) - duringHandle = self.event.addTrigger( - 'during', events.append, ('first', 'during')) - self.event.addTrigger( - 'during', events.append, ('second', 'during')) - self.event.fireEvent() - self.assertEqual(events, [('second', 'during')]) - - - def test_triggersRunOnce(self): - """ - A trigger should only be called on the first call to - L{_ThreePhaseEvent.fireEvent}. - """ - events = [] - self.event.addTrigger('before', events.append, 'before') - self.event.addTrigger('during', events.append, 'during') - self.event.addTrigger('after', events.append, 'after') - self.event.fireEvent() - self.event.fireEvent() - self.assertEqual(events, ['before', 'during', 'after']) - - - def test_finishedBeforeTriggersCleared(self): - """ - The temporary list L{_ThreePhaseEvent.finishedBefore} should be emptied - and the state reset to C{'BASE'} before the first during-phase trigger - executes. - """ - events = [] - def duringTrigger(): - events.append('during') - self.assertEqual(self.event.finishedBefore, []) - self.assertEqual(self.event.state, 'BASE') - self.event.addTrigger('before', events.append, 'before') - self.event.addTrigger('during', duringTrigger) - self.event.fireEvent() - self.assertEqual(events, ['before', 'during']) - - - -class SystemEventTestCase(unittest.TestCase): - """ - Tests for the reactor's implementation of the C{fireSystemEvent}, - C{addSystemEventTrigger}, and C{removeSystemEventTrigger} methods of the - L{IReactorCore} interface. - - @ivar triggers: A list of the handles to triggers which have been added to - the reactor. - """ - def setUp(self): - """ - Create an empty list in which to store trigger handles. - """ - self.triggers = [] - - - def tearDown(self): - """ - Remove all remaining triggers from the reactor. - """ - while self.triggers: - trigger = self.triggers.pop() - try: - reactor.removeSystemEventTrigger(trigger) - except (ValueError, KeyError): - pass - - - def addTrigger(self, event, phase, func): - """ - Add a trigger to the reactor and remember it in C{self.triggers}. - """ - t = reactor.addSystemEventTrigger(event, phase, func) - self.triggers.append(t) - return t - - - def removeTrigger(self, trigger): - """ - Remove a trigger by its handle from the reactor and from - C{self.triggers}. - """ - reactor.removeSystemEventTrigger(trigger) - self.triggers.remove(trigger) - - - def _addSystemEventTriggerTest(self, phase): - eventType = 'test' - events = [] - def trigger(): - events.append(None) - self.addTrigger(phase, eventType, trigger) - self.assertEqual(events, []) - reactor.fireSystemEvent(eventType) - self.assertEqual(events, [None]) - - - def test_beforePhase(self): - """ - L{IReactorCore.addSystemEventTrigger} should accept the C{'before'} - phase and not call the given object until the right event is fired. - """ - self._addSystemEventTriggerTest('before') - - - def test_duringPhase(self): - """ - L{IReactorCore.addSystemEventTrigger} should accept the C{'during'} - phase and not call the given object until the right event is fired. - """ - self._addSystemEventTriggerTest('during') - - - def test_afterPhase(self): - """ - L{IReactorCore.addSystemEventTrigger} should accept the C{'after'} - phase and not call the given object until the right event is fired. - """ - self._addSystemEventTriggerTest('after') - - - def test_unknownPhase(self): - """ - L{IReactorCore.addSystemEventTrigger} should reject phases other than - C{'before'}, C{'during'}, or C{'after'}. - """ - eventType = 'test' - self.assertRaises( - KeyError, self.addTrigger, 'xxx', eventType, lambda: None) - - - def test_beforePreceedsDuring(self): - """ - L{IReactorCore.addSystemEventTrigger} should call triggers added to the - C{'before'} phase before it calls triggers added to the C{'during'} - phase. - """ - eventType = 'test' - events = [] - def beforeTrigger(): - events.append('before') - def duringTrigger(): - events.append('during') - self.addTrigger('before', eventType, beforeTrigger) - self.addTrigger('during', eventType, duringTrigger) - self.assertEqual(events, []) - reactor.fireSystemEvent(eventType) - self.assertEqual(events, ['before', 'during']) - - - def test_duringPreceedsAfter(self): - """ - L{IReactorCore.addSystemEventTrigger} should call triggers added to the - C{'during'} phase before it calls triggers added to the C{'after'} - phase. - """ - eventType = 'test' - events = [] - def duringTrigger(): - events.append('during') - def afterTrigger(): - events.append('after') - self.addTrigger('during', eventType, duringTrigger) - self.addTrigger('after', eventType, afterTrigger) - self.assertEqual(events, []) - reactor.fireSystemEvent(eventType) - self.assertEqual(events, ['during', 'after']) - - - def test_beforeReturnsDeferred(self): - """ - If a trigger added to the C{'before'} phase of an event returns a - L{Deferred}, the C{'during'} phase should be delayed until it is called - back. - """ - triggerDeferred = Deferred() - eventType = 'test' - events = [] - def beforeTrigger(): - return triggerDeferred - def duringTrigger(): - events.append('during') - self.addTrigger('before', eventType, beforeTrigger) - self.addTrigger('during', eventType, duringTrigger) - self.assertEqual(events, []) - reactor.fireSystemEvent(eventType) - self.assertEqual(events, []) - triggerDeferred.callback(None) - self.assertEqual(events, ['during']) - - - def test_multipleBeforeReturnDeferred(self): - """ - If more than one trigger added to the C{'before'} phase of an event - return L{Deferred}s, the C{'during'} phase should be delayed until they - are all called back. - """ - firstDeferred = Deferred() - secondDeferred = Deferred() - eventType = 'test' - events = [] - def firstBeforeTrigger(): - return firstDeferred - def secondBeforeTrigger(): - return secondDeferred - def duringTrigger(): - events.append('during') - self.addTrigger('before', eventType, firstBeforeTrigger) - self.addTrigger('before', eventType, secondBeforeTrigger) - self.addTrigger('during', eventType, duringTrigger) - self.assertEqual(events, []) - reactor.fireSystemEvent(eventType) - self.assertEqual(events, []) - firstDeferred.callback(None) - self.assertEqual(events, []) - secondDeferred.callback(None) - self.assertEqual(events, ['during']) - - - def test_subsequentBeforeTriggerFiresPriorBeforeDeferred(self): - """ - If a trigger added to the C{'before'} phase of an event calls back a - L{Deferred} returned by an earlier trigger in the C{'before'} phase of - the same event, the remaining C{'before'} triggers for that event - should be run and any further L{Deferred}s waited on before proceeding - to the C{'during'} events. - """ - eventType = 'test' - events = [] - firstDeferred = Deferred() - secondDeferred = Deferred() - def firstBeforeTrigger(): - return firstDeferred - def secondBeforeTrigger(): - firstDeferred.callback(None) - def thirdBeforeTrigger(): - events.append('before') - return secondDeferred - def duringTrigger(): - events.append('during') - self.addTrigger('before', eventType, firstBeforeTrigger) - self.addTrigger('before', eventType, secondBeforeTrigger) - self.addTrigger('before', eventType, thirdBeforeTrigger) - self.addTrigger('during', eventType, duringTrigger) - self.assertEqual(events, []) - reactor.fireSystemEvent(eventType) - self.assertEqual(events, ['before']) - secondDeferred.callback(None) - self.assertEqual(events, ['before', 'during']) - - - def test_removeSystemEventTrigger(self): - """ - A trigger removed with L{IReactorCore.removeSystemEventTrigger} should - not be called when the event fires. - """ - eventType = 'test' - events = [] - def firstBeforeTrigger(): - events.append('first') - def secondBeforeTrigger(): - events.append('second') - self.addTrigger('before', eventType, firstBeforeTrigger) - self.removeTrigger( - self.addTrigger('before', eventType, secondBeforeTrigger)) - self.assertEqual(events, []) - reactor.fireSystemEvent(eventType) - self.assertEqual(events, ['first']) - - - def test_removeNonExistentSystemEventTrigger(self): - """ - Passing an object to L{IReactorCore.removeSystemEventTrigger} which was - not returned by a previous call to - L{IReactorCore.addSystemEventTrigger} or which has already been passed - to C{removeSystemEventTrigger} should result in L{TypeError}, - L{KeyError}, or L{ValueError} being raised. - """ - b = self.addTrigger('during', 'test', lambda: None) - self.removeTrigger(b) - self.assertRaises( - TypeError, reactor.removeSystemEventTrigger, None) - self.assertRaises( - ValueError, reactor.removeSystemEventTrigger, b) - self.assertRaises( - KeyError, - reactor.removeSystemEventTrigger, - (b[0], ('xxx',) + b[1][1:])) - - - def test_interactionBetweenDifferentEvents(self): - """ - L{IReactorCore.fireSystemEvent} should behave the same way for a - particular system event regardless of whether Deferreds are being - waited on for a different system event. - """ - events = [] - - firstEvent = 'first-event' - firstDeferred = Deferred() - def beforeFirstEvent(): - events.append(('before', 'first')) - return firstDeferred - def afterFirstEvent(): - events.append(('after', 'first')) - - secondEvent = 'second-event' - secondDeferred = Deferred() - def beforeSecondEvent(): - events.append(('before', 'second')) - return secondDeferred - def afterSecondEvent(): - events.append(('after', 'second')) - - self.addTrigger('before', firstEvent, beforeFirstEvent) - self.addTrigger('after', firstEvent, afterFirstEvent) - self.addTrigger('before', secondEvent, beforeSecondEvent) - self.addTrigger('after', secondEvent, afterSecondEvent) - - self.assertEqual(events, []) - - # After this, firstEvent should be stuck before 'during' waiting for - # firstDeferred. - reactor.fireSystemEvent(firstEvent) - self.assertEqual(events, [('before', 'first')]) - - # After this, secondEvent should be stuck before 'during' waiting for - # secondDeferred. - reactor.fireSystemEvent(secondEvent) - self.assertEqual(events, [('before', 'first'), ('before', 'second')]) - - # After this, firstEvent should have finished completely, but - # secondEvent should be at the same place. - firstDeferred.callback(None) - self.assertEqual(events, [('before', 'first'), ('before', 'second'), - ('after', 'first')]) - - # After this, secondEvent should have finished completely. - secondDeferred.callback(None) - self.assertEqual(events, [('before', 'first'), ('before', 'second'), - ('after', 'first'), ('after', 'second')]) - - - -class TimeTestCase(unittest.TestCase): - """ - Tests for the IReactorTime part of the reactor. - """ - - - def test_seconds(self): - """ - L{twisted.internet.reactor.seconds} should return something - like a number. - - 1. This test specifically does not assert any relation to the - "system time" as returned by L{time.time} or - L{twisted.python.runtime.seconds}, because at some point we - may find a better option for scheduling calls than - wallclock-time. - 2. This test *also* does not assert anything about the type of - the result, because operations may not return ints or - floats: For example, datetime-datetime == timedelta(0). - """ - now = reactor.seconds() - self.assertEquals(now-now+now, now) - - - def test_callLaterUsesReactorSecondsInDelayedCall(self): - """ - L{reactor.callLater} should use the reactor's seconds factory - to produce the time at which the DelayedCall will be called. - """ - oseconds = reactor.seconds - reactor.seconds = lambda: 100 - try: - call = reactor.callLater(5, lambda: None) - self.assertEquals(call.getTime(), 105) - finally: - reactor.seconds = oseconds - - - def test_callLaterUsesReactorSecondsAsDelayedCallSecondsFactory(self): - """ - L{reactor.callLater} should propagate its own seconds factory - to the DelayedCall to use as its own seconds factory. - """ - oseconds = reactor.seconds - reactor.seconds = lambda: 100 - try: - call = reactor.callLater(5, lambda: None) - self.assertEquals(call.seconds(), 100) - finally: - reactor.seconds = oseconds - - - def test_callLater(self): - """ - Test that a DelayedCall really calls the function it is - supposed to call. - """ - d = Deferred() - reactor.callLater(0, d.callback, None) - d.addCallback(self.assertEqual, None) - return d - - - def test_cancelDelayedCall(self): - """ - Test that when a DelayedCall is cancelled it does not run. - """ - called = [] - def function(): - called.append(None) - call = reactor.callLater(0, function) - call.cancel() - - # Schedule a call in two "iterations" to check to make sure that the - # above call never ran. - d = Deferred() - def check(): - try: - self.assertEqual(called, []) - except: - d.errback() - else: - d.callback(None) - reactor.callLater(0, reactor.callLater, 0, check) - return d - - - def test_cancelCancelledDelayedCall(self): - """ - Test that cancelling a DelayedCall which has already been cancelled - raises the appropriate exception. - """ - call = reactor.callLater(0, lambda: None) - call.cancel() - self.assertRaises(error.AlreadyCancelled, call.cancel) - - - def test_cancelCalledDelayedCallSynchronous(self): - """ - Test that cancelling a DelayedCall in the DelayedCall's function as - that function is being invoked by the DelayedCall raises the - appropriate exception. - """ - d = Deferred() - def later(): - try: - self.assertRaises(error.AlreadyCalled, call.cancel) - except: - d.errback() - else: - d.callback(None) - call = reactor.callLater(0, later) - return d - - - def test_cancelCalledDelayedCallAsynchronous(self): - """ - Test that cancelling a DelayedCall after it has run its function - raises the appropriate exception. - """ - d = Deferred() - def check(): - try: - self.assertRaises(error.AlreadyCalled, call.cancel) - except: - d.errback() - else: - d.callback(None) - def later(): - reactor.callLater(0, check) - call = reactor.callLater(0, later) - return d - - - def testCallLaterDelayAndReset(self): - """ - Test that the reactor handles DelayedCalls which have been - reset or delayed. - """ - clock = Clock() - clock.install() - try: - callbackTimes = [None, None] - - def resetCallback(): - callbackTimes[0] = clock() - - def delayCallback(): - callbackTimes[1] = clock() - - ireset = reactor.callLater(2, resetCallback) - idelay = reactor.callLater(3, delayCallback) - - clock.pump(reactor, [0, 1]) - - self.assertIdentical(callbackTimes[0], None) - self.assertIdentical(callbackTimes[1], None) - - ireset.reset(2) # (now)1 + 2 = 3 - idelay.delay(3) # (orig)3 + 3 = 6 - - clock.pump(reactor, [0, 1]) - - self.assertIdentical(callbackTimes[0], None) - self.assertIdentical(callbackTimes[1], None) - - clock.pump(reactor, [0, 1]) - - self.assertEquals(callbackTimes[0], 3) - self.assertEquals(callbackTimes[1], None) - - clock.pump(reactor, [0, 3]) - self.assertEquals(callbackTimes[1], 6) - finally: - clock.uninstall() - - - def testCallLaterTime(self): - d = reactor.callLater(10, lambda: None) - try: - self.failUnless(d.getTime() - (time.time() + 10) < 1) - finally: - d.cancel() - - def testCallInNextIteration(self): - calls = [] - def f1(): - calls.append('f1') - reactor.callLater(0.0, f2) - def f2(): - calls.append('f2') - reactor.callLater(0.0, f3) - def f3(): - calls.append('f3') - - reactor.callLater(0, f1) - self.assertEquals(calls, []) - reactor.iterate() - self.assertEquals(calls, ['f1']) - reactor.iterate() - self.assertEquals(calls, ['f1', 'f2']) - reactor.iterate() - self.assertEquals(calls, ['f1', 'f2', 'f3']) - - def testCallLaterOrder(self): - l = [] - l2 = [] - def f(x): - l.append(x) - def f2(x): - l2.append(x) - def done(): - self.assertEquals(l, range(20)) - def done2(): - self.assertEquals(l2, range(10)) - - for n in range(10): - reactor.callLater(0, f, n) - for n in range(10): - reactor.callLater(0, f, n+10) - reactor.callLater(0.1, f2, n) - - reactor.callLater(0, done) - reactor.callLater(0.1, done2) - d = Deferred() - reactor.callLater(0.2, d.callback, None) - return d - - testCallLaterOrder.todo = "See bug 1396" - testCallLaterOrder.skip = "Trial bug, todo doesn't work! See bug 1397" - def testCallLaterOrder2(self): - # This time destroy the clock resolution so that it fails reliably - # even on systems that don't have a crappy clock resolution. - - def seconds(): - return int(time.time()) - - base_original = base.seconds - runtime_original = runtime.seconds - base.seconds = seconds - runtime.seconds = seconds - - def cleanup(x): - runtime.seconds = runtime_original - base.seconds = base_original - return x - return maybeDeferred(self.testCallLaterOrder).addBoth(cleanup) - - testCallLaterOrder2.todo = "See bug 1396" - testCallLaterOrder2.skip = "Trial bug, todo doesn't work! See bug 1397" - - def testDelayedCallStringification(self): - # Mostly just make sure str() isn't going to raise anything for - # DelayedCalls within reason. - dc = reactor.callLater(0, lambda x, y: None, 'x', y=10) - str(dc) - dc.reset(5) - str(dc) - dc.cancel() - str(dc) - - dc = reactor.callLater(0, lambda: None, x=[({'hello': u'world'}, 10j), reactor], *range(10)) - str(dc) - dc.cancel() - str(dc) - - def calledBack(ignored): - str(dc) - d = Deferred().addCallback(calledBack) - dc = reactor.callLater(0, d.callback, None) - str(dc) - return d - - - def testDelayedCallSecondsOverride(self): - """ - Test that the C{seconds} argument to DelayedCall gets used instead of - the default timing function, if it is not None. - """ - def seconds(): - return 10 - dc = base.DelayedCall(5, lambda: None, (), {}, lambda dc: None, - lambda dc: None, seconds) - self.assertEquals(dc.getTime(), 5) - dc.reset(3) - self.assertEquals(dc.getTime(), 13) - - -class CallFromThreadTests(unittest.TestCase): - def testWakeUp(self): - # Make sure other threads can wake up the reactor - d = Deferred() - def wake(): - time.sleep(0.1) - # callFromThread will call wakeUp for us - reactor.callFromThread(d.callback, None) - reactor.callInThread(wake) - return d - - if interfaces.IReactorThreads(reactor, None) is None: - testWakeUp.skip = "Nothing to wake up for without thread support" - - def _stopCallFromThreadCallback(self): - self.stopped = True - - def _callFromThreadCallback(self, d): - reactor.callFromThread(self._callFromThreadCallback2, d) - reactor.callLater(0, self._stopCallFromThreadCallback) - - def _callFromThreadCallback2(self, d): - try: - self.assert_(self.stopped) - except: - # Send the error to the deferred - d.errback() - else: - d.callback(None) - - def testCallFromThreadStops(self): - """ - Ensure that callFromThread from inside a callFromThread - callback doesn't sit in an infinite loop and lets other - things happen too. - """ - self.stopped = False - d = defer.Deferred() - reactor.callFromThread(self._callFromThreadCallback, d) - return d - - - -class DummyReactor(base.ReactorBase): - """ - A reactor faking the methods needed to make it starts. - """ - - def __init__(self, clock): - """ - @param clock: the clock used to fake time. - @type clock: C{task.Clock}. - """ - base.ReactorBase.__init__(self) - self.clock = clock - - - def installWaker(self): - """ - Called by C{self._initThreads}: no waker is needed for the tests. - """ - - - def callLater(self, _seconds, _f, *args, **kw): - """ - Override callLater using the internal clock. - """ - return self.clock.callLater( _seconds, _f, *args, **kw) - - - def removeAll(self): - """ - Needed during stop. - """ - return [] - - - -class ReactorBaseTestCase(unittest.TestCase): - """ - Tests for L{base.ReactorBase} object. - """ - - def setUp(self): - """ - Create a clock and a L{DummyReactor}. - """ - self.clock = task.Clock() - self.reactor = DummyReactor(self.clock) - - - def test_stopWhenNotStarted(self): - """ - Test that the reactor stop raises an error when the reactor is not - started. - """ - self.assertRaises(RuntimeError, self.reactor.stop) - - - def test_stopWhenAlreadyStopped(self): - """ - Test that the reactor stop raises an error when the reactor is already - stopped. - """ - self.reactor.startRunning() - self.reactor.stop() - self.assertRaises(RuntimeError, self.reactor.stop) - - - def test_stopShutDownEvents(self): - """ - Verify that reactor.stop fires shutdown events. - """ - events = [] - self.reactor.addSystemEventTrigger( - "before", "shutdown", - lambda: events.append(("before", "shutdown"))) - self.reactor.addSystemEventTrigger( - "during", "shutdown", - lambda: events.append(("during", "shutdown"))) - self.reactor.startRunning() - self.reactor.stop() - - # Simulate the mainloop spinning a little bit. Do this to allow - # reactor.stop() to schedule the shutdown event to be fired as opposed - # to assuming reactor.stop() will fire the shutdown event before - # returning. - - # Generally, randomly scheduling things to happen instead of doing them - # synchronously is wrong. However, this is finicky functionality which - # was always poorly specified and was implemented such that most times - # the shutdown event was fired asynchronously. If you're implementing - # a new API, don't look at this advance(0) and think it's great and - # copy it. - - # See #3168, #3146, and #3198. - self.reactor.clock.advance(0) - - self.assertEquals(events, [("before", "shutdown"), - ("during", "shutdown")]) - - - def test_multipleRun(self): - """ - Verify that the reactor.startRunning raises an error when called - multiple times. - """ - self.reactor.startRunning() - self.assertWarns(DeprecationWarning, - "Reactor already running! This behavior is deprecated since " - "Twisted 8.0", - __file__, - self.reactor.startRunning) - - - def test_crash(self): - """ - reactor.crash should NOT fire shutdown triggers. - """ - events = [] - self.reactor.addSystemEventTrigger( - "before", "shutdown", - lambda: events.append(("before", "shutdown"))) - - self.reactor.callWhenRunning( - self.reactor.callLater, 0, self.reactor.crash) - self.reactor.startRunning() - self.clock.advance(0.1) - self.failIf(events, "reactor.crash invoked shutdown triggers, but it " - "isn't supposed to.") - - - -class ReactorCoreTestCase(unittest.TestCase): - """ - Test core functionalities of the reactor. - """ - - def test_run(self): - """ - Test that reactor.crash terminates reactor.run - """ - for i in xrange(3): - reactor.callLater(0.01, reactor.crash) - reactor.run() - - - def test_iterate(self): - """ - Test that reactor.iterate(0) doesn't block - """ - start = time.time() - # twisted timers are distinct from the underlying event loop's - # timers, so this fail-safe probably won't keep a failure from - # hanging the test - t = reactor.callLater(10, reactor.crash) - reactor.iterate(0) # shouldn't block - stop = time.time() - elapsed = stop - start - self.failUnless(elapsed < 8) - t.cancel() - - - -class ReactorFDTestCase(unittest.TestCase): - """ - Tests for L{interfaces.IReactorFDSet}. - """ - - def test_getReaders(self): - """ - Check that L{interfaces.IReactorFDSet.getReaders} reflects the actions - made with L{interfaces.IReactorFDSet.addReader} and - L{interfaces.IReactorFDSet.removeReader}. - """ - s = socket.socket() - self.addCleanup(s.close) - - c = Connection(s, protocol.Protocol()) - self.assertNotIn(c, reactor.getReaders()) - - reactor.addReader(c) - self.assertIn(c, reactor.getReaders()) - - reactor.removeReader(c) - self.assertNotIn(c, reactor.getReaders()) - - - def test_getWriters(self): - """ - Check that L{interfaces.IReactorFDSet.getWriters} reflects the actions - made with L{interfaces.IReactorFDSet.addWriter} and - L{interfaces.IReactorFDSet.removeWriter}. - """ - s = socket.socket() - self.addCleanup(s.close) - - c = Connection(s, protocol.Protocol()) - self.assertNotIn(c, reactor.getWriters()) - - reactor.addWriter(c) - self.assertIn(c, reactor.getWriters()) - - reactor.removeWriter(c) - self.assertNotIn(c, reactor.getWriters()) - -if not interfaces.IReactorFDSet.providedBy(reactor): - ReactorFDTestCase.skip = "Reactor not providing IReactorFDSet" - - - -class DelayedTestCase(unittest.TestCase): - def setUp(self): - self.finished = 0 - self.counter = 0 - self.timers = {} - self.deferred = defer.Deferred() - # ick. Sometimes there are magic timers already running: - # popsicle.Freezer.tick . Kill off all such timers now so they won't - # interfere with the test. Of course, this kind of requires that - # getDelayedCalls already works, so certain failure modes won't be - # noticed. - if not hasattr(reactor, "getDelayedCalls"): - return - for t in reactor.getDelayedCalls(): - t.cancel() - reactor.iterate() # flush timers - - def tearDown(self): - for t in self.timers.values(): - t.cancel() - - def checkTimers(self): - l1 = self.timers.values() - l2 = list(reactor.getDelayedCalls()) - - # There should be at least the calls we put in. There may be other - # calls that are none of our business and that we should ignore, - # though. - - missing = [] - for dc in l1: - if dc not in l2: - missing.append(dc) - if missing: - self.finished = 1 - self.failIf(missing, "Should have been missing no calls, instead was missing " + repr(missing)) - - def callback(self, tag): - del self.timers[tag] - self.checkTimers() - - def addCallback(self, tag): - self.callback(tag) - self.addTimer(15, self.callback) - - def done(self, tag): - self.finished = 1 - self.callback(tag) - self.deferred.callback(None) - - def addTimer(self, when, callback): - self.timers[self.counter] = reactor.callLater(when * 0.01, callback, - self.counter) - self.counter += 1 - self.checkTimers() - - def testGetDelayedCalls(self): - if not hasattr(reactor, "getDelayedCalls"): - return - # This is not a race because we don't do anything which might call - # the reactor until we have all the timers set up. If we did, this - # test might fail on slow systems. - self.checkTimers() - self.addTimer(35, self.done) - self.addTimer(20, self.callback) - self.addTimer(30, self.callback) - which = self.counter - self.addTimer(29, self.callback) - self.addTimer(25, self.addCallback) - self.addTimer(26, self.callback) - - self.timers[which].cancel() - del self.timers[which] - self.checkTimers() - - self.deferred.addCallback(lambda x : self.checkTimers()) - return self.deferred - - def testActive(self): - dcall = reactor.callLater(0, lambda: None) - self.assertEquals(dcall.active(), 1) - reactor.iterate() - self.assertEquals(dcall.active(), 0) - -resolve_helper = """ -import %(reactor)s -%(reactor)s.install() -from twisted.internet import reactor - -class Foo: - def __init__(self): - reactor.callWhenRunning(self.start) - self.timer = reactor.callLater(3, self.failed) - def start(self): - reactor.resolve('localhost').addBoth(self.done) - def done(self, res): - print 'done', res - reactor.stop() - def failed(self): - print 'failed' - self.timer = None - reactor.stop() -f = Foo() -reactor.run() -""" - -class ChildResolveProtocol(protocol.ProcessProtocol): - def __init__(self, onCompletion): - self.onCompletion = onCompletion - - def connectionMade(self): - self.output = [] - self.error = [] - - def outReceived(self, out): - self.output.append(out) - - def errReceived(self, err): - self.error.append(err) - - def processEnded(self, reason): - self.onCompletion.callback((reason, self.output, self.error)) - self.onCompletion = None - - -class Resolve(unittest.TestCase): - def testChildResolve(self): - # I've seen problems with reactor.run under gtk2reactor. Spawn a - # child which just does reactor.resolve after the reactor has - # started, fail if it does not complete in a timely fashion. - helperPath = os.path.abspath(self.mktemp()) - helperFile = open(helperPath, 'w') - - # Eeueuuggg - reactorName = reactor.__module__ - - helperFile.write(resolve_helper % {'reactor': reactorName}) - helperFile.close() - - env = os.environ.copy() - env['PYTHONPATH'] = os.pathsep.join(sys.path) - - helperDeferred = Deferred() - helperProto = ChildResolveProtocol(helperDeferred) - - reactor.spawnProcess(helperProto, sys.executable, ("python", "-u", helperPath), env) - - def cbFinished((reason, output, error)): - # If the output is "done 127.0.0.1\n" we don't really care what - # else happened. - output = ''.join(output) - if output != 'done 127.0.0.1\n': - self.fail(( - "The child process failed to produce the desired results:\n" - " Reason for termination was: %r\n" - " Output stream was: %r\n" - " Error stream was: %r\n") % (reason.getErrorMessage(), output, ''.join(error))) - - helperDeferred.addCallback(cbFinished) - return helperDeferred - -if not interfaces.IReactorProcess(reactor, None): - Resolve.skip = "cannot run test: reactor doesn't support IReactorProcess" - -class Counter: - index = 0 - - def add(self): - self.index = self.index + 1 - - -class Order: - - stage = 0 - - def a(self): - if self.stage != 0: raise RuntimeError - self.stage = 1 - - def b(self): - if self.stage != 1: raise RuntimeError - self.stage = 2 - - def c(self): - if self.stage != 2: raise RuntimeError - self.stage = 3 - - -class CallFromThreadTestCase(unittest.TestCase): - """Task scheduling from threads tests.""" - - if interfaces.IReactorThreads(reactor, None) is None: - skip = "Nothing to test without thread support" - - def schedule(self, *args, **kwargs): - """Override in subclasses.""" - reactor.callFromThread(*args, **kwargs) - - def testScheduling(self): - c = Counter() - for i in range(100): - self.schedule(c.add) - for i in range(100): - reactor.iterate() - self.assertEquals(c.index, 100) - - def testCorrectOrder(self): - o = Order() - self.schedule(o.a) - self.schedule(o.b) - self.schedule(o.c) - reactor.iterate() - reactor.iterate() - reactor.iterate() - self.assertEquals(o.stage, 3) - - def testNotRunAtOnce(self): - c = Counter() - self.schedule(c.add) - # scheduled tasks should not be run at once: - self.assertEquals(c.index, 0) - reactor.iterate() - self.assertEquals(c.index, 1) - - -class MyProtocol(protocol.Protocol): - """Sample protocol.""" - -class MyFactory(protocol.Factory): - """Sample factory.""" - - protocol = MyProtocol - - -class ProtocolTestCase(unittest.TestCase): - - def testFactory(self): - factory = MyFactory() - protocol = factory.buildProtocol(None) - self.assertEquals(protocol.factory, factory) - self.assert_( isinstance(protocol, factory.protocol) ) - - -class DummyProducer(object): - """ - Very uninteresting producer implementation used by tests to ensure the - right methods are called by the consumer with which it is registered. - - @type events: C{list} of C{str} - @ivar events: The producer/consumer related events which have happened to - this producer. Strings in this list may be C{'resume'}, C{'stop'}, or - C{'pause'}. Elements are added as they occur. - """ - - def __init__(self): - self.events = [] - - - def resumeProducing(self): - self.events.append('resume') - - - def stopProducing(self): - self.events.append('stop') - - - def pauseProducing(self): - self.events.append('pause') - - - -class SillyDescriptor(abstract.FileDescriptor): - """ - A descriptor whose data buffer gets filled very fast. - - Useful for testing FileDescriptor's IConsumer interface, since - the data buffer fills as soon as at least four characters are - written to it, and gets emptied in a single doWrite() cycle. - """ - bufferSize = 3 - connected = True - - def writeSomeData(self, data): - """ - Always write all data. - """ - return len(data) - - - def startWriting(self): - """ - Do nothing: bypass the reactor. - """ - stopWriting = startWriting - - - -class ReentrantProducer(DummyProducer): - """ - Similar to L{DummyProducer}, but with a resumeProducing method which calls - back into an L{IConsumer} method of the consumer against which it is - registered. - - @ivar consumer: The consumer with which this producer has been or will - be registered. - - @ivar methodName: The name of the method to call on the consumer inside - C{resumeProducing}. - - @ivar methodArgs: The arguments to pass to the consumer method invoked in - C{resumeProducing}. - """ - def __init__(self, consumer, methodName, *methodArgs): - super(ReentrantProducer, self).__init__() - self.consumer = consumer - self.methodName = methodName - self.methodArgs = methodArgs - - - def resumeProducing(self): - super(ReentrantProducer, self).resumeProducing() - getattr(self.consumer, self.methodName)(*self.methodArgs) - - - -class TestProducer(unittest.TestCase): - """ - Test abstract.FileDescriptor's consumer interface. - """ - def test_doubleProducer(self): - """ - Verify that registering a non-streaming producer invokes its - resumeProducing() method and that you can only register one producer - at a time. - """ - fd = abstract.FileDescriptor() - fd.connected = 1 - dp = DummyProducer() - fd.registerProducer(dp, 0) - self.assertEquals(dp.events, ['resume']) - self.assertRaises(RuntimeError, fd.registerProducer, DummyProducer(), 0) - - - def test_unconnectedFileDescriptor(self): - """ - Verify that registering a producer when the connection has already - been closed invokes its stopProducing() method. - """ - fd = abstract.FileDescriptor() - fd.disconnected = 1 - dp = DummyProducer() - fd.registerProducer(dp, 0) - self.assertEquals(dp.events, ['stop']) - - - def _dontPausePullConsumerTest(self, methodName): - descriptor = SillyDescriptor() - producer = DummyProducer() - descriptor.registerProducer(producer, streaming=False) - self.assertEqual(producer.events, ['resume']) - del producer.events[:] - - # Fill up the descriptor's write buffer so we can observe whether or - # not it pauses its producer in that case. - getattr(descriptor, methodName)('1234') - - self.assertEqual(producer.events, []) - - - def test_dontPausePullConsumerOnWrite(self): - """ - Verify that FileDescriptor does not call producer.pauseProducing() on a - non-streaming pull producer in response to a L{IConsumer.write} call - which results in a full write buffer. Issue #2286. - """ - return self._dontPausePullConsumerTest('write') - - - def test_dontPausePullConsumerOnWriteSequence(self): - """ - Like L{test_dontPausePullConsumerOnWrite}, but for a call to - C{writeSequence} rather than L{IConsumer.write}. - - C{writeSequence} is not part of L{IConsumer}, but - L{abstract.FileDescriptor} has supported consumery behavior in response - to calls to L{writeSequence} forever. - """ - return self._dontPausePullConsumerTest('writeSequence') - - - def _reentrantStreamingProducerTest(self, methodName): - descriptor = SillyDescriptor() - producer = ReentrantProducer(descriptor, methodName, 'spam') - descriptor.registerProducer(producer, streaming=True) - - # Start things off by filling up the descriptor's buffer so it will - # pause its producer. - getattr(descriptor, methodName)('spam') - - # Sanity check - make sure that worked. - self.assertEqual(producer.events, ['pause']) - del producer.events[:] - - # After one call to doWrite, the buffer has been emptied so the - # FileDescriptor should resume its producer. That will result in an - # immediate call to FileDescriptor.write which will again fill the - # buffer and result in the producer being paused. - descriptor.doWrite() - self.assertEqual(producer.events, ['resume', 'pause']) - del producer.events[:] - - # After a second call to doWrite, the exact same thing should have - # happened. Prior to the bugfix for which this test was written, - # FileDescriptor would have incorrectly believed its producer was - # already resumed (it was paused) and so not resume it again. - descriptor.doWrite() - self.assertEqual(producer.events, ['resume', 'pause']) - - - def test_reentrantStreamingProducerUsingWrite(self): - """ - Verify that FileDescriptor tracks producer's paused state correctly. - Issue #811, fixed in revision r12857. - """ - return self._reentrantStreamingProducerTest('write') - - - def test_reentrantStreamingProducerUsingWriteSequence(self): - """ - Like L{test_reentrantStreamingProducerUsingWrite}, but for calls to - C{writeSequence}. - - C{writeSequence} is B{not} part of L{IConsumer}, however - C{abstract.FileDescriptor} has supported consumery behavior in response - to calls to C{writeSequence} forever. - """ - return self._reentrantStreamingProducerTest('writeSequence') - - - -class PortStringification(unittest.TestCase): - if interfaces.IReactorTCP(reactor, None) is not None: - def testTCP(self): - p = reactor.listenTCP(0, protocol.ServerFactory()) - portNo = p.getHost().port - self.assertNotEqual(str(p).find(str(portNo)), -1, - "%d not found in %s" % (portNo, p)) - return p.stopListening() - - if interfaces.IReactorUDP(reactor, None) is not None: - def testUDP(self): - p = reactor.listenUDP(0, protocol.DatagramProtocol()) - portNo = p.getHost().port - self.assertNotEqual(str(p).find(str(portNo)), -1, - "%d not found in %s" % (portNo, p)) - return p.stopListening() - - if interfaces.IReactorSSL(reactor, None) is not None and ssl: - def testSSL(self, ssl=ssl): - pem = util.sibpath(__file__, 'server.pem') - p = reactor.listenSSL(0, protocol.ServerFactory(), ssl.DefaultOpenSSLContextFactory(pem, pem)) - portNo = p.getHost().port - self.assertNotEqual(str(p).find(str(portNo)), -1, - "%d not found in %s" % (portNo, p)) - return p.stopListening() diff --git a/tools/buildbot/pylibs/twisted/test/test_iutils.py b/tools/buildbot/pylibs/twisted/test/test_iutils.py deleted file mode 100644 index 3b77d86..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_iutils.py +++ /dev/null @@ -1,151 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Test running processes. -""" - -import warnings, os, sys, signal - -# Twisted Imports -from twisted.trial import unittest - -from twisted.internet import reactor, utils, interfaces - - -class UtilsTestCase(unittest.TestCase): - """ - Test running a process using L{utils.getProcessOutput}, - L{utils.getProcessValue}, and L{utils.getProcessOutputAndValue}. - """ - - output = None - value = None - - def makeSourceFile(self, sourceLines): - script = self.mktemp() - scriptFile = file(script, 'wt') - scriptFile.write(os.linesep.join(sourceLines) + os.linesep) - scriptFile.close() - return script - - def testOutput(self): - scriptFile = self.makeSourceFile([ - 'print "hello world"' - ]) - d = utils.getProcessOutput(sys.executable, ['-u', scriptFile]) - return d.addCallback(self.assertEquals, "hello world\n") - - def testOutputWithErrorIgnored(self): - # make sure stderr raises an error normally - exe = sys.executable - scriptFile = self.makeSourceFile([ - 'import sys', - 'sys.stderr.write("hello world\\n")' - ]) - - d = utils.getProcessOutput(exe, ['-u', scriptFile], errortoo=0) - return self.assertFailure(d, IOError) - - def testOutputWithErrorCollected(self): - # make sure stderr raises an error normally - exe = sys.executable - scriptFile = self.makeSourceFile([ - 'import sys', - 'sys.stderr.write("hello world\\n")' - ]) - - d = utils.getProcessOutput(exe, ['-u', scriptFile], errortoo=1) - return d.addCallback(self.assertEquals, "hello world" + os.linesep) - - def testValue(self): - exe = sys.executable - scriptFile = self.makeSourceFile([ - "import sys", - "sys.exit(1)" - ]) - - d = utils.getProcessValue(exe, ['-u', scriptFile]) - return d.addCallback(self.assertEquals, 1) - - def testOutputAndValue(self): - exe = sys.executable - scriptFile = self.makeSourceFile([ - "import sys", - "sys.stdout.write('hello world!\\n')", - "sys.stderr.write('goodbye world!\\n')", - "sys.exit(1)" - ]) - - def gotOutputAndValue((out, err, code)): - self.assertEquals(out, "hello world!" + os.linesep) - self.assertEquals(err, "goodbye world!" + os.linesep) - self.assertEquals(code, 1) - d = utils.getProcessOutputAndValue(exe, [scriptFile]) - return d.addCallback(gotOutputAndValue) - - def testOutputSignal(self): - # Use SIGKILL here because it's guaranteed to be delivered. Using - # SIGHUP might not work in, e.g., a buildbot slave run under the - # 'nohup' command. - exe = sys.executable - scriptFile = self.makeSourceFile([ - "import sys, os, signal", - "sys.stdout.write('stdout bytes\\n')", - "sys.stderr.write('stderr bytes\\n')", - "sys.stdout.flush()", - "sys.stderr.flush()", - "os.kill(os.getpid(), signal.SIGKILL)" - ]) - - def gotOutputAndValue(err): - (out, err, sig) = err.value # XXX Sigh wtf - self.assertEquals(out, "stdout bytes" + os.linesep) - self.assertEquals(err, "stderr bytes" + os.linesep) - self.assertEquals(sig, signal.SIGKILL) - - d = utils.getProcessOutputAndValue(exe, ['-u', scriptFile]) - return d.addErrback(gotOutputAndValue) - - - -class WarningSuppression(unittest.TestCase): - def setUp(self): - self.warnings = [] - self.originalshow = warnings.showwarning - warnings.showwarning = self.showwarning - - - def tearDown(self): - warnings.showwarning = self.originalshow - - - def showwarning(self, *a, **kw): - self.warnings.append((a, kw)) - - - def testSuppressWarnings(self): - def f(msg): - warnings.warn(msg) - g = utils.suppressWarnings(f, (('ignore',), dict(message="This is message"))) - - # Start off with a sanity check - calling the original function - # should emit the warning. - f("Sanity check message") - self.assertEquals(len(self.warnings), 1) - - # Now that that's out of the way, call the wrapped function, and - # make sure no new warnings show up. - g("This is message") - self.assertEquals(len(self.warnings), 1) - - # Finally, emit another warning which should not be ignored, and - # make sure it is not. - g("Unignored message") - self.assertEquals(len(self.warnings), 2) - - - -if interfaces.IReactorProcess(reactor, None) is None: - UtilsTestCase.skip = "reactor doesn't implement IReactorProcess" diff --git a/tools/buildbot/pylibs/twisted/test/test_jelly.py b/tools/buildbot/pylibs/twisted/test/test_jelly.py deleted file mode 100644 index 4c90b9b..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_jelly.py +++ /dev/null @@ -1,589 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Test cases for L{jelly} object serialization. -""" - -import datetime - -try: - import decimal -except ImportError: - decimal = None - -from twisted.spread import jelly, pb -from twisted.python.compat import set, frozenset - -from twisted.trial import unittest - - - -class TestNode(object, jelly.Jellyable): - """ - An object to test jellyfying of new style class instances. - """ - classAttr = 4 - - def __init__(self, parent=None): - if parent: - self.id = parent.id + 1 - parent.children.append(self) - else: - self.id = 1 - self.parent = parent - self.children = [] - - - -class A: - """ - Dummy class. - """ - - def amethod(self): - """ - Method tp be used in serialization tests. - """ - - - -def afunc(self): - """ - A dummy function to test function serialization. - """ - - - -class B: - """ - Dummy class. - """ - - def bmethod(self): - """ - Method to be used in serialization tests. - """ - - - -class C: - """ - Dummy class. - """ - - def cmethod(self): - """ - Method to be used in serialization tests. - """ - - - -class D(object): - """ - Dummy new-style class. - """ - - - -class SimpleJellyTest: - def __init__(self, x, y): - self.x = x - self.y = y - - def isTheSameAs(self, other): - return self.__dict__ == other.__dict__ - - - -class JellyTestCase(unittest.TestCase): - """ - Testcases for L{jelly} module serialization. - - @cvar decimalData: serialized version of decimal data, to be used in tests. - @type decimalData: C{list} - """ - - def _testSecurity(self, inputList, atom): - """ - Helper test method to test security options for a type. - - @param inputList: a sample input for the type. - @param inputList: C{list} - - @param atom: atom identifier for the type. - @type atom: C{str} - """ - c = jelly.jelly(inputList) - taster = jelly.SecurityOptions() - taster.allowBasicTypes() - # By default, it should succeed - jelly.unjelly(c, taster) - taster.allowedTypes.pop(atom) - # But it should raise an exception when disallowed - self.assertRaises(jelly.InsecureJelly, jelly.unjelly, c, taster) - - - def test_methodSelfIdentity(self): - a = A() - b = B() - a.bmethod = b.bmethod - b.a = a - im_ = jelly.unjelly(jelly.jelly(b)).a.bmethod - self.assertEquals(im_.im_class, im_.im_self.__class__) - - - def test_methodsNotSelfIdentity(self): - """ - If a class change after an instance has been created, L{jelly.unjelly} - shoud raise a C{TypeError} when trying to unjelly the instance. - """ - a = A() - b = B() - c = C() - a.bmethod = c.cmethod - b.a = a - savecmethod = C.cmethod - del C.cmethod - try: - self.assertRaises(TypeError, jelly.unjelly, jelly.jelly(b)) - finally: - C.cmethod = savecmethod - - - def test_newStyle(self): - n = D() - n.x = 1 - n2 = D() - n.n2 = n2 - n.n3 = n2 - c = jelly.jelly(n) - m = jelly.unjelly(c) - self.assertIsInstance(m, D) - self.assertIdentical(m.n2, m.n3) - - - def test_dateTime(self): - dtn = datetime.datetime.now() - dtd = datetime.datetime.now() - dtn - input = [dtn, dtd] - c = jelly.jelly(input) - output = jelly.unjelly(c) - self.assertEquals(input, output) - self.assertNotIdentical(input, output) - - - def test_decimal(self): - """ - Jellying L{decimal.Decimal} instances and then unjellying the result - should produce objects which represent the values of the original - inputs. - """ - inputList = [decimal.Decimal('9.95'), - decimal.Decimal(0), - decimal.Decimal(123456), - decimal.Decimal('-78.901')] - c = jelly.jelly(inputList) - output = jelly.unjelly(c) - self.assertEquals(inputList, output) - self.assertNotIdentical(inputList, output) - - - decimalData = ['list', ['decimal', 995, -2], ['decimal', 0, 0], - ['decimal', 123456, 0], ['decimal', -78901, -3]] - - - def test_decimalUnjelly(self): - """ - Unjellying the s-expressions produced by jelly for L{decimal.Decimal} - instances should result in L{decimal.Decimal} instances with the values - represented by the s-expressions. - - This test also verifies that C{self.decimalData} contains valid jellied - data. This is important since L{test_decimalMissing} re-uses - C{self.decimalData} and is expected to be unable to produce - L{decimal.Decimal} instances even though the s-expression correctly - represents a list of them. - """ - expected = [decimal.Decimal('9.95'), - decimal.Decimal(0), - decimal.Decimal(123456), - decimal.Decimal('-78.901')] - output = jelly.unjelly(self.decimalData) - self.assertEquals(output, expected) - - - def test_decimalMissing(self): - """ - If decimal is unavailable on the unjelly side, L{jelly.unjelly} should - gracefully return L{jelly.Unpersistable} objects. - """ - self.patch(jelly, 'decimal', None) - output = jelly.unjelly(self.decimalData) - self.assertEquals(len(output), 4) - for i in range(4): - self.assertIsInstance(output[i], jelly.Unpersistable) - self.assertEquals(output[0].reason, - "Could not unpersist decimal: 9.95") - self.assertEquals(output[1].reason, - "Could not unpersist decimal: 0") - self.assertEquals(output[2].reason, - "Could not unpersist decimal: 123456") - self.assertEquals(output[3].reason, - "Could not unpersist decimal: -78.901") - - - def test_decimalSecurity(self): - """ - By default, C{decimal} objects should be allowed by - L{jelly.SecurityOptions}. If not allowed, L{jelly.unjelly} should raise - L{jelly.InsecureJelly} when trying to unjelly it. - """ - inputList = [decimal.Decimal('9.95')] - self._testSecurity(inputList, "decimal") - - if decimal is None: - skipReason = "decimal not available" - test_decimal.skip = skipReason - test_decimalUnjelly.skip = skipReason - test_decimalSecurity.skip = skipReason - - - def test_set(self): - """ - Jellying C{set} instances and then unjellying the result - should produce objects which represent the values of the original - inputs. - """ - inputList = [set([1, 2, 3])] - output = jelly.unjelly(jelly.jelly(inputList)) - self.assertEquals(inputList, output) - self.assertNotIdentical(inputList, output) - - - def test_frozenset(self): - """ - Jellying C{frozenset} instances and then unjellying the result - should produce objects which represent the values of the original - inputs. - """ - inputList = [frozenset([1, 2, 3])] - output = jelly.unjelly(jelly.jelly(inputList)) - self.assertEquals(inputList, output) - self.assertNotIdentical(inputList, output) - - - def test_setSecurity(self): - """ - By default, C{set} objects should be allowed by - L{jelly.SecurityOptions}. If not allowed, L{jelly.unjelly} should raise - L{jelly.InsecureJelly} when trying to unjelly it. - """ - inputList = [set([1, 2, 3])] - self._testSecurity(inputList, "set") - - - def test_frozensetSecurity(self): - """ - By default, C{frozenset} objects should be allowed by - L{jelly.SecurityOptions}. If not allowed, L{jelly.unjelly} should raise - L{jelly.InsecureJelly} when trying to unjelly it. - """ - inputList = [frozenset([1, 2, 3])] - self._testSecurity(inputList, "frozenset") - - - def test_oldSets(self): - """ - Test jellying C{sets.Set}: it should serialize to the same thing as - C{set} jelly, and be unjellied as C{set} if available. - """ - inputList = [jelly._sets.Set([1, 2, 3])] - inputJelly = jelly.jelly(inputList) - self.assertEquals(inputJelly, jelly.jelly([set([1, 2, 3])])) - output = jelly.unjelly(inputJelly) - # Even if the class is different, it should coerce to the same list - self.assertEquals(list(inputList[0]), list(output[0])) - if set is jelly._sets.Set: - self.assertIsInstance(output[0], jelly._sets.Set) - else: - self.assertIsInstance(output[0], set) - - - def test_oldImmutableSets(self): - """ - Test jellying C{sets.ImmutableSet}: it should serialize to the same - thing as C{frozenset} jelly, and be unjellied as C{frozenset} if - available. - """ - inputList = [jelly._sets.ImmutableSet([1, 2, 3])] - inputJelly = jelly.jelly(inputList) - self.assertEquals(inputJelly, jelly.jelly([frozenset([1, 2, 3])])) - output = jelly.unjelly(inputJelly) - # Even if the class is different, it should coerce to the same list - self.assertEquals(list(inputList[0]), list(output[0])) - if frozenset is jelly._sets.ImmutableSet: - self.assertIsInstance(output[0], jelly._sets.ImmutableSet) - else: - self.assertIsInstance(output[0], frozenset) - - - def test_simple(self): - """ - Simplest test case. - """ - self.failUnless(SimpleJellyTest('a', 'b').isTheSameAs( - SimpleJellyTest('a', 'b'))) - a = SimpleJellyTest(1, 2) - cereal = jelly.jelly(a) - b = jelly.unjelly(cereal) - self.failUnless(a.isTheSameAs(b)) - - - def test_identity(self): - """ - Test to make sure that objects retain identity properly. - """ - x = [] - y = (x) - x.append(y) - x.append(y) - self.assertIdentical(x[0], x[1]) - self.assertIdentical(x[0][0], x) - s = jelly.jelly(x) - z = jelly.unjelly(s) - self.assertIdentical(z[0], z[1]) - self.assertIdentical(z[0][0], z) - - - def test_unicode(self): - x = unicode('blah') - y = jelly.unjelly(jelly.jelly(x)) - self.assertEquals(x, y) - self.assertEquals(type(x), type(y)) - - - def test_stressReferences(self): - reref = [] - toplevelTuple = ({'list': reref}, reref) - reref.append(toplevelTuple) - s = jelly.jelly(toplevelTuple) - z = jelly.unjelly(s) - self.assertIdentical(z[0]['list'], z[1]) - self.assertIdentical(z[0]['list'][0], z) - - - def test_moreReferences(self): - a = [] - t = (a,) - a.append((t,)) - s = jelly.jelly(t) - z = jelly.unjelly(s) - self.assertIdentical(z[0][0][0], z) - - - def test_typeSecurity(self): - """ - Test for type-level security of serialization. - """ - taster = jelly.SecurityOptions() - dct = jelly.jelly({}) - self.assertRaises(jelly.InsecureJelly, jelly.unjelly, dct, taster) - - - def test_newStyleClasses(self): - j = jelly.jelly(D) - uj = jelly.unjelly(D) - self.assertIdentical(D, uj) - - - def test_lotsaTypes(self): - """ - Test for all types currently supported in jelly - """ - a = A() - jelly.unjelly(jelly.jelly(a)) - jelly.unjelly(jelly.jelly(a.amethod)) - items = [afunc, [1, 2, 3], not bool(1), bool(1), 'test', 20.3, - (1, 2, 3), None, A, unittest, {'a': 1}, A.amethod] - for i in items: - self.assertEquals(i, jelly.unjelly(jelly.jelly(i))) - - - def test_setState(self): - global TupleState - class TupleState: - def __init__(self, other): - self.other = other - def __getstate__(self): - return (self.other,) - def __setstate__(self, state): - self.other = state[0] - def __hash__(self): - return hash(self.other) - a = A() - t1 = TupleState(a) - t2 = TupleState(a) - t3 = TupleState((t1, t2)) - d = {t1: t1, t2: t2, t3: t3, "t3": t3} - t3prime = jelly.unjelly(jelly.jelly(d))["t3"] - self.assertIdentical(t3prime.other[0].other, t3prime.other[1].other) - - - def test_classSecurity(self): - """ - Test for class-level security of serialization. - """ - taster = jelly.SecurityOptions() - taster.allowInstancesOf(A, B) - a = A() - b = B() - c = C() - # add a little complexity to the data - a.b = b - a.c = c - # and a backreference - a.x = b - b.c = c - # first, a friendly insecure serialization - friendly = jelly.jelly(a, taster) - x = jelly.unjelly(friendly, taster) - self.assertIsInstance(x.c, jelly.Unpersistable) - # now, a malicious one - mean = jelly.jelly(a) - self.assertRaises(jelly.InsecureJelly, jelly.unjelly, mean, taster) - self.assertIdentical(x.x, x.b, "Identity mismatch") - # test class serialization - friendly = jelly.jelly(A, taster) - x = jelly.unjelly(friendly, taster) - self.assertIdentical(x, A, "A came back: %s" % x) - - - def test_unjellyable(self): - """ - Test that if Unjellyable is used to deserialize a jellied object, - state comes out right. - """ - class JellyableTestClass(jelly.Jellyable): - pass - jelly.setUnjellyableForClass(JellyableTestClass, jelly.Unjellyable) - input = JellyableTestClass() - input.attribute = 'value' - output = jelly.unjelly(jelly.jelly(input)) - self.assertEquals(output.attribute, 'value') - self.assertIsInstance(output, jelly.Unjellyable) - - - def test_persistentStorage(self): - perst = [{}, 1] - def persistentStore(obj, jel, perst = perst): - perst[1] = perst[1] + 1 - perst[0][perst[1]] = obj - return str(perst[1]) - - def persistentLoad(pidstr, unj, perst = perst): - pid = int(pidstr) - return perst[0][pid] - - a = SimpleJellyTest(1, 2) - b = SimpleJellyTest(3, 4) - c = SimpleJellyTest(5, 6) - - a.b = b - a.c = c - c.b = b - - jel = jelly.jelly(a, persistentStore = persistentStore) - x = jelly.unjelly(jel, persistentLoad = persistentLoad) - - self.assertIdentical(x.b, x.c.b) - self.failUnless(perst[0], "persistentStore was not called.") - self.assertIdentical(x.b, a.b, "Persistent storage identity failure.") - - - def test_newStyleClassesAttributes(self): - n = TestNode() - n1 = TestNode(n) - n11 = TestNode(n1) - n2 = TestNode(n) - # Jelly it - jel = jelly.jelly(n) - m = jelly.unjelly(jel) - # Check that it has been restored ok - self._check_newstyle(n, m) - - - def _check_newstyle(self, a, b): - self.assertEqual(a.id, b.id) - self.assertEqual(a.classAttr, 4) - self.assertEqual(b.classAttr, 4) - self.assertEqual(len(a.children), len(b.children)) - for x, y in zip(a.children, b.children): - self._check_newstyle(x, y) - - - -class ClassA(pb.Copyable, pb.RemoteCopy): - def __init__(self): - self.ref = ClassB(self) - - - -class ClassB(pb.Copyable, pb.RemoteCopy): - def __init__(self, ref): - self.ref = ref - - - -class CircularReferenceTestCase(unittest.TestCase): - """ - Tests for circular references handling in the jelly/unjelly process. - """ - - def test_simpleCircle(self): - jelly.setUnjellyableForClass(ClassA, ClassA) - jelly.setUnjellyableForClass(ClassB, ClassB) - a = jelly.unjelly(jelly.jelly(ClassA())) - self.assertIdentical(a.ref.ref, a, - "Identity not preserved in circular reference") - - - def test_circleWithInvoker(self): - class DummyInvokerClass: - pass - dummyInvoker = DummyInvokerClass() - dummyInvoker.serializingPerspective = None - a0 = ClassA() - jelly.setUnjellyableForClass(ClassA, ClassA) - jelly.setUnjellyableForClass(ClassB, ClassB) - j = jelly.jelly(a0, invoker=dummyInvoker) - a1 = jelly.unjelly(j) - self.failUnlessIdentical(a1.ref.ref, a1, - "Identity not preserved in circular reference") - - - def test_set(self): - """ - Check that a C{set} can contain a circular reference and be serialized - and unserialized without losing the reference. - """ - s = set() - a = SimpleJellyTest(s, None) - s.add(a) - res = jelly.unjelly(jelly.jelly(a)) - self.assertIsInstance(res.x, set) - self.assertEquals(list(res.x), [res]) - - - def test_frozenset(self): - """ - Check that a C{frozenset} can contain a circular reference and be - serializeserialized without losing the reference. - """ - a = SimpleJellyTest(None, None) - s = frozenset([a]) - a.x = s - res = jelly.unjelly(jelly.jelly(a)) - self.assertIsInstance(res.x, frozenset) - self.assertEquals(list(res.x), [res]) diff --git a/tools/buildbot/pylibs/twisted/test/test_journal.py b/tools/buildbot/pylibs/twisted/test/test_journal.py deleted file mode 100644 index 20dc8a1..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_journal.py +++ /dev/null @@ -1,169 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Testing for twisted.persisted.journal.""" - -from twisted.trial import unittest -from twisted.persisted.journal.base import ICommand, MemoryJournal, serviceCommand, ServiceWrapperCommand, command, Wrappable -from twisted.persisted.journal.picklelog import DirDBMLog -from zope.interface import implements - -import shutil, os.path - - - -class AddTime: - - implements(ICommand) - - def execute(self, svc, cmdtime): - svc.values["time"] = cmdtime - - -class Counter(Wrappable): - - objectType = "counter" - - def __init__(self, uid): - self.uid = uid - self.x = 0 - - def getUid(self): - return self.uid - - def _increment(self): - self.x += 1 - - increment = command("_increment") - - -class Service: - - def __init__(self, logpath, journalpath): - log = DirDBMLog(logpath) - self.journal = MemoryJournal(log, self, journalpath, self._gotData) - self.journal.updateFromLog() - - def _gotData(self, result): - if result is None: - self.values = {} - self.counters = {} - else: - self.values, self.counters = result - - def _makeCounter(self, id): - c = Counter(id) - self.counters[id] = c - return c - - makeCounter = serviceCommand("_makeCounter") - - def loadObject(self, type, id): - if type != "counter": raise ValueError - return self.counters[id] - - def _add(self, key, value): - """Add a new entry.""" - self.values[key] = value - - def _delete(self, key): - """Delete an entry.""" - del self.values[key] - - def get(self, key): - """Return value of an entry.""" - return self.values[key] - - def addtime(self, journal): - """Set a key 'time' with the current time.""" - journal.executeCommand(AddTime()) - - # and now the command wrappers - - add = serviceCommand("_add") - - delete = serviceCommand("_delete") - - -class JournalTestCase(unittest.TestCase): - - def setUp(self): - self.logpath = self.mktemp() - self.journalpath = self.mktemp() - self.svc = Service(self.logpath, self.journalpath) - - def tearDown(self): - if hasattr(self, "svc"): - del self.svc - # delete stuff? ... - if os.path.isdir(self.logpath): - shutil.rmtree(self.logpath) - if os.path.exists(self.logpath): - os.unlink(self.logpath) - if os.path.isdir(self.journalpath): - shutil.rmtree(self.journalpath) - if os.path.exists(self.journalpath): - os.unlink(self.journalpath) - - def testCommandExecution(self): - svc = self.svc - svc.add(svc.journal, "foo", "bar") - self.assertEquals(svc.get("foo"), "bar") - - svc.delete(svc.journal, "foo") - self.assertRaises(KeyError, svc.get, "foo") - - def testLogging(self): - svc = self.svc - log = self.svc.journal.log - j = self.svc.journal - svc.add(j, "foo", "bar") - svc.add(j, 1, "hello") - svc.delete(j, "foo") - - commands = [ServiceWrapperCommand("_add", ("foo", "bar")), - ServiceWrapperCommand("_add", (1, "hello")), - ServiceWrapperCommand("_delete", ("foo",))] - - self.assertEquals(log.getCurrentIndex(), 3) - for i in range(1, 4): - for a, b in zip(commands[i-1:], [c for t, c in log.getCommandsSince(i)]): - self.assertEquals(a, b) - - def testRecovery(self): - svc = self.svc - j = svc.journal - svc.add(j, "foo", "bar") - svc.add(j, 1, "hello") - # we sync *before* delete to make sure commands get executed - svc.journal.sync((svc.values, svc.counters)) - svc.delete(j, "foo") - d = svc.makeCounter(j, 1) - d.addCallback(lambda c, j=j: c.increment(j)) - del svc, self.svc - - # first, load from snapshot - svc = Service(self.logpath, self.journalpath) - self.assertEquals(svc.values, {1: "hello"}) - self.assertEquals(svc.counters[1].x, 1) - del svc - - # now, tamper with log, and then try - f = open(self.journalpath, "w") - f.write("sfsdfsdfsd") - f.close() - svc = Service(self.logpath, self.journalpath) - self.assertEquals(svc.values, {1: "hello"}) - self.assertEquals(svc.counters[1].x, 1) - - def testTime(self): - svc = self.svc - svc.addtime(svc.journal) - t = svc.get("time") - - log = self.svc.journal.log - (t2, c), = log.getCommandsSince(1) - self.assertEquals(t, t2) - - diff --git a/tools/buildbot/pylibs/twisted/test/test_lockfile.py b/tools/buildbot/pylibs/twisted/test/test_lockfile.py deleted file mode 100644 index a928ee9..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_lockfile.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright (c) 2005 Divmod, Inc. -# See LICENSE for details. - -from twisted.trial import unittest -from twisted.python import lockfile - -class LockingTestCase(unittest.TestCase): - def testBasics(self): - lockf = self.mktemp() - lock = lockfile.FilesystemLock(lockf) - self.failUnless(lock.lock()) - self.failUnless(lock.clean) - lock.unlock() - self.failUnless(lock.lock()) - self.failUnless(lock.clean) - lock.unlock() - - - def testProtection(self): - lockf = self.mktemp() - lock = lockfile.FilesystemLock(lockf) - self.failUnless(lock.lock()) - self.failUnless(lock.clean) - self.failIf(lock.lock()) - lock.unlock() - - - def testBigLoop(self): - lockf = self.mktemp() - lock = lockfile.FilesystemLock(lockf) - self.failUnless(lock.lock()) - for i in xrange(500): - self.failIf(lock.lock()) - lock.unlock() - - - def testIsLocked(self): - lockf = self.mktemp() - self.failIf(lockfile.isLocked(lockf)) - lock = lockfile.FilesystemLock(lockf) - self.failUnless(lock.lock()) - self.failUnless(lockfile.isLocked(lockf)) - lock.unlock() - self.failIf(lockfile.isLocked(lockf)) - - # A multiprocess test would be good here, for the sake of - # completeness. However, it is fairly safe to rely on the - # filesystem to provide the semantics we require. - diff --git a/tools/buildbot/pylibs/twisted/test/test_log.py b/tools/buildbot/pylibs/twisted/test/test_log.py deleted file mode 100644 index ba48f49..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_log.py +++ /dev/null @@ -1,434 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -import os, sys, time, logging -from cStringIO import StringIO - -from twisted.trial import unittest - -from twisted.python import log -from twisted.python import failure - - -class LogTest(unittest.TestCase): - - def setUp(self): - self.catcher = [] - log.addObserver(self.catcher.append) - - def tearDown(self): - log.removeObserver(self.catcher.append) - - def testObservation(self): - catcher = self.catcher - log.msg("test", testShouldCatch=True) - i = catcher.pop() - self.assertEquals(i["message"][0], "test") - self.assertEquals(i["testShouldCatch"], True) - self.failUnless(i.has_key("time")) - self.assertEquals(len(catcher), 0) - - def testContext(self): - catcher = self.catcher - log.callWithContext({"subsystem": "not the default", - "subsubsystem": "a", - "other": "c"}, - log.callWithContext, - {"subsubsystem": "b"}, log.msg, "foo", other="d") - i = catcher.pop() - self.assertEquals(i['subsubsystem'], 'b') - self.assertEquals(i['subsystem'], 'not the default') - self.assertEquals(i['other'], 'd') - self.assertEquals(i['message'][0], 'foo') - - def testErrors(self): - for e, ig in [("hello world","hello world"), - (KeyError(), KeyError), - (failure.Failure(RuntimeError()), RuntimeError)]: - log.err(e) - i = self.catcher.pop() - self.assertEquals(i['isError'], 1) - self.flushLoggedErrors(ig) - - def testErrorsWithWhy(self): - for e, ig in [("hello world","hello world"), - (KeyError(), KeyError), - (failure.Failure(RuntimeError()), RuntimeError)]: - log.err(e, 'foobar') - i = self.catcher.pop() - self.assertEquals(i['isError'], 1) - self.assertEquals(i['why'], 'foobar') - self.flushLoggedErrors(ig) - - - def testErroneousErrors(self): - L1 = [] - L2 = [] - log.addObserver(lambda events: L1.append(events)) - log.addObserver(lambda events: 1/0) - log.addObserver(lambda events: L2.append(events)) - log.msg("Howdy, y'all.") - - # XXX - use private _flushErrors so we don't also catch - # the deprecation warnings - excs = [f.type for f in log._flushErrors(ZeroDivisionError)] - self.assertEquals([ZeroDivisionError], excs) - - self.assertEquals(len(L1), 2) - self.assertEquals(len(L2), 2) - - self.assertEquals(L1[1]['message'], ("Howdy, y'all.",)) - self.assertEquals(L2[0]['message'], ("Howdy, y'all.",)) - - # The observer has been removed, there should be no exception - log.msg("Howdy, y'all.") - - self.assertEquals(len(L1), 3) - self.assertEquals(len(L2), 3) - self.assertEquals(L1[2]['message'], ("Howdy, y'all.",)) - self.assertEquals(L2[2]['message'], ("Howdy, y'all.",)) - - -class FakeFile(list): - def write(self, bytes): - self.append(bytes) - - def flush(self): - pass - -class EvilStr: - def __str__(self): - 1/0 - -class EvilRepr: - def __str__(self): - return "Happy Evil Repr" - def __repr__(self): - 1/0 - -class EvilReprStr(EvilStr, EvilRepr): - pass - -class LogPublisherTestCaseMixin: - def setUp(self): - """ - Add a log observer which records log events in C{self.out}. Also, - make sure the default string encoding is ASCII so that - L{testSingleUnicode} can test the behavior of logging unencodable - unicode messages. - """ - self.out = FakeFile() - self.lp = log.LogPublisher() - self.flo = log.FileLogObserver(self.out) - self.lp.addObserver(self.flo.emit) - - try: - str(u'\N{VULGAR FRACTION ONE HALF}') - except UnicodeEncodeError: - # This is the behavior we want - don't change anything. - self._origEncoding = None - else: - reload(sys) - self._origEncoding = sys.getdefaultencoding() - sys.setdefaultencoding('ascii') - - - def tearDown(self): - """ - Verify that everything written to the fake file C{self.out} was a - C{str}. Also, restore the default string encoding to its previous - setting, if it was modified by L{setUp}. - """ - for chunk in self.out: - self.failUnless(isinstance(chunk, str), "%r was not a string" % (chunk,)) - - if self._origEncoding is not None: - sys.setdefaultencoding(self._origEncoding) - del sys.setdefaultencoding - - - -class LogPublisherTestCase(LogPublisherTestCaseMixin, unittest.TestCase): - def testSingleString(self): - self.lp.msg("Hello, world.") - self.assertEquals(len(self.out), 1) - - - def testMultipleString(self): - # Test some stupid behavior that will be deprecated real soon. - # If you are reading this and trying to learn how the logging - # system works, *do not use this feature*. - self.lp.msg("Hello, ", "world.") - self.assertEquals(len(self.out), 1) - - - def testSingleUnicode(self): - self.lp.msg(u"Hello, \N{VULGAR FRACTION ONE HALF} world.") - self.assertEquals(len(self.out), 1) - self.assertIn('with str error Traceback', self.out[0]) - self.assertIn('UnicodeEncodeError', self.out[0]) - - - -class FileObserverTestCase(LogPublisherTestCaseMixin, unittest.TestCase): - def test_getTimezoneOffset(self): - """ - Attempt to verify that L{FileLogObserver.getTimezoneOffset} returns - correct values for the current C{TZ} environment setting. Do this - by setting C{TZ} to various well-known values and asserting that the - reported offset is correct. - """ - localDaylightTuple = (2006, 6, 30, 0, 0, 0, 4, 181, 1) - utcDaylightTimestamp = time.mktime(localDaylightTuple) - localStandardTuple = (2007, 1, 31, 0, 0, 0, 2, 31, 0) - utcStandardTimestamp = time.mktime(localStandardTuple) - - originalTimezone = os.environ.get('TZ', None) - try: - # Test something west of UTC - os.environ['TZ'] = 'America/New_York' - time.tzset() - self.assertEqual( - self.flo.getTimezoneOffset(utcDaylightTimestamp), - 14400) - self.assertEqual( - self.flo.getTimezoneOffset(utcStandardTimestamp), - 18000) - - # Test something east of UTC - os.environ['TZ'] = 'Europe/Berlin' - time.tzset() - self.assertEqual( - self.flo.getTimezoneOffset(utcDaylightTimestamp), - -7200) - self.assertEqual( - self.flo.getTimezoneOffset(utcStandardTimestamp), - -3600) - - # Test a timezone that doesn't have DST - os.environ['TZ'] = 'Africa/Johannesburg' - time.tzset() - self.assertEqual( - self.flo.getTimezoneOffset(utcDaylightTimestamp), - -7200) - self.assertEqual( - self.flo.getTimezoneOffset(utcStandardTimestamp), - -7200) - finally: - if originalTimezone is None: - del os.environ['TZ'] - else: - os.environ['TZ'] = originalTimezone - time.tzset() - if getattr(time, 'tzset', None) is None: - test_getTimezoneOffset.skip = ( - "Platform cannot change timezone, cannot verify correct offsets " - "in well-known timezones.") - - - def test_timeFormatting(self): - """ - Test the method of L{FileLogObserver} which turns a timestamp into a - human-readable string. - """ - # There is no function in the time module which converts a UTC time - # tuple to a timestamp. - when = time.mktime((2001, 2, 3, 4, 5, 6, 7, 8, 0)) - time.timezone - - # Pretend to be in US/Eastern for a moment - self.flo.getTimezoneOffset = lambda when: 18000 - self.assertEquals(self.flo.formatTime(when), '2001-02-02 23:05:06-0500') - - # Okay now we're in Eastern Europe somewhere - self.flo.getTimezoneOffset = lambda when: -3600 - self.assertEquals(self.flo.formatTime(when), '2001-02-03 05:05:06+0100') - - # And off in the Pacific or someplace like that - self.flo.getTimezoneOffset = lambda when: -39600 - self.assertEquals(self.flo.formatTime(when), '2001-02-03 15:05:06+1100') - - # One of those weird places with a half-hour offset timezone - self.flo.getTimezoneOffset = lambda when: 5400 - self.assertEquals(self.flo.formatTime(when), '2001-02-03 02:35:06-0130') - - # Half-hour offset in the other direction - self.flo.getTimezoneOffset = lambda when: -5400 - self.assertEquals(self.flo.formatTime(when), '2001-02-03 05:35:06+0130') - - # If a strftime-format string is present on the logger, it should - # use that instead. Note we don't assert anything about day, hour - # or minute because we cannot easily control what time.strftime() - # thinks the local timezone is. - self.flo.timeFormat = '%Y %m' - self.assertEquals(self.flo.formatTime(when), '2001 02') - - - def test_loggingAnObjectWithBroken__str__(self): - #HELLO, MCFLY - self.lp.msg(EvilStr()) - self.assertEquals(len(self.out), 1) - # Logging system shouldn't need to crap itself for this trivial case - self.assertNotIn('UNFORMATTABLE', self.out[0]) - - - def test_formattingAnObjectWithBroken__str__(self): - self.lp.msg(format='%(blat)s', blat=EvilStr()) - self.assertEquals(len(self.out), 1) - self.assertIn('Invalid format string or unformattable object', self.out[0]) - - - def test_brokenSystem__str__(self): - self.lp.msg('huh', system=EvilStr()) - self.assertEquals(len(self.out), 1) - self.assertIn('Invalid format string or unformattable object', self.out[0]) - - - def test_formattingAnObjectWithBroken__repr__Indirect(self): - self.lp.msg(format='%(blat)s', blat=[EvilRepr()]) - self.assertEquals(len(self.out), 1) - self.assertIn('UNFORMATTABLE OBJECT', self.out[0]) - - - def test_systemWithBroker__repr__Indirect(self): - self.lp.msg('huh', system=[EvilRepr()]) - self.assertEquals(len(self.out), 1) - self.assertIn('UNFORMATTABLE OBJECT', self.out[0]) - - - def test_simpleBrokenFormat(self): - self.lp.msg(format='hooj %s %s', blat=1) - self.assertEquals(len(self.out), 1) - self.assertIn('Invalid format string or unformattable object', self.out[0]) - - - def test_ridiculousFormat(self): - self.lp.msg(format=42, blat=1) - self.assertEquals(len(self.out), 1) - self.assertIn('Invalid format string or unformattable object', self.out[0]) - - - def test_evilFormat__repr__And__str__(self): - self.lp.msg(format=EvilReprStr(), blat=1) - self.assertEquals(len(self.out), 1) - self.assertIn('PATHOLOGICAL', self.out[0]) - - - def test_strangeEventDict(self): - """ - This kind of eventDict used to fail silently, so test it does. - """ - self.lp.msg(message='', isError=False) - self.assertEquals(len(self.out), 0) - - -class PythonLoggingObserverTestCase(unittest.TestCase): - """ - Test the bridge with python logging module. - """ - def setUp(self): - self.out = StringIO() - - rootLogger = logging.getLogger("") - self.originalLevel = rootLogger.getEffectiveLevel() - rootLogger.setLevel(logging.DEBUG) - self.hdlr = logging.StreamHandler(self.out) - fmt = logging.Formatter(logging.BASIC_FORMAT) - self.hdlr.setFormatter(fmt) - rootLogger.addHandler(self.hdlr) - - self.lp = log.LogPublisher() - self.obs = log.PythonLoggingObserver() - self.lp.addObserver(self.obs.emit) - - def tearDown(self): - rootLogger = logging.getLogger("") - rootLogger.removeHandler(self.hdlr) - rootLogger.setLevel(self.originalLevel) - logging.shutdown() - - def test_singleString(self): - """ - Test simple output, and default log level. - """ - self.lp.msg("Hello, world.") - self.assertIn("Hello, world.", self.out.getvalue()) - self.assertIn("INFO", self.out.getvalue()) - - def test_errorString(self): - """ - Test error output. - """ - self.lp.msg(failure=failure.Failure(ValueError("That is bad.")), isError=True) - self.assertIn("ERROR", self.out.getvalue()) - - def test_formatString(self): - """ - Test logging with a format. - """ - self.lp.msg(format="%(bar)s oo %(foo)s", bar="Hello", foo="world") - self.assertIn("Hello oo world", self.out.getvalue()) - - def test_customLevel(self): - """ - Test the logLevel keyword for customizing level used. - """ - self.lp.msg("Spam egg.", logLevel=logging.DEBUG) - self.assertIn("Spam egg.", self.out.getvalue()) - self.assertIn("DEBUG", self.out.getvalue()) - self.out.reset() - self.lp.msg("Foo bar.", logLevel=logging.WARNING) - self.assertIn("Foo bar.", self.out.getvalue()) - self.assertIn("WARNING", self.out.getvalue()) - - def test_strangeEventDict(self): - """ - Verify that an event dictionary which is not an error and has an empty - message isn't recorded. - """ - self.lp.msg(message='', isError=False) - self.assertEquals(self.out.getvalue(), '') - - -class PythonLoggingIntegrationTestCase(unittest.TestCase): - """ - Test integration of python logging bridge. - """ - def test_startStopObserver(self): - """ - Test that start and stop methods of the observer actually register - and unregister to the log system. - """ - oldAddObserver = log.addObserver - oldRemoveObserver = log.removeObserver - l = [] - try: - log.addObserver = l.append - log.removeObserver = l.remove - obs = log.PythonLoggingObserver() - obs.start() - self.assertEquals(l[0], obs.emit) - obs.stop() - self.assertEquals(len(l), 0) - finally: - log.addObserver = oldAddObserver - log.removeObserver = oldRemoveObserver - - def test_inheritance(self): - """ - Test that we can inherit L{log.PythonLoggingObserver} and use super: - that's basically a validation that L{log.PythonLoggingObserver} is - new-style class. - """ - class MyObserver(log.PythonLoggingObserver): - def emit(self, eventDict): - super(MyObserver, self).emit(eventDict) - obs = MyObserver() - l = [] - oldEmit = log.PythonLoggingObserver.emit - try: - log.PythonLoggingObserver.emit = l.append - obs.emit('foo') - self.assertEquals(len(l), 1) - finally: - log.PythonLoggingObserver.emit = oldEmit - diff --git a/tools/buildbot/pylibs/twisted/test/test_logfile.py b/tools/buildbot/pylibs/twisted/test/test_logfile.py deleted file mode 100644 index a4c0b0f..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_logfile.py +++ /dev/null @@ -1,288 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.trial import unittest - -# system imports -import os, time, stat - -# twisted imports -from twisted.python import logfile, runtime - - -class LogFileTestCase(unittest.TestCase): - """ - Test the rotating log file. - """ - - def setUp(self): - self.dir = self.mktemp() - os.makedirs(self.dir) - self.name = "test.log" - self.path = os.path.join(self.dir, self.name) - - - def tearDown(self): - """ - Restore back write rights on created paths: if tests modified the - rights, that will allow the paths to be removed easily afterwards. - """ - os.chmod(self.dir, 0777) - if os.path.exists(self.path): - os.chmod(self.path, 0777) - - - def testWriting(self): - log = logfile.LogFile(self.name, self.dir) - log.write("123") - log.write("456") - log.flush() - log.write("7890") - log.close() - - f = open(self.path, "r") - self.assertEquals(f.read(), "1234567890") - f.close() - - def testRotation(self): - # this logfile should rotate every 10 bytes - log = logfile.LogFile(self.name, self.dir, rotateLength=10) - - # test automatic rotation - log.write("123") - log.write("4567890") - log.write("1" * 11) - self.assert_(os.path.exists("%s.1" % self.path)) - self.assert_(not os.path.exists("%s.2" % self.path)) - log.write('') - self.assert_(os.path.exists("%s.1" % self.path)) - self.assert_(os.path.exists("%s.2" % self.path)) - self.assert_(not os.path.exists("%s.3" % self.path)) - log.write("3") - self.assert_(not os.path.exists("%s.3" % self.path)) - - # test manual rotation - log.rotate() - self.assert_(os.path.exists("%s.3" % self.path)) - self.assert_(not os.path.exists("%s.4" % self.path)) - log.close() - - self.assertEquals(log.listLogs(), [1, 2, 3]) - - def testAppend(self): - log = logfile.LogFile(self.name, self.dir) - log.write("0123456789") - log.close() - - log = logfile.LogFile(self.name, self.dir) - self.assertEquals(log.size, 10) - self.assertEquals(log._file.tell(), log.size) - log.write("abc") - self.assertEquals(log.size, 13) - self.assertEquals(log._file.tell(), log.size) - f = log._file - f.seek(0, 0) - self.assertEquals(f.read(), "0123456789abc") - log.close() - - def testLogReader(self): - log = logfile.LogFile(self.name, self.dir) - log.write("abc\n") - log.write("def\n") - log.rotate() - log.write("ghi\n") - log.flush() - - # check reading logs - self.assertEquals(log.listLogs(), [1]) - reader = log.getCurrentLog() - reader._file.seek(0) - self.assertEquals(reader.readLines(), ["ghi\n"]) - self.assertEquals(reader.readLines(), []) - reader.close() - reader = log.getLog(1) - self.assertEquals(reader.readLines(), ["abc\n", "def\n"]) - self.assertEquals(reader.readLines(), []) - reader.close() - - # check getting illegal log readers - self.assertRaises(ValueError, log.getLog, 2) - self.assertRaises(TypeError, log.getLog, "1") - - # check that log numbers are higher for older logs - log.rotate() - self.assertEquals(log.listLogs(), [1, 2]) - reader = log.getLog(1) - reader._file.seek(0) - self.assertEquals(reader.readLines(), ["ghi\n"]) - self.assertEquals(reader.readLines(), []) - reader.close() - reader = log.getLog(2) - self.assertEquals(reader.readLines(), ["abc\n", "def\n"]) - self.assertEquals(reader.readLines(), []) - reader.close() - - def testModePreservation(self): - """ - Check rotated files have same permissions as original. - """ - f = open(self.path, "w").close() - os.chmod(self.path, 0707) - mode = os.stat(self.path)[stat.ST_MODE] - log = logfile.LogFile(self.name, self.dir) - log.write("abc") - log.rotate() - self.assertEquals(mode, os.stat(self.path)[stat.ST_MODE]) - - - def test_noPermission(self): - """ - Check it keeps working when permission on dir changes. - """ - log = logfile.LogFile(self.name, self.dir) - log.write("abc") - - # change permissions so rotation would fail - os.chmod(self.dir, 0444) - - # if this succeeds, chmod doesn't restrict us, so we can't - # do the test - try: - f = open(os.path.join(self.dir,"xxx"), "w") - except (OSError, IOError): - pass - else: - f.close() - return - - log.rotate() # this should not fail - - log.write("def") - log.flush() - - f = log._file - self.assertEquals(f.tell(), 6) - f.seek(0, 0) - self.assertEquals(f.read(), "abcdef") - log.close() - - - def test_maxNumberOfLog(self): - """ - Test it respect the limit on the number of files when maxRotatedFiles - is not None. - """ - log = logfile.LogFile(self.name, self.dir, rotateLength=10, - maxRotatedFiles=3) - log.write("1" * 11) - log.write("2" * 11) - self.failUnless(os.path.exists("%s.1" % self.path)) - - log.write("3" * 11) - self.failUnless(os.path.exists("%s.2" % self.path)) - - log.write("4" * 11) - self.failUnless(os.path.exists("%s.3" % self.path)) - self.assertEquals(file("%s.3" % self.path).read(), "1" * 11) - - log.write("5" * 11) - self.assertEquals(file("%s.3" % self.path).read(), "2" * 11) - self.failUnless(not os.path.exists("%s.4" % self.path)) - - def test_fromFullPath(self): - """ - Test the fromFullPath method. - """ - log1 = logfile.LogFile(self.name, self.dir, 10, defaultMode=0777) - log2 = logfile.LogFile.fromFullPath(self.path, 10, defaultMode=0777) - self.assertEquals(log1.name, log2.name) - self.assertEquals(os.path.abspath(log1.path), log2.path) - self.assertEquals(log1.rotateLength, log2.rotateLength) - self.assertEquals(log1.defaultMode, log2.defaultMode) - - def test_defaultPermissions(self): - """ - Test the default permission of the log file: if the file exist, it - should keep the permission. - """ - f = file(self.path, "w") - os.chmod(self.path, 0707) - currentMode = stat.S_IMODE(os.stat(self.path)[stat.ST_MODE]) - f.close() - log1 = logfile.LogFile(self.name, self.dir) - self.assertEquals(stat.S_IMODE(os.stat(self.path)[stat.ST_MODE]), - currentMode) - - def test_specifiedPermissions(self): - """ - Test specifying the permissions used on the log file. - """ - log1 = logfile.LogFile(self.name, self.dir, defaultMode=0066) - mode = stat.S_IMODE(os.stat(self.path)[stat.ST_MODE]) - if runtime.platform.isWindows(): - # The only thing we can get here is global read-only - self.assertEquals(mode, 0444) - else: - self.assertEquals(mode, 0066) - - -class RiggedDailyLogFile(logfile.DailyLogFile): - _clock = 0.0 - - def _openFile(self): - logfile.DailyLogFile._openFile(self) - # rig the date to match _clock, not mtime - self.lastDate = self.toDate() - - def toDate(self, *args): - if args: - return time.gmtime(*args)[:3] - return time.gmtime(self._clock)[:3] - -class DailyLogFileTestCase(unittest.TestCase): - """ - Test rotating log file. - """ - - def setUp(self): - self.dir = self.mktemp() - os.makedirs(self.dir) - self.name = "testdaily.log" - self.path = os.path.join(self.dir, self.name) - - - def testWriting(self): - log = RiggedDailyLogFile(self.name, self.dir) - log.write("123") - log.write("456") - log.flush() - log.write("7890") - log.close() - - f = open(self.path, "r") - self.assertEquals(f.read(), "1234567890") - f.close() - - def testRotation(self): - # this logfile should rotate every 10 bytes - log = RiggedDailyLogFile(self.name, self.dir) - days = [(self.path + '.' + log.suffix(day * 86400)) for day in range(3)] - - # test automatic rotation - log._clock = 0.0 # 1970/01/01 00:00.00 - log.write("123") - log._clock = 43200 # 1970/01/01 12:00.00 - log.write("4567890") - log._clock = 86400 # 1970/01/02 00:00.00 - log.write("1" * 11) - self.assert_(os.path.exists(days[0])) - self.assert_(not os.path.exists(days[1])) - log._clock = 172800 # 1970/01/03 00:00.00 - log.write('') - self.assert_(os.path.exists(days[0])) - self.assert_(os.path.exists(days[1])) - self.assert_(not os.path.exists(days[2])) - log._clock = 259199 # 1970/01/03 23:59.59 - log.write("3") - self.assert_(not os.path.exists(days[2])) - diff --git a/tools/buildbot/pylibs/twisted/test/test_loopback.py b/tools/buildbot/pylibs/twisted/test/test_loopback.py deleted file mode 100644 index 53b2bfa..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_loopback.py +++ /dev/null @@ -1,328 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Test case for twisted.protocols.loopback -""" - -from zope.interface import implements - -from twisted.trial import unittest -from twisted.trial.util import suppress as SUPPRESS -from twisted.protocols import basic, loopback -from twisted.internet import defer -from twisted.internet.protocol import Protocol -from twisted.internet.defer import Deferred -from twisted.internet.interfaces import IAddress, IPushProducer, IPullProducer -from twisted.internet import reactor - - -class SimpleProtocol(basic.LineReceiver): - def __init__(self): - self.conn = defer.Deferred() - self.lines = [] - self.connLost = [] - - def connectionMade(self): - self.conn.callback(None) - - def lineReceived(self, line): - self.lines.append(line) - - def connectionLost(self, reason): - self.connLost.append(reason) - - -class DoomProtocol(SimpleProtocol): - i = 0 - def lineReceived(self, line): - self.i += 1 - if self.i < 4: - # by this point we should have connection closed, - # but just in case we didn't we won't ever send 'Hello 4' - self.sendLine("Hello %d" % self.i) - SimpleProtocol.lineReceived(self, line) - if self.lines[-1] == "Hello 3": - self.transport.loseConnection() - - -class LoopbackTestCaseMixin: - def testRegularFunction(self): - s = SimpleProtocol() - c = SimpleProtocol() - - def sendALine(result): - s.sendLine("THIS IS LINE ONE!") - s.transport.loseConnection() - s.conn.addCallback(sendALine) - - def check(ignored): - self.assertEquals(c.lines, ["THIS IS LINE ONE!"]) - self.assertEquals(len(s.connLost), 1) - self.assertEquals(len(c.connLost), 1) - d = defer.maybeDeferred(self.loopbackFunc, s, c) - d.addCallback(check) - return d - - def testSneakyHiddenDoom(self): - s = DoomProtocol() - c = DoomProtocol() - - def sendALine(result): - s.sendLine("DOOM LINE") - s.conn.addCallback(sendALine) - - def check(ignored): - self.assertEquals(s.lines, ['Hello 1', 'Hello 2', 'Hello 3']) - self.assertEquals(c.lines, ['DOOM LINE', 'Hello 1', 'Hello 2', 'Hello 3']) - self.assertEquals(len(s.connLost), 1) - self.assertEquals(len(c.connLost), 1) - d = defer.maybeDeferred(self.loopbackFunc, s, c) - d.addCallback(check) - return d - - - -class LoopbackTestCase(LoopbackTestCaseMixin, unittest.TestCase): - loopbackFunc = staticmethod(loopback.loopback) - - def testRegularFunction(self): - """ - Suppress loopback deprecation warning. - """ - return LoopbackTestCaseMixin.testRegularFunction(self) - testRegularFunction.suppress = [ - SUPPRESS(message="loopback\(\) is deprecated", - category=DeprecationWarning)] - - - -class LoopbackAsyncTestCase(LoopbackTestCase): - loopbackFunc = staticmethod(loopback.loopbackAsync) - - - def test_makeConnection(self): - """ - Test that the client and server protocol both have makeConnection - invoked on them by loopbackAsync. - """ - class TestProtocol(Protocol): - transport = None - def makeConnection(self, transport): - self.transport = transport - - server = TestProtocol() - client = TestProtocol() - loopback.loopbackAsync(server, client) - self.failIfEqual(client.transport, None) - self.failIfEqual(server.transport, None) - - - def _hostpeertest(self, get, testServer): - """ - Test one of the permutations of client/server host/peer. - """ - class TestProtocol(Protocol): - def makeConnection(self, transport): - Protocol.makeConnection(self, transport) - self.onConnection.callback(transport) - - if testServer: - server = TestProtocol() - d = server.onConnection = Deferred() - client = Protocol() - else: - server = Protocol() - client = TestProtocol() - d = client.onConnection = Deferred() - - loopback.loopbackAsync(server, client) - - def connected(transport): - host = getattr(transport, get)() - self.failUnless(IAddress.providedBy(host)) - - return d.addCallback(connected) - - - def test_serverHost(self): - """ - Test that the server gets a transport with a properly functioning - implementation of L{ITransport.getHost}. - """ - return self._hostpeertest("getHost", True) - - - def test_serverPeer(self): - """ - Like C{test_serverHost} but for L{ITransport.getPeer} - """ - return self._hostpeertest("getPeer", True) - - - def test_clientHost(self, get="getHost"): - """ - Test that the client gets a transport with a properly functioning - implementation of L{ITransport.getHost}. - """ - return self._hostpeertest("getHost", False) - - - def test_clientPeer(self): - """ - Like C{test_clientHost} but for L{ITransport.getPeer}. - """ - return self._hostpeertest("getPeer", False) - - - def _greetingtest(self, write, testServer): - """ - Test one of the permutations of write/writeSequence client/server. - """ - class GreeteeProtocol(Protocol): - bytes = "" - def dataReceived(self, bytes): - self.bytes += bytes - if self.bytes == "bytes": - self.received.callback(None) - - class GreeterProtocol(Protocol): - def connectionMade(self): - getattr(self.transport, write)("bytes") - - if testServer: - server = GreeterProtocol() - client = GreeteeProtocol() - d = client.received = Deferred() - else: - server = GreeteeProtocol() - d = server.received = Deferred() - client = GreeterProtocol() - - loopback.loopbackAsync(server, client) - return d - - - def test_clientGreeting(self): - """ - Test that on a connection where the client speaks first, the server - receives the bytes sent by the client. - """ - return self._greetingtest("write", False) - - - def test_clientGreetingSequence(self): - """ - Like C{test_clientGreeting}, but use C{writeSequence} instead of - C{write} to issue the greeting. - """ - return self._greetingtest("writeSequence", False) - - - def test_serverGreeting(self, write="write"): - """ - Test that on a connection where the server speaks first, the client - receives the bytes sent by the server. - """ - return self._greetingtest("write", True) - - - def test_serverGreetingSequence(self): - """ - Like C{test_serverGreeting}, but use C{writeSequence} instead of - C{write} to issue the greeting. - """ - return self._greetingtest("writeSequence", True) - - - def _producertest(self, producerClass): - toProduce = map(str, range(0, 10)) - - class ProducingProtocol(Protocol): - def connectionMade(self): - self.producer = producerClass(list(toProduce)) - self.producer.start(self.transport) - - class ReceivingProtocol(Protocol): - bytes = "" - def dataReceived(self, bytes): - self.bytes += bytes - if self.bytes == ''.join(toProduce): - self.received.callback((client, server)) - - server = ProducingProtocol() - client = ReceivingProtocol() - client.received = Deferred() - - loopback.loopbackAsync(server, client) - return client.received - - - def test_pushProducer(self): - """ - Test a push producer registered against a loopback transport. - """ - class PushProducer(object): - implements(IPushProducer) - resumed = False - - def __init__(self, toProduce): - self.toProduce = toProduce - - def resumeProducing(self): - self.resumed = True - - def start(self, consumer): - self.consumer = consumer - consumer.registerProducer(self, True) - self._produceAndSchedule() - - def _produceAndSchedule(self): - if self.toProduce: - self.consumer.write(self.toProduce.pop(0)) - reactor.callLater(0, self._produceAndSchedule) - else: - self.consumer.unregisterProducer() - d = self._producertest(PushProducer) - - def finished((client, server)): - self.failIf( - server.producer.resumed, - "Streaming producer should not have been resumed.") - d.addCallback(finished) - return d - - - def test_pullProducer(self): - """ - Test a pull producer registered against a loopback transport. - """ - class PullProducer(object): - implements(IPullProducer) - - def __init__(self, toProduce): - self.toProduce = toProduce - - def start(self, consumer): - self.consumer = consumer - self.consumer.registerProducer(self, False) - - def resumeProducing(self): - self.consumer.write(self.toProduce.pop(0)) - if not self.toProduce: - self.consumer.unregisterProducer() - return self._producertest(PullProducer) - - -class LoopbackTCPTestCase(LoopbackTestCase): - loopbackFunc = staticmethod(loopback.loopbackTCP) - - -class LoopbackUNIXTestCase(LoopbackTestCase): - loopbackFunc = staticmethod(loopback.loopbackUNIX) - - def setUp(self): - from twisted.internet import reactor, interfaces - if interfaces.IReactorUNIX(reactor, None) is None: - raise unittest.SkipTest("Current reactor does not support UNIX sockets") diff --git a/tools/buildbot/pylibs/twisted/test/test_manhole.py b/tools/buildbot/pylibs/twisted/test/test_manhole.py deleted file mode 100644 index 254df59..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_manhole.py +++ /dev/null @@ -1,75 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -from twisted.trial import unittest -from twisted.manhole import service -from twisted.spread.util import LocalAsRemote - -class Dummy: - pass - -class DummyTransport: - def getHost(self): - return 'INET', '127.0.0.1', 0 - -class DummyManholeClient(LocalAsRemote): - zero = 0 - broker = Dummy() - broker.transport = DummyTransport() - - def __init__(self): - self.messages = [] - - def console(self, messages): - self.messages.extend(messages) - - def receiveExplorer(self, xplorer): - pass - - def setZero(self): - self.zero = len(self.messages) - - def getMessages(self): - return self.messages[self.zero:] - - # local interface - sync_console = console - sync_receiveExplorer = receiveExplorer - sync_setZero = setZero - sync_getMessages = getMessages - -class ManholeTest(unittest.TestCase): - """Various tests for the manhole service. - - Both the the importIdentity and importMain tests are known to fail - when the __name__ in the manhole namespace is set to certain - values. - """ - def setUp(self): - self.service = service.Service() - self.p = service.Perspective(self.service) - self.client = DummyManholeClient() - self.p.attached(self.client, None) - - def test_importIdentity(self): - """Making sure imported module is the same as one previously loaded. - """ - self.p.perspective_do("from twisted.manhole import service") - self.client.setZero() - self.p.perspective_do("int(service is sys.modules['twisted.manhole.service'])") - msg = self.client.getMessages()[0] - self.failUnlessEqual(msg, ('result',"1\n")) - - def test_importMain(self): - """Trying to import __main__""" - self.client.setZero() - self.p.perspective_do("import __main__") - if self.client.getMessages(): - msg = self.client.getMessages()[0] - if msg[0] in ("exception","stderr"): - self.fail(msg[1]) - -#if __name__=='__main__': -# unittest.main() diff --git a/tools/buildbot/pylibs/twisted/test/test_memcache.py b/tools/buildbot/pylibs/twisted/test/test_memcache.py deleted file mode 100644 index ea8fb40..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_memcache.py +++ /dev/null @@ -1,510 +0,0 @@ -# Copyright (c) 2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test the memcache client protocol. -""" - -from twisted.protocols.memcache import MemCacheProtocol, NoSuchCommand -from twisted.protocols.memcache import ClientError, ServerError - -from twisted.trial.unittest import TestCase -from twisted.test.proto_helpers import StringTransportWithDisconnection -from twisted.internet.task import Clock -from twisted.internet.defer import Deferred, gatherResults, TimeoutError - - - -class MemCacheTestCase(TestCase): - """ - Test client protocol class L{MemCacheProtocol}. - """ - - def setUp(self): - """ - Create a memcache client, connect it to a string protocol, and make it - use a deterministic clock. - """ - self.proto = MemCacheProtocol() - self.clock = Clock() - self.proto.callLater = self.clock.callLater - self.transport = StringTransportWithDisconnection() - self.transport.protocol = self.proto - self.proto.makeConnection(self.transport) - - - def _test(self, d, send, recv, result): - """ - Shortcut method for classic tests. - - @param d: the resulting deferred from the memcache command. - @type d: C{Deferred} - - @param send: the expected data to be sent. - @type send: C{str} - - @param recv: the data to simulate as reception. - @type recv: C{str} - - @param result: the expected result. - @type result: C{any} - """ - def cb(res): - self.assertEquals(res, result) - self.assertEquals(self.transport.value(), send) - d.addCallback(cb) - self.proto.dataReceived(recv) - return d - - - def test_get(self): - """ - L{MemCacheProtocol.get} should return a L{Deferred} which is - called back with the value and the flag associated with the given key - if the server returns a successful result. - """ - return self._test(self.proto.get("foo"), "get foo\r\n", - "VALUE foo 0 3\r\nbar\r\nEND\r\n", (0, "bar")) - - - def test_emptyGet(self): - """ - Test getting a non-available key: it should succeed but return C{None} - as value and C{0} as flag. - """ - return self._test(self.proto.get("foo"), "get foo\r\n", - "END\r\n", (0, None)) - - - def test_set(self): - """ - L{MemCacheProtocol.set} should return a L{Deferred} which is - called back with C{True} when the operation succeeds. - """ - return self._test(self.proto.set("foo", "bar"), - "set foo 0 0 3\r\nbar\r\n", "STORED\r\n", True) - - - def test_add(self): - """ - L{MemCacheProtocol.add} should return a L{Deferred} which is - called back with C{True} when the operation succeeds. - """ - return self._test(self.proto.add("foo", "bar"), - "add foo 0 0 3\r\nbar\r\n", "STORED\r\n", True) - - - def test_replace(self): - """ - L{MemCacheProtocol.replace} should return a L{Deferred} which - is called back with C{True} when the operation succeeds. - """ - return self._test(self.proto.replace("foo", "bar"), - "replace foo 0 0 3\r\nbar\r\n", "STORED\r\n", True) - - - def test_errorAdd(self): - """ - Test an erroneous add: if a L{MemCacheProtocol.add} is called but the - key already exists on the server, it returns a B{NOT STORED} answer, - which should callback the resulting L{Deferred} with C{False}. - """ - return self._test(self.proto.add("foo", "bar"), - "add foo 0 0 3\r\nbar\r\n", "NOT STORED\r\n", False) - - - def test_errorReplace(self): - """ - Test an erroneous replace: if a L{MemCacheProtocol.replace} is called - but the key doesn't exist on the server, it returns a B{NOT STORED} - answer, which should callback the resulting L{Deferred} with C{False}. - """ - return self._test(self.proto.replace("foo", "bar"), - "replace foo 0 0 3\r\nbar\r\n", "NOT STORED\r\n", False) - - - def test_delete(self): - """ - L{MemCacheProtocol.delete} should return a L{Deferred} which is - called back with C{True} when the server notifies a success. - """ - return self._test(self.proto.delete("bar"), "delete bar\r\n", - "DELETED\r\n", True) - - - def test_errorDelete(self): - """ - Test a error during a delete: if key doesn't exist on the server, it - returns a B{NOT FOUND} answer which should callback the resulting - L{Deferred} with C{False}. - """ - return self._test(self.proto.delete("bar"), "delete bar\r\n", - "NOT FOUND\r\n", False) - - - def test_increment(self): - """ - Test incrementing a variable: L{MemCacheProtocol.increment} should - return a L{Deferred} which is called back with the incremented value of - the given key. - """ - return self._test(self.proto.increment("foo"), "incr foo 1\r\n", - "4\r\n", 4) - - - def test_decrement(self): - """ - Test decrementing a variable: L{MemCacheProtocol.decrement} should - return a L{Deferred} which is called back with the decremented value of - the given key. - """ - return self._test( - self.proto.decrement("foo"), "decr foo 1\r\n", "5\r\n", 5) - - - def test_incrementVal(self): - """ - L{MemCacheProtocol.increment} takes an optional argument C{value} which - should replace the default value of 1 when specified. - """ - return self._test(self.proto.increment("foo", 8), "incr foo 8\r\n", - "4\r\n", 4) - - - def test_decrementVal(self): - """ - L{MemCacheProtocol.decrement} takes an optional argument C{value} which - should replace the default value of 1 when specified. - """ - return self._test(self.proto.decrement("foo", 3), "decr foo 3\r\n", - "5\r\n", 5) - - - def test_stats(self): - """ - Test retrieving server statistics via the L{MemCacheProtocol.stats} - command: it should parse the data sent by the server and call back the - resulting L{Deferred} with a dictionary of the received statistics. - """ - return self._test(self.proto.stats(), "stats\r\n", - "STAT foo bar\r\nSTAT egg spam\r\nEND\r\n", - {"foo": "bar", "egg": "spam"}) - - - def test_version(self): - """ - Test version retrieval via the L{MemCacheProtocol.version} command: it - should return a L{Deferred} which is called back with the version sent - by the server. - """ - return self._test(self.proto.version(), "version\r\n", - "VERSION 1.1\r\n", "1.1") - - - def test_flushAll(self): - """ - L{MemCacheProtocol.flushAll} should return a L{Deferred} which is - called back with C{True} if the server acknowledges success. - """ - return self._test(self.proto.flushAll(), "flush_all\r\n", - "OK\r\n", True) - - - def test_invalidGetResponse(self): - """ - If the value returned doesn't match the expected key of the current, we - should get an error in L{MemCacheProtocol.dataReceived}. - """ - self.proto.get("foo") - s = "spamegg" - self.assertRaises(RuntimeError, - self.proto.dataReceived, - "VALUE bar 0 %s\r\n%s\r\nEND\r\n" % (len(s), s)) - - - def test_timeOut(self): - """ - Test the timeout on outgoing requests: when timeout is detected, all - current commands should fail with a L{TimeoutError}, and the - connection should be closed. - """ - d1 = self.proto.get("foo") - d2 = self.proto.get("bar") - d3 = Deferred() - self.proto.connectionLost = d3.callback - - self.clock.advance(self.proto.persistentTimeOut) - self.assertFailure(d1, TimeoutError) - self.assertFailure(d2, TimeoutError) - def checkMessage(error): - self.assertEquals(str(error), "Connection timeout") - d1.addCallback(checkMessage) - return gatherResults([d1, d2, d3]) - - - def test_timeoutRemoved(self): - """ - When a request gets a response, no pending timeout call should remain - around. - """ - d = self.proto.get("foo") - - self.clock.advance(self.proto.persistentTimeOut - 1) - self.proto.dataReceived("VALUE foo 0 3\r\nbar\r\nEND\r\n") - - def check(result): - self.assertEquals(result, (0, "bar")) - self.assertEquals(len(self.clock.calls), 0) - d.addCallback(check) - return d - - - def test_timeOutRaw(self): - """ - Test the timeout when raw mode was started: the timeout should not be - reset until all the data has been received, so we can have a - L{TimeoutError} when waiting for raw data. - """ - d1 = self.proto.get("foo") - d2 = Deferred() - self.proto.connectionLost = d2.callback - - self.proto.dataReceived("VALUE foo 0 10\r\n12345") - self.clock.advance(self.proto.persistentTimeOut) - self.assertFailure(d1, TimeoutError) - return gatherResults([d1, d2]) - - - def test_timeOutStat(self): - """ - Test the timeout when stat command has started: the timeout should not - be reset until the final B{END} is received. - """ - d1 = self.proto.stats() - d2 = Deferred() - self.proto.connectionLost = d2.callback - - self.proto.dataReceived("STAT foo bar\r\n") - self.clock.advance(self.proto.persistentTimeOut) - self.assertFailure(d1, TimeoutError) - return gatherResults([d1, d2]) - - - def test_timeoutPipelining(self): - """ - When two requests are sent, a timeout call should remain around for the - second request, and its timeout time should be correct. - """ - d1 = self.proto.get("foo") - d2 = self.proto.get("bar") - d3 = Deferred() - self.proto.connectionLost = d3.callback - - self.clock.advance(self.proto.persistentTimeOut - 1) - self.proto.dataReceived("VALUE foo 0 3\r\nbar\r\nEND\r\n") - - def check(result): - self.assertEquals(result, (0, "bar")) - self.assertEquals(len(self.clock.calls), 1) - for i in range(self.proto.persistentTimeOut): - self.clock.advance(1) - return self.assertFailure(d2, TimeoutError).addCallback(checkTime) - def checkTime(ignored): - # Check that the timeout happened C{self.proto.persistentTimeOut} - # after the last response - self.assertEquals(self.clock.seconds(), - 2 * self.proto.persistentTimeOut - 1) - d1.addCallback(check) - return d1 - - - def test_timeoutNotReset(self): - """ - Check that timeout is not resetted for every command, but keep the - timeout from the first command without response. - """ - d1 = self.proto.get("foo") - d3 = Deferred() - self.proto.connectionLost = d3.callback - - self.clock.advance(self.proto.persistentTimeOut - 1) - d2 = self.proto.get("bar") - self.clock.advance(1) - self.assertFailure(d1, TimeoutError) - self.assertFailure(d2, TimeoutError) - return gatherResults([d1, d2, d3]) - - - def test_tooLongKey(self): - """ - Test that an error is raised when trying to use a too long key: the - called command should return a L{Deferred} which fail with a - L{ClientError}. - """ - d1 = self.assertFailure(self.proto.set("a" * 500, "bar"), ClientError) - d2 = self.assertFailure(self.proto.increment("a" * 500), ClientError) - d3 = self.assertFailure(self.proto.get("a" * 500), ClientError) - d4 = self.assertFailure(self.proto.append("a" * 500, "bar"), ClientError) - d5 = self.assertFailure(self.proto.prepend("a" * 500, "bar"), ClientError) - return gatherResults([d1, d2, d3, d4, d5]) - - - def test_invalidCommand(self): - """ - When an unknown command is sent directly (not through public API), the - server answers with an B{ERROR} token, and the command should fail with - L{NoSuchCommand}. - """ - d = self.proto._set("egg", "foo", "bar", 0, 0, "") - self.assertEquals(self.transport.value(), "egg foo 0 0 3\r\nbar\r\n") - self.assertFailure(d, NoSuchCommand) - self.proto.dataReceived("ERROR\r\n") - return d - - - def test_clientError(self): - """ - Test the L{ClientError} error: when the server send a B{CLIENT_ERROR} - token, the originating command should fail with L{ClientError}, and the - error should contain the text sent by the server. - """ - a = "eggspamm" - d = self.proto.set("foo", a) - self.assertEquals(self.transport.value(), - "set foo 0 0 8\r\neggspamm\r\n") - self.assertFailure(d, ClientError) - def check(err): - self.assertEquals(str(err), "We don't like egg and spam") - d.addCallback(check) - self.proto.dataReceived("CLIENT_ERROR We don't like egg and spam\r\n") - return d - - - def test_serverError(self): - """ - Test the L{ServerError} error: when the server send a B{SERVER_ERROR} - token, the originating command should fail with L{ServerError}, and the - error should contain the text sent by the server. - """ - a = "eggspamm" - d = self.proto.set("foo", a) - self.assertEquals(self.transport.value(), - "set foo 0 0 8\r\neggspamm\r\n") - self.assertFailure(d, ServerError) - def check(err): - self.assertEquals(str(err), "zomg") - d.addCallback(check) - self.proto.dataReceived("SERVER_ERROR zomg\r\n") - return d - - - def test_unicodeKey(self): - """ - Using a non-string key as argument to commands should raise an error. - """ - d1 = self.assertFailure(self.proto.set(u"foo", "bar"), ClientError) - d2 = self.assertFailure(self.proto.increment(u"egg"), ClientError) - d3 = self.assertFailure(self.proto.get(1), ClientError) - d4 = self.assertFailure(self.proto.delete(u"bar"), ClientError) - d5 = self.assertFailure(self.proto.append(u"foo", "bar"), ClientError) - d6 = self.assertFailure(self.proto.prepend(u"foo", "bar"), ClientError) - return gatherResults([d1, d2, d3, d4, d5, d6]) - - - def test_unicodeValue(self): - """ - Using a non-string value should raise an error. - """ - return self.assertFailure(self.proto.set("foo", u"bar"), ClientError) - - - def test_pipelining(self): - """ - Test that multiple requests can be sent subsequently to the server, and - that the protocol order the responses correctly and dispatch to the - corresponding client command. - """ - d1 = self.proto.get("foo") - d1.addCallback(self.assertEquals, (0, "bar")) - d2 = self.proto.set("bar", "spamspamspam") - d2.addCallback(self.assertEquals, True) - d3 = self.proto.get("egg") - d3.addCallback(self.assertEquals, (0, "spam")) - self.assertEquals(self.transport.value(), - "get foo\r\nset bar 0 0 12\r\nspamspamspam\r\nget egg\r\n") - self.proto.dataReceived("VALUE foo 0 3\r\nbar\r\nEND\r\n" - "STORED\r\n" - "VALUE egg 0 4\r\nspam\r\nEND\r\n") - return gatherResults([d1, d2, d3]) - - - def test_getInChunks(self): - """ - If the value retrieved by a C{get} arrive in chunks, the protocol - should be able to reconstruct it and to produce the good value. - """ - d = self.proto.get("foo") - d.addCallback(self.assertEquals, (0, "0123456789")) - self.assertEquals(self.transport.value(), "get foo\r\n") - self.proto.dataReceived("VALUE foo 0 10\r\n0123456") - self.proto.dataReceived("789") - self.proto.dataReceived("\r\nEND") - self.proto.dataReceived("\r\n") - return d - - - def test_append(self): - """ - L{MemCacheProtocol.append} behaves like a L{MemCacheProtocol.set} - method: it should return a L{Deferred} which is called back with - C{True} when the operation succeeds. - """ - return self._test(self.proto.append("foo", "bar"), - "append foo 0 0 3\r\nbar\r\n", "STORED\r\n", True) - - - def test_prepend(self): - """ - L{MemCacheProtocol.prepend} behaves like a L{MemCacheProtocol.set} - method: it should return a L{Deferred} which is called back with - C{True} when the operation succeeds. - """ - return self._test(self.proto.prepend("foo", "bar"), - "prepend foo 0 0 3\r\nbar\r\n", "STORED\r\n", True) - - - def test_gets(self): - """ - L{MemCacheProtocol.get} should handle an additional cas result when - C{withIdentifier} is C{True} and forward it in the resulting - L{Deferred}. - """ - return self._test(self.proto.get("foo", True), "gets foo\r\n", - "VALUE foo 0 3 1234\r\nbar\r\nEND\r\n", (0, "1234", "bar")) - - - def test_emptyGets(self): - """ - Test getting a non-available key with gets: it should succeed but - return C{None} as value, C{0} as flag and an empty cas value. - """ - return self._test(self.proto.get("foo", True), "gets foo\r\n", - "END\r\n", (0, "", None)) - - - def test_checkAndSet(self): - """ - L{MemCacheProtocol.checkAndSet} passes an additional cas identifier that the - server should handle to check if the data has to be updated. - """ - return self._test(self.proto.checkAndSet("foo", "bar", cas="1234"), - "cas foo 0 0 3 1234\r\nbar\r\n", "STORED\r\n", True) - - - def test_casUnknowKey(self): - """ - When L{MemCacheProtocol.checkAndSet} response is C{EXISTS}, the resulting - L{Deferred} should fire with C{False}. - """ - return self._test(self.proto.checkAndSet("foo", "bar", cas="1234"), - "cas foo 0 0 3 1234\r\nbar\r\n", "EXISTS\r\n", False) diff --git a/tools/buildbot/pylibs/twisted/test/test_modules.py b/tools/buildbot/pylibs/twisted/test/test_modules.py deleted file mode 100644 index 9b764f5..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_modules.py +++ /dev/null @@ -1,371 +0,0 @@ -# Copyright (c) 2006-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for twisted.python.modules, abstract access to imported or importable -objects. -""" - -import os -import sys -import itertools -import zipfile -import compileall - -from twisted.trial.unittest import TestCase - -from twisted.python import modules -from twisted.python.filepath import FilePath -from twisted.python.reflect import namedAny - -from twisted.test.test_paths import zipit - - - -class PySpaceTestCase(TestCase): - - def findByIteration(self, modname, where=modules, importPackages=False): - """ - You don't ever actually want to do this, so it's not in the public API, but - sometimes we want to compare the result of an iterative call with a - lookup call and make sure they're the same for test purposes. - """ - for modinfo in where.walkModules(importPackages=importPackages): - if modinfo.name == modname: - return modinfo - self.fail("Unable to find module %r through iteration." % (modname,)) - - - -class BasicTests(PySpaceTestCase): - def test_nonexistentPaths(self): - """ - Verify that L{modules.walkModules} ignores entries in sys.path which - do not exist in the filesystem. - """ - existentPath = FilePath(self.mktemp()) - os.makedirs(existentPath.child("test_package").path) - existentPath.child("test_package").child("__init__.py").setContent("") - - nonexistentPath = FilePath(self.mktemp()) - self.failIf(nonexistentPath.exists()) - - originalSearchPaths = sys.path[:] - sys.path[:] = [existentPath.path] - try: - expected = [modules.getModule("test_package")] - - beforeModules = list(modules.walkModules()) - sys.path.append(nonexistentPath.path) - afterModules = list(modules.walkModules()) - finally: - sys.path[:] = originalSearchPaths - - self.assertEqual(beforeModules, expected) - self.assertEqual(afterModules, expected) - - - def test_nonDirectoryPaths(self): - """ - Verify that L{modules.walkModules} ignores entries in sys.path which - refer to regular files in the filesystem. - """ - existentPath = FilePath(self.mktemp()) - os.makedirs(existentPath.child("test_package").path) - existentPath.child("test_package").child("__init__.py").setContent("") - - nonDirectoryPath = FilePath(self.mktemp()) - self.failIf(nonDirectoryPath.exists()) - nonDirectoryPath.setContent("zip file or whatever\n") - - originalSearchPaths = sys.path[:] - sys.path[:] = [existentPath.path] - try: - beforeModules = list(modules.walkModules()) - sys.path.append(nonDirectoryPath.path) - afterModules = list(modules.walkModules()) - finally: - sys.path[:] = originalSearchPaths - - self.assertEqual(beforeModules, afterModules) - - - def test_twistedShowsUp(self): - """ - Scrounge around in the top-level module namespace and make sure that - Twisted shows up, and that the module thusly obtained is the same as - the module that we find when we look for it explicitly by name. - """ - self.assertEquals(modules.getModule('twisted'), - self.findByIteration("twisted")) - - - def test_dottedNames(self): - """ - Verify that the walkModules APIs will give us back subpackages, not just - subpackages. - """ - self.assertEquals( - modules.getModule('twisted.python'), - self.findByIteration("twisted.python", - where=modules.getModule('twisted'))) - - - def test_onlyTopModules(self): - """ - Verify that the iterModules API will only return top-level modules and - packages, not submodules or subpackages. - """ - for module in modules.iterModules(): - self.failIf( - '.' in module.name, - "no nested modules should be returned from iterModules: %r" - % (module.filePath)) - - - def test_loadPackagesAndModules(self): - """ - Verify that we can locate and load packages, modules, submodules, and - subpackages. - """ - for n in ['os', - 'twisted', - 'twisted.python', - 'twisted.python.reflect']: - m = namedAny(n) - self.failUnlessIdentical( - modules.getModule(n).load(), - m) - self.failUnlessIdentical( - self.findByIteration(n).load(), - m) - - - def test_pathEntriesOnPath(self): - """ - Verify that path entries discovered via module loading are, in fact, on - sys.path somewhere. - """ - for n in ['os', - 'twisted', - 'twisted.python', - 'twisted.python.reflect']: - self.failUnlessIn( - modules.getModule(n).pathEntry.filePath.path, - sys.path) - - - def test_alwaysPreferPy(self): - """ - Verify that .py files will always be preferred to .pyc files, regardless of - directory listing order. - """ - mypath = FilePath(self.mktemp()) - mypath.createDirectory() - pp = modules.PythonPath(sysPath=[mypath.path]) - originalSmartPath = pp._smartPath - def _evilSmartPath(pathName): - o = originalSmartPath(pathName) - originalChildren = o.children - def evilChildren(): - # normally this order is random; let's make sure it always - # comes up .pyc-first. - x = originalChildren() - x.sort() - x.reverse() - return x - o.children = evilChildren - return o - mypath.child("abcd.py").setContent('\n') - compileall.compile_dir(mypath.path, quiet=True) - # sanity check - self.assertEquals(len(mypath.children()), 2) - pp._smartPath = _evilSmartPath - self.assertEquals(pp['abcd'].filePath, - mypath.child('abcd.py')) - - - def test_packageMissingPath(self): - """ - A package can delete its __path__ for some reasons, - C{modules.PythonPath} should be able to deal with it. - """ - mypath = FilePath(self.mktemp()) - mypath.createDirectory() - pp = modules.PythonPath(sysPath=[mypath.path]) - subpath = mypath.child("abcd") - subpath.createDirectory() - subpath.child("__init__.py").setContent('del __path__\n') - sys.path.append(mypath.path) - import abcd - try: - l = list(pp.walkModules()) - self.assertEquals(len(l), 1) - self.assertEquals(l[0].name, 'abcd') - finally: - del abcd - del sys.modules['abcd'] - sys.path.remove(mypath.path) - - - -class PathModificationTest(PySpaceTestCase): - """ - These tests share setup/cleanup behavior of creating a dummy package and - stuffing some code in it. - """ - - _serialnum = itertools.count().next # used to generate serial numbers for - # package names. - - def setUp(self): - self.pathExtensionName = self.mktemp() - self.pathExtension = FilePath(self.pathExtensionName) - self.pathExtension.createDirectory() - self.packageName = "pyspacetests%d" % (self._serialnum(),) - self.packagePath = self.pathExtension.child(self.packageName) - self.packagePath.createDirectory() - self.packagePath.child("__init__.py").setContent("") - self.packagePath.child("a.py").setContent("") - self.packagePath.child("b.py").setContent("") - self.packagePath.child("c__init__.py").setContent("") - self.pathSetUp = False - - - def _setupSysPath(self): - assert not self.pathSetUp - self.pathSetUp = True - sys.path.append(self.pathExtensionName) - - - def _underUnderPathTest(self, doImport=True): - moddir2 = self.mktemp() - fpmd = FilePath(moddir2) - fpmd.createDirectory() - fpmd.child("foozle.py").setContent("x = 123\n") - self.packagePath.child("__init__.py").setContent( - "__path__.append(%r)\n" % (moddir2,)) - # Cut here - self._setupSysPath() - modinfo = modules.getModule(self.packageName) - self.assertEquals( - self.findByIteration(self.packageName+".foozle", modinfo, - importPackages=doImport), - modinfo['foozle']) - self.assertEquals(modinfo['foozle'].load().x, 123) - - - def test_underUnderPathAlreadyImported(self): - """ - Verify that iterModules will honor the __path__ of already-loaded packages. - """ - self._underUnderPathTest() - - - def test_underUnderPathNotAlreadyImported(self): - """ - Verify that iterModules will honor the __path__ of already-loaded packages. - """ - self._underUnderPathTest(False) - - - test_underUnderPathNotAlreadyImported.todo = ( - "This may be impossible but it sure would be nice.") - - - def _listModules(self): - pkginfo = modules.getModule(self.packageName) - nfni = [modinfo.name.split(".")[-1] for modinfo in - pkginfo.iterModules()] - nfni.sort() - self.failUnlessEqual(nfni, ['a', 'b', 'c__init__']) - - - def test_listingModules(self): - """ - Make sure the module list comes back as we expect from iterModules on a - package, whether zipped or not. - """ - self._setupSysPath() - self._listModules() - - - def test_listingModulesAlreadyImported(self): - """ - Make sure the module list comes back as we expect from iterModules on a - package, whether zipped or not, even if the package has already been - imported. - """ - self._setupSysPath() - namedAny(self.packageName) - self._listModules() - - - def tearDown(self): - # Intentionally using 'assert' here, this is not a test assertion, this - # is just an "oh fuck what is going ON" assertion. -glyph - if self.pathSetUp: - HORK = "path cleanup failed: don't be surprised if other tests break" - assert sys.path.pop() is self.pathExtensionName, HORK+", 1" - assert self.pathExtensionName not in sys.path, HORK+", 2" - - - -class RebindingTest(PathModificationTest): - """ - These tests verify that the default path interrogation API works properly - even when sys.path has been rebound to a different object. - """ - def _setupSysPath(self): - assert not self.pathSetUp - self.pathSetUp = True - self.savedSysPath = sys.path - sys.path = sys.path[:] - sys.path.append(self.pathExtensionName) - - - def tearDown(self): - """ - Clean up sys.path by re-binding our original object. - """ - if self.pathSetUp: - sys.path = self.savedSysPath - - - -class ZipPathModificationTest(PathModificationTest): - def _setupSysPath(self): - assert not self.pathSetUp - zipit(self.pathExtensionName, self.pathExtensionName+'.zip') - self.pathExtensionName += '.zip' - assert zipfile.is_zipfile(self.pathExtensionName) - PathModificationTest._setupSysPath(self) - - -class PythonPathTestCase(TestCase): - """ - Tests for the class which provides the implementation for all of the - public API of L{twisted.python.modules}. - """ - def test_unhandledImporter(self): - """ - Make sure that the behavior when encountering an unknown importer - type is not catastrophic failure. - """ - class SecretImporter(object): - pass - - def hook(name): - return SecretImporter() - - syspath = ['example/path'] - sysmodules = {} - syshooks = [hook] - syscache = {} - def sysloader(name): - return None - space = modules.PythonPath( - syspath, sysmodules, syshooks, syscache, sysloader) - entries = list(space.iterEntries()) - self.assertEquals(len(entries), 1) - self.assertRaises(KeyError, lambda: entries[0]['module']) diff --git a/tools/buildbot/pylibs/twisted/test/test_monkey.py b/tools/buildbot/pylibs/twisted/test/test_monkey.py deleted file mode 100644 index 7a446c5..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_monkey.py +++ /dev/null @@ -1,161 +0,0 @@ -# Copyright (c) 2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.python.monkey}. -""" - -from twisted.trial import unittest -from twisted.python.monkey import MonkeyPatcher - - -class TestObj: - def __init__(self): - self.foo = 'foo value' - self.bar = 'bar value' - self.baz = 'baz value' - - -class MonkeyPatcherTest(unittest.TestCase): - """ - Tests for L{MonkeyPatcher} monkey-patching class. - """ - - def setUp(self): - self.testObject = TestObj() - self.originalObject = TestObj() - self.monkeyPatcher = MonkeyPatcher() - - - def test_empty(self): - """ - A monkey patcher without patches shouldn't change a thing. - """ - self.monkeyPatcher.patch() - - # We can't assert that all state is unchanged, but at least we can - # check our test object. - self.assertEquals(self.originalObject.foo, self.testObject.foo) - self.assertEquals(self.originalObject.bar, self.testObject.bar) - self.assertEquals(self.originalObject.baz, self.testObject.baz) - - - def test_constructWithPatches(self): - """ - Constructing a L{MonkeyPatcher} with patches should add all of the - given patches to the patch list. - """ - patcher = MonkeyPatcher((self.testObject, 'foo', 'haha'), - (self.testObject, 'bar', 'hehe')) - patcher.patch() - self.assertEquals('haha', self.testObject.foo) - self.assertEquals('hehe', self.testObject.bar) - self.assertEquals(self.originalObject.baz, self.testObject.baz) - - - def test_patchExisting(self): - """ - Patching an attribute that exists sets it to the value defined in the - patch. - """ - self.monkeyPatcher.addPatch(self.testObject, 'foo', 'haha') - self.monkeyPatcher.patch() - self.assertEquals(self.testObject.foo, 'haha') - - - def test_patchNonExisting(self): - """ - Patching a non-existing attribute fails with an C{AttributeError}. - """ - self.monkeyPatcher.addPatch(self.testObject, 'nowhere', - 'blow up please') - self.assertRaises(AttributeError, self.monkeyPatcher.patch) - - - def test_patchAlreadyPatched(self): - """ - Adding a patch for an object and attribute that already have a patch - overrides the existing patch. - """ - self.monkeyPatcher.addPatch(self.testObject, 'foo', 'blah') - self.monkeyPatcher.addPatch(self.testObject, 'foo', 'BLAH') - self.monkeyPatcher.patch() - self.assertEquals(self.testObject.foo, 'BLAH') - self.monkeyPatcher.restore() - self.assertEquals(self.testObject.foo, self.originalObject.foo) - - - def test_restoreTwiceIsANoOp(self): - """ - Restoring an already-restored monkey patch is a no-op. - """ - self.monkeyPatcher.addPatch(self.testObject, 'foo', 'blah') - self.monkeyPatcher.patch() - self.monkeyPatcher.restore() - self.assertEquals(self.testObject.foo, self.originalObject.foo) - self.monkeyPatcher.restore() - self.assertEquals(self.testObject.foo, self.originalObject.foo) - - - def test_runWithPatchesDecoration(self): - """ - runWithPatches should run the given callable, passing in all arguments - and keyword arguments, and return the return value of the callable. - """ - log = [] - - def f(a, b, c=None): - log.append((a, b, c)) - return 'foo' - - result = self.monkeyPatcher.runWithPatches(f, 1, 2, c=10) - self.assertEquals('foo', result) - self.assertEquals([(1, 2, 10)], log) - - - def test_repeatedRunWithPatches(self): - """ - We should be able to call the same function with runWithPatches more - than once. All patches should apply for each call. - """ - def f(): - return (self.testObject.foo, self.testObject.bar, - self.testObject.baz) - - self.monkeyPatcher.addPatch(self.testObject, 'foo', 'haha') - result = self.monkeyPatcher.runWithPatches(f) - self.assertEquals( - ('haha', self.originalObject.bar, self.originalObject.baz), result) - result = self.monkeyPatcher.runWithPatches(f) - self.assertEquals( - ('haha', self.originalObject.bar, self.originalObject.baz), - result) - - - def test_runWithPatchesRestores(self): - """ - C{runWithPatches} should restore the original values after the function - has executed. - """ - self.monkeyPatcher.addPatch(self.testObject, 'foo', 'haha') - self.assertEquals(self.originalObject.foo, self.testObject.foo) - self.monkeyPatcher.runWithPatches(lambda: None) - self.assertEquals(self.originalObject.foo, self.testObject.foo) - - - def test_runWithPatchesRestoresOnException(self): - """ - Test runWithPatches restores the original values even when the function - raises an exception. - """ - def _(): - self.assertEquals(self.testObject.foo, 'haha') - self.assertEquals(self.testObject.bar, 'blahblah') - raise RuntimeError, "Something went wrong!" - - self.monkeyPatcher.addPatch(self.testObject, 'foo', 'haha') - self.monkeyPatcher.addPatch(self.testObject, 'bar', 'blahblah') - - self.assertRaises(RuntimeError, self.monkeyPatcher.runWithPatches, _) - self.assertEquals(self.testObject.foo, self.originalObject.foo) - self.assertEquals(self.testObject.bar, self.originalObject.bar) diff --git a/tools/buildbot/pylibs/twisted/test/test_newcred.py b/tools/buildbot/pylibs/twisted/test/test_newcred.py deleted file mode 100644 index 623bb3b..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_newcred.py +++ /dev/null @@ -1,444 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Now with 30% more starch. -""" - - -import hmac -from zope.interface import implements, Interface - -from twisted.trial import unittest -from twisted.cred import portal, checkers, credentials, error -from twisted.python import components -from twisted.internet import defer -from twisted.internet.defer import deferredGenerator as dG, waitForDeferred as wFD - -try: - from crypt import crypt -except ImportError: - crypt = None - -try: - from twisted.cred.pamauth import callIntoPAM -except ImportError: - pamauth = None -else: - from twisted.cred import pamauth - -class ITestable(Interface): - pass - -class TestAvatar: - def __init__(self, name): - self.name = name - self.loggedIn = False - self.loggedOut = False - - def login(self): - assert not self.loggedIn - self.loggedIn = True - - def logout(self): - self.loggedOut = True - -class Testable(components.Adapter): - implements(ITestable) - -# components.Interface(TestAvatar).adaptWith(Testable, ITestable) - -components.registerAdapter(Testable, TestAvatar, ITestable) - -class IDerivedCredentials(credentials.IUsernamePassword): - pass - -class DerivedCredentials(object): - implements(IDerivedCredentials, ITestable) - - def __init__(self, username, password): - self.username = username - self.password = password - - def checkPassword(self, password): - return password == self.password - - -class TestRealm: - implements(portal.IRealm) - def __init__(self): - self.avatars = {} - - def requestAvatar(self, avatarId, mind, *interfaces): - if self.avatars.has_key(avatarId): - avatar = self.avatars[avatarId] - else: - avatar = TestAvatar(avatarId) - self.avatars[avatarId] = avatar - avatar.login() - return (interfaces[0], interfaces[0](avatar), - avatar.logout) - -class NewCredTest(unittest.TestCase): - def setUp(self): - r = self.realm = TestRealm() - p = self.portal = portal.Portal(r) - up = self.checker = checkers.InMemoryUsernamePasswordDatabaseDontUse() - up.addUser("bob", "hello") - p.registerChecker(up) - - def testListCheckers(self): - expected = [credentials.IUsernamePassword, credentials.IUsernameHashedPassword] - got = self.portal.listCredentialsInterfaces() - expected.sort() - got.sort() - self.assertEquals(got, expected) - - def testBasicLogin(self): - l = []; f = [] - self.portal.login(credentials.UsernamePassword("bob", "hello"), - self, ITestable).addCallback( - l.append).addErrback(f.append) - if f: - raise f[0] - # print l[0].getBriefTraceback() - iface, impl, logout = l[0] - # whitebox - self.assertEquals(iface, ITestable) - self.failUnless(iface.providedBy(impl), - "%s does not implement %s" % (impl, iface)) - # greybox - self.failUnless(impl.original.loggedIn) - self.failUnless(not impl.original.loggedOut) - logout() - self.failUnless(impl.original.loggedOut) - - def test_derivedInterface(self): - """ - Login with credentials implementing an interface inheriting from an - interface registered with a checker (but not itself registered). - """ - l = [] - f = [] - self.portal.login(DerivedCredentials("bob", "hello"), self, ITestable - ).addCallback(l.append - ).addErrback(f.append) - if f: - raise f[0] - iface, impl, logout = l[0] - # whitebox - self.assertEquals(iface, ITestable) - self.failUnless(iface.providedBy(impl), - "%s does not implement %s" % (impl, iface)) - # greybox - self.failUnless(impl.original.loggedIn) - self.failUnless(not impl.original.loggedOut) - logout() - self.failUnless(impl.original.loggedOut) - - def testFailedLogin(self): - l = [] - self.portal.login(credentials.UsernamePassword("bob", "h3llo"), - self, ITestable).addErrback( - lambda x: x.trap(error.UnauthorizedLogin)).addCallback(l.append) - self.failUnless(l) - self.failUnlessEqual(error.UnauthorizedLogin, l[0]) - - def testFailedLoginName(self): - l = [] - self.portal.login(credentials.UsernamePassword("jay", "hello"), - self, ITestable).addErrback( - lambda x: x.trap(error.UnauthorizedLogin)).addCallback(l.append) - self.failUnless(l) - self.failUnlessEqual(error.UnauthorizedLogin, l[0]) - - -class CramMD5CredentialsTestCase(unittest.TestCase): - def testIdempotentChallenge(self): - c = credentials.CramMD5Credentials() - chal = c.getChallenge() - self.assertEquals(chal, c.getChallenge()) - - def testCheckPassword(self): - c = credentials.CramMD5Credentials() - chal = c.getChallenge() - c.response = hmac.HMAC('secret', chal).hexdigest() - self.failUnless(c.checkPassword('secret')) - - def testWrongPassword(self): - c = credentials.CramMD5Credentials() - self.failIf(c.checkPassword('secret')) - -class OnDiskDatabaseTestCase(unittest.TestCase): - users = [ - ('user1', 'pass1'), - ('user2', 'pass2'), - ('user3', 'pass3'), - ] - - - def testUserLookup(self): - dbfile = self.mktemp() - db = checkers.FilePasswordDB(dbfile) - f = file(dbfile, 'w') - for (u, p) in self.users: - f.write('%s:%s\n' % (u, p)) - f.close() - - for (u, p) in self.users: - self.failUnlessRaises(KeyError, db.getUser, u.upper()) - self.assertEquals(db.getUser(u), (u, p)) - - def testCaseInSensitivity(self): - dbfile = self.mktemp() - db = checkers.FilePasswordDB(dbfile, caseSensitive=0) - f = file(dbfile, 'w') - for (u, p) in self.users: - f.write('%s:%s\n' % (u, p)) - f.close() - - for (u, p) in self.users: - self.assertEquals(db.getUser(u.upper()), (u, p)) - - def testRequestAvatarId(self): - dbfile = self.mktemp() - db = checkers.FilePasswordDB(dbfile, caseSensitive=0) - f = file(dbfile, 'w') - for (u, p) in self.users: - f.write('%s:%s\n' % (u, p)) - f.close() - creds = [credentials.UsernamePassword(u, p) for u, p in self.users] - d = defer.gatherResults( - [defer.maybeDeferred(db.requestAvatarId, c) for c in creds]) - d.addCallback(self.assertEquals, [u for u, p in self.users]) - return d - - def testRequestAvatarId_hashed(self): - dbfile = self.mktemp() - db = checkers.FilePasswordDB(dbfile, caseSensitive=0) - f = file(dbfile, 'w') - for (u, p) in self.users: - f.write('%s:%s\n' % (u, p)) - f.close() - creds = [credentials.UsernameHashedPassword(u, p) for u, p in self.users] - d = defer.gatherResults( - [defer.maybeDeferred(db.requestAvatarId, c) for c in creds]) - d.addCallback(self.assertEquals, [u for u, p in self.users]) - return d - - - -class HashedPasswordOnDiskDatabaseTestCase(unittest.TestCase): - users = [ - ('user1', 'pass1'), - ('user2', 'pass2'), - ('user3', 'pass3'), - ] - - - def hash(self, u, p, s): - return crypt(p, s) - - def setUp(self): - dbfile = self.mktemp() - self.db = checkers.FilePasswordDB(dbfile, hash=self.hash) - f = file(dbfile, 'w') - for (u, p) in self.users: - f.write('%s:%s\n' % (u, crypt(p, u[:2]))) - f.close() - r = TestRealm() - self.port = portal.Portal(r) - self.port.registerChecker(self.db) - - def testGoodCredentials(self): - goodCreds = [credentials.UsernamePassword(u, p) for u, p in self.users] - d = defer.gatherResults([self.db.requestAvatarId(c) for c in goodCreds]) - d.addCallback(self.assertEquals, [u for u, p in self.users]) - return d - - def testGoodCredentials_login(self): - goodCreds = [credentials.UsernamePassword(u, p) for u, p in self.users] - d = defer.gatherResults([self.port.login(c, None, ITestable) - for c in goodCreds]) - d.addCallback(lambda x: [a.original.name for i, a, l in x]) - d.addCallback(self.assertEquals, [u for u, p in self.users]) - return d - - def testBadCredentials(self): - badCreds = [credentials.UsernamePassword(u, 'wrong password') - for u, p in self.users] - d = defer.DeferredList([self.port.login(c, None, ITestable) - for c in badCreds], consumeErrors=True) - d.addCallback(self._assertFailures, error.UnauthorizedLogin) - return d - - def testHashedCredentials(self): - hashedCreds = [credentials.UsernameHashedPassword(u, crypt(p, u[:2])) - for u, p in self.users] - d = defer.DeferredList([self.port.login(c, None, ITestable) - for c in hashedCreds], consumeErrors=True) - d.addCallback(self._assertFailures, error.UnhandledCredentials) - return d - - def _assertFailures(self, failures, *expectedFailures): - for flag, failure in failures: - self.failUnlessEqual(flag, defer.FAILURE) - failure.trap(*expectedFailures) - return None - - if crypt is None: - skip = "crypt module not available" - -class PluggableAuthenticationModulesTest(unittest.TestCase): - - def setUp(self): - """ - Replace L{pamauth.callIntoPAM} with a dummy implementation with - easily-controlled behavior. - """ - self._oldCallIntoPAM = pamauth.callIntoPAM - pamauth.callIntoPAM = self.callIntoPAM - - - def tearDown(self): - """ - Restore the original value of L{pamauth.callIntoPAM}. - """ - pamauth.callIntoPAM = self._oldCallIntoPAM - - - def callIntoPAM(self, service, user, conv): - if service != 'Twisted': - raise error.UnauthorizedLogin('bad service: %s' % service) - if user != 'testuser': - raise error.UnauthorizedLogin('bad username: %s' % user) - questions = [ - (1, "Password"), - (2, "Message w/ Input"), - (3, "Message w/o Input"), - ] - replies = conv(questions) - if replies != [ - ("password", 0), - ("entry", 0), - ("", 0) - ]: - raise error.UnauthorizedLogin('bad conversion: %s' % repr(replies)) - return 1 - - def _makeConv(self, d): - def conv(questions): - return defer.succeed([(d[t], 0) for t, q in questions]) - return conv - - def testRequestAvatarId(self): - db = checkers.PluggableAuthenticationModulesChecker() - conv = self._makeConv({1:'password', 2:'entry', 3:''}) - creds = credentials.PluggableAuthenticationModules('testuser', - conv) - d = db.requestAvatarId(creds) - d.addCallback(self.assertEquals, 'testuser') - return d - - def testBadCredentials(self): - db = checkers.PluggableAuthenticationModulesChecker() - conv = self._makeConv({1:'', 2:'', 3:''}) - creds = credentials.PluggableAuthenticationModules('testuser', - conv) - d = db.requestAvatarId(creds) - self.assertFailure(d, error.UnauthorizedLogin) - return d - - def testBadUsername(self): - db = checkers.PluggableAuthenticationModulesChecker() - conv = self._makeConv({1:'password', 2:'entry', 3:''}) - creds = credentials.PluggableAuthenticationModules('baduser', - conv) - d = db.requestAvatarId(creds) - self.assertFailure(d, error.UnauthorizedLogin) - return d - - if not pamauth: - skip = "Can't run without PyPAM" - -class CheckersMixin: - def testPositive(self): - for chk in self.getCheckers(): - for (cred, avatarId) in self.getGoodCredentials(): - r = wFD(chk.requestAvatarId(cred)) - yield r - self.assertEquals(r.getResult(), avatarId) - testPositive = dG(testPositive) - - def testNegative(self): - for chk in self.getCheckers(): - for cred in self.getBadCredentials(): - r = wFD(chk.requestAvatarId(cred)) - yield r - self.assertRaises(error.UnauthorizedLogin, r.getResult) - testNegative = dG(testNegative) - -class HashlessFilePasswordDBMixin: - credClass = credentials.UsernamePassword - diskHash = None - networkHash = staticmethod(lambda x: x) - - _validCredentials = [ - ('user1', 'password1'), - ('user2', 'password2'), - ('user3', 'password3')] - - def getGoodCredentials(self): - for u, p in self._validCredentials: - yield self.credClass(u, self.networkHash(p)), u - - def getBadCredentials(self): - for u, p in [('user1', 'password3'), - ('user2', 'password1'), - ('bloof', 'blarf')]: - yield self.credClass(u, self.networkHash(p)) - - def getCheckers(self): - diskHash = self.diskHash or (lambda x: x) - hashCheck = self.diskHash and (lambda username, password, stored: self.diskHash(password)) - - for cache in True, False: - fn = self.mktemp() - fObj = file(fn, 'w') - for u, p in self._validCredentials: - fObj.write('%s:%s\n' % (u, diskHash(p))) - fObj.close() - yield checkers.FilePasswordDB(fn, cache=cache, hash=hashCheck) - - fn = self.mktemp() - fObj = file(fn, 'w') - for u, p in self._validCredentials: - fObj.write('%s dingle dongle %s\n' % (diskHash(p), u)) - fObj.close() - yield checkers.FilePasswordDB(fn, ' ', 3, 0, cache=cache, hash=hashCheck) - - fn = self.mktemp() - fObj = file(fn, 'w') - for u, p in self._validCredentials: - fObj.write('zip,zap,%s,zup,%s\n' % (u.title(), diskHash(p))) - fObj.close() - yield checkers.FilePasswordDB(fn, ',', 2, 4, False, cache=cache, hash=hashCheck) - -class LocallyHashedFilePasswordDBMixin(HashlessFilePasswordDBMixin): - diskHash = staticmethod(lambda x: x.encode('hex')) - -class NetworkHashedFilePasswordDBMixin(HashlessFilePasswordDBMixin): - networkHash = staticmethod(lambda x: x.encode('hex')) - class credClass(credentials.UsernameHashedPassword): - def checkPassword(self, password): - return self.hashed.decode('hex') == password - -class HashlessFilePasswordDBCheckerTestCase(HashlessFilePasswordDBMixin, CheckersMixin, unittest.TestCase): - pass - -class LocallyHashedFilePasswordDBCheckerTestCase(LocallyHashedFilePasswordDBMixin, CheckersMixin, unittest.TestCase): - pass - -class NetworkHashedFilePasswordDBCheckerTestCase(NetworkHashedFilePasswordDBMixin, CheckersMixin, unittest.TestCase): - pass - diff --git a/tools/buildbot/pylibs/twisted/test/test_nmea.py b/tools/buildbot/pylibs/twisted/test/test_nmea.py deleted file mode 100644 index fafe655..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_nmea.py +++ /dev/null @@ -1,115 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Test cases for the NMEA GPS protocol""" - -import StringIO - -from twisted.trial import unittest -from twisted.internet import reactor, protocol -from twisted.python import reflect - -from twisted.protocols.gps import nmea - -class StringIOWithNoClose(StringIO.StringIO): - def close(self): - pass - -class ResultHarvester: - def __init__(self): - self.results = [] - - def __call__(self, *args): - self.results.append(args) - - def performTest(self, function, *args, **kwargs): - l = len(self.results) - try: - function(*args, **kwargs) - except Exception, e: - self.results.append(e) - if l == len(self.results): - self.results.append(NotImplementedError()) - -class NMEATester(nmea.NMEAReceiver): - ignore_invalid_sentence = 0 - ignore_checksum_mismatch = 0 - ignore_unknown_sentencetypes = 0 - convert_dates_before_y2k = 1 - - def connectionMade(self): - self.resultHarvester = ResultHarvester() - for fn in reflect.prefixedMethodNames(self.__class__, 'decode_'): - setattr(self, 'handle_' + fn, self.resultHarvester) - -class NMEAReceiverTestCase(unittest.TestCase): - messages = ( - # fix - signal acquired - "$GPGGA,231713.0,3910.413,N,07641.994,W,1,05,1.35,00044,M,-033,M,,*69", - # fix - signal not acquired - "$GPGGA,235947.000,0000.0000,N,00000.0000,E,0,00,0.0,0.0,M,,,,0000*00", - # junk - "lkjasdfkl!@#(*$!@(*#(ASDkfjasdfLMASDCVKAW!@#($)!(@#)(*", - # fix - signal acquired (invalid checksum) - "$GPGGA,231713.0,3910.413,N,07641.994,W,1,05,1.35,00044,M,-033,M,,*68", - # invalid sentence - "$GPGGX,231713.0,3910.413,N,07641.994,W,1,05,1.35,00044,M,-033,M,,*68", - # position acquired - "$GPGLL,4250.5589,S,14718.5084,E,092204.999,A*2D", - # position not acquired - "$GPGLL,0000.0000,N,00000.0000,E,235947.000,V*2D", - # active satellites (no fix) - "$GPGSA,A,1,,,,,,,,,,,,,0.0,0.0,0.0*30", - # active satellites - "$GPGSA,A,3,01,20,19,13,,,,,,,,,40.4,24.4,32.2*0A", - # positiontime (no fix) - "$GPRMC,235947.000,V,0000.0000,N,00000.0000,E,,,041299,,*1D", - # positiontime - "$GPRMC,092204.999,A,4250.5589,S,14718.5084,E,0.00,89.68,211200,,*25", - # course over ground (no fix - not implemented) - "$GPVTG,,T,,M,,N,,K*4E", - # course over ground (not implemented) - "$GPVTG,89.68,T,,M,0.00,N,0.0,K*5F", - ) - results = ( - (83833.0, 39.17355, -76.6999, nmea.POSFIX_SPS, 5, 1.35, (44.0, 'M'), (-33.0, 'M'), None), - (86387.0, 0.0, 0.0, 0, 0, 0.0, (0.0, 'M'), None, None), - nmea.InvalidSentence(), - nmea.InvalidChecksum(), - nmea.InvalidSentence(), - (-42.842648333333337, 147.30847333333332, 33724.999000000003, 1), - (0.0, 0.0, 86387.0, 0), - ((None, None, None, None, None, None, None, None, None, None, None, None), (nmea.MODE_AUTO, nmea.MODE_NOFIX), 0.0, 0.0, 0.0), - ((1, 20, 19, 13, None, None, None, None, None, None, None, None), (nmea.MODE_AUTO, nmea.MODE_3D), 40.4, 24.4, 32.2), - (0.0, 0.0, None, None, 86387.0, (1999, 12, 4), None), - (-42.842648333333337, 147.30847333333332, 0.0, 89.68, 33724.999, (2000, 12, 21), None), - NotImplementedError(), - NotImplementedError(), - ) - def testGPSMessages(self): - dummy = NMEATester() - dummy.makeConnection(protocol.FileWrapper(StringIOWithNoClose())) - for line in self.messages: - dummy.resultHarvester.performTest(dummy.lineReceived, line) - def munge(myTuple): - if type(myTuple) != type(()): - return - newTuple = [] - for v in myTuple: - if type(v) == type(1.1): - v = float(int(v * 10000.0)) * 0.0001 - newTuple.append(v) - return tuple(newTuple) - for (message, expectedResult, actualResult) in zip(self.messages, self.results, dummy.resultHarvester.results): - expectedResult = munge(expectedResult) - actualResult = munge(actualResult) - if isinstance(expectedResult, Exception): - if isinstance(actualResult, Exception): - self.failUnlessEqual(expectedResult.__class__, actualResult.__class__, "\nInput:\n%s\nExpected:\n%s.%s\nResults:\n%s.%s\n" % (message, expectedResult.__class__.__module__, expectedResult.__class__.__name__, actualResult.__class__.__module__, actualResult.__class__.__name__)) - else: - self.failUnlessEqual(1, 0, "\nInput:\n%s\nExpected:\n%s.%s\nResults:\n%r\n" % (message, expectedResult.__class__.__module__, expectedResult.__class__.__name__, actualResult)) - else: - self.failUnlessEqual(expectedResult, actualResult, "\nInput:\n%s\nExpected: %r\nResults: %r\n" % (message, expectedResult, actualResult)) - -testCases = [NMEAReceiverTestCase] diff --git a/tools/buildbot/pylibs/twisted/test/test_paths.py b/tools/buildbot/pylibs/twisted/test/test_paths.py deleted file mode 100644 index fe4f925..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_paths.py +++ /dev/null @@ -1,648 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test cases covering L{twisted.python.filepath} and L{twisted.python.zippath}. -""" - -import os, time, pickle, errno, zipfile, stat - -from twisted.python.win32 import WindowsError, ERROR_DIRECTORY -from twisted.python import filepath -from twisted.python.zippath import ZipArchive -from twisted.python.runtime import platform - -from twisted.trial import unittest - - -class AbstractFilePathTestCase(unittest.TestCase): - - f1content = "file 1" - f2content = "file 2" - - def _mkpath(self, *p): - x = os.path.abspath(os.path.join(self.cmn, *p)) - self.all.append(x) - return x - - def subdir(self, *dirname): - os.mkdir(self._mkpath(*dirname)) - - def subfile(self, *dirname): - return open(self._mkpath(*dirname), "wb") - - def setUp(self): - self.now = time.time() - cmn = self.cmn = os.path.abspath(self.mktemp()) - self.all = [cmn] - os.mkdir(cmn) - self.subdir("sub1") - f = self.subfile("file1") - f.write(self.f1content) - f = self.subfile("sub1", "file2") - f.write(self.f2content) - self.subdir('sub3') - f = self.subfile("sub3", "file3.ext1") - f = self.subfile("sub3", "file3.ext2") - f = self.subfile("sub3", "file3.ext3") - self.all.sort() - - self.path = filepath.FilePath(cmn) - - def test_segmentsFromPositive(self): - """ - Verify that the segments between two paths are correctly identified. - """ - self.assertEquals( - self.path.child("a").child("b").child("c").segmentsFrom(self.path), - ["a", "b", "c"]) - - def test_segmentsFromNegative(self): - """Verify that segmentsFrom notices when the ancestor isn't an ancestor. - """ - self.assertRaises( - ValueError, - self.path.child("a").child("b").child("c").segmentsFrom, - self.path.child("d").child("c").child("e")) - - def test_walk(self): - """Verify that walking the path gives the same result as the known file - hierarchy. - """ - x = [foo.path for foo in self.path.walk()] - x.sort() - self.assertEquals(x, self.all) - - def test_validSubdir(self): - """Verify that a valid subdirectory will show up as a directory, but not as a - file, not as a symlink, and be listable. - """ - sub1 = self.path.child('sub1') - self.failUnless(sub1.exists(), - "This directory does exist.") - self.failUnless(sub1.isdir(), - "It's a directory.") - self.failUnless(not sub1.isfile(), - "It's a directory.") - self.failUnless(not sub1.islink(), - "It's a directory.") - self.failUnlessEqual(sub1.listdir(), - ['file2']) - - - def test_invalidSubdir(self): - """ - Verify that a subdirectory that doesn't exist is reported as such. - """ - sub2 = self.path.child('sub2') - self.failIf(sub2.exists(), - "This directory does not exist.") - - def test_validFiles(self): - """ - Make sure that we can read existent non-empty files. - """ - f1 = self.path.child('file1') - self.failUnlessEqual(f1.open().read(), self.f1content) - f2 = self.path.child('sub1').child('file2') - self.failUnlessEqual(f2.open().read(), self.f2content) - - - def test_dictionaryKeys(self): - """ - Verify that path instances are usable as dictionary keys. - """ - f1 = self.path.child('file1') - f1prime = self.path.child('file1') - f2 = self.path.child('file2') - dictoid = {} - dictoid[f1] = 3 - dictoid[f1prime] = 4 - self.assertEquals(dictoid[f1], 4) - self.assertEquals(dictoid.keys(), [f1]) - self.assertIdentical(dictoid.keys()[0], f1) - self.assertNotIdentical(dictoid.keys()[0], f1prime) # sanity check - dictoid[f2] = 5 - self.assertEquals(dictoid[f2], 5) - self.assertEquals(len(dictoid), 2) - - - def test_dictionaryKeyWithString(self): - """ - Verify that path instances are usable as dictionary keys which do not clash - with their string counterparts. - """ - f1 = self.path.child('file1') - dictoid = {f1: 'hello'} - dictoid[f1.path] = 'goodbye' - self.assertEquals(len(dictoid), 2) - - - def test_childrenNonexistentError(self): - """ - Verify that children raises the appropriate exception for non-existent - directories. - """ - self.assertRaises(filepath.UnlistableError, - self.path.child('not real').children) - - def test_childrenNotDirectoryError(self): - """ - Verify that listdir raises the appropriate exception for attempting to list - a file rather than a directory. - """ - self.assertRaises(filepath.UnlistableError, - self.path.child('file1').children) - - - def test_newTimesAreFloats(self): - """ - Verify that all times returned from the various new time functions are ints - (and hopefully therefore 'high precision'). - """ - for p in self.path, self.path.child('file1'): - self.failUnlessEqual(type(p.getAccessTime()), float) - self.failUnlessEqual(type(p.getModificationTime()), float) - self.failUnlessEqual(type(p.getStatusChangeTime()), float) - - - def test_oldTimesAreInts(self): - """ - Verify that all times returned from the various time functions are - integers, for compatibility. - """ - for p in self.path, self.path.child('file1'): - self.failUnlessEqual(type(p.getatime()), int) - self.failUnlessEqual(type(p.getmtime()), int) - self.failUnlessEqual(type(p.getctime()), int) - - - -class FakeWindowsPath(filepath.FilePath): - """ - A test version of FilePath which overrides listdir to raise L{WindowsError}. - """ - - def listdir(self): - """ - @raise WindowsError: always. - """ - raise WindowsError( - ERROR_DIRECTORY, - "A directory's validness was called into question") - - -class ListingCompatibilityTests(unittest.TestCase): - """ - These tests verify compatibility with legacy behavior of directory listing. - """ - - def test_windowsErrorExcept(self): - """ - Verify that when a WindowsError is raised from listdir, catching - WindowsError works. - """ - fwp = FakeWindowsPath(self.mktemp()) - self.assertRaises(filepath.UnlistableError, fwp.children) - self.assertRaises(WindowsError, fwp.children) - - - def test_alwaysCatchOSError(self): - """ - Verify that in the normal case where a directory does not exist, we will - get an OSError. - """ - fp = filepath.FilePath(self.mktemp()) - self.assertRaises(OSError, fp.children) - - - def test_keepOriginalAttributes(self): - """ - Verify that the Unlistable exception raised will preserve the attributes of - the previously-raised exception. - """ - fp = filepath.FilePath(self.mktemp()) - ose = self.assertRaises(OSError, fp.children) - d1 = ose.__dict__.keys() - d1.remove('originalException') - d2 = ose.originalException.__dict__.keys() - d1.sort() - d2.sort() - self.assertEquals(d1, d2) - - - -def zipit(dirname, zfname): - """ - create a zipfile on zfname, containing the contents of dirname' - """ - zf = zipfile.ZipFile(zfname, "w") - basedir = os.path.basename(dirname) - for root, dirs, files, in os.walk(dirname): - for fname in files: - fspath = os.path.join(root, fname) - arcpath = os.path.join(root, fname)[len(dirname)+1:] - # print fspath, '=>', arcpath - zf.write(fspath, arcpath) - zf.close() - -class ZipFilePathTestCase(AbstractFilePathTestCase): - - def setUp(self): - AbstractFilePathTestCase.setUp(self) - zipit(self.cmn, self.cmn+'.zip') - self.path = ZipArchive(self.cmn+'.zip') - self.all = [x.replace(self.cmn, self.cmn+'.zip') for x in self.all] - - -class FilePathTestCase(AbstractFilePathTestCase): - - def test_chmod(self): - """ - Make sure that calling L{FilePath.chmod} modifies the permissions of - the passed file as expected (using C{os.stat} to check). We use some - basic modes that should work everywhere (even on Windows). - """ - for mode in (0555, 0777): - self.path.child("sub1").chmod(mode) - self.assertEquals( - stat.S_IMODE(os.stat(self.path.child("sub1").path).st_mode), - mode) - - - def test_getAndSet(self): - content = 'newcontent' - self.path.child('new').setContent(content) - newcontent = self.path.child('new').getContent() - self.failUnlessEqual(content, newcontent) - content = 'content' - self.path.child('new').setContent(content, '.tmp') - newcontent = self.path.child('new').getContent() - self.failUnlessEqual(content, newcontent) - - - def test_symbolicLink(self): - """ - Verify the behavior of the C{isLink} method against links and - non-links. Also check that the symbolic link shares the directory - property with its target. - """ - s4 = self.path.child("sub4") - s3 = self.path.child("sub3") - os.symlink(s3.path, s4.path) - self.assertTrue(s4.islink()) - self.assertFalse(s3.islink()) - self.assertTrue(s4.isdir()) - self.assertTrue(s3.isdir()) - - - def test_linkTo(self): - """ - Verify that symlink creates a valid symlink that is both a link and a - file if its target is a file, or a directory if its target is a - directory. - """ - targetLinks = [ - (self.path.child("sub2"), self.path.child("sub2.link")), - (self.path.child("sub2").child("file3.ext1"), - self.path.child("file3.ext1.link")) - ] - for target, link in targetLinks: - target.linkTo(link) - self.assertTrue(link.islink(), "This is a link") - self.assertEquals(target.isdir(), link.isdir()) - self.assertEquals(target.isfile(), link.isfile()) - - - def test_linkToErrors(self): - """ - Verify C{linkTo} fails in the following case: - - the target is in a directory that doesn't exist - - the target already exists - """ - self.assertRaises(OSError, self.path.child("file1").linkTo, - self.path.child('nosub').child('file1')) - self.assertRaises(OSError, self.path.child("file1").linkTo, - self.path.child('sub1').child('file2')) - - - if not getattr(os, "symlink", None): - skipMsg = "Your platform does not support symbolic links." - test_symbolicLink.skip = skipMsg - test_linkTo.skip = skipMsg - test_linkToErrors.skip = skipMsg - - - def testMultiExt(self): - f3 = self.path.child('sub3').child('file3') - exts = '.foo','.bar', 'ext1','ext2','ext3' - self.failIf(f3.siblingExtensionSearch(*exts)) - f3e = f3.siblingExtension(".foo") - f3e.touch() - self.failIf(not f3.siblingExtensionSearch(*exts).exists()) - self.failIf(not f3.siblingExtensionSearch('*').exists()) - f3e.remove() - self.failIf(f3.siblingExtensionSearch(*exts)) - - def testPreauthChild(self): - fp = filepath.FilePath('.') - fp.preauthChild('foo/bar') - self.assertRaises(filepath.InsecurePath, fp.child, '/foo') - - def testStatCache(self): - p = self.path.child('stattest') - p.touch() - self.failUnlessEqual(p.getsize(), 0) - self.failUnlessEqual(abs(p.getmtime() - time.time()) // 20, 0) - self.failUnlessEqual(abs(p.getctime() - time.time()) // 20, 0) - self.failUnlessEqual(abs(p.getatime() - time.time()) // 20, 0) - self.failUnlessEqual(p.exists(), True) - self.failUnlessEqual(p.exists(), True) - # OOB removal: FilePath.remove() will automatically restat - os.remove(p.path) - # test caching - self.failUnlessEqual(p.exists(), True) - p.restat(reraise=False) - self.failUnlessEqual(p.exists(), False) - self.failUnlessEqual(p.islink(), False) - self.failUnlessEqual(p.isdir(), False) - self.failUnlessEqual(p.isfile(), False) - - def testPersist(self): - newpath = pickle.loads(pickle.dumps(self.path)) - self.failUnlessEqual(self.path.__class__, newpath.__class__) - self.failUnlessEqual(self.path.path, newpath.path) - - def testInsecureUNIX(self): - self.assertRaises(filepath.InsecurePath, self.path.child, "..") - self.assertRaises(filepath.InsecurePath, self.path.child, "/etc") - self.assertRaises(filepath.InsecurePath, self.path.child, "../..") - - def testInsecureWin32(self): - self.assertRaises(filepath.InsecurePath, self.path.child, r"..\..") - self.assertRaises(filepath.InsecurePath, self.path.child, r"C:randomfile") - - if platform.getType() != 'win32': - testInsecureWin32.skip = "Consider yourself lucky." - - def testInsecureWin32Whacky(self): - """Windows has 'special' filenames like NUL and CON and COM1 and LPR - and PRN and ... god knows what else. They can be located anywhere in - the filesystem. For obvious reasons, we do not wish to normally permit - access to these. - """ - self.assertRaises(filepath.InsecurePath, self.path.child, "CON") - self.assertRaises(filepath.InsecurePath, self.path.child, "C:CON") - self.assertRaises(filepath.InsecurePath, self.path.child, r"C:\CON") - - if platform.getType() != 'win32': - testInsecureWin32Whacky.skip = "Consider yourself lucky." - - def testComparison(self): - self.assertEquals(filepath.FilePath('a'), - filepath.FilePath('a')) - self.failUnless(filepath.FilePath('z') > - filepath.FilePath('a')) - self.failUnless(filepath.FilePath('z') >= - filepath.FilePath('a')) - self.failUnless(filepath.FilePath('a') >= - filepath.FilePath('a')) - self.failUnless(filepath.FilePath('a') <= - filepath.FilePath('a')) - self.failUnless(filepath.FilePath('a') < - filepath.FilePath('z')) - self.failUnless(filepath.FilePath('a') <= - filepath.FilePath('z')) - self.failUnless(filepath.FilePath('a') != - filepath.FilePath('z')) - self.failUnless(filepath.FilePath('z') != - filepath.FilePath('a')) - - self.failIf(filepath.FilePath('z') != - filepath.FilePath('z')) - - def testSibling(self): - p = self.path.child('sibling_start') - ts = p.sibling('sibling_test') - self.assertEquals(ts.dirname(), p.dirname()) - self.assertEquals(ts.basename(), 'sibling_test') - ts.createDirectory() - self.assertIn(ts, self.path.children()) - - def testTemporarySibling(self): - ts = self.path.temporarySibling() - self.assertEquals(ts.dirname(), self.path.dirname()) - self.assertNotIn(ts.basename(), self.path.listdir()) - ts.createDirectory() - self.assertIn(ts, self.path.parent().children()) - - def testRemove(self): - self.path.remove() - self.failIf(self.path.exists()) - - - def test_removeWithSymlink(self): - """ - For a path which is a symbolic link, L{FilePath.remove} just deletes - the link, not the target. - """ - link = self.path.child("sub1.link") - # setUp creates the sub1 child - os.symlink(self.path.child("sub1").path, link.path) - link.remove() - self.assertFalse(link.exists()) - self.assertTrue(self.path.child("sub1").exists()) - - if getattr(os, 'symlink', None) is None: - test_removeWithSymlink.skip = "Platform doesn't support symbolic links" - - - def testCopyTo(self): - self.assertRaises((OSError, IOError), self.path.copyTo, self.path.child('file1')) - oldPaths = list(self.path.walk()) # Record initial state - fp = filepath.FilePath(self.mktemp()) - self.path.copyTo(fp) - self.path.remove() - fp.copyTo(self.path) - newPaths = list(self.path.walk()) # Record double-copy state - newPaths.sort() - oldPaths.sort() - self.assertEquals(newPaths, oldPaths) - - def testMoveTo(self): - self.assertRaises((OSError, IOError), self.path.moveTo, self.path.child('file1')) - oldPaths = list(self.path.walk()) # Record initial state - fp = filepath.FilePath(self.mktemp()) - self.path.moveTo(fp) - fp.moveTo(self.path) - newPaths = list(self.path.walk()) # Record double-move state - newPaths.sort() - oldPaths.sort() - self.assertEquals(newPaths, oldPaths) - - - def test_crossMountMoveTo(self): - """ - C{moveTo} should be able to handle C{EXDEV} error raised by - C{os.rename} when trying to move a file on a different mounted - filesystem. - """ - # Bit of a whitebox test - force os.rename, which moveTo tries - # before falling back to a slower method, to fail, forcing moveTo to - # use the slower behavior. - invokedWith = [] - def faultyRename(src, dest): - invokedWith.append((src, dest)) - if len(invokedWith) == 2: - raise OSError(errno.EXDEV, 'Test-induced failure simulating cross-device rename failure') - return originalRename(src, dest) - - originalRename = os.rename - os.rename = faultyRename - try: - self.testMoveTo() - # A bit of a sanity check for this whitebox test - if our rename - # was never invoked, the test has probably fallen into - # disrepair! - self.failUnless(len(invokedWith) >= 2) - finally: - os.rename = originalRename - - - def testOpen(self): - # Opening a file for reading when it does not already exist is an error - nonexistent = self.path.child('nonexistent') - e = self.assertRaises(IOError, nonexistent.open) - self.assertEquals(e.errno, errno.ENOENT) - - # Opening a file for writing when it does not exist is okay - writer = self.path.child('writer') - f = writer.open('w') - f.write('abc\ndef') - f.close() - - # Make sure those bytes ended up there - and test opening a file for - # reading when it does exist at the same time - f = writer.open() - self.assertEquals(f.read(), 'abc\ndef') - f.close() - - # Re-opening that file in write mode should erase whatever was there. - f = writer.open('w') - f.close() - f = writer.open() - self.assertEquals(f.read(), '') - f.close() - - # Put some bytes in a file so we can test that appending does not - # destroy them. - appender = self.path.child('appender') - f = appender.open('w') - f.write('abc') - f.close() - - f = appender.open('a') - f.write('def') - f.close() - - f = appender.open('r') - self.assertEquals(f.read(), 'abcdef') - f.close() - - # read/write should let us do both without erasing those bytes - f = appender.open('r+') - self.assertEquals(f.read(), 'abcdef') - # ANSI C *requires* an fseek or an fgetpos between an fread and an - # fwrite or an fwrite and a fread. We can't reliable get Python to - # invoke fgetpos, so we seek to a 0 byte offset from the current - # position instead. Also, Python sucks for making this seek - # relative to 1 instead of a symbolic constant representing the - # current file position. - f.seek(0, 1) - # Put in some new bytes for us to test for later. - f.write('ghi') - f.close() - - # Make sure those new bytes really showed up - f = appender.open('r') - self.assertEquals(f.read(), 'abcdefghi') - f.close() - - # write/read should let us do both, but erase anything that's there - # already. - f = appender.open('w+') - self.assertEquals(f.read(), '') - f.seek(0, 1) # Don't forget this! - f.write('123') - f.close() - - # super append mode should let us read and write and also position the - # cursor at the end of the file, without erasing everything. - f = appender.open('a+') - - # The order of these lines may seem surprising, but it is necessary. - # The cursor is not at the end of the file until after the first write. - f.write('456') - f.seek(0, 1) # Asinine. - self.assertEquals(f.read(), '') - - f.seek(0, 0) - self.assertEquals(f.read(), '123456') - f.close() - - # Opening a file exclusively must fail if that file exists already. - nonexistent.requireCreate(True) - nonexistent.open('w').close() - existent = nonexistent - del nonexistent - self.assertRaises((OSError, IOError), existent.open) - - - def test_existsCache(self): - """ - Check that C{filepath.FilePath.exists} correctly restat the object if - an operation has occurred in the mean time. - """ - fp = filepath.FilePath(self.mktemp()) - self.assertEquals(fp.exists(), False) - - fp.makedirs() - self.assertEquals(fp.exists(), True) - - - -from twisted.python import urlpath - -class URLPathTestCase(unittest.TestCase): - def setUp(self): - self.path = urlpath.URLPath.fromString("http://example.com/foo/bar?yes=no&no=yes#footer") - - def testStringConversion(self): - self.assertEquals(str(self.path), "http://example.com/foo/bar?yes=no&no=yes#footer") - - def testChildString(self): - self.assertEquals(str(self.path.child('hello')), "http://example.com/foo/bar/hello") - self.assertEquals(str(self.path.child('hello').child('')), "http://example.com/foo/bar/hello/") - - def testSiblingString(self): - self.assertEquals(str(self.path.sibling('baz')), 'http://example.com/foo/baz') - - # The sibling of http://example.com/foo/bar/ - # is http://example.comf/foo/bar/baz - # because really we are constructing a sibling of - # http://example.com/foo/bar/index.html - self.assertEquals(str(self.path.child('').sibling('baz')), 'http://example.com/foo/bar/baz') - - def testParentString(self): - # parent should be equivalent to '..' - # 'foo' is the current directory, '/' is the parent directory - self.assertEquals(str(self.path.parent()), 'http://example.com/') - self.assertEquals(str(self.path.child('').parent()), 'http://example.com/foo/') - self.assertEquals(str(self.path.child('baz').parent()), 'http://example.com/foo/') - self.assertEquals(str(self.path.parent().parent().parent().parent().parent()), 'http://example.com/') - - def testHereString(self): - # here should be equivalent to '.' - self.assertEquals(str(self.path.here()), 'http://example.com/foo/') - self.assertEquals(str(self.path.child('').here()), 'http://example.com/foo/bar/') - diff --git a/tools/buildbot/pylibs/twisted/test/test_pb.py b/tools/buildbot/pylibs/twisted/test/test_pb.py deleted file mode 100644 index 9d3e1b9..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_pb.py +++ /dev/null @@ -1,1618 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for Perspective Broker module. - -TODO: update protocol level tests to use new connection API, leaving -only specific tests for old API. -""" - -# issue1195 TODOs: replace pump.pump() with something involving Deferreds. -# Clean up warning suppression. Find a better replacement for the handful of -# reactor.callLater(0.1, ..) calls. - -import sys, os, time, gc - -from cStringIO import StringIO -from zope.interface import implements, Interface - -from twisted.trial import unittest - -from twisted.spread import pb, util, publish, jelly -from twisted.internet import protocol, main, reactor, defer -from twisted.internet.error import ConnectionRefusedError -from twisted.internet.defer import Deferred, gatherResults -from twisted.python import failure, log -from twisted.cred.error import UnauthorizedLogin, UnhandledCredentials -from twisted.cred import portal, checkers, credentials - - -class Dummy(pb.Viewable): - def view_doNothing(self, user): - if isinstance(user, DummyPerspective): - return 'hello world!' - else: - return 'goodbye, cruel world!' - - -class DummyPerspective(pb.Avatar): - def perspective_getDummyViewPoint(self): - return Dummy() - - -class DummyRealm(object): - implements(portal.IRealm) - - def requestAvatar(self, avatarId, mind, *interfaces): - for iface in interfaces: - if iface is pb.IPerspective: - return iface, DummyPerspective(), lambda: None - - -class IOPump: - """ - Utility to pump data between clients and servers for protocol testing. - - Perhaps this is a utility worthy of being in protocol.py? - """ - def __init__(self, client, server, clientIO, serverIO): - self.client = client - self.server = server - self.clientIO = clientIO - self.serverIO = serverIO - - def flush(self): - """ - Pump until there is no more input or output. This does not run any - timers, so don't use it with any code that calls reactor.callLater. - """ - # failsafe timeout - timeout = time.time() + 5 - while self.pump(): - if time.time() > timeout: - return - - def pump(self): - """ - Move data back and forth. - - Returns whether any data was moved. - """ - self.clientIO.seek(0) - self.serverIO.seek(0) - cData = self.clientIO.read() - sData = self.serverIO.read() - self.clientIO.seek(0) - self.serverIO.seek(0) - self.clientIO.truncate() - self.serverIO.truncate() - self.client.transport._checkProducer() - self.server.transport._checkProducer() - for byte in cData: - self.server.dataReceived(byte) - for byte in sData: - self.client.dataReceived(byte) - if cData or sData: - return 1 - else: - return 0 - - -def connectedServerAndClient(): - """ - Returns a 3-tuple: (client, server, pump). - """ - clientBroker = pb.Broker() - checker = checkers.InMemoryUsernamePasswordDatabaseDontUse(guest='guest') - factory = pb.PBServerFactory(portal.Portal(DummyRealm(), [checker])) - serverBroker = factory.buildProtocol(('127.0.0.1',)) - - clientTransport = StringIO() - serverTransport = StringIO() - clientBroker.makeConnection(protocol.FileWrapper(clientTransport)) - serverBroker.makeConnection(protocol.FileWrapper(serverTransport)) - pump = IOPump(clientBroker, serverBroker, clientTransport, serverTransport) - # Challenge-response authentication: - pump.flush() - return clientBroker, serverBroker, pump - - -class SimpleRemote(pb.Referenceable): - def remote_thunk(self, arg): - self.arg = arg - return arg + 1 - - def remote_knuth(self, arg): - raise Exception() - - -class NestedRemote(pb.Referenceable): - def remote_getSimple(self): - return SimpleRemote() - - -class SimpleCopy(pb.Copyable): - def __init__(self): - self.x = 1 - self.y = {"Hello":"World"} - self.z = ['test'] - - -class SimpleLocalCopy(pb.RemoteCopy): - pass - -pb.setCopierForClass(SimpleCopy, SimpleLocalCopy) - - -class SimpleFactoryCopy(pb.Copyable): - """ - @cvar allIDs: hold every created instances of this class. - @type allIDs: C{dict} - """ - allIDs = {} - def __init__(self, id): - self.id = id - SimpleFactoryCopy.allIDs[id] = self - - -def createFactoryCopy(state): - """ - Factory of L{SimpleFactoryCopy}, getting a created instance given the - C{id} found in C{state}. - """ - stateId = state.get("id", None) - if stateId is None: - raise RuntimeError("factory copy state has no 'id' member %s" % - (repr(state),)) - if not stateId in SimpleFactoryCopy.allIDs: - raise RuntimeError("factory class has no ID: %s" % - (SimpleFactoryCopy.allIDs,)) - inst = SimpleFactoryCopy.allIDs[stateId] - if not inst: - raise RuntimeError("factory method found no object with id") - return inst - -pb.setFactoryForClass(SimpleFactoryCopy, createFactoryCopy) - - -class NestedCopy(pb.Referenceable): - def remote_getCopy(self): - return SimpleCopy() - - def remote_getFactory(self, value): - return SimpleFactoryCopy(value) - - - -class SimpleCache(pb.Cacheable): - def __init___(self): - self.x = 1 - self.y = {"Hello":"World"} - self.z = ['test'] - - -class NestedComplicatedCache(pb.Referenceable): - def __init__(self): - self.c = VeryVeryComplicatedCacheable() - - def remote_getCache(self): - return self.c - - -class VeryVeryComplicatedCacheable(pb.Cacheable): - def __init__(self): - self.x = 1 - self.y = 2 - self.foo = 3 - - def setFoo4(self): - self.foo = 4 - self.observer.callRemote('foo',4) - - def getStateToCacheAndObserveFor(self, perspective, observer): - self.observer = observer - return {"x": self.x, - "y": self.y, - "foo": self.foo} - - def stoppedObserving(self, perspective, observer): - log.msg("stopped observing") - observer.callRemote("end") - if observer == self.observer: - self.observer = None - - -class RatherBaroqueCache(pb.RemoteCache): - def observe_foo(self, newFoo): - self.foo = newFoo - - def observe_end(self): - log.msg("the end of things") - -pb.setCopierForClass(VeryVeryComplicatedCacheable, RatherBaroqueCache) - - -class SimpleLocalCache(pb.RemoteCache): - def setCopyableState(self, state): - self.__dict__.update(state) - - def checkMethod(self): - return self.check - - def checkSelf(self): - return self - - def check(self): - return 1 - -pb.setCopierForClass(SimpleCache, SimpleLocalCache) - - -class NestedCache(pb.Referenceable): - def __init__(self): - self.x = SimpleCache() - - def remote_getCache(self): - return [self.x,self.x] - - def remote_putCache(self, cache): - return (self.x is cache) - - -class Observable(pb.Referenceable): - def __init__(self): - self.observers = [] - - def remote_observe(self, obs): - self.observers.append(obs) - - def remote_unobserve(self, obs): - self.observers.remove(obs) - - def notify(self, obj): - for observer in self.observers: - observer.callRemote('notify', self, obj) - - -class DeferredRemote(pb.Referenceable): - def __init__(self): - self.run = 0 - - def runMe(self, arg): - self.run = arg - return arg + 1 - - def dontRunMe(self, arg): - assert 0, "shouldn't have been run!" - - def remote_doItLater(self): - d = defer.Deferred() - d.addCallbacks(self.runMe, self.dontRunMe) - self.d = d - return d - - -class Observer(pb.Referenceable): - notified = 0 - obj = None - def remote_notify(self, other, obj): - self.obj = obj - self.notified = self.notified + 1 - other.callRemote('unobserve',self) - - -class NewStyleCopy(pb.Copyable, pb.RemoteCopy, object): - def __init__(self, s): - self.s = s -pb.setUnjellyableForClass(NewStyleCopy, NewStyleCopy) - - -class NewStyleCopy2(pb.Copyable, pb.RemoteCopy, object): - allocated = 0 - initialized = 0 - value = 1 - - def __new__(self): - NewStyleCopy2.allocated += 1 - inst = object.__new__(self) - inst.value = 2 - return inst - - def __init__(self): - NewStyleCopy2.initialized += 1 - -pb.setUnjellyableForClass(NewStyleCopy2, NewStyleCopy2) - - -class NewStyleCacheCopy(pb.Cacheable, pb.RemoteCache, object): - def getStateToCacheAndObserveFor(self, perspective, observer): - return self.__dict__ - -pb.setCopierForClass(NewStyleCacheCopy, NewStyleCacheCopy) - - -class Echoer(pb.Root): - def remote_echo(self, st): - return st - - -class CachedReturner(pb.Root): - def __init__(self, cache): - self.cache = cache - def remote_giveMeCache(self, st): - return self.cache - - -class NewStyleTestCase(unittest.TestCase): - def setUp(self): - """ - Create a pb server using L{Echoer} protocol and connect a client to it. - """ - self.server = reactor.listenTCP(0, pb.PBServerFactory(Echoer())) - clientFactory = pb.PBClientFactory() - reactor.connectTCP("localhost", self.server.getHost().port, - clientFactory) - def gotRoot(ref): - self.ref = ref - return clientFactory.getRootObject().addCallback(gotRoot) - - - def tearDown(self): - """ - Close client and server connections, reset values of L{NewStyleCopy2} - class variables. - """ - NewStyleCopy2.allocated = 0 - NewStyleCopy2.initialized = 0 - NewStyleCopy2.value = 1 - self.ref.broker.transport.loseConnection() - return self.server.stopListening() - - def test_newStyle(self): - """ - Create a new style object, send it over the wire, and check the result. - """ - orig = NewStyleCopy("value") - d = self.ref.callRemote("echo", orig) - def cb(res): - self.failUnless(isinstance(res, NewStyleCopy)) - self.failUnlessEqual(res.s, "value") - self.failIf(res is orig) # no cheating :) - d.addCallback(cb) - return d - - def test_alloc(self): - """ - Send a new style object and check the number of allocations. - """ - orig = NewStyleCopy2() - self.failUnlessEqual(NewStyleCopy2.allocated, 1) - self.failUnlessEqual(NewStyleCopy2.initialized, 1) - d = self.ref.callRemote("echo", orig) - def cb(res): - # receiving the response creates a third one on the way back - self.failUnless(isinstance(res, NewStyleCopy2)) - self.failUnlessEqual(res.value, 2) - self.failUnlessEqual(NewStyleCopy2.allocated, 3) - self.failUnlessEqual(NewStyleCopy2.initialized, 1) - self.failIf(res is orig) # no cheating :) - # sending the object creates a second one on the far side - d.addCallback(cb) - return d - - - -class ConnectionNotifyServerFactory(pb.PBServerFactory): - """ - A server factory which stores the last connection and fires a - L{defer.Deferred} on connection made. This factory can handle only one - client connection. - - @ivar protocolInstance: the last protocol instance. - @type protocolInstance: C{pb.Broker} - - @ivar connectionMade: the deferred fired upon connection. - @type connectionMade: C{defer.Deferred} - """ - protocolInstance = None - - def __init__(self, root): - """ - Initialize the factory. - """ - pb.PBServerFactory.__init__(self, root) - self.connectionMade = defer.Deferred() - - - def clientConnectionMade(self, protocol): - """ - Store the protocol and fire the connection deferred. - """ - self.protocolInstance = protocol - self.connectionMade.callback(None) - - - -class NewStyleCachedTestCase(unittest.TestCase): - def setUp(self): - """ - Create a pb server using L{CachedReturner} protocol and connect a - client to it. - """ - self.orig = NewStyleCacheCopy() - self.orig.s = "value" - self.server = reactor.listenTCP(0, - ConnectionNotifyServerFactory(CachedReturner(self.orig))) - clientFactory = pb.PBClientFactory() - reactor.connectTCP("localhost", self.server.getHost().port, - clientFactory) - def gotRoot(ref): - self.ref = ref - d1 = clientFactory.getRootObject().addCallback(gotRoot) - d2 = self.server.factory.connectionMade - return defer.gatherResults([d1, d2]) - - - def tearDown(self): - """ - Close client and server connections. - """ - self.server.factory.protocolInstance.transport.loseConnection() - self.ref.broker.transport.loseConnection() - return self.server.stopListening() - - - def test_newStyleCache(self): - """ - Get the object from the cache, and checks its properties. - """ - d = self.ref.callRemote("giveMeCache", self.orig) - def cb(res): - self.failUnless(isinstance(res, NewStyleCacheCopy)) - self.failUnlessEqual(res.s, "value") - self.failIf(res is self.orig) # no cheating :) - d.addCallback(cb) - return d - - - -class BrokerTestCase(unittest.TestCase): - thunkResult = None - - def tearDown(self): - try: - # from RemotePublished.getFileName - os.unlink('None-None-TESTING.pub') - except OSError: - pass - - def thunkErrorBad(self, error): - self.fail("This should cause a return value, not %s" % (error,)) - - def thunkResultGood(self, result): - self.thunkResult = result - - def thunkErrorGood(self, tb): - pass - - def thunkResultBad(self, result): - self.fail("This should cause an error, not %s" % (result,)) - - def test_reference(self): - c, s, pump = connectedServerAndClient() - - class X(pb.Referenceable): - def remote_catch(self,arg): - self.caught = arg - - class Y(pb.Referenceable): - def remote_throw(self, a, b): - a.callRemote('catch', b) - - s.setNameForLocal("y", Y()) - y = c.remoteForName("y") - x = X() - z = X() - y.callRemote('throw', x, z) - pump.pump() - pump.pump() - pump.pump() - self.assertIdentical(x.caught, z, "X should have caught Z") - - # make sure references to remote methods are equals - self.assertEquals(y.remoteMethod('throw'), y.remoteMethod('throw')) - - def test_result(self): - c, s, pump = connectedServerAndClient() - for x, y in (c, s), (s, c): - # test reflexivity - foo = SimpleRemote() - x.setNameForLocal("foo", foo) - bar = y.remoteForName("foo") - self.expectedThunkResult = 8 - bar.callRemote('thunk',self.expectedThunkResult - 1 - ).addCallbacks(self.thunkResultGood, self.thunkErrorBad) - # Send question. - pump.pump() - # Send response. - pump.pump() - # Shouldn't require any more pumping than that... - self.assertEquals(self.thunkResult, self.expectedThunkResult, - "result wasn't received.") - - def refcountResult(self, result): - self.nestedRemote = result - - def test_tooManyRefs(self): - l = [] - e = [] - c, s, pump = connectedServerAndClient() - foo = NestedRemote() - s.setNameForLocal("foo", foo) - x = c.remoteForName("foo") - for igno in xrange(pb.MAX_BROKER_REFS + 10): - if s.transport.closed or c.transport.closed: - break - x.callRemote("getSimple").addCallbacks(l.append, e.append) - pump.pump() - expected = (pb.MAX_BROKER_REFS - 1) - self.assertTrue(s.transport.closed, "transport was not closed") - self.assertEquals(len(l), expected, - "expected %s got %s" % (expected, len(l))) - - def test_copy(self): - c, s, pump = connectedServerAndClient() - foo = NestedCopy() - s.setNameForLocal("foo", foo) - x = c.remoteForName("foo") - x.callRemote('getCopy' - ).addCallbacks(self.thunkResultGood, self.thunkErrorBad) - pump.pump() - pump.pump() - self.assertEquals(self.thunkResult.x, 1) - self.assertEquals(self.thunkResult.y['Hello'], 'World') - self.assertEquals(self.thunkResult.z[0], 'test') - - def test_observe(self): - c, s, pump = connectedServerAndClient() - - # this is really testing the comparison between remote objects, to make - # sure that you can *UN*observe when you have an observer architecture. - a = Observable() - b = Observer() - s.setNameForLocal("a", a) - ra = c.remoteForName("a") - ra.callRemote('observe',b) - pump.pump() - a.notify(1) - pump.pump() - pump.pump() - a.notify(10) - pump.pump() - pump.pump() - self.assertNotIdentical(b.obj, None, "didn't notify") - self.assertEquals(b.obj, 1, 'notified too much') - - def test_defer(self): - c, s, pump = connectedServerAndClient() - d = DeferredRemote() - s.setNameForLocal("d", d) - e = c.remoteForName("d") - pump.pump(); pump.pump() - results = [] - e.callRemote('doItLater').addCallback(results.append) - pump.pump(); pump.pump() - self.assertFalse(d.run, "Deferred method run too early.") - d.d.callback(5) - self.assertEquals(d.run, 5, "Deferred method run too late.") - pump.pump(); pump.pump() - self.assertEquals(results[0], 6, "Incorrect result.") - - - def test_refcount(self): - c, s, pump = connectedServerAndClient() - foo = NestedRemote() - s.setNameForLocal("foo", foo) - bar = c.remoteForName("foo") - bar.callRemote('getSimple' - ).addCallbacks(self.refcountResult, self.thunkErrorBad) - - # send question - pump.pump() - # send response - pump.pump() - - # delving into internal structures here, because GC is sort of - # inherently internal. - rluid = self.nestedRemote.luid - self.assertIn(rluid, s.localObjects) - del self.nestedRemote - # nudge the gc - if sys.hexversion >= 0x2000000 and os.name != "java": - gc.collect() - # try to nudge the GC even if we can't really - pump.pump() - pump.pump() - pump.pump() - self.assertNotIn(rluid, s.localObjects) - - def test_cache(self): - c, s, pump = connectedServerAndClient() - obj = NestedCache() - obj2 = NestedComplicatedCache() - vcc = obj2.c - s.setNameForLocal("obj", obj) - s.setNameForLocal("xxx", obj2) - o2 = c.remoteForName("obj") - o3 = c.remoteForName("xxx") - coll = [] - o2.callRemote("getCache" - ).addCallback(coll.append).addErrback(coll.append) - o2.callRemote("getCache" - ).addCallback(coll.append).addErrback(coll.append) - complex = [] - o3.callRemote("getCache").addCallback(complex.append) - o3.callRemote("getCache").addCallback(complex.append) - pump.flush() - # `worst things first' - self.assertEquals(complex[0].x, 1) - self.assertEquals(complex[0].y, 2) - self.assertEquals(complex[0].foo, 3) - - vcc.setFoo4() - pump.flush() - self.assertEquals(complex[0].foo, 4) - self.assertEquals(len(coll), 2) - cp = coll[0][0] - self.assertIdentical(cp.checkMethod().im_self, cp, - "potential refcounting issue") - self.assertIdentical(cp.checkSelf(), cp, - "other potential refcounting issue") - col2 = [] - o2.callRemote('putCache',cp).addCallback(col2.append) - pump.flush() - # The objects were the same (testing lcache identity) - self.assertTrue(col2[0]) - # test equality of references to methods - self.assertEquals(o2.remoteMethod("getCache"), - o2.remoteMethod("getCache")) - - # now, refcounting (similiar to testRefCount) - luid = cp.luid - baroqueLuid = complex[0].luid - self.assertIn(luid, s.remotelyCachedObjects, - "remote cache doesn't have it") - del coll - del cp - pump.flush() - del complex - del col2 - # extra nudge... - pump.flush() - # del vcc.observer - # nudge the gc - if sys.hexversion >= 0x2000000 and os.name != "java": - gc.collect() - # try to nudge the GC even if we can't really - pump.flush() - # The GC is done with it. - self.assertNotIn(luid, s.remotelyCachedObjects, - "Server still had it after GC") - self.assertNotIn(luid, c.locallyCachedObjects, - "Client still had it after GC") - self.assertNotIn(baroqueLuid, s.remotelyCachedObjects, - "Server still had complex after GC") - self.assertNotIn(baroqueLuid, c.locallyCachedObjects, - "Client still had complex after GC") - self.assertIdentical(vcc.observer, None, "observer was not removed") - - def test_publishable(self): - try: - os.unlink('None-None-TESTING.pub') # from RemotePublished.getFileName - except OSError: - pass # Sometimes it's not there. - c, s, pump = connectedServerAndClient() - foo = GetPublisher() - # foo.pub.timestamp = 1.0 - s.setNameForLocal("foo", foo) - bar = c.remoteForName("foo") - accum = [] - bar.callRemote('getPub').addCallbacks(accum.append, self.thunkErrorBad) - pump.flush() - obj = accum.pop() - self.assertEquals(obj.activateCalled, 1) - self.assertEquals(obj.isActivated, 1) - self.assertEquals(obj.yayIGotPublished, 1) - # timestamp's dirty, we don't have a cache file - self.assertEquals(obj._wasCleanWhenLoaded, 0) - c, s, pump = connectedServerAndClient() - s.setNameForLocal("foo", foo) - bar = c.remoteForName("foo") - bar.callRemote('getPub').addCallbacks(accum.append, self.thunkErrorBad) - pump.flush() - obj = accum.pop() - # timestamp's clean, our cache file is up-to-date - self.assertEquals(obj._wasCleanWhenLoaded, 1) - - def gotCopy(self, val): - self.thunkResult = val.id - - - def test_factoryCopy(self): - c, s, pump = connectedServerAndClient() - ID = 99 - obj = NestedCopy() - s.setNameForLocal("foo", obj) - x = c.remoteForName("foo") - x.callRemote('getFactory', ID - ).addCallbacks(self.gotCopy, self.thunkResultBad) - pump.pump() - pump.pump() - pump.pump() - self.assertEquals(self.thunkResult, ID, - "ID not correct on factory object %s" % (self.thunkResult,)) - - -bigString = "helloworld" * 50 - -callbackArgs = None -callbackKeyword = None - -def finishedCallback(*args, **kw): - global callbackArgs, callbackKeyword - callbackArgs = args - callbackKeyword = kw - - -class Pagerizer(pb.Referenceable): - def __init__(self, callback, *args, **kw): - self.callback, self.args, self.kw = callback, args, kw - - def remote_getPages(self, collector): - util.StringPager(collector, bigString, 100, - self.callback, *self.args, **self.kw) - self.args = self.kw = None - - -class FilePagerizer(pb.Referenceable): - pager = None - - def __init__(self, filename, callback, *args, **kw): - self.filename = filename - self.callback, self.args, self.kw = callback, args, kw - - def remote_getPages(self, collector): - self.pager = util.FilePager(collector, file(self.filename), - self.callback, *self.args, **self.kw) - self.args = self.kw = None - - - -class PagingTestCase(unittest.TestCase): - """ - Test pb objects sending data by pages. - """ - - def setUp(self): - """ - Create a file used to test L{util.FilePager}. - """ - self.filename = self.mktemp() - fd = file(self.filename, 'w') - fd.write(bigString) - fd.close() - - - def test_pagingWithCallback(self): - """ - Test L{util.StringPager}, passing a callback to fire when all pages - are sent. - """ - c, s, pump = connectedServerAndClient() - s.setNameForLocal("foo", Pagerizer(finishedCallback, 'hello', value=10)) - x = c.remoteForName("foo") - l = [] - util.getAllPages(x, "getPages").addCallback(l.append) - while not l: - pump.pump() - self.assertEquals(''.join(l[0]), bigString, - "Pages received not equal to pages sent!") - self.assertEquals(callbackArgs, ('hello',), - "Completed callback not invoked") - self.assertEquals(callbackKeyword, {'value': 10}, - "Completed callback not invoked") - - - def test_pagingWithoutCallback(self): - """ - Test L{util.StringPager} without a callback. - """ - c, s, pump = connectedServerAndClient() - s.setNameForLocal("foo", Pagerizer(None)) - x = c.remoteForName("foo") - l = [] - util.getAllPages(x, "getPages").addCallback(l.append) - while not l: - pump.pump() - self.assertEquals(''.join(l[0]), bigString, - "Pages received not equal to pages sent!") - - - def test_emptyFilePaging(self): - """ - Test L{util.FilePager}, sending an empty file. - """ - filenameEmpty = self.mktemp() - fd = file(filenameEmpty, 'w') - fd.close() - c, s, pump = connectedServerAndClient() - pagerizer = FilePagerizer(filenameEmpty, None) - s.setNameForLocal("bar", pagerizer) - x = c.remoteForName("bar") - l = [] - util.getAllPages(x, "getPages").addCallback(l.append) - ttl = 10 - while not l and ttl > 0: - pump.pump() - ttl -= 1 - if not ttl: - self.fail('getAllPages timed out') - self.assertEquals(''.join(l[0]), '', - "Pages received not equal to pages sent!") - - - def test_filePagingWithCallback(self): - """ - Test L{util.FilePager}, passing a callback to fire when all pages - are sent, and verify that the pager doesn't keep chunks in memory. - """ - c, s, pump = connectedServerAndClient() - pagerizer = FilePagerizer(self.filename, finishedCallback, - 'frodo', value = 9) - s.setNameForLocal("bar", pagerizer) - x = c.remoteForName("bar") - l = [] - util.getAllPages(x, "getPages").addCallback(l.append) - while not l: - pump.pump() - self.assertEquals(''.join(l[0]), bigString, - "Pages received not equal to pages sent!") - self.assertEquals(callbackArgs, ('frodo',), - "Completed callback not invoked") - self.assertEquals(callbackKeyword, {'value': 9}, - "Completed callback not invoked") - self.assertEquals(pagerizer.pager.chunks, []) - - - def test_filePagingWithoutCallback(self): - """ - Test L{util.FilePager} without a callback. - """ - c, s, pump = connectedServerAndClient() - pagerizer = FilePagerizer(self.filename, None) - s.setNameForLocal("bar", pagerizer) - x = c.remoteForName("bar") - l = [] - util.getAllPages(x, "getPages").addCallback(l.append) - while not l: - pump.pump() - self.assertEquals(''.join(l[0]), bigString, - "Pages received not equal to pages sent!") - self.assertEquals(pagerizer.pager.chunks, []) - - - -class DumbPublishable(publish.Publishable): - def getStateToPublish(self): - return {"yayIGotPublished": 1} - - -class DumbPub(publish.RemotePublished): - def activated(self): - self.activateCalled = 1 - - -class GetPublisher(pb.Referenceable): - def __init__(self): - self.pub = DumbPublishable("TESTING") - - def remote_getPub(self): - return self.pub - - -pb.setCopierForClass(DumbPublishable, DumbPub) - -class DisconnectionTestCase(unittest.TestCase): - """ - Test disconnection callbacks. - """ - - def error(self, *args): - raise RuntimeError("I shouldn't have been called: %s" % (args,)) - - - def gotDisconnected(self): - """ - Called on broker disconnect. - """ - self.gotCallback = 1 - - def objectDisconnected(self, o): - """ - Called on RemoteReference disconnect. - """ - self.assertEquals(o, self.remoteObject) - self.objectCallback = 1 - - def test_badSerialization(self): - c, s, pump = connectedServerAndClient() - pump.pump() - s.setNameForLocal("o", BadCopySet()) - g = c.remoteForName("o") - l = [] - g.callRemote("setBadCopy", BadCopyable()).addErrback(l.append) - pump.flush() - self.assertEquals(len(l), 1) - - def test_disconnection(self): - c, s, pump = connectedServerAndClient() - pump.pump() - s.setNameForLocal("o", SimpleRemote()) - - # get a client reference to server object - r = c.remoteForName("o") - pump.pump() - pump.pump() - pump.pump() - - # register and then unregister disconnect callbacks - # making sure they get unregistered - c.notifyOnDisconnect(self.error) - self.assertIn(self.error, c.disconnects) - c.dontNotifyOnDisconnect(self.error) - self.assertNotIn(self.error, c.disconnects) - - r.notifyOnDisconnect(self.error) - self.assertIn(r._disconnected, c.disconnects) - self.assertIn(self.error, r.disconnectCallbacks) - r.dontNotifyOnDisconnect(self.error) - self.assertNotIn(r._disconnected, c.disconnects) - self.assertNotIn(self.error, r.disconnectCallbacks) - - # register disconnect callbacks - c.notifyOnDisconnect(self.gotDisconnected) - r.notifyOnDisconnect(self.objectDisconnected) - self.remoteObject = r - - # disconnect - c.connectionLost(failure.Failure(main.CONNECTION_DONE)) - self.assertTrue(self.gotCallback) - self.assertTrue(self.objectCallback) - - -class FreakOut(Exception): - pass - - -class BadCopyable(pb.Copyable): - def getStateToCopyFor(self, p): - raise FreakOut() - - -class BadCopySet(pb.Referenceable): - def remote_setBadCopy(self, bc): - return None - - -class LocalRemoteTest(util.LocalAsRemote): - reportAllTracebacks = 0 - - def sync_add1(self, x): - return x + 1 - - def async_add(self, x=0, y=1): - return x + y - - def async_fail(self): - raise RuntimeError() - - - -class TestRealm(object): - """ - A realm which repeatedly gives out a single instance of L{MyPerspective} - for non-anonymous logins and which gives out a new instance of L{Echoer} - for each anonymous login. - """ - - def __init__(self): - self.p = MyPerspective() - - def requestAvatar(self, avatarId, mind, interface): - """ - Verify that the mind and interface supplied have the expected values - (this should really be done somewhere else, like inside a test method) - and return an avatar appropriate for the given identifier. - """ - assert interface == pb.IPerspective - assert mind == "BRAINS!" - if avatarId is checkers.ANONYMOUS: - return pb.IPerspective, Echoer(), lambda: None - else: - self.p.loggedIn = 1 - return pb.IPerspective, self.p, self.p.logout - - - -class MyPerspective(pb.Avatar): - - implements(pb.IPerspective) - - loggedIn = loggedOut = False - - def __init__(self): - pass - - - def perspective_getViewPoint(self): - return MyView() - - - def perspective_add(self, a, b): - """ - Add the given objects and return the result. This is a method - unavailable on L{Echoer}, so it can only be invoked by authenticated - users who received their avatar from L{TestRealm}. - """ - return a + b - - - def logout(self): - self.loggedOut = True - - - -class MyView(pb.Viewable): - - def view_check(self, user): - return isinstance(user, MyPerspective) - - - -class NewCredTestCase(unittest.TestCase): - """ - Tests related to the L{twisted.cred} support in PB. - """ - def setUp(self): - """ - Create a portal with no checkers and wrap it around a simple test - realm. Set up a PB server on a TCP port which serves perspectives - using that portal. - """ - self.realm = TestRealm() - self.portal = portal.Portal(self.realm) - self.factory = pb.PBServerFactory(self.portal) - self.port = reactor.listenTCP(0, self.factory, interface="127.0.0.1") - self.portno = self.port.getHost().port - - - def tearDown(self): - """ - Shut down the TCP port created by L{setUp}. - """ - return self.port.stopListening() - - def getFactoryAndRootObject(self, clientFactory=pb.PBClientFactory): - factory = clientFactory() - rootObjDeferred = factory.getRootObject() - reactor.connectTCP('127.0.0.1', self.portno, factory) - return factory, rootObjDeferred - - - def test_getRootObject(self): - """ - Assert only that L{PBClientFactory.getRootObject}'s Deferred fires with - a L{RemoteReference}. - """ - factory, rootObjDeferred = self.getFactoryAndRootObject() - - def gotRootObject(rootObj): - self.failUnless(isinstance(rootObj, pb.RemoteReference)) - disconnectedDeferred = defer.Deferred() - rootObj.notifyOnDisconnect(disconnectedDeferred.callback) - factory.disconnect() - return disconnectedDeferred - - return rootObjDeferred.addCallback(gotRootObject) - - - def test_deadReferenceError(self): - """ - Test that when a connection is lost, calling a method on a - RemoteReference obtained from it raises DeadReferenceError. - """ - factory, rootObjDeferred = self.getFactoryAndRootObject() - - def gotRootObject(rootObj): - disconnectedDeferred = defer.Deferred() - rootObj.notifyOnDisconnect(disconnectedDeferred.callback) - - def lostConnection(ign): - self.assertRaises( - pb.DeadReferenceError, - rootObj.callRemote, 'method') - - disconnectedDeferred.addCallback(lostConnection) - factory.disconnect() - return disconnectedDeferred - - return rootObjDeferred.addCallback(gotRootObject) - - - def test_clientConnectionLost(self): - """ - Test that if the L{reconnecting} flag is passed with a True value then - a remote call made from a disconnection notification callback gets a - result successfully. - """ - class ReconnectOnce(pb.PBClientFactory): - reconnectedAlready = False - def clientConnectionLost(self, connector, reason): - reconnecting = not self.reconnectedAlready - self.reconnectedAlready = True - if reconnecting: - connector.connect() - return pb.PBClientFactory.clientConnectionLost( - self, connector, reason, reconnecting) - - factory, rootObjDeferred = self.getFactoryAndRootObject(ReconnectOnce) - - def gotRootObject(rootObj): - self.assertIsInstance(rootObj, pb.RemoteReference) - - d = defer.Deferred() - rootObj.notifyOnDisconnect(d.callback) - factory.disconnect() - - def disconnected(ign): - d = factory.getRootObject() - - def gotAnotherRootObject(anotherRootObj): - self.assertIsInstance(anotherRootObj, pb.RemoteReference) - - d = defer.Deferred() - anotherRootObj.notifyOnDisconnect(d.callback) - factory.disconnect() - return d - return d.addCallback(gotAnotherRootObject) - return d.addCallback(disconnected) - return rootObjDeferred.addCallback(gotRootObject) - - - def test_immediateClose(self): - """ - Test that if a Broker loses its connection without receiving any bytes, - it doesn't raise any exceptions or log any errors. - """ - serverProto = self.factory.buildProtocol(('127.0.0.1', 12345)) - serverProto.makeConnection(protocol.FileWrapper(StringIO())) - serverProto.connectionLost(failure.Failure(main.CONNECTION_DONE)) - - - def test_loginConnectionRefused(self): - """ - L{PBClientFactory.login} returns a L{Deferred} which is errbacked - with the L{ConnectionRefusedError} if the underlying connection is - refused. - """ - clientFactory = pb.PBClientFactory() - loginDeferred = clientFactory.login( - credentials.UsernamePassword("foo", "bar")) - clientFactory.clientConnectionFailed( - None, - failure.Failure( - ConnectionRefusedError("Test simulated refused connection"))) - return self.assertFailure(loginDeferred, ConnectionRefusedError) - - - def test_loginLogout(self): - """ - Test that login can be performed with IUsernamePassword credentials and - that when the connection is dropped the avatar is logged out. - """ - self.portal.registerChecker( - checkers.InMemoryUsernamePasswordDatabaseDontUse(user='pass')) - factory = pb.PBClientFactory() - creds = credentials.UsernamePassword("user", "pass") - - # NOTE: real code probably won't need anything where we have the - # "BRAINS!" argument, passing None is fine. We just do it here to - # test that it is being passed. It is used to give additional info to - # the realm to aid perspective creation, if you don't need that, - # ignore it. - mind = "BRAINS!" - - d = factory.login(creds, mind) - def cbLogin(perspective): - self.assertEquals(self.realm.p.loggedIn, 1) - self.assert_(isinstance(perspective, pb.RemoteReference)) - - factory.disconnect() - d = Deferred() - reactor.callLater(1.0, d.callback, None) - return d - d.addCallback(cbLogin) - - def cbLogout(ignored): - self.assertEquals(self.realm.p.loggedOut, 1) - d.addCallback(cbLogout) - - reactor.connectTCP("127.0.0.1", self.portno, factory) - return d - - - def test_badUsernamePasswordLogin(self): - """ - Test that a login attempt with an invalid user or invalid password - fails in the appropriate way. - """ - self.portal.registerChecker( - checkers.InMemoryUsernamePasswordDatabaseDontUse(user='pass')) - factory = pb.PBClientFactory() - - firstLogin = factory.login( - credentials.UsernamePassword('nosuchuser', 'pass')) - secondLogin = factory.login( - credentials.UsernamePassword('user', 'wrongpass')) - - self.assertFailure(firstLogin, UnauthorizedLogin) - self.assertFailure(secondLogin, UnauthorizedLogin) - d = gatherResults([firstLogin, secondLogin]) - - def cleanup(passthrough): - self.flushLoggedErrors(UnauthorizedLogin) - factory.disconnect() - return passthrough - d.addBoth(cleanup) - - reactor.connectTCP("127.0.0.1", self.portno, factory) - return d - - - def test_anonymousLogin(self): - """ - Verify that a PB server using a portal configured with an checker which - allows IAnonymous credentials can be logged into using IAnonymous - credentials. - """ - self.portal.registerChecker(checkers.AllowAnonymousAccess()) - factory = pb.PBClientFactory() - d = factory.login(credentials.Anonymous(), "BRAINS!") - - def cbLoggedIn(perspective): - return perspective.callRemote('echo', 123) - d.addCallback(cbLoggedIn) - - d.addCallback(self.assertEqual, 123) - - def cleanup(passthrough): - factory.disconnect() - d = Deferred() - reactor.callLater(1.0, d.callback, None) - return d - d.addBoth(cleanup) - - reactor.connectTCP("127.0.0.1", self.portno, factory) - return d - - - def test_anonymousLoginNotPermitted(self): - """ - Verify that without an anonymous checker set up, anonymous login is - rejected. - """ - self.portal.registerChecker( - checkers.InMemoryUsernamePasswordDatabaseDontUse(user='pass')) - factory = pb.PBClientFactory() - d = factory.login(credentials.Anonymous(),"BRAINS!") - self.assertFailure(d, UnhandledCredentials) - - def cleanup(passthrough): - self.flushLoggedErrors(UnhandledCredentials) - factory.disconnect() - return passthrough - d.addBoth(cleanup) - - reactor.connectTCP('127.0.0.1', self.portno, factory) - return d - - - def test_anonymousLoginWithMultipleCheckers(self): - """ - Like L{test_anonymousLogin} but against a portal with a checker for - both IAnonymous and IUsernamePassword. - """ - self.portal.registerChecker(checkers.AllowAnonymousAccess()) - self.portal.registerChecker( - checkers.InMemoryUsernamePasswordDatabaseDontUse(user='pass')) - factory = pb.PBClientFactory() - d = factory.login(credentials.Anonymous(), "BRAINS!") - - def cbLogin(perspective): - return perspective.callRemote('echo', 123) - d.addCallback(cbLogin) - - d.addCallback(self.assertEqual, 123) - - def cleanup(passthrough): - factory.disconnect() - return passthrough - d.addBoth(cleanup) - - reactor.connectTCP('127.0.0.1', self.portno, factory) - return d - - - def test_authenticatedLoginWithMultipleCheckers(self): - """ - Like L{test_anonymousLoginWithMultipleCheckers} but check that - username/password authentication works. - """ - self.portal.registerChecker(checkers.AllowAnonymousAccess()) - self.portal.registerChecker( - checkers.InMemoryUsernamePasswordDatabaseDontUse(user='pass')) - factory = pb.PBClientFactory() - d = factory.login( - credentials.UsernamePassword('user', 'pass'), "BRAINS!") - - def cbLogin(perspective): - return perspective.callRemote('add', 100, 23) - d.addCallback(cbLogin) - - d.addCallback(self.assertEqual, 123) - - def cleanup(passthrough): - factory.disconnect() - return passthrough - d.addBoth(cleanup) - - reactor.connectTCP('127.0.0.1', self.portno, factory) - return d - - - def test_view(self): - """ - Verify that a viewpoint can be retrieved after authenticating with - cred. - """ - self.portal.registerChecker( - checkers.InMemoryUsernamePasswordDatabaseDontUse(user='pass')) - factory = pb.PBClientFactory() - d = factory.login( - credentials.UsernamePassword("user", "pass"), "BRAINS!") - - def cbLogin(perspective): - return perspective.callRemote("getViewPoint") - d.addCallback(cbLogin) - - def cbView(viewpoint): - return viewpoint.callRemote("check") - d.addCallback(cbView) - - d.addCallback(self.failUnless) - - def cleanup(passthrough): - factory.disconnect() - d = Deferred() - reactor.callLater(1.0, d.callback, None) - return d - d.addBoth(cleanup) - - reactor.connectTCP("127.0.0.1", self.portno, factory) - return d - - - -class NonSubclassingPerspective: - implements(pb.IPerspective) - - # IPerspective implementation - def perspectiveMessageReceived(self, broker, message, args, kwargs): - args = broker.unserialize(args, self) - kwargs = broker.unserialize(kwargs, self) - return broker.serialize((message, args, kwargs)) - - # Methods required by TestRealm - def logout(self): - self.loggedOut = True - - - -class NSPTestCase(unittest.TestCase): - def setUp(self): - self.realm = TestRealm() - self.realm.p = NonSubclassingPerspective() - self.portal = portal.Portal(self.realm) - self.checker = checkers.InMemoryUsernamePasswordDatabaseDontUse() - self.checker.addUser("user", "pass") - self.portal.registerChecker(self.checker) - self.factory = pb.PBServerFactory(self.portal) - self.port = reactor.listenTCP(0, self.factory, interface="127.0.0.1") - self.portno = self.port.getHost().port - - def tearDown(self): - return self.port.stopListening() - - def test_NSP(self): - factory = pb.PBClientFactory() - d = factory.login(credentials.UsernamePassword('user', 'pass'), - "BRAINS!") - reactor.connectTCP('127.0.0.1', self.portno, factory) - d.addCallback(lambda p: p.callRemote('ANYTHING', 'here', bar='baz')) - d.addCallback(self.assertEquals, - ('ANYTHING', ('here',), {'bar': 'baz'})) - d.addCallback(lambda res: factory.disconnect()) - return d - - - -class IForwarded(Interface): - """ - Interface used for testing L{util.LocalAsyncForwarder}. - """ - - def forwardMe(): - """ - Simple synchronous method. - """ - - def forwardDeferred(): - """ - Simple asynchronous method. - """ - - -class Forwarded: - """ - Test implementation of L{IForwarded}. - - @ivar forwarded: set if C{forwardMe} is called. - @type forwarded: C{bool} - @ivar unforwarded: set if C{dontForwardMe} is called. - @type unforwarded: C{bool} - """ - implements(IForwarded) - forwarded = False - unforwarded = False - - def forwardMe(self): - """ - Set a local flag to test afterwards. - """ - self.forwarded = True - - def dontForwardMe(self): - """ - Set a local flag to test afterwards. This should not be called as it's - not in the interface. - """ - self.unforwarded = True - - def forwardDeferred(self): - """ - Asynchronously return C{True}. - """ - return defer.succeed(True) - - -class SpreadUtilTestCase(unittest.TestCase): - """ - Tests for L{twisted.spread.util}. - """ - - def test_sync(self): - """ - Call a synchronous method of a L{util.LocalAsRemote} object and check - the result. - """ - o = LocalRemoteTest() - self.assertEquals(o.callRemote("add1", 2), 3) - - def test_async(self): - """ - Call an asynchronous method of a L{util.LocalAsRemote} object and check - the result. - """ - o = LocalRemoteTest() - o = LocalRemoteTest() - d = o.callRemote("add", 2, y=4) - self.assertTrue(isinstance(d, defer.Deferred)) - d.addCallback(self.assertEquals, 6) - return d - - def test_asyncFail(self): - """ - Test a asynchronous failure on a remote method call. - """ - l = [] - o = LocalRemoteTest() - d = o.callRemote("fail") - def eb(f): - self.assertTrue(isinstance(f, failure.Failure)) - f.trap(RuntimeError) - d.addCallbacks(lambda res: self.fail("supposed to fail"), eb) - return d - - def test_remoteMethod(self): - """ - Test the C{remoteMethod} facility of L{util.LocalAsRemote}. - """ - o = LocalRemoteTest() - m = o.remoteMethod("add1") - self.assertEquals(m(3), 4) - - def test_localAsyncForwarder(self): - """ - Test a call to L{util.LocalAsyncForwarder} using L{Forwarded} local - object. - """ - f = Forwarded() - lf = util.LocalAsyncForwarder(f, IForwarded) - lf.callRemote("forwardMe") - self.assertTrue(f.forwarded) - lf.callRemote("dontForwardMe") - self.assertFalse(f.unforwarded) - rr = lf.callRemote("forwardDeferred") - l = [] - rr.addCallback(l.append) - self.assertEqual(l[0], 1) - - - -class PBWithSecurityOptionsTest(unittest.TestCase): - """ - Test security customization. - """ - - def test_clientDefaultSecurityOptions(self): - """ - By default, client broker should use C{jelly.globalSecurity} as - security settings. - """ - factory = pb.PBClientFactory() - broker = factory.buildProtocol(None) - self.assertIdentical(broker.security, jelly.globalSecurity) - - - def test_serverDefaultSecurityOptions(self): - """ - By default, server broker should use C{jelly.globalSecurity} as - security settings. - """ - factory = pb.PBServerFactory(Echoer()) - broker = factory.buildProtocol(None) - self.assertIdentical(broker.security, jelly.globalSecurity) - - - def test_clientSecurityCustomization(self): - """ - Check that the security settings are passed from the client factory to - the broker object. - """ - security = jelly.SecurityOptions() - factory = pb.PBClientFactory(security=security) - broker = factory.buildProtocol(None) - self.assertIdentical(broker.security, security) - - - def test_serverSecurityCustomization(self): - """ - Check that the security settings are passed from the server factory to - the broker object. - """ - security = jelly.SecurityOptions() - factory = pb.PBServerFactory(Echoer(), security=security) - broker = factory.buildProtocol(None) - self.assertIdentical(broker.security, security) - diff --git a/tools/buildbot/pylibs/twisted/test/test_pbfailure.py b/tools/buildbot/pylibs/twisted/test/test_pbfailure.py deleted file mode 100644 index a0981de..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_pbfailure.py +++ /dev/null @@ -1,407 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for error handling in PB. -""" - -from twisted.trial import unittest - -from twisted.spread import pb, flavors, jelly -from twisted.internet import reactor, defer -from twisted.python import log - -## -# test exceptions -## -class AsynchronousException(Exception): - """ - Helper used to test remote methods which return Deferreds which fail with - exceptions which are not L{pb.Error} subclasses. - """ - - -class SynchronousException(Exception): - """ - Helper used to test remote methods which raise exceptions which are not - L{pb.Error} subclasses. - """ - - -class AsynchronousError(pb.Error): - """ - Helper used to test remote methods which return Deferreds which fail with - exceptions which are L{pb.Error} subclasses. - """ - - -class SynchronousError(pb.Error): - """ - Helper used to test remote methods which raise exceptions which are - L{pb.Error} subclasses. - """ - - -#class JellyError(flavors.Jellyable, pb.Error): pass -class JellyError(flavors.Jellyable, pb.Error, pb.RemoteCopy): - pass - - -class SecurityError(pb.Error, pb.RemoteCopy): - pass - -pb.setUnjellyableForClass(JellyError, JellyError) -pb.setUnjellyableForClass(SecurityError, SecurityError) -pb.globalSecurity.allowInstancesOf(SecurityError) - - -#### -# server-side -#### -class SimpleRoot(pb.Root): - def remote_asynchronousException(self): - """ - Fail asynchronously with a non-pb.Error exception. - """ - return defer.fail(AsynchronousException("remote asynchronous exception")) - - def remote_synchronousException(self): - """ - Fail synchronously with a non-pb.Error exception. - """ - raise SynchronousException("remote synchronous exception") - - def remote_asynchronousError(self): - """ - Fail asynchronously with a pb.Error exception. - """ - return defer.fail(AsynchronousError("remote asynchronous error")) - - def remote_synchronousError(self): - """ - Fail synchronously with a pb.Error exception. - """ - raise SynchronousError("remote synchronous error") - - def remote_unknownError(self): - """ - Fail with error that is not known to client. - """ - class UnknownError(pb.Error): - pass - raise UnknownError("I'm not known to client!") - - def remote_jelly(self): - self.raiseJelly() - - def remote_security(self): - self.raiseSecurity() - - def remote_deferredJelly(self): - d = defer.Deferred() - d.addCallback(self.raiseJelly) - d.callback(None) - return d - - def remote_deferredSecurity(self): - d = defer.Deferred() - d.addCallback(self.raiseSecurity) - d.callback(None) - return d - - def raiseJelly(self, results=None): - raise JellyError("I'm jellyable!") - - def raiseSecurity(self, results=None): - raise SecurityError("I'm secure!") - - - -class PBConnTestCase(unittest.TestCase): - unsafeTracebacks = 0 - - def setUp(self): - self._setUpServer() - self._setUpClient() - - def _setUpServer(self): - self.serverFactory = pb.PBServerFactory(SimpleRoot()) - self.serverFactory.unsafeTracebacks = self.unsafeTracebacks - self.serverPort = reactor.listenTCP(0, self.serverFactory, interface="127.0.0.1") - - def _setUpClient(self): - portNo = self.serverPort.getHost().port - self.clientFactory = pb.PBClientFactory() - self.clientConnector = reactor.connectTCP("127.0.0.1", portNo, self.clientFactory) - - def tearDown(self): - return defer.gatherResults([ - self._tearDownServer(), - self._tearDownClient()]) - - def _tearDownServer(self): - return defer.maybeDeferred(self.serverPort.stopListening) - - def _tearDownClient(self): - self.clientConnector.disconnect() - return defer.succeed(None) - - - -class PBFailureTest(PBConnTestCase): - compare = unittest.TestCase.assertEquals - - - def _exceptionTest(self, method, exceptionType, flush): - def eb(err): - err.trap(exceptionType) - self.compare(err.traceback, "Traceback unavailable\n") - if flush: - errs = self.flushLoggedErrors(exceptionType) - self.assertEqual(len(errs), 1) - return (err.type, err.value, err.traceback) - d = self.clientFactory.getRootObject() - def gotRootObject(root): - d = root.callRemote(method) - d.addErrback(eb) - return d - d.addCallback(gotRootObject) - return d - - - def test_asynchronousException(self): - """ - Test that a Deferred returned by a remote method which already has a - Failure correctly has that error passed back to the calling side. - """ - return self._exceptionTest( - 'asynchronousException', AsynchronousException, True) - - - def test_synchronousException(self): - """ - Like L{test_asynchronousException}, but for a method which raises an - exception synchronously. - """ - return self._exceptionTest( - 'synchronousException', SynchronousException, True) - - - def test_asynchronousError(self): - """ - Like L{test_asynchronousException}, but for a method which returns a - Deferred failing with an L{pb.Error} subclass. - """ - return self._exceptionTest( - 'asynchronousError', AsynchronousError, False) - - - def test_synchronousError(self): - """ - Like L{test_asynchronousError}, but for a method which synchronously - raises a L{pb.Error} subclass. - """ - return self._exceptionTest( - 'synchronousError', SynchronousError, False) - - - def _success(self, result, expectedResult): - self.assertEquals(result, expectedResult) - return result - - - def _addFailingCallbacks(self, remoteCall, expectedResult, eb): - remoteCall.addCallbacks(self._success, eb, - callbackArgs=(expectedResult,)) - return remoteCall - - - def _testImpl(self, method, expected, eb, exc=None): - """ - Call the given remote method and attach the given errback to the - resulting Deferred. If C{exc} is not None, also assert that one - exception of that type was logged. - """ - rootDeferred = self.clientFactory.getRootObject() - def gotRootObj(obj): - failureDeferred = self._addFailingCallbacks(obj.callRemote(method), expected, eb) - if exc is not None: - def gotFailure(err): - self.assertEquals(len(self.flushLoggedErrors(exc)), 1) - return err - failureDeferred.addBoth(gotFailure) - return failureDeferred - rootDeferred.addCallback(gotRootObj) - return rootDeferred - - - def test_jellyFailure(self): - """ - Test that an exception which is a subclass of L{pb.Error} has more - information passed across the network to the calling side. - """ - def failureJelly(fail): - fail.trap(JellyError) - self.failIf(isinstance(fail.type, str)) - self.failUnless(isinstance(fail.value, fail.type)) - return 43 - return self._testImpl('jelly', 43, failureJelly) - - - def test_deferredJellyFailure(self): - """ - Test that a Deferred which fails with a L{pb.Error} is treated in - the same way as a synchronously raised L{pb.Error}. - """ - def failureDeferredJelly(fail): - fail.trap(JellyError) - self.failIf(isinstance(fail.type, str)) - self.failUnless(isinstance(fail.value, fail.type)) - return 430 - return self._testImpl('deferredJelly', 430, failureDeferredJelly) - - - def test_unjellyableFailure(self): - """ - An non-jellyable L{pb.Error} subclass raised by a remote method is - turned into a Failure with a type set to the FQPN of the exception - type. - """ - def failureUnjellyable(fail): - self.assertEqual( - fail.type, 'twisted.test.test_pbfailure.SynchronousError') - return 431 - return self._testImpl('synchronousError', 431, failureUnjellyable) - - - def test_unknownFailure(self): - """ - Test that an exception which is a subclass of L{pb.Error} but not - known on the client side has its type set properly. - """ - def failureUnknown(fail): - self.assertEqual( - fail.type, 'twisted.test.test_pbfailure.UnknownError') - return 4310 - return self._testImpl('unknownError', 4310, failureUnknown) - - - def test_securityFailure(self): - """ - Test that even if an exception is not explicitly jellyable (by being - a L{pb.Jellyable} subclass), as long as it is an L{pb.Error} - subclass it receives the same special treatment. - """ - def failureSecurity(fail): - fail.trap(SecurityError) - self.failIf(isinstance(fail.type, str)) - self.failUnless(isinstance(fail.value, fail.type)) - return 4300 - return self._testImpl('security', 4300, failureSecurity) - - - def test_deferredSecurity(self): - """ - Test that a Deferred which fails with a L{pb.Error} which is not - also a L{pb.Jellyable} is treated in the same way as a synchronously - raised exception of the same type. - """ - def failureDeferredSecurity(fail): - fail.trap(SecurityError) - self.failIf(isinstance(fail.type, str)) - self.failUnless(isinstance(fail.value, fail.type)) - return 43000 - return self._testImpl('deferredSecurity', 43000, failureDeferredSecurity) - - - def test_noSuchMethodFailure(self): - """ - Test that attempting to call a method which is not defined correctly - results in an AttributeError on the calling side. - """ - def failureNoSuch(fail): - fail.trap(pb.NoSuchMethod) - self.compare(fail.traceback, "Traceback unavailable\n") - return 42000 - return self._testImpl('nosuch', 42000, failureNoSuch, AttributeError) - - - def test_copiedFailureLogging(self): - """ - Test that a copied failure received from a PB call can be logged - locally. - - Note: this test needs some serious help: all it really tests is that - log.err(copiedFailure) doesn't raise an exception. - """ - d = self.clientFactory.getRootObject() - - def connected(rootObj): - return rootObj.callRemote('synchronousException') - d.addCallback(connected) - - def exception(failure): - log.err(failure) - errs = self.flushLoggedErrors(SynchronousException) - self.assertEquals(len(errs), 2) - d.addErrback(exception) - - return d - - - -class PBFailureTestUnsafe(PBFailureTest): - compare = unittest.TestCase.failIfEquals - unsafeTracebacks = 1 - - - -class DummyInvoker(object): - """ - A behaviorless object to be used as the invoker parameter to - L{jelly.jelly}. - """ - serializingPerspective = None - - - -class FailureJellyingTests(unittest.TestCase): - """ - Tests for the interaction of jelly and failures. - """ - def test_unjelliedFailureCheck(self): - """ - An unjellied L{CopyableFailure} has a check method which behaves the - same way as the original L{CopyableFailure}'s check method. - """ - original = pb.CopyableFailure(ZeroDivisionError()) - self.assertIdentical( - original.check(ZeroDivisionError), ZeroDivisionError) - self.assertIdentical(original.check(ArithmeticError), ArithmeticError) - copied = jelly.unjelly(jelly.jelly(original, invoker=DummyInvoker())) - self.assertIdentical( - copied.check(ZeroDivisionError), ZeroDivisionError) - self.assertIdentical(copied.check(ArithmeticError), ArithmeticError) - - - def test_twiceUnjelliedFailureCheck(self): - """ - The object which results from jellying a L{CopyableFailure}, unjellying - the result, creating a new L{CopyableFailure} from the result of that, - jellying it, and finally unjellying the result of that has a check - method which behaves the same way as the original L{CopyableFailure}'s - check method. - """ - original = pb.CopyableFailure(ZeroDivisionError()) - self.assertIdentical( - original.check(ZeroDivisionError), ZeroDivisionError) - self.assertIdentical(original.check(ArithmeticError), ArithmeticError) - copiedOnce = jelly.unjelly( - jelly.jelly(original, invoker=DummyInvoker())) - derivative = pb.CopyableFailure(copiedOnce) - copiedTwice = jelly.unjelly( - jelly.jelly(derivative, invoker=DummyInvoker())) - self.assertIdentical( - copiedTwice.check(ZeroDivisionError), ZeroDivisionError) - self.assertIdentical( - copiedTwice.check(ArithmeticError), ArithmeticError) diff --git a/tools/buildbot/pylibs/twisted/test/test_pcp.py b/tools/buildbot/pylibs/twisted/test/test_pcp.py deleted file mode 100644 index 806d45b..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_pcp.py +++ /dev/null @@ -1,368 +0,0 @@ -# -*- Python -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -__version__ = '$Revision: 1.5 $'[11:-2] - -from StringIO import StringIO -from twisted.trial import unittest -from twisted.protocols import pcp - -# Goal: - -# Take a Protocol instance. Own all outgoing data - anything that -# would go to p.transport.write. Own all incoming data - anything -# that comes to p.dataReceived. - -# I need: -# Something with the AbstractFileDescriptor interface. -# That is: -# - acts as a Transport -# - has a method write() -# - which buffers -# - acts as a Consumer -# - has a registerProducer, unRegisterProducer -# - tells the Producer to back off (pauseProducing) when its buffer is full. -# - tells the Producer to resumeProducing when its buffer is not so full. -# - acts as a Producer -# - calls registerProducer -# - calls write() on consumers -# - honors requests to pause/resume producing -# - honors stopProducing, and passes it along to upstream Producers - - -class DummyTransport: - """A dumb transport to wrap around.""" - - def __init__(self): - self._writes = [] - - def write(self, data): - self._writes.append(data) - - def getvalue(self): - return ''.join(self._writes) - -class DummyProducer: - resumed = False - stopped = False - paused = False - - def __init__(self, consumer): - self.consumer = consumer - - def resumeProducing(self): - self.resumed = True - self.paused = False - - def pauseProducing(self): - self.paused = True - - def stopProducing(self): - self.stopped = True - - -class DummyConsumer(DummyTransport): - producer = None - finished = False - unregistered = True - - def registerProducer(self, producer, streaming): - self.producer = (producer, streaming) - - def unregisterProducer(self): - self.unregistered = True - - def finish(self): - self.finished = True - -class TransportInterfaceTest(unittest.TestCase): - proxyClass = pcp.BasicProducerConsumerProxy - - def setUp(self): - self.underlying = DummyConsumer() - self.transport = self.proxyClass(self.underlying) - - def testWrite(self): - self.transport.write("some bytes") - -class ConsumerInterfaceTest: - """Test ProducerConsumerProxy as a Consumer. - - Normally we have ProducingServer -> ConsumingTransport. - - If I am to go between (Server -> Shaper -> Transport), I have to - play the role of Consumer convincingly for the ProducingServer. - """ - - def setUp(self): - self.underlying = DummyConsumer() - self.consumer = self.proxyClass(self.underlying) - self.producer = DummyProducer(self.consumer) - - def testRegisterPush(self): - self.consumer.registerProducer(self.producer, True) - ## Consumer should NOT have called PushProducer.resumeProducing - self.failIf(self.producer.resumed) - - ## I'm I'm just a proxy, should I only do resumeProducing when - ## I get poked myself? - #def testRegisterPull(self): - # self.consumer.registerProducer(self.producer, False) - # ## Consumer SHOULD have called PushProducer.resumeProducing - # self.failUnless(self.producer.resumed) - - def testUnregister(self): - self.consumer.registerProducer(self.producer, False) - self.consumer.unregisterProducer() - # Now when the consumer would ordinarily want more data, it - # shouldn't ask producer for it. - # The most succinct way to trigger "want more data" is to proxy for - # a PullProducer and have someone ask me for data. - self.producer.resumed = False - self.consumer.resumeProducing() - self.failIf(self.producer.resumed) - - def testFinish(self): - self.consumer.registerProducer(self.producer, False) - self.consumer.finish() - # I guess finish should behave like unregister? - self.producer.resumed = False - self.consumer.resumeProducing() - self.failIf(self.producer.resumed) - - -class ProducerInterfaceTest: - """Test ProducerConsumerProxy as a Producer. - - Normally we have ProducingServer -> ConsumingTransport. - - If I am to go between (Server -> Shaper -> Transport), I have to - play the role of Producer convincingly for the ConsumingTransport. - """ - - def setUp(self): - self.consumer = DummyConsumer() - self.producer = self.proxyClass(self.consumer) - - def testRegistersProducer(self): - self.failUnlessEqual(self.consumer.producer[0], self.producer) - - def testPause(self): - self.producer.pauseProducing() - self.producer.write("yakkity yak") - self.failIf(self.consumer.getvalue(), - "Paused producer should not have sent data.") - - def testResume(self): - self.producer.pauseProducing() - self.producer.resumeProducing() - self.producer.write("yakkity yak") - self.failUnlessEqual(self.consumer.getvalue(), "yakkity yak") - - def testResumeNoEmptyWrite(self): - self.producer.pauseProducing() - self.producer.resumeProducing() - self.failUnlessEqual(len(self.consumer._writes), 0, - "Resume triggered an empty write.") - - def testResumeBuffer(self): - self.producer.pauseProducing() - self.producer.write("buffer this") - self.producer.resumeProducing() - self.failUnlessEqual(self.consumer.getvalue(), "buffer this") - - def testStop(self): - self.producer.stopProducing() - self.producer.write("yakkity yak") - self.failIf(self.consumer.getvalue(), - "Stopped producer should not have sent data.") - - -class PCP_ConsumerInterfaceTest(ConsumerInterfaceTest, unittest.TestCase): - proxyClass = pcp.BasicProducerConsumerProxy - -class PCPII_ConsumerInterfaceTest(ConsumerInterfaceTest, unittest.TestCase): - proxyClass = pcp.ProducerConsumerProxy - -class PCP_ProducerInterfaceTest(ProducerInterfaceTest, unittest.TestCase): - proxyClass = pcp.BasicProducerConsumerProxy - -class PCPII_ProducerInterfaceTest(ProducerInterfaceTest, unittest.TestCase): - proxyClass = pcp.ProducerConsumerProxy - -class ProducerProxyTest(unittest.TestCase): - """Producer methods on me should be relayed to the Producer I proxy. - """ - proxyClass = pcp.BasicProducerConsumerProxy - - def setUp(self): - self.proxy = self.proxyClass(None) - self.parentProducer = DummyProducer(self.proxy) - self.proxy.registerProducer(self.parentProducer, True) - - def testStop(self): - self.proxy.stopProducing() - self.failUnless(self.parentProducer.stopped) - - -class ConsumerProxyTest(unittest.TestCase): - """Consumer methods on me should be relayed to the Consumer I proxy. - """ - proxyClass = pcp.BasicProducerConsumerProxy - - def setUp(self): - self.underlying = DummyConsumer() - self.consumer = self.proxyClass(self.underlying) - - def testWrite(self): - # NOTE: This test only valid for streaming (Push) systems. - self.consumer.write("some bytes") - self.failUnlessEqual(self.underlying.getvalue(), "some bytes") - - def testFinish(self): - self.consumer.finish() - self.failUnless(self.underlying.finished) - - def testUnregister(self): - self.consumer.unregisterProducer() - self.failUnless(self.underlying.unregistered) - - -class PullProducerTest: - def setUp(self): - self.underlying = DummyConsumer() - self.proxy = self.proxyClass(self.underlying) - self.parentProducer = DummyProducer(self.proxy) - self.proxy.registerProducer(self.parentProducer, True) - - def testHoldWrites(self): - self.proxy.write("hello") - # Consumer should get no data before it says resumeProducing. - self.failIf(self.underlying.getvalue(), - "Pulling Consumer got data before it pulled.") - - def testPull(self): - self.proxy.write("hello") - self.proxy.resumeProducing() - self.failUnlessEqual(self.underlying.getvalue(), "hello") - - def testMergeWrites(self): - self.proxy.write("hello ") - self.proxy.write("sunshine") - self.proxy.resumeProducing() - nwrites = len(self.underlying._writes) - self.failUnlessEqual(nwrites, 1, "Pull resulted in %d writes instead " - "of 1." % (nwrites,)) - self.failUnlessEqual(self.underlying.getvalue(), "hello sunshine") - - - def testLateWrite(self): - # consumer sends its initial pull before we have data - self.proxy.resumeProducing() - self.proxy.write("data") - # This data should answer that pull request. - self.failUnlessEqual(self.underlying.getvalue(), "data") - -class PCP_PullProducerTest(PullProducerTest, unittest.TestCase): - class proxyClass(pcp.BasicProducerConsumerProxy): - iAmStreaming = False - -class PCPII_PullProducerTest(PullProducerTest, unittest.TestCase): - class proxyClass(pcp.ProducerConsumerProxy): - iAmStreaming = False - -# Buffering! - -class BufferedConsumerTest(unittest.TestCase): - """As a consumer, ask the producer to pause after too much data.""" - - proxyClass = pcp.ProducerConsumerProxy - - def setUp(self): - self.underlying = DummyConsumer() - self.proxy = self.proxyClass(self.underlying) - self.proxy.bufferSize = 100 - - self.parentProducer = DummyProducer(self.proxy) - self.proxy.registerProducer(self.parentProducer, True) - - def testRegisterPull(self): - self.proxy.registerProducer(self.parentProducer, False) - ## Consumer SHOULD have called PushProducer.resumeProducing - self.failUnless(self.parentProducer.resumed) - - def testPauseIntercept(self): - self.proxy.pauseProducing() - self.failIf(self.parentProducer.paused) - - def testResumeIntercept(self): - self.proxy.pauseProducing() - self.proxy.resumeProducing() - # With a streaming producer, just because the proxy was resumed is - # not necessarily a reason to resume the parent producer. The state - # of the buffer should decide that. - self.failIf(self.parentProducer.resumed) - - def testTriggerPause(self): - """Make sure I say \"when.\"""" - - # Pause the proxy so data sent to it builds up in its buffer. - self.proxy.pauseProducing() - self.failIf(self.parentProducer.paused, "don't pause yet") - self.proxy.write("x" * 51) - self.failIf(self.parentProducer.paused, "don't pause yet") - self.proxy.write("x" * 51) - self.failUnless(self.parentProducer.paused) - - def testTriggerResume(self): - """Make sure I resumeProducing when my buffer empties.""" - self.proxy.pauseProducing() - self.proxy.write("x" * 102) - self.failUnless(self.parentProducer.paused, "should be paused") - self.proxy.resumeProducing() - # Resuming should have emptied my buffer, so I should tell my - # parent to resume too. - self.failIf(self.parentProducer.paused, - "Producer should have resumed.") - self.failIf(self.proxy.producerPaused) - -class BufferedPullTests(unittest.TestCase): - class proxyClass(pcp.ProducerConsumerProxy): - iAmStreaming = False - - def _writeSomeData(self, data): - pcp.ProducerConsumerProxy._writeSomeData(self, data[:100]) - return min(len(data), 100) - - def setUp(self): - self.underlying = DummyConsumer() - self.proxy = self.proxyClass(self.underlying) - self.proxy.bufferSize = 100 - - self.parentProducer = DummyProducer(self.proxy) - self.proxy.registerProducer(self.parentProducer, False) - - def testResumePull(self): - # If proxy has no data to send on resumeProducing, it had better pull - # some from its PullProducer. - self.parentProducer.resumed = False - self.proxy.resumeProducing() - self.failUnless(self.parentProducer.resumed) - - def testLateWriteBuffering(self): - # consumer sends its initial pull before we have data - self.proxy.resumeProducing() - self.proxy.write("datum" * 21) - # This data should answer that pull request. - self.failUnlessEqual(self.underlying.getvalue(), "datum" * 20) - # but there should be some left over - self.failUnlessEqual(self.proxy._buffer, ["datum"]) - - -# TODO: -# test that web request finishing bug (when we weren't proxying -# unregisterProducer but were proxying finish, web file transfers -# would hang on the last block.) -# test what happens if writeSomeBytes decided to write zero bytes. diff --git a/tools/buildbot/pylibs/twisted/test/test_persisted.py b/tools/buildbot/pylibs/twisted/test/test_persisted.py deleted file mode 100644 index 1e60df6..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_persisted.py +++ /dev/null @@ -1,474 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -# System Imports -import sys - -from twisted.trial import unittest - -try: - import cPickle as pickle -except ImportError: - import pickle - -try: - import cStringIO as StringIO -except ImportError: - import StringIO - -# Twisted Imports -from twisted.persisted import styles, aot, crefutil - - -class VersionTestCase(unittest.TestCase): - def testNullVersionUpgrade(self): - global NullVersioned - class NullVersioned: - ok = 0 - pkcl = pickle.dumps(NullVersioned()) - class NullVersioned(styles.Versioned): - persistenceVersion = 1 - def upgradeToVersion1(self): - self.ok = 1 - mnv = pickle.loads(pkcl) - styles.doUpgrade() - assert mnv.ok, "initial upgrade not run!" - - def testVersionUpgrade(self): - global MyVersioned - class MyVersioned(styles.Versioned): - persistenceVersion = 2 - persistenceForgets = ['garbagedata'] - v3 = 0 - v4 = 0 - - def __init__(self): - self.somedata = 'xxx' - self.garbagedata = lambda q: 'cant persist' - - def upgradeToVersion3(self): - self.v3 += 1 - - def upgradeToVersion4(self): - self.v4 += 1 - mv = MyVersioned() - assert not (mv.v3 or mv.v4), "hasn't been upgraded yet" - pickl = pickle.dumps(mv) - MyVersioned.persistenceVersion = 4 - obj = pickle.loads(pickl) - styles.doUpgrade() - assert obj.v3, "didn't do version 3 upgrade" - assert obj.v4, "didn't do version 4 upgrade" - pickl = pickle.dumps(obj) - obj = pickle.loads(pickl) - styles.doUpgrade() - assert obj.v3 == 1, "upgraded unnecessarily" - assert obj.v4 == 1, "upgraded unnecessarily" - - def testNonIdentityHash(self): - global ClassWithCustomHash - class ClassWithCustomHash(styles.Versioned): - def __init__(self, unique, hash): - self.unique = unique - self.hash = hash - def __hash__(self): - return self.hash - - v1 = ClassWithCustomHash('v1', 0) - v2 = ClassWithCustomHash('v2', 0) - - pkl = pickle.dumps((v1, v2)) - del v1, v2 - ClassWithCustomHash.persistenceVersion = 1 - ClassWithCustomHash.upgradeToVersion1 = lambda self: setattr(self, 'upgraded', True) - v1, v2 = pickle.loads(pkl) - styles.doUpgrade() - self.assertEquals(v1.unique, 'v1') - self.assertEquals(v2.unique, 'v2') - self.failUnless(v1.upgraded) - self.failUnless(v2.upgraded) - - def testUpgradeDeserializesObjectsRequiringUpgrade(self): - global ToyClassA, ToyClassB - class ToyClassA(styles.Versioned): - pass - class ToyClassB(styles.Versioned): - pass - x = ToyClassA() - y = ToyClassB() - pklA, pklB = pickle.dumps(x), pickle.dumps(y) - del x, y - ToyClassA.persistenceVersion = 1 - def upgradeToVersion1(self): - self.y = pickle.loads(pklB) - styles.doUpgrade() - ToyClassA.upgradeToVersion1 = upgradeToVersion1 - ToyClassB.persistenceVersion = 1 - ToyClassB.upgradeToVersion1 = lambda self: setattr(self, 'upgraded', True) - - x = pickle.loads(pklA) - styles.doUpgrade() - self.failUnless(x.y.upgraded) - -class MyEphemeral(styles.Ephemeral): - - def __init__(self, x): - self.x = x - - -class EphemeralTestCase(unittest.TestCase): - - def testEphemeral(self): - o = MyEphemeral(3) - self.assertEquals(o.__class__, MyEphemeral) - self.assertEquals(o.x, 3) - - pickl = pickle.dumps(o) - o = pickle.loads(pickl) - - self.assertEquals(o.__class__, styles.Ephemeral) - self.assert_(not hasattr(o, 'x')) - - -class Pickleable: - - def __init__(self, x): - self.x = x - - def getX(self): - return self.x - -class A: - """ - dummy class - """ - def amethod(self): - pass - -class B: - """ - dummy class - """ - def bmethod(self): - pass - -def funktion(): - pass - -try: - from twisted.persisted import marmalade -except ImportError: - pass -else: - class Marmaladeable(marmalade.DOMJellyable): - - jellyDOMVersion = 1 - - def __init__(self, integer, instance, name, sequence): - self.integer = integer - self.instance = instance - self.sequence = sequence - self.name = name - - def jellyToDOM_1(self, jellier, element): - from twisted.python.reflect import qual - element.setAttribute("integer", str(self.integer)) - element.setAttribute("instance", qual(self.instance.__class__)) # not l33t enough - element.setAttribute("name", str(self.name)) - # oops forgot self.sequence - - def unjellyFromDOM_1(self, unjellier, element): - from twisted.python.reflect import namedClass - self.integer = int(element.getAttribute("integer")) - self.instance = namedClass(element.getAttribute("instance"))() - self.name = element.getAttribute("name") - # just give us any ol' list - self.sequence = [self.instance, self.instance] - - def jellyToDOM_2(self, jellier, element): - element.setAttribute("integer", str(self.integer)) - element.setAttribute("name", str(self.name)) - instanceNode = jellier.jellyToNode(self.instance) # l33ter! - instanceNode.setAttribute("parent:role", "instance") - element.appendChild(instanceNode) - i = 0 - for seqel in self.sequence: - seqNode = jellier.jellyToNode(seqel) - seqNode.setAttribute("parent:role", "sequence:%d" % i) - element.appendChild(seqNode) - i = i + 1 - - def unjellyFromDOM_2(self, unjellier, element): - self.integer = int(element.getAttribute("integer")) - self.name = element.getAttribute("name") - - # Note to people reading this as an example: if you don't use - # "unjellyInto", and instead use "unjellyFromNode", it will appear to - # work. _however_, it will also have some really surprising results - # when you have references in your application; i.e. you will get - # _Dereference instances in places where you thought you should have - # references to back-referenced data. I am working on making this - # simpler. - from twisted.web.microdom import Element - self.sequence = [] - i = 0 - for node in element.childNodes: - if isinstance(node, Element): - if node.getAttribute("parent:role") == 'instance': - unjellier.unjellyAttribute(self, "instance", node) - else: - self.sequence.append(None) - unjellier.unjellyLater(node).addCallback( - self.gotSequenceItem, i) - i = i + 1 - - def gotSequenceItem(self, seqitem, num): - self.sequence[num] = seqitem - - - class MarmaladeTestCase(unittest.TestCase): - - def testMarmaladeable(self): - m = Marmaladeable(1, B(), "testing", [1, 2, 3]) - s = marmalade.jellyToXML(m) - u = marmalade.unjellyFromXML(s) - assert u.sequence == [u.instance, u.instance] - u.sequence.append(u.instance) - u.jellyDOMVersion = 2 - s2 = marmalade.jellyToXML(u) - u2 = marmalade.unjellyFromXML(s2) - self.assertEquals( u2.sequence, [u2.instance, u2.instance, u2.instance]) - - def testCopyReg(self): - s = "foo_bar" - sio = StringIO.StringIO() - sio.write(s) - assert marmalade.unjellyFromXML(marmalade.jellyToXML({1:sio}))[1].getvalue() == s - - def testMethodSelfIdentity(self): - a = A() - b = B() - a.bmethod = b.bmethod - b.a = a - im_ = marmalade.unjellyFromXML(marmalade.jellyToXML(b)).a.bmethod - self.assertEquals(im_.im_class, im_.im_self.__class__) - - - def test_methodNotSelfIdentity(self): - """ - If a class change after an instance has been created, - L{marmalade.unjellyFromXML} shoud raise a C{TypeError} when trying - to unjelly the instance. - """ - a = A() - b = B() - a.bmethod = b.bmethod - b.a = a - savedbmethod = B.bmethod - del B.bmethod - try: - self.assertRaises(TypeError, marmalade.unjellyFromXML, - marmalade.jellyToXML(b)) - finally: - B.bmethod = savedbmethod - - - def test_unjellyWrongRole(self): - """ - When trying to unjelly a dictionnary dump, C{role} attributes - should have the C{key}. Otherwise, L{marmalade.unjellyFromXML} - should raise a C{TypeError}. - """ - data = marmalade.jellyToXML({"a": 1}) - data = data.replace('role="key"', 'role="foo"') - self.assertRaises(TypeError, marmalade.unjellyFromXML, data) - - - def test_unjellyUnknownNodeType(self): - """ - L{marmalade.unjellyFromXML} should raise a C{TypeError} when trying - to unjelly an unknown type. - """ - data = marmalade.jellyToXML({}) - data = data.replace('dictionary', 'unknowntype') - self.assertRaises(TypeError, marmalade.unjellyFromXML, data) - - - def testBasicIdentity(self): - # Anyone wanting to make this datastructure more complex, and thus this - # test more comprehensive, is welcome to do so. - dj = marmalade.DOMJellier().jellyToNode - d = {'hello': 'world', "method": dj} - l = [1, 2, 3, - "he\tllo\n\n\"x world!", - u"goodbye \n\t\u1010 world!", - 1, 1.0, 100 ** 100l, unittest, marmalade.DOMJellier, d, - funktion, - True, False, - (2, 4, [2]), - ] - t = tuple(l) - l.append(l) - l.append(t) - l.append(t) - uj = marmalade.unjellyFromXML(marmalade.jellyToXML([l, l])) - assert uj[0] is uj[1] - assert uj[1][0:5] == l[0:5] - -class PicklingTestCase(unittest.TestCase): - """Test pickling of extra object types.""" - - def testModule(self): - pickl = pickle.dumps(styles) - o = pickle.loads(pickl) - self.assertEquals(o, styles) - - def testClassMethod(self): - pickl = pickle.dumps(Pickleable.getX) - o = pickle.loads(pickl) - self.assertEquals(o, Pickleable.getX) - - def testInstanceMethod(self): - obj = Pickleable(4) - pickl = pickle.dumps(obj.getX) - o = pickle.loads(pickl) - self.assertEquals(o(), 4) - self.assertEquals(type(o), type(obj.getX)) - - def testStringIO(self): - f = StringIO.StringIO() - f.write("abc") - pickl = pickle.dumps(f) - o = pickle.loads(pickl) - self.assertEquals(type(o), type(f)) - self.assertEquals(f.getvalue(), "abc") - - -class EvilSourceror: - def __init__(self, x): - self.a = self - self.a.b = self - self.a.b.c = x - -class NonDictState: - def __getstate__(self): - return self.state - def __setstate__(self, state): - self.state = state - -class AOTTestCase(unittest.TestCase): - def testSimpleTypes(self): - obj = (1, 2.0, 3j, True, slice(1, 2, 3), 'hello', u'world', sys.maxint + 1, None, Ellipsis) - rtObj = aot.unjellyFromSource(aot.jellyToSource(obj)) - self.assertEquals(obj, rtObj) - - def testMethodSelfIdentity(self): - a = A() - b = B() - a.bmethod = b.bmethod - b.a = a - im_ = aot.unjellyFromSource(aot.jellyToSource(b)).a.bmethod - self.assertEquals(im_.im_class, im_.im_self.__class__) - - - def test_methodNotSelfIdentity(self): - """ - If a class change after an instance has been created, - L{aot.unjellyFromSource} shoud raise a C{TypeError} when trying to - unjelly the instance. - """ - a = A() - b = B() - a.bmethod = b.bmethod - b.a = a - savedbmethod = B.bmethod - del B.bmethod - try: - self.assertRaises(TypeError, aot.unjellyFromSource, - aot.jellyToSource(b)) - finally: - B.bmethod = savedbmethod - - - def test_unsupportedType(self): - """ - L{aot.jellyToSource} should raise a C{TypeError} when trying to jelly - an unknown type. - """ - try: - set - except: - from sets import Set as set - self.assertRaises(TypeError, aot.jellyToSource, set()) - - - def testBasicIdentity(self): - # Anyone wanting to make this datastructure more complex, and thus this - # test more comprehensive, is welcome to do so. - aj = aot.AOTJellier().jellyToAO - d = {'hello': 'world', "method": aj} - l = [1, 2, 3, - "he\tllo\n\n\"x world!", - u"goodbye \n\t\u1010 world!", - 1, 1.0, 100 ** 100l, unittest, aot.AOTJellier, d, - funktion - ] - t = tuple(l) - l.append(l) - l.append(t) - l.append(t) - uj = aot.unjellyFromSource(aot.jellyToSource([l, l])) - assert uj[0] is uj[1] - assert uj[1][0:5] == l[0:5] - - - def testNonDictState(self): - a = NonDictState() - a.state = "meringue!" - assert aot.unjellyFromSource(aot.jellyToSource(a)).state == a.state - - def testCopyReg(self): - s = "foo_bar" - sio = StringIO.StringIO() - sio.write(s) - uj = aot.unjellyFromSource(aot.jellyToSource(sio)) - # print repr(uj.__dict__) - assert uj.getvalue() == s - - def testFunkyReferences(self): - o = EvilSourceror(EvilSourceror([])) - j1 = aot.jellyToAOT(o) - oj = aot.unjellyFromAOT(j1) - - assert oj.a is oj - assert oj.a.b is oj.b - assert oj.c is not oj.c.c - - -class CrefUtilTestCase(unittest.TestCase): - """ - Tests for L{crefutil}. - """ - - def test_dictUnknownKey(self): - """ - L{crefutil._DictKeyAndValue} only support keys C{0} and C{1}. - """ - d = crefutil._DictKeyAndValue({}) - self.assertRaises(RuntimeError, d.__setitem__, 2, 3) - - - def test_deferSetMultipleTimes(self): - """ - L{crefutil._Defer} can be assigned a key only one time. - """ - d = crefutil._Defer() - d[0] = 1 - self.assertRaises(RuntimeError, d.__setitem__, 0, 1) - - - -testCases = [VersionTestCase, EphemeralTestCase, PicklingTestCase] - diff --git a/tools/buildbot/pylibs/twisted/test/test_plugin.py b/tools/buildbot/pylibs/twisted/test/test_plugin.py deleted file mode 100644 index 48bb142..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_plugin.py +++ /dev/null @@ -1,694 +0,0 @@ -# Copyright (c) 2005 Divmod, Inc. -# Copyright (c) 2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for Twisted plugin system. -""" - -import sys, errno, os, time -import compileall - -from zope.interface import Interface - -from twisted.trial import unittest -from twisted.python.filepath import FilePath -from twisted.python.util import mergeFunctionMetadata - -from twisted import plugin - - - -class ITestPlugin(Interface): - """ - A plugin for use by the plugin system's unit tests. - - Do not use this. - """ - - - -class ITestPlugin2(Interface): - """ - See L{ITestPlugin}. - """ - - - -class PluginTestCase(unittest.TestCase): - """ - Tests which verify the behavior of the current, active Twisted plugins - directory. - """ - - def setUp(self): - """ - Save C{sys.path} and C{sys.modules}, and create a package for tests. - """ - self.originalPath = sys.path[:] - self.savedModules = sys.modules.copy() - - self.root = FilePath(self.mktemp()) - self.root.createDirectory() - self.package = self.root.child('mypackage') - self.package.createDirectory() - self.package.child('__init__.py').setContent("") - - FilePath(__file__).sibling('plugin_basic.py' - ).copyTo(self.package.child('testplugin.py')) - - self.originalPlugin = "testplugin" - - sys.path.insert(0, self.root.path) - import mypackage - self.module = mypackage - - - def tearDown(self): - """ - Restore C{sys.path} and C{sys.modules} to their original values. - """ - sys.path[:] = self.originalPath - sys.modules.clear() - sys.modules.update(self.savedModules) - - - def _unimportPythonModule(self, module, deleteSource=False): - modulePath = module.__name__.split('.') - packageName = '.'.join(modulePath[:-1]) - moduleName = modulePath[-1] - - delattr(sys.modules[packageName], moduleName) - del sys.modules[module.__name__] - for ext in ['c', 'o'] + (deleteSource and [''] or []): - try: - os.remove(module.__file__ + ext) - except OSError, ose: - if ose.errno != errno.ENOENT: - raise - - - def _clearCache(self): - """ - Remove the plugins B{droping.cache} file. - """ - self.package.child('dropin.cache').remove() - - - def _withCacheness(meth): - """ - This is a paranoid test wrapper, that calls C{meth} 2 times, clear the - cache, and calls it 2 other times. It's supposed to ensure that the - plugin system behaves correctly no matter what the state of the cache - is. - """ - def wrapped(self): - meth(self) - meth(self) - self._clearCache() - meth(self) - meth(self) - return mergeFunctionMetadata(meth, wrapped) - - - def test_cache(self): - """ - Check that the cache returned by L{plugin.getCache} hold the plugin - B{testplugin}, and that this plugin has the properties we expect: - provide L{TestPlugin}, has the good name and description, and can be - loaded successfully. - """ - cache = plugin.getCache(self.module) - - dropin = cache[self.originalPlugin] - self.assertEquals(dropin.moduleName, - 'mypackage.%s' % (self.originalPlugin,)) - self.assertIn("I'm a test drop-in.", dropin.description) - - # Note, not the preferred way to get a plugin by its interface. - p1 = [p for p in dropin.plugins if ITestPlugin in p.provided][0] - self.assertIdentical(p1.dropin, dropin) - self.assertEquals(p1.name, "TestPlugin") - - # Check the content of the description comes from the plugin module - # docstring - self.assertEquals( - p1.description.strip(), - "A plugin used solely for testing purposes.") - self.assertEquals(p1.provided, [ITestPlugin, plugin.IPlugin]) - realPlugin = p1.load() - # The plugin should match the class present in sys.modules - self.assertIdentical( - realPlugin, - sys.modules['mypackage.%s' % (self.originalPlugin,)].TestPlugin) - - # And it should also match if we import it classicly - import mypackage.testplugin as tp - self.assertIdentical(realPlugin, tp.TestPlugin) - - test_cache = _withCacheness(test_cache) - - - def test_plugins(self): - """ - L{plugin.getPlugins} should return the list of plugins matching the - specified interface (here, L{ITestPlugin2}), and these plugins - should be instances of classes with a C{test} method, to be sure - L{plugin.getPlugins} load classes correctly. - """ - plugins = list(plugin.getPlugins(ITestPlugin2, self.module)) - - self.assertEquals(len(plugins), 2) - - names = ['AnotherTestPlugin', 'ThirdTestPlugin'] - for p in plugins: - names.remove(p.__name__) - p.test() - - test_plugins = _withCacheness(test_plugins) - - - def test_detectNewFiles(self): - """ - Check that L{plugin.getPlugins} is able to detect plugins added at - runtime. - """ - FilePath(__file__).sibling('plugin_extra1.py' - ).copyTo(self.package.child('pluginextra.py')) - try: - # Check that the current situation is clean - self.failIfIn('mypackage.pluginextra', sys.modules) - self.failIf(hasattr(sys.modules['mypackage'], 'pluginextra'), - "mypackage still has pluginextra module") - - plgs = list(plugin.getPlugins(ITestPlugin, self.module)) - - # We should find 2 plugins: the one in testplugin, and the one in - # pluginextra - self.assertEquals(len(plgs), 2) - - names = ['TestPlugin', 'FourthTestPlugin'] - for p in plgs: - names.remove(p.__name__) - p.test1() - finally: - self._unimportPythonModule( - sys.modules['mypackage.pluginextra'], - True) - - test_detectNewFiles = _withCacheness(test_detectNewFiles) - - - def test_detectFilesChanged(self): - """ - Check that if the content of a plugin change, L{plugin.getPlugins} is - able to detect the new plugins added. - """ - FilePath(__file__).sibling('plugin_extra1.py' - ).copyTo(self.package.child('pluginextra.py')) - try: - plgs = list(plugin.getPlugins(ITestPlugin, self.module)) - # Sanity check - self.assertEquals(len(plgs), 2) - - FilePath(__file__).sibling('plugin_extra2.py' - ).copyTo(self.package.child('pluginextra.py')) - - # Fake out Python. - self._unimportPythonModule(sys.modules['mypackage.pluginextra']) - - # Make sure additions are noticed - plgs = list(plugin.getPlugins(ITestPlugin, self.module)) - - self.assertEquals(len(plgs), 3) - - names = ['TestPlugin', 'FourthTestPlugin', 'FifthTestPlugin'] - for p in plgs: - names.remove(p.__name__) - p.test1() - finally: - self._unimportPythonModule( - sys.modules['mypackage.pluginextra'], - True) - - test_detectFilesChanged = _withCacheness(test_detectFilesChanged) - - - def test_detectFilesRemoved(self): - """ - Check that when a dropin file is removed, L{plugin.getPlugins} doesn't - return it anymore. - """ - FilePath(__file__).sibling('plugin_extra1.py' - ).copyTo(self.package.child('pluginextra.py')) - try: - # Generate a cache with pluginextra in it. - list(plugin.getPlugins(ITestPlugin, self.module)) - - finally: - self._unimportPythonModule( - sys.modules['mypackage.pluginextra'], - True) - plgs = list(plugin.getPlugins(ITestPlugin, self.module)) - self.assertEquals(1, len(plgs)) - - test_detectFilesRemoved = _withCacheness(test_detectFilesRemoved) - - - def test_nonexistentPathEntry(self): - """ - Test that getCache skips over any entries in a plugin package's - C{__path__} which do not exist. - """ - path = self.mktemp() - self.failIf(os.path.exists(path)) - # Add the test directory to the plugins path - self.module.__path__.append(path) - try: - plgs = list(plugin.getPlugins(ITestPlugin, self.module)) - self.assertEqual(len(plgs), 1) - finally: - self.module.__path__.remove(path) - - test_nonexistentPathEntry = _withCacheness(test_nonexistentPathEntry) - - - def test_nonDirectoryChildEntry(self): - """ - Test that getCache skips over any entries in a plugin package's - C{__path__} which refer to children of paths which are not directories. - """ - path = FilePath(self.mktemp()) - self.failIf(path.exists()) - path.touch() - child = path.child("test_package").path - self.module.__path__.append(child) - try: - plgs = list(plugin.getPlugins(ITestPlugin, self.module)) - self.assertEqual(len(plgs), 1) - finally: - self.module.__path__.remove(child) - - test_nonDirectoryChildEntry = _withCacheness(test_nonDirectoryChildEntry) - - - def test_deployedMode(self): - """ - The C{dropin.cache} file may not be writable: the cache should still be - attainable, but an error should be logged to show that the cache - couldn't be updated. - """ - # Generate the cache - plugin.getCache(self.module) - - # Add a new plugin - FilePath(__file__).sibling('plugin_extra1.py' - ).copyTo(self.package.child('pluginextra.py')) - - os.chmod(self.package.path, 0500) - # Change the right of dropin.cache too for windows - os.chmod(self.package.child('dropin.cache').path, 0400) - self.addCleanup(os.chmod, self.package.path, 0700) - self.addCleanup(os.chmod, - self.package.child('dropin.cache').path, 0700) - - cache = plugin.getCache(self.module) - # The new plugin should be reported - self.assertIn('pluginextra', cache) - self.assertIn(self.originalPlugin, cache) - - errors = self.flushLoggedErrors() - self.assertEquals(len(errors), 1) - # Windows report OSError, others IOError - errors[0].trap(OSError, IOError) - - - -# This is something like the Twisted plugins file. -pluginInitFile = """ -from twisted.plugin import pluginPackagePaths -__path__.extend(pluginPackagePaths(__name__)) -__all__ = [] -""" - -def pluginFileContents(name): - return ( - "from zope.interface import classProvides\n" - "from twisted.plugin import IPlugin\n" - "from twisted.test.test_plugin import ITestPlugin\n" - "\n" - "class %s(object):\n" - " classProvides(IPlugin, ITestPlugin)\n") % (name,) - - -def _createPluginDummy(entrypath, pluginContent, real, pluginModule): - """ - Create a plugindummy package. - """ - entrypath.createDirectory() - pkg = entrypath.child('plugindummy') - pkg.createDirectory() - if real: - pkg.child('__init__.py').setContent('') - plugs = pkg.child('plugins') - plugs.createDirectory() - if real: - plugs.child('__init__.py').setContent(pluginInitFile) - plugs.child(pluginModule + '.py').setContent(pluginContent) - return plugs - - - -class DeveloperSetupTests(unittest.TestCase): - """ - These tests verify things about the plugin system without actually - interacting with the deployed 'twisted.plugins' package, instead creating a - temporary package. - """ - - def setUp(self): - """ - Create a complex environment with multiple entries on sys.path, akin to - a developer's environment who has a development (trunk) checkout of - Twisted, a system installed version of Twisted (for their operating - system's tools) and a project which provides Twisted plugins. - """ - self.savedPath = sys.path[:] - self.savedModules = sys.modules.copy() - self.fakeRoot = FilePath(self.mktemp()) - self.fakeRoot.createDirectory() - self.systemPath = self.fakeRoot.child('system_path') - self.devPath = self.fakeRoot.child('development_path') - self.appPath = self.fakeRoot.child('application_path') - self.systemPackage = _createPluginDummy( - self.systemPath, pluginFileContents('system'), - True, 'plugindummy_builtin') - self.devPackage = _createPluginDummy( - self.devPath, pluginFileContents('dev'), - True, 'plugindummy_builtin') - self.appPackage = _createPluginDummy( - self.appPath, pluginFileContents('app'), - False, 'plugindummy_app') - - # Now we're going to do the system installation. - sys.path.extend([x.path for x in [self.systemPath, - self.appPath]]) - # Run all the way through the plugins list to cause the - # L{plugin.getPlugins} generator to write cache files for the system - # installation. - self.getAllPlugins() - self.sysplug = self.systemPath.child('plugindummy').child('plugins') - self.syscache = self.sysplug.child('dropin.cache') - # Make sure there's a nice big difference in modification times so that - # we won't re-build the system cache. - now = time.time() - os.utime( - self.sysplug.child('plugindummy_builtin.py').path, - (now - 5000,) * 2) - os.utime(self.syscache.path, (now - 2000,) * 2) - # For extra realism, let's make sure that the system path is no longer - # writable. - self.lockSystem() - self.resetEnvironment() - - - def lockSystem(self): - """ - Lock the system directories, as if they were unwritable by this user. - """ - os.chmod(self.sysplug.path, 0555) - os.chmod(self.syscache.path, 0555) - - - def unlockSystem(self): - """ - Unlock the system directories, as if they were writable by this user. - """ - os.chmod(self.sysplug.path, 0777) - os.chmod(self.syscache.path, 0777) - - - def getAllPlugins(self): - """ - Get all the plugins loadable from our dummy package, and return their - short names. - """ - # Import the module we just added to our path. (Local scope because - # this package doesn't exist outside of this test.) - import plugindummy.plugins - x = list(plugin.getPlugins(ITestPlugin, plugindummy.plugins)) - return [plug.__name__ for plug in x] - - - def resetEnvironment(self): - """ - Change the environment to what it should be just as the test is - starting. - """ - self.unsetEnvironment() - sys.path.extend([x.path for x in [self.devPath, - self.systemPath, - self.appPath]]) - - def unsetEnvironment(self): - """ - Change the Python environment back to what it was before the test was - started. - """ - sys.modules.clear() - sys.modules.update(self.savedModules) - sys.path[:] = self.savedPath - - - def tearDown(self): - """ - Reset the Python environment to what it was before this test ran, and - restore permissions on files which were marked read-only so that the - directory may be cleanly cleaned up. - """ - self.unsetEnvironment() - # Normally we wouldn't "clean up" the filesystem like this (leaving - # things for post-test inspection), but if we left the permissions the - # way they were, we'd be leaving files around that the buildbots - # couldn't delete, and that would be bad. - self.unlockSystem() - - - def test_developmentPluginAvailability(self): - """ - Plugins added in the development path should be loadable, even when - the (now non-importable) system path contains its own idea of the - list of plugins for a package. Inversely, plugins added in the - system path should not be available. - """ - # Run 3 times: uncached, cached, and then cached again to make sure we - # didn't overwrite / corrupt the cache on the cached try. - for x in range(3): - names = self.getAllPlugins() - names.sort() - self.assertEqual(names, ['app', 'dev']) - - - def test_freshPyReplacesStalePyc(self): - """ - Verify that if a stale .pyc file on the PYTHONPATH is replaced by a - fresh .py file, the plugins in the new .py are picked up rather than - the stale .pyc, even if the .pyc is still around. - """ - mypath = self.appPackage.child("stale.py") - mypath.setContent(pluginFileContents('one')) - # Make it super stale - x = time.time() - 1000 - os.utime(mypath.path, (x, x)) - pyc = mypath.sibling('stale.pyc') - # compile it - compileall.compile_dir(self.appPackage.path, quiet=1) - os.utime(pyc.path, (x, x)) - # Eliminate the other option. - mypath.remove() - # Make sure it's the .pyc path getting cached. - self.resetEnvironment() - # Sanity check. - self.assertIn('one', self.getAllPlugins()) - self.failIfIn('two', self.getAllPlugins()) - self.resetEnvironment() - mypath.setContent(pluginFileContents('two')) - self.failIfIn('one', self.getAllPlugins()) - self.assertIn('two', self.getAllPlugins()) - - - def test_newPluginsOnReadOnlyPath(self): - """ - Verify that a failure to write the dropin.cache file on a read-only - path will not affect the list of plugins returned. - - Note: this test should pass on both Linux and Windows, but may not - provide useful coverage on Windows due to the different meaning of - "read-only directory". - """ - self.unlockSystem() - self.sysplug.child('newstuff.py').setContent(pluginFileContents('one')) - self.lockSystem() - - # Take the developer path out, so that the system plugins are actually - # examined. - sys.path.remove(self.devPath.path) - - # Sanity check to make sure we're only flushing the error logged - # below... - self.assertEqual(len(self.flushLoggedErrors()), 0) - self.assertIn('one', self.getAllPlugins()) - self.assertEqual(len(self.flushLoggedErrors()), 1) - - - -class AdjacentPackageTests(unittest.TestCase): - """ - Tests for the behavior of the plugin system when there are multiple - installed copies of the package containing the plugins being loaded. - """ - - def setUp(self): - """ - Save the elements of C{sys.path} and the items of C{sys.modules}. - """ - self.originalPath = sys.path[:] - self.savedModules = sys.modules.copy() - - - def tearDown(self): - """ - Restore C{sys.path} and C{sys.modules} to their original values. - """ - sys.path[:] = self.originalPath - sys.modules.clear() - sys.modules.update(self.savedModules) - - - def createDummyPackage(self, root, name, pluginName): - """ - Create a directory containing a Python package named I{dummy} with a - I{plugins} subpackage. - - @type root: L{FilePath} - @param root: The directory in which to create the hierarchy. - - @type name: C{str} - @param name: The name of the directory to create which will contain - the package. - - @type pluginName: C{str} - @param pluginName: The name of a module to create in the - I{dummy.plugins} package. - - @rtype: L{FilePath} - @return: The directory which was created to contain the I{dummy} - package. - """ - directory = root.child(name) - package = directory.child('dummy') - package.makedirs() - package.child('__init__.py').setContent('') - plugins = package.child('plugins') - plugins.makedirs() - plugins.child('__init__.py').setContent(pluginInitFile) - pluginModule = plugins.child(pluginName + '.py') - pluginModule.setContent(pluginFileContents(name)) - return directory - - - def test_hiddenPackageSamePluginModuleNameObscured(self): - """ - Only plugins from the first package in sys.path should be returned by - getPlugins in the case where there are two Python packages by the same - name installed, each with a plugin module by a single name. - """ - root = FilePath(self.mktemp()) - root.makedirs() - - firstDirectory = self.createDummyPackage(root, 'first', 'someplugin') - secondDirectory = self.createDummyPackage(root, 'second', 'someplugin') - - sys.path.append(firstDirectory.path) - sys.path.append(secondDirectory.path) - - import dummy.plugins - - plugins = list(plugin.getPlugins(ITestPlugin, dummy.plugins)) - self.assertEqual(['first'], [p.__name__ for p in plugins]) - - - def test_hiddenPackageDifferentPluginModuleNameObscured(self): - """ - Plugins from the first package in sys.path should be returned by - getPlugins in the case where there are two Python packages by the same - name installed, each with a plugin module by a different name. - """ - root = FilePath(self.mktemp()) - root.makedirs() - - firstDirectory = self.createDummyPackage(root, 'first', 'thisplugin') - secondDirectory = self.createDummyPackage(root, 'second', 'thatplugin') - - sys.path.append(firstDirectory.path) - sys.path.append(secondDirectory.path) - - import dummy.plugins - - plugins = list(plugin.getPlugins(ITestPlugin, dummy.plugins)) - self.assertEqual(['first'], [p.__name__ for p in plugins]) - - - -class PackagePathTests(unittest.TestCase): - """ - Tests for L{plugin.pluginPackagePaths} which constructs search paths for - plugin packages. - """ - - def setUp(self): - """ - Save the elements of C{sys.path}. - """ - self.originalPath = sys.path[:] - - - def tearDown(self): - """ - Restore C{sys.path} to its original value. - """ - sys.path[:] = self.originalPath - - - def test_pluginDirectories(self): - """ - L{plugin.pluginPackagePaths} should return a list containing each - directory in C{sys.path} with a suffix based on the supplied package - name. - """ - foo = FilePath('foo') - bar = FilePath('bar') - sys.path = [foo.path, bar.path] - self.assertEqual( - plugin.pluginPackagePaths('dummy.plugins'), - [foo.child('dummy').child('plugins').path, - bar.child('dummy').child('plugins').path]) - - - def test_pluginPackagesExcluded(self): - """ - L{plugin.pluginPackagePaths} should exclude directories which are - Python packages. The only allowed plugin package (the only one - associated with a I{dummy} package which Python will allow to be - imported) will already be known to the caller of - L{plugin.pluginPackagePaths} and will most commonly already be in - the C{__path__} they are about to mutate. - """ - root = FilePath(self.mktemp()) - foo = root.child('foo').child('dummy').child('plugins') - foo.makedirs() - foo.child('__init__.py').setContent('') - sys.path = [root.child('foo').path, root.child('bar').path] - self.assertEqual( - plugin.pluginPackagePaths('dummy.plugins'), - [root.child('bar').child('dummy').child('plugins').path]) diff --git a/tools/buildbot/pylibs/twisted/test/test_policies.py b/tools/buildbot/pylibs/twisted/test/test_policies.py deleted file mode 100644 index 16f37e5..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_policies.py +++ /dev/null @@ -1,682 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test code for policies. -""" - -from StringIO import StringIO - -from twisted.trial import unittest -from twisted.test.proto_helpers import StringTransportWithDisconnection - -from twisted.internet import protocol, reactor, address, defer, task -from twisted.protocols import policies - - - -class StringIOWithoutClosing(StringIO): - def close(self): pass - - - -class SimpleProtocol(protocol.Protocol): - - connected = disconnected = 0 - buffer = "" - - def __init__(self): - self.dConnected = defer.Deferred() - self.dDisconnected = defer.Deferred() - - def connectionMade(self): - self.connected = 1 - self.dConnected.callback('') - - def connectionLost(self, reason): - self.disconnected = 1 - self.dDisconnected.callback('') - - def dataReceived(self, data): - self.buffer += data - - - -class SillyFactory(protocol.ClientFactory): - - def __init__(self, p): - self.p = p - - def buildProtocol(self, addr): - return self.p - - -class EchoProtocol(protocol.Protocol): - paused = False - - def pauseProducing(self): - self.paused = True - - def resumeProducing(self): - self.paused = False - - def stopProducing(self): - pass - - def dataReceived(self, data): - self.transport.write(data) - - - -class Server(protocol.ServerFactory): - """ - A simple server factory using L{EchoProtocol}. - """ - protocol = EchoProtocol - - - -class TestableThrottlingFactory(policies.ThrottlingFactory): - """ - L{policies.ThrottlingFactory} using a L{task.Clock} for tests. - """ - - def __init__(self, clock, *args, **kwargs): - """ - @param clock: object providing a callLater method that can be used - for tests. - @type clock: C{task.Clock} or alike. - """ - policies.ThrottlingFactory.__init__(self, *args, **kwargs) - self.clock = clock - - - def callLater(self, period, func): - """ - Forward to the testable clock. - """ - return self.clock.callLater(period, func) - - - -class TestableTimeoutFactory(policies.TimeoutFactory): - """ - L{policies.TimeoutFactory} using a L{task.Clock} for tests. - """ - - def __init__(self, clock, *args, **kwargs): - """ - @param clock: object providing a callLater method that can be used - for tests. - @type clock: C{task.Clock} or alike. - """ - policies.TimeoutFactory.__init__(self, *args, **kwargs) - self.clock = clock - - - def callLater(self, period, func): - """ - Forward to the testable clock. - """ - return self.clock.callLater(period, func) - - - -class PausableStringTransport(StringTransportWithDisconnection): - """ - A string transport saving the current production state. - - @ivar paused: whether the production is paused or not. - @type paused: C{bool} - """ - paused = False - - def pauseProducing(self): - """ - Notification of production pause: set C{self.paused}. - """ - self.paused = True - - - def resumeProducing(self): - """ - Notification of production restart: unset C{self.paused}. - """ - self.paused = False - - - -class WrapperTestCase(unittest.TestCase): - def testProtocolFactoryAttribute(self): - """ - Make sure protocol.factory is the wrapped factory, not the wrapping - factory. - """ - f = Server() - wf = policies.WrappingFactory(f) - p = wf.buildProtocol(address.IPv4Address('TCP', '127.0.0.1', 35)) - self.assertIdentical(p.wrappedProtocol.factory, f) - - - -class WrappingFactory(policies.WrappingFactory): - protocol = lambda s, f, p: p - - def startFactory(self): - policies.WrappingFactory.startFactory(self) - self.deferred.callback(None) - - - -class ThrottlingTestCase(unittest.TestCase): - """ - Tests for L{policies.ThrottlingFactory}. - """ - - def test_limit(self): - """ - Full test using a custom server limiting number of connections. - """ - server = Server() - c1, c2, c3, c4 = [SimpleProtocol() for i in range(4)] - tServer = policies.ThrottlingFactory(server, 2) - wrapTServer = WrappingFactory(tServer) - wrapTServer.deferred = defer.Deferred() - - # Start listening - p = reactor.listenTCP(0, wrapTServer, interface="127.0.0.1") - n = p.getHost().port - - def _connect123(results): - reactor.connectTCP("127.0.0.1", n, SillyFactory(c1)) - c1.dConnected.addCallback( - lambda r: reactor.connectTCP("127.0.0.1", n, SillyFactory(c2))) - c2.dConnected.addCallback( - lambda r: reactor.connectTCP("127.0.0.1", n, SillyFactory(c3))) - return c3.dDisconnected - - def _check123(results): - self.assertEquals([c.connected for c in c1, c2, c3], [1, 1, 1]) - self.assertEquals([c.disconnected for c in c1, c2, c3], [0, 0, 1]) - self.assertEquals(len(tServer.protocols.keys()), 2) - return results - - def _lose1(results): - # disconnect one protocol and now another should be able to connect - c1.transport.loseConnection() - return c1.dDisconnected - - def _connect4(results): - reactor.connectTCP("127.0.0.1", n, SillyFactory(c4)) - return c4.dConnected - - def _check4(results): - self.assertEquals(c4.connected, 1) - self.assertEquals(c4.disconnected, 0) - return results - - def _cleanup(results): - for c in c2, c4: - c.transport.loseConnection() - return defer.DeferredList([ - defer.maybeDeferred(p.stopListening), - c2.dDisconnected, - c4.dDisconnected]) - - wrapTServer.deferred.addCallback(_connect123) - wrapTServer.deferred.addCallback(_check123) - wrapTServer.deferred.addCallback(_lose1) - wrapTServer.deferred.addCallback(_connect4) - wrapTServer.deferred.addCallback(_check4) - wrapTServer.deferred.addCallback(_cleanup) - return wrapTServer.deferred - - - def test_writeLimit(self): - """ - Check the writeLimit parameter: write data, and check for the pause - status. - """ - server = Server() - tServer = TestableThrottlingFactory(task.Clock(), server, writeLimit=10) - port = tServer.buildProtocol(address.IPv4Address('TCP', '127.0.0.1', 0)) - tr = PausableStringTransport() - tr.protocol = port - port.makeConnection(tr) - port.producer = port.wrappedProtocol - - port.dataReceived("0123456789") - port.dataReceived("abcdefghij") - self.assertEquals(tr.value(), "0123456789abcdefghij") - self.assertEquals(tServer.writtenThisSecond, 20) - self.assertFalse(port.wrappedProtocol.paused) - - # at this point server should've written 20 bytes, 10 bytes - # above the limit so writing should be paused around 1 second - # from 'now', and resumed a second after that - tServer.clock.advance(1.05) - self.assertEquals(tServer.writtenThisSecond, 0) - self.assertTrue(port.wrappedProtocol.paused) - - tServer.clock.advance(1.05) - self.assertEquals(tServer.writtenThisSecond, 0) - self.assertFalse(port.wrappedProtocol.paused) - - - def test_readLimit(self): - """ - Check the readLimit parameter: read data and check for the pause - status. - """ - server = Server() - tServer = TestableThrottlingFactory(task.Clock(), server, readLimit=10) - port = tServer.buildProtocol(address.IPv4Address('TCP', '127.0.0.1', 0)) - tr = PausableStringTransport() - tr.protocol = port - port.makeConnection(tr) - - port.dataReceived("0123456789") - port.dataReceived("abcdefghij") - self.assertEquals(tr.value(), "0123456789abcdefghij") - self.assertEquals(tServer.readThisSecond, 20) - - tServer.clock.advance(1.05) - self.assertEquals(tServer.readThisSecond, 0) - self.assertTrue(tr.paused) - - tServer.clock.advance(1.05) - self.assertEquals(tServer.readThisSecond, 0) - self.assertFalse(tr.paused) - - tr.clear() - port.dataReceived("0123456789") - port.dataReceived("abcdefghij") - self.assertEquals(tr.value(), "0123456789abcdefghij") - self.assertEquals(tServer.readThisSecond, 20) - - tServer.clock.advance(1.05) - self.assertEquals(tServer.readThisSecond, 0) - self.assertTrue(tr.paused) - - tServer.clock.advance(1.05) - self.assertEquals(tServer.readThisSecond, 0) - self.assertFalse(tr.paused) - - - -class TimeoutTestCase(unittest.TestCase): - """ - Tests for L{policies.TimeoutFactory}. - """ - - def setUp(self): - """ - Create a testable, deterministic clock, and a set of - server factory/protocol/transport. - """ - self.clock = task.Clock() - wrappedFactory = protocol.ServerFactory() - wrappedFactory.protocol = SimpleProtocol - self.factory = TestableTimeoutFactory(self.clock, wrappedFactory, 3) - self.proto = self.factory.buildProtocol( - address.IPv4Address('TCP', '127.0.0.1', 12345)) - self.transport = StringTransportWithDisconnection() - self.transport.protocol = self.proto - self.proto.makeConnection(self.transport) - - - def test_timeout(self): - """ - Make sure that when a TimeoutFactory accepts a connection, it will - time out that connection if no data is read or written within the - timeout period. - """ - # Let almost 3 time units pass - self.clock.pump([0.0, 0.5, 1.0, 1.0, 0.4]) - self.failIf(self.proto.wrappedProtocol.disconnected) - - # Now let the timer elapse - self.clock.pump([0.0, 0.2]) - self.failUnless(self.proto.wrappedProtocol.disconnected) - - - def test_sendAvoidsTimeout(self): - """ - Make sure that writing data to a transport from a protocol - constructed by a TimeoutFactory resets the timeout countdown. - """ - # Let half the countdown period elapse - self.clock.pump([0.0, 0.5, 1.0]) - self.failIf(self.proto.wrappedProtocol.disconnected) - - # Send some data (self.proto is the /real/ proto's transport, so this - # is the write that gets called) - self.proto.write('bytes bytes bytes') - - # More time passes, putting us past the original timeout - self.clock.pump([0.0, 1.0, 1.0]) - self.failIf(self.proto.wrappedProtocol.disconnected) - - # Make sure writeSequence delays timeout as well - self.proto.writeSequence(['bytes'] * 3) - - # Tick tock - self.clock.pump([0.0, 1.0, 1.0]) - self.failIf(self.proto.wrappedProtocol.disconnected) - - # Don't write anything more, just let the timeout expire - self.clock.pump([0.0, 2.0]) - self.failUnless(self.proto.wrappedProtocol.disconnected) - - - def test_receiveAvoidsTimeout(self): - """ - Make sure that receiving data also resets the timeout countdown. - """ - # Let half the countdown period elapse - self.clock.pump([0.0, 1.0, 0.5]) - self.failIf(self.proto.wrappedProtocol.disconnected) - - # Some bytes arrive, they should reset the counter - self.proto.dataReceived('bytes bytes bytes') - - # We pass the original timeout - self.clock.pump([0.0, 1.0, 1.0]) - self.failIf(self.proto.wrappedProtocol.disconnected) - - # Nothing more arrives though, the new timeout deadline is passed, - # the connection should be dropped. - self.clock.pump([0.0, 1.0, 1.0]) - self.failUnless(self.proto.wrappedProtocol.disconnected) - - - -class TimeoutTester(protocol.Protocol, policies.TimeoutMixin): - """ - A testable protocol with timeout facility. - - @ivar timedOut: set to C{True} if a timeout has been detected. - @type timedOut: C{bool} - """ - timeOut = 3 - timedOut = False - - def __init__(self, clock): - """ - Initialize the protocol with a C{task.Clock} object. - """ - self.clock = clock - - - def connectionMade(self): - """ - Upon connection, set the timeout. - """ - self.setTimeout(self.timeOut) - - - def dataReceived(self, data): - """ - Reset the timeout on data. - """ - self.resetTimeout() - protocol.Protocol.dataReceived(self, data) - - - def connectionLost(self, reason=None): - """ - On connection lost, cancel all timeout operations. - """ - self.setTimeout(None) - - - def timeoutConnection(self): - """ - Flags the timedOut variable to indicate the timeout of the connection. - """ - self.timedOut = True - - - def callLater(self, timeout, func, *args, **kwargs): - """ - Override callLater to use the deterministic clock. - """ - return self.clock.callLater(timeout, func, *args, **kwargs) - - - -class TestTimeout(unittest.TestCase): - """ - Tests for L{policies.TimeoutMixin}. - """ - - def setUp(self): - """ - Create a testable, deterministic clock and a C{TimeoutTester} instance. - """ - self.clock = task.Clock() - self.proto = TimeoutTester(self.clock) - - - def test_overriddenCallLater(self): - """ - Test that the callLater of the clock is used instead of - C{reactor.callLater}. - """ - self.proto.setTimeout(10) - self.assertEquals(len(self.clock.calls), 1) - - - def test_timeout(self): - """ - Check that the protocol does timeout at the time specified by its - C{timeOut} attribute. - """ - s = StringIOWithoutClosing() - self.proto.makeConnection(protocol.FileWrapper(s)) - - # timeOut value is 3 - self.clock.pump([0, 0.5, 1.0, 1.0]) - self.failIf(self.proto.timedOut) - self.clock.pump([0, 1.0]) - self.failUnless(self.proto.timedOut) - - - def test_noTimeout(self): - """ - Check that receiving data is delaying the timeout of the connection. - """ - s = StringIOWithoutClosing() - self.proto.makeConnection(protocol.FileWrapper(s)) - - self.clock.pump([0, 0.5, 1.0, 1.0]) - self.failIf(self.proto.timedOut) - self.proto.dataReceived('hello there') - self.clock.pump([0, 1.0, 1.0, 0.5]) - self.failIf(self.proto.timedOut) - self.clock.pump([0, 1.0]) - self.failUnless(self.proto.timedOut) - - - def test_resetTimeout(self): - """ - Check that setting a new value for timeout cancel the previous value - and install a new timeout. - """ - self.proto.timeOut = None - s = StringIOWithoutClosing() - self.proto.makeConnection(protocol.FileWrapper(s)) - - self.proto.setTimeout(1) - self.assertEquals(self.proto.timeOut, 1) - - self.clock.pump([0, 0.9]) - self.failIf(self.proto.timedOut) - self.clock.pump([0, 0.2]) - self.failUnless(self.proto.timedOut) - - - def test_cancelTimeout(self): - """ - Setting the timeout to C{None} cancel any timeout operations. - """ - self.proto.timeOut = 5 - s = StringIOWithoutClosing() - self.proto.makeConnection(protocol.FileWrapper(s)) - - self.proto.setTimeout(None) - self.assertEquals(self.proto.timeOut, None) - - self.clock.pump([0, 5, 5, 5]) - self.failIf(self.proto.timedOut) - - - def test_return(self): - """ - setTimeout should return the value of the previous timeout. - """ - self.proto.timeOut = 5 - - self.assertEquals(self.proto.setTimeout(10), 5) - self.assertEquals(self.proto.setTimeout(None), 10) - self.assertEquals(self.proto.setTimeout(1), None) - self.assertEquals(self.proto.timeOut, 1) - - # Clean up the DelayedCall - self.proto.setTimeout(None) - - - -class LimitTotalConnectionsFactoryTestCase(unittest.TestCase): - """Tests for policies.LimitTotalConnectionsFactory""" - def testConnectionCounting(self): - # Make a basic factory - factory = policies.LimitTotalConnectionsFactory() - factory.protocol = protocol.Protocol - - # connectionCount starts at zero - self.assertEqual(0, factory.connectionCount) - - # connectionCount increments as connections are made - p1 = factory.buildProtocol(None) - self.assertEqual(1, factory.connectionCount) - p2 = factory.buildProtocol(None) - self.assertEqual(2, factory.connectionCount) - - # and decrements as they are lost - p1.connectionLost(None) - self.assertEqual(1, factory.connectionCount) - p2.connectionLost(None) - self.assertEqual(0, factory.connectionCount) - - def testConnectionLimiting(self): - # Make a basic factory with a connection limit of 1 - factory = policies.LimitTotalConnectionsFactory() - factory.protocol = protocol.Protocol - factory.connectionLimit = 1 - - # Make a connection - p = factory.buildProtocol(None) - self.assertNotEqual(None, p) - self.assertEqual(1, factory.connectionCount) - - # Try to make a second connection, which will exceed the connection - # limit. This should return None, because overflowProtocol is None. - self.assertEqual(None, factory.buildProtocol(None)) - self.assertEqual(1, factory.connectionCount) - - # Define an overflow protocol - class OverflowProtocol(protocol.Protocol): - def connectionMade(self): - factory.overflowed = True - factory.overflowProtocol = OverflowProtocol - factory.overflowed = False - - # Try to make a second connection again, now that we have an overflow - # protocol. Note that overflow connections count towards the connection - # count. - op = factory.buildProtocol(None) - op.makeConnection(None) # to trigger connectionMade - self.assertEqual(True, factory.overflowed) - self.assertEqual(2, factory.connectionCount) - - # Close the connections. - p.connectionLost(None) - self.assertEqual(1, factory.connectionCount) - op.connectionLost(None) - self.assertEqual(0, factory.connectionCount) - - -class WriteSequenceEchoProtocol(EchoProtocol): - def dataReceived(self, bytes): - if bytes.find('vector!') != -1: - self.transport.writeSequence([bytes]) - else: - EchoProtocol.dataReceived(self, bytes) - -class TestLoggingFactory(policies.TrafficLoggingFactory): - openFile = None - def open(self, name): - assert self.openFile is None, "open() called too many times" - self.openFile = StringIO() - return self.openFile - - - -class LoggingFactoryTestCase(unittest.TestCase): - """ - Tests for L{policies.TrafficLoggingFactory}. - """ - - def test_thingsGetLogged(self): - """ - Check the output produced by L{policies.TrafficLoggingFactory}. - """ - wrappedFactory = Server() - wrappedFactory.protocol = WriteSequenceEchoProtocol - t = StringTransportWithDisconnection() - f = TestLoggingFactory(wrappedFactory, 'test') - p = f.buildProtocol(('1.2.3.4', 5678)) - t.protocol = p - p.makeConnection(t) - - v = f.openFile.getvalue() - self.failUnless('*' in v, "* not found in %r" % (v,)) - self.failIf(t.value()) - - p.dataReceived('here are some bytes') - - v = f.openFile.getvalue() - self.assertIn("C 1: 'here are some bytes'", v) - self.assertIn("S 1: 'here are some bytes'", v) - self.assertEquals(t.value(), 'here are some bytes') - - t.clear() - p.dataReceived('prepare for vector! to the extreme') - v = f.openFile.getvalue() - self.assertIn("SV 1: ['prepare for vector! to the extreme']", v) - self.assertEquals(t.value(), 'prepare for vector! to the extreme') - - p.loseConnection() - - v = f.openFile.getvalue() - self.assertIn('ConnectionDone', v) - - - def test_counter(self): - """ - Test counter management with the resetCounter method. - """ - wrappedFactory = Server() - f = TestLoggingFactory(wrappedFactory, 'test') - self.assertEqual(f._counter, 0) - f.buildProtocol(('1.2.3.4', 5678)) - self.assertEqual(f._counter, 1) - # Reset log file - f.openFile = None - f.buildProtocol(('1.2.3.4', 5679)) - self.assertEqual(f._counter, 2) - - f.resetCounter() - self.assertEqual(f._counter, 0) - diff --git a/tools/buildbot/pylibs/twisted/test/test_postfix.py b/tools/buildbot/pylibs/twisted/test/test_postfix.py deleted file mode 100644 index 69307e0..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_postfix.py +++ /dev/null @@ -1,104 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -""" -Test cases for twisted.protocols.postfix module. -""" - -from twisted.trial import unittest -from twisted import protocols -from twisted import internet -from twisted.protocols import loopback -from twisted.protocols import postfix -from twisted.internet import defer, protocol -from twisted.test.test_protocols import StringIOWithoutClosing - -class PostfixTCPMapQuoteTestCase(unittest.TestCase): - data = [ - # (raw, quoted, [aliasQuotedForms]), - ('foo', 'foo'), - ('foo bar', 'foo%20bar'), - ('foo\tbar', 'foo%09bar'), - ('foo\nbar', 'foo%0Abar', 'foo%0abar'), - ('foo\r\nbar', 'foo%0D%0Abar', 'foo%0D%0abar', 'foo%0d%0Abar', 'foo%0d%0abar'), - ('foo ', 'foo%20'), - (' foo', '%20foo'), - ] - - def testData(self): - for entry in self.data: - raw = entry[0] - quoted = entry[1:] - - self.assertEquals(postfix.quote(raw), quoted[0]) - for q in quoted: - self.assertEquals(postfix.unquote(q), raw) - -class PostfixTCPMapServerTestCase: - data = { - # 'key': 'value', - } - - chat = [ - # (input, expected_output), - ] - - def testChat(self): - factory = postfix.PostfixTCPMapDictServerFactory(self.data) - output = StringIOWithoutClosing() - transport = internet.protocol.FileWrapper(output) - - protocol = postfix.PostfixTCPMapServer() - protocol.service = factory - protocol.factory = factory - protocol.makeConnection(transport) - - for input, expected_output in self.chat: - protocol.lineReceived(input) - # self.runReactor(1) - self.assertEquals(output.getvalue(), expected_output, - 'For %r, expected %r but got %r' % ( - input, expected_output, output.getvalue() - )) - output.truncate(0) - protocol.setTimeout(None) - - def testDeferredChat(self): - factory = postfix.PostfixTCPMapDeferringDictServerFactory(self.data) - output = StringIOWithoutClosing() - transport = internet.protocol.FileWrapper(output) - - protocol = postfix.PostfixTCPMapServer() - protocol.service = factory - protocol.factory = factory - protocol.makeConnection(transport) - - for input, expected_output in self.chat: - protocol.lineReceived(input) - # self.runReactor(1) - self.assertEquals(output.getvalue(), expected_output, - 'For %r, expected %r but got %r' % ( - input, expected_output, output.getvalue() - )) - output.truncate(0) - protocol.setTimeout(None) - -class Valid(PostfixTCPMapServerTestCase, unittest.TestCase): - data = { - 'foo': 'ThisIs Foo', - 'bar': ' bar really is found\r\n', - } - chat = [ - ('get', "400 Command 'get' takes 1 parameters.\n"), - ('get foo bar', "500 \n"), - ('put', "400 Command 'put' takes 2 parameters.\n"), - ('put foo', "400 Command 'put' takes 2 parameters.\n"), - ('put foo bar baz', "500 put is not implemented yet.\n"), - ('put foo bar', '500 put is not implemented yet.\n'), - ('get foo', '200 ThisIs%20Foo\n'), - ('get bar', '200 %20bar%20really%20is%20found%0D%0A\n'), - ('get baz', '500 \n'), - ('foo', '400 unknown command\n'), - ] diff --git a/tools/buildbot/pylibs/twisted/test/test_process.py b/tools/buildbot/pylibs/twisted/test/test_process.py deleted file mode 100644 index 9bf0500..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_process.py +++ /dev/null @@ -1,2237 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test running processes. -""" - -import gzip -import os -import popen2 -import sys -import signal -import StringIO -import errno -import gc -import warnings -import socket -try: - import fcntl -except ImportError: - fcntl = None - -from zope.interface.verify import verifyObject - -from twisted.internet import reactor, protocol, error, interfaces, defer -from twisted.internet import selectreactor -from twisted.trial import unittest -from twisted.python import util, runtime, procutils - -try: - from twisted.internet import process -except ImportError: - process = None - - - -class StubProcessProtocol(protocol.ProcessProtocol): - """ - ProcessProtocol counter-implementation: all methods on this class raise an - exception, so instances of this may be used to verify that only certain - methods are called. - """ - def outReceived(self, data): - raise NotImplementedError() - - def errReceived(self, data): - raise NotImplementedError() - - def inConnectionLost(self): - raise NotImplementedError() - - def outConnectionLost(self): - raise NotImplementedError() - - def errConnectionLost(self): - raise NotImplementedError() - - - -class ProcessProtocolTests(unittest.TestCase): - """ - Tests for behavior provided by the process protocol base class, - L{protocol.ProcessProtocol}. - """ - def test_interface(self): - """ - L{ProcessProtocol} implements L{IProcessProtocol}. - """ - verifyObject(interfaces.IProcessProtocol, protocol.ProcessProtocol()) - - - def test_outReceived(self): - """ - Verify that when stdout is delivered to - L{ProcessProtocol.childDataReceived}, it is forwarded to - L{ProcessProtocol.outReceived}. - """ - received = [] - class OutProtocol(StubProcessProtocol): - def outReceived(self, data): - received.append(data) - - bytes = "bytes" - p = OutProtocol() - p.childDataReceived(1, bytes) - self.assertEqual(received, [bytes]) - - - def test_errReceived(self): - """ - Similar to L{test_outReceived}, but for stderr. - """ - received = [] - class ErrProtocol(StubProcessProtocol): - def errReceived(self, data): - received.append(data) - - bytes = "bytes" - p = ErrProtocol() - p.childDataReceived(2, bytes) - self.assertEqual(received, [bytes]) - - - def test_inConnectionLost(self): - """ - Verify that when stdin close notification is delivered to - L{ProcessProtocol.childConnectionLost}, it is forwarded to - L{ProcessProtocol.inConnectionLost}. - """ - lost = [] - class InLostProtocol(StubProcessProtocol): - def inConnectionLost(self): - lost.append(None) - - p = InLostProtocol() - p.childConnectionLost(0) - self.assertEqual(lost, [None]) - - - def test_outConnectionLost(self): - """ - Similar to L{test_inConnectionLost}, but for stdout. - """ - lost = [] - class OutLostProtocol(StubProcessProtocol): - def outConnectionLost(self): - lost.append(None) - - p = OutLostProtocol() - p.childConnectionLost(1) - self.assertEqual(lost, [None]) - - - def test_errConnectionLost(self): - """ - Similar to L{test_inConnectionLost}, but for stderr. - """ - lost = [] - class ErrLostProtocol(StubProcessProtocol): - def errConnectionLost(self): - lost.append(None) - - p = ErrLostProtocol() - p.childConnectionLost(2) - self.assertEqual(lost, [None]) - - - -class TrivialProcessProtocol(protocol.ProcessProtocol): - """ - Simple process protocol for tests purpose. - - @ivar outData: data received from stdin - @ivar errData: data received from stderr - """ - - def __init__(self, d): - """ - Create the deferred that will be fired at the end, and initialize - data structures. - """ - self.deferred = d - self.outData = [] - self.errData = [] - - def processEnded(self, reason): - self.reason = reason - self.deferred.callback(None) - - def outReceived(self, data): - self.outData.append(data) - - def errReceived(self, data): - self.errData.append(data) - - -class TestProcessProtocol(protocol.ProcessProtocol): - - def connectionMade(self): - self.stages = [1] - self.data = '' - self.err = '' - self.transport.write("abcd") - - def childDataReceived(self, childFD, data): - """ - Override and disable the dispatch provided by the base class to ensure - that it is really this method which is being called, and the transport - is not going directly to L{outReceived} or L{errReceived}. - """ - if childFD == 1: - self.data += data - elif childFD == 2: - self.err += data - - - def childConnectionLost(self, childFD): - """ - Similarly to L{childDataReceived}, disable the automatic dispatch - provided by the base implementation to verify that the transport is - calling this method directly. - """ - if childFD == 1: - self.stages.append(2) - if self.data != "abcd": - raise RuntimeError - self.transport.write("1234") - elif childFD == 2: - self.stages.append(3) - if self.err != "1234": - print 'err != 1234: ' + repr(self.err) - raise RuntimeError() - self.transport.write("abcd") - self.stages.append(4) - elif childFD == 0: - self.stages.append(5) - - def processEnded(self, reason): - self.reason = reason - self.deferred.callback(None) - - -class EchoProtocol(protocol.ProcessProtocol): - - s = "1234567" * 1001 - n = 10 - finished = 0 - - failure = None - - def __init__(self, onEnded): - self.onEnded = onEnded - self.count = 0 - - def connectionMade(self): - assert self.n > 2 - for i in range(self.n - 2): - self.transport.write(self.s) - # test writeSequence - self.transport.writeSequence([self.s, self.s]) - self.buffer = self.s * self.n - - def outReceived(self, data): - if buffer(self.buffer, self.count, len(data)) != buffer(data): - self.failure = ("wrong bytes received", data, self.count) - self.transport.closeStdin() - else: - self.count += len(data) - if self.count == len(self.buffer): - self.transport.closeStdin() - - def processEnded(self, reason): - self.finished = 1 - if not reason.check(error.ProcessDone): - self.failure = "process didn't terminate normally: " + str(reason) - self.onEnded.callback(self) - - - -class SignalProtocol(protocol.ProcessProtocol): - """ - A process protocol that sends a signal when data is first received. - - @ivar deferred: deferred firing on C{processEnded}. - @type deferred: L{defer.Deferred} - - @ivar signal: the signal to send to the process. - @type signal: C{str} - """ - - def __init__(self, deferred, sig): - self.deferred = deferred - self.signal = sig - - - def outReceived(self, data): - self.transport.signalProcess(self.signal) - - - def processEnded(self, reason): - """ - Callback C{self.deferred} with C{None} if C{reason} is a - L{error.ProcessTerminated} failure with C{exitCode} set to C{None}, - C{signal} set to C{self.signal}, and C{status} holding the status code - of the exited process. Otherwise, errback with a C{ValueError} - describing the problem. - """ - if not reason.check(error.ProcessTerminated): - return self.deferred.errback( - ValueError("wrong termination: %s" % (reason,))) - v = reason.value - signalValue = getattr(signal, 'SIG' + self.signal) - if v.exitCode is not None: - return self.deferred.errback( - ValueError("SIG%s: exitCode is %s, not None" % - (self.signal, v.exitCode))) - if v.signal != signalValue: - return self.deferred.errback( - ValueError("SIG%s: .signal was %s, wanted %s" % - (self.signal, v.signal, signalValue))) - if os.WTERMSIG(v.status) != signalValue: - return self.deferred.errback( - ValueError('SIG%s: %s' % (self.signal, os.WTERMSIG(v.status)))) - self.deferred.callback(None) - - - -class TestManyProcessProtocol(TestProcessProtocol): - def __init__(self): - self.deferred = defer.Deferred() - - def processEnded(self, reason): - self.reason = reason - if reason.check(error.ProcessDone): - self.deferred.callback(None) - else: - self.deferred.errback(reason) - - - -class UtilityProcessProtocol(protocol.ProcessProtocol): - """ - Helper class for launching a Python process and getting a result from it. - - @ivar program: A string giving a Python program for the child process to - run. - """ - program = None - - def run(cls, reactor, argv, env): - """ - Run a Python process connected to a new instance of this protocol - class. Return the protocol instance. - - The Python process is given C{self.program} on the command line to - execute, in addition to anything specified by C{argv}. C{env} is - the complete environment. - """ - exe = sys.executable - self = cls() - reactor.spawnProcess( - self, exe, [exe, "-c", self.program] + argv, env=env) - return self - run = classmethod(run) - - - def __init__(self): - self.bytes = [] - self.requests = [] - - - def parseChunks(self, bytes): - """ - Called with all bytes received on stdout when the process exits. - """ - raise NotImplementedError() - - - def getResult(self): - """ - Return a Deferred which will fire with the result of L{parseChunks} - when the child process exits. - """ - d = defer.Deferred() - self.requests.append(d) - return d - - - def _fireResultDeferreds(self, result): - """ - Callback all Deferreds returned up until now by L{getResult} - with the given result object. - """ - requests = self.requests - self.requests = None - for d in requests: - d.callback(result) - - - def outReceived(self, bytes): - """ - Accumulate output from the child process in a list. - """ - self.bytes.append(bytes) - - - def processEnded(self, reason): - """ - Handle process termination by parsing all received output and firing - any waiting Deferreds. - """ - self._fireResultDeferreds(self.parseChunks(self.bytes)) - - - - -class GetArgumentVector(UtilityProcessProtocol): - """ - Protocol which will read a serialized argv from a process and - expose it to interested parties. - """ - program = ( - "from sys import stdout, argv\n" - "stdout.write(chr(0).join(argv))\n" - "stdout.flush()\n") - - def parseChunks(self, chunks): - """ - Parse the output from the process to which this protocol was - connected, which is a single unterminated line of \\0-separated - strings giving the argv of that process. Return this as a list of - str objects. - """ - return ''.join(chunks).split('\0') - - - -class GetEnvironmentDictionary(UtilityProcessProtocol): - """ - Protocol which will read a serialized environment dict from a process - and expose it to interested parties. - """ - program = ( - "from sys import stdout\n" - "from os import environ\n" - "items = environ.iteritems()\n" - "stdout.write(chr(0).join([k + chr(0) + v for k, v in items]))\n" - "stdout.flush()\n") - - def parseChunks(self, chunks): - """ - Parse the output from the process to which this protocol was - connected, which is a single unterminated line of \\0-separated - strings giving key value pairs of the environment from that process. - Return this as a dictionary. - """ - environString = ''.join(chunks) - if not environString: - return {} - environ = iter(environString.split('\0')) - d = {} - while 1: - try: - k = environ.next() - except StopIteration: - break - else: - v = environ.next() - d[k] = v - return d - - - -class ProcessTestCase(unittest.TestCase): - """Test running a process.""" - - usePTY = False - - def testStdio(self): - """twisted.internet.stdio test.""" - exe = sys.executable - scriptPath = util.sibpath(__file__, "process_twisted.py") - p = Accumulator() - d = p.endedDeferred = defer.Deferred() - env = {"PYTHONPATH": os.pathsep.join(sys.path)} - reactor.spawnProcess(p, exe, [exe, "-u", scriptPath], env=env, - path=None, usePTY=self.usePTY) - p.transport.write("hello, world") - p.transport.write("abc") - p.transport.write("123") - p.transport.closeStdin() - - def processEnded(ign): - self.assertEquals(p.outF.getvalue(), "hello, worldabc123", - "Output follows:\n" - "%s\n" - "Error message from process_twisted follows:\n" - "%s\n" % (p.outF.getvalue(), p.errF.getvalue())) - return d.addCallback(processEnded) - - - def test_unsetPid(self): - """ - Test if pid is None/non-None before/after process termination. This - reuses process_echoer.py to get a process that blocks on stdin. - """ - finished = defer.Deferred() - p = TrivialProcessProtocol(finished) - exe = sys.executable - scriptPath = util.sibpath(__file__, "process_echoer.py") - procTrans = reactor.spawnProcess(p, exe, - [exe, "-u", scriptPath], env=None) - self.failUnless(procTrans.pid) - - def afterProcessEnd(ignored): - self.assertEqual(procTrans.pid, None) - - p.transport.closeStdin() - return finished.addCallback(afterProcessEnd) - - - def test_process(self): - """ - Test running a process: check its output, it exitCode, some property of - signalProcess. - """ - exe = sys.executable - scriptPath = util.sibpath(__file__, "process_tester.py") - d = defer.Deferred() - p = TestProcessProtocol() - p.deferred = d - reactor.spawnProcess(p, exe, [exe, "-u", scriptPath], env=None) - def check(ignored): - self.assertEquals(p.stages, [1, 2, 3, 4, 5]) - f = p.reason - f.trap(error.ProcessTerminated) - self.assertEquals(f.value.exitCode, 23) - # would .signal be available on non-posix? - # self.assertEquals(f.value.signal, None) - self.assertRaises( - error.ProcessExitedAlready, p.transport.signalProcess, 'INT') - try: - import process_tester, glob - for f in glob.glob(process_tester.test_file_match): - os.remove(f) - except: - pass - d.addCallback(check) - return d - - def testManyProcesses(self): - - def _check(results, protocols): - for p in protocols: - self.assertEquals(p.stages, [1, 2, 3, 4, 5], "[%d] stages = %s" % (id(p.transport), str(p.stages))) - # test status code - f = p.reason - f.trap(error.ProcessTerminated) - self.assertEquals(f.value.exitCode, 23) - - exe = sys.executable - scriptPath = util.sibpath(__file__, "process_tester.py") - args = [exe, "-u", scriptPath] - protocols = [] - deferreds = [] - - for i in xrange(50): - p = TestManyProcessProtocol() - protocols.append(p) - reactor.spawnProcess(p, exe, args, env=None) - deferreds.append(p.deferred) - - deferredList = defer.DeferredList(deferreds, consumeErrors=True) - deferredList.addCallback(_check, protocols) - return deferredList - - def testEcho(self): - finished = defer.Deferred() - p = EchoProtocol(finished) - - exe = sys.executable - scriptPath = util.sibpath(__file__, "process_echoer.py") - reactor.spawnProcess(p, exe, [exe, "-u", scriptPath], env=None) - - def asserts(ignored): - self.failIf(p.failure, p.failure) - self.failUnless(hasattr(p, 'buffer')) - self.assertEquals(len(''.join(p.buffer)), len(p.s * p.n)) - - def takedownProcess(err): - p.transport.closeStdin() - return err - - return finished.addCallback(asserts).addErrback(takedownProcess) - testEcho.timeout = 60 # XXX This should not be. There is already a - # global timeout value. Why do you think this - # test can complete more quickly? - - - def testCommandLine(self): - args = [r'a\"b ', r'a\b ', r' a\\"b', r' a\\b', r'"foo bar" "', '\tab', '"\\', 'a"b', "a'b"] - pyExe = sys.executable - scriptPath = util.sibpath(__file__, "process_cmdline.py") - p = Accumulator() - d = p.endedDeferred = defer.Deferred() - reactor.spawnProcess(p, pyExe, [pyExe, "-u", scriptPath]+args, env=None, - path=None) - - def processEnded(ign): - self.assertEquals(p.errF.getvalue(), "") - recvdArgs = p.outF.getvalue().splitlines() - self.assertEquals(recvdArgs, args) - return d.addCallback(processEnded) - - - def test_wrongArguments(self): - """ - Test invalid arguments to spawnProcess: arguments and environment - must only contains string or unicode, and not null bytes. - """ - exe = sys.executable - p = protocol.ProcessProtocol() - - badEnvs = [ - {"foo": 2}, - {"foo": "egg\0a"}, - {3: "bar"}, - {"bar\0foo": "bar"}] - - badArgs = [ - [exe, 2], - "spam", - [exe, "foo\0bar"]] - - # Sanity check - this will fail for people who have mucked with - # their site configuration in a stupid way, but there's nothing we - # can do about that. - badUnicode = u'\N{SNOWMAN}' - try: - badUnicode.encode(sys.getdefaultencoding()) - except UnicodeEncodeError: - # Okay, that unicode doesn't encode, put it in as a bad environment - # key. - badEnvs.append({badUnicode: 'value for bad unicode key'}) - badEnvs.append({'key for bad unicode value': badUnicode}) - badArgs.append([exe, badUnicode]) - else: - # It _did_ encode. Most likely, Gtk2 is being used and the - # default system encoding is UTF-8, which can encode anything. - # In any case, if implicit unicode -> str conversion works for - # that string, we can't test that TypeError gets raised instead, - # so just leave it off. - pass - - for env in badEnvs: - self.assertRaises( - TypeError, - reactor.spawnProcess, p, exe, [exe, "-c", ""], env=env) - - for args in badArgs: - self.assertRaises( - TypeError, - reactor.spawnProcess, p, exe, args, env=None) - - - # Use upper-case so that the environment key test uses an upper case - # name: some versions of Windows only support upper case environment - # variable names, and I think Python (as of 2.5) doesn't use the right - # syscall for lowercase or mixed case names to work anyway. - okayUnicode = u"UNICODE" - encodedValue = "UNICODE" - - def _deprecatedUnicodeSupportTest(self, processProtocolClass, argv=[], env={}): - """ - Check that a deprecation warning is emitted when passing unicode to - spawnProcess for an argv value or an environment key or value. - Check that the warning is of the right type, has the right message, - and refers to the correct file. Unfortunately, don't check that the - line number is correct, because that is too hard for me to figure - out. - - @param processProtocolClass: A L{UtilityProcessProtocol} subclass - which will be instantiated to communicate with the child process. - - @param argv: The argv argument to spawnProcess. - - @param env: The env argument to spawnProcess. - - @return: A Deferred which fires when the test is complete. - """ - # Sanity to check to make sure we can actually encode this unicode - # with the default system encoding. This may be excessively - # paranoid. -exarkun - self.assertEqual( - self.okayUnicode.encode(sys.getdefaultencoding()), - self.encodedValue) - - p = self.assertWarns(DeprecationWarning, - "Argument strings and environment keys/values passed to " - "reactor.spawnProcess should be str, not unicode.", __file__, - processProtocolClass.run, reactor, argv, env) - return p.getResult() - - - def test_deprecatedUnicodeArgvSupport(self): - """ - Test that a unicode string passed for an argument value is allowed - if it can be encoded with the default system encoding, but that a - deprecation warning is emitted. - """ - d = self._deprecatedUnicodeSupportTest(GetArgumentVector, argv=[self.okayUnicode]) - def gotArgVector(argv): - self.assertEqual(argv, ['-c', self.encodedValue]) - d.addCallback(gotArgVector) - return d - - - def test_deprecatedUnicodeEnvKeySupport(self): - """ - Test that a unicode string passed for the key of the environment - dictionary is allowed if it can be encoded with the default system - encoding, but that a deprecation warning is emitted. - """ - d = self._deprecatedUnicodeSupportTest( - GetEnvironmentDictionary, env={self.okayUnicode: self.encodedValue}) - def gotEnvironment(environ): - self.assertEqual(environ[self.encodedValue], self.encodedValue) - d.addCallback(gotEnvironment) - return d - - - def test_deprecatedUnicodeEnvValueSupport(self): - """ - Test that a unicode string passed for the value of the environment - dictionary is allowed if it can be encoded with the default system - encoding, but that a deprecation warning is emitted. - """ - d = self._deprecatedUnicodeSupportTest( - GetEnvironmentDictionary, env={self.encodedValue: self.okayUnicode}) - def gotEnvironment(environ): - # On Windows, the environment contains more things than we - # specified, so only make sure that at least the key we wanted - # is there, rather than testing the dictionary for exact - # equality. - self.assertEqual(environ[self.encodedValue], self.encodedValue) - d.addCallback(gotEnvironment) - return d - - - -class TwoProcessProtocol(protocol.ProcessProtocol): - num = -1 - finished = 0 - def __init__(self): - self.deferred = defer.Deferred() - def outReceived(self, data): - pass - def processEnded(self, reason): - self.finished = 1 - self.deferred.callback(None) - -class TestTwoProcessesBase: - def setUp(self): - self.processes = [None, None] - self.pp = [None, None] - self.done = 0 - self.verbose = 0 - - def createProcesses(self, usePTY=0): - exe = sys.executable - scriptPath = util.sibpath(__file__, "process_reader.py") - for num in (0,1): - self.pp[num] = TwoProcessProtocol() - self.pp[num].num = num - p = reactor.spawnProcess(self.pp[num], - exe, [exe, "-u", scriptPath], env=None, - usePTY=usePTY) - self.processes[num] = p - - def close(self, num): - if self.verbose: print "closing stdin [%d]" % num - p = self.processes[num] - pp = self.pp[num] - self.failIf(pp.finished, "Process finished too early") - p.loseConnection() - if self.verbose: print self.pp[0].finished, self.pp[1].finished - - def _onClose(self): - return defer.gatherResults([ p.deferred for p in self.pp ]) - - def testClose(self): - if self.verbose: print "starting processes" - self.createProcesses() - reactor.callLater(1, self.close, 0) - reactor.callLater(2, self.close, 1) - return self._onClose() - -class TestTwoProcessesNonPosix(TestTwoProcessesBase, unittest.TestCase): - pass - -class TestTwoProcessesPosix(TestTwoProcessesBase, unittest.TestCase): - def tearDown(self): - for pp, pr in zip(self.pp, self.processes): - if not pp.finished: - try: - os.kill(pr.pid, signal.SIGTERM) - except OSError: - # If the test failed the process may already be dead - # The error here is only noise - pass - return self._onClose() - - def kill(self, num): - if self.verbose: print "kill [%d] with SIGTERM" % num - p = self.processes[num] - pp = self.pp[num] - self.failIf(pp.finished, "Process finished too early") - os.kill(p.pid, signal.SIGTERM) - if self.verbose: print self.pp[0].finished, self.pp[1].finished - - def testKill(self): - if self.verbose: print "starting processes" - self.createProcesses(usePTY=0) - reactor.callLater(1, self.kill, 0) - reactor.callLater(2, self.kill, 1) - return self._onClose() - - def testClosePty(self): - if self.verbose: print "starting processes" - self.createProcesses(usePTY=1) - reactor.callLater(1, self.close, 0) - reactor.callLater(2, self.close, 1) - return self._onClose() - - def testKillPty(self): - if self.verbose: print "starting processes" - self.createProcesses(usePTY=1) - reactor.callLater(1, self.kill, 0) - reactor.callLater(2, self.kill, 1) - return self._onClose() - -class FDChecker(protocol.ProcessProtocol): - state = 0 - data = "" - failed = None - - def __init__(self, d): - self.deferred = d - - def fail(self, why): - self.failed = why - self.deferred.callback(None) - - def connectionMade(self): - self.transport.writeToChild(0, "abcd") - self.state = 1 - - def childDataReceived(self, childFD, data): - if self.state == 1: - if childFD != 1: - self.fail("read '%s' on fd %d (not 1) during state 1" \ - % (childFD, data)) - return - self.data += data - #print "len", len(self.data) - if len(self.data) == 6: - if self.data != "righto": - self.fail("got '%s' on fd1, expected 'righto'" \ - % self.data) - return - self.data = "" - self.state = 2 - #print "state2", self.state - self.transport.writeToChild(3, "efgh") - return - if self.state == 2: - self.fail("read '%s' on fd %s during state 2" % (childFD, data)) - return - if self.state == 3: - if childFD != 1: - self.fail("read '%s' on fd %s (not 1) during state 3" \ - % (childFD, data)) - return - self.data += data - if len(self.data) == 6: - if self.data != "closed": - self.fail("got '%s' on fd1, expected 'closed'" \ - % self.data) - return - self.state = 4 - return - if self.state == 4: - self.fail("read '%s' on fd %s during state 4" % (childFD, data)) - return - - def childConnectionLost(self, childFD): - if self.state == 1: - self.fail("got connectionLost(%d) during state 1" % childFD) - return - if self.state == 2: - if childFD != 4: - self.fail("got connectionLost(%d) (not 4) during state 2" \ - % childFD) - return - self.state = 3 - self.transport.closeChildFD(5) - return - - def processEnded(self, status): - rc = status.value.exitCode - if self.state != 4: - self.fail("processEnded early, rc %d" % rc) - return - if status.value.signal != None: - self.fail("processEnded with signal %s" % status.value.signal) - return - if rc != 0: - self.fail("processEnded with rc %d" % rc) - return - self.deferred.callback(None) - - -class FDTest(unittest.TestCase): - - def testFD(self): - exe = sys.executable - scriptPath = util.sibpath(__file__, "process_fds.py") - d = defer.Deferred() - p = FDChecker(d) - reactor.spawnProcess(p, exe, [exe, "-u", scriptPath], env=None, - path=None, - childFDs={0:"w", 1:"r", 2:2, - 3:"w", 4:"r", 5:"w"}) - d.addCallback(lambda x : self.failIf(p.failed, p.failed)) - return d - - def testLinger(self): - # See what happens when all the pipes close before the process - # actually stops. This test *requires* SIGCHLD catching to work, - # as there is no other way to find out the process is done. - exe = sys.executable - scriptPath = util.sibpath(__file__, "process_linger.py") - p = Accumulator() - d = p.endedDeferred = defer.Deferred() - reactor.spawnProcess(p, exe, [exe, "-u", scriptPath], env=None, - path=None, - childFDs={1:"r", 2:2}, - ) - def processEnded(ign): - self.failUnlessEqual(p.outF.getvalue(), - "here is some text\ngoodbye\n") - return d.addCallback(processEnded) - - - -class Accumulator(protocol.ProcessProtocol): - """Accumulate data from a process.""" - - closed = 0 - endedDeferred = None - - def connectionMade(self): - self.outF = StringIO.StringIO() - self.errF = StringIO.StringIO() - - def outReceived(self, d): - self.outF.write(d) - - def errReceived(self, d): - self.errF.write(d) - - def outConnectionLost(self): - pass - - def errConnectionLost(self): - pass - - def processEnded(self, reason): - self.closed = 1 - if self.endedDeferred is not None: - d, self.endedDeferred = self.endedDeferred, None - d.callback(None) - - -class PosixProcessBase: - """ - Test running processes. - """ - usePTY = False - - def getCommand(self, commandName): - """ - Return the path of the shell command named C{commandName}, looking at - common locations. - """ - if os.path.exists('/bin/%s' % (commandName,)): - cmd = '/bin/%s' % (commandName,) - elif os.path.exists('/usr/bin/%s' % (commandName,)): - cmd = '/usr/bin/%s' % (commandName,) - else: - raise RuntimeError( - "%s not found in /bin or /usr/bin" % (commandName,)) - return cmd - - def testNormalTermination(self): - cmd = self.getCommand('true') - - d = defer.Deferred() - p = TrivialProcessProtocol(d) - reactor.spawnProcess(p, cmd, ['true'], env=None, - usePTY=self.usePTY) - def check(ignored): - p.reason.trap(error.ProcessDone) - self.assertEquals(p.reason.value.exitCode, 0) - self.assertEquals(p.reason.value.signal, None) - d.addCallback(check) - return d - - - def test_abnormalTermination(self): - """ - When a process terminates with a system exit code set to 1, - C{processEnded} is called with a L{error.ProcessTerminated} error, - the C{exitCode} attribute reflecting the system exit code. - """ - exe = sys.executable - - d = defer.Deferred() - p = TrivialProcessProtocol(d) - reactor.spawnProcess(p, exe, [exe, '-c', 'import sys; sys.exit(1)'], - env=None, usePTY=self.usePTY) - - def check(ignored): - p.reason.trap(error.ProcessTerminated) - self.assertEquals(p.reason.value.exitCode, 1) - self.assertEquals(p.reason.value.signal, None) - d.addCallback(check) - return d - - - def _testSignal(self, sig): - exe = sys.executable - scriptPath = util.sibpath(__file__, "process_signal.py") - d = defer.Deferred() - p = SignalProtocol(d, sig) - reactor.spawnProcess(p, exe, [exe, "-u", scriptPath], env=None, - usePTY=self.usePTY) - return d - - - def test_signalHUP(self): - """ - Sending the SIGHUP signal to a running process interrupts it, and - C{processEnded} is called with a L{error.ProcessTerminated} instance - with the C{exitCode} set to C{None} and the C{signal} attribute set to - C{signal.SIGHUP}. C{os.WTERMSIG} can also be used on the C{status} - attribute to extract the signal value. - """ - return self._testSignal('HUP') - - - def test_signalINT(self): - """ - Sending the SIGINT signal to a running process interrupts it, and - C{processEnded} is called with a L{error.ProcessTerminated} instance - with the C{exitCode} set to C{None} and the C{signal} attribute set to - C{signal.SIGINT}. C{os.WTERMSIG} can also be used on the C{status} - attribute to extract the signal value. - """ - return self._testSignal('INT') - - - def test_signalKILL(self): - """ - Sending the SIGKILL signal to a running process interrupts it, and - C{processEnded} is called with a L{error.ProcessTerminated} instance - with the C{exitCode} set to C{None} and the C{signal} attribute set to - C{signal.SIGKILL}. C{os.WTERMSIG} can also be used on the C{status} - attribute to extract the signal value. - """ - return self._testSignal('KILL') - - - def test_signalTERM(self): - """ - Sending the SIGTERM signal to a running process interrupts it, and - C{processEnded} is called with a L{error.ProcessTerminated} instance - with the C{exitCode} set to C{None} and the C{signal} attribute set to - C{signal.SIGTERM}. C{os.WTERMSIG} can also be used on the C{status} - attribute to extract the signal value. - """ - return self._testSignal('TERM') - - - def test_executionError(self): - """ - Raise an error during execvpe to check error management. - """ - cmd = self.getCommand('false') - - d = defer.Deferred() - p = TrivialProcessProtocol(d) - def buggyexecvpe(command, args, environment): - raise RuntimeError("Ouch") - oldexecvpe = os.execvpe - os.execvpe = buggyexecvpe - try: - reactor.spawnProcess(p, cmd, ['false'], env=None, - usePTY=self.usePTY) - - def check(ignored): - errData = "".join(p.errData + p.outData) - self.assertIn("Upon execvpe", errData) - self.assertIn("Ouch", errData) - d.addCallback(check) - finally: - os.execvpe = oldexecvpe - return d - - - -class MockOS(object): - """ - The mock OS: overwrite L{os}, L{fcntl} and {sys} functions with fake ones. - - @ivar exited: set to True when C{_exit} is called. - @type exited: C{bool} - - @ivar O_RDWR: dumb value faking C{os.O_RDWR}. - @type O_RDWR: C{int} - - @ivar O_NOCTTY: dumb value faking C{os.O_NOCTTY}. - @type O_NOCTTY: C{int} - - @ivar WNOHANG: dumb value faking C{os.WNOHANG}. - @type WNOHANG: C{int} - - @ivar raiseFork: if not C{None}, subsequent calls to fork will raise this - object. - @type raiseFork: C{NoneType} or C{Exception} - - @ivar raiseExec: if set, subsequent calls to execvpe will raise an error. - @type raiseExec: C{bool} - - @ivar fdio: fake file object returned by calls to fdopen. - @type fdio: C{StringIO.StringIO} - - @ivar actions: hold names of some actions executed by the object, in order - of execution. - - @type actions: C{list} of C{str} - - @ivar closed: keep track of the file descriptor closed. - @param closed: C{list} of C{int} - - @ivar child: whether fork return for the child or the parent. - @type child: C{bool} - - @ivar pipeCount: count the number of time that C{os.pipe} has been called. - @type pipeCount: C{int} - - @ivar raiseWaitPid: if set, subsequent calls to waitpid will raise an - the error specified. - @type raiseWaitPid: C{None} or a class - - @ivar waitChild: if set, subsequent calls to waitpid will return it. - @type waitChild: C{None} or a tuple - """ - exited = False - O_RDWR = 1 - O_NOCTTY = 1 - WNOHANG = 1 - raiseExec = False - fdio = None - child = True - raiseWaitPid = None - raiseFork = None - waitChild = None - - def __init__(self): - """ - Initialiaze data structures. - """ - self.actions = [] - self.closed = [] - self.pipeCount = 0 - - - def open(self, dev, flags): - """ - Fake C{os.open}. Return a non fd number to be sure it's not used - elsewhere. - """ - return -3 - - - def fdopen(self, fd, flag): - """ - Fake C{os.fdopen}. Return a StringIO object whose content can be tested - later via C{self.fdio}. - """ - self.fdio = StringIO.StringIO() - return self.fdio - - - def setsid(self): - """ - Fake C{os.setsid}. Do nothing. - """ - - - def fork(self): - """ - Fake C{os.fork}. Save the action in C{self.actions}, and return 0 if - C{self.child} is set, or a dumb number. - """ - self.actions.append(('fork', gc.isenabled())) - if self.raiseFork is not None: - raise self.raiseFork - elif self.child: - # Child result is 0 - return 0 - else: - return 21 - - - def close(self, fd): - """ - Fake C{os.close}, saving the closed fd in C{self.closed}. - """ - self.closed.append(fd) - - - def dup2(self, fd1, fd2): - """ - Fake C{os.dup2}. Do nothing. - """ - - - def write(self, fd, data): - """ - Fake C{os.write}. Do nothing. - """ - - - def execvpe(self, command, args, env): - """ - Fake C{os.execvpe}. Save the action, and raise an error if - C{self.raiseExec} is set. - """ - self.actions.append('exec') - if self.raiseExec: - raise RuntimeError("Bar") - - - def pipe(self): - """ - Fake C{os.pipe}. Return non fd numbers to be sure it's not used - elsewhere, and increment C{self.pipeCount}. This is used to uniquify - the result. - """ - self.pipeCount += 1 - return - 2 * self.pipeCount + 1, - 2 * self.pipeCount - - - def ttyname(self, fd): - """ - Fake C{os.ttyname}. Return a dumb string. - """ - return "foo" - - - def _exit(self, code): - """ - Fake C{os._exit}. Save the action, set the C{self.exited} flag, and - raise C{SystemError}. - """ - self.actions.append('exit') - self.exited = True - # Don't forget to raise an error, or you'll end up in parent - # code path. - raise SystemError() - - - def ioctl(self, fd, flags, arg): - """ - Override C{fcntl.ioctl}. Do nothing. - """ - - - def setNonBlocking(self, fd): - """ - Override C{fdesc.setNonBlocking}. Do nothing. - """ - - - def waitpid(self, pid, options): - """ - Override C{os.waitpid}. Return values meaning that the child process - has exited, save executed action. - """ - self.actions.append('waitpid') - if self.raiseWaitPid is not None: - raise self.raiseWaitPid - if self.waitChild is not None: - return self.waitChild - return 1, 0 - - - def settrace(self, arg): - """ - Override C{sys.settrace} to keep coverage working. - """ - - - def getegid(self): - """ - Override C{os.getegid}. Return a dumb number. - """ - return 1234 - - - def getgid(self): - """ - Override C{os.getgid}. Return a dumb number. - """ - return 1235 - - - def geteuid(self): - """ - Override C{os.geteuid}. Return a dumb number. - """ - return 1236 - - - def getuid(self): - """ - Override C{os.getuid}. Return a dumb number. - """ - return 1237 - - - def setuid(self, val): - """ - Override C{os.setuid}. Do nothing. - """ - self.actions.append(('setuid', val)) - - - def setgid(self, val): - """ - Override C{os.setgid}. Do nothing. - """ - self.actions.append(('setgid', val)) - - - def setregid(self, val1, val2): - """ - Override C{os.setregid}. Do nothing. - """ - self.actions.append(('setregid', val1, val2)) - - - def setreuid(self, val1, val2): - """ - Override C{os.setreuid}. Save the action. - """ - self.actions.append(('setreuid', val1, val2)) - - - def switchUID(self, uid, gid): - """ - Override C{util.switchuid}. Save the action. - """ - self.actions.append(('switchuid', uid, gid)) - - - -if process is not None: - class DumbProcessWriter(process.ProcessWriter): - """ - A fake L{process.ProcessWriter} used for tests. - """ - - def startReading(self): - """ - Here's the faking: don't do anything here. - """ - - - - class DumbProcessReader(process.ProcessReader): - """ - A fake L{process.ProcessReader} used for tests. - """ - - def startReading(self): - """ - Here's the faking: don't do anything here. - """ - - - - class DumbPTYProcess(process.PTYProcess): - """ - A fake L{process.PTYProcess} used for tests. - """ - - def startReading(self): - """ - Here's the faking: don't do anything here. - """ - - - -class MockProcessTestCase(unittest.TestCase): - """ - Mock a process runner to test forked child code path. - """ - - def setUp(self): - """ - Replace L{process} os, fcntl, sys, switchUID modules with the mock - class L{MockOS}. - """ - if gc.isenabled(): - self.addCleanup(gc.enable) - else: - self.addCleanup(gc.disable) - self.mockos = MockOS() - self.oldos = os - self.oldfcntl = fcntl - self.oldsys = sys - self.oldSwitchUID = util.switchUID - self.oldFdesc = process.fdesc - process.os = self.mockos - process.fcntl = self.mockos - process.sys = self.mockos - process.switchUID = self.mockos.switchUID - process.fdesc = self.mockos - process.Process.processReaderFactory = DumbProcessReader - process.Process.processWriterFactory = DumbProcessWriter - - - def tearDown(self): - """ - Restore L{process} modules, and reset processes registered for reap. - """ - process.os = self.oldos - process.fcntl = self.oldfcntl - process.sys = self.oldsys - process.switchUID = self.oldSwitchUID - process.fdesc = self.oldFdesc - process.Process.processReaderFactory = process.ProcessReader - process.Process.processWriterFactory = process.ProcessWriter - process.reapProcessHandlers = {} - - - def test_mockFork(self): - """ - Test a classic spawnProcess. Check the path of the client code: - fork, exec, exit. - """ - gc.enable() - - cmd = '/mock/ouch' - - d = defer.Deferred() - p = TrivialProcessProtocol(d) - try: - reactor.spawnProcess(p, cmd, ['ouch'], env=None, - usePTY=False) - except SystemError: - self.assert_(self.mockos.exited) - self.assertEquals( - self.mockos.actions, [("fork", False), "exec", "exit"]) - else: - self.fail("Should not be here") - - # It should leave the garbage collector disabled. - self.assertFalse(gc.isenabled()) - - - def _mockForkInParentTest(self): - """ - Assert that in the main process, spawnProcess disables the garbage - collector, calls fork, closes the pipe file descriptors it created for - the child process, and calls waitpid. - """ - self.mockos.child = False - cmd = '/mock/ouch' - - d = defer.Deferred() - p = TrivialProcessProtocol(d) - reactor.spawnProcess(p, cmd, ['ouch'], env=None, - usePTY=False) - # It should close the first read pipe, and the 2 last write pipes - self.assertEqual(self.mockos.closed, [-1, -4, -6]) - self.assertEquals(self.mockos.actions, [("fork", False), "waitpid"]) - - - def test_mockForkInParentGarbageCollectorEnabled(self): - """ - The garbage collector should be enabled when L{reactor.spawnProcess} - returns if it was initially enabled. - - @see L{_mockForkInParentTest} - """ - gc.enable() - self._mockForkInParentTest() - self.assertTrue(gc.isenabled()) - - - def test_mockForkInParentGarbageCollectorDisabled(self): - """ - The garbage collector should be disabled when L{reactor.spawnProcess} - returns if it was initially disabled. - - @see L{_mockForkInParentTest} - """ - gc.disable() - self._mockForkInParentTest() - self.assertFalse(gc.isenabled()) - - - def test_mockForkTTY(self): - """ - Test a TTY spawnProcess: check the path of the client code: - fork, exec, exit. - """ - cmd = '/mock/ouch' - - d = defer.Deferred() - p = TrivialProcessProtocol(d) - try: - reactor.spawnProcess(p, cmd, ['ouch'], env=None, - usePTY=True) - except SystemError: - self.assert_(self.mockos.exited) - self.assertEquals( - self.mockos.actions, [("fork", False), "exec", "exit"]) - else: - self.fail("Should not be here") - - - def _mockWithForkError(self): - """ - Assert that if the fork call fails, no other process setup calls are - made and that spawnProcess raises the exception fork raised. - """ - self.mockos.raiseFork = OSError(errno.EAGAIN, None) - protocol = TrivialProcessProtocol(None) - self.assertRaises(OSError, reactor.spawnProcess, protocol, None) - self.assertEqual(self.mockos.actions, [("fork", False)]) - - - def test_mockWithForkErrorGarbageCollectorEnabled(self): - """ - The garbage collector should be enabled when L{reactor.spawnProcess} - raises because L{os.fork} raised, if it was initially enabled. - """ - gc.enable() - self._mockWithForkError() - self.assertTrue(gc.isenabled()) - - - def test_mockWithForkErrorGarbageCollectorDisabled(self): - """ - The garbage collector should be disabled when - L{reactor.spawnProcess} raises because L{os.fork} raised, if it was - initially disabled. - """ - gc.disable() - self._mockWithForkError() - self.assertFalse(gc.isenabled()) - - - def test_mockWithExecError(self): - """ - Spawn a process but simulate an error during execution in the client - path: C{os.execvpe} raises an error. It should close all the standard - fds, try to print the error encountered, and exit cleanly. - """ - cmd = '/mock/ouch' - - d = defer.Deferred() - p = TrivialProcessProtocol(d) - self.mockos.raiseExec = True - try: - reactor.spawnProcess(p, cmd, ['ouch'], env=None, - usePTY=False) - except SystemError: - self.assert_(self.mockos.exited) - self.assertEquals( - self.mockos.actions, [("fork", False), "exec", "exit"]) - # Check that fd have been closed - self.assertIn(0, self.mockos.closed) - self.assertIn(1, self.mockos.closed) - self.assertIn(2, self.mockos.closed) - # Check content of traceback - self.assertIn("RuntimeError: Bar", self.mockos.fdio.getvalue()) - else: - self.fail("Should not be here") - - - def test_mockSetUid(self): - """ - Try creating a process with setting its uid: it's almost the same path - as the standard path, but with a C{switchUID} call before the exec. - """ - cmd = '/mock/ouch' - - d = defer.Deferred() - p = TrivialProcessProtocol(d) - try: - reactor.spawnProcess(p, cmd, ['ouch'], env=None, - usePTY=False, uid=8080) - except SystemError: - self.assert_(self.mockos.exited) - self.assertEquals(self.mockos.actions, - [('setuid', 0), ('setgid', 0), ('fork', False), - ('switchuid', 8080, 1234), 'exec', 'exit']) - else: - self.fail("Should not be here") - - - def test_mockSetUidInParent(self): - """ - Try creating a process with setting its uid, in the parent path: it - should switch to root before fork, then restore initial uid/gids. - """ - self.mockos.child = False - cmd = '/mock/ouch' - - d = defer.Deferred() - p = TrivialProcessProtocol(d) - reactor.spawnProcess(p, cmd, ['ouch'], env=None, - usePTY=False, uid=8080) - self.assertEquals(self.mockos.actions, - [('setuid', 0), ('setgid', 0), ('fork', False), - ('setregid', 1235, 1234), ('setreuid', 1237, 1236), 'waitpid']) - - - def test_mockPTYSetUid(self): - """ - Try creating a PTY process with setting its uid: it's almost the same - path as the standard path, but with a C{switchUID} call before the - exec. - """ - cmd = '/mock/ouch' - - d = defer.Deferred() - p = TrivialProcessProtocol(d) - try: - reactor.spawnProcess(p, cmd, ['ouch'], env=None, - usePTY=True, uid=8081) - except SystemError: - self.assert_(self.mockos.exited) - self.assertEquals(self.mockos.actions, - [('setuid', 0), ('setgid', 0), ('fork', False), - ('switchuid', 8081, 1234), 'exec', 'exit']) - else: - self.fail("Should not be here") - - - def test_mockPTYSetUidInParent(self): - """ - Try creating a PTY process with setting its uid, in the parent path: it - should switch to root before fork, then restore initial uid/gids. - """ - self.mockos.child = False - cmd = '/mock/ouch' - - d = defer.Deferred() - p = TrivialProcessProtocol(d) - oldPTYProcess = process.PTYProcess - try: - process.PTYProcess = DumbPTYProcess - reactor.spawnProcess(p, cmd, ['ouch'], env=None, - usePTY=True, uid=8080) - finally: - process.PTYProcess = oldPTYProcess - self.assertEquals(self.mockos.actions, - [('setuid', 0), ('setgid', 0), ('fork', False), - ('setregid', 1235, 1234), ('setreuid', 1237, 1236), 'waitpid']) - - - def test_mockWithWaitError(self): - """ - Test that reapProcess logs errors raised. - """ - self.mockos.child = False - cmd = '/mock/ouch' - self.mockos.waitChild = (0, 0) - - d = defer.Deferred() - p = TrivialProcessProtocol(d) - proc = reactor.spawnProcess(p, cmd, ['ouch'], env=None, - usePTY=False) - self.assertEquals(self.mockos.actions, [("fork", False), "waitpid"]) - - self.mockos.raiseWaitPid = OSError() - proc.reapProcess() - errors = self.flushLoggedErrors() - self.assertEquals(len(errors), 1) - errors[0].trap(OSError) - - - def test_mockErrorECHILDInReapProcess(self): - """ - Test that reapProcess doesn't log anything when waitpid raises a - C{OSError} with errno C{ECHILD}. - """ - self.mockos.child = False - cmd = '/mock/ouch' - self.mockos.waitChild = (0, 0) - - d = defer.Deferred() - p = TrivialProcessProtocol(d) - proc = reactor.spawnProcess(p, cmd, ['ouch'], env=None, - usePTY=False) - self.assertEquals(self.mockos.actions, [("fork", False), "waitpid"]) - - self.mockos.raiseWaitPid = OSError() - self.mockos.raiseWaitPid.errno = errno.ECHILD - # This should not produce any errors - proc.reapProcess() - - -class PosixProcessTestCase(unittest.TestCase, PosixProcessBase): - # add three non-pty test cases - - def testStderr(self): - # we assume there is no file named ZZXXX..., both in . and in /tmp - cmd = self.getCommand('ls') - - p = Accumulator() - d = p.endedDeferred = defer.Deferred() - reactor.spawnProcess(p, cmd, - [cmd, - "ZZXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"], - env=None, path="/tmp", - usePTY=self.usePTY) - - def processEnded(ign): - self.assertEquals(lsOut, p.errF.getvalue()) - return d.addCallback(processEnded) - - def testProcess(self): - cmd = self.getCommand('gzip') - s = "there's no place like home!\n" * 3 - p = Accumulator() - d = p.endedDeferred = defer.Deferred() - reactor.spawnProcess(p, cmd, [cmd, "-c"], env=None, path="/tmp", - usePTY=self.usePTY) - p.transport.write(s) - p.transport.closeStdin() - - def processEnded(ign): - f = p.outF - f.seek(0, 0) - gf = gzip.GzipFile(fileobj=f) - self.assertEquals(gf.read(), s) - return d.addCallback(processEnded) - - - -class PosixProcessTestCasePTY(unittest.TestCase, PosixProcessBase): - """ - Just like PosixProcessTestCase, but use ptys instead of pipes. - """ - usePTY = True - # PTYs only offer one input and one output. What still makes sense? - # testNormalTermination - # test_abnormalTermination - # testSignal - # testProcess, but not without p.transport.closeStdin - # might be solveable: TODO: add test if so - - def testOpeningTTY(self): - exe = sys.executable - scriptPath = util.sibpath(__file__, "process_tty.py") - p = Accumulator() - d = p.endedDeferred = defer.Deferred() - reactor.spawnProcess(p, exe, [exe, "-u", scriptPath], env=None, - path=None, usePTY=self.usePTY) - p.transport.write("hello world!\n") - - def processEnded(ign): - self.assertRaises( - error.ProcessExitedAlready, p.transport.signalProcess, 'HUP') - self.assertEquals( - p.outF.getvalue(), - "hello world!\r\nhello world!\r\n", - "Error message from process_tty follows:\n\n%s\n\n" % p.outF.getvalue()) - return d.addCallback(processEnded) - - - def testBadArgs(self): - pyExe = sys.executable - pyArgs = [pyExe, "-u", "-c", "print 'hello'"] - p = Accumulator() - self.assertRaises(ValueError, reactor.spawnProcess, p, pyExe, pyArgs, - usePTY=1, childFDs={1:'r'}) - - - -class Win32SignalProtocol(SignalProtocol): - """ - A win32-specific process protocol that handles C{processEnded} - differently: processes should exit with exit code 1. - """ - - def processEnded(self, reason): - """ - Callback C{self.deferred} with C{None} if C{reason} is a - L{error.ProcessTerminated} failure with C{exitCode} set to 1. - Otherwise, errback with a C{ValueError} describing the problem. - """ - if not reason.check(error.ProcessTerminated): - return self.deferred.errback( - ValueError("wrong termination: %s" % (reason,))) - v = reason.value - if v.exitCode != 1: - return self.deferred.errback( - ValueError("Wrong exit code: %s" % (reason.exitCode,))) - self.deferred.callback(None) - - - -class Win32ProcessTestCase(unittest.TestCase): - """ - Test process programs that are packaged with twisted. - """ - - def testStdinReader(self): - pyExe = sys.executable - scriptPath = util.sibpath(__file__, "process_stdinreader.py") - p = Accumulator() - d = p.endedDeferred = defer.Deferred() - reactor.spawnProcess(p, pyExe, [pyExe, "-u", scriptPath], env=None, - path=None) - p.transport.write("hello, world") - p.transport.closeStdin() - - def processEnded(ign): - self.assertEquals(p.errF.getvalue(), "err\nerr\n") - self.assertEquals(p.outF.getvalue(), "out\nhello, world\nout\n") - return d.addCallback(processEnded) - - - def testBadArgs(self): - pyExe = sys.executable - pyArgs = [pyExe, "-u", "-c", "print 'hello'"] - p = Accumulator() - self.assertRaises(ValueError, - reactor.spawnProcess, p, pyExe, pyArgs, uid=1) - self.assertRaises(ValueError, - reactor.spawnProcess, p, pyExe, pyArgs, gid=1) - self.assertRaises(ValueError, - reactor.spawnProcess, p, pyExe, pyArgs, usePTY=1) - self.assertRaises(ValueError, - reactor.spawnProcess, p, pyExe, pyArgs, childFDs={1:'r'}) - - - def _testSignal(self, sig): - exe = sys.executable - scriptPath = util.sibpath(__file__, "process_signal.py") - d = defer.Deferred() - p = Win32SignalProtocol(d, sig) - reactor.spawnProcess(p, exe, [exe, "-u", scriptPath], env=None) - return d - - - def test_signalTERM(self): - """ - Sending the SIGTERM signal terminates a created process, and - C{processEnded} is called with a L{error.ProcessTerminated} instance - with the C{exitCode} attribute set to 1. - """ - return self._testSignal('TERM') - - - def test_signalINT(self): - """ - Sending the SIGINT signal terminates a created process, and - C{processEnded} is called with a L{error.ProcessTerminated} instance - with the C{exitCode} attribute set to 1. - """ - return self._testSignal('INT') - - - def test_signalKILL(self): - """ - Sending the SIGKILL signal terminates a created process, and - C{processEnded} is called with a L{error.ProcessTerminated} instance - with the C{exitCode} attribute set to 1. - """ - return self._testSignal('KILL') - - - -class Dumbwin32procPidTest(unittest.TestCase): - """ - Simple test for the pid attribute of Process on win32. - """ - - def test_pid(self): - """ - Launch process with mock win32process. The only mock aspect of this - module is that the pid of the process created will always be 42. - """ - from twisted.internet import _dumbwin32proc - from twisted.test import mock_win32process - self.patch(_dumbwin32proc, "win32process", mock_win32process) - exe = sys.executable - scriptPath = util.sibpath(__file__, "process_cmdline.py") - - d = defer.Deferred() - processProto = TrivialProcessProtocol(d) - comspec = str(os.environ["COMSPEC"]) - cmd = [comspec, "/c", exe, scriptPath] - - p = _dumbwin32proc.Process(reactor, - processProto, - None, - cmd, - {}, - None) - self.assertEquals(42, p.pid) - self.assertEquals("", repr(p)) - - def pidCompleteCb(result): - self.assertEquals(None, p.pid) - return d.addCallback(pidCompleteCb) - - - -class UtilTestCase(unittest.TestCase): - """ - Tests for process-related helper functions (currently only - L{procutils.which}. - """ - def setUp(self): - """ - Create several directories and files, some of which are executable - and some of which are not. Save the current PATH setting. - """ - j = os.path.join - - base = self.mktemp() - - self.foo = j(base, "foo") - self.baz = j(base, "baz") - self.foobar = j(self.foo, "bar") - self.foobaz = j(self.foo, "baz") - self.bazfoo = j(self.baz, "foo") - self.bazbar = j(self.baz, "bar") - - for d in self.foobar, self.foobaz, self.bazfoo, self.bazbar: - os.makedirs(d) - - for name, mode in [(j(self.foobaz, "executable"), 0700), - (j(self.foo, "executable"), 0700), - (j(self.bazfoo, "executable"), 0700), - (j(self.bazfoo, "executable.bin"), 0700), - (j(self.bazbar, "executable"), 0)]: - f = file(name, "w") - f.close() - os.chmod(name, mode) - - self.oldPath = os.environ.get('PATH', None) - os.environ['PATH'] = os.pathsep.join(( - self.foobar, self.foobaz, self.bazfoo, self.bazbar)) - - - def tearDown(self): - """ - Restore the saved PATH setting. - """ - if self.oldPath is None: - try: - del os.environ['PATH'] - except KeyError: - pass - else: - os.environ['PATH'] = self.oldPath - - - def test_whichWithoutPATH(self): - """ - Test that if C{os.environ} does not have a C{'PATH'} key, - L{procutils.which} returns an empty list. - """ - del os.environ['PATH'] - self.assertEqual(procutils.which("executable"), []) - - - def testWhich(self): - j = os.path.join - paths = procutils.which("executable") - expectedPaths = [j(self.foobaz, "executable"), - j(self.bazfoo, "executable")] - if runtime.platform.isWindows(): - expectedPaths.append(j(self.bazbar, "executable")) - self.assertEquals(paths, expectedPaths) - - - def testWhichPathExt(self): - j = os.path.join - old = os.environ.get('PATHEXT', None) - os.environ['PATHEXT'] = os.pathsep.join(('.bin', '.exe', '.sh')) - try: - paths = procutils.which("executable") - finally: - if old is None: - del os.environ['PATHEXT'] - else: - os.environ['PATHEXT'] = old - expectedPaths = [j(self.foobaz, "executable"), - j(self.bazfoo, "executable"), - j(self.bazfoo, "executable.bin")] - if runtime.platform.isWindows(): - expectedPaths.append(j(self.bazbar, "executable")) - self.assertEquals(paths, expectedPaths) - - - -class ClosingPipesProcessProtocol(protocol.ProcessProtocol): - output = '' - errput = '' - - def __init__(self, outOrErr): - self.deferred = defer.Deferred() - self.outOrErr = outOrErr - - def processEnded(self, reason): - self.deferred.callback(reason) - - def outReceived(self, data): - self.output += data - - def errReceived(self, data): - self.errput += data - - -class ClosingPipes(unittest.TestCase): - - def doit(self, fd): - p = ClosingPipesProcessProtocol(True) - p.deferred.addCallbacks( - callback=lambda _: self.fail("I wanted an errback."), - errback=self._endProcess, errbackArgs=(p,)) - reactor.spawnProcess(p, sys.executable, - [sys.executable, '-u', '-c', - r'raw_input(); import sys, os; os.write(%d, "foo\n"); sys.exit(42)' % fd], - env=None) - p.transport.write('go\n') - - if fd == 1: - p.transport.closeStdout() - elif fd == 2: - p.transport.closeStderr() - else: - raise RuntimeError - - # make the buggy case not hang - p.transport.closeStdin() - return p.deferred - - def _endProcess(self, reason, p): - self.failIf(reason.check(error.ProcessDone), - 'Child should fail due to EPIPE.') - reason.trap(error.ProcessTerminated) - # child must not get past that write without raising - self.failIfEqual(reason.value.exitCode, 42, - 'process reason was %r' % reason) - self.failUnlessEqual(p.output, '') - return p.errput - - def test_stdout(self): - """ProcessProtocol.transport.closeStdout actually closes the pipe.""" - d = self.doit(1) - def _check(errput): - self.failIfEqual(errput.find('OSError'), -1) - if runtime.platform.getType() != 'win32': - self.failIfEqual(errput.find('Broken pipe'), -1) - d.addCallback(_check) - return d - - def test_stderr(self): - """ProcessProtocol.transport.closeStderr actually closes the pipe.""" - d = self.doit(2) - def _check(errput): - # there should be no stderr open, so nothing for it to - # write the error to. - self.failUnlessEqual(errput, '') - d.addCallback(_check) - return d - - -class SystemEventOrderRegressionTests(unittest.TestCase): - """ - Ordering and reentrancy tests for C{reactor.callWhenRunning} and reactor - shutdown (see #3146 and #3168). - """ - def setUp(self): - """ - Clear the SIGCHLD handler, if there is one, to ensure an environment - like the one which exists prior to a call to L{reactor.run}. - """ - self.originalHandler = signal.signal(signal.SIGCHLD, signal.SIG_DFL) - self.processTransports = [] - - - def tearDown(self): - """ - Restore the original SIGCHLD handler and reap processes as long as - there seem to be any remaining. - """ - signal.signal(signal.SIGCHLD, signal.SIG_DFL) - while self.processTransports: - transport = self.processTransports.pop() - if transport.pid is not None: - os.waitpid(transport.pid, 0) - signal.signal(signal.SIGCHLD, self.originalHandler) - - - def unbuildReactor(self, reactor): - """ - Clean up any resources which may have been allocated for the given - reactor by its creation or by a test which used it. - """ - # Chris says: - # - # XXX This explicit calls to clean up the waker should become obsolete - # when bug #3063 is fixed. -radix, 2008-02-29. Fortunately it should - # probably cause an error when bug #3063 is fixed, so it should be - # removed in the same branch that fixes it. - # - # -exarkun - reactor.removeReader(reactor.waker) - reactor.waker.connectionLost(None) - - # Here's an extra thing unrelated to wakers but necessary for - # cleaning up after the reactors we make. -exarkun - reactor.disconnectAll() - - - def buildReactor(self): - """ - Create and return an instance of L{selectreactor.SelectReactor}. - """ - reactor = selectreactor.SelectReactor() - self.addCleanup(self.unbuildReactor, reactor) - return reactor - - - def spawnProcess(self, reactor): - """ - Call C{reactor.spawnProcess} with some simple arguments. Do this here - so that code object referenced by the stack frame has a C{co_filename} - attribute set to this file so that L{TestCase.assertWarns} can be used. - """ - self.processTransports.append( - reactor.spawnProcess( - protocol.ProcessProtocol(), sys.executable, - [sys.executable, "-c", ""])) - - - def test_spawnProcessTooEarlyWarns(self): - """ - C{reactor.spawnProcess} emits a warning if it is called before - C{reactor.run}. - - If you can figure out a way to make it safe to run - C{reactor.spawnProcess} before C{reactor.run}, you may delete the - warning and this test. - """ - reactor = self.buildReactor() - self.assertWarns( - error.PotentialZombieWarning, - error.PotentialZombieWarning.MESSAGE, __file__, - self.spawnProcess, reactor) - - - def test_callWhenRunningSpawnProcessWarningFree(self): - """ - L{PotentialZombieWarning} is not emitted when the reactor is run after - C{reactor.callWhenRunning(reactor.spawnProcess, ...)} has been called. - """ - events = [] - self.patch(warnings, 'warn', lambda *a, **kw: events.append(a)) - reactor = self.buildReactor() - reactor.callWhenRunning(self.spawnProcess, reactor) - reactor.callWhenRunning(reactor.stop) - reactor.run() - self.assertFalse(events) - - - def test_clientConnectionFailedStopsReactor(self): - """ - The reactor can be stopped by a client factory's - C{clientConnectionFailed} method. - - This isn't really a process test but it's here for simplicity of - implementation and it won't be very long lived. - """ - class Stop(protocol.ClientFactory): - def clientConnectionFailed(self, connector, reason): - reactor.stop() - probe = socket.socket() - probe.bind(('', 0)) - host, port = probe.getsockname() - probe.close() - reactor = self.buildReactor() - reactor.connectTCP(host, port, Stop()) - reactor.run() - - - def test_shutdownTriggersRun(self): - """ - C{reactor.run()} does not return until shutdown triggers have all run. - """ - events = [] - reactor = self.buildReactor() - reactor.addSystemEventTrigger( - 'after', 'shutdown', events.append, "done") - reactor.callWhenRunning(reactor.stop) - reactor.run() - self.assertEqual(events, ["done"]) - - - -skipMessage = "wrong platform or reactor doesn't support IReactorProcess" -if (runtime.platform.getType() != 'posix') or (not interfaces.IReactorProcess(reactor, None)): - PosixProcessTestCase.skip = skipMessage - PosixProcessTestCasePTY.skip = skipMessage - TestTwoProcessesPosix.skip = skipMessage - FDTest.skip = skipMessage -else: - # do this before running the tests: it uses SIGCHLD and stuff internally - lsOut = popen2.popen3("/bin/ls ZZXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")[2].read() - -if (runtime.platform.getType() != 'win32') or (not interfaces.IReactorProcess(reactor, None)): - Win32ProcessTestCase.skip = skipMessage - TestTwoProcessesNonPosix.skip = skipMessage - Dumbwin32procPidTest.skip = skipMessage - -if not interfaces.IReactorProcess(reactor, None): - ProcessTestCase.skip = skipMessage - ClosingPipes.skip = skipMessage - -if process is None: - MockProcessTestCase.skip = skipMessage - SystemEventOrderRegressionTests.skip = skipMessage diff --git a/tools/buildbot/pylibs/twisted/test/test_protocols.py b/tools/buildbot/pylibs/twisted/test/test_protocols.py deleted file mode 100644 index 8fc8ae5..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_protocols.py +++ /dev/null @@ -1,725 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Test cases for twisted.protocols package. -""" - -from twisted.trial import unittest -from twisted.protocols import basic, wire, portforward -from twisted.internet import reactor, protocol, defer, task, error -from twisted.test import proto_helpers - -import struct -import StringIO - -class StringIOWithoutClosing(StringIO.StringIO): - """ - A StringIO that can't be closed. - """ - def close(self): - """ - Do nothing. - """ - -class LineTester(basic.LineReceiver): - """ - A line receiver that parses data received and make actions on some tokens. - - @type delimiter: C{str} - @ivar delimiter: character used between received lines. - @type MAX_LENGTH: C{int} - @ivar MAX_LENGTH: size of a line when C{lineLengthExceeded} will be called. - @type clock: L{twisted.internet.task.Clock} - @ivar clock: clock simulating reactor callLater. Pass it to constructor if - you want to use the pause/rawpause functionalities. - """ - - delimiter = '\n' - MAX_LENGTH = 64 - - def __init__(self, clock=None): - """ - If given, use a clock to make callLater calls. - """ - self.clock = clock - - def connectionMade(self): - """ - Create/clean data received on connection. - """ - self.received = [] - - def lineReceived(self, line): - """ - Receive line and make some action for some tokens: pause, rawpause, - stop, len, produce, unproduce. - """ - self.received.append(line) - if line == '': - self.setRawMode() - elif line == 'pause': - self.pauseProducing() - self.clock.callLater(0, self.resumeProducing) - elif line == 'rawpause': - self.pauseProducing() - self.setRawMode() - self.received.append('') - self.clock.callLater(0, self.resumeProducing) - elif line == 'stop': - self.stopProducing() - elif line[:4] == 'len ': - self.length = int(line[4:]) - elif line.startswith('produce'): - self.transport.registerProducer(self, False) - elif line.startswith('unproduce'): - self.transport.unregisterProducer() - - def rawDataReceived(self, data): - """ - Read raw data, until the quantity specified by a previous 'len' line is - reached. - """ - data, rest = data[:self.length], data[self.length:] - self.length = self.length - len(data) - self.received[-1] = self.received[-1] + data - if self.length == 0: - self.setLineMode(rest) - - def lineLengthExceeded(self, line): - """ - Adjust line mode when long lines received. - """ - if len(line) > self.MAX_LENGTH + 1: - self.setLineMode(line[self.MAX_LENGTH + 1:]) - - -class LineOnlyTester(basic.LineOnlyReceiver): - """ - A buffering line only receiver. - """ - delimiter = '\n' - MAX_LENGTH = 64 - - def connectionMade(self): - """ - Create/clean data received on connection. - """ - self.received = [] - - def lineReceived(self, line): - """ - Save received data. - """ - self.received.append(line) - -class WireTestCase(unittest.TestCase): - """ - Test wire protocols. - """ - def testEcho(self): - """ - Test wire.Echo protocol: send some data and check it send it back. - """ - t = StringIOWithoutClosing() - a = wire.Echo() - a.makeConnection(protocol.FileWrapper(t)) - a.dataReceived("hello") - a.dataReceived("world") - a.dataReceived("how") - a.dataReceived("are") - a.dataReceived("you") - self.failUnlessEqual(t.getvalue(), "helloworldhowareyou") - - def testWho(self): - """ - Test wire.Who protocol. - """ - t = StringIOWithoutClosing() - a = wire.Who() - a.makeConnection(protocol.FileWrapper(t)) - self.failUnlessEqual(t.getvalue(), "root\r\n") - - def testQOTD(self): - """ - Test wire.QOTD protocol. - """ - t = StringIOWithoutClosing() - a = wire.QOTD() - a.makeConnection(protocol.FileWrapper(t)) - self.failUnlessEqual(t.getvalue(), - "An apple a day keeps the doctor away.\r\n") - - def testDiscard(self): - """ - Test wire.Discard protocol. - """ - t = StringIOWithoutClosing() - a = wire.Discard() - a.makeConnection(protocol.FileWrapper(t)) - a.dataReceived("hello") - a.dataReceived("world") - a.dataReceived("how") - a.dataReceived("are") - a.dataReceived("you") - self.failUnlessEqual(t.getvalue(), "") - -class LineReceiverTestCase(unittest.TestCase): - """ - Test LineReceiver, using the C{LineTester} wrapper. - """ - buffer = '''\ -len 10 - -0123456789len 5 - -1234 -len 20 -foo 123 - -0123456789 -012345678len 0 -foo 5 - -1234567890123456789012345678901234567890123456789012345678901234567890 -len 1 - -a''' - - output = ['len 10', '0123456789', 'len 5', '1234\n', - 'len 20', 'foo 123', '0123456789\n012345678', - 'len 0', 'foo 5', '', '67890', 'len 1', 'a'] - - def testBuffer(self): - """ - Test buffering for different packet size, checking received matches - expected data. - """ - for packet_size in range(1, 10): - t = StringIOWithoutClosing() - a = LineTester() - a.makeConnection(protocol.FileWrapper(t)) - for i in range(len(self.buffer)/packet_size + 1): - s = self.buffer[i*packet_size:(i+1)*packet_size] - a.dataReceived(s) - self.failUnlessEqual(self.output, a.received) - - - pause_buf = 'twiddle1\ntwiddle2\npause\ntwiddle3\n' - - pause_output1 = ['twiddle1', 'twiddle2', 'pause'] - pause_output2 = pause_output1+['twiddle3'] - - def testPausing(self): - """ - Test pause inside data receiving. It uses fake clock to see if - pausing/resuming work. - """ - for packet_size in range(1, 10): - t = StringIOWithoutClosing() - clock = task.Clock() - a = LineTester(clock) - a.makeConnection(protocol.FileWrapper(t)) - for i in range(len(self.pause_buf)/packet_size + 1): - s = self.pause_buf[i*packet_size:(i+1)*packet_size] - a.dataReceived(s) - self.failUnlessEqual(self.pause_output1, a.received) - clock.advance(0) - self.failUnlessEqual(self.pause_output2, a.received) - - rawpause_buf = 'twiddle1\ntwiddle2\nlen 5\nrawpause\n12345twiddle3\n' - - rawpause_output1 = ['twiddle1', 'twiddle2', 'len 5', 'rawpause', ''] - rawpause_output2 = ['twiddle1', 'twiddle2', 'len 5', 'rawpause', '12345', - 'twiddle3'] - - def testRawPausing(self): - """ - Test pause inside raw date receiving. - """ - for packet_size in range(1, 10): - t = StringIOWithoutClosing() - clock = task.Clock() - a = LineTester(clock) - a.makeConnection(protocol.FileWrapper(t)) - for i in range(len(self.rawpause_buf)/packet_size + 1): - s = self.rawpause_buf[i*packet_size:(i+1)*packet_size] - a.dataReceived(s) - self.failUnlessEqual(self.rawpause_output1, a.received) - clock.advance(0) - self.failUnlessEqual(self.rawpause_output2, a.received) - - stop_buf = 'twiddle1\ntwiddle2\nstop\nmore\nstuff\n' - - stop_output = ['twiddle1', 'twiddle2', 'stop'] - - def testStopProducing(self): - """ - Test stop inside producing. - """ - for packet_size in range(1, 10): - t = StringIOWithoutClosing() - a = LineTester() - a.makeConnection(protocol.FileWrapper(t)) - for i in range(len(self.stop_buf)/packet_size + 1): - s = self.stop_buf[i*packet_size:(i+1)*packet_size] - a.dataReceived(s) - self.failUnlessEqual(self.stop_output, a.received) - - - def testLineReceiverAsProducer(self): - """ - Test produce/unproduce in receiving. - """ - a = LineTester() - t = StringIOWithoutClosing() - a.makeConnection(protocol.FileWrapper(t)) - a.dataReceived('produce\nhello world\nunproduce\ngoodbye\n') - self.assertEquals(a.received, - ['produce', 'hello world', 'unproduce', 'goodbye']) - - -class LineOnlyReceiverTestCase(unittest.TestCase): - """ - Test line only receiveer. - """ - buffer = """foo - bleakness - desolation - plastic forks - """ - - def testBuffer(self): - """ - Test buffering over line protocol: data received should match buffer. - """ - t = StringIOWithoutClosing() - a = LineOnlyTester() - a.makeConnection(protocol.FileWrapper(t)) - for c in self.buffer: - a.dataReceived(c) - self.failUnlessEqual(a.received, self.buffer.split('\n')[:-1]) - - def testLineTooLong(self): - """ - Test sending a line too long: it should close the connection. - """ - t = StringIOWithoutClosing() - a = LineOnlyTester() - a.makeConnection(protocol.FileWrapper(t)) - res = a.dataReceived('x'*200) - self.assertTrue(isinstance(res, error.ConnectionLost)) - - - -class TestMixin: - - def connectionMade(self): - self.received = [] - - def stringReceived(self, s): - self.received.append(s) - - MAX_LENGTH = 50 - closed = 0 - - def connectionLost(self, reason): - self.closed = 1 - - -class TestNetstring(TestMixin, basic.NetstringReceiver): - pass - - -class LPTestCaseMixin: - - illegalStrings = [] - protocol = None - - def getProtocol(self): - t = StringIOWithoutClosing() - a = self.protocol() - a.makeConnection(protocol.FileWrapper(t)) - return a - - def test_illegal(self): - """ - Assert that illegal strings cause the transport to be closed. - """ - for s in self.illegalStrings: - r = self.getProtocol() - for c in s: - r.dataReceived(c) - self.assertEquals(r.transport.closed, 1) - - -class NetstringReceiverTestCase(unittest.TestCase, LPTestCaseMixin): - - strings = ['hello', 'world', 'how', 'are', 'you123', ':today', "a"*515] - - illegalStrings = [ - '9999999999999999999999', 'abc', '4:abcde', - '51:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab,',] - - protocol = TestNetstring - - def testBuffer(self): - for packet_size in range(1, 10): - t = StringIOWithoutClosing() - a = TestNetstring() - a.MAX_LENGTH = 699 - a.makeConnection(protocol.FileWrapper(t)) - for s in self.strings: - a.sendString(s) - out = t.getvalue() - for i in range(len(out)/packet_size + 1): - s = out[i*packet_size:(i+1)*packet_size] - if s: - a.dataReceived(s) - self.assertEquals(a.received, self.strings) - - -class IntNTestCaseMixin(LPTestCaseMixin): - """ - TestCase mixin for int-prefixed protocols. - """ - - protocol = None - strings = None - illegalStrings = None - partialStrings = None - - def test_receive(self): - """ - Test receiving data find the same data send. - """ - r = self.getProtocol() - for s in self.strings: - for c in struct.pack(self.protocol.structFormat,len(s)) + s: - r.dataReceived(c) - self.assertEquals(r.received, self.strings) - - def test_partial(self): - """ - Send partial data, nothing should be definitely received. - """ - for s in self.partialStrings: - r = self.getProtocol() - for c in s: - r.dataReceived(c) - self.assertEquals(r.received, []) - - def test_send(self): - """ - Test sending data over protocol. - """ - r = self.getProtocol() - r.sendString("b" * 16) - self.assertEquals(r.transport.file.getvalue(), - struct.pack(self.protocol.structFormat, 16) + "b" * 16) - - -class TestInt32(TestMixin, basic.Int32StringReceiver): - """ - A L{basic.Int32StringReceiver} storing received strings in an array. - - @ivar received: array holding received strings. - """ - - -class Int32TestCase(unittest.TestCase, IntNTestCaseMixin): - """ - Test case for int32-prefixed protocol - """ - protocol = TestInt32 - strings = ["a", "b" * 16] - illegalStrings = ["\x10\x00\x00\x00aaaaaa"] - partialStrings = ["\x00\x00\x00", "hello there", ""] - - def test_data(self): - """ - Test specific behavior of the 32-bits length. - """ - r = self.getProtocol() - r.sendString("foo") - self.assertEquals(r.transport.file.getvalue(), "\x00\x00\x00\x03foo") - r.dataReceived("\x00\x00\x00\x04ubar") - self.assertEquals(r.received, ["ubar"]) - - -class TestInt16(TestMixin, basic.Int16StringReceiver): - """ - A L{basic.Int16StringReceiver} storing received strings in an array. - - @ivar received: array holding received strings. - """ - - -class Int16TestCase(unittest.TestCase, IntNTestCaseMixin): - """ - Test case for int16-prefixed protocol - """ - protocol = TestInt16 - strings = ["a", "b" * 16] - illegalStrings = ["\x10\x00aaaaaa"] - partialStrings = ["\x00", "hello there", ""] - - def test_data(self): - """ - Test specific behavior of the 16-bits length. - """ - r = self.getProtocol() - r.sendString("foo") - self.assertEquals(r.transport.file.getvalue(), "\x00\x03foo") - r.dataReceived("\x00\x04ubar") - self.assertEquals(r.received, ["ubar"]) - - def test_tooLongSend(self): - """ - Send too much data: that should cause an error. - """ - r = self.getProtocol() - tooSend = "b" * (2**(r.prefixLength*8) + 1) - self.assertRaises(AssertionError, r.sendString, tooSend) - - -class TestInt8(TestMixin, basic.Int8StringReceiver): - """ - A L{basic.Int8StringReceiver} storing received strings in an array. - - @ivar received: array holding received strings. - """ - - -class Int8TestCase(unittest.TestCase, IntNTestCaseMixin): - """ - Test case for int8-prefixed protocol - """ - protocol = TestInt8 - strings = ["a", "b" * 16] - illegalStrings = ["\x00\x00aaaaaa"] - partialStrings = ["\x08", "dzadz", ""] - - def test_data(self): - """ - Test specific behavior of the 8-bits length. - """ - r = self.getProtocol() - r.sendString("foo") - self.assertEquals(r.transport.file.getvalue(), "\x03foo") - r.dataReceived("\x04ubar") - self.assertEquals(r.received, ["ubar"]) - - def test_tooLongSend(self): - """ - Send too much data: that should cause an error. - """ - r = self.getProtocol() - tooSend = "b" * (2**(r.prefixLength*8) + 1) - self.assertRaises(AssertionError, r.sendString, tooSend) - - -class OnlyProducerTransport(object): - # Transport which isn't really a transport, just looks like one to - # someone not looking very hard. - - paused = False - disconnecting = False - - def __init__(self): - self.data = [] - - def pauseProducing(self): - self.paused = True - - def resumeProducing(self): - self.paused = False - - def write(self, bytes): - self.data.append(bytes) - - -class ConsumingProtocol(basic.LineReceiver): - # Protocol that really, really doesn't want any more bytes. - - def lineReceived(self, line): - self.transport.write(line) - self.pauseProducing() - - -class ProducerTestCase(unittest.TestCase): - def testPauseResume(self): - p = ConsumingProtocol() - t = OnlyProducerTransport() - p.makeConnection(t) - - p.dataReceived('hello, ') - self.failIf(t.data) - self.failIf(t.paused) - self.failIf(p.paused) - - p.dataReceived('world\r\n') - - self.assertEquals(t.data, ['hello, world']) - self.failUnless(t.paused) - self.failUnless(p.paused) - - p.resumeProducing() - - self.failIf(t.paused) - self.failIf(p.paused) - - p.dataReceived('hello\r\nworld\r\n') - - self.assertEquals(t.data, ['hello, world', 'hello']) - self.failUnless(t.paused) - self.failUnless(p.paused) - - p.resumeProducing() - p.dataReceived('goodbye\r\n') - - self.assertEquals(t.data, ['hello, world', 'hello', 'world']) - self.failUnless(t.paused) - self.failUnless(p.paused) - - p.resumeProducing() - - self.assertEquals(t.data, ['hello, world', 'hello', 'world', 'goodbye']) - self.failUnless(t.paused) - self.failUnless(p.paused) - - p.resumeProducing() - - self.assertEquals(t.data, ['hello, world', 'hello', 'world', 'goodbye']) - self.failIf(t.paused) - self.failIf(p.paused) - - - -class TestableProxyClientFactory(portforward.ProxyClientFactory): - """ - Test proxy client factory that keeps the last created protocol instance. - - @ivar protoInstance: the last instance of the protocol. - @type protoInstance: L{portforward.ProxyClient} - """ - - def buildProtocol(self, addr): - """ - Create the protocol instance and keeps track of it. - """ - proto = portforward.ProxyClientFactory.buildProtocol(self, addr) - self.protoInstance = proto - return proto - - - -class TestableProxyFactory(portforward.ProxyFactory): - """ - Test proxy factory that keeps the last created protocol instance. - - @ivar protoInstance: the last instance of the protocol. - @type protoInstance: L{portforward.ProxyServer} - - @ivar clientFactoryInstance: client factory used by C{protoInstance} to - create forward connections. - @type clientFactoryInstance: L{TestableProxyClientFactory} - """ - - def buildProtocol(self, addr): - """ - Create the protocol instance, keeps track of it, and makes it use - C{clientFactoryInstance} as client factory. - """ - proto = portforward.ProxyFactory.buildProtocol(self, addr) - self.clientFactoryInstance = TestableProxyClientFactory() - # Force the use of this specific instance - proto.clientProtocolFactory = lambda: self.clientFactoryInstance - self.protoInstance = proto - return proto - - - -class Portforwarding(unittest.TestCase): - """ - Test port forwarding. - """ - - def setUp(self): - self.serverProtocol = wire.Echo() - self.clientProtocol = protocol.Protocol() - self.openPorts = [] - - - def tearDown(self): - try: - self.proxyServerFactory.protoInstance.transport.loseConnection() - except AttributeError: - pass - try: - self.proxyServerFactory.clientFactoryInstance.protoInstance.transport.loseConnection() - except AttributeError: - pass - try: - self.clientProtocol.transport.loseConnection() - except AttributeError: - pass - try: - self.serverProtocol.transport.loseConnection() - except AttributeError: - pass - return defer.gatherResults( - [defer.maybeDeferred(p.stopListening) for p in self.openPorts]) - - - def test_portforward(self): - """ - Test port forwarding through Echo protocol. - """ - realServerFactory = protocol.ServerFactory() - realServerFactory.protocol = lambda: self.serverProtocol - realServerPort = reactor.listenTCP(0, realServerFactory, - interface='127.0.0.1') - self.openPorts.append(realServerPort) - self.proxyServerFactory = TestableProxyFactory('127.0.0.1', - realServerPort.getHost().port) - proxyServerPort = reactor.listenTCP(0, self.proxyServerFactory, - interface='127.0.0.1') - self.openPorts.append(proxyServerPort) - - nBytes = 1000 - received = [] - d = defer.Deferred() - def testDataReceived(data): - received.extend(data) - if len(received) >= nBytes: - self.assertEquals(''.join(received), 'x' * nBytes) - d.callback(None) - self.clientProtocol.dataReceived = testDataReceived - - def testConnectionMade(): - self.clientProtocol.transport.write('x' * nBytes) - self.clientProtocol.connectionMade = testConnectionMade - - clientFactory = protocol.ClientFactory() - clientFactory.protocol = lambda: self.clientProtocol - - reactor.connectTCP( - '127.0.0.1', proxyServerPort.getHost().port, clientFactory) - - return d - - - -class StringTransportTestCase(unittest.TestCase): - """ - Test L{proto_helpers.StringTransport} helper behaviour. - """ - - def test_noUnicode(self): - """ - Test that L{proto_helpers.StringTransport} doesn't accept unicode data. - """ - s = proto_helpers.StringTransport() - self.assertRaises(TypeError, s.write, u'foo') diff --git a/tools/buildbot/pylibs/twisted/test/test_randbytes.py b/tools/buildbot/pylibs/twisted/test/test_randbytes.py deleted file mode 100644 index d62504f..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_randbytes.py +++ /dev/null @@ -1,178 +0,0 @@ -# Copyright (c) 2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test cases for L{twisted.python.randbytes}. -""" - -import os, sys - -from twisted.trial import unittest -from twisted.python import randbytes - -try: - from Crypto.Util import randpool -except ImportError: - randpool = None - - - -class SecureRandomTestCaseBase(object): - """ - Base class for secureRandom test cases. - """ - - def _check(self, source): - """ - The given random bytes source should return the number of bytes - requested each time it is called and should probably not return the - same bytes on two consecutive calls (although this is a perfectly - legitimate occurrence and rejecting it may generate a spurious failure - -- maybe we'll get lucky and the heat death with come first). - """ - for nbytes in range(17, 25): - s = source(nbytes) - self.assertEquals(len(s), nbytes) - s2 = source(nbytes) - self.assertEquals(len(s2), nbytes) - # This is crude but hey - self.assertNotEquals(s2, s) - - - -class SecureRandomTestCase(SecureRandomTestCaseBase, unittest.TestCase): - """ - Test secureRandom under normal conditions. - """ - - def test_normal(self): - """ - L{randbytes.secureRandom} should return a string of the requested - length and make some effort to make its result otherwise unpredictable. - """ - self._check(randbytes.secureRandom) - - - -class ConditionalSecureRandomTestCase(SecureRandomTestCaseBase, - unittest.TestCase): - """ - Test random sources one by one, then remove it to. - """ - - def setUp(self): - """ - Create a L{randbytes.RandomFactory} to use in the tests. - """ - self.factory = randbytes.RandomFactory() - - - def errorFactory(self, nbytes): - """ - A factory raising an error when a source is not available. - """ - raise randbytes.SourceNotAvailable() - - - def test_osUrandom(self): - """ - L{RandomFactory._osUrandom} should work as a random source whenever - L{os.urandom} is available. - """ - try: - self._check(self.factory._osUrandom) - except randbytes.SourceNotAvailable: - # Not available on Python 2.3 - self.assertTrue(sys.version_info < (2, 4)) - - - def test_fileUrandom(self): - """ - L{RandomFactory._fileUrandom} should work as a random source whenever - C{/dev/urandom} is available. - """ - try: - self._check(self.factory._fileUrandom) - except randbytes.SourceNotAvailable: - # The test should only fail in /dev/urandom doesn't exist - self.assertFalse(os.path.exists('/dev/urandom')) - - - def test_cryptoRandom(self): - """ - L{RandomFactory._cryptoRandom} should work as a random source whenever - L{PyCrypto} is installed. - """ - try: - self._check(self.factory._cryptoRandom) - except randbytes.SourceNotAvailable: - # It fails if PyCrypto is not here - self.assertIdentical(randpool, None) - - - def test_withoutOsUrandom(self): - """ - If L{os.urandom} is not available but L{PyCrypto} is, - L{RandomFactory.secureRandom} should still work as a random source. - """ - self.factory._osUrandom = self.errorFactory - self._check(self.factory.secureRandom) - - if randpool is None: - test_withoutOsUrandom.skip = "PyCrypto not available" - - - def test_withoutOsAndFileUrandom(self): - """ - Remove C{os.urandom} and /dev/urandom read. - """ - self.factory._osUrandom = self.errorFactory - self.factory._fileUrandom = self.errorFactory - self._check(self.factory.secureRandom) - - if randpool is None: - test_withoutOsAndFileUrandom.skip = "PyCrypto not available" - - - def test_withoutAnything(self): - """ - Remove all secure sources and assert it raises a failure. Then try the - fallback parameter. - """ - self.factory._osUrandom = self.errorFactory - self.factory._fileUrandom = self.errorFactory - self.factory._cryptoRandom = self.errorFactory - self.assertRaises(randbytes.SecureRandomNotAvailable, - self.factory.secureRandom, 18) - def wrapper(): - return self.factory.secureRandom(18, fallback=True) - s = self.assertWarns( - RuntimeWarning, - "Neither PyCrypto nor urandom available - " - "proceeding with non-cryptographically secure random source", - __file__, - wrapper) - self.assertEquals(len(s), 18) - - - -class RandomTestCaseBase(SecureRandomTestCaseBase, unittest.TestCase): - """ - 'Normal' random test cases. - """ - - def test_normal(self): - """ - Test basic case. - """ - self._check(randbytes.insecureRandom) - - - def test_withoutGetrandbits(self): - """ - Test C{insecureRandom} without C{random.getrandbits}. - """ - factory = randbytes.RandomFactory() - factory.getrandbits = None - self._check(factory.insecureRandom) - diff --git a/tools/buildbot/pylibs/twisted/test/test_rebuild.py b/tools/buildbot/pylibs/twisted/test/test_rebuild.py deleted file mode 100644 index c96853a..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_rebuild.py +++ /dev/null @@ -1,217 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -import sys, os -import new - -from twisted.trial import unittest -from twisted.python import rebuild - -import crash_test_dummy -f = crash_test_dummy.foo - -class Foo: pass -class Bar(Foo): pass -class Baz(object): pass -class Buz(Bar, Baz): pass - -class RebuildTestCase(unittest.TestCase): - """ - Simple testcase for rebuilding, to at least exercise the code. - """ - def setUp(self): - self.libPath = self.mktemp() - os.mkdir(self.libPath) - self.fakelibPath = os.path.join(self.libPath, 'twisted_rebuild_fakelib') - os.mkdir(self.fakelibPath) - file(os.path.join(self.fakelibPath, '__init__.py'), 'w').close() - sys.path.insert(0, self.libPath) - - def tearDown(self): - sys.path.remove(self.libPath) - - def testFileRebuild(self): - from twisted.python.util import sibpath - import shutil, time - shutil.copyfile(sibpath(__file__, "myrebuilder1.py"), - os.path.join(self.fakelibPath, "myrebuilder.py")) - from twisted_rebuild_fakelib import myrebuilder - a = myrebuilder.A() - try: - object - except NameError: - pass - else: - from twisted.test import test_rebuild - b = myrebuilder.B() - class C(myrebuilder.B): - pass - test_rebuild.C = C - c = C() - i = myrebuilder.Inherit() - self.assertEquals(a.a(), 'a') - # necessary because the file has not "changed" if a second has not gone - # by in unix. This sucks, but it's not often that you'll be doing more - # than one reload per second. - time.sleep(1.1) - shutil.copyfile(sibpath(__file__, "myrebuilder2.py"), - os.path.join(self.fakelibPath, "myrebuilder.py")) - rebuild.rebuild(myrebuilder) - try: - object - except NameError: - pass - else: - b2 = myrebuilder.B() - self.assertEquals(b2.b(), 'c') - self.assertEquals(b.b(), 'c') - self.assertEquals(i.a(), 'd') - self.assertEquals(a.a(), 'b') - # more work to be done on new-style classes - # self.assertEquals(c.b(), 'c') - - def testRebuild(self): - """ - Rebuilding an unchanged module. - """ - # This test would actually pass if rebuild was a no-op, but it - # ensures rebuild doesn't break stuff while being a less - # complex test than testFileRebuild. - - x = crash_test_dummy.X('a') - - rebuild.rebuild(crash_test_dummy, doLog=False) - # Instance rebuilding is triggered by attribute access. - x.do() - self.failUnlessIdentical(x.__class__, crash_test_dummy.X) - - self.failUnlessIdentical(f, crash_test_dummy.foo) - - def testComponentInteraction(self): - x = crash_test_dummy.XComponent() - x.setAdapter(crash_test_dummy.IX, crash_test_dummy.XA) - oldComponent = x.getComponent(crash_test_dummy.IX) - rebuild.rebuild(crash_test_dummy, 0) - newComponent = x.getComponent(crash_test_dummy.IX) - - newComponent.method() - - self.assertEquals(newComponent.__class__, crash_test_dummy.XA) - - # Test that a duplicate registerAdapter is not allowed - from twisted.python import components - self.failUnlessRaises(ValueError, components.registerAdapter, - crash_test_dummy.XA, crash_test_dummy.X, - crash_test_dummy.IX) - - def testUpdateInstance(self): - global Foo, Buz - - b = Buz() - - class Foo: - def foo(self): - pass - class Buz(Bar, Baz): - x = 10 - - rebuild.updateInstance(b) - assert hasattr(b, 'foo'), "Missing method on rebuilt instance" - assert hasattr(b, 'x'), "Missing class attribute on rebuilt instance" - - def testBananaInteraction(self): - from twisted.python import rebuild - from twisted.spread import banana - rebuild.latestClass(banana.Banana) - - - -class NewStyleTestCase(unittest.TestCase): - """ - Tests for rebuilding new-style classes of various sorts. - """ - def setUp(self): - self.m = new.module('whipping') - sys.modules['whipping'] = self.m - - - def tearDown(self): - del sys.modules['whipping'] - del self.m - - - def test_slots(self): - """ - Try to rebuild a new style class with slots defined. - """ - classDefinition = ( - "class SlottedClass(object):\n" - " __slots__ = ['a']\n") - - exec classDefinition in self.m.__dict__ - inst = self.m.SlottedClass() - inst.a = 7 - exec classDefinition in self.m.__dict__ - rebuild.updateInstance(inst) - self.assertEqual(inst.a, 7) - self.assertIdentical(type(inst), self.m.SlottedClass) - - if sys.version_info < (2, 6): - test_slots.skip = "__class__ assignment for class with slots is only available starting Python 2.6" - - - def test_errorSlots(self): - """ - Try to rebuild a new style class with slots defined: this should fail. - """ - classDefinition = ( - "class SlottedClass(object):\n" - " __slots__ = ['a']\n") - - exec classDefinition in self.m.__dict__ - inst = self.m.SlottedClass() - inst.a = 7 - exec classDefinition in self.m.__dict__ - self.assertRaises(rebuild.RebuildError, rebuild.updateInstance, inst) - - if sys.version_info >= (2, 6): - test_errorSlots.skip = "__class__ assignment for class with slots should work starting Python 2.6" - - - def test_typeSubclass(self): - """ - Try to rebuild a base type subclass. - """ - classDefinition = ( - "class ListSubclass(list):\n" - " pass\n") - - exec classDefinition in self.m.__dict__ - inst = self.m.ListSubclass() - inst.append(2) - exec classDefinition in self.m.__dict__ - rebuild.updateInstance(inst) - self.assertEqual(inst[0], 2) - self.assertIdentical(type(inst), self.m.ListSubclass) - - - def test_instanceSlots(self): - """ - Test that when rebuilding an instance with a __slots__ attribute, it - fails accurately instead of giving a L{rebuild.RebuildError}. - """ - classDefinition = ( - "class NotSlottedClass(object):\n" - " pass\n") - - exec classDefinition in self.m.__dict__ - inst = self.m.NotSlottedClass() - inst.__slots__ = ['a'] - classDefinition = ( - "class NotSlottedClass:\n" - " pass\n") - exec classDefinition in self.m.__dict__ - # Moving from new-style class to old-style should fail. - self.assertRaises(TypeError, rebuild.updateInstance, inst) - diff --git a/tools/buildbot/pylibs/twisted/test/test_reflect.py b/tools/buildbot/pylibs/twisted/test/test_reflect.py deleted file mode 100644 index 5e970b8..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_reflect.py +++ /dev/null @@ -1,491 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Test cases for twisted.reflect module. -""" - -import weakref, os -from ihooks import ModuleImporter - -try: - from collections import deque -except ImportError: - deque = None - -# Twisted Imports -from twisted.trial import unittest -from twisted.python import reflect - - - -class SettableTest(unittest.TestCase): - def setUp(self): - self.setter = reflect.Settable() - - def tearDown(self): - del self.setter - - def testSet(self): - self.setter(a=1, b=2) - self.failUnlessEqual(self.setter.a, 1) - self.failUnlessEqual(self.setter.b, 2) - - -class AccessorTester(reflect.Accessor): - def set_x(self, x): - self.y = x - self.reallySet('x',x) - - def get_z(self): - self.q = 1 - return 1 - - def del_z(self): - self.reallyDel("q") - - -class AccessorTest(unittest.TestCase): - def setUp(self): - self.tester = AccessorTester() - - def testSet(self): - self.tester.x = 1 - self.failUnlessEqual(self.tester.x, 1) - self.failUnlessEqual(self.tester.y, 1) - - def testGet(self): - self.failUnlessEqual(self.tester.z, 1) - self.failUnlessEqual(self.tester.q, 1) - - def testDel(self): - self.tester.z - self.failUnlessEqual(self.tester.q, 1) - del self.tester.z - self.failUnlessEqual(hasattr(self.tester, "q"), 0) - self.tester.x = 1 - del self.tester.x - self.failUnlessEqual(hasattr(self.tester, "x"), 0) - - -class LookupsTestCase(unittest.TestCase): - """ - Tests for L{namedClass}, L{namedModule}, and L{namedAny}. - """ - - def test_namedClassLookup(self): - """ - L{namedClass} should return the class object for the name it is passed. - """ - self.assertIdentical( - reflect.namedClass("twisted.python.reflect.Summer"), - reflect.Summer) - - - def test_namedModuleLookup(self): - """ - L{namedModule} should return the module object for the name it is - passed. - """ - self.assertIdentical( - reflect.namedModule("twisted.python.reflect"), reflect) - - - def test_namedAnyPackageLookup(self): - """ - L{namedAny} should return the package object for the name it is passed. - """ - import twisted.python - self.assertIdentical( - reflect.namedAny("twisted.python"), twisted.python) - - def test_namedAnyModuleLookup(self): - """ - L{namedAny} should return the module object for the name it is passed. - """ - self.assertIdentical( - reflect.namedAny("twisted.python.reflect"), reflect) - - - def test_namedAnyClassLookup(self): - """ - L{namedAny} should return the class object for the name it is passed. - """ - self.assertIdentical( - reflect.namedAny("twisted.python.reflect.Summer"), reflect.Summer) - - - def test_namedAnyAttributeLookup(self): - """ - L{namedAny} should return the object an attribute of a non-module, - non-package object is bound to for the name it is passed. - """ - # Note - not assertEqual because unbound method lookup creates a new - # object every time. This is a foolishness of Python's object - # implementation, not a bug in Twisted. - self.assertEqual( - reflect.namedAny("twisted.python.reflect.Summer.reallySet"), - reflect.Summer.reallySet) - - - def test_namedAnySecondAttributeLookup(self): - """ - L{namedAny} should return the object an attribute of an object which - itself was an attribute of a non-module, non-package object is bound to - for the name it is passed. - """ - self.assertIdentical( - reflect.namedAny( - "twisted.python.reflect.Summer.reallySet.__doc__"), - reflect.Summer.reallySet.__doc__) - - - def test_importExceptions(self): - """ - Exceptions raised by modules which L{namedAny} causes to be imported - should pass through L{namedAny} to the caller. - """ - self.assertRaises( - ZeroDivisionError, - reflect.namedAny, "twisted.test.reflect_helper_ZDE") - # Make sure that this behavior is *consistent* for 2.3, where there is - # no post-failed-import cleanup - self.assertRaises( - ZeroDivisionError, - reflect.namedAny, "twisted.test.reflect_helper_ZDE") - self.assertRaises( - ValueError, - reflect.namedAny, "twisted.test.reflect_helper_VE") - # Modules which themselves raise ImportError when imported should result in an ImportError - self.assertRaises( - ImportError, - reflect.namedAny, "twisted.test.reflect_helper_IE") - - - def test_attributeExceptions(self): - """ - If segments on the end of a fully-qualified Python name represents - attributes which aren't actually present on the object represented by - the earlier segments, L{namedAny} should raise an L{AttributeError}. - """ - self.assertRaises( - AttributeError, - reflect.namedAny, "twisted.nosuchmoduleintheworld") - # ImportError behaves somewhat differently between "import - # extant.nonextant" and "import extant.nonextant.nonextant", so test - # the latter as well. - self.assertRaises( - AttributeError, - reflect.namedAny, "twisted.nosuch.modulein.theworld") - self.assertRaises( - AttributeError, - reflect.namedAny, "twisted.python.reflect.Summer.nosuchattributeintheworld") - - - def test_invalidNames(self): - """ - Passing a name which isn't a fully-qualified Python name to L{namedAny} - should result in a L{ValueError}. - """ - # Finally, invalid module names should raise a ValueError - self.assertRaises( - ValueError, - reflect.namedAny, "") - self.assertRaises( - ValueError, - reflect.namedAny, "12345") - self.assertRaises( - ValueError, - reflect.namedAny, "@#$@(#.!@(#!@#") - # This case is kind of stupid and is mostly a historical accident. - self.assertRaises( - ValueError, - reflect.namedAny, "tcelfer.nohtyp.detsiwt") - - - -class ImportHooksLookupTests(LookupsTestCase): - """ - Tests for lookup methods in the presence of L{ihooks}-style import hooks. - Runs all of the tests from L{LookupsTestCase} after installing a custom - import hook. - """ - def setUp(self): - """ - Perturb the normal import behavior subtly by installing an import - hook. No custom behavior is provided, but this adds some extra - frames to the call stack, which L{namedAny} must be able to account - for. - """ - self.importer = ModuleImporter() - self.importer.install() - - - def tearDown(self): - """ - Uninstall the custom import hook. - """ - self.importer.uninstall() - - - -class ObjectGrep(unittest.TestCase): - def test_dictionary(self): - """ - Test references search through a dictionnary, as a key or as a value. - """ - o = object() - d1 = {None: o} - d2 = {o: None} - - self.assertIn("[None]", reflect.objgrep(d1, o, reflect.isSame)) - self.assertIn("{None}", reflect.objgrep(d2, o, reflect.isSame)) - - def test_list(self): - """ - Test references search through a list. - """ - o = object() - L = [None, o] - - self.assertIn("[1]", reflect.objgrep(L, o, reflect.isSame)) - - def test_tuple(self): - """ - Test references search through a tuple. - """ - o = object() - T = (o, None) - - self.assertIn("[0]", reflect.objgrep(T, o, reflect.isSame)) - - def test_instance(self): - """ - Test references search through an object attribute. - """ - class Dummy: - pass - o = object() - d = Dummy() - d.o = o - - self.assertIn(".o", reflect.objgrep(d, o, reflect.isSame)) - - def test_weakref(self): - """ - Test references search through a weakref object. - """ - class Dummy: - pass - o = Dummy() - w1 = weakref.ref(o) - - self.assertIn("()", reflect.objgrep(w1, o, reflect.isSame)) - - def test_boundMethod(self): - """ - Test references search through method special attributes. - """ - class Dummy: - def dummy(self): - pass - o = Dummy() - m = o.dummy - - self.assertIn(".im_self", reflect.objgrep(m, m.im_self, reflect.isSame)) - self.assertIn(".im_class", reflect.objgrep(m, m.im_class, reflect.isSame)) - self.assertIn(".im_func", reflect.objgrep(m, m.im_func, reflect.isSame)) - - def test_everything(self): - """ - Test references search using complex set of objects. - """ - class Dummy: - def method(self): - pass - - o = Dummy() - D1 = {(): "baz", None: "Quux", o: "Foosh"} - L = [None, (), D1, 3] - T = (L, {}, Dummy()) - D2 = {0: "foo", 1: "bar", 2: T} - i = Dummy() - i.attr = D2 - m = i.method - w = weakref.ref(m) - - self.assertIn("().im_self.attr[2][0][2]{'Foosh'}", reflect.objgrep(w, o, reflect.isSame)) - - def test_depthLimit(self): - """ - Test the depth of references search. - """ - a = [] - b = [a] - c = [a, b] - d = [a, c] - - self.assertEquals(['[0]'], reflect.objgrep(d, a, reflect.isSame, maxDepth=1)) - self.assertEquals(['[0]', '[1][0]'], reflect.objgrep(d, a, reflect.isSame, maxDepth=2)) - self.assertEquals(['[0]', '[1][0]', '[1][1][0]'], reflect.objgrep(d, a, reflect.isSame, maxDepth=3)) - - def test_deque(self): - """ - Test references search through a deque object. Only for Python > 2.3. - """ - o = object() - D = deque() - D.append(None) - D.append(o) - - self.assertIn("[1]", reflect.objgrep(D, o, reflect.isSame)) - - if deque is None: - test_deque.skip = "Deque not available" - - -class GetClass(unittest.TestCase): - def testOld(self): - class OldClass: - pass - old = OldClass() - self.assertIn(reflect.getClass(OldClass).__name__, ('class', 'classobj')) - self.assertEquals(reflect.getClass(old).__name__, 'OldClass') - - def testNew(self): - class NewClass(object): - pass - new = NewClass() - self.assertEquals(reflect.getClass(NewClass).__name__, 'type') - self.assertEquals(reflect.getClass(new).__name__, 'NewClass') - -class Breakable(object): - - breakRepr = False - breakStr = False - - def __str__(self): - if self.breakStr: - raise self - else: - return '' - - def __repr__(self): - if self.breakRepr: - raise self - else: - return 'Breakable()' - -class BrokenType(Breakable, type): - breakName = False - def get___name__(self): - if self.breakName: - raise RuntimeError("no name") - return 'BrokenType' - __name__ = property(get___name__) - -class BTBase(Breakable): - __metaclass__ = BrokenType - breakRepr = True - breakStr = True - - -class NoClassAttr(object): - __class__ = property(lambda x: x.not_class) - -class SafeRepr(unittest.TestCase): - - def testWorkingRepr(self): - x = [1,2,3] - self.assertEquals(reflect.safe_repr(x), repr(x)) - - def testBrokenRepr(self): - b = Breakable() - b.breakRepr = True - reflect.safe_repr(b) - - def testBrokenStr(self): - b = Breakable() - b.breakStr = True - reflect.safe_repr(b) - - def testBrokenClassRepr(self): - class X(BTBase): - breakRepr = True - reflect.safe_repr(X) - reflect.safe_repr(X()) - - def testBrokenClassStr(self): - class X(BTBase): - breakStr = True - reflect.safe_repr(X) - reflect.safe_repr(X()) - - def testBroken__Class__Attr(self): - reflect.safe_repr(NoClassAttr()) - - def testBroken__Class__Name__Attr(self): - class X(BTBase): - breakName = True - reflect.safe_repr(X()) - - -class SafeStr(unittest.TestCase): - def testWorkingStr(self): - x = [1,2,3] - self.assertEquals(reflect.safe_str(x), str(x)) - - def testBrokenStr(self): - b = Breakable() - b.breakStr = True - reflect.safe_str(b) - - def testBrokenRepr(self): - b = Breakable() - b.breakRepr = True - reflect.safe_str(b) - - def testBrokenClassStr(self): - class X(BTBase): - breakStr = True - reflect.safe_str(X) - reflect.safe_str(X()) - - def testBrokenClassRepr(self): - class X(BTBase): - breakRepr = True - reflect.safe_str(X) - reflect.safe_str(X()) - - def testBroken__Class__Attr(self): - reflect.safe_str(NoClassAttr()) - - def testBroken__Class__Name__Attr(self): - class X(BTBase): - breakName = True - reflect.safe_str(X()) - - -class FilenameToModule(unittest.TestCase): - """ - Test L{reflect.filenameToModuleName} detection. - """ - def test_directory(self): - """ - Tests it finds good name for directories/packages. - """ - module = reflect.filenameToModuleName(os.path.join('twisted', 'test')) - self.assertEquals(module, 'test') - module = reflect.filenameToModuleName(os.path.join('twisted', 'test') - + os.path.sep) - self.assertEquals(module, 'test') - - def test_file(self): - """ - Test it finds good name for files. - """ - module = reflect.filenameToModuleName( - os.path.join('twisted', 'test', 'test_reflect.py')) - self.assertEquals(module, 'test_reflect') - diff --git a/tools/buildbot/pylibs/twisted/test/test_reflector.py b/tools/buildbot/pylibs/twisted/test/test_reflector.py deleted file mode 100644 index 15c4b67..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_reflector.py +++ /dev/null @@ -1,396 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for twisted.enterprise reflectors. -""" - -import random - -from twisted.internet import reactor, interfaces, defer -from twisted.enterprise.row import RowObject -from twisted.enterprise.reflector import EQUAL -from twisted.enterprise.sqlreflector import SQLReflector -from twisted.enterprise import util -from twisted.test.test_adbapi import makeSQLTests -from twisted.trial.util import suppress as suppressWarning -from twisted.trial import unittest - - -tableName = "testTable" -childTableName = "childTable" - - -class TestRow(RowObject): - rowColumns = [("key_string", "varchar"), - ("col2", "int"), - ("another_column", "varchar"), - ("Column4", "varchar"), - ("column_5_", "int")] - rowKeyColumns = [("key_string", "varchar")] - rowTableName = tableName - - -class ChildRow(RowObject): - rowColumns = [("childId", "int"), - ("foo", "varchar"), - ("test_key", "varchar"), - ("stuff", "varchar"), - ("gogogo", "int"), - ("data", "varchar")] - rowKeyColumns = [("childId", "int")] - rowTableName = childTableName - rowForeignKeys = [(tableName, - [("test_key","varchar")], - [("key_string","varchar")], - None, 1)] - - -main_table_schema = """ -CREATE TABLE testTable ( - key_string varchar(64), - col2 integer, - another_column varchar(64), - Column4 varchar(64), - column_5_ integer -) -""" - -child_table_schema = """ -CREATE TABLE childTable ( - childId integer, - foo varchar(64), - test_key varchar(64), - stuff varchar(64), - gogogo integer, - data varchar(64) -) -""" - - -def randomizeRow(row, nulls_ok=True, trailing_spaces_ok=True): - values = {} - for name, type in row.rowColumns: - if util.getKeyColumn(row, name): - values[name] = getattr(row, name) - continue - elif nulls_ok and random.randint(0, 9) == 0: - value = None # null - elif type == 'int': - value = random.randint(-10000, 10000) - else: - if random.randint(0, 9) == 0: - value = '' - else: - value = ''.join(map(lambda i:chr(random.randrange(32,127)), - xrange(random.randint(1, 64)))) - if not trailing_spaces_ok: - value = value.rstrip() - setattr(row, name, value) - values[name] = value - return values - - -def rowMatches(row, values): - for name, type in row.rowColumns: - if getattr(row, name) != values[name]: - print ("Mismatch on column %s: |%s| (row) |%s| (values)" % - (name, getattr(row, name), values[name])) - return False - return True - - -rowObjectSuppression = suppressWarning( - message="twisted.enterprise.row is deprecated since Twisted 8.0", - category=DeprecationWarning) - - -reflectorSuppression = suppressWarning( - message="twisted.enterprise.reflector is deprecated since Twisted 8.0", - category=DeprecationWarning) - - -class ReflectorTestBase: - """ - Base class for testing reflectors. - """ - - if interfaces.IReactorThreads(reactor, None) is None: - skip = "No thread support, no reflector tests" - - count = 100 # a parameter used for running iterative tests - - def randomizeRow(self, row): - return randomizeRow(row, self.nulls_ok, self.trailing_spaces_ok) - - def setUp(self): - d = self.createReflector() - d.addCallback(self._cbSetUp) - return d - - def _cbSetUp(self, reflector): - self.reflector = reflector - - def tearDown(self): - return self.destroyReflector() - - def destroyReflector(self): - pass - - def test_reflector(self): - """ - Full featured tests of reflector. - """ - # create one row to work with - row = TestRow() - row.assignKeyAttr("key_string", "first") - values = self.randomizeRow(row) - - # save it - d = self.reflector.insertRow(row) - - def _loadBack(_): - # now load it back in - whereClause = [("key_string", EQUAL, "first")] - d = self.reflector.loadObjectsFrom(tableName, - whereClause=whereClause) - return d.addCallback(self.gotData) - - def _getParent(_): - # make sure it came back as what we saved - self.failUnless(len(self.data) == 1, "no row") - parent = self.data[0] - self.failUnless(rowMatches(parent, values), "no match") - return parent - - d.addCallback(_loadBack) - d.addCallback(_getParent) - d.addCallback(self._cbTestReflector) - return d - test_reflector.suppress = [rowObjectSuppression, reflectorSuppression] - - def _cbTestReflector(self, parent): - # create some child rows - test_values = {} - inserts = [] - child_values = {} - for i in range(0, self.num_iterations): - row = ChildRow() - row.assignKeyAttr("childId", i) - values = self.randomizeRow(row) - values['test_key'] = row.test_key = "first" - child_values[i] = values - inserts.append(self.reflector.insertRow(row)) - row = None - #del inserts - d = defer.gatherResults(inserts) - values = [None] - - def _loadObjects(_): - d = self.reflector.loadObjectsFrom(childTableName, parentRow=parent) - return d.addCallback(self.gotData) - - def _checkLoadObjects(_): - self.failUnless(len(self.data) == self.num_iterations, - "no rows on query") - self.failUnless(len(parent.childRows) == self.num_iterations, - "did not load child rows: %d" % len(parent.childRows)) - for child in parent.childRows: - self.failUnless(rowMatches(child, child_values[child.childId]), - "child %d does not match" % child.childId) - - def _checkLoadObjects2(_): - self.failUnless(len(self.data) == self.num_iterations, - "no rows on query") - self.failUnless(len(parent.childRows) == self.num_iterations, - "child rows added twice!: %d" % len(parent.childRows)) - - def _changeParent(_): - # now change the parent - values[0] = self.randomizeRow(parent) - return self.reflector.updateRow(parent) - - def _loadBack(_): - # now load it back in - whereClause = [("key_string", EQUAL, "first")] - d = self.reflector.loadObjectsFrom(tableName, whereClause=whereClause) - return d.addCallback(self.gotData) - - def _checkLoadBack(_): - # make sure it came back as what we saved - self.failUnless(len(self.data) == 1, "no row") - parent = self.data[0] - self.failUnless(rowMatches(parent, values[0]), "no match") - # save parent - test_values[parent.key_string] = values[0] - parent = None - - def _saveMoreTestRows(_): - # save some more test rows - ds = [] - for i in range(0, self.num_iterations): - row = TestRow() - row.assignKeyAttr("key_string", "bulk%d"%i) - test_values[row.key_string] = self.randomizeRow(row) - ds.append(self.reflector.insertRow(row)) - return defer.gatherResults(ds) - - def _loadRowsBack(_): - # now load them all back in - d = self.reflector.loadObjectsFrom("testTable") - return d.addCallback(self.gotData) - - def _checkRowsBack(_): - # make sure they are the same - self.failUnless(len(self.data) == self.num_iterations + 1, - "query did not get rows") - for row in self.data: - self.failUnless(rowMatches(row, test_values[row.key_string]), - "child %s does not match" % row.key_string) - - def _changeRows(_): - # now change them all - ds = [] - for row in self.data: - test_values[row.key_string] = self.randomizeRow(row) - ds.append(self.reflector.updateRow(row)) - d = defer.gatherResults(ds) - return d.addCallback(_cbChangeRows) - - def _cbChangeRows(_): - self.data = None - - def _deleteRows(_): - # now delete them - ds = [] - for row in self.data: - ds.append(self.reflector.deleteRow(row)) - d = defer.gatherResults(ds) - return d.addCallback(_cbChangeRows) - - def _checkRowsDeleted(_): - self.failUnless(len(self.data) == 0, "rows were not deleted") - - d.addCallback(_loadObjects) - d.addCallback(_checkLoadObjects) - d.addCallback(_loadObjects) - d.addCallback(_checkLoadObjects2) - d.addCallback(_changeParent) - d.addCallback(_loadBack) - d.addCallback(_checkLoadBack) - d.addCallback(_saveMoreTestRows) - d.addCallback(_loadRowsBack) - d.addCallback(_checkRowsBack) - d.addCallback(_changeRows) - d.addCallback(_loadRowsBack) - d.addCallback(_checkRowsBack) - d.addCallback(_deleteRows) - d.addCallback(_loadRowsBack) - d.addCallback(_checkRowsDeleted) - return d - - - def test_saveAndDelete(self): - """ - Create a row and then try to delete it. - """ - # create one row to work with - row = TestRow() - row.assignKeyAttr("key_string", "first") - values = self.randomizeRow(row) - # save it - d = self.reflector.insertRow(row) - def _deleteRow(_): - # delete it - return self.reflector.deleteRow(row) - d.addCallback(_deleteRow) - return d - test_saveAndDelete.suppress = [rowObjectSuppression, reflectorSuppression] - - - def gotData(self, data): - self.data = data - - -ReflectorTestBase.timeout = 30.0 - - -class SQLReflectorTestBase(ReflectorTestBase): - """ - Base class for the SQL reflector. - """ - - def createReflector(self): - self.startDB() - self.dbpool = self.makePool() - self.dbpool.start() - - if self.can_clear: - d = self.dbpool.runOperation('DROP TABLE testTable') - d.addCallback(lambda _: - self.dbpool.runOperation('DROP TABLE childTable')) - d.addErrback(lambda _: None) - else: - d = defer.succeed(None) - - d.addCallback(lambda _: self.dbpool.runOperation(main_table_schema)) - d.addCallback(lambda _: self.dbpool.runOperation(child_table_schema)) - reflectorClass = self.escape_slashes and SQLReflector \ - or NoSlashSQLReflector - d.addCallback(lambda _: - reflectorClass(self.dbpool, [TestRow, ChildRow])) - return d - - def destroyReflector(self): - d = self.dbpool.runOperation('DROP TABLE testTable') - d.addCallback(lambda _: - self.dbpool.runOperation('DROP TABLE childTable')) - def close(_): - self.dbpool.close() - self.stopDB() - d.addCallback(close) - return d - - -class DeprecationTestCase(unittest.TestCase): - """ - Test various deprecations of twisted.enterprise. - """ - - def test_rowDeprecation(self): - """ - Test deprecation of L{RowObject}. - """ - def wrapper(): - return TestRow() - self.assertWarns(DeprecationWarning, - "twisted.enterprise.row is deprecated since Twisted 8.0", - __file__, - wrapper) - - def test_reflectorDeprecation(self): - """ - Test deprecation of L{SQLReflector}. - """ - def wrapper(): - return SQLReflector(None, ()) - from twisted.enterprise import sqlreflector - self.assertWarns(DeprecationWarning, - "twisted.enterprise.reflector is deprecated since Twisted 8.0", - sqlreflector.__file__, - wrapper) - - -# GadflyReflectorTestCase SQLiteReflectorTestCase PyPgSQLReflectorTestCase -# PsycopgReflectorTestCase MySQLReflectorTestCase FirebirdReflectorTestCase -makeSQLTests(SQLReflectorTestBase, 'ReflectorTestCase', globals()) - - -class NoSlashSQLReflector(SQLReflector): - """ - An sql reflector that only escapes single quotes. - """ - - def escape_string(self, text): - return text.replace("'", "''") - diff --git a/tools/buildbot/pylibs/twisted/test/test_roots.py b/tools/buildbot/pylibs/twisted/test/test_roots.py deleted file mode 100644 index 023b8fe..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_roots.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.trial import unittest -from twisted.python import roots -import types - -class RootsTest(unittest.TestCase): - - def testExceptions(self): - request = roots.Request() - try: - request.write("blah") - except NotImplementedError: - pass - else: - self.fail() - try: - request.finish() - except NotImplementedError: - pass - else: - self.fail() - - def testCollection(self): - collection = roots.Collection() - collection.putEntity("x", 'test') - self.failUnlessEqual(collection.getStaticEntity("x"), - 'test') - collection.delEntity("x") - self.failUnlessEqual(collection.getStaticEntity('x'), - None) - try: - collection.storeEntity("x", None) - except NotImplementedError: - pass - else: - self.fail() - try: - collection.removeEntity("x", None) - except NotImplementedError: - pass - else: - self.fail() - - def testConstrained(self): - class const(roots.Constrained): - def nameConstraint(self, name): - return (name == 'x') - c = const() - self.failUnlessEqual(c.putEntity('x', 'test'), None) - self.failUnlessRaises(roots.ConstraintViolation, - c.putEntity, 'y', 'test') - - - def testHomogenous(self): - h = roots.Homogenous() - h.entityType = types.IntType - h.putEntity('a', 1) - self.failUnlessEqual(h.getStaticEntity('a'),1 ) - self.failUnlessRaises(roots.ConstraintViolation, - h.putEntity, 'x', 'y') - diff --git a/tools/buildbot/pylibs/twisted/test/test_shortcut.py b/tools/buildbot/pylibs/twisted/test/test_shortcut.py deleted file mode 100644 index 6ce862c..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_shortcut.py +++ /dev/null @@ -1,20 +0,0 @@ -"""Test win32 shortcut script -""" - -from twisted.trial import unittest - -import os -if os.name == 'nt': - - from twisted.python import shortcut - import os.path - import sys - - class ShortcutTest(unittest.TestCase): - def testCreate(self): - s1=shortcut.Shortcut("test_shortcut.py") - tempname=self.mktemp() + '.lnk' - s1.save(tempname) - self.assert_(os.path.exists(tempname)) - sc=shortcut.open(tempname) - self.assert_(sc.GetPath(0)[0].endswith('test_shortcut.py')) diff --git a/tools/buildbot/pylibs/twisted/test/test_sip.py b/tools/buildbot/pylibs/twisted/test/test_sip.py deleted file mode 100644 index 332fcb2..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_sip.py +++ /dev/null @@ -1,740 +0,0 @@ -# -*- test-case-name: twisted.test.test_sip -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Session Initialization Protocol tests.""" - -from twisted.trial import unittest -from twisted.protocols import sip -from twisted.internet import defer, reactor - -from twisted.test import proto_helpers - -from twisted import cred -import twisted.cred.portal -import twisted.cred.checkers - -from zope.interface import implements - - -# request, prefixed by random CRLFs -request1 = "\n\r\n\n\r" + """\ -INVITE sip:foo SIP/2.0 -From: mo -To: joe -Content-Length: 4 - -abcd""".replace("\n", "\r\n") - -# request, no content-length -request2 = """INVITE sip:foo SIP/2.0 -From: mo -To: joe - -1234""".replace("\n", "\r\n") - -# request, with garbage after -request3 = """INVITE sip:foo SIP/2.0 -From: mo -To: joe -Content-Length: 4 - -1234 - -lalalal""".replace("\n", "\r\n") - -# three requests -request4 = """INVITE sip:foo SIP/2.0 -From: mo -To: joe -Content-Length: 0 - -INVITE sip:loop SIP/2.0 -From: foo -To: bar -Content-Length: 4 - -abcdINVITE sip:loop SIP/2.0 -From: foo -To: bar -Content-Length: 4 - -1234""".replace("\n", "\r\n") - -# response, no content -response1 = """SIP/2.0 200 OK -From: foo -To:bar -Content-Length: 0 - -""".replace("\n", "\r\n") - -# short header version -request_short = """\ -INVITE sip:foo SIP/2.0 -f: mo -t: joe -l: 4 - -abcd""".replace("\n", "\r\n") - -request_natted = """\ -INVITE sip:foo SIP/2.0 -Via: SIP/2.0/UDP 10.0.0.1:5060;rport - -""".replace("\n", "\r\n") - -class TestRealm: - def requestAvatar(self, avatarId, mind, *interfaces): - return sip.IContact, None, lambda: None - -class MessageParsingTestCase(unittest.TestCase): - def setUp(self): - self.l = [] - self.parser = sip.MessagesParser(self.l.append) - - def feedMessage(self, message): - self.parser.dataReceived(message) - self.parser.dataDone() - - def validateMessage(self, m, method, uri, headers, body): - """Validate Requests.""" - self.assertEquals(m.method, method) - self.assertEquals(m.uri.toString(), uri) - self.assertEquals(m.headers, headers) - self.assertEquals(m.body, body) - self.assertEquals(m.finished, 1) - - def testSimple(self): - l = self.l - self.feedMessage(request1) - self.assertEquals(len(l), 1) - self.validateMessage(l[0], "INVITE", "sip:foo", - {"from": ["mo"], "to": ["joe"], "content-length": ["4"]}, - "abcd") - - def testTwoMessages(self): - l = self.l - self.feedMessage(request1) - self.feedMessage(request2) - self.assertEquals(len(l), 2) - self.validateMessage(l[0], "INVITE", "sip:foo", - {"from": ["mo"], "to": ["joe"], "content-length": ["4"]}, - "abcd") - self.validateMessage(l[1], "INVITE", "sip:foo", - {"from": ["mo"], "to": ["joe"]}, - "1234") - - def testGarbage(self): - l = self.l - self.feedMessage(request3) - self.assertEquals(len(l), 1) - self.validateMessage(l[0], "INVITE", "sip:foo", - {"from": ["mo"], "to": ["joe"], "content-length": ["4"]}, - "1234") - - def testThreeInOne(self): - l = self.l - self.feedMessage(request4) - self.assertEquals(len(l), 3) - self.validateMessage(l[0], "INVITE", "sip:foo", - {"from": ["mo"], "to": ["joe"], "content-length": ["0"]}, - "") - self.validateMessage(l[1], "INVITE", "sip:loop", - {"from": ["foo"], "to": ["bar"], "content-length": ["4"]}, - "abcd") - self.validateMessage(l[2], "INVITE", "sip:loop", - {"from": ["foo"], "to": ["bar"], "content-length": ["4"]}, - "1234") - - def testShort(self): - l = self.l - self.feedMessage(request_short) - self.assertEquals(len(l), 1) - self.validateMessage(l[0], "INVITE", "sip:foo", - {"from": ["mo"], "to": ["joe"], "content-length": ["4"]}, - "abcd") - - def testSimpleResponse(self): - l = self.l - self.feedMessage(response1) - self.assertEquals(len(l), 1) - m = l[0] - self.assertEquals(m.code, 200) - self.assertEquals(m.phrase, "OK") - self.assertEquals(m.headers, {"from": ["foo"], "to": ["bar"], "content-length": ["0"]}) - self.assertEquals(m.body, "") - self.assertEquals(m.finished, 1) - - -class MessageParsingTestCase2(MessageParsingTestCase): - """Same as base class, but feed data char by char.""" - - def feedMessage(self, message): - for c in message: - self.parser.dataReceived(c) - self.parser.dataDone() - - -class MakeMessageTestCase(unittest.TestCase): - - def testRequest(self): - r = sip.Request("INVITE", "sip:foo") - r.addHeader("foo", "bar") - self.assertEquals(r.toString(), "INVITE sip:foo SIP/2.0\r\nFoo: bar\r\n\r\n") - - def testResponse(self): - r = sip.Response(200, "OK") - r.addHeader("foo", "bar") - r.addHeader("Content-Length", "4") - r.bodyDataReceived("1234") - self.assertEquals(r.toString(), "SIP/2.0 200 OK\r\nFoo: bar\r\nContent-Length: 4\r\n\r\n1234") - - def testStatusCode(self): - r = sip.Response(200) - self.assertEquals(r.toString(), "SIP/2.0 200 OK\r\n\r\n") - - -class ViaTestCase(unittest.TestCase): - - def checkRoundtrip(self, v): - s = v.toString() - self.assertEquals(s, sip.parseViaHeader(s).toString()) - - def testExtraWhitespace(self): - v1 = sip.parseViaHeader('SIP/2.0/UDP 192.168.1.1:5060') - v2 = sip.parseViaHeader('SIP/2.0/UDP 192.168.1.1:5060') - self.assertEquals(v1.transport, v2.transport) - self.assertEquals(v1.host, v2.host) - self.assertEquals(v1.port, v2.port) - - def testComplex(self): - s = "SIP/2.0/UDP first.example.com:4000;ttl=16;maddr=224.2.0.1 ;branch=a7c6a8dlze (Example)" - v = sip.parseViaHeader(s) - self.assertEquals(v.transport, "UDP") - self.assertEquals(v.host, "first.example.com") - self.assertEquals(v.port, 4000) - self.assertEquals(v.ttl, 16) - self.assertEquals(v.maddr, "224.2.0.1") - self.assertEquals(v.branch, "a7c6a8dlze") - self.assertEquals(v.hidden, 0) - self.assertEquals(v.toString(), - "SIP/2.0/UDP first.example.com:4000;ttl=16;branch=a7c6a8dlze;maddr=224.2.0.1") - self.checkRoundtrip(v) - - def testSimple(self): - s = "SIP/2.0/UDP example.com;hidden" - v = sip.parseViaHeader(s) - self.assertEquals(v.transport, "UDP") - self.assertEquals(v.host, "example.com") - self.assertEquals(v.port, 5060) - self.assertEquals(v.ttl, None) - self.assertEquals(v.maddr, None) - self.assertEquals(v.branch, None) - self.assertEquals(v.hidden, 1) - self.assertEquals(v.toString(), - "SIP/2.0/UDP example.com:5060;hidden") - self.checkRoundtrip(v) - - def testSimpler(self): - v = sip.Via("example.com") - self.checkRoundtrip(v) - - def testRPort(self): - v = sip.Via("foo.bar", rport=True) - self.assertEquals(v.toString(), "SIP/2.0/UDP foo.bar:5060;rport") - - def testNAT(self): - s = "SIP/2.0/UDP 10.0.0.1:5060;received=22.13.1.5;rport=12345" - v = sip.parseViaHeader(s) - self.assertEquals(v.transport, "UDP") - self.assertEquals(v.host, "10.0.0.1") - self.assertEquals(v.port, 5060) - self.assertEquals(v.received, "22.13.1.5") - self.assertEquals(v.rport, 12345) - - self.assertNotEquals(v.toString().find("rport=12345"), -1) - -class URLTestCase(unittest.TestCase): - - def testRoundtrip(self): - for url in [ - "sip:j.doe@big.com", - "sip:j.doe:secret@big.com;transport=tcp", - "sip:j.doe@big.com?subject=project", - "sip:example.com", - ]: - self.assertEquals(sip.parseURL(url).toString(), url) - - def testComplex(self): - s = ("sip:user:pass@hosta:123;transport=udp;user=phone;method=foo;" - "ttl=12;maddr=1.2.3.4;blah;goo=bar?a=b&c=d") - url = sip.parseURL(s) - for k, v in [("username", "user"), ("password", "pass"), - ("host", "hosta"), ("port", 123), - ("transport", "udp"), ("usertype", "phone"), - ("method", "foo"), ("ttl", 12), - ("maddr", "1.2.3.4"), ("other", ["blah", "goo=bar"]), - ("headers", {"a": "b", "c": "d"})]: - self.assertEquals(getattr(url, k), v) - - -class ParseTestCase(unittest.TestCase): - - def testParseAddress(self): - for address, name, urls, params in [ - ('"A. G. Bell" ', "A. G. Bell", "sip:foo@example.com", {}), - ("Anon ", "Anon", "sip:foo@example.com", {}), - ("sip:foo@example.com", "", "sip:foo@example.com", {}), - ("", "", "sip:foo@example.com", {}), - ("foo ;tag=bar;foo=baz", "foo", "sip:foo@example.com", {"tag": "bar", "foo": "baz"}), - ]: - gname, gurl, gparams = sip.parseAddress(address) - self.assertEquals(name, gname) - self.assertEquals(gurl.toString(), urls) - self.assertEquals(gparams, params) - - -class DummyLocator: - implements(sip.ILocator) - def getAddress(self, logicalURL): - return defer.succeed(sip.URL("server.com", port=5060)) - -class FailingLocator: - implements(sip.ILocator) - def getAddress(self, logicalURL): - return defer.fail(LookupError()) - - -class ProxyTestCase(unittest.TestCase): - - def setUp(self): - self.proxy = sip.Proxy("127.0.0.1") - self.proxy.locator = DummyLocator() - self.sent = [] - self.proxy.sendMessage = lambda dest, msg: self.sent.append((dest, msg)) - - def testRequestForward(self): - r = sip.Request("INVITE", "sip:foo") - r.addHeader("via", sip.Via("1.2.3.4").toString()) - r.addHeader("via", sip.Via("1.2.3.5").toString()) - r.addHeader("foo", "bar") - r.addHeader("to", "") - r.addHeader("contact", "") - self.proxy.datagramReceived(r.toString(), ("1.2.3.4", 5060)) - self.assertEquals(len(self.sent), 1) - dest, m = self.sent[0] - self.assertEquals(dest.port, 5060) - self.assertEquals(dest.host, "server.com") - self.assertEquals(m.uri.toString(), "sip:foo") - self.assertEquals(m.method, "INVITE") - self.assertEquals(m.headers["via"], - ["SIP/2.0/UDP 127.0.0.1:5060", - "SIP/2.0/UDP 1.2.3.4:5060", - "SIP/2.0/UDP 1.2.3.5:5060"]) - - - def testReceivedRequestForward(self): - r = sip.Request("INVITE", "sip:foo") - r.addHeader("via", sip.Via("1.2.3.4").toString()) - r.addHeader("foo", "bar") - r.addHeader("to", "") - r.addHeader("contact", "") - self.proxy.datagramReceived(r.toString(), ("1.1.1.1", 5060)) - dest, m = self.sent[0] - self.assertEquals(m.headers["via"], - ["SIP/2.0/UDP 127.0.0.1:5060", - "SIP/2.0/UDP 1.2.3.4:5060;received=1.1.1.1"]) - - - def testResponseWrongVia(self): - # first via must match proxy's address - r = sip.Response(200) - r.addHeader("via", sip.Via("foo.com").toString()) - self.proxy.datagramReceived(r.toString(), ("1.1.1.1", 5060)) - self.assertEquals(len(self.sent), 0) - - def testResponseForward(self): - r = sip.Response(200) - r.addHeader("via", sip.Via("127.0.0.1").toString()) - r.addHeader("via", sip.Via("client.com", port=1234).toString()) - self.proxy.datagramReceived(r.toString(), ("1.1.1.1", 5060)) - self.assertEquals(len(self.sent), 1) - dest, m = self.sent[0] - self.assertEquals((dest.host, dest.port), ("client.com", 1234)) - self.assertEquals(m.code, 200) - self.assertEquals(m.headers["via"], ["SIP/2.0/UDP client.com:1234"]) - - def testReceivedResponseForward(self): - r = sip.Response(200) - r.addHeader("via", sip.Via("127.0.0.1").toString()) - r.addHeader("via", sip.Via("10.0.0.1", received="client.com").toString()) - self.proxy.datagramReceived(r.toString(), ("1.1.1.1", 5060)) - self.assertEquals(len(self.sent), 1) - dest, m = self.sent[0] - self.assertEquals((dest.host, dest.port), ("client.com", 5060)) - - def testResponseToUs(self): - r = sip.Response(200) - r.addHeader("via", sip.Via("127.0.0.1").toString()) - l = [] - self.proxy.gotResponse = lambda *a: l.append(a) - self.proxy.datagramReceived(r.toString(), ("1.1.1.1", 5060)) - self.assertEquals(len(l), 1) - m, addr = l[0] - self.assertEquals(len(m.headers.get("via", [])), 0) - self.assertEquals(m.code, 200) - - def testLoop(self): - r = sip.Request("INVITE", "sip:foo") - r.addHeader("via", sip.Via("1.2.3.4").toString()) - r.addHeader("via", sip.Via("127.0.0.1").toString()) - self.proxy.datagramReceived(r.toString(), ("client.com", 5060)) - self.assertEquals(self.sent, []) - - def testCantForwardRequest(self): - r = sip.Request("INVITE", "sip:foo") - r.addHeader("via", sip.Via("1.2.3.4").toString()) - r.addHeader("to", "") - self.proxy.locator = FailingLocator() - self.proxy.datagramReceived(r.toString(), ("1.2.3.4", 5060)) - self.assertEquals(len(self.sent), 1) - dest, m = self.sent[0] - self.assertEquals((dest.host, dest.port), ("1.2.3.4", 5060)) - self.assertEquals(m.code, 404) - self.assertEquals(m.headers["via"], ["SIP/2.0/UDP 1.2.3.4:5060"]) - - def testCantForwardResponse(self): - pass - - #testCantForwardResponse.skip = "not implemented yet" - - -class RegistrationTestCase(unittest.TestCase): - - def setUp(self): - self.proxy = sip.RegisterProxy(host="127.0.0.1") - self.registry = sip.InMemoryRegistry("bell.example.com") - self.proxy.registry = self.proxy.locator = self.registry - self.sent = [] - self.proxy.sendMessage = lambda dest, msg: self.sent.append((dest, msg)) - - def tearDown(self): - for d, uri in self.registry.users.values(): - d.cancel() - del self.proxy - - def register(self): - r = sip.Request("REGISTER", "sip:bell.example.com") - r.addHeader("to", "sip:joe@bell.example.com") - r.addHeader("contact", "sip:joe@client.com:1234") - r.addHeader("via", sip.Via("client.com").toString()) - self.proxy.datagramReceived(r.toString(), ("client.com", 5060)) - - def unregister(self): - r = sip.Request("REGISTER", "sip:bell.example.com") - r.addHeader("to", "sip:joe@bell.example.com") - r.addHeader("contact", "*") - r.addHeader("via", sip.Via("client.com").toString()) - r.addHeader("expires", "0") - self.proxy.datagramReceived(r.toString(), ("client.com", 5060)) - - def testRegister(self): - self.register() - dest, m = self.sent[0] - self.assertEquals((dest.host, dest.port), ("client.com", 5060)) - self.assertEquals(m.code, 200) - self.assertEquals(m.headers["via"], ["SIP/2.0/UDP client.com:5060"]) - self.assertEquals(m.headers["to"], ["sip:joe@bell.example.com"]) - self.assertEquals(m.headers["contact"], ["sip:joe@client.com:5060"]) - self.failUnless(int(m.headers["expires"][0]) in (3600, 3601, 3599, 3598)) - self.assertEquals(len(self.registry.users), 1) - dc, uri = self.registry.users["joe"] - self.assertEquals(uri.toString(), "sip:joe@client.com:5060") - d = self.proxy.locator.getAddress(sip.URL(username="joe", - host="bell.example.com")) - d.addCallback(lambda desturl : (desturl.host, desturl.port)) - d.addCallback(self.assertEquals, ('client.com', 5060)) - return d - - def testUnregister(self): - self.register() - self.unregister() - dest, m = self.sent[1] - self.assertEquals((dest.host, dest.port), ("client.com", 5060)) - self.assertEquals(m.code, 200) - self.assertEquals(m.headers["via"], ["SIP/2.0/UDP client.com:5060"]) - self.assertEquals(m.headers["to"], ["sip:joe@bell.example.com"]) - self.assertEquals(m.headers["contact"], ["sip:joe@client.com:5060"]) - self.assertEquals(m.headers["expires"], ["0"]) - self.assertEquals(self.registry.users, {}) - - - def addPortal(self): - r = TestRealm() - p = cred.portal.Portal(r) - c = cred.checkers.InMemoryUsernamePasswordDatabaseDontUse() - c.addUser('userXname@127.0.0.1', 'passXword') - p.registerChecker(c) - self.proxy.portal = p - - def testFailedAuthentication(self): - self.addPortal() - self.register() - - self.assertEquals(len(self.registry.users), 0) - self.assertEquals(len(self.sent), 1) - dest, m = self.sent[0] - self.assertEquals(m.code, 401) - - - def testBasicAuthentication(self): - self.addPortal() - self.proxy.authorizers = self.proxy.authorizers.copy() - self.proxy.authorizers['basic'] = sip.BasicAuthorizer() - - r = sip.Request("REGISTER", "sip:bell.example.com") - r.addHeader("to", "sip:joe@bell.example.com") - r.addHeader("contact", "sip:joe@client.com:1234") - r.addHeader("via", sip.Via("client.com").toString()) - r.addHeader("authorization", "Basic " + "userXname:passXword".encode('base64')) - self.proxy.datagramReceived(r.toString(), ("client.com", 5060)) - - self.assertEquals(len(self.registry.users), 1) - self.assertEquals(len(self.sent), 1) - dest, m = self.sent[0] - self.assertEquals(m.code, 200) - - - def testFailedBasicAuthentication(self): - self.addPortal() - self.proxy.authorizers = self.proxy.authorizers.copy() - self.proxy.authorizers['basic'] = sip.BasicAuthorizer() - - r = sip.Request("REGISTER", "sip:bell.example.com") - r.addHeader("to", "sip:joe@bell.example.com") - r.addHeader("contact", "sip:joe@client.com:1234") - r.addHeader("via", sip.Via("client.com").toString()) - r.addHeader("authorization", "Basic " + "userXname:password".encode('base64')) - self.proxy.datagramReceived(r.toString(), ("client.com", 5060)) - - self.assertEquals(len(self.registry.users), 0) - self.assertEquals(len(self.sent), 1) - dest, m = self.sent[0] - self.assertEquals(m.code, 401) - - def testWrongDomainRegister(self): - r = sip.Request("REGISTER", "sip:wrong.com") - r.addHeader("to", "sip:joe@bell.example.com") - r.addHeader("contact", "sip:joe@client.com:1234") - r.addHeader("via", sip.Via("client.com").toString()) - self.proxy.datagramReceived(r.toString(), ("client.com", 5060)) - self.assertEquals(len(self.sent), 0) - - def testWrongToDomainRegister(self): - r = sip.Request("REGISTER", "sip:bell.example.com") - r.addHeader("to", "sip:joe@foo.com") - r.addHeader("contact", "sip:joe@client.com:1234") - r.addHeader("via", sip.Via("client.com").toString()) - self.proxy.datagramReceived(r.toString(), ("client.com", 5060)) - self.assertEquals(len(self.sent), 0) - - def testWrongDomainLookup(self): - self.register() - url = sip.URL(username="joe", host="foo.com") - d = self.proxy.locator.getAddress(url) - self.assertFailure(d, LookupError) - return d - - def testNoContactLookup(self): - self.register() - url = sip.URL(username="jane", host="bell.example.com") - d = self.proxy.locator.getAddress(url) - self.assertFailure(d, LookupError) - return d - - -class Client(sip.Base): - - def __init__(self): - sip.Base.__init__(self) - self.received = [] - self.deferred = defer.Deferred() - - def handle_response(self, response, addr): - self.received.append(response) - self.deferred.callback(self.received) - - -class LiveTest(unittest.TestCase): - - def setUp(self): - self.proxy = sip.RegisterProxy(host="127.0.0.1") - self.registry = sip.InMemoryRegistry("bell.example.com") - self.proxy.registry = self.proxy.locator = self.registry - self.serverPort = reactor.listenUDP(0, self.proxy, interface="127.0.0.1") - self.client = Client() - self.clientPort = reactor.listenUDP(0, self.client, interface="127.0.0.1") - self.serverAddress = (self.serverPort.getHost().host, - self.serverPort.getHost().port) - - def tearDown(self): - for d, uri in self.registry.users.values(): - d.cancel() - d1 = defer.maybeDeferred(self.clientPort.stopListening) - d2 = defer.maybeDeferred(self.serverPort.stopListening) - return defer.gatherResults([d1, d2]) - - def testRegister(self): - p = self.clientPort.getHost().port - r = sip.Request("REGISTER", "sip:bell.example.com") - r.addHeader("to", "sip:joe@bell.example.com") - r.addHeader("contact", "sip:joe@127.0.0.1:%d" % p) - r.addHeader("via", sip.Via("127.0.0.1", port=p).toString()) - self.client.sendMessage(sip.URL(host="127.0.0.1", port=self.serverAddress[1]), - r) - d = self.client.deferred - def check(received): - self.assertEquals(len(received), 1) - r = received[0] - self.assertEquals(r.code, 200) - d.addCallback(check) - return d - - def testAmoralRPort(self): - # rport is allowed without a value, apparently because server - # implementors might be too stupid to check the received port - # against 5060 and see if they're equal, and because client - # implementors might be too stupid to bind to port 5060, or set a - # value on the rport parameter they send if they bind to another - # port. - p = self.clientPort.getHost().port - r = sip.Request("REGISTER", "sip:bell.example.com") - r.addHeader("to", "sip:joe@bell.example.com") - r.addHeader("contact", "sip:joe@127.0.0.1:%d" % p) - r.addHeader("via", sip.Via("127.0.0.1", port=p, rport=True).toString()) - self.client.sendMessage(sip.URL(host="127.0.0.1", port=self.serverAddress[1]), - r) - d = self.client.deferred - def check(received): - self.assertEquals(len(received), 1) - r = received[0] - self.assertEquals(r.code, 200) - d.addCallback(check) - return d - - -registerRequest = """ -REGISTER sip:intarweb.us SIP/2.0\r -Via: SIP/2.0/UDP 192.168.1.100:50609\r -From: \r -To: \r -Contact: "exarkun" \r -Call-ID: 94E7E5DAF39111D791C6000393764646@intarweb.us\r -CSeq: 9898 REGISTER\r -Expires: 500\r -User-Agent: X-Lite build 1061\r -Content-Length: 0\r -\r -""" - -challengeResponse = """\ -SIP/2.0 401 Unauthorized\r -Via: SIP/2.0/UDP 192.168.1.100:50609;received=127.0.0.1;rport=5632\r -To: \r -From: \r -Call-ID: 94E7E5DAF39111D791C6000393764646@intarweb.us\r -CSeq: 9898 REGISTER\r -WWW-Authenticate: Digest nonce="92956076410767313901322208775",opaque="1674186428",qop-options="auth",algorithm="MD5",realm="intarweb.us"\r -\r -""" - -authRequest = """\ -REGISTER sip:intarweb.us SIP/2.0\r -Via: SIP/2.0/UDP 192.168.1.100:50609\r -From: \r -To: \r -Contact: "exarkun" \r -Call-ID: 94E7E5DAF39111D791C6000393764646@intarweb.us\r -CSeq: 9899 REGISTER\r -Expires: 500\r -Authorization: Digest username="exarkun",realm="intarweb.us",nonce="92956076410767313901322208775",response="4a47980eea31694f997369214292374b",uri="sip:intarweb.us",algorithm=MD5,opaque="1674186428"\r -User-Agent: X-Lite build 1061\r -Content-Length: 0\r -\r -""" - -okResponse = """\ -SIP/2.0 200 OK\r -Via: SIP/2.0/UDP 192.168.1.100:50609;received=127.0.0.1;rport=5632\r -To: \r -From: \r -Call-ID: 94E7E5DAF39111D791C6000393764646@intarweb.us\r -CSeq: 9899 REGISTER\r -Contact: sip:exarkun@127.0.0.1:5632\r -Expires: 3600\r -Content-Length: 0\r -\r -""" - -class FakeDigestAuthorizer(sip.DigestAuthorizer): - def generateNonce(self): - return '92956076410767313901322208775' - def generateOpaque(self): - return '1674186428' - - -class FakeRegistry(sip.InMemoryRegistry): - """Make sure expiration is always seen to be 3600. - - Otherwise slow reactors fail tests incorrectly. - """ - - def _cbReg(self, reg): - if 3600 < reg.secondsToExpiry or reg.secondsToExpiry < 3598: - raise RuntimeError, "bad seconds to expire: %s" % reg.secondsToExpiry - reg.secondsToExpiry = 3600 - return reg - - def getRegistrationInfo(self, uri): - return sip.InMemoryRegistry.getRegistrationInfo(self, uri).addCallback(self._cbReg) - - def registerAddress(self, domainURL, logicalURL, physicalURL): - return sip.InMemoryRegistry.registerAddress(self, domainURL, logicalURL, physicalURL).addCallback(self._cbReg) - -class AuthorizationTestCase(unittest.TestCase): - def setUp(self): - self.proxy = sip.RegisterProxy(host="intarweb.us") - self.proxy.authorizers = self.proxy.authorizers.copy() - self.proxy.authorizers['digest'] = FakeDigestAuthorizer() - self.registry = FakeRegistry("intarweb.us") - self.proxy.registry = self.proxy.locator = self.registry - self.transport = proto_helpers.FakeDatagramTransport() - self.proxy.transport = self.transport - - r = TestRealm() - p = cred.portal.Portal(r) - c = cred.checkers.InMemoryUsernamePasswordDatabaseDontUse() - c.addUser('exarkun@intarweb.us', 'password') - p.registerChecker(c) - self.proxy.portal = p - - def tearDown(self): - for d, uri in self.registry.users.values(): - d.cancel() - del self.proxy - - def testChallenge(self): - self.proxy.datagramReceived(registerRequest, ("127.0.0.1", 5632)) - self.assertEquals( - self.transport.written[-1], - ((challengeResponse, ("127.0.0.1", 5632))) - ) - self.transport.written = [] - - self.proxy.datagramReceived(authRequest, ("127.0.0.1", 5632)) - self.assertEquals( - self.transport.written[-1], - ((okResponse, ("127.0.0.1", 5632))) - ) diff --git a/tools/buildbot/pylibs/twisted/test/test_sob.py b/tools/buildbot/pylibs/twisted/test/test_sob.py deleted file mode 100644 index 62bd564..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_sob.py +++ /dev/null @@ -1,188 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -# System Imports -from twisted.trial import unittest -from twisted.persisted import sob -from twisted.python import components -import sys, os - -try: - from twisted.web import microdom - gotMicrodom = True -except ImportError: - import warnings - warnings.warn("Not testing xml persistence as twisted.web.microdom " - "not available") - gotMicrodom = False - -class Dummy(components.Componentized): - pass - -objects = [ -1, -"hello", -(1, "hello"), -[1, "hello"], -{1:"hello"}, -] - -class FakeModule(object): - pass - -class PersistTestCase(unittest.TestCase): - def testStyles(self): - for o in objects: - p = sob.Persistent(o, '') - for style in 'xml source pickle'.split(): - if style == 'xml' and not gotMicrodom: - continue - p.setStyle(style) - p.save(filename='persisttest.'+style) - o1 = sob.load('persisttest.'+style, style) - self.failUnlessEqual(o, o1) - - def testStylesBeingSet(self): - o = Dummy() - o.foo = 5 - o.setComponent(sob.IPersistable, sob.Persistent(o, 'lala')) - for style in 'xml source pickle'.split(): - if style == 'xml' and not gotMicrodom: - continue - sob.IPersistable(o).setStyle(style) - sob.IPersistable(o).save(filename='lala.'+style) - o1 = sob.load('lala.'+style, style) - self.failUnlessEqual(o.foo, o1.foo) - self.failUnlessEqual(sob.IPersistable(o1).style, style) - - - def testNames(self): - o = [1,2,3] - p = sob.Persistent(o, 'object') - for style in 'xml source pickle'.split(): - if style == 'xml' and not gotMicrodom: - continue - p.setStyle(style) - p.save() - o1 = sob.load('object.ta'+style[0], style) - self.failUnlessEqual(o, o1) - for tag in 'lala lolo'.split(): - p.save(tag) - o1 = sob.load('object-'+tag+'.ta'+style[0], style) - self.failUnlessEqual(o, o1) - - def testEncryptedStyles(self): - try: - import Crypto - except ImportError: - raise unittest.SkipTest() - for o in objects: - phrase='once I was the king of spain' - p = sob.Persistent(o, '') - for style in 'xml source pickle'.split(): - if style == 'xml' and not gotMicrodom: - continue - p.setStyle(style) - p.save(filename='epersisttest.'+style, passphrase=phrase) - o1 = sob.load('epersisttest.'+style, style, phrase) - self.failUnlessEqual(o, o1) - - def testPython(self): - open("persisttest.python", 'w').write('foo=[1,2,3] ') - o = sob.loadValueFromFile('persisttest.python', 'foo') - self.failUnlessEqual(o, [1,2,3]) - - def testEncryptedPython(self): - try: - import Crypto - except ImportError: - raise unittest.SkipTest() - phrase='once I was the king of spain' - open("epersisttest.python", 'w').write( - sob._encrypt(phrase, 'foo=[1,2,3]')) - o = sob.loadValueFromFile('epersisttest.python', 'foo', phrase) - self.failUnlessEqual(o, [1,2,3]) - - def testTypeGuesser(self): - self.assertRaises(KeyError, sob.guessType, "file.blah") - self.assertEqual('python', sob.guessType("file.py")) - self.assertEqual('python', sob.guessType("file.tac")) - self.assertEqual('python', sob.guessType("file.etac")) - self.assertEqual('pickle', sob.guessType("file.tap")) - self.assertEqual('pickle', sob.guessType("file.etap")) - self.assertEqual('source', sob.guessType("file.tas")) - self.assertEqual('source', sob.guessType("file.etas")) - if gotMicrodom: - self.assertEqual('xml', sob.guessType("file.tax")) - self.assertEqual('xml', sob.guessType("file.etax")) - - def testEverythingEphemeralGetattr(self): - """ - Verify that _EverythingEphermal.__getattr__ works. - """ - self.fakeMain.testMainModGetattr = 1 - - dirname = self.mktemp() - os.mkdir(dirname) - - filename = os.path.join(dirname, 'persisttest.ee_getattr') - - f = file(filename, 'w') - f.write('import __main__\n') - f.write('if __main__.testMainModGetattr != 1: raise AssertionError\n') - f.write('app = None\n') - f.close() - - sob.load(filename, 'source') - - def testEverythingEphemeralSetattr(self): - """ - Verify that _EverythingEphemeral.__setattr__ won't affect __main__. - """ - self.fakeMain.testMainModSetattr = 1 - - dirname = self.mktemp() - os.mkdir(dirname) - - filename = os.path.join(dirname, 'persisttest.ee_setattr') - f = file(filename, 'w') - f.write('import __main__\n') - f.write('__main__.testMainModSetattr = 2\n') - f.write('app = None\n') - f.close() - - sob.load(filename, 'source') - - self.assertEqual(self.fakeMain.testMainModSetattr, 1) - - def testEverythingEphemeralException(self): - """ - Test that an exception during load() won't cause _EE to mask __main__ - """ - dirname = self.mktemp() - os.mkdir(dirname) - filename = os.path.join(dirname, 'persisttest.ee_exception') - - f = file(filename, 'w') - f.write('raise ValueError\n') - f.close() - - self.assertRaises(ValueError, sob.load, filename, 'source') - self.assertEqual(type(sys.modules['__main__']), FakeModule) - - def setUp(self): - """ - Replace the __main__ module with a fake one, so that it can be mutated - in tests - """ - self.realMain = sys.modules['__main__'] - self.fakeMain = sys.modules['__main__'] = FakeModule() - - def tearDown(self): - """ - Restore __main__ to its original value - """ - sys.modules['__main__'] = self.realMain - diff --git a/tools/buildbot/pylibs/twisted/test/test_socks.py b/tools/buildbot/pylibs/twisted/test/test_socks.py deleted file mode 100644 index 28df92c..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_socks.py +++ /dev/null @@ -1,280 +0,0 @@ -"""SOCKS unit tests.""" - -from twisted.trial import unittest -from twisted.test import proto_helpers -import struct, socket -from twisted.internet import defer, address -from twisted.protocols import socks - -class StringTCPTransport(proto_helpers.StringTransport): - stringTCPTransport_closing = False - peer = None - - def getPeer(self): - return self.peer - - def getHost(self): - return address.IPv4Address('TCP', '2.3.4.5', 42) - - def loseConnection(self): - self.stringTCPTransport_closing = True - - -class SOCKSv4Driver(socks.SOCKSv4): - # last SOCKSv4Outgoing instantiated - driver_outgoing = None - - # last SOCKSv4IncomingFactory instantiated - driver_listen = None - - def connectClass(self, host, port, klass, *args): - # fake it - proto = klass(*args) - proto.transport = StringTCPTransport() - proto.transport.peer = address.IPv4Address('TCP', host, port) - proto.connectionMade() - self.driver_outgoing = proto - return defer.succeed(proto) - - def listenClass(self, port, klass, *args): - # fake it - factory = klass(*args) - self.driver_listen = factory - if port == 0: - port = 1234 - return defer.succeed(('6.7.8.9', port)) - -class Connect(unittest.TestCase): - def setUp(self): - self.sock = SOCKSv4Driver() - self.sock.transport = StringTCPTransport() - self.sock.connectionMade() - - def tearDown(self): - outgoing = self.sock.driver_outgoing - if outgoing is not None: - self.assert_(outgoing.transport.stringTCPTransport_closing, - "Outgoing SOCKS connections need to be closed.") - - def test_simple(self): - self.sock.dataReceived( - struct.pack('!BBH', 4, 1, 34) - + socket.inet_aton('1.2.3.4') - + 'fooBAR' - + '\0') - sent = self.sock.transport.value() - self.sock.transport.clear() - self.assertEqual(sent, - struct.pack('!BBH', 0, 90, 34) - + socket.inet_aton('1.2.3.4')) - self.assert_(not self.sock.transport.stringTCPTransport_closing) - self.assert_(self.sock.driver_outgoing is not None) - - # pass some data through - self.sock.dataReceived('hello, world') - self.assertEqual(self.sock.driver_outgoing.transport.value(), - 'hello, world') - - # the other way around - self.sock.driver_outgoing.dataReceived('hi there') - self.assertEqual(self.sock.transport.value(), 'hi there') - - self.sock.connectionLost('fake reason') - - def test_access_denied(self): - self.sock.authorize = lambda code, server, port, user: 0 - self.sock.dataReceived( - struct.pack('!BBH', 4, 1, 4242) - + socket.inet_aton('10.2.3.4') - + 'fooBAR' - + '\0') - self.assertEqual(self.sock.transport.value(), - struct.pack('!BBH', 0, 91, 0) - + socket.inet_aton('0.0.0.0')) - self.assert_(self.sock.transport.stringTCPTransport_closing) - self.assertIdentical(self.sock.driver_outgoing, None) - - def test_eof_remote(self): - self.sock.dataReceived( - struct.pack('!BBH', 4, 1, 34) - + socket.inet_aton('1.2.3.4') - + 'fooBAR' - + '\0') - sent = self.sock.transport.value() - self.sock.transport.clear() - - # pass some data through - self.sock.dataReceived('hello, world') - self.assertEqual(self.sock.driver_outgoing.transport.value(), - 'hello, world') - - # now close it from the server side - self.sock.driver_outgoing.transport.loseConnection() - self.sock.driver_outgoing.connectionLost('fake reason') - - def test_eof_local(self): - self.sock.dataReceived( - struct.pack('!BBH', 4, 1, 34) - + socket.inet_aton('1.2.3.4') - + 'fooBAR' - + '\0') - sent = self.sock.transport.value() - self.sock.transport.clear() - - # pass some data through - self.sock.dataReceived('hello, world') - self.assertEqual(self.sock.driver_outgoing.transport.value(), - 'hello, world') - - # now close it from the client side - self.sock.connectionLost('fake reason') - -class Bind(unittest.TestCase): - def setUp(self): - self.sock = SOCKSv4Driver() - self.sock.transport = StringTCPTransport() - self.sock.connectionMade() - -## def tearDown(self): -## # TODO ensure the listen port is closed -## listen = self.sock.driver_listen -## if listen is not None: -## self.assert_(incoming.transport.stringTCPTransport_closing, -## "Incoming SOCKS connections need to be closed.") - - def test_simple(self): - self.sock.dataReceived( - struct.pack('!BBH', 4, 2, 34) - + socket.inet_aton('1.2.3.4') - + 'fooBAR' - + '\0') - sent = self.sock.transport.value() - self.sock.transport.clear() - self.assertEqual(sent, - struct.pack('!BBH', 0, 90, 1234) - + socket.inet_aton('6.7.8.9')) - self.assert_(not self.sock.transport.stringTCPTransport_closing) - self.assert_(self.sock.driver_listen is not None) - - # connect - incoming = self.sock.driver_listen.buildProtocol(('1.2.3.4', 5345)) - self.assertNotIdentical(incoming, None) - incoming.transport = StringTCPTransport() - incoming.connectionMade() - - # now we should have the second reply packet - sent = self.sock.transport.value() - self.sock.transport.clear() - self.assertEqual(sent, - struct.pack('!BBH', 0, 90, 0) - + socket.inet_aton('0.0.0.0')) - self.assert_(not self.sock.transport.stringTCPTransport_closing) - - # pass some data through - self.sock.dataReceived('hello, world') - self.assertEqual(incoming.transport.value(), - 'hello, world') - - # the other way around - incoming.dataReceived('hi there') - self.assertEqual(self.sock.transport.value(), 'hi there') - - self.sock.connectionLost('fake reason') - - def test_access_denied(self): - self.sock.authorize = lambda code, server, port, user: 0 - self.sock.dataReceived( - struct.pack('!BBH', 4, 2, 4242) - + socket.inet_aton('10.2.3.4') - + 'fooBAR' - + '\0') - self.assertEqual(self.sock.transport.value(), - struct.pack('!BBH', 0, 91, 0) - + socket.inet_aton('0.0.0.0')) - self.assert_(self.sock.transport.stringTCPTransport_closing) - self.assertIdentical(self.sock.driver_listen, None) - - def test_eof_remote(self): - self.sock.dataReceived( - struct.pack('!BBH', 4, 2, 34) - + socket.inet_aton('1.2.3.4') - + 'fooBAR' - + '\0') - sent = self.sock.transport.value() - self.sock.transport.clear() - - # connect - incoming = self.sock.driver_listen.buildProtocol(('1.2.3.4', 5345)) - self.assertNotIdentical(incoming, None) - incoming.transport = StringTCPTransport() - incoming.connectionMade() - - # now we should have the second reply packet - sent = self.sock.transport.value() - self.sock.transport.clear() - self.assertEqual(sent, - struct.pack('!BBH', 0, 90, 0) - + socket.inet_aton('0.0.0.0')) - self.assert_(not self.sock.transport.stringTCPTransport_closing) - - # pass some data through - self.sock.dataReceived('hello, world') - self.assertEqual(incoming.transport.value(), - 'hello, world') - - # now close it from the server side - incoming.transport.loseConnection() - incoming.connectionLost('fake reason') - - def test_eof_local(self): - self.sock.dataReceived( - struct.pack('!BBH', 4, 2, 34) - + socket.inet_aton('1.2.3.4') - + 'fooBAR' - + '\0') - sent = self.sock.transport.value() - self.sock.transport.clear() - - # connect - incoming = self.sock.driver_listen.buildProtocol(('1.2.3.4', 5345)) - self.assertNotIdentical(incoming, None) - incoming.transport = StringTCPTransport() - incoming.connectionMade() - - # now we should have the second reply packet - sent = self.sock.transport.value() - self.sock.transport.clear() - self.assertEqual(sent, - struct.pack('!BBH', 0, 90, 0) - + socket.inet_aton('0.0.0.0')) - self.assert_(not self.sock.transport.stringTCPTransport_closing) - - # pass some data through - self.sock.dataReceived('hello, world') - self.assertEqual(incoming.transport.value(), - 'hello, world') - - # now close it from the client side - self.sock.connectionLost('fake reason') - - def test_bad_source(self): - self.sock.dataReceived( - struct.pack('!BBH', 4, 2, 34) - + socket.inet_aton('1.2.3.4') - + 'fooBAR' - + '\0') - sent = self.sock.transport.value() - self.sock.transport.clear() - - # connect from WRONG address - incoming = self.sock.driver_listen.buildProtocol(('1.6.6.6', 666)) - self.assertIdentical(incoming, None) - - # Now we should have the second reply packet and it should - # be a failure. The connection should be closing. - sent = self.sock.transport.value() - self.sock.transport.clear() - self.assertEqual(sent, - struct.pack('!BBH', 0, 91, 0) - + socket.inet_aton('0.0.0.0')) - self.assert_(self.sock.transport.stringTCPTransport_closing) diff --git a/tools/buildbot/pylibs/twisted/test/test_split_compat.py b/tools/buildbot/pylibs/twisted/test/test_split_compat.py deleted file mode 100644 index fe3be37..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_split_compat.py +++ /dev/null @@ -1,35 +0,0 @@ -import os, string, shutil - -from twisted.trial import unittest, util -from twisted.python import reflect - - -movedModules = [('twisted.protocols.smtp', 'twisted.mail.smtp'), - ('twisted.protocols.imap4', 'twisted.mail.imap4'), - ('twisted.protocols.pop3', 'twisted.mail.pop3'), - ('twisted.protocols.dns', 'twisted.names.dns'), - ('twisted.protocols.ethernet', 'twisted.pair.ethernet'), - ('twisted.protocols.raw', 'twisted.pair.raw'), - ('twisted.protocols.rawudp', 'twisted.pair.rawudp'), - ('twisted.protocols.ip', 'twisted.pair.ip'), - ('twisted.protocols.irc', 'twisted.words.protocols.irc'), - ('twisted.protocols.msn', 'twisted.words.protocols.msn'), - ('twisted.protocols.toc', 'twisted.words.protocols.toc'), - ('twisted.protocols.oscar', 'twisted.words.protocols.oscar'), - ] - - -class TestCompatibility(unittest.TestCase): - def testCompatibility(self): - for oldName, newName in movedModules: - try: - old = reflect.namedModule(oldName) - new = reflect.namedModule(newName) - except ImportError, e: - continue - for someName in vars(new): - if someName == '__doc__': - continue - self.assertIdentical(getattr(old, someName), - getattr(new, someName)) - testCompatibility.suppress = [util.suppress(category=DeprecationWarning)] diff --git a/tools/buildbot/pylibs/twisted/test/test_ssl.py b/tools/buildbot/pylibs/twisted/test/test_ssl.py deleted file mode 100644 index 1589299..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_ssl.py +++ /dev/null @@ -1,431 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -from twisted.trial import unittest, util as trial_util -from twisted.internet import protocol, reactor, interfaces, defer -from twisted.protocols import basic -from twisted.python import util, log -from twisted.python.runtime import platform -from twisted.test.test_tcp import WriteDataTestCase, ProperlyCloseFilesMixin - -import os, errno - -try: - from OpenSSL import SSL, crypto - from twisted.internet import ssl - from twisted.test.ssl_helpers import ClientTLSContext -except ImportError: - def _noSSL(): - # ugh, make pyflakes happy. - global SSL - global ssl - SSL = ssl = None - _noSSL() - -certPath = util.sibpath(__file__, "server.pem") - -class UnintelligentProtocol(basic.LineReceiver): - pretext = [ - "first line", - "last thing before tls starts", - "STARTTLS"] - - posttext = [ - "first thing after tls started", - "last thing ever"] - - def connectionMade(self): - for l in self.pretext: - self.sendLine(l) - - def lineReceived(self, line): - if line == "READY": - self.transport.startTLS(ClientTLSContext(), self.factory.client) - for l in self.posttext: - self.sendLine(l) - self.transport.loseConnection() - - -class LineCollector(basic.LineReceiver): - def __init__(self, doTLS, fillBuffer=0): - self.doTLS = doTLS - self.fillBuffer = fillBuffer - - def connectionMade(self): - self.factory.rawdata = '' - self.factory.lines = [] - - def lineReceived(self, line): - self.factory.lines.append(line) - if line == 'STARTTLS': - if self.fillBuffer: - for x in range(500): - self.sendLine('X'*1000) - self.sendLine('READY') - if self.doTLS: - ctx = ServerTLSContext( - privateKeyFileName=certPath, - certificateFileName=certPath, - ) - self.transport.startTLS(ctx, self.factory.server) - else: - self.setRawMode() - - def rawDataReceived(self, data): - self.factory.rawdata += data - self.factory.done = 1 - - def connectionLost(self, reason): - self.factory.done = 1 - - -class SingleLineServerProtocol(protocol.Protocol): - def connectionMade(self): - self.transport.identifier = 'SERVER' - self.transport.write("+OK \r\n") - self.transport.getPeerCertificate() - - -class RecordingClientProtocol(protocol.Protocol): - def connectionMade(self): - self.transport.identifier = 'CLIENT' - self.buffer = [] - self.transport.getPeerCertificate() - - def dataReceived(self, data): - self.factory.buffer.append(data) - - -class ImmediatelyDisconnectingProtocol(protocol.Protocol): - def connectionMade(self): - self.transport.loseConnection() - - def connectionLost(self, reason): - self.factory.connectionDisconnected.callback(None) - - -class AlmostImmediatelyDisconnectingProtocol(protocol.Protocol): - def connectionMade(self): - # Twisted's SSL support is terribly broken. - reactor.callLater(0.1, self.transport.loseConnection) - - def connectionLost(self, reason): - self.factory.connectionDisconnected.callback(reason) - - -def generateCertificateObjects(organization, organizationalUnit): - pkey = crypto.PKey() - pkey.generate_key(crypto.TYPE_RSA, 512) - req = crypto.X509Req() - subject = req.get_subject() - subject.O = organization - subject.OU = organizationalUnit - req.set_pubkey(pkey) - req.sign(pkey, "md5") - - # Here comes the actual certificate - cert = crypto.X509() - cert.set_serial_number(1) - cert.gmtime_adj_notBefore(0) - cert.gmtime_adj_notAfter(60) # Testing certificates need not be long lived - cert.set_issuer(req.get_subject()) - cert.set_subject(req.get_subject()) - cert.set_pubkey(req.get_pubkey()) - cert.sign(pkey, "md5") - - return pkey, req, cert - - -def generateCertificateFiles(basename, organization, organizationalUnit): - pkey, req, cert = generateCertificateObjects(organization, organizationalUnit) - - for ext, obj, dumpFunc in [ - ('key', pkey, crypto.dump_privatekey), - ('req', req, crypto.dump_certificate_request), - ('cert', cert, crypto.dump_certificate)]: - fName = os.extsep.join((basename, ext)) - fObj = file(fName, 'w') - fObj.write(dumpFunc(crypto.FILETYPE_PEM, obj)) - fObj.close() - - -class ContextGeneratingMixin: - def makeContextFactory(self, org, orgUnit, *args, **kwArgs): - base = self.mktemp() - generateCertificateFiles(base, org, orgUnit) - serverCtxFactory = ssl.DefaultOpenSSLContextFactory( - os.extsep.join((base, 'key')), - os.extsep.join((base, 'cert')), - *args, **kwArgs) - - return base, serverCtxFactory - - def setupServerAndClient(self, clientArgs, clientKwArgs, serverArgs, serverKwArgs): - self.clientBase, self.clientCtxFactory = self.makeContextFactory( - *clientArgs, **clientKwArgs) - self.serverBase, self.serverCtxFactory = self.makeContextFactory( - *serverArgs, **serverKwArgs) - - -if SSL is not None: - class ServerTLSContext(ssl.DefaultOpenSSLContextFactory): - isClient = 0 - def __init__(self, *args, **kw): - kw['sslmethod'] = SSL.TLSv1_METHOD - ssl.DefaultOpenSSLContextFactory.__init__(self, *args, **kw) - - -class StolenTCPTestCase(ProperlyCloseFilesMixin, WriteDataTestCase): - """ - For SSL transports, test many of the same things which are tested for - TCP transports. - """ - def createServer(self, address, portNumber, factory): - contextFactory = ssl.CertificateOptions() - return reactor.listenSSL( - portNumber, factory, contextFactory, interface=address) - - - def connectClient(self, address, portNumber, clientCreator): - contextFactory = ssl.CertificateOptions() - return clientCreator.connectSSL(address, portNumber, contextFactory) - - - def getHandleExceptionType(self): - return SSL.SysCallError - - - def getHandleErrorCode(self): - # Windows 2000 SP 4 and Windows XP SP 2 give back WSAENOTSOCK for - # SSL.Connection.write for some reason. - if platform.getType() == 'win32': - return errno.WSAENOTSOCK - return ProperlyCloseFilesMixin.getHandleErrorCode(self) - - -class TLSTestCase(unittest.TestCase): - fillBuffer = 0 - - port = None - clientProto = None - serverProto = None - - def tearDown(self): - if self.clientProto is not None and self.clientProto.transport is not None: - self.clientProto.transport.loseConnection() - if self.serverProto is not None and self.serverProto.transport is not None: - self.serverProto.transport.loseConnection() - - if self.port is not None: - return defer.maybeDeferred(self.port.stopListening) - - def _runTest(self, clientProto, serverProto, clientIsServer=False): - self.clientProto = clientProto - cf = self.clientFactory = protocol.ClientFactory() - cf.protocol = lambda: clientProto - if clientIsServer: - cf.server = 0 - else: - cf.client = 1 - - self.serverProto = serverProto - sf = self.serverFactory = protocol.ServerFactory() - sf.protocol = lambda: serverProto - if clientIsServer: - sf.client = 0 - else: - sf.server = 1 - - if clientIsServer: - inCharge = cf - else: - inCharge = sf - inCharge.done = 0 - - port = self.port = reactor.listenTCP(0, sf, interface="127.0.0.1") - portNo = port.getHost().port - - reactor.connectTCP('127.0.0.1', portNo, cf) - - i = 0 - while i < 1000 and not inCharge.done: - reactor.iterate(0.01) - i += 1 - self.failUnless( - inCharge.done, - "Never finished reading all lines: %s" % (inCharge.lines,)) - - - def testTLS(self): - self._runTest(UnintelligentProtocol(), LineCollector(1, self.fillBuffer)) - self.assertEquals( - self.serverFactory.lines, - UnintelligentProtocol.pretext + UnintelligentProtocol.posttext - ) - - - def testUnTLS(self): - self._runTest(UnintelligentProtocol(), LineCollector(0, self.fillBuffer)) - self.assertEquals( - self.serverFactory.lines, - UnintelligentProtocol.pretext - ) - self.failUnless(self.serverFactory.rawdata, "No encrypted bytes received") - - - def testBackwardsTLS(self): - self._runTest(LineCollector(1, self.fillBuffer), UnintelligentProtocol(), True) - self.assertEquals( - self.clientFactory.lines, - UnintelligentProtocol.pretext + UnintelligentProtocol.posttext - ) - - - -_bufferedSuppression = trial_util.suppress( - message="startTLS with unwritten buffered data currently doesn't work " - "right. See issue #686. Closing connection.", - category=RuntimeWarning) - - -class SpammyTLSTestCase(TLSTestCase): - """ - Test TLS features with bytes sitting in the out buffer. - """ - fillBuffer = 1 - - def testTLS(self): - return TLSTestCase.testTLS(self) - testTLS.suppress = [_bufferedSuppression] - testTLS.todo = "startTLS doesn't empty buffer before starting TLS. :(" - - - def testBackwardsTLS(self): - return TLSTestCase.testBackwardsTLS(self) - testBackwardsTLS.suppress = [_bufferedSuppression] - testBackwardsTLS.todo = "startTLS doesn't empty buffer before starting TLS. :(" - - -class BufferingTestCase(unittest.TestCase): - port = None - connector = None - serverProto = None - clientProto = None - - def tearDown(self): - if self.serverProto is not None and self.serverProto.transport is not None: - self.serverProto.transport.loseConnection() - if self.clientProto is not None and self.clientProto.transport is not None: - self.clientProto.transport.loseConnection() - if self.port is not None: - return defer.maybeDeferred(self.port.stopListening) - - def testOpenSSLBuffering(self): - serverProto = self.serverProto = SingleLineServerProtocol() - clientProto = self.clientProto = RecordingClientProtocol() - - server = protocol.ServerFactory() - client = self.client = protocol.ClientFactory() - - server.protocol = lambda: serverProto - client.protocol = lambda: clientProto - client.buffer = [] - - sCTX = ssl.DefaultOpenSSLContextFactory(certPath, certPath) - cCTX = ssl.ClientContextFactory() - - port = self.port = reactor.listenSSL(0, server, sCTX, interface='127.0.0.1') - reactor.connectSSL('127.0.0.1', port.getHost().port, client, cCTX) - - i = 0 - while i < 5000 and not client.buffer: - i += 1 - reactor.iterate() - - self.assertEquals(client.buffer, ["+OK \r\n"]) - - -class ConnectionLostTestCase(unittest.TestCase, ContextGeneratingMixin): - - def testImmediateDisconnect(self): - org = "twisted.test.test_ssl" - self.setupServerAndClient( - (org, org + ", client"), {}, - (org, org + ", server"), {}) - - # Set up a server, connect to it with a client, which should work since our verifiers - # allow anything, then disconnect. - serverProtocolFactory = protocol.ServerFactory() - serverProtocolFactory.protocol = protocol.Protocol - self.serverPort = serverPort = reactor.listenSSL(0, - serverProtocolFactory, self.serverCtxFactory) - - clientProtocolFactory = protocol.ClientFactory() - clientProtocolFactory.protocol = ImmediatelyDisconnectingProtocol - clientProtocolFactory.connectionDisconnected = defer.Deferred() - clientConnector = reactor.connectSSL('127.0.0.1', - serverPort.getHost().port, clientProtocolFactory, self.clientCtxFactory) - - return clientProtocolFactory.connectionDisconnected.addCallback( - lambda ignoredResult: self.serverPort.stopListening()) - - def testFailedVerify(self): - org = "twisted.test.test_ssl" - self.setupServerAndClient( - (org, org + ", client"), {}, - (org, org + ", server"), {}) - - def verify(*a): - return False - self.clientCtxFactory.getContext().set_verify(SSL.VERIFY_PEER, verify) - - serverConnLost = defer.Deferred() - serverProtocol = protocol.Protocol() - serverProtocol.connectionLost = serverConnLost.callback - serverProtocolFactory = protocol.ServerFactory() - serverProtocolFactory.protocol = lambda: serverProtocol - self.serverPort = serverPort = reactor.listenSSL(0, - serverProtocolFactory, self.serverCtxFactory) - - clientConnLost = defer.Deferred() - clientProtocol = protocol.Protocol() - clientProtocol.connectionLost = clientConnLost.callback - clientProtocolFactory = protocol.ClientFactory() - clientProtocolFactory.protocol = lambda: clientProtocol - clientConnector = reactor.connectSSL('127.0.0.1', - serverPort.getHost().port, clientProtocolFactory, self.clientCtxFactory) - - dl = defer.DeferredList([serverConnLost, clientConnLost], consumeErrors=True) - return dl.addCallback(self._cbLostConns) - - def _cbLostConns(self, results): - (sSuccess, sResult), (cSuccess, cResult) = results - - self.failIf(sSuccess) - self.failIf(cSuccess) - - acceptableErrors = [SSL.Error] - - # Rather than getting a verification failure on Windows, we are getting - # a connection failure. Without something like sslverify proxying - # in-between we can't fix up the platform's errors, so let's just - # specifically say it is only OK in this one case to keep the tests - # passing. Normally we'd like to be as strict as possible here, so - # we're not going to allow this to report errors incorrectly on any - # other platforms. - - if platform.isWindows(): - from twisted.internet.error import ConnectionLost - acceptableErrors.append(ConnectionLost) - - sResult.trap(*acceptableErrors) - cResult.trap(*acceptableErrors) - - return self.serverPort.stopListening() - - -if interfaces.IReactorSSL(reactor, None) is None: - for tCase in [StolenTCPTestCase, TLSTestCase, SpammyTLSTestCase, - BufferingTestCase, ConnectionLostTestCase]: - tCase.skip = "Reactor does not support SSL, cannot run SSL tests" diff --git a/tools/buildbot/pylibs/twisted/test/test_sslverify.py b/tools/buildbot/pylibs/twisted/test/test_sslverify.py deleted file mode 100644 index ad05b9f..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_sslverify.py +++ /dev/null @@ -1,534 +0,0 @@ -# Copyright 2005 Divmod, Inc. See LICENSE file for details -# Copyright (c) 2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -import itertools - -try: - from OpenSSL import SSL - from OpenSSL.crypto import PKey, X509, X509Req - from OpenSSL.crypto import TYPE_RSA - from twisted.internet import _sslverify as sslverify -except ImportError: - pass - -from twisted.trial import unittest -from twisted.internet import protocol, defer, reactor -from twisted.python.reflect import objgrep, isSame -from twisted.python import log - -from twisted.internet.error import CertificateError, ConnectionLost -from twisted.internet import interfaces - - -# A couple of static PEM-format certificates to be used by various tests. -A_HOST_CERTIFICATE_PEM = """ ------BEGIN CERTIFICATE----- - MIIC2jCCAkMCAjA5MA0GCSqGSIb3DQEBBAUAMIG0MQswCQYDVQQGEwJVUzEiMCAG - A1UEAxMZZXhhbXBsZS50d2lzdGVkbWF0cml4LmNvbTEPMA0GA1UEBxMGQm9zdG9u - MRwwGgYDVQQKExNUd2lzdGVkIE1hdHJpeCBMYWJzMRYwFAYDVQQIEw1NYXNzYWNo - dXNldHRzMScwJQYJKoZIhvcNAQkBFhhub2JvZHlAdHdpc3RlZG1hdHJpeC5jb20x - ETAPBgNVBAsTCFNlY3VyaXR5MB4XDTA2MDgxNjAxMDEwOFoXDTA3MDgxNjAxMDEw - OFowgbQxCzAJBgNVBAYTAlVTMSIwIAYDVQQDExlleGFtcGxlLnR3aXN0ZWRtYXRy - aXguY29tMQ8wDQYDVQQHEwZCb3N0b24xHDAaBgNVBAoTE1R3aXN0ZWQgTWF0cml4 - IExhYnMxFjAUBgNVBAgTDU1hc3NhY2h1c2V0dHMxJzAlBgkqhkiG9w0BCQEWGG5v - Ym9keUB0d2lzdGVkbWF0cml4LmNvbTERMA8GA1UECxMIU2VjdXJpdHkwgZ8wDQYJ - KoZIhvcNAQEBBQADgY0AMIGJAoGBAMzH8CDF/U91y/bdbdbJKnLgnyvQ9Ig9ZNZp - 8hpsu4huil60zF03+Lexg2l1FIfURScjBuaJMR6HiMYTMjhzLuByRZ17KW4wYkGi - KXstz03VIKy4Tjc+v4aXFI4XdRw10gGMGQlGGscXF/RSoN84VoDKBfOMWdXeConJ - VyC4w3iJAgMBAAEwDQYJKoZIhvcNAQEEBQADgYEAviMT4lBoxOgQy32LIgZ4lVCj - JNOiZYg8GMQ6y0ugp86X80UjOvkGtNf/R7YgED/giKRN/q/XJiLJDEhzknkocwmO - S+4b2XpiaZYxRyKWwL221O7CGmtWYyZl2+92YYmmCiNzWQPfP6BOMlfax0AGLHls - fXzCWdG0O/3Lk2SRM0I= ------END CERTIFICATE----- -""" - -A_PEER_CERTIFICATE_PEM = """ ------BEGIN CERTIFICATE----- - MIIC3jCCAkcCAjA6MA0GCSqGSIb3DQEBBAUAMIG2MQswCQYDVQQGEwJVUzEiMCAG - A1UEAxMZZXhhbXBsZS50d2lzdGVkbWF0cml4LmNvbTEPMA0GA1UEBxMGQm9zdG9u - MRwwGgYDVQQKExNUd2lzdGVkIE1hdHJpeCBMYWJzMRYwFAYDVQQIEw1NYXNzYWNo - dXNldHRzMSkwJwYJKoZIhvcNAQkBFhpzb21lYm9keUB0d2lzdGVkbWF0cml4LmNv - bTERMA8GA1UECxMIU2VjdXJpdHkwHhcNMDYwODE2MDEwMTU2WhcNMDcwODE2MDEw - MTU2WjCBtjELMAkGA1UEBhMCVVMxIjAgBgNVBAMTGWV4YW1wbGUudHdpc3RlZG1h - dHJpeC5jb20xDzANBgNVBAcTBkJvc3RvbjEcMBoGA1UEChMTVHdpc3RlZCBNYXRy - aXggTGFiczEWMBQGA1UECBMNTWFzc2FjaHVzZXR0czEpMCcGCSqGSIb3DQEJARYa - c29tZWJvZHlAdHdpc3RlZG1hdHJpeC5jb20xETAPBgNVBAsTCFNlY3VyaXR5MIGf - MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCnm+WBlgFNbMlHehib9ePGGDXF+Nz4 - CjGuUmVBaXCRCiVjg3kSDecwqfb0fqTksBZ+oQ1UBjMcSh7OcvFXJZnUesBikGWE - JE4V8Bjh+RmbJ1ZAlUPZ40bAkww0OpyIRAGMvKG+4yLFTO4WDxKmfDcrOb6ID8WJ - e1u+i3XGkIf/5QIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAD4Oukm3YYkhedUepBEA - vvXIQhVDqL7mk6OqYdXmNj6R7ZMC8WWvGZxrzDI1bZuB+4aIxxd1FXC3UOHiR/xg - i9cDl1y8P/qRp4aEBNF6rI0D4AxTbfnHQx4ERDAOShJdYZs/2zifPJ6va6YvrEyr - yqDtGhklsWW3ZwBzEh5VEOUp ------END CERTIFICATE----- -""" - - - -counter = itertools.count().next -def makeCertificate(**kw): - keypair = PKey() - keypair.generate_key(TYPE_RSA, 512) - - certificate = X509() - certificate.gmtime_adj_notBefore(0) - certificate.gmtime_adj_notAfter(60 * 60 * 24 * 365) # One year - for xname in certificate.get_issuer(), certificate.get_subject(): - for (k, v) in kw.items(): - setattr(xname, k, v) - - certificate.set_serial_number(counter()) - certificate.set_pubkey(keypair) - certificate.sign(keypair, "md5") - - return keypair, certificate - - - -class DataCallbackProtocol(protocol.Protocol): - def dataReceived(self, data): - d, self.factory.onData = self.factory.onData, None - if d is not None: - d.callback(data) - - def connectionLost(self, reason): - d, self.factory.onLost = self.factory.onLost, None - if d is not None: - d.errback(reason) - -class WritingProtocol(protocol.Protocol): - byte = 'x' - def connectionMade(self): - self.transport.write(self.byte) - - def connectionLost(self, reason): - self.factory.onLost.errback(reason) - - -class OpenSSLOptions(unittest.TestCase): - serverPort = clientConn = None - onServerLost = onClientLost = None - - sKey = None - sCert = None - cKey = None - cCert = None - - def setUp(self): - """ - Create class variables of client and server certificates. - """ - self.sKey, self.sCert = makeCertificate( - O="Server Test Certificate", - CN="server") - self.cKey, self.cCert = makeCertificate( - O="Client Test Certificate", - CN="client") - - def tearDown(self): - if self.serverPort is not None: - self.serverPort.stopListening() - if self.clientConn is not None: - self.clientConn.disconnect() - - L = [] - if self.onServerLost is not None: - L.append(self.onServerLost) - if self.onClientLost is not None: - L.append(self.onClientLost) - - return defer.DeferredList(L, consumeErrors=True) - - def loopback(self, serverCertOpts, clientCertOpts, - onServerLost=None, onClientLost=None, onData=None): - if onServerLost is None: - self.onServerLost = onServerLost = defer.Deferred() - if onClientLost is None: - self.onClientLost = onClientLost = defer.Deferred() - if onData is None: - onData = defer.Deferred() - - serverFactory = protocol.ServerFactory() - serverFactory.protocol = DataCallbackProtocol - serverFactory.onLost = onServerLost - serverFactory.onData = onData - - clientFactory = protocol.ClientFactory() - clientFactory.protocol = WritingProtocol - clientFactory.onLost = onClientLost - - self.serverPort = reactor.listenSSL(0, serverFactory, serverCertOpts) - self.clientConn = reactor.connectSSL('127.0.0.1', - self.serverPort.getHost().port, clientFactory, clientCertOpts) - - def test_abbreviatingDistinguishedNames(self): - """ - Check that abbreviations used in certificates correctly map to - complete names. - """ - self.assertEquals( - sslverify.DN(CN='a', OU='hello'), - sslverify.DistinguishedName(commonName='a', - organizationalUnitName='hello')) - self.assertNotEquals( - sslverify.DN(CN='a', OU='hello'), - sslverify.DN(CN='a', OU='hello', emailAddress='xxx')) - dn = sslverify.DN(CN='abcdefg') - self.assertRaises(AttributeError, setattr, dn, 'Cn', 'x') - self.assertEquals(dn.CN, dn.commonName) - dn.CN = 'bcdefga' - self.assertEquals(dn.CN, dn.commonName) - - - def testInspectDistinguishedName(self): - n = sslverify.DN(commonName='common name', - organizationName='organization name', - organizationalUnitName='organizational unit name', - localityName='locality name', - stateOrProvinceName='state or province name', - countryName='country name', - emailAddress='email address') - s = n.inspect() - for k in [ - 'common name', - 'organization name', - 'organizational unit name', - 'locality name', - 'state or province name', - 'country name', - 'email address']: - self.assertIn(k, s, "%r was not in inspect output." % (k,)) - self.assertIn(k.title(), s, "%r was not in inspect output." % (k,)) - - - def testInspectDistinguishedNameWithoutAllFields(self): - n = sslverify.DN(localityName='locality name') - s = n.inspect() - for k in [ - 'common name', - 'organization name', - 'organizational unit name', - 'state or province name', - 'country name', - 'email address']: - self.assertNotIn(k, s, "%r was in inspect output." % (k,)) - self.assertNotIn(k.title(), s, "%r was in inspect output." % (k,)) - self.assertIn('locality name', s) - self.assertIn('Locality Name', s) - - - def test_inspectCertificate(self): - """ - Test that the C{inspect} method of L{sslverify.Certificate} returns - a human-readable string containing some basic information about the - certificate. - """ - c = sslverify.Certificate.loadPEM(A_HOST_CERTIFICATE_PEM) - self.assertEqual( - c.inspect().split('\n'), - ["Certificate For Subject:", - " Organizational Unit Name: Security", - " Organization Name: Twisted Matrix Labs", - " Common Name: example.twistedmatrix.com", - " State Or Province Name: Massachusetts", - " Country Name: US", - " Email Address: nobody@twistedmatrix.com", - " Locality Name: Boston", - "", - "Issuer:", - " Organizational Unit Name: Security", - " Organization Name: Twisted Matrix Labs", - " Common Name: example.twistedmatrix.com", - " State Or Province Name: Massachusetts", - " Country Name: US", - " Email Address: nobody@twistedmatrix.com", - " Locality Name: Boston", - "", - "Serial Number: 12345", - "Digest: C4:96:11:00:30:C3:EC:EE:A3:55:AA:ED:8C:84:85:18", - "Public Key with Hash: ff33994c80812aa95a79cdb85362d054"]) - - - def test_certificateOptionsSerialization(self): - """ - Test that __setstate__(__getstate__()) round-trips properly. - """ - firstOpts = sslverify.OpenSSLCertificateOptions( - privateKey=self.sKey, - certificate=self.sCert, - method=SSL.SSLv3_METHOD, - verify=True, - caCerts=[self.sCert], - verifyDepth=2, - requireCertificate=False, - verifyOnce=False, - enableSingleUseKeys=False, - enableSessions=False, - fixBrokenPeers=True) - context = firstOpts.getContext() - state = firstOpts.__getstate__() - - # The context shouldn't be in the state to serialize - self.failIf(objgrep(state, context, isSame), - objgrep(state, context, isSame)) - - opts = sslverify.OpenSSLCertificateOptions() - opts.__setstate__(state) - self.assertEqual(opts.privateKey, self.sKey) - self.assertEqual(opts.certificate, self.sCert) - self.assertEqual(opts.method, SSL.SSLv3_METHOD) - self.assertEqual(opts.verify, True) - self.assertEqual(opts.caCerts, [self.sCert]) - self.assertEqual(opts.verifyDepth, 2) - self.assertEqual(opts.requireCertificate, False) - self.assertEqual(opts.verifyOnce, False) - self.assertEqual(opts.enableSingleUseKeys, False) - self.assertEqual(opts.enableSessions, False) - self.assertEqual(opts.fixBrokenPeers, True) - - - def test_allowedAnonymousClientConnection(self): - """ - Check that anonymous connections are allowed when certificates aren't - required on the server. - """ - onData = defer.Deferred() - self.loopback(sslverify.OpenSSLCertificateOptions(privateKey=self.sKey, - certificate=self.sCert, requireCertificate=False), - sslverify.OpenSSLCertificateOptions( - requireCertificate=False), - onData=onData) - - return onData.addCallback( - lambda result: self.assertEquals(result, WritingProtocol.byte)) - - def test_refusedAnonymousClientConnection(self): - """ - Check that anonymous connections are refused when certificates are - required on the server. - """ - onServerLost = defer.Deferred() - onClientLost = defer.Deferred() - self.loopback(sslverify.OpenSSLCertificateOptions(privateKey=self.sKey, - certificate=self.sCert, verify=True, - caCerts=[self.sCert], requireCertificate=True), - sslverify.OpenSSLCertificateOptions( - requireCertificate=False), - onServerLost=onServerLost, - onClientLost=onClientLost) - - d = defer.DeferredList([onClientLost, onServerLost], - consumeErrors=True) - - - def afterLost(((cSuccess, cResult), (sSuccess, sResult))): - - self.failIf(cSuccess) - self.failIf(sSuccess) - # Win32 fails to report the SSL Error, and report a connection lost - # instead: there is a race condition so that's not totally - # surprising (see ticket #2877 in the tracker) - cResult.trap(SSL.Error, ConnectionLost) - sResult.trap(SSL.Error) - - return d.addCallback(afterLost) - - def test_failedCertificateVerification(self): - """ - Check that connecting with a certificate not accepted by the server CA - fails. - """ - onServerLost = defer.Deferred() - onClientLost = defer.Deferred() - self.loopback(sslverify.OpenSSLCertificateOptions(privateKey=self.sKey, - certificate=self.sCert, verify=False, - requireCertificate=False), - sslverify.OpenSSLCertificateOptions(verify=True, - requireCertificate=False, caCerts=[self.cCert]), - onServerLost=onServerLost, - onClientLost=onClientLost) - - d = defer.DeferredList([onClientLost, onServerLost], - consumeErrors=True) - def afterLost(((cSuccess, cResult), (sSuccess, sResult))): - - self.failIf(cSuccess) - self.failIf(sSuccess) - - return d.addCallback(afterLost) - - def test_successfulCertificateVerification(self): - """ - Test a successful connection with client certificate validation on - server side. - """ - onData = defer.Deferred() - self.loopback(sslverify.OpenSSLCertificateOptions(privateKey=self.sKey, - certificate=self.sCert, verify=False, - requireCertificate=False), - sslverify.OpenSSLCertificateOptions(verify=True, - requireCertificate=True, caCerts=[self.sCert]), - onData=onData) - - return onData.addCallback( - lambda result: self.assertEquals(result, WritingProtocol.byte)) - - def test_successfulSymmetricSelfSignedCertificateVerification(self): - """ - Test a successful connection with validation on both server and client - sides. - """ - onData = defer.Deferred() - self.loopback(sslverify.OpenSSLCertificateOptions(privateKey=self.sKey, - certificate=self.sCert, verify=True, - requireCertificate=True, caCerts=[self.cCert]), - sslverify.OpenSSLCertificateOptions(privateKey=self.cKey, - certificate=self.cCert, verify=True, - requireCertificate=True, caCerts=[self.sCert]), - onData=onData) - - return onData.addCallback( - lambda result: self.assertEquals(result, WritingProtocol.byte)) - - def test_verification(self): - """ - Check certificates verification building custom certificates data. - """ - clientDN = sslverify.DistinguishedName(commonName='client') - clientKey = sslverify.KeyPair.generate() - clientCertReq = clientKey.certificateRequest(clientDN) - - serverDN = sslverify.DistinguishedName(commonName='server') - serverKey = sslverify.KeyPair.generate() - serverCertReq = serverKey.certificateRequest(serverDN) - - clientSelfCertReq = clientKey.certificateRequest(clientDN) - clientSelfCertData = clientKey.signCertificateRequest( - clientDN, clientSelfCertReq, lambda dn: True, 132) - clientSelfCert = clientKey.newCertificate(clientSelfCertData) - - serverSelfCertReq = serverKey.certificateRequest(serverDN) - serverSelfCertData = serverKey.signCertificateRequest( - serverDN, serverSelfCertReq, lambda dn: True, 516) - serverSelfCert = serverKey.newCertificate(serverSelfCertData) - - clientCertData = serverKey.signCertificateRequest( - serverDN, clientCertReq, lambda dn: True, 7) - clientCert = clientKey.newCertificate(clientCertData) - - serverCertData = clientKey.signCertificateRequest( - clientDN, serverCertReq, lambda dn: True, 42) - serverCert = serverKey.newCertificate(serverCertData) - - onData = defer.Deferred() - - serverOpts = serverCert.options(serverSelfCert) - clientOpts = clientCert.options(clientSelfCert) - - self.loopback(serverOpts, - clientOpts, - onData=onData) - - return onData.addCallback( - lambda result: self.assertEquals(result, WritingProtocol.byte)) - - - -if interfaces.IReactorSSL(reactor, None) is None: - OpenSSLOptions.skip = "Reactor does not support SSL, cannot run SSL tests" - - - -class _NotSSLTransport: - def getHandle(self): - return self - -class _MaybeSSLTransport: - def getHandle(self): - return self - - def get_peer_certificate(self): - return None - - def get_host_certificate(self): - return None - - -class _ActualSSLTransport: - def getHandle(self): - return self - - def get_host_certificate(self): - return sslverify.Certificate.loadPEM(A_HOST_CERTIFICATE_PEM).original - - def get_peer_certificate(self): - return sslverify.Certificate.loadPEM(A_PEER_CERTIFICATE_PEM).original - - -class Constructors(unittest.TestCase): - def test_peerFromNonSSLTransport(self): - """ - Verify that peerFromTransport raises an exception if the transport - passed is not actually an SSL transport. - """ - x = self.assertRaises(CertificateError, - sslverify.Certificate.peerFromTransport, - _NotSSLTransport()) - self.failUnless(str(x).startswith("non-TLS")) - - def test_peerFromBlankSSLTransport(self): - """ - Verify that peerFromTransport raises an exception if the transport - passed is an SSL transport, but doesn't have a peer certificate. - """ - x = self.assertRaises(CertificateError, - sslverify.Certificate.peerFromTransport, - _MaybeSSLTransport()) - self.failUnless(str(x).startswith("TLS")) - - def test_hostFromNonSSLTransport(self): - """ - Verify that hostFromTransport raises an exception if the transport - passed is not actually an SSL transport. - """ - x = self.assertRaises(CertificateError, - sslverify.Certificate.hostFromTransport, - _NotSSLTransport()) - self.failUnless(str(x).startswith("non-TLS")) - - def test_hostFromBlankSSLTransport(self): - """ - Verify that hostFromTransport raises an exception if the transport - passed is an SSL transport, but doesn't have a host certificate. - """ - x = self.assertRaises(CertificateError, - sslverify.Certificate.hostFromTransport, - _MaybeSSLTransport()) - self.failUnless(str(x).startswith("TLS")) - - - def test_hostFromSSLTransport(self): - """ - Verify that hostFromTransport successfully creates the correct - certificate if passed a valid SSL transport. - """ - self.assertEqual( - sslverify.Certificate.hostFromTransport( - _ActualSSLTransport()).serialNumber(), - 12345) - - def test_peerFromSSLTransport(self): - """ - Verify that peerFromTransport successfully creates the correct - certificate if passed a valid SSL transport. - """ - self.assertEqual( - sslverify.Certificate.peerFromTransport( - _ActualSSLTransport()).serialNumber(), - 12346) - - - -if interfaces.IReactorSSL(reactor, None) is None: - Constructors.skip = "Reactor does not support SSL, cannot run SSL tests" diff --git a/tools/buildbot/pylibs/twisted/test/test_stateful.py b/tools/buildbot/pylibs/twisted/test/test_stateful.py deleted file mode 100644 index 19b7ab0..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_stateful.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Test cases for twisted.protocols.stateful -""" - -from twisted.test import test_protocols -from twisted.protocols.stateful import StatefulProtocol - -from struct import pack, unpack, calcsize - - -class MyInt32StringReceiver(StatefulProtocol): - """ - A stateful Int32StringReceiver. - """ - MAX_LENGTH = 99999 - structFormat = "!I" - prefixLength = calcsize(structFormat) - - def getInitialState(self): - return self._getHeader, 4 - - def _getHeader(self, msg): - length, = unpack("!i", msg) - if length > self.MAX_LENGTH: - self.transport.loseConnection() - return - return self._getString, length - - def _getString(self, msg): - self.stringReceived(msg) - return self._getHeader, 4 - - def stringReceived(self, msg): - """ - Override this. - """ - raise NotImplementedError - - def sendString(self, data): - """ - Send an int32-prefixed string to the other end of the connection. - """ - self.transport.write(pack(self.structFormat, len(data)) + data) - - -class TestInt32(MyInt32StringReceiver): - def connectionMade(self): - self.received = [] - - def stringReceived(self, s): - self.received.append(s) - - MAX_LENGTH = 50 - closed = 0 - - def connectionLost(self, reason): - self.closed = 1 - - -class Int32TestCase(test_protocols.Int32TestCase): - protocol = TestInt32 - - def test_bigReceive(self): - r = self.getProtocol() - big = "" - for s in self.strings * 4: - big += pack("!i", len(s)) + s - r.dataReceived(big) - self.assertEquals(r.received, self.strings * 4) - diff --git a/tools/buildbot/pylibs/twisted/test/test_stdio.py b/tools/buildbot/pylibs/twisted/test/test_stdio.py deleted file mode 100644 index b47b6cf..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_stdio.py +++ /dev/null @@ -1,265 +0,0 @@ -# Copyright (c) 2006-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -import os, sys - -from twisted.trial import unittest -from twisted.python import filepath -from twisted.internet import error, defer, protocol, reactor - - -# A short string which is intended to appear here and nowhere else, -# particularly not in any random garbage output CPython unavoidable -# generates (such as in warning text and so forth). This is searched -# for in the output from stdio_test_lastwrite.py and if it is found at -# the end, the functionality works. -UNIQUE_LAST_WRITE_STRING = 'xyz123abc Twisted is great!' - - -class StandardIOTestProcessProtocol(protocol.ProcessProtocol): - """ - Test helper for collecting output from a child process and notifying - something when it exits. - - @ivar onConnection: A L{defer.Deferred} which will be called back with - C{None} when the connection to the child process is established. - - @ivar onCompletion: A L{defer.Deferred} which will be errbacked with the - failure associated with the child process exiting when it exits. - - @ivar onDataReceived: A L{defer.Deferred} which will be called back with - this instance whenever C{childDataReceived} is called, or C{None} to - suppress these callbacks. - - @ivar data: A C{dict} mapping file descriptors to strings containing all - bytes received from the child process on each file descriptor. - """ - onDataReceived = None - - def __init__(self): - self.onConnection = defer.Deferred() - self.onCompletion = defer.Deferred() - self.data = {} - - - def connectionMade(self): - self.onConnection.callback(None) - - - def childDataReceived(self, name, bytes): - """ - Record all bytes received from the child process in the C{data} - dictionary. Fire C{onDataReceived} if it is not C{None}. - """ - self.data[name] = self.data.get(name, '') + bytes - if self.onDataReceived is not None: - d, self.onDataReceived = self.onDataReceived, None - d.callback(self) - - - def processEnded(self, reason): - self.onCompletion.callback(reason) - - - -class StandardInputOutputTestCase(unittest.TestCase): - def _spawnProcess(self, proto, sibling, *args, **kw): - """ - Launch a child Python process and communicate with it using the - given ProcessProtocol. - - @param proto: A L{ProcessProtocol} instance which will be connected - to the child process. - - @param sibling: The basename of a file containing the Python program - to run in the child process. - - @param *args: strings which will be passed to the child process on - the command line as C{argv[2:]}. - - @param **kw: additional arguments to pass to L{reactor.spawnProcess}. - - @return: The L{IProcessTransport} provider for the spawned process. - """ - import twisted - subenv = dict(os.environ) - subenv['PYTHONPATH'] = os.pathsep.join( - [os.path.abspath( - os.path.dirname(os.path.dirname(twisted.__file__))), - subenv.get('PYTHONPATH', '') - ]) - args = [sys.executable, - filepath.FilePath(__file__).sibling(sibling).path, - reactor.__class__.__module__] + list(args) - return reactor.spawnProcess( - proto, - sys.executable, - args, - env=subenv, - **kw) - - - def _requireFailure(self, d, callback): - def cb(result): - self.fail("Process terminated with non-Failure: %r" % (result,)) - def eb(err): - return callback(err) - return d.addCallbacks(cb, eb) - - - def test_loseConnection(self): - """ - Verify that a protocol connected to L{StandardIO} can disconnect - itself using C{transport.loseConnection}. - """ - p = StandardIOTestProcessProtocol() - d = p.onCompletion - self._spawnProcess(p, 'stdio_test_loseconn.py') - - def processEnded(reason): - self.failIfIn(1, p.data) - reason.trap(error.ProcessDone) - return self._requireFailure(d, processEnded) - - - def test_lastWriteReceived(self): - """ - Verify that a write made directly to stdout using L{os.write} - after StandardIO has finished is reliably received by the - process reading that stdout. - """ - p = StandardIOTestProcessProtocol() - - # Note: the OS X bug which prompted the addition of this test - # is an apparent race condition involving non-blocking PTYs. - # Delaying the parent process significantly increases the - # likelihood of the race going the wrong way. If you need to - # fiddle with this code at all, uncommenting the next line - # will likely make your life much easier. It is commented out - # because it makes the test quite slow. - - # p.onConnection.addCallback(lambda ign: __import__('time').sleep(5)) - - try: - self._spawnProcess( - p, 'stdio_test_lastwrite.py', UNIQUE_LAST_WRITE_STRING, - usePTY=True) - except ValueError, e: - # Some platforms don't work with usePTY=True - raise unittest.SkipTest(str(e)) - - def processEnded(reason): - """ - Asserts that the parent received the bytes written by the child - immediately after the child starts. - """ - self.assertTrue( - p.data[1].endswith(UNIQUE_LAST_WRITE_STRING), - "Received %r from child, did not find expected bytes." % ( - p.data,)) - reason.trap(error.ProcessDone) - return self._requireFailure(p.onCompletion, processEnded) - - - def test_hostAndPeer(self): - """ - Verify that the transport of a protocol connected to L{StandardIO} - has C{getHost} and C{getPeer} methods. - """ - p = StandardIOTestProcessProtocol() - d = p.onCompletion - self._spawnProcess(p, 'stdio_test_hostpeer.py') - - def processEnded(reason): - host, peer = p.data[1].splitlines() - self.failUnless(host) - self.failUnless(peer) - reason.trap(error.ProcessDone) - return self._requireFailure(d, processEnded) - - - def test_write(self): - """ - Verify that the C{write} method of the transport of a protocol - connected to L{StandardIO} sends bytes to standard out. - """ - p = StandardIOTestProcessProtocol() - d = p.onCompletion - - self._spawnProcess(p, 'stdio_test_write.py') - - def processEnded(reason): - self.assertEquals(p.data[1], 'ok!') - reason.trap(error.ProcessDone) - return self._requireFailure(d, processEnded) - - - def test_writeSequence(self): - """ - Verify that the C{writeSequence} method of the transport of a - protocol connected to L{StandardIO} sends bytes to standard out. - """ - p = StandardIOTestProcessProtocol() - d = p.onCompletion - - self._spawnProcess(p, 'stdio_test_writeseq.py') - - def processEnded(reason): - self.assertEquals(p.data[1], 'ok!') - reason.trap(error.ProcessDone) - return self._requireFailure(d, processEnded) - - - def _junkPath(self): - junkPath = self.mktemp() - junkFile = file(junkPath, 'w') - for i in xrange(1024): - junkFile.write(str(i) + '\n') - junkFile.close() - return junkPath - - - def test_producer(self): - """ - Verify that the transport of a protocol connected to L{StandardIO} - is a working L{IProducer} provider. - """ - p = StandardIOTestProcessProtocol() - d = p.onCompletion - - written = [] - toWrite = range(100) - - def connectionMade(ign): - if toWrite: - written.append(str(toWrite.pop()) + "\n") - proc.write(written[-1]) - reactor.callLater(0.01, connectionMade, None) - - proc = self._spawnProcess(p, 'stdio_test_producer.py') - - p.onConnection.addCallback(connectionMade) - - def processEnded(reason): - self.assertEquals(p.data[1], ''.join(written)) - self.failIf(toWrite, "Connection lost with %d writes left to go." % (len(toWrite),)) - reason.trap(error.ProcessDone) - return self._requireFailure(d, processEnded) - - - def test_consumer(self): - """ - Verify that the transport of a protocol connected to L{StandardIO} - is a working L{IConsumer} provider. - """ - p = StandardIOTestProcessProtocol() - d = p.onCompletion - - junkPath = self._junkPath() - - self._spawnProcess(p, 'stdio_test_consumer.py', junkPath) - - def processEnded(reason): - self.assertEquals(p.data[1], file(junkPath).read()) - reason.trap(error.ProcessDone) - return self._requireFailure(d, processEnded) diff --git a/tools/buildbot/pylibs/twisted/test/test_strcred.py b/tools/buildbot/pylibs/twisted/test/test_strcred.py deleted file mode 100644 index 07096ca..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_strcred.py +++ /dev/null @@ -1,623 +0,0 @@ -# Copyright (c) 2007-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{strcred}. -""" - -import os -import StringIO - -from twisted import plugin -from twisted.trial import unittest -from twisted.cred import credentials, checkers, error, strcred -from twisted.plugins import cred_file, cred_anonymous -from twisted.python import usage - - -try: - import crypt -except ImportError: - crypt = None - -try: - import pwd -except ImportError: - pwd = None - -try: - import spwd -except ImportError: - spwd = None - - - -def getInvalidAuthType(): - """ - Helper method to produce an auth type that doesn't exist. - """ - invalidAuthType = 'ThisPluginDoesNotExist' - while (invalidAuthType in - [factory.authType for factory in strcred.findCheckerFactories()]): - invalidAuthType += '_' - return invalidAuthType - - - -class TestPublicAPI(unittest.TestCase): - - def test_emptyDescription(self): - """ - Test that the description string cannot be empty. - """ - iat = getInvalidAuthType() - self.assertRaises(strcred.InvalidAuthType, strcred.makeChecker, iat) - self.assertRaises(strcred.InvalidAuthType, strcred.findCheckerFactory, iat) - - - def test_invalidAuthType(self): - """ - Test that an unrecognized auth type raises an exception. - """ - iat = getInvalidAuthType() - self.assertRaises(strcred.InvalidAuthType, strcred.makeChecker, iat) - self.assertRaises(strcred.InvalidAuthType, strcred.findCheckerFactory, iat) - - - -class TestStrcredFunctions(unittest.TestCase): - - def test_findCheckerFactories(self): - """ - Test that findCheckerFactories returns all available plugins. - """ - availablePlugins = list(strcred.findCheckerFactories()) - for plg in plugin.getPlugins(strcred.ICheckerFactory): - self.assertIn(plg, availablePlugins) - - - def test_findCheckerFactory(self): - """ - Test that findCheckerFactory returns the first plugin - available for a given authentication type. - """ - self.assertIdentical(strcred.findCheckerFactory('file'), - cred_file.theFileCheckerFactory) - - - -class TestMemoryChecker(unittest.TestCase): - - def setUp(self): - self.admin = credentials.UsernamePassword('admin', 'asdf') - self.alice = credentials.UsernamePassword('alice', 'foo') - self.badPass = credentials.UsernamePassword('alice', 'foobar') - self.badUser = credentials.UsernamePassword('x', 'yz') - self.checker = strcred.makeChecker('memory:admin:asdf:alice:foo') - - - def test_isChecker(self): - """ - Verifies that strcred.makeChecker('memory') returns an object - that implements the L{ICredentialsChecker} interface. - """ - self.assertTrue(checkers.ICredentialsChecker.providedBy(self.checker)) - self.assertIn(credentials.IUsernamePassword, - self.checker.credentialInterfaces) - - - def test_badFormatArgString(self): - """ - Test that an argument string which does not contain user:pass - pairs (i.e., an odd number of ':' characters) raises an exception. - """ - self.assertRaises(strcred.InvalidAuthArgumentString, - strcred.makeChecker, 'memory:a:b:c') - - - def test_memoryCheckerSucceeds(self): - """ - Test that the checker works with valid credentials. - """ - def _gotAvatar(username): - self.assertEquals(username, self.admin.username) - return (self.checker - .requestAvatarId(self.admin) - .addCallback(_gotAvatar)) - - - def test_memoryCheckerFailsUsername(self): - """ - Test that the checker fails with an invalid username. - """ - return self.assertFailure(self.checker.requestAvatarId(self.badUser), - error.UnauthorizedLogin) - - - def test_memoryCheckerFailsPassword(self): - """ - Test that the checker fails with an invalid password. - """ - return self.assertFailure(self.checker.requestAvatarId(self.badPass), - error.UnauthorizedLogin) - - - -class TestAnonymousChecker(unittest.TestCase): - - def test_isChecker(self): - """ - Verifies that strcred.makeChecker('anonymous') returns an object - that implements the L{ICredentialsChecker} interface. - """ - checker = strcred.makeChecker('anonymous') - self.assertTrue(checkers.ICredentialsChecker.providedBy(checker)) - self.assertIn(credentials.IAnonymous, checker.credentialInterfaces) - - - def testAnonymousAccessSucceeds(self): - """ - Test that we can log in anonymously using this checker. - """ - checker = strcred.makeChecker('anonymous') - request = checker.requestAvatarId(credentials.Anonymous()) - def _gotAvatar(avatar): - self.assertIdentical(checkers.ANONYMOUS, avatar) - return request.addCallback(_gotAvatar) - - - -class TestUnixChecker(unittest.TestCase): - users = { - 'admin': 'asdf', - 'alice': 'foo', - } - - - def _pwd(self, username): - return (username, crypt.crypt(self.users[username], 'F/'), - 1000, 1000, username, '/home/'+username, '/bin/sh') - - - def _spwd(self, username): - return (username, crypt.crypt(self.users[username], 'F/'), - 0, 0, 99999, 7, -1, -1, -1) - - - def setUp(self): - self.admin = credentials.UsernamePassword('admin', 'asdf') - self.alice = credentials.UsernamePassword('alice', 'foo') - self.badPass = credentials.UsernamePassword('alice', 'foobar') - self.badUser = credentials.UsernamePassword('x', 'yz') - self.checker = strcred.makeChecker('unix') - # Hack around the pwd and spwd modules, since we can't really - # go about reading your /etc/passwd or /etc/shadow files - if pwd: - self._pwd_getpwnam = pwd.getpwnam - pwd.getpwnam = self._pwd - if spwd: - self._spwd_getspnam = spwd.getspnam - spwd.getspnam = self._spwd - - - def tearDown(self): - if pwd: - pwd.getpwnam = self._pwd_getpwnam - if spwd: - spwd.getspnam = self._spwd_getspnam - - - def test_isChecker(self): - """ - Verifies that strcred.makeChecker('unix') returns an object - that implements the L{ICredentialsChecker} interface. - """ - self.assertTrue(checkers.ICredentialsChecker.providedBy(self.checker)) - self.assertIn(credentials.IUsernamePassword, - self.checker.credentialInterfaces) - - - def test_unixCheckerSucceeds(self): - """ - Test that the checker works with valid credentials. - """ - def _gotAvatar(username): - self.assertEquals(username, self.admin.username) - return (self.checker - .requestAvatarId(self.admin) - .addCallback(_gotAvatar)) - - - def test_unixCheckerFailsUsername(self): - """ - Test that the checker fails with an invalid username. - """ - return self.assertFailure(self.checker.requestAvatarId(self.badUser), - error.UnauthorizedLogin) - - - def test_unixCheckerFailsPassword(self): - """ - Test that the checker fails with an invalid password. - """ - return self.assertFailure(self.checker.requestAvatarId(self.badPass), - error.UnauthorizedLogin) - - - if None in (pwd, spwd, crypt): - for method in (test_unixCheckerSucceeds, - test_unixCheckerFailsUsername, - test_unixCheckerFailsPassword): - method.skip = 'pwd and spwd are both unavailable' - - - -class TestFileDBChecker(unittest.TestCase): - """ - Test for the --auth=file:... file checker. - """ - - def setUp(self): - self.admin = credentials.UsernamePassword('admin', 'asdf') - self.alice = credentials.UsernamePassword('alice', 'foo') - self.badPass = credentials.UsernamePassword('alice', 'foobar') - self.badUser = credentials.UsernamePassword('x', 'yz') - self.filename = self.mktemp() - file(self.filename, 'w').write('admin:asdf\nalice:foo\n') - self.checker = strcred.makeChecker('file:' + self.filename) - - - def _fakeFilename(self): - filename = '/DoesNotExist' - while os.path.exists(filename): - filename += '_' - return filename - - - def test_isChecker(self): - """ - Verifies that strcred.makeChecker('memory') returns an object - that implements the L{ICredentialsChecker} interface. - """ - self.assertTrue(checkers.ICredentialsChecker.providedBy(self.checker)) - self.assertIn(credentials.IUsernamePassword, - self.checker.credentialInterfaces) - - - def test_fileCheckerSucceeds(self): - """ - Test that the checker works with valid credentials. - """ - def _gotAvatar(username): - self.assertEquals(username, self.admin.username) - return (self.checker - .requestAvatarId(self.admin) - .addCallback(_gotAvatar)) - - - def test_fileCheckerFailsUsername(self): - """ - Test that the checker fails with an invalid username. - """ - return self.assertFailure(self.checker.requestAvatarId(self.badUser), - error.UnauthorizedLogin) - - - def test_fileCheckerFailsPassword(self): - """ - Test that the checker fails with an invalid password. - """ - return self.assertFailure(self.checker.requestAvatarId(self.badPass), - error.UnauthorizedLogin) - - - def test_failsWithEmptyFilename(self): - """ - Test that an empty filename raises an error. - """ - self.assertRaises(ValueError, strcred.makeChecker, 'file') - self.assertRaises(ValueError, strcred.makeChecker, 'file:') - - - def test_warnWithBadFilename(self): - """ - When the file auth plugin is given a file that doesn't exist, it - should produce a warning. - """ - oldOutput = cred_file.theFileCheckerFactory.errorOutput - newOutput = StringIO.StringIO() - cred_file.theFileCheckerFactory.errorOutput = newOutput - checker = strcred.makeChecker('file:' + self._fakeFilename()) - cred_file.theFileCheckerFactory.errorOutput = oldOutput - self.assertIn(cred_file.invalidFileWarning, newOutput.getvalue()) - - - -class DummyOptions(usage.Options, strcred.AuthOptionMixin): - """ - Simple options for testing L{strcred.AuthOptionMixin}. - """ - - - -class TestCheckerOptions(unittest.TestCase): - - def test_createsList(self): - """ - Test that the --auth command line creates a list in the - Options instance and appends values to it. - """ - options = DummyOptions() - options.parseOptions(['--auth', 'memory']) - self.assertEqual(len(options['credCheckers']), 1) - options = DummyOptions() - options.parseOptions(['--auth', 'memory', '--auth', 'memory']) - self.assertEqual(len(options['credCheckers']), 2) - - - def test_invalidAuthError(self): - """ - Test that the --auth command line raises an exception when it - gets a parameter it doesn't understand. - """ - options = DummyOptions() - # If someone adds a 'ThisPluginDoesNotExist' then this unit - # test should still run. - invalidParameter = getInvalidAuthType() - self.assertRaises( - usage.UsageError, - options.parseOptions, ['--auth', invalidParameter]) - self.assertRaises( - usage.UsageError, - options.parseOptions, ['--help-auth-type', invalidParameter]) - - - def test_createsDictionary(self): - """ - Test that the --auth command line creates a dictionary - mapping supported interfaces to the list of credentials - checkers that support it. - """ - options = DummyOptions() - options.parseOptions(['--auth', 'memory', '--auth', 'anonymous']) - chd = options['credInterfaces'] - self.assertEquals(len(chd[credentials.IAnonymous]), 1) - self.assertEquals(len(chd[credentials.IUsernamePassword]), 1) - chdAnonymous = chd[credentials.IAnonymous][0] - chdUserPass = chd[credentials.IUsernamePassword][0] - self.assertTrue(checkers.ICredentialsChecker.providedBy(chdAnonymous)) - self.assertTrue(checkers.ICredentialsChecker.providedBy(chdUserPass)) - self.assertIn(credentials.IAnonymous, - chdAnonymous.credentialInterfaces) - self.assertIn(credentials.IUsernamePassword, - chdUserPass.credentialInterfaces) - - - def test_credInterfacesProvidesLists(self): - """ - Test that when two --auth arguments are passed along which - support the same interface, a list with both is created. - """ - options = DummyOptions() - options.parseOptions(['--auth', 'memory', '--auth', 'unix']) - self.assertEquals( - options['credCheckers'], - options['credInterfaces'][credentials.IUsernamePassword]) - - - def test_listDoesNotDisplayDuplicates(self): - """ - Test that the list for --help-auth does not duplicate items. - """ - authTypes = [] - options = DummyOptions() - for cf in options._checkerFactoriesForOptHelpAuth(): - self.assertNotIn(cf.authType, authTypes) - authTypes.append(cf.authType) - - - def test_displaysListCorrectly(self): - """ - Test that the --help-auth argument correctly displays all - available authentication plugins, then exits. - """ - newStdout = StringIO.StringIO() - options = DummyOptions() - options.authOutput = newStdout - self.assertRaises(SystemExit, options.parseOptions, ['--help-auth']) - for checkerFactory in strcred.findCheckerFactories(): - self.assertIn(checkerFactory.authType, newStdout.getvalue()) - - - def test_displaysHelpCorrectly(self): - """ - Test that the --help-auth-for argument will correctly display - the help file for a particular authentication plugin. - """ - newStdout = StringIO.StringIO() - options = DummyOptions() - options.authOutput = newStdout - self.assertRaises( - SystemExit, options.parseOptions, ['--help-auth-type', 'file']) - for line in cred_file.theFileCheckerFactory.authHelp: - if line.strip(): - self.assertIn(line.strip(), newStdout.getvalue()) - - - def test_unexpectedException(self): - """ - When the checker specified by --auth raises an unexpected error, it - should be caught and re-raised within a L{usage.UsageError}. - """ - options = DummyOptions() - err = self.assertRaises(usage.UsageError, options.parseOptions, - ['--auth', 'file']) - self.assertEquals(str(err), - "Unexpected error: 'file' requires a filename") - - - -class OptionsForUsernamePassword(usage.Options, strcred.AuthOptionMixin): - supportedInterfaces = (credentials.IUsernamePassword,) - - - -class OptionsForUsernameHashedPassword(usage.Options, strcred.AuthOptionMixin): - supportedInterfaces = (credentials.IUsernameHashedPassword,) - - - -class OptionsSupportsAllInterfaces(usage.Options, strcred.AuthOptionMixin): - supportedInterfaces = None - - - -class OptionsSupportsNoInterfaces(usage.Options, strcred.AuthOptionMixin): - supportedInterfaces = [] - - - -class TestLimitingInterfaces(unittest.TestCase): - """ - Tests functionality that allows an application to limit the - credential interfaces it can support. For the purposes of this - test, we use IUsernameHashedPassword, although this will never - really be used by the command line. - - (I have, to date, not thought of a half-decent way for a user to - specify a hash algorithm via the command-line. Nor do I think it's - very useful.) - - I should note that, at first, this test is counter-intuitive, - because we're using the checker with a pre-defined hash function - as the 'bad' checker. See the documentation for - L{twisted.cred.checkers.FilePasswordDB.hash} for more details. - """ - - def setUp(self): - self.filename = self.mktemp() - file(self.filename, 'w').write('admin:asdf\nalice:foo\n') - self.goodChecker = checkers.FilePasswordDB(self.filename) - self.badChecker = checkers.FilePasswordDB(self.filename, hash=self._hash) - self.anonChecker = checkers.AllowAnonymousAccess() - - - def _hash(self, networkUsername, networkPassword, storedPassword): - """ - A dumb hash that doesn't really do anything. - """ - return networkPassword - - - def test_supportsInterface(self): - """ - Test that the supportsInterface method behaves appropriately. - """ - options = OptionsForUsernamePassword() - self.assertTrue( - options.supportsInterface(credentials.IUsernamePassword)) - self.assertFalse( - options.supportsInterface(credentials.IAnonymous)) - self.assertRaises( - strcred.UnsupportedInterfaces, options.addChecker, self.anonChecker) - - - def test_supportsAllInterfaces(self): - """ - Test that the supportsInterface method behaves appropriately - when the supportedInterfaces attribute is None. - """ - options = OptionsSupportsAllInterfaces() - self.assertTrue( - options.supportsInterface(credentials.IUsernamePassword)) - self.assertTrue( - options.supportsInterface(credentials.IAnonymous)) - - - def test_supportsCheckerFactory(self): - """ - Test that the supportsCheckerFactory method behaves appropriately. - """ - options = OptionsForUsernamePassword() - fileCF = cred_file.theFileCheckerFactory - anonCF = cred_anonymous.theAnonymousCheckerFactory - self.assertTrue(options.supportsCheckerFactory(fileCF)) - self.assertFalse(options.supportsCheckerFactory(anonCF)) - - - def test_canAddSupportedChecker(self): - """ - Test that when addChecker is called with a checker that - implements at least one of the interfaces our application - supports, it is successful. - """ - options = OptionsForUsernamePassword() - options.addChecker(self.goodChecker) - iface = options.supportedInterfaces[0] - # Test that we did get IUsernamePassword - self.assertIdentical(options['credInterfaces'][iface][0], self.goodChecker) - self.assertIdentical(options['credCheckers'][0], self.goodChecker) - # Test that we didn't get IUsernameHashedPassword - self.assertEquals(len(options['credInterfaces'][iface]), 1) - self.assertEquals(len(options['credCheckers']), 1) - - - def test_failOnAddingUnsupportedChecker(self): - """ - Test that when addChecker is called with a checker that does - not implement any supported interfaces, it fails. - """ - options = OptionsForUsernameHashedPassword() - self.assertRaises(strcred.UnsupportedInterfaces, - options.addChecker, self.badChecker) - - - def test_unsupportedInterfaceError(self): - """ - Test that the --auth command line raises an exception when it - gets a checker we don't support. - """ - options = OptionsSupportsNoInterfaces() - authType = cred_anonymous.theAnonymousCheckerFactory.authType - self.assertRaises( - usage.UsageError, - options.parseOptions, ['--auth', authType]) - - - def test_helpAuthLimitsOutput(self): - """ - Test that --help-auth will only list checkers that purport to - supply at least one of the credential interfaces our - application can use. - """ - options = OptionsForUsernamePassword() - for factory in options._checkerFactoriesForOptHelpAuth(): - invalid = True - for interface in factory.credentialInterfaces: - if options.supportsInterface(interface): - invalid = False - if invalid: - raise strcred.UnsupportedInterfaces() - - - def test_helpAuthTypeLimitsOutput(self): - """ - Test that --help-auth-type will display a warning if you get - help for an authType that does not supply at least one of the - credential interfaces our application can use. - """ - options = OptionsForUsernamePassword() - # Find an interface that we can use for our test - invalidFactory = None - for factory in strcred.findCheckerFactories(): - if not options.supportsCheckerFactory(factory): - invalidFactory = factory - break - self.assertNotIdentical(invalidFactory, None) - # Capture output and make sure the warning is there - newStdout = StringIO.StringIO() - options.authOutput = newStdout - self.assertRaises(SystemExit, options.parseOptions, - ['--help-auth-type', 'anonymous']) - self.assertIn(strcred.notSupportedWarning, newStdout.getvalue()) - diff --git a/tools/buildbot/pylibs/twisted/test/test_strerror.py b/tools/buildbot/pylibs/twisted/test/test_strerror.py deleted file mode 100644 index 8918cf5..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_strerror.py +++ /dev/null @@ -1,145 +0,0 @@ -# Copyright (c) 2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test strerror -""" - -import socket -import os - -from twisted.trial.unittest import TestCase -from twisted.internet.tcp import ECONNABORTED -from twisted.python.win32 import _ErrorFormatter, formatError -from twisted.python.runtime import platform - - - -class ErrorFormatingTestCase(TestCase): - """ - Tests for C{_ErrorFormatter.formatError}. - """ - probeErrorCode = ECONNABORTED - probeMessage = "correct message value" - - def test_strerrorFormatting(self): - """ - L{_ErrorFormatter.formatError} should use L{os.strerror} to format - error messages if it is constructed without any better mechanism. - """ - formatter = _ErrorFormatter(None, None, None) - message = formatter.formatError(self.probeErrorCode) - self.assertEqual(message, os.strerror(self.probeErrorCode)) - - - def test_emptyErrorTab(self): - """ - L{_ErrorFormatter.formatError} should use L{os.strerror} to format - error messages if it is constructed with only an error tab which does - not contain the error code it is called with. - """ - error = 1 - # Sanity check - self.assertNotEqual(self.probeErrorCode, error) - formatter = _ErrorFormatter(None, None, {error: 'wrong message'}) - message = formatter.formatError(self.probeErrorCode) - self.assertEqual(message, os.strerror(self.probeErrorCode)) - - - def test_errorTab(self): - """ - L{_ErrorFormatter.formatError} should use C{errorTab} if it is supplied - and contains the requested error code. - """ - formatter = _ErrorFormatter( - None, None, {self.probeErrorCode: self.probeMessage}) - message = formatter.formatError(self.probeErrorCode) - self.assertEqual(message, self.probeMessage) - - - def test_formatMessage(self): - """ - L{_ErrorFormatter.formatError} should return the return value of - C{formatMessage} if it is supplied. - """ - formatCalls = [] - def formatMessage(errorCode): - formatCalls.append(errorCode) - return self.probeMessage - formatter = _ErrorFormatter( - None, formatMessage, {self.probeErrorCode: 'wrong message'}) - message = formatter.formatError(self.probeErrorCode) - self.assertEqual(message, self.probeMessage) - self.assertEqual(formatCalls, [self.probeErrorCode]) - - - def test_winError(self): - """ - L{_ErrorFormatter.formatError} should return the message argument from - the exception L{winError} returns, if L{winError} is supplied. - """ - winCalls = [] - def winError(errorCode): - winCalls.append(errorCode) - return (errorCode, self.probeMessage) - formatter = _ErrorFormatter( - winError, - lambda error: 'formatMessage: wrong message', - {self.probeErrorCode: 'errorTab: wrong message'}) - message = formatter.formatError(self.probeErrorCode) - self.assertEqual(message, self.probeMessage) - - - def test_fromEnvironment(self): - """ - L{_ErrorFormatter.fromEnvironment} should create an L{_ErrorFormatter} - instance with attributes populated from available modules. - """ - formatter = _ErrorFormatter.fromEnvironment() - - if formatter.winError is not None: - from ctypes import WinError - self.assertEqual( - formatter.formatError(self.probeErrorCode), - WinError(self.probeErrorCode)[1]) - formatter.winError = None - - if formatter.formatMessage is not None: - from win32api import FormatMessage - self.assertEqual( - formatter.formatError(self.probeErrorCode), - FormatMessage(self.probeErrorCode)) - formatter.formatMessage = None - - if formatter.errorTab is not None: - from socket import errorTab - self.assertEqual( - formatter.formatError(self.probeErrorCode), - errorTab[self.probeErrorCode]) - - if platform.getType() != "win32": - test_fromEnvironment.skip = "This error lookup only works on Windows" - - - def test_correctLookups(self): - """ - Given an known-good errno, make sure that formatMessage gives results - matching either C{socket.errorTab}, C{ctypes.WinError}, or - C{win32api.FormatMessage}. - """ - acceptable = [socket.errorTab[ECONNABORTED]] - try: - from ctypes import WinError - acceptable.append(WinError(ECONNABORTED)[1]) - except ImportError: - pass - try: - from win32api import FormatMessage - acceptable.append(FormatMessage(ECONNABORTED)) - except ImportError: - pass - - self.assertIn(formatError(ECONNABORTED), acceptable) - - if platform.getType() != "win32": - test_correctLookups.skip = "This error lookup only works on Windows" diff --git a/tools/buildbot/pylibs/twisted/test/test_strports.py b/tools/buildbot/pylibs/twisted/test/test_strports.py deleted file mode 100644 index b057ba4..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_strports.py +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -from twisted.application import strports -from twisted.trial import unittest - -class ParserTestCase(unittest.TestCase): - - f = "Factory" - - def testSimpleNumeric(self): - self.assertEqual(strports.parse('80', self.f), - ('TCP', (80, self.f), {'interface':'', 'backlog':50})) - - def testSimpleTCP(self): - self.assertEqual(strports.parse('tcp:80', self.f), - ('TCP', (80, self.f), {'interface':'', 'backlog':50})) - - def testInterfaceTCP(self): - self.assertEqual(strports.parse('tcp:80:interface=127.0.0.1', self.f), - ('TCP', (80, self.f), - {'interface':'127.0.0.1', 'backlog':50})) - - def testBacklogTCP(self): - self.assertEqual(strports.parse('tcp:80:backlog=6', self.f), - ('TCP', (80, self.f), - {'interface':'', 'backlog':6})) - - def testSimpleUnix(self): - self.assertEqual(strports.parse('unix:/var/run/finger', self.f), - ('UNIX', ('/var/run/finger', self.f), - {'mode':0666, 'backlog':50})) - - def testModedUNIX(self): - self.assertEqual(strports.parse('unix:/var/run/finger:mode=0660', - self.f), - ('UNIX', ('/var/run/finger', self.f), - {'mode':0660, 'backlog':50})) - - def testAllKeywords(self): - self.assertEqual(strports.parse('port=80', self.f), - ('TCP', (80, self.f), {'interface':'', 'backlog':50})) - - def testEscape(self): - self.assertEqual(strports.parse(r'unix:foo\:bar\=baz\:qux\\', self.f), - ('UNIX', ('foo:bar=baz:qux\\', self.f), - {'mode':0666, 'backlog':50})) - - def testImpliedEscape(self): - self.assertEqual(strports.parse(r'unix:address=foo=bar', self.f), - ('UNIX', ('foo=bar', self.f), - {'mode':0666, 'backlog':50})) - - def testNonstandardDefault(self): - self.assertEqual(strports.parse('filename', self.f, 'unix'), - ('UNIX', ('filename', self.f), - {'mode':0666, 'backlog':50})) diff --git a/tools/buildbot/pylibs/twisted/test/test_task.py b/tools/buildbot/pylibs/twisted/test/test_task.py deleted file mode 100644 index 422b04e..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_task.py +++ /dev/null @@ -1,479 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.python.compat import set - -from twisted.trial import unittest - -from twisted.internet import interfaces, task, reactor, defer, error - -# Be compatible with any jerks who used our private stuff -Clock = task.Clock - -from twisted.python import failure - - -class TestableLoopingCall(task.LoopingCall): - def __init__(self, clock, *a, **kw): - super(TestableLoopingCall, self).__init__(*a, **kw) - self.clock = clock - - - -class TestException(Exception): - pass - - - -class ClockTestCase(unittest.TestCase): - """ - Test the non-wallclock based clock implementation. - """ - def testSeconds(self): - """ - Test that the L{seconds} method of the fake clock returns fake time. - """ - c = task.Clock() - self.assertEquals(c.seconds(), 0) - - - def testCallLater(self): - """ - Test that calls can be scheduled for later with the fake clock and - hands back an L{IDelayedCall}. - """ - c = task.Clock() - call = c.callLater(1, lambda a, b: None, 1, b=2) - self.failUnless(interfaces.IDelayedCall.providedBy(call)) - self.assertEquals(call.getTime(), 1) - self.failUnless(call.active()) - - - def testCallLaterCancelled(self): - """ - Test that calls can be cancelled. - """ - c = task.Clock() - call = c.callLater(1, lambda a, b: None, 1, b=2) - call.cancel() - self.failIf(call.active()) - - - def test_callLaterOrdering(self): - """ - Test that the DelayedCall returned is not one previously - created. - """ - c = task.Clock() - call1 = c.callLater(10, lambda a, b: None, 1, b=2) - call2 = c.callLater(1, lambda a, b: None, 3, b=4) - self.failIf(call1 is call2) - - - def testAdvance(self): - """ - Test that advancing the clock will fire some calls. - """ - events = [] - c = task.Clock() - call = c.callLater(2, lambda: events.append(None)) - c.advance(1) - self.assertEquals(events, []) - c.advance(1) - self.assertEquals(events, [None]) - self.failIf(call.active()) - - - def testAdvanceCancel(self): - """ - Test attemping to cancel the call in a callback. - - AlreadyCalled should be raised, not for example a ValueError from - removing the call from Clock.calls. This requires call.called to be - set before the callback is called. - """ - c = task.Clock() - def cb(): - self.assertRaises(error.AlreadyCalled, call.cancel) - call = c.callLater(1, cb) - c.advance(1) - - - def testCallLaterDelayed(self): - """ - Test that calls can be delayed. - """ - events = [] - c = task.Clock() - call = c.callLater(1, lambda a, b: events.append((a, b)), 1, b=2) - call.delay(1) - self.assertEquals(call.getTime(), 2) - c.advance(1.5) - self.assertEquals(events, []) - c.advance(1.0) - self.assertEquals(events, [(1, 2)]) - - - def testCallLaterResetLater(self): - """ - Test that calls can have their time reset to a later time. - """ - events = [] - c = task.Clock() - call = c.callLater(2, lambda a, b: events.append((a, b)), 1, b=2) - c.advance(1) - call.reset(3) - self.assertEquals(call.getTime(), 4) - c.advance(2) - self.assertEquals(events, []) - c.advance(1) - self.assertEquals(events, [(1, 2)]) - - - def testCallLaterResetSooner(self): - """ - Test that calls can have their time reset to an earlier time. - """ - events = [] - c = task.Clock() - call = c.callLater(4, lambda a, b: events.append((a, b)), 1, b=2) - call.reset(3) - self.assertEquals(call.getTime(), 3) - c.advance(3) - self.assertEquals(events, [(1, 2)]) - - - def test_getDelayedCalls(self): - """ - Test that we can get a list of all delayed calls - """ - c = task.Clock() - call = c.callLater(1, lambda x: None) - call2 = c.callLater(2, lambda x: None) - - calls = c.getDelayedCalls() - - self.assertEquals(set([call, call2]), set(calls)) - - - def test_getDelayedCallsEmpty(self): - """ - Test that we get an empty list from getDelayedCalls on a newly - constructed Clock. - """ - c = task.Clock() - self.assertEquals(c.getDelayedCalls(), []) - - - def test_providesIReactorTime(self): - c = task.Clock() - self.failUnless(interfaces.IReactorTime.providedBy(c), - "Clock does not provide IReactorTime") - - -class LoopTestCase(unittest.TestCase): - """ - Tests for L{task.LoopingCall} based on a fake L{IReactorTime} - implementation. - """ - def test_defaultClock(self): - """ - L{LoopingCall}'s default clock should be the reactor. - """ - call = task.LoopingCall(lambda: None) - self.assertEqual(call.clock, reactor) - - - def test_callbackTimeSkips(self): - """ - When more time than the defined interval passes during the execution - of a callback, L{LoopingCall} should schedule the next call for the - next interval which is still in the future. - """ - times = [] - callDuration = None - clock = task.Clock() - def aCallback(): - times.append(clock.seconds()) - clock.advance(callDuration) - call = task.LoopingCall(aCallback) - call.clock = clock - - callDuration = 2 - call.start(0.5) - self.assertEqual(times, [0]) - self.assertEqual(clock.seconds(), 2) - - # An iteration should have occurred at 2, but since 2 is the present - # and not the future, it is skipped. - clock.advance(0) - self.assertEqual(times, [0]) - - # 2.5 is in the future, and is not skipped. - callDuration = 1 - clock.advance(0.5) - self.assertEqual(times, [0, 2.5]) - self.assertEqual(clock.seconds(), 3.5) - - # Another iteration should have occurred, but it is again the - # present and not the future, so it is skipped as well. - clock.advance(0) - self.assertEqual(times, [0, 2.5]) - - # 4 is in the future, and is not skipped. - callDuration = 0 - clock.advance(0.5) - self.assertEqual(times, [0, 2.5, 4]) - self.assertEqual(clock.seconds(), 4) - - - def test_reactorTimeSkips(self): - """ - When more time than the defined interval passes between when - L{LoopingCall} schedules itself to run again and when it actually - runs again, it should schedule the next call for the next interval - which is still in the future. - """ - times = [] - clock = task.Clock() - def aCallback(): - times.append(clock.seconds()) - - call = task.LoopingCall(aCallback) - call.clock = clock - - call.start(0.5) - self.assertEqual(times, [0]) - - clock.advance(2) - self.assertEqual(times, [0, 2]) - - clock.advance(1) - self.assertEqual(times, [0, 2, 3]) - - clock.advance(0) - self.assertEqual(times, [0, 2, 3]) - - - def testBasicFunction(self): - # Arrange to have time advanced enough so that our function is - # called a few times. - # Only need to go to 2.5 to get 3 calls, since the first call - # happens before any time has elapsed. - timings = [0.05, 0.1, 0.1] - - clock = task.Clock() - - L = [] - def foo(a, b, c=None, d=None): - L.append((a, b, c, d)) - - lc = TestableLoopingCall(clock, foo, "a", "b", d="d") - D = lc.start(0.1) - - theResult = [] - def saveResult(result): - theResult.append(result) - D.addCallback(saveResult) - - clock.pump(timings) - - self.assertEquals(len(L), 3, - "got %d iterations, not 3" % (len(L),)) - - for (a, b, c, d) in L: - self.assertEquals(a, "a") - self.assertEquals(b, "b") - self.assertEquals(c, None) - self.assertEquals(d, "d") - - lc.stop() - self.assertIdentical(theResult[0], lc) - - # Make sure it isn't planning to do anything further. - self.failIf(clock.calls) - - - def testDelayedStart(self): - timings = [0.05, 0.1, 0.1] - - clock = task.Clock() - - L = [] - lc = TestableLoopingCall(clock, L.append, None) - d = lc.start(0.1, now=False) - - theResult = [] - def saveResult(result): - theResult.append(result) - d.addCallback(saveResult) - - clock.pump(timings) - - self.assertEquals(len(L), 2, - "got %d iterations, not 2" % (len(L),)) - lc.stop() - self.assertIdentical(theResult[0], lc) - - self.failIf(clock.calls) - - - def testBadDelay(self): - lc = task.LoopingCall(lambda: None) - self.assertRaises(ValueError, lc.start, -1) - - - # Make sure that LoopingCall.stop() prevents any subsequent calls. - def _stoppingTest(self, delay): - ran = [] - def foo(): - ran.append(None) - - clock = task.Clock() - lc = TestableLoopingCall(clock, foo) - d = lc.start(delay, now=False) - lc.stop() - self.failIf(ran) - self.failIf(clock.calls) - - - def testStopAtOnce(self): - return self._stoppingTest(0) - - - def testStoppingBeforeDelayedStart(self): - return self._stoppingTest(10) - - - -class ReactorLoopTestCase(unittest.TestCase): - # Slightly inferior tests which exercise interactions with an actual - # reactor. - def testFailure(self): - def foo(x): - raise TestException(x) - - lc = task.LoopingCall(foo, "bar") - return self.assertFailure(lc.start(0.1), TestException) - - - def testFailAndStop(self): - def foo(x): - lc.stop() - raise TestException(x) - - lc = task.LoopingCall(foo, "bar") - return self.assertFailure(lc.start(0.1), TestException) - - - def testEveryIteration(self): - ran = [] - - def foo(): - ran.append(None) - if len(ran) > 5: - lc.stop() - - lc = task.LoopingCall(foo) - d = lc.start(0) - def stopped(ign): - self.assertEquals(len(ran), 6) - return d.addCallback(stopped) - - - def testStopAtOnceLater(self): - # Ensure that even when LoopingCall.stop() is called from a - # reactor callback, it still prevents any subsequent calls. - d = defer.Deferred() - def foo(): - d.errback(failure.DefaultException( - "This task also should never get called.")) - self._lc = task.LoopingCall(foo) - self._lc.start(1, now=False) - reactor.callLater(0, self._callback_for_testStopAtOnceLater, d) - return d - - - def _callback_for_testStopAtOnceLater(self, d): - self._lc.stop() - reactor.callLater(0, d.callback, "success") - - def testWaitDeferred(self): - # Tests if the callable isn't scheduled again before the returned - # deferred has fired. - timings = [0.2, 0.8] - clock = task.Clock() - - def foo(): - d = defer.Deferred() - d.addCallback(lambda _: lc.stop()) - clock.callLater(1, d.callback, None) - return d - - lc = TestableLoopingCall(clock, foo) - d = lc.start(0.2) - clock.pump(timings) - self.failIf(clock.calls) - - def testFailurePropagation(self): - # Tests if the failure of the errback of the deferred returned by the - # callable is propagated to the lc errback. - # - # To make sure this test does not hang trial when LoopingCall does not - # wait for the callable's deferred, it also checks there are no - # calls in the clock's callLater queue. - timings = [0.3] - clock = task.Clock() - - def foo(): - d = defer.Deferred() - clock.callLater(0.3, d.errback, TestException()) - return d - - lc = TestableLoopingCall(clock, foo) - d = lc.start(1) - self.assertFailure(d, TestException) - - clock.pump(timings) - self.failIf(clock.calls) - return d - - - -class DeferLaterTests(unittest.TestCase): - """ - Tests for L{task.deferLater}. - """ - def test_callback(self): - """ - The L{Deferred} returned by L{task.deferLater} is called back after - the specified delay with the result of the function passed in. - """ - results = [] - flag = object() - def callable(foo, bar): - results.append((foo, bar)) - return flag - - clock = task.Clock() - d = task.deferLater(clock, 3, callable, 'foo', bar='bar') - d.addCallback(self.assertIdentical, flag) - clock.advance(2) - self.assertEqual(results, []) - clock.advance(1) - self.assertEqual(results, [('foo', 'bar')]) - return d - - - def test_errback(self): - """ - The L{Deferred} returned by L{task.deferLater} is errbacked if the - supplied function raises an exception. - """ - def callable(): - raise TestException() - - clock = task.Clock() - d = task.deferLater(clock, 1, callable) - clock.advance(1) - return self.assertFailure(d, TestException) diff --git a/tools/buildbot/pylibs/twisted/test/test_tcp.py b/tools/buildbot/pylibs/twisted/test/test_tcp.py deleted file mode 100644 index 96d4c02..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_tcp.py +++ /dev/null @@ -1,1776 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for implementations of L{IReactorTCP}. -""" - -import socket, random, errno - -from zope.interface import implements - -from twisted.trial import unittest - -from twisted.python.log import msg -from twisted.internet import protocol, reactor, defer, interfaces -from twisted.internet import error -from twisted.internet.address import IPv4Address -from twisted.internet.interfaces import IHalfCloseableProtocol, IPullProducer -from twisted.protocols import policies - -def loopUntil(predicate, interval=0): - """ - Poor excuse for an event notification helper. This polls a condition and - calls back a Deferred when it is seen to be true. - - Do not use this function. - """ - from twisted.internet import task - d = defer.Deferred() - def check(): - res = predicate() - if res: - d.callback(res) - call = task.LoopingCall(check) - def stop(result): - call.stop() - return result - d.addCallback(stop) - d2 = call.start(interval) - d2.addErrback(d.errback) - return d - - -class ClosingProtocol(protocol.Protocol): - - def connectionMade(self): - self.transport.loseConnection() - - def connectionLost(self, reason): - reason.trap(error.ConnectionDone) - -class ClosingFactory(protocol.ServerFactory): - """Factory that closes port immediatley.""" - - def buildProtocol(self, conn): - self.port.stopListening() - return ClosingProtocol() - - -class MyProtocol(protocol.Protocol): - made = closed = failed = 0 - - closedDeferred = None - - data = "" - - factory = None - - def connectionMade(self): - self.made = 1 - if (self.factory is not None and - self.factory.protocolConnectionMade is not None): - d = self.factory.protocolConnectionMade - self.factory.protocolConnectionMade = None - d.callback(self) - - def dataReceived(self, data): - self.data += data - - def connectionLost(self, reason): - self.closed = 1 - if self.closedDeferred is not None: - d, self.closedDeferred = self.closedDeferred, None - d.callback(None) - - -class MyProtocolFactoryMixin(object): - """ - Mixin for factories which create L{MyProtocol} instances. - - @type protocolFactory: no-argument callable - @ivar protocolFactory: Factory for protocols - takes the place of the - typical C{protocol} attribute of factories (but that name is used by - this class for something else). - - @type protocolConnectionMade: L{NoneType} or L{defer.Deferred} - @ivar protocolConnectionMade: When an instance of L{MyProtocol} is - connected, if this is not C{None}, the L{Deferred} will be called - back with the protocol instance and the attribute set to C{None}. - - @type protocolConnectionLost: L{NoneType} or L{defer.Deferred} - @ivar protocolConnectionLost: When an instance of L{MyProtocol} is - created, this will be set as its C{closedDeferred} attribute and - then this attribute will be set to C{None} so the L{defer.Deferred} - is not used by more than one protocol. - - @ivar protocol: The most recently created L{MyProtocol} instance which - was returned from C{buildProtocol}. - - @type called: C{int} - @ivar called: A counter which is incremented each time C{buildProtocol} - is called. - - @ivar peerAddresses: A C{list} of the addresses passed to C{buildProtocol}. - """ - protocolFactory = MyProtocol - - protocolConnectionMade = None - protocolConnectionLost = None - protocol = None - called = 0 - - def __init__(self): - self.peerAddresses = [] - - - def buildProtocol(self, addr): - """ - Create a L{MyProtocol} and set it up to be able to perform - callbacks. - """ - self.peerAddresses.append(addr) - self.called += 1 - p = self.protocolFactory() - p.factory = self - p.closedDeferred = self.protocolConnectionLost - self.protocolConnectionLost = None - self.protocol = p - return p - - - -class MyServerFactory(MyProtocolFactoryMixin, protocol.ServerFactory): - """ - Server factory which creates L{MyProtocol} instances. - """ - - - -class MyClientFactory(MyProtocolFactoryMixin, protocol.ClientFactory): - """ - Client factory which creates L{MyProtocol} instances. - """ - failed = 0 - stopped = 0 - - def __init__(self): - MyProtocolFactoryMixin.__init__(self) - self.deferred = defer.Deferred() - self.failDeferred = defer.Deferred() - - def clientConnectionFailed(self, connector, reason): - self.failed = 1 - self.reason = reason - self.failDeferred.callback(None) - - def clientConnectionLost(self, connector, reason): - self.lostReason = reason - self.deferred.callback(None) - - def stopFactory(self): - self.stopped = 1 - - - -class ListeningTestCase(unittest.TestCase): - - def test_listen(self): - """ - L{IReactorTCP.listenTCP} returns an object which provides - L{IListeningPort}. - """ - f = MyServerFactory() - p1 = reactor.listenTCP(0, f, interface="127.0.0.1") - self.addCleanup(p1.stopListening) - self.failUnless(interfaces.IListeningPort.providedBy(p1)) - - - def testStopListening(self): - """ - The L{IListeningPort} returned by L{IReactorTCP.listenTCP} can be - stopped with its C{stopListening} method. After the L{Deferred} it - (optionally) returns has been called back, the port number can be bound - to a new server. - """ - f = MyServerFactory() - port = reactor.listenTCP(0, f, interface="127.0.0.1") - n = port.getHost().port - - def cbStopListening(ignored): - # Make sure we can rebind the port right away - port = reactor.listenTCP(n, f, interface="127.0.0.1") - return port.stopListening() - - d = defer.maybeDeferred(port.stopListening) - d.addCallback(cbStopListening) - return d - - - def testNumberedInterface(self): - f = MyServerFactory() - # listen only on the loopback interface - p1 = reactor.listenTCP(0, f, interface='127.0.0.1') - return p1.stopListening() - - def testPortRepr(self): - f = MyServerFactory() - p = reactor.listenTCP(0, f) - portNo = str(p.getHost().port) - self.failIf(repr(p).find(portNo) == -1) - def stoppedListening(ign): - self.failIf(repr(p).find(portNo) != -1) - d = defer.maybeDeferred(p.stopListening) - return d.addCallback(stoppedListening) - - - def test_serverRepr(self): - """ - Check that the repr string of the server transport get the good port - number if the server listens on 0. - """ - server = MyServerFactory() - serverConnMade = server.protocolConnectionMade = defer.Deferred() - port = reactor.listenTCP(0, server) - self.addCleanup(port.stopListening) - - client = MyClientFactory() - clientConnMade = client.protocolConnectionMade = defer.Deferred() - connector = reactor.connectTCP("127.0.0.1", - port.getHost().port, client) - self.addCleanup(connector.disconnect) - def check((serverProto, clientProto)): - portNumber = port.getHost().port - self.assertEquals(repr(serverProto.transport), - "" % (portNumber,)) - serverProto.transport.loseConnection() - clientProto.transport.loseConnection() - return defer.gatherResults([serverConnMade, clientConnMade] - ).addCallback(check) - - - -def callWithSpew(f): - from twisted.python.util import spewerWithLinenums as spewer - import sys - sys.settrace(spewer) - try: - f() - finally: - sys.settrace(None) - -class LoopbackTestCase(unittest.TestCase): - """ - Test loopback connections. - """ - def test_closePortInProtocolFactory(self): - """ - A port created with L{IReactorTCP.listenTCP} can be connected to with - L{IReactorTCP.connectTCP}. - """ - f = ClosingFactory() - port = reactor.listenTCP(0, f, interface="127.0.0.1") - self.addCleanup(port.stopListening) - portNumber = port.getHost().port - f.port = port - clientF = MyClientFactory() - reactor.connectTCP("127.0.0.1", portNumber, clientF) - def check(x): - self.assertTrue(clientF.protocol.made) - self.assertTrue(port.disconnected) - clientF.lostReason.trap(error.ConnectionDone) - return clientF.deferred.addCallback(check) - - def _trapCnxDone(self, obj): - getattr(obj, 'trap', lambda x: None)(error.ConnectionDone) - - - def _connectedClientAndServerTest(self, callback): - """ - Invoke the given callback with a client protocol and a server protocol - which have been connected to each other. - """ - serverFactory = MyServerFactory() - serverConnMade = defer.Deferred() - serverFactory.protocolConnectionMade = serverConnMade - port = reactor.listenTCP(0, serverFactory, interface="127.0.0.1") - self.addCleanup(port.stopListening) - - portNumber = port.getHost().port - clientF = MyClientFactory() - clientConnMade = defer.Deferred() - clientF.protocolConnectionMade = clientConnMade - reactor.connectTCP("127.0.0.1", portNumber, clientF) - - connsMade = defer.gatherResults([serverConnMade, clientConnMade]) - def connected((serverProtocol, clientProtocol)): - callback(serverProtocol, clientProtocol) - serverProtocol.transport.loseConnection() - clientProtocol.transport.loseConnection() - connsMade.addCallback(connected) - return connsMade - - - def test_tcpNoDelay(self): - """ - The transport of a protocol connected with L{IReactorTCP.connectTCP} or - L{IReactor.TCP.listenTCP} can have its I{TCP_NODELAY} state inspected - and manipulated with L{ITCPTransport.getTcpNoDelay} and - L{ITCPTransport.setTcpNoDelay}. - """ - def check(serverProtocol, clientProtocol): - for p in [serverProtocol, clientProtocol]: - transport = p.transport - self.assertEquals(transport.getTcpNoDelay(), 0) - transport.setTcpNoDelay(1) - self.assertEquals(transport.getTcpNoDelay(), 1) - transport.setTcpNoDelay(0) - self.assertEquals(transport.getTcpNoDelay(), 0) - return self._connectedClientAndServerTest(check) - - - def test_tcpKeepAlive(self): - """ - The transport of a protocol connected with L{IReactorTCP.connectTCP} or - L{IReactor.TCP.listenTCP} can have its I{SO_KEEPALIVE} state inspected - and manipulated with L{ITCPTransport.getTcpKeepAlive} and - L{ITCPTransport.setTcpKeepAlive}. - """ - def check(serverProtocol, clientProtocol): - for p in [serverProtocol, clientProtocol]: - transport = p.transport - self.assertEquals(transport.getTcpKeepAlive(), 0) - transport.setTcpKeepAlive(1) - self.assertEquals(transport.getTcpKeepAlive(), 1) - transport.setTcpKeepAlive(0) - self.assertEquals(transport.getTcpKeepAlive(), 0) - return self._connectedClientAndServerTest(check) - - - def testFailing(self): - clientF = MyClientFactory() - # XXX we assume no one is listening on TCP port 69 - reactor.connectTCP("127.0.0.1", 69, clientF, timeout=5) - def check(ignored): - clientF.reason.trap(error.ConnectionRefusedError) - return clientF.failDeferred.addCallback(check) - - - def test_connectionRefusedErrorNumber(self): - """ - Assert that the error number of the ConnectionRefusedError is - ECONNREFUSED, and not some other socket related error. - """ - - # Bind a number of ports in the operating system. We will attempt - # to connect to these in turn immediately after closing them, in the - # hopes that no one else has bound them in the mean time. Any - # connection which succeeds is ignored and causes us to move on to - # the next port. As soon as a connection attempt fails, we move on - # to making an assertion about how it failed. If they all succeed, - # the test will fail. - - # It would be nice to have a simpler, reliable way to cause a - # connection failure from the platform. - # - # On Linux (2.6.15), connecting to port 0 always fails. FreeBSD - # (5.4) rejects the connection attempt with EADDRNOTAVAIL. - # - # On FreeBSD (5.4), listening on a port and then repeatedly - # connecting to it without ever accepting any connections eventually - # leads to an ECONNREFUSED. On Linux (2.6.15), a seemingly - # unbounded number of connections succeed. - - serverSockets = [] - for i in xrange(10): - serverSocket = socket.socket() - serverSocket.bind(('127.0.0.1', 0)) - serverSocket.listen(1) - serverSockets.append(serverSocket) - random.shuffle(serverSockets) - - clientCreator = protocol.ClientCreator(reactor, protocol.Protocol) - - def tryConnectFailure(): - def connected(proto): - """ - Darn. Kill it and try again, if there are any tries left. - """ - proto.transport.loseConnection() - if serverSockets: - return tryConnectFailure() - self.fail("Could not fail to connect - could not test errno for that case.") - - serverSocket = serverSockets.pop() - serverHost, serverPort = serverSocket.getsockname() - serverSocket.close() - - connectDeferred = clientCreator.connectTCP(serverHost, serverPort) - connectDeferred.addCallback(connected) - return connectDeferred - - refusedDeferred = tryConnectFailure() - self.assertFailure(refusedDeferred, error.ConnectionRefusedError) - def connRefused(exc): - self.assertEqual(exc.osError, errno.ECONNREFUSED) - refusedDeferred.addCallback(connRefused) - def cleanup(passthrough): - while serverSockets: - serverSockets.pop().close() - return passthrough - refusedDeferred.addBoth(cleanup) - return refusedDeferred - - - def test_connectByServiceFail(self): - """ - Connecting to a named service which does not exist raises - L{error.ServiceNameUnknownError}. - """ - self.assertRaises( - error.ServiceNameUnknownError, - reactor.connectTCP, - "127.0.0.1", "thisbetternotexist", MyClientFactory()) - - - def test_connectByService(self): - """ - L{IReactorTCP.connectTCP} accepts the name of a service instead of a - port number and connects to the port number associated with that - service, as defined by L{socket.getservbyname}. - """ - serverFactory = MyServerFactory() - serverConnMade = defer.Deferred() - serverFactory.protocolConnectionMade = serverConnMade - port = reactor.listenTCP(0, serverFactory, interface="127.0.0.1") - self.addCleanup(port.stopListening) - portNumber = port.getHost().port - clientFactory = MyClientFactory() - clientConnMade = defer.Deferred() - clientFactory.protocolConnectionMade = clientConnMade - - def fakeGetServicePortByName(serviceName, protocolName): - if serviceName == 'http' and protocolName == 'tcp': - return portNumber - return 10 - self.patch(socket, 'getservbyname', fakeGetServicePortByName) - - c = reactor.connectTCP('127.0.0.1', 'http', clientFactory) - - connMade = defer.gatherResults([serverConnMade, clientConnMade]) - def connected((serverProtocol, clientProtocol)): - self.assertTrue( - serverFactory.called, - "Server factory was not called upon to build a protocol.") - serverProtocol.transport.loseConnection() - clientProtocol.transport.loseConnection() - connMade.addCallback(connected) - return connMade - - -class StartStopFactory(protocol.Factory): - - started = 0 - stopped = 0 - - def startFactory(self): - if self.started or self.stopped: - raise RuntimeError - self.started = 1 - - def stopFactory(self): - if not self.started or self.stopped: - raise RuntimeError - self.stopped = 1 - - -class ClientStartStopFactory(MyClientFactory): - - started = 0 - stopped = 0 - - def startFactory(self): - if self.started or self.stopped: - raise RuntimeError - self.started = 1 - - def stopFactory(self): - if not self.started or self.stopped: - raise RuntimeError - self.stopped = 1 - - -class FactoryTestCase(unittest.TestCase): - """Tests for factories.""" - - def test_serverStartStop(self): - """ - The factory passed to L{IReactorTCP.listenTCP} should be started only - when it transitions from being used on no ports to being used on one - port and should be stopped only when it transitions from being used on - one port to being used on no ports. - """ - # Note - this test doesn't need to use listenTCP. It is exercising - # logic implemented in Factory.doStart and Factory.doStop, so it could - # just call that directly. Some other test can make sure that - # listenTCP and stopListening correctly call doStart and - # doStop. -exarkun - - f = StartStopFactory() - - # listen on port - p1 = reactor.listenTCP(0, f, interface='127.0.0.1') - self.addCleanup(p1.stopListening) - - self.assertEqual((f.started, f.stopped), (1, 0)) - - # listen on two more ports - p2 = reactor.listenTCP(0, f, interface='127.0.0.1') - p3 = reactor.listenTCP(0, f, interface='127.0.0.1') - - self.assertEqual((f.started, f.stopped), (1, 0)) - - # close two ports - d1 = defer.maybeDeferred(p1.stopListening) - d2 = defer.maybeDeferred(p2.stopListening) - closedDeferred = defer.gatherResults([d1, d2]) - def cbClosed(ignored): - self.assertEqual((f.started, f.stopped), (1, 0)) - # Close the last port - return p3.stopListening() - closedDeferred.addCallback(cbClosed) - - def cbClosedAll(ignored): - self.assertEquals((f.started, f.stopped), (1, 1)) - closedDeferred.addCallback(cbClosedAll) - return closedDeferred - - - def test_clientStartStop(self): - """ - The factory passed to L{IReactorTCP.connectTCP} should be started when - the connection attempt starts and stopped when it is over. - """ - f = ClosingFactory() - p = reactor.listenTCP(0, f, interface="127.0.0.1") - self.addCleanup(p.stopListening) - portNumber = p.getHost().port - f.port = p - - factory = ClientStartStopFactory() - reactor.connectTCP("127.0.0.1", portNumber, factory) - self.assertTrue(factory.started) - return loopUntil(lambda: factory.stopped) - - - -class ConnectorTestCase(unittest.TestCase): - - def test_connectorIdentity(self): - """ - L{IReactorTCP.connectTCP} returns an object which provides - L{IConnector}. The destination of the connector is the address which - was passed to C{connectTCP}. The same connector object is passed to - the factory's C{startedConnecting} method as to the factory's - C{clientConnectionLost} method. - """ - serverFactory = ClosingFactory() - tcpPort = reactor.listenTCP(0, serverFactory, interface="127.0.0.1") - self.addCleanup(tcpPort.stopListening) - portNumber = tcpPort.getHost().port - serverFactory.port = tcpPort - - seenConnectors = [] - seenFailures = [] - - clientFactory = ClientStartStopFactory() - clientFactory.clientConnectionLost = ( - lambda connector, reason: (seenConnectors.append(connector), - seenFailures.append(reason))) - clientFactory.startedConnecting = seenConnectors.append - - connector = reactor.connectTCP("127.0.0.1", portNumber, clientFactory) - self.assertTrue(interfaces.IConnector.providedBy(connector)) - dest = connector.getDestination() - self.assertEquals(dest.type, "TCP") - self.assertEquals(dest.host, "127.0.0.1") - self.assertEquals(dest.port, portNumber) - - d = loopUntil(lambda: clientFactory.stopped) - def clientFactoryStopped(ignored): - seenFailures[0].trap(error.ConnectionDone) - self.assertEqual(seenConnectors, [connector, connector]) - d.addCallback(clientFactoryStopped) - return d - - - def test_userFail(self): - """ - Calling L{IConnector.stopConnecting} in C{Factory.startedConnecting} - results in C{Factory.clientConnectionFailed} being called with - L{error.UserError} as the reason. - """ - serverFactory = MyServerFactory() - tcpPort = reactor.listenTCP(0, serverFactory, interface="127.0.0.1") - self.addCleanup(tcpPort.stopListening) - portNumber = tcpPort.getHost().port - - def startedConnecting(connector): - connector.stopConnecting() - - clientFactory = ClientStartStopFactory() - clientFactory.startedConnecting = startedConnecting - reactor.connectTCP("127.0.0.1", portNumber, clientFactory) - - d = loopUntil(lambda: clientFactory.stopped) - def check(ignored): - self.assertEquals(clientFactory.failed, 1) - clientFactory.reason.trap(error.UserError) - return d.addCallback(check) - - - def test_reconnect(self): - """ - Calling L{IConnector.connect} in C{Factory.clientConnectionLost} causes - a new connection attempt to be made. - """ - serverFactory = ClosingFactory() - tcpPort = reactor.listenTCP(0, serverFactory, interface="127.0.0.1") - self.addCleanup(tcpPort.stopListening) - portNumber = tcpPort.getHost().port - serverFactory.port = tcpPort - - clientFactory = MyClientFactory() - - def clientConnectionLost(connector, reason): - connector.connect() - clientFactory.clientConnectionLost = clientConnectionLost - reactor.connectTCP("127.0.0.1", portNumber, clientFactory) - - d = loopUntil(lambda: clientFactory.failed) - def reconnectFailed(ignored): - p = clientFactory.protocol - self.assertEqual((p.made, p.closed), (1, 1)) - clientFactory.reason.trap(error.ConnectionRefusedError) - self.assertEqual(clientFactory.stopped, 1) - return d.addCallback(reconnectFailed) - - - -class CannotBindTestCase(unittest.TestCase): - """ - Tests for correct behavior when a reactor cannot bind to the required TCP - port. - """ - - def test_cannotBind(self): - """ - L{IReactorTCP.listenTCP} raises L{error.CannotListenError} if the - address to listen on is already in use. - """ - f = MyServerFactory() - - p1 = reactor.listenTCP(0, f, interface='127.0.0.1') - self.addCleanup(p1.stopListening) - n = p1.getHost().port - dest = p1.getHost() - self.assertEquals(dest.type, "TCP") - self.assertEquals(dest.host, "127.0.0.1") - self.assertEquals(dest.port, n) - - # make sure new listen raises error - self.assertRaises(error.CannotListenError, - reactor.listenTCP, n, f, interface='127.0.0.1') - - - - def _fireWhenDoneFunc(self, d, f): - """Returns closure that when called calls f and then callbacks d. - """ - from twisted.python import util as tputil - def newf(*args, **kw): - rtn = f(*args, **kw) - d.callback('') - return rtn - return tputil.mergeFunctionMetadata(f, newf) - - - def test_clientBind(self): - """ - L{IReactorTCP.connectTCP} calls C{Factory.clientConnectionFailed} with - L{error.ConnectBindError} if the bind address specified is already in - use. - """ - theDeferred = defer.Deferred() - sf = MyServerFactory() - sf.startFactory = self._fireWhenDoneFunc(theDeferred, sf.startFactory) - p = reactor.listenTCP(0, sf, interface="127.0.0.1") - self.addCleanup(p.stopListening) - - def _connect1(results): - d = defer.Deferred() - cf1 = MyClientFactory() - cf1.buildProtocol = self._fireWhenDoneFunc(d, cf1.buildProtocol) - reactor.connectTCP("127.0.0.1", p.getHost().port, cf1, - bindAddress=("127.0.0.1", 0)) - d.addCallback(_conmade, cf1) - return d - - def _conmade(results, cf1): - d = defer.Deferred() - cf1.protocol.connectionMade = self._fireWhenDoneFunc( - d, cf1.protocol.connectionMade) - d.addCallback(_check1connect2, cf1) - return d - - def _check1connect2(results, cf1): - self.assertEquals(cf1.protocol.made, 1) - - d1 = defer.Deferred() - d2 = defer.Deferred() - port = cf1.protocol.transport.getHost().port - cf2 = MyClientFactory() - cf2.clientConnectionFailed = self._fireWhenDoneFunc( - d1, cf2.clientConnectionFailed) - cf2.stopFactory = self._fireWhenDoneFunc(d2, cf2.stopFactory) - reactor.connectTCP("127.0.0.1", p.getHost().port, cf2, - bindAddress=("127.0.0.1", port)) - d1.addCallback(_check2failed, cf1, cf2) - d2.addCallback(_check2stopped, cf1, cf2) - dl = defer.DeferredList([d1, d2]) - dl.addCallback(_stop, cf1, cf2) - return dl - - def _check2failed(results, cf1, cf2): - self.assertEquals(cf2.failed, 1) - cf2.reason.trap(error.ConnectBindError) - self.assertTrue(cf2.reason.check(error.ConnectBindError)) - return results - - def _check2stopped(results, cf1, cf2): - self.assertEquals(cf2.stopped, 1) - return results - - def _stop(results, cf1, cf2): - d = defer.Deferred() - d.addCallback(_check1cleanup, cf1) - cf1.stopFactory = self._fireWhenDoneFunc(d, cf1.stopFactory) - cf1.protocol.transport.loseConnection() - return d - - def _check1cleanup(results, cf1): - self.assertEquals(cf1.stopped, 1) - - theDeferred.addCallback(_connect1) - return theDeferred - - - -class MyOtherClientFactory(protocol.ClientFactory): - def buildProtocol(self, address): - self.address = address - self.protocol = MyProtocol() - return self.protocol - - - -class LocalRemoteAddressTestCase(unittest.TestCase): - """ - Tests for correct getHost/getPeer values and that the correct address is - passed to buildProtocol. - """ - def test_hostAddress(self): - """ - L{IListeningPort.getHost} returns the same address as a client - connection's L{ITCPTransport.getPeer}. - """ - f1 = MyServerFactory() - p1 = reactor.listenTCP(0, f1, interface='127.0.0.1') - self.addCleanup(p1.stopListening) - n = p1.getHost().port - - f2 = MyOtherClientFactory() - p2 = reactor.connectTCP('127.0.0.1', n, f2) - - d = loopUntil(lambda :p2.state == "connected") - def check(ignored): - self.assertEquals(p1.getHost(), f2.address) - self.assertEquals(p1.getHost(), f2.protocol.transport.getPeer()) - return p1.stopListening() - def cleanup(ignored): - p2.transport.loseConnection() - return d.addCallback(check).addCallback(cleanup) - - -class WriterProtocol(protocol.Protocol): - def connectionMade(self): - # use everything ITransport claims to provide. If something here - # fails, the exception will be written to the log, but it will not - # directly flunk the test. The test will fail when maximum number of - # iterations have passed and the writer's factory.done has not yet - # been set. - self.transport.write("Hello Cleveland!\n") - seq = ["Goodbye", " cruel", " world", "\n"] - self.transport.writeSequence(seq) - peer = self.transport.getPeer() - if peer.type != "TCP": - print "getPeer returned non-TCP socket:", peer - self.factory.problem = 1 - us = self.transport.getHost() - if us.type != "TCP": - print "getHost returned non-TCP socket:", us - self.factory.problem = 1 - self.factory.done = 1 - - self.transport.loseConnection() - -class ReaderProtocol(protocol.Protocol): - def dataReceived(self, data): - self.factory.data += data - def connectionLost(self, reason): - self.factory.done = 1 - -class WriterClientFactory(protocol.ClientFactory): - def __init__(self): - self.done = 0 - self.data = "" - def buildProtocol(self, addr): - p = ReaderProtocol() - p.factory = self - self.protocol = p - return p - -class WriteDataTestCase(unittest.TestCase): - """ - Test that connected TCP sockets can actually write data. Try to exercise - the entire ITransport interface. - """ - - def test_writer(self): - """ - L{ITCPTransport.write} and L{ITCPTransport.writeSequence} send bytes to - the other end of the connection. - """ - f = protocol.Factory() - f.protocol = WriterProtocol - f.done = 0 - f.problem = 0 - wrappedF = WiredFactory(f) - p = reactor.listenTCP(0, wrappedF, interface="127.0.0.1") - self.addCleanup(p.stopListening) - n = p.getHost().port - clientF = WriterClientFactory() - wrappedClientF = WiredFactory(clientF) - reactor.connectTCP("127.0.0.1", n, wrappedClientF) - - def check(ignored): - self.failUnless(f.done, "writer didn't finish, it probably died") - self.failUnless(f.problem == 0, "writer indicated an error") - self.failUnless(clientF.done, - "client didn't see connection dropped") - expected = "".join(["Hello Cleveland!\n", - "Goodbye", " cruel", " world", "\n"]) - self.failUnless(clientF.data == expected, - "client didn't receive all the data it expected") - d = defer.gatherResults([wrappedF.onDisconnect, - wrappedClientF.onDisconnect]) - return d.addCallback(check) - - - def test_writeAfterShutdownWithoutReading(self): - """ - A TCP transport which is written to after the connection has been shut - down should notify its protocol that the connection has been lost, even - if the TCP transport is not actively being monitored for read events - (ie, pauseProducing was called on it). - """ - # This is an unpleasant thing. Generally tests shouldn't skip or - # run based on the name of the reactor being used (most tests - # shouldn't care _at all_ what reactor is being used, in fact). The - # Gtk reactor cannot pass this test, though, because it fails to - # implement IReactorTCP entirely correctly. Gtk is quite old at - # this point, so it's more likely that gtkreactor will be deprecated - # and removed rather than fixed to handle this case correctly. - # Since this is a pre-existing (and very long-standing) issue with - # the Gtk reactor, there's no reason for it to prevent this test - # being added to exercise the other reactors, for which the behavior - # was also untested but at least works correctly (now). See #2833 - # for information on the status of gtkreactor. - if reactor.__class__.__name__ == 'IOCPReactor': - raise unittest.SkipTest( - "iocpreactor does not, in fact, stop reading immediately after " - "pauseProducing is called. This results in a bonus disconnection " - "notification. Under some circumstances, it might be possible to " - "not receive this notifications (specifically, pauseProducing, " - "deliver some data, proceed with this test).") - if reactor.__class__.__name__ == 'GtkReactor': - raise unittest.SkipTest( - "gtkreactor does not implement unclean disconnection " - "notification correctly. This might more properly be " - "a todo, but due to technical limitations it cannot be.") - - # Called back after the protocol for the client side of the connection - # has paused its transport, preventing it from reading, therefore - # preventing it from noticing the disconnection before the rest of the - # actions which are necessary to trigger the case this test is for have - # been taken. - clientPaused = defer.Deferred() - - # Called back when the protocol for the server side of the connection - # has received connection lost notification. - serverLost = defer.Deferred() - - class Disconnecter(protocol.Protocol): - """ - Protocol for the server side of the connection which disconnects - itself in a callback on clientPaused and publishes notification - when its connection is actually lost. - """ - def connectionMade(self): - """ - Set up a callback on clientPaused to lose the connection. - """ - msg('Disconnector.connectionMade') - def disconnect(ignored): - msg('Disconnector.connectionMade disconnect') - self.transport.loseConnection() - msg('loseConnection called') - clientPaused.addCallback(disconnect) - - def connectionLost(self, reason): - """ - Notify observers that the server side of the connection has - ended. - """ - msg('Disconnecter.connectionLost') - serverLost.callback(None) - msg('serverLost called back') - - # Create the server port to which a connection will be made. - server = protocol.ServerFactory() - server.protocol = Disconnecter - port = reactor.listenTCP(0, server, interface='127.0.0.1') - self.addCleanup(port.stopListening) - addr = port.getHost() - - class Infinite(object): - """ - A producer which will write to its consumer as long as - resumeProducing is called. - - @ivar consumer: The L{IConsumer} which will be written to. - """ - implements(IPullProducer) - - def __init__(self, consumer): - self.consumer = consumer - - def resumeProducing(self): - msg('Infinite.resumeProducing') - self.consumer.write('x') - msg('Infinite.resumeProducing wrote to consumer') - - def stopProducing(self): - msg('Infinite.stopProducing') - - - class UnreadingWriter(protocol.Protocol): - """ - Trivial protocol which pauses its transport immediately and then - writes some bytes to it. - """ - def connectionMade(self): - msg('UnreadingWriter.connectionMade') - self.transport.pauseProducing() - clientPaused.callback(None) - msg('clientPaused called back') - def write(ignored): - msg('UnreadingWriter.connectionMade write') - # This needs to be enough bytes to spill over into the - # userspace Twisted send buffer - if it all fits into - # the kernel, Twisted won't even poll for OUT events, - # which means it won't poll for any events at all, so - # the disconnection is never noticed. This is due to - # #1662. When #1662 is fixed, this test will likely - # need to be adjusted, otherwise connection lost - # notification will happen too soon and the test will - # probably begin to fail with ConnectionDone instead of - # ConnectionLost (in any case, it will no longer be - # entirely correct). - producer = Infinite(self.transport) - msg('UnreadingWriter.connectionMade write created producer') - self.transport.registerProducer(producer, False) - msg('UnreadingWriter.connectionMade write registered producer') - serverLost.addCallback(write) - - # Create the client and initiate the connection - client = MyClientFactory() - client.protocolFactory = UnreadingWriter - clientConnectionLost = client.deferred - def cbClientLost(ignored): - msg('cbClientLost') - return client.lostReason - clientConnectionLost.addCallback(cbClientLost) - msg('Connecting to %s:%s' % (addr.host, addr.port)) - connector = reactor.connectTCP(addr.host, addr.port, client) - - # By the end of the test, the client should have received notification - # of unclean disconnection. - msg('Returning Deferred') - return self.assertFailure(clientConnectionLost, error.ConnectionLost) - - - -class ConnectionLosingProtocol(protocol.Protocol): - def connectionMade(self): - self.transport.write("1") - self.transport.loseConnection() - self.master._connectionMade() - self.master.ports.append(self.transport) - - - -class NoopProtocol(protocol.Protocol): - def connectionMade(self): - self.d = defer.Deferred() - self.master.serverConns.append(self.d) - - def connectionLost(self, reason): - self.d.callback(True) - - - -class ConnectionLostNotifyingProtocol(protocol.Protocol): - """ - Protocol which fires a Deferred which was previously passed to - its initializer when the connection is lost. - """ - def __init__(self, onConnectionLost): - self.onConnectionLost = onConnectionLost - - - def connectionLost(self, reason): - self.onConnectionLost.callback(self) - - - -class HandleSavingProtocol(ConnectionLostNotifyingProtocol): - """ - Protocol which grabs the platform-specific socket handle and - saves it as an attribute on itself when the connection is - established. - """ - def makeConnection(self, transport): - """ - Save the platform-specific socket handle for future - introspection. - """ - self.handle = transport.getHandle() - return protocol.Protocol.makeConnection(self, transport) - - - -class ProperlyCloseFilesMixin: - """ - Tests for platform resources properly being cleaned up. - """ - def createServer(self, address, portNumber, factory): - """ - Bind a server port to which connections will be made. The server - should use the given protocol factory. - - @return: The L{IListeningPort} for the server created. - """ - raise NotImplementedError() - - - def connectClient(self, address, portNumber, clientCreator): - """ - Establish a connection to the given address using the given - L{ClientCreator} instance. - - @return: A Deferred which will fire with the connected protocol instance. - """ - raise NotImplementedError() - - - def getHandleExceptionType(self): - """ - Return the exception class which will be raised when an operation is - attempted on a closed platform handle. - """ - raise NotImplementedError() - - - def getHandleErrorCode(self): - """ - Return the errno expected to result from writing to a closed - platform socket handle. - """ - # These platforms have been seen to give EBADF: - # - # Linux 2.4.26, Linux 2.6.15, OS X 10.4, FreeBSD 5.4 - # Windows 2000 SP 4, Windows XP SP 2 - return errno.EBADF - - - def test_properlyCloseFiles(self): - """ - Test that lost connections properly have their underlying socket - resources cleaned up. - """ - onServerConnectionLost = defer.Deferred() - serverFactory = protocol.ServerFactory() - serverFactory.protocol = lambda: ConnectionLostNotifyingProtocol( - onServerConnectionLost) - serverPort = self.createServer('127.0.0.1', 0, serverFactory) - - onClientConnectionLost = defer.Deferred() - serverAddr = serverPort.getHost() - clientCreator = protocol.ClientCreator( - reactor, lambda: HandleSavingProtocol(onClientConnectionLost)) - clientDeferred = self.connectClient( - serverAddr.host, serverAddr.port, clientCreator) - - def clientConnected(client): - """ - Disconnect the client. Return a Deferred which fires when both - the client and the server have received disconnect notification. - """ - client.transport.loseConnection() - return defer.gatherResults([ - onClientConnectionLost, onServerConnectionLost]) - clientDeferred.addCallback(clientConnected) - - def clientDisconnected((client, server)): - """ - Verify that the underlying platform socket handle has been - cleaned up. - """ - expectedErrorCode = self.getHandleErrorCode() - err = self.assertRaises( - self.getHandleExceptionType(), client.handle.send, 'bytes') - self.assertEqual(err.args[0], expectedErrorCode) - clientDeferred.addCallback(clientDisconnected) - - def cleanup(passthrough): - """ - Shut down the server port. Return a Deferred which fires when - this has completed. - """ - result = defer.maybeDeferred(serverPort.stopListening) - result.addCallback(lambda ign: passthrough) - return result - clientDeferred.addBoth(cleanup) - - return clientDeferred - - - -class ProperlyCloseFilesTestCase(unittest.TestCase, ProperlyCloseFilesMixin): - def createServer(self, address, portNumber, factory): - return reactor.listenTCP(portNumber, factory, interface=address) - - - def connectClient(self, address, portNumber, clientCreator): - return clientCreator.connectTCP(address, portNumber) - - - def getHandleExceptionType(self): - return socket.error - - - -class WiredForDeferreds(policies.ProtocolWrapper): - def __init__(self, factory, wrappedProtocol): - policies.ProtocolWrapper.__init__(self, factory, wrappedProtocol) - - def connectionMade(self): - policies.ProtocolWrapper.connectionMade(self) - self.factory.onConnect.callback(None) - - def connectionLost(self, reason): - policies.ProtocolWrapper.connectionLost(self, reason) - self.factory.onDisconnect.callback(None) - - - -class WiredFactory(policies.WrappingFactory): - protocol = WiredForDeferreds - - def __init__(self, wrappedFactory): - policies.WrappingFactory.__init__(self, wrappedFactory) - self.onConnect = defer.Deferred() - self.onDisconnect = defer.Deferred() - - - -class AddressTestCase(unittest.TestCase): - """ - Tests for address-related interactions with client and server protocols. - """ - def setUp(self): - """ - Create a port and connected client/server pair which can be used - to test factory behavior related to addresses. - - @return: A L{defer.Deferred} which will be called back when both the - client and server protocols have received their connection made - callback. - """ - class RememberingWrapper(protocol.ClientFactory): - """ - Simple wrapper factory which records the addresses which are - passed to its L{buildProtocol} method and delegates actual - protocol creation to another factory. - - @ivar addresses: A list of the objects passed to buildProtocol. - @ivar factory: The wrapped factory to which protocol creation is - delegated. - """ - def __init__(self, factory): - self.addresses = [] - self.factory = factory - - # Only bother to pass on buildProtocol calls to the wrapped - # factory - doStart, doStop, etc aren't necessary for this test - # to pass. - def buildProtocol(self, addr): - """ - Append the given address to C{self.addresses} and forward - the call to C{self.factory}. - """ - self.addresses.append(addr) - return self.factory.buildProtocol(addr) - - # Make a server which we can receive connection and disconnection - # notification for, and which will record the address passed to its - # buildProtocol. - self.server = MyServerFactory() - self.serverConnMade = self.server.protocolConnectionMade = defer.Deferred() - self.serverConnLost = self.server.protocolConnectionLost = defer.Deferred() - # RememberingWrapper is a ClientFactory, but ClientFactory is-a - # ServerFactory, so this is okay. - self.serverWrapper = RememberingWrapper(self.server) - - # Do something similar for a client. - self.client = MyClientFactory() - self.clientConnMade = self.client.protocolConnectionMade = defer.Deferred() - self.clientConnLost = self.client.protocolConnectionLost = defer.Deferred() - self.clientWrapper = RememberingWrapper(self.client) - - self.port = reactor.listenTCP(0, self.serverWrapper, interface='127.0.0.1') - self.connector = reactor.connectTCP( - self.port.getHost().host, self.port.getHost().port, self.clientWrapper) - - return defer.gatherResults([self.serverConnMade, self.clientConnMade]) - - - def tearDown(self): - """ - Disconnect the client/server pair and shutdown the port created in - L{setUp}. - """ - self.connector.disconnect() - return defer.gatherResults([ - self.serverConnLost, self.clientConnLost, - defer.maybeDeferred(self.port.stopListening)]) - - - def test_buildProtocolClient(self): - """ - L{ClientFactory.buildProtocol} should be invoked with the address of - the server to which a connection has been established, which should - be the same as the address reported by the C{getHost} method of the - transport of the server protocol and as the C{getPeer} method of the - transport of the client protocol. - """ - serverHost = self.server.protocol.transport.getHost() - clientPeer = self.client.protocol.transport.getPeer() - - self.assertEqual( - self.clientWrapper.addresses, - [IPv4Address('TCP', serverHost.host, serverHost.port)]) - self.assertEqual( - self.clientWrapper.addresses, - [IPv4Address('TCP', clientPeer.host, clientPeer.port)]) - - - def test_buildProtocolServer(self): - """ - L{ServerFactory.buildProtocol} should be invoked with the address of - the client which has connected to the port the factory is listening on, - which should be the same as the address reported by the C{getPeer} - method of the transport of the server protocol and as the C{getHost} - method of the transport of the client protocol. - """ - clientHost = self.client.protocol.transport.getHost() - serverPeer = self.server.protocol.transport.getPeer() - - self.assertEqual( - self.serverWrapper.addresses, - [IPv4Address('TCP', serverPeer.host, serverPeer.port)]) - self.assertEqual( - self.serverWrapper.addresses, - [IPv4Address('TCP', clientHost.host, clientHost.port)]) - - - -class LargeBufferWriterProtocol(protocol.Protocol): - - # Win32 sockets cannot handle single huge chunks of bytes. Write one - # massive string to make sure Twisted deals with this fact. - - def connectionMade(self): - # write 60MB - self.transport.write('X'*self.factory.len) - self.factory.done = 1 - self.transport.loseConnection() - -class LargeBufferReaderProtocol(protocol.Protocol): - def dataReceived(self, data): - self.factory.len += len(data) - def connectionLost(self, reason): - self.factory.done = 1 - -class LargeBufferReaderClientFactory(protocol.ClientFactory): - def __init__(self): - self.done = 0 - self.len = 0 - def buildProtocol(self, addr): - p = LargeBufferReaderProtocol() - p.factory = self - self.protocol = p - return p - - -class FireOnClose(policies.ProtocolWrapper): - """A wrapper around a protocol that makes it fire a deferred when - connectionLost is called. - """ - def connectionLost(self, reason): - policies.ProtocolWrapper.connectionLost(self, reason) - self.factory.deferred.callback(None) - - -class FireOnCloseFactory(policies.WrappingFactory): - protocol = FireOnClose - - def __init__(self, wrappedFactory): - policies.WrappingFactory.__init__(self, wrappedFactory) - self.deferred = defer.Deferred() - - -class LargeBufferTestCase(unittest.TestCase): - """Test that buffering large amounts of data works. - """ - - datalen = 60*1024*1024 - def testWriter(self): - f = protocol.Factory() - f.protocol = LargeBufferWriterProtocol - f.done = 0 - f.problem = 0 - f.len = self.datalen - wrappedF = FireOnCloseFactory(f) - p = reactor.listenTCP(0, wrappedF, interface="127.0.0.1") - self.addCleanup(p.stopListening) - n = p.getHost().port - clientF = LargeBufferReaderClientFactory() - wrappedClientF = FireOnCloseFactory(clientF) - reactor.connectTCP("127.0.0.1", n, wrappedClientF) - - d = defer.gatherResults([wrappedF.deferred, wrappedClientF.deferred]) - def check(ignored): - self.failUnless(f.done, "writer didn't finish, it probably died") - self.failUnless(clientF.len == self.datalen, - "client didn't receive all the data it expected " - "(%d != %d)" % (clientF.len, self.datalen)) - self.failUnless(clientF.done, - "client didn't see connection dropped") - return d.addCallback(check) - - -class MyHCProtocol(MyProtocol): - - implements(IHalfCloseableProtocol) - - readHalfClosed = False - writeHalfClosed = False - - def readConnectionLost(self): - self.readHalfClosed = True - # Invoke notification logic from the base class to simplify testing. - if self.writeHalfClosed: - self.connectionLost(None) - - def writeConnectionLost(self): - self.writeHalfClosed = True - # Invoke notification logic from the base class to simplify testing. - if self.readHalfClosed: - self.connectionLost(None) - - -class MyHCFactory(protocol.ServerFactory): - - called = 0 - protocolConnectionMade = None - - def buildProtocol(self, addr): - self.called += 1 - p = MyHCProtocol() - p.factory = self - self.protocol = p - return p - - -class HalfCloseTestCase(unittest.TestCase): - """Test half-closing connections.""" - - def setUp(self): - self.f = f = MyHCFactory() - self.p = p = reactor.listenTCP(0, f, interface="127.0.0.1") - self.addCleanup(p.stopListening) - d = loopUntil(lambda :p.connected) - - self.cf = protocol.ClientCreator(reactor, MyHCProtocol) - - d.addCallback(lambda _: self.cf.connectTCP(p.getHost().host, - p.getHost().port)) - d.addCallback(self._setUp) - return d - - def _setUp(self, client): - self.client = client - self.clientProtoConnectionLost = self.client.closedDeferred = defer.Deferred() - self.assertEquals(self.client.transport.connected, 1) - # Wait for the server to notice there is a connection, too. - return loopUntil(lambda: getattr(self.f, 'protocol', None) is not None) - - def tearDown(self): - self.assertEquals(self.client.closed, 0) - self.client.transport.loseConnection() - d = defer.maybeDeferred(self.p.stopListening) - d.addCallback(lambda ign: self.clientProtoConnectionLost) - d.addCallback(self._tearDown) - return d - - def _tearDown(self, ignored): - self.assertEquals(self.client.closed, 1) - # because we did half-close, the server also needs to - # closed explicitly. - self.assertEquals(self.f.protocol.closed, 0) - d = defer.Deferred() - def _connectionLost(reason): - self.f.protocol.closed = 1 - d.callback(None) - self.f.protocol.connectionLost = _connectionLost - self.f.protocol.transport.loseConnection() - d.addCallback(lambda x:self.assertEquals(self.f.protocol.closed, 1)) - return d - - def testCloseWriteCloser(self): - client = self.client - f = self.f - t = client.transport - - t.write("hello") - d = loopUntil(lambda :len(t._tempDataBuffer) == 0) - def loseWrite(ignored): - t.loseWriteConnection() - return loopUntil(lambda :t._writeDisconnected) - def check(ignored): - self.assertEquals(client.closed, False) - self.assertEquals(client.writeHalfClosed, True) - self.assertEquals(client.readHalfClosed, False) - return loopUntil(lambda :f.protocol.readHalfClosed) - def write(ignored): - w = client.transport.write - w(" world") - w("lalala fooled you") - self.assertEquals(0, len(client.transport._tempDataBuffer)) - self.assertEquals(f.protocol.data, "hello") - self.assertEquals(f.protocol.closed, False) - self.assertEquals(f.protocol.readHalfClosed, True) - return d.addCallback(loseWrite).addCallback(check).addCallback(write) - - def testWriteCloseNotification(self): - f = self.f - f.protocol.transport.loseWriteConnection() - - d = defer.gatherResults([ - loopUntil(lambda :f.protocol.writeHalfClosed), - loopUntil(lambda :self.client.readHalfClosed)]) - d.addCallback(lambda _: self.assertEquals( - f.protocol.readHalfClosed, False)) - return d - - -class HalfClose2TestCase(unittest.TestCase): - - def setUp(self): - self.f = f = MyServerFactory() - self.f.protocolConnectionMade = defer.Deferred() - self.p = p = reactor.listenTCP(0, f, interface="127.0.0.1") - - # XXX we don't test server side yet since we don't do it yet - d = protocol.ClientCreator(reactor, MyProtocol).connectTCP( - p.getHost().host, p.getHost().port) - d.addCallback(self._gotClient) - return d - - def _gotClient(self, client): - self.client = client - # Now wait for the server to catch up - it doesn't matter if this - # Deferred has already fired and gone away, in that case we'll - # return None and not wait at all, which is precisely correct. - return self.f.protocolConnectionMade - - def tearDown(self): - self.client.transport.loseConnection() - return self.p.stopListening() - - def testNoNotification(self): - """ - TCP protocols support half-close connections, but not all of them - support being notified of write closes. In this case, test that - half-closing the connection causes the peer's connection to be - closed. - """ - self.client.transport.write("hello") - self.client.transport.loseWriteConnection() - self.f.protocol.closedDeferred = d = defer.Deferred() - self.client.closedDeferred = d2 = defer.Deferred() - d.addCallback(lambda x: - self.assertEqual(self.f.protocol.data, 'hello')) - d.addCallback(lambda x: self.assertEqual(self.f.protocol.closed, True)) - return defer.gatherResults([d, d2]) - - def testShutdownException(self): - """ - If the other side has already closed its connection, - loseWriteConnection should pass silently. - """ - self.f.protocol.transport.loseConnection() - self.client.transport.write("X") - self.client.transport.loseWriteConnection() - self.f.protocol.closedDeferred = d = defer.Deferred() - self.client.closedDeferred = d2 = defer.Deferred() - d.addCallback(lambda x: - self.failUnlessEqual(self.f.protocol.closed, True)) - return defer.gatherResults([d, d2]) - - -class HalfCloseBuggyApplicationTests(unittest.TestCase): - """ - Test half-closing connections where notification code has bugs. - """ - - def setUp(self): - """ - Set up a server and connect a client to it. Return a Deferred which - only fires once this is done. - """ - self.serverFactory = MyHCFactory() - self.serverFactory.protocolConnectionMade = defer.Deferred() - self.port = reactor.listenTCP( - 0, self.serverFactory, interface="127.0.0.1") - self.addCleanup(self.port.stopListening) - addr = self.port.getHost() - creator = protocol.ClientCreator(reactor, MyHCProtocol) - clientDeferred = creator.connectTCP(addr.host, addr.port) - def setClient(clientProtocol): - self.clientProtocol = clientProtocol - clientDeferred.addCallback(setClient) - return defer.gatherResults([ - self.serverFactory.protocolConnectionMade, - clientDeferred]) - - - def aBug(self, *args): - """ - Fake implementation of a callback which illegally raises an - exception. - """ - raise RuntimeError("ONO I AM BUGGY CODE") - - - def _notificationRaisesTest(self): - """ - Helper for testing that an exception is logged by the time the - client protocol loses its connection. - """ - closed = self.clientProtocol.closedDeferred = defer.Deferred() - self.clientProtocol.transport.loseWriteConnection() - def check(ignored): - errors = self.flushLoggedErrors(RuntimeError) - self.assertEqual(len(errors), 1) - closed.addCallback(check) - return closed - - - def test_readNotificationRaises(self): - """ - If C{readConnectionLost} raises an exception when the transport - calls it to notify the protocol of that event, the exception should - be logged and the protocol should be disconnected completely. - """ - self.serverFactory.protocol.readConnectionLost = self.aBug - return self._notificationRaisesTest() - - - def test_writeNotificationRaises(self): - """ - If C{writeConnectionLost} raises an exception when the transport - calls it to notify the protocol of that event, the exception should - be logged and the protocol should be disconnected completely. - """ - self.clientProtocol.writeConnectionLost = self.aBug - return self._notificationRaisesTest() - - - -class LogTestCase(unittest.TestCase): - """ - Test logging facility of TCP base classes. - """ - - def test_logstrClientSetup(self): - """ - Check that the log customization of the client transport happens - once the client is connected. - """ - server = MyServerFactory() - - client = MyClientFactory() - client.protocolConnectionMade = defer.Deferred() - - port = reactor.listenTCP(0, server, interface='127.0.0.1') - self.addCleanup(port.stopListening) - - connector = reactor.connectTCP( - port.getHost().host, port.getHost().port, client) - self.addCleanup(connector.disconnect) - - # It should still have the default value - self.assertEquals(connector.transport.logstr, - "Uninitialized") - - def cb(ign): - self.assertEquals(connector.transport.logstr, - "MyProtocol,client") - client.protocolConnectionMade.addCallback(cb) - return client.protocolConnectionMade - - - -class PauseProducingTestCase(unittest.TestCase): - """ - Test some behaviors of pausing the production of a transport. - """ - - def test_pauseProducingInConnectionMade(self): - """ - In C{connectionMade} of a client protocol, C{pauseProducing} used to be - ignored: this test is here to ensure it's not ignored. - """ - server = MyServerFactory() - - client = MyClientFactory() - client.protocolConnectionMade = defer.Deferred() - - port = reactor.listenTCP(0, server, interface='127.0.0.1') - self.addCleanup(port.stopListening) - - connector = reactor.connectTCP( - port.getHost().host, port.getHost().port, client) - self.addCleanup(connector.disconnect) - - def checkInConnectionMade(proto): - tr = proto.transport - # The transport should already be monitored - self.assertIn(tr, reactor.getReaders() + - reactor.getWriters()) - proto.transport.pauseProducing() - self.assertNotIn(tr, reactor.getReaders() + - reactor.getWriters()) - d = defer.Deferred() - d.addCallback(checkAfterConnectionMade) - reactor.callLater(0, d.callback, proto) - return d - def checkAfterConnectionMade(proto): - tr = proto.transport - # The transport should still not be monitored - self.assertNotIn(tr, reactor.getReaders() + - reactor.getWriters()) - client.protocolConnectionMade.addCallback(checkInConnectionMade) - return client.protocolConnectionMade - - if not interfaces.IReactorFDSet.providedBy(reactor): - test_pauseProducingInConnectionMade.skip = "Reactor not providing IReactorFDSet" - - - -class CallBackOrderTestCase(unittest.TestCase): - """ - Test the order of reactor callbacks - """ - - def test_loseOrder(self): - """ - Check that Protocol.connectionLost is called before factory's - clientConnectionLost - """ - server = MyServerFactory() - server.protocolConnectionMade = (defer.Deferred() - .addCallback(lambda proto: self.addCleanup( - proto.transport.loseConnection))) - - client = MyClientFactory() - client.protocolConnectionLost = defer.Deferred() - client.protocolConnectionMade = defer.Deferred() - - def _cbCM(res): - """ - protocol.connectionMade callback - """ - reactor.callLater(0, client.protocol.transport.loseConnection) - - client.protocolConnectionMade.addCallback(_cbCM) - - port = reactor.listenTCP(0, server, interface='127.0.0.1') - self.addCleanup(port.stopListening) - - connector = reactor.connectTCP( - port.getHost().host, port.getHost().port, client) - self.addCleanup(connector.disconnect) - - def _cbCCL(res): - """ - factory.clientConnectionLost callback - """ - return 'CCL' - - def _cbCL(res): - """ - protocol.connectionLost callback - """ - return 'CL' - - def _cbGather(res): - self.assertEquals(res, ['CL', 'CCL']) - - d = defer.gatherResults([ - client.protocolConnectionLost.addCallback(_cbCL), - client.deferred.addCallback(_cbCCL)]) - return d.addCallback(_cbGather) - - - -try: - import resource -except ImportError: - pass -else: - numRounds = resource.getrlimit(resource.RLIMIT_NOFILE)[0] + 10 - ProperlyCloseFilesTestCase.numberRounds = numRounds diff --git a/tools/buildbot/pylibs/twisted/test/test_tcp_internals.py b/tools/buildbot/pylibs/twisted/test/test_tcp_internals.py deleted file mode 100644 index e4bf5bd..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_tcp_internals.py +++ /dev/null @@ -1,240 +0,0 @@ -# Copyright (c) 2006 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Whitebox tests for TCP APIs. -""" - -import errno, socket, os - -try: - import resource -except ImportError: - resource = None - -from twisted.trial.unittest import TestCase - -from twisted.python import log -from twisted.internet.tcp import ECONNABORTED, ENOMEM, ENFILE, EMFILE, ENOBUFS, EINPROGRESS, Port -from twisted.internet.protocol import ServerFactory -from twisted.python.runtime import platform -from twisted.internet.defer import maybeDeferred, gatherResults -from twisted.internet import reactor, interfaces - - -class PlatformAssumptionsTestCase(TestCase): - """ - Test assumptions about platform behaviors. - """ - socketLimit = 8192 - - def setUp(self): - self.openSockets = [] - if resource is not None: - self.originalFileLimit = resource.getrlimit(resource.RLIMIT_NOFILE) - resource.setrlimit(resource.RLIMIT_NOFILE, (128, self.originalFileLimit[1])) - self.socketLimit = 256 - - - def tearDown(self): - while self.openSockets: - self.openSockets.pop().close() - if resource is not None: - # OS X implicitly lowers the hard limit in the setrlimit call - # above. Retrieve the new hard limit to pass in to this - # setrlimit call, so that it doesn't give us a permission denied - # error. - currentHardLimit = resource.getrlimit(resource.RLIMIT_NOFILE)[1] - newSoftLimit = min(self.originalFileLimit[0], currentHardLimit) - resource.setrlimit(resource.RLIMIT_NOFILE, (newSoftLimit, currentHardLimit)) - - - def socket(self): - """ - Create and return a new socket object, also tracking it so it can be - closed in the test tear down. - """ - s = socket.socket() - self.openSockets.append(s) - return s - - - def test_acceptOutOfFiles(self): - """ - Test that the platform accept(2) call fails with either L{EMFILE} or - L{ENOBUFS} when there are too many file descriptors open. - """ - # Make a server to which to connect - port = self.socket() - port.bind(('127.0.0.1', 0)) - serverPortNumber = port.getsockname()[1] - port.listen(5) - - # Use up all the file descriptors - for i in xrange(self.socketLimit): - try: - self.socket() - except socket.error, e: - if e.args[0] in (EMFILE, ENOBUFS): - self.openSockets.pop().close() - break - else: - raise - else: - self.fail("Could provoke neither EMFILE nor ENOBUFS from platform.") - - # Make a client to use to connect to the server - client = self.socket() - client.setblocking(False) - - # Non-blocking connect is supposed to fail, but this is not true - # everywhere (e.g. freeBSD) - self.assertIn(client.connect_ex(('127.0.0.1', serverPortNumber)), - (0, EINPROGRESS)) - - # Make sure that the accept call fails in the way we expect. - exc = self.assertRaises(socket.error, port.accept) - self.assertIn(exc.args[0], (EMFILE, ENOBUFS)) - if platform.getType() == "win32": - test_acceptOutOfFiles.skip = ( - "Windows requires an unacceptably large amount of resources to " - "provoke this behavior in the naive manner.") - - - -class SelectReactorTestCase(TestCase): - """ - Tests for select-specific failure conditions. - """ - - def setUp(self): - self.ports = [] - self.messages = [] - log.addObserver(self.messages.append) - - - def tearDown(self): - log.removeObserver(self.messages.append) - return gatherResults([ - maybeDeferred(p.stopListening) - for p in self.ports]) - - - def port(self, portNumber, factory, interface): - """ - Create, start, and return a new L{Port}, also tracking it so it can - be stopped in the test tear down. - """ - p = Port(portNumber, factory, interface=interface) - p.startListening() - self.ports.append(p) - return p - - - def _acceptFailureTest(self, socketErrorNumber): - """ - Test behavior in the face of an exception from C{accept(2)}. - - On any exception which indicates the platform is unable or unwilling - to allocate further resources to us, the existing port should remain - listening, a message should be logged, and the exception should not - propagate outward from doRead. - - @param socketErrorNumber: The errno to simulate from accept. - """ - class FakeSocket(object): - """ - Pretend to be a socket in an overloaded system. - """ - def accept(self): - raise socket.error( - socketErrorNumber, os.strerror(socketErrorNumber)) - - factory = ServerFactory() - port = self.port(0, factory, interface='127.0.0.1') - originalSocket = port.socket - try: - port.socket = FakeSocket() - - port.doRead() - - expectedFormat = "Could not accept new connection (%s)" - expectedErrorCode = errno.errorcode[socketErrorNumber] - expectedMessage = expectedFormat % (expectedErrorCode,) - for msg in self.messages: - if msg.get('message') == (expectedMessage,): - break - else: - self.fail("Log event for failed accept not found in " - "%r" % (self.messages,)) - finally: - port.socket = originalSocket - - - def test_tooManyFilesFromAccept(self): - """ - C{accept(2)} can fail with C{EMFILE} when there are too many open file - descriptors in the process. Test that this doesn't negatively impact - any other existing connections. - - C{EMFILE} mainly occurs on Linux when the open file rlimit is - encountered. - """ - return self._acceptFailureTest(EMFILE) - - - def test_noBufferSpaceFromAccept(self): - """ - Similar to L{test_tooManyFilesFromAccept}, but test the case where - C{accept(2)} fails with C{ENOBUFS}. - - This mainly occurs on Windows and FreeBSD, but may be possible on - Linux and other platforms as well. - """ - return self._acceptFailureTest(ENOBUFS) - - - def test_connectionAbortedFromAccept(self): - """ - Similar to L{test_tooManyFilesFromAccept}, but test the case where - C{accept(2)} fails with C{ECONNABORTED}. - - It is not clear whether this is actually possible for TCP - connections on modern versions of Linux. - """ - return self._acceptFailureTest(ECONNABORTED) - - - def test_noFilesFromAccept(self): - """ - Similar to L{test_tooManyFilesFromAccept}, but test the case where - C{accept(2)} fails with C{ENFILE}. - - This can occur on Linux when the system has exhausted (!) its supply - of inodes. - """ - return self._acceptFailureTest(ENFILE) - if platform.getType() == 'win32': - test_noFilesFromAccept.skip = "Windows accept(2) cannot generate ENFILE" - - - def test_noMemoryFromAccept(self): - """ - Similar to L{test_tooManyFilesFromAccept}, but test the case where - C{accept(2)} fails with C{ENOMEM}. - - On Linux at least, this can sensibly occur, even in a Python program - (which eats memory like no ones business), when memory has become - fragmented or low memory has been filled (d_alloc calls - kmem_cache_alloc calls kmalloc - kmalloc only allocates out of low - memory). - """ - return self._acceptFailureTest(ENOMEM) - if platform.getType() == 'win32': - test_noMemoryFromAccept.skip = "Windows accept(2) cannot generate ENOMEM" - -if not interfaces.IReactorFDSet.providedBy(reactor): - skipMsg = 'This test only applies to reactors that implement IReactorFDset' - PlatformAssumptionsTestCase.skip = skipMsg - SelectReactorTestCase.skip = skipMsg - diff --git a/tools/buildbot/pylibs/twisted/test/test_text.py b/tools/buildbot/pylibs/twisted/test/test_text.py deleted file mode 100644 index cd0109d..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_text.py +++ /dev/null @@ -1,156 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -from twisted.trial import unittest -from twisted.python import text -import string -from cStringIO import StringIO - -sampleText = \ -"""Every attempt to employ mathematical methods in the study of chemical -questions must be considered profoundly irrational and contrary to the -spirit of chemistry ... If mathematical analysis should ever hold a -prominent place in chemistry - an aberration which is happily almost -impossible - it would occasion a rapid and widespread degeneration of that -science. - -- Auguste Comte, Philosophie Positive, Paris, 1838 -""" - -lineWidth = 72 - -def set_lineWidth(n): - global lineWidth - lineWidth = n - -class WrapTest(unittest.TestCase): - def setUp(self): - self.sampleSplitText = string.split(sampleText) - - self.output = text.wordWrap(sampleText, lineWidth) - - def test_wordCount(self): - """Compare the number of words.""" - words = [] - for line in self.output: - words.extend(string.split(line)) - wordCount = len(words) - sampleTextWordCount = len(self.sampleSplitText) - - self.failUnlessEqual(wordCount, sampleTextWordCount) - - def test_wordMatch(self): - """Compare the lists of words.""" - - words = [] - for line in self.output: - words.extend(string.split(line)) - - # Using failUnlessEqual here prints out some - # rather too long lists. - self.failUnless(self.sampleSplitText == words) - - def test_lineLength(self): - """Check the length of the lines.""" - failures = [] - for line in self.output: - if not len(line) <= lineWidth: - failures.append(len(line)) - - if failures: - self.fail("%d of %d lines were too long.\n" - "%d < %s" % (len(failures), len(self.output), - lineWidth, failures)) - - -class SplitTest(unittest.TestCase): - """Tests for text.splitQuoted()""" - - def test_oneWord(self): - """Splitting strings with one-word phrases.""" - s = 'This code "works."' - r = text.splitQuoted(s) - self.failUnlessEqual(['This', 'code', 'works.'], r) - - def test_multiWord(self): - s = 'The "hairy monkey" likes pie.' - r = text.splitQuoted(s) - self.failUnlessEqual(['The', 'hairy monkey', 'likes', 'pie.'], r) - - # Some of the many tests that would fail: - - #def test_preserveWhitespace(self): - # phrase = '"MANY SPACES"' - # s = 'With %s between.' % (phrase,) - # r = text.splitQuoted(s) - # self.failUnlessEqual(['With', phrase, 'between.'], r) - - #def test_escapedSpace(self): - # s = r"One\ Phrase" - # r = text.splitQuoted(s) - # self.failUnlessEqual(["One Phrase"], r) - -class StrFileTest(unittest.TestCase): - def setUp(self): - self.io = StringIO("this is a test string") - - def tearDown(self): - pass - - def test_1_f(self): - self.assertEquals(False, text.strFile("x", self.io)) - - def test_1_1(self): - self.assertEquals(True, text.strFile("t", self.io)) - - def test_1_2(self): - self.assertEquals(True, text.strFile("h", self.io)) - - def test_1_3(self): - self.assertEquals(True, text.strFile("i", self.io)) - - def test_1_4(self): - self.assertEquals(True, text.strFile("s", self.io)) - - def test_1_5(self): - self.assertEquals(True, text.strFile("n", self.io)) - - def test_1_6(self): - self.assertEquals(True, text.strFile("g", self.io)) - - def test_3_1(self): - self.assertEquals(True, text.strFile("thi", self.io)) - - def test_3_2(self): - self.assertEquals(True, text.strFile("his", self.io)) - - def test_3_3(self): - self.assertEquals(True, text.strFile("is ", self.io)) - - def test_3_4(self): - self.assertEquals(True, text.strFile("ing", self.io)) - - def test_3_f(self): - self.assertEquals(False, text.strFile("bla", self.io)) - - def test_large_1(self): - self.assertEquals(True, text.strFile("this is a test", self.io)) - - def test_large_2(self): - self.assertEquals(True, text.strFile("is a test string", self.io)) - - def test_large_f(self): - self.assertEquals(False, text.strFile("ds jhfsa k fdas", self.io)) - - def test_overlarge_f(self): - self.assertEquals(False, text.strFile("djhsakj dhsa fkhsa s,mdbnfsauiw bndasdf hreew", self.io)) - - def test_self(self): - self.assertEquals(True, text.strFile("this is a test string", self.io)) - - def test_insensitive(self): - self.assertEquals(True, text.strFile("ThIs is A test STRING", self.io, False)) - -testCases = [WrapTest, SplitTest, StrFileTest] - diff --git a/tools/buildbot/pylibs/twisted/test/test_threadable.py b/tools/buildbot/pylibs/twisted/test/test_threadable.py deleted file mode 100644 index 394541e..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_threadable.py +++ /dev/null @@ -1,104 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -import sys, pickle - -try: - import threading -except ImportError: - threading = None - -from twisted.trial import unittest -from twisted.python import threadable -from twisted.internet import defer, reactor - -class TestObject: - synchronized = ['aMethod'] - - x = -1 - y = 1 - - def aMethod(self): - for i in xrange(10): - self.x, self.y = self.y, self.x - self.z = self.x + self.y - assert self.z == 0, "z == %d, not 0 as expected" % (self.z,) - -threadable.synchronize(TestObject) - -class SynchronizationTestCase(unittest.TestCase): - if hasattr(sys, 'getcheckinterval'): - def setUpClass(self): - self.checkInterval = sys.getcheckinterval() - sys.setcheckinterval(7) - - def tearDownClass(self): - sys.setcheckinterval(self.checkInterval) - - - def setUp(self): - # XXX This is a trial hack. We need to make sure the reactor - # actually *starts* for isInIOThread() to have a meaningful result. - # Returning a Deferred here should force that to happen, if it has - # not happened already. In the future, this should not be - # necessary. - d = defer.Deferred() - reactor.callLater(0, d.callback, None) - return d - - - def testIsInIOThread(self): - foreignResult = [] - t = threading.Thread(target=lambda: foreignResult.append(threadable.isInIOThread())) - t.start() - t.join() - self.failIf(foreignResult[0], "Non-IO thread reported as IO thread") - self.failUnless(threadable.isInIOThread(), "IO thread reported as not IO thread") - - - def testThreadedSynchronization(self): - o = TestObject() - - errors = [] - - def callMethodLots(): - try: - for i in xrange(1000): - o.aMethod() - except AssertionError, e: - errors.append(str(e)) - - threads = [] - for x in range(5): - t = threading.Thread(target=callMethodLots) - threads.append(t) - t.start() - - for t in threads: - t.join() - - if errors: - raise unittest.FailTest(errors) - - def testUnthreadedSynchronization(self): - o = TestObject() - for i in xrange(1000): - o.aMethod() - -class SerializationTestCase(unittest.TestCase): - def testPickling(self): - lock = threadable.XLock() - lockType = type(lock) - lockPickle = pickle.dumps(lock) - newLock = pickle.loads(lockPickle) - self.failUnless(isinstance(newLock, lockType)) - - def testUnpickling(self): - lockPickle = 'ctwisted.python.threadable\nunpickle_lock\np0\n(tp1\nRp2\n.' - lock = pickle.loads(lockPickle) - newPickle = pickle.dumps(lock, 2) - newLock = pickle.loads(newPickle) - -if threading is None: - SynchronizationTestCase.testThreadedSynchronization.skip = "Platform lacks thread support" - SerializationTestCase.testPickling.skip = "Platform lacks thread support" diff --git a/tools/buildbot/pylibs/twisted/test/test_threadpool.py b/tools/buildbot/pylibs/twisted/test/test_threadpool.py deleted file mode 100644 index f0b57b2..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_threadpool.py +++ /dev/null @@ -1,307 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -import pickle, time, weakref, gc - -from twisted.trial import unittest, util -from twisted.python import threadable -from twisted.internet import reactor, interfaces - -# -# See the end of this module for the remainder of the imports. -# - -class Synchronization(object): - failures = 0 - - def __init__(self, N, waiting): - self.N = N - self.waiting = waiting - self.lock = threading.Lock() - self.runs = [] - - def run(self): - # This is the testy part: this is supposed to be invoked - # serially from multiple threads. If that is actually the - # case, we will never fail to acquire this lock. If it is - # *not* the case, we might get here while someone else is - # holding the lock. - if self.lock.acquire(False): - if not len(self.runs) % 5: - time.sleep(0.0002) # Constant selected based on - # empirical data to maximize the - # chance of a quick failure if this - # code is broken. - self.lock.release() - else: - self.failures += 1 - - # This is just the only way I can think of to wake up the test - # method. It doesn't actually have anything to do with the - # test. - self.lock.acquire() - self.runs.append(None) - if len(self.runs) == self.N: - self.waiting.release() - self.lock.release() - - synchronized = ["run"] -threadable.synchronize(Synchronization) - - - -class ThreadPoolTestCase(unittest.TestCase): - """ - Test threadpools. - """ - - def test_threadCreationArguments(self): - """ - Test that creating threads in the threadpool with application-level - objects as arguments doesn't results in those objects never being - freed, with the thread maintaining a reference to them as long as it - exists. - """ - try: - tp = threadpool.ThreadPool(0, 1) - tp.start() - - # Sanity check - no threads should have been started yet. - self.assertEqual(tp.threads, []) - - # Here's our function - def worker(arg): - pass - # weakref need an object subclass - class Dumb(object): - pass - # And here's the unique object - unique = Dumb() - - workerRef = weakref.ref(worker) - uniqueRef = weakref.ref(unique) - - # Put some work in - tp.callInThread(worker, unique) - - # Add an event to wait completion - event = threading.Event() - tp.callInThread(event.set) - event.wait(self.getTimeout()) - - del worker - del unique - gc.collect() - self.assertEquals(uniqueRef(), None) - self.assertEquals(workerRef(), None) - finally: - tp.stop() - - - def test_persistence(self): - """ - Threadpools can be pickled and unpickled, which should preserve the - number of threads and other parameters. - """ - tp = threadpool.ThreadPool(7, 20) - tp.start() - - # XXX Sigh - race condition: start should return a Deferred - # which fires when all the workers it started have fully - # started up. - time.sleep(0.1) - - self.assertEquals(len(tp.threads), 7) - self.assertEquals(tp.min, 7) - self.assertEquals(tp.max, 20) - - # check that unpickled threadpool has same number of threads - s = pickle.dumps(tp) - tp2 = pickle.loads(s) - tp2.start() - - # XXX As above - time.sleep(0.1) - - self.assertEquals(len(tp2.threads), 7) - self.assertEquals(tp2.min, 7) - self.assertEquals(tp2.max, 20) - - tp.stop() - tp2.stop() - - - def _waitForLock(self, lock): - for i in xrange(1000000): - if lock.acquire(False): - break - time.sleep(1e-5) - else: - self.fail("A long time passed without succeeding") - - - def _threadpoolTest(self, method): - """ - Test synchronization of calls made with C{method}, which should be - one of the mecanisms of the threadpool to execute work in threads. - """ - # This is a schizophrenic test: it seems to be trying to test - # both the callInThread()/dispatch() behavior of the ThreadPool as well - # as the serialization behavior of threadable.synchronize(). It - # would probably make more sense as two much simpler tests. - N = 10 - - tp = threadpool.ThreadPool() - tp.start() - try: - waiting = threading.Lock() - waiting.acquire() - actor = Synchronization(N, waiting) - - for i in xrange(N): - method(tp, actor) - - self._waitForLock(waiting) - - self.failIf(actor.failures, "run() re-entered %d times" % - (actor.failures,)) - finally: - tp.stop() - - - def test_dispatch(self): - """ - Call C{_threadpoolTest} with C{dispatch}. - """ - return self._threadpoolTest( - lambda tp, actor: tp.dispatch(actor, actor.run)) - - test_dispatch.suppress = [util.suppress( - message="dispatch\(\) is deprecated since Twisted 8.0, " - "use callInThread\(\) instead", - category=DeprecationWarning)] - - - def test_callInThread(self): - """ - Call C{_threadpoolTest} with C{callInThread}. - """ - return self._threadpoolTest( - lambda tp, actor: tp.callInThread(actor.run)) - - - def test_existingWork(self): - """ - Work added to the threadpool before its start should be executed once - the threadpool is started: this is ensured by trying to release a lock - previously acquired. - """ - waiter = threading.Lock() - waiter.acquire() - - tp = threadpool.ThreadPool(0, 1) - tp.callInThread(waiter.release) # before start() - tp.start() - - try: - self._waitForLock(waiter) - finally: - tp.stop() - - - def test_dispatchDeprecation(self): - """ - Test for the deprecation of the dispatch method. - """ - tp = threadpool.ThreadPool() - tp.start() - def cb(): - return tp.dispatch(None, lambda: None) - try: - self.assertWarns(DeprecationWarning, - "dispatch() is deprecated since Twisted 8.0, " - "use callInThread() instead", - __file__, cb) - finally: - tp.stop() - - - def test_dispatchWithCallbackDeprecation(self): - """ - Test for the deprecation of the dispatchWithCallback method. - """ - tp = threadpool.ThreadPool() - tp.start() - def cb(): - return tp.dispatchWithCallback( - None, - lambda x: None, - lambda x: None, - lambda: None) - try: - self.assertWarns(DeprecationWarning, - "dispatchWithCallback() is deprecated since Twisted 8.0, " - "use twisted.internet.threads.deferToThread() instead.", - __file__, cb) - finally: - tp.stop() - - - -class RaceConditionTestCase(unittest.TestCase): - def setUp(self): - self.event = threading.Event() - self.threadpool = threadpool.ThreadPool(0, 10) - self.threadpool.start() - - - def tearDown(self): - del self.event - self.threadpool.stop() - del self.threadpool - - - def test_synchronization(self): - """ - Test a race condition: ensure that actions run in the pool synchronize - with actions run in the main thread. - """ - timeout = self.getTimeout() - self.threadpool.callInThread(self.event.set) - self.event.wait(timeout) - self.event.clear() - for i in range(3): - self.threadpool.callInThread(self.event.wait) - self.threadpool.callInThread(self.event.set) - self.event.wait(timeout) - if not self.event.isSet(): - self.event.set() - self.fail("Actions not synchronized") - - - def test_singleThread(self): - """ - Test that the creation of new threads in the pool occurs only when - more jobs are added and all existing threads are occupied. - """ - # Ensure no threads running - self.assertEquals(self.threadpool.workers, 0) - timeout = self.getTimeout() - for i in range(10): - self.threadpool.callInThread(self.event.set) - self.event.wait(timeout) - self.event.clear() - - # Ensure there are very few threads running - self.failUnless(self.threadpool.workers <= 2) - - - -if interfaces.IReactorThreads(reactor, None) is None: - for cls in ThreadPoolTestCase, RaceConditionTestCase: - setattr(cls, 'skip', "No thread support, nothing to test here") -else: - import threading - from twisted.python import threadpool - diff --git a/tools/buildbot/pylibs/twisted/test/test_threads.py b/tools/buildbot/pylibs/twisted/test/test_threads.py deleted file mode 100644 index 33fd42a..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_threads.py +++ /dev/null @@ -1,356 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Test methods in twisted.internet.threads and reactor thread APIs. -""" - -import sys, os, time - -from twisted.trial import unittest - -from twisted.internet import reactor, defer, interfaces, threads, protocol, error -from twisted.python import failure, threadable, log - -class ReactorThreadsTestCase(unittest.TestCase): - """ - Tests for the reactor threading API. - """ - - def test_suggestThreadPoolSize(self): - """ - Try to change maximum number of threads. - """ - reactor.suggestThreadPoolSize(34) - self.assertEquals(reactor.threadpool.max, 34) - reactor.suggestThreadPoolSize(4) - self.assertEquals(reactor.threadpool.max, 4) - - - def _waitForThread(self): - """ - The reactor's threadpool is only available when the reactor is running, - so to have a sane behavior during the tests we make a dummy - L{threads.deferToThread} call. - """ - return threads.deferToThread(time.sleep, 0) - - - def test_callInThread(self): - """ - Test callInThread functionality: set a C{threading.Event}, and check - that it's not in the main thread. - """ - def cb(ign): - waiter = threading.Event() - result = [] - def threadedFunc(): - result.append(threadable.isInIOThread()) - waiter.set() - - reactor.callInThread(threadedFunc) - waiter.wait(120) - if not waiter.isSet(): - self.fail("Timed out waiting for event.") - else: - self.assertEquals(result, [False]) - return self._waitForThread().addCallback(cb) - - - def test_callFromThread(self): - """ - Test callFromThread functionality: from the main thread, and from - another thread. - """ - def cb(ign): - firedByReactorThread = defer.Deferred() - firedByOtherThread = defer.Deferred() - - def threadedFunc(): - reactor.callFromThread(firedByOtherThread.callback, None) - - reactor.callInThread(threadedFunc) - reactor.callFromThread(firedByReactorThread.callback, None) - - return defer.DeferredList( - [firedByReactorThread, firedByOtherThread], - fireOnOneErrback=True) - return self._waitForThread().addCallback(cb) - - - def test_wakerOverflow(self): - """ - Try to make an overflow on the reactor waker using callFromThread. - """ - def cb(ign): - self.failure = None - waiter = threading.Event() - def threadedFunction(): - # Hopefully a hundred thousand queued calls is enough to - # trigger the error condition - for i in xrange(100000): - try: - reactor.callFromThread(lambda: None) - except: - self.failure = failure.Failure() - break - waiter.set() - reactor.callInThread(threadedFunction) - waiter.wait(120) - if not waiter.isSet(): - self.fail("Timed out waiting for event") - if self.failure is not None: - return defer.fail(self.failure) - return self._waitForThread().addCallback(cb) - - def _testBlockingCallFromThread(self, reactorFunc): - """ - Utility method to test L{threads.blockingCallFromThread}. - """ - waiter = threading.Event() - results = [] - errors = [] - def cb1(ign): - def threadedFunc(): - try: - r = threads.blockingCallFromThread(reactor, reactorFunc) - except Exception, e: - errors.append(e) - else: - results.append(r) - waiter.set() - - reactor.callInThread(threadedFunc) - return threads.deferToThread(waiter.wait, self.getTimeout()) - - def cb2(ign): - if not waiter.isSet(): - self.fail("Timed out waiting for event") - return results, errors - - return self._waitForThread().addCallback(cb1).addBoth(cb2) - - def test_blockingCallFromThread(self): - """ - Test blockingCallFromThread facility: create a thread, call a function - in the reactor using L{threads.blockingCallFromThread}, and verify the - result returned. - """ - def reactorFunc(): - return defer.succeed("foo") - def cb(res): - self.assertEquals(res[0][0], "foo") - - return self._testBlockingCallFromThread(reactorFunc).addCallback(cb) - - def test_asyncBlockingCallFromThread(self): - """ - Test blockingCallFromThread as above, but be sure the resulting - Deferred is not already fired. - """ - def reactorFunc(): - d = defer.Deferred() - reactor.callLater(0.1, d.callback, "egg") - return d - def cb(res): - self.assertEquals(res[0][0], "egg") - - return self._testBlockingCallFromThread(reactorFunc).addCallback(cb) - - def test_errorBlockingCallFromThread(self): - """ - Test error report for blockingCallFromThread. - """ - def reactorFunc(): - return defer.fail(RuntimeError("bar")) - def cb(res): - self.assert_(isinstance(res[1][0], RuntimeError)) - self.assertEquals(res[1][0].args[0], "bar") - - return self._testBlockingCallFromThread(reactorFunc).addCallback(cb) - - def test_asyncErrorBlockingCallFromThread(self): - """ - Test error report for blockingCallFromThread as above, but be sure the - resulting Deferred is not already fired. - """ - def reactorFunc(): - d = defer.Deferred() - reactor.callLater(0.1, d.errback, RuntimeError("spam")) - return d - def cb(res): - self.assert_(isinstance(res[1][0], RuntimeError)) - self.assertEquals(res[1][0].args[0], "spam") - - return self._testBlockingCallFromThread(reactorFunc).addCallback(cb) - - -class Counter: - index = 0 - problem = 0 - - def add(self): - """A non thread-safe method.""" - next = self.index + 1 - # another thread could jump in here and increment self.index on us - if next != self.index + 1: - self.problem = 1 - raise ValueError - # or here, same issue but we wouldn't catch it. We'd overwrite - # their results, and the index will have lost a count. If - # several threads get in here, we will actually make the count - # go backwards when we overwrite it. - self.index = next - - - -class DeferredResultTestCase(unittest.TestCase): - """ - Test twisted.internet.threads. - """ - - def setUp(self): - reactor.suggestThreadPoolSize(8) - - - def tearDown(self): - reactor.suggestThreadPoolSize(0) - - - def testCallMultiple(self): - L = [] - N = 10 - d = defer.Deferred() - - def finished(): - self.assertEquals(L, range(N)) - d.callback(None) - - threads.callMultipleInThread([ - (L.append, (i,), {}) for i in xrange(N) - ] + [(reactor.callFromThread, (finished,), {})]) - return d - - - def testDeferredResult(self): - d = threads.deferToThread(lambda x, y=5: x + y, 3, y=4) - d.addCallback(self.assertEquals, 7) - return d - - - def testDeferredFailure(self): - class NewError(Exception): - pass - def raiseError(): - raise NewError - d = threads.deferToThread(raiseError) - return self.assertFailure(d, NewError) - - - def testDeferredFailure2(self): - # set up a condition that causes cReactor to hang. These conditions - # can also be set by other tests when the full test suite is run in - # alphabetical order (test_flow.FlowTest.testThreaded followed by - # test_internet.ReactorCoreTestCase.testStop, to be precise). By - # setting them up explicitly here, we can reproduce the hang in a - # single precise test case instead of depending upon side effects of - # other tests. - # - # alas, this test appears to flunk the default reactor too - - d = threads.deferToThread(lambda: None) - d.addCallback(lambda ign: threads.deferToThread(lambda: 1/0)) - return self.assertFailure(d, ZeroDivisionError) - - -_callBeforeStartupProgram = """ -import time -import %(reactor)s -%(reactor)s.install() - -from twisted.internet import reactor - -def threadedCall(): - print 'threaded call' - -reactor.callInThread(threadedCall) - -# Spin very briefly to try to give the thread a chance to run, if it -# is going to. Is there a better way to achieve this behavior? -for i in xrange(100): - time.sleep(0.0) -""" - - -class ThreadStartupProcessProtocol(protocol.ProcessProtocol): - def __init__(self, finished): - self.finished = finished - self.out = [] - self.err = [] - - def outReceived(self, out): - self.out.append(out) - - def errReceived(self, err): - self.err.append(err) - - def processEnded(self, reason): - self.finished.callback((self.out, self.err, reason)) - - - -class StartupBehaviorTestCase(unittest.TestCase): - """ - Test cases for the behavior of the reactor threadpool near startup - boundary conditions. - - In particular, this asserts that no threaded calls are attempted - until the reactor starts up, that calls attempted before it starts - are in fact executed once it has started, and that in both cases, - the reactor properly cleans itself up (which is tested for - somewhat implicitly, by requiring a child process be able to exit, - something it cannot do unless the threadpool has been properly - torn down). - """ - - - def testCallBeforeStartupUnexecuted(self): - progname = self.mktemp() - progfile = file(progname, 'w') - progfile.write(_callBeforeStartupProgram % {'reactor': reactor.__module__}) - progfile.close() - - def programFinished((out, err, reason)): - if reason.check(error.ProcessTerminated): - self.fail("Process did not exit cleanly (out: %s err: %s)" % (out, err)) - - if err: - log.msg("Unexpected output on standard error: %s" % (err,)) - self.failIf(out, "Expected no output, instead received:\n%s" % (out,)) - - def programTimeout(err): - err.trap(error.TimeoutError) - proto.signalProcess('KILL') - return err - - env = os.environ.copy() - env['PYTHONPATH'] = os.pathsep.join(sys.path) - d = defer.Deferred().addCallbacks(programFinished, programTimeout) - proto = ThreadStartupProcessProtocol(d) - reactor.spawnProcess(proto, sys.executable, ('python', progname), env) - return d - - - -if interfaces.IReactorThreads(reactor, None) is None: - for cls in (ReactorThreadsTestCase, - DeferredResultTestCase, - StartupBehaviorTestCase): - cls.skip = "No thread support, nothing to test here." -else: - import threading - -if interfaces.IReactorProcess(reactor, None) is None: - for cls in (StartupBehaviorTestCase,): - cls.skip = "No process support, cannot run subprocess thread tests." diff --git a/tools/buildbot/pylibs/twisted/test/test_timeoutqueue.py b/tools/buildbot/pylibs/twisted/test/test_timeoutqueue.py deleted file mode 100644 index 146b8ec..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_timeoutqueue.py +++ /dev/null @@ -1,73 +0,0 @@ - -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test cases for timeoutqueue module. -""" - -import time - -from twisted.python import timeoutqueue -from twisted.trial import unittest, util -from twisted.internet import reactor, interfaces - -timeoutqueueSuppression = util.suppress( - message="timeoutqueue is deprecated since Twisted 8.0", - category=DeprecationWarning) - - -class TimeoutQueueTest(unittest.TestCase): - """ - Test L{timeoutqueue.TimeoutQueue} class. - """ - - def tearDown(self): - del self.q - - def put(self): - time.sleep(1) - self.q.put(1) - - def test_timeout(self): - q = self.q = timeoutqueue.TimeoutQueue() - - try: - q.wait(1) - except timeoutqueue.TimedOut: - pass - else: - self.fail("Didn't time out") - test_timeout.suppress = [timeoutqueueSuppression] - - def test_get(self): - q = self.q = timeoutqueue.TimeoutQueue() - - start = time.time() - threading.Thread(target=self.put).start() - q.wait(1.5) - assert time.time() - start < 2 - - result = q.get(0) - if result != 1: - self.fail("Didn't get item we put in") - test_get.suppress = [timeoutqueueSuppression] - - def test_deprecation(self): - """ - Test that L{timeoutqueue.TimeoutQueue} prints a warning message. - """ - def createQueue(): - return timeoutqueue.TimeoutQueue() - self.q = self.assertWarns( - DeprecationWarning, - "timeoutqueue is deprecated since Twisted 8.0", - __file__, - createQueue) - - if interfaces.IReactorThreads(reactor, None) is None: - test_get.skip = "No thread support, no way to test putting during a blocked get" - else: - global threading - import threading - diff --git a/tools/buildbot/pylibs/twisted/test/test_tpfile.py b/tools/buildbot/pylibs/twisted/test/test_tpfile.py deleted file mode 100644 index eaa1789..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_tpfile.py +++ /dev/null @@ -1,52 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -from twisted.trial import unittest -from twisted.protocols import loopback -from twisted.protocols import basic -from twisted.internet import protocol, abstract - -import StringIO - -class BufferingServer(protocol.Protocol): - buffer = '' - def dataReceived(self, data): - self.buffer += data - -class FileSendingClient(protocol.Protocol): - def __init__(self, f): - self.f = f - - def connectionMade(self): - s = basic.FileSender() - d = s.beginFileTransfer(self.f, self.transport, lambda x: x) - d.addCallback(lambda r: self.transport.loseConnection()) - -class FileSenderTestCase(unittest.TestCase): - def testSendingFile(self): - testStr = 'xyz' * 100 + 'abc' * 100 + '123' * 100 - s = BufferingServer() - c = FileSendingClient(StringIO.StringIO(testStr)) - - d = loopback.loopbackTCP(s, c) - d.addCallback(lambda x : self.assertEquals(s.buffer, testStr)) - return d - - def testSendingEmptyFile(self): - fileSender = basic.FileSender() - consumer = abstract.FileDescriptor() - consumer.connected = 1 - emptyFile = StringIO.StringIO('') - - d = fileSender.beginFileTransfer(emptyFile, consumer, lambda x: x) - - # The producer will be immediately exhausted, and so immediately - # unregistered - self.assertEqual(consumer.producer, None) - - # Which means the Deferred from FileSender should have been called - self.failUnless(d.called, - 'producer unregistered with deferred being called') - diff --git a/tools/buildbot/pylibs/twisted/test/test_twistd.py b/tools/buildbot/pylibs/twisted/test/test_twistd.py deleted file mode 100644 index 3c67a5f..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_twistd.py +++ /dev/null @@ -1,724 +0,0 @@ -# Copyright (c) 2007-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.application.app} and L{twisted.scripts.twistd}. -""" - -import os, sys, cPickle -try: - import pwd, grp -except ImportError: - pwd = grp = None - -from zope.interface import implements - -from twisted.trial import unittest - -from twisted.application import service, app -from twisted.scripts import twistd -from twisted.python import log - -try: - import profile -except ImportError: - profile = None - -try: - import hotshot - import hotshot.stats -except (ImportError, SystemExit): - # For some reasons, hotshot.stats seems to raise SystemExit on some - # distributions, probably when considered non-free. See the import of - # this module in twisted.application.app for more details. - hotshot = None - -try: - import cProfile - import pstats -except ImportError: - cProfile = None - - - -def patchUserDatabase(patch, user, uid, group, gid): - """ - Patch L{pwd.getpwnam} so that it behaves as though only one user exists - and patch L{grp.getgrnam} so that it behaves as though only one group - exists. - - @param patch: A function like L{TestCase.patch} which will be used to - install the fake implementations. - - @type user: C{str} - @param user: The name of the single user which will exist. - - @type uid: C{int} - @param uid: The UID of the single user which will exist. - - @type group: C{str} - @param group: The name of the single user which will exist. - - @type gid: C{int} - @param gid: The GID of the single group which will exist. - """ - # Try not to be an unverified fake, but try not to depend on quirks of - # the system either (eg, run as a process with a uid and gid which - # equal each other, and so doesn't reliably test that uid is used where - # uid should be used and gid is used where gid should be used). -exarkun - pwent = pwd.getpwuid(os.getuid()) - grent = grp.getgrgid(os.getgid()) - - def getpwnam(name): - result = list(pwent) - result[result.index(pwent.pw_name)] = user - result[result.index(pwent.pw_uid)] = uid - result = tuple(result) - return {user: result}[name] - - def getgrnam(name): - result = list(grent) - result[result.index(grent.gr_name)] = group - result[result.index(grent.gr_gid)] = gid - result = tuple(result) - return {group: result}[name] - - patch(pwd, "getpwnam", getpwnam) - patch(grp, "getgrnam", getgrnam) - - - -class MockServiceMaker(object): - """ - A non-implementation of L{twisted.application.service.IServiceMaker}. - """ - tapname = 'ueoa' - - def makeService(self, options): - """ - Take a L{usage.Options} instance and return a - L{service.IService} provider. - """ - self.options = options - self.service = service.Service() - return self.service - - - -class CrippledApplicationRunner(twistd._SomeApplicationRunner): - """ - An application runner that cripples the platform-specific runner and - nasty side-effect-having code so that we can use it without actually - running any environment-affecting code. - """ - def preApplication(self): - pass - - def postApplication(self): - pass - - def startLogging(self, observer): - pass - - - -class ServerOptionsTest(unittest.TestCase): - """ - Non-platform-specific tests for the pltaform-specific ServerOptions class. - """ - - def test_postOptionsSubCommandCausesNoSave(self): - """ - postOptions should set no_save to True when a subcommand is used. - """ - config = twistd.ServerOptions() - config.subCommand = 'ueoa' - config.postOptions() - self.assertEquals(config['no_save'], True) - - - def test_postOptionsNoSubCommandSavesAsUsual(self): - """ - If no sub command is used, postOptions should not touch no_save. - """ - config = twistd.ServerOptions() - config.postOptions() - self.assertEquals(config['no_save'], False) - - - def test_reportProfileDeprecation(self): - """ - Check that the --report-profile option prints a C{DeprecationWarning}. - """ - config = twistd.ServerOptions() - self.assertWarns( - DeprecationWarning, "--report-profile option is deprecated and " - "a no-op since Twisted 8.0.", app.__file__, - config.parseOptions, ["--report-profile", "foo"]) - - - -class TapFileTest(unittest.TestCase): - """ - Test twistd-related functionality that requires a tap file on disk. - """ - - def setUp(self): - """ - Create a trivial Application and put it in a tap file on disk. - """ - self.tapfile = self.mktemp() - cPickle.dump(service.Application("Hi!"), file(self.tapfile, 'wb')) - - - def test_createOrGetApplicationWithTapFile(self): - """ - Ensure that the createOrGetApplication call that 'twistd -f foo.tap' - makes will load the Application out of foo.tap. - """ - config = twistd.ServerOptions() - config.parseOptions(['-f', self.tapfile]) - application = CrippledApplicationRunner(config).createOrGetApplication() - self.assertEquals(service.IService(application).name, 'Hi!') - - - -class TestApplicationRunner(app.ApplicationRunner): - """ - An ApplicationRunner which tracks the environment in which its - methods are called. - """ - def preApplication(self): - self.order = ["pre"] - self.hadApplicationPreApplication = hasattr(self, 'application') - - - def getLogObserver(self): - self.order.append("log") - self.hadApplicationLogObserver = hasattr(self, 'application') - return lambda events: None - - - def startLogging(self, observer): - pass - - - def postApplication(self): - self.order.append("post") - self.hadApplicationPostApplication = hasattr(self, 'application') - - - -class ApplicationRunnerTest(unittest.TestCase): - """ - Non-platform-specific tests for the platform-specific ApplicationRunner. - """ - def setUp(self): - config = twistd.ServerOptions() - self.serviceMaker = MockServiceMaker() - # Set up a config object like it's been parsed with a subcommand - config.loadedPlugins = {'test_command': self.serviceMaker} - config.subOptions = object() - config.subCommand = 'test_command' - self.config = config - - - def test_applicationRunnerGetsCorrectApplication(self): - """ - Ensure that a twistd plugin gets used in appropriate ways: it - is passed its Options instance, and the service it returns is - added to the application. - """ - arunner = CrippledApplicationRunner(self.config) - arunner.run() - - self.assertIdentical( - self.serviceMaker.options, self.config.subOptions, - "ServiceMaker.makeService needs to be passed the correct " - "sub Command object.") - self.assertIdentical( - self.serviceMaker.service, - service.IService(arunner.application).services[0], - "ServiceMaker.makeService's result needs to be set as a child " - "of the Application.") - - - def test_preAndPostApplication(self): - """ - Test thet preApplication and postApplication methods are - called by ApplicationRunner.run() when appropriate. - """ - s = TestApplicationRunner(self.config) - s.run() - self.failIf(s.hadApplicationPreApplication) - self.failUnless(s.hadApplicationPostApplication) - self.failUnless(s.hadApplicationLogObserver) - self.assertEquals(s.order, ["pre", "log", "post"]) - - - def test_stdoutLogObserver(self): - """ - Verify that if C{'-'} is specified as the log file, stdout is used. - """ - self.config.parseOptions(["--logfile", "-", "--nodaemon"]) - runner = CrippledApplicationRunner(self.config) - observerMethod = runner.getLogObserver() - observer = observerMethod.im_self - self.failUnless(isinstance(observer, log.FileLogObserver)) - writeMethod = observer.write - fileObj = writeMethod.__self__ - self.assertIdentical(fileObj, sys.stdout) - - - def test_fileLogObserver(self): - """ - Verify that if a string other than C{'-'} is specified as the log file, - the file with that name is used. - """ - logfilename = os.path.abspath(self.mktemp()) - self.config.parseOptions(["--logfile", logfilename]) - runner = CrippledApplicationRunner(self.config) - observerMethod = runner.getLogObserver() - observer = observerMethod.im_self - self.failUnless(isinstance(observer, log.FileLogObserver)) - writeMethod = observer.write - fileObj = writeMethod.im_self - self.assertEqual(fileObj.path, logfilename) - - - def _applicationStartsWithConfiguredID(self, argv, uid, gid): - """ - Assert that given a particular command line, an application is started - as a particular UID/GID. - - @param argv: A list of strings giving the options to parse. - @param uid: An integer giving the expected UID. - @param gid: An integer giving the expected GID. - """ - self.config.parseOptions(argv) - - events = [] - class FakeUnixApplicationRunner(twistd._SomeApplicationRunner): - def setupEnvironment(self, chroot, rundir, nodaemon, pidfile): - events.append('environment') - - def shedPrivileges(self, euid, uid, gid): - events.append(('privileges', euid, uid, gid)) - - def startReactor(self, reactor, oldstdout, oldstderr): - events.append('reactor') - - def removePID(self, pidfile): - pass - - - class FakeService(object): - implements(service.IService, service.IProcess) - - processName = None - - def privilegedStartService(self): - events.append('privilegedStartService') - - def startService(self): - events.append('startService') - - def stopService(self): - pass - - runner = FakeUnixApplicationRunner(self.config) - runner.preApplication() - runner.application = FakeService() - runner.postApplication() - - self.assertEqual( - events, - ['environment', 'privilegedStartService', - ('privileges', False, uid, gid), 'startService', 'reactor']) - - - def test_applicationStartsWithConfiguredNumericIDs(self): - """ - L{postApplication} should change the UID and GID to the values - specified as numeric strings by the configuration after running - L{service.IService.privilegedStartService} and before running - L{service.IService.startService}. - """ - uid = 1234 - gid = 4321 - self._applicationStartsWithConfiguredID( - ["--uid", str(uid), "--gid", str(gid)], uid, gid) - - - def test_applicationStartsWithConfiguredNameIDs(self): - """ - L{postApplication} should change the UID and GID to the values - specified as user and group names by the configuration after running - L{service.IService.privilegedStartService} and before running - L{service.IService.startService}. - """ - user = "foo" - uid = 1234 - group = "bar" - gid = 4321 - patchUserDatabase(self.patch, user, uid, group, gid) - self._applicationStartsWithConfiguredID( - ["--uid", user, "--gid", group], uid, gid) - - if getattr(os, 'setuid', None) is None: - msg = "Platform does not support --uid/--gid twistd options." - test_applicationStartsWithConfiguredNameIDs.skip = msg - test_applicationStartsWithConfiguredNumericIDs.skip = msg - del msg - - - def test_startReactorRunsTheReactor(self): - """ - L{startReactor} calls L{reactor.run}. - """ - reactor = DummyReactor() - runner = app.ApplicationRunner({ - "profile": False, - "profiler": "profile", - "debug": False}) - runner.startReactor(reactor, None, None) - self.assertTrue( - reactor.called, "startReactor did not call reactor.run()") - - - -class DummyReactor(object): - """ - A dummy reactor, only providing a C{run} method and checking that it - has been called. - - @ivar called: if C{run} has been called or not. - @type called: C{bool} - """ - called = False - - def run(self): - """ - A fake run method, checking that it's been called one and only time. - """ - if self.called: - raise RuntimeError("Already called") - self.called = True - - - -class AppProfilingTestCase(unittest.TestCase): - """ - Tests for L{app.AppProfiler}. - """ - - def test_profile(self): - """ - L{app.ProfileRunner.run} should call the C{run} method of the reactor - and save profile data in the specified file. - """ - config = twistd.ServerOptions() - config["profile"] = self.mktemp() - config["profiler"] = "profile" - profiler = app.AppProfiler(config) - reactor = DummyReactor() - - profiler.run(reactor) - - self.assertTrue(reactor.called) - data = file(config["profile"]).read() - self.assertIn("DummyReactor.run", data) - self.assertIn("function calls", data) - - if profile is None: - test_profile.skip = "profile module not available" - - - def test_profileSaveStats(self): - """ - With the C{savestats} option specified, L{app.ProfileRunner.run} - should save the raw stats object instead of a summary output. - """ - config = twistd.ServerOptions() - config["profile"] = self.mktemp() - config["profiler"] = "profile" - config["savestats"] = True - profiler = app.AppProfiler(config) - reactor = DummyReactor() - - profiler.run(reactor) - - self.assertTrue(reactor.called) - data = file(config["profile"]).read() - self.assertIn("DummyReactor.run", data) - self.assertNotIn("function calls", data) - - if profile is None: - test_profileSaveStats.skip = "profile module not available" - - - def test_withoutProfile(self): - """ - When the C{profile} module is not present, L{app.ProfilerRunner.run} - should raise a C{SystemExit} exception. - """ - savedModules = sys.modules.copy() - - config = twistd.ServerOptions() - config["profiler"] = "profile" - profiler = app.AppProfiler(config) - - sys.modules["profile"] = None - try: - self.assertRaises(SystemExit, profiler.run, None) - finally: - sys.modules.clear() - sys.modules.update(savedModules) - - - def test_profilePrintStatsError(self): - """ - When an error happens during the print of the stats, C{sys.stdout} - should be restored to its initial value. - """ - class ErroneousProfile(profile.Profile): - def print_stats(self): - raise RuntimeError("Boom") - self.patch(profile, "Profile", ErroneousProfile) - - config = twistd.ServerOptions() - config["profile"] = self.mktemp() - config["profiler"] = "profile" - profiler = app.AppProfiler(config) - reactor = DummyReactor() - - oldStdout = sys.stdout - self.assertRaises(RuntimeError, profiler.run, reactor) - self.assertIdentical(sys.stdout, oldStdout) - - if profile is None: - test_profilePrintStatsError.skip = "profile module not available" - - - def test_hotshot(self): - """ - L{app.HotshotRunner.run} should call the C{run} method of the reactor - and save profile data in the specified file. - """ - config = twistd.ServerOptions() - config["profile"] = self.mktemp() - config["profiler"] = "hotshot" - profiler = app.AppProfiler(config) - reactor = DummyReactor() - - profiler.run(reactor) - - self.assertTrue(reactor.called) - data = file(config["profile"]).read() - self.assertIn("run", data) - self.assertIn("function calls", data) - - if hotshot is None: - test_hotshot.skip = "hotshot module not available" - - - def test_hotshotSaveStats(self): - """ - With the C{savestats} option specified, L{app.HotshotRunner.run} should - save the raw stats object instead of a summary output. - """ - config = twistd.ServerOptions() - config["profile"] = self.mktemp() - config["profiler"] = "hotshot" - config["savestats"] = True - profiler = app.AppProfiler(config) - reactor = DummyReactor() - - profiler.run(reactor) - - self.assertTrue(reactor.called) - data = file(config["profile"]).read() - self.assertIn("hotshot-version", data) - self.assertIn("run", data) - self.assertNotIn("function calls", data) - - if hotshot is None: - test_hotshotSaveStats.skip = "hotshot module not available" - - - def test_withoutHotshot(self): - """ - When the C{hotshot} module is not present, L{app.HotshotRunner.run} - should raise a C{SystemExit} exception and log the C{ImportError}. - """ - savedModules = sys.modules.copy() - sys.modules["hotshot"] = None - - config = twistd.ServerOptions() - config["profiler"] = "hotshot" - profiler = app.AppProfiler(config) - try: - self.assertRaises(SystemExit, profiler.run, None) - finally: - sys.modules.clear() - sys.modules.update(savedModules) - - - def test_nothotshotDeprecation(self): - """ - Check that switching on the C{nothotshot} option produces a warning and - sets the profiler to B{profile}. - """ - config = twistd.ServerOptions() - config['nothotshot'] = True - profiler = self.assertWarns(DeprecationWarning, - "The --nothotshot option is deprecated. Please specify the " - "profiler name using the --profiler option", - app.__file__, app.AppProfiler, config) - self.assertEquals(profiler.profiler, "profile") - - - def test_hotshotPrintStatsError(self): - """ - When an error happens while printing the stats, C{sys.stdout} - should be restored to its initial value. - """ - import pstats - class ErroneousStats(pstats.Stats): - def print_stats(self): - raise RuntimeError("Boom") - self.patch(pstats, "Stats", ErroneousStats) - - config = twistd.ServerOptions() - config["profile"] = self.mktemp() - config["profiler"] = "hotshot" - profiler = app.AppProfiler(config) - reactor = DummyReactor() - - oldStdout = sys.stdout - self.assertRaises(RuntimeError, profiler.run, reactor) - self.assertIdentical(sys.stdout, oldStdout) - - if hotshot is None: - test_hotshotPrintStatsError.skip = "hotshot module not available" - - - def test_cProfile(self): - """ - L{app.CProfileRunner.run} should call the C{run} method of the - reactor and save profile data in the specified file. - """ - config = twistd.ServerOptions() - config["profile"] = self.mktemp() - config["profiler"] = "cProfile" - profiler = app.AppProfiler(config) - reactor = DummyReactor() - - profiler.run(reactor) - - self.assertTrue(reactor.called) - data = file(config["profile"]).read() - self.assertIn("run", data) - self.assertIn("function calls", data) - - if cProfile is None: - test_cProfile.skip = "cProfile module not available" - - - def test_cProfileSaveStats(self): - """ - With the C{savestats} option specified, - L{app.CProfileRunner.run} should save the raw stats object - instead of a summary output. - """ - config = twistd.ServerOptions() - config["profile"] = self.mktemp() - config["profiler"] = "cProfile" - config["savestats"] = True - profiler = app.AppProfiler(config) - reactor = DummyReactor() - - profiler.run(reactor) - - self.assertTrue(reactor.called) - data = file(config["profile"]).read() - self.assertIn("run", data) - - if cProfile is None: - test_cProfileSaveStats.skip = "cProfile module not available" - - - def test_withoutCProfile(self): - """ - When the C{cProfile} module is not present, - L{app.CProfileRunner.run} should raise a C{SystemExit} - exception and log the C{ImportError}. - """ - savedModules = sys.modules.copy() - sys.modules["cProfile"] = None - - config = twistd.ServerOptions() - config["profiler"] = "cProfile" - profiler = app.AppProfiler(config) - try: - self.assertRaises(SystemExit, profiler.run, None) - finally: - sys.modules.clear() - sys.modules.update(savedModules) - - - def test_unknownProfiler(self): - """ - Check that L{app.AppProfiler} raises L{SystemExit} when given an - unknown profiler name. - """ - config = twistd.ServerOptions() - config["profile"] = self.mktemp() - config["profiler"] = "foobar" - - error = self.assertRaises(SystemExit, app.AppProfiler, config) - self.assertEquals(str(error), "Unsupported profiler name: foobar") - - - def test_oldRunWithProfiler(self): - """ - L{app.runWithProfiler} should print a C{DeprecationWarning} pointing - at L{AppProfiler}. - """ - class DummyProfiler(object): - called = False - def run(self, reactor): - self.called = True - profiler = DummyProfiler() - self.patch(app, "AppProfiler", lambda conf: profiler) - - def runWithProfiler(): - return app.runWithProfiler(DummyReactor(), {}) - - self.assertWarns(DeprecationWarning, - "runWithProfiler is deprecated since Twisted 8.0. " - "Use ProfileRunner instead.", __file__, - runWithProfiler) - self.assertTrue(profiler.called) - - - def test_oldRunWithHotshot(self): - """ - L{app.runWithHotshot} should print a C{DeprecationWarning} pointing - at L{AppProfiler}. - """ - class DummyProfiler(object): - called = False - def run(self, reactor): - self.called = True - profiler = DummyProfiler() - self.patch(app, "AppProfiler", lambda conf: profiler) - - def runWithHotshot(): - return app.runWithHotshot(DummyReactor(), {}) - - self.assertWarns(DeprecationWarning, - "runWithHotshot is deprecated since Twisted 8.0. " - "Use HotshotRunner instead.", __file__, - runWithHotshot) - self.assertTrue(profiler.called) diff --git a/tools/buildbot/pylibs/twisted/test/test_udp.py b/tools/buildbot/pylibs/twisted/test/test_udp.py deleted file mode 100644 index 182efa8..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_udp.py +++ /dev/null @@ -1,801 +0,0 @@ -# -*- test-case-name: twisted.test.test_udp -*- -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for implementations of L{IReactorUDP} and L{IReactorMulticast}. -""" - -from twisted.trial import unittest, util - -from twisted.internet.defer import Deferred, gatherResults, maybeDeferred -from twisted.internet import protocol, reactor, error, defer, interfaces -from twisted.python import runtime - - -class Mixin: - - started = 0 - stopped = 0 - - startedDeferred = None - - def __init__(self): - self.packets = [] - - def startProtocol(self): - self.started = 1 - if self.startedDeferred is not None: - d, self.startedDeferred = self.startedDeferred, None - d.callback(None) - - def stopProtocol(self): - self.stopped = 1 - - -class Server(Mixin, protocol.DatagramProtocol): - packetReceived = None - refused = 0 - - - def datagramReceived(self, data, addr): - self.packets.append((data, addr)) - if self.packetReceived is not None: - d, self.packetReceived = self.packetReceived, None - d.callback(None) - - - -class Client(Mixin, protocol.ConnectedDatagramProtocol): - - packetReceived = None - refused = 0 - - def datagramReceived(self, data): - self.packets.append(data) - if self.packetReceived is not None: - d, self.packetReceived = self.packetReceived, None - d.callback(None) - - def connectionFailed(self, failure): - if self.startedDeferred is not None: - d, self.startedDeferred = self.startedDeferred, None - d.errback(failure) - self.failure = failure - - def connectionRefused(self): - if self.startedDeferred is not None: - d, self.startedDeferred = self.startedDeferred, None - d.errback(error.ConnectionRefusedError("yup")) - self.refused = 1 - - -class GoodClient(Server): - - def connectionRefused(self): - if self.startedDeferred is not None: - d, self.startedDeferred = self.startedDeferred, None - d.errback(error.ConnectionRefusedError("yup")) - self.refused = 1 - - - -class BadClientError(Exception): - """ - Raised by BadClient at the end of every datagramReceived call to try and - screw stuff up. - """ - - - -class BadClient(protocol.DatagramProtocol): - """ - A DatagramProtocol which always raises an exception from datagramReceived. - Used to test error handling behavior in the reactor for that method. - """ - d = None - - def setDeferred(self, d): - """ - Set the Deferred which will be called back when datagramReceived is - called. - """ - self.d = d - - - def datagramReceived(self, bytes, addr): - if self.d is not None: - d, self.d = self.d, None - d.callback(bytes) - raise BadClientError("Application code is very buggy!") - - - -class OldConnectedUDPTestCase(unittest.TestCase): - def testStartStop(self): - client = Client() - d = client.startedDeferred = defer.Deferred() - port2 = reactor.connectUDP("127.0.0.1", 8888, client) - - def assertName(): - self.failUnless(repr(port2).find('test_udp.Client') >= 0) - - def cbStarted(ignored): - self.assertEquals(client.started, 1) - self.assertEquals(client.stopped, 0) - assertName() - d = defer.maybeDeferred(port2.stopListening) - d.addCallback(lambda ign: assertName()) - return d - - return d.addCallback(cbStarted) - testStartStop.suppress = [ - util.suppress(message='use listenUDP and then transport.connect', - category=DeprecationWarning)] - - - def testDNSFailure(self): - client = Client() - d = client.startedDeferred = defer.Deferred() - # if this domain exists, shoot your sysadmin - reactor.connectUDP("xxxxxxxxx.zzzzzzzzz.yyyyy.", 8888, client) - - def didNotConnect(ign): - self.assertEquals(client.stopped, 0) - self.assertEquals(client.started, 0) - - d = self.assertFailure(d, error.DNSLookupError) - d.addCallback(didNotConnect) - return d - testDNSFailure.suppress = [ - util.suppress(message='use listenUDP and then transport.connect', - category=DeprecationWarning)] - - - def testSendPackets(self): - server = Server() - serverStarted = server.startedDeferred = defer.Deferred() - - client = Client() - clientStarted = client.startedDeferred = defer.Deferred() - - port1 = reactor.listenUDP(0, server, interface="127.0.0.1") - - def cbServerStarted(ignored): - self.port2 = reactor.connectUDP("127.0.0.1", - server.transport.getHost().port, - client) - return clientStarted - - d = serverStarted.addCallback(cbServerStarted) - - def cbClientStarted(ignored): - clientSend = server.packetReceived = defer.Deferred() - serverSend = client.packetReceived = defer.Deferred() - - cAddr = client.transport.getHost() - server.transport.write("hello", (cAddr.host, cAddr.port)) - client.transport.write("world") - - # No one will ever call errback on either of these Deferreds, - # otherwise I would pass fireOnOneErrback=True here. - return defer.DeferredList([clientSend, serverSend]) - - d.addCallback(cbClientStarted) - - def cbPackets(ignored): - self.assertEquals(client.packets, ["hello"]) - self.assertEquals(server.packets, - [("world", ("127.0.0.1", - client.transport.getHost().port))]) - - return defer.DeferredList([ - defer.maybeDeferred(port1.stopListening), - defer.maybeDeferred(self.port2.stopListening)], - fireOnOneErrback=True) - - d.addCallback(cbPackets) - return d - testSendPackets.suppress = [ - util.suppress(message='use listenUDP and then transport.connect', - category=DeprecationWarning)] - - - def test_connectionRefused(self): - """ - Test that using the connected UDP API will deliver connection refused - notification when packets are sent to an address at which no one is - listening. - """ - # XXX - assume no one listening on port 80 UDP - client = Client() - clientStarted = client.startedDeferred = Deferred() - server = Server() - serverStarted = server.startedDeferred = Deferred() - started = gatherResults([clientStarted, serverStarted]) - - clientPort = reactor.connectUDP("127.0.0.1", 80, client) - serverPort = reactor.listenUDP(0, server, interface="127.0.0.1") - - def cbStarted(ignored): - clientRefused = client.startedDeferred = Deferred() - - client.transport.write("a") - client.transport.write("b") - server.transport.write("c", ("127.0.0.1", 80)) - server.transport.write("d", ("127.0.0.1", 80)) - server.transport.write("e", ("127.0.0.1", 80)) - - c = clientPort.getHost() - s = serverPort.getHost() - server.transport.write("toserver", (s.host, s.port)) - server.transport.write("toclient", (c.host, c.port)) - - return self.assertFailure(clientRefused, error.ConnectionRefusedError) - started.addCallback(cbStarted) - - def cleanup(passthrough): - result = gatherResults([ - maybeDeferred(clientPort.stopListening), - maybeDeferred(serverPort.stopListening)]) - result.addCallback(lambda ign: passthrough) - return result - - started.addBoth(cleanup) - return started - test_connectionRefused.suppress = [ - util.suppress(message='use listenUDP and then transport.connect', - category=DeprecationWarning)] - - - -class UDPTestCase(unittest.TestCase): - - def testOldAddress(self): - server = Server() - d = server.startedDeferred = defer.Deferred() - p = reactor.listenUDP(0, server, interface="127.0.0.1") - def cbStarted(ignored): - addr = p.getHost() - self.assertEquals(addr, ('INET_UDP', addr.host, addr.port)) - return p.stopListening() - return d.addCallback(cbStarted) - testOldAddress.suppress = [ - util.suppress(message='IPv4Address.__getitem__', - category=DeprecationWarning)] - - - def testStartStop(self): - server = Server() - d = server.startedDeferred = defer.Deferred() - port1 = reactor.listenUDP(0, server, interface="127.0.0.1") - def cbStarted(ignored): - self.assertEquals(server.started, 1) - self.assertEquals(server.stopped, 0) - return port1.stopListening() - def cbStopped(ignored): - self.assertEquals(server.stopped, 1) - return d.addCallback(cbStarted).addCallback(cbStopped) - - def testRebind(self): - # Ensure binding the same DatagramProtocol repeatedly invokes all - # the right callbacks. - server = Server() - d = server.startedDeferred = defer.Deferred() - p = reactor.listenUDP(0, server, interface="127.0.0.1") - - def cbStarted(ignored, port): - return port.stopListening() - - def cbStopped(ignored): - d = server.startedDeferred = defer.Deferred() - p = reactor.listenUDP(0, server, interface="127.0.0.1") - return d.addCallback(cbStarted, p) - - return d.addCallback(cbStarted, p) - - - def testBindError(self): - server = Server() - d = server.startedDeferred = defer.Deferred() - port = reactor.listenUDP(0, server, interface='127.0.0.1') - - def cbStarted(ignored): - self.assertEquals(port.getHost(), server.transport.getHost()) - - server2 = Server() - self.assertRaises( - error.CannotListenError, - reactor.listenUDP, port.getHost().port, server2, - interface='127.0.0.1') - d.addCallback(cbStarted) - - def cbFinished(ignored): - return port.stopListening() - d.addCallback(cbFinished) - return d - - def testSendPackets(self): - server = Server() - serverStarted = server.startedDeferred = defer.Deferred() - port1 = reactor.listenUDP(0, server, interface="127.0.0.1") - - client = GoodClient() - clientStarted = client.startedDeferred = defer.Deferred() - - def cbServerStarted(ignored): - self.port2 = reactor.listenUDP(0, client, interface="127.0.0.1") - return clientStarted - - d = serverStarted.addCallback(cbServerStarted) - - def cbClientStarted(ignored): - client.transport.connect("127.0.0.1", - server.transport.getHost().port) - cAddr = client.transport.getHost() - sAddr = server.transport.getHost() - - serverSend = client.packetReceived = defer.Deferred() - server.transport.write("hello", (cAddr.host, cAddr.port)) - - clientWrites = [ - ("a",), - ("b", None), - ("c", (sAddr.host, sAddr.port))] - - def cbClientSend(ignored): - if clientWrites: - nextClientWrite = server.packetReceived = defer.Deferred() - nextClientWrite.addCallback(cbClientSend) - client.transport.write(*clientWrites.pop(0)) - return nextClientWrite - - # No one will ever call .errback on either of these Deferreds, - # but there is a non-trivial amount of test code which might - # cause them to fail somehow. So fireOnOneErrback=True. - return defer.DeferredList([ - cbClientSend(None), - serverSend], - fireOnOneErrback=True) - - d.addCallback(cbClientStarted) - - def cbSendsFinished(ignored): - cAddr = client.transport.getHost() - sAddr = server.transport.getHost() - self.assertEquals( - client.packets, - [("hello", (sAddr.host, sAddr.port))]) - clientAddr = (cAddr.host, cAddr.port) - self.assertEquals( - server.packets, - [("a", clientAddr), - ("b", clientAddr), - ("c", clientAddr)]) - - d.addCallback(cbSendsFinished) - - def cbFinished(ignored): - return defer.DeferredList([ - defer.maybeDeferred(port1.stopListening), - defer.maybeDeferred(self.port2.stopListening)], - fireOnOneErrback=True) - - d.addCallback(cbFinished) - return d - - - def testConnectionRefused(self): - # assume no one listening on port 80 UDP - client = GoodClient() - clientStarted = client.startedDeferred = defer.Deferred() - port = reactor.listenUDP(0, client, interface="127.0.0.1") - - server = Server() - serverStarted = server.startedDeferred = defer.Deferred() - port2 = reactor.listenUDP(0, server, interface="127.0.0.1") - - d = defer.DeferredList( - [clientStarted, serverStarted], - fireOnOneErrback=True) - - def cbStarted(ignored): - connectionRefused = client.startedDeferred = defer.Deferred() - client.transport.connect("127.0.0.1", 80) - - for i in range(10): - client.transport.write(str(i)) - server.transport.write(str(i), ("127.0.0.1", 80)) - - return self.assertFailure( - connectionRefused, - error.ConnectionRefusedError) - - d.addCallback(cbStarted) - - def cbFinished(ignored): - return defer.DeferredList([ - defer.maybeDeferred(port.stopListening), - defer.maybeDeferred(port2.stopListening)], - fireOnOneErrback=True) - - d.addCallback(cbFinished) - return d - - def testBadConnect(self): - client = GoodClient() - port = reactor.listenUDP(0, client, interface="127.0.0.1") - self.assertRaises(ValueError, client.transport.connect, - "localhost", 80) - client.transport.connect("127.0.0.1", 80) - self.assertRaises(RuntimeError, client.transport.connect, - "127.0.0.1", 80) - return port.stopListening() - - - - def testDatagramReceivedError(self): - """ - Test that when datagramReceived raises an exception it is logged but - the port is not disconnected. - """ - finalDeferred = defer.Deferred() - - def cbCompleted(ign): - """ - Flush the exceptions which the reactor should have logged and make - sure they're actually there. - """ - errs = self.flushLoggedErrors(BadClientError) - self.assertEquals(len(errs), 2, "Incorrectly found %d errors, expected 2" % (len(errs),)) - finalDeferred.addCallback(cbCompleted) - - client = BadClient() - port = reactor.listenUDP(0, client, interface='127.0.0.1') - - def cbCleanup(result): - """ - Disconnect the port we started and pass on whatever was given to us - in case it was a Failure. - """ - return defer.maybeDeferred(port.stopListening).addBoth(lambda ign: result) - finalDeferred.addBoth(cbCleanup) - - addr = port.getHost() - - # UDP is not reliable. Try to send as many as 60 packets before giving - # up. Conceivably, all sixty could be lost, but they probably won't be - # unless all UDP traffic is being dropped, and then the rest of these - # UDP tests will likely fail as well. Ideally, this test (and probably - # others) wouldn't even use actual UDP traffic: instead, they would - # stub out the socket with a fake one which could be made to behave in - # whatever way the test desires. Unfortunately, this is hard because - # of differences in various reactor implementations. - attempts = range(60) - succeededAttempts = [] - - def makeAttempt(): - """ - Send one packet to the listening BadClient. Set up a 0.1 second - timeout to do re-transmits in case the packet is dropped. When two - packets have been received by the BadClient, stop sending and let - the finalDeferred's callbacks do some assertions. - """ - if not attempts: - try: - self.fail("Not enough packets received") - except: - finalDeferred.errback() - - self.failIfIdentical(client.transport, None, "UDP Protocol lost its transport") - - packet = str(attempts.pop(0)) - packetDeferred = defer.Deferred() - client.setDeferred(packetDeferred) - client.transport.write(packet, (addr.host, addr.port)) - - def cbPacketReceived(packet): - """ - A packet arrived. Cancel the timeout for it, record it, and - maybe finish the test. - """ - timeoutCall.cancel() - succeededAttempts.append(packet) - if len(succeededAttempts) == 2: - # The second error has not yet been logged, since the - # exception which causes it hasn't even been raised yet. - # Give the datagramReceived call a chance to finish, then - # let the test finish asserting things. - reactor.callLater(0, finalDeferred.callback, None) - else: - makeAttempt() - - def ebPacketTimeout(err): - """ - The packet wasn't received quickly enough. Try sending another - one. It doesn't matter if the packet for which this was the - timeout eventually arrives: makeAttempt throws away the - Deferred on which this function is the errback, so when - datagramReceived callbacks, so it won't be on this Deferred, so - it won't raise an AlreadyCalledError. - """ - makeAttempt() - - packetDeferred.addCallbacks(cbPacketReceived, ebPacketTimeout) - packetDeferred.addErrback(finalDeferred.errback) - - timeoutCall = reactor.callLater( - 0.1, packetDeferred.errback, - error.TimeoutError( - "Timed out in testDatagramReceivedError")) - - makeAttempt() - return finalDeferred - - - def testPortRepr(self): - client = GoodClient() - p = reactor.listenUDP(0, client) - portNo = str(p.getHost().port) - self.failIf(repr(p).find(portNo) == -1) - def stoppedListening(ign): - self.failIf(repr(p).find(portNo) != -1) - d = defer.maybeDeferred(p.stopListening) - d.addCallback(stoppedListening) - return d - - -class ReactorShutdownInteraction(unittest.TestCase): - """Test reactor shutdown interaction""" - - def setUp(self): - """Start a UDP port""" - self.server = Server() - self.port = reactor.listenUDP(0, self.server, interface='127.0.0.1') - - def tearDown(self): - """Stop the UDP port""" - return self.port.stopListening() - - def testShutdownFromDatagramReceived(self): - """Test reactor shutdown while in a recvfrom() loop""" - - # udp.Port's doRead calls recvfrom() in a loop, as an optimization. - # It is important this loop terminate under various conditions. - # Previously, if datagramReceived synchronously invoked - # reactor.stop(), under certain reactors, the Port's socket would - # synchronously disappear, causing an AttributeError inside that - # loop. This was mishandled, causing the loop to spin forever. - # This test is primarily to ensure that the loop never spins - # forever. - - finished = defer.Deferred() - pr = self.server.packetReceived = defer.Deferred() - - def pktRece(ignored): - # Simulate reactor.stop() behavior :( - self.server.transport.connectionLost() - # Then delay this Deferred chain until the protocol has been - # disconnected, as the reactor should do in an error condition - # such as we are inducing. This is very much a whitebox test. - reactor.callLater(0, finished.callback, None) - pr.addCallback(pktRece) - - def flushErrors(ignored): - # We are breaking abstraction and calling private APIs, any - # number of horrible errors might occur. As long as the reactor - # doesn't hang, this test is satisfied. (There may be room for - # another, stricter test.) - self.flushLoggedErrors() - finished.addCallback(flushErrors) - self.server.transport.write('\0' * 64, ('127.0.0.1', - self.server.transport.getHost().port)) - return finished - - - -class MulticastTestCase(unittest.TestCase): - - def setUp(self): - self.server = Server() - self.client = Client() - # multicast won't work if we listen over loopback, apparently - self.port1 = reactor.listenMulticast(0, self.server) - self.port2 = reactor.listenMulticast(0, self.client) - self.client.transport.connect( - "127.0.0.1", self.server.transport.getHost().port) - - - def tearDown(self): - return gatherResults([ - maybeDeferred(self.port1.stopListening), - maybeDeferred(self.port2.stopListening)]) - - - def testTTL(self): - for o in self.client, self.server: - self.assertEquals(o.transport.getTTL(), 1) - o.transport.setTTL(2) - self.assertEquals(o.transport.getTTL(), 2) - - - def test_loopback(self): - """ - Test that after loopback mode has been set, multicast packets are - delivered to their sender. - """ - self.assertEquals(self.server.transport.getLoopbackMode(), 1) - addr = self.server.transport.getHost() - joined = self.server.transport.joinGroup("225.0.0.250") - - def cbJoined(ignored): - d = self.server.packetReceived = Deferred() - self.server.transport.write("hello", ("225.0.0.250", addr.port)) - return d - joined.addCallback(cbJoined) - - def cbPacket(ignored): - self.assertEqual(len(self.server.packets), 1) - self.server.transport.setLoopbackMode(0) - self.assertEquals(self.server.transport.getLoopbackMode(), 0) - self.server.transport.write("hello", ("225.0.0.250", addr.port)) - - # This is fairly lame. - d = Deferred() - reactor.callLater(0, d.callback, None) - return d - joined.addCallback(cbPacket) - - def cbNoPacket(ignored): - self.assertEqual(len(self.server.packets), 1) - joined.addCallback(cbNoPacket) - - return joined - - - def test_interface(self): - """ - Test C{getOutgoingInterface} and C{setOutgoingInterface}. - """ - self.assertEqual( - self.client.transport.getOutgoingInterface(), "0.0.0.0") - self.assertEqual( - self.server.transport.getOutgoingInterface(), "0.0.0.0") - - d1 = self.client.transport.setOutgoingInterface("127.0.0.1") - d2 = self.server.transport.setOutgoingInterface("127.0.0.1") - result = gatherResults([d1, d2]) - - def cbInterfaces(ignored): - self.assertEqual( - self.client.transport.getOutgoingInterface(), "127.0.0.1") - self.assertEqual( - self.server.transport.getOutgoingInterface(), "127.0.0.1") - result.addCallback(cbInterfaces) - return result - - - def test_joinLeave(self): - """ - Test that multicast a group can be joined and left. - """ - d = self.client.transport.joinGroup("225.0.0.250") - - def clientJoined(ignored): - return self.client.transport.leaveGroup("225.0.0.250") - d.addCallback(clientJoined) - - def clientLeft(ignored): - return self.server.transport.joinGroup("225.0.0.250") - d.addCallback(clientLeft) - - def serverJoined(ignored): - return self.server.transport.leaveGroup("225.0.0.250") - d.addCallback(serverJoined) - - return d - - - def test_joinFailure(self): - """ - Test that an attempt to join an address which is not a multicast - address fails with L{error.MulticastJoinError}. - """ - # 127.0.0.1 is not a multicast address, so joining it should fail. - return self.assertFailure( - self.client.transport.joinGroup("127.0.0.1"), - error.MulticastJoinError) - if runtime.platform.isWindows(): - test_joinFailure.todo = "Windows' multicast is wonky" - - - def test_multicast(self): - """ - Test that a multicast group can be joined and messages sent to and - received from it. - """ - c = Server() - p = reactor.listenMulticast(0, c) - addr = self.server.transport.getHost() - - joined = self.server.transport.joinGroup("225.0.0.250") - - def cbJoined(ignored): - d = self.server.packetReceived = Deferred() - c.transport.write("hello world", ("225.0.0.250", addr.port)) - return d - joined.addCallback(cbJoined) - - def cbPacket(ignored): - self.assertEquals(self.server.packets[0][0], "hello world") - joined.addCallback(cbPacket) - - def cleanup(passthrough): - result = maybeDeferred(p.stopListening) - result.addCallback(lambda ign: passthrough) - return result - joined.addCallback(cleanup) - - return joined - - - def test_multiListen(self): - """ - Test that multiple sockets can listen on the same multicast port and - that they both receive multicast messages directed to that address. - """ - firstClient = Server() - firstPort = reactor.listenMulticast( - 0, firstClient, listenMultiple=True) - - portno = firstPort.getHost().port - - secondClient = Server() - secondPort = reactor.listenMulticast( - portno, secondClient, listenMultiple=True) - - joined = self.server.transport.joinGroup("225.0.0.250") - - def serverJoined(ignored): - d1 = firstClient.packetReceived = Deferred() - d2 = secondClient.packetReceived = Deferred() - firstClient.transport.write("hello world", ("225.0.0.250", portno)) - return gatherResults([d1, d2]) - joined.addCallback(serverJoined) - - def gotPackets(ignored): - self.assertEquals(firstClient.packets[0][0], "hello world") - self.assertEquals(secondClient.packets[0][0], "hello world") - joined.addCallback(gotPackets) - - def cleanup(passthrough): - result = gatherResults([ - maybeDeferred(firstPort.stopListening), - maybeDeferred(secondPort.stopListening)]) - result.addCallback(lambda ign: passthrough) - return result - joined.addBoth(cleanup) - return joined - if runtime.platform.isWindows(): - test_multiListen.skip = ("on non-linux platforms it appears multiple " - "processes can listen, but not multiple sockets " - "in same process?") - -if not interfaces.IReactorUDP(reactor, None): - UDPTestCase.skip = "This reactor does not support UDP" - ReactorShutdownInteraction.skip = "This reactor does not support UDP" -if not hasattr(reactor, "connectUDP"): - OldConnectedUDPTestCase.skip = "This reactor does not support connectUDP" -if not interfaces.IReactorMulticast(reactor, None): - MulticastTestCase.skip = "This reactor does not support multicast" - -def checkForLinux22(): - import os - if os.path.exists("/proc/version"): - s = open("/proc/version").read() - if s.startswith("Linux version"): - s = s.split()[2] - if s.split(".")[:2] == ["2", "2"]: - f = MulticastTestCase.testInterface.im_func - f.todo = "figure out why this fails in linux 2.2" -checkForLinux22() diff --git a/tools/buildbot/pylibs/twisted/test/test_unix.py b/tools/buildbot/pylibs/twisted/test/test_unix.py deleted file mode 100644 index eddf13e..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_unix.py +++ /dev/null @@ -1,418 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for implementations of L{IReactorUNIX} and L{IReactorUNIXDatagram}. -""" - -import stat, os, sys, types -import socket - -from twisted.internet import interfaces, reactor, protocol, error, address, defer, utils -from twisted.python import lockfile -from twisted.trial import unittest - -from twisted.test.test_tcp import MyServerFactory, MyClientFactory - - -class FailedConnectionClientFactory(protocol.ClientFactory): - def __init__(self, onFail): - self.onFail = onFail - - def clientConnectionFailed(self, connector, reason): - self.onFail.errback(reason) - - - -class UnixSocketTestCase(unittest.TestCase): - """ - Test unix sockets. - """ - def test_peerBind(self): - """ - The address passed to the server factory's C{buildProtocol} method and - the address returned by the connected protocol's transport's C{getPeer} - method match the address the client socket is bound to. - """ - filename = self.mktemp() - peername = self.mktemp() - serverFactory = MyServerFactory() - connMade = serverFactory.protocolConnectionMade = defer.Deferred() - unixPort = reactor.listenUNIX(filename, serverFactory) - self.addCleanup(unixPort.stopListening) - unixSocket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - self.addCleanup(unixSocket.close) - unixSocket.bind(peername) - unixSocket.connect(filename) - def cbConnMade(proto): - expected = address.UNIXAddress(peername) - self.assertEqual(serverFactory.peerAddresses, [expected]) - self.assertEqual(proto.transport.getPeer(), expected) - connMade.addCallback(cbConnMade) - return connMade - - - def test_dumber(self): - """ - L{IReactorUNIX.connectUNIX} can be used to connect a client to a server - started with L{IReactorUNIX.listenUNIX}. - """ - filename = self.mktemp() - serverFactory = MyServerFactory() - serverConnMade = defer.Deferred() - serverFactory.protocolConnectionMade = serverConnMade - unixPort = reactor.listenUNIX(filename, serverFactory) - self.addCleanup(unixPort.stopListening) - clientFactory = MyClientFactory() - clientConnMade = defer.Deferred() - clientFactory.protocolConnectionMade = clientConnMade - c = reactor.connectUNIX(filename, clientFactory) - d = defer.gatherResults([serverConnMade, clientConnMade]) - def allConnected((serverProtocol, clientProtocol)): - - # Incidental assertion which may or may not be redundant with some - # other test. This probably deserves its own test method. - self.assertEqual(clientFactory.peerAddresses, - [address.UNIXAddress(filename)]) - - clientProtocol.transport.loseConnection() - serverProtocol.transport.loseConnection() - d.addCallback(allConnected) - return d - - - def test_mode(self): - """ - The UNIX socket created by L{IReactorUNIX.listenUNIX} is created with - the mode specified. - """ - mode = 0600 - filename = self.mktemp() - serverFactory = MyServerFactory() - unixPort = reactor.listenUNIX(filename, serverFactory, mode=mode) - self.addCleanup(unixPort.stopListening) - self.assertEquals(stat.S_IMODE(os.stat(filename).st_mode), mode) - - - def test_pidFile(self): - """ - A lockfile is created and locked when L{IReactorUNIX.listenUNIX} is - called and released when the Deferred returned by the L{IListeningPort} - provider's C{stopListening} method is called back. - """ - filename = self.mktemp() - serverFactory = MyServerFactory() - serverConnMade = defer.Deferred() - serverFactory.protocolConnectionMade = serverConnMade - unixPort = reactor.listenUNIX(filename, serverFactory, wantPID=True) - self.assertTrue(lockfile.isLocked(filename + ".lock")) - - # XXX This part would test something about the checkPID parameter, but - # it doesn't actually. It should be rewritten to test the several - # different possible behaviors. -exarkun - clientFactory = MyClientFactory() - clientConnMade = defer.Deferred() - clientFactory.protocolConnectionMade = clientConnMade - c = reactor.connectUNIX(filename, clientFactory, checkPID=1) - - d = defer.gatherResults([serverConnMade, clientConnMade]) - def _portStuff((serverProtocol, clientProto)): - - # Incidental assertion which may or may not be redundant with some - # other test. This probably deserves its own test method. - self.assertEqual(clientFactory.peerAddresses, - [address.UNIXAddress(filename)]) - - clientProto.transport.loseConnection() - serverProtocol.transport.loseConnection() - return unixPort.stopListening() - d.addCallback(_portStuff) - - def _check(ignored): - self.failIf(lockfile.isLocked(filename + ".lock"), 'locked') - d.addCallback(_check) - return d - - - def test_socketLocking(self): - """ - L{IReactorUNIX.listenUNIX} raises L{error.CannotListenError} if passed - the name of a file on which a server is already listening. - """ - filename = self.mktemp() - serverFactory = MyServerFactory() - unixPort = reactor.listenUNIX(filename, serverFactory, wantPID=True) - - self.assertRaises( - error.CannotListenError, - reactor.listenUNIX, filename, serverFactory, wantPID=True) - - def stoppedListening(ign): - unixPort = reactor.listenUNIX(filename, serverFactory, wantPID=True) - return unixPort.stopListening() - - return unixPort.stopListening().addCallback(stoppedListening) - - - def _uncleanSocketTest(self, callback): - self.filename = self.mktemp() - source = ("from twisted.internet import protocol, reactor\n" - "reactor.listenUNIX(%r, protocol.ServerFactory(), wantPID=True)\n") % (self.filename,) - env = {'PYTHONPATH': os.pathsep.join(sys.path)} - - d = utils.getProcessValue(sys.executable, ("-u", "-c", source), env=env) - d.addCallback(callback) - return d - - - def test_uncleanServerSocketLocking(self): - """ - If passed C{True} for the C{wantPID} parameter, a server can be started - listening with L{IReactorUNIX.listenUNIX} when passed the name of a - file on which a previous server which has not exited cleanly has been - listening using the C{wantPID} option. - """ - def ranStupidChild(ign): - # If this next call succeeds, our lock handling is correct. - p = reactor.listenUNIX(self.filename, MyServerFactory(), wantPID=True) - return p.stopListening() - return self._uncleanSocketTest(ranStupidChild) - - - def test_connectToUncleanServer(self): - """ - If passed C{True} for the C{checkPID} parameter, a client connection - attempt made with L{IReactorUNIX.connectUNIX} fails with - L{error.BadFileError}. - """ - def ranStupidChild(ign): - d = defer.Deferred() - f = FailedConnectionClientFactory(d) - c = reactor.connectUNIX(self.filename, f, checkPID=True) - return self.assertFailure(d, error.BadFileError) - return self._uncleanSocketTest(ranStupidChild) - - - def _reprTest(self, serverFactory, factoryName): - """ - Test the C{__str__} and C{__repr__} implementations of a UNIX port when - used with the given factory. - """ - filename = self.mktemp() - unixPort = reactor.listenUNIX(filename, serverFactory) - - connectedString = "<%s on %r>" % (factoryName, filename) - self.assertEqual(repr(unixPort), connectedString) - self.assertEqual(str(unixPort), connectedString) - - d = defer.maybeDeferred(unixPort.stopListening) - def stoppedListening(ign): - unconnectedString = "<%s (not listening)>" % (factoryName,) - self.assertEqual(repr(unixPort), unconnectedString) - self.assertEqual(str(unixPort), unconnectedString) - d.addCallback(stoppedListening) - return d - - - def test_reprWithClassicFactory(self): - """ - The two string representations of the L{IListeningPort} returned by - L{IReactorUNIX.listenUNIX} contains the name of the classic factory - class being used and the filename on which the port is listening or - indicates that the port is not listening. - """ - class ClassicFactory: - def doStart(self): - pass - - def doStop(self): - pass - - # Sanity check - self.assertIsInstance(ClassicFactory, types.ClassType) - - return self._reprTest( - ClassicFactory(), "twisted.test.test_unix.ClassicFactory") - - - def test_reprWithNewStyleFactory(self): - """ - The two string representations of the L{IListeningPort} returned by - L{IReactorUNIX.listenUNIX} contains the name of the new-style factory - class being used and the filename on which the port is listening or - indicates that the port is not listening. - """ - class NewStyleFactory(object): - def doStart(self): - pass - - def doStop(self): - pass - - # Sanity check - self.assertIsInstance(NewStyleFactory, type) - - return self._reprTest( - NewStyleFactory(), "twisted.test.test_unix.NewStyleFactory") - - - -class ClientProto(protocol.ConnectedDatagramProtocol): - started = stopped = False - gotback = None - - def __init__(self): - self.deferredStarted = defer.Deferred() - self.deferredGotBack = defer.Deferred() - - def stopProtocol(self): - self.stopped = True - - def startProtocol(self): - self.started = True - self.deferredStarted.callback(None) - - def datagramReceived(self, data): - self.gotback = data - self.deferredGotBack.callback(None) - -class ServerProto(protocol.DatagramProtocol): - started = stopped = False - gotwhat = gotfrom = None - - def __init__(self): - self.deferredStarted = defer.Deferred() - self.deferredGotWhat = defer.Deferred() - - def stopProtocol(self): - self.stopped = True - - def startProtocol(self): - self.started = True - self.deferredStarted.callback(None) - - def datagramReceived(self, data, addr): - self.gotfrom = addr - self.transport.write("hi back", addr) - self.gotwhat = data - self.deferredGotWhat.callback(None) - - - -class DatagramUnixSocketTestCase(unittest.TestCase): - """ - Test datagram UNIX sockets. - """ - def test_exchange(self): - """ - Test that a datagram can be sent to and received by a server and vice - versa. - """ - clientaddr = self.mktemp() - serveraddr = self.mktemp() - sp = ServerProto() - cp = ClientProto() - s = reactor.listenUNIXDatagram(serveraddr, sp) - self.addCleanup(s.stopListening) - c = reactor.connectUNIXDatagram(serveraddr, cp, bindAddress=clientaddr) - self.addCleanup(c.stopListening) - - d = defer.gatherResults([sp.deferredStarted, cp.deferredStarted]) - def write(ignored): - cp.transport.write("hi") - return defer.gatherResults([sp.deferredGotWhat, - cp.deferredGotBack]) - - def _cbTestExchange(ignored): - self.failUnlessEqual("hi", sp.gotwhat) - self.failUnlessEqual(clientaddr, sp.gotfrom) - self.failUnlessEqual("hi back", cp.gotback) - - d.addCallback(write) - d.addCallback(_cbTestExchange) - return d - - - def test_cannotListen(self): - """ - L{IReactorUNIXDatagram.listenUNIXDatagram} raises - L{error.CannotListenError} if the unix socket specified is already in - use. - """ - addr = self.mktemp() - p = ServerProto() - s = reactor.listenUNIXDatagram(addr, p) - self.failUnlessRaises(error.CannotListenError, reactor.listenUNIXDatagram, addr, p) - s.stopListening() - os.unlink(addr) - - # test connecting to bound and connected (somewhere else) address - - def _reprTest(self, serverProto, protocolName): - """ - Test the C{__str__} and C{__repr__} implementations of a UNIX datagram - port when used with the given protocol. - """ - filename = self.mktemp() - unixPort = reactor.listenUNIXDatagram(filename, serverProto) - - connectedString = "<%s on %r>" % (protocolName, filename) - self.assertEqual(repr(unixPort), connectedString) - self.assertEqual(str(unixPort), connectedString) - - stopDeferred = defer.maybeDeferred(unixPort.stopListening) - def stoppedListening(ign): - unconnectedString = "<%s (not listening)>" % (protocolName,) - self.assertEqual(repr(unixPort), unconnectedString) - self.assertEqual(str(unixPort), unconnectedString) - stopDeferred.addCallback(stoppedListening) - return stopDeferred - - - def test_reprWithClassicProtocol(self): - """ - The two string representations of the L{IListeningPort} returned by - L{IReactorUNIXDatagram.listenUNIXDatagram} contains the name of the - classic protocol class being used and the filename on which the port is - listening or indicates that the port is not listening. - """ - class ClassicProtocol: - def makeConnection(self, transport): - pass - - def doStop(self): - pass - - # Sanity check - self.assertIsInstance(ClassicProtocol, types.ClassType) - - return self._reprTest( - ClassicProtocol(), "twisted.test.test_unix.ClassicProtocol") - - - def test_reprWithNewStyleProtocol(self): - """ - The two string representations of the L{IListeningPort} returned by - L{IReactorUNIXDatagram.listenUNIXDatagram} contains the name of the - new-style protocol class being used and the filename on which the port - is listening or indicates that the port is not listening. - """ - class NewStyleProtocol(object): - def makeConnection(self, transport): - pass - - def doStop(self): - pass - - # Sanity check - self.assertIsInstance(NewStyleProtocol, type) - - return self._reprTest( - NewStyleProtocol(), "twisted.test.test_unix.NewStyleProtocol") - - - -if not interfaces.IReactorUNIX(reactor, None): - UnixSocketTestCase.skip = "This reactor does not support UNIX domain sockets" -if not interfaces.IReactorUNIXDatagram(reactor, None): - DatagramUnixSocketTestCase.skip = "This reactor does not support UNIX datagram sockets" diff --git a/tools/buildbot/pylibs/twisted/test/test_usage.py b/tools/buildbot/pylibs/twisted/test/test_usage.py deleted file mode 100644 index e77c179..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_usage.py +++ /dev/null @@ -1,372 +0,0 @@ - -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -from twisted.trial import unittest -from twisted.python import usage - - -class WellBehaved(usage.Options): - optParameters = [['long', 'w', 'default', 'and a docstring'], - ['another', 'n', 'no docstring'], - ['longonly', None, 'noshort'], - ['shortless', None, 'except', - 'this one got docstring'], - ] - optFlags = [['aflag', 'f', - """ - - flagallicious docstringness for this here - - """], - ['flout', 'o'], - ] - - def opt_myflag(self): - self.opts['myflag'] = "PONY!" - - def opt_myparam(self, value): - self.opts['myparam'] = "%s WITH A PONY!" % (value,) - - -class ParseCorrectnessTest(unittest.TestCase): - """ - Test Options.parseArgs for correct values under good conditions. - """ - def setUp(self): - """ - Instantiate and parseOptions a well-behaved Options class. - """ - - self.niceArgV = ("--long Alpha -n Beta " - "--shortless Gamma -f --myflag " - "--myparam Tofu").split() - - self.nice = WellBehaved() - - self.nice.parseOptions(self.niceArgV) - - def test_checkParameters(self): - """ - Checking that parameters have correct values. - """ - self.failUnlessEqual(self.nice.opts['long'], "Alpha") - self.failUnlessEqual(self.nice.opts['another'], "Beta") - self.failUnlessEqual(self.nice.opts['longonly'], "noshort") - self.failUnlessEqual(self.nice.opts['shortless'], "Gamma") - - def test_checkFlags(self): - """ - Checking that flags have correct values. - """ - self.failUnlessEqual(self.nice.opts['aflag'], 1) - self.failUnlessEqual(self.nice.opts['flout'], 0) - - def test_checkCustoms(self): - """ - Checking that custom flags and parameters have correct values. - """ - self.failUnlessEqual(self.nice.opts['myflag'], "PONY!") - self.failUnlessEqual(self.nice.opts['myparam'], "Tofu WITH A PONY!") - - -class TypedOptions(usage.Options): - optParameters = [ - ['fooint', None, 392, 'Foo int', int], - ['foofloat', None, 4.23, 'Foo float', float], - ['eggint', None, None, 'Egg int without default', int], - ['eggfloat', None, None, 'Egg float without default', float], - ] - - -class TypedTestCase(unittest.TestCase): - """ - Test Options.parseArgs for options with forced types. - """ - def setUp(self): - self.usage = TypedOptions() - - def test_defaultValues(self): - """ - Test parsing of default values. - """ - argV = [] - self.usage.parseOptions(argV) - self.failUnlessEqual(self.usage.opts['fooint'], 392) - self.assert_(isinstance(self.usage.opts['fooint'], int)) - self.failUnlessEqual(self.usage.opts['foofloat'], 4.23) - self.assert_(isinstance(self.usage.opts['foofloat'], float)) - self.failUnlessEqual(self.usage.opts['eggint'], None) - self.failUnlessEqual(self.usage.opts['eggfloat'], None) - - def test_parsingValues(self): - """ - Test basic parsing of int and float values. - """ - argV = ("--fooint 912 --foofloat -823.1 " - "--eggint 32 --eggfloat 21").split() - self.usage.parseOptions(argV) - self.failUnlessEqual(self.usage.opts['fooint'], 912) - self.assert_(isinstance(self.usage.opts['fooint'], int)) - self.failUnlessEqual(self.usage.opts['foofloat'], -823.1) - self.assert_(isinstance(self.usage.opts['foofloat'], float)) - self.failUnlessEqual(self.usage.opts['eggint'], 32) - self.assert_(isinstance(self.usage.opts['eggint'], int)) - self.failUnlessEqual(self.usage.opts['eggfloat'], 21.) - self.assert_(isinstance(self.usage.opts['eggfloat'], float)) - - def test_invalidValues(self): - """ - Check that passing wrong values raises an error. - """ - argV = "--fooint egg".split() - self.assertRaises(usage.UsageError, self.usage.parseOptions, argV) - - -class WrongTypedOptions(usage.Options): - optParameters = [ - ['barwrong', None, None, 'Bar with wrong coerce', 'he'] - ] - - -class WeirdCallableOptions(usage.Options): - def _bar(value): - raise RuntimeError("Ouch") - def _foo(value): - raise ValueError("Yay") - optParameters = [ - ['barwrong', None, None, 'Bar with strange callable', _bar], - ['foowrong', None, None, 'Foo with strange callable', _foo] - ] - - -class WrongTypedTestCase(unittest.TestCase): - """ - Test Options.parseArgs for wrong coerce options. - """ - def test_nonCallable(self): - """ - Check that using a non callable type fails. - """ - us = WrongTypedOptions() - argV = "--barwrong egg".split() - self.assertRaises(TypeError, us.parseOptions, argV) - - def test_notCalledInDefault(self): - """ - Test that the coerce functions are not called if no values are - provided. - """ - us = WeirdCallableOptions() - argV = [] - us.parseOptions(argV) - - def test_weirdCallable(self): - """ - Test what happens when coerce functions raise errors. - """ - us = WeirdCallableOptions() - argV = "--foowrong blah".split() - # ValueError is swallowed as UsageError - e = self.assertRaises(usage.UsageError, us.parseOptions, argV) - self.assertEquals(str(e), "Parameter type enforcement failed: Yay") - - us = WeirdCallableOptions() - argV = "--barwrong blah".split() - # RuntimeError is not swallowed - self.assertRaises(RuntimeError, us.parseOptions, argV) - - -class OutputTest(unittest.TestCase): - def test_uppercasing(self): - """ - Error output case adjustment does not mangle options - """ - opt = WellBehaved() - e = self.assertRaises(usage.UsageError, - opt.parseOptions, ['-Z']) - self.assertEquals(str(e), 'option -Z not recognized') - - -class InquisitionOptions(usage.Options): - optFlags = [ - ('expect', 'e'), - ] - optParameters = [ - ('torture-device', 't', - 'comfy-chair', - 'set preferred torture device'), - ] - - -class HolyQuestOptions(usage.Options): - optFlags = [('horseback', 'h', - 'use a horse'), - ('for-grail', 'g'), - ] - - -class SubCommandOptions(usage.Options): - optFlags = [('europian-swallow', None, - 'set default swallow type to Europian'), - ] - subCommands = [ - ('inquisition', 'inquest', InquisitionOptions, - 'Perform an inquisition'), - ('holyquest', 'quest', HolyQuestOptions, - 'Embark upon a holy quest'), - ] - - -class SubCommandTest(unittest.TestCase): - - def test_simpleSubcommand(self): - o = SubCommandOptions() - o.parseOptions(['--europian-swallow', 'inquisition']) - self.failUnlessEqual(o['europian-swallow'], True) - self.failUnlessEqual(o.subCommand, 'inquisition') - self.failUnless(isinstance(o.subOptions, InquisitionOptions)) - self.failUnlessEqual(o.subOptions['expect'], False) - self.failUnlessEqual(o.subOptions['torture-device'], 'comfy-chair') - - def test_subcommandWithFlagsAndOptions(self): - o = SubCommandOptions() - o.parseOptions(['inquisition', '--expect', '--torture-device=feather']) - self.failUnlessEqual(o['europian-swallow'], False) - self.failUnlessEqual(o.subCommand, 'inquisition') - self.failUnless(isinstance(o.subOptions, InquisitionOptions)) - self.failUnlessEqual(o.subOptions['expect'], True) - self.failUnlessEqual(o.subOptions['torture-device'], 'feather') - - def test_subcommandAliasWithFlagsAndOptions(self): - o = SubCommandOptions() - o.parseOptions(['inquest', '--expect', '--torture-device=feather']) - self.failUnlessEqual(o['europian-swallow'], False) - self.failUnlessEqual(o.subCommand, 'inquisition') - self.failUnless(isinstance(o.subOptions, InquisitionOptions)) - self.failUnlessEqual(o.subOptions['expect'], True) - self.failUnlessEqual(o.subOptions['torture-device'], 'feather') - - def test_anotherSubcommandWithFlagsAndOptions(self): - o = SubCommandOptions() - o.parseOptions(['holyquest', '--for-grail']) - self.failUnlessEqual(o['europian-swallow'], False) - self.failUnlessEqual(o.subCommand, 'holyquest') - self.failUnless(isinstance(o.subOptions, HolyQuestOptions)) - self.failUnlessEqual(o.subOptions['horseback'], False) - self.failUnlessEqual(o.subOptions['for-grail'], True) - - def test_noSubcommand(self): - o = SubCommandOptions() - o.parseOptions(['--europian-swallow']) - self.failUnlessEqual(o['europian-swallow'], True) - self.failUnlessEqual(o.subCommand, None) - self.failIf(hasattr(o, 'subOptions')) - - def test_defaultSubcommand(self): - o = SubCommandOptions() - o.defaultSubCommand = 'inquest' - o.parseOptions(['--europian-swallow']) - self.failUnlessEqual(o['europian-swallow'], True) - self.failUnlessEqual(o.subCommand, 'inquisition') - self.failUnless(isinstance(o.subOptions, InquisitionOptions)) - self.failUnlessEqual(o.subOptions['expect'], False) - self.failUnlessEqual(o.subOptions['torture-device'], 'comfy-chair') - - def test_subCommandParseOptionsHasParent(self): - class SubOpt(usage.Options): - def parseOptions(self, *a, **kw): - self.sawParent = self.parent - usage.Options.parseOptions(self, *a, **kw) - class Opt(usage.Options): - subCommands = [ - ('foo', 'f', SubOpt, 'bar'), - ] - o = Opt() - o.parseOptions(['foo']) - self.failUnless(hasattr(o.subOptions, 'sawParent')) - self.failUnlessEqual(o.subOptions.sawParent , o) - - def test_subCommandInTwoPlaces(self): - """ - The .parent pointer is correct even when the same Options class is - used twice. - """ - class SubOpt(usage.Options): - pass - class OptFoo(usage.Options): - subCommands = [ - ('foo', 'f', SubOpt, 'quux'), - ] - class OptBar(usage.Options): - subCommands = [ - ('bar', 'b', SubOpt, 'quux'), - ] - oFoo = OptFoo() - oFoo.parseOptions(['foo']) - oBar=OptBar() - oBar.parseOptions(['bar']) - self.failUnless(hasattr(oFoo.subOptions, 'parent')) - self.failUnless(hasattr(oBar.subOptions, 'parent')) - self.failUnlessIdentical(oFoo.subOptions.parent, oFoo) - self.failUnlessIdentical(oBar.subOptions.parent, oBar) - - -class HelpStringTest(unittest.TestCase): - def setUp(self): - """ - Instantiate a well-behaved Options class. - """ - - self.niceArgV = ("--long Alpha -n Beta " - "--shortless Gamma -f --myflag " - "--myparam Tofu").split() - - self.nice = WellBehaved() - - def test_noGoBoom(self): - """ - __str__ shouldn't go boom. - """ - try: - self.nice.__str__() - except Exception, e: - self.fail(e) - - def test_whitespaceStripFlagsAndParameters(self): - """ - Extra whitespace in flag and parameters docs is stripped. - """ - # We test this by making sure aflag and it's help string are on the - # same line. - lines = [s for s in str(self.nice).splitlines() if s.find("aflag")>=0] - self.failUnless(len(lines) > 0) - self.failUnless(lines[0].find("flagallicious") >= 0) - - -class PortCoerceTestCase(unittest.TestCase): - """ - Test the behavior of L{usage.portCoerce}. - """ - def test_validCoerce(self): - """ - Test the answers with valid input. - """ - self.assertEquals(0, usage.portCoerce("0")) - self.assertEquals(3210, usage.portCoerce("3210")) - self.assertEquals(65535, usage.portCoerce("65535")) - - def test_errorCoerce(self): - """ - Test error path. - """ - self.assertRaises(ValueError, usage.portCoerce, "") - self.assertRaises(ValueError, usage.portCoerce, "-21") - self.assertRaises(ValueError, usage.portCoerce, "212189") - self.assertRaises(ValueError, usage.portCoerce, "foo") - - -if __name__ == '__main__': - unittest.main() - diff --git a/tools/buildbot/pylibs/twisted/test/test_zshcomp.py b/tools/buildbot/pylibs/twisted/test/test_zshcomp.py deleted file mode 100644 index 096f9d6..0000000 --- a/tools/buildbot/pylibs/twisted/test/test_zshcomp.py +++ /dev/null @@ -1,210 +0,0 @@ -# Copyright (c) 2006 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test cases for twisted.python.zshcomp -""" - -import os, os.path -from cStringIO import StringIO - -from twisted.trial import unittest -from twisted.python import zshcomp, usage - -class ZshcompTestCase(unittest.TestCase): - """ - Tests for the zsh completion function builder in twisted/python/zshcomp.py - """ - def test_buildAll(self): - """ - Build all the completion functions for twisted commands - no errors - should be raised - """ - dirname = self.mktemp() - os.mkdir(dirname) - skippedCmds = [x[0] for x in zshcomp.makeCompFunctionFiles(dirname)] - - # verify a zsh function was created for each twisted command - for info in zshcomp.generateFor: - if info[0] in skippedCmds: - continue - funcPath = os.path.join(dirname, '_' + info[0]) - self.failUnless(os.path.exists(funcPath)) - - def test_accumulateMetadata(self): - """ - Test that the zsh_* variables you can place on Option classes gets - picked up correctly - """ - opts = TestOptions2() - ag = zshcomp.ArgumentsGenerator('dummy_cmd', opts, 'dummy_value') - - altArgDescr = TestOptions.zsh_altArgDescr.copy() - altArgDescr.update(TestOptions2.zsh_altArgDescr) - - actionDescr = TestOptions.zsh_actionDescr.copy() - actionDescr.update(TestOptions2.zsh_actionDescr) - - self.failUnlessEquals(ag.altArgDescr, altArgDescr) - self.failUnlessEquals(ag.actionDescr, actionDescr) - self.failUnlessEquals(ag.multiUse, TestOptions.zsh_multiUse) - self.failUnlessEquals(ag.mutuallyExclusive, - TestOptions.zsh_mutuallyExclusive) - self.failUnlessEquals(ag.actions, TestOptions.zsh_actions) - self.failUnlessEquals(ag.extras, TestOptions.zsh_extras) - - def test_accumulateAdditionalOptions(self): - """ - Test that we pick up options that are only defined by having an - appropriately named method on your Options class, - e.g. def opt_foo(self, foo) - """ - opts = TestOptions2() - ag = zshcomp.ArgumentsGenerator('dummy_cmd', opts, 'dummy_value') - - self.failUnless('nocrash' in ag.optFlags_d and \ - 'nocrash' in ag.optAll_d) - self.failUnless('difficulty' in ag.optParams_d and \ - 'difficulty' in ag.optAll_d) - - def test_verifyZshNames(self): - """ - Test that using a parameter/flag name that doesn't exist - will raise an error - """ - class TmpOptions(TestOptions2): - zsh_actions = {'detaill' : 'foo'} # Note typo of detail - - opts = TmpOptions() - self.failUnlessRaises(ValueError, zshcomp.ArgumentsGenerator, - 'dummy_cmd', opts, 'dummy_value') - - def test_zshCode(self): - """ - Generate a completion function, and test the textual output - against a known correct output - """ - cmd_name = 'testprog' - opts = CodeTestOptions() - f = StringIO() - b = zshcomp.Builder(cmd_name, opts, f) - b.write() - f.reset() - self.failUnlessEquals(f.read(), testOutput1) - - def test_skipBuild(self): - """ - Test that makeCompFunctionFiles skips building for commands whos - script module cannot be imported - """ - generateFor = [('test_cmd', 'no.way.your.gonna.import.this', 'Foo')] - skips = zshcomp.makeCompFunctionFiles('out_dir', generateFor, {}) - # no exceptions should be raised. hooray. - self.failUnlessEqual(len(skips), 1) - self.failUnlessEqual(len(skips[0]), 2) - self.failUnlessEqual(skips[0][0], 'test_cmd') - self.failUnless(isinstance(skips[0][1], ImportError)) - self.flushLoggedErrors(self, ImportError) - -class TestOptions(usage.Options): - """ - Command-line options for an imaginary game - """ - optFlags = [['fokker', 'f', - 'Select the Fokker Dr.I as your dogfighter aircraft'], - ['albatros', 'a', - 'Select the Albatros D-III as your dogfighter aircraft'], - ['spad', 's', - 'Select the SPAD S.VII as your dogfighter aircraft'], - ['bristol', 'b', - 'Select the Bristol Scout as your dogfighter aircraft'], - ['physics', 'p', - 'Enable secret Twisted physics engine'], - ['jam', 'j', - 'Enable a small chance that your machine guns will jam!'], - ['verbose', 'v', - 'Verbose logging (may be specified more than once)'], - ] - - optParameters = [['pilot-name', None, "What's your name, Ace?", - 'Manfred von Richthofen'], - ['detail', 'd', - 'Select the level of rendering detail (1-5)', '3'], - ] - - - zsh_altArgDescr = {'physics' : 'Twisted-Physics', - 'detail' : 'Rendering detail level'} - zsh_actionDescr = {'detail' : 'Pick your detail'} - zsh_multiUse = ['verbose'] - zsh_mutuallyExclusive = [['fokker', 'albatros', 'spad', 'bristol']] - zsh_actions = {'detail' : '(1 2 3 4 5)'} - zsh_extras = [':saved game file to load:_files'] - -class TestOptions2(TestOptions): - """ - Extend the options and zsh metadata provided by TestOptions. zshcomp must - accumulate options and metadata from all classes in the hiearchy so this - is important for testing - """ - optFlags = [['no-stalls', None, - 'Turn off the ability to stall your aircraft']] - optParameters = [['reality-level', None, - 'Select the level of physics reality (1-5)', '5']] - - zsh_altArgDescr = {'no-stalls' : 'Can\'t stall your plane'} - zsh_actionDescr = {'reality-level' : 'Physics reality level'} - - def opt_nocrash(self): - """Select that you can't crash your plane""" - - def opt_difficulty(self, difficulty): - """How tough are you? (1-10)""" - -def _accuracyAction(): - return '(1 2 3)' - -class CodeTestOptions(usage.Options): - """ - Command-line options for an imaginary program - """ - optFlags = [['color', 'c', 'Turn on color output'], - ['gray', 'g', 'Turn on gray-scale output'], - ['verbose', 'v', - 'Verbose logging (may be specified more than once)'], - ] - - optParameters = [['optimization', None, - 'Select the level of optimization (1-5)', '5'], - ['accuracy', 'a', - 'Select the level of accuracy (1-3)', '3'], - ] - - - zsh_altArgDescr = {'color' : 'Color on', - 'optimization' : 'Optimization level'} - zsh_actionDescr = {'optimization' : 'Optimization?', - 'accuracy' : 'Accuracy?'} - zsh_multiUse = ['verbose'] - zsh_mutuallyExclusive = [['color', 'gray']] - zsh_actions = {'optimization' : '(1 2 3 4 5)', - 'accuracy' : _accuracyAction} - zsh_extras = [':output file:_files'] - -testOutput1 = """#compdef testprog -_arguments -s -A "-*" \\ -':output file:_files' \\ -'(--accuracy)-a[3]:Accuracy?:(1 2 3)' \\ -'(-a)--accuracy=[3]:Accuracy?:(1 2 3)' \\ -'(--gray -g --color)-c[Color on]' \\ -'(--gray -g -c)--color[Color on]' \\ -'(--color -c --gray)-g[Turn on gray-scale output]' \\ -'(--color -c -g)--gray[Turn on gray-scale output]' \\ -'--help[Display this help and exit.]' \\ -'--optimization=[Optimization level]:Optimization?:(1 2 3 4 5)' \\ -'*-v[Verbose logging (may be specified more than once)]' \\ -'*--verbose[Verbose logging (may be specified more than once)]' \\ -'--version[version]' \\ -&& return 0 -""" - diff --git a/tools/buildbot/pylibs/twisted/test/testutils.py b/tools/buildbot/pylibs/twisted/test/testutils.py deleted file mode 100644 index a310ea2..0000000 --- a/tools/buildbot/pylibs/twisted/test/testutils.py +++ /dev/null @@ -1,55 +0,0 @@ -from cStringIO import StringIO -from twisted.internet.protocol import FileWrapper - -class IOPump: - """Utility to pump data between clients and servers for protocol testing. - - Perhaps this is a utility worthy of being in protocol.py? - """ - def __init__(self, client, server, clientIO, serverIO): - self.client = client - self.server = server - self.clientIO = clientIO - self.serverIO = serverIO - - def flush(self): - "Pump until there is no more input or output." - while self.pump(): - pass - - def pump(self): - """Move data back and forth. - - Returns whether any data was moved. - """ - self.clientIO.seek(0) - self.serverIO.seek(0) - cData = self.clientIO.read() - sData = self.serverIO.read() - self.clientIO.seek(0) - self.serverIO.seek(0) - self.clientIO.truncate() - self.serverIO.truncate() - for byte in cData: - self.server.dataReceived(byte) - for byte in sData: - self.client.dataReceived(byte) - if cData or sData: - return 1 - else: - return 0 - - -def returnConnected(server, client): - """Take two Protocol instances and connect them. - """ - cio = StringIO() - sio = StringIO() - client.makeConnection(FileWrapper(cio)) - server.makeConnection(FileWrapper(sio)) - pump = IOPump(client, server, cio, sio) - # Challenge-response authentication: - pump.flush() - # Uh... - pump.flush() - return pump diff --git a/tools/buildbot/pylibs/twisted/test/threading_latency.py b/tools/buildbot/pylibs/twisted/test/threading_latency.py deleted file mode 100644 index 719f9b5..0000000 --- a/tools/buildbot/pylibs/twisted/test/threading_latency.py +++ /dev/null @@ -1,54 +0,0 @@ -"""Measure latency of reactor thread APIs. run with runtests.""" - -from pyunit import unittest -import time - -from twisted.internet import reactor, threads - - -class LatencyTestCase(unittest.TestCase): - - numRounds = 5 - - def setUp(self): - self.from_times = [] - self.in_times = [] - - def tearDown(self): - threads.shutdown() - - def wait(self): - start = time.time() - while time.time() - start < 1: - reactor.iterate(1.0) - - def printResult(self): - print - print - print "callFromThread latency:" - sum = 0 - for t in self.from_times: sum += t - print "%f millisecond" % ((sum / self.numRounds) * 1000) - - print "callInThread latency:" - sum = 0 - for t in self.in_times: sum += t - print "%f millisecond" % ((sum / self.numRounds) * 1000) - print - print - - def testCallFromThread(self): - for i in range(self.numRounds): - reactor.callInThread(self.tcmf_2, time.time()) - self.wait() - assert len(self.in_times) == len(self.from_times) - assert len(self.in_times) == self.numRounds - self.printResult() - - def tcmf_2(self, start): - # runs in thread - self.in_times.append(time.time() - start) - reactor.callFromThread(self.tcmf_3, time.time()) - - def tcmf_3(self, start): - self.from_times.append(time.time() - start) diff --git a/tools/buildbot/pylibs/twisted/test/time_helpers.py b/tools/buildbot/pylibs/twisted/test/time_helpers.py deleted file mode 100644 index fd8aecc..0000000 --- a/tools/buildbot/pylibs/twisted/test/time_helpers.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Helper class to writing deterministic time-based unit tests. - -Do not use this module. It is a lie. See L{twisted.internet.task.Clock} -instead. -""" - -class Clock(object): - """ - A utility for monkey-patches various parts of Twisted to use a - simulated timing mechanism. DO NOT use this class. Use - L{twisted.internet.task.Clock}. - """ - rightNow = 0.0 - - def __call__(self): - """ - Return the current simulated time. - """ - return self.rightNow - - def install(self): - """ - Monkeypatch L{twisted.internet.reactor.seconds} to use - L{__call__} as a time source - """ - # Violation is fun. - from twisted.internet import reactor - self.reactor_original = reactor.seconds - reactor.seconds = self - - def uninstall(self): - """ - Remove the monkeypatching of L{twisted.internet.reactor.seconds}. - """ - from twisted.internet import reactor - reactor.seconds = self.reactor_original - - def adjust(self, amount): - """ - Adjust the current simulated time upward by the given C{amount}. - - Note that this does not cause any scheduled calls to be run. - """ - self.rightNow += amount - - def pump(self, reactor, timings): - """ - Iterate the given C{reactor} with increments of time specified - by C{timings}. - - For each timing, the simulated time will be L{adjust}ed and - the reactor will be iterated twice. - """ - timings = list(timings) - timings.reverse() - self.adjust(timings.pop()) - while timings: - self.adjust(timings.pop()) - reactor.iterate() - reactor.iterate() - diff --git a/tools/buildbot/pylibs/twisted/topfiles/CREDITS b/tools/buildbot/pylibs/twisted/topfiles/CREDITS deleted file mode 100644 index a4eeece..0000000 --- a/tools/buildbot/pylibs/twisted/topfiles/CREDITS +++ /dev/null @@ -1,60 +0,0 @@ -The Matrix - -- Glyph "Glyph" Lefkowitz - electric violin -- Sean "Riley" Riley - grand piano -- Allen "Dash" Short - vocals and guitar -- Christopher "Radix" Armstrong - percussion -- Paul "z3p" Swartz - oboe -- Jürgen "snibril" Hermann - synthesizer -- Moshe "vertical" Zadka - accordion -- Benjamin Bruheim - kazoo -- Travis B. "Nafai" Hartwell - keyboards -- Itamar "itamar" Shtull-Trauring - alto recorder -- Andrew "spiv" Bennetts - glockenspiel -- Kevin "Acapnotic" Turner - trombone -- Donovan "fzZzy" Preston - bass and harmonium -- Jp "exarkun" Calderone - geopolitical sociographic dissonance engine -- Gavin "skreech" Cooper - torque wrench -- Jonathan "jml" Lange - pipe organ -- Bob "etrepum" Ippolito - low frequency oscillator -- Pavel "PenguinOfDoom" Pergamenshchik - electronic balalaika -- Jonathan D. "slyphon" Simms - theramin and drums -- Brian "warner" Warner - hertzian field renderer -- Mary Gardiner - krummhorn -- Eric "teratorn" Mangold - serpentine bassoon -- Tommi "Tv" Virtanen - didgeridoo -- Justin "justinj" Johnson - bass mandolin -- Ralph "ralphm" Meijer - vocals and timbales -- David "dreid" Reid - banjo - -Extras - -- Jerry Hebert -- Nick Moffit -- Jeremy Fincher diff --git a/tools/buildbot/pylibs/twisted/topfiles/ChangeLog.Old b/tools/buildbot/pylibs/twisted/topfiles/ChangeLog.Old deleted file mode 100644 index 30594b2..0000000 --- a/tools/buildbot/pylibs/twisted/topfiles/ChangeLog.Old +++ /dev/null @@ -1,3888 +0,0 @@ -2005-03-12 Jp Calderone - - * twisted/scripts/mktap.py, twisted/scripts/twistd.py, - twisted/application/app.py: Changed UID and GID defaults for Process - to None. Changed mktap behavior to not specify UID and GID if they - are not given on the command line. Changed application startup to - not change UID or GID if they are not given. Changed twistd to add - UID and GID setting command line arguments. - -2005-02-10 Jp Calderone - - * twisted/internet/defer.py: DeferredLock, DeferredSemaphore, and - DeferredQueue added. - - * twisted/test/test_defer.py: Tests for above mentioned three new - classes. - -2004-11-27 Brian Warner - - * util.py (SignalStateManager.save): don't save signal handlers - for SIGKILL and SIGSTOP, since we can't set them anyway. - Python2.4c1 raises an error when you try. - -2004-11-07 Brian Warner - - * twisted/test/test_internet.py: correctly check for SSL support. - Improve timeout for testCallLater and testGetDelayedCalls to avoid - spurious failures on slow test systems. Close sockets in - PortStringification to fix trial warnings. - - * twisted/internet/ssl.py: add a comment describing the correct - way to import twisted.internet.ssl (since it might partially fail - if OpenSSL is not available) - -2004-11-06 Jp Calderone - - * twisted/trial/assertions.py: assertRaises/failUnlessRaises now - returns the caught exception to allow tests to inspect the contents. - -2004-11-02 Brian Warner - - * loopback.py (loopbackTCP): use trial's spinWhile and spinUntil - primitives instead of doing reactor.iterate() ourselves. Make sure - to wait for everything before finishing. - -2004-10-26 Cory Dodt - - * twisted/python/{which,process}.py, - twisted/test/{test_wprocess,wprocess_for_testing}.py, - twisted/internet/{default,error,wprocess,process}.py: back out - wprocess due to test failures in wprocess and new trial. Resolves - issue 760. - -2004-10-24 Itamar Shtull-Trauring - - * TCP: Half-close of write and read for TCP connections, including - protocol notification for protocols that implement - IHalfCloseableProtocol. - -2004-10-07 Jp Calderone - - * Transports: Add a maximum to the number of bytes that will be - held in the write buffer even after they have been sent. This - puts a maximum on the cost of writing faster than the network - can accommodate. - -2004-10-06 Itamar Shtull-Trauring - - * Transports: New TCP/SSL/etc. buffering algorithm. All writes are - now stored until next iteration before being written, and many - small writes are not expensive. - -2004-09-30 Brian Warner - - * glib2reactor.py: new reactor that uses just glib2, not gtk2. - This one doesn't require a DISPLAY, and cannot be used for GUI - apps. - - * gtk2reactor.py: import gobject *after* pygtk.require, to make - sure we get the same versions of both - -2004-09-18 Christopher Armstrong - - * twisted/internet/defer.py: Add deferredGenerator and - waitForDeferred. This lets you write kinda-sorta - synchronous-looking code that uses Deferreds. See the - waitForDeferred docstring. - -2004-09-11 Cory Dodt - - * twisted/python/{which,process}.py, - twisted/test/{test_wprocess,wprocess_for_testing}.py, - twisted/internet/{default,error,wprocess,process}.py: merge the - "wprocess" branch which uses Trent Mick's process.py to enable - spawnProcess in the default reactor on Windows - -2004-08-24 Brian Warner - - * twisted/application/internet.py (TimerService): make it possible - to restart a stopped TimerService. Threw out a lot of (apparently) - unnecessary code in the process. Make sure it gets pickled in a - not-running state too. - * twisted/test/test_application.py (TestInternet2.testTimer): test - the changes, and update the way the test peeks inside TimerService - -2004-07-18 Paul Swartz - - * twisted/internet/utils.py: By passing errortoo=1, you can get - stderr from getProcessOutput - -2004-07-18 Paul Swartz - - * twisted/conch/unix.py: if the utmp module is available, record - user logins/logouts into utmp/wtmp. - -2004-06-25 Paul Swartz - * twisted/conch/checkers.py: Use functionality of crypt module instead - of an external module. - -2004-06-25 Jp Calderone - - * twisted/spread/banana.py: Disabled automatic import and use of - cBanana. PB will now use the pure-Python version of banana unless - cBanana is manually installed by the application. - -2004-06-12 Paul Swartz - - * twisted/conch/client: added -r flag to reconnect to the server if - the connection is lost (closes 623). - -2004-06-06 Dave Peticolas - - * twisted/test/test_enterprise.py: test open callback and - connect/disconnect. - - * twisted/enterprise/adbapi.py: add open callback support - and disconnect() method. Issue 480. - -2004-06-05 Dave Peticolas - - * twisted/enterprise/adbapi.py: Don't log sql exceptions (issue 631). - Remove deprecated api. - - * twisted/news/database.py: do not use adbapi.Augmentation - -2004-06-03 Itamar Shtull-Trauring - - * twisted/internet/gtk2reactor.py: The choice between glib event - loop and gtk+ event loop is determined by argument at reactor - install time. - -2004-05-31 Dave Peticolas - - * twisted/enterprise/sqlreflector.py: don't use Augmentation - - * twisted/enterprise/populate.sql: remove - - * twisted/enterprise/schema.sql: remove - - * twisted/enterprise/row.py: remove deprecated classes - - * twisted/enterprise/dbgadgets.py: remove - - * twisted/enterprise/dbcred.py: remove - - * twisted/test/test_enterprise.py: Fix Firebird test case. - -2004-05-21 Itamar Shtull-Trauring - - * twisted/internet/gtk2reactor.py: use glib event loop directly - instead of gtk2's event loop if possible. - -2004-05-04 Jp Calderone - - * twisted.news, twisted.protocols.nntp: Moved back into trunk - pending an alternate split-up strategy. - -2004-05-04 Itamar Shtull-Trauring - - * twisted.internet.reactor.listenUDP: transport.write() on UDP - ports no longer supports unresolved hostnames (though deprecated - support still exists). - -2004-4-18 Christopher Armstrong - - * twisted/lore/nevowlore.py, twisted/plugins.tml: Added Nevow - support for lore. See docstring of twisted.lore.nevowlore. - -2004-4-18 Christopher Armstrong - - * twisted.news, twisted.protocols.nntp: Moved into a third party - package. Deprecated backwards-compatibility exists by importing - from the third-party package if available. - -2004-4-11 Paul Swartz - - * twisted.conch: refactored the Conch client to separate connecting - to a server from user authentication from client-specific actions. - -2004-03-23 Andrew Bennetts - - * twisted.protocols.http: Small optimisation to HTTP implementation. - This changes return value of toChunk to a tuple of strings, rather - than one string. - -2004-4-3 Paul Swartz - - * twisted.python.lockfile: added lockfile support, based on - liblockfile. - * twisted.internet.unix.Port: added a wantPID kwarg. If True, it - checks for and gets a lockfile for the UNIX socket. - * twisted.internet.unix.Connector: added a checkPID kwarg. If True, - it checks that the lockfile for the socket is current. - -2004-03-23 Pavel Pergamenshchik - - * twisted.internet.iocp: Support for Windows IO Completion Ports. - Use with "--reactor=iocp" parameter to twistd or trial. - -2004-03-20 Itamar Shtull-Trauring - - * twisted.internet: getHost(), getPeer(), buildProtocol() etc. - all use address objects from twisted.internet.address. - - * twisted/internet/udp.py: Connected UDP support is now part of - the standard listenUDP-resulting UDP transport using a connect() - method. - -2004-03-18 Jp Calderone - - * twisted/application/internet.py: Changed TimerService to - log errors from the function it calls. - - * twisted/application/test_application.py: Added test case - for logging of exceptions from functions TimerService calls. - -2004-03-07 Christopher Armstrong - - * .: Releasing Twisted 1.2.1alpha1. - -2004-03-03 Christopher Armstrong - - * twisted/web/server.py: Fix UnsupportedMethod so that users' - allowedMethods are actually honored. - - * twisted/web/resource.py: (Resource.render) If the resource has - an 'allowedMethods' attribute, pass it to UnsupportedMethod. - -2004-02-27 Andrew Bennetts - - * twisted/internet/defer.py: Add consumeErrors flag to DeferredList. - This takes care of the most common use-case for the recently - deprecated addDeferred method. - -2004-02-28 Dave Peticolas - - * setup.py: install tap2rpm as a bin script - - * twisted/test/test_enterprise.py: Test Firebird db. Fix typos. - -2004-02-27 Andrew Bennetts - - * twisted/internet/defer.py: Deprecated DeferredList.addDeferred. It - isn't as useful as it looks, and can have surprising behaviour. - -2004-02-25 Christopher Armstrong - - * twisted/protocols/dns.py: Fixed a bug in TCP support: It - wouldn't process any messages after the first, causing AXFR - queries to be totally broken (in addition to other problems in the - implementation of AXFR). - - * twisted/names/client.py: Fixed the AXFR client (lookupZone), - thanks to DJB's wonderful documentation of the horribleness of - DNS. - -2004-02-25 Christopher Armstrong - - * .: Releasing Twisted 1.2.0 final! Same as rc3. - -2004-02-24 Christopher Armstrong - - * .: Releasing Twisted 1.2.0rc3 (same as rc2, with cBanana bug - fixed). - -2004-02-19 Kevin Turner - - * twisted/application/service.py (IService.disownServiceParent) - (IServiceCollection.removeService): These may return Deferred if they - have asynchronous side effects. - -2004-02-18 Christopher Armstrong - - * .: Releasing Twisted 1.2.0rc2. Brown-paper bag release bug. - -2004-02-17 Christopher Armstrong - - * .: Releasing Twisted 1.2.0rc1. - -2004-02-13 Brian Warner - - * doc/howto/faq.xhtml: add entry on transport.getPeer() - -2004-01-31 Christopher Armstrong - - * .: Releasing Twisted 1.1.2alpha2 (problem with Debian packaging). - -2004-01-30 Christopher Armstrong - - * .: Releasing Twisted 1.1.2alpha1. - -2004-01-23 Christopher Armstrong - - * twisted/scripts/trial.py: trial now supports a --coverage - option, requiring Python 2.3.3. Give it a directory name (relative - to _trial_temp) to put code-coverage info in. It uses the stdlib - 'trace' module. - -2004-01-21 Pavel Pergamenshchik - - * twisted/protocols/stateful.py: A new way to write protocols! - Current state is encoded as a pair (func, len). As soon as len - of data arrives, func is called with that amount of data. New - state is returned from func. - * twisted/test/test_stateful.py: Tests and an example, an - Int32StringReceiver implementation. - -2004-01-18 Christopher Armstrong - - * twisted/web/resource.py: The default render method of Resource - now supports delegating to methods of the form "render_*" where - "*" is the HTTP method that was used to make the - request. Examples: request_GET, request_HEAD, request_CONNECT, and - so on. This won't break any existing code - when people want to - use the better API, they can stop overriding 'render' and instead - override individual render_* methods. - -2004-01-13 Itamar Shtull-Trauring - - * twisted/web/soap.py: Beginning of client SOAP support. - -2004-01-10 Andrew Bennetts - - * twisted/protocols/ftp.py: Added support for partial downloads - and uploads to FTPClient (see the offset parameter of retrieveFile). - -2004-01-09 Jp Calderone - - * twisted/protocols/imap4.py: Add IMessageCopier interface to allow - for optimized implementations of message copying. - -2004-01-06 Brian Warner - - * twisted/internet/default.py (PosixReactorBase.spawnProcess): add - a 'childFDs' argument which allows the child's file descriptors to - be arbitrarily mapped to parent FDs or pipes. This allows you to - set up additional pipes into the child (say for a GPG passphrase - or separate status information). - - * twisted/internet/process.py (Process): add childFDs, split out - ProcessReader and ProcessWriter (so that Process itself is no - longer also reading stdout). - - * twisted/internet/protocol.py (ProcessProtocol): add new - childDataReceived and childConnectionLost methods, which default - to invoking the old methods for backwards compatibility - - * twisted/test/test_process.py (FDTest): add test for childFDs - mapping. Also add timeouts to most tests, and make all - reactor.iterate() loops wait 10ms between iterations to avoid - spamming the CPU quite so badly. Closes issue435. - * twisted/test/process_fds.py: new child process for FDTest - - * doc/howto/process.xhtml: document childFDs argument, add example - -2004-01-04 Itamar Shtull-Trauring - - * twisted/internet/gladereactor.py: logs all network traffic for - TCP/SSL/Unix sockets, allowing traffic to be displayed. - -2004-01-04 Dave Peticolas - - * twisted/test/test_enterprise.py: test deleting rows not in cache - - * twisted/enterprise/reflector.py: deleted rows don't have to be - in cache - - * doc/examples/row_example.py: use KeyFactory from row_util - - * doc/examples/row_util.py: add KeyFactory - -2003-12-31 Brian Warner - - * twisted/internet/defer.py (Deferred.setTimeout): if the Deferred - has already been called, don't bother with the timeout. This - happens when trial.util.deferredResult is used with a timeout - argument and the Deferred was created by defer.succeed(). - * twisted/test/test_defer.py - (DeferredTestCase.testImmediateSuccess2): test for same - -2003-12-31 Jp Calderone - - * twisted/protocols/ident.py: Client and server ident implementation - * twisted/test/test_ident.py: Test cases for ident protocol - -2003-12-29 Jp Calderone - - * twisted/spread/pb.py: Changed PBServerFactory to use "protocol" - instance attribute for Broker creation. - -2003-12-26 Itamar Shtull-Trauring - - * twisted/web/server.py: display of tracebacks on web pages can - now be disabled by setting displayTracebacks to False on the Site - or by using applicable tap option. Woven does not yet use - this attribute. - -2003-12-23 Itamar Shtull-Trauring - - * twisted/web/client.py: if Host header is passed, use that - instead of extracting from request URL. - -2003-12-14 Dave Peticolas - - * twisted/test/test_enterprise.py: Frederico Di Gregorio's patch - adding a psycopg test case. - -2003-12-09 Christopher Armstrong - - * .: Releasing Twisted 1.1.1, based on rc4. - -2003-12-06 Itamar Shtull-Trauring - - * twisted/internet/wxreactor.py: Added experimental wxPython reactor, - which seems to work better than the twisted.internet.wxsupport. - -2003-12-05 Paul Swartz - - * twisted/conch/ssh/filetransfer.py, session.py: added SFTPv3 support - to the Conch server. - -2003-12-04 Christopher Armstrong - - * .: Releasing Twisted 1.1.1rc4, based on rc2. rc3 never happened! - -2003-12-04 Brian Warner - - * twisted/persisted/sob.py (Persistent): fix misspelled class name, - add compatibility binding to "Persistant" (sic). - - * twisted/test/test_sob.py: use Persistent - * twisted/application/service.py (Application): use Persistent - -2003-12-03 Jp Calderone - - * twisted/protocols/imap4.py: Added support for the - IDLE command (RFC 2177). - -2003-12-03 Jp Calderone - - * twisted/python/log.py: Added exception handling to - log publishing code. Observers which raise exceptions - will now be removed from the observer list. - -2003-12-02 Jp Calderone - - * .: Releasing Twisted 1.1.1rc3. - -2003-12-01 Christopher Armstrong - - * .: Releasing Twisted 1.1.1rc2 (from CVS HEAD). - -2003-12-01 Jp Calderone - - * twisted/python/runtime.py: Added seconds method to Platform - class. - - * twisted/internet/base.py, twisted/internet/task.py: Changed - use of time.time() to use Platform.seconds() instead. - -2003-11-24 Jp Calderone - - * twisted/internet/abstract.py: Changed FileDescriptor's - registerProducer method to immediately call the given producer's - stopProducing method if the FileDescriptor is in the process of - or has finished disconnecting. - -2003-11-24 Jp Calderone - - * twisted/protocols/imap4.py: Fix incorrect behavior of closing the - mailbox in response to an EXPUNGE command. - -2003-11-21 Jp Calderone - - * twisted/trial/runner.py: Added missing calls to setUpClass and - tearDownClass in SingletonRunner. - -2003-11-21 Christopher Armstrong - - * .: Releasing Twisted 1.1.1rc1. - -2003-11-20 Jp Calderone - - * twisted/protocols/imap4.py: Fixed incorrect generation of - INTERNALDATE information. - -2003-11-20 Jp Calderone - - * twisted/internet/abstract.py: Added an assert to - FileDescriptor.resumeProducing to prevent it from being - called when the transport is no longer connected. - -2003-11-20 Jp Calderone - - * twisted/internet/tasks.py: LoopingCall added. - -2003-10-14 Itamar Shtull-Trauring - - * twisted/internet/tasks.py: Deprecated scheduling API removed. - -2003-11-18 Jonathan Simms - - * twisted/protocols/ftp.py: refactored to add cred support, - pipelining, security. - * twisted/test/test_ftp.py: tests for the new ftp - -2003-11-18 Sam Jordan - - * twisted/protocols/msn.py: support for MSNP8 - * doc/examples/msn_example.py: small msn example - -2003-11-13 Paul Swartz - - * twisted/conch/ssh/agent.py: support for the OpenSSH agent protocol - * twisted/conch/ssh/connection.py: fix broken channel retrieval code - * twisted/conch/ssh/userauth.py: refactoring to allow use of the agent - * twisted/conch/ssj/transport.py: fix intermittent test failure - * twisted/internet/protocol.py: add UNIX socket support to - ClientCreator - * twisted/scripts/conch.py: use the key agent if available, also - agent forwarding - -2003-11-07 Brian Warner - - * twisted/application/app.py (getApplication): provide a more - constructive error message when a .tac file doesn't define - 'application'. Closes issue387. - -2003-11-01 Paul Swartz - - * twisted/conch/ssh/common.py: use GMPy for faster math if it's - available - -2003-10-24 Christopher Armstrong - - * .: Releasing Twisted 1.1.0 final. Same codebase as rc2. - -2003-10-24 Brian Warner - - * doc/howto/test-standard.xhtml: Add section on how to clean up. - - * twisted/test/test_conch.py: improve post-test cleanup. Addresses - problems seen in issue343. - - * twisted/internet/base.py (ReactorBase.callLater): prefix - "internal" parameter names with an underscore, to avoid colliding - with named parameters in the user's callback invocation. Closes - issue347. - (ReactorBase.addSystemEventTrigger) - (ReactorBase.callWhenRunning) - (ReactorBase.callInThread): same - * doc/howto/coding-standard.xhtml (Callback Arguments): explain why - -2003-10-22 Christopher Armstrong - - * .: Releasing Twisted 1.1.0rc2. - -2003-10-21 Andrew Bennetts - - * twisted/lore/tree.py, twisted/lore/lint.py, - doc/howto/stylesheet.css: add a plain 'listing' class, for file - listings that aren't python source or HTML. This has slightly changed - the classes in the generated HTML, so custom stylesheets may need - updating. - -2003-10-16 Christopher Armstrong - - * .: Releasing Twisted 1.1.0alpha3. - -2003-10-16 Brian Warner - - * doc/howto/pb-cred.xhtml: update for newcred. Closes issue172. - -2003-10-15 Brian Warner - - * twisted/internet/base.py: add optional debug code, enabled with - base.DelayedCall.debug=True . If active, the call stack which - invoked reactor.callLater will be recorded in each DelayedCall. If - an exception happens when the timer function is run, the creator - stack will be logged in addition to the usual log.deferr(). - - * twisted/internet/defer.py: add some optional debug code, enabled - with defer.Deferred.debug=True . If active, it will record a stack - trace when the Deferred is created, and another when it is first - invoked. AlreadyCalledErrors will be given these two stack traces, - making it slightly easier to find the source of the problem. - -2003-10-15 Christopher Armstrong - - * .: Releasing Twisted 1.1.0alpha2 (alpha1 was dead in the water). - -2003-10-15 Brian Warner - - * setup.py: remove cReactor/ to the sandbox. Closes issue318. - -2003-10-14 Itamar Shtull-Trauring - - * twisted/web/static.py: registry no longer has support for - getting services based on their interfaces. - -2003-10-14 Christopher Armstrong - - * .: Releasing Twisted 1.1.0alpha1. - -2003-10-13 Bob Ippolito - - * doc/howto/choosing-reactor.xhtml: - Added cfreactor/Cocoa information. - - * doc/examples/cocoaDemo: - Removed, replaced by doc/examples/Cocoa cfreactor demos. - - * doc/examples/Cocoa: - Moved from sandbox/etrepum/examples/PyObjC, cleaned up. - - * twisted/internet/cfsupport, twisted/internet/cfreactor.py: - Moved from sandbox/etrepum, cleaned up. - - * twisted/application/app.py: - Added 'cf' -> twisted.internet.cfreactor to reactorTypes - - * setup.py: - sys.platform=='darwin' - build cfsupport, do not build cReactor. - - * INSTALL: - Changed URL of pimp repository to shorter version. - -2003-10-12 Jp Calderone - - * bin/tktwistd, twisted/scripts/tktwistd.py, doc/man/tktwistd.1: - Removed. - -2003-10-12 Itamar Shtull-Trauring - - * twisted/spread/pb.py: Perspective Broker no longer sends - detailed tracebacks over the wire unless the "unsafeTracebacks" - attribute is set of the factory. - -2003-10-02 Jp Calderone - - * setup.py, twisted/test/test_dir.py, twisted/python/_c_dir.c: - Removed _c_dir extension module for portability and maintenance - reasons. - -2003-10-03 Moshe Zadka - - * twisted/spread/util.py twisted/test/test_spread.py: Fix issue - 286 - -2003-10-01 Brian Warner - - * twisted/web/client.py (HTTPDownloader): accept either a filename - or a file-like object (it must respond to .write and .close, and - partial requests will not be used with file-like objects). errback - the deferred if an IOError occurs in .open, .write. or .close, - usually something like "permission denied" or "file system full". - Closes issue234. - * twisted/test/test_webclient.py (WebClientTestCase.write): verify - that the errback gets called - - * twisted/scripts/trial.py (run): add --until-failure option to - re-run the test until something fails. Closes issue87. - -2003-09-30 Brian Warner - - * twisted/test/test_conch.py (testOurServerOpenSSHClient): replace - reactor.run() with .iterate calls: when using .run, exceptions in - the server cause a hang. - -2003-9-29 Moshe Zadka - - * twisted/tap/procmon.py twisted/plugins.tml: remove procmon - tap. It was crufty and hard to port properly to new application. - -2003-09-29 Brian Warner - - * twisted/scripts/trial.py (Options.opt_reactor): make trial - accept the same reactor-name abbreviations as twistd does. Closes - issue69. - (top): add test-case-name tag - - * doc/man/trial.1: document the change - -2003-09-28 Christopher Armstrong - - * .: Releasing Twisted 1.0.8alpha3. - -2003-09-27 Cory Dodt - - * win32/main.aap win32/pyx.x-foo.iss.template win32/README.win32: - Be nice to people who don't install Python for "All Users" on win32. - -2003-9-18 Moshe Zadka - - * twisted/application/strports.py twisted/test/test_strports.py: - New API/mini-language for defining ports - -2003-9-18 Moshe Zadka - - * twisted/web/spider.py: removed, it was unmaintained. - -2003-09-19 Christopher Armstrong - - * twisted/names/authority.py twisted/test/test_names.py - twisted/protocols/dns.py: Client and server support for TTLs on - all records. All Record_* types now take a ttl= keyword - argument. You can pass the ttl= argument to all the record classes - in your pyzones, too. - -2003-09-19 Moshe Zadka - - * twisted/application/__init__.py twisted/application/app.py - twisted/application/compat.py twisted/application/internet.py - twisted/application/service.py twisted/scripts/twistd.py - twisted/scripts/twistw.py twisted/scripts/mktap.py - twisted/scripts/tapconvert.py bin/twistw: Update to new-style - applications. - -2003-09-19 Jp Calderone - - * twisted/names/client.py: Instantiation of theResolver global made - lazy. As a result importing it directly will now fail if it has not - yet been created. It should not be used directly anymore; instead, - use the module-scope lookup methods, or instantiate your own - resolver. - - * twisted/mail/relaymanager.py: Instantiation of MXCalculator made - lazy. - -2003-09-18 Stephen Thorne - - * twisted/web/distrib.py: Removed dependancy on twisted.web.widgets, and - instead using woven. - -2003-09-18 Stephen Thorne - - * doc/howto/woven-reference.html: Added this new documentation file. - * doc/howto/index.html: Added woven-reference to index - * admin/: Added woven-reference.tex to book.tex - -2003-09-18 Stephen Thorne - - * twisted/web/woven/widgets.py: Stop the 'Option' widget from having a - name="" attribute. Closes issue255. - -2003-09-16 Christopher Armstrong - - * .: Releasing Twisted 1.0.8alpha1. - - * .: Releasing Twisted 1.0.8alpha2 (Fixed Debian packages). - -2003-09-13 Christopher Armstrong - - * .: Releasing Twisted 1.0.7 (no code changes since 1.0.7rc1). - - * twisted/web/vhost.py: Un-gobble the path segment that a vhost eats - when the resource we're wrapping isLeaf. Potentially closes issue125. - -2003-09-12 Itamar Shtull-Trauring - - * twisted/web/microdom.py: lenient mode correctly handles - # tidy does this, for example. - prefix = "" - oldvalue = c.value - match = self.COMMENT.match(oldvalue) - if match: - prefix = match.group() - oldvalue = oldvalue[len(prefix):] - - # now see if contents are actual node and comment or CDATA - try: - e = parseString("%s" % oldvalue).childNodes[0] - except (ParseError, MismatchedTags): - return - if len(e.childNodes) != 1: - return - e = e.firstChild() - if isinstance(e, (CDATASection, Comment)): - el.childNodes = [] - if prefix: - el.childNodes.append(Text(prefix)) - el.childNodes.append(e) - - def gotDoctype(self, doctype): - self._mddoctype = doctype - - def gotTagStart(self, name, attributes): - # print ' '*self.indentlevel, 'start tag',name - # self.indentlevel += 1 - parent = self._getparent() - if (self.beExtremelyLenient and isinstance(parent, Element)): - parentName = parent.tagName - myName = name - if self.caseInsensitive: - parentName = parentName.lower() - myName = myName.lower() - if myName in self.laterClosers.get(parentName, []): - self.gotTagEnd(parent.tagName) - parent = self._getparent() - attributes = _unescapeDict(attributes) - namespaces = self.nsstack[-1][0] - newspaces = {} - for k, v in attributes.items(): - if k.startswith('xmlns'): - spacenames = k.split(':',1) - if len(spacenames) == 2: - newspaces[spacenames[1]] = v - else: - newspaces[''] = v - del attributes[k] - if newspaces: - namespaces = namespaces.copy() - namespaces.update(newspaces) - for k, v in attributes.items(): - ksplit = k.split(':', 1) - if len(ksplit) == 2: - pfx, tv = ksplit - if pfx != 'xml' and namespaces.has_key(pfx): - attributes[namespaces[pfx], tv] = v - del attributes[k] - el = Element(name, attributes, parent, - self.filename, self.saveMark(), - caseInsensitive=self.caseInsensitive, - preserveCase=self.preserveCase, - namespace=namespaces.get('')) - revspaces = _reverseDict(newspaces) - el.addPrefixes(revspaces) - - if newspaces: - rscopy = self.nsstack[-1][2].copy() - rscopy.update(revspaces) - self.nsstack.append((namespaces, el, rscopy)) - self.elementstack.append(el) - if parent: - parent.appendChild(el) - if (self.beExtremelyLenient and el.tagName in self.soonClosers): - self.gotTagEnd(name) - - def _gotStandalone(self, factory, data): - parent = self._getparent() - te = factory(data, parent) - if parent: - parent.appendChild(te) - elif self.beExtremelyLenient: - self.documents.append(te) - - def gotText(self, data): - if data.strip() or self.shouldPreserveSpace(): - self._gotStandalone(Text, data) - - def gotComment(self, data): - self._gotStandalone(Comment, data) - - def gotEntityReference(self, entityRef): - self._gotStandalone(EntityReference, entityRef) - - def gotCData(self, cdata): - self._gotStandalone(CDATASection, cdata) - - def gotTagEnd(self, name): - # print ' '*self.indentlevel, 'end tag',name - # self.indentlevel -= 1 - if not self.elementstack: - if self.beExtremelyLenient: - return - raise MismatchedTags(*((self.filename, "NOTHING", name) - +self.saveMark()+(0,0))) - el = self.elementstack.pop() - pfxdix = self.nsstack[-1][2] - if self.nsstack[-1][1] is el: - nstuple = self.nsstack.pop() - else: - nstuple = None - if self.caseInsensitive: - tn = el.tagName.lower() - cname = name.lower() - else: - tn = el.tagName - cname = name - - nsplit = name.split(':',1) - if len(nsplit) == 2: - pfx, newname = nsplit - ns = pfxdix.get(pfx,None) - if ns is not None: - if el.namespace != ns: - if not self.beExtremelyLenient: - raise MismatchedTags(*((self.filename, el.tagName, name) - +self.saveMark()+el._markpos)) - if not (tn == cname): - if self.beExtremelyLenient: - if self.elementstack: - lastEl = self.elementstack[0] - for idx in xrange(len(self.elementstack)): - if self.elementstack[-(idx+1)].tagName == cname: - self.elementstack[-(idx+1)].endTag(name) - break - else: - # this was a garbage close tag; wait for a real one - self.elementstack.append(el) - if nstuple is not None: - self.nsstack.append(nstuple) - return - del self.elementstack[-(idx+1):] - if not self.elementstack: - self.documents.append(lastEl) - return - else: - raise MismatchedTags(*((self.filename, el.tagName, name) - +self.saveMark()+el._markpos)) - el.endTag(name) - if not self.elementstack: - self.documents.append(el) - if self.beExtremelyLenient and el.tagName == "script": - self._fixScriptElement(el) - - def connectionLost(self, reason): - XMLParser.connectionLost(self, reason) # This can cause more events! - if self.elementstack: - if self.beExtremelyLenient: - self.documents.append(self.elementstack[0]) - else: - raise MismatchedTags(*((self.filename, self.elementstack[-1], - "END_OF_FILE") - +self.saveMark() - +self.elementstack[-1]._markpos)) - - -def parse(readable, *args, **kwargs): - """Parse HTML or XML readable.""" - if not hasattr(readable, "read"): - readable = open(readable, "rb") - mdp = MicroDOMParser(*args, **kwargs) - mdp.filename = getattr(readable, "name", "") - mdp.makeConnection(None) - if hasattr(readable,"getvalue"): - mdp.dataReceived(readable.getvalue()) - else: - r = readable.read(1024) - while r: - mdp.dataReceived(r) - r = readable.read(1024) - mdp.connectionLost(None) - - if not mdp.documents: - raise ParseError(mdp.filename, 0, 0, "No top-level Nodes in document") - - if mdp.beExtremelyLenient: - if len(mdp.documents) == 1: - d = mdp.documents[0] - if not isinstance(d, Element): - el = Element("html") - el.appendChild(d) - d = el - else: - d = Element("html") - for child in mdp.documents: - d.appendChild(child) - else: - d = mdp.documents[0] - doc = Document(d) - doc.doctype = mdp._mddoctype - return doc - -def parseString(st, *args, **kw): - if isinstance(st, UnicodeType): - # this isn't particularly ideal, but it does work. - return parse(StringIO(st.encode('UTF-16')), *args, **kw) - return parse(StringIO(st), *args, **kw) - - -def parseXML(readable): - """Parse an XML readable object.""" - return parse(readable, caseInsensitive=0, preserveCase=1) - - -def parseXMLString(st): - """Parse an XML readable object.""" - return parseString(st, caseInsensitive=0, preserveCase=1) - - -# Utility - -class lmx: - """Easy creation of XML.""" - - def __init__(self, node='div'): - if isinstance(node, StringTypes): - node = Element(node) - self.node = node - - def __getattr__(self, name): - if name[0] == '_': - raise AttributeError("no private attrs") - return lambda **kw: self.add(name,**kw) - - def __setitem__(self, key, val): - self.node.setAttribute(key, val) - - def __getitem__(self, key): - return self.node.getAttribute(key) - - def text(self, txt, raw=0): - nn = Text(txt, raw=raw) - self.node.appendChild(nn) - return self - - def add(self, tagName, **kw): - newNode = Element(tagName, caseInsensitive=0, preserveCase=0) - self.node.appendChild(newNode) - xf = lmx(newNode) - for k, v in kw.items(): - if k[0] == '_': - k = k[1:] - xf[k]=v - return xf diff --git a/tools/buildbot/pylibs/twisted/web/monitor.py b/tools/buildbot/pylibs/twisted/web/monitor.py deleted file mode 100644 index 052e94c..0000000 --- a/tools/buildbot/pylibs/twisted/web/monitor.py +++ /dev/null @@ -1,85 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -from twisted.web import client -from twisted.internet import reactor -import md5 -from zope.interface import implements - -class IChangeNotified: - pass - -class BaseChangeNotified: - - implements(IChangeNotified) - - def reportChange(self, old, new): - pass - - def reportNoChange(self): - pass - -class ChangeChecker: - - working = 0 - call = None - - def __init__(self, notified, url, delay=60): - self.notified = notified - self.url = url - self.md5 = None - self.delay = delay - - def start(self): - self.working = 1 - self._getPage() - - def stop(self): - if self.call: - self.call.cancel() - self.call = None - self.working = 0 - - def _getPage(self): - d = client.getPage(self.url) - d.addErrback(self.noPage) - d.addCallback(self.page) - self.call = None - - def noPage(self, e): - self.gotMD5(None) - - def page(self, p): - if p is None: - return self.gotMD5(None) - m = md5.new() - m.update(p) - self.gotMD5(m.digest()) - - def gotMD5(self, md5): - if not self.working: - return - if md5 != self.md5: - self.notified.reportChange(self.md5, md5) - self.md5 = md5 - else: - self.notified.reportNoChange() - if not self.call: - self.call = reactor.callLater(self.delay, self._getPage) - - -class ProxyChangeChecker(ChangeChecker): - - def __init__(self, proxyHost, proxyPort, notified, url, delay=60): - self.proxyHost = proxyHost - self.proxyPort = proxyPort - ChangeChecker.__init__(self, notified, url, delay) - - def _getPage(self): - factory = client.HTTPClientFactory(self.proxyHost, self.url) - factory.headers = {'pragma': 'no-cache'} - reactor.connectTCP(self.proxyHost, self.proxyPort, factory) - d = factory.deferred - d.addErrback(self.noPage) - d.addCallback(self.page) diff --git a/tools/buildbot/pylibs/twisted/web/proxy.py b/tools/buildbot/pylibs/twisted/web/proxy.py deleted file mode 100644 index 98e5c41..0000000 --- a/tools/buildbot/pylibs/twisted/web/proxy.py +++ /dev/null @@ -1,283 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_proxy -*- -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Simplistic HTTP proxy support. - -This comes in two main variants - the Proxy and the ReverseProxy. - -When a Proxy is in use, a browser trying to connect to a server (say, -www.yahoo.com) will be intercepted by the Proxy, and the proxy will covertly -connect to the server, and return the result. - -When a ReverseProxy is in use, the client connects directly to the ReverseProxy -(say, www.yahoo.com) which farms off the request to one of a pool of servers, -and returns the result. - -Normally, a Proxy is used on the client end of an Internet connection, while a -ReverseProxy is used on the server end. -""" - -import urlparse -from urllib import quote as urlquote - -from twisted.internet import reactor -from twisted.internet.protocol import ClientFactory -from twisted.web.resource import Resource -from twisted.web.server import NOT_DONE_YET -from twisted.web.http import HTTPClient, Request, HTTPChannel - - - -class ProxyClient(HTTPClient): - """ - Used by ProxyClientFactory to implement a simple web proxy. - """ - - def __init__(self, command, rest, version, headers, data, father): - self.father = father - self.command = command - self.rest = rest - if "proxy-connection" in headers: - del headers["proxy-connection"] - headers["connection"] = "close" - self.headers = headers - self.data = data - - - def connectionMade(self): - self.sendCommand(self.command, self.rest) - for header, value in self.headers.items(): - self.sendHeader(header, value) - self.endHeaders() - self.transport.write(self.data) - - - def handleStatus(self, version, code, message): - if message: - # Add a whitespace to message, this allows empty messages - # transparently - message = " %s" % (message,) - self.father.transport.write("%s %s%s\r\n" % (version, code, message)) - - - def handleHeader(self, key, value): - self.father.transport.write("%s: %s\r\n" % (key, value)) - - - def handleEndHeaders(self): - self.father.transport.write("\r\n") - - - def handleResponsePart(self, buffer): - self.father.transport.write(buffer) - - - def handleResponseEnd(self): - self.transport.loseConnection() - self.father.channel.transport.loseConnection() - - - -class ProxyClientFactory(ClientFactory): - """ - Used by ProxyRequest to implement a simple web proxy. - """ - - protocol = ProxyClient - - - def __init__(self, command, rest, version, headers, data, father): - self.father = father - self.command = command - self.rest = rest - self.headers = headers - self.data = data - self.version = version - - - def buildProtocol(self, addr): - return self.protocol(self.command, self.rest, self.version, - self.headers, self.data, self.father) - - - def clientConnectionFailed(self, connector, reason): - self.father.transport.write("HTTP/1.0 501 Gateway error\r\n") - self.father.transport.write("Content-Type: text/html\r\n") - self.father.transport.write("\r\n") - self.father.transport.write('''

                  Could not connect

                  ''') - self.father.transport.loseConnection() - - - -class ProxyRequest(Request): - """ - Used by Proxy to implement a simple web proxy. - - @ivar reactor: the reactor used to create connections. - @type reactor: object providing L{twisted.internet.interfaces.IReactorTCP} - """ - - protocols = {'http': ProxyClientFactory} - ports = {'http': 80} - - def __init__(self, channel, queued, reactor=reactor): - Request.__init__(self, channel, queued) - self.reactor = reactor - - - def process(self): - parsed = urlparse.urlparse(self.uri) - protocol = parsed[0] - host = parsed[1] - port = self.ports[protocol] - if ':' in host: - host, port = host.split(':') - port = int(port) - rest = urlparse.urlunparse(('', '') + parsed[2:]) - if not rest: - rest = rest + '/' - class_ = self.protocols[protocol] - headers = self.getAllHeaders().copy() - if 'host' not in headers: - headers['host'] = host - self.content.seek(0, 0) - s = self.content.read() - clientFactory = class_(self.method, rest, self.clientproto, headers, - s, self) - self.reactor.connectTCP(host, port, clientFactory) - - - -class Proxy(HTTPChannel): - """ - This class implements a simple web proxy. - - Since it inherits from L{twisted.protocols.http.HTTPChannel}, to use it you - should do something like this:: - - from twisted.web import http - f = http.HTTPFactory() - f.protocol = Proxy - - Make the HTTPFactory a listener on a port as per usual, and you have - a fully-functioning web proxy! - """ - - requestFactory = ProxyRequest - - - -class ReverseProxyRequest(Request): - """ - Used by ReverseProxy to implement a simple reverse proxy. - - @ivar proxyClientFactoryClass: a proxy client factory class, used to create - new connections. - @type proxyClientFactoryClass: L{ClientFactory} - - @ivar reactor: the reactor used to create connections. - @type reactor: object providing L{twisted.internet.interfaces.IReactorTCP} - """ - - proxyClientFactoryClass = ProxyClientFactory - - def __init__(self, channel, queued, reactor=reactor): - Request.__init__(self, channel, queued) - self.reactor = reactor - - - def process(self): - self.received_headers['host'] = self.factory.host - clientFactory = self.proxyClientFactoryClass( - self.method, self.uri, self.clientproto, self.getAllHeaders(), - self.content.read(), self) - self.reactor.connectTCP(self.factory.host, self.factory.port, - clientFactory) - - - -class ReverseProxy(HTTPChannel): - """ - Implements a simple reverse proxy. - - For details of usage, see the file examples/proxy.py. - """ - - requestFactory = ReverseProxyRequest - - - -class ReverseProxyResource(Resource): - """ - Resource that renders the results gotten from another server - - Put this resource in the tree to cause everything below it to be relayed - to a different server. - - @ivar proxyClientFactoryClass: a proxy client factory class, used to create - new connections. - @type proxyClientFactoryClass: L{ClientFactory} - - @ivar reactor: the reactor used to create connections. - @type reactor: object providing L{twisted.internet.interfaces.IReactorTCP} - """ - - proxyClientFactoryClass = ProxyClientFactory - - - def __init__(self, host, port, path, reactor=reactor): - """ - @param host: the host of the web server to proxy. - @type host: C{str} - - @param port: the port of the web server to proxy. - @type port: C{port} - - @param path: the base path to fetch data from. Note that you shouldn't - put any trailing slashes in it, it will be added automatically in - request. For example, if you put B{/foo}, a request on B{/bar} will - be proxied to B{/foo/bar}. Any required encoding of special - characters (such as " " or "/") should have been done already. - - @type path: C{str} - """ - Resource.__init__(self) - self.host = host - self.port = port - self.path = path - self.reactor = reactor - - - def getChild(self, path, request): - """ - Create and return a proxy resource with the same proxy configuration - as this one, except that its path also contains the segment given by - C{path} at the end. - """ - return ReverseProxyResource( - self.host, self.port, self.path + '/' + urlquote(path, safe="")) - - - def render(self, request): - """ - Render a request by forwarding it to the proxied server. - """ - # RFC 2616 tells us that we can omit the port if it's the default port, - # but we have to provide it otherwise - if self.port == 80: - request.received_headers['host'] = self.host - else: - request.received_headers['host'] = "%s:%d" % (self.host, self.port) - request.content.seek(0, 0) - qs = urlparse.urlparse(request.uri)[4] - if qs: - rest = self.path + '?' + qs - else: - rest = self.path - clientFactory = self.proxyClientFactoryClass( - request.method, rest, request.clientproto, - request.getAllHeaders(), request.content.read(), request) - self.reactor.connectTCP(self.host, self.port, clientFactory) - return NOT_DONE_YET diff --git a/tools/buildbot/pylibs/twisted/web/resource.py b/tools/buildbot/pylibs/twisted/web/resource.py deleted file mode 100644 index 0becb8d..0000000 --- a/tools/buildbot/pylibs/twisted/web/resource.py +++ /dev/null @@ -1,204 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_web -*- -# -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""I hold the lowest-level Resource class.""" - - -# System Imports -from twisted.internet import defer -from twisted.python import roots, reflect -from zope.interface import Attribute, implements, Interface - -class IResource(Interface): - """A web resource.""" - - isLeaf = Attribute(\ -"""Signal if this IResource implementor is a "leaf node" or not. If True, -getChildWithDefault will not be called on this Resource.""") - - def getChildWithDefault(name, request): - """Return a child with the given name for the given request. - This is the external interface used by the Resource publishing - machinery. If implementing IResource without subclassing - Resource, it must be provided. However, if subclassing Resource, - getChild overridden instead. - """ - - def putChild(path, child): - """Put a child IResource implementor at the given path. - """ - - def render(request): - """Render a request. This is called on the leaf resource for - a request. Render must return either a string, which will - be sent to the browser as the HTML for the request, or - server.NOT_DONE_YET. If NOT_DONE_YET is returned, - at some point later (in a Deferred callback, usually) - call request.write("") to write data to the request, - and request.finish() to send the data to the browser. - """ - - -def getChildForRequest(resource, request): - """Traverse resource tree to find who will handle the request.""" - while request.postpath and not resource.isLeaf: - pathElement = request.postpath.pop(0) - request.prepath.append(pathElement) - resource = resource.getChildWithDefault(pathElement, request) - return resource - - -class Resource: - """I define a web-accessible resource. - - I serve 2 main purposes; one is to provide a standard representation for - what HTTP specification calls an 'entity', and the other is to provide an - abstract directory structure for URL retrieval. - """ - - implements(IResource) - - entityType = IResource - - server = None - - def __init__(self): - """Initialize. - """ - self.children = {} - - isLeaf = 0 - - ### Abstract Collection Interface - - def listStaticNames(self): - return self.children.keys() - - def listStaticEntities(self): - return self.children.items() - - def listNames(self): - return self.listStaticNames() + self.listDynamicNames() - - def listEntities(self): - return self.listStaticEntities() + self.listDynamicEntities() - - def listDynamicNames(self): - return [] - - def listDynamicEntities(self, request=None): - return [] - - def getStaticEntity(self, name): - return self.children.get(name) - - def getDynamicEntity(self, name, request): - if not self.children.has_key(name): - return self.getChild(name, request) - else: - return None - - def delEntity(self, name): - del self.children[name] - - def reallyPutEntity(self, name, entity): - self.children[name] = entity - - # Concrete HTTP interface - - def getChild(self, path, request): - """Retrieve a 'child' resource from me. - - Implement this to create dynamic resource generation -- resources which - are always available may be registered with self.putChild(). - - This will not be called if the class-level variable 'isLeaf' is set in - your subclass; instead, the 'postpath' attribute of the request will be - left as a list of the remaining path elements. - - For example, the URL /foo/bar/baz will normally be:: - - | site.resource.getChild('foo').getChild('bar').getChild('baz'). - - However, if the resource returned by 'bar' has isLeaf set to true, then - the getChild call will never be made on it. - - @param path: a string, describing the child - - @param request: a twisted.web.server.Request specifying meta-information - about the request that is being made for this child. - """ - return error.NoResource("No such child resource.") - - def getChildWithDefault(self, path, request): - """Retrieve a static or dynamically generated child resource from me. - - First checks if a resource was added manually by putChild, and then - call getChild to check for dynamic resources. Only override if you want - to affect behaviour of all child lookups, rather than just dynamic - ones. - - This will check to see if I have a pre-registered child resource of the - given name, and call getChild if I do not. - """ - if self.children.has_key(path): - return self.children[path] - - return self.getChild(path, request) - - def getChildForRequest(self, request): - import warnings - warnings.warn("Please use module level getChildForRequest.", DeprecationWarning, 2) - return getChildForRequest(self, request) - - def putChild(self, path, child): - """Register a static child. - - You almost certainly don't want '/' in your path. If you - intended to have the root of a folder, e.g. /foo/, you want - path to be ''. - """ - self.children[path] = child - child.server = self.server - - def render(self, request): - """Render a given resource. See L{IResource}'s render method. - - I delegate to methods of self with the form 'render_METHOD' - where METHOD is the HTTP that was used to make the - request. Examples: render_GET, render_HEAD, render_POST, and - so on. Generally you should implement those methods instead of - overriding this one. - - render_METHOD methods are expected to return a string which - will be the rendered page, unless the return value is - twisted.web.server.NOT_DONE_YET, in which case it is this - class's responsibility to write the results to - request.write(data), then call request.finish(). - - Old code that overrides render() directly is likewise expected - to return a string or NOT_DONE_YET. - """ - m = getattr(self, 'render_' + request.method, None) - if not m: - from twisted.web.server import UnsupportedMethod - raise UnsupportedMethod(getattr(self, 'allowedMethods', ())) - return m(request) - - def render_HEAD(self, request): - """Default handling of HEAD method. - - I just return self.render_GET(request). When method is HEAD, - the framework will handle this correctly. - """ - return self.render_GET(request) - - -#t.w imports -#This is ugly, I know, but since error.py directly access resource.Resource -#during import-time (it subclasses it), the Resource class must be defined -#by the time error is imported. -import error diff --git a/tools/buildbot/pylibs/twisted/web/rewrite.py b/tools/buildbot/pylibs/twisted/web/rewrite.py deleted file mode 100644 index b41ca00..0000000 --- a/tools/buildbot/pylibs/twisted/web/rewrite.py +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -from twisted.web import resource - -class RewriterResource(resource.Resource): - - def __init__(self, orig, *rewriteRules): - resource.Resource.__init__(self) - self.resource = orig - self.rewriteRules = list(rewriteRules) - - def _rewrite(self, request): - for rewriteRule in self.rewriteRules: - rewriteRule(request) - - def getChild(self, path, request): - request.postpath.insert(0, path) - request.prepath.pop() - self._rewrite(request) - path = request.postpath.pop(0) - request.prepath.append(path) - return self.resource.getChildWithDefault(path, request) - - def render(self, request): - self._rewrite(request) - return self.resource.render(request) - - -def tildeToUsers(request): - if request.postpath and request.postpath[0][:1]=='~': - request.postpath[:1] = ['users', request.postpath[0][1:]] - request.path = '/'+'/'.join(request.prepath+request.postpath) - -def alias(aliasPath, sourcePath): - """ - I am not a very good aliaser. But I'm the best I can be. If I'm - aliasing to a Resource that generates links, and it uses any parts - of request.prepath to do so, the links will not be relative to the - aliased path, but rather to the aliased-to path. That I can't - alias static.File directory listings that nicely. However, I can - still be useful, as many resources will play nice. - """ - sourcePath = sourcePath.split('/') - aliasPath = aliasPath.split('/') - def rewriter(request): - if request.postpath[:len(aliasPath)] == aliasPath: - after = request.postpath[len(aliasPath):] - request.postpath = sourcePath + after - request.path = '/'+'/'.join(request.prepath+request.postpath) - return rewriter diff --git a/tools/buildbot/pylibs/twisted/web/script.py b/tools/buildbot/pylibs/twisted/web/script.py deleted file mode 100644 index d1fae3f..0000000 --- a/tools/buildbot/pylibs/twisted/web/script.py +++ /dev/null @@ -1,163 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""I contain PythonScript, which is a very simple python script resource. -""" - -import server -import resource -import html -import error - -try: - import cStringIO as StringIO -except ImportError: - import StringIO - -from twisted.web import http -from twisted import copyright -import traceback -import os -from twisted.web import resource -from twisted.web import static - -rpyNoResource = """

                  You forgot to assign to the variable "resource" in your script. For example:

                  -
                  -# MyCoolWebApp.rpy
                  -
                  -import mygreatresource
                  -
                  -resource = mygreatresource.MyGreatResource()
                  -
                  -""" - -class AlreadyCached(Exception): - """This exception is raised when a path has already been cached. - """ - -class CacheScanner: - def __init__(self, path, registry): - self.path = path - self.registry = registry - self.doCache = 0 - - def cache(self): - c = self.registry.getCachedPath(self.path) - if c is not None: - raise AlreadyCached(c) - self.recache() - - def recache(self): - self.doCache = 1 - -noRsrc = error.ErrorPage(500, "Whoops! Internal Error", rpyNoResource) - -def ResourceScript(path, registry): - """ - I am a normal py file which must define a 'resource' global, which should - be an instance of (a subclass of) web.resource.Resource; it will be - renderred. - """ - cs = CacheScanner(path, registry) - glob = {'__file__': path, - 'resource': noRsrc, - 'registry': registry, - 'cache': cs.cache, - 'recache': cs.recache} - try: - execfile(path, glob, glob) - except AlreadyCached, ac: - return ac.args[0] - rsrc = glob['resource'] - if cs.doCache and rsrc is not noRsrc: - registry.cachePath(path, rsrc) - return rsrc - -def ResourceTemplate(path, registry): - from quixote import ptl_compile - - glob = {'__file__': path, - 'resource': error.ErrorPage(500, "Whoops! Internal Error", - rpyNoResource), - 'registry': registry} - - e = ptl_compile.compile_template(open(path), path) - exec e in glob - return glob['resource'] - - -class ResourceScriptWrapper(resource.Resource): - - def __init__(self, path, registry=None): - resource.Resource.__init__(self) - self.path = path - self.registry = registry or static.Registry() - - def render(self, request): - res = ResourceScript(self.path, self.registry) - return res.render(request) - - def getChildWithDefault(self, path, request): - res = ResourceScript(self.path, self.registry) - return res.getChildWithDefault(path, request) - - - -class ResourceScriptDirectory(resource.Resource): - def __init__(self, pathname, registry=None): - resource.Resource.__init__(self) - self.path = pathname - self.registry = registry or static.Registry() - - def getChild(self, path, request): - fn = os.path.join(self.path, path) - - if os.path.isdir(fn): - return ResourceScriptDirectory(fn, self.registry) - if os.path.exists(fn): - return ResourceScript(fn, self.registry) - return error.NoResource() - - def render(self, request): - return error.NoResource().render(request) - - -class PythonScript(resource.Resource): - """I am an extremely simple dynamic resource; an embedded python script. - - This will execute a file (usually of the extension '.epy') as Python code, - internal to the webserver. - """ - isLeaf = 1 - def __init__(self, filename, registry): - """Initialize me with a script name. - """ - self.filename = filename - self.registry = registry - - def render(self, request): - """Render me to a web client. - - Load my file, execute it in a special namespace (with 'request' and - '__file__' global vars) and finish the request. Output to the web-page - will NOT be handled with print - standard output goes to the log - but - with request.write. - """ - request.setHeader("x-powered-by","Twisted/%s" % copyright.version) - namespace = {'request': request, - '__file__': self.filename, - 'registry': self.registry} - try: - execfile(self.filename, namespace, namespace) - except IOError, e: - if e.errno == 2: #file not found - request.setResponseCode(http.NOT_FOUND) - request.write(error.NoResource("File not found.").render(request)) - except: - io = StringIO.StringIO() - traceback.print_exc(file=io) - request.write(html.PRE(io.getvalue())) - request.finish() - return server.NOT_DONE_YET diff --git a/tools/buildbot/pylibs/twisted/web/server.py b/tools/buildbot/pylibs/twisted/web/server.py deleted file mode 100644 index 9ee9579..0000000 --- a/tools/buildbot/pylibs/twisted/web/server.py +++ /dev/null @@ -1,571 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_web -*- - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""This is a web-server which integrates with the twisted.internet -infrastructure. -""" - -# System Imports - -import string -import types -import operator -import copy -import time -import os -from urllib import quote -try: - from twisted.protocols._c_urlarg import unquote -except ImportError: - from urllib import unquote - -#some useful constants -NOT_DONE_YET = 1 - -# Twisted Imports -from twisted.spread import pb -from twisted.internet import defer, address, task -from twisted.web import http -from twisted.python import log, reflect, failure, components -from twisted import copyright - -# Sibling Imports -import error, resource -from twisted.web import util as webutil - - -# backwards compatability -date_time_string = http.datetimeToString -string_date_time = http.stringToDatetime - -# Support for other methods may be implemented on a per-resource basis. -supportedMethods = ('GET', 'HEAD', 'POST') - - -class UnsupportedMethod(Exception): - """Raised by a resource when faced with a strange request method. - - RFC 2616 (HTTP 1.1) gives us two choices when faced with this situtation: - If the type of request is known to us, but not allowed for the requested - resource, respond with NOT_ALLOWED. Otherwise, if the request is something - we don't know how to deal with in any case, respond with NOT_IMPLEMENTED. - - When this exception is raised by a Resource's render method, the server - will make the appropriate response. - - This exception's first argument MUST be a sequence of the methods the - resource *does* support. - """ - - allowedMethods = () - - def __init__(self, allowedMethods, *args): - Exception.__init__(self, allowedMethods, *args) - self.allowedMethods = allowedMethods - - if not operator.isSequenceType(allowedMethods): - why = "but my first argument is not a sequence." - s = ("First argument must be a sequence of" - " supported methods, %s" % (why,)) - raise TypeError, s - -def _addressToTuple(addr): - if isinstance(addr, address.IPv4Address): - return ('INET', addr.host, addr.port) - elif isinstance(addr, address.UNIXAddress): - return ('UNIX', addr.name) - else: - return tuple(addr) - -class Request(pb.Copyable, http.Request, components.Componentized): - - site = None - appRootURL = None - __pychecker__ = 'unusednames=issuer' - - def __init__(self, *args, **kw): - http.Request.__init__(self, *args, **kw) - components.Componentized.__init__(self) - self.notifications = [] - - def getStateToCopyFor(self, issuer): - x = self.__dict__.copy() - del x['transport'] - # XXX refactor this attribute out; it's from protocol - # del x['server'] - del x['channel'] - del x['content'] - del x['site'] - self.content.seek(0, 0) - x['content_data'] = self.content.read() - x['remote'] = pb.ViewPoint(issuer, self) - - # Address objects aren't jellyable - x['host'] = _addressToTuple(x['host']) - x['client'] = _addressToTuple(x['client']) - - return x - - # HTML generation helpers - - def sibLink(self, name): - "Return the text that links to a sibling of the requested resource." - if self.postpath: - return (len(self.postpath)*"../") + name - else: - return name - - def childLink(self, name): - "Return the text that links to a child of the requested resource." - lpp = len(self.postpath) - if lpp > 1: - return ((lpp-1)*"../") + name - elif lpp == 1: - return name - else: # lpp == 0 - if len(self.prepath) and self.prepath[-1]: - return self.prepath[-1] + '/' + name - else: - return name - - def process(self): - "Process a request." - - # get site from channel - self.site = self.channel.site - - # set various default headers - self.setHeader('server', version) - self.setHeader('date', http.datetimeToString()) - self.setHeader('content-type', "text/html") - - # Resource Identification - self.prepath = [] - self.postpath = map(unquote, string.split(self.path[1:], '/')) - try: - resrc = self.site.getResourceFor(self) - self.render(resrc) - except: - self.processingFailed(failure.Failure()) - - - def render(self, resrc): - try: - body = resrc.render(self) - except UnsupportedMethod, e: - allowedMethods = e.allowedMethods - if (self.method == "HEAD") and ("GET" in allowedMethods): - # We must support HEAD (RFC 2616, 5.1.1). If the - # resource doesn't, fake it by giving the resource - # a 'GET' request and then return only the headers, - # not the body. - log.msg("Using GET to fake a HEAD request for %s" % - (resrc,)) - self.method = "GET" - body = resrc.render(self) - - if body is NOT_DONE_YET: - log.msg("Tried to fake a HEAD request for %s, but " - "it got away from me." % resrc) - # Oh well, I guess we won't include the content length. - else: - self.setHeader('content-length', str(len(body))) - - self.write('') - self.finish() - return - - if self.method in (supportedMethods): - # We MUST include an Allow header - # (RFC 2616, 10.4.6 and 14.7) - self.setHeader('Allow', allowedMethods) - s = ('''Your browser approached me (at %(URI)s) with''' - ''' the method "%(method)s". I only allow''' - ''' the method%(plural)s %(allowed)s here.''' % { - 'URI': self.uri, - 'method': self.method, - 'plural': ((len(allowedMethods) > 1) and 's') or '', - 'allowed': string.join(allowedMethods, ', ') - }) - epage = error.ErrorPage(http.NOT_ALLOWED, - "Method Not Allowed", s) - body = epage.render(self) - else: - epage = error.ErrorPage(http.NOT_IMPLEMENTED, "Huh?", - """I don't know how to treat a""" - """ %s request.""" - % (self.method)) - body = epage.render(self) - # end except UnsupportedMethod - - if body == NOT_DONE_YET: - return - if type(body) is not types.StringType: - body = error.ErrorPage(http.INTERNAL_SERVER_ERROR, - "Request did not return a string", - "Request: "+html.PRE(reflect.safe_repr(self))+"
                  "+ - "Resource: "+html.PRE(reflect.safe_repr(resrc))+"
                  "+ - "Value: "+html.PRE(reflect.safe_repr(body))).render(self) - - if self.method == "HEAD": - if len(body) > 0: - # This is a Bad Thing (RFC 2616, 9.4) - log.msg("Warning: HEAD request %s for resource %s is" - " returning a message body." - " I think I'll eat it." - % (self, resrc)) - self.setHeader('content-length', str(len(body))) - self.write('') - else: - self.setHeader('content-length', str(len(body))) - self.write(body) - self.finish() - - def processingFailed(self, reason): - log.err(reason) - if self.site.displayTracebacks: - body = ("web.Server Traceback (most recent call last)" - "web.Server Traceback (most recent call last):\n\n" - "%s\n\n\n" - % webutil.formatFailure(reason)) - else: - body = ("Processing Failed" - "Processing Failed") - - self.setResponseCode(http.INTERNAL_SERVER_ERROR) - self.setHeader('content-type',"text/html") - self.setHeader('content-length', str(len(body))) - self.write(body) - self.finish() - return reason - - def notifyFinish(self): - """Notify when finishing the request - - @return: A deferred. The deferred will be triggered when the - request is finished -- with a C{None} value if the request - finishes successfully or with an error if the request is stopped - by the client. - """ - self.notifications.append(defer.Deferred()) - return self.notifications[-1] - - def connectionLost(self, reason): - for d in self.notifications: - d.errback(reason) - self.notifications = [] - - def finish(self): - http.Request.finish(self) - for d in self.notifications: - d.callback(None) - self.notifications = [] - - def view_write(self, issuer, data): - """Remote version of write; same interface. - """ - self.write(data) - - def view_finish(self, issuer): - """Remote version of finish; same interface. - """ - self.finish() - - def view_addCookie(self, issuer, k, v, **kwargs): - """Remote version of addCookie; same interface. - """ - self.addCookie(k, v, **kwargs) - - def view_setHeader(self, issuer, k, v): - """Remote version of setHeader; same interface. - """ - self.setHeader(k, v) - - def view_setLastModified(self, issuer, when): - """Remote version of setLastModified; same interface. - """ - self.setLastModified(when) - - def view_setETag(self, issuer, tag): - """Remote version of setETag; same interface. - """ - self.setETag(tag) - - def view_setResponseCode(self, issuer, code): - """Remote version of setResponseCode; same interface. - """ - self.setResponseCode(code) - - def view_registerProducer(self, issuer, producer, streaming): - """Remote version of registerProducer; same interface. - (requires a remote producer.) - """ - self.registerProducer(_RemoteProducerWrapper(producer), streaming) - - def view_unregisterProducer(self, issuer): - self.unregisterProducer() - - ### these calls remain local - - session = None - - def getSession(self, sessionInterface = None): - # Session management - if not self.session: - cookiename = string.join(['TWISTED_SESSION'] + self.sitepath, "_") - sessionCookie = self.getCookie(cookiename) - if sessionCookie: - try: - self.session = self.site.getSession(sessionCookie) - except KeyError: - pass - # if it still hasn't been set, fix it up. - if not self.session: - self.session = self.site.makeSession() - self.addCookie(cookiename, self.session.uid, path='/') - self.session.touch() - if sessionInterface: - return self.session.getComponent(sessionInterface) - return self.session - - def _prePathURL(self, prepath): - port = self.getHost().port - if self.isSecure(): - default = 443 - else: - default = 80 - if port == default: - hostport = '' - else: - hostport = ':%d' % port - return 'http%s://%s%s/%s' % ( - self.isSecure() and 's' or '', - self.getRequestHostname(), - hostport, - '/'.join([quote(segment, safe='') for segment in prepath])) - - def prePathURL(self): - return self._prePathURL(self.prepath) - - def URLPath(self): - from twisted.python import urlpath - return urlpath.URLPath.fromRequest(self) - - def rememberRootURL(self): - """ - Remember the currently-processed part of the URL for later - recalling. - """ - url = self._prePathURL(self.prepath[:-1]) - self.appRootURL = url - - def getRootURL(self): - """ - Get a previously-remembered URL. - """ - return self.appRootURL - - -class _RemoteProducerWrapper: - def __init__(self, remote): - self.resumeProducing = remote.remoteMethod("resumeProducing") - self.pauseProducing = remote.remoteMethod("pauseProducing") - self.stopProducing = remote.remoteMethod("stopProducing") - - -class Session(components.Componentized): - """ - A user's session with a system. - - This utility class contains no functionality, but is used to - represent a session. - - @ivar sessionTimeout: timeout of a session, in seconds. - @ivar loopFactory: factory for creating L{task.LoopingCall}. Mainly for - testing. - """ - sessionTimeout = 900 - loopFactory = task.LoopingCall - - def __init__(self, site, uid): - """ - Initialize a session with a unique ID for that session. - """ - components.Componentized.__init__(self) - self.site = site - self.uid = uid - self.expireCallbacks = [] - self.checkExpiredLoop = None - self.touch() - self.sessionNamespaces = {} - - - def startCheckingExpiration(self, lifetime): - """ - Start expiration tracking. - - @type lifetime: C{int} or C{float} - @param lifetime: The number of seconds this session is allowed to be - idle before it expires. - - @return: C{None} - """ - self.checkExpiredLoop = self.loopFactory(self.checkExpired) - self.checkExpiredLoop.start(lifetime, now=False) - - - def notifyOnExpire(self, callback): - """ - Call this callback when the session expires or logs out. - """ - self.expireCallbacks.append(callback) - - - def expire(self): - """ - Expire/logout of the session. - """ - del self.site.sessions[self.uid] - for c in self.expireCallbacks: - c() - self.expireCallbacks = [] - if self.checkExpiredLoop is not None: - self.checkExpiredLoop.stop() - # Break reference cycle. - self.checkExpiredLoop = None - - - def _getTime(self): - """ - Return current time used for session validity. - """ - return time.time() - - - def touch(self): - """ - Notify session modification. - """ - self.lastModified = self._getTime() - - - def checkExpired(self): - """ - Is it time for me to expire? - - If I haven't been touched in fifteen minutes, I will call my - expire method. - """ - # If I haven't been touched in 15 minutes: - if self._getTime() - self.lastModified > self.sessionTimeout: - if self.uid in self.site.sessions: - self.expire() - - -version = "TwistedWeb/%s" % copyright.version - - -class Site(http.HTTPFactory): - """ - A web site: manage log, sessions, and resources. - - @ivar counter: increment value used for generating unique sessions ID. - @ivar requestFactory: factory creating requests objects. Default to - L{Request}. - @ivar displayTracebacks: if set, Twisted internal errors are displayed on - rendered pages. Default to C{True}. - @ivar sessionFactory: factory for sessions objects. Default to L{Session}. - @ivar sessionCheckTime: interval between each check of session expiration. - """ - counter = 0 - requestFactory = Request - displayTracebacks = True - sessionFactory = Session - sessionCheckTime = 1800 - - def __init__(self, resource, logPath=None, timeout=60*60*12): - """ - Initialize. - """ - http.HTTPFactory.__init__(self, logPath=logPath, timeout=timeout) - self.sessions = {} - self.resource = resource - - def _openLogFile(self, path): - from twisted.python import logfile - return logfile.LogFile(os.path.basename(path), os.path.dirname(path)) - - def __getstate__(self): - d = self.__dict__.copy() - d['sessions'] = {} - return d - - def _mkuid(self): - """ - (internal) Generate an opaque, unique ID for a user's session. - """ - import md5, random - self.counter = self.counter + 1 - return md5.new("%s_%s" % (str(random.random()) , str(self.counter))).hexdigest() - - def makeSession(self): - """ - Generate a new Session instance, and store it for future reference. - """ - uid = self._mkuid() - session = self.sessions[uid] = self.sessionFactory(self, uid) - session.startCheckingExpiration(self.sessionCheckTime) - return session - - def getSession(self, uid): - """ - Get a previously generated session, by its unique ID. - This raises a KeyError if the session is not found. - """ - return self.sessions[uid] - - def buildProtocol(self, addr): - """ - Generate a channel attached to this site. - """ - channel = http.HTTPFactory.buildProtocol(self, addr) - channel.requestFactory = self.requestFactory - channel.site = self - return channel - - isLeaf = 0 - - def render(self, request): - """ - Redirect because a Site is always a directory. - """ - request.redirect(request.prePathURL() + '/') - request.finish() - - def getChildWithDefault(self, pathEl, request): - """ - Emulate a resource's getChild method. - """ - request.site = self - return self.resource.getChildWithDefault(pathEl, request) - - def getResourceFor(self, request): - """ - Get a resource for a request. - - This iterates through the resource heirarchy, calling - getChildWithDefault on each resource it finds for a path element, - stopping when it hits an element where isLeaf is true. - """ - request.site = self - # Sitepath is used to determine cookie names between distributed - # servers and disconnected sites. - request.sitepath = copy.copy(request.prepath) - return resource.getChildForRequest(self.resource, request) - - -import html - diff --git a/tools/buildbot/pylibs/twisted/web/soap.py b/tools/buildbot/pylibs/twisted/web/soap.py deleted file mode 100644 index 00b0473..0000000 --- a/tools/buildbot/pylibs/twisted/web/soap.py +++ /dev/null @@ -1,154 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_soap -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -SOAP support for twisted.web. - -Requires SOAPpy 0.10.1 or later. - -Maintainer: U{Itamar Shtull-Trauring} - -Future plans: -SOAPContext support of some kind. -Pluggable method lookup policies. -""" - -# SOAPpy -import SOAPpy - -# twisted imports -from twisted.web import server, resource, client -from twisted.internet import defer - - -class SOAPPublisher(resource.Resource): - """Publish SOAP methods. - - By default, publish methods beginning with 'soap_'. If the method - has an attribute 'useKeywords', it well get the arguments passed - as keyword args. - """ - - isLeaf = 1 - - # override to change the encoding used for responses - encoding = "UTF-8" - - def lookupFunction(self, functionName): - """Lookup published SOAP function. - - Override in subclasses. Default behaviour - publish methods - starting with soap_. - - @return: callable or None if not found. - """ - return getattr(self, "soap_%s" % functionName, None) - - def render(self, request): - """Handle a SOAP command.""" - data = request.content.read() - - p, header, body, attrs = SOAPpy.parseSOAPRPC(data, 1, 1, 1) - - methodName, args, kwargs, ns = p._name, p._aslist, p._asdict, p._ns - - # deal with changes in SOAPpy 0.11 - if callable(args): - args = args() - if callable(kwargs): - kwargs = kwargs() - - function = self.lookupFunction(methodName) - - if not function: - self._methodNotFound(request, methodName) - return server.NOT_DONE_YET - else: - if hasattr(function, "useKeywords"): - keywords = {} - for k, v in kwargs.items(): - keywords[str(k)] = v - d = defer.maybeDeferred(function, **keywords) - else: - d = defer.maybeDeferred(function, *args) - - d.addCallback(self._gotResult, request, methodName) - d.addErrback(self._gotError, request, methodName) - return server.NOT_DONE_YET - - def _methodNotFound(self, request, methodName): - response = SOAPpy.buildSOAP(SOAPpy.faultType("%s:Client" % - SOAPpy.NS.ENV_T, "Method %s not found" % methodName), - encoding=self.encoding) - self._sendResponse(request, response, status=500) - - def _gotResult(self, result, request, methodName): - if not isinstance(result, SOAPpy.voidType): - result = {"Result": result} - response = SOAPpy.buildSOAP(kw={'%sResponse' % methodName: result}, - encoding=self.encoding) - self._sendResponse(request, response) - - def _gotError(self, failure, request, methodName): - e = failure.value - if isinstance(e, SOAPpy.faultType): - fault = e - else: - fault = SOAPpy.faultType("%s:Server" % SOAPpy.NS.ENV_T, - "Method %s failed." % methodName) - response = SOAPpy.buildSOAP(fault, encoding=self.encoding) - self._sendResponse(request, response, status=500) - - def _sendResponse(self, request, response, status=200): - request.setResponseCode(status) - - if self.encoding is not None: - mimeType = 'text/xml; charset="%s"' % self.encoding - else: - mimeType = "text/xml" - request.setHeader("Content-type", mimeType) - request.setHeader("Content-length", str(len(response))) - request.write(response) - request.finish() - - -class Proxy: - """A Proxy for making remote SOAP calls. - - Pass the URL of the remote SOAP server to the constructor. - - Use proxy.callRemote('foobar', 1, 2) to call remote method - 'foobar' with args 1 and 2, proxy.callRemote('foobar', x=1) - will call foobar with named argument 'x'. - """ - - # at some point this should have encoding etc. kwargs - def __init__(self, url, namespace=None, header=None): - self.url = url - self.namespace = namespace - self.header = header - - def _cbGotResult(self, result): - result = SOAPpy.parseSOAPRPC(result) - if hasattr(result, 'Result'): - return result.Result - elif len(result) == 1: - ## SOAPpy 0.11.6 wraps the return results in a containing structure. - ## This check added to make Proxy behaviour emulate SOAPProxy, which - ## flattens the structure by default. - ## This behaviour is OK because even singleton lists are wrapped in - ## another singleton structType, which is almost always useless. - return result[0] - else: - return result - - def callRemote(self, method, *args, **kwargs): - payload = SOAPpy.buildSOAP(args=args, kw=kwargs, method=method, - header=self.header, namespace=self.namespace) - return client.getPage(self.url, postdata=payload, method="POST", - headers={'content-type': 'text/xml', - 'SOAPAction': method} - ).addCallback(self._cbGotResult) - diff --git a/tools/buildbot/pylibs/twisted/web/static.py b/tools/buildbot/pylibs/twisted/web/static.py deleted file mode 100644 index 9d5dd56..0000000 --- a/tools/buildbot/pylibs/twisted/web/static.py +++ /dev/null @@ -1,466 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_web -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""I deal with static resources. -""" - -from __future__ import nested_scopes - -# System Imports -import os, stat, string -import cStringIO -import traceback -import warnings -import types -StringIO = cStringIO -del cStringIO -import urllib - -# Sibling Imports -from twisted.web import server -from twisted.web import error -from twisted.web import resource -from twisted.web.util import redirectTo - -# Twisted Imports -from twisted.web import http -from twisted.python import threadable, log, components, failure, filepath -from twisted.internet import abstract, interfaces, defer -from twisted.spread import pb -from twisted.persisted import styles -from twisted.python.util import InsensitiveDict -from twisted.python.runtime import platformType - - -dangerousPathError = error.NoResource("Invalid request URL.") - -def isDangerous(path): - return path == '..' or '/' in path or os.sep in path - - -class Data(resource.Resource): - """ - This is a static, in-memory resource. - """ - - def __init__(self, data, type): - resource.Resource.__init__(self) - self.data = data - self.type = type - - def render(self, request): - request.setHeader("content-type", self.type) - request.setHeader("content-length", str(len(self.data))) - if request.method == "HEAD": - return '' - return self.data - -def addSlash(request): - qs = '' - qindex = string.find(request.uri, '?') - if qindex != -1: - qs = request.uri[qindex:] - - return "http%s://%s%s/%s" % ( - request.isSecure() and 's' or '', - request.getHeader("host"), - (string.split(request.uri,'?')[0]), - qs) - -class Redirect(resource.Resource): - def __init__(self, request): - resource.Resource.__init__(self) - self.url = addSlash(request) - - def render(self, request): - return redirectTo(self.url, request) - - -class Registry(components.Componentized, styles.Versioned): - """ - I am a Componentized object that will be made available to internal Twisted - file-based dynamic web content such as .rpy and .epy scripts. - """ - - def __init__(self): - components.Componentized.__init__(self) - self._pathCache = {} - - persistenceVersion = 1 - - def upgradeToVersion1(self): - self._pathCache = {} - - def cachePath(self, path, rsrc): - self._pathCache[path] = rsrc - - def getCachedPath(self, path): - return self._pathCache.get(path) - - -def loadMimeTypes(mimetype_locations=['/etc/mime.types']): - """ - Multiple file locations containing mime-types can be passed as a list. - The files will be sourced in that order, overriding mime-types from the - files sourced beforehand, but only if a new entry explicitly overrides - the current entry. - """ - import mimetypes - # Grab Python's built-in mimetypes dictionary. - contentTypes = mimetypes.types_map - # Update Python's semi-erroneous dictionary with a few of the - # usual suspects. - contentTypes.update( - { - '.conf': 'text/plain', - '.diff': 'text/plain', - '.exe': 'application/x-executable', - '.flac': 'audio/x-flac', - '.java': 'text/plain', - '.ogg': 'application/ogg', - '.oz': 'text/x-oz', - '.swf': 'application/x-shockwave-flash', - '.tgz': 'application/x-gtar', - '.wml': 'text/vnd.wap.wml', - '.xul': 'application/vnd.mozilla.xul+xml', - '.py': 'text/plain', - '.patch': 'text/plain', - } - ) - # Users can override these mime-types by loading them out configuration - # files (this defaults to ['/etc/mime.types']). - for location in mimetype_locations: - if os.path.exists(location): - more = mimetypes.read_mime_types(location) - if more is not None: - contentTypes.update(more) - - return contentTypes - -def getTypeAndEncoding(filename, types, encodings, defaultType): - p, ext = os.path.splitext(filename) - ext = ext.lower() - if encodings.has_key(ext): - enc = encodings[ext] - ext = os.path.splitext(p)[1].lower() - else: - enc = None - type = types.get(ext, defaultType) - return type, enc - -class File(resource.Resource, styles.Versioned, filepath.FilePath): - """ - File is a resource that represents a plain non-interpreted file - (although it can look for an extension like .rpy or .cgi and hand the - file to a processor for interpretation if you wish). Its constructor - takes a file path. - - Alternatively, you can give a directory path to the constructor. In this - case the resource will represent that directory, and its children will - be files underneath that directory. This provides access to an entire - filesystem tree with a single Resource. - - If you map the URL 'http://server/FILE' to a resource created as - File('/tmp'), then http://server/FILE/ will return an HTML-formatted - listing of the /tmp/ directory, and http://server/FILE/foo/bar.html will - return the contents of /tmp/foo/bar.html . - - @cvar childNotFound: L{Resource} used to render 404 Not Found error pages. - """ - - contentTypes = loadMimeTypes() - - contentEncodings = { - ".gz" : "gzip", - ".bz2": "bzip2" - } - - processors = {} - - indexNames = ["index", "index.html", "index.htm", "index.trp", "index.rpy"] - - type = None - - ### Versioning - - persistenceVersion = 6 - - def upgradeToVersion6(self): - self.ignoredExts = [] - if self.allowExt: - self.ignoreExt("*") - del self.allowExt - - def upgradeToVersion5(self): - if not isinstance(self.registry, Registry): - self.registry = Registry() - - def upgradeToVersion4(self): - if not hasattr(self, 'registry'): - self.registry = {} - - def upgradeToVersion3(self): - if not hasattr(self, 'allowExt'): - self.allowExt = 0 - - def upgradeToVersion2(self): - self.defaultType = "text/html" - - def upgradeToVersion1(self): - if hasattr(self, 'indexName'): - self.indexNames = [self.indexName] - del self.indexName - - def __init__(self, path, defaultType="text/html", ignoredExts=(), registry=None, allowExt=0): - """Create a file with the given path. - """ - resource.Resource.__init__(self) - filepath.FilePath.__init__(self, path) - # Remove the dots from the path to split - self.defaultType = defaultType - if ignoredExts in (0, 1) or allowExt: - warnings.warn("ignoredExts should receive a list, not a boolean") - if ignoredExts or allowExt: - self.ignoredExts = ['*'] - else: - self.ignoredExts = [] - else: - self.ignoredExts = list(ignoredExts) - self.registry = registry or Registry() - - def ignoreExt(self, ext): - """Ignore the given extension. - - Serve file.ext if file is requested - """ - self.ignoredExts.append(ext) - - childNotFound = error.NoResource("File not found.") - - def directoryListing(self): - from twisted.web.woven import dirlist - return dirlist.DirectoryLister(self.path, - self.listNames(), - self.contentTypes, - self.contentEncodings, - self.defaultType) - - def getChild(self, path, request): - """See twisted.web.Resource.getChild. - """ - self.restat() - - if not self.isdir(): - return self.childNotFound - - if path: - fpath = self.child(path) - else: - fpath = self.childSearchPreauth(*self.indexNames) - if fpath is None: - return self.directoryListing() - - if not fpath.exists(): - fpath = fpath.siblingExtensionSearch(*self.ignoredExts) - if fpath is None: - return self.childNotFound - - if platformType == "win32": - # don't want .RPY to be different than .rpy, since that would allow - # source disclosure. - processor = InsensitiveDict(self.processors).get(fpath.splitext()[1]) - else: - processor = self.processors.get(fpath.splitext()[1]) - if processor: - return resource.IResource(processor(fpath.path, self.registry)) - return self.createSimilarFile(fpath.path) - - # methods to allow subclasses to e.g. decrypt files on the fly: - def openForReading(self): - """Open a file and return it.""" - return self.open() - - def getFileSize(self): - """Return file size.""" - return self.getsize() - - - def render(self, request): - """You know what you doing.""" - self.restat() - - if self.type is None: - self.type, self.encoding = getTypeAndEncoding(self.basename(), - self.contentTypes, - self.contentEncodings, - self.defaultType) - - if not self.exists(): - return self.childNotFound.render(request) - - if self.isdir(): - return self.redirect(request) - - #for content-length - fsize = size = self.getFileSize() - -# request.setHeader('accept-ranges','bytes') - - if self.type: - request.setHeader('content-type', self.type) - if self.encoding: - request.setHeader('content-encoding', self.encoding) - - try: - f = self.openForReading() - except IOError, e: - import errno - if e[0] == errno.EACCES: - return error.ForbiddenResource().render(request) - else: - raise - - if request.setLastModified(self.getmtime()) is http.CACHED: - return '' - -# Commented out because it's totally broken. --jknight 11/29/04 -# try: -# range = request.getHeader('range') -# -# if range is not None: -# # This is a request for partial data... -# bytesrange = string.split(range, '=') -# assert bytesrange[0] == 'bytes',\ -# "Syntactically invalid http range header!" -# start, end = string.split(bytesrange[1],'-') -# if start: -# f.seek(int(start)) -# if end: -# end = int(end) -# size = end -# else: -# end = size -# request.setResponseCode(http.PARTIAL_CONTENT) -# request.setHeader('content-range',"bytes %s-%s/%s " % ( -# str(start), str(end), str(size))) -# #content-length should be the actual size of the stuff we're -# #sending, not the full size of the on-server entity. -# fsize = end - int(start) -# -# request.setHeader('content-length', str(fsize)) -# except: -# traceback.print_exc(file=log.logfile) - - request.setHeader('content-length', str(fsize)) - if request.method == 'HEAD': - return '' - - # return data - FileTransfer(f, size, request) - # and make sure the connection doesn't get closed - return server.NOT_DONE_YET - - def redirect(self, request): - return redirectTo(addSlash(request), request) - - def listNames(self): - if not self.isdir(): - return [] - directory = self.listdir() - directory.sort() - return directory - - def listEntities(self): - return map(lambda fileName, self=self: self.createSimilarFile(os.path.join(self.path, fileName)), self.listNames()) - - def createPickleChild(self, name, child): - if not os.path.isdir(self.path): - resource.Resource.putChild(self, name, child) - # xxx use a file-extension-to-save-function dictionary instead - if type(child) == type(""): - fl = open(os.path.join(self.path, name), 'wb') - fl.write(child) - else: - if '.' not in name: - name = name + '.trp' - fl = open(os.path.join(self.path, name), 'wb') - from pickle import Pickler - pk = Pickler(fl) - pk.dump(child) - fl.close() - - def createSimilarFile(self, path): - f = self.__class__(path, self.defaultType, self.ignoredExts, self.registry) - # refactoring by steps, here - constructor should almost certainly take these - f.processors = self.processors - f.indexNames = self.indexNames[:] - f.childNotFound = self.childNotFound - return f - -class FileTransfer(pb.Viewable): - """ - A class to represent the transfer of a file over the network. - """ - request = None - - def __init__(self, file, size, request): - self.file = file - self.size = size - self.request = request - self.written = self.file.tell() - request.registerProducer(self, 0) - - def resumeProducing(self): - if not self.request: - return - data = self.file.read(min(abstract.FileDescriptor.bufferSize, self.size - self.written)) - if data: - self.written += len(data) - # this .write will spin the reactor, calling .doWrite and then - # .resumeProducing again, so be prepared for a re-entrant call - self.request.write(data) - if self.request and self.file.tell() == self.size: - self.request.unregisterProducer() - self.request.finish() - self.request = None - - def pauseProducing(self): - pass - - def stopProducing(self): - self.file.close() - self.request = None - - # Remotely relay producer interface. - - def view_resumeProducing(self, issuer): - self.resumeProducing() - - def view_pauseProducing(self, issuer): - self.pauseProducing() - - def view_stopProducing(self, issuer): - self.stopProducing() - - - synchronized = ['resumeProducing', 'stopProducing'] - -threadable.synchronize(FileTransfer) - -"""I contain AsIsProcessor, which serves files 'As Is' - Inspired by Apache's mod_asis -""" - -class ASISProcessor(resource.Resource): - - def __init__(self, path, registry=None): - resource.Resource.__init__(self) - self.path = path - self.registry = registry or Registry() - - def render(self, request): - request.startedWriting = 1 - res = File(self.path, registry=self.registry) - return res.render(request) diff --git a/tools/buildbot/pylibs/twisted/web/sux.py b/tools/buildbot/pylibs/twisted/web/sux.py deleted file mode 100644 index 6f8fea1..0000000 --- a/tools/buildbot/pylibs/twisted/web/sux.py +++ /dev/null @@ -1,657 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_xml -*- -# -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -*S*mall, *U*ncomplicated *X*ML. - -This is a very simple implementation of XML/HTML as a network -protocol. It is not at all clever. Its main features are that it -does not: - - - support namespaces - - mung mnemonic entity references - - validate - - perform *any* external actions (such as fetching URLs or writing files) - under *any* circumstances - - has lots and lots of horrible hacks for supporting broken HTML (as an - option, they're not on by default). -""" - -from twisted.internet.protocol import Protocol, FileWrapper -from twisted.python.reflect import prefixedMethodNames - - - -# Elements of the three-tuples in the state table. -BEGIN_HANDLER = 0 -DO_HANDLER = 1 -END_HANDLER = 2 - -identChars = '.-_:' -lenientIdentChars = identChars + ';+#/%~' - -def nop(*args, **kw): - "Do nothing." - - -def unionlist(*args): - l = [] - for x in args: - l.extend(x) - d = dict([(x, 1) for x in l]) - return d.keys() - - -def zipfndict(*args, **kw): - default = kw.get('default', nop) - d = {} - for key in unionlist(*[fndict.keys() for fndict in args]): - d[key] = tuple([x.get(key, default) for x in args]) - return d - - -def prefixedMethodClassDict(clazz, prefix): - return dict([(name, getattr(clazz, prefix + name)) for name in prefixedMethodNames(clazz, prefix)]) - - -def prefixedMethodObjDict(obj, prefix): - return dict([(name, getattr(obj, prefix + name)) for name in prefixedMethodNames(obj.__class__, prefix)]) - - -class ParseError(Exception): - - def __init__(self, filename, line, col, message): - self.filename = filename - self.line = line - self.col = col - self.message = message - - def __str__(self): - return "%s:%s:%s: %s" % (self.filename, self.line, self.col, - self.message) - -class XMLParser(Protocol): - - state = None - encodings = None - filename = "" - beExtremelyLenient = 0 - _prepend = None - - # _leadingBodyData will sometimes be set before switching to the - # 'bodydata' state, when we "accidentally" read a byte of bodydata - # in a different state. - _leadingBodyData = None - - def connectionMade(self): - self.lineno = 1 - self.colno = 0 - self.encodings = [] - - def saveMark(self): - '''Get the line number and column of the last character parsed''' - # This gets replaced during dataReceived, restored afterwards - return (self.lineno, self.colno) - - def _parseError(self, message): - raise ParseError(*((self.filename,)+self.saveMark()+(message,))) - - def _buildStateTable(self): - '''Return a dictionary of begin, do, end state function tuples''' - # _buildStateTable leaves something to be desired but it does what it - # does.. probably slowly, so I'm doing some evil caching so it doesn't - # get called more than once per class. - stateTable = getattr(self.__class__, '__stateTable', None) - if stateTable is None: - stateTable = self.__class__.__stateTable = zipfndict( - *[prefixedMethodObjDict(self, prefix) - for prefix in ('begin_', 'do_', 'end_')]) - return stateTable - - def _decode(self, data): - if 'UTF-16' in self.encodings or 'UCS-2' in self.encodings: - assert not len(data) & 1, 'UTF-16 must come in pairs for now' - if self._prepend: - data = self._prepend + data - for encoding in self.encodings: - data = unicode(data, encoding) - return data - - def maybeBodyData(self): - if self.endtag: - return 'bodydata' - - # Get ready for fun! We're going to allow - # to work! - # We do this by making everything between a Text - # BUT - # -radix - - if (self.tagName == 'script' - and not self.tagAttributes.has_key('src')): - # we do this ourselves rather than having begin_waitforendscript - # becuase that can get called multiple times and we don't want - # bodydata to get reset other than the first time. - self.begin_bodydata(None) - return 'waitforendscript' - return 'bodydata' - - - - def dataReceived(self, data): - stateTable = self._buildStateTable() - if not self.state: - # all UTF-16 starts with this string - if data.startswith('\xff\xfe'): - self._prepend = '\xff\xfe' - self.encodings.append('UTF-16') - data = data[2:] - elif data.startswith('\xfe\xff'): - self._prepend = '\xfe\xff' - self.encodings.append('UTF-16') - data = data[2:] - self.state = 'begin' - if self.encodings: - data = self._decode(data) - # bring state, lineno, colno into local scope - lineno, colno = self.lineno, self.colno - curState = self.state - # replace saveMark with a nested scope function - _saveMark = self.saveMark - def saveMark(): - return (lineno, colno) - self.saveMark = saveMark - # fetch functions from the stateTable - beginFn, doFn, endFn = stateTable[curState] - try: - for byte in data: - # do newline stuff - if byte == '\n': - lineno += 1 - colno = 0 - else: - colno += 1 - newState = doFn(byte) - if newState is not None and newState != curState: - # this is the endFn from the previous state - endFn() - curState = newState - beginFn, doFn, endFn = stateTable[curState] - beginFn(byte) - finally: - self.saveMark = _saveMark - self.lineno, self.colno = lineno, colno - # state doesn't make sense if there's an exception.. - self.state = curState - - - def connectionLost(self, reason): - """ - End the last state we were in. - """ - stateTable = self._buildStateTable() - stateTable[self.state][END_HANDLER]() - - - # state methods - - def do_begin(self, byte): - if byte.isspace(): - return - if byte != '<': - if self.beExtremelyLenient: - self._leadingBodyData = byte - return 'bodydata' - self._parseError("First char of document [%r] wasn't <" % (byte,)) - return 'tagstart' - - def begin_comment(self, byte): - self.commentbuf = '' - - def do_comment(self, byte): - self.commentbuf += byte - if self.commentbuf.endswith('-->'): - self.gotComment(self.commentbuf[:-3]) - return 'bodydata' - - def begin_tagstart(self, byte): - self.tagName = '' # name of the tag - self.tagAttributes = {} # attributes of the tag - self.termtag = 0 # is the tag self-terminating - self.endtag = 0 - - def do_tagstart(self, byte): - if byte.isalnum() or byte in identChars: - self.tagName += byte - if self.tagName == '!--': - return 'comment' - elif byte.isspace(): - if self.tagName: - if self.endtag: - # properly strict thing to do here is probably to only - # accept whitespace - return 'waitforgt' - return 'attrs' - else: - self._parseError("Whitespace before tag-name") - elif byte == '>': - if self.endtag: - self.gotTagEnd(self.tagName) - return 'bodydata' - else: - self.gotTagStart(self.tagName, {}) - return (not self.beExtremelyLenient) and 'bodydata' or self.maybeBodyData() - elif byte == '/': - if self.tagName: - return 'afterslash' - else: - self.endtag = 1 - elif byte in '!?': - if self.tagName: - if not self.beExtremelyLenient: - self._parseError("Invalid character in tag-name") - else: - self.tagName += byte - self.termtag = 1 - elif byte == '[': - if self.tagName == '!': - return 'expectcdata' - else: - self._parseError("Invalid '[' in tag-name") - else: - if self.beExtremelyLenient: - self.bodydata = '<' - return 'unentity' - self._parseError('Invalid tag character: %r'% byte) - - def begin_unentity(self, byte): - self.bodydata += byte - - def do_unentity(self, byte): - self.bodydata += byte - return 'bodydata' - - def end_unentity(self): - self.gotText(self.bodydata) - - def begin_expectcdata(self, byte): - self.cdatabuf = byte - - def do_expectcdata(self, byte): - self.cdatabuf += byte - cdb = self.cdatabuf - cd = '[CDATA[' - if len(cd) > len(cdb): - if cd.startswith(cdb): - return - elif self.beExtremelyLenient: - ## WHAT THE CRAP!? MSWord9 generates HTML that includes these - ## bizarre chunks, so I've gotta ignore - ## 'em as best I can. this should really be a separate parse - ## state but I don't even have any idea what these _are_. - return 'waitforgt' - else: - self._parseError("Mal-formed CDATA header") - if cd == cdb: - self.cdatabuf = '' - return 'cdata' - self._parseError("Mal-formed CDATA header") - - def do_cdata(self, byte): - self.cdatabuf += byte - if self.cdatabuf.endswith("]]>"): - self.cdatabuf = self.cdatabuf[:-3] - return 'bodydata' - - def end_cdata(self): - self.gotCData(self.cdatabuf) - self.cdatabuf = '' - - def do_attrs(self, byte): - if byte.isalnum() or byte in identChars: - # XXX FIXME really handle !DOCTYPE at some point - if self.tagName == '!DOCTYPE': - return 'doctype' - if self.tagName[0] in '!?': - return 'waitforgt' - return 'attrname' - elif byte.isspace(): - return - elif byte == '>': - self.gotTagStart(self.tagName, self.tagAttributes) - return (not self.beExtremelyLenient) and 'bodydata' or self.maybeBodyData() - elif byte == '/': - return 'afterslash' - elif self.beExtremelyLenient: - # discard and move on? Only case I've seen of this so far was: - # - return - self._parseError("Unexpected character: %r" % byte) - - def begin_doctype(self, byte): - self.doctype = byte - - def do_doctype(self, byte): - if byte == '>': - return 'bodydata' - self.doctype += byte - - def end_doctype(self): - self.gotDoctype(self.doctype) - self.doctype = None - - def do_waitforgt(self, byte): - if byte == '>': - if self.endtag or not self.beExtremelyLenient: - return 'bodydata' - return self.maybeBodyData() - - def begin_attrname(self, byte): - self.attrname = byte - self._attrname_termtag = 0 - - def do_attrname(self, byte): - if byte.isalnum() or byte in identChars: - self.attrname += byte - return - elif byte == '=': - return 'beforeattrval' - elif byte.isspace(): - return 'beforeeq' - elif self.beExtremelyLenient: - if byte in '"\'': - return 'attrval' - if byte in lenientIdentChars or byte.isalnum(): - self.attrname += byte - return - if byte == '/': - self._attrname_termtag = 1 - return - if byte == '>': - self.attrval = 'True' - self.tagAttributes[self.attrname] = self.attrval - self.gotTagStart(self.tagName, self.tagAttributes) - if self._attrname_termtag: - self.gotTagEnd(self.tagName) - return 'bodydata' - return self.maybeBodyData() - # something is really broken. let's leave this attribute where it - # is and move on to the next thing - return - self._parseError("Invalid attribute name: %r %r" % (self.attrname, byte)) - - def do_beforeattrval(self, byte): - if byte in '"\'': - return 'attrval' - elif byte.isspace(): - return - elif self.beExtremelyLenient: - if byte in lenientIdentChars or byte.isalnum(): - return 'messyattr' - if byte == '>': - self.attrval = 'True' - self.tagAttributes[self.attrname] = self.attrval - self.gotTagStart(self.tagName, self.tagAttributes) - return self.maybeBodyData() - if byte == '\\': - # I saw this in actual HTML once: - # SM - return - self._parseError("Invalid initial attribute value: %r; Attribute values must be quoted." % byte) - - attrname = '' - attrval = '' - - def begin_beforeeq(self,byte): - self._beforeeq_termtag = 0 - - def do_beforeeq(self, byte): - if byte == '=': - return 'beforeattrval' - elif byte.isspace(): - return - elif self.beExtremelyLenient: - if byte.isalnum() or byte in identChars: - self.attrval = 'True' - self.tagAttributes[self.attrname] = self.attrval - return 'attrname' - elif byte == '>': - self.attrval = 'True' - self.tagAttributes[self.attrname] = self.attrval - self.gotTagStart(self.tagName, self.tagAttributes) - if self._beforeeq_termtag: - self.gotTagEnd(self.tagName) - return 'bodydata' - return self.maybeBodyData() - elif byte == '/': - self._beforeeq_termtag = 1 - return - self._parseError("Invalid attribute") - - def begin_attrval(self, byte): - self.quotetype = byte - self.attrval = '' - - def do_attrval(self, byte): - if byte == self.quotetype: - return 'attrs' - self.attrval += byte - - def end_attrval(self): - self.tagAttributes[self.attrname] = self.attrval - self.attrname = self.attrval = '' - - def begin_messyattr(self, byte): - self.attrval = byte - - def do_messyattr(self, byte): - if byte.isspace(): - return 'attrs' - elif byte == '>': - endTag = 0 - if self.attrval.endswith('/'): - endTag = 1 - self.attrval = self.attrval[:-1] - self.tagAttributes[self.attrname] = self.attrval - self.gotTagStart(self.tagName, self.tagAttributes) - if endTag: - self.gotTagEnd(self.tagName) - return 'bodydata' - return self.maybeBodyData() - else: - self.attrval += byte - - def end_messyattr(self): - if self.attrval: - self.tagAttributes[self.attrname] = self.attrval - - def begin_afterslash(self, byte): - self._after_slash_closed = 0 - - def do_afterslash(self, byte): - # this state is only after a self-terminating slash, e.g. - if self._after_slash_closed: - self._parseError("Mal-formed")#XXX When does this happen?? - if byte != '>': - if self.beExtremelyLenient: - return - else: - self._parseError("No data allowed after '/'") - self._after_slash_closed = 1 - self.gotTagStart(self.tagName, self.tagAttributes) - self.gotTagEnd(self.tagName) - # don't need maybeBodyData here because there better not be - # any javascript code after a , we need to - # remember all the data we've been through so we can append it - # to bodydata - self.temptagdata += byte - - # 1 - if byte == '/': - self.endtag = True - elif not self.endtag: - self.bodydata += "<" + self.temptagdata - return 'waitforendscript' - # 2 - elif byte.isalnum() or byte in identChars: - self.tagName += byte - if not 'script'.startswith(self.tagName): - self.bodydata += "<" + self.temptagdata - return 'waitforendscript' - elif self.tagName == 'script': - self.gotText(self.bodydata) - self.gotTagEnd(self.tagName) - return 'waitforgt' - # 3 - elif byte.isspace(): - return 'waitscriptendtag' - # 4 - else: - self.bodydata += "<" + self.temptagdata - return 'waitforendscript' - - - def begin_entityref(self, byte): - self.erefbuf = '' - self.erefextra = '' # extra bit for lenient mode - - def do_entityref(self, byte): - if byte.isspace() or byte == "<": - if self.beExtremelyLenient: - # '&foo' probably was '&foo' - if self.erefbuf and self.erefbuf != "amp": - self.erefextra = self.erefbuf - self.erefbuf = "amp" - if byte == "<": - return "tagstart" - else: - self.erefextra += byte - return 'spacebodydata' - self._parseError("Bad entity reference") - elif byte != ';': - self.erefbuf += byte - else: - return 'bodydata' - - def end_entityref(self): - self.gotEntityReference(self.erefbuf) - - # hacky support for space after & in entityref in beExtremelyLenient - # state should only happen in that case - def begin_spacebodydata(self, byte): - self.bodydata = self.erefextra - self.erefextra = None - do_spacebodydata = do_bodydata - end_spacebodydata = end_bodydata - - # Sorta SAX-ish API - - def gotTagStart(self, name, attributes): - '''Encountered an opening tag. - - Default behaviour is to print.''' - print 'begin', name, attributes - - def gotText(self, data): - '''Encountered text - - Default behaviour is to print.''' - print 'text:', repr(data) - - def gotEntityReference(self, entityRef): - '''Encountered mnemonic entity reference - - Default behaviour is to print.''' - print 'entityRef: &%s;' % entityRef - - def gotComment(self, comment): - '''Encountered comment. - - Default behaviour is to ignore.''' - pass - - def gotCData(self, cdata): - '''Encountered CDATA - - Default behaviour is to call the gotText method''' - self.gotText(cdata) - - def gotDoctype(self, doctype): - """Encountered DOCTYPE - - This is really grotty: it basically just gives you everything between - '' as an argument. - """ - print '!DOCTYPE', repr(doctype) - - def gotTagEnd(self, name): - '''Encountered closing tag - - Default behaviour is to print.''' - print 'end', name - -if __name__ == '__main__': - from cStringIO import StringIO - testDocument = ''' - - - - - A - - boz &zop; - - - ''' - x = XMLParser() - x.makeConnection(FileWrapper(StringIO())) - # fn = "/home/glyph/Projects/Twisted/doc/howto/ipc10paper.html" - fn = "/home/glyph/gruesome.xml" - # testDocument = open(fn).read() - x.dataReceived(testDocument) diff --git a/tools/buildbot/pylibs/twisted/web/tap.py b/tools/buildbot/pylibs/twisted/web/tap.py deleted file mode 100644 index 559b801..0000000 --- a/tools/buildbot/pylibs/twisted/web/tap.py +++ /dev/null @@ -1,201 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Support for creating a service which runs a web server. -""" - -import os - -# Twisted Imports -from twisted.web import server, static, twcgi, script, demo, distrib, trp -from twisted.internet import interfaces -from twisted.python import usage, reflect -from twisted.spread import pb -from twisted.application import internet, service, strports - - -class Options(usage.Options): - synopsis = "Usage: mktap web [options]" - optParameters = [["port", "p", "8080","Port to start the server on."], - ["logfile", "l", None, "Path to web CLF (Combined Log Format) log file."], - ["https", None, None, "Port to listen on for Secure HTTP."], - ["certificate", "c", "server.pem", "SSL certificate to use for HTTPS. "], - ["privkey", "k", "server.pem", "SSL certificate to use for HTTPS."], - ] - optFlags = [["personal", "", - "Instead of generating a webserver, generate a " - "ResourcePublisher which listens on " - "~/%s" % distrib.UserDirectory.userSocketName], - ["notracebacks", "n", "Display tracebacks in broken web pages. " + - "Displaying tracebacks to users may be security risk!"], -] - zsh_actions = {"logfile" : "_files -g '*.log'", "certificate" : "_files -g '*.pem'", - "privkey" : "_files -g '*.pem'"} - - - longdesc = """\ -This creates a web.tap file that can be used by twistd. If you specify -no arguments, it will be a demo webserver that has the Test class from -twisted.web.demo in it.""" - - def __init__(self): - usage.Options.__init__(self) - self['indexes'] = [] - self['root'] = None - - def opt_index(self, indexName): - """Add the name of a file used to check for directory indexes. - [default: index, index.html] - """ - self['indexes'].append(indexName) - - opt_i = opt_index - - def opt_user(self): - """Makes a server with ~/public_html and ~/.twistd-web-pb support for - users. - """ - self['root'] = distrib.UserDirectory() - - opt_u = opt_user - - def opt_path(self, path): - """ is either a specific file or a directory to - be set as the root of the web server. Use this if you - have a directory full of HTML, cgi, php3, epy, or rpy files or - any other files that you want to be served up raw. - """ - - self['root'] = static.File(os.path.abspath(path)) - self['root'].processors = { - '.cgi': twcgi.CGIScript, - '.php3': twcgi.PHP3Script, - '.php': twcgi.PHPScript, - '.epy': script.PythonScript, - '.rpy': script.ResourceScript, - '.trp': trp.ResourceUnpickler, - } - - def opt_processor(self, proc): - """`ext=class' where `class' is added as a Processor for files ending - with `ext'. - """ - if not isinstance(self['root'], static.File): - raise usage.UsageError("You can only use --processor after --path.") - ext, klass = proc.split('=', 1) - self['root'].processors[ext] = reflect.namedClass(klass) - - def opt_static(self, path): - """Same as --path, this is deprecated and will be removed in a - future release.""" - print ("WARNING: --static is deprecated and will be removed in" - "a future release. Please use --path.") - self.opt_path(path) - opt_s = opt_static - - def opt_class(self, className): - """Create a Resource subclass with a zero-argument constructor. - """ - classObj = reflect.namedClass(className) - self['root'] = classObj() - - - def opt_resource_script(self, name): - """An .rpy file to be used as the root resource of the webserver.""" - self['root'] = script.ResourceScriptWrapper(name) - - - def opt_mime_type(self, defaultType): - """Specify the default mime-type for static files.""" - if not isinstance(self['root'], static.File): - raise usage.UsageError("You can only use --mime_type after --path.") - self['root'].defaultType = defaultType - opt_m = opt_mime_type - - - def opt_allow_ignore_ext(self): - """Specify whether or not a request for 'foo' should return 'foo.ext'""" - if not isinstance(self['root'], static.File): - raise usage.UsageError("You can only use --allow_ignore_ext " - "after --path.") - self['root'].ignoreExt('*') - - def opt_ignore_ext(self, ext): - """Specify an extension to ignore. These will be processed in order. - """ - if not isinstance(self['root'], static.File): - raise usage.UsageError("You can only use --ignore_ext " - "after --path.") - self['root'].ignoreExt(ext) - - def opt_flashconduit(self, port=None): - """Start a flashconduit on the specified port. - """ - if not port: - port = "4321" - self['flashconduit'] = port - - def postOptions(self): - if self['https']: - try: - from twisted.internet.ssl import DefaultOpenSSLContextFactory - except ImportError: - raise usage.UsageError("SSL support not installed") - - - -def makePersonalServerFactory(site): - """ - Create and return a factory which will respond to I{distrib} requests - against the given site. - - @type site: L{twisted.web.server.Site} - @rtype: L{twisted.internet.protocol.Factory} - """ - return pb.PBServerFactory(distrib.ResourcePublisher(site)) - - - -def makeService(config): - s = service.MultiService() - if config['root']: - root = config['root'] - if config['indexes']: - config['root'].indexNames = config['indexes'] - else: - # This really ought to be web.Admin or something - root = demo.Test() - - if isinstance(root, static.File): - root.registry.setComponent(interfaces.IServiceCollection, s) - - if config['logfile']: - site = server.Site(root, logPath=config['logfile']) - else: - site = server.Site(root) - - site.displayTracebacks = not config["notracebacks"] - - if config['personal']: - import pwd - name, passwd, uid, gid, gecos, dir, shell = pwd.getpwuid(os.getuid()) - personal = internet.UNIXServer( - os.path.join(dir, distrib.UserDirectory.userSocketName), - makePersonalServerFactory(site)) - personal.setServiceParent(s) - else: - if config['https']: - from twisted.internet.ssl import DefaultOpenSSLContextFactory - i = internet.SSLServer(int(config['https']), site, - DefaultOpenSSLContextFactory(config['privkey'], - config['certificate'])) - i.setServiceParent(s) - strports.service(config['port'], site).setServiceParent(s) - - flashport = config.get('flashconduit', None) - if flashport: - from twisted.web.woven.flashconduit import FlashConduitFactory - i = internet.TCPServer(int(flashport), FlashConduitFactory(site)) - i.setServiceParent(s) - return s diff --git a/tools/buildbot/pylibs/twisted/web/test/__init__.py b/tools/buildbot/pylibs/twisted/web/test/__init__.py deleted file mode 100644 index 1ca3db1..0000000 --- a/tools/buildbot/pylibs/twisted/web/test/__init__.py +++ /dev/null @@ -1 +0,0 @@ -'web tests' diff --git a/tools/buildbot/pylibs/twisted/web/test/test_cgi.py b/tools/buildbot/pylibs/twisted/web/test/test_cgi.py deleted file mode 100644 index 528c4d1..0000000 --- a/tools/buildbot/pylibs/twisted/web/test/test_cgi.py +++ /dev/null @@ -1,121 +0,0 @@ -import sys, os - -from twisted.trial import unittest -from twisted.internet import reactor, interfaces -from twisted.python import util -from twisted.web import static, twcgi, server, resource -from twisted.web import client - -DUMMY_CGI = '''\ -print "Header: OK" -print -print "cgi output" -''' - -READINPUT_CGI = '''\ -# this is an example of a correctly-written CGI script which reads a body -# from stdin, which only reads env['CONTENT_LENGTH'] bytes. - -import os, sys - -body_length = int(os.environ.get('CONTENT_LENGTH',0)) -indata = sys.stdin.read(body_length) -print "Header: OK" -print -print "readinput ok" -''' - -READALLINPUT_CGI = '''\ -# this is an example of the typical (incorrect) CGI script which expects -# the server to close stdin when the body of the request is complete. -# A correct CGI should only read env['CONTENT_LENGTH'] bytes. - -import sys - -indata = sys.stdin.read() -print "Header: OK" -print -print "readallinput ok" -''' - -class PythonScript(twcgi.FilteredScript): - filter = sys.executable - filters = sys.executable, # web2's version - -class CGI(unittest.TestCase): - def startServer(self, cgi): - root = resource.Resource() - cgipath = util.sibpath(__file__, cgi) - root.putChild("cgi", PythonScript(cgipath)) - site = server.Site(root) - self.p = reactor.listenTCP(0, site) - return self.p.getHost().port - - def tearDown(self): - if self.p: - return self.p.stopListening() - - - def testCGI(self): - cgiFilename = os.path.abspath(self.mktemp()) - cgiFile = file(cgiFilename, 'wt') - cgiFile.write(DUMMY_CGI) - cgiFile.close() - - portnum = self.startServer(cgiFilename) - d = client.getPage("http://localhost:%d/cgi" % portnum) - d.addCallback(self._testCGI_1) - return d - def _testCGI_1(self, res): - self.failUnlessEqual(res, "cgi output" + os.linesep) - - - def testReadEmptyInput(self): - cgiFilename = os.path.abspath(self.mktemp()) - cgiFile = file(cgiFilename, 'wt') - cgiFile.write(READINPUT_CGI) - cgiFile.close() - - portnum = self.startServer(cgiFilename) - d = client.getPage("http://localhost:%d/cgi" % portnum) - d.addCallback(self._testReadEmptyInput_1) - return d - testReadEmptyInput.timeout = 5 - def _testReadEmptyInput_1(self, res): - self.failUnlessEqual(res, "readinput ok%s" % os.linesep) - - def testReadInput(self): - cgiFilename = os.path.abspath(self.mktemp()) - cgiFile = file(cgiFilename, 'wt') - cgiFile.write(READINPUT_CGI) - cgiFile.close() - - portnum = self.startServer(cgiFilename) - d = client.getPage("http://localhost:%d/cgi" % portnum, - method="POST", - postdata="Here is your stdin") - d.addCallback(self._testReadInput_1) - return d - testReadInput.timeout = 5 - def _testReadInput_1(self, res): - self.failUnlessEqual(res, "readinput ok%s" % os.linesep) - - - def testReadAllInput(self): - cgiFilename = os.path.abspath(self.mktemp()) - cgiFile = file(cgiFilename, 'wt') - cgiFile.write(READALLINPUT_CGI) - cgiFile.close() - - portnum = self.startServer(cgiFilename) - d = client.getPage("http://localhost:%d/cgi" % portnum, - method="POST", - postdata="Here is your stdin") - d.addCallback(self._testReadAllInput_1) - return d - testReadAllInput.timeout = 5 - def _testReadAllInput_1(self, res): - self.failUnlessEqual(res, "readallinput ok%s" % os.linesep) - -if not interfaces.IReactorProcess.providedBy(reactor): - CGI.skip = "CGI tests require a functional reactor.spawnProcess()" diff --git a/tools/buildbot/pylibs/twisted/web/test/test_distrib.py b/tools/buildbot/pylibs/twisted/web/test/test_distrib.py deleted file mode 100644 index 152b3f3..0000000 --- a/tools/buildbot/pylibs/twisted/web/test/test_distrib.py +++ /dev/null @@ -1,64 +0,0 @@ -# Copyright (c) 2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.web.distrib}. -""" - -from twisted.trial import unittest -from twisted.web import http, distrib, client, resource, static, server -from twisted.internet import reactor, defer -from twisted.spread import pb -from twisted.python import log - -class MySite(server.Site): - def stopFactory(self): - if hasattr(self, "logFile"): - if self.logFile != log.logfile: - self.logFile.close() - del self.logFile - - -class PBServerFactory(pb.PBServerFactory): - def buildProtocol(self, addr): - self.proto = pb.PBServerFactory.buildProtocol(self, addr) - return self.proto - - -class DistribTest(unittest.TestCase): - port1 = None - port2 = None - sub = None - - def tearDown(self): - dl = [defer.Deferred(), defer.Deferred()] - self.f1.proto.notifyOnDisconnect(lambda: dl[0].callback(None)) - if self.sub is not None: - self.sub.publisher.broker.notifyOnDisconnect( - lambda: dl[1].callback(None)) - self.sub.publisher.broker.transport.loseConnection() - http._logDateTimeStop() - if self.port1 is not None: - dl.append(self.port1.stopListening()) - if self.port2 is not None: - dl.append(self.port2.stopListening()) - return defer.gatherResults(dl) - - def testDistrib(self): - # site1 is the publisher - r1 = resource.Resource() - r1.putChild("there", static.Data("root", "text/plain")) - site1 = server.Site(r1) - self.f1 = PBServerFactory(distrib.ResourcePublisher(site1)) - self.port1 = reactor.listenTCP(0, self.f1) - self.sub = distrib.ResourceSubscription("127.0.0.1", - self.port1.getHost().port) - r2 = resource.Resource() - r2.putChild("here", self.sub) - f2 = MySite(r2) - self.port2 = reactor.listenTCP(0, f2) - d = client.getPage("http://127.0.0.1:%d/here/there" % \ - self.port2.getHost().port) - d.addCallback(self.failUnlessEqual, 'root') - return d - diff --git a/tools/buildbot/pylibs/twisted/web/test/test_domhelpers.py b/tools/buildbot/pylibs/twisted/web/test/test_domhelpers.py deleted file mode 100644 index 6d52fc2..0000000 --- a/tools/buildbot/pylibs/twisted/web/test/test_domhelpers.py +++ /dev/null @@ -1,234 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_domhelpers -*- -# -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -"""Specific tests for (some of) the methods in t.web.domhelpers""" - -from twisted.trial.unittest import TestCase - -from twisted.web import microdom - -from twisted.web import domhelpers - -class DomHelpersTest(TestCase): - def test_getElementsByTagName(self): - doc1=microdom.parseString('') - actual=domhelpers.getElementsByTagName(doc1, 'foo')[0].nodeName - expected='foo' - self.assertEquals(actual, expected) - el1=doc1.documentElement - actual=domhelpers.getElementsByTagName(el1, 'foo')[0].nodeName - self.assertEqual(actual, expected) - - doc2_xml='' - doc2=microdom.parseString(doc2_xml) - tag_list=domhelpers.getElementsByTagName(doc2, 'foo') - actual=''.join([node.getAttribute('in') for node in tag_list]) - expected='abcdefgh' - self.assertEquals(actual, expected) - el2=doc2.documentElement - tag_list=domhelpers.getElementsByTagName(el2, 'foo') - actual=''.join([node.getAttribute('in') for node in tag_list]) - self.assertEqual(actual, expected) - - doc3_xml=''' - - - - - - - - - - - - - - - -''' - doc3=microdom.parseString(doc3_xml) - tag_list=domhelpers.getElementsByTagName(doc3, 'foo') - actual=''.join([node.getAttribute('in') for node in tag_list]) - expected='abdgheicfj' - self.assertEquals(actual, expected) - el3=doc3.documentElement - tag_list=domhelpers.getElementsByTagName(el3, 'foo') - actual=''.join([node.getAttribute('in') for node in tag_list]) - self.assertEqual(actual, expected) - - doc4_xml='' - doc4=microdom.parseString(doc4_xml) - actual=domhelpers.getElementsByTagName(doc4, 'foo') - root=doc4.documentElement - expected=[root, root.lastChild().firstChild()] - self.assertEquals(actual, expected) - actual=domhelpers.getElementsByTagName(root, 'foo') - self.assertEqual(actual, expected) - - - def test_gatherTextNodes(self): - doc1=microdom.parseString('foo') - actual=domhelpers.gatherTextNodes(doc1) - expected='foo' - self.assertEqual(actual, expected) - actual=domhelpers.gatherTextNodes(doc1.documentElement) - self.assertEqual(actual, expected) - - doc2_xml='abcdefgh' - doc2=microdom.parseString(doc2_xml) - actual=domhelpers.gatherTextNodes(doc2) - expected='abcdefgh' - self.assertEqual(actual, expected) - actual=domhelpers.gatherTextNodes(doc2.documentElement) - self.assertEqual(actual, expected) - - doc3_xml=('abdghei' + - 'cfj') - doc3=microdom.parseString(doc3_xml) - actual=domhelpers.gatherTextNodes(doc3) - expected='abdgheicfj' - self.assertEqual(actual, expected) - actual=domhelpers.gatherTextNodes(doc3.documentElement) - self.assertEqual(actual, expected) - - doc4_xml=''' - - - - stuff - - -''' - doc4=microdom.parseString(doc4_xml) - actual=domhelpers.gatherTextNodes(doc4) - expected='\n stuff\n ' - assert actual==expected, 'expected %s, got %s' % (expected, actual) - actual=domhelpers.gatherTextNodes(doc4.documentElement) - self.assertEqual(actual, expected) - - doc5_xml='Soufflé' - doc5=microdom.parseString(doc5_xml) - actual=domhelpers.gatherTextNodes(doc5) - expected='Soufflé' - self.assertEqual(actual, expected) - actual=domhelpers.gatherTextNodes(doc5.documentElement) - self.assertEqual(actual, expected) - - def test_clearNode(self): - doc1=microdom.parseString('') - a_node=doc1.documentElement - domhelpers.clearNode(a_node) - actual=doc1.documentElement.toxml() - expected='' - assert actual==expected, 'expected %s, got %s' % (expected, actual) - - doc2=microdom.parseString('') - b_node=doc2.documentElement.childNodes[0] - domhelpers.clearNode(b_node) - actual=doc2.documentElement.toxml() - expected='' - assert actual==expected, 'expected %s, got %s' % (expected, actual) - - doc3=microdom.parseString('') - c_node=doc3.documentElement.childNodes[0].childNodes[0] - domhelpers.clearNode(c_node) - actual=doc3.documentElement.toxml() - expected='' - assert actual==expected, 'expected %s, got %s' % (expected, actual) - - def test_get(self): - doc1=microdom.parseString('') - node=domhelpers.get(doc1, "foo") - actual=node.toxml() - expected='' - assert actual==expected, 'expected %s, got %s' % (expected, actual) - - node=domhelpers.get(doc1, "bar") - actual=node.toxml() - expected='' - assert actual==expected, 'expected %s, got %s' % (expected, actual) - - self.assertRaises(domhelpers.NodeLookupError, - domhelpers.get, - doc1, - "pzork") - - def test_getIfExists(self): - doc1=microdom.parseString('') - node=domhelpers.getIfExists(doc1, "foo") - actual=node.toxml() - expected='' - assert actual==expected, 'expected %s, got %s' % (expected, actual) - - node=domhelpers.getIfExists(doc1, "pzork") - assert node==None, 'expected None, didn\'t get None' - - def test_getAndClear(self): - doc1=microdom.parseString('') - node=domhelpers.getAndClear(doc1, "foo") - actual=node.toxml() - expected='' - assert actual==expected, 'expected %s, got %s' % (expected, actual) - - def test_locateNodes(self): - doc1=microdom.parseString('') - node_list=domhelpers.locateNodes(doc1.childNodes, 'foo', 'olive', - noNesting=1) - actual=''.join([node.toxml() for node in node_list]) - expected='' - assert actual==expected, 'expected %s, got %s' % (expected, actual) - - node_list=domhelpers.locateNodes(doc1.childNodes, 'foo', 'olive', - noNesting=0) - actual=''.join([node.toxml() for node in node_list]) - expected='' - assert actual==expected, 'expected %s, got %s' % (expected, actual) - - def test_getParents(self): - doc1=microdom.parseString('') - node_list=domhelpers.getParents(doc1.childNodes[0].childNodes[0].childNodes[0]) - actual=''.join([node.tagName for node in node_list - if hasattr(node, 'tagName')]) - expected='cba' - assert actual==expected, 'expected %s, got %s' % (expected, actual) - - def test_findElementsWithAttribute(self): - doc1=microdom.parseString('') - node_list=domhelpers.findElementsWithAttribute(doc1, 'foo') - actual=''.join([node.tagName for node in node_list]) - expected='abc' - assert actual==expected, 'expected %s, got %s' % (expected, actual) - - node_list=domhelpers.findElementsWithAttribute(doc1, 'foo', '1') - actual=''.join([node.tagName for node in node_list]) - expected='ac' - assert actual==expected, 'expected %s, got %s' % (expected, actual) - - def test_findNodesNamed(self): - doc1=microdom.parseString('a') - node_list=domhelpers.findNodesNamed(doc1, 'foo') - actual=len(node_list) - expected=2 - assert actual==expected, 'expected %d, got %d' % (expected, actual) - - # NOT SURE WHAT THESE ARE SUPPOSED TO DO.. - # def test_RawText FIXME - # def test_superSetAttribute FIXME - # def test_superPrependAttribute FIXME - # def test_superAppendAttribute FIXME - # def test_substitute FIXME - - def test_escape(self): - j='this string " contains many & characters> xml< won\'t like' - expected='this string " contains many & characters> xml< won\'t like' - self.assertEqual(domhelpers.escape(j), expected) - - def test_unescape(self): - j='this string " has && entities > < and some characters xml won\'t like<' - expected='this string " has && entities > < and some characters xml won\'t like<' - self.assertEqual(domhelpers.unescape(j), expected) diff --git a/tools/buildbot/pylibs/twisted/web/test/test_http.py b/tools/buildbot/pylibs/twisted/web/test/test_http.py deleted file mode 100644 index 97caba5..0000000 --- a/tools/buildbot/pylibs/twisted/web/test/test_http.py +++ /dev/null @@ -1,548 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Test HTTP support. -""" - -from urlparse import urlparse, urlunsplit, clear_cache -import string, random, urllib, cgi - -from twisted.trial import unittest -from twisted.web import http -from twisted.protocols import loopback -from twisted.internet import protocol -from twisted.test.test_protocols import StringIOWithoutClosing - - -class DateTimeTest(unittest.TestCase): - """Test date parsing functions.""" - - def testRoundtrip(self): - for i in range(10000): - time = random.randint(0, 2000000000) - timestr = http.datetimeToString(time) - time2 = http.stringToDatetime(timestr) - self.assertEquals(time, time2) - - -class OrderedDict: - - def __init__(self, dict): - self.dict = dict - self.l = dict.keys() - - def __setitem__(self, k, v): - self.l.append(k) - self.dict[k] = v - - def __getitem__(self, k): - return self.dict[k] - - def items(self): - result = [] - for i in self.l: - result.append((i, self.dict[i])) - return result - - def __getattr__(self, attr): - return getattr(self.dict, attr) - - -class DummyHTTPHandler(http.Request): - - def process(self): - self.headers = OrderedDict(self.headers) - self.content.seek(0, 0) - data = self.content.read() - length = self.getHeader('content-length') - request = "'''\n"+str(length)+"\n"+data+"'''\n" - self.setResponseCode(200) - self.setHeader("Request", self.uri) - self.setHeader("Command", self.method) - self.setHeader("Version", self.clientproto) - self.setHeader("Content-Length", len(request)) - self.write(request) - self.finish() - - -class LoopbackHTTPClient(http.HTTPClient): - - def connectionMade(self): - self.sendCommand("GET", "/foo/bar") - self.sendHeader("Content-Length", 10) - self.endHeaders() - self.transport.write("0123456789") - - -class HTTP1_0TestCase(unittest.TestCase): - - requests = '''\ -GET / HTTP/1.0 - -GET / HTTP/1.1 -Accept: text/html - -''' - requests = string.replace(requests, '\n', '\r\n') - - expected_response = "HTTP/1.0 200 OK\015\012Request: /\015\012Command: GET\015\012Version: HTTP/1.0\015\012Content-length: 13\015\012\015\012'''\012None\012'''\012" - - def test_buffer(self): - """ - Send requests over a channel and check responses match what is expected. - """ - b = StringIOWithoutClosing() - a = http.HTTPChannel() - a.requestFactory = DummyHTTPHandler - a.makeConnection(protocol.FileWrapper(b)) - # one byte at a time, to stress it. - for byte in self.requests: - a.dataReceived(byte) - a.connectionLost(IOError("all one")) - value = b.getvalue() - self.assertEquals(value, self.expected_response) - - -class HTTP1_1TestCase(HTTP1_0TestCase): - - requests = '''\ -GET / HTTP/1.1 -Accept: text/html - -POST / HTTP/1.1 -Content-Length: 10 - -0123456789POST / HTTP/1.1 -Content-Length: 10 - -0123456789HEAD / HTTP/1.1 - -''' - requests = string.replace(requests, '\n', '\r\n') - - expected_response = "HTTP/1.1 200 OK\015\012Request: /\015\012Command: GET\015\012Version: HTTP/1.1\015\012Content-length: 13\015\012\015\012'''\012None\012'''\012HTTP/1.1 200 OK\015\012Request: /\015\012Command: POST\015\012Version: HTTP/1.1\015\012Content-length: 21\015\012\015\012'''\01210\0120123456789'''\012HTTP/1.1 200 OK\015\012Request: /\015\012Command: POST\015\012Version: HTTP/1.1\015\012Content-length: 21\015\012\015\012'''\01210\0120123456789'''\012HTTP/1.1 200 OK\015\012Request: /\015\012Command: HEAD\015\012Version: HTTP/1.1\015\012Content-length: 13\015\012\015\012" - -class HTTP1_1_close_TestCase(HTTP1_0TestCase): - - requests = '''\ -GET / HTTP/1.1 -Accept: text/html -Connection: close - -GET / HTTP/1.0 - -''' - - requests = string.replace(requests, '\n', '\r\n') - - expected_response = "HTTP/1.1 200 OK\015\012Connection: close\015\012Request: /\015\012Command: GET\015\012Version: HTTP/1.1\015\012Content-length: 13\015\012\015\012'''\012None\012'''\012" - - -class HTTP0_9TestCase(HTTP1_0TestCase): - - requests = '''\ -GET / -''' - requests = string.replace(requests, '\n', '\r\n') - - expected_response = "HTTP/1.1 400 Bad Request\r\n\r\n" - - -class HTTPLoopbackTestCase(unittest.TestCase): - - expectedHeaders = {'request' : '/foo/bar', - 'command' : 'GET', - 'version' : 'HTTP/1.0', - 'content-length' : '21'} - numHeaders = 0 - gotStatus = 0 - gotResponse = 0 - gotEndHeaders = 0 - - def _handleStatus(self, version, status, message): - self.gotStatus = 1 - self.assertEquals(version, "HTTP/1.0") - self.assertEquals(status, "200") - - def _handleResponse(self, data): - self.gotResponse = 1 - self.assertEquals(data, "'''\n10\n0123456789'''\n") - - def _handleHeader(self, key, value): - self.numHeaders = self.numHeaders + 1 - self.assertEquals(self.expectedHeaders[string.lower(key)], value) - - def _handleEndHeaders(self): - self.gotEndHeaders = 1 - self.assertEquals(self.numHeaders, 4) - - def testLoopback(self): - server = http.HTTPChannel() - server.requestFactory = DummyHTTPHandler - client = LoopbackHTTPClient() - client.handleResponse = self._handleResponse - client.handleHeader = self._handleHeader - client.handleEndHeaders = self._handleEndHeaders - client.handleStatus = self._handleStatus - d = loopback.loopbackAsync(server, client) - d.addCallback(self._cbTestLoopback) - return d - - def _cbTestLoopback(self, ignored): - if not (self.gotStatus and self.gotResponse and self.gotEndHeaders): - raise RuntimeError( - "didn't got all callbacks %s" - % [self.gotStatus, self.gotResponse, self.gotEndHeaders]) - del self.gotEndHeaders - del self.gotResponse - del self.gotStatus - del self.numHeaders - - -class PRequest: - """Dummy request for persistence tests.""" - - def __init__(self, **headers): - self.received_headers = headers - self.headers = {} - - def getHeader(self, k): - return self.received_headers.get(k, '') - - def setHeader(self, k, v): - self.headers[k] = v - - -class PersistenceTestCase(unittest.TestCase): - """Tests for persistent HTTP connections.""" - - ptests = [#(PRequest(connection="Keep-Alive"), "HTTP/1.0", 1, {'connection' : 'Keep-Alive'}), - (PRequest(), "HTTP/1.0", 0, {'connection': None}), - (PRequest(connection="close"), "HTTP/1.1", 0, {'connection' : 'close'}), - (PRequest(), "HTTP/1.1", 1, {'connection': None}), - (PRequest(), "HTTP/0.9", 0, {'connection': None}), - ] - - - def testAlgorithm(self): - c = http.HTTPChannel() - for req, version, correctResult, resultHeaders in self.ptests: - result = c.checkPersistence(req, version) - self.assertEquals(result, correctResult) - for header in resultHeaders.keys(): - self.assertEquals(req.headers.get(header, None), resultHeaders[header]) - - -class ChunkingTestCase(unittest.TestCase): - - strings = ["abcv", "", "fdfsd423", "Ffasfas\r\n", - "523523\n\rfsdf", "4234"] - - def testChunks(self): - for s in self.strings: - self.assertEquals((s, ''), http.fromChunk(''.join(http.toChunk(s)))) - self.assertRaises(ValueError, http.fromChunk, '-5\r\nmalformed!\r\n') - - def testConcatenatedChunks(self): - chunked = ''.join([''.join(http.toChunk(t)) for t in self.strings]) - result = [] - buffer = "" - for c in chunked: - buffer = buffer + c - try: - data, buffer = http.fromChunk(buffer) - result.append(data) - except ValueError: - pass - self.assertEquals(result, self.strings) - - - -class ParsingTestCase(unittest.TestCase): - - def runRequest(self, httpRequest, requestClass, success=1): - httpRequest = httpRequest.replace("\n", "\r\n") - b = StringIOWithoutClosing() - a = http.HTTPChannel() - a.requestFactory = requestClass - a.makeConnection(protocol.FileWrapper(b)) - # one byte at a time, to stress it. - for byte in httpRequest: - if a.transport.closed: - break - a.dataReceived(byte) - a.connectionLost(IOError("all done")) - if success: - self.assertEquals(self.didRequest, 1) - del self.didRequest - else: - self.assert_(not hasattr(self, "didRequest")) - - def testBasicAuth(self): - testcase = self - class Request(http.Request): - l = [] - def process(self): - testcase.assertEquals(self.getUser(), self.l[0]) - testcase.assertEquals(self.getPassword(), self.l[1]) - for u, p in [("foo", "bar"), ("hello", "there:z")]: - Request.l[:] = [u, p] - s = "%s:%s" % (u, p) - f = "GET / HTTP/1.0\nAuthorization: Basic %s\n\n" % (s.encode("base64").strip(), ) - self.runRequest(f, Request, 0) - - def testTooManyHeaders(self): - httpRequest = "GET / HTTP/1.0\n" - for i in range(502): - httpRequest += "%s: foo\n" % i - httpRequest += "\n" - class MyRequest(http.Request): - def process(self): - raise RuntimeError, "should not get called" - self.runRequest(httpRequest, MyRequest, 0) - - def testHeaders(self): - httpRequest = """\ -GET / HTTP/1.0 -Foo: bar -baz: 1 2 3 - -""" - testcase = self - - class MyRequest(http.Request): - def process(self): - testcase.assertEquals(self.getHeader('foo'), 'bar') - testcase.assertEquals(self.getHeader('Foo'), 'bar') - testcase.assertEquals(self.getHeader('bAz'), '1 2 3') - testcase.didRequest = 1 - self.finish() - - self.runRequest(httpRequest, MyRequest) - - def testCookies(self): - """ - Test cookies parsing and reading. - """ - httpRequest = '''\ -GET / HTTP/1.0 -Cookie: rabbit="eat carrot"; ninja=secret; spam="hey 1=1!" - -''' - testcase = self - - class MyRequest(http.Request): - def process(self): - testcase.assertEquals(self.getCookie('rabbit'), '"eat carrot"') - testcase.assertEquals(self.getCookie('ninja'), 'secret') - testcase.assertEquals(self.getCookie('spam'), '"hey 1=1!"') - testcase.didRequest = 1 - self.finish() - - self.runRequest(httpRequest, MyRequest) - - def testGET(self): - httpRequest = '''\ -GET /?key=value&multiple=two+words&multiple=more%20words&empty= HTTP/1.0 - -''' - testcase = self - class MyRequest(http.Request): - def process(self): - testcase.assertEquals(self.method, "GET") - testcase.assertEquals(self.args["key"], ["value"]) - testcase.assertEquals(self.args["empty"], [""]) - testcase.assertEquals(self.args["multiple"], ["two words", "more words"]) - testcase.didRequest = 1 - self.finish() - - self.runRequest(httpRequest, MyRequest) - - - def test_extraQuestionMark(self): - """ - While only a single '?' is allowed in an URL, several other servers - allow several and pass all after the first through as part of the - query arguments. Test that we emulate this behavior. - """ - httpRequest = 'GET /foo?bar=?&baz=quux HTTP/1.0\n\n' - - testcase = self - class MyRequest(http.Request): - def process(self): - testcase.assertEqual(self.method, 'GET') - testcase.assertEqual(self.path, '/foo') - testcase.assertEqual(self.args['bar'], ['?']) - testcase.assertEqual(self.args['baz'], ['quux']) - testcase.didRequest = 1 - self.finish() - - self.runRequest(httpRequest, MyRequest) - - - def testPOST(self): - query = 'key=value&multiple=two+words&multiple=more%20words&empty=' - httpRequest = '''\ -POST / HTTP/1.0 -Content-Length: %d -Content-Type: application/x-www-form-urlencoded - -%s''' % (len(query), query) - - testcase = self - class MyRequest(http.Request): - def process(self): - testcase.assertEquals(self.method, "POST") - testcase.assertEquals(self.args["key"], ["value"]) - testcase.assertEquals(self.args["empty"], [""]) - testcase.assertEquals(self.args["multiple"], ["two words", "more words"]) - testcase.didRequest = 1 - self.finish() - - self.runRequest(httpRequest, MyRequest) - - def testMissingContentDisposition(self): - req = '''\ -POST / HTTP/1.0 -Content-Type: multipart/form-data; boundary=AaB03x -Content-Length: 103 - ---AaB03x -Content-Type: text/plain -Content-Transfer-Encoding: quoted-printable - -abasdfg ---AaB03x-- -''' - self.runRequest(req, http.Request, success=False) - -class QueryArgumentsTestCase(unittest.TestCase): - def testUnquote(self): - try: - from twisted.protocols import _c_urlarg - except ImportError: - raise unittest.SkipTest("_c_urlarg module is not available") - # work exactly like urllib.unquote, including stupid things - # % followed by a non-hexdigit in the middle and in the end - self.failUnlessEqual(urllib.unquote("%notreally%n"), - _c_urlarg.unquote("%notreally%n")) - # % followed by hexdigit, followed by non-hexdigit - self.failUnlessEqual(urllib.unquote("%1quite%1"), - _c_urlarg.unquote("%1quite%1")) - # unquoted text, followed by some quoted chars, ends in a trailing % - self.failUnlessEqual(urllib.unquote("blah%21%40%23blah%"), - _c_urlarg.unquote("blah%21%40%23blah%")) - # Empty string - self.failUnlessEqual(urllib.unquote(""), _c_urlarg.unquote("")) - - def testParseqs(self): - self.failUnlessEqual(cgi.parse_qs("a=b&d=c;+=f"), - http.parse_qs("a=b&d=c;+=f")) - self.failUnlessRaises(ValueError, http.parse_qs, "blah", - strict_parsing = 1) - self.failUnlessEqual(cgi.parse_qs("a=&b=c", keep_blank_values = 1), - http.parse_qs("a=&b=c", keep_blank_values = 1)) - self.failUnlessEqual(cgi.parse_qs("a=&b=c"), - http.parse_qs("a=&b=c")) - - - def test_urlparse(self): - """ - For a given URL, L{http.urlparse} should behave the same as - L{urlparse}, except it should always return C{str}, never C{unicode}. - """ - def urls(): - for scheme in ('http', 'https'): - for host in ('example.com',): - for port in (None, 100): - for path in ('', 'path'): - if port is not None: - host = host + ':' + str(port) - yield urlunsplit((scheme, host, path, '', '')) - - - def assertSameParsing(url, decode): - """ - Verify that C{url} is parsed into the same objects by both - L{http.urlparse} and L{urlparse}. - """ - urlToStandardImplementation = url - if decode: - urlToStandardImplementation = url.decode('ascii') - standardResult = urlparse(urlToStandardImplementation) - scheme, netloc, path, params, query, fragment = http.urlparse(url) - self.assertEqual( - (scheme, netloc, path, params, query, fragment), - standardResult) - self.assertTrue(isinstance(scheme, str)) - self.assertTrue(isinstance(netloc, str)) - self.assertTrue(isinstance(path, str)) - self.assertTrue(isinstance(params, str)) - self.assertTrue(isinstance(query, str)) - self.assertTrue(isinstance(fragment, str)) - - # With caching, unicode then str - clear_cache() - for url in urls(): - assertSameParsing(url, True) - assertSameParsing(url, False) - - # With caching, str then unicode - clear_cache() - for url in urls(): - assertSameParsing(url, False) - assertSameParsing(url, True) - - # Without caching - for url in urls(): - clear_cache() - assertSameParsing(url, True) - clear_cache() - assertSameParsing(url, False) - - - def test_urlparseRejectsUnicode(self): - """ - L{http.urlparse} should reject unicode input early. - """ - self.assertRaises(TypeError, http.urlparse, u'http://example.org/path') - - - def testEscchar(self): - try: - from twisted.protocols import _c_urlarg - except ImportError: - raise unittest.SkipTest("_c_urlarg module is not available") - self.failUnlessEqual("!@#+b", - _c_urlarg.unquote("+21+40+23+b", "+")) - -class ClientDriver(http.HTTPClient): - def handleStatus(self, version, status, message): - self.version = version - self.status = status - self.message = message - -class ClientStatusParsing(unittest.TestCase): - def testBaseline(self): - c = ClientDriver() - c.lineReceived('HTTP/1.0 201 foo') - self.failUnlessEqual(c.version, 'HTTP/1.0') - self.failUnlessEqual(c.status, '201') - self.failUnlessEqual(c.message, 'foo') - - def testNoMessage(self): - c = ClientDriver() - c.lineReceived('HTTP/1.0 201') - self.failUnlessEqual(c.version, 'HTTP/1.0') - self.failUnlessEqual(c.status, '201') - self.failUnlessEqual(c.message, '') - - def testNoMessage_trailingSpace(self): - c = ClientDriver() - c.lineReceived('HTTP/1.0 201 ') - self.failUnlessEqual(c.version, 'HTTP/1.0') - self.failUnlessEqual(c.status, '201') - self.failUnlessEqual(c.message, '') - diff --git a/tools/buildbot/pylibs/twisted/web/test/test_mvc.py b/tools/buildbot/pylibs/twisted/web/test/test_mvc.py deleted file mode 100644 index 312eaf9..0000000 --- a/tools/buildbot/pylibs/twisted/web/test/test_mvc.py +++ /dev/null @@ -1,122 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Test cases for Twisted Model-View-Controller architecture.""" - -import random - -try: - import cPickle as pickle -except ImportError: - import pickle - -from twisted.trial import unittest - -from twisted.web.woven import model, view, controller, interfaces -from twisted.python import components - -# simple pickled string storage to test persistence -persisted_model = "" - -class MyModel(model.Model): - def __init__(self, foo, random=None): - # I hate having to explicitly initialize the super - model.Model.__init__(self) - self.foo=foo - self.random=random - -class MyView(view.View): - def __init__(self, model, *args, **kwargs): - view.View.__init__(self, model, *args, **kwargs) - self.model.addView(self) - # pretend self.foo is what the user now sees on their screen - self.foo = self.model.foo - self.random = self.model.random - self.controller = interfaces.IController(self.model, None) - - def modelChanged(self, changed): - if changed.has_key('foo'): - self.foo = changed['foo'] - if changed.has_key('random'): - self.random = changed['random'] - - def twiddleControl(self, newValue): - """ - The user twiddled a control onscreen, causing this event - """ - self.controller.setFoo(newValue) - - def pushButton(self): - """ - The user hit a button onscreen, causing this event - """ - return self.controller.doRandom() - -# Register MyView as the view for instances of type MyModel -components.registerAdapter(MyView, MyModel, interfaces.IView) - -class MyController(controller.Controller): - def setFoo(self, newValue): - self.model.foo = newValue - self.model.notify({'foo': newValue}) - self.persist() - - def doRandom(self): - rnd = random.choice(range(100)) - self.model.random = rnd - self.model.notify({'random': rnd}) - self.persist() - return rnd - - def persist(self): - """ - Save the model object to persistent storage - """ - global persisted_model - - persisted_model = pickle.dumps(self.model) - -# Register MyController as the controller for instances of type MyModel -components.registerAdapter(MyController, MyModel, interfaces.IController) - -class MVCTestCase(unittest.TestCase): - """Test MVC.""" - def setUp(self): - self.model = MyModel("foo") - - def getView(self): - return interfaces.IView(self.model, None) - - def testViewConstruction(self): - view = self.getView() - self.assert_(isinstance(view, MyView)) - - def testControllerConstruction(self): - view = self.getView() - self.assert_(isinstance(view.controller, MyController)) - - def testModelManipulation(self): - view = self.getView() - view.twiddleControl("bar") - self.assertEquals("bar", self.model.foo) - - def testMoreModelManipulation(self): - view = self.getView() - value = view.pushButton() - self.assertEquals(value, self.model.random) - - def testViewManipulation(self): - """When the model updates the view should too""" - view = self.getView() - view.twiddleControl("bar") - self.assertEquals("bar", view.foo) - - def testMoreViewManipulation(self): - """When the model updates the view should too""" - view = self.getView() - value = view.pushButton() - self.assertEquals(value, view.random) - - -testCases = [MVCTestCase] diff --git a/tools/buildbot/pylibs/twisted/web/test/test_proxy.py b/tools/buildbot/pylibs/twisted/web/test/test_proxy.py deleted file mode 100644 index 4b0194b..0000000 --- a/tools/buildbot/pylibs/twisted/web/test/test_proxy.py +++ /dev/null @@ -1,407 +0,0 @@ -# Copyright (c) 2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test for L{twisted.web.proxy}. -""" - -from twisted.trial.unittest import TestCase -from twisted.test.proto_helpers import StringTransportWithDisconnection -from twisted.internet.error import ConnectionDone - -from twisted.web.resource import Resource -from twisted.web.server import Site -from twisted.web.proxy import ReverseProxyResource, ProxyClientFactory -from twisted.web.proxy import ProxyClient, ProxyRequest, ReverseProxyRequest - - - -class FakeReactor(object): - """ - A fake reactor to be used in tests. - - @ivar connect: a list that keeps track of connection attempts (ie, calls - to C{connectTCP}). - @type connect: C{list} - """ - - def __init__(self): - """ - Initialize the C{connect} list. - """ - self.connect = [] - - - def connectTCP(self, host, port, factory): - """ - Fake L{reactor.connectTCP}, that does nothing but log the call. - """ - self.connect.append([host, port, factory]) - - - -class ReverseProxyResourceTestCase(TestCase): - """ - Tests for L{ReverseProxyResource}. - """ - - def _testRender(self, uri, expectedURI): - """ - Check that a request pointing at C{uri} produce a new proxy connection, - with the path of this request pointing at C{expectedURI}. - """ - root = Resource() - reactor = FakeReactor() - resource = ReverseProxyResource("127.0.0.1", 1234, "/path", reactor) - root.putChild('index', resource) - site = Site(root) - - transport = StringTransportWithDisconnection() - channel = site.buildProtocol(None) - channel.makeConnection(transport) - # Clear the timeout if the tests failed - self.addCleanup(channel.connectionLost, None) - - channel.dataReceived("GET %s HTTP/1.1\r\nAccept: text/html\r\n\r\n" % - (uri,)) - - # Check that one connection has been created, to the good host/port - self.assertEquals(len(reactor.connect), 1) - self.assertEquals(reactor.connect[0][0], "127.0.0.1") - self.assertEquals(reactor.connect[0][1], 1234) - - # Check the factory passed to the connect, and its given path - factory = reactor.connect[0][2] - self.assertIsInstance(factory, ProxyClientFactory) - self.assertEquals(factory.rest, expectedURI) - self.assertEquals(factory.headers["host"], "127.0.0.1:1234") - - - def test_render(self): - """ - Test that L{ReverseProxyResource.render} initiates a connection to the - given server with a L{ProxyClientFactory} as parameter. - """ - return self._testRender("/index", "/path") - - - def test_renderWithQuery(self): - """ - Test that L{ReverseProxyResource.render} passes query parameters to the - created factory. - """ - return self._testRender("/index?foo=bar", "/path?foo=bar") - - - def test_getChild(self): - """ - The L{ReverseProxyResource.getChild} method should return a resource - instance with the same class as the originating resource, forward port - and host values, and update the path value with the value passed. - """ - resource = ReverseProxyResource("127.0.0.1", 1234, "/path") - child = resource.getChild('foo', None) - # The child should keep the same class - self.assertIsInstance(child, ReverseProxyResource) - self.assertEquals(child.path, "/path/foo") - self.assertEquals(child.port, 1234) - self.assertEquals(child.host, "127.0.0.1") - - - def test_getChildWithSpecial(self): - """ - The L{ReverseProxyResource} return by C{getChild} has a path which has - already been quoted. - """ - resource = ReverseProxyResource("127.0.0.1", 1234, "/path") - child = resource.getChild(' /%', None) - self.assertEqual(child.path, "/path/%20%2F%25") - - - -class DummyParent(object): - """ - A dummy parent request that holds a channel and its transport. - - @ivar channel: the request channel. - @ivar transport: the transport of the channel. - """ - - def __init__(self, channel): - """ - Hold a reference to the channel and its transport. - """ - self.channel = channel - self.transport = channel.transport - - - -class DummyChannel(object): - """ - A dummy HTTP channel, that does nothing but holds a transport and saves - connection lost. - - @ivar transport: the transport used by the client. - @ivar lostReason: the reason saved at connection lost. - """ - - def __init__(self, transport): - """ - Hold a reference to the transport. - """ - self.transport = transport - self.lostReason = None - - - def connectionLost(self, reason): - """ - Keep track of the connection lost reason. - """ - self.lostReason = reason - - - -class ProxyClientTestCase(TestCase): - """ - Tests for L{ProxyClient}. - """ - - def _testDataForward(self, data, method="GET", body=""): - """ - Build a fake proxy connection, and send C{data} over it, checking that - it's forwarded to the originating request. - """ - # Connect everything - clientTransport = StringTransportWithDisconnection() - serverTransport = StringTransportWithDisconnection() - channel = DummyChannel(serverTransport) - parent = DummyParent(channel) - serverTransport.protocol = channel - - client = ProxyClient(method, '/foo', 'HTTP/1.0', - {"accept": "text/html"}, body, parent) - clientTransport.protocol = client - client.makeConnection(clientTransport) - - # Check data sent - self.assertEquals(clientTransport.value(), - "%s /foo HTTP/1.0\r\n" - "connection: close\r\n" - "accept: text/html\r\n\r\n%s" % (method, body)) - - # Fake an answer - client.dataReceived(data) - - # Check that the data has been forwarded - self.assertEquals(serverTransport.value(), data) - - clientTransport.loseConnection() - self.assertIsInstance(channel.lostReason, ConnectionDone) - - - def test_forward(self): - """ - When connected to the server, L{ProxyClient} should send the saved - request, with modifications of the headers, and then forward the result - to the parent request. - """ - return self._testDataForward("200 OK\r\nFoo: bar\r\n\r\nSome data\r\n") - - - def test_postData(self): - """ - Try to post content in the request, and check that the proxy client - forward the body of the request. - """ - return self._testDataForward( - "200 OK\r\nFoo: bar\r\n\r\nSome data\r\n", "POST", "Some content") - - - def test_statusWithMessage(self): - """ - If the response contains a status with a message, it should be - forwarded to the parent request with all the information. - """ - return self._testDataForward("404 Not Found\r\n") - - - def test_headersCleanups(self): - """ - The headers given at initialization should be modified: - B{proxy-connection} should be removed if present, and B{connection} - should be added. - """ - client = ProxyClient('GET', '/foo', 'HTTP/1.0', - {"accept": "text/html", "proxy-connection": "foo"}, '', None) - self.assertEquals(client.headers, - {"accept": "text/html", "connection": "close"}) - - - -class ProxyClientFactoryTestCase(TestCase): - """ - Tests for L{ProxyClientFactory}. - """ - - def test_connectionFailed(self): - """ - Check that L{ProxyClientFactory.clientConnectionFailed} produces - a B{501} response to the parent request. - """ - serverTransport = StringTransportWithDisconnection() - channel = DummyChannel(serverTransport) - parent = DummyParent(channel) - serverTransport.protocol = channel - factory = ProxyClientFactory('GET', '/foo', 'HTTP/1.0', - {"accept": "text/html"}, '', parent) - - factory.clientConnectionFailed(None, None) - self.assertEquals(serverTransport.value(), - "HTTP/1.0 501 Gateway error\r\n" - "Content-Type: text/html\r\n\r\n" - "

                  Could not connect

                  ") - self.assertIsInstance(channel.lostReason, ConnectionDone) - - - def test_buildProtocol(self): - """ - L{ProxyClientFactory.buildProtocol} should produce a L{ProxyClient} - with the same values of attributes (with updates on the headers). - """ - factory = ProxyClientFactory('GET', '/foo', 'HTTP/1.0', - {"accept": "text/html"}, 'Some data', - None) - proto = factory.buildProtocol(None) - self.assertIsInstance(proto, ProxyClient) - self.assertEquals(proto.command, 'GET') - self.assertEquals(proto.rest, '/foo') - self.assertEquals(proto.data, 'Some data') - self.assertEquals(proto.headers, - {"accept": "text/html", "connection": "close"}) - - - -class ProxyRequestTestCase(TestCase): - """ - Tests for L{ProxyRequest}. - """ - - def _testProcess(self, uri, expectedURI, method="GET", data=""): - """ - Build a request pointing at C{uri}, and check that a proxied request - is created, pointing a C{expectedURI}. - """ - transport = StringTransportWithDisconnection() - channel = DummyChannel(transport) - reactor = FakeReactor() - request = ProxyRequest(channel, False, reactor) - request.gotLength(len(data)) - request.handleContentChunk(data) - request.requestReceived(method, 'http://example.com%s' % (uri,), - 'HTTP/1.0') - - self.assertEquals(len(reactor.connect), 1) - self.assertEquals(reactor.connect[0][0], "example.com") - self.assertEquals(reactor.connect[0][1], 80) - - factory = reactor.connect[0][2] - self.assertIsInstance(factory, ProxyClientFactory) - self.assertEquals(factory.command, method) - self.assertEquals(factory.version, 'HTTP/1.0') - self.assertEquals(factory.headers, {'host': 'example.com'}) - self.assertEquals(factory.data, data) - self.assertEquals(factory.rest, expectedURI) - self.assertEquals(factory.father, request) - - - def test_process(self): - """ - L{ProxyRequest.process} should create a connection to the given server, - with a L{ProxyClientFactory} as connection factory, with the correct - parameters: - - forward comment, version and data values - - update headers with the B{host} value - - remove the host from the URL - - pass the request as parent request - """ - return self._testProcess("/foo/bar", "/foo/bar") - - - def test_processWithoutTrailingSlash(self): - """ - If the incoming request doesn't contain a slash, - L{ProxyRequest.process} should add one when instantiating - L{ProxyClientFactory}. - """ - return self._testProcess("", "/") - - - def test_processWithData(self): - """ - L{ProxyRequest.process} should be able to retrieve request body and - to forward it. - """ - return self._testProcess( - "/foo/bar", "/foo/bar", "POST", "Some content") - - - def test_processWithPort(self): - """ - Check that L{ProxyRequest.process} correctly parse port in the incoming - URL, and create a outgoing connection with this port. - """ - transport = StringTransportWithDisconnection() - channel = DummyChannel(transport) - reactor = FakeReactor() - request = ProxyRequest(channel, False, reactor) - request.gotLength(0) - request.requestReceived('GET', 'http://example.com:1234/foo/bar', - 'HTTP/1.0') - - # That should create one connection, with the port parsed from the URL - self.assertEquals(len(reactor.connect), 1) - self.assertEquals(reactor.connect[0][0], "example.com") - self.assertEquals(reactor.connect[0][1], 1234) - - - -class DummyFactory(object): - """ - A simple holder for C{host} and C{port} information. - """ - - def __init__(self, host, port): - self.host = host - self.port = port - - - -class ReverseProxyRequestTestCase(TestCase): - """ - Tests for L{ReverseProxyRequest}. - """ - - def test_process(self): - """ - L{ReverseProxyRequest.process} should create a connection to its - factory host/port, using a L{ProxyClientFactory} instantiated with the - correct parameters, and particulary set the B{host} header to the - factory host. - """ - transport = StringTransportWithDisconnection() - channel = DummyChannel(transport) - reactor = FakeReactor() - request = ReverseProxyRequest(channel, False, reactor) - request.factory = DummyFactory("example.com", 1234) - request.gotLength(0) - request.requestReceived('GET', '/foo/bar', 'HTTP/1.0') - - # Check that one connection has been created, to the good host/port - self.assertEquals(len(reactor.connect), 1) - self.assertEquals(reactor.connect[0][0], "example.com") - self.assertEquals(reactor.connect[0][1], 1234) - - # Check the factory passed to the connect, and its headers - factory = reactor.connect[0][2] - self.assertIsInstance(factory, ProxyClientFactory) - self.assertEquals(factory.headers, {'host': 'example.com'}) diff --git a/tools/buildbot/pylibs/twisted/web/test/test_soap.py b/tools/buildbot/pylibs/twisted/web/test/test_soap.py deleted file mode 100644 index 54e990e..0000000 --- a/tools/buildbot/pylibs/twisted/web/test/test_soap.py +++ /dev/null @@ -1,114 +0,0 @@ -# -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. -# - -"""Test SOAP support.""" - -try: - import SOAPpy -except ImportError: - SOAPpy = None - class SOAPPublisher: pass -else: - from twisted.web import soap - SOAPPublisher = soap.SOAPPublisher - -from twisted.trial import unittest -from twisted.web import server, error -from twisted.internet import reactor, defer - - -class Test(SOAPPublisher): - - def soap_add(self, a, b): - return a + b - - def soap_kwargs(self, a=1, b=2): - return a + b - soap_kwargs.useKeywords=True - - def soap_triple(self, string, num): - return [string, num, None] - - def soap_struct(self): - return SOAPpy.structType({"a": "c"}) - - def soap_defer(self, x): - return defer.succeed(x) - - def soap_deferFail(self): - return defer.fail(ValueError()) - - def soap_fail(self): - raise RuntimeError - - def soap_deferFault(self): - return defer.fail(ValueError()) - - def soap_complex(self): - return {"a": ["b", "c", 12, []], "D": "foo"} - - def soap_dict(self, map, key): - return map[key] - - -class SOAPTestCase(unittest.TestCase): - - def setUp(self): - self.publisher = Test() - self.p = reactor.listenTCP(0, server.Site(self.publisher), - interface="127.0.0.1") - self.port = self.p.getHost().port - - def tearDown(self): - return self.p.stopListening() - - def proxy(self): - return soap.Proxy("http://127.0.0.1:%d/" % self.port) - - def testResults(self): - inputOutput = [ - ("add", (2, 3), 5), - ("defer", ("a",), "a"), - ("dict", ({"a": 1}, "a"), 1), - ("triple", ("a", 1), ["a", 1, None])] - - dl = [] - for meth, args, outp in inputOutput: - d = self.proxy().callRemote(meth, *args) - d.addCallback(self.assertEquals, outp) - dl.append(d) - - # SOAPpy kinda blows. - d = self.proxy().callRemote('complex') - d.addCallback(lambda result: result._asdict()) - d.addCallback(self.assertEquals, {"a": ["b", "c", 12, []], "D": "foo"}) - dl.append(d) - - # We now return to our regularly scheduled program, already in progress. - return defer.DeferredList(dl, fireOnOneErrback=True) - - def testMethodNotFound(self): - """ - Check that a non existing method return error 500. - """ - d = self.proxy().callRemote('doesntexist') - self.assertFailure(d, error.Error) - def cb(err): - self.assertEquals(int(err.status), 500) - d.addCallback(cb) - return d - - def testLookupFunction(self): - """ - Test lookupFunction method on publisher, to see available remote - methods. - """ - self.assertTrue(self.publisher.lookupFunction("add")) - self.assertTrue(self.publisher.lookupFunction("fail")) - self.assertFalse(self.publisher.lookupFunction("foobar")) - -if not SOAPpy: - SOAPTestCase.skip = "SOAPpy not installed" - diff --git a/tools/buildbot/pylibs/twisted/web/test/test_static.py b/tools/buildbot/pylibs/twisted/web/test/test_static.py deleted file mode 100644 index eb0463a..0000000 --- a/tools/buildbot/pylibs/twisted/web/test/test_static.py +++ /dev/null @@ -1,64 +0,0 @@ -from twisted.trial import unittest -import os -from twisted.web import static - -class FakeRequest: - method = 'GET' - - _headers = None - _setHeaders = None - _written = '' - - def __init__(self): - self._headers = {} - self._setHeaders = {} - - def getHeader(self, k): - if self._headers is None: - return None - return self._headers.get(k) - - def setHeader(self, k, v): - self._setHeaders.setdefault(k, []).append(v) - - def setLastModified(self, x): - pass - def registerProducer(self, producer, x): - producer.resumeProducing() - def unregisterProducer(self): - pass - def finish(self): - pass - - def write(self, data): - self._written = self._written + data - -class Range(unittest.TestCase): - todo = (unittest.FailTest, 'No range support yet.') - - def setUp(self): - self.tmpdir = self.mktemp() - os.mkdir(self.tmpdir) - name = os.path.join(self.tmpdir, 'junk') - f = file(name, 'w') - f.write(8000 * 'x') - f.close() - self.file = static.File(name) - self.request = FakeRequest() - - def testBodyLength(self): - self.request._headers['range'] = 'bytes=0-1999' - self.file.render(self.request) - self.assertEquals(len(self.request._written), 2000) - - def testContentLength(self): - """Content-Length of a request is correct.""" - self.request._headers['range'] = 'bytes=0-1999' - self.file.render(self.request) - self.assertEquals(self.request._setHeaders['content-length'], ['2000']) - - def testContentRange(self): - """Content-Range of a request is correct.""" - self.request._headers['range'] = 'bytes=0-1999' - self.file.render(self.request) - self.assertEquals(self.request._setHeaders.get('content-range'), ['bytes 0-1999/8000']) diff --git a/tools/buildbot/pylibs/twisted/web/test/test_tap.py b/tools/buildbot/pylibs/twisted/web/test/test_tap.py deleted file mode 100644 index 553f9ca..0000000 --- a/tools/buildbot/pylibs/twisted/web/test/test_tap.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (c) 2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.web.tap}. -""" - -from twisted.trial.unittest import TestCase - -from twisted.web.server import Site -from twisted.web.static import Data -from twisted.web.distrib import ResourcePublisher -from twisted.web.tap import makePersonalServerFactory - -from twisted.spread.pb import PBServerFactory - - -class ServiceTests(TestCase): - """ - Tests for the service creation APIs in L{twisted.web.tap}. - """ - def test_makePersonalServerFactory(self): - """ - L{makePersonalServerFactory} returns a PB server factory which has - as its root object a L{ResourcePublisher}. - """ - # The fact that this pile of objects can actually be used somehow is - # verified by twisted.web.test.test_distrib. - site = Site(Data("foo bar", "text/plain")) - serverFactory = makePersonalServerFactory(site) - self.assertIsInstance(serverFactory, PBServerFactory) - self.assertIsInstance(serverFactory.root, ResourcePublisher) - self.assertIdentical(serverFactory.root.site, site) diff --git a/tools/buildbot/pylibs/twisted/web/test/test_web.py b/tools/buildbot/pylibs/twisted/web/test/test_web.py deleted file mode 100644 index 2bbb390..0000000 --- a/tools/buildbot/pylibs/twisted/web/test/test_web.py +++ /dev/null @@ -1,611 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.trial import unittest -from cStringIO import StringIO - -from twisted.web import server, resource, util -from twisted.internet import defer, interfaces, error, task -from twisted.web import http -from twisted.python import log -from twisted.internet.address import IPv4Address -from zope.interface import implements - -class DummyRequest: - uri='http://dummy/' - method = 'GET' - - def getHeader(self, h): - return None - - def registerProducer(self, prod,s): - self.go = 1 - while self.go: - prod.resumeProducing() - - def unregisterProducer(self): - self.go = 0 - - def __init__(self, postpath, session=None): - self.sitepath = [] - self.written = [] - self.finished = 0 - self.postpath = postpath - self.prepath = [] - self.session = None - self.protoSession = session or server.Session(0, self) - self.args = {} - self.outgoingHeaders = {} - - def setHeader(self, name, value): - """TODO: make this assert on write() if the header is content-length - """ - self.outgoingHeaders[name.lower()] = value - - def getSession(self): - if self.session: - return self.session - assert not self.written, "Session cannot be requested after data has been written." - self.session = self.protoSession - return self.session - def write(self, data): - self.written.append(data) - def finish(self): - self.finished = self.finished + 1 - def addArg(self, name, value): - self.args[name] = [value] - def setResponseCode(self, code): - assert not self.written, "Response code cannot be set after data has been written: %s." % "@@@@".join(self.written) - def setLastModified(self, when): - assert not self.written, "Last-Modified cannot be set after data has been written: %s." % "@@@@".join(self.written) - def setETag(self, tag): - assert not self.written, "ETag cannot be set after data has been written: %s." % "@@@@".join(self.written) - -class ResourceTestCase(unittest.TestCase): - def testListEntities(self): - r = resource.Resource() - self.failUnlessEqual([], r.listEntities()) - - -class SimpleResource(resource.Resource): - def render(self, request): - if http.CACHED in (request.setLastModified(10), - request.setETag('MatchingTag')): - return '' - else: - return "correct" - -class SiteTest(unittest.TestCase): - def testSimplestSite(self): - sres1 = SimpleResource() - sres2 = SimpleResource() - sres1.putChild("",sres2) - site = server.Site(sres1) - assert site.getResourceFor(DummyRequest([''])) is sres2, "Got the wrong resource." - - - -class SessionTest(unittest.TestCase): - - def setUp(self): - """ - Set up a session using a simulated scheduler. Creates a - C{times} attribute which specifies the return values of the - session's C{_getTime} method. - """ - clock = self.clock = task.Clock() - times = self.times = [] - - class MockSession(server.Session): - """ - A mock L{server.Session} object which fakes out scheduling - with the C{clock} attribute and fakes out the current time - to be the elements of L{SessionTest}'s C{times} attribute. - """ - def loopFactory(self, *a, **kw): - """ - Create a L{task.LoopingCall} which uses - L{SessionTest}'s C{clock} attribute. - """ - call = task.LoopingCall(*a, **kw) - call.clock = clock - return call - - def _getTime(self): - return times.pop(0) - - self.site = server.Site(SimpleResource()) - self.site.sessionFactory = MockSession - - - def test_basicExpiration(self): - """ - Test session expiration: setup a session, and simulate an expiration - time. - """ - self.times.extend([0, server.Session.sessionTimeout + 1]) - session = self.site.makeSession() - hasExpired = [False] - def cbExpire(): - hasExpired[0] = True - session.notifyOnExpire(cbExpire) - self.clock.advance(server.Site.sessionCheckTime - 1) - # Looping call should not have been executed - self.failIf(hasExpired[0]) - - self.clock.advance(1) - - self.failUnless(hasExpired[0]) - - - def test_delayedCallCleanup(self): - """ - Checking to make sure Sessions do not leave extra DelayedCalls. - """ - self.times.extend([0, 100]) - - session = self.site.makeSession() - loop = session.checkExpiredLoop - session.touch() - self.failUnless(loop.running) - - session.expire() - - self.failIf(self.clock.calls) - self.failIf(loop.running) - - - -# Conditional requests: -# If-None-Match, If-Modified-Since - -# make conditional request: -# normal response if condition succeeds -# if condition fails: -# response code -# no body - -def httpBody(whole): - return whole.split('\r\n\r\n', 1)[1] - -def httpHeader(whole, key): - key = key.lower() - headers = whole.split('\r\n\r\n', 1)[0] - for header in headers.split('\r\n'): - if header.lower().startswith(key): - return header.split(':', 1)[1].strip() - return None - -def httpCode(whole): - l1 = whole.split('\r\n', 1)[0] - return int(l1.split()[1]) - -class ConditionalTest(unittest.TestCase): - """web.server's handling of conditional requests for cache validation.""" - - # XXX: test web.distrib. - - def setUp(self): - self.resrc = SimpleResource() - self.resrc.putChild('', self.resrc) - self.site = server.Site(self.resrc) - self.site = server.Site(self.resrc) - self.site.logFile = log.logfile - - # HELLLLLLLLLLP! This harness is Very Ugly. - self.channel = self.site.buildProtocol(None) - self.transport = http.StringTransport() - self.transport.close = lambda *a, **kw: None - self.transport.disconnecting = lambda *a, **kw: 0 - self.transport.getPeer = lambda *a, **kw: "peer" - self.transport.getHost = lambda *a, **kw: "host" - self.channel.makeConnection(self.transport) - for l in ["GET / HTTP/1.1", - "Accept: text/html"]: - self.channel.lineReceived(l) - - def tearDown(self): - self.channel.connectionLost(None) - - def test_modified(self): - """If-Modified-Since cache validator (positive)""" - self.channel.lineReceived("If-Modified-Since: %s" - % http.datetimeToString(1)) - self.channel.lineReceived('') - result = self.transport.getvalue() - self.failUnlessEqual(httpCode(result), http.OK) - self.failUnlessEqual(httpBody(result), "correct") - - def test_unmodified(self): - """If-Modified-Since cache validator (negative)""" - self.channel.lineReceived("If-Modified-Since: %s" - % http.datetimeToString(100)) - self.channel.lineReceived('') - result = self.transport.getvalue() - self.failUnlessEqual(httpCode(result), http.NOT_MODIFIED) - self.failUnlessEqual(httpBody(result), "") - - def test_etagMatchedNot(self): - """If-None-Match ETag cache validator (positive)""" - self.channel.lineReceived("If-None-Match: unmatchedTag") - self.channel.lineReceived('') - result = self.transport.getvalue() - self.failUnlessEqual(httpCode(result), http.OK) - self.failUnlessEqual(httpBody(result), "correct") - - def test_etagMatched(self): - """If-None-Match ETag cache validator (negative)""" - self.channel.lineReceived("If-None-Match: MatchingTag") - self.channel.lineReceived('') - result = self.transport.getvalue() - self.failUnlessEqual(httpHeader(result, "ETag"), "MatchingTag") - self.failUnlessEqual(httpCode(result), http.NOT_MODIFIED) - self.failUnlessEqual(httpBody(result), "") - -from twisted.web import google -class GoogleTestCase(unittest.TestCase): - def testCheckGoogle(self): - raise unittest.SkipTest("no violation of google ToS") - d = google.checkGoogle('site:www.twistedmatrix.com twisted') - d.addCallback(self.assertEquals, 'http://twistedmatrix.com/') - return d - -from twisted.web import static -from twisted.web import script - -class StaticFileTest(unittest.TestCase): - - def testStaticPaths(self): - import os - dp = os.path.join(self.mktemp(),"hello") - ddp = os.path.join(dp, "goodbye") - tp = os.path.abspath(os.path.join(dp,"world.txt")) - tpy = os.path.join(dp,"wyrld.rpy") - os.makedirs(dp) - f = open(tp,"wb") - f.write("hello world") - f = open(tpy, "wb") - f.write(""" -from twisted.web.static import Data -resource = Data('dynamic world','text/plain') -""") - f = static.File(dp) - f.processors = { - '.rpy': script.ResourceScript, - } - - f.indexNames = f.indexNames + ['world.txt'] - self.assertEquals(f.getChild('', DummyRequest([''])).path, - tp) - self.assertEquals(f.getChild('wyrld.rpy', DummyRequest(['wyrld.rpy']) - ).__class__, - static.Data) - f = static.File(dp) - wtextr = DummyRequest(['world.txt']) - wtext = f.getChild('world.txt', wtextr) - self.assertEquals(wtext.path, tp) - wtext.render(wtextr) - self.assertEquals(wtextr.outgoingHeaders.get('content-length'), - str(len('hello world'))) - self.assertNotEquals(f.getChild('', DummyRequest([''])).__class__, - static.File) - - def testIgnoreExt(self): - f = static.File(".") - f.ignoreExt(".foo") - self.assertEquals(f.ignoredExts, [".foo"]) - f = static.File(".") - self.assertEquals(f.ignoredExts, []) - f = static.File(".", ignoredExts=(".bar", ".baz")) - self.assertEquals(f.ignoredExts, [".bar", ".baz"]) - - def testIgnoredExts(self): - import os - dp = os.path.join(self.mktemp(), 'allYourBase') - fp = os.path.join(dp, 'AreBelong.ToUs') - os.makedirs(dp) - open(fp, 'wb').write("Take off every 'Zig'!!") - f = static.File(dp) - f.ignoreExt('.ToUs') - dreq = DummyRequest(['']) - child_without_ext = f.getChild('AreBelong', dreq) - self.assertNotEquals(child_without_ext, f.childNotFound) - -class DummyChannel: - class TCP: - port = 80 - def getPeer(self): - return IPv4Address("TCP", 'client.example.com', 12344) - def getHost(self): - return IPv4Address("TCP", 'example.com', self.port) - class SSL(TCP): - implements(interfaces.ISSLTransport) - transport = TCP() - site = server.Site(resource.Resource()) - -class TestRequest(unittest.TestCase): - - def testChildLink(self): - request = server.Request(DummyChannel(), 1) - request.gotLength(0) - request.requestReceived('GET', '/foo/bar', 'HTTP/1.0') - self.assertEqual(request.childLink('baz'), 'bar/baz') - request = server.Request(DummyChannel(), 1) - request.gotLength(0) - request.requestReceived('GET', '/foo/bar/', 'HTTP/1.0') - self.assertEqual(request.childLink('baz'), 'baz') - - def testPrePathURLSimple(self): - request = server.Request(DummyChannel(), 1) - request.gotLength(0) - request.requestReceived('GET', '/foo/bar', 'HTTP/1.0') - request.setHost('example.com', 80) - self.assertEqual(request.prePathURL(), 'http://example.com/foo/bar') - - def testPrePathURLNonDefault(self): - d = DummyChannel() - d.transport = DummyChannel.TCP() - d.transport.port = 81 - request = server.Request(d, 1) - request.setHost('example.com', 81) - request.gotLength(0) - request.requestReceived('GET', '/foo/bar', 'HTTP/1.0') - self.assertEqual(request.prePathURL(), 'http://example.com:81/foo/bar') - - def testPrePathURLSSLPort(self): - d = DummyChannel() - d.transport = DummyChannel.TCP() - d.transport.port = 443 - request = server.Request(d, 1) - request.setHost('example.com', 443) - request.gotLength(0) - request.requestReceived('GET', '/foo/bar', 'HTTP/1.0') - self.assertEqual(request.prePathURL(), 'http://example.com:443/foo/bar') - - def testPrePathURLSSLPortAndSSL(self): - d = DummyChannel() - d.transport = DummyChannel.SSL() - d.transport.port = 443 - request = server.Request(d, 1) - request.setHost('example.com', 443) - request.gotLength(0) - request.requestReceived('GET', '/foo/bar', 'HTTP/1.0') - self.assertEqual(request.prePathURL(), 'https://example.com/foo/bar') - - def testPrePathURLHTTPPortAndSSL(self): - d = DummyChannel() - d.transport = DummyChannel.SSL() - d.transport.port = 80 - request = server.Request(d, 1) - request.setHost('example.com', 80) - request.gotLength(0) - request.requestReceived('GET', '/foo/bar', 'HTTP/1.0') - self.assertEqual(request.prePathURL(), 'https://example.com:80/foo/bar') - - def testPrePathURLSSLNonDefault(self): - d = DummyChannel() - d.transport = DummyChannel.SSL() - d.transport.port = 81 - request = server.Request(d, 1) - request.setHost('example.com', 81) - request.gotLength(0) - request.requestReceived('GET', '/foo/bar', 'HTTP/1.0') - self.assertEqual(request.prePathURL(), 'https://example.com:81/foo/bar') - - def testPrePathURLSetSSLHost(self): - d = DummyChannel() - d.transport = DummyChannel.TCP() - d.transport.port = 81 - request = server.Request(d, 1) - request.setHost('foo.com', 81, 1) - request.gotLength(0) - request.requestReceived('GET', '/foo/bar', 'HTTP/1.0') - self.assertEqual(request.prePathURL(), 'https://foo.com:81/foo/bar') - - - def test_prePathURLQuoting(self): - """ - L{Request.prePathURL} quotes special characters in the URL segments to - preserve the original meaning. - """ - d = DummyChannel() - request = server.Request(d, 1) - request.setHost('example.com', 80) - request.gotLength(0) - request.requestReceived('GET', '/foo%2Fbar', 'HTTP/1.0') - self.assertEqual(request.prePathURL(), 'http://example.com/foo%2Fbar') - - - def testNotifyFinishConnectionLost(self): - d = DummyChannel() - d.transport = DummyChannel.TCP() - request = server.Request(d, 1) - finished = request.notifyFinish() - request.connectionLost(error.ConnectionDone("Connection done")) - return self.assertFailure(finished, error.ConnectionDone) - - -class RootResource(resource.Resource): - isLeaf=0 - def getChildWithDefault(self, name, request): - request.rememberRootURL() - return resource.Resource.getChildWithDefault(self, name, request) - def render(self, request): - return '' - -class RememberURLTest(unittest.TestCase): - def createServer(self, r): - chan = DummyChannel() - chan.transport = DummyChannel.TCP() - chan.site = server.Site(r) - return chan - - def testSimple(self): - r = resource.Resource() - r.isLeaf=0 - rr = RootResource() - r.putChild('foo', rr) - rr.putChild('', rr) - rr.putChild('bar', resource.Resource()) - chan = self.createServer(r) - for url in ['/foo/', '/foo/bar', '/foo/bar/baz', '/foo/bar/']: - request = server.Request(chan, 1) - request.setHost('example.com', 81) - request.gotLength(0) - request.requestReceived('GET', url, 'HTTP/1.0') - self.assertEqual(request.getRootURL(), "http://example.com/foo") - - def testRoot(self): - rr = RootResource() - rr.putChild('', rr) - rr.putChild('bar', resource.Resource()) - chan = self.createServer(rr) - for url in ['/', '/bar', '/bar/baz', '/bar/']: - request = server.Request(chan, 1) - request.setHost('example.com', 81) - request.gotLength(0) - request.requestReceived('GET', url, 'HTTP/1.0') - self.assertEqual(request.getRootURL(), "http://example.com/") - - -class NewRenderResource(resource.Resource): - def render_GET(self, request): - return "hi hi" - - def render_HEH(self, request): - return "ho ho" - - -class NewRenderTestCase(unittest.TestCase): - def _getReq(self): - d = DummyChannel() - d.site.resource.putChild('newrender', NewRenderResource()) - d.transport = DummyChannel.TCP() - d.transport.port = 81 - request = server.Request(d, 1) - request.setHost('example.com', 81) - request.gotLength(0) - return request - - def testGoodMethods(self): - req = self._getReq() - req.requestReceived('GET', '/newrender', 'HTTP/1.0') - self.assertEquals(req.transport.getvalue().splitlines()[-1], 'hi hi') - - req = self._getReq() - req.requestReceived('HEH', '/newrender', 'HTTP/1.0') - self.assertEquals(req.transport.getvalue().splitlines()[-1], 'ho ho') - - def testBadMethods(self): - req = self._getReq() - req.requestReceived('CONNECT', '/newrender', 'HTTP/1.0') - self.assertEquals(req.code, 501) - - req = self._getReq() - req.requestReceived('hlalauguG', '/newrender', 'HTTP/1.0') - self.assertEquals(req.code, 501) - - def testImplicitHead(self): - req = self._getReq() - req.requestReceived('HEAD', '/newrender', 'HTTP/1.0') - self.assertEquals(req.code, 200) - self.assertEquals(-1, req.transport.getvalue().find('hi hi')) - - -class SDResource(resource.Resource): - def __init__(self,default): self.default=default - def getChildWithDefault(self,name,request): - d=defer.succeed(self.default) - return util.DeferredResource(d).getChildWithDefault(name, request) - -class SDTest(unittest.TestCase): - - def testDeferredResource(self): - r = resource.Resource() - r.isLeaf = 1 - s = SDResource(r) - d = DummyRequest(['foo', 'bar', 'baz']) - resource.getChildForRequest(s, d) - self.assertEqual(d.postpath, ['bar', 'baz']) - -class DummyRequestForLogTest(DummyRequest): - uri='/dummy' # parent class uri has "http://", which doesn't really happen - code = 123 - client = '1.2.3.4' - clientproto = 'HTTP/1.0' - sentLength = None - - def __init__(self, *a, **kw): - DummyRequest.__init__(self, *a, **kw) - self.headers = {} - - def getHeader(self, h): - return self.headers.get(h.lower(), None) - - def getClientIP(self): - return self.client - -class TestLogEscaping(unittest.TestCase): - def setUp(self): - self.site = http.HTTPFactory() - self.site.logFile = StringIO() - self.request = DummyRequestForLogTest(self.site, False) - - def testSimple(self): - http._logDateTime = "[%02d/%3s/%4d:%02d:%02d:%02d +0000]" % ( - 25, 'Oct', 2004, 12, 31, 59) - self.site.log(self.request) - self.site.logFile.seek(0) - self.assertEqual( - self.site.logFile.read(), - '1.2.3.4 - - [25/Oct/2004:12:31:59 +0000] "GET /dummy HTTP/1.0" 123 - "-" "-"\n') - - def testMethodQuote(self): - http._logDateTime = "[%02d/%3s/%4d:%02d:%02d:%02d +0000]" % ( - 25, 'Oct', 2004, 12, 31, 59) - self.request.method = 'G"T' - self.site.log(self.request) - self.site.logFile.seek(0) - self.assertEqual( - self.site.logFile.read(), - '1.2.3.4 - - [25/Oct/2004:12:31:59 +0000] "G\\"T /dummy HTTP/1.0" 123 - "-" "-"\n') - - def testRequestQuote(self): - http._logDateTime = "[%02d/%3s/%4d:%02d:%02d:%02d +0000]" % ( - 25, 'Oct', 2004, 12, 31, 59) - self.request.uri='/dummy"withquote' - self.site.log(self.request) - self.site.logFile.seek(0) - self.assertEqual( - self.site.logFile.read(), - '1.2.3.4 - - [25/Oct/2004:12:31:59 +0000] "GET /dummy\\"withquote HTTP/1.0" 123 - "-" "-"\n') - - def testProtoQuote(self): - http._logDateTime = "[%02d/%3s/%4d:%02d:%02d:%02d +0000]" % ( - 25, 'Oct', 2004, 12, 31, 59) - self.request.clientproto='HT"P/1.0' - self.site.log(self.request) - self.site.logFile.seek(0) - self.assertEqual( - self.site.logFile.read(), - '1.2.3.4 - - [25/Oct/2004:12:31:59 +0000] "GET /dummy HT\\"P/1.0" 123 - "-" "-"\n') - - def testRefererQuote(self): - http._logDateTime = "[%02d/%3s/%4d:%02d:%02d:%02d +0000]" % ( - 25, 'Oct', 2004, 12, 31, 59) - self.request.headers['referer'] = 'http://malicious" ".website.invalid' - self.site.log(self.request) - self.site.logFile.seek(0) - self.assertEqual( - self.site.logFile.read(), - '1.2.3.4 - - [25/Oct/2004:12:31:59 +0000] "GET /dummy HTTP/1.0" 123 - "http://malicious\\" \\".website.invalid" "-"\n') - - def testUserAgentQuote(self): - http._logDateTime = "[%02d/%3s/%4d:%02d:%02d:%02d +0000]" % ( - 25, 'Oct', 2004, 12, 31, 59) - self.request.headers['user-agent'] = 'Malicious Web" Evil' - self.site.log(self.request) - self.site.logFile.seek(0) - self.assertEqual( - self.site.logFile.read(), - '1.2.3.4 - - [25/Oct/2004:12:31:59 +0000] "GET /dummy HTTP/1.0" 123 - "-" "Malicious Web\\" Evil"\n') diff --git a/tools/buildbot/pylibs/twisted/web/test/test_webclient.py b/tools/buildbot/pylibs/twisted/web/test/test_webclient.py deleted file mode 100644 index a1bab78..0000000 --- a/tools/buildbot/pylibs/twisted/web/test/test_webclient.py +++ /dev/null @@ -1,475 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.web.client}. -""" - -import os - -from urlparse import urlparse - -from twisted.trial import unittest -from twisted.web import server, static, client, error, util, resource -from twisted.internet import reactor, defer, interfaces -from twisted.python.filepath import FilePath - -try: - from twisted.internet import ssl -except: - ssl = None - -serverCallID = None - -class LongTimeTakingResource(resource.Resource): - def render(self, request): - global serverCallID - serverCallID = reactor.callLater(1, self.writeIt, request) - return server.NOT_DONE_YET - - def writeIt(self, request): - request.write("hello!!!") - request.finish() - -class CookieMirrorResource(resource.Resource): - def render(self, request): - l = [] - for k,v in request.received_cookies.items(): - l.append((k, v)) - l.sort() - return repr(l) - -class RawCookieMirrorResource(resource.Resource): - def render(self, request): - return repr(request.getHeader('cookie')) - -class ErrorResource(resource.Resource): - - def render(self, request): - request.setResponseCode(401) - if request.args.get("showlength"): - request.setHeader("content-length", "0") - return "" - -class NoLengthResource(resource.Resource): - - def render(self, request): - return "nolength" - -class HostHeaderResource(resource.Resource): - - def render(self, request): - return request.received_headers["host"] - -class PayloadResource(resource.Resource): - - def render(self, request): - data = request.content.read() - if len(data) != 100 or int(request.received_headers["content-length"]) != 100: - return "ERROR" - return data - -class BrokenDownloadResource(resource.Resource): - - def render(self, request): - # only sends 3 bytes even though it claims to send 5 - request.setHeader("content-length", "5") - request.write('abc') - return '' - - - -class ParseUrlTestCase(unittest.TestCase): - """ - Test URL parsing facility and defaults values. - """ - - def testParse(self): - scheme, host, port, path = client._parse("http://127.0.0.1/") - self.assertEquals(path, "/") - self.assertEquals(port, 80) - scheme, host, port, path = client._parse("https://127.0.0.1/") - self.assertEquals(path, "/") - self.assertEquals(port, 443) - scheme, host, port, path = client._parse("http://spam:12345/") - self.assertEquals(port, 12345) - scheme, host, port, path = client._parse("http://foo ") - self.assertEquals(host, "foo") - self.assertEquals(path, "/") - scheme, host, port, path = client._parse("http://egg:7890") - self.assertEquals(port, 7890) - self.assertEquals(host, "egg") - self.assertEquals(path, "/") - - - def test_externalUnicodeInterference(self): - """ - L{client._parse} should return C{str} for the scheme, host, and path - elements of its return tuple, even when passed an URL which has - previously been passed to L{urlparse} as a C{unicode} string. - """ - badInput = u'http://example.com/path' - goodInput = badInput.encode('ascii') - urlparse(badInput) - scheme, host, port, path = client._parse(goodInput) - self.assertTrue(isinstance(scheme, str)) - self.assertTrue(isinstance(host, str)) - self.assertTrue(isinstance(path, str)) - - - -class WebClientTestCase(unittest.TestCase): - def _listen(self, site): - return reactor.listenTCP(0, site, interface="127.0.0.1") - - def setUp(self): - name = self.mktemp() - os.mkdir(name) - FilePath(name).child("file").setContent("0123456789") - r = static.File(name) - r.putChild("redirect", util.Redirect("/file")) - r.putChild("wait", LongTimeTakingResource()) - r.putChild("error", ErrorResource()) - r.putChild("nolength", NoLengthResource()) - r.putChild("host", HostHeaderResource()) - r.putChild("payload", PayloadResource()) - r.putChild("broken", BrokenDownloadResource()) - site = server.Site(r, timeout=None) - self.port = self._listen(site) - self.portno = self.port.getHost().port - - def tearDown(self): - if serverCallID and serverCallID.active(): - serverCallID.cancel() - return self.port.stopListening() - - def getURL(self, path): - return "http://127.0.0.1:%d/%s" % (self.portno, path) - - def testPayload(self): - s = "0123456789" * 10 - return client.getPage(self.getURL("payload"), postdata=s - ).addCallback(self.assertEquals, s - ) - - def testBrokenDownload(self): - # test what happens when download gets disconnected in the middle - d = client.getPage(self.getURL("broken")) - d = self.assertFailure(d, client.PartialDownloadError) - d.addCallback(lambda exc: self.assertEquals(exc.response, "abc")) - return d - - def testHostHeader(self): - # if we pass Host header explicitly, it should be used, otherwise - # it should extract from url - return defer.gatherResults([ - client.getPage(self.getURL("host")).addCallback(self.assertEquals, "127.0.0.1"), - client.getPage(self.getURL("host"), headers={"Host": "www.example.com"}).addCallback(self.assertEquals, "www.example.com")]) - - - def test_getPage(self): - """ - L{client.getPage} returns a L{Deferred} which is called back with - the body of the response if the default method B{GET} is used. - """ - d = client.getPage(self.getURL("file")) - d.addCallback(self.assertEquals, "0123456789") - return d - - - def test_getPageHead(self): - """ - L{client.getPage} returns a L{Deferred} which is called back with - the empty string if the method is C{HEAD} and there is a successful - response code. - """ - def getPage(method): - return client.getPage(self.getURL("file"), method=method) - return defer.gatherResults([ - getPage("head").addCallback(self.assertEqual, ""), - getPage("HEAD").addCallback(self.assertEqual, "")]) - - - def testTimeoutNotTriggering(self): - # Test that when the timeout doesn't trigger, things work as expected. - d = client.getPage(self.getURL("wait"), timeout=100) - d.addCallback(self.assertEquals, "hello!!!") - return d - - def testTimeoutTriggering(self): - # Test that when the timeout does trigger, we get a defer.TimeoutError. - return self.assertFailure( - client.getPage(self.getURL("wait"), timeout=0.5), - defer.TimeoutError) - - def testDownloadPage(self): - downloads = [] - downloadData = [("file", self.mktemp(), "0123456789"), - ("nolength", self.mktemp(), "nolength")] - - for (url, name, data) in downloadData: - d = client.downloadPage(self.getURL(url), name) - d.addCallback(self._cbDownloadPageTest, data, name) - downloads.append(d) - return defer.gatherResults(downloads) - - def _cbDownloadPageTest(self, ignored, data, name): - bytes = file(name, "rb").read() - self.assertEquals(bytes, data) - - def testDownloadPageError1(self): - class errorfile: - def write(self, data): - raise IOError, "badness happened during write" - def close(self): - pass - ef = errorfile() - return self.assertFailure( - client.downloadPage(self.getURL("file"), ef), - IOError) - - def testDownloadPageError2(self): - class errorfile: - def write(self, data): - pass - def close(self): - raise IOError, "badness happened during close" - ef = errorfile() - return self.assertFailure( - client.downloadPage(self.getURL("file"), ef), - IOError) - - def testDownloadPageError3(self): - # make sure failures in open() are caught too. This is tricky. - # Might only work on posix. - tmpfile = open("unwritable", "wb") - tmpfile.close() - os.chmod("unwritable", 0) # make it unwritable (to us) - d = self.assertFailure( - client.downloadPage(self.getURL("file"), "unwritable"), - IOError) - d.addBoth(self._cleanupDownloadPageError3) - return d - - def _cleanupDownloadPageError3(self, ignored): - os.chmod("unwritable", 0700) - os.unlink("unwritable") - return ignored - - def _downloadTest(self, method): - dl = [] - for (url, code) in [("nosuchfile", "404"), ("error", "401"), - ("error?showlength=1", "401")]: - d = method(url) - d = self.assertFailure(d, error.Error) - d.addCallback(lambda exc, code=code: self.assertEquals(exc.args[0], code)) - dl.append(d) - return defer.DeferredList(dl, fireOnOneErrback=True) - - def testServerError(self): - return self._downloadTest(lambda url: client.getPage(self.getURL(url))) - - def testDownloadServerError(self): - return self._downloadTest(lambda url: client.downloadPage(self.getURL(url), url.split('?')[0])) - - def testFactoryInfo(self): - url = self.getURL('file') - scheme, host, port, path = client._parse(url) - factory = client.HTTPClientFactory(url) - reactor.connectTCP(host, port, factory) - return factory.deferred.addCallback(self._cbFactoryInfo, factory) - - def _cbFactoryInfo(self, ignoredResult, factory): - self.assertEquals(factory.status, '200') - self.assert_(factory.version.startswith('HTTP/')) - self.assertEquals(factory.message, 'OK') - self.assertEquals(factory.response_headers['content-length'][0], '10') - - - def testRedirect(self): - return client.getPage(self.getURL("redirect")).addCallback(self._cbRedirect) - - def _cbRedirect(self, pageData): - self.assertEquals(pageData, "0123456789") - d = self.assertFailure( - client.getPage(self.getURL("redirect"), followRedirect=0), - error.PageRedirect) - d.addCallback(self._cbCheckLocation) - return d - - def _cbCheckLocation(self, exc): - self.assertEquals(exc.location, "/file") - - def testPartial(self): - name = self.mktemp() - f = open(name, "wb") - f.write("abcd") - f.close() - - downloads = [] - partialDownload = [(True, "abcd456789"), - (True, "abcd456789"), - (False, "0123456789")] - - d = defer.succeed(None) - for (partial, expectedData) in partialDownload: - d.addCallback(self._cbRunPartial, name, partial) - d.addCallback(self._cbPartialTest, expectedData, name) - - return d - - testPartial.skip = "Cannot test until webserver can serve partial data properly" - - def _cbRunPartial(self, ignored, name, partial): - return client.downloadPage(self.getURL("file"), name, supportPartial=partial) - - def _cbPartialTest(self, ignored, expectedData, filename): - bytes = file(filename, "rb").read() - self.assertEquals(bytes, expectedData) - -class WebClientSSLTestCase(WebClientTestCase): - def _listen(self, site): - from twisted import test - return reactor.listenSSL(0, site, - contextFactory=ssl.DefaultOpenSSLContextFactory( - FilePath(test.__file__).sibling('server.pem').path, - FilePath(test.__file__).sibling('server.pem').path, - ), - interface="127.0.0.1") - - def getURL(self, path): - return "https://127.0.0.1:%d/%s" % (self.portno, path) - - def testFactoryInfo(self): - url = self.getURL('file') - scheme, host, port, path = client._parse(url) - factory = client.HTTPClientFactory(url) - reactor.connectSSL(host, port, factory, ssl.ClientContextFactory()) - # The base class defines _cbFactoryInfo correctly for this - return factory.deferred.addCallback(self._cbFactoryInfo, factory) - -class WebClientRedirectBetweenSSLandPlainText(unittest.TestCase): - def getHTTPS(self, path): - return "https://127.0.0.1:%d/%s" % (self.tlsPortno, path) - - def getHTTP(self, path): - return "http://127.0.0.1:%d/%s" % (self.plainPortno, path) - - def setUp(self): - plainRoot = static.Data('not me', 'text/plain') - tlsRoot = static.Data('me neither', 'text/plain') - - plainSite = server.Site(plainRoot, timeout=None) - tlsSite = server.Site(tlsRoot, timeout=None) - - from twisted import test - self.tlsPort = reactor.listenSSL(0, tlsSite, - contextFactory=ssl.DefaultOpenSSLContextFactory( - FilePath(test.__file__).sibling('server.pem').path, - FilePath(test.__file__).sibling('server.pem').path, - ), - interface="127.0.0.1") - self.plainPort = reactor.listenTCP(0, plainSite, interface="127.0.0.1") - - self.plainPortno = self.plainPort.getHost().port - self.tlsPortno = self.tlsPort.getHost().port - - plainRoot.putChild('one', util.Redirect(self.getHTTPS('two'))) - tlsRoot.putChild('two', util.Redirect(self.getHTTP('three'))) - plainRoot.putChild('three', util.Redirect(self.getHTTPS('four'))) - tlsRoot.putChild('four', static.Data('FOUND IT!', 'text/plain')) - - def tearDown(self): - ds = map(defer.maybeDeferred, - [self.plainPort.stopListening, self.tlsPort.stopListening]) - return defer.gatherResults(ds) - - def testHoppingAround(self): - return client.getPage(self.getHTTP("one") - ).addCallback(self.assertEquals, "FOUND IT!" - ) - -class FakeTransport: - disconnecting = False - def __init__(self): - self.data = [] - def write(self, stuff): - self.data.append(stuff) - -class CookieTestCase(unittest.TestCase): - def _listen(self, site): - return reactor.listenTCP(0, site, interface="127.0.0.1") - - def setUp(self): - root = static.Data('El toro!', 'text/plain') - root.putChild("cookiemirror", CookieMirrorResource()) - root.putChild("rawcookiemirror", RawCookieMirrorResource()) - site = server.Site(root, timeout=None) - self.port = self._listen(site) - self.portno = self.port.getHost().port - - def tearDown(self): - return self.port.stopListening() - - def getHTTP(self, path): - return "http://127.0.0.1:%d/%s" % (self.portno, path) - - def testNoCookies(self): - return client.getPage(self.getHTTP("cookiemirror") - ).addCallback(self.assertEquals, "[]" - ) - - def testSomeCookies(self): - cookies = {'foo': 'bar', 'baz': 'quux'} - return client.getPage(self.getHTTP("cookiemirror"), cookies=cookies - ).addCallback(self.assertEquals, "[('baz', 'quux'), ('foo', 'bar')]" - ) - - def testRawNoCookies(self): - return client.getPage(self.getHTTP("rawcookiemirror") - ).addCallback(self.assertEquals, "None" - ) - - def testRawSomeCookies(self): - cookies = {'foo': 'bar', 'baz': 'quux'} - return client.getPage(self.getHTTP("rawcookiemirror"), cookies=cookies - ).addCallback(self.assertEquals, "'foo=bar; baz=quux'" - ) - - def testCookieHeaderParsing(self): - d = defer.Deferred() - factory = client.HTTPClientFactory('http://foo.example.com/') - proto = factory.buildProtocol('127.42.42.42') - proto.transport = FakeTransport() - proto.connectionMade() - for line in [ - '200 Ok', - 'Squash: yes', - 'Hands: stolen', - 'Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/; expires=Wednesday, 09-Nov-99 23:12:40 GMT', - 'Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/', - 'Set-Cookie: SHIPPING=FEDEX; path=/foo', - '', - 'body', - 'more body', - ]: - proto.dataReceived(line + '\r\n') - self.assertEquals(proto.transport.data, - ['GET / HTTP/1.0\r\n', - 'Host: foo.example.com\r\n', - 'User-Agent: Twisted PageGetter\r\n', - '\r\n']) - self.assertEquals(factory.cookies, - { - 'CUSTOMER': 'WILE_E_COYOTE', - 'PART_NUMBER': 'ROCKET_LAUNCHER_0001', - 'SHIPPING': 'FEDEX', - }) - -if ssl is None or not hasattr(ssl, 'DefaultOpenSSLContextFactory'): - for case in [WebClientSSLTestCase, WebClientRedirectBetweenSSLandPlainText]: - case.skip = "OpenSSL not present" - -if not interfaces.IReactorSSL(reactor, None): - for case in [WebClientSSLTestCase, WebClientRedirectBetweenSSLandPlainText]: - case.skip = "Reactor doesn't support SSL" diff --git a/tools/buildbot/pylibs/twisted/web/test/test_woven.py b/tools/buildbot/pylibs/twisted/web/test/test_woven.py deleted file mode 100644 index 29dd17f..0000000 --- a/tools/buildbot/pylibs/twisted/web/test/test_woven.py +++ /dev/null @@ -1,570 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -from twisted.trial import unittest -from twisted.web import server, resource, microdom, domhelpers -from twisted.web import http -from twisted.web.test import test_web -from twisted.internet import reactor, defer, address - -from twisted.web.woven import template, model, view, controller, widgets, input, page, guard - -outputNum = 0 - -# Reusable test harness - -class WovenTC(unittest.TestCase): - modelFactory = lambda self: None - resourceFactory = None - def setUp(self): - self.m = self.modelFactory() - self.t = self.resourceFactory(self.m) - self.r = test_web.DummyRequest(['']) - self.r.prepath = [''] - self.prerender() - self.t.render(self.r) - - self.channel = "a fake channel" - self.output = ''.join(self.r.written) - assert self.output, "No output was generated by the test." - global outputNum - open("wovenTestOutput%s.html" % (outputNum + 1), 'w').write(self.output) - outputNum += 1 - self.d = microdom.parseString(self.output) - - def prerender(self): - pass - -# Test 1 -# Test that replacing nodes with a string works properly - - -class SimpleTemplate(template.DOMTemplate): - template = """ - - <span view="getTitle">Hello</span> - - -

                  Hi

                  - -
                  """ - - def factory_getTitle(self, request, node): - return "Title" - - def factory_getHello(self, request, node): - return "Hello" - - -class DOMTemplateTest(WovenTC): - resourceFactory = SimpleTemplate - def testSimpleRender(self): - titleNode = self.d.getElementById("title") - helloNode = self.d.getElementById("hello") - - self.assert_(domhelpers.gatherTextNodes(titleNode) == 'Title') - self.assert_(domhelpers.gatherTextNodes(helloNode) == 'Hello') - - -# Test 2 -# Test just like the first, but with Text widgets - -class TemplateWithWidgets(SimpleTemplate): - def wcfactory_getTitle(self, request, node): - return widgets.Text("Title") - - def wcfactory_getHello(self, request, node): - return widgets.Text("Hello") - - -class TWWTest(DOMTemplateTest): - resourceFactory = TemplateWithWidgets - - -# Test 3 -# Test a fancier widget, and controllers handling submitted input - - -class MDemo(model.AttributeModel): - foo = "Hello world" - color = 'blue' - - -class FancyBox(widgets.Widget): - def setUp(self, request, node, data): - self['style'] = 'margin: 1em; padding: 1em; background-color: %s' % data - - -class VDemo(view.View): - template = """ - -
                  - -
                  -Type a color and hit submit: - - -
                  - - -""" - def wvfactory_FancyBox(self, request, node, model): - return FancyBox(model) - - def renderFailure(self, failure, request): - return failure - - -class ChangeColor(input.Anything): - def commit(self, request, node, data): - session = request.getSession() - session.color = data - self.model.setData(request, data) - self.model.notify({'request': request}) - - -class CDemo(controller.Controller): - def setUp(self, request): - session = request.getSession() - self.model.color = getattr(session, 'color', self.model.color) - - def wcfactory_change(self, request, node, model): - return ChangeColor(model) - - -view.registerViewForModel(VDemo, MDemo) -controller.registerControllerForModel(CDemo, MDemo) - - -class ControllerTest(WovenTC): - modelFactory = MDemo - resourceFactory = CDemo - - def prerender(self): - self.r.addArg('color', 'red') - - def testControllerOutput(self): - boxNode = self.d.getElementById("box") - assert boxNode, "Test %s failed" % outputNum - style = boxNode.getAttribute("style") - styles = style.split(";") - sDict = {} - for item in styles: - key, value = item.split(":") - key = key.strip() - value = value.strip() - sDict[key] = value - -# print sDict - assert sDict['background-color'] == 'red' - - -# Test 4 -# Test a list, a list widget, and Deferred data handling - -identityList = ['asdf', 'foo', 'fredf', 'bob'] - -class MIdentityList(model.AttributeModel): - def __init__(self): - model.Model.__init__(self) - self.identityList = defer.Deferred() - self.identityList.callback(identityList) - - -class VIdentityList(view.View): - template = """ -
                    -
                  • - Stuff. -
                  • -
                  -""" - - def wvfactory_identityList(self, request, node, model): - return widgets.List(model) - - def wvfactory_text(self, request, node, model): - return widgets.Text(model) - - def renderFailure(self, failure, request): - return failure - - -class CIdentityList(controller.Controller): - pass - - -view.registerViewForModel(VIdentityList, MIdentityList) -controller.registerControllerForModel(CIdentityList, MIdentityList) - - -class ListDeferredTest(WovenTC): - modelFactory = MIdentityList - resourceFactory = CIdentityList - - def testOutput(self): - listNode = self.d.getElementById("list") - assert listNode, "Test %s failed; there was no element with the id 'list' in the output" % outputNum - liNodes = domhelpers.getElementsByTagName(listNode, 'li') - assert len(liNodes) == len(identityList), "Test %s failed; the number of 'li' nodes did not match the list size" % outputNum - - -# Test 5 -# Test nested lists - -class LLModel(model.AttributeModel): - data = [['foo', 'bar', 'baz'], - ['gum', 'shoe'], - ['ggg', 'hhh', 'iii'] - ] - - -class LLView(view.View): - template = """ -
                    -
                  • -
                      -
                    1. -
                    -
                  • -
                  -""" - - def wvfactory_List(self, request, node, model): - return widgets.List(model) - - -class NestedListTest(WovenTC): - modelFactory = LLModel - resourceFactory = LLView - - def testOutput(self): - listNode = self.d.getElementById("first") - assert listNode, "Test %s failed" % outputNum - liNodes = filter(lambda x: hasattr(x, 'tagName') and x.tagName == 'li', listNode.childNodes) -# print len(liNodes), len(self.m.data), liNodes, self.m.data - assert len(liNodes) == len(self.m.data), "Test %s failed" % outputNum - for i in range(len(liNodes)): - sublistNode = domhelpers.getElementsByTagName(liNodes[i], 'ol')[0] - subLiNodes = domhelpers.getElementsByTagName(sublistNode, 'li') - assert len(self.m.data[i]) == len(subLiNodes) - -# Test 6 -# Test notification when a model is a dict or a list - -class MNotifyTest(model.AttributeModel): - def initialize(self, *args, **kwargs): - self.root = {"inventory": [], 'log': ""} - - -class VNotifyTest(view.View): - template = """ - -
                    -
                  1. -
                  - -
                  - - -
                  - -""" - - def wvfactory_someText(self, request, node, m): - return widgets.Text(m) - -class InventoryUpdater(input.Anything): - def commit(self, request, node, data): - invmodel = self.model.getSubmodel(request, "inventory") - log = self.model.getSubmodel(request, "log") - inv = invmodel.getData(request) - inv.append(data) # just add a string to the list - log.setData(request, log.getData(request) + ("%s added to servers\n" % data)) - invmodel.setData(request, inv) - invmodel.notify({'request': request}) - - -class CNotifyTest(controller.Controller): - def wcfactory_updateInventory(self, request, node, model): - return InventoryUpdater(model) - - -view.registerViewForModel(VNotifyTest, MNotifyTest) -controller.registerControllerForModel(CNotifyTest, MNotifyTest) - -class NotifyTest(WovenTC): - modelFactory = MNotifyTest - resourceFactory = CNotifyTest - - def prerender(self): - self.r.addArg('root', 'test') - - def testComplexNotification(self): - listNode = self.d.getElementById("theList") - self.assert_(listNode, "Test %s failed" % outputNum) - liNodes = domhelpers.getElementsByTagName(listNode, 'li') - self.assert_(liNodes, - "DOM was not updated by notifying Widgets. Test %s" % outputNum) - text = domhelpers.gatherTextNodes(liNodes[0]) - self.assert_(text.strip() == "test", - "Wrong output: %s. Test %s" % (text, outputNum)) - -view.registerViewForModel(LLView, LLModel) - -#### Test 7 -# Test model path syntax -# model="/" should get you the root object -# model="." should get you the current object -# model=".." should get you the parent model object - - -# xxx sanity check for now; just make sure it doesn't raise anything - -class ModelPathTest(WovenTC): - modelFactory = lambda self: ['hello', ['hi', 'there'], - 'hi', ['asdf', ['qwer', 'asdf']]] - resourceFactory = page.Page - - def prerender(self): - self.t.template = """ -
                  -
                  -
                  - -
                  -
                  -
                  - -
                  -
                  -
                  - -
                  -
                  -
                  - -
                  -
                  -
                  - -""" - -#### Test 8 -# Test a large number of widgets - -class HugeTest(WovenTC): - modelFactory = lambda self: ['hello' for x in range(100)] - resourceFactory = page.Page - - def prerender(self): - self.t.template = """ -
                  -
                  -
                  -""" - - def testHugeTest(self): - pass - - -class ListOfDeferredsTest(WovenTC): - """Test rendering a model which is a list of Deferreds.""" - - modelFactory = lambda self: [defer.succeed("hello"), defer.succeed("world")] - resourceFactory = page.Page - - def prerender(self): - t = '''
                  - -
                  ''' - self.t.template = t - - def testResult(self): - n = self.d.firstChild() - self.assertEquals(len(n.childNodes), 2) - for c in n.childNodes: - self.assertEquals(c.nodeName, "b") - self.assertEquals(n.firstChild().firstChild().toxml().strip(), "hello") - self.assertEquals(n.lastChild().firstChild().toxml().strip(), "world") - - -class FakeHTTPChannel: - # TODO: this should be an interface in twisted.protocols.http... lots of - # things want to fake out HTTP - def __init__(self): - self.transport = self - self.factory = self - self.received_cookies = {} - - # 'factory' attribute needs this - def log(self, req): - pass - - # 'channel' of request needs this - def requestDone(self, req): - self.req = req - - # 'transport' attribute needs this - def getPeer(self): - return address.IPv4Address("TCP", "fake", "fake") - def getHost(self): - return address.IPv4Address("TCP", "fake", 80) - - def write(self, data): - # print data - pass - def writeSequence(self, datas): - for data in datas: - self.write(data) - - # Utility for testing. - - def makeFakeRequest(self, path, **vars): - req = FakeHTTPRequest(self, queued=0) - req.received_cookies.update(self.received_cookies) - req.requestReceived("GET", path, "1.0") - return req - -class FakeHTTPRequest(server.Request): - def __init__(self, *args, **kw): - server.Request.__init__(self, *args, **kw) - self._cookieCache = {} - from cStringIO import StringIO - self.content = StringIO() - self.received_headers['host'] = 'fake.com' - self.written = StringIO() - - def write(self, data): - self.written.write(data) - server.Request.write(self, data) - - def addCookie(self, k, v, *args,**kw): - server.Request.addCookie(self,k,v,*args,**kw) - assert not self._cookieCache.has_key(k), "Should not be setting duplicate cookies!" - self._cookieCache[k] = v - self.channel.received_cookies[k] = v - - def processingFailed(self, fail): - raise fail - -class FakeSite(server.Site): - def getResourceFor(self, req): - res = server.Site.getResourceFor(self,req) - self.caughtRes = res - return res - -from twisted.web import static - -class GuardTest(unittest.TestCase): - def testSessionInit(self): - sessWrapped = static.Data("you should never see this", "text/plain") - swChild = static.Data("NO", "text/plain") - sessWrapped.putChild("yyy",swChild) - swrap = guard.SessionWrapper(sessWrapped) - da = static.Data("b","text/plain") - da.putChild("xxx", swrap) - st = FakeSite(da) - chan = FakeHTTPChannel() - chan.site = st - - # first we're going to make sure that the session doesn't get set by - # accident when browsing without first explicitly initializing the - # session - req = FakeHTTPRequest(chan, queued=0) - req.requestReceived("GET", "/xxx/yyy", "1.0") - assert len(req._cookieCache.values()) == 0, req._cookieCache.values() - self.assertEquals(req.getSession(),None) - - # now we're going to make sure that the redirect and cookie are properly set - req = FakeHTTPRequest(chan, queued=0) - req.requestReceived("GET", "/xxx/"+guard.INIT_SESSION, "1.0") - ccv = req._cookieCache.values() - self.assertEquals(len(ccv),1) - cookie = ccv[0] - # redirect set? - self.failUnless(req.headers.has_key('location')) - # redirect matches cookie? - self.assertEquals(req.headers['location'].split('/')[-1], guard.SESSION_KEY+cookie) - # URL is correct? - self.assertEquals(req.headers['location'], - 'http://fake.com/xxx/'+guard.SESSION_KEY+cookie) - oldreq = req - - # now let's try with a request for the session-cookie URL that has a cookie set - url = "/"+(oldreq.headers['location'].split('http://fake.com/',1))[1] - req = chan.makeFakeRequest(url) - self.assertEquals(req.headers['location'].split('?')[0], - 'http://fake.com/xxx/') - for sz in swrap.sessions.values(): - sz.expire() - - - -class _TestPage(page.Page): - template = """ - - -
                  First:
                  -
                  Second:
                  -
                  Third:
                  - - - """ - - def wmfactory_title(self, request): - d = defer.Deferred() - reactor.callLater(0, d.callback, 'The Result') - return d - -class DeferredModelTestCase(unittest.TestCase): - def testDeferredModel(self): - # Test that multiple uses of a deferred model work correctly. - channel = FakeHTTPChannel() - channel.site = FakeSite(_TestPage()) - request = channel.makeFakeRequest('/') - - d = request.notifyFinish() - def check(_): - dom = microdom.parseXMLString(request.written.getvalue()) - spanElems = domhelpers.findNodesNamed(dom, 'span') - for spanElem in spanElems: - self.failUnlessEqual('The Result', spanElem.childNodes[0].data) - - return d.addCallback(check) - - -class MyMacroPage(page.Page): - template = """\ - - - - - -""" - def wvfactory_foo(self, request, node, model): - return widgets.ExpandMacro(model, macroFile = 'cdataxtester.html', - macroFileDirectory = '.', - macroName = 'foo' - ) - -class ExpandMacroTestCase(WovenTC): - resourceFactory = MyMacroPage - def setUp(self, *args, **kwargs): - thepage = """\ - - - -""" - file('cdatatester.html', 'wb').write(thepage) - WovenTC.setUp(self, *args, **kwargs) - def testCDATANotQuoted(self): - self.failUnless(self.output.find('<>\'"&')>=0) - - - diff --git a/tools/buildbot/pylibs/twisted/web/test/test_xml.py b/tools/buildbot/pylibs/twisted/web/test/test_xml.py deleted file mode 100644 index a2e235c..0000000 --- a/tools/buildbot/pylibs/twisted/web/test/test_xml.py +++ /dev/null @@ -1,760 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_xml -*- -# -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Some fairly inadequate testcases for Twisted XML support.""" - -from __future__ import nested_scopes - -from twisted.trial.unittest import TestCase - -from twisted.web import sux - -from twisted.web import microdom - -from twisted.web import domhelpers - -class Sux0r(sux.XMLParser): - def __init__(self): - self.tokens = [] - - def getTagStarts(self): - return [token for token in self.tokens if token[0] == 'start'] - - def gotTagStart(self, name, attrs): - self.tokens.append(("start", name, attrs)) - - def gotText(self, text): - self.tokens.append(("text", text)) - -class SUXTest(TestCase): - - def testBork(self): - s = "" - ms = Sux0r() - ms.connectionMade() - ms.dataReceived(s) - self.failUnlessEqual(len(ms.getTagStarts()),3) - - -class MicroDOMTest(TestCase): - - def test_leadingTextDropping(self): - """ - Make sure that if there's no top-level node lenient-mode won't - drop leading text that's outside of any elements. - """ - s = "Hi orders!
                  Well.
                  " - d = microdom.parseString(s, beExtremelyLenient=True) - self.assertEquals(d.firstChild().toxml(), - 'Hi orders!
                  Well.
                  ') - - def test_trailingTextDropping(self): - """ - Ensure that no *trailing* text in a mal-formed - no-top-level-element document(s) will not be dropped. - """ - s = "
                  Hi orders!" - d = microdom.parseString(s, beExtremelyLenient=True) - self.assertEquals(d.firstChild().toxml(), - '
                  Hi orders!') - - - def test_noTags(self): - """ - A string with nothing that looks like a tag at all should just - be parsed as body text. - """ - s = "Hi orders!" - d = microdom.parseString(s, beExtremelyLenient=True) - self.assertEquals(d.firstChild().toxml(), - "Hi orders!") - - - def test_surroundingCrap(self): - """ - If a document is surrounded by non-xml text, the text should - be remain in the XML. - """ - s = "Hi
                  orders!" - d = microdom.parseString(s, beExtremelyLenient=True) - self.assertEquals(d.firstChild().toxml(), - "Hi
                  orders!") - - - def testCaseSensitiveSoonCloser(self): - s = """ - -

                  - -

                  - -

                  - This is an insane set of text nodes that should NOT be gathered under - the A tag above. -

                  - - """ - d = microdom.parseString(s, beExtremelyLenient=1) - l = domhelpers.findNodesNamed(d.documentElement, 'a') - n = domhelpers.gatherTextNodes(l[0],1).replace(' ',' ') - self.assertEquals(n.find('insane'), -1) - - - def test_lenientParenting(self): - """ - Test that C{parentNode} attributes are set to meaningful values when - we are parsing HTML that lacks a root node. - """ - # Spare the rod, ruin the child. - s = "

                  " - d = microdom.parseString(s, beExtremelyLenient=1) - self.assertIdentical(d.documentElement, - d.documentElement.firstChild().parentNode) - - - def test_lenientParentSingle(self): - """ - Test that the C{parentNode} attribute is set to a meaningful value - when we parse an HTML document that has a non-Element root node. - """ - s = "Hello" - d = microdom.parseString(s, beExtremelyLenient=1) - self.assertIdentical(d.documentElement, - d.documentElement.firstChild().parentNode) - - - def testUnEntities(self): - s = """ - - This HTML goes between Stupid <=CrAzY!=> Dumb. - - """ - d = microdom.parseString(s, beExtremelyLenient=1) - n = domhelpers.gatherTextNodes(d) - self.assertNotEquals(n.find('>'), -1) - - def testEmptyError(self): - self.assertRaises(sux.ParseError, microdom.parseString, "") - - def testTameDocument(self): - s = """ - - - - - test - - - - - """ - d = microdom.parseString(s) - self.assertEquals( - domhelpers.gatherTextNodes(d.documentElement).strip() ,'test') - - def testAwfulTagSoup(self): - s = """ - - I send you this message to have your advice!!!!</titl e - </headd> - - <body bgcolor alink hlink vlink> - - <h1><BLINK>SALE</blINK> TWENTY MILLION EMAILS & FUR COAT NOW - FREE WITH `ENLARGER'</h1> - - YES THIS WONDERFUL AWFER IS NOW HERER!!! - - <script LANGUAGE="javascript"> -function give_answers() { -if (score < 70) { -alert("I hate you"); -}} - </script><a href=/foo.com/lalal name=foo>lalal</a> - </body> - </HTML> - """ - d = microdom.parseString(s, beExtremelyLenient=1) - l = domhelpers.findNodesNamed(d.documentElement, 'blink') - self.assertEquals(len(l), 1) - - def testScriptLeniency(self): - s = """ - <script>(foo < bar) and (bar > foo)</script> - <script language="javascript">foo </scrip bar </script> - <script src="foo"> - <script src="foo">baz</script> - <script /><script></script> - """ - d = microdom.parseString(s, beExtremelyLenient=1) - self.assertEquals(d.firstChild().firstChild().firstChild().data, - "(foo < bar) and (bar > foo)") - self.assertEquals( - d.firstChild().getElementsByTagName("script")[1].firstChild().data, - "foo </scrip bar ") - - def testScriptLeniencyIntelligence(self): - # if there is comment or CDATA in script, the autoquoting in bEL mode - # should not happen - s = """<script><!-- lalal --></script>""" - self.assertEquals( - microdom.parseString(s, beExtremelyLenient=1).firstChild().toxml(), s) - s = """<script><![CDATA[lalal]]></script>""" - self.assertEquals( - microdom.parseString(s, beExtremelyLenient=1).firstChild().toxml(), s) - s = """<script> // <![CDATA[ - lalal - //]]></script>""" - self.assertEquals( - microdom.parseString(s, beExtremelyLenient=1).firstChild().toxml(), s) - - def testPreserveCase(self): - s = '<eNcApSuLaTe><sUxor></sUxor><bOrk><w00T>TeXt</W00t></BoRk></EnCaPsUlAtE>' - s2 = s.lower().replace('text', 'TeXt') - # these are the only two option permutations that *can* parse the above - d = microdom.parseString(s, caseInsensitive=1, preserveCase=1) - d2 = microdom.parseString(s, caseInsensitive=1, preserveCase=0) - # caseInsensitive=0 preserveCase=0 is not valid, it's converted to - # caseInsensitive=0 preserveCase=1 - d3 = microdom.parseString(s2, caseInsensitive=0, preserveCase=1) - d4 = microdom.parseString(s2, caseInsensitive=1, preserveCase=0) - d5 = microdom.parseString(s2, caseInsensitive=1, preserveCase=1) - # this is slightly contrived, toxml() doesn't need to be identical - # for the documents to be equivalent (i.e. <b></b> to <b/>), - # however this assertion tests preserving case for start and - # end tags while still matching stuff like <bOrk></BoRk> - self.assertEquals(d.documentElement.toxml(), s) - self.assert_(d.isEqualToDocument(d2), "%r != %r" % (d.toxml(), d2.toxml())) - self.assert_(d2.isEqualToDocument(d3), "%r != %r" % (d2.toxml(), d3.toxml())) - # caseInsensitive=0 on the left, NOT perserveCase=1 on the right - ## XXX THIS TEST IS TURNED OFF UNTIL SOMEONE WHO CARES ABOUT FIXING IT DOES - #self.failIf(d3.isEqualToDocument(d2), "%r == %r" % (d3.toxml(), d2.toxml())) - self.assert_(d3.isEqualToDocument(d4), "%r != %r" % (d3.toxml(), d4.toxml())) - self.assert_(d4.isEqualToDocument(d5), "%r != %r" % (d4.toxml(), d5.toxml())) - - def testDifferentQuotes(self): - s = '<test a="a" b=\'b\' />' - d = microdom.parseString(s) - e = d.documentElement - self.assertEquals(e.getAttribute('a'), 'a') - self.assertEquals(e.getAttribute('b'), 'b') - - def testLinebreaks(self): - s = '<test \na="a"\n\tb="#b" />' - d = microdom.parseString(s) - e = d.documentElement - self.assertEquals(e.getAttribute('a'), 'a') - self.assertEquals(e.getAttribute('b'), '#b') - - def testMismatchedTags(self): - for s in '<test>', '<test> </tset>', '</test>': - self.assertRaises(microdom.MismatchedTags, microdom.parseString, s) - - def testComment(self): - s = "<bar><!--<foo />--></bar>" - d = microdom.parseString(s) - e = d.documentElement - self.assertEquals(e.nodeName, "bar") - c = e.childNodes[0] - self.assert_(isinstance(c, microdom.Comment)) - self.assertEquals(c.value, "<foo />") - c2 = c.cloneNode() - self.assert_(c is not c2) - self.assertEquals(c2.toxml(), "<!--<foo />-->") - - def testText(self): - d = microdom.parseString("<bar>xxxx</bar>").documentElement - text = d.childNodes[0] - self.assert_(isinstance(text, microdom.Text)) - self.assertEquals(text.value, "xxxx") - clone = text.cloneNode() - self.assert_(clone is not text) - self.assertEquals(clone.toxml(), "xxxx") - - def testEntities(self): - nodes = microdom.parseString("<b>& AB;</b>").documentElement.childNodes - self.assertEquals(len(nodes), 2) - self.assertEquals(nodes[0].data, "&") - self.assertEquals(nodes[1].data, " AB;") - self.assertEquals(nodes[0].cloneNode().toxml(), "&") - for n in nodes: - self.assert_(isinstance(n, microdom.EntityReference)) - - def testCData(self): - s = '<x><![CDATA[</x>\r\n & foo]]></x>' - cdata = microdom.parseString(s).documentElement.childNodes[0] - self.assert_(isinstance(cdata, microdom.CDATASection)) - self.assertEquals(cdata.data, "</x>\r\n & foo") - self.assertEquals(cdata.cloneNode().toxml(), "<![CDATA[</x>\r\n & foo]]>") - - def testSingletons(self): - s = "<foo><b/><b /><b\n/></foo>" - s2 = "<foo><b/><b/><b/></foo>" - nodes = microdom.parseString(s).documentElement.childNodes - nodes2 = microdom.parseString(s2).documentElement.childNodes - self.assertEquals(len(nodes), 3) - for (n, n2) in zip(nodes, nodes2): - self.assert_(isinstance(n, microdom.Element)) - self.assertEquals(n.nodeName, "b") - self.assert_(n.isEqualToNode(n2)) - - def testAttributes(self): - s = '<foo a="b" />' - node = microdom.parseString(s).documentElement - - self.assertEquals(node.getAttribute("a"), "b") - self.assertEquals(node.getAttribute("c"), None) - self.assert_(node.hasAttribute("a")) - self.assert_(not node.hasAttribute("c")) - a = node.getAttributeNode("a") - self.assertEquals(a.value, "b") - - node.setAttribute("foo", "bar") - self.assertEquals(node.getAttribute("foo"), "bar") - - def testChildren(self): - s = "<foo><bar /><baz /><bax>foo</bax></foo>" - d = microdom.parseString(s).documentElement - self.assertEquals([n.nodeName for n in d.childNodes], ["bar", "baz", "bax"]) - self.assertEquals(d.lastChild().nodeName, "bax") - self.assertEquals(d.firstChild().nodeName, "bar") - self.assert_(d.hasChildNodes()) - self.assert_(not d.firstChild().hasChildNodes()) - - def testMutate(self): - s = "<foo />" - s1 = '<foo a="b"><bar/><foo/></foo>' - s2 = '<foo a="b">foo</foo>' - d = microdom.parseString(s).documentElement - d1 = microdom.parseString(s1).documentElement - d2 = microdom.parseString(s2).documentElement - - d.appendChild(d.cloneNode()) - d.setAttribute("a", "b") - child = d.childNodes[0] - self.assertEquals(child.getAttribute("a"), None) - self.assertEquals(child.nodeName, "foo") - - d.insertBefore(microdom.Element("bar"), child) - self.assertEquals(d.childNodes[0].nodeName, "bar") - self.assertEquals(d.childNodes[1], child) - for n in d.childNodes: - self.assertEquals(n.parentNode, d) - self.assert_(d.isEqualToNode(d1)) - - d.removeChild(child) - self.assertEquals(len(d.childNodes), 1) - self.assertEquals(d.childNodes[0].nodeName, "bar") - - t = microdom.Text("foo") - d.replaceChild(t, d.firstChild()) - self.assertEquals(d.firstChild(), t) - self.assert_(d.isEqualToNode(d2)) - - def testSearch(self): - s = "<foo><bar id='me' /><baz><foo /></baz></foo>" - s2 = "<fOo><bAr id='me' /><bAz><fOO /></bAz></fOo>" - d = microdom.parseString(s) - d2 = microdom.parseString(s2, caseInsensitive=0, preserveCase=1) - d3 = microdom.parseString(s2, caseInsensitive=1, preserveCase=1) - - root = d.documentElement - self.assertEquals(root.firstChild(), d.getElementById('me')) - self.assertEquals(d.getElementsByTagName("foo"), - [root, root.lastChild().firstChild()]) - - root = d2.documentElement - self.assertEquals(root.firstChild(), d2.getElementById('me')) - self.assertEquals(d2.getElementsByTagName('fOo'), [root]) - self.assertEquals(d2.getElementsByTagName('fOO'), - [root.lastChild().firstChild()]) - self.assertEquals(d2.getElementsByTagName('foo'), []) - - root = d3.documentElement - self.assertEquals(root.firstChild(), d3.getElementById('me')) - self.assertEquals(d3.getElementsByTagName('FOO'), - [root, root.lastChild().firstChild()]) - self.assertEquals(d3.getElementsByTagName('fOo'), - [root, root.lastChild().firstChild()]) - - def testDoctype(self): - s = ('<?xml version="1.0"?>' - '<!DOCTYPE foo PUBLIC "baz" "http://www.example.com/example.dtd">' - '<foo></foo>') - s2 = '<foo/>' - d = microdom.parseString(s) - d2 = microdom.parseString(s2) - self.assertEquals(d.doctype, - 'foo PUBLIC "baz" "http://www.example.com/example.dtd"') - self.assertEquals(d.toxml(), s) - self.failIf(d.isEqualToDocument(d2)) - self.failUnless(d.documentElement.isEqualToNode(d2.documentElement)) - - samples = [("<img/>", "<img />"), - ("<foo A='b'>x</foo>", '<foo A="b">x</foo>'), - ("<foo><BAR /></foo>", "<foo><BAR></BAR></foo>"), - ("<foo>hello there & yoyoy</foo>", - "<foo>hello there & yoyoy</foo>"), - ] - - def testOutput(self): - for s, out in self.samples: - d = microdom.parseString(s, caseInsensitive=0) - d2 = microdom.parseString(out, caseInsensitive=0) - testOut = d.documentElement.toxml() - self.assertEquals(out, testOut) - self.assert_(d.isEqualToDocument(d2)) - - def testErrors(self): - for s in ["<foo>&am</foo>", "<foo", "<f>&</f>", "<() />"]: - self.assertRaises(Exception, microdom.parseString, s) - - def testCaseInsensitive(self): - s = "<foo a='b'><BAx>x</bax></FOO>" - s2 = '<foo a="b"><bax>x</bax></foo>' - s3 = "<FOO a='b'><BAx>x</BAx></FOO>" - s4 = "<foo A='b'>x</foo>" - d = microdom.parseString(s) - d2 = microdom.parseString(s2) - d3 = microdom.parseString(s3, caseInsensitive=1) - d4 = microdom.parseString(s4, caseInsensitive=1, preserveCase=1) - d5 = microdom.parseString(s4, caseInsensitive=1, preserveCase=0) - d6 = microdom.parseString(s4, caseInsensitive=0, preserveCase=0) - out = microdom.parseString(s).documentElement.toxml() - self.assertRaises(microdom.MismatchedTags, microdom.parseString, - s, caseInsensitive=0) - self.assertEquals(out, s2) - self.failUnless(d.isEqualToDocument(d2)) - self.failUnless(d.isEqualToDocument(d3)) - self.failUnless(d4.documentElement.hasAttribute('a')) - self.failIf(d6.documentElement.hasAttribute('a')) - self.assertEquals(d4.documentElement.toxml(), '<foo A="b">x</foo>') - self.assertEquals(d5.documentElement.toxml(), '<foo a="b">x</foo>') - def testEatingWhitespace(self): - s = """<hello> - </hello>""" - d = microdom.parseString(s) - self.failUnless(not d.documentElement.hasChildNodes(), - d.documentElement.childNodes) - self.failUnless(d.isEqualToDocument(microdom.parseString('<hello></hello>'))) - - def testLenientAmpersand(self): - prefix = "<?xml version='1.0'?>" - # we use <pre> so space will be preserved - for i, o in [("&", "&"), - ("& ", "& "), - ("&", "&"), - ("&hello monkey", "&hello monkey")]: - d = microdom.parseString("%s<pre>%s</pre>" - % (prefix, i), beExtremelyLenient=1) - self.assertEquals(d.documentElement.toxml(), "<pre>%s</pre>" % o) - # non-space preserving - d = microdom.parseString("<t>hello & there</t>", beExtremelyLenient=1) - self.assertEquals(d.documentElement.toxml(), "<t>hello & there</t>") - - def testInsensitiveLenient(self): - # testing issue #537 - d = microdom.parseString( - "<?xml version='1.0'?><bar><xA><y>c</Xa> <foo></bar>", - beExtremelyLenient=1) - self.assertEquals(d.documentElement.firstChild().toxml(), "<xa><y>c</y></xa>") - - def testSpacing(self): - # testing issue #414 - s = "<?xml version='1.0'?><p><q>smart</q> <code>HairDryer</code></p>" - d = microdom.parseString(s, beExtremelyLenient=1) - expected = "<p><q>smart</q> <code>HairDryer</code></p>" - actual = d.documentElement.toxml() - self.assertEquals(expected, actual) - - testSpacing.todo = "AAARGH white space swallowing screws this up" - - def testLaterCloserSimple(self): - s = "<ul><li>foo<li>bar<li>baz</ul>" - d = microdom.parseString(s, beExtremelyLenient=1) - expected = "<ul><li>foo</li><li>bar</li><li>baz</li></ul>" - actual = d.documentElement.toxml() - self.assertEquals(expected, actual) - - def testLaterCloserCaseInsensitive(self): - s = "<DL><p><DT>foo<DD>bar</DL>" - d = microdom.parseString(s, beExtremelyLenient=1) - expected = "<dl><p></p><dt>foo</dt><dd>bar</dd></dl>" - actual = d.documentElement.toxml() - self.assertEquals(expected, actual) - - def testLaterCloserTable(self): - s = ("<table>" - "<tr><th>name<th>value<th>comment" - "<tr><th>this<td>tag<td>soup" - "<tr><th>must<td>be<td>handled" - "</table>") - expected = ("<table>" - "<tr><th>name</th><th>value</th><th>comment</th></tr>" - "<tr><th>this</th><td>tag</td><td>soup</td></tr>" - "<tr><th>must</th><td>be</td><td>handled</td></tr>" - "</table>") - d = microdom.parseString(s, beExtremelyLenient=1) - actual = d.documentElement.toxml() - self.assertEquals(expected, actual) - testLaterCloserTable.todo = "Table parsing needs to be fixed." - - def testLaterCloserDL(self): - s = ("<dl>" - "<dt>word<dd>definition" - "<dt>word<dt>word<dd>definition<dd>definition" - "</dl>") - expected = ("<dl>" - "<dt>word</dt><dd>definition</dd>" - "<dt>word</dt><dt>word</dt><dd>definition</dd><dd>definition</dd>" - "</dl>") - d = microdom.parseString(s, beExtremelyLenient=1) - actual = d.documentElement.toxml() - self.assertEquals(expected, actual) - - def testLaterCloserDL2(self): - s = ("<dl>" - "<dt>word<dd>definition<p>more definition" - "<dt>word" - "</dl>") - expected = ("<dl>" - "<dt>word</dt><dd>definition<p>more definition</p></dd>" - "<dt>word</dt>" - "</dl>") - d = microdom.parseString(s, beExtremelyLenient=1) - actual = d.documentElement.toxml() - self.assertEquals(expected, actual) - - testLaterCloserDL2.todo = "unclosed <p> messes it up." - - def testUnicodeTolerance(self): - import struct - s = '<foo><bar><baz /></bar></foo>' - j =(u'<?xml version="1.0" encoding="UCS-2" ?>\r\n<JAPANESE>\r\n' - u'<TITLE>\u5c02\u9580\u5bb6\u30ea\u30b9\u30c8 ') - j2=('\xff\xfe<\x00?\x00x\x00m\x00l\x00 \x00v\x00e\x00r\x00s\x00i\x00o' - '\x00n\x00=\x00"\x001\x00.\x000\x00"\x00 \x00e\x00n\x00c\x00o\x00d' - '\x00i\x00n\x00g\x00=\x00"\x00U\x00C\x00S\x00-\x002\x00"\x00 \x00?' - '\x00>\x00\r\x00\n\x00<\x00J\x00A\x00P\x00A\x00N\x00E\x00S\x00E' - '\x00>\x00\r\x00\n\x00<\x00T\x00I\x00T\x00L\x00E\x00>\x00\x02\\' - '\x80\x95\xb6[\xea0\xb90\xc80 \x00<\x00/\x00T\x00I\x00T\x00L\x00E' - '\x00>\x00<\x00/\x00J\x00A\x00P\x00A\x00N\x00E\x00S\x00E\x00>\x00') - def reverseBytes(s): - fmt = str(len(s) / 2) + 'H' - return struct.pack('<' + fmt, *struct.unpack('>' + fmt, s)) - urd = microdom.parseString(reverseBytes(s.encode('UTF-16'))) - ud = microdom.parseString(s.encode('UTF-16')) - sd = microdom.parseString(s) - self.assert_(ud.isEqualToDocument(sd)) - self.assert_(ud.isEqualToDocument(urd)) - ud = microdom.parseString(j) - urd = microdom.parseString(reverseBytes(j2)) - sd = microdom.parseString(j2) - self.assert_(ud.isEqualToDocument(sd)) - self.assert_(ud.isEqualToDocument(urd)) - - # test that raw text still gets encoded - # test that comments get encoded - j3=microdom.parseString(u'') - hdr='' - div=microdom.lmx().text(u'\u221a', raw=1).node - de=j3.documentElement - de.appendChild(div) - de.appendChild(j3.createComment(u'\u221a')) - self.assertEquals(j3.toxml(), hdr+ - u'
                  \u221a
                  '.encode('utf8')) - - def testNamedChildren(self): - tests = {"asdfadsf" - "" : 3, - 'asdf' : 0, - '' : 1, - } - for t in tests.keys(): - node = microdom.parseString(t).documentElement - result = domhelpers.namedChildren(node, 'bar') - self.assertEquals(len(result), tests[t]) - if result: - self.assert_(hasattr(result[0], 'tagName')) - - def testCloneNode(self): - s = 'x' - node = microdom.parseString(s).documentElement - clone = node.cloneNode(deep=1) - self.failIfEquals(node, clone) - self.assertEquals(len(node.childNodes), len(clone.childNodes)) - c1, c2 = node.firstChild(), clone.firstChild() - self.failIfEquals(c1, c2) - self.assertEquals(len(c1.childNodes), len(c2.childNodes)) - self.failIfEquals(c1.firstChild(), c2.firstChild()) - self.assertEquals(s, clone.toxml()) - self.assertEquals(node.namespace, clone.namespace) - - def testCloneDocument(self): - s = ('' - '') - - node = microdom.parseString(s) - clone = node.cloneNode(deep=1) - self.failIfEquals(node, clone) - self.assertEquals(len(node.childNodes), len(clone.childNodes)) - self.assertEquals(s, clone.toxml()) - - self.failUnless(clone.isEqualToDocument(node)) - self.failUnless(node.isEqualToDocument(clone)) - - - def testLMX(self): - n = microdom.Element("p") - lmx = microdom.lmx(n) - lmx.text("foo") - b = lmx.b(a="c") - b.foo()["z"] = "foo" - b.foo() - b.add("bar", c="y") - - s = '

                  foo

                  ' - self.assertEquals(s, n.toxml()) - - def testDict(self): - n = microdom.Element("p") - d = {n : 1} # will fail if Element is unhashable - - def testEscaping(self): - # issue 590 - raw = "&'some \"stuff\"', " - cooked = "&'some "stuff"', <what up?>" - esc1 = microdom.escape(raw) - self.assertEquals(esc1, cooked) - self.assertEquals(microdom.unescape(esc1), raw) - - def testNamespaces(self): - s = ''' - - - - here is some space - - - - ''' - d = microdom.parseString(s) - # at least make sure it doesn't traceback - s2 = d.toprettyxml() - self.assertEquals(d.documentElement.namespace, - "base") - self.assertEquals(d.documentElement.getElementsByTagName("y")[0].namespace, - "base") - self.assertEquals( - d.documentElement.getElementsByTagName("y")[1].getAttributeNS('base','q'), - '1') - - d2 = microdom.parseString(s2) - self.assertEquals(d2.documentElement.namespace, - "base") - self.assertEquals(d2.documentElement.getElementsByTagName("y")[0].namespace, - "base") - self.assertEquals( - d2.documentElement.getElementsByTagName("y")[1].getAttributeNS('base','q'), - '1') - - def testNamespaceDelete(self): - """ - Test that C{toxml} can support xml structures that remove namespaces. - """ - s1 = ('' - '') - s2 = microdom.parseString(s1).toxml() - self.assertEquals(s1, s2) - - def testNamespaceInheritance(self): - """ - Check that unspecified namespace is a thing separate from undefined - namespace. This test added after discovering some weirdness in Lore. - """ - # will only work if childNodes is mutated. not sure why. - child = microdom.Element('ol') - parent = microdom.Element('div', namespace='http://www.w3.org/1999/xhtml') - parent.childNodes = [child] - self.assertEquals(parent.toxml(), - '
                    ') - - -class TestBrokenHTML(TestCase): - """ - Tests for when microdom encounters very bad HTML and C{beExtremelyLenient} - is enabled. These tests are inspired by some HTML generated in by a mailer, - which breaks up very long lines by splitting them with '!\n '. The expected - behaviour is loosely modelled on the way Firefox treats very bad HTML. - """ - - def checkParsed(self, input, expected, beExtremelyLenient=1): - """ - Check that C{input}, when parsed, produces a DOM where the XML - of the document element is equal to C{expected}. - """ - output = microdom.parseString(input, - beExtremelyLenient=beExtremelyLenient) - self.assertEquals(output.documentElement.toxml(), expected) - - - def test_brokenAttributeName(self): - """ - Check that microdom does its best to handle broken attribute names. - The important thing is that it doesn't raise an exception. - """ - input = '

                    Foo

                    ' - expected = ('

                    ' - 'Foo

                    ') - self.checkParsed(input, expected) - - - def test_brokenAttributeValue(self): - """ - Check that microdom encompasses broken attribute values. - """ - input = '

                    Foo

                    ' - expected = '

                    Foo

                    ' - self.checkParsed(input, expected) - - - def test_brokenOpeningTag(self): - """ - Check that microdom does its best to handle broken opening tags. - The important thing is that it doesn't raise an exception. - """ - input = '

                    Hello World!

                    ' - expected = '

                    Hello World!

                    ' - self.checkParsed(input, expected) - - - def test_brokenSelfClosingTag(self): - """ - Check that microdom does its best to handle broken self-closing tags - The important thing is that it doesn't raise an exception. - """ - self.checkParsed('', - '') - self.checkParsed('', '') - - - def test_brokenClosingTag(self): - """ - Check that microdom does its best to handle broken closing tags. - The important thing is that it doesn't raise an exception. - """ - input = '

                    Hello World!

                    ' - expected = '

                    Hello World!

                    ' - self.checkParsed(input, expected) - input = '

                    Hello World!

                    ' - self.checkParsed(input, expected) - input = '

                    Hello World!

                    ' - self.checkParsed(input, expected) - input = '

                    Hello World!

                    ' - expected = '

                    Hello World!

                    ' - self.checkParsed(input, expected) - diff --git a/tools/buildbot/pylibs/twisted/web/test/test_xmlrpc.py b/tools/buildbot/pylibs/twisted/web/test/test_xmlrpc.py deleted file mode 100644 index c34430a..0000000 --- a/tools/buildbot/pylibs/twisted/web/test/test_xmlrpc.py +++ /dev/null @@ -1,452 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_xmlrpc -*- -# -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test XML-RPC support. -""" - -try: - import xmlrpclib -except ImportError: - xmlrpclib = None - class XMLRPC: pass -else: - from twisted.web import xmlrpc - from twisted.web.xmlrpc import XMLRPC, addIntrospection, _QueryFactory - -from twisted.trial import unittest -from twisted.web import server, static, client, error, http -from twisted.internet import reactor, defer -from twisted.internet.error import ConnectionDone -from twisted.python import failure - - -class TestRuntimeError(RuntimeError): - pass - -class TestValueError(ValueError): - pass - - - -class Test(XMLRPC): - - FAILURE = 666 - NOT_FOUND = 23 - SESSION_EXPIRED = 42 - - # the doc string is part of the test - def xmlrpc_add(self, a, b): - """ - This function add two numbers. - """ - return a + b - - xmlrpc_add.signature = [['int', 'int', 'int'], - ['double', 'double', 'double']] - - # the doc string is part of the test - def xmlrpc_pair(self, string, num): - """ - This function puts the two arguments in an array. - """ - return [string, num] - - xmlrpc_pair.signature = [['array', 'string', 'int']] - - # the doc string is part of the test - def xmlrpc_defer(self, x): - """Help for defer.""" - return defer.succeed(x) - - def xmlrpc_deferFail(self): - return defer.fail(TestValueError()) - - # don't add a doc string, it's part of the test - def xmlrpc_fail(self): - raise TestRuntimeError - - def xmlrpc_fault(self): - return xmlrpc.Fault(12, "hello") - - def xmlrpc_deferFault(self): - return defer.fail(xmlrpc.Fault(17, "hi")) - - def xmlrpc_complex(self): - return {"a": ["b", "c", 12, []], "D": "foo"} - - def xmlrpc_dict(self, map, key): - return map[key] - - def _getFunction(self, functionPath): - try: - return XMLRPC._getFunction(self, functionPath) - except xmlrpc.NoSuchFunction: - if functionPath.startswith("SESSION"): - raise xmlrpc.Fault(self.SESSION_EXPIRED, - "Session non-existant/expired.") - else: - raise - - xmlrpc_dict.help = 'Help for dict.' - -class TestAuthHeader(Test): - """ - This is used to get the header info so that we can test - authentication. - """ - def __init__(self): - Test.__init__(self) - self.request = None - - def render(self, request): - self.request = request - return Test.render(self, request) - - def xmlrpc_authinfo(self): - return self.request.getUser(), self.request.getPassword() - - -class TestQueryProtocol(xmlrpc.QueryProtocol): - """ - QueryProtocol for tests that saves headers received inside the factory. - """ - def handleHeader(self, key, val): - self.factory.headers[key.lower()] = val - - -class TestQueryFactory(xmlrpc._QueryFactory): - """ - QueryFactory using L{TestQueryProtocol} for saving headers. - """ - protocol = TestQueryProtocol - - def __init__(self, *args, **kwargs): - self.headers = {} - xmlrpc._QueryFactory.__init__(self, *args, **kwargs) - - -class XMLRPCTestCase(unittest.TestCase): - - def setUp(self): - self.p = reactor.listenTCP(0, server.Site(Test()), - interface="127.0.0.1") - self.port = self.p.getHost().port - self.factories = [] - - def tearDown(self): - self.factories = [] - return self.p.stopListening() - - def queryFactory(self, *args, **kwargs): - """ - Specific queryFactory for proxy that uses our custom - L{TestQueryFactory}, and save factories. - """ - factory = TestQueryFactory(*args, **kwargs) - self.factories.append(factory) - return factory - - def proxy(self): - p = xmlrpc.Proxy("http://127.0.0.1:%d/" % self.port) - p.queryFactory = self.queryFactory - return p - - def test_results(self): - inputOutput = [ - ("add", (2, 3), 5), - ("defer", ("a",), "a"), - ("dict", ({"a": 1}, "a"), 1), - ("pair", ("a", 1), ["a", 1]), - ("complex", (), {"a": ["b", "c", 12, []], "D": "foo"})] - - dl = [] - for meth, args, outp in inputOutput: - d = self.proxy().callRemote(meth, *args) - d.addCallback(self.assertEquals, outp) - dl.append(d) - return defer.DeferredList(dl, fireOnOneErrback=True) - - def test_errors(self): - """ - Verify that for each way a method exposed via XML-RPC can fail, the - correct 'Content-type' header is set in the response and that the - client-side Deferred is errbacked with an appropriate C{Fault} - instance. - """ - dl = [] - for code, methodName in [(666, "fail"), (666, "deferFail"), - (12, "fault"), (23, "noSuchMethod"), - (17, "deferFault"), (42, "SESSION_TEST")]: - d = self.proxy().callRemote(methodName) - d = self.assertFailure(d, xmlrpc.Fault) - d.addCallback(lambda exc, code=code: - self.assertEquals(exc.faultCode, code)) - dl.append(d) - d = defer.DeferredList(dl, fireOnOneErrback=True) - def cb(ign): - for factory in self.factories: - self.assertEquals(factory.headers['content-type'], - 'text/xml') - self.flushLoggedErrors(TestRuntimeError, TestValueError) - d.addCallback(cb) - return d - - def test_errorGet(self): - """ - A classic GET on the xml server should return a NOT_ALLOWED. - """ - d = client.getPage("http://127.0.0.1:%d/" % (self.port,)) - d = self.assertFailure(d, error.Error) - d.addCallback( - lambda exc: self.assertEquals(int(exc.args[0]), http.NOT_ALLOWED)) - return d - - def test_errorXMLContent(self): - """ - Test that an invalid XML input returns an L{xmlrpc.Fault}. - """ - d = client.getPage("http://127.0.0.1:%d/" % (self.port,), - method="POST", postdata="foo") - def cb(result): - self.assertRaises(xmlrpc.Fault, xmlrpclib.loads, result) - d.addCallback(cb) - return d - - -class XMLRPCTestCase2(XMLRPCTestCase): - """ - Test with proxy that doesn't add a slash. - """ - - def proxy(self): - p = xmlrpc.Proxy("http://127.0.0.1:%d" % self.port) - p.queryFactory = self.queryFactory - return p - - - -class XMLRPCAllowNoneTestCase(unittest.TestCase): - """ - Test with allowNone set to True. - - These are not meant to be exhaustive serialization tests, since - L{xmlrpclib} does all of the actual serialization work. They are just - meant to exercise a few codepaths to make sure we are calling into - xmlrpclib correctly. - """ - - def setUp(self): - self.p = reactor.listenTCP( - 0, server.Site(Test(allowNone=True)), interface="127.0.0.1") - self.port = self.p.getHost().port - - - def tearDown(self): - return self.p.stopListening() - - - def proxy(self): - return xmlrpc.Proxy("http://127.0.0.1:%d" % (self.port,), - allowNone=True) - - - def test_deferredNone(self): - """ - Test that passing a C{None} as an argument to a remote method and - returning a L{Deferred} which fires with C{None} properly passes - over the network if allowNone is set to True. - """ - d = self.proxy().callRemote('defer', None) - d.addCallback(self.assertEquals, None) - return d - - - def test_dictWithNoneValue(self): - """ - Test that return a C{dict} with C{None} as a value works properly. - """ - d = self.proxy().callRemote('defer', {'a': None}) - d.addCallback(self.assertEquals, {'a': None}) - return d - - - -class XMLRPCTestAuthenticated(XMLRPCTestCase): - """ - Test with authenticated proxy. We run this with the same inout/ouput as - above. - """ - user = "username" - password = "asecret" - - def setUp(self): - self.p = reactor.listenTCP(0, server.Site(TestAuthHeader()), - interface="127.0.0.1") - self.port = self.p.getHost().port - self.factories = [] - - - def test_authInfoInURL(self): - p = xmlrpc.Proxy("http://%s:%s@127.0.0.1:%d/" % ( - self.user, self.password, self.port)) - d = p.callRemote("authinfo") - d.addCallback(self.assertEquals, [self.user, self.password]) - return d - - - def test_explicitAuthInfo(self): - p = xmlrpc.Proxy("http://127.0.0.1:%d/" % ( - self.port,), self.user, self.password) - d = p.callRemote("authinfo") - d.addCallback(self.assertEquals, [self.user, self.password]) - return d - - - def test_explicitAuthInfoOverride(self): - p = xmlrpc.Proxy("http://wrong:info@127.0.0.1:%d/" % ( - self.port,), self.user, self.password) - d = p.callRemote("authinfo") - d.addCallback(self.assertEquals, [self.user, self.password]) - return d - - -class XMLRPCTestIntrospection(XMLRPCTestCase): - - def setUp(self): - xmlrpc = Test() - addIntrospection(xmlrpc) - self.p = reactor.listenTCP(0, server.Site(xmlrpc),interface="127.0.0.1") - self.port = self.p.getHost().port - self.factories = [] - - def test_listMethods(self): - - def cbMethods(meths): - meths.sort() - self.failUnlessEqual( - meths, - ['add', 'complex', 'defer', 'deferFail', - 'deferFault', 'dict', 'fail', 'fault', - 'pair', 'system.listMethods', - 'system.methodHelp', - 'system.methodSignature']) - - d = self.proxy().callRemote("system.listMethods") - d.addCallback(cbMethods) - return d - - def test_methodHelp(self): - inputOutputs = [ - ("defer", "Help for defer."), - ("fail", ""), - ("dict", "Help for dict.")] - - dl = [] - for meth, expected in inputOutputs: - d = self.proxy().callRemote("system.methodHelp", meth) - d.addCallback(self.assertEquals, expected) - dl.append(d) - return defer.DeferredList(dl, fireOnOneErrback=True) - - def test_methodSignature(self): - inputOutputs = [ - ("defer", ""), - ("add", [['int', 'int', 'int'], - ['double', 'double', 'double']]), - ("pair", [['array', 'string', 'int']])] - - dl = [] - for meth, expected in inputOutputs: - d = self.proxy().callRemote("system.methodSignature", meth) - d.addCallback(self.assertEquals, expected) - dl.append(d) - return defer.DeferredList(dl, fireOnOneErrback=True) - - -class XMLRPCClientErrorHandling(unittest.TestCase): - """ - Test error handling on the xmlrpc client. - """ - def setUp(self): - self.resource = static.File(__file__) - self.resource.isLeaf = True - self.port = reactor.listenTCP(0, server.Site(self.resource), - interface='127.0.0.1') - - def tearDown(self): - return self.port.stopListening() - - def test_erroneousResponse(self): - """ - Test that calling the xmlrpc client on a static http server raises - an exception. - """ - proxy = xmlrpc.Proxy("http://127.0.0.1:%d/" % - (self.port.getHost().port,)) - return self.assertFailure(proxy.callRemote("someMethod"), Exception) - - - -class TestQueryFactoryParseResponse(unittest.TestCase): - """ - Test the behaviour of L{_QueryFactory.parseResponse}. - """ - - def setUp(self): - # The _QueryFactory that we are testing. We don't care about any - # of the constructor parameters. - self.queryFactory = _QueryFactory( - path=None, host=None, method='POST', user=None, password=None, - allowNone=False, args=()) - # An XML-RPC response that will parse without raising an error. - self.goodContents = xmlrpclib.dumps(('',)) - # An 'XML-RPC response' that will raise a parsing error. - self.badContents = 'invalid xml' - # A dummy 'reason' to pass to clientConnectionLost. We don't care - # what it is. - self.reason = failure.Failure(ConnectionDone()) - - - def test_parseResponseCallbackSafety(self): - """ - We can safely call L{_QueryFactory.clientConnectionLost} as a callback - of L{_QueryFactory.parseResponse}. - """ - d = self.queryFactory.deferred - # The failure mode is that this callback raises an AlreadyCalled - # error. We have to add it now so that it gets called synchronously - # and triggers the race condition. - d.addCallback(self.queryFactory.clientConnectionLost, self.reason) - self.queryFactory.parseResponse(self.goodContents) - return d - - - def test_parseResponseErrbackSafety(self): - """ - We can safely call L{_QueryFactory.clientConnectionLost} as an errback - of L{_QueryFactory.parseResponse}. - """ - d = self.queryFactory.deferred - # The failure mode is that this callback raises an AlreadyCalled - # error. We have to add it now so that it gets called synchronously - # and triggers the race condition. - d.addErrback(self.queryFactory.clientConnectionLost, self.reason) - self.queryFactory.parseResponse(self.badContents) - return d - - - def test_badStatusErrbackSafety(self): - """ - We can safely call L{_QueryFactory.clientConnectionLost} as an errback - of L{_QueryFactory.badStatus}. - """ - d = self.queryFactory.deferred - # The failure mode is that this callback raises an AlreadyCalled - # error. We have to add it now so that it gets called synchronously - # and triggers the race condition. - d.addErrback(self.queryFactory.clientConnectionLost, self.reason) - self.queryFactory.badStatus('status', 'message') - return d diff --git a/tools/buildbot/pylibs/twisted/web/topfiles/NEWS b/tools/buildbot/pylibs/twisted/web/topfiles/NEWS deleted file mode 100644 index 5168065a..0000000 --- a/tools/buildbot/pylibs/twisted/web/topfiles/NEWS +++ /dev/null @@ -1,107 +0,0 @@ -8.1.0 (2008-05-18) -================== - -Fixes ------ - - - Fixed an XMLRPC bug whereby sometimes a callRemote Deferred would - accidentally be fired twice when a connection was lost during the handling of - a response (#3152) - - Fixed a bug in the "Using Twisted Web" document which prevented an example - resource from being renderable (#3147) - - The deprecated mktap API is no longer used (#3127) - - -8.0.0 (2008-03-17) -================== - -Features --------- - - Add support to twisted.web.client.getPage for the HTTP HEAD method. (#2750) - -Fixes ------ - - Set content-type in xmlrpc responses to "text/xml" (#2430) - - Add more error checking in the xmlrpc.XMLRPC render method, and enforce - POST requests. (#2505) - - Reject unicode input to twisted.web.client._parse to reject invalid - unicode URLs early. (#2628) - - Correctly re-quote URL path segments when generating an URL string to - return from Request.prePathURL. (#2934) - - Make twisted.web.proxy.ProxyClientFactory close the connection when - reporting a 501 error. (#1089) - - Fix twisted.web.proxy.ReverseProxyResource to specify the port in the - host header if different from 80. (#1117) - - Change twisted.web.proxy.ReverseProxyResource so that it correctly encodes - the request URI it sends on to the server for which it is a proxy. (#3013) - - Make "twistd web --personal" use PBServerFactory (#2681) - -Misc ----- - - #1996, #2382, #2211, #2633, #2634, #2640, #2752, #238, #2905 - - -0.7.0 (2007-01-02) -================== - -Features --------- - - Python 2.5 is now supported (#1867) - - twisted.web.xmlrpc now supports the xml-rpc extension type - in both the server and the client (#469) - -Fixes ------ - - Microdom and SUX now manages certain malformed XML more resiliently - (#1984, #2225, #2298) - - twisted.web.client.getPage can now deal with an URL of the form - "http://example.com" (no trailing slash) (#1080) - - The HTTP server now allows (invalid) URLs with multiple question - marks (#1550) - - '=' can now be in the value of a cookie (#1051) - - Microdom now correctly handles xmlns="" (#2184) - -Deprecations and Removals -------------------------- - - websetroot was removed, because it wasn't working anyway (#945) - - woven.guard no longer supports the old twisted.cred API (#1440) - -Other ------ -The following changes are minor or closely related to other changes. - - - #1636, #1637, #1638, #1936, #1883, #447 - - -0.6.0 (2006-05-21) -================== - -Features --------- - - Basic auth support for the XMLRPC client (#1474). - -Fixes ------ - - More correct datetime parsing. - - Efficiency improvements (#974) - - Handle popular non-RFC compliant formats for If-Modified-Since - headers (#976). - - Improve support for certain buggy CGI scripts. - - CONTENT_LENGTH is now available to CGI scripts. - - Support for even worse HTML in microdom (#1358). - - Trying to view a user's home page when the user doesn't have a - ~/public_html no longer displays a traceback (#551). - - Misc: #543, #1011, #1005, #1287, #1337, #1383, #1079, #1492, #1189, - #737, #872. - - -0.5.0 -===== - - Client properly reports timeouts as error - - "Socially deprecate" woven - - Fix memory leak in _c_urlarg library - - Stop using _c_urlarg library - - Fix 'gzip' and 'bzip2' content-encodings - - Escape log entries so remote user cannot corrupt the log - - Commented out range support because it's broken - - Fix HEAD responses without content-length diff --git a/tools/buildbot/pylibs/twisted/web/topfiles/README b/tools/buildbot/pylibs/twisted/web/topfiles/README deleted file mode 100644 index fb8ecc1..0000000 --- a/tools/buildbot/pylibs/twisted/web/topfiles/README +++ /dev/null @@ -1 +0,0 @@ -Twisted Web 8.1.0 diff --git a/tools/buildbot/pylibs/twisted/web/topfiles/setup.py b/tools/buildbot/pylibs/twisted/web/topfiles/setup.py deleted file mode 100644 index f1450bf..0000000 --- a/tools/buildbot/pylibs/twisted/web/topfiles/setup.py +++ /dev/null @@ -1,28 +0,0 @@ -import sys - -try: - from twisted.python import dist -except ImportError: - raise SystemExit("twisted.python.dist module not found. Make sure you " - "have installed the Twisted core package before " - "attempting to install any other Twisted projects.") - -if __name__ == '__main__': - dist.setup( - twisted_subproject="web", - scripts=dist.getScripts("web"), - # metadata - name="Twisted Web", - description="Twisted web server, programmable in Python.", - author="Twisted Matrix Laboratories", - author_email="twisted-python@twistedmatrix.com", - maintainer="James Knight", - maintainer_email="foom@fuhm.net", - url="http://twistedmatrix.com/trac/wiki/TwistedWeb", - license="MIT", - long_description="""\ -Twisted Web is a complete web server, aimed at hosting web -applications using Twisted and Python, but fully able to serve static -pages, also. -""", - ) diff --git a/tools/buildbot/pylibs/twisted/web/trp.py b/tools/buildbot/pylibs/twisted/web/trp.py deleted file mode 100644 index e2be8d6..0000000 --- a/tools/buildbot/pylibs/twisted/web/trp.py +++ /dev/null @@ -1,15 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -I contain ResourceUnpickler, which will unpickle any python object -named with the file extension .trp. -""" -from pickle import Unpickler - -def ResourceUnpickler(path, registry = None): - fl = open(path) - result = Unpickler(fl).load() - return result diff --git a/tools/buildbot/pylibs/twisted/web/twcgi.py b/tools/buildbot/pylibs/twisted/web/twcgi.py deleted file mode 100644 index 187df92..0000000 --- a/tools/buildbot/pylibs/twisted/web/twcgi.py +++ /dev/null @@ -1,256 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_cgi -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""I hold resource classes and helper classes that deal with CGI scripts. -""" - -# System Imports -import string -import os -import sys -import urllib - -# Twisted Imports -from twisted.web import http -from twisted.internet import reactor, protocol -from twisted.spread import pb -from twisted.python import log, filepath - -# Sibling Imports -import server -import error -import html -import resource -import static -from server import NOT_DONE_YET - -class CGIDirectory(resource.Resource, filepath.FilePath): - def __init__(self, pathname): - resource.Resource.__init__(self) - filepath.FilePath.__init__(self, pathname) - - def getChild(self, path, request): - fnp = self.child(path) - if not fnp.exists(): - return static.File.childNotFound - elif fnp.isdir(): - return CGIDirectory(fnp.path) - else: - return CGIScript(fnp.path) - return error.NoResource() - - def render(self, request): - return error.NoResource("CGI directories do not support directory listing.").render(request) - -class CGIScript(resource.Resource): - """I represent a CGI script. - - My implementation is complex due to the fact that it requires asynchronous - IPC with an external process with an unpleasant protocol. - """ - isLeaf = 1 - def __init__(self, filename, registry=None): - """Initialize, with the name of a CGI script file. - """ - self.filename = filename - - def render(self, request): - """Do various things to conform to the CGI specification. - - I will set up the usual slew of environment variables, then spin off a - process. - """ - script_name = "/"+string.join(request.prepath, '/') - python_path = string.join(sys.path, os.pathsep) - serverName = string.split(request.getRequestHostname(), ':')[0] - env = {"SERVER_SOFTWARE": server.version, - "SERVER_NAME": serverName, - "GATEWAY_INTERFACE": "CGI/1.1", - "SERVER_PROTOCOL": request.clientproto, - "SERVER_PORT": str(request.getHost().port), - "REQUEST_METHOD": request.method, - "SCRIPT_NAME": script_name, # XXX - "SCRIPT_FILENAME": self.filename, - "REQUEST_URI": request.uri, - } - - client = request.getClient() - if client is not None: - env['REMOTE_HOST'] = client - ip = request.getClientIP() - if ip is not None: - env['REMOTE_ADDR'] = ip - pp = request.postpath - if pp: - env["PATH_INFO"] = "/"+string.join(pp, '/') - - if hasattr(request, "content"): - # request.content is either a StringIO or a TemporaryFile, and - # the file pointer is sitting at the beginning (seek(0,0)) - request.content.seek(0,2) - length = request.content.tell() - request.content.seek(0,0) - env['CONTENT_LENGTH'] = str(length) - - qindex = string.find(request.uri, '?') - if qindex != -1: - qs = env['QUERY_STRING'] = request.uri[qindex+1:] - if '=' in qs: - qargs = [] - else: - qargs = [urllib.unquote(x) for x in qs.split('+')] - else: - env['QUERY_STRING'] = '' - qargs = [] - - # Propogate HTTP headers - for title, header in request.getAllHeaders().items(): - envname = string.upper(string.replace(title, '-', '_')) - if title not in ('content-type', 'content-length'): - envname = "HTTP_" + envname - env[envname] = header - # Propogate our environment - for key, value in os.environ.items(): - if not env.has_key(key): - env[key] = value - # And they're off! - self.runProcess(env, request, qargs) - return NOT_DONE_YET - - def runProcess(self, env, request, qargs=[]): - p = CGIProcessProtocol(request) - reactor.spawnProcess(p, self.filename, [self.filename]+qargs, env, os.path.dirname(self.filename)) - - -class FilteredScript(CGIScript): - """I am a special version of a CGI script, that uses a specific executable. - - This is useful for interfacing with other scripting languages that adhere - to the CGI standard (cf. PHPScript). My 'filter' attribute specifies what - executable to run, and my 'filename' init parameter describes which script - to pass to the first argument of that script. - """ - - filter = '/usr/bin/cat' - - def runProcess(self, env, request, qargs=[]): - p = CGIProcessProtocol(request) - reactor.spawnProcess(p, self.filter, [self.filter, self.filename]+qargs, env, os.path.dirname(self.filename)) - - -class PHP3Script(FilteredScript): - """I am a FilteredScript that uses the default PHP3 command on most systems. - """ - - filter = '/usr/bin/php3' - - -class PHPScript(FilteredScript): - """I am a FilteredScript that uses the PHP command on most systems. - Sometimes, php wants the path to itself as argv[0]. This is that time. - """ - - filter = '/usr/bin/php4' - - -class CGIProcessProtocol(protocol.ProcessProtocol, pb.Viewable): - handling_headers = 1 - headers_written = 0 - headertext = '' - errortext = '' - - # Remotely relay producer interface. - - def view_resumeProducing(self, issuer): - self.resumeProducing() - - def view_pauseProducing(self, issuer): - self.pauseProducing() - - def view_stopProducing(self, issuer): - self.stopProducing() - - def resumeProducing(self): - self.transport.resumeProducing() - - def pauseProducing(self): - self.transport.pauseProducing() - - def stopProducing(self): - self.transport.loseConnection() - - def __init__(self, request): - self.request = request - - def connectionMade(self): - self.request.registerProducer(self, 1) - self.request.content.seek(0, 0) - content = self.request.content.read() - if content: - self.transport.write(content) - self.transport.closeStdin() - - def errReceived(self, error): - self.errortext = self.errortext + error - - def outReceived(self, output): - """ - Handle a chunk of input - """ - # First, make sure that the headers from the script are sorted - # out (we'll want to do some parsing on these later.) - if self.handling_headers: - text = self.headertext + output - headerEnds = [] - for delimiter in '\n\n','\r\n\r\n','\r\r', '\n\r\n': - headerend = string.find(text,delimiter) - if headerend != -1: - headerEnds.append((headerend, delimiter)) - if headerEnds: - headerEnds.sort() - headerend, delimiter = headerEnds[0] - self.headertext = text[:headerend] - # This is a final version of the header text. - linebreak = delimiter[:len(delimiter)/2] - headers = string.split(self.headertext, linebreak) - for header in headers: - br = string.find(header,': ') - if br == -1: - log.msg( 'ignoring malformed CGI header: %s' % header ) - else: - headerName = string.lower(header[:br]) - headerText = header[br+2:] - if headerName == 'location': - self.request.setResponseCode(http.FOUND) - if headerName == 'status': - try: - statusNum = int(headerText[:3]) #"XXX " sometimes happens. - except: - log.msg( "malformed status header" ) - else: - self.request.setResponseCode(statusNum) - else: - self.request.setHeader(headerName,headerText) - output = text[headerend+len(delimiter):] - self.handling_headers = 0 - if self.handling_headers: - self.headertext = text - if not self.handling_headers: - self.request.write(output) - - def processEnded(self, reason): - if reason.value.exitCode != 0: - log.msg("CGI %s exited with exit code %s" % - (self.request.uri, reason.value.exitCode)) - if self.errortext: - log.msg("Errors from CGI %s: %s" % (self.request.uri, self.errortext)) - if self.handling_headers: - log.msg("Premature end of headers in %s: %s" % (self.request.uri, self.headertext)) - self.request.write( - error.ErrorPage(http.INTERNAL_SERVER_ERROR, - "CGI Script Error", - "Premature end of script headers.").render(self.request)) - self.request.unregisterProducer() - self.request.finish() diff --git a/tools/buildbot/pylibs/twisted/web/util.py b/tools/buildbot/pylibs/twisted/web/util.py deleted file mode 100644 index 0a50de6..0000000 --- a/tools/buildbot/pylibs/twisted/web/util.py +++ /dev/null @@ -1,390 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_web -*- - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -from cStringIO import StringIO - -from twisted.python import failure - -import html -import resource - - -import linecache -import string, re -import types - - -def redirectTo(URL, request): - request.redirect(URL) - return """ - - - - - - click here - - -""" % {'url': URL} - -class Redirect(resource.Resource): - - isLeaf = 1 - - def __init__(self, url): - resource.Resource.__init__(self) - self.url = url - - def render(self, request): - return redirectTo(self.url, request) - - def getChild(self, name, request): - return self - -class ChildRedirector(Redirect): - isLeaf = 0 - def __init__(self, url): - # XXX is this enough? - if ((url.find('://') == -1) - and (not url.startswith('..')) - and (not url.startswith('/'))): - raise ValueError("It seems you've given me a redirect (%s) that is a child of myself! That's not good, it'll cause an infinite redirect." % url) - Redirect.__init__(self, url) - - def getChild(self, name, request): - newUrl = self.url - if not newUrl.endswith('/'): - newUrl += '/' - newUrl += name - return ChildRedirector(newUrl) - - -from twisted.python import urlpath - -class ParentRedirect(resource.Resource): - """ - I redirect to URLPath.here(). - """ - isLeaf = 1 - def render(self, request): - return redirectTo(urlpath.URLPath.fromRequest(request).here(), request) - - def getChild(self, request): - return self - - -class DeferredResource(resource.Resource): - """ - I wrap up a Deferred that will eventually result in a Resource - object. - """ - isLeaf = 1 - - def __init__(self, d): - resource.Resource.__init__(self) - self.d = d - - def getChild(self, name, request): - return self - - def render(self, request): - self.d.addCallback(self._cbChild, request).addErrback( - self._ebChild,request) - from twisted.web.server import NOT_DONE_YET - return NOT_DONE_YET - - def _cbChild(self, child, request): - result = resource.getChildForRequest(child, request).render(request) - from twisted.web.server import NOT_DONE_YET - if result == NOT_DONE_YET: - return - else: - request.write(result) - request.finish() - - def _ebChild(self, reason, request): - request.processingFailed(reason) - return reason - - -stylesheet = """ - -""" - - -def htmlrepr(x): - return htmlReprTypes.get(type(x), htmlUnknown)(x) - -def saferepr(x): - try: - rx = repr(x) - except: - rx = "" % (x.__class__, id(x)) - return rx - -def htmlUnknown(x): - return ''+html.escape(saferepr(x))+'' - -def htmlDict(d): - io = StringIO() - w = io.write - w('
                    Dictionary instance @ %s' % hex(id(d))) - w('') - for k, v in d.items(): - - if k == '__builtins__': - v = 'builtin dictionary' - w('' % (htmlrepr(k), htmlrepr(v))) - w('
                    %s%s
                    ') - return io.getvalue() - -def htmlList(l): - io = StringIO() - w = io.write - w('
                    List instance @ %s' % hex(id(l))) - for i in l: - w('
                    %s
                    ' % htmlrepr(i)) - w('
                    ') - return io.getvalue() - -def htmlInst(i): - if hasattr(i, "__html__"): - s = i.__html__() - else: - s = html.escape(saferepr(i)) - return '''
                    %s instance @ %s - %s
                    - ''' % (i.__class__, hex(id(i)), s) - -def htmlString(s): - return html.escape(saferepr(s)) - -def htmlFunc(f): - return ('
                    ' + - html.escape("function %s in file %s at line %s" % - (f.__name__, f.func_code.co_filename, - f.func_code.co_firstlineno))+ - '
                    ') - -htmlReprTypes = {types.DictType: htmlDict, - types.ListType: htmlList, - types.InstanceType: htmlInst, - types.StringType: htmlString, - types.FunctionType: htmlFunc} - - - -def htmlIndent(snippetLine): - ret = string.replace(string.replace(html.escape(string.rstrip(snippetLine)), - ' ', ' '), - '\t', '        ') - return ret - -def formatFailure(myFailure): - - exceptionHTML = """ -

                    %s: %s

                    -""" - - frameHTML = """ -
                    %s, line %s in %s
                    -""" - - snippetLineHTML = """ -
                    %s%s
                    -""" - - snippetHighlightLineHTML = """ -
                    %s%s
                    -""" - - variableHTML = """ -%s%s -""" - - if not isinstance(myFailure, failure.Failure): - return html.PRE(str(myFailure)) - io = StringIO() - w = io.write - w(stylesheet) - w('') - w(exceptionHTML % (html.escape(str(myFailure.type)), - html.escape(str(myFailure.value)))) - w('') - w('
                    ') - first = 1 - for method, filename, lineno, localVars, globalVars in myFailure.frames: - if filename == '': - continue - if first: - w('
                    ') - first = 0 - else: - w('
                    ') - w(frameHTML % (filename, lineno, method)) - - w('
                    ') - textSnippet = '' - for snipLineNo in range(lineno-2, lineno+2): - snipLine = linecache.getline(filename, snipLineNo) - textSnippet += snipLine - snipLine = htmlIndent(snipLine) - if snipLineNo == lineno: - w(snippetHighlightLineHTML % (snipLineNo, snipLine)) - else: - w(snippetLineHTML % (snipLineNo, snipLine)) - w('
                    ') - - # Instance variables - for name, var in localVars: - if name == 'self' and hasattr(var, '__dict__'): - usedVars = [ (key, value) for (key, value) in var.__dict__.items() - if re.search(r'\W'+'self.'+key+r'\W', textSnippet) ] - if usedVars: - w('
                    Self') - w('') - for key, value in usedVars: - w(variableHTML % (key, htmlrepr(value))) - w('
                    ') - break - - # Local and global vars - for nm, varList in ('Locals', localVars), ('Globals', globalVars): - usedVars = [ (name, var) for (name, var) in varList - if re.search(r'\W'+name+r'\W', textSnippet) ] - if usedVars: - w('
                    %s' % nm) - for name, var in usedVars: - w(variableHTML % (name, htmlrepr(var))) - w('
                    ') - - w('
                    ') # frame - w('
                    ') # stacktrace - w(' ') - w(exceptionHTML % (html.escape(str(myFailure.type)), - html.escape(str(myFailure.value)))) - - return io.getvalue() diff --git a/tools/buildbot/pylibs/twisted/web/vhost.py b/tools/buildbot/pylibs/twisted/web/vhost.py deleted file mode 100644 index 433c4b3..0000000 --- a/tools/buildbot/pylibs/twisted/web/vhost.py +++ /dev/null @@ -1,141 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""I am a virtual hosts implementation. -""" - -# System Imports -import string - -# Twisted Imports -from twisted.python import roots - -# Sibling Imports -import resource -import error - -class VirtualHostCollection(roots.Homogenous): - """Wrapper for virtual hosts collection. - - This exists for configuration purposes. - """ - entityType = resource.Resource - - def __init__(self, nvh): - self.nvh = nvh - - def listStaticEntities(self): - return self.nvh.hosts.items() - - def getStaticEntity(self, name): - return self.nvh.hosts.get(self) - - def reallyPutEntity(self, name, entity): - self.nvh.addHost(name, entity) - - def delEntity(self, name): - self.nvh.removeHost(name) - - -class NameVirtualHost(resource.Resource): - """I am a resource which represents named virtual hosts. - """ - - default = None - - def __init__(self): - """Initialize. - """ - resource.Resource.__init__(self) - self.hosts = {} - - def listStaticEntities(self): - return resource.Resource.listStaticEntities(self) + [("Virtual Hosts", VirtualHostCollection(self))] - - def getStaticEntity(self, name): - if name == "Virtual Hosts": - return VirtualHostCollection(self) - else: - return resource.Resource.getStaticEntity(self, name) - - def addHost(self, name, resrc): - """Add a host to this virtual host. - - This will take a host named `name', and map it to a resource - `resrc'. For example, a setup for our virtual hosts would be:: - - nvh.addHost('divunal.com', divunalDirectory) - nvh.addHost('www.divunal.com', divunalDirectory) - nvh.addHost('twistedmatrix.com', twistedMatrixDirectory) - nvh.addHost('www.twistedmatrix.com', twistedMatrixDirectory) - """ - self.hosts[name] = resrc - - def removeHost(self, name): - """Remove a host.""" - del self.hosts[name] - - def _getResourceForRequest(self, request): - """(Internal) Get the appropriate resource for the given host. - """ - hostHeader = request.getHeader('host') - if hostHeader == None: - return self.default or error.NoResource() - else: - host = string.split(string.lower(hostHeader),':')[0] - return (self.hosts.get(host, self.default) - or error.NoResource("host %s not in vhost map" % repr(host))) - - def render(self, request): - """Implementation of resource.Resource's render method. - """ - resrc = self._getResourceForRequest(request) - return resrc.render(request) - - def getChild(self, path, request): - """Implementation of resource.Resource's getChild method. - """ - resrc = self._getResourceForRequest(request) - if resrc.isLeaf: - request.postpath.insert(0,request.prepath.pop(-1)) - return resrc - else: - return resrc.getChildWithDefault(path, request) - -class _HostResource(resource.Resource): - - def getChild(self, path, request): - if ':' in path: - host, port = path.split(':', 1) - port = int(port) - else: - host, port = path, 80 - request.setHost(host, port) - prefixLen = 3+request.isSecure()+4+len(path)+len(request.prepath[-3]) - request.path = '/'+'/'.join(request.postpath) - request.uri = request.uri[prefixLen:] - del request.prepath[:3] - return request.site.getResourceFor(request) - - -class VHostMonsterResource(resource.Resource): - - """ - Use this to be able to record the hostname and method (http vs. https) - in the URL without disturbing your web site. If you put this resource - in a URL http://foo.com/bar then requests to - http://foo.com/bar/http/baz.com/something will be equivalent to - http://foo.com/something, except that the hostname the request will - appear to be accessing will be "baz.com". So if "baz.com" is redirecting - all requests for to foo.com, while foo.com is inaccessible from the outside, - then redirect and url generation will work correctly - """ - def getChild(self, path, request): - if path == 'http': - request.isSecure = lambda: 0 - elif path == 'https': - request.isSecure = lambda: 1 - return _HostResource() - diff --git a/tools/buildbot/pylibs/twisted/web/widgets.py b/tools/buildbot/pylibs/twisted/web/widgets.py deleted file mode 100644 index de2af70..0000000 --- a/tools/buildbot/pylibs/twisted/web/widgets.py +++ /dev/null @@ -1,1050 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_web -*- -# -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""A twisted web component framework. - -This module is DEPRECATED. -""" - -import warnings -warnings.warn("This module is deprecated, please use Woven instead.", DeprecationWarning) - -# System Imports -import string, time, types, traceback, pprint, sys, os -import linecache -import re -from cStringIO import StringIO - -# Twisted Imports -from twisted.python import failure, log, rebuild, reflect, util -from twisted.internet import defer -from twisted.web import http - -# Sibling Imports -import html, resource, error -import util as webutil - -#backwards compatibility -from util import formatFailure, htmlrepr, htmlUnknown, htmlDict, htmlList,\ - htmlInst, htmlString, htmlReprTypes - - - -from server import NOT_DONE_YET - -True = (1==1) -False = not True - - -# magic value that sez a widget needs to take over the whole page. - -FORGET_IT = 99 - -def listify(x): - return [x] -def _ellipsize(x): - y = repr(x) - if len(y) > 1024: - return y[:1024]+"..." - return y - - -class Widget: - """A component of a web page. - """ - title = None - def getTitle(self, request): - return self.title or reflect.qual(self.__class__) - - def display(self, request): - """Implement me to represent your widget. - - I must return a list of strings and twisted.internet.defer.Deferred - instances. - """ - raise NotImplementedError("%s.display" % reflect.qual(self.__class__)) - -class StreamWidget(Widget): - """A 'streamable' component of a webpage. - """ - - def stream(self, write, request): - """Call 'write' multiple times with a string argument to represent this widget. - """ - raise NotImplementedError("%s.stream" % reflect.qual(self.__class__)) - - def display(self, request): - """Produce a list containing a single string. - """ - l = [] - try: - result = self.stream(l.append, request) - if result is not None: - return result - return l - except: - return [webutil.formatFailure(failure.Failure())] - -class WidgetMixin(Widget): - """A mix-in wrapper for a Widget. - - This mixin can be used to wrap functionality in any other widget with a - method of your choosing. It is designed to be used for mix-in classes that - can be mixed in to Form, StreamWidget, Presentation, etc, to augment the - data available to the 'display' methods of those classes, usually by adding - it to a Session. - """ - - def display(self): - raise NotImplementedError("%s.display" % self.__class__) - - def displayMixedWidget(self, request): - for base in reflect.allYourBase(self.__class__): - if issubclass(base, Widget) and not issubclass(base, WidgetMixin): - return base.display(self, request) - -class Presentation(Widget): - """I am a widget which formats a template with interspersed python expressions. - """ - template = ''' - Hello, %%%%world%%%%. - ''' - world = "you didn't assign to the 'template' attribute" - def __init__(self, template=None, filename=None): - if filename: - self.template = open(filename).read() - elif template: - self.template = template - self.variables = {} - self.tmpl = string.split(self.template, "%%%%") - - def addClassVars(self, namespace, Class): - for base in Class.__bases__: - # Traverse only superclasses that know about Presentation. - if issubclass(base, Presentation) and base is not Presentation: - self.addClassVars(namespace, base) - # 'lower' classes in the class heirarchy take precedence. - for k in Class.__dict__.keys(): - namespace[k] = getattr(self, k) - - def addVariables(self, namespace, request): - self.addClassVars(namespace, self.__class__) - - def prePresent(self, request): - """Perform any tasks which must be done before presenting the page. - """ - - def formatTraceback(self, tb): - return [html.PRE(tb)] - - def streamCall(self, call, *args, **kw): - """Utility: Call a method like StreamWidget's 'stream'. - """ - io = StringIO() - apply(call, (io.write,) + args, kw) - return io.getvalue() - - def display(self, request): - tm = [] - flip = 0 - namespace = {} - self.prePresent(request) - self.addVariables(namespace, request) - # This variable may not be obscured... - namespace['request'] = request - namespace['self'] = self - for elem in self.tmpl: - flip = not flip - if flip: - if elem: - tm.append(elem) - else: - try: - x = eval(elem, namespace, namespace) - except: - log.deferr() - tm.append(webutil.formatFailure(failure.Failure())) - else: - if isinstance(x, types.ListType): - tm.extend(x) - elif isinstance(x, Widget): - val = x.display(request) - if not isinstance(val, types.ListType): - raise Exception("%s.display did not return a list, it returned %s!" % (x.__class__, repr(val))) - tm.extend(val) - else: - # Only two allowed types here should be deferred and - # string. - tm.append(x) - return tm - - -def htmlFor_hidden(write, name, value): - write('' % (name, value)) - -def htmlFor_file(write, name, value): - write('' % name) - -def htmlFor_string(write, name, value): - write('' % (name, value)) - -def htmlFor_password(write, name, value): - write('' % name) - -def htmlFor_text(write, name, value): - write('' % (name, value)) - -def htmlFor_menu(write, name, value, allowMultiple=False): - "Value of the format [(optionName, displayName[, selected]), ...]" - - write(' \n") - -def htmlFor_multimenu(write, name, value): - "Value of the format [(optionName, displayName[, selected]), ...]" - return htmlFor_menu(write, name, value, True) - -def htmlFor_checkbox(write, name, value): - "A checkbox." - if value: - value = 'checked = "1"' - else: - value = '' - write('\n' % (name, value)) - -def htmlFor_checkgroup(write, name, value): - "A check-group." - for optionName, displayName, checked in value: - checked = (checked and 'checked = "1"') or '' - write('%s
                    \n' % (name, optionName, checked, displayName)) - -def htmlFor_radio(write, name, value): - "A radio button group." - for optionName, displayName, checked in value: - checked = (checked and 'checked = "1"') or '' - write('%s
                    \n' % (name, optionName, checked, displayName)) - -class FormInputError(Exception): - pass - -class Form(Widget): - """I am a web form. - - In order to use me, you probably want to set self.formFields (or override - 'getFormFields') and override 'process'. In order to demonstrate how this - is done, here is a small sample Form subclass:: - - | from twisted.web import widgets - | class HelloForm(widgets.Form): - | formFields = [ - | ['string', 'Who to greet?', 'whoToGreet', 'World', - | 'This is for choosing who to greet.'], - | ['menu', 'How to greet?', 'how', [('cheerfully', 'with a smile'), - | ('sullenly', 'without enthusiasm'), - | ('spontaneously', 'on the spur of the moment')]] - | 'This is for choosing how to greet them.'] - | def process(self, write, request, submit, whoToGreet, how): - | write('The web wakes up and %s says, \"Hello, %s!\"' % (how, whoToGreet)) - - If you load this widget, you will see that it displays a form with 2 inputs - derived from data in formFields. Note the argument names to 'process': - after 'write' and 'request', they are the same as the 3rd elements ('Input - Name' parameters) of the formFields list. - """ - - formGen = { - 'hidden': htmlFor_hidden, - 'file': htmlFor_file, - 'string': htmlFor_string, - 'int': htmlFor_string, - 'float': htmlFor_string, - 'text': htmlFor_text, - 'menu': htmlFor_menu, - 'multimenu': htmlFor_multimenu, - 'password': htmlFor_password, - 'checkbox': htmlFor_checkbox, - 'checkgroup': htmlFor_checkgroup, - 'radio': htmlFor_radio, - } - - formParse = { - 'int': int, - 'float': float, - } - - formFields = [ - ] - - # do we raise an error when we get extra args or not? - formAcceptExtraArgs = 0 - - def getFormFields(self, request, fieldSet = None): - """I return a list of lists describing this form, or a Deferred. - - This information is used both to display the form and to process it. - The list is in the following format:: - - | [['Input Type', 'Display Name', 'Input Name', 'Input Value', 'Description'], - | ['Input Type 2', 'Display Name 2', 'Input Name 2', 'Input Value 2', 'Description 2'] - | ...] - - Valid values for 'Input Type' are: - - - 'hidden': a hidden field that contains a string that the user won't change - - - 'string': a short string - - - 'int': an integer, e.g. 1, 0, 25 or -23 - - - 'float': a float, e.g. 1.0, 2, -3.45, or 28.4324231 - - - 'text': a longer text field, suitable for entering paragraphs - - - 'menu': an HTML SELECT input, a list of choices - - - 'multimenu': an HTML SELECT input allowing multiple choices - - - 'checkgroup': a group of checkboxes - - - 'radio': a group of radio buttons - - - 'password': a 'string' field where the contents are not visible as the user types - - - 'file': a file-upload form (EXPERIMENTAL) - - 'Display Name' is a descriptive string that will be used to - identify the field to the user. - - The 'Input Name' must be a legal Python identifier that describes both - the value's name on the HTML form and the name of an argument to - 'self.process()'. - - The 'Input Value' is usually a string, but its value can depend on the - 'Input Type'. 'int' it is an integer, 'menu' it is a list of pairs of - strings, representing (value, name) pairs for the menu options. Input - value for 'checkgroup' and 'radio' should be a list of ('inputName', - 'Display Name', 'checked') triplets. - - The 'Description' field is an (optional) string which describes the form - item to the user. - - If this result is statically determined for your Form subclass, you can - assign it to FormSubclass.formFields; if you need to determine it - dynamically, you can override this method. - - Note: In many cases it is desirable to use user input for defaults in - the form rather than those supplied by your calculations, which is what - this method will do to self.formFields. If this is the case for you, - but you still need to dynamically calculate some fields, pass your - results back through this method by doing:: - - | def getFormFields(self, request): - | myFormFields = [self.myFieldCalculator()] - | return widgets.Form.getFormFields(self, request, myFormFields) - - """ - fields = [] - if fieldSet is None: - fieldSet = self.formFields - if not self.shouldProcess(request): - return fieldSet - - for field in fieldSet: - if len(field)==5: - inputType, displayName, inputName, inputValue, description = field - else: - inputType, displayName, inputName, inputValue = field - description = "" - - if inputType == 'checkbox': - if request.args.has_key('__checkboxes__'): - if inputName in request.args['__checkboxes__']: - inputValue = 1 - else: - inputValue = 0 - else: - inputValue = 0 - elif inputType in ('checkgroup', 'radio'): - if request.args.has_key(inputName): - keys = request.args[inputName] - else: - keys = [] - iv = inputValue - inputValue = [] - for optionName, optionDisplayName, checked in iv: - checked = optionName in keys - inputValue.append([optionName, optionDisplayName, checked]) - elif request.args.has_key(inputName): - iv = request.args[inputName][0] - if inputType in ['menu', 'multimenu']: - if iv in inputValue: - inputValue.remove(iv) - inputValue.insert(0, iv) - else: - inputValue = iv - fields.append([inputType, displayName, inputName, inputValue, description]) - return fields - - submitNames = ['Submit'] - actionURI = '' - - def format(self, form, write, request): - """I display an HTML FORM according to the result of self.getFormFields. - """ - write('
                    \n' - '\n' % (self.actionURI or request.uri)) - - for field in form: - if len(field) == 5: - inputType, displayName, inputName, inputValue, description = field - else: - inputType, displayName, inputName, inputValue = field - description = "" - write('\n\n' - '\n\n' % description) - - - write('\n
                    %s\n' % - (displayName, ((inputType == 'text') and 'top') or 'middle')) - self.formGen[inputType](write, inputName, inputValue) - write('\n
                    \n%s

                    \n') - for submitName in self.submitNames: - write('\n' % submitName) - write('
                    \n' - '\n' - % (reflect.qual(self.__class__))) - fid = self.getFormID() - if fid: - write('\n' % fid) - write("
                    \n") - - def getFormID(self): - """Override me: I disambiguate between multiple forms of the same type. - - In order to determine which form an HTTP POST request is for, you must - have some unique identifier which distinguishes your form from other - forms of the same class. An example of such a unique identifier would - be: on a page with multiple FrobConf forms, each FrobConf form refers - to a particular Frobnitz instance, which has a unique id(). The - FrobConf form's getFormID would probably look like this:: - - | def getFormID(self): - | return str(id(self.frobnitz)) - - By default, this method will return None, since distinct Form instances - may be identical as far as the application is concerned. - """ - - def process(self, write, request, submit, **kw): - """Override me: I process a form. - - I will only be called when the correct form input data to process this - form has been received. - - I take a variable number of arguments, beginning with 'write', - 'request', and 'submit'. 'write' is a callable object that will append - a string to the response, 'request' is a twisted.web.request.Request - instance, and 'submit' is the name of the submit action taken. - - The remainder of my arguments must be correctly named. They will each be named after one of the - - """ - write("
                    Submit: %s 
                    %s
                    " % (submit, html.PRE(pprint.PrettyPrinter().pformat(kw)))) - - def _doProcess(self, form, write, request): - """(internal) Prepare arguments for self.process. - """ - args = request.args.copy() - kw = {} - for field in form: - inputType, displayName, inputName, inputValue = field[:4] - if inputType == 'checkbox': - if request.args.has_key('__checkboxes__'): - if inputName in request.args['__checkboxes__']: - formData = 1 - else: - formData = 0 - else: - formData = 0 - elif inputType in ['checkgroup', 'radio', 'multimenu']: - if args.has_key(inputName): - formData = args[inputName] - del args[inputName] - else: - formData = [] - else: - if not args.has_key(inputName): - raise FormInputError("missing field %s." % repr(inputName)) - formData = args[inputName] - del args[inputName] - if not len(formData) == 1: - raise FormInputError("multiple values for field %s." %repr(inputName)) - formData = formData[0] - method = self.formParse.get(inputType) - if method: - try: - formData = method(formData) - except: - raise FormInputError("%s: %s" % (displayName, "error")) - kw[inputName] = formData - submitAction = args.get('submit') - if submitAction: - submitAction = submitAction[0] - for field in ['submit', '__formtype__', '__checkboxes__']: - if args.has_key(field): - del args[field] - if args and not self.formAcceptExtraArgs: - raise FormInputError("unknown fields: %s" % repr(args)) - return apply(self.process, (write, request, submitAction), kw) - - def formatError(self,error): - """Format an error message. - - By default, this will make the message appear in red, bold italics. - """ - return '%s
                    \n' % error - - def shouldProcess(self, request): - args = request.args - fid = self.getFormID() - return (args and # there are arguments to the request - args.has_key('__formtype__') and # this is a widgets.Form request - args['__formtype__'][0] == reflect.qual(self.__class__) and # it is for a form of my type - ((not fid) or # I am only allowed one form per page - (args.has_key('__formid__') and # if I distinguish myself from others, the request must too - args['__formid__'][0] == fid))) # I am in fact the same - - def tryAgain(self, err, req): - """Utility method for re-drawing the form with an error message. - - This is handy in forms that process Deferred results. Normally you can - just raise a FormInputError() and this will happen by default. - - """ - l = [] - w = l.append - w(self.formatError(err)) - self.format(self.getFormFields(req), w, req) - return l - - def display(self, request): - """Display the form.""" - form = self.getFormFields(request) - if isinstance(form, defer.Deferred): - if self.shouldProcess(request): - form.addCallback(lambda form, f=self._displayProcess, r=request: f(r, form)) - else: - form.addCallback(lambda form, f=self._displayFormat, r=request: f(r, form)) - return [form] - else: - if self.shouldProcess(request): - return self._displayProcess(request, form) - else: - return self._displayFormat(request, form) - - def _displayProcess(self, request, form): - l = [] - write = l.append - try: - val = self._doProcess(form, write, request) - if val: - l.extend(val) - except FormInputError, fie: - write(self.formatError(str(fie))) - return l - - def _displayFormat(self, request, form): - l = [] - self.format(form, l.append, request) - return l - - - -class DataWidget(Widget): - def __init__(self, data): - self.data = data - def display(self, request): - return [self.data] - -class Time(Widget): - def display(self, request): - return [time.ctime(time.time())] - -class Container(Widget): - def __init__(self, *widgets): - self.widgets = widgets - - def display(self, request): - value = [] - for widget in self.widgets: - d = widget.display(request) - value.extend(d) - return value - -class _RequestDeferral: - def __init__(self): - self.deferred = defer.Deferred() - self.io = StringIO() - self.write = self.io.write - - def finish(self): - self.deferred.callback([self.io.getvalue()]) - -def possiblyDeferWidget(widget, request): - # web in my head get it out get it out - try: - disp = widget.display(request) - # if this widget wants to defer anything -- well, I guess we've got to - # defer it. - for elem in disp: - if isinstance(elem, defer.Deferred): - req = _RequestDeferral() - RenderSession(disp, req) - return req.deferred - return string.join(disp, '') - except: - io = StringIO() - traceback.print_exc(file=io) - return html.PRE(io.getvalue()) - -class RenderSession: - """I handle rendering of a list of deferreds, outputting their - results in correct order.""" - - class Sentinel: - pass - - def __init__(self, lst, request): - self.lst = lst - self.request = request - self.needsHeaders = 0 - self.beforeBody = 1 - self.forgotten = 0 - self.pauseList = [] - for i in range(len(self.lst)): - item = self.lst[i] - if isinstance(item, defer.Deferred): - self._addDeferred(item, self.lst, i) - self.keepRendering() - - def _addDeferred(self, deferred, lst, idx): - sentinel = self.Sentinel() - if hasattr(deferred, 'needsHeader'): - # You might want to set a header from a deferred, in which - # case you have to set an attribute -- needsHeader. - self.needsHeaders = self.needsHeaders + 1 - args = (sentinel, 1) - else: - args = (sentinel, 0) - lst[idx] = sentinel, deferred - deferred.pause() - self.pauseList.append(deferred) - deferred.addCallbacks(self.callback, self.callback, - callbackArgs=args, errbackArgs=args) - - - def callback(self, result, sentinel, decNeedsHeaders): - if self.forgotten: - return - if result != FORGET_IT: - self.needsHeaders = self.needsHeaders - decNeedsHeaders - else: - result = [FORGET_IT] - - # Make sure result is a sequence, - if not type(result) in (types.ListType, types.TupleType): - result = [result] - - # If the deferred does not wish to produce its result all at - # once, it can give us a partial result as - # (NOT_DONE_YET, partial_result) - ## XXX: How would a deferred go about producing the result in multiple - ## stages?? --glyph - if result[0] is NOT_DONE_YET: - done = 0 - result = result[1] - if not type(result) in (types.ListType, types.TupleType): - result = [result] - else: - done = 1 - - for i in xrange(len(result)): - item = result[i] - if isinstance(item, defer.Deferred): - self._addDeferred(item, result, i) - - for position in range(len(self.lst)): - item = self.lst[position] - if type(item) is types.TupleType and len(item) > 0: - if item[0] is sentinel: - break - else: - raise AssertionError('Sentinel for Deferred not found!') - - if done: - self.lst[position:position+1] = result - else: - self.lst[position:position] = result - - self.keepRendering() - - - def keepRendering(self): - while self.pauseList: - pl = self.pauseList - self.pauseList = [] - for deferred in pl: - deferred.unpause() - return - - if self.needsHeaders: - # short circuit actual rendering process until we're sure no - # more deferreds need to set headers... - return - - assert self.lst is not None, "This shouldn't happen." - while 1: - item = self.lst[0] - if self.beforeBody and FORGET_IT in self.lst: - # If I haven't moved yet, and the widget wants to take - # over the page, let it do so! - self.forgotten = 1 - return - - if isinstance(item, types.StringType): - self.beforeBody = 0 - self.request.write(item) - elif type(item) is types.TupleType and len(item) > 0: - if isinstance(item[0], self.Sentinel): - return - elif isinstance(item, failure.Failure): - self.request.write(webutil.formatFailure(item)) - else: - self.beforeBody = 0 - unknown = html.PRE(repr(item)) - self.request.write("RENDERING UNKNOWN: %s" % unknown) - - del self.lst[0] - if len(self.lst) == 0: - self.lst = None - self.request.finish() - return - - -## XXX: is this needed? -class WidgetResource(resource.Resource): - def __init__(self, widget): - self.widget = widget - resource.Resource.__init__(self) - - def render(self, request): - RenderSession(self.widget.display(request), request) - return NOT_DONE_YET - - -class Page(resource.Resource, Presentation): - - def __init__(self): - resource.Resource.__init__(self) - Presentation.__init__(self) - - def render(self, request): - displayed = self.display(request) - RenderSession(displayed, request) - return NOT_DONE_YET - - -class WidgetPage(Page): - """ - I am a Page that takes a Widget in its constructor, and displays that - Widget wrapped up in a simple HTML template. - """ - stylesheet = ''' - a - { - font-family: Lucida, Verdana, Helvetica, Arial, sans-serif; - color: #369; - text-decoration: none; - } - - th - { - font-family: Lucida, Verdana, Helvetica, Arial, sans-serif; - font-weight: bold; - text-decoration: none; - text-align: left; - } - - pre, code - { - font-family: "Courier New", Courier, monospace; - } - - p, body, td, ol, ul, menu, blockquote, div - { - font-family: Lucida, Verdana, Helvetica, Arial, sans-serif; - color: #000; - } - ''' - - template = ''' - - %%%%self.title%%%% - - - - - -

                    %%%%self.title%%%%

                    - %%%%self.widget%%%% - - - ''' - - title = 'No Title' - widget = 'No Widget' - - def __init__(self, widget): - Page.__init__(self) - self.widget = widget - if hasattr(widget, 'stylesheet'): - self.stylesheet = widget.stylesheet - - def prePresent(self, request): - self.title = self.widget.getTitle(request) - - def render(self, request): - displayed = self.display(request) - RenderSession(displayed, request) - return NOT_DONE_YET - -class Gadget(resource.Resource): - """I am a collection of Widgets, to be rendered through a Page Factory. - self.pageFactory should be a Resource that takes a Widget in its - constructor. The default is twisted.web.widgets.WidgetPage. - """ - - isLeaf = 0 - - def __init__(self): - resource.Resource.__init__(self) - self.widgets = {} - self.files = [] - self.modules = [] - self.paths = {} - - def render(self, request): - #Redirect to view this entity as a collection. - request.setResponseCode(http.FOUND) - # TODO who says it's not https? - request.setHeader("location","http%s://%s%s/" % ( - request.isSecure() and 's' or '', - request.getHeader("host"), - (string.split(request.uri,'?')[0]))) - return "NO DICE!" - - def putWidget(self, path, widget): - """ - Gadget.putWidget(path, widget) - Add a Widget to this Gadget. It will be rendered through the - pageFactory associated with this Gadget, whenever 'path' is requested. - """ - self.widgets[path] = widget - - #this is an obsolete function - def addFile(self, path): - """ - Gadget.addFile(path) - Add a static path to this Gadget. This method is obsolete, use - Gadget.putPath instead. - """ - - log.msg("Gadget.addFile() is deprecated.") - self.paths[path] = path - - def putPath(self, path, pathname): - """ - Gadget.putPath(path, pathname) - Add a static path to this Gadget. Whenever 'path' is requested, - twisted.web.static.File(pathname) is sent. - """ - self.paths[path] = pathname - - def getWidget(self, path, request): - return self.widgets.get(path) - - def pageFactory(self, *args, **kwargs): - """ - Gadget.pageFactory(*args, **kwargs) -> Resource - By default, this method returns self.page(*args, **kwargs). It - is only for backwards-compatibility -- you should set the 'pageFactory' - attribute on your Gadget inside of its __init__ method. - """ - #XXX: delete this after a while. - if hasattr(self, "page"): - log.msg("Gadget.page is deprecated, use Gadget.pageFactory instead") - return apply(self.page, args, kwargs) - else: - return apply(WidgetPage, args, kwargs) - - def getChild(self, path, request): - if path == '': - # ZOOP! - if isinstance(self, Widget): - return self.pageFactory(self) - widget = self.getWidget(path, request) - if widget: - if isinstance(widget, resource.Resource): - return widget - else: - p = self.pageFactory(widget) - p.isLeaf = getattr(widget,'isLeaf',0) - return p - elif self.paths.has_key(path): - prefix = getattr(sys.modules[self.__module__], '__file__', '') - if prefix: - prefix = os.path.abspath(os.path.dirname(prefix)) - return static.File(os.path.join(prefix, self.paths[path])) - - elif path == '__reload__': - return self.pageFactory(Reloader(map(reflect.namedModule, [self.__module__] + self.modules))) - else: - return error.NoResource("No such child resource in gadget.") - - -class TitleBox(Presentation): - - template = '''\ -\ -
                    %%%%self.title%%%%
                    \ -\ -\ -
                    %%%%self.widget%%%%
                    \ -''' - - borderColor = '#000000' - titleTextColor = '#ffffff' - boxTextColor = '#000000' - boxColor = '#ffffff' - widthOption = 'width="100%"' - - title = 'No Title' - widget = 'No Widget' - - def __init__(self, title, widget): - """Wrap a widget with a given title. - """ - self.widget = widget - self.title = title - Presentation.__init__(self) - - -class Reloader(Presentation): - template = ''' - Reloading... -
                      - %%%%reload(request)%%%% -
                    ... reloaded! - ''' - def __init__(self, modules): - Presentation.__init__(self) - self.modules = modules - - def reload(self, request): - request.redirect("..") - x = [] - write = x.append - for module in self.modules: - rebuild.rebuild(module) - write('
                  1. reloaded %s
                    ' % module.__name__) - return x - -class Sidebar(StreamWidget): - bar = [ - ['Twisted', - ['mirror', 'http://coopweb.org/ssd/twisted/'], - ['mailing list', 'cgi-bin/mailman/listinfo/twisted-python'] - ] - ] - - headingColor = 'ffffff' - headingTextColor = '000000' - activeHeadingColor = '000000' - activeHeadingTextColor = 'ffffff' - sectionColor = '000088' - sectionTextColor = '008888' - activeSectionColor = '0000ff' - activeSectionTextColor = '00ffff' - - def __init__(self, highlightHeading, highlightSection): - self.highlightHeading = highlightHeading - self.highlightSection = highlightSection - - def getList(self): - return self.bar - - def stream(self, write, request): - write("") - for each in self.getList(): - if each[0] == self.highlightHeading: - headingColor = self.activeHeadingColor - headingTextColor = self.activeHeadingTextColor - canHighlight = 1 - else: - headingColor = self.headingColor - headingTextColor = self.headingTextColor - canHighlight = 0 - write('\n' % (headingColor, headingTextColor, each[0])) - for name, link in each[1:]: - if canHighlight and (name == self.highlightSection): - sectionColor = self.activeSectionColor - sectionTextColor = self.activeSectionTextColor - else: - sectionColor = self.sectionColor - sectionTextColor = self.sectionTextColor - write('' - '' - % (sectionColor, sectionColor, request.sibLink(link), sectionTextColor, name)) - write("
                    ' - '%s' - '
                    -%s' - '
                    ") - -# moved from template.py -from twisted.web.woven import template -from twisted.python import components - -class WebWidgetNodeMutator(template.NodeMutator): - """A WebWidgetNodeMutator replaces the node that is passed in to generate - with the result of generating the twisted.web.widget instance it adapts. - """ - def generate(self, request, node): - widget = self.data - displayed = widget.display(request) - try: - html = string.join(displayed) - except: - pr = Presentation() - pr.tmpl = displayed - #strList = pr.display(request) - html = string.join(displayed) - stringMutator = template.StringNodeMutator(html) - return stringMutator.generate(request, node) - -components.registerAdapter(WebWidgetNodeMutator, Widget, template.INodeMutator) - -import static diff --git a/tools/buildbot/pylibs/twisted/web/woven/FlashConduit.fla b/tools/buildbot/pylibs/twisted/web/woven/FlashConduit.fla deleted file mode 100644 index 7406364..0000000 Binary files a/tools/buildbot/pylibs/twisted/web/woven/FlashConduit.fla and /dev/null differ diff --git a/tools/buildbot/pylibs/twisted/web/woven/FlashConduit.swf b/tools/buildbot/pylibs/twisted/web/woven/FlashConduit.swf deleted file mode 100644 index 6e0c6cd..0000000 Binary files a/tools/buildbot/pylibs/twisted/web/woven/FlashConduit.swf and /dev/null differ diff --git a/tools/buildbot/pylibs/twisted/web/woven/FlashConduitGlue.html b/tools/buildbot/pylibs/twisted/web/woven/FlashConduitGlue.html deleted file mode 100644 index 1dc6367..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/FlashConduitGlue.html +++ /dev/null @@ -1,25 +0,0 @@ -
                    - - - - - - - - - - - - -
                    diff --git a/tools/buildbot/pylibs/twisted/web/woven/WebConduit2_mozilla.js b/tools/buildbot/pylibs/twisted/web/woven/WebConduit2_mozilla.js deleted file mode 100644 index 97dc118..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/WebConduit2_mozilla.js +++ /dev/null @@ -1,82 +0,0 @@ -var woven_eventQueue = [] -woven_eventQueueBusy = 0 -woven_clientSideEventNum = 0 -woven_requestingEvent = 0 - -function woven_eventHandler(eventName, node) { - var eventTarget = node.getAttribute('id') - var additionalArguments = '' - for (i = 2; i\n') - document.write('on error resume next\n') - document.write('Sub FlashConduit_swf_FSCommand(ByVal command, ByVal args)\n') - document.write('call FlashConduit_swf_DoFSCommand(command, args)\n') - document.write('end sub\n') - document.write('\n') - } - -} - -var woven_eventQueue = [] -woven_eventQueueBusy = 0 -woven_clientSideEventNum = 0 - -function woven_eventHandler(eventName, node) { - var eventTarget = node.getAttribute('id') - var additionalArguments = '' - for (i = 2; i - - - -
                  2. diff --git a/tools/buildbot/pylibs/twisted/web/woven/__init__.py b/tools/buildbot/pylibs/twisted/web/woven/__init__.py deleted file mode 100644 index 51dfd75..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# __init__.py - -"""Woven, the Web Object Visualization Environment.""" diff --git a/tools/buildbot/pylibs/twisted/web/woven/controller.py b/tools/buildbot/pylibs/twisted/web/woven/controller.py deleted file mode 100644 index a7aca0c..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/controller.py +++ /dev/null @@ -1,436 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_woven -*- -# -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -from __future__ import nested_scopes - -__version__ = "$Revision: 1.67 $"[11:-2] - -import os -import cgi -import types - -from twisted.python import log -from twisted.python import components -from twisted.python import failure -from zope.interface import implements -from twisted.web import resource, server, static -from twisted.web.woven import interfaces, utils -from twisted.web import woven -from twisted.web import microdom -from twisted.web.static import redirectTo, addSlash - -import warnings -from time import time as now - -def controllerFactory(controllerClass): - return lambda request, node, model: controllerClass(model) - -def controllerMethod(controllerClass): - return lambda self, request, node, model: controllerClass(model) - - -class Controller(resource.Resource): - """ - A Controller which handles to events from the user. Such events - are `web request', `form submit', etc. - - I should be the IResource implementor for your Models (and - L{registerControllerForModel} makes this so). - """ - - implements(interfaces.IController) - setupStacks = 1 - addSlash = 1 # Should this controller add a slash to the url automatically? - controllerLibraries = [] - viewFactory = None - templateDirectory = "" - def __init__(self, m, inputhandlers=None, view=None, controllers=None, templateDirectory = None): - #self.start = now() - resource.Resource.__init__(self) - self.model = m - # It's the responsibility of the calling code to make sure setView is - # called on this controller before it's rendered. - self.view = None - self.subcontrollers = [] - if self.setupStacks: - self.setupControllerStack() - if inputhandlers is None and controllers is None: - self._inputhandlers = [] - elif inputhandlers: - print "The inputhandlers arg is deprecated, please use controllers instead" - self._inputhandlers = inputhandlers - else: - self._inputhandlers = controllers - if templateDirectory is not None: - self.templateDirectory = templateDirectory - self._valid = {} - self._invalid = {} - self._process = {} - self._parent = None - - def setupControllerStack(self): - self.controllerStack = utils.Stack([]) - from twisted.web.woven import input - if input not in self.controllerLibraries: - self.controllerLibraries.append(input) - for library in self.controllerLibraries: - self.importControllerLibrary(library) - self.controllerStack.push(self) - - def importControllerLibrary(self, namespace): - if not hasattr(namespace, 'getSubcontroller'): - namespace.getSubcontroller = utils.createGetFunction(namespace) - self.controllerStack.push(namespace) - - def getSubcontroller(self, request, node, model, controllerName): - controller = None - cm = getattr(self, 'wcfactory_' + - controllerName, None) - if cm is None: - cm = getattr(self, 'factory_' + - controllerName, None) - if cm is not None: - warnings.warn("factory_ methods are deprecated; please use " - "wcfactory_ instead", DeprecationWarning) - if cm: - if cm.func_code.co_argcount == 1 and not type(cm) == types.LambdaType: - warnings.warn("A Controller Factory takes " - "(request, node, model) " - "now instead of (model)", DeprecationWarning) - controller = controllerFactory(model) - else: - controller = cm(request, node, model) - return controller - - def setSubcontrollerFactory(self, name, factory, setup=None): - setattr(self, "wcfactory_" + name, lambda request, node, m: - factory(m)) - - def setView(self, view): - self.view = view - - def setNode(self, node): - self.node = node - - def setUp(self, request, *args): - """ - @type request: L{twisted.web.server.Request} - """ - pass - - def getChild(self, name, request): - """ - Look for a factory method to create the object to handle the - next segment of the URL. If a wchild_* method is found, it will - be called to produce the Resource object to handle the next - segment of the path. If a wchild_* method is not found, - getDynamicChild will be called with the name and request. - - @param name: The name of the child being requested. - @type name: string - @param request: The HTTP request being handled. - @type request: L{twisted.web.server.Request} - """ - if not name: - method = "index" - else: - method = name.replace('.', '_') - f = getattr(self, "wchild_%s" % method, None) - if f: - return f(request) - else: - child = self.getDynamicChild(name, request) - if child is None: - return resource.Resource.getChild(self, name, request) - else: - return child - - def getDynamicChild(self, name, request): - """ - This method is called when getChild cannot find a matching wchild_* - method in the Controller. Override me if you wish to have dynamic - handling of child pages. Should return a Resource if appropriate. - Return None to indicate no resource found. - - @param name: The name of the child being requested. - @type name: string - @param request: The HTTP request being handled. - @type request: L{twisted.web.server.Request} - """ - pass - - def wchild_index(self, request): - """By default, we return ourself as the index. - Override this to provide different behavior - for a URL that ends in a slash. - """ - self.addSlash = 0 - return self - - def render(self, request): - """ - Trigger any inputhandlers that were passed in to this Page, - then delegate to the View for traversing the DOM. Finally, - call gatheredControllers to deal with any InputHandlers that - were constructed from any controller= tags in the - DOM. gatheredControllers will render the page to the browser - when it is done. - """ - if self.addSlash and request.uri.split('?')[0][-1] != '/': - return redirectTo(addSlash(request), request) - # Handle any inputhandlers that were passed in to the controller first - for ih in self._inputhandlers: - ih._parent = self - ih.handle(request) - self._inputhandlers = [] - for key, value in self._valid.items(): - key.commit(request, None, value) - self._valid = {} - return self.renderView(request) - - def makeView(self, model, templateFile=None, parentCount=0): - if self.viewFactory is None: - self.viewFactory = self.__class__ - v = self.viewFactory(model, templateFile=templateFile, templateDirectory=self.templateDirectory) - v.parentCount = parentCount - v.tapestry = self - v.importViewLibrary(self) - return v - - def renderView(self, request): - if self.view is None: - if self.viewFactory is not None: - self.setView(self.makeView(self.model, None)) - else: - self.setView(interfaces.IView(self.model, None)) - self.view.setController(self) - return self.view.render(request, doneCallback=self.gatheredControllers) - - def gatheredControllers(self, v, d, request): - process = {} - request.args = {} - for key, value in self._valid.items(): - key.commit(request, None, value) - process[key.submodel] = value - self.process(request, **process) - #log.msg("Sending page!") - self.pageRenderComplete(request) - utils.doSendPage(v, d, request) - #v.unlinkViews() - - #print "Page time: ", now() - self.start - #return view.View.render(self, request, block=0) - - def aggregateValid(self, request, input, data): - self._valid[input] = data - - def aggregateInvalid(self, request, input, data): - self._invalid[input] = data - - def process(self, request, **kwargs): - if kwargs: - log.msg("Processing results: ", kwargs) - - def setSubmodel(self, submodel): - self.submodel = submodel - - def handle(self, request): - """ - By default, we don't do anything - """ - pass - - def exit(self, request): - """We are done handling the node to which this controller was attached. - """ - pass - - def domChanged(self, request, widget, node): - parent = getattr(self, '_parent', None) - if parent is not None: - parent.domChanged(request, widget, node) - - def pageRenderComplete(self, request): - """Override this to recieve notification when the view rendering - process is complete. - """ - pass - -WOVEN_PATH = os.path.split(woven.__file__)[0] - -class LiveController(Controller): - """A Controller that encapsulates logic that makes it possible for this - page to be "Live". A live page can have it's content updated after the - page has been sent to the browser, and can translate client-side - javascript events into server-side events. - """ - pageSession = None - def render(self, request): - """First, check to see if this request is attempting to hook up the - output conduit. If so, do it. Otherwise, unlink the current session's - View from the MVC notification infrastructure, then render the page - normally. - """ - # Check to see if we're hooking up an output conduit - sess = request.getSession(interfaces.IWovenLivePage) - #print "REQUEST.ARGS", request.args - if request.args.has_key('woven_hookupOutputConduitToThisFrame'): - sess.hookupOutputConduit(request) - return server.NOT_DONE_YET - if request.args.has_key('woven_clientSideEventName'): - try: - request.d = microdom.parseString('', caseInsensitive=0, preserveCase=0) - eventName = request.args['woven_clientSideEventName'][0] - eventTarget = request.args['woven_clientSideEventTarget'][0] - eventArgs = request.args.get('woven_clientSideEventArguments', []) - #print "EVENT", eventName, eventTarget, eventArgs - return self.clientToServerEvent(request, eventName, eventTarget, eventArgs) - except: - fail = failure.Failure() - self.view.renderFailure(fail, request) - return server.NOT_DONE_YET - - # Unlink the current page in this user's session from MVC notifications - page = sess.getCurrentPage() - #request.currentId = getattr(sess, 'currentId', 0) - if page is not None: - page.view.unlinkViews() - sess.setCurrentPage(None) - #print "PAGE SESSION IS NONE" - self.pageSession = None - return Controller.render(self, request) - - def clientToServerEvent(self, request, eventName, eventTarget, eventArgs): - """The client sent an asynchronous event to the server. - Locate the View object targeted by this event and attempt - to call onEvent on it. - """ - sess = request.getSession(interfaces.IWovenLivePage) - self.view = sess.getCurrentPage().view - #request.d = self.view.d - print "clientToServerEvent", eventTarget - target = self.view.subviews[eventTarget] - print "target, parent", target, target.parent - #target.parent = self.view - #target.controller._parent = self - - ## From the time we call onEvent until it returns, we want all - ## calls to IWovenLivePage.sendScript to be appended to this - ## list so we can spit them out in the response, immediately - ## below. - scriptOutput = [] - orig = sess.sendScript - sess.sendScript = scriptOutput.append - target.onEvent(request, eventName, *eventArgs) - sess.sendScript = orig - - scriptOutput.append('parent.woven_clientToServerEventComplete()') - - #print "GATHERED JS", scriptOutput - - return ''' - - - %s event sent to %s (%s) with arguments %s. - -''' % ('\n'.join(scriptOutput), eventName, cgi.escape(str(target)), eventTarget, eventArgs) - - def gatheredControllers(self, v, d, request): - Controller.gatheredControllers(self, v, d, request) - sess = request.getSession(interfaces.IWovenLivePage) - self.pageSession = sess - sess.setCurrentPage(self) - sess.currentId = request.currentId - - def domChanged(self, request, widget, node): - sess = request.getSession(interfaces.IWovenLivePage) - print "domchanged" - if sess is not None: - if not hasattr(node, 'getAttribute'): - return - page = sess.getCurrentPage() - if page is None: - return - nodeId = node.getAttribute('id') - #logger.warn("DOM for %r is changing to %s", nodeId, node.toprettyxml()) - nodeXML = node.toxml() - nodeXML = nodeXML.replace("\\", "\\\\") - nodeXML = nodeXML.replace("'", "\\'") - nodeXML = nodeXML.replace('"', '\\"') - nodeXML = nodeXML.replace('\n', '\\n') - nodeXML = nodeXML.replace('\r', ' ') - nodeXML = nodeXML.replace('\b', ' ') - nodeXML = nodeXML.replace('\t', ' ') - nodeXML = nodeXML.replace('\000', ' ') - nodeXML = nodeXML.replace('\v', ' ') - nodeXML = nodeXML.replace('\f', ' ') - - js = "parent.woven_replaceElement('%s', '%s')" % (nodeId, nodeXML) - #for key in widget.subviews.keys(): - # view.subviews[key].unlinkViews() - oldNode = page.view.subviews[nodeId] - for id, subview in oldNode.subviews.items(): - subview.unlinkViews() - topSubviews = page.view.subviews - #print "Widgetid, subviews", id(widget), widget.subviews - if widget.subviews: - def recurseSubviews(w): - #print "w.subviews", w.subviews - topSubviews.update(w.subviews) - for id, sv in w.subviews.items(): - recurseSubviews(sv) - #print "recursing" - recurseSubviews(widget) - #page.view.subviews.update(widget.subviews) - sess.sendScript(js) - - def wchild_WebConduit2_js(self, request): - #print "returning js file" - h = request.getHeader("user-agent") - if h.count("MSIE"): - fl = "WebConduit2_msie.js" - else: - fl = "WebConduit2_mozilla.js" - - return static.File(os.path.join(WOVEN_PATH, fl)) - - def wchild_FlashConduit_swf(self, request): - #print "returning flash file" - h = request.getHeader("user-agent") - if h.count("MSIE"): - fl = "FlashConduit.swf" - else: - fl = "FlashConduit.swf" - return static.File(os.path.join(WOVEN_PATH, fl)) - - def wchild_input_html(self, request): - return BlankPage() - - -class BlankPage(resource.Resource): - def render(self, request): - return "This space intentionally left blank" - - -WController = Controller - -def registerControllerForModel(controller, model): - """ - Registers `controller' as an adapter of `model' for IController, and - optionally registers it for IResource, if it implements it. - - @param controller: A class that implements L{interfaces.IController}, usually a - L{Controller} subclass. Optionally it can implement - L{resource.IResource}. - @param model: Any class, but probably a L{twisted.web.woven.model.Model} - subclass. - """ - components.registerAdapter(controller, model, interfaces.IController) - if resource.IResource.implementedBy(controller): - components.registerAdapter(controller, model, resource.IResource) - diff --git a/tools/buildbot/pylibs/twisted/web/woven/dirlist.py b/tools/buildbot/pylibs/twisted/web/woven/dirlist.py deleted file mode 100644 index 4889efe..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/dirlist.py +++ /dev/null @@ -1,114 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Directory listing.""" - -# system imports -from os.path import join as joinpath -import urllib, os - -# sibling imports -import page, model, widgets, view - -# twisted imports -from twisted.web.microdom import lmx -from twisted.web.domhelpers import RawText -from twisted.python.filepath import FilePath -from twisted.web.static import File, getTypeAndEncoding - - -class DirectoryLister(page.Page): - template = ''' - - - - - - - -

                    - - - - - - - - - - - - - - - - - -
                    FilenameContent typeContent encoding
                    - - - - ''' - - def __init__(self, pathname, dirs=None, - contentTypes=File.contentTypes, - contentEncodings=File.contentEncodings, - defaultType='text/html'): - self.contentTypes = contentTypes - self.contentEncodings = contentEncodings - self.defaultType = defaultType - # dirs allows usage of the File to specify what gets listed - self.dirs = dirs - self.path = pathname - page.Page.__init__(self) - - def wmfactory_listing(self, request): - if self.dirs is None: - directory = os.listdir(self.path) - directory.sort() - else: - directory = self.dirs - - files = []; dirs = [] - - for path in directory: - url = urllib.quote(path, "/") - if os.path.isdir(os.path.join(self.path, path)): - url = url + '/' - dirs.append({'link':{"text": path + "/", "href":url}, - 'type': '[Directory]', 'encoding': ''}) - else: - mimetype, encoding = getTypeAndEncoding(path, self.contentTypes, - self.contentEncodings, - self.defaultType) - files.append({ - 'link': {"text": path, "href": url}, - 'type': '[%s]' % mimetype, - 'encoding': (encoding and '[%s]' % encoding or '')}) - - return files + dirs - - def wmfactory_header(self, request): - return "Directory listing for %s" % urllib.unquote(request.uri) - - def __repr__(self): - return '' % self.path - - __str__ = __repr__ diff --git a/tools/buildbot/pylibs/twisted/web/woven/flashconduit.py b/tools/buildbot/pylibs/twisted/web/woven/flashconduit.py deleted file mode 100644 index 36e7920..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/flashconduit.py +++ /dev/null @@ -1,35 +0,0 @@ -from twisted.internet.protocol import Factory -from twisted.protocols.basic import LineReceiver -from twisted.python import log -from twisted.web.woven import interfaces - - -class FlashConduit(LineReceiver): - delimiter = '\0' - keepalive = 1 - def connectionMade(self): - print "connection with flash movie opened" - #self.transport.write("alert('helllllllo')\0") - - def connectionLost(self, reason): - print "connection lost" - #self.lp.unhookOutputConduit() - - def lineReceived(self, line): - session = self.factory.site.getSession(line) - self.lp = lp = session.getComponent(interfaces.IWovenLivePage) - lp.hookupOutputConduit(self) - - def writeScript(self, data): - #print "writing javascript", data - self.transport.write(data + '\0') - - def finish(self): - pass - - -class FlashConduitFactory(Factory): - protocol = FlashConduit - - def __init__(self, site): - self.site = site \ No newline at end of file diff --git a/tools/buildbot/pylibs/twisted/web/woven/form.py b/tools/buildbot/pylibs/twisted/web/woven/form.py deleted file mode 100644 index 749d0d8..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/form.py +++ /dev/null @@ -1,575 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_woven -*- -# -# WORK IN PROGRESS: HARD HAT REQUIRED -# - -from __future__ import nested_scopes - -# Twisted Imports - -from twisted.python import formmethod, failure -from twisted.python.components import registerAdapter -from twisted.web import domhelpers, resource, util -from twisted.internet import defer - -# Sibling Imports -from twisted.web.woven import model, view, controller, widgets, input, interfaces - -from twisted.web.microdom import parseString, lmx, Element - - -#other imports -import math - -# map formmethod.Argument to functions that render them: -_renderers = {} - -def registerRenderer(argumentClass, renderer): - """Register a renderer for a given argument class. - - The renderer function should act in the same way - as the 'input_XXX' methods of C{FormFillerWidget}. - """ - assert callable(renderer) - global _renderers - _renderers[argumentClass] = renderer - - -class FormFillerWidget(widgets.Widget): - - SPANNING_TYPES = ["hidden", "submit"] - - def getValue(self, request, argument): - """Return value for form input.""" - if not self.model.alwaysDefault: - values = request.args.get(argument.name, None) - if values: - try: - return argument.coerce(values[0]) - except formmethod.InputError: - return values[0] - return argument.default - - def getValues(self, request, argument): - """Return values for form input.""" - if not self.model.alwaysDefault: - values = request.args.get(argument.name, None) - if values: - try: - return argument.coerce(values) - except formmethod.InputError: - return values - return argument.default - - def createShell(self, request, node, data): - """Create a `shell' node that will hold the additional form - elements, if one is required. - """ - return lmx(node).table(border="0") - - def input_single(self, request, content, model, templateAttributes={}): - """ - Returns a text input node built based upon the node model. - Optionally takes an already-coded DOM node merges that - information with the model's information. Returns a new (??) - lmx node. - """ - #in a text field, only the following options are allowed (well, more - #are, but they're not supported yet - can add them in later) - attribs = ['type', 'name', 'value', 'size', 'maxlength', - 'readonly'] #only MSIE recognizes readonly and disabled - - arguments = {} - for attrib in attribs: - #model hints and values override anything in the template - val = model.getHint(attrib, templateAttributes.get(attrib, None)) - if val: - arguments[attrib] = str(val) - - value = self.getValue(request, model) - if value: - arguments["value"] = str(value) - - arguments["type"] = "text" #these are default - arguments["name"] = model.name - - return content.input(**arguments) - - def input_string(self, request, content, model, templateAttributes={}): - if not templateAttributes.has_key("size"): - templateAttributes["size"] = '60' - return self.input_single(request, content, model, templateAttributes) - - input_integer = input_single - input_integerrange = input_single - input_float = input_single - - def input_text(self, request, content, model, templateAttributes={}): - r = content.textarea( - cols=str(model.getHint('cols', - templateAttributes.get('cols', '60'))), - rows=str(model.getHint('rows', - templateAttributes.get('rows', '10'))), - name=model.name, - wrap=str(model.getHint('wrap', - templateAttributes.get('wrap', "virtual")))) - r.text(str(self.getValue(request, model))) - return r - - def input_hidden(self, request, content, model, templateAttributes={}): - return content.input(type="hidden", - name=model.name, - value=str(self.getValue(request, model))) - - def input_submit(self, request, content, model, templateAttributes={}): - arguments = {} - val = model.getHint("onClick", templateAttributes.get("onClick", None)) - if val: - arguments["onClick"] = val - arguments["type"] = "submit" - arguments["name"] = model.name - div = content.div() - for tag, value, desc in model.choices: - args = arguments.copy() - args["value"] = tag - div.input(**args) - div.text(" ") - if model.reset: - div.input(type="reset") - return div - - def input_choice(self, request, content, model, templateAttributes={}): - # am I not evil? allow onChange js events - arguments = {} - val = model.getHint("onChange", templateAttributes.get("onChange", None)) - if val: - arguments["onChange"] = val - arguments["name"] = model.name - s = content.select(**arguments) - default = self.getValues(request, model) - for tag, value, desc in model.choices: - kw = {} - if value in default: - kw = {'selected' : '1'} - s.option(value=tag, **kw).text(desc) - return s - - def input_group(self, request, content, model, groupValues, inputType, - templateAttributes={}): - """ - Base code for a group of objects. Checkgroup will use this, as - well as radiogroup. In the attributes, rows means how many rows - the group should be arranged into, cols means how many cols the - group should be arranged into. Columns take precedence over - rows: if both are specified, the output will always generate the - correct number of columns. However, if the number of elements - in the group exceed (or is smaller than) rows*cols, then the - number of rows will be off. A cols attribute of 1 will mean that - all the elements will be listed one underneath another. The - default is a rows attribute of 1: everything listed next to each - other. - """ - rows = model.getHint('rows', templateAttributes.get('rows', None)) - cols = model.getHint('cols', templateAttributes.get('cols', None)) - if rows: - rows = int(rows) - if cols: - cols = int(cols) - - defaults = self.getValues(request, model) - if (rows and rows>1) or (cols and cols>1): #build a table - s = content.table(border="0") - if cols: - breakat = cols - else: - breakat = math.ceil(float(len(groupValues))/rows) - for i in range(0, len(groupValues), breakat): - tr = s.tr() - for j in range(0, breakat): - if i+j >= len(groupValues): - break - tag, value, desc = groupValues[i+j] - kw = {} - if value in defaults: - kw = {'checked' : '1'} - tr.td().input(type=inputType, name=model.name, - value=tag, **kw).text(desc) - - else: - s = content.div() - for tag, value, desc in groupValues: - kw = {} - if value in defaults: - kw = {'checked' : '1'} - s.input(type=inputType, name=model.name, - value=tag, **kw).text(desc) - if cols: - s.br() - - return s - - def input_checkgroup(self, request, content, model, templateAttributes={}): - return self.input_group(request, content, model, model.flags, - "checkbox", templateAttributes) - - def input_radiogroup(self, request, content, model, templateAttributes={}): - return self.input_group(request, content, model, model.choices, - "radio", templateAttributes) - - #I don't know why they're the same, but they were. So I removed the - #excess code. Maybe someone should look into removing it entirely. - input_flags = input_checkgroup - - def input_boolean(self, request, content, model, templateAttributes={}): - kw = {} - if self.getValue(request, model): - kw = {'checked' : '1'} - return content.input(type="checkbox", name=model.name, **kw) - - def input_file(self, request, content, model, templateAttributes={}): - kw = {} - for attrib in ['size', 'accept']: - val = model.getHint(attrib, templateAttributes.get(attrib, None)) - if val: - kw[attrib] = str(val) - return content.input(type="file", name=model.name, **kw) - - def input_date(self, request, content, model, templateAttributes={}): - breakLines = model.getHint('breaklines', 1) - date = self.getValues(request, model) - if date == None: - year, month, day = "", "", "" - else: - year, month, day = date - div = content.div() - div.text("Year: ") - div.input(type="text", size="4", maxlength="4", name=model.name, value=str(year)) - if breakLines: - div.br() - div.text("Month: ") - div.input(type="text", size="2", maxlength="2", name=model.name, value=str(month)) - if breakLines: - div.br() - div.text("Day: ") - div.input(type="text", size="2", maxlength="2", name=model.name, value=str(day)) - return div - - def input_password(self, request, content, model, templateAttributes={}): - return content.input( - type="password", - size=str(templateAttributes.get('size', "60")), - name=model.name) - - def input_verifiedpassword(self, request, content, model, templateAttributes={}): - breakLines = model.getHint('breaklines', 1) - values = self.getValues(request, model) - if isinstance(values, (str, unicode)): - values = (values, values) - if not values: - p1, p2 = "", "" - elif len(values) == 1: - p1, p2 = values, "" - elif len(values) == 2: - p1, p2 = values - else: - p1, p2 = "", "" - div = content.div() - div.text("Password: ") - div.input(type="password", size="20", name=model.name, value=str(p1)) - if breakLines: - div.br() - div.text("Verify: ") - div.input(type="password", size="20", name=model.name, value=str(p2)) - return div - - - def convergeInput(self, request, content, model, templateNode): - name = model.__class__.__name__.lower() - if _renderers.has_key(model.__class__): - imeth = _renderers[model.__class__] - else: - imeth = getattr(self,"input_"+name) - - return imeth(request, content, model, templateNode.attributes).node - - def createInput(self, request, shell, model, templateAttributes={}): - name = model.__class__.__name__.lower() - if _renderers.has_key(model.__class__): - imeth = _renderers[model.__class__] - else: - imeth = getattr(self,"input_"+name) - if name in self.SPANNING_TYPES: - td = shell.tr().td(valign="top", colspan="2") - return (imeth(request, td, model).node, shell.tr().td(colspan="2").node) - else: - if model.allowNone: - required = "" - else: - required = " *" - tr = shell.tr() - tr.td(align="right", valign="top").text(model.getShortDescription()+":"+required) - content = tr.td(valign="top") - return (imeth(request, content, model).node, - content.div(_class="formDescription"). # because class is a keyword - text(model.getLongDescription()).node) - - def setUp(self, request, node, data): - # node = widgets.Widget.generateDOM(self,request,node) - lmn = lmx(node) - if not node.hasAttribute('action'): - lmn['action'] = (request.prepath+request.postpath)[-1] - if not node.hasAttribute("method"): - lmn['method'] = 'post' - lmn['enctype'] = 'multipart/form-data' - self.errorNodes = errorNodes = {} # name: nodes which trap errors - self.inputNodes = inputNodes = {} - for errorNode in domhelpers.findElementsWithAttribute(node, 'errorFor'): - errorNodes[errorNode.getAttribute('errorFor')] = errorNode - argz={} - # list to figure out which nodes are in the template already and which aren't - hasSubmit = 0 - argList = self.model.fmethod.getArgs() - for arg in argList: - if isinstance(arg, formmethod.Submit): - hasSubmit = 1 - argz[arg.name] = arg - inNodes = domhelpers.findElements( - node, - lambda n: n.tagName.lower() in ('textarea', 'select', 'input', - 'div')) - for inNode in inNodes: - t = inNode.getAttribute("type") - if t and t.lower() == "submit": - hasSubmit = 1 - if not inNode.hasAttribute("name"): - continue - nName = inNode.getAttribute("name") - if argz.has_key(nName): - #send an empty content shell - we just want the node - inputNodes[nName] = self.convergeInput(request, lmx(), - argz[nName], inNode) - inNode.parentNode.replaceChild(inputNodes[nName], inNode) - del argz[nName] - # TODO: - # * some arg types should only have a single node (text, string, etc) - # * some should have multiple nodes (choice, checkgroup) - # * some have a bunch of ancillary nodes that are possible values (menu, radiogroup) - # these should all be taken into account when walking through the template - if argz: - shell = self.createShell(request, node, data) - # create inputs, in the same order they were passed to us: - for remArg in [arg for arg in argList if argz.has_key(arg.name)]: - inputNode, errorNode = self.createInput(request, shell, remArg) - errorNodes[remArg.name] = errorNode - inputNodes[remArg.name] = inputNode - - if not hasSubmit: - lmn.input(type="submit") - - -class FormErrorWidget(FormFillerWidget): - def setUp(self, request, node, data): - FormFillerWidget.setUp(self, request, node, data) - for k, f in self.model.err.items(): - en = self.errorNodes[k] - tn = self.inputNodes[k] - en.setAttribute('class', 'formError') - tn.setAttribute('class', 'formInputError') - en.childNodes[:]=[] # gurfle, CLEAR IT NOW!@# - if isinstance(f, failure.Failure): - f = f.getErrorMessage() - lmx(en).text(str(f)) - - -class FormDisplayModel(model.MethodModel): - def initialize(self, fmethod, alwaysDefault=False): - self.fmethod = fmethod - self.alwaysDefault = alwaysDefault - -class FormErrorModel(FormDisplayModel): - def initialize(self, fmethod, args, err): - FormDisplayModel.initialize(self, fmethod) - self.args = args - if isinstance(err, failure.Failure): - err = err.value - if isinstance(err, Exception): - self.err = getattr(err, "descriptions", {}) - self.desc = err - else: - self.err = err - self.desc = "Please try again" - - def wmfactory_description(self, request): - return str(self.desc) - -class _RequestHack(model.MethodModel): - def wmfactory_hack(self, request): - rv = [[str(a), repr(b)] for (a, b) - in request._outDict.items()] - #print 'hack', rv - return rv - -class FormProcessor(resource.Resource): - def __init__(self, formMethod, callback=None, errback=None): - resource.Resource.__init__(self) - self.formMethod = formMethod - if callback is None: - callback = self.viewFactory - self.callback = callback - if errback is None: - errback = self.errorViewFactory - self.errback = errback - - def getArgs(self, request): - """Return the formmethod.Arguments. - - Overridable hook to allow pre-processing, e.g. if we want to enable - on them depending on one of the inputs. - """ - return self.formMethod.getArgs() - - def render(self, request): - outDict = {} - errDict = {} - for methodArg in self.getArgs(request): - valmethod = getattr(self,"mangle_"+ - (methodArg.__class__.__name__.lower()), None) - tmpval = request.args.get(methodArg.name) - if valmethod: - # mangle the argument to a basic datatype that coerce will like - tmpval = valmethod(tmpval) - # coerce it - try: - cv = methodArg.coerce(tmpval) - outDict[methodArg.name] = cv - except: - errDict[methodArg.name] = failure.Failure() - if errDict: - # there were problems processing the form - return self.errback(self.errorModelFactory( - request.args, outDict, errDict)).render(request) - else: - try: - if self.formMethod.takesRequest: - outObj = self.formMethod.call(request=request, **outDict) - else: - outObj = self.formMethod.call(**outDict) - except formmethod.FormException, e: - err = request.errorInfo = self.errorModelFactory( - request.args, outDict, e) - return self.errback(err).render(request) - else: - request._outDict = outDict # CHOMP CHOMP! - # I wanted better default behavior for debugging, so I could - # see the arguments passed, but there is no channel for this in - # the existing callback structure. So, here it goes. - if isinstance(outObj, defer.Deferred): - def _ebModel(err): - if err.trap(formmethod.FormException): - mf = self.errorModelFactory(request.args, outDict, - err.value) - return self.errback(mf) - raise err - (outObj - .addCallback(self.modelFactory) - .addCallback(self.callback) - .addErrback(_ebModel)) - return util.DeferredResource(outObj).render(request) - else: - return self.callback(self.modelFactory(outObj)).render( - request) - - def errorModelFactory(self, args, out, err): - return FormErrorModel(self.formMethod, args, err) - - def errorViewFactory(self, m): - v = view.View(m) - v.template = ''' - - - Form Error View - - - - Error: -
                    -
                    - - - ''' - return v - - def modelFactory(self, outObj): - adapt = interfaces.IModel(outObj, outObj) - # print 'factorizing', adapt - return adapt - - def viewFactory(self, model): - # return interfaces.IView(model) - if model is None: - bodyStr = ''' - - - - - -
                    - -
                    - ''' - model = _RequestHack() - else: - bodyStr = '
                    ' - v = view.View(model) - v.template = ''' - - - Thank You - - -

                    Thank You for Using Woven

                    - %s - - - ''' % bodyStr - return v - - # manglizers - - def mangle_single(self, args): - if args: - return args[0] - else: - return '' - - mangle_string = mangle_single - mangle_text = mangle_single - mangle_integer = mangle_single - mangle_password = mangle_single - mangle_integerrange = mangle_single - mangle_float = mangle_single - mangle_choice = mangle_single - mangle_boolean = mangle_single - mangle_hidden = mangle_single - mangle_submit = mangle_single - mangle_file = mangle_single - mangle_radiogroup = mangle_single - - def mangle_multi(self, args): - if args is None: - return [] - return args - - mangle_checkgroup = mangle_multi - mangle_flags = mangle_multi - -from twisted.python.formmethod import FormMethod - -view.registerViewForModel(FormFillerWidget, FormDisplayModel) -view.registerViewForModel(FormErrorWidget, FormErrorModel) -registerAdapter(FormDisplayModel, FormMethod, interfaces.IModel) - diff --git a/tools/buildbot/pylibs/twisted/web/woven/guard.py b/tools/buildbot/pylibs/twisted/web/woven/guard.py deleted file mode 100644 index ab5d56b..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/guard.py +++ /dev/null @@ -1,383 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_woven -*- - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -"""Resource protection for Woven. If you wish to use twisted.cred to protect -your Woven application, you are probably most interested in -L{UsernamePasswordWrapper}. -""" - -from __future__ import nested_scopes - -__version__ = "$Revision: 1.34 $"[11:-2] - -import random -import time -import md5 -import urllib - -# Twisted Imports - -from twisted.python import log, components -from twisted.web.resource import Resource, IResource -from twisted.web.util import redirectTo, Redirect, DeferredResource -from twisted.web.static import addSlash -from twisted.internet import reactor -from twisted.cred.error import LoginFailed, UnauthorizedLogin - -def _sessionCookie(): - return md5.new("%s_%s" % (str(random.random()) , str(time.time()))).hexdigest() - -class GuardSession(components.Componentized): - """A user's session with a system. - - This utility class contains no functionality, but is used to - represent a session. - """ - def __init__(self, guard, uid): - """Initialize a session with a unique ID for that session. - """ - components.Componentized.__init__(self) - self.guard = guard - self.uid = uid - self.expireCallbacks = [] - self.checkExpiredID = None - self.setLifetime(60) - self.services = {} - self.portals = {} - self.touch() - - def _getSelf(self, interface=None): - self.touch() - if interface is None: - return self - else: - return self.getComponent(interface) - - # Old Guard interfaces - - def clientForService(self, service): - x = self.services.get(service) - if x: - return x[1] - else: - return x - - def setClientForService(self, ident, perspective, client, service): - if self.services.has_key(service): - p, c, i = self.services[service] - p.detached(c, ident) - del self.services[service] - else: - self.services[service] = perspective, client, ident - perspective.attached(client, ident) - # this return value is useful for services that need to do asynchronous - # stuff. - return client - - # New Guard Interfaces - - def resourceForPortal(self, port): - return self.portals.get(port) - - def setResourceForPortal(self, rsrc, port, logout): - self.portalLogout(port) - self.portals[port] = rsrc, logout - return rsrc - - def portalLogout(self, port): - p = self.portals.get(port) - if p: - r, l = p - try: l() - except: log.err() - del self.portals[port] - - # timeouts and expiration - - def setLifetime(self, lifetime): - """Set the approximate lifetime of this session, in seconds. - - This is highly imprecise, but it allows you to set some general - parameters about when this session will expire. A callback will be - scheduled each 'lifetime' seconds, and if I have not been 'touch()'ed - in half a lifetime, I will be immediately expired. - """ - self.lifetime = lifetime - - def notifyOnExpire(self, callback): - """Call this callback when the session expires or logs out. - """ - self.expireCallbacks.append(callback) - - def expire(self): - """Expire/logout of the session. - """ - log.msg("expired session %s" % self.uid) - del self.guard.sessions[self.uid] - for c in self.expireCallbacks: - try: - c() - except: - log.err() - self.expireCallbacks = [] - if self.checkExpiredID: - self.checkExpiredID.cancel() - self.checkExpiredID = None - - def touch(self): - self.lastModified = time.time() - - def checkExpired(self): - self.checkExpiredID = None - # If I haven't been touched in 15 minutes: - if time.time() - self.lastModified > self.lifetime / 2: - if self.guard.sessions.has_key(self.uid): - self.expire() - else: - log.msg("no session to expire: %s" % self.uid) - else: - log.msg("session given the will to live for %s more seconds" % self.lifetime) - self.checkExpiredID = reactor.callLater(self.lifetime, - self.checkExpired) - def __getstate__(self): - d = self.__dict__.copy() - if d.has_key('checkExpiredID'): - del d['checkExpiredID'] - return d - - def __setstate__(self, d): - self.__dict__.update(d) - self.touch() - self.checkExpired() - -INIT_SESSION = 'session-init' - -def _setSession(wrap, req, cook): - req.session = wrap.sessions[cook] - req.getSession = req.session._getSelf - -def urlToChild(request, *ar, **kw): - pp = request.prepath.pop() - orig = request.prePathURL() - request.prepath.append(pp) - c = '/'.join(ar) - if orig[-1] == '/': - # this SHOULD only happen in the case where the URL is just the hostname - ret = orig + c - else: - ret = orig + '/' + c - args = request.args.copy() - args.update(kw) - if args: - ret += '?'+urllib.urlencode(args) - return ret - -def redirectToSession(request, garbage): - rd = Redirect(urlToChild(request, *request.postpath, **{garbage:1})) - rd.isLeaf = 1 - return rd - -SESSION_KEY='__session_key__' - -class SessionWrapper(Resource): - - sessionLifetime = 1800 - - def __init__(self, rsrc, cookieKey=None): - Resource.__init__(self) - self.resource = rsrc - if cookieKey is None: - cookieKey = "woven_session_" + _sessionCookie() - self.cookieKey = cookieKey - self.sessions = {} - - def render(self, request): - return redirectTo(addSlash(request), request) - - def getChild(self, path, request): - if not request.prepath: - return None - cookie = request.getCookie(self.cookieKey) - setupURL = urlToChild(request, INIT_SESSION, *([path]+request.postpath)) - request.setupSessionURL = setupURL - request.setupSession = lambda: Redirect(setupURL) - if path.startswith(SESSION_KEY): - key = path[len(SESSION_KEY):] - if key not in self.sessions: - return redirectToSession(request, '__start_session__') - self.sessions[key].setLifetime(self.sessionLifetime) - if cookie == key: - # /sessionized-url/${SESSION_KEY}aef9c34aecc3d9148/foo - # ^ - # we are this getChild - # with a matching cookie - return redirectToSession(request, '__session_just_started__') - else: - # We attempted to negotiate the session but failed (the user - # probably has cookies disabled): now we're going to return the - # resource we contain. In general the getChild shouldn't stop - # there. - # /sessionized-url/${SESSION_KEY}aef9c34aecc3d9148/foo - # ^ we are this getChild - # without a cookie (or with a mismatched cookie) - _setSession(self, request, key) - return self.resource - elif cookie in self.sessions: - # /sessionized-url/foo - # ^ we are this getChild - # with a session - _setSession(self, request, cookie) - return getResource(self.resource, path, request) - elif path == INIT_SESSION: - # initialize the session - # /sessionized-url/session-init - # ^ this getChild - # without a session - newCookie = _sessionCookie() - request.addCookie(self.cookieKey, newCookie, path="/") - sz = self.sessions[newCookie] = GuardSession(self, newCookie) - sz.checkExpired() - rd = Redirect(urlToChild(request, SESSION_KEY+newCookie, - *request.postpath)) - rd.isLeaf = 1 - return rd - else: - # /sessionized-url/foo - # ^ we are this getChild - # without a session - request.getSession = lambda interface=None: None - return getResource(self.resource, path, request) - -def getResource(resource, path, request): - if resource.isLeaf: - request.postpath.insert(0, request.prepath.pop()) - return resource - else: - return resource.getChildWithDefault(path, request) - -INIT_PERSPECTIVE = 'perspective-init' -DESTROY_PERSPECTIVE = 'perspective-destroy' - -from twisted.python import formmethod as fm -from twisted.web.woven import form - - -newLoginSignature = fm.MethodSignature( - fm.String("username", "", - "Username", "Your user name."), - fm.Password("password", "", - "Password", "Your password."), - fm.Submit("submit", choices=[("Login", "", "")], allowNone=1), - ) - -from twisted.cred.credentials import UsernamePassword, Anonymous - -class UsernamePasswordWrapper(Resource): - """I bring a C{twisted.cred} Portal to the web. Use me to provide different Resources - (usually entire pages) based on a user's authentication details. - - A C{UsernamePasswordWrapper} is a - L{Resource}, and is usually wrapped in a - L{SessionWrapper} before being inserted into the site tree. - - The L{Realm} associated with your - L{Portal} should be prepared to accept a - request for an avatar that implements the L{twisted.web.resource.IResource} - interface. This avatar should probably be something like a Woven - L{Page}. That is, it should represent a whole - web page. Once you return this avatar, requests for it's children do not go - through guard. - - If you want to determine what unauthenticated users see, make sure your - L{Portal} has a checker associated that allows - anonymous access. (See L{twisted.cred.checkers.AllowAnonymousAccess}) - - """ - - def __init__(self, portal, callback=None, errback=None): - """Constructs a UsernamePasswordWrapper around the given portal. - - @param portal: A cred portal for your web application. The checkers - associated with this portal must be able to accept username/password - credentials. - @type portal: L{twisted.cred.portal.Portal} - - @param callback: Gets called after a successful login attempt. - A resource that redirects to "." will display the avatar resource. - If this parameter isn't provided, defaults to a standard Woven - "Thank You" page. - @type callback: A callable that accepts a Woven - L{model} and returns a - L{IResource}. - - @param errback: Gets called after a failed login attempt. - If this parameter is not provided, defaults to a the standard Woven - form error (i.e. The original form on a page of its own, with - errors noted.) - @type errback: A callable that accepts a Woven - L{model} and returns a - L{IResource}. - """ - Resource.__init__(self) - self.portal = portal - self.callback = callback - self.errback = errback - - def _ebFilter(self, f): - f.trap(LoginFailed, UnauthorizedLogin) - raise fm.FormException(password="Login failed, please enter correct username and password.") - - def getChild(self, path, request): - s = request.getSession() - if s is None: - return request.setupSession() - if path == INIT_PERSPECTIVE: - def loginSuccess(result): - interface, avatarAspect, logout = result - s.setResourceForPortal(avatarAspect, self.portal, logout) - - def triggerLogin(username, password, submit=None): - return self.portal.login( - UsernamePassword(username, password), - None, - IResource - ).addCallback( - loginSuccess - ).addErrback( - self._ebFilter - ) - - return form.FormProcessor( - newLoginSignature.method( - triggerLogin - ), - callback=self.callback, - errback=self.errback - ) - elif path == DESTROY_PERSPECTIVE: - s.portalLogout(self.portal) - return Redirect(".") - else: - r = s.resourceForPortal(self.portal) - if r: - ## Delegate our getChild to the resource our portal says is the right one. - return getResource(r[0], path, request) - else: - return DeferredResource( - self.portal.login(Anonymous(), None, IResource - ).addCallback( - lambda (interface, avatarAspect, logout): - getResource(s.setResourceForPortal(avatarAspect, - self.portal, logout), - path, request))) - - - -from twisted.web.woven import interfaces, utils -## Dumb hack until we have an ISession and use interface-to-interface adaption -components.registerAdapter(utils.WovenLivePage, GuardSession, interfaces.IWovenLivePage) - diff --git a/tools/buildbot/pylibs/twisted/web/woven/input.py b/tools/buildbot/pylibs/twisted/web/woven/input.py deleted file mode 100644 index 7d7d956..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/input.py +++ /dev/null @@ -1,347 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_woven -*- -# -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -# dominput - -import os -import inspect - -from twisted.internet import defer -from twisted.python import log -from twisted.python.reflect import qual - -from twisted.web import domhelpers -from twisted.web.woven import template, controller, utils - -__version__ = "$Revision: 1.34 $"[11:-2] - -controllerFactory = controller.controllerFactory - - -class InputHandler(controller.Controller): - """ - An InputHandler is like a controller, but it operates on something - contained inside of C{self.model} instead of directly on C{self.model}. - For example, a Handler whose C{model} has been set to C{"foo"} will handle - C{self.model.foo}. - - The handler's job is to interpret the request and: - - 1. Check for valid input - 2. If the input is valid, update the model - 3. Use any special API of the view widget to change the view (other - than what the view updates automatically from the model) e.g. in the - case of an error, tell the view to report an error to the user - 4. Return a success value; by default these values are simply recorded - and the page is rendered, but these values could be used to determine - what page to display next, etc. - """ - invalidErrorText = "Error!" - setupStacks = 0 - def __init__(self, model=None, - parent=None, - name=None, - check=None, - commit = None, - invalidErrorText = None, - submodel=None, - controllerStack=None): - self.controllerStack = controllerStack - controller.Controller.__init__(self, model) - self._check = check - self._commit = commit - self._errback = None - self._parent = parent - if invalidErrorText is not None: - self.invalidErrorText = invalidErrorText - if submodel is not None: - self.submodel = submodel - if name is not None: - self.inputName = name - - def initialize(self): - pass - - def setNode(self, node): - self.node = node - - def getInput(self, request): - """ - Return the data associated with this handler from the request, if any. - """ - name = getattr(self, 'inputName', self.submodel) - input = request.args.get(name, None) - if input: - return input - - def handle(self, request): - self.initialize() - data = self.getInput(request) - success = self.check(request, data) - if isinstance(success, defer.Deferred): - success.addCallback(self.dispatchCheckResult, request, data) - success.addErrback(utils.renderFailure, request) - return success - self.dispatchCheckResult(success, request, data) - - def dispatchCheckResult(self, success, request, data): - if success is not None: - if success: - result = self.handleValid(request, data) - else: - result = self.handleInvalid(request, data) - if isinstance(result, defer.Deferred): - return result - - def check(self, request, data): - """ - Check whether the input in the request is valid for this handler - and return a boolean indicating validity. - """ - if self._check is None: - raise NotImplementedError(qual(self.__class__)+'.check') - # self._check is probably a bound method or simple function that - # doesn't have a reference to this InputHandler; pass it - return self._check(self, request, data) - - def handleValid(self, request, data): - """ - It has been determined that the input for this handler is valid; - however, that does not mean the entire form is valid. - """ - self._parent.aggregateValid(request, self, data) - - def aggregateValid(self, request, inputhandler, data): - """By default we just pass the method calls all the way up to the root - Controller. However, an intelligent InputHandler could override this - and implement a state machine that waits for all data to be collected - and then fires. - """ - self._parent.aggregateValid(request, inputhandler, data) - - def handleInvalid(self, request, data): - """ - Once it has been determined that the input is invalid, we should - tell our view to report this fact to the user. - """ - self._parent.aggregateInvalid(request, self, data) - self.view.setError(request, self.invalidErrorText) - - def aggregateInvalid(self, request, inputhandler, data): - """By default we just pass this method call all the way up to the root - Controller. - """ - self._parent.aggregateInvalid(request, inputhandler, data) - - def commit(self, request, node, data): - """ - It has been determined that the input for the entire form is completely - valid; it is now safe for all handlers to commit changes to the model. - """ - if self._commit is None: - data = str(data) - if data != self.view.getData(): - self.model.setData(data) - self.model.notify({'request': request, self.submodel: data}) - else: - func = self._commit - if hasattr(func, 'im_func'): - func = func.im_func - args, varargs, varkw, defaults = inspect.getargspec(func) - if args[1] == 'request': - self._commit(request, data) - else: - self._commit(data) - - -class DefaultHandler(InputHandler): - def handle(self, request): - """ - By default, we don't do anything - """ - pass - - -class SingleValue(InputHandler): - def getInput(self, request): - name = getattr(self, 'inputName', self.submodel) - input = request.args.get(name, None) - if input: - return input[0] - - -class Anything(SingleValue): - """ - Handle anything except for None - """ - def check(self, request, data): - if data is not None: - return 1 - return None - - -class Integer(SingleValue): - """ - Only allow a single integer - """ - def check(self, request, data): - if data is None: return None - try: - int(data) - return 1 - except (TypeError, ValueError): - return 0 - - def handleInvalid(self, request, data): - self.invalidErrorText = "%s is not an integer. Please enter an integer." % data - SingleValue.handleInvalid(self, request, data) - - -class Float(SingleValue): - """ - Only allow a single float - """ - def check(self, request, data): - if data is None: return None - try: - float(data) - return 1 - except (TypeError, ValueError): - return 0 - - def handleInvalid(self, request, data): - self.invalidErrorText = "%s is not an float. Please enter a float." % data - SingleValue.handleInvalid(self, request, data) - - -class List(InputHandler): - def check(self, request, data): - return None - - -class DictAggregator(Anything): - """An InputHandler for a
                    tag, for triggering a function - when all of the form's individual inputs have been validated. - Also for use gathering a dict of arguments to pass to a parent's - aggregateValid if no commit function is passed. - - Usage example:: - - - - -
                    - - def theCommitFunction(anInteger=None, aString=None): - '''Note how the keyword arguments match up with the leaf model - names above - ''' - print "Yay", anInteger, aString - - class CMyController(controller.Controller): - def wcfactory_theForm(self, request, node, m): - return input.FormAggregator(m, commit=theCommitFunction) - """ - def aggregateValid(self, request, inputhandler, data): - """Aggregate valid input from inputhandlers below us, into a dictionary. - """ - self._valid[inputhandler] = data - - def aggregateInvalid(self, request, inputhandler, data): - self._invalid[inputhandler] = data - - def exit(self, request): - """This is the node complete message - """ - if self._commit: - # Introspect the commit function to see what - # keyword arguments it takes - func = self._commit - if hasattr(func, 'im_func'): - func = func.im_func - args, varargs, varkw, defaults = inspect.getargspec( - func) - wantsRequest = len(args) > 1 and args[1] == 'request' - - if self._invalid: - # whoops error!!!1 - if self._errback: - self._errback(request, self._invalid) - elif self._valid: - # We've got all the input - # Gather it into a dict and call the commit function - results = {} - for item in self._valid: - results[item.model.name] = self._valid[item] - if self._commit: - if wantsRequest: - self._commit(request, **results) - else: - self._commit(**results) - else: - self._parent.aggregateValid(request, self, results) - return results - - -class ListAggregator(Anything): - def aggregateValid(self, request, inputhandler, data): - """Aggregate valid input from inputhandlers below us into a - list until we have all input from controllers below us to pass - to the commit function that was passed to the constructor or - our parent's aggregateValid. - """ - if not hasattr(self, '_validList'): - self._validList = [] - self._validList.append(data) - - def aggregateInvalid(self, request, inputhandler, data): - if not hasattr(self, '_invalidList'): - self._invalidList = [] - self._invalidList.append(data) - - def exit(self, request): - if self._commit: - # Introspect the commit function to see what - #arguments it takes - func = self._commit - if hasattr(func, 'im_func'): - func = func.im_func - args, varargs, varkw, defaults = inspect.getargspec(func) - self.numArgs = len(args) - wantsRequest = args[1] == 'request' - if wantsRequest: - numArgs -= 1 - else: - # Introspect the template to see if we still have - # controllers that will be giving us input - - # aggregateValid is called before the view renders the node, so - # we can count the number of controllers below us the first time - # we are called - if not hasattr(self, 'numArgs'): - self.numArgs = len(domhelpers.findElementsWithAttributeShallow( - self.view.node, "controller")) - - if self._invalidList: - self._parent.aggregateInvalid(request, self, self._invalidList) - else: - if self._commit: - if wantsRequest: - self._commit(request, *self._validList) - else: - self._commit(*self._validList) - self._parent.aggregateValid(request, self, self._invalidList) - - def commit(self, request, node, data): - """If we're using the ListAggregator, we don't want the list of items - to be rerendered - xxx Need to have a "node complete" message sent to the controller - so we can reset state, so controllers can be re-run or ignore input the second time - """ - pass - diff --git a/tools/buildbot/pylibs/twisted/web/woven/interfaces.py b/tools/buildbot/pylibs/twisted/web/woven/interfaces.py deleted file mode 100644 index 3c2c2ad..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/interfaces.py +++ /dev/null @@ -1,198 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_woven -*- - -__version__ = "$Revision: 1.13 $"[11:-2] - -from zope.interface import Interface - -class IModel(Interface): - """A MVC Model.""" - def addView(view): - """Add a view for the model to keep track of. - """ - - def removeView(view): - """Remove a view that the model no longer should keep track of. - """ - - def notify(changed=None): - """Notify all views that something was changed on me. - Passing a dictionary of {'attribute': 'new value'} in changed - will pass this dictionary to the view for increased performance. - If you don't want to do this, don't, and just use the traditional - MVC paradigm of querying the model for things you're interested - in. - """ - - def getData(): - """Return the raw data contained by this Model object, if it is a - wrapper. If not, return self. - """ - - def setData(request, data): - """Set the raw data referenced by this Model object, if it is a - wrapper. This is done by telling our Parent model to setSubmodel - the new data. If this object is not a wrapper, keep the data - around and return it for subsequent getData calls. - """ - - def lookupSubmodel(request, submodelPath): - """Return an IModel implementor for the given submodel path - string. This path may be any number of elements separated - by /. The default implementation splits on "/" and calls - getSubmodel until the path is exhausted. You will not normally - need to override this behavior. - """ - - def getSubmodel(request, submodelName): - """Return an IModel implementor for the submodel named - "submodelName". If this object contains simple data types, - they can be adapted to IModel using - model.adaptToIModel(m, parent, name) before returning. - """ - - def setSubmodel(request, submodelName, data): - """Set the given data as a submodel of this model. The data - need not implement IModel, since getSubmodel should adapt - the data to IModel before returning it. - """ - - -class IView(Interface): - """A MVC View""" - def __init__(model, controller=None): - """A view must be told what its model is, and may be told what its - controller is, but can also look up its controller if none specified. - """ - - def modelChanged(changed): - """Dispatch changed messages to any update_* methods which - may have been defined, then pass the update notification on - to the controller. - """ - - def controllerFactory(): - """Hook for subclasses to customize the controller that is associated - with the model associated with this view. - - Default behavior: Look up a component that implements IController - for the self.model instance. - """ - - def setController(controller): - """Set the controller that this view is related to.""" - - def importViewLibrary(moduleOrObject): - """Import the given object or module into this View's view namespace - stack. If the given object or module has a getSubview function or - method, it will be called when a node has a view="foo" attribute. - If no getSubview method is defined, a default one will be provided - which looks for the literal name in the namespace. - """ - - def getSubview(request, node, model, viewName): - """Look for a view named "viewName" to handle the node "node". - When a node
                    is present in the template, this - method will be called with viewName set to "foo". - - Return None if this View doesn't want to provide a Subview for - the given name. - """ - - def setSubviewFactory(name, factory, setup=None): - """Set the callable "factory", which takes a model and should - return a Widget, to be called by the default implementation of - getSubview when the viewName "name" is present in the template. - - This would generally be used like this: - - view.setSubviewFactory("foo", MyFancyWidgetClass) - - This is equivalent to:: - - def wvfactory_foo(self, request, node, m): - return MyFancyWidgetClass(m) - - Which will cause an instance of MyFancyWidgetClass to be - instanciated when template node
                    is encountered. - - If setup is passed, it will be passed to new instances returned - from this factory as a setup method. The setup method is called - each time the Widget is generated. Setup methods take (request, - widget, model) as arguments. - - This is equivalent to:: - - def wvupdate_foo(self, request, widget, model): - # whatever you want - """ - - def __adapt__(adaptable, default): - if hasattr(adaptable, 'original'): - return IView(adaptable.original, default) - return default - - -class IController(Interface): - """A MVC Controller""" - def setView(view): - """Set the view that this controller is related to. - """ - - def importControllerLibrary(moduleOrObject): - """Import the given object or module into this Controllers's - controller namespace stack. If the given object or module has a - getSubcontroller function or method, it will be called when a node - has a controller="foo" attribute. If no getSubcontroller method is - defined, a default one will be provided which looks for the literal - name in the namespace. - """ - - def getSubcontroller(request, node, model, controllerName): - """Look for a controller named "controllerName" to handle the node - "node". When a node
                    is present in the - template, this method will be called with controllerName set to "foo". - - Return None if this Controller doesn't want to provide a Subcontroller - for the given name. - """ - - def setSubcontrollerFactory(name, factory): - """Set the callable "factory", which takes a model and should - return an InputHandler, to be called by the default implementation of - getSubview when the controllerName "name" is present in the template. - - This would generally be used like this:: - - view.setSubcontrollerFactory("foo", MyFancyInputHandlerClass) - - This is equivalent to:: - - def wcfactory_foo(self, request, node, m): - return MyFancyInputHandlerClass(m) - - Which will cause an instance of MyFancyInputHandlerClass to be - instanciated when template node
                    is - encountered. - """ - - def __adapt__(adaptable, default): - if hasattr(adaptable, 'original'): - return IController(adaptable.original, default) - return default - - -class IWovenLivePage(Interface): - def getCurrentPage(): - """Return the current page object contained in this session. - """ - - def setCurrentPage(page): - """Set the current page object contained in this session. - """ - - def sendJavaScript(js): - """Send "js" to the live page's persistent output conduit for - execution in the browser. If there is no conduit connected yet, - save the js and write it as soon as the output conduit is - connected. - """ diff --git a/tools/buildbot/pylibs/twisted/web/woven/model.py b/tools/buildbot/pylibs/twisted/web/woven/model.py deleted file mode 100644 index 90153c2..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/model.py +++ /dev/null @@ -1,487 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_woven -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -__version__ = "$Revision: 1.53 $"[11:-2] - -import types -import weakref -import warnings - -from zope.interface import implements - -from twisted.python import components, reflect -from twisted.internet import defer - -from twisted.web.woven import interfaces - -class _Nothing: pass - -def adaptToIModel(m, parent=None, submodel=None): - adapted = interfaces.IModel(m, None) - if adapted is None: - adapted = Wrapper(m) - adapted.parent = parent - adapted.name = submodel - return adapted - - -class Model: - """ - A Model which keeps track of views which are looking at it in order - to notify them when the model changes. - """ - implements(interfaces.IModel) - - def __init__(self, *args, **kwargs): - if len(args): - self.original = args[0] - else: - self.original = self - self.name = '' - self.parent = None - self.views = [] - self.subviews = {} - self.submodels = {} - self._getter = kwargs.get('getter') - self._setter = kwargs.get('setter') - self.cachedFor = None - self.initialize(*args, **kwargs) - - def __getstate__(self): - self.views = [] - self.subviews = {} - self.submodels = {} - return self.__dict__ - - def invalidateCache(self): - """Invalidate the cache for this object, so the next time - getData is called, it's getter method is called again. - """ - self.cachedFor = None - - def initialize(self, *args, **kwargs): - """ - Hook for subclasses to initialize themselves without having to - mess with the __init__ chain. - """ - pass - - def addView(self, view): - """ - Add a view for the model to keep track of. - """ - if view not in [ref() for ref in self.views]: - self.views.append(weakref.ref(view)) - - def addSubview(self, name, subview): - subviewList = self.subviews.get(name, []) - subviewList.append(weakref.ref(subview)) - self.subviews[name] = subviewList - - def removeView(self, view): - """ - Remove a view that the model no longer should keep track of. - """ - # AM: loop on a _copy_ of the list, since we're changing it!!! - for weakref in list(self.views): - ref = weakref() - if ref is view or ref is None: - self.views.remove(weakref) - - def setGetter(self, getter): - self._getter = getter - - def setSetter(self, setter): - self._setter = setter - - def notify(self, changed=None): - """ - Notify all views that something was changed on me. - Passing a dictionary of {'attribute': 'new value'} in changed - will pass this dictionary to the view for increased performance. - If you don't want to do this, don't, and just use the traditional - MVC paradigm of querying the model for things you're interested - in. - """ - self.cachedFor = None - if changed is None: changed = {} - retVal = [] - # AM: loop on a _copy_ of the list, since we're changing it!!! - for view in list(self.views): - ref = view() - if ref is not None: - retVal.append((ref, ref.modelChanged(changed))) - else: - self.views.remove(view) - for key, value in self.subviews.items(): - if value.wantsAllNotifications or changed.has_key(key): - for item in list(value): - ref = item() - if ref is not None: - retVal.append((ref, ref.modelChanged(changed))) - else: - value.remove(item) - return retVal - - protected_names = ['initialize', 'addView', 'addSubview', 'removeView', 'notify', 'getSubmodel', 'setSubmodel', 'getData', 'setData'] - allowed_names = [] - - def lookupSubmodel(self, request, submodelName): - """ - Look up a full submodel name. I will split on `/' and call - L{getSubmodel} on each element in the 'path'. - - Override me if you don't want 'traversing'-style lookup, but - would rather like to look up a model based on the entire model - name specified. - - If you override me to return Deferreds, make sure I look up - values in a cache (created by L{setSubmodel}) before doing a - regular Deferred lookup. - - XXX: Move bits of this docstring to interfaces.py - """ - if not submodelName: - return None - - # Special case: If the first character is / - # Start at the bottom of the model stack - currentModel = self - if submodelName[0] == '/': - while currentModel.parent is not None: - currentModel = currentModel.parent - submodelName = submodelName[1:] - - submodelList = submodelName.split('/') #[:-1] -# print "submodelList", submodelList - for element in submodelList: - if element == '.' or element == '': - continue - elif element == '..': - currentModel = currentModel.parent - else: - currentModel = currentModel.getSubmodel(request, element) - if currentModel is None: - return None - return currentModel - - def submodelCheck(self, request, name): - """Check if a submodel name is allowed. Subclass me to implement a - name security policy. - """ - if self.allowed_names: - return (name in self.allowed_names) - else: - return (name and name[0] != '_' and name not in self.protected_names) - - - def submodelFactory(self, request, name): - warnings.warn("Warning: default Model lookup strategy is changing:" - "use either AttributeModel or MethodModel for now.", - DeprecationWarning) - if hasattr(self, name): - return getattr(self, name) - else: - return None - - def getSubmodel(self, request, name): - """ - Get the submodel `name' of this model. If I ever return a - Deferred, then I ought to check for cached values (created by - L{setSubmodel}) before doing a regular Deferred lookup. - """ - if self.submodels.has_key(name): - return self.submodels[name] - if not self.submodelCheck(request, name): - return None - m = self.submodelFactory(request, name) - if m is None: - return None - sm = adaptToIModel(m, self, name) - self.submodels[name] = sm - return sm - - def setSubmodel(self, request=None, name=None, value=None): - """ - Set a submodel on this model. If getSubmodel or lookupSubmodel - ever return a Deferred, I ought to set this in a place that - lookupSubmodel/getSubmodel know about, so they can use it as a - cache. - """ - if self.submodelCheck(request, name): - if self.submodels.has_key(name): - del self.submodels[name] - setattr(self, name, value) - - def dataWillChange(self): - pass - - def getData(self, request): - if self.cachedFor != id(request) and self._getter is not None: - self.cachedFor = id(request) - self.dataWillChange() - self.orig = self.original = self._getter(request) - return self.original - - def setData(self, request, data): - if self._setter is not None: - self.cachedFor = None - return self._setter(request, data) - else: - if hasattr(self, 'parent') and self.parent: - self.parent.setSubmodel(request, self.name, data) - self.orig = self.original = data - - -class MethodModel(Model): - """Look up submodels with wmfactory_* methods. - """ - - def submodelCheck(self, request, name): - """Allow any submodel for which I have a submodel. - """ - return hasattr(self, "wmfactory_"+name) - - def submodelFactory(self, request, name): - """Call a wmfactory_name method on this model. - """ - meth = getattr(self, "wmfactory_"+name) - return meth(request) - - def getSubmodel(self, request=None, name=None): - if name is None: - warnings.warn("Warning! getSubmodel should now take the request as the first argument") - name = request - request = None - - cached = self.submodels.has_key(name) - sm = Model.getSubmodel(self, request, name) - if sm is not None: - if not cached: - sm.cachedFor = id(request) - sm._getter = getattr(self, "wmfactory_"+name) - return sm - - -class AttributeModel(Model): - """Look up submodels as attributes with hosts.allow/deny-style security. - """ - def submodelFactory(self, request, name): - if hasattr(self, name): - return getattr(self, name) - else: - return None - - -#backwards compatibility -WModel = Model - - -class Wrapper(Model): - """ - I'm a generic wrapper to provide limited interaction with the - Woven models and submodels. - """ - parent = None - name = None - def __init__(self, orig): - Model.__init__(self) - self.orig = self.original = orig - - def dataWillChange(self): - pass - - def __repr__(self): - myLongName = reflect.qual(self.__class__) - return "<%s instance at 0x%x: wrapped data: %s>" % (myLongName, - id(self), self.original) - - -class ListModel(Wrapper): - """ - I wrap a Python list and allow it to interact with the Woven - models and submodels. - """ - def dataWillChange(self): - self.submodels = {} - - def getSubmodel(self, request=None, name=None): - if name is None and type(request) is type(""): - warnings.warn("Warning!") - name = request - request = None - if self.submodels.has_key(name): - return self.submodels[name] - orig = self.original - try: - i = int(name) - except: - return None - if i > len(orig): - return None - sm = adaptToIModel(orig[i], self, name) - self.submodels[name] = sm - return sm - - def setSubmodel(self, request=None, name=None, value=None): - if value is None: - warnings.warn("Warning!") - value = name - name = request - request = None - self.original[int(name)] = value - - def __len__(self): - return len(self.original) - - def __getitem__(self, name): - return self.getSubmodel(None, str(name)) - - def __setitem__(self, name, value): - self.setSubmodel(None, str(name), value) - - def __repr__(self): - myLongName = reflect.qual(self.__class__) - return "<%s instance at 0x%x: wrapped data: %s>" % (myLongName, - id(self), self.original) - - -class StringModel(ListModel): - - """ I wrap a Python string and allow it to interact with the Woven models - and submodels. """ - - def setSubmodel(self, request=None, name=None, value=None): - raise ValueError("Strings are immutable.") - - -# pyPgSQL returns "PgResultSet" instances instead of lists, which look, act -# and breathe just like lists. pyPgSQL really shouldn't do this, but this works -try: - from pyPgSQL import PgSQL - components.registerAdapter(ListModel, PgSQL.PgResultSet, interfaces.IModel) -except: - pass - -class DictionaryModel(Wrapper): - """ - I wrap a Python dictionary and allow it to interact with the Woven - models and submodels. - """ - def dataWillChange(self): - self.submodels = {} - - def getSubmodel(self, request=None, name=None): - if name is None and type(request) is type(""): - warnings.warn("getSubmodel must get a request argument now") - name = request - request = None - if self.submodels.has_key(name): - return self.submodels[name] - orig = self.original - if name not in orig: - return None - sm = adaptToIModel(orig[name], self, name) - self.submodels[name] = sm - return sm - - def setSubmodel(self, request=None, name=None, value=None): - if value is None: - warnings.warn("Warning!") - value = name - name = request - request = None - self.original[name] = value - - -class AttributeWrapper(Wrapper): - """ - I wrap an attribute named "name" of the given parent object. - """ - def __init__(self, parent, name): - self.original = None - parent = ObjectWrapper(parent) - Wrapper.__init__(self, parent.getSubmodel(None, name)) - self.parent = parent - self.name = name - - -class ObjectWrapper(Wrapper): - """ - I may wrap an object and allow it to interact with the Woven models - and submodels. By default, I am not registered for use with anything. - """ - def getSubmodel(self, request=None, name=None): - if name is None and type(request) is type(""): - warnings.warn("Warning!") - name = request - request = None - if self.submodels.has_key(name): - return self.submodels[name] - sm = adaptToIModel(getattr(self.original, name), self, name) - self.submodels[name] = sm - return sm - - def setSubmodel(self, request=None, name=None, value=None): - if value is None: - warnings.warn("Warning!") - value = name - name = request - request = None - setattr(self.original, name, value) - -class UnsafeObjectWrapper(ObjectWrapper): - """ - I may wrap an object and allow it to interact with the Woven models - and submodels. By default, I am not registered for use with anything. - I am unsafe because I allow methods to be called. In fact, I am - dangerously unsafe. Be wary or I will kill your security model! - """ - def getSubmodel(self, request=None, name=None): - if name is None and type(request) is type(""): - warnings.warn("Warning!") - name = request - request = None - if self.submodels.has_key(name): - return self.submodels[name] - value = getattr(self.original, name) - if callable(value): - return value() - sm = adaptToIModel(value, self, name) - self.submodels = sm - return sm - - -class DeferredWrapper(Wrapper): - def setData(self, request=None, data=_Nothing): - if data is _Nothing: - warnings.warn("setData should be called with request as first arg") - data = request - request = None - if isinstance(data, defer.Deferred): - self.original = data - else: - views, subviews = self.views, self.subviews - new = adaptToIModel(data, self.parent, self.name) - self.__class__ = new.__class__ - self.__dict__ = new.__dict__ - self.views, self.subviews = views, subviews - -class Link(AttributeModel): - def __init__(self, href, text): - AttributeModel.__init__(self) - self.href = href - self.text = text - -try: - components.registerAdapter(StringModel, types.StringType, interfaces.IModel) - components.registerAdapter(ListModel, types.ListType, interfaces.IModel) - components.registerAdapter(ListModel, types.TupleType, interfaces.IModel) - components.registerAdapter(DictionaryModel, types.DictionaryType, interfaces.IModel) - components.registerAdapter(DeferredWrapper, defer.Deferred, interfaces.IModel) - components.registerAdapter(DeferredWrapper, defer.DeferredList, interfaces.IModel) -except ValueError: - # The adapters were already registered - pass diff --git a/tools/buildbot/pylibs/twisted/web/woven/page.py b/tools/buildbot/pylibs/twisted/web/woven/page.py deleted file mode 100644 index 11e7485..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/page.py +++ /dev/null @@ -1,105 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_woven -*- -# -# page.py - -__version__ = "$Revision: 1.23 $"[11:-2] - -from twisted.python import reflect -from twisted.web import resource -from twisted.web.woven import model, view, controller, interfaces, template - -class Page(model.MethodModel, controller.Controller, view.View): - """ - @cvar appRoot: Set this to True if you want me to call - request.rememberRootURL() in my getChild, so you can later use - request.getRootURL() to get the URL to this "application"'s root - resource. (You don't have to worry if there will be multiple - instances of this Page involved in a single request; I'll only - call it for the upper-most instance). - """ - - appRoot = False - - def __init__(self, *args, **kwargs): - templateFile = kwargs.setdefault('templateFile', None) - inputhandlers = kwargs.setdefault('inputhandlers', None) - controllers = kwargs.setdefault('controllers', None) - templateDirectory = kwargs.setdefault('templateDirectory', None) - template = kwargs.setdefault('template', None) - - del kwargs['templateFile'] - del kwargs['inputhandlers'] - del kwargs['controllers'] - del kwargs['templateDirectory'] - del kwargs['template'] - - model.Model.__init__(self, *args, **kwargs) - if len(args): - self.model = args[0] - else: - self.model = self - - controller.Controller.__init__(self, self.model, - inputhandlers=inputhandlers, - controllers=controllers) - self.view = self - view.View.__init__(self, self.model, controller=self, - templateFile=templateFile, - templateDirectory = templateDirectory, - template = template) - self.controller = self - self.controllerRendered = 0 - - def getChild(self, name, request): - # Don't call the rememberURL if we already did once; That way - # we can support an idiom of setting appName as a class - # attribue *even if* the same class is used more than once in - # a hierarchy of Pages. - if self.appRoot and not request.getRootURL(): - request.rememberRootURL() - return controller.Controller.getChild(self, name, request) - - - def renderView(self, request): - return view.View.render(self, request, - doneCallback=self.gatheredControllers) - -class LivePage(model.MethodModel, controller.LiveController, view.LiveView): - - appRoot = False - - def __init__(self, m=None, templateFile=None, inputhandlers=None, - templateDirectory=None, controllers=None, *args, **kwargs): - template = kwargs.setdefault('template', None) - del kwargs['template'] - - model.Model.__init__(self, *args, **kwargs) - if m is None: - self.model = self - else: - self.model = m - - controller.LiveController.__init__(self, self.model, - inputhandlers=inputhandlers, - controllers=controllers) - self.view = self - view.View.__init__(self, self.model, controller=self, - templateFile=templateFile, - templateDirectory=templateDirectory, - template=template) - self.controller = self - self.controllerRendered = 0 - - - def getChild(self, name, request): - # Don't call the rememberPath if we already did once; That way - # we can support an idiom of setting appName as a class - # attribue *even if* the same class is used more than once in - # a hierarchy of Pages. - if self.appRoot and not request.getRootURL(): - request.rememberRootURL() - return controller.Controller.getChild(self, name, request) - - def renderView(self, request): - return view.View.render(self, request, - doneCallback=self.gatheredControllers) diff --git a/tools/buildbot/pylibs/twisted/web/woven/simpleguard.py b/tools/buildbot/pylibs/twisted/web/woven/simpleguard.py deleted file mode 100644 index 65c1ad4..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/simpleguard.py +++ /dev/null @@ -1,82 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -""" -A simple guard framework for implementing web sites that only need -'Anonymous' vs 'Logged on' distinction, but nothing more. - -If you need - - multiple levels of access, or - - multiple-interface applications, or - - anything else more complex than 'Logged on' and 'Not logged on' - -you need to use twisted.web.woven.guard directly. -""" - -from twisted.cred import portal, checkers as checkerslib -from twisted.web import resource, util -from twisted.web.woven import guard -from zope.interface import implements - - -class Authenticated: - - def __init__(self, name=None): - self.name = name - - def __nonzero__(self): - return bool(self.name) - - -class MarkAuthenticatedResource: - - implements(resource.IResource) - - isLeaf = False - - def __init__(self, resource, name): - self.authenticated = Authenticated(name) - self.resource = resource - - def render(self, request): - request.setComponent(Authenticated, self.authenticated) - return self.resource.render(request) - - def getChildWithDefault(self, path, request): - request.setComponent(Authenticated, self.authenticated) - return self.resource.getChildWithDefault(path, request) - - -class MarkingRealm: - - implements(portal.IRealm) - - def __init__(self, resource, nonauthenticated=None): - self.resource = resource - self.nonauthenticated = (nonauthenticated or - MarkAuthenticatedResource(resource, None)) - - def requestAvatar(self, avatarId, mind, *interfaces): - if resource.IResource not in interfaces: - raise NotImplementedError("no interface") - if avatarId: - return (resource.IResource, - MarkAuthenticatedResource(self.resource, avatarId), - lambda:None) - else: - return resource.IResource, self.nonauthenticated, lambda:None - - -def parentRedirect(_): - return util.ParentRedirect() - -def guardResource(resource, checkers, callback=parentRedirect, errback=None, - nonauthenticated=None): - myPortal = portal.Portal(MarkingRealm(resource, nonauthenticated)) - for checker in checkers+[checkerslib.AllowAnonymousAccess()]: - myPortal.registerChecker(checker) - un = guard.UsernamePasswordWrapper(myPortal, - callback=callback, errback=errback) - return guard.SessionWrapper(un) diff --git a/tools/buildbot/pylibs/twisted/web/woven/tapestry.py b/tools/buildbot/pylibs/twisted/web/woven/tapestry.py deleted file mode 100644 index 11b6042..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/tapestry.py +++ /dev/null @@ -1,170 +0,0 @@ - -""" -Woven object collections. - -THIS MODULE IS HIGHLY EXPERIMENTAL AND MAY BE DEPRECATED SOON. -""" - -from __future__ import nested_scopes - -__version__ = "$Revision: 1.13 $"[11:-2] - - -import warnings -warnings.warn("The tapestry module is deprecated. Use page instead.", DeprecationWarning, 1) - -# System Imports -import sys -import os - -# Twisted Imports - -from twisted.internet.defer import Deferred - -from twisted.web.resource import Resource, IResource -from twisted.web.static import redirectTo, addSlash, File, Data -from twisted.web.server import NOT_DONE_YET -from twisted.web import util - -from twisted.python.reflect import qual - -# Sibling Imports -from twisted.web.woven.view import View - -_ChildJuggler = util.DeferredResource - -class ModelLoader(Resource): - """Resource for loading models. (see loadModel) - """ - def __init__(self, parent, templateFile=None): - Resource.__init__(self) - self.parent = parent - self.templateFile = templateFile - - def modelClass(self, other): - return other - - def getChild(self, path, request): - d = self.loadModel(path, request) - templateFile = (self.templateFile or self.__class__.__name__+'.html') - d.addCallback( - lambda result: self.parent.makeView(self.modelClass(result), - templateFile, 1)) - return util.DeferredResource(d) - - def loadModelNow(self, path, request): - """Override this rather than loadModel if your model-loading is - synchronous. - """ - raise NotImplementedError("%s.loadModelNow" % (reflect.qual(self.__class__))) - - def loadModel(self, path, request): - """Load a model, for the given path and request. - - @rtype: L{Deferred} - """ - from twisted.internet.defer import execute - return execute(self.loadModelNow, path, request) - - -from twisted.web import microdom -from twisted.web import domhelpers - -class TapestryView(View): - tapestry = None - parentCount = 0 - def lookupTemplate(self, request): - fullFile = os.path.join(self.templateDirectory, self.templateFile) - document = microdom.parse(open(fullFile)) - if self.tapestry: - return self.tapestry.templateMutate(document, self.parentCount) - return document - -class Tapestry(Resource): - """ - I am a top-level aggregation of Woven objects: a full `site' or - `application'. - """ - viewFactory = TapestryView - def __init__(self, templateDirectory, viewFactory=None, metaTemplate=None): - """ - Create a tapestry with a specified template directory. - """ - Resource.__init__(self) - self.templateDirectory = templateDirectory - if viewFactory is not None: - self.viewFactory = viewFactory - if metaTemplate: - self.metaTemplate = microdom.parse(open( - os.path.join(templateDirectory, metaTemplate))) - else: - self.metaTemplate = None - - def templateMutate(self, document, parentCount=0): - if self.metaTemplate: - newDoc = self.metaTemplate.cloneNode(1) - if parentCount: - dotdot = parentCount * '../' - for ddname in 'href', 'src', 'action': - for node in domhelpers.findElementsWithAttribute(newDoc, ddname): - node.setAttribute(ddname, dotdot + node.getAttribute(ddname)) - ttl = domhelpers.findNodesNamed(newDoc, "title")[0] - ttl2 = domhelpers.findNodesNamed(document, "title")[0] - ttl.childNodes[:] = [] - for n in ttl2.childNodes: - ttl.appendChild(n) - body = domhelpers.findElementsWithAttribute(newDoc, "class", "__BODY__")[0] - body2 = domhelpers.findNodesNamed(document, "body")[0] - ndx = body.parentNode.childNodes.index(body) - body.parentNode.childNodes[ndx:ndx+1] = body2.childNodes - for n in body2.childNodes: - n.parentNode = body.parentNode - f = open("garbage.html", "wb") - f.write(newDoc.toprettyxml()) - return newDoc - return document - - def makeView(self, model, name, parentCount=0): - v = self.viewFactory(model, name) - v.parentCount = parentCount - v.templateDirectory = self.templateDirectory - v.tapestry = self - v.importViewLibrary(self) - return v - - def getSubview(self, request, node, model, viewName): - mod = sys.modules[self.__class__.__module__] - # print "I'm getting a subview", mod, viewName - - # try just the name - vm = getattr(mod, viewName, None) - if vm: - return vm(model) - - # try the name + a V - vn2 = "V"+viewName.capitalize() - vm = getattr(mod, vn2, None) - if vm: - return vm(model) - - vm = getattr(self, 'wvfactory_'+viewName, None) - if vm: - return vm(request, node, model) - - def render(self, request): - return redirectTo(addSlash(request), request) - - def getChild(self, path, request): - if path == '': path = 'index' - path = path.replace(".","_") - cm = getattr(self, "wchild_"+path, None) - if cm: - p = cm(request) - if isinstance(p, Deferred): - return util.DeferredResource(p) - adapter = IResource(p, None) - if adapter is not None: - return adapter - # maybe we want direct support for ModelLoader? - # cl = getattr(self, "wload_"+path, None) #??? - return Resource.getChild(self, path, request) diff --git a/tools/buildbot/pylibs/twisted/web/woven/template.py b/tools/buildbot/pylibs/twisted/web/woven/template.py deleted file mode 100644 index a25ab43..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/template.py +++ /dev/null @@ -1,374 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_woven -*- -# -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -DOMTemplate - -Most templating systems provide commands that you embed -in the HTML to repeat elements, include fragments from other -files, etc. This works fairly well for simple constructs and people -tend to get a false sense of simplicity from this. However, in my -experience, as soon as the programmer wants to make the logic -even slightly more complicated, the templating system must be -bent and abused in ways it was never meant to be used. - -The theory behind DOMTemplate is that Python code instead -of template syntax in the HTML should be used to manipulate -the structure of the HTML. DOMTemplate uses the DOM, a w3c -standard tree-based representation of an HTML document that -provides an API that allows you to traverse nodes in the tree, -examine their attributes, move, add, and delete them. It is a -fairly low level API, meaning it takes quite a bit of code to get -a bit done, but it is standard -- learn the DOM once, you can -use it from ActionScript, JavaScript, Java, C++, whatever. - -A DOMTemplate subclass must do two things: indicate which -template it wants to use, and indicate which elements it is -interested in. - -A short example:: - - | class Test(DOMTemplate): - | template = ''' - | Foo - | - |
                    - | This test node will be replaced - |
                    - | - | - | ''' - | - | def factory_test(self, request, node): - | ''' - | The test method will be called with the request and the - | DOM node that the test method was associated with. - | ''' - | # self.d has been bound to the main DOM "document" object - | newNode = self.d.createTextNode("Testing, 1,2,3") - | - | # Replace the test node with our single new text node - | return newNode -""" - -import warnings - -try: - import cPickle as pickle -except ImportError: - import pickle - -import string, os, sys, stat, types -from twisted.web import microdom - -from twisted.python import components -from twisted.web import resource, html -from twisted.web.resource import Resource -from twisted.web.woven import controller, utils, interfaces - -from twisted.internet import defer -from twisted.python import failure -from twisted.internet import reactor, defer -from twisted.python import log -from zope.interface import implements, Interface - -from twisted.web.server import NOT_DONE_YET -STOP_RENDERING = 1 -RESTART_RENDERING = 2 - - - -class INodeMutator(Interface): - """A component that implements NodeMutator knows how to mutate - DOM based on the instructions in the object it wraps. - """ - def generate(request, node): - """The generate method should do the work of mutating the DOM - based on the object this adapter wraps. - """ - pass - - -class NodeMutator: - implements(INodeMutator) - def __init__(self, data): - self.data = data - -class NodeNodeMutator(NodeMutator): - """A NodeNodeMutator replaces the node that is passed in to generate - with the node it adapts. - """ - def __init__(self, data): - assert data is not None - NodeMutator.__init__(self, data) - - def generate(self, request, node): - if self.data is not node: - parent = node.parentNode - if parent: - parent.replaceChild(self.data, node) - else: - log.msg("Warning: There was no parent for node %s; node not mutated." % node) - return self.data - - -class NoneNodeMutator(NodeMutator): - def generate(self, request, node): - return node # do nothing - child = request.d.createTextNode("None") - node.parentNode.replaceChild(child, node) - - -class StringNodeMutator(NodeMutator): - """A StringNodeMutator replaces the node that is passed in to generate - with the string it adapts. - """ - def generate(self, request, node): - if self.data: - try: - child = microdom.parseString(self.data) - except Exception, e: - log.msg("Error parsing return value, probably invalid xml:", e) - child = request.d.createTextNode(self.data) - else: - child = request.d.createTextNode(self.data) - nodeMutator = NodeNodeMutator(child) - return nodeMutator.generate(request, node) - - -components.registerAdapter(NodeNodeMutator, microdom.Node, INodeMutator) -components.registerAdapter(NoneNodeMutator, type(None), INodeMutator) -components.registerAdapter(StringNodeMutator, type(""), INodeMutator) - - -class DOMTemplate(Resource): - """A resource that renders pages using DOM.""" - - isLeaf = 1 - templateFile = '' - templateDirectory = '' - template = '' - _cachedTemplate = None - - def __init__(self, templateFile = None): - """ - @param templateFile: The name of a file containing a template. - @type templateFile: String - """ - Resource.__init__(self) - if templateFile: - self.templateFile = templateFile - - self.outstandingCallbacks = 0 - self.failed = 0 - - def render(self, request): - template = self.getTemplate(request) - if template: - self.d = microdom.parseString(template) - else: - if not self.templateFile: - raise AttributeError, "%s does not define self.templateFile to operate on" % self.__class__ - self.d = self.lookupTemplate(request) - self.handleDocument(request, self.d) - return NOT_DONE_YET - - def getTemplate(self, request): - """ - Override this if you want to have your subclass look up its template - using a different method. - """ - return self.template - - def lookupTemplate(self, request): - """ - Use acquisition to look up the template named by self.templateFile, - located anywhere above this object in the heirarchy, and use it - as the template. The first time the template is used it is cached - for speed. - """ - if self.template: - return microdom.parseString(self.template) - if not self.templateDirectory: - mod = sys.modules[self.__module__] - if hasattr(mod, '__file__'): - self.templateDirectory = os.path.split(mod.__file__)[0] - # First see if templateDirectory + templateFile is a file - templatePath = os.path.join(self.templateDirectory, self.templateFile) - # Check to see if there is an already compiled copy of it - templateName = os.path.splitext(self.templateFile)[0] - compiledTemplateName = '.' + templateName + '.pxp' - compiledTemplatePath = os.path.join(self.templateDirectory, compiledTemplateName) - # No? Compile and save it - if (not os.path.exists(compiledTemplatePath) or - os.stat(compiledTemplatePath)[stat.ST_MTIME] < os.stat(templatePath)[stat.ST_MTIME]): - compiledTemplate = microdom.parse(templatePath) - pickle.dump(compiledTemplate, open(compiledTemplatePath, 'wb'), 1) - else: - compiledTemplate = pickle.load(open(compiledTemplatePath, "rb")) - return compiledTemplate - - def setUp(self, request, document): - pass - - def handleDocument(self, request, document): - """ - Handle the root node, and send the page if there are no - outstanding callbacks when it returns. - """ - try: - request.d = document - self.setUp(request, document) - # Don't let outstandingCallbacks get to 0 until the - # entire tree has been recursed - # If you don't do this, and any callback has already - # completed by the time the dispatchResultCallback - # is added in dispachResult, then sendPage will be - # called prematurely within dispatchResultCallback - # resulting in much gnashing of teeth. - self.outstandingCallbacks += 1 - for node in document.childNodes: - request.currentParent = node - self.handleNode(request, node) - self.outstandingCallbacks -= 1 - if not self.outstandingCallbacks: - return self.sendPage(request) - except: - self.renderFailure(None, request) - - def dispatchResult(self, request, node, result): - """ - Check a given result from handling a node and hand it to a process* - method which will convert the result into a node and insert it - into the DOM tree. Return the new node. - """ - if not isinstance(result, defer.Deferred): - adapter = INodeMutator(result, None) - if adapter is None: - raise NotImplementedError( - "Your factory method returned %s, but there is no " - "INodeMutator adapter registerred for %s." % - (result, getattr(result, "__class__", - None) or type(result))) - result = adapter.generate(request, node) - if isinstance(result, defer.Deferred): - self.outstandingCallbacks += 1 - result.addCallback(self.dispatchResultCallback, request, node) - result.addErrback(self.renderFailure, request) - # Got to wait until the callback comes in - return result - - def recurseChildren(self, request, node): - """ - If this node has children, handle them. - """ - request.currentParent = node - if not node: return - if type(node.childNodes) == type(""): return - if node.hasChildNodes(): - for child in node.childNodes: - self.handleNode(request, child) - - def dispatchResultCallback(self, result, request, node): - """ - Deal with a callback from a deferred, dispatching the result - and recursing children. - """ - self.outstandingCallbacks -= 1 - node = self.dispatchResult(request, node, result) - self.recurseChildren(request, node) - if not self.outstandingCallbacks: - return self.sendPage(request) - - def handleNode(self, request, node): - """ - Handle a single node by looking up a method for it, calling the method - and dispatching the result. - - Also, handle all childNodes of this node using recursion. - """ - if not hasattr(node, 'getAttribute'): # text node? - return node - - viewName = node.getAttribute('view') - if viewName: - method = getattr(self, "factory_" + viewName, None) - if not method: - raise NotImplementedError, "You specified view name %s on a node, but no factory_%s method was found." % (viewName, viewName) - - result = method(request, node) - node = self.dispatchResult(request, node, result) - - if not isinstance(node, defer.Deferred): - self.recurseChildren(request, node) - - def sendPage(self, request): - """ - Send the results of the DOM mutation to the browser. - """ - page = str(self.d.toxml()) - request.write(page) - request.finish() - return page - - def renderFailure(self, failure, request): - try: - xml = request.d.toxml() - except: - xml = "" -# if not hasattr(request, 'channel'): -# log.msg("The request got away from me before I could render an error page.") -# log.err(failure) -# return failure - if not self.failed: - self.failed = 1 - if failure: - request.write("%s: %s\n" % (html.escape(str(failure.type)), html.escape(str(failure.value)))) - else: - request.write("Failure!\n") - utils.renderFailure(failure, request) - request.write("

                    Here is the partially processed DOM:

                    ") - request.write("\n
                    \n")
                    -            request.write(html.escape(xml))
                    -            request.write("\n
                    \n") - request.write("") - request.finish() - return failure - -########################################## -# Deprecation zone -# Wear a hard hat -########################################## - - -# DOMView is now deprecated since the functionality was merged into domtemplate -DOMView = DOMTemplate - -# DOMController is now renamed woven.controller.Controller -class DOMController(controller.Controller, Resource): - """ - A simple controller that automatically passes responsibility on to the view - class registered for the model. You can override render to perform - more advanced template lookup logic. - """ - - def __init__(self, *args, **kwargs): - log.msg("DeprecationWarning: DOMController is deprecated; it has been renamed twisted.web.woven.controller.Controller.\n") - controller.Controller.__init__(self, *args, **kwargs) - Resource.__init__(self) - - def setUp(self, request): - pass - - def render(self, request): - self.setUp(request) - self.view = interfaces.IView(self.model, None) - self.view.setController(self) - return self.view.render(request) - - def process(self, request, **kwargs): - log.msg("Processing results: ", kwargs) - return RESTART_RENDERING diff --git a/tools/buildbot/pylibs/twisted/web/woven/utils.py b/tools/buildbot/pylibs/twisted/web/woven/utils.py deleted file mode 100644 index 472ac51..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/utils.py +++ /dev/null @@ -1,198 +0,0 @@ -from __future__ import nested_scopes - -from types import ClassType - -from twisted.web import server -from twisted.web import util as webutil -from twisted.web.woven import interfaces -from twisted.python import failure, log, components -from zope.interface import implements - -def renderFailure(fail, request): - if not fail: - fail = failure.Failure() - log.err(fail) - request.write(webutil.formatFailure(fail)) - #request.finish() - - -def doSendPage(self, d, request): - page = str(d.toprettyxml()) - request.setHeader('content-length', str(len(page))) - request.write(page) - request.finish() - return page - - -class Script: - type="javascript1.2" - def __init__(self, script): - self.script = script - - -class WovenLivePage: - implements(interfaces.IWovenLivePage) - - currentPage = None - def __init__(self, session): - self.session = session - self.output = None - self.input = None - self.cached = [] - self.inputCache = [] - - def getCurrentPage(self): - """Return the current page object contained in this session. - """ - return self.currentPage - - def setCurrentPage(self, page): - """Set the current page object contained in this session. - """ - self.currentPage = page - - def write(self, text): - """Write "text" to the live page's persistent output conduit. - If there is no conduit connected yet, save the text and write it - as soon as the output conduit is connected. - """ - if self.output is None: - self.cached.append(text) - print "CACHING", `self.cached` - else: - if isinstance(text, Script): - if hasattr(self.output, 'writeScript'): - self.output.writeScript(text.script) - return - text = '\r\n' % (text.type, text.script) - print "WRITING", text - if text[-1] != '\n': - text += '\n' - self.output.write(text) - - def sendScript(self, js): - self.write(Script(js)) - if self.output is not None and not getattr(self.output, 'keepalive', None): - print "## woot, teh connection was open" - ## Close the connection; the javascript will have to open it again to get the next event. - self.output.finish() - self.output = None - - def hookupOutputConduit(self, request): - """Hook up the given request as the output conduit for this - session. - """ - print "TOOT! WE HOOKED UP OUTPUT!", `self.cached` - self.output = request - for text in self.cached: - self.write(text) - if self.cached: - self.cached = [] - if not getattr(self.output, 'keepalive', None): - ## Close the connection; the javascript will have to open it again to get the next event. - request.finish() - self.output = None - - def unhookOutputConduit(self): - self.output = None - - def hookupInputConduit(self, obj): - """Hook up the given object as the input conduit for this - session. - """ - print "HOOKING UP", self.inputCache - self.input = obj - for text in self.inputCache: - self.pushThroughInputConduit(text) - self.inputCache = [] - print "DONE HOOKING", self.inputCache - - def pushThroughInputConduit(self, inp): - """Push some text through the input conduit. - """ - print "PUSHING INPUT", inp - if self.input is None: - self.inputCache.append(inp) - else: - self.input(inp) - -class Stack: - def __init__(self, stack=None): - if stack is None: - self.stack = [] - else: - self.stack = stack - - def push(self, item): - self.stack.insert(0, item) - - def pop(self): - if self.stack: - return self.stack.pop(0) - - def peek(self): - for x in self.stack: - if x is not None: - return x - - def poke(self, item): - self.stack[0] = item - - def clone(self): - return Stack(self.stack[:]) - - def __len__(self): - return len(self.stack) - - def __getitem__(self, item): - return self.stack[item] - - -class GetFunction: - def __init__(self, namespace): - self.namespace = namespace - - def __call__(self, request, node, model, viewName): - """Get a name from my namespace. - """ - from twisted.web.woven import widgets - if viewName == "None": - return widgets.DefaultWidget(model) - - vc = getattr(self.namespace, viewName, None) - # don't call modules and random crap in the namespace, only widgets - if vc and isinstance(vc, (type, ClassType)) and issubclass(vc, widgets.Widget): - return vc(model) - - -def createGetFunction(namespace): - return GetFunction(namespace) - - -class SetId: - def __init__(self, theId): - self.theId = theId - - def __call__(self, request, wid, data): - id = wid.attributes.get('id', None) - if not id: - wid.setAttribute('id', self.theId) - else: - top = wid - while getattr(top, 'parent', None) is not None: - top = top.parent - if top.subviews.has_key(self.theId): - del top.subviews[self.theId] - top.subviews[id] = wid - if wid.parent.subviews.has_key(self.theId): - del wid.parent.subviews[self.theId] - wid.parent.subviews[id] = wid - - -def createSetIdFunction(theId): - return SetId(theId) - - - -components.registerAdapter(WovenLivePage, server.Session, interfaces.IWovenLivePage) - diff --git a/tools/buildbot/pylibs/twisted/web/woven/view.py b/tools/buildbot/pylibs/twisted/web/woven/view.py deleted file mode 100644 index d792fc7..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/view.py +++ /dev/null @@ -1,687 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_woven -*- -# -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -from __future__ import nested_scopes - -__version__ = "$Revision: 1.91 $"[11:-2] - -# Sibling imports -import interfaces -import utils -import controller -from utils import doSendPage -import model - -# Twisted imports -from twisted.internet import defer -from twisted.python import components -from twisted.python import log -from twisted.web import resource, microdom, html, error -from twisted.web.server import NOT_DONE_YET -from zope.interface import implements - -try: - import cPickle as pickle -except ImportError: - import pickle - -import os -import sys -import stat -import warnings -import types - - -def peek(stack): - if stack is None: - return None - it = None - while it is None and stack is not None: - it, stack = stack - return it - - -def poke(stack, new): - it, stack = stack - return (new, stack) - - -def filterStack(stack): - returnVal = [] - while stack is not None: - it, stack = stack - if it is not None: - returnVal.append(it) - return returnVal - - -def viewFactory(viewClass): - return lambda request, node, model: viewClass(model) - -def viewMethod(viewClass): - return lambda self, request, node, model: viewClass(model) - - -templateCache = {} - - -class View: - implements(resource.IResource, interfaces.IView) - # wvfactory_xxx method signature: request, node, model; returns Widget - # wvupdate_xxx method signature: request, widget, data; mutates widget - # based on data (not necessarily an IModel; - # has been unwrapped at this point) - - wantsAllNotifications = 0 - templateFile = '' - templateDirectory = '' - template = '' - - isLeaf = 1 - - def getChild(self, path, request): - return error.NoResource("No such child resource.") - - def getChildWithDefault(self, path, request): - return self.getChild(path, request) - - viewLibraries = [] - setupStacks = 1 - livePage = 0 - doneCallback = None - templateNode = None - def __init__(self, m, templateFile=None, templateDirectory=None, template=None, controller=None, doneCallback=None, modelStack=None, viewStack=None, controllerStack=None): - """ - A view must be told what its model is, and may be told what its - controller is, but can also look up its controller if none specified. - """ - if not interfaces.IModel.providedBy(m): - m = model.adaptToIModel(m, None, None) - self.model = self.mainModel = m - # It's the responsibility of the calling code to make sure - # setController is called on this view before it's rendered. - self.controller = None - self.subviews = {} - if self.setupStacks: - self.modelStack = None - self.viewStack = None - self.controllerStack = None - if doneCallback is None and self.doneCallback is None: - self.doneCallback = doSendPage - else: - print "DoneCallback", doneCallback - self.doneCallback = doneCallback - if template is not None: - self.template = template - if templateFile is not None: - self.templateFile = templateFile - if templateDirectory is not None: - self.templateDirectory = templateDirectory - - self.outstandingCallbacks = 0 - self.outstandingNodes = [] - self.failed = 0 - self.setupMethods = [] - - def setupAllStacks(self): - self.modelStack = (self.model, None) - self.controllerStack = (self.controller, (input, None)) - self.setupViewStack() - - def setUp(self, request, d): - pass - - def setupViewStack(self): - self.viewStack = None - if widgets not in self.viewLibraries: - self.viewLibraries.append(widgets) - for library in self.viewLibraries: - if not hasattr(library, 'getSubview'): - library.getSubview = utils.createGetFunction(library) - self.viewStack = (library, self.viewStack) - self.viewStack = (self, self.viewStack) - - def importViewLibrary(self, namespace): - self.viewLibraries.append(namespace) - return self - - def render(self, request, doneCallback=None): - if not getattr(request, 'currentId', 0): - request.currentId = 0 - request.currentPage = self - if self.controller is None: - self.controller = controller.Controller(self.model) - if doneCallback is not None: - self.doneCallback = doneCallback - else: - self.doneCallback = doSendPage - self.setupAllStacks() - template = self.getTemplate(request) - if template: - self.d = microdom.parseString(template, caseInsensitive=0, preserveCase=0) - else: - if not self.templateFile: - raise AttributeError, "%s does not define self.templateFile to operate on" % self.__class__ - self.d = self.lookupTemplate(request) - request.d = self.d - self.handleDocument(request, self.d) - return NOT_DONE_YET - - def getTemplate(self, request): - """ - Override this if you want to have your subclass look up its template - using a different method. - """ - return self.template - - def lookupTemplate(self, request): - """ - Use acquisition to look up the template named by self.templateFile, - located anywhere above this object in the heirarchy, and use it - as the template. The first time the template is used it is cached - for speed. - """ - if self.template: - return microdom.parseString(self.template, caseInsensitive=0, preserveCase=0) - if not self.templateDirectory: - mod = sys.modules[self.__module__] - if hasattr(mod, '__file__'): - self.templateDirectory = os.path.split(mod.__file__)[0] - # First see if templateDirectory + templateFile is a file - templatePath = os.path.join(self.templateDirectory, self.templateFile) - if not os.path.exists(templatePath): - raise RuntimeError, "The template %r was not found." % templatePath - # Check to see if there is an already parsed copy of it - mtime = os.path.getmtime(templatePath) - cachedTemplate = templateCache.get(templatePath, None) - compiledTemplate = None - - if cachedTemplate is not None: - if cachedTemplate[0] == mtime: - compiledTemplate = templateCache[templatePath][1].cloneNode(deep=1) - - if compiledTemplate is None: - compiledTemplate = microdom.parse(templatePath, caseInsensitive=0, preserveCase=0) - templateCache[templatePath] = (mtime, compiledTemplate.cloneNode(deep=1)) - return compiledTemplate - - def handleDocument(self, request, document): - """Handle the root node, and send the page if there are no - outstanding callbacks when it returns. - """ - try: - request.d = document - self.setUp(request, document) - # Don't let outstandingCallbacks get to 0 until the - # entire tree has been recursed - # If you don't do this, and any callback has already - # completed by the time the dispatchResultCallback - # is added in dispachResult, then sendPage will be - # called prematurely within dispatchResultCallback - # resulting in much gnashing of teeth. - self.outstandingNodes = document.childNodes[:] + [1] - self.outstandingNodes.reverse() - - self.outstandingCallbacks += 1 - self.handleOutstanding(request) - self.outstandingCallbacks -= 1 - if not self.outstandingCallbacks: - return self.sendPage(request) - except: - self.renderFailure(None, request) - - def handleOutstanding(self, request): - while self.outstandingNodes: - node = self.outstandingNodes.pop() - if node is 1: - self.modelStack = self.modelStack[1] - self.viewStack = self.viewStack[1] - if self.controllerStack is not None: - controller, self.controllerStack = self.controllerStack - if controller is not None: - controller.exit(request) - attrs = getattr(node, 'attributes', None) - if (attrs is not None and - (attrs.get('model') or attrs.get('view') or attrs.get('controller'))): - self.outstandingNodes.append(1) - self.handleNode(request, node) - else: - if attrs is not None and (attrs.get('view') or attrs.get('controller')): - self.outstandingNodes.append(node) - if hasattr(node, 'childNodes') and node.childNodes: - self.recurseChildren(request, node) - - def recurseChildren(self, request, node): - """If this node has children, handle them. - """ - new = node.childNodes[:] - new.reverse() - self.outstandingNodes.extend(new) - - def dispatchResult(self, request, node, result): - """Check a given result from handling a node and look up a NodeMutator - adapter which will convert the result into a node and insert it - into the DOM tree. Return the new node. - """ - if not isinstance(result, defer.Deferred): - if node.parentNode is not None: - node.parentNode.replaceChild(result, node) - else: - raise RuntimeError, "We're dying here, please report this immediately" - else: - self.outstandingCallbacks += 1 - result.addCallback(self.dispatchResultCallback, request, node) - result.addErrback(self.renderFailure, request) - # Got to wait until the callback comes in - return result - - def modelChanged(self, changed): - """Rerender this view, because our model has changed. - """ - # arg. this needs to go away. - request = changed.get('request', None) - oldNode = self.node - #import pdb; pdb.set_trace() - newNode = self.generate(request, oldNode) - returnNode = self.dispatchResult(request, oldNode, newNode) - self.handleNewNode(request, returnNode) - self.handleOutstanding(request) - self.controller.domChanged(request, self, returnNode) - - def generate(self, request, node): - """Allow a view to be used like a widget. Will look up the template - file and return it in place of the incoming node. - """ - newNode = self.lookupTemplate(request).childNodes[0] - newNode.setAttribute('id', 'woven_id_%s' % id(self)) - self.node = newNode - return newNode - - def setController(self, controller): - self.controller = controller - self.controllerStack = (controller, self.controllerStack) - - def setNode(self, node): - if self.templateNode == None: - self.templateNode = node - self.node = node - - def setSubmodel(self, name): - self.submodel = name - - def getNodeModel(self, request, node, submodel): - """ - Get the model object associated with this node. If this node has a - model= attribute, call getSubmodel on the current model object. - If not, return the top of the model stack. - """ - parent = None - if submodel: - if submodel == '.': - m = peek(self.modelStack) - else: - modelStack = self.modelStack - while modelStack is not None: - parent, modelStack = modelStack - if parent is None: - continue - m = parent.lookupSubmodel(request, submodel) - if m is not None: - #print "model", m - break - else: - raise Exception("Node had a model=%s " - "attribute, but the submodel was not " - "found in %s." % (submodel, - filterStack(self.modelStack))) - else: - m = None - self.modelStack = (m, self.modelStack) - if m is not None: -# print "M NAME", m.name -# if parent is not m: -# m.parent = parent -# if not getattr(m, 'name', None): -# m.name = submodel - return m - #print `submodel`, self.getTopOfModelStack() - if submodel: - return peek(self.modelStack) - return None - - def getNodeController(self, request, node, submodel, model): - """ - Get a controller object to handle this node. If the node has no - controller= attribute, first check to see if there is an IController - adapter for our model. - """ - controllerName = node.attributes.get('controller') - controller = None - - if model is None: - model = peek(self.modelStack) - - # Look up a controller factory. - if controllerName: - #if not node.hasAttribute('name'): - # warnings.warn("POTENTIAL ERROR: %s had a controller, but not a " - # "'name' attribute." % node) - controllerStack = self.controllerStack - while controllerStack is not None: - namespace, controllerStack = controllerStack - if namespace is None: - continue - controller = namespace.getSubcontroller(request, node, model, controllerName) - if controller is not None: - break - else: - raise NotImplementedError("You specified controller name %s on " - "a node, but no wcfactory_%s method " - "was found in %s." % (controllerName, - controllerName, - filterStack(self.controllerStack) - )) - elif node.attributes.get("model"): - # If no "controller" attribute was specified on the node, see if - # there is a IController adapter registerred for the model. - controller = interfaces.IController( - model, - None) - - return controller - - - def getSubview(self, request, node, model, viewName): - """Get a sub-view from me. - - @returns: L{widgets.Widget} - """ - view = None - vm = getattr(self, 'wvfactory_' + viewName, None) - if vm is None: - vm = getattr(self, 'factory_' + viewName, None) - if vm is not None: - warnings.warn("factory_ methods are deprecated; please use " - "wvfactory_ instead", DeprecationWarning) - if vm: - if vm.func_code.co_argcount == 3 and not type(vm) == types.LambdaType: - warnings.warn("wvfactory_ methods take (request, node, " - "model) instead of (request, node) now. \n" - "Please instantiate your widgets with a " - "reference to model instead of self.model", - DeprecationWarning) - self.model = model - view = vm(request, node) - self.model = self.mainModel - else: - view = vm(request, node, model) - - setupMethod = getattr(self, 'wvupdate_' + viewName, None) - if setupMethod: - if view is None: - view = widgets.Widget(model) - view.setupMethods.append(setupMethod) - return view - - - def getNodeView(self, request, node, submodel, model): - view = None - viewName = node.attributes.get('view') - - if model is None: - model = peek(self.modelStack) - - # Look up a view factory. - if viewName: - viewStack = self.viewStack - while viewStack is not None: - namespace, viewStack = viewStack - if namespace is None: - continue - try: - view = namespace.getSubview(request, node, model, viewName) - except AttributeError: - # Was that from something in the viewStack that didn't - # have a getSubview? - if not hasattr(namespace, "getSubview"): - log.msg("Warning: There is no getSubview on %r" % - (namespace,)) - continue - else: - # No, something else is really broken. - raise - if view is not None: - break - else: - raise NotImplementedError( - "You specified view name %s on a node %s, but no " - "wvfactory_%s method was found in %s. (Or maybe they were " - "found but they returned None.)" % ( - viewName, node, viewName, - filterStack(self.viewStack))) - elif node.attributes.get("model"): - # If no "view" attribute was specified on the node, see if there - # is a IView adapter registerred for the model. - # First, see if the model is Componentized. - if isinstance(model, components.Componentized): - view = model.getAdapter(interfaces.IView) - if not view and hasattr(model, '__class__'): - view = interfaces.IView(model, None) - - return view - - def handleNode(self, request, node): - submodelName = node.attributes.get('model') - if submodelName is None: - submodelName = "" - model = self.getNodeModel(request, node, submodelName) - view = self.getNodeView(request, node, submodelName, model) - controller = self.getNodeController(request, node, submodelName, model) - if view or controller: - if model is None: - model = peek(self.modelStack) - if not view or not isinstance(view, View): - view = widgets.DefaultWidget(model) - - if not controller: - controller = input.DefaultHandler(model) - - prevView, stack = self.viewStack - while isinstance(prevView, widgets.DefaultWidget) and stack is not None: - prevView, stack = stack - if prevView is None: - prevMod = None - else: - prevMod = prevView.model - if model is not prevMod and not isinstance(view, widgets.DefaultWidget): - model.addView(view) - submodelList = [x.name for x in filterStack(self.modelStack) if x.name] - submodelList.reverse() - submodelName = '/'.join(submodelList) - if not getattr(view, 'submodel', None): - view.submodel = submodelName - - theId = node.attributes.get("id") - if self.livePage and not theId: - theId = "woven_id_%d" % id(view) - view.setupMethods.append(utils.createSetIdFunction(theId)) - view.outgoingId = theId - #print "SET AN ID", theId - self.subviews[theId] = view - view.parent = peek(self.viewStack) - view.parent.subviews[theId] = view - # If a Widget was constructed directly with a model that so far - # is not in modelspace, we should put it on the stack so other - # Widgets below this one can find it. - if view.model is not peek(self.modelStack): - self.modelStack = poke(self.modelStack, view.model) - - cParent = peek(self.controllerStack) - if controller._parent is None or cParent != controller: - controller._parent = cParent - - self.controllerStack = (controller, self.controllerStack) - self.viewStack = (view, self.viewStack) - - view.viewStack = self.viewStack - view.controllerStack = self.controllerStack - view.modelStack = self.modelStack - - view.setController(controller) - view.setNode(node) - - if not getattr(controller, 'submodel', None): - controller.setSubmodel(submodelName) - - controller.setView(view) - controller.setNode(node) - - controllerResult = controller.handle(request) - if controllerResult is not None: - ## It's a deferred - controller - self.outstandingCallbacks += 1 - controllerResult.addCallback( - self.handleControllerResults, - request, - node, - controller, - view) - controllerResult.addErrback(self.renderFailure, request) - else: - viewResult = view.generate(request, node) - returnNode = self.dispatchResult(request, node, viewResult) - self.handleNewNode(request, returnNode) - else: - self.controllerStack = (controller, self.controllerStack) - self.viewStack = (view, self.viewStack) - - def handleControllerResults(self, - controllerResult, request, node, controller, view): - """Handle a deferred from a controller. - """ - self.outstandingCallbacks -= 1 - if isinstance(controllerResult, defer.Deferred): - self.outstandingCallbacks += 1 - controllerResult.addCallback( - self.handleControllerResults, - request, - node, - controller, - view) - controllerResult.addErrback(self.renderFailure, request) - else: - viewResult = view.generate(request, node) - returnNode = self.dispatchResult(request, node, viewResult) - self.handleNewNode(request, returnNode) - return controllerResult - - def handleNewNode(self, request, returnNode): - if not isinstance(returnNode, defer.Deferred): - self.recurseChildren(request, returnNode) - else: - # TODO: Need to handle deferreds here? - pass - - def sendPage(self, request): - """ - Check to see if handlers recorded any errors before sending the page - """ - self.doneCallback(self, self.d, request) - - def setSubviewFactory(self, name, factory, setup=None, *args, **kwargs): - setattr(self, "wvfactory_" + name, lambda request, node, m: - factory(m, *args, **kwargs)) - if setup: - setattr(self, "wvupdate_" + name, setup) - - def __setitem__(self, key, value): - pass - - def unlinkViews(self): - #print "unlinking views" - self.model.removeView(self) - for key, value in self.subviews.items(): - value.unlinkViews() -# value.model.removeView(value) - - def dispatchResultCallback(self, result, request, node): - """Deal with a callback from a deferred, checking to see if it is - ok to send the page yet or not. - """ - self.outstandingCallbacks -= 1 - #node = self.dispatchResult(request, node, result) - #self.recurseChildren(request, node) - if not self.outstandingCallbacks: - self.sendPage(request) - return result - - def renderFailure(self, failure, request): - try: - xml = request.d.toprettyxml() - except: - xml = "" -# if not hasattr(request, 'channel'): -# log.msg("The request got away from me before I could render an error page.") -# log.err(failure) -# return failure - if not self.failed: - self.failed = 1 - if failure: - request.write("%s: %s\n" % (html.escape(str(failure.type)), html.escape(str(failure.value)))) - else: - request.write("Failure!\n") - utils.renderFailure(failure, request) - request.write("

                    Here is the partially processed DOM:

                    ") - request.write("\n
                    \n")
                    -            request.write(html.escape(xml))
                    -            request.write("\n
                    \n") - request.write("") - request.finish() - return failure - -class LiveView(View): - livePage = 1 - def wvfactory_webConduitGlue(self, request, node, m): - if request.getHeader("user-agent").count("MSIE"): - return View(m, templateFile="FlashConduitGlue.html") - else: - return View(m, templateFile="WebConduitGlue.html") - - def wvupdate_woven_flashConduitSessionView(self, request, wid, mod): - #print "updating flash thingie" - uid = request.getSession().uid - n = wid.templateNode - if n.attributes.has_key('src'): - n.attributes['src'] = n.attributes.get('src') + '?twisted_session=' + str(uid) - else: - n.attributes['value'] = n.attributes.get('value') + '?twisted_session=' + str(uid) - #print wid.templateNode.toxml() - - -#backwards compatibility -WView = View - - -def registerViewForModel(view, model): - """ - Registers `view' as an adapter of `model' for L{interfaces.IView}. - """ - components.registerAdapter(view, model, interfaces.IView) -# adapter = resource.IResource(model, None) -# if adapter is None and resource.IResource.providedBy(view): -# components.registerAdapter(view, model, resource.IResource) - - - -#sibling imports:: - -# If no widget/handler was found in the container controller or view, these -# modules will be searched. - -import input -import widgets - diff --git a/tools/buildbot/pylibs/twisted/web/woven/widgets.py b/tools/buildbot/pylibs/twisted/web/woven/widgets.py deleted file mode 100644 index 6028338..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/widgets.py +++ /dev/null @@ -1,1036 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_woven -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -# DOMWidgets - -from __future__ import nested_scopes - -import urllib -import warnings -from twisted.web.microdom import parseString, Element, Node -from twisted.web import domhelpers - - -#sibling imports -import model -import template -import view -import utils -import interfaces - -from twisted.python import components, failure -from twisted.python import reflect -from twisted.python import log -from twisted.internet import defer - -viewFactory = view.viewFactory -document = parseString("", caseInsensitive=0, preserveCase=0) - -missingPattern = Element("div", caseInsensitive=0, preserveCase=0) -missingPattern.setAttribute("style", "border: dashed red 1px; margin: 4px") - -""" -DOMWidgets are views which can be composed into bigger views. -""" - -DEBUG = 0 - -_RAISE = 1 - -class Dummy: - pass - -class Widget(view.View): - """ - A Widget wraps an object, its model, for display. The model can be a - simple Python object (string, list, etc.) or it can be an instance - of L{model.Model}. (The former case is for interface purposes, so that - the rest of the code does not have to treat simple objects differently - from Model instances.) - - If the model is-a Model, there are two possibilities: - - - we are being called to enable an operation on the model - - we are really being called to enable an operation on an attribute - of the model, which we will call the submodel - - @cvar tagName: The tag name of the element that this widget creates. If this - is None, then the original Node will be cloned. - @cvar wantsAllNotifications: Indicate that this widget wants to recieve every - change notification from the main model, not just notifications that affect - its model. - @ivar model: If the current model is an L{model.Model}, then the result of - model.getData(). Otherwise the original object itself. - """ - # wvupdate_xxx method signature: request, widget, data; returns None - - # Don't do lots of work setting up my stacks; they will be passed to me - setupStacks = 0 - - # Should we clear the node before we render the widget? - clearNode = 0 - - # If some code has to ask if a widget is livePage, the answer is yes - livePage = 1 - - tagName = None - def __init__(self, model = None, submodel = None, setup = None, controller = None, viewStack=None, *args, **kwargs): - """ - @type model: L{interfaces.IModel} - - @param submodel: see L{Widget.setSubmodel} - @type submodel: String - - @type setup: Callable - """ - self.errorFactory = Error - self.controller = controller - self.become = None - self._reset() - view.View.__init__(self, model) - self.node = None - self.templateNode = None - if submodel: - self.submodel = submodel - else: - self.submodel = "" - if setup: - self.setupMethods = [setup] - else: - self.setupMethods = [] - self.viewStack = viewStack - self.initialize(*args, **kwargs) - - def _reset(self): - self.attributes = {} - self.slots = {} - self._children = [] - - def initialize(self, *args, **kwargs): - """ - Use this method instead of __init__ to initialize your Widget, so you - don't have to deal with calling the __init__ of the superclass. - """ - pass - - def setSubmodel(self, submodel): - """ - I use the submodel to know which attribute in self.model I am responsible for - """ - self.submodel = submodel - - def getData(self, request=None): - """ - I have a model; however since I am a widget I am only responsible - for a portion of that model. This method returns the portion I am - responsible for. - - The return value of this may be a Deferred; if it is, then - L{setData} will be called once the result is available. - """ - return self.model.getData(request) - - def setData(self, request=None, data=None): - """ - If the return value of L{getData} is a Deferred, I am called - when the result of the Deferred is available. - """ - self.model.setData(request, data) - - def add(self, item): - """ - Add `item' to the children of the resultant DOM Node of this widget. - - @type item: A DOM node or L{Widget}. - """ - self._children.append(item) - - def appendChild(self, item): - """ - Add `item' to the children of the resultant DOM Node of this widget. - - @type item: A DOM node or L{Widget}. - """ - self._children.append(item) - - def insert(self, index, item): - """ - Insert `item' at `index' in the children list of the resultant DOM Node - of this widget. - - @type item: A DOM node or L{Widget}. - """ - self._children.insert(index, item) - - def setNode(self, node): - """ - Set a node for this widget to use instead of creating one programatically. - Useful for looking up a node in a template and using that. - """ - # self.templateNode should always be the original, unmutated - # node that was in the HTML template. - if self.templateNode == None: - self.templateNode = node - self.node = node - - def cleanNode(self, node): - """ - Do your part, prevent infinite recursion! - """ - if not DEBUG: - if node.attributes.has_key('model'): - del node.attributes['model'] - if node.attributes.has_key('view'): - del node.attributes['view'] - if node.attributes.has_key('controller'): - del node.attributes['controller'] - return node - - def generate(self, request, node): - data = self.getData(request) - if isinstance(data, defer.Deferred): - data.addCallback(self.setDataCallback, request, node) - data.addErrback(utils.renderFailure, request) - return data - return self._regenerate(request, node, data) - - def _regenerate(self, request, node, data): - self._reset() - self.setUp(request, node, data) - for setupMethod in self.setupMethods: - setupMethod(request, self, data) - # generateDOM should always get a reference to the - # templateNode from the original HTML - result = self.generateDOM(request, self.templateNode or node) - if DEBUG: - result.attributes['woven_class'] = reflect.qual(self.__class__) - return result - - def setDataCallback(self, result, request, node): - if isinstance(self.getData(request), defer.Deferred): - self.setData(request, result) - data = self.getData(request) - if isinstance(data, defer.Deferred): - import warnings - warnings.warn("%r has returned a Deferred multiple times for the " - "same request; this is a potential infinite loop." - % self.getData) - data.addCallback(self.setDataCallback, request, node) - data.addErrback(utils.renderFailure, request) - return data - - newNode = self._regenerate(request, node, result) - returnNode = self.dispatchResult(request, node, newNode) - # isinstance(Element) added because I was having problems with - # this code trying to call setAttribute on my RawTexts -radix 2003-5-28 - if hasattr(self, 'outgoingId') and isinstance(returnNode, Element): - returnNode.attributes['id'] = self.outgoingId - self.handleNewNode(request, returnNode) - self.handleOutstanding(request) - if self.subviews: - self.getTopModel().subviews.update(self.subviews) - self.controller.domChanged(request, self, returnNode) - - ## We need to return the result along the callback chain - ## so that any other views which added a setDataCallback - ## to the same deferred will get the correct data. - return result - - def setUp(self, request, node, data): - """ - Override this method to set up your Widget prior to generateDOM. This - is a good place to call methods like L{add}, L{insert}, L{__setitem__} - and L{__getitem__}. - - Overriding this method obsoletes overriding generateDOM directly, in - most cases. - - @type request: L{twisted.web.server.Request}. - @param node: The DOM node which this Widget is operating on. - @param data: The Model data this Widget is meant to operate upon. - """ - pass - - def generateDOM(self, request, node): - """ - @returns: A DOM Node to replace the Node in the template that this - Widget handles. This Node is created based on L{tagName}, - L{children}, and L{attributes} (You should populate these - in L{setUp}, probably). - """ - if self.become: - #print "becoming" - become = self.become - self.become = None - parent = node.parentNode - node.parentNode = None - old = node.cloneNode(1) - node.parentNode = parent - gen = become.generateDOM(request, node) - if old.attributes.has_key('model'): - del old.attributes['model'] - del old.attributes['controller'] - gen.appendChild(old) - self.node = gen - return gen - if DEBUG: - template = node.toxml() - log.msg(template) - if not self.tagName: - self.tagName = self.templateNode.tagName - if node is not self.templateNode or self.tagName != self.templateNode.tagName: - parent = node.parentNode - node = document.createElement(self.tagName, caseInsensitive=0, preserveCase=0) - node.parentNode = parent - else: - parentNode = node.parentNode - node.parentNode = None - if self.clearNode: - new = node.cloneNode(0) - else: - new = node.cloneNode(1) - node.parentNode = parentNode - node = self.cleanNode(new) - #print "NICE CLEAN NODE", node.toxml(), self._children - node.attributes.update(self.attributes) - for item in self._children: - if hasattr(item, 'generate'): - parentNode = node.parentNode - node.parentNode = None - item = item.generate(request, node.cloneNode(1)) - node.parentNode = parentNode - node.appendChild(item) - #print "WE GOT A NODE", node.toxml() - self.node = node - return self.node - - def modelChanged(self, payload): - request = payload.get('request', None) - if request is None: - request = Dummy() - request.d = document - oldNode = self.node - if payload.has_key(self.submodel): - data = payload[self.submodel] - else: - data = self.getData(request) - newNode = self._regenerate(request, oldNode, data) - returnNode = self.dispatchResult(request, oldNode, newNode) - # shot in the dark: this seems to make *my* code work. probably will - # break if returnNode returns a Deferred, as it's supposed to be able - # to do -glyph -# self.viewStack.push(self) -# self.controller.controllerStack.push(self.controller) - self.handleNewNode(request, returnNode) - self.handleOutstanding(request) - self.controller.domChanged(request, self, returnNode) - - def __setitem__(self, item, value): - """ - Convenience syntax for adding attributes to the resultant DOM Node of - this widget. - """ - assert value is not None - self.attributes[item] = value - - setAttribute = __setitem__ - - def __getitem__(self, item): - """ - Convenience syntax for getting an attribute from the resultant DOM Node - of this widget. - """ - return self.attributes[item] - - getAttribute = __getitem__ - - def setError(self, request, message): - """ - Convenience method for allowing a Controller to report an error to the - user. When this is called, a Widget of class self.errorFactory is instanciated - and set to self.become. When generate is subsequently called, self.become - will be responsible for mutating the DOM instead of this widget. - """ - #print "setError called", self - id = self.attributes.get('id', '') - - self.become = self.errorFactory(self.model, message) - self.become['id'] = id -# self.modelChanged({'request': request}) - - def getTopModel(self): - """Get a reference to this page's top model object. - """ - top = self.model - while top.parent is not None: - top = top.parent - return top - - def getAllPatterns(self, name, default=missingPattern, clone=1, deep=1): - """Get all nodes below this one which have a matching pattern attribute. - """ - if self.slots.has_key(name): - slots = self.slots[name] - else: - sm = self.submodel.split('/')[-1] - slots = domhelpers.locateNodes(self.templateNode, name + 'Of', sm) - if not slots: -# slots = domhelpers.locateNodes(self.templateNode, "pattern", name, noNesting=1) - matcher = lambda n, name=name: isinstance(n, Element) and \ - n.attributes.has_key("pattern") and n.attributes["pattern"] == name - recurseMatcher = lambda n: isinstance(n, Element) and not n.attributes.has_key("view") and not n.attributes.has_key('model') - slots = domhelpers.findNodesShallowOnMatch(self.templateNode, matcher, recurseMatcher) - if not slots: - msg = 'WARNING: No template nodes were found '\ - '(tagged %s="%s"'\ - ' or pattern="%s") for node %s (full submodel path %s)' % (name + "Of", - sm, name, self.templateNode, `self.submodel`) - if default is _RAISE: - raise Exception(msg) - if DEBUG: - warnings.warn(msg) - if default is missingPattern: - newNode = missingPattern.cloneNode(1) - newNode.appendChild(document.createTextNode(msg)) - return [newNode] - if default is None: - return None - return [default] - self.slots[name] = slots - if clone: - return [x.cloneNode(deep) for x in slots] - return slots - - def getPattern(self, name, default=missingPattern, clone=1, deep=1): - """Get a named slot from the incoming template node. Returns a copy - of the node and all its children. If there was more than one node with - the same slot identifier, they will be returned in a round-robin fashion. - """ - slots = self.getAllPatterns(name, default=default, clone=0) - if slots is None: - return None - slot = slots.pop(0) - slots.append(slot) - if clone: - parentNode = slot.parentNode - slot.parentNode = None - clone = slot.cloneNode(deep) - if clone.attributes.has_key('pattern'): - del clone.attributes['pattern'] - elif clone.attributes.has_key(name + 'Of'): - del clone.attributes[name + 'Of'] - slot.parentNode = parentNode - if DEBUG: - clone.attributes['ofPattern'] = name + 'Of' - clone.attributes['nameOf'] = self.submodel.split('/')[-1] - return clone - if DEBUG: - slot.attributes['ofPattern'] = name + 'Of' - slot.attributes['nameOf'] = self.submodel.split('/')[-1] - return slot - - def addUpdateMethod(self, updateMethod): - """Add a method to this widget that will be called when the widget - is being rendered. The signature for this method should be - updateMethod(request, widget, data) where widget will be the - instance you are calling addUpdateMethod on. - """ - self.setupMethods.append(updateMethod) - - def addEventHandler(self, eventName, handler, *args): - """Add an event handler to this widget. eventName is a string - indicating which javascript event handler should cause this - handler to fire. Handler is a callable that has the signature - handler(request, widget, *args). - """ - def handlerUpdateStep(request, widget, data): - extraArgs = '' - for x in args: - extraArgs += " ,'" + x.replace("'", "\\'") + "'" - widget[eventName] = "return woven_eventHandler('%s', this%s)" % (eventName, extraArgs) - setattr(self, 'wevent_' + eventName, handler) - self.addUpdateMethod(handlerUpdateStep) - - def onEvent(self, request, eventName, *args): - """Dispatch a client-side event to an event handler that was - registered using addEventHandler. - """ - eventHandler = getattr(self, 'wevent_' + eventName, None) - if eventHandler is None: - raise NotImplementedError("A client side '%s' event occurred," - " but there was no event handler registered on %s." % - (eventName, self)) - - eventHandler(request, self, *args) - - -class DefaultWidget(Widget): - def generate(self, request, node): - """ - By default, we just return the node unchanged - """ - self.cleanNode(node) - if self.become: - become = self.become - self.become = None - parent = node.parentNode - node.parentNode = None - old = node.cloneNode(1) - node.parentNode = parent - gen = become.generateDOM(request, node) - del old.attributes['model'] - gen.appendChild(self.cleanNode(old)) - return gen - return node - - def modelChanged(self, payload): - """We're not concerned if the model has changed. - """ - pass - - -class Attributes(Widget): - """Set attributes on a node. - - Assumes model is a dictionary of attributes. - """ - - def setUp(self, request, node, data): - for k, v in data.items(): - self[k] = v - - -class Text(Widget): - """ - A simple Widget that renders some text. - """ - def __init__(self, model, raw=0, clear=1, *args, **kwargs): - """ - @param model: The text to render. - @type model: A string or L{model.Model}. - @param raw: A boolean that specifies whether to render the text as - a L{domhelpers.RawText} or as a DOM TextNode. - """ - self.raw = raw - self.clearNode = clear - Widget.__init__(self, model, *args, **kwargs) - - def generate(self, request, node): - if self.templateNode is None: - if self.raw: - return domhelpers.RawText(str(self.getData(request))) - else: - return document.createTextNode(str(self.getData(request))) - return Widget.generate(self, request, node) - - def setUp(self, request, node, data): - if self.raw: - textNode = domhelpers.RawText(str(data)) - else: - textNode = document.createTextNode(str(data)) - self.appendChild(textNode) - - -class ParagraphText(Widget): - """ - Like a normal text widget, but it takes line breaks in the text and - formats them as HTML paragraphs. - """ - def setUp(self, request, node, data): - nSplit = data.split('\n') - for line in nSplit: - if line.strip(): - para = request.d.createElement('p', caseInsensitive=0, preserveCase=0) - para.appendChild(request.d.createTextNode(line)) - self.add(para) - -class Image(Widget): - """ - A simple Widget that creates an `img' tag. - """ - tagName = 'img' - border = '0' - def setUp(self, request, node, data): - self['border'] = self.border - self['src'] = data - - -class Error(Widget): - tagName = 'span' - def __init__(self, model, message="", *args, **kwargs): - Widget.__init__(self, model, *args, **kwargs) - self.message = message - - def generateDOM(self, request, node): - self['style'] = 'color: red' - self.add(Text(" " + self.message)) - return Widget.generateDOM(self, request, node) - - -class Div(Widget): - tagName = 'div' - - -class Span(Widget): - tagName = 'span' - - -class Br(Widget): - tagName = 'br' - - -class Input(Widget): - tagName = 'input' - def setSubmodel(self, submodel): - self.submodel = submodel - self['name'] = submodel - - def setUp(self, request, node, data): - if not self.attributes.has_key('name') and not node.attributes.get('name'): - if self.submodel: - id = self.submodel - else: - id = self.attributes.get('id', node.attributes.get('id')) - self['name'] = id - if data is None: - data = '' - if not self.attributes.has_key('value'): - self['value'] = str(data) - - -class CheckBox(Input): - def setUp(self, request, node, data): - self['type'] = 'checkbox' - Input.setUp(self, request, node, data) - - -class RadioButton(Input): - def setUp(self, request, node, data): - self['type'] = 'radio' - Input.setUp(self, request, node, data) - - -class File(Input): - def setUp(self, request, node, data): - self['type'] = 'file' - Input.setUp(self, request, node, data) - - -class Hidden(Input): - def setUp(self, request, node, data): - self['type'] = 'hidden' - Input.setUp(self, request, node, data) - - -class InputText(Input): - def setUp(self, request, node, data): - self['type'] = 'text' - Input.setUp(self, request, node, data) - - -class PasswordText(Input): - """ - I render a password input field. - """ - def setUp(self, request, node, data): - self['type'] = 'password' - Input.setUp(self, request, node, data) - - -class Button(Input): - def setUp(self, request, node, data): - self['type'] = 'button' - Input.setUp(self, request, node, data) - - -class Select(Input): - tagName = 'select' - - -class Option(Widget): - tagName = 'option' - def initialize(self): - self.text = '' - - def setText(self, text): - """ - Set the text to be displayed within the select menu. - """ - self.text = text - - def setValue(self, value): - self['value'] = str(value) - - def setUp(self, request, node, data): - self.add(Text(self.text or data)) - if data is None: - data = '' - if not self.attributes.has_key('value'): - self['value'] = str(data) - -class Anchor(Widget): - tagName = 'a' - trailingSlash = '' - def initialize(self): - self.baseHREF = '' - self.parameters = {} - self.raw = 0 - self.text = '' - - def setRaw(self, raw): - self.raw = raw - - def setLink(self, href): - self.baseHREF= href - - def setParameter(self, key, value): - self.parameters[key] = value - - def setText(self, text): - self.text = text - - def setUp(self, request, node, data): - href = self.baseHREF - params = urllib.urlencode(self.parameters) - if params: - href = href + '?' + params - self['href'] = href or str(data) + self.trailingSlash - if data is None: - data = "" - self.add(Text(self.text or data, self.raw, 0)) - - -class SubAnchor(Anchor): - def initialize(self): - warnings.warn( - "SubAnchor is deprecated, you might want either Anchor or DirectoryAnchor", - DeprecationWarning) - Anchor.initialize(self) - - - -class DirectoryAnchor(Anchor): - trailingSlash = '/' - - -def appendModel(newNode, modelName): - if newNode is None: return - curModel = newNode.attributes.get('model') - if curModel is None: - newModel = str(modelName) - else: - newModel = '/'.join((curModel, str(modelName))) - newNode.attributes['model'] = newModel - - -class List(Widget): - """ - I am a widget which knows how to generateDOM for a python list. - - A List should be specified in the template HTML as so:: - - |
                      - |
                    • This will be displayed if the list - | is empty.
                    • - |
                    • Foo
                    • - |
                    - - If you have nested lists, you may also do something like this:: - - | - | - | - | - | - | - | - | - |
                    AB
                    ***None***
                    All done!
                    - - Where blah is the name of a list on the model; eg:: - - | self.model.blah = ['foo', 'bar'] - - """ - tagName = None - defaultItemView = "DefaultWidget" - def generateDOM(self, request, node): - node = Widget.generateDOM(self, request, node) - listHeaders = self.getAllPatterns('listHeader', None) - listFooters = self.getAllPatterns('listFooter', None) - emptyLists = self.getAllPatterns('emptyList', None) - domhelpers.clearNode(node) - if listHeaders: - node.childNodes.extend(listHeaders) - for n in listHeaders: n.parentNode = node - data = self.getData(request) - if data: - self._iterateData(node, self.submodel, data) - elif emptyLists: - node.childNodes.extend(emptyLists) - for n in emptyLists: n.parentNode = node - if listFooters: - node.childNodes.extend(listFooters) - for n in listFooters: n.parentNode = node - return node - - def _iterateData(self, parentNode, submodel, data): - currentListItem = 0 - retVal = [None] * len(data) - for itemNum in range(len(data)): - # theory: by appending copies of the li node - # each node will be handled once we exit from - # here because handleNode will then recurse into - # the newly appended nodes - - newNode = self.getPattern('listItem') - if newNode.getAttribute('model') == '.': - newNode.removeAttribute('model') - elif not newNode.attributes.get("view"): - newNode.attributes["view"] = self.defaultItemView - appendModel(newNode, itemNum) - retVal[itemNum] = newNode - newNode.parentNode = parentNode -# parentNode.appendChild(newNode) - parentNode.childNodes.extend(retVal) - - -class KeyedList(List): - """ - I am a widget which knows how to display the values stored within a - Python dictionary.. - - A KeyedList should be specified in the template HTML as so:: - - |
                      - |
                    • This will be displayed if the list is - | empty.
                    • - |
                    • Foo
                    • - |
                    - - I can take advantage of C{listHeader}, C{listFooter} and C{emptyList} - items just as a L{List} can. - """ - def _iterateData(self, parentNode, submodel, data): - """ - """ - currentListItem = 0 - keys = data.keys() - # Keys may be a tuple, if this is not a true dictionary but a dictionary-like object - if hasattr(keys, 'sort'): - keys.sort() - for key in keys: - newNode = self.getPattern('keyedListItem') - if not newNode: - newNode = self.getPattern('item', _RAISE) - if newNode: - warnings.warn("itemOf= is deprecated, " - "please use listItemOf instead", - DeprecationWarning) - - appendModel(newNode, key) - if not newNode.attributes.get("view"): - newNode.attributes["view"] = "DefaultWidget" - parentNode.appendChild(newNode) - - -class ColumnList(Widget): - def __init__(self, model, columns=1, start=0, end=0, *args, **kwargs): - Widget.__init__(self, model, *args, **kwargs) - self.columns = columns - self.start = start - self.end = end - - def setColumns(self, columns): - self.columns = columns - - def setStart(self, start): - self.start = start - - def setEnd(self, end): - self.end = end - - def setUp(self, request, node, data): - pattern = self.getPattern('columnListRow', clone=0) - if self.end: - listSize = self.end - self.start - if listSize > len(data): - listSize = len(data) - else: - listSize = len(data) - for itemNum in range(listSize): - if itemNum % self.columns == 0: - row = self.getPattern('columnListRow') - domhelpers.clearNode(row) - node.appendChild(row) - - newNode = self.getPattern('columnListItem') - - appendModel(newNode, itemNum + self.start) - if not newNode.attributes.get("view"): - newNode.attributes["view"] = "DefaultWidget" - row.appendChild(newNode) - node.removeChild(pattern) - return node - - -class Bold(Widget): - tagName = 'b' - - -class Table(Widget): - tagName = 'table' - - -class Row(Widget): - tagName = 'tr' - - -class Cell(Widget): - tagName = 'td' - - -class RawText(Widget): - def generateDOM(self, request, node): - self.node = domhelpers.RawText(self.getData(request)) - return self.node - -from types import StringType - -class Link(Widget): - """A utility class for generating bar tags. - """ - tagName = 'a' - def setUp(self, request, node, data): - # TODO: we ought to support Deferreds here for both text and href! - if isinstance(data, StringType): - node.tagName = self.tagName - node.attributes["href"] = data - else: - data = self.model - txt = data.getSubmodel(request, "text").getData(request) - if not isinstance(txt, Node): - txt = document.createTextNode(txt) - lnk = data.getSubmodel(request, "href").getData(request) - self['href'] = lnk - node.tagName = self.tagName - domhelpers.clearNode(node) - node.appendChild(txt) - -class RootRelativeLink(Link): - """ - Just like a regular Link, only it makes the href relative to the - appRoot (that is, request.getRootURL()). - """ - def setUp(self, request, node, data): - # hack, hack: some juggling so I can type less and share more - # code with Link - st = isinstance(data, StringType) - if st: - data = request.getRootURL() + '/' + data - Link.setUp(self, request, node, data) - if not st: - self['href'] = request.getRootURL() + '/' + self['href'] - -class ExpandMacro(Widget): - """A Macro expansion widget modeled after the METAL expander - in ZPT/TAL/METAL. Usage: - - In the Page that is being rendered, place the ExpandMacro widget - on the node you want replaced with the Macro, and provide nodes - tagged with fill-slot= attributes which will fill slots in the Macro:: - - def wvfactory_myMacro(self, request, node, model): - return ExpandMacro( - model, - macroFile="MyMacro.html", - macroName="main") - -
                    - Hello - World -
                    - - Then, in your Macro template file ("MyMacro.html" in the above - example) designate a node as the macro node, and nodes - inside that as the slot nodes:: - -
                    -

                    , !

                    -
                    - """ - def __init__(self, model, macroTemplate = "", macroFile="", macroFileDirectory="", macroName="", **kwargs): - self.macroTemplate = macroTemplate - self.macroFile=macroFile - self.macroFileDirectory=macroFileDirectory - self.macroName=macroName - Widget.__init__(self, model, **kwargs) - - def generate(self, request, node): - if self.macroTemplate: - templ = view.View( - self.model, - template = self.macroTemplate).lookupTemplate(request) - else: - templ = view.View( - self.model, - templateFile=self.macroFile, - templateDirectory=self.macroFileDirectory).lookupTemplate(request) - - ## We are going to return the macro node from the metatemplate, - ## after replacing any slot= nodes in it with fill-slot= nodes from `node' - macrolist = domhelpers.locateNodes(templ.childNodes, "macro", self.macroName) - assert len(macrolist) == 1, ("No macro or more than " - "one macro named %s found." % self.macroName) - - macro = macrolist[0] - del macro.attributes['macro'] - slots = domhelpers.findElementsWithAttributeShallow(macro, "slot") - for slot in slots: - slotName = slot.attributes.get("slot") - fillerlist = domhelpers.locateNodes(node.childNodes, "fill-slot", slotName) - assert len(fillerlist) <= 1, "More than one fill-slot found with name %s" % slotName - if len(fillerlist): - filler = fillerlist[0] - filler.tagName = filler.endTagName = slot.tagName - del filler.attributes['fill-slot'] - del slot.attributes['slot'] - filler.attributes.update(slot.attributes) - slot.parentNode.replaceChild(filler, slot) - - return macro - -class DeferredWidget(Widget): - def setDataCallback(self, result, request, node): - model = result - view = None - if isinstance(model, components.Componentized): - view = model.getAdapter(interfaces.IView) - if not view and hasattr(model, '__class__'): - view = interfaces.IView(model, None) - - if view: - view["id"] = self.attributes.get('id', '') - view.templateNode = node - view.controller = self.controller - return view.setDataCallback(result, request, node) - else: - return Widget.setDataCallback(self, result, request, node) - - -class Break(Widget): - """Break into pdb when this widget is rendered. Mildly - useful for debugging template structure, model stacks, - etc. - """ - def setUp(self, request, node, data): - import pdb; pdb.set_trace() - - -view.registerViewForModel(Text, model.StringModel) -view.registerViewForModel(List, model.ListModel) -view.registerViewForModel(KeyedList, model.DictionaryModel) -view.registerViewForModel(Link, model.Link) -view.registerViewForModel(DeferredWidget, model.DeferredWrapper) diff --git a/tools/buildbot/pylibs/twisted/web/xmlrpc.py b/tools/buildbot/pylibs/twisted/web/xmlrpc.py deleted file mode 100644 index 70be322..0000000 --- a/tools/buildbot/pylibs/twisted/web/xmlrpc.py +++ /dev/null @@ -1,414 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_xmlrpc -*- -# -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -A generic resource for publishing objects via XML-RPC. - -Requires xmlrpclib (comes standard with Python 2.2 and later, otherwise can be -downloaded from http://www.pythonware.com/products/xmlrpc/). - -Maintainer: U{Itamar Shtull-Trauring} -""" -from __future__ import nested_scopes - -__version__ = "$Revision: 1.32 $"[11:-2] - -# System Imports -import xmlrpclib -import urlparse - -# Sibling Imports -from twisted.web import resource, server, http -from twisted.internet import defer, protocol, reactor -from twisted.python import log, reflect, failure - -# These are deprecated, use the class level definitions -NOT_FOUND = 8001 -FAILURE = 8002 - - -# Useful so people don't need to import xmlrpclib directly -Fault = xmlrpclib.Fault -Binary = xmlrpclib.Binary -Boolean = xmlrpclib.Boolean -DateTime = xmlrpclib.DateTime - -class NoSuchFunction(Fault): - """ - There is no function by the given name. - """ - - -class Handler: - """ - Handle a XML-RPC request and store the state for a request in progress. - - Override the run() method and return result using self.result, - a Deferred. - - We require this class since we're not using threads, so we can't - encapsulate state in a running function if we're going to have - to wait for results. - - For example, lets say we want to authenticate against twisted.cred, - run a LDAP query and then pass its result to a database query, all - as a result of a single XML-RPC command. We'd use a Handler instance - to store the state of the running command. - """ - - def __init__(self, resource, *args): - self.resource = resource # the XML-RPC resource we are connected to - self.result = defer.Deferred() - self.run(*args) - - def run(self, *args): - # event driven equivalent of 'raise UnimplementedError' - self.result.errback( - NotImplementedError("Implement run() in subclasses")) - - -class XMLRPC(resource.Resource): - """ - A resource that implements XML-RPC. - - You probably want to connect this to '/RPC2'. - - Methods published can return XML-RPC serializable results, Faults, - Binary, Boolean, DateTime, Deferreds, or Handler instances. - - By default methods beginning with 'xmlrpc_' are published. - - Sub-handlers for prefixed methods (e.g., system.listMethods) - can be added with putSubHandler. By default, prefixes are - separated with a '.'. Override self.separator to change this. - """ - - # Error codes for Twisted, if they conflict with yours then - # modify them at runtime. - NOT_FOUND = 8001 - FAILURE = 8002 - - isLeaf = 1 - separator = '.' - allowedMethods = ('POST',) - - def __init__(self, allowNone=False): - resource.Resource.__init__(self) - self.subHandlers = {} - self.allowNone = allowNone - - def putSubHandler(self, prefix, handler): - self.subHandlers[prefix] = handler - - def getSubHandler(self, prefix): - return self.subHandlers.get(prefix, None) - - def getSubHandlerPrefixes(self): - return self.subHandlers.keys() - - def render_POST(self, request): - request.content.seek(0, 0) - request.setHeader("content-type", "text/xml") - try: - args, functionPath = xmlrpclib.loads(request.content.read()) - except Exception, e: - f = Fault(self.FAILURE, "Can't deserialize input: %s" % (e,)) - self._cbRender(f, request) - else: - try: - function = self._getFunction(functionPath) - except Fault, f: - self._cbRender(f, request) - else: - defer.maybeDeferred(function, *args).addErrback( - self._ebRender - ).addCallback( - self._cbRender, request - ) - return server.NOT_DONE_YET - - def _cbRender(self, result, request): - if isinstance(result, Handler): - result = result.result - if not isinstance(result, Fault): - result = (result,) - try: - s = xmlrpclib.dumps(result, methodresponse=True, - allow_none=self.allowNone) - except Exception, e: - f = Fault(self.FAILURE, "Can't serialize output: %s" % (e,)) - s = xmlrpclib.dumps(f, methodresponse=True, - allow_none=self.allowNone) - request.setHeader("content-length", str(len(s))) - request.write(s) - request.finish() - - def _ebRender(self, failure): - if isinstance(failure.value, Fault): - return failure.value - log.err(failure) - return Fault(self.FAILURE, "error") - - def _getFunction(self, functionPath): - """ - Given a string, return a function, or raise NoSuchFunction. - - This returned function will be called, and should return the result - of the call, a Deferred, or a Fault instance. - - Override in subclasses if you want your own policy. The default - policy is that given functionPath 'foo', return the method at - self.xmlrpc_foo, i.e. getattr(self, "xmlrpc_" + functionPath). - If functionPath contains self.separator, the sub-handler for - the initial prefix is used to search for the remaining path. - """ - if functionPath.find(self.separator) != -1: - prefix, functionPath = functionPath.split(self.separator, 1) - handler = self.getSubHandler(prefix) - if handler is None: - raise NoSuchFunction(self.NOT_FOUND, - "no such subHandler %s" % prefix) - return handler._getFunction(functionPath) - - f = getattr(self, "xmlrpc_%s" % functionPath, None) - if not f: - raise NoSuchFunction(self.NOT_FOUND, - "function %s not found" % functionPath) - elif not callable(f): - raise NoSuchFunction(self.NOT_FOUND, - "function %s not callable" % functionPath) - else: - return f - - def _listFunctions(self): - """ - Return a list of the names of all xmlrpc methods. - """ - return reflect.prefixedMethodNames(self.__class__, 'xmlrpc_') - - -class XMLRPCIntrospection(XMLRPC): - """ - Implement the XML-RPC Introspection API. - - By default, the methodHelp method returns the 'help' method attribute, - if it exists, otherwise the __doc__ method attribute, if it exists, - otherwise the empty string. - - To enable the methodSignature method, add a 'signature' method attribute - containing a list of lists. See methodSignature's documentation for the - format. Note the type strings should be XML-RPC types, not Python types. - """ - - def __init__(self, parent): - """ - Implement Introspection support for an XMLRPC server. - - @param parent: the XMLRPC server to add Introspection support to. - """ - - XMLRPC.__init__(self) - self._xmlrpc_parent = parent - - def xmlrpc_listMethods(self): - """ - Return a list of the method names implemented by this server. - """ - functions = [] - todo = [(self._xmlrpc_parent, '')] - while todo: - obj, prefix = todo.pop(0) - functions.extend([prefix + name for name in obj._listFunctions()]) - todo.extend([ (obj.getSubHandler(name), - prefix + name + obj.separator) - for name in obj.getSubHandlerPrefixes() ]) - return functions - - xmlrpc_listMethods.signature = [['array']] - - def xmlrpc_methodHelp(self, method): - """ - Return a documentation string describing the use of the given method. - """ - method = self._xmlrpc_parent._getFunction(method) - return (getattr(method, 'help', None) - or getattr(method, '__doc__', None) or '') - - xmlrpc_methodHelp.signature = [['string', 'string']] - - def xmlrpc_methodSignature(self, method): - """ - Return a list of type signatures. - - Each type signature is a list of the form [rtype, type1, type2, ...] - where rtype is the return type and typeN is the type of the Nth - argument. If no signature information is available, the empty - string is returned. - """ - method = self._xmlrpc_parent._getFunction(method) - return getattr(method, 'signature', None) or '' - - xmlrpc_methodSignature.signature = [['array', 'string'], - ['string', 'string']] - - -def addIntrospection(xmlrpc): - """ - Add Introspection support to an XMLRPC server. - - @param xmlrpc: The xmlrpc server to add Introspection support to. - """ - xmlrpc.putSubHandler('system', XMLRPCIntrospection(xmlrpc)) - - -class QueryProtocol(http.HTTPClient): - - def connectionMade(self): - self.sendCommand('POST', self.factory.path) - self.sendHeader('User-Agent', 'Twisted/XMLRPClib') - self.sendHeader('Host', self.factory.host) - self.sendHeader('Content-type', 'text/xml') - self.sendHeader('Content-length', str(len(self.factory.payload))) - if self.factory.user: - auth = '%s:%s' % (self.factory.user, self.factory.password) - auth = auth.encode('base64').strip() - self.sendHeader('Authorization', 'Basic %s' % (auth,)) - self.endHeaders() - self.transport.write(self.factory.payload) - - def handleStatus(self, version, status, message): - if status != '200': - self.factory.badStatus(status, message) - - def handleResponse(self, contents): - self.factory.parseResponse(contents) - - -payloadTemplate = """ - -%s -%s - -""" - - -class _QueryFactory(protocol.ClientFactory): - - deferred = None - protocol = QueryProtocol - - def __init__(self, path, host, method, user=None, password=None, - allowNone=False, args=()): - self.path, self.host = path, host - self.user, self.password = user, password - self.payload = payloadTemplate % (method, - xmlrpclib.dumps(args, allow_none=allowNone)) - self.deferred = defer.Deferred() - - def parseResponse(self, contents): - if not self.deferred: - return - try: - response = xmlrpclib.loads(contents) - except: - deferred, self.deferred = self.deferred, None - deferred.errback(failure.Failure()) - else: - deferred, self.deferred = self.deferred, None - deferred.callback(response[0][0]) - - def clientConnectionLost(self, _, reason): - if self.deferred is not None: - deferred, self.deferred = self.deferred, None - deferred.errback(reason) - - clientConnectionFailed = clientConnectionLost - - def badStatus(self, status, message): - deferred, self.deferred = self.deferred, None - deferred.errback(ValueError(status, message)) - - - -class Proxy: - """ - A Proxy for making remote XML-RPC calls. - - Pass the URL of the remote XML-RPC server to the constructor. - - Use proxy.callRemote('foobar', *args) to call remote method - 'foobar' with *args. - - @ivar queryFactory: object returning a factory for XML-RPC protocol. Mainly - useful for tests. - """ - queryFactory = _QueryFactory - - def __init__(self, url, user=None, password=None, allowNone=False): - """ - @type url: C{str} - @param url: The URL to which to post method calls. Calls will be made - over SSL if the scheme is HTTPS. If netloc contains username or - password information, these will be used to authenticate, as long as - the C{user} and C{password} arguments are not specified. - - @type user: C{str} or None - @param user: The username with which to authenticate with the server - when making calls. If specified, overrides any username information - embedded in C{url}. If not specified, a value may be taken from C{url} - if present. - - @type password: C{str} or None - @param password: The password with which to authenticate with the - server when making calls. If specified, overrides any password - information embedded in C{url}. If not specified, a value may be taken - from C{url} if present. - - @type allowNone: C{bool} or None - @param allowNone: allow the use of None values in parameters. It's - passed to the underlying xmlrpclib implementation. Default to False. - """ - scheme, netloc, path, params, query, fragment = urlparse.urlparse(url) - netlocParts = netloc.split('@') - if len(netlocParts) == 2: - userpass = netlocParts.pop(0).split(':') - self.user = userpass.pop(0) - try: - self.password = userpass.pop(0) - except: - self.password = None - else: - self.user = self.password = None - hostport = netlocParts[0].split(':') - self.host = hostport.pop(0) - try: - self.port = int(hostport.pop(0)) - except: - self.port = None - self.path = path - if self.path in ['', None]: - self.path = '/' - self.secure = (scheme == 'https') - if user is not None: - self.user = user - if password is not None: - self.password = password - self.allowNone = allowNone - - def callRemote(self, method, *args): - factory = self.queryFactory( - self.path, self.host, method, self.user, - self.password, self.allowNone, args) - if self.secure: - from twisted.internet import ssl - reactor.connectSSL(self.host, self.port or 443, - factory, ssl.ClientContextFactory()) - else: - reactor.connectTCP(self.host, self.port or 80, factory) - return factory.deferred - -__all__ = ["XMLRPC", "Handler", "NoSuchFunction", "Fault", "Proxy"] - diff --git a/tools/buildbot/pylibs/twisted/words/__init__.py b/tools/buildbot/pylibs/twisted/words/__init__.py deleted file mode 100644 index 725af4c..0000000 --- a/tools/buildbot/pylibs/twisted/words/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -# -*- test-case-name: twisted.words.test -*- -# Copyright (c) 2001-2005 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Twisted Words: a Twisted Chat service. -""" - -from twisted.words._version import version -__version__ = version.short() diff --git a/tools/buildbot/pylibs/twisted/words/_version.py b/tools/buildbot/pylibs/twisted/words/_version.py deleted file mode 100644 index 2dbf234..0000000 --- a/tools/buildbot/pylibs/twisted/words/_version.py +++ /dev/null @@ -1,3 +0,0 @@ -# This is an auto-generated file. Do not edit it. -from twisted.python import versions -version = versions.Version('twisted.words', 8, 1, 0) diff --git a/tools/buildbot/pylibs/twisted/words/ewords.py b/tools/buildbot/pylibs/twisted/words/ewords.py deleted file mode 100644 index 5aa9345..0000000 --- a/tools/buildbot/pylibs/twisted/words/ewords.py +++ /dev/null @@ -1,34 +0,0 @@ -# -*- test-case-name: twisted.words.test -*- -# Copyright (c) 2001-2005 Twisted Matrix Laboratories. -# See LICENSE for details. - -"""Exception definitions for Words -""" - -class WordsError(Exception): - def __str__(self): - return self.__class__.__name__ + ': ' + Exception.__str__(self) - -class NoSuchUser(WordsError): - pass - - -class DuplicateUser(WordsError): - pass - - -class NoSuchGroup(WordsError): - pass - - -class DuplicateGroup(WordsError): - pass - - -class AlreadyLoggedIn(WordsError): - pass - -__all__ = [ - 'WordsError', 'NoSuchUser', 'DuplicateUser', - 'NoSuchGroup', 'DuplicateGroup', 'AlreadyLoggedIn', - ] diff --git a/tools/buildbot/pylibs/twisted/words/im/__init__.py b/tools/buildbot/pylibs/twisted/words/im/__init__.py deleted file mode 100644 index 9f511b7..0000000 --- a/tools/buildbot/pylibs/twisted/words/im/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Instance Messenger, Pan-protocol chat client.""" - -import warnings -warnings.warn("twisted.im will be undergoing a rewrite at some point in the future.") diff --git a/tools/buildbot/pylibs/twisted/words/im/baseaccount.py b/tools/buildbot/pylibs/twisted/words/im/baseaccount.py deleted file mode 100644 index 4cbe669..0000000 --- a/tools/buildbot/pylibs/twisted/words/im/baseaccount.py +++ /dev/null @@ -1,62 +0,0 @@ -# -*- Python -*- -# -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - - -class AccountManager: - """I am responsible for managing a user's accounts. - - That is, remembering what accounts are available, their settings, - adding and removal of accounts, etc. - - @ivar accounts: A collection of available accounts. - @type accounts: mapping of strings to L{Account}s. - """ - def __init__(self): - self.accounts = {} - - def getSnapShot(self): - """A snapshot of all the accounts and their status. - - @returns: A list of tuples, each of the form - (string:accountName, boolean:isOnline, - boolean:autoLogin, string:gatewayType) - """ - data = [] - for account in self.accounts.values(): - data.append((account.accountName, account.isOnline(), - account.autoLogin, account.gatewayType)) - return data - - def isEmpty(self): - return len(self.accounts) == 0 - - def getConnectionInfo(self): - connectioninfo = [] - for account in self.accounts.values(): - connectioninfo.append(account.isOnline()) - return connectioninfo - - def addAccount(self, account): - self.accounts[account.accountName] = account - - def delAccount(self, accountName): - del self.accounts[accountName] - - def connect(self, accountName, chatui): - """ - @returntype: Deferred L{interfaces.IClient} - """ - return self.accounts[accountName].logOn(chatui) - - def disconnect(self, accountName): - pass - #self.accounts[accountName].logOff() - not yet implemented - - def quit(self): - pass - #for account in self.accounts.values(): - # account.logOff() - not yet implemented diff --git a/tools/buildbot/pylibs/twisted/words/im/basechat.py b/tools/buildbot/pylibs/twisted/words/im/basechat.py deleted file mode 100644 index 4555bef..0000000 --- a/tools/buildbot/pylibs/twisted/words/im/basechat.py +++ /dev/null @@ -1,316 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -"""Base classes for Instance Messenger clients.""" - -from twisted.words.im.locals import OFFLINE, ONLINE, AWAY - -class ContactsList: - """A GUI object that displays a contacts list""" - def __init__(self, chatui): - """ - @param chatui: ??? - @type chatui: L{ChatUI} - """ - self.chatui = chatui - self.contacts = {} - self.onlineContacts = {} - self.clients = [] - - def setContactStatus(self, person): - """Inform the user that a person's status has changed. - - @type person: L{Person} - """ - if not self.contacts.has_key(person.name): - self.contacts[person.name] = person - if not self.onlineContacts.has_key(person.name) and \ - (person.status == ONLINE or person.status == AWAY): - self.onlineContacts[person.name] = person - if self.onlineContacts.has_key(person.name) and \ - person.status == OFFLINE: - del self.onlineContacts[person.name] - - def registerAccountClient(self, client): - """Notify the user that an account client has been signed on to. - - @type client: L{Client} - """ - if not client in self.clients: - self.clients.append(client) - - def unregisterAccountClient(self, client): - """Notify the user that an account client has been signed off - or disconnected from. - - @type client: L{Client} - """ - if client in self.clients: - self.clients.remove(client) - - def contactChangedNick(self, person, newnick): - oldname = person.name - if self.contacts.has_key(oldname): - del self.contacts[oldname] - person.name = newnick - self.contacts[newnick] = person - if self.onlineContacts.has_key(oldname): - del self.onlineContacts[oldname] - self.onlineContacts[newnick] = person - - -class Conversation: - """A GUI window of a conversation with a specific person""" - def __init__(self, person, chatui): - """ - @type person: L{Person} - @type chatui: L{ChatUI} - """ - self.chatui = chatui - self.person = person - - def show(self): - """Displays the ConversationWindow""" - raise NotImplementedError("Subclasses must implement this method") - - def hide(self): - """Hides the ConversationWindow""" - raise NotImplementedError("Subclasses must implement this method") - - def sendText(self, text): - """Sends text to the person with whom the user is conversing. - - @returntype: L{Deferred} - """ - self.person.sendMessage(text, None) - - def showMessage(self, text, metadata=None): - """Display a message sent from the person with whom she is conversing - - @type text: string - @type metadata: dict - """ - raise NotImplementedError("Subclasses must implement this method") - - def contactChangedNick(self, person, newnick): - """Change a person's name. - - @type person: L{Person} - @type newnick: string - """ - self.person.name = newnick - - -class GroupConversation: - """A conversation with a group of people.""" - def __init__(self, group, chatui): - """ - @type group: L{Group} - @param chatui: ??? - @type chatui: L{ChatUI} - """ - self.chatui = chatui - self.group = group - self.members = [] - - def show(self): - """Displays the GroupConversationWindow.""" - raise NotImplementedError("Subclasses must implement this method") - - def hide(self): - """Hides the GroupConversationWindow.""" - raise NotImplementedError("Subclasses must implement this method") - - def sendText(self, text): - """Sends text to the group. - - @type text: string - @returntype: L{Deferred} - """ - self.group.sendGroupMessage(text, None) - - def showGroupMessage(self, sender, text, metadata=None): - """Displays to the user a message sent to this group from the given sender - @type sender: string (XXX: Not Person?) - @type text: string - @type metadata: dict - """ - raise NotImplementedError("Subclasses must implement this method") - - def setGroupMembers(self, members): - """Sets the list of members in the group and displays it to the user - """ - self.members = members - - def setTopic(self, topic, author): - """Displays the topic (from the server) for the group conversation window - - @type topic: string - @type author: string (XXX: Not Person?) - """ - raise NotImplementedError("Subclasses must implement this method") - - def memberJoined(self, member): - """Adds the given member to the list of members in the group conversation - and displays this to the user - - @type member: string (XXX: Not Person?) - """ - if not member in self.members: - self.members.append(member) - - def memberChangedNick(self, oldnick, newnick): - """Changes the oldnick in the list of members to newnick and displays this - change to the user - - @type oldnick: string - @type newnick: string - """ - if oldnick in self.members: - self.members.remove(oldnick) - self.members.append(newnick) - #self.chatui.contactChangedNick(oldnick, newnick) - - def memberLeft(self, member): - """Deletes the given member from the list of members in the group - conversation and displays the change to the user - - @type member: string - """ - if member in self.members: - self.members.remove(member) - - -class ChatUI: - """A GUI chat client""" - def __init__(self): - self.conversations = {} # cache of all direct windows - self.groupConversations = {} # cache of all group windows - self.persons = {} # keys are (name, client) - self.groups = {} # cache of all groups - self.onlineClients = [] # list of message sources currently online - self.contactsList = ContactsList(self) - - def registerAccountClient(self, client): - """Notifies user that an account has been signed on to. - - @type client: L{Client} - @returns: client, so that I may be used in a callback chain - """ - print "signing onto", client.accountName - self.onlineClients.append(client) - self.contactsList.registerAccountClient(client) - return client - - def unregisterAccountClient(self, client): - """Notifies user that an account has been signed off or disconnected - - @type client: L{Client} - """ - print "signing off from", client.accountName - self.onlineClients.remove(client) - self.contactsList.unregisterAccountClient(client) - - def getContactsList(self): - """ - @returntype: L{ContactsList} - """ - return self.contactsList - - def getConversation(self, person, Class=Conversation, stayHidden=0): - """For the given person object, returns the conversation window - or creates and returns a new conversation window if one does not exist. - - @type person: L{Person} - @type Class: L{Conversation} class - @type stayHidden: boolean - - @returntype: L{Conversation} - """ - conv = self.conversations.get(person) - if not conv: - conv = Class(person, self) - self.conversations[person] = conv - if stayHidden: - conv.hide() - else: - conv.show() - return conv - - def getGroupConversation(self,group,Class=GroupConversation,stayHidden=0): - """For the given group object, returns the group conversation window or - creates and returns a new group conversation window if it doesn't exist - - @type group: L{Group} - @type Class: L{Conversation} class - @type stayHidden: boolean - - @returntype: L{GroupConversation} - """ - conv = self.groupConversations.get(group) - if not conv: - conv = Class(group, self) - self.groupConversations[group] = conv - if stayHidden: - conv.hide() - else: - conv.show() - return conv - - def getPerson(self, name, client): - """For the given name and account client, returns the instance of the - AbstractPerson subclass, or creates and returns a new AbstractPerson - subclass of the type Class - - @type name: string - @type client: L{Client} - - @returntype: L{Person} - """ - account = client.account - p = self.persons.get((name, account)) - if not p: - p = account.getPerson(name) - self.persons[name, account] = p - return p - - def getGroup(self, name, client): - """For the given name and account client, returns the instance of the - AbstractGroup subclass, or creates and returns a new AbstractGroup - subclass of the type Class - - @type name: string - @type client: L{Client} - - @returntype: L{Group} - """ - # I accept 'client' instead of 'account' in my signature for - # backwards compatibility. (Groups changed to be Account-oriented - # in CVS revision 1.8.) - account = client.account - g = self.groups.get((name, account)) - if not g: - g = account.getGroup(name) - self.groups[name, account] = g - return g - - def contactChangedNick(self, oldnick, newnick): - """For the given person, changes the person's name to newnick, and - tells the contact list and any conversation windows with that person - to change as well. - - @type oldnick: string - @type newnick: string - """ - if self.persons.has_key((person.name, person.account)): - conv = self.conversations.get(person) - if conv: - conv.contactChangedNick(person, newnick) - - self.contactsList.contactChangedNick(person, newnick) - - del self.persons[person.name, person.account] - person.name = newnick - self.persons[person.name, person.account] = person diff --git a/tools/buildbot/pylibs/twisted/words/im/basesupport.py b/tools/buildbot/pylibs/twisted/words/im/basesupport.py deleted file mode 100644 index 1b2a2a9..0000000 --- a/tools/buildbot/pylibs/twisted/words/im/basesupport.py +++ /dev/null @@ -1,270 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -"""Instance Messenger base classes for protocol support. - -You will find these useful if you're adding a new protocol to IM. -""" - -# Abstract representation of chat "model" classes - -from twisted.words.im.locals import ONLINE, OFFLINE, OfflineError -from twisted.words.im import interfaces - -from twisted.internet.protocol import Protocol - -from twisted.python.reflect import prefixedMethods -from twisted.persisted import styles - -from twisted.internet import error - -class AbstractGroup: - def __init__(self, name, account): - self.name = name - self.account = account - - def getGroupCommands(self): - """finds group commands - - these commands are methods on me that start with imgroup_; they are - called with no arguments - """ - return prefixedMethods(self, "imgroup_") - - def getTargetCommands(self, target): - """finds group commands - - these commands are methods on me that start with imgroup_; they are - called with a user present within this room as an argument - - you may want to override this in your group in order to filter for - appropriate commands on the given user - """ - return prefixedMethods(self, "imtarget_") - - def join(self): - if not self.account.client: - raise OfflineError - self.account.client.joinGroup(self.name) - - def leave(self): - if not self.account.client: - raise OfflineError - self.account.client.leaveGroup(self.name) - - def __repr__(self): - return '<%s %r>' % (self.__class__, self.name) - - def __str__(self): - return '%s@%s' % (self.name, self.account.accountName) - -class AbstractPerson: - def __init__(self, name, baseAccount): - self.name = name - self.account = baseAccount - self.status = OFFLINE - - def getPersonCommands(self): - """finds person commands - - these commands are methods on me that start with imperson_; they are - called with no arguments - """ - return prefixedMethods(self, "imperson_") - - def getIdleTime(self): - """ - Returns a string. - """ - return '--' - - def __repr__(self): - return '<%s %r/%s>' % (self.__class__, self.name, self.status) - - def __str__(self): - return '%s@%s' % (self.name, self.account.accountName) - -class AbstractClientMixin: - """Designed to be mixed in to a Protocol implementing class. - - Inherit from me first. - - @ivar _logonDeferred: Fired when I am done logging in. - """ - def __init__(self, account, chatui, logonDeferred): - for base in self.__class__.__bases__: - if issubclass(base, Protocol): - self.__class__._protoBase = base - break - else: - pass - self.account = account - self.chat = chatui - self._logonDeferred = logonDeferred - - def connectionMade(self): - self._protoBase.connectionMade(self) - - def connectionLost(self, reason): - self.account._clientLost(self, reason) - self.unregisterAsAccountClient() - return self._protoBase.connectionLost(self, reason) - - def unregisterAsAccountClient(self): - """Tell the chat UI that I have `signed off'. - """ - self.chat.unregisterAccountClient(self) - - -class AbstractAccount(styles.Versioned): - """Base class for Accounts. - - I am the start of an implementation of L{IAccount}, I - implement L{isOnline} and most of L{logOn}, though you'll need to implement - L{_startLogOn} in a subclass. - - @cvar _groupFactory: A Callable that will return a L{IGroup} appropriate - for this account type. - @cvar _personFactory: A Callable that will return a L{IPerson} appropriate - for this account type. - - @type _isConnecting: boolean - @ivar _isConnecting: Whether I am in the process of establishing a - connection to the server. - @type _isOnline: boolean - @ivar _isOnline: Whether I am currently on-line with the server. - - @ivar accountName: - @ivar autoLogin: - @ivar username: - @ivar password: - @ivar host: - @ivar port: - """ - - _isOnline = 0 - _isConnecting = 0 - client = None - - _groupFactory = AbstractGroup - _personFactory = AbstractPerson - - persistanceVersion = 2 - - def __init__(self, accountName, autoLogin, username, password, host, port): - self.accountName = accountName - self.autoLogin = autoLogin - self.username = username - self.password = password - self.host = host - self.port = port - - self._groups = {} - self._persons = {} - - def upgrateToVersion2(self): - # Added in CVS revision 1.16. - for k in ('_groups', '_persons'): - if not hasattr(self, k): - setattr(self, k, {}) - - def __getstate__(self): - state = styles.Versioned.__getstate__(self) - for k in ('client', '_isOnline', '_isConnecting'): - try: - del state[k] - except KeyError: - pass - return state - - def isOnline(self): - return self._isOnline - - def logOn(self, chatui): - """Log on to this account. - - Takes care to not start a connection if a connection is - already in progress. You will need to implement - L{_startLogOn} for this to work, and it would be a good idea - to override L{_loginFailed} too. - - @returntype: Deferred L{interfaces.IClient} - """ - if (not self._isConnecting) and (not self._isOnline): - self._isConnecting = 1 - d = self._startLogOn(chatui) - d.addCallback(self._cb_logOn) - # if chatui is not None: - # (I don't particularly like having to pass chatUI to this function, - # but we haven't factored it out yet.) - d.addCallback(chatui.registerAccountClient) - d.addErrback(self._loginFailed) - return d - else: - raise error.ConnectError("Connection in progress") - - def getGroup(self, name): - """Group factory. - - @param name: Name of the group on this account. - @type name: string - """ - group = self._groups.get(name) - if group is None: - group = self._groupFactory(name, self) - self._groups[name] = group - return group - - def getPerson(self, name): - """Person factory. - - @param name: Name of the person on this account. - @type name: string - """ - person = self._persons.get(name) - if person is None: - person = self._personFactory(name, self) - self._persons[name] = person - return person - - def _startLogOn(self, chatui): - """Start the sign on process. - - Factored out of L{logOn}. - - @returntype: Deferred L{interfaces.IClient} - """ - raise NotImplementedError() - - def _cb_logOn(self, client): - self._isConnecting = 0 - self._isOnline = 1 - self.client = client - return client - - def _loginFailed(self, reason): - """Errorback for L{logOn}. - - @type reason: Failure - - @returns: I{reason}, for further processing in the callback chain. - @returntype: Failure - """ - self._isConnecting = 0 - self._isOnline = 0 # just in case - return reason - - def _clientLost(self, client, reason): - self.client = None - self._isConnecting = 0 - self._isOnline = 0 - return reason - - def __repr__(self): - return "<%s: %s (%s@%s:%s)>" % (self.__class__, - self.accountName, - self.username, - self.host, - self.port) diff --git a/tools/buildbot/pylibs/twisted/words/im/gtkaccount.py b/tools/buildbot/pylibs/twisted/words/im/gtkaccount.py deleted file mode 100644 index 61b52d7..0000000 --- a/tools/buildbot/pylibs/twisted/words/im/gtkaccount.py +++ /dev/null @@ -1,224 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -try: - import cPickle as pickle -except ImportError: - import pickle - -import gtk - -from twisted.words.im.gtkcommon import GLADE_FILE, SETTINGS_FILE, autoConnectMethods,\ - openGlade - -from twisted.words.im import gtkchat - -### This generic stuff uses the word "account" in a very different way -- chat -### accounts are potential sources of messages, InstanceMessenger accounts are -### individual network connections. - -class AccountManager: - def __init__(self): - self.xml = openGlade(GLADE_FILE, root="MainIMWindow") - self.chatui = gtkchat.GtkChatClientUI(self.xml) - self.chatui._accountmanager = self # TODO: clean this up... it's used in gtkchat - print self.xml._o - autoConnectMethods(self, self.chatui.theContactsList) - self.widget = self.xml.get_widget("AccountManWidget") - self.widget.show_all() - try: - f = open(SETTINGS_FILE) - self.accounts = pickle.load(f) - print 'loaded!' - self.refreshAccounts() - except IOError: - self.accounts = [] - print 'initialized!' - - def on_ConsoleButton_clicked(self, b): - #### For debugging purposes... - from twisted.manhole.ui.pywidgets import LocalInteraction - l = LocalInteraction() - l.localNS['chat'] = self.chatui - l.show_all() - - def created(self, acct): - self.accounts.append(acct) - self.refreshAccounts() - - def refreshAccounts(self): - w = self.xml.get_widget("accountsList") - w.clear() - for acct in self.accounts: - l = [acct.accountName, acct.isOnline() and 'yes' or 'no', - acct.autoLogin and 'yes' or 'no', acct.gatewayType] - w.append(l) - - def lockNewAccount(self, b): - self.xml.get_widget("NewAccountButton").set_sensitive(not b) - - def on_NewAccountButton_clicked(self, b): - NewAccount(self) - - def on_MainIMWindow_destroy(self, w): - print 'Saving...' - pickle.dump(self.accounts, open(SETTINGS_FILE,'wb')) - print 'Saved.' - gtk.mainquit() - - - def on_DeleteAccountButton_clicked(self, b): - lw = self.xml.get_widget("accountsList") - if lw.selection: - del self.accounts[lw.selection[0]] - self.refreshAccounts() - - def on_LogOnButton_clicked(self, b): - lw = self.xml.get_widget("accountsList") - if lw.selection: - self.accounts[lw.selection[0]].logOn(self.chatui) - - -class DummyAccountForm: - def __init__(self, manager): - self.widget = gtk.GtkButton("HELLO") - - def create(self, sname, autoLogin): - return None - - -class NewAccount: - def __init__(self, manager): - self.manager = manager - self.manager.lockNewAccount(1) - self.xml = openGlade(GLADE_FILE, root="NewAccountWindow") - autoConnectMethods(self) - self.widget = self.xml.get_widget("NewAccountWindow") - self.frame = self.xml.get_widget("GatewayFrame") - # Making up for a deficiency in glade. - widgetMenu = self.xml.get_widget("GatewayOptionMenu") - m = gtk.GtkMenu() - activ = 0 - self.currentGateway = None - for name, klas in registeredTypes: - i = gtk.GtkMenuItem(name) - m.append(i) - k = klas(self.manager) - i.connect("activate", self.gatewaySelected, k) - if not activ: - activ = 1 - self.gatewaySelected(None, k) - widgetMenu.set_menu(m) - self.widget.show_all() - - def gatewaySelected(self, ig, k): - if self.currentGateway: - self.frame.remove(self.currentGateway.widget) - self.currentGateway = k - self.frame.add(k.widget) - k.widget.show_all() - - def createAccount(self, b): - autoLogin = self.xml.get_widget("AutoLogin").get_active() - accountName = self.xml.get_widget("accountName").get_text() - x = self.currentGateway.create(accountName, autoLogin) - if x: - self.manager.created(x) - self.destroyMe() - - def destroyMe(self, b=None): - self.widget.destroy() - - def on_NewAccountWindow_destroy(self, w): - self.manager.lockNewAccount(0) - -from twisted.words.im.pbsupport import PBAccount -from twisted.words.im.tocsupport import TOCAccount -from twisted.words.im.ircsupport import IRCAccount - - -class PBAccountForm: - def __init__(self, manager): - self.manager = manager - self.xml = openGlade(GLADE_FILE, root="PBAccountWidget") - autoConnectMethods(self) - self.widget = self.xml.get_widget("PBAccountWidget") - self.on_serviceType_changed() - self.selectedRow = None - - def addPerspective(self, b): - stype = self.xml.get_widget("serviceType").get_text() - sname = self.xml.get_widget("serviceName").get_text() - pname = self.xml.get_widget("perspectiveName").get_text() - self.xml.get_widget("serviceList").append([stype, sname, pname]) - - def removePerspective(self, b): - if self.selectedRow is not None: - self.xml.get_widget("serviceList").remove(self.selectedRow) - - def on_serviceType_changed(self, w=None): - self.xml.get_widget("serviceName").set_text(self.xml.get_widget("serviceType").get_text()) - self.xml.get_widget("perspectiveName").set_text(self.xml.get_widget("identity").get_text()) - - on_identity_changed = on_serviceType_changed - - def on_serviceList_select_row(self, slist, row, column, event): - self.selectedRow = row - - def create(self, accName, autoLogin): - host = self.xml.get_widget("hostname").get_text() - port = self.xml.get_widget("portno").get_text() - user = self.xml.get_widget("identity").get_text() - pasw = self.xml.get_widget("password").get_text() - serviceList = self.xml.get_widget("serviceList") - services = [] - for r in xrange(0, serviceList.rows): - row = [] - for c in xrange(0, serviceList.columns): - row.append(serviceList.get_text(r, c)) - services.append(row) - if not services: - services.append([ - self.xml.get_widget("serviceType").get_text(), - self.xml.get_widget("serviceName").get_text(), - self.xml.get_widget("perspectiveName").get_text()]) - return PBAccount(accName, autoLogin, user, pasw, host, int(port), - services) - - -class TOCAccountForm: - def __init__(self, maanger): - self.xml = openGlade(GLADE_FILE, root="TOCAccountWidget") - self.widget = self.xml.get_widget("TOCAccountWidget") - - def create(self, accountName, autoLogin): - return TOCAccount( - accountName, autoLogin, - self.xml.get_widget("TOCName").get_text(), - self.xml.get_widget("TOCPass").get_text(), - self.xml.get_widget("TOCHost").get_text(), - int(self.xml.get_widget("TOCPort").get_text()) ) - - -class IRCAccountForm: - def __init__(self, maanger): - self.xml = openGlade(GLADE_FILE, root="IRCAccountWidget") - self.widget = self.xml.get_widget("IRCAccountWidget") - - def create(self, accountName, autoLogin): - return IRCAccount( - accountName, autoLogin, - self.xml.get_widget("ircNick").get_text(), - self.xml.get_widget("ircPassword").get_text(), - self.xml.get_widget("ircServer").get_text(), - int(self.xml.get_widget("ircPort").get_text()), - self.xml.get_widget("ircChannels").get_text(), - ) - - - -registeredTypes = [ ("Twisted", PBAccountForm), - ("AOL Instant Messenger", TOCAccountForm), - ["IRC", IRCAccountForm], - ("Dummy", DummyAccountForm) ] diff --git a/tools/buildbot/pylibs/twisted/words/im/gtkchat.py b/tools/buildbot/pylibs/twisted/words/im/gtkchat.py deleted file mode 100644 index 9c1a426..0000000 --- a/tools/buildbot/pylibs/twisted/words/im/gtkchat.py +++ /dev/null @@ -1,413 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -import string -import time - -import gtk - -from twisted.words.im.gtkcommon import GLADE_FILE, autoConnectMethods, InputOutputWindow, openGlade - -class ContactsList: - def __init__(self, chatui, xml): - self.xml = xml# openGlade(GLADE_FILE, root="ContactsWidget") - # self.widget = self.xml.get_widget("ContactsWidget") - self.people = [] - self.onlinePeople = [] - self.countOnline = 0 - autoConnectMethods(self) - self.selectedPerson = None - self.xml.get_widget("OnlineCount").set_text("Online: 0") - self.chat = chatui - - # Construct Menu for Account Selection - self.optionMenu = self.xml.get_widget("AccountsListPopup") - self.accountMenuItems = [] - self.currentAccount = None - - - def registerAccountClient(self, account): - print 'registering account client', self, account - self.accountMenuItems.append(account) - self._updateAccountMenu() - self.chat._accountmanager.refreshAccounts() - - def _updateAccountMenu(self): - # This seems to be necessary -- I don't understand gtk's handling of - # GtkOptionMenus - print 'updating account menu', self.accountMenuItems - self.accountMenu = gtk.GtkMenu() - for account in self.accountMenuItems: - i = gtk.GtkMenuItem(account.accountName) - i.connect('activate', self.on_AccountsListPopup_activate, account) - self.accountMenu.append(i) - if self.accountMenuItems: - print "setting default account to", self.accountMenuItems[0] - self.currentAccount = self.accountMenuItems[0] - self.accountMenu.show_all() - self.optionMenu.set_menu(self.accountMenu) - - def on_AccountsListPopup_activate(self, w, account): - print 'setting current account', account - self.currentAccount = account - - def on_AddContactButton_clicked(self, b): - self.currentAccount.addContact( - self.xml.get_widget("ContactNameEntry").get_text()) - - def unregisterAccountClient(self,account): - print 'unregistering account client', self, account - self.accountMenuItems.remove(account) - self._updateAccountMenu() - - def setContactStatus(self, person): - if person not in self.people: - self.people.append(person) - self.refreshContactsLists() - - def on_OnlineContactsTree_select_row(self, w, row, column, event): - self.selectedPerson = self.onlinePeople[row] - entry = self.xml.get_widget("ContactNameEntry") - entry.set_text(self.selectedPerson.name) - self.currentAccount = self.selectedPerson.account.client - idx = self.accountMenuItems.index(self.currentAccount) - self.accountMenu.set_active(idx) - self.optionMenu.remove_menu() - self.optionMenu.set_menu(self.accountMenu) - - def on_PlainSendIM_clicked(self, b): - self.chat.getConversation( - self.currentAccount.getPerson( - self.xml.get_widget("ContactNameEntry").get_text())) -## if self.selectedPerson: -## c = self.chat.getConversation(self.selectedPerson) - - def on_PlainJoinChat_clicked(self, b): - ## GroupJoinWindow(self.chat) - name = self.xml.get_widget("ContactNameEntry").get_text() - self.currentAccount.joinGroup(name) - - def refreshContactsLists(self): - # HIDEOUSLY inefficient - online = self.xml.get_widget("OnlineContactsTree") - offline = self.xml.get_widget("OfflineContactsList") - online.freeze() - offline.freeze() - online.clear() - offline.clear() - self.countOnline = 0 - self.onlinePeople = [] - self.people.sort(lambda x, y: cmp(x.name, y.name)) - for person in self.people: - if person.isOnline(): - self.onlinePeople.append(person) - online.append([person.name, str(person.getStatus()), - person.getIdleTime(), - person.account.accountName]) - self.countOnline = self.countOnline + 1 - offline.append([person.name, person.account.accountName, - 'Aliasing Not Implemented', 'Groups Not Implemented']) - self.xml.get_widget("OnlineCount").set_text("Online: %d" % self.countOnline) - online.thaw() - offline.thaw() - - - -def colorhash(name): - h = hash(name) - l = [0x5555ff, - 0x55aa55, - 0x55aaff, - 0xff5555, - 0xff55ff, - 0xffaa55] - index = l[h % len(l)] - return '%06.x' % (abs(hash(name)) & index) - - -def _msgDisplay(output, name, text, color, isEmote): - text = string.replace(text, '\n', '\n\t') - ins = output.insert - ins(None, color, None, "[ %s ] " % time.strftime("%H:%M:%S")) - if isEmote: - ins(None, color, None, "* %s " % name) - ins(None, None, None, "%s\n" % text) - else: - ins(None, color, None, "<%s> " % name) - ins(None, None, None, "%s\n" % text) - - -class Conversation(InputOutputWindow): - """GUI representation of a conversation. - """ - def __init__(self, person): - InputOutputWindow.__init__(self, - "ConversationWidget", - "ConversationMessageEntry", - "ConversationOutput") - self.person = person - alloc_color = self.output.get_colormap().alloc - self.personColor = alloc_color("#%s" % colorhash(person.name)) - self.myColor = alloc_color("#0000ff") - print "allocated my color %s and person color %s" % ( - self.myColor, self.personColor) - - def getTitle(self): - return "Conversation - %s (%s)" % (self.person.name, - self.person.account.accountName) - - # Chat Interface Implementation - - def sendText(self, text): - metadata = None - if text[:4] == "/me ": - text = text[4:] - metadata = {"style": "emote"} - self.person.sendMessage(text, metadata).addCallback(self._cbTextSent, text, metadata) - - def showMessage(self, text, metadata=None): - _msgDisplay(self.output, self.person.name, text, self.personColor, - (metadata and metadata.get("style", None) == "emote")) - - # Internal - - def _cbTextSent(self, result, text, metadata=None): - _msgDisplay(self.output, self.person.account.client.name, - text, self.myColor, - (metadata and metadata.get("style", None) == "emote")) - -class GroupConversation(InputOutputWindow): - def __init__(self, group): - InputOutputWindow.__init__(self, - "GroupChatBox", - "GroupInput", - "GroupOutput") - self.group = group - self.members = [] - self.membersHidden = 0 - self._colorcache = {} - alloc_color = self.output.get_colormap().alloc - self.myColor = alloc_color("#0000ff") - # TODO: we shouldn't be getting group conversations randomly without - # names, but irc autojoin appears broken. - self.xml.get_widget("NickLabel").set_text( - getattr(self.group.account.client,"name","(no name)")) - participantList = self.xml.get_widget("ParticipantList") - groupBox = self.xml.get_widget("GroupActionsBox") - for method in group.getGroupCommands(): - b = gtk.GtkButton(method.__name__) - b.connect("clicked", self._doGroupAction, method) - groupBox.add(b) - self.setTopic("No Topic Yet", "No Topic Author Yet") - - # GTK Event Handlers - - def on_HideButton_clicked(self, b): - self.membersHidden = not self.membersHidden - self.xml.get_widget("GroupHPaned").set_position(self.membersHidden and -1 or 20000) - - def on_LeaveButton_clicked(self, b): - self.win.destroy() - self.group.leave() - - def on_AddContactButton_clicked(self, b): - lw = self.xml.get_widget("ParticipantList") - - if lw.selection: - self.group.client.addContact(self.members[lw.selection[0]]) - - def on_TopicEntry_focus_out_event(self, w, e): - self.xml.get_widget("TopicEntry").set_text(self._topic) - - def on_TopicEntry_activate(self, e): - print "ACTIVATING TOPIC!!" - self.group.setTopic(e.get_text()) - # self.xml.get_widget("TopicEntry").set_editable(0) - self.xml.get_widget("GroupInput").grab_focus() - - def on_ParticipantList_unselect_row(self, w, row, column, event): - print 'row unselected' - personBox = self.xml.get_widget("PersonActionsBox") - for child in personBox.children(): - personBox.remove(child) - - def on_ParticipantList_select_row(self, w, row, column, event): - self.selectedPerson = self.group.account.client.getPerson(self.members[row]) - print 'selected', self.selectedPerson - personBox = self.xml.get_widget("PersonActionsBox") - personFrame = self.xml.get_widget("PersonFrame") - # clear out old buttons - for child in personBox.children(): - personBox.remove(child) - personFrame.set_label("Person: %s" % self.selectedPerson.name) - for method in self.selectedPerson.getPersonCommands(): - b = gtk.GtkButton(method.__name__) - b.connect("clicked", self._doPersonAction, method) - personBox.add(b) - b.show() - for method in self.group.getTargetCommands(self.selectedPerson): - b = gtk.GtkButton(method.__name__) - b.connect("clicked", self._doTargetAction, method, - self.selectedPerson) - personBox.add(b) - b.show() - - def _doGroupAction(self, evt, method): - method() - - def _doPersonAction(self, evt, method): - method() - - def _doTargetAction(self, evt, method, person): - method(person) - - def hidden(self, w): - InputOutputWindow.hidden(self, w) - self.group.leave() - - def getTitle(self): - return "Group Conversation - " + self.group.name - - # Chat Interface Implementation - def sendText(self, text): - metadata = None - if text[:4] == "/me ": - text = text[4:] - metadata = {"style": "emote"} - self.group.sendGroupMessage(text, metadata).addCallback(self._cbTextSent, text, metadata=metadata) - - def showGroupMessage(self, sender, text, metadata=None): - _msgDisplay(self.output, sender, text, self._cacheColorHash(sender), - (metadata and metadata.get("style", None) == "emote")) - - - def setGroupMembers(self, members): - self.members = members - self.refreshMemberList() - - def setTopic(self, topic, author): - self._topic = topic - self._topicAuthor = author - self.xml.get_widget("TopicEntry").set_text(topic) - self.xml.get_widget("AuthorLabel").set_text(author) - - def memberJoined(self, member): - self.members.append(member) - self.output.insert_defaults("> %s joined <\n" % member) - self.refreshMemberList() - - def memberChangedNick(self, member, newnick): - self.members.remove(member) - self.members.append(newnick) - self.output.insert_defaults("> %s becomes %s <\n" % (member, newnick)) - self.refreshMemberList() - - def memberLeft(self, member): - self.members.remove(member) - self.output.insert_defaults("> %s left <\n" % member) - self.refreshMemberList() - - - - # Tab Completion - - def tabComplete(self, word): - """InputOutputWindow calls me when tab is pressed.""" - if not word: - return [] - potentialMatches = [] - for nick in self.members: - if string.lower(nick[:len(word)]) == string.lower(word): - potentialMatches.append(nick + ": ") #colon is a nick-specific thing - return potentialMatches - - # Internal - - def _cbTextSent(self, result, text, metadata=None): - _msgDisplay(self.output, self.group.account.client.name, - text, self.myColor, - (metadata and metadata.get("style", None) == "emote")) - - def refreshMemberList(self): - pl = self.xml.get_widget("ParticipantList") - pl.freeze() - pl.clear() - self.members.sort(lambda x,y: cmp(string.lower(x), string.lower(y))) - for member in self.members: - pl.append([member]) - pl.thaw() - - def _cacheColorHash(self, name): - if self._colorcache.has_key(name): - return self._colorcache[name] - else: - alloc_color = self.output.get_colormap().alloc - c = alloc_color('#%s' % colorhash(name)) - self._colorcache[name] = c - return c - - - - -class GtkChatClientUI: - def __init__(self,xml): - self.conversations = {} # cache of all direct windows - self.groupConversations = {} # cache of all group windows - self.personCache = {} # keys are (name, account) - self.groupCache = {} # cache of all groups - self.theContactsList = ContactsList(self,xml) - self.onlineAccounts = [] # list of message sources currently online - - def registerAccountClient(self,account): - print 'registering account client' - self.onlineAccounts.append(account) - self.getContactsList().registerAccountClient(account) - - def unregisterAccountClient(self,account): - print 'unregistering account client' - self.onlineAccounts.remove(account) - self.getContactsList().unregisterAccountClient(account) - - def contactsListClose(self, w, evt): - return gtk.TRUE - - def getContactsList(self): - return self.theContactsList - - def getConversation(self, person): - conv = self.conversations.get(person) - if not conv: - conv = Conversation(person) - self.conversations[person] = conv - conv.show() - return conv - - def getGroupConversation(self, group, stayHidden=0): - conv = self.groupConversations.get(group) - if not conv: - conv = GroupConversation(group) - self.groupConversations[group] = conv - if not stayHidden: - conv.show() - else: - conv.hide() - return conv - - # ??? Why doesn't this inherit the basechat.ChatUI implementation? - - def getPerson(self, name, client): - account = client.account - p = self.personCache.get((name, account)) - if not p: - p = account.getPerson(name) - self.personCache[name, account] = p - return p - - def getGroup(self, name, client): - account = client.account - g = self.groupCache.get((name, account)) - if g is None: - g = account.getGroup(name) - self.groupCache[name, account] = g - return g diff --git a/tools/buildbot/pylibs/twisted/words/im/gtkcommon.py b/tools/buildbot/pylibs/twisted/words/im/gtkcommon.py deleted file mode 100644 index e2a1dc7..0000000 --- a/tools/buildbot/pylibs/twisted/words/im/gtkcommon.py +++ /dev/null @@ -1,190 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -import os, re - -from twisted.python import reflect -from twisted.python import util -from twisted.manhole.ui.pywidgets import isCursorOnFirstLine, isCursorOnLastLine - -import string -import gtk -from libglade import GladeXML - -GLADE_FILE = util.sibpath(__file__, "instancemessenger.glade") -SETTINGS_FILE = os.path.expanduser("~/.InstanceMessenger") - -OFFLINE = 0 -ONLINE = 1 -AWAY = 2 - -True = gtk.TRUE -False = gtk.FALSE - - -class InputOutputWindow: - - def __init__(self, rootName, inputName, outputName): - self.xml = openGlade(GLADE_FILE, root=rootName) - wid = self.xml.get_widget - self.entry = wid(inputName) - #self.entry.set_word_wrap(gtk.TRUE) - self.output = wid(outputName) - #self.output.set_word_wrap(gtk.TRUE) - self.widget = wid(rootName) - self.history = [] - self.histpos = 0 - self.linemode = True - self.currentlyVisible = 0 - self.win = None - autoConnectMethods(self) - - def show(self): - if not self.currentlyVisible: - self.win = w = gtk.GtkWindow(gtk.WINDOW_TOPLEVEL) - self.connectid = w.connect("destroy", self.hidden) - w.add(self.widget) - w.set_title(self.getTitle()) - w.show_all() - self.entry.grab_focus() - self.currentlyVisible = 1 - - def hidden(self, w): - self.win = None - w.remove(self.widget) - self.currentlyVisible = 0 - - def hide(self): - if self.currentlyVisible: - self.win.remove(self.widget) - self.currentlyVisible = 0 - self.win.disconnect(self.connectid) - self.win.destroy() - - - def handle_key_press_event(self, entry, event): - stopSignal = False - # ASSUMPTION: Assume Meta == mod4 - isMeta = event.state & gtk.GDK.MOD4_MASK - - ## - # Return handling - ## - if event.keyval == gtk.GDK.Return: - isShift = event.state & gtk.GDK.SHIFT_MASK - if isShift: - self.linemode = True - entry.insert_defaults('\n') - else: - stopSignal = True - text = entry.get_chars(0,-1) - if not text: - return - self.entry.delete_text(0, -1) - self.linemode = False - self.sendText(text) - self.history.append(text) - self.histpos = len(self.history) - - ## - # History handling - ## - elif ((event.keyval == gtk.GDK.Up and isCursorOnFirstLine(entry)) - or (isMeta and event.string == 'p')): - print "history up" - self.historyUp() - stopSignal = True - elif ((event.keyval == gtk.GDK.Down and isCursorOnLastLine(entry)) - or (isMeta and event.string == 'n')): - print "history down" - self.historyDown() - stopSignal = True - - ## - # Tab Completion - ## - elif event.keyval == gtk.GDK.Tab: - oldpos = entry.get_point() - word, pos = self.getCurrentWord(entry) - result = self.tabComplete(word) - - #If there are multiple potential matches, then we spit - #them out and don't insert a tab, so the user can type - #a couple more characters and try completing again. - if len(result) > 1: - for nick in result: - self.output.insert_defaults(nick + " ") - self.output.insert_defaults('\n') - stopSignal = True - - elif result: #only happens when len(result) == 1 - entry.freeze() - entry.delete_text(*pos) - entry.set_position(pos[0]) - entry.insert_defaults(result[0]) - entry.set_position(oldpos+len(result[0])-len(word)) - entry.thaw() - stopSignal = True - - if stopSignal: - entry.emit_stop_by_name("key_press_event") - return True - - def tabComplete(self, word): - """Override me to implement tab completion for your window, - I should return a list of potential matches.""" - return [] - - def getCurrentWord(self, entry): - i = entry.get_point() - text = entry.get_chars(0,-1) - word = re.split(r'\s', text)[-1] - start = string.rfind(text, word) - end = start+len(word) - return (word, (start, end)) - - def historyUp(self): - if self.histpos > 0: - self.entry.delete_text(0, -1) - self.histpos = self.histpos - 1 - self.entry.insert_defaults(self.history[self.histpos]) - self.entry.set_position(0) - - def historyDown(self): - if self.histpos < len(self.history) - 1: - self.histpos = self.histpos + 1 - self.entry.delete_text(0, -1) - self.entry.insert_defaults(self.history[self.histpos]) - elif self.histpos == len(self.history) - 1: - self.histpos = self.histpos + 1 - self.entry.delete_text(0, -1) - - -def createMethodDict(o, d=None): - if d is None: - d = {} - for base in reflect.allYourBase(o.__class__) + [o.__class__]: - for n in dir(base): - m = getattr(o, n) - #print 'd[%s] = %s' % (n, m) - d[n] = m - #print d - return d - -def autoConnectMethods(*objs): - o = {} - for obj in objs: - createMethodDict(obj, o) - # print 'connecting', o - objs[0].xml.signal_autoconnect(o) - - - -def openGlade(*args, **kwargs): - # print "opening glade file" - r = GladeXML(*args, **kwargs) - if r._o: - return r - else: - raise IOError("Couldn't open Glade XML: %s; %s" % (args, kwargs)) diff --git a/tools/buildbot/pylibs/twisted/words/im/instancemessenger.glade b/tools/buildbot/pylibs/twisted/words/im/instancemessenger.glade deleted file mode 100644 index 33ffaa2..0000000 --- a/tools/buildbot/pylibs/twisted/words/im/instancemessenger.glade +++ /dev/null @@ -1,3165 +0,0 @@ - - - - - InstanceMessenger - instancemessenger - - src - pixmaps - C - True - True - True - - - - GtkWindow - UnseenConversationWindow - False - Unseen Conversation Window - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - False - True - False - - - GtkVBox - ConversationWidget - False - 0 - - - GtkVPaned - vpaned1 - 10 - 6 - 0 - - 0 - True - True - - - - GtkScrolledWindow - scrolledwindow10 - GTK_POLICY_NEVER - GTK_POLICY_ALWAYS - GTK_UPDATE_CONTINUOUS - GTK_UPDATE_CONTINUOUS - - False - True - - - - GtkText - ConversationOutput - False - - - - - - GtkScrolledWindow - scrolledwindow11 - GTK_POLICY_NEVER - GTK_POLICY_AUTOMATIC - GTK_UPDATE_CONTINUOUS - GTK_UPDATE_CONTINUOUS - - True - False - - - - GtkText - ConversationMessageEntry - True - True - - key_press_event - handle_key_press_event - Tue, 29 Jan 2002 12:42:58 GMT - - True - - - - - - - GtkHBox - hbox9 - True - 0 - - 3 - False - True - - - - GtkButton - button42 - True - - GTK_RELIEF_NORMAL - - 3 - True - True - - - - - GtkButton - AddRemoveContact - True - - GTK_RELIEF_NORMAL - - 3 - True - True - - - - - GtkButton - CloseContact - True - - GTK_RELIEF_NORMAL - - 3 - True - True - - - - - - - - GtkWindow - MainIMWindow - - destroy - on_MainIMWindow_destroy - Sun, 21 Jul 2002 08:16:08 GMT - - Instance Messenger - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - True - True - False - - - GtkNotebook - ContactsNotebook - True - - key_press_event - on_ContactsWidget_key_press_event - Tue, 07 May 2002 03:02:33 GMT - - True - True - GTK_POS_TOP - False - 2 - 2 - False - - - GtkVBox - vbox11 - False - 0 - - - GtkLabel - OnlineCount - - GTK_JUSTIFY_CENTER - False - 0.5 - 0.5 - 0 - 0 - - 0 - False - False - - - - - GtkScrolledWindow - scrolledwindow14 - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - GTK_UPDATE_CONTINUOUS - GTK_UPDATE_CONTINUOUS - - 0 - True - True - - - - GtkCTree - OnlineContactsTree - True - - tree_select_row - on_OnlineContactsTree_tree_select_row - Tue, 07 May 2002 03:06:32 GMT - - - select_row - on_OnlineContactsTree_select_row - Tue, 07 May 2002 04:36:10 GMT - - 4 - 109,35,23,80 - GTK_SELECTION_SINGLE - True - GTK_SHADOW_IN - - - GtkLabel - CTree:title - label77 - - GTK_JUSTIFY_CENTER - False - 0.5 - 0.5 - 0 - 0 - - - - GtkLabel - CTree:title - label78 - - GTK_JUSTIFY_CENTER - False - 0.5 - 0.5 - 0 - 0 - - - - GtkLabel - CTree:title - label79 - - GTK_JUSTIFY_CENTER - False - 0.5 - 0.5 - 0 - 0 - - - - GtkLabel - CTree:title - label80 - - GTK_JUSTIFY_CENTER - False - 0.5 - 0.5 - 0 - 0 - - - - - - GtkVBox - vbox30 - False - 2 - - 1 - False - True - - - - GtkEntry - ContactNameEntry - True - - activate - on_ContactNameEntry_activate - Tue, 07 May 2002 04:07:25 GMT - - True - True - 0 - - - 0 - False - False - - - - - GtkOptionMenu - AccountsListPopup - True - Nothing -To -Speak -Of - - 1 - - 0 - False - False - - - - - GtkHBox - hbox7 - False - 0 - - 0 - True - True - - - - GtkButton - PlainSendIM - True - - clicked - on_PlainSendIM_clicked - Tue, 29 Jan 2002 03:17:35 GMT - - - GTK_RELIEF_NORMAL - - 0 - True - False - - - - - GtkButton - PlainGetInfo - True - - clicked - on_PlainGetInfo_clicked - Tue, 07 May 2002 04:06:59 GMT - - - GTK_RELIEF_NORMAL - - 0 - True - False - - - - - GtkButton - PlainJoinChat - True - - clicked - on_PlainJoinChat_clicked - Tue, 29 Jan 2002 13:04:49 GMT - - - GTK_RELIEF_NORMAL - - 0 - True - False - - - - - GtkButton - PlainGoAway - True - - clicked - on_PlainGoAway_clicked - Tue, 07 May 2002 04:06:53 GMT - - - GTK_RELIEF_NORMAL - - 0 - True - False - - - - - - GtkHBox - hbox8 - False - 0 - - 0 - True - True - - - - GtkButton - AddContactButton - True - - clicked - on_AddContactButton_clicked - Tue, 07 May 2002 04:06:33 GMT - - - GTK_RELIEF_NORMAL - - 0 - True - False - - - - - GtkButton - RemoveContactButton - True - - clicked - on_RemoveContactButton_clicked - Tue, 07 May 2002 04:06:28 GMT - - - GTK_RELIEF_NORMAL - - 0 - True - False - - - - - - - - GtkLabel - Notebook:tab - label35 - - GTK_JUSTIFY_CENTER - False - 0.5 - 0.5 - 0 - 0 - - - - GtkVBox - vbox14 - False - 0 - - - GtkScrolledWindow - OfflineContactsScroll - GTK_POLICY_AUTOMATIC - GTK_POLICY_ALWAYS - GTK_UPDATE_CONTINUOUS - GTK_UPDATE_CONTINUOUS - - 0 - True - True - - - - GtkCList - OfflineContactsList - True - - select_row - on_OfflineContactsList_select_row - Tue, 07 May 2002 03:00:07 GMT - - 4 - 66,80,80,80 - GTK_SELECTION_SINGLE - True - GTK_SHADOW_IN - - - GtkLabel - CList:title - label41 - - GTK_JUSTIFY_CENTER - False - 0.5 - 0.5 - 0 - 0 - - - - GtkLabel - CList:title - label42 - - GTK_JUSTIFY_CENTER - False - 0.5 - 0.5 - 0 - 0 - - - - GtkLabel - CList:title - label43 - - GTK_JUSTIFY_CENTER - False - 0.5 - 0.5 - 0 - 0 - - - - GtkLabel - CList:title - label44 - - GTK_JUSTIFY_CENTER - False - 0.5 - 0.5 - 0 - 0 - - - - - - - GtkLabel - Notebook:tab - label36 - - GTK_JUSTIFY_CENTER - False - 0.5 - 0.5 - 0 - 0 - - - - GtkVBox - AccountManWidget - False - 0 - - - GtkScrolledWindow - scrolledwindow12 - GTK_POLICY_AUTOMATIC - GTK_POLICY_ALWAYS - GTK_UPDATE_CONTINUOUS - GTK_UPDATE_CONTINUOUS - - 0 - True - True - - - - GtkCList - accountsList - True - 4 - 80,36,34,80 - GTK_SELECTION_SINGLE - True - GTK_SHADOW_IN - - - GtkLabel - CList:title - label45 - - GTK_JUSTIFY_CENTER - False - 0.5 - 0.5 - 0 - 0 - - - - GtkLabel - CList:title - label46 - - GTK_JUSTIFY_CENTER - False - 0.5 - 0.5 - 0 - 0 - - - - GtkLabel - CList:title - label47 - - GTK_JUSTIFY_CENTER - False - 0.5 - 0.5 - 0 - 0 - - - - GtkLabel - CList:title - label48 - - GTK_JUSTIFY_CENTER - False - 0.5 - 0.5 - 0 - 0 - - - - - - GtkTable - table5 - 2 - 3 - False - 0 - 0 - - 3 - False - True - - - - GtkButton - NewAccountButton - True - True - - clicked - on_NewAccountButton_clicked - Sun, 27 Jan 2002 10:32:20 GMT - - - GTK_RELIEF_NORMAL - - 0 - 1 - 0 - 1 - 0 - 0 - False - False - False - False - True - False - - - - - GtkButton - button46 - False - True - - GTK_RELIEF_NORMAL - - 1 - 2 - 0 - 1 - 0 - 0 - False - False - False - False - True - False - - - - - GtkButton - LogOnButton - True - True - True - True - - clicked - on_LogOnButton_clicked - Mon, 28 Jan 2002 04:06:23 GMT - - - GTK_RELIEF_NORMAL - - 2 - 3 - 1 - 2 - 0 - 0 - False - False - False - False - True - False - - - - - GtkButton - DeleteAccountButton - True - True - - clicked - on_DeleteAccountButton_clicked - Mon, 28 Jan 2002 00:18:22 GMT - - - GTK_RELIEF_NORMAL - - 2 - 3 - 0 - 1 - 0 - 0 - False - False - False - False - True - False - - - - - GtkButton - ConsoleButton - True - True - - clicked - on_ConsoleButton_clicked - Mon, 29 Apr 2002 09:13:32 GMT - - - GTK_RELIEF_NORMAL - - 1 - 2 - 1 - 2 - 0 - 0 - False - False - False - False - True - False - - - - - GtkButton - button75 - True - True - - GTK_RELIEF_NORMAL - - 0 - 1 - 1 - 2 - 0 - 0 - True - True - False - False - True - True - - - - - - - GtkLabel - Notebook:tab - label107 - - GTK_JUSTIFY_CENTER - False - 0.5 - 0.5 - 0 - 0 - - - - - - GtkWindow - UnseenGroupWindow - False - Unseen Group Window - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - False - True - False - - - GtkVBox - GroupChatBox - False - 0 - - - GtkHBox - hbox5 - False - 0 - - 0 - False - True - - - - GtkEntry - TopicEntry - True - - activate - on_TopicEntry_activate - Sat, 23 Feb 2002 02:57:41 GMT - - - focus_out_event - on_TopicEntry_focus_out_event - Sun, 21 Jul 2002 09:36:54 GMT - - True - True - 0 - <TOPIC NOT RECEIVED> - - 0 - True - True - - - - - GtkLabel - AuthorLabel - - GTK_JUSTIFY_CENTER - False - 0.5 - 0.5 - 0 - 0 - - 0 - False - False - - - - - GtkButton - HideButton - True - - clicked - on_HideButton_clicked - Tue, 29 Jan 2002 14:10:00 GMT - - - GTK_RELIEF_NORMAL - - 0 - False - False - - - - - - GtkVPaned - vpaned2 - 10 - 6 - 0 - - 0 - True - True - - - - GtkHPaned - GroupHPaned - 6 - 6 - - False - True - - - - GtkScrolledWindow - scrolledwindow4 - GTK_POLICY_NEVER - GTK_POLICY_ALWAYS - GTK_UPDATE_CONTINUOUS - GTK_UPDATE_CONTINUOUS - - False - True - - - - GtkText - GroupOutput - True - False - - - - - - GtkVBox - actionvbox - 110 - False - 1 - - True - False - - - - GtkScrolledWindow - scrolledwindow5 - GTK_POLICY_NEVER - GTK_POLICY_ALWAYS - GTK_UPDATE_CONTINUOUS - GTK_UPDATE_CONTINUOUS - - 0 - True - True - - - - GtkCList - ParticipantList - True - - select_row - on_ParticipantList_select_row - Sat, 13 Jul 2002 08:11:12 GMT - - - unselect_row - on_ParticipantList_unselect_row - Sat, 13 Jul 2002 08:23:25 GMT - - 1 - 80 - GTK_SELECTION_SINGLE - False - GTK_SHADOW_IN - - - GtkLabel - CList:title - label18 - - GTK_JUSTIFY_CENTER - False - 0.5 - 0.5 - 0 - 0 - - - - - - GtkFrame - frame10 - - 0 - GTK_SHADOW_ETCHED_IN - - 0 - False - False - - - - GtkVBox - GroupActionsBox - False - 0 - - - Placeholder - - - - Placeholder - - - - Placeholder - - - - - - GtkFrame - PersonFrame - - 0 - GTK_SHADOW_ETCHED_IN - - 0 - False - False - - - - GtkVBox - PersonActionsBox - False - 0 - - - Placeholder - - - - Placeholder - - - - Placeholder - - - - - - - - GtkHBox - hbox6 - False - 0 - - True - False - - - - GtkLabel - NickLabel - - GTK_JUSTIFY_CENTER - False - 0.5 - 0.5 - 0 - 0 - - 4 - False - False - - - - - GtkScrolledWindow - scrolledwindow9 - GTK_POLICY_NEVER - GTK_POLICY_AUTOMATIC - GTK_UPDATE_CONTINUOUS - GTK_UPDATE_CONTINUOUS - - 0 - True - True - - - - GtkText - GroupInput - True - True - - key_press_event - handle_key_press_event - Tue, 29 Jan 2002 12:41:03 GMT - - True - - - - - - - - - - GtkWindow - NewAccountWindow - 3 - False - - destroy - on_NewAccountWindow_destroy - Sun, 27 Jan 2002 10:35:19 GMT - - New Account - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - False - True - True - - - GtkVBox - vbox17 - False - 0 - - - GtkHBox - hbox11 - False - 0 - - 3 - False - True - - - - GtkLabel - label49 - - GTK_JUSTIFY_CENTER - False - 0.5 - 0.5 - 0 - 0 - - 0 - False - True - - - - - GtkOptionMenu - GatewayOptionMenu - True - Twisted (Perspective Broker) -Internet Relay Chat -AIM (TOC) -AIM (OSCAR) - - 0 - - 4 - True - True - - - - - - GtkFrame - GatewayFrame - 3 - - 0 - GTK_SHADOW_ETCHED_IN - - 0 - True - True - - - - Placeholder - - - - - GtkFrame - frame2 - 3 - - 0 - GTK_SHADOW_ETCHED_IN - - 0 - False - True - - - - GtkTable - table1 - 3 - 2 - 2 - False - 0 - 0 - - - GtkCheckButton - AutoLogin - True - - False - True - - 1 - 2 - 0 - 1 - 0 - 0 - True - True - False - False - True - False - - - - - GtkEntry - accountName - True - True - True - 0 - - - 1 - 2 - 1 - 2 - 0 - 0 - True - True - False - False - True - False - - - - - GtkLabel - label50 - - GTK_JUSTIFY_RIGHT - False - 0 - 0.5 - 0 - 0 - - 0 - 1 - 0 - 1 - 0 - 0 - False - True - False - False - True - True - - - - - GtkLabel - label51 - - GTK_JUSTIFY_RIGHT - False - 0 - 0.5 - 0 - 0 - - 0 - 1 - 1 - 2 - 0 - 0 - False - True - False - False - True - True - - - - - - - GtkHButtonBox - hbuttonbox2 - GTK_BUTTONBOX_SPREAD - 30 - 85 - 27 - 7 - 0 - - 0 - False - True - - - - GtkButton - button50 - True - True - - clicked - createAccount - Sun, 27 Jan 2002 11:25:05 GMT - - - GTK_RELIEF_NORMAL - - - - GtkButton - button51 - True - True - - clicked - destroyMe - Sun, 27 Jan 2002 11:27:12 GMT - - - GTK_RELIEF_NORMAL - - - - - - - GtkWindow - PBAccountWindow - False - PB Account Window - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - False - True - False - - - GtkVBox - PBAccountWidget - 4 - False - 0 - - - GtkTable - table3 - 4 - 2 - False - 0 - 0 - - 0 - False - True - - - - GtkEntry - hostname - True - True - True - 0 - twistedmatrix.com - - 1 - 2 - 2 - 3 - 0 - 0 - True - False - False - False - True - False - - - - - GtkEntry - identity - True - True - - changed - on_identity_changed - Sun, 27 Jan 2002 11:52:17 GMT - - True - True - 0 - - - 1 - 2 - 0 - 1 - 0 - 0 - True - False - False - False - True - False - - - - - GtkLabel - label52 - - GTK_JUSTIFY_RIGHT - False - 0 - 0.5 - 0 - 0 - - 0 - 1 - 2 - 3 - 0 - 0 - False - False - False - False - True - False - - - - - GtkLabel - label54 - - GTK_JUSTIFY_RIGHT - False - 0 - 0.5 - 0 - 0 - - 0 - 1 - 0 - 1 - 0 - 0 - False - False - False - False - True - False - - - - - GtkEntry - password - True - True - False - 0 - - - 1 - 2 - 1 - 2 - 0 - 0 - True - False - False - False - True - False - - - - - GtkEntry - portno - True - True - True - 0 - 8787 - - 1 - 2 - 3 - 4 - 0 - 0 - True - False - False - False - True - False - - - - - GtkLabel - label55 - - GTK_JUSTIFY_RIGHT - False - 0 - 0.5 - 0 - 0 - - 0 - 1 - 1 - 2 - 0 - 0 - False - False - False - False - True - False - - - - - GtkLabel - label53 - - GTK_JUSTIFY_RIGHT - False - 0 - 0.5 - 0 - 0 - - 0 - 1 - 3 - 4 - 0 - 0 - False - False - False - False - True - False - - - - - - GtkFrame - frame3 - - 0 - GTK_SHADOW_ETCHED_IN - - 0 - True - True - - - - GtkVBox - vbox19 - 3 - False - 0 - - - GtkScrolledWindow - scrolledwindow13 - GTK_POLICY_AUTOMATIC - GTK_POLICY_ALWAYS - GTK_UPDATE_CONTINUOUS - GTK_UPDATE_CONTINUOUS - - 0 - True - True - - - - GtkCList - serviceList - True - - select_row - on_serviceList_select_row - Sun, 27 Jan 2002 12:04:38 GMT - - 3 - 80,80,80 - GTK_SELECTION_SINGLE - True - GTK_SHADOW_IN - - - GtkLabel - CList:title - label60 - - GTK_JUSTIFY_CENTER - False - 0.5 - 0.5 - 0 - 0 - - - - GtkLabel - CList:title - label61 - - GTK_JUSTIFY_CENTER - False - 0.5 - 0.5 - 0 - 0 - - - - GtkLabel - CList:title - label62 - - GTK_JUSTIFY_CENTER - False - 0.5 - 0.5 - 0 - 0 - - - - - - GtkTable - table4 - 3 - 2 - False - 0 - 0 - - 0 - False - True - - - - GtkLabel - label63 - - GTK_JUSTIFY_RIGHT - False - 0 - 0.5 - 0 - 0 - - 0 - 1 - 2 - 3 - 0 - 0 - False - False - False - False - True - False - - - - - GtkLabel - label59 - - GTK_JUSTIFY_RIGHT - False - 0 - 0.5 - 0 - 0 - - 0 - 1 - 0 - 1 - 0 - 0 - False - False - False - False - True - False - - - - - GtkCombo - serviceCombo - False - True - False - True - False - twisted.words -twisted.reality -twisted.manhole - - - 1 - 2 - 0 - 1 - 0 - 0 - True - False - False - False - True - False - - - - GtkEntry - GtkCombo:entry - serviceType - True - - changed - on_serviceType_changed - Sun, 27 Jan 2002 11:49:07 GMT - - True - True - 0 - twisted.words - - - - - GtkLabel - label64 - - GTK_JUSTIFY_RIGHT - False - 0 - 0.5 - 0 - 0 - - 0 - 1 - 1 - 2 - 0 - 0 - False - False - False - False - True - False - - - - - GtkEntry - serviceName - True - True - True - 0 - - - 1 - 2 - 1 - 2 - 0 - 0 - True - False - False - False - True - False - - - - - GtkEntry - perspectiveName - True - True - True - 0 - - - 1 - 2 - 2 - 3 - 0 - 0 - True - False - False - False - True - False - - - - - - GtkHBox - hbox13 - False - 0 - - 0 - False - True - - - - GtkButton - button53 - True - - clicked - addPerspective - Mon, 28 Jan 2002 01:07:15 GMT - - - GTK_RELIEF_NORMAL - - 0 - True - False - - - - - GtkButton - button54 - True - - clicked - removePerspective - Sun, 27 Jan 2002 11:34:36 GMT - - - GTK_RELIEF_NORMAL - - 0 - True - False - - - - - - - - - - GtkWindow - IRCAccountWindow - IRC Account Window - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - False - True - False - - - GtkTable - IRCAccountWidget - 5 - 2 - False - 0 - 0 - - - GtkLabel - label65 - - GTK_JUSTIFY_RIGHT - False - 0 - 0.5 - 0 - 0 - - 0 - 1 - 0 - 1 - 0 - 0 - False - False - False - False - True - False - - - - - GtkLabel - label66 - - GTK_JUSTIFY_RIGHT - False - 0 - 0.5 - 0 - 0 - - 0 - 1 - 1 - 2 - 0 - 0 - False - False - False - False - True - False - - - - - GtkLabel - label67 - - GTK_JUSTIFY_RIGHT - False - 0 - 0.5 - 0 - 0 - - 0 - 1 - 2 - 3 - 0 - 0 - False - False - False - False - True - False - - - - - GtkLabel - label68 - - GTK_JUSTIFY_RIGHT - False - 0 - 0.5 - 0 - 0 - - 0 - 1 - 3 - 4 - 0 - 0 - False - False - False - False - True - False - - - - - GtkLabel - label69 - - GTK_JUSTIFY_RIGHT - False - 0 - 0.5 - 0 - 0 - - 0 - 1 - 4 - 5 - 0 - 0 - False - False - False - False - True - False - - - - - GtkEntry - ircNick - True - True - True - 0 - - - 1 - 2 - 0 - 1 - 0 - 0 - True - False - False - False - True - False - - - - - GtkEntry - ircServer - True - True - True - 0 - - - 1 - 2 - 1 - 2 - 0 - 0 - True - False - False - False - True - False - - - - - GtkEntry - ircPort - True - True - True - 0 - 6667 - - 1 - 2 - 2 - 3 - 0 - 0 - True - False - False - False - True - False - - - - - GtkEntry - ircChannels - True - True - True - 0 - - - 1 - 2 - 3 - 4 - 0 - 0 - True - False - False - False - True - False - - - - - GtkEntry - ircPassword - True - True - True - 0 - - - 1 - 2 - 4 - 5 - 0 - 0 - True - False - False - False - True - False - - - - - - - GtkWindow - TOCAccountWindow - TOC Account Window - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - False - True - False - - - GtkTable - TOCAccountWidget - 4 - 2 - False - 0 - 0 - - - GtkLabel - label70 - - GTK_JUSTIFY_CENTER - False - 0 - 0.5 - 0 - 0 - - 0 - 1 - 0 - 1 - 0 - 0 - False - False - False - False - True - False - - - - - GtkLabel - label71 - - GTK_JUSTIFY_CENTER - False - 0 - 0.5 - 0 - 0 - - 0 - 1 - 1 - 2 - 0 - 0 - False - False - False - False - True - False - - - - - GtkLabel - label72 - - GTK_JUSTIFY_CENTER - False - 0 - 0.5 - 0 - 0 - - 0 - 1 - 2 - 3 - 0 - 0 - False - False - False - False - True - False - - - - - GtkLabel - label73 - - GTK_JUSTIFY_CENTER - False - 0 - 0.5 - 0 - 0 - - 0 - 1 - 3 - 4 - 0 - 0 - False - False - False - False - True - False - - - - - GtkEntry - TOCName - True - True - True - 0 - - - 1 - 2 - 0 - 1 - 0 - 0 - True - False - False - False - True - False - - - - - GtkEntry - TOCPass - True - True - False - 0 - - - 1 - 2 - 1 - 2 - 0 - 0 - True - False - False - False - True - False - - - - - GtkEntry - TOCHost - True - True - True - 0 - toc.oscar.aol.com - - 1 - 2 - 2 - 3 - 0 - 0 - True - False - False - False - True - False - - - - - GtkEntry - TOCPort - True - True - True - 0 - 9898 - - 1 - 2 - 3 - 4 - 0 - 0 - True - False - False - False - True - False - - - - - - - GtkWindow - JoinGroupWindow - 5 - False - Group to Join - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - False - True - False - - - GtkVBox - vbox20 - False - 0 - - - GtkOptionMenu - AccountSelector - True - None -In -Particular - - 0 - - 0 - False - False - - - - - GtkHBox - hbox15 - False - 5 - - 0 - True - True - - - - GtkEntry - GroupNameEntry - True - True - - activate - on_GroupJoinButton_clicked - Tue, 29 Jan 2002 13:27:18 GMT - - True - True - 0 - - - 0 - True - True - - - - - GtkButton - GroupJoinButton - True - True - True - - clicked - on_GroupJoinButton_clicked - Tue, 29 Jan 2002 13:16:50 GMT - - - GTK_RELIEF_NORMAL - - 0 - False - False - - - - - - - - GtkWindow - UnifiedWindow - Twisted Instance Messenger - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - False - True - False - - - GtkVBox - vbox25 - False - 0 - - - GtkHBox - hbox28 - False - 0 - - 0 - False - True - - - - GtkButton - button74 - True - - GTK_RELIEF_NORMAL - - 0 - False - False - - - - - GtkEntry - entry3 - True - True - True - 0 - - - 0 - True - True - - - - - GtkOptionMenu - optionmenu3 - List -Of -Online -Accounts - - 0 - - 0 - False - False - - - - - GtkOptionMenu - optionmenu4 - True - Contact -Person -Group -Account - - 0 - - 0 - False - False - - - - - - GtkHPaned - hpaned1 - 10 - 6 - 0 - - 0 - True - True - - - - GtkVBox - vbox26 - False - 0 - - True - False - - - - GtkFrame - frame7 - 2 - - 0 - GTK_SHADOW_ETCHED_IN - - 0 - True - True - - - - GtkVBox - vbox27 - False - 0 - - - GtkScrolledWindow - scrolledwindow18 - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - GTK_UPDATE_CONTINUOUS - GTK_UPDATE_CONTINUOUS - - 0 - True - True - - - - GtkCList - clist4 - 4 - 18,25,25,80 - GTK_SELECTION_SINGLE - False - GTK_SHADOW_IN - - - GtkLabel - CList:title - label95 - - GTK_JUSTIFY_CENTER - False - 0.5 - 0.5 - 0 - 0 - - - - GtkLabel - CList:title - label96 - - GTK_JUSTIFY_CENTER - False - 0.5 - 0.5 - 0 - 0 - - - - GtkLabel - CList:title - label97 - - GTK_JUSTIFY_CENTER - False - 0.5 - 0.5 - 0 - 0 - - - - GtkLabel - CList:title - label98 - - GTK_JUSTIFY_CENTER - False - 0.5 - 0.5 - 0 - 0 - - - - - - GtkHBox - hbox23 - True - 2 - - 0 - True - True - - - - GtkButton - button65 - - GTK_RELIEF_NORMAL - - 0 - True - True - - - - - GtkButton - button66 - - GTK_RELIEF_NORMAL - - 0 - True - True - - - - - GtkButton - button67 - - GTK_RELIEF_NORMAL - - 0 - True - True - - - - - - - - GtkFrame - frame8 - 2 - - 0 - GTK_SHADOW_ETCHED_IN - - 0 - True - True - - - - GtkVBox - vbox28 - False - 0 - - - GtkScrolledWindow - scrolledwindow19 - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - GTK_UPDATE_CONTINUOUS - GTK_UPDATE_CONTINUOUS - - 0 - True - True - - - - GtkCList - clist5 - 3 - 18,17,80 - GTK_SELECTION_SINGLE - False - GTK_SHADOW_IN - - - GtkLabel - CList:title - label99 - - GTK_JUSTIFY_CENTER - False - 0.5 - 0.5 - 0 - 0 - - - - GtkLabel - CList:title - label100 - - GTK_JUSTIFY_CENTER - False - 0.5 - 0.5 - 0 - 0 - - - - GtkLabel - CList:title - label101 - - GTK_JUSTIFY_CENTER - False - 0.5 - 0.5 - 0 - 0 - - - - - - GtkHBox - hbox24 - True - 2 - - 0 - False - True - - - - GtkButton - button68 - True - - GTK_RELIEF_NORMAL - - 0 - True - True - - - - - GtkButton - button69 - True - - GTK_RELIEF_NORMAL - - 0 - True - True - - - - - GtkButton - button70 - True - - GTK_RELIEF_NORMAL - - 0 - True - True - - - - - GtkButton - button71 - True - - GTK_RELIEF_NORMAL - - 0 - False - False - - - - - - - - GtkFrame - frame9 - 2 - - 0 - GTK_SHADOW_ETCHED_IN - - 0 - True - True - - - - GtkVBox - vbox29 - False - 0 - - - GtkScrolledWindow - scrolledwindow20 - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - GTK_UPDATE_CONTINUOUS - GTK_UPDATE_CONTINUOUS - - 0 - True - True - - - - GtkCList - clist6 - 3 - 21,75,80 - GTK_SELECTION_SINGLE - False - GTK_SHADOW_IN - - - GtkLabel - CList:title - label102 - - GTK_JUSTIFY_CENTER - False - 0.5 - 0.5 - 0 - 0 - - - - GtkLabel - CList:title - label103 - - GTK_JUSTIFY_CENTER - False - 0.5 - 0.5 - 0 - 0 - - - - GtkLabel - CList:title - label104 - - GTK_JUSTIFY_CENTER - False - 0.5 - 0.5 - 0 - 0 - - - - - - GtkHBox - hbox27 - True - 2 - - 0 - False - True - - - - GtkButton - button72 - - GTK_RELIEF_NORMAL - - 0 - True - True - - - - - GtkButton - button73 - - GTK_RELIEF_NORMAL - - 0 - True - True - - - - - - - - GtkHSeparator - hseparator2 - - 0 - True - True - - - - - GtkLabel - label105 - - GTK_JUSTIFY_CENTER - False - 0.5 - 0.5 - 0 - 3 - - 0 - False - False - - - - - - GtkLabel - label106 - - GTK_JUSTIFY_CENTER - False - 0.5 - 0.5 - 0 - 0 - - True - True - - - - - - - diff --git a/tools/buildbot/pylibs/twisted/words/im/interfaces.py b/tools/buildbot/pylibs/twisted/words/im/interfaces.py deleted file mode 100644 index e0872bb..0000000 --- a/tools/buildbot/pylibs/twisted/words/im/interfaces.py +++ /dev/null @@ -1,324 +0,0 @@ -# -*- Python -*- -""" -Pan-protocol chat client. -""" -from zope.interface import Interface - -from twisted.words.im import locals - -# (Random musings, may not reflect on current state of code:) -# -# Accounts have Protocol components (clients) -# Persons have Conversation components -# Groups have GroupConversation components -# Persons and Groups are associated with specific Accounts -# At run-time, Clients/Accounts are slaved to a User Interface -# (Note: User may be a bot, so don't assume all UIs are built on gui toolkits) - - -class IAccount(Interface): - """I represent a user's account with a chat service. - - @cvar gatewayType: Identifies the protocol used by this account. - @type gatewayType: string - - @ivar client: The Client currently connecting to this account, if any. - @type client: L{IClient} - """ - - def __init__(accountName, autoLogin, username, password, host, port): - """ - @type accountName: string - @param accountName: A name to refer to the account by locally. - @type autoLogin: boolean - @type username: string - @type password: string - @type host: string - @type port: integer - """ - - def isOnline(): - """Am I online? - - @returntype: boolean - """ - - def logOn(chatui): - """Go on-line. - - @type chatui: Implementor of C{IChatUI} - - @returntype: Deferred L{Client} - """ - - def logOff(): - """Sign off. - """ - - def getGroup(groupName): - """ - @returntype: L{Group} - """ - - def getPerson(personName): - """ - @returntype: L{Person} - """ - -class IClient(Interface): - """ - @ivar account: The Account I am a Client for. - @type account: L{IAccount} - """ - def __init__(account, chatui, logonDeferred): - """ - @type account: L{IAccount} - @type chatui: L{IChatUI} - @param logonDeferred: Will be called back once I am logged on. - @type logonDeferred: L{Deferred} - """ - - def joinGroup(groupName): - """ - @param groupName: The name of the group to join. - @type groupName: string - """ - - def leaveGroup(groupName): - """ - @param groupName: The name of the group to leave. - @type groupName: string - """ - - def getGroupConversation(name,hide=0): - pass - - def getPerson(name): - pass - - -class IPerson(Interface): - def __init__(name, account): - """Initialize me. - - @param name: My name, as the server knows me. - @type name: string - @param account: The account I am accessed through. - @type account: I{Account} - """ - - def isOnline(): - """Am I online right now? - - @returntype: boolean - """ - - def getStatus(): - """What is my on-line status? - - @returns: L{locals.StatusEnum} - """ - - def getIdleTime(): - """ - @returntype: string (XXX: How about a scalar?) - """ - - def sendMessage(text, metadata=None): - """Send a message to this person. - - @type text: string - @type metadata: dict - """ - - -class IGroup(Interface): - """A group which you may have a conversation with. - - Groups generally have a loosely-defined set of members, who may - leave and join at any time. - - @ivar name: My name, as the server knows me. - @type name: string - @ivar account: The account I am accessed through. - @type account: I{Account} - """ - - def __init__(name, account): - """Initialize me. - - @param name: My name, as the server knows me. - @type name: string - @param account: The account I am accessed through. - @type account: I{Account} - """ - - def setTopic(text): - """Set this Groups topic on the server. - - @type text: string - """ - - def sendGroupMessage(text, metadata=None): - """Send a message to this group. - - @type text: string - - @type metadata: dict - @param metadata: Valid keys for this dictionary include: - - - C{'style'}: associated with one of: - - C{'emote'}: indicates this is an action - """ - - def join(): - pass - - def leave(): - """Depart this group""" - - -class IConversation(Interface): - """A conversation with a specific person.""" - def __init__(person, chatui): - """ - @type person: L{IPerson} - """ - - def show(): - """doesn't seem like it belongs in this interface.""" - - def hide(): - """nor this neither.""" - - def sendText(text, metadata): - pass - - def showMessage(text, metadata): - pass - - def changedNick(person, newnick): - """ - @param person: XXX Shouldn't this always be Conversation.person? - """ - -class IGroupConversation(Interface): - def show(): - """doesn't seem like it belongs in this interface.""" - - def hide(): - """nor this neither.""" - - def sendText(text, metadata): - pass - - def showGroupMessage(sender, text, metadata): - pass - - def setGroupMembers(members): - """Sets the list of members in the group and displays it to the user - """ - - def setTopic(topic, author): - """Displays the topic (from the server) for the group conversation window - - @type topic: string - @type author: string (XXX: Not Person?) - """ - - def memberJoined(member): - """Adds the given member to the list of members in the group conversation - and displays this to the user - - @type member: string (XXX: Not Person?) - """ - - def memberChangedNick(oldnick, newnick): - """Changes the oldnick in the list of members to newnick and displays this - change to the user - - @type oldnick: string (XXX: Not Person?) - @type newnick: string - """ - - def memberLeft(member): - """Deletes the given member from the list of members in the group - conversation and displays the change to the user - - @type member: string (XXX: Not Person?) - """ - - -class IChatUI(Interface): - def registerAccountClient(client): - """Notifies user that an account has been signed on to. - - @type client: L{Client} - """ - - def unregisterAccountClient(client): - """Notifies user that an account has been signed off or disconnected - - @type client: L{Client} - """ - - def getContactsList(): - """ - @returntype: L{ContactsList} - """ - - # WARNING: You'll want to be polymorphed into something with - # intrinsic stoning resistance before continuing. - - def getConversation(person, Class, stayHidden=0): - """For the given person object, returns the conversation window - or creates and returns a new conversation window if one does not exist. - - @type person: L{Person} - @type Class: L{Conversation} class - @type stayHidden: boolean - - @returntype: L{Conversation} - """ - - def getGroupConversation(group,Class,stayHidden=0): - """For the given group object, returns the group conversation window or - creates and returns a new group conversation window if it doesn't exist. - - @type group: L{Group} - @type Class: L{Conversation} class - @type stayHidden: boolean - - @returntype: L{GroupConversation} - """ - - def getPerson(name, client): - """Get a Person for a client. - - Duplicates L{IAccount.getPerson}. - - @type name: string - @type client: L{Client} - - @returntype: L{Person} - """ - - def getGroup(name, client): - """Get a Group for a client. - - Duplicates L{IAccount.getGroup}. - - @type name: string - @type client: L{Client} - - @returntype: L{Group} - """ - - def contactChangedNick(oldnick, newnick): - """For the given person, changes the person's name to newnick, and - tells the contact list and any conversation windows with that person - to change as well. - - @type oldnick: string - @type newnick: string - """ diff --git a/tools/buildbot/pylibs/twisted/words/im/ircsupport.py b/tools/buildbot/pylibs/twisted/words/im/ircsupport.py deleted file mode 100644 index 3fe5c65..0000000 --- a/tools/buildbot/pylibs/twisted/words/im/ircsupport.py +++ /dev/null @@ -1,268 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""IRC support for Instance Messenger.""" - -import string - -from twisted.words.protocols import irc -from twisted.words.im.locals import ONLINE -from twisted.internet import defer, reactor, protocol -from twisted.internet.defer import succeed -from twisted.words.im import basesupport, interfaces, locals -from zope.interface import implements - - -class IRCPerson(basesupport.AbstractPerson): - - def imperson_whois(self): - if self.account.client is None: - raise locals.OfflineError - self.account.client.sendLine("WHOIS %s" % self.name) - - ### interface impl - - def isOnline(self): - return ONLINE - - def getStatus(self): - return ONLINE - - def setStatus(self,status): - self.status=status - self.chat.getContactsList().setContactStatus(self) - - def sendMessage(self, text, meta=None): - if self.account.client is None: - raise locals.OfflineError - for line in string.split(text, '\n'): - if meta and meta.get("style", None) == "emote": - self.account.client.ctcpMakeQuery(self.name,[('ACTION', line)]) - else: - self.account.client.msg(self.name, line) - return succeed(text) - -class IRCGroup(basesupport.AbstractGroup): - - implements(interfaces.IGroup) - - def imgroup_testAction(self): - print 'action test!' - - def imtarget_kick(self, target): - if self.account.client is None: - raise locals.OfflineError - reason = "for great justice!" - self.account.client.sendLine("KICK #%s %s :%s" % ( - self.name, target.name, reason)) - - ### Interface Implementation - - def setTopic(self, topic): - if self.account.client is None: - raise locals.OfflineError - self.account.client.topic(self.name, topic) - - def sendGroupMessage(self, text, meta={}): - if self.account.client is None: - raise locals.OfflineError - if meta and meta.get("style", None) == "emote": - self.account.client.me(self.name,text) - return succeed(text) - #standard shmandard, clients don't support plain escaped newlines! - for line in string.split(text, '\n'): - self.account.client.say(self.name, line) - return succeed(text) - - def leave(self): - if self.account.client is None: - raise locals.OfflineError - self.account.client.leave(self.name) - self.account.client.getGroupConversation(self.name,1) - - -class IRCProto(basesupport.AbstractClientMixin, irc.IRCClient): - def __init__(self, account, chatui, logonDeferred=None): - basesupport.AbstractClientMixin.__init__(self, account, chatui, - logonDeferred) - self._namreplies={} - self._ingroups={} - self._groups={} - self._topics={} - - def getGroupConversation(self, name, hide=0): - name=string.lower(name) - return self.chat.getGroupConversation(self.chat.getGroup(name, self), - stayHidden=hide) - - def getPerson(self,name): - return self.chat.getPerson(name, self) - - def connectionMade(self): - # XXX: Why do I duplicate code in IRCClient.register? - try: - print 'connection made on irc service!?', self - if self.account.password: - self.sendLine("PASS :%s" % self.account.password) - self.setNick(self.account.username) - self.sendLine("USER %s foo bar :Twisted-IM user" % (self.nickname,)) - for channel in self.account.channels: - self.joinGroup(channel) - self.account._isOnline=1 - print 'uh, registering irc acct' - if self._logonDeferred is not None: - self._logonDeferred.callback(self) - self.chat.getContactsList() - except: - import traceback - traceback.print_exc() - - def setNick(self,nick): - self.name=nick - self.accountName="%s (IRC)"%nick - irc.IRCClient.setNick(self,nick) - - def kickedFrom(self, channel, kicker, message): - """Called when I am kicked from a channel. - """ - print 'ono i was kicked', channel, kicker, message - return self.chat.getGroupConversation( - self.chat.getGroup(channel[1:], self), 1) - - def userKicked(self, kickee, channel, kicker, message): - print 'whew somebody else', kickee, channel, kicker, message - - def noticed(self, username, channel, message): - self.privmsg(username, channel, message, {"dontAutoRespond": 1}) - - def privmsg(self, username, channel, message, metadata=None): - if metadata is None: - metadata = {} - username=string.split(username,'!',1)[0] - if username==self.name: return - if channel[0]=='#': - group=channel[1:] - self.getGroupConversation(group).showGroupMessage(username, message, metadata) - return - self.chat.getConversation(self.getPerson(username)).showMessage(message, metadata) - - def action(self,username,channel,emote): - username=string.split(username,'!',1)[0] - if username==self.name: return - meta={'style':'emote'} - if channel[0]=='#': - group=channel[1:] - self.getGroupConversation(group).showGroupMessage(username, emote, meta) - return - self.chat.getConversation(self.getPerson(username)).showMessage(emote,meta) - - def irc_RPL_NAMREPLY(self,prefix,params): - """ - RPL_NAMREPLY - >> NAMES #bnl - << :Arlington.VA.US.Undernet.Org 353 z3p = #bnl :pSwede Dan-- SkOyg AG - """ - group=string.lower(params[2][1:]) - users=string.split(params[3]) - for ui in range(len(users)): - while users[ui][0] in ["@","+"]: # channel modes - users[ui]=users[ui][1:] - if not self._namreplies.has_key(group): - self._namreplies[group]=[] - self._namreplies[group].extend(users) - for nickname in users: - try: - self._ingroups[nickname].append(group) - except: - self._ingroups[nickname]=[group] - - def irc_RPL_ENDOFNAMES(self,prefix,params): - group=params[1][1:] - self.getGroupConversation(group).setGroupMembers(self._namreplies[string.lower(group)]) - del self._namreplies[string.lower(group)] - - def irc_RPL_TOPIC(self,prefix,params): - self._topics[params[1][1:]]=params[2] - - def irc_333(self,prefix,params): - group=params[1][1:] - self.getGroupConversation(group).setTopic(self._topics[group],params[2]) - del self._topics[group] - - def irc_TOPIC(self,prefix,params): - nickname = string.split(prefix,"!")[0] - group = params[0][1:] - topic = params[1] - self.getGroupConversation(group).setTopic(topic,nickname) - - def irc_JOIN(self,prefix,params): - nickname=string.split(prefix,"!")[0] - group=string.lower(params[0][1:]) - if nickname!=self.nickname: - try: - self._ingroups[nickname].append(group) - except: - self._ingroups[nickname]=[group] - self.getGroupConversation(group).memberJoined(nickname) - - def irc_PART(self,prefix,params): - nickname=string.split(prefix,"!")[0] - group=string.lower(params[0][1:]) - if nickname!=self.nickname: - if group in self._ingroups[nickname]: - self._ingroups[nickname].remove(group) - self.getGroupConversation(group).memberLeft(nickname) - else: - print "%s left %s, but wasn't in the room."%(nickname,group) - - def irc_QUIT(self,prefix,params): - nickname=string.split(prefix,"!")[0] - if self._ingroups.has_key(nickname): - for group in self._ingroups[nickname]: - self.getGroupConversation(group).memberLeft(nickname) - self._ingroups[nickname]=[] - else: - print '*** WARNING: ingroups had no such key %s' % nickname - - def irc_NICK(self, prefix, params): - fromNick = string.split(prefix, "!")[0] - toNick = params[0] - if not self._ingroups.has_key(fromNick): - print "%s changed nick to %s. But she's not in any groups!?" % (fromNick, toNick) - return - for group in self._ingroups[fromNick]: - self.getGroupConversation(group).memberChangedNick(fromNick, toNick) - self._ingroups[toNick] = self._ingroups[fromNick] - del self._ingroups[fromNick] - - def irc_unknown(self, prefix, command, params): - print "unknown message from IRCserver. prefix: %s, command: %s, params: %s" % (prefix, command, params) - - # GTKIM calls - def joinGroup(self,name): - self.join(name) - self.getGroupConversation(name) - -class IRCAccount(basesupport.AbstractAccount): - implements(interfaces.IAccount) - gatewayType = "IRC" - - _groupFactory = IRCGroup - _personFactory = IRCPerson - - def __init__(self, accountName, autoLogin, username, password, host, port, - channels=''): - basesupport.AbstractAccount.__init__(self, accountName, autoLogin, - username, password, host, port) - self.channels = map(string.strip,string.split(channels,',')) - if self.channels == ['']: - self.channels = [] - - def _startLogOn(self, chatui): - logonDeferred = defer.Deferred() - cc = protocol.ClientCreator(reactor, IRCProto, self, chatui, - logonDeferred) - d = cc.connectTCP(self.host, self.port) - d.addErrback(logonDeferred.errback) - return logonDeferred diff --git a/tools/buildbot/pylibs/twisted/words/im/jyaccount.py b/tools/buildbot/pylibs/twisted/words/im/jyaccount.py deleted file mode 100644 index 41b9004..0000000 --- a/tools/buildbot/pylibs/twisted/words/im/jyaccount.py +++ /dev/null @@ -1,243 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -from twisted.words.im.baseaccount import AccountManager -from twisted.words.im.pbsupport import PBAccount -from twisted.words.im.tocsupport import TOCAccount -from twisted.words.im.ircsupport import IRCAccount -import twisted.words.im.jychat - -from java.awt import GridLayout, FlowLayout, BorderLayout, Container -import sys -from java.awt.event import ActionListener -from javax.swing import JTextField, JPasswordField, JComboBox, JPanel, JLabel,\ - JCheckBox, JFrame, JButton, BoxLayout, JTable, JScrollPane, \ - ListSelectionModel -from javax.swing.border import TitledBorder -from javax.swing.table import DefaultTableModel - -doublebuffered = 0 -stype = "twisted.words" - - -class NewAccountGUI: - def __init__(self, amgui): - self.amgui = amgui - self.am = amgui.acctmanager - self.buildgwinfo() - self.autologin = JCheckBox("Automatically Log In") - self.acctname = JTextField() - self.gwoptions = JPanel(doublebuffered) - self.gwoptions.border = TitledBorder("Gateway Options") - self.buildgwoptions("Twisted") - self.mainframe = JFrame("New Account Window") - self.buildpane() - - def buildgwinfo(self): - self.gateways = {"Twisted" : {"ident" : JTextField(), - "passwd" : JPasswordField(), - "host" : JTextField("twistedmatrix.com"), - "port" : JTextField("8787"), - "service" : JTextField("twisted.words"), - "persp" : JTextField()}, - "AIM" : {"ident" : JTextField(), - "passwd" : JPasswordField(), - "host" : JTextField("toc.oscar.aol.com"), - "port" : JTextField("9898")}, - "IRC" : {"ident" : JTextField(), - "passwd" : JPasswordField(), - "host" : JTextField(), - "port" : JTextField("6667"), - "channels" : JTextField()} - } - self.displayorder = { "Twisted" : [["Identity Name", "ident"], - ["Password", "passwd"], - ["Host", "host"], - ["Port", "port"], - ["Service Name", "service"], - ["Perspective Name", "persp"]], - "AIM" : [["Screen Name", "ident"], - ["Password", "passwd"], - ["Host", "host"], - ["Port", "port"]], - "IRC" : [["Nickname", "ident"], - ["Password", "passwd"], - ["Host", "host"], - ["Port", "port"], - ["Channels", "channels"]] - } - - def buildgwoptions(self, gw): - self.gwoptions.removeAll() - self.gwoptions.layout = GridLayout(len(self.gateways[gw]), 2) - for mapping in self.displayorder[gw]: - self.gwoptions.add(JLabel(mapping[0])) - self.gwoptions.add(self.gateways[gw][mapping[1]]) - - def buildpane(self): - gw = JPanel(GridLayout(1, 2), doublebuffered) - gw.add(JLabel("Gateway")) - self.gwlist = JComboBox(self.gateways.keys())#, actionPerformed=self.changegw) - self.gwlist.setSelectedItem("Twisted") - gw.add(self.gwlist) - - stdoptions = JPanel(GridLayout(2, 2), doublebuffered) - stdoptions.border = TitledBorder("Standard Options") - stdoptions.add(JLabel()) - stdoptions.add(self.autologin) - stdoptions.add(JLabel("Account Name")) - stdoptions.add(self.acctname) - - buttons = JPanel(FlowLayout(), doublebuffered) - buttons.add(JButton("OK", actionPerformed=self.addaccount)) - buttons.add(JButton("Cancel", actionPerformed=self.cancel)) - - mainpane = self.mainframe.getContentPane() - mainpane.layout = BoxLayout(mainpane, BoxLayout.Y_AXIS) - mainpane.add(gw) - mainpane.add(self.gwoptions) - mainpane.add(stdoptions) - mainpane.add(buttons) - - def show(self): - self.mainframe.setLocation(100, 100) - self.mainframe.pack() - self.mainframe.show() - - #actionlisteners - def changegw(self, ae): - self.buildgwoptions(self.gwlist.getSelectedItem()) - self.mainframe.pack() - self.mainframe.show() - - def addaccount(self, ae): - gwselection = self.gwlist.getSelectedItem() - gw = self.gateways[gwselection] - name = gw["ident"].text - passwd = gw["passwd"].text - host = gw["host"].text - port = int(gw["port"].text) - autologin = self.autologin.isSelected() - acctname = self.acctname.text - - if gwselection == "Twisted": - sname = gw["service"].text - perspective = gw["persp"].text - self.am.addAccount(PBAccount(acctname, autologin, name, passwd, - host, port, - [[stype, sname, perspective]])) - elif gwselection == "AIM": - self.am.addAccount(TOCAccount(acctname, autologin, name, passwd, - host, port)) - elif gwselection == "IRC": - channels = gw["channels"].text - self.am.addAccount(IRCAccount(acctname, autologin, name, passwd, - host, port, channels)) - - self.amgui.update() - print "Added new account" - self.mainframe.dispose() - - def cancel(self, ae): - print "Cancelling new account creation" - self.mainframe.dispose() - - -class UneditableTableModel(DefaultTableModel): - def isCellEditable(self, x, y): - return 0 - -class AccountManagementGUI: - def __init__(self): - self.acctmanager = AccountManager() - self.mainframe = JFrame("Account Manager") - self.chatui = None - self.headers = ["Account Name", "Status", "Autologin", "Gateway"] - self.data = UneditableTableModel([], self.headers) - self.table = JTable(self.data) - self.table.columnSelectionAllowed = 0 #cannot select columns - self.table.selectionMode = ListSelectionModel.SINGLE_SELECTION - - self.connectbutton = JButton("Connect", actionPerformed=self.connect) - self.dconnbutton = JButton("Disconnect", actionPerformed=self.disconnect) - self.deletebutton = JButton("Delete", actionPerformed=self.deleteAccount) - self.buildpane() - self.mainframe.pack() - self.mainframe.show() - - def buildpane(self): - buttons = JPanel(FlowLayout(), doublebuffered) - buttons.add(self.connectbutton) - buttons.add(self.dconnbutton) - buttons.add(JButton("New", actionPerformed=self.addNewAccount)) - buttons.add(self.deletebutton) - buttons.add(JButton("Quit", actionPerformed=self.quit)) - - mainpane = self.mainframe.getContentPane() - mainpane.layout = BoxLayout(mainpane, BoxLayout.Y_AXIS) - mainpane.add(JScrollPane(self.table)) - mainpane.add(buttons) - self.update() - - def update(self): - self.data.setDataVector(self.acctmanager.getSnapShot(), self.headers) - if self.acctmanager.isEmpty(): - self.deletebutton.setEnabled(0) - self.connectbutton.setEnabled(0) - self.dconnbutton.setEnabled(0) - else: - self.deletebutton.setEnabled(1) - if not 1 in self.acctmanager.getConnectionInfo(): #all disconnected - self.dconnbutton.setEnabled(0) - self.connectbutton.setEnabled(1) - elif not 0 in self.acctmanager.getConnectionInfo(): #all connected - self.dconnbutton.setEnabled(1) - self.connectbutton.setEnabled(0) - else: - self.dconnbutton.setEnabled(1) - self.connectbutton.setEnabled(1) - - #callable button actions - def connect(self, ae): - print "Trying to connect" - row = self.table.getSelectedRow() - if row < 0: - print "Trying to connect to an account but no account selected" - else: - acctname = self.data.getValueAt(row, 0) - if not self.chatui: - self.chatui = twisted.words.im.jychat.JyChatUI() - self.acctmanager.connect(acctname, self.chatui) - self.update() - - def disconnect(self, ae): - print "Trying to disconnect" - row = self.table.getSelectedRow() - if row < 0: - print "Trying to logoff an account but no account was selected." - else: - acctname = self.data.getValueAt(row, 0) - self.acctmanager.disconnect(acctname) - self.update() - - def addNewAccount(self, ae): - print "Starting new account creation" - NewAccountGUI(self).show() - - def deleteAccount(self, ae): - print "Deleting account" - row = self.table.getSelectedRow() - if row < 0: - print "Trying to delete an account but no account selected" - else: - acctname = self.data.getValueAt(row, 0) - self.acctmanager.delAccount(acctname) - self.update() - - def quit(self, ae): - self.acctmanager.quit() - sys.exit() - -if __name__ == "__main__": - n = AccountManagementGUI() diff --git a/tools/buildbot/pylibs/twisted/words/im/jychat.py b/tools/buildbot/pylibs/twisted/words/im/jychat.py deleted file mode 100644 index 54d4ca8..0000000 --- a/tools/buildbot/pylibs/twisted/words/im/jychat.py +++ /dev/null @@ -1,286 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -from twisted.words.im.basechat import ContactsList, Conversation, GroupConversation,\ - ChatUI -from twisted.words.im.locals import OFFLINE, ONLINE, AWAY - -from java.awt import GridLayout, FlowLayout, BorderLayout, Container -import sys -from java.awt.event import ActionListener -from javax.swing import JTextField, JPasswordField, JComboBox, JPanel, JLabel,\ - JTextArea, JFrame, JButton, BoxLayout, JTable, JScrollPane, \ - ListSelectionModel -from javax.swing.table import DefaultTableModel - -doublebuffered = 0 - - -class UneditableTableModel(DefaultTableModel): - def isCellEditable(self, x, y): - return 0 - -class _AccountAdder: - def __init__(self, contactslist): - self.contactslist = contactslist - self.mainframe = JFrame("Add New Contact") - self.account = JComboBox(self.contactslist.clientsByName.keys()) - self.contactname = JTextField() - self.buildpane() - - def buildpane(self): - buttons = JPanel() - buttons.add(JButton("OK", actionPerformed=self.add)) - buttons.add(JButton("Cancel", actionPerformed=self.cancel)) - - acct = JPanel(GridLayout(1, 2), doublebuffered) - acct.add(JLabel("Account")) - acct.add(self.account) - - mainpane = self.mainframe.getContentPane() - mainpane.setLayout(BoxLayout(mainpane, BoxLayout.Y_AXIS)) - mainpane.add(self.contactname) - mainpane.add(acct) - mainpane.add(buttons) - self.mainframe.pack() - self.mainframe.show() - - #action listeners - def add(self, ae): - acct = self.contactslist.clientsByName[self.account.getSelectedItem()] - acct.addContact(self.contactname.getText()) - self.mainframe.dispose() - - def cancel(self, ae): - self.mainframe.dispose() - -class ContactsListGUI(ContactsList): - """A GUI object that displays a contacts list""" - def __init__(self, chatui): - ContactsList.__init__(self, chatui) - self.clientsByName = {} - self.mainframe = JFrame("Contacts List") - self.headers = ["Contact", "Status", "Idle", "Account"] - self.data = UneditableTableModel([], self.headers) - self.table = JTable(self.data, - columnSelectionAllowed = 0, #cannot select columns - selectionMode = ListSelectionModel.SINGLE_SELECTION) - - self.buildpane() - self.mainframe.pack() - self.mainframe.show() - - def setContactStatus(self, person): - ContactsList.setContactStatus(self, person) - self.update() - - def registerAccountClient(self, client): - ContactsList.registerAccountClient(self, client) - if not client.accountName in self.clientsByName.keys(): - self.clientsByName[client.accountName] = client - - def unregisterAccount(self, client): - ContactsList.unregisterAccountClient(self, client) - if client.accountName in self.clientsByName.keys(): - del self.clientsByName[client.accountName] - - def contactChangedNick(self, person, newnick): - ContactsList.contactChangedNick(self, person, newnick) - self.update() - - #GUI code - def buildpane(self): - buttons = JPanel(FlowLayout(), doublebuffered) - buttons.add(JButton("Send Message", actionPerformed=self.message)) - buttons.add(JButton("Add Contact", actionPerformed=self.addContact)) - #buttons.add(JButton("Quit", actionPerformed=self.quit)) - - mainpane = self.mainframe.getContentPane() - mainpane.setLayout(BoxLayout(mainpane, BoxLayout.Y_AXIS)) - mainpane.add(JScrollPane(self.table)) - mainpane.add(buttons) - self.update() - - def update(self): - contactdata = [] - for contact in self.onlineContacts.values(): - if contact.status == AWAY: - stat = "(away)" - else: - stat = "(active)" - contactdata.append([contact.name, stat, contact.getIdleTime(), - contact.client.accountName]) - self.data.setDataVector(contactdata, self.headers) - - #callable actionlisteners - def message(self, ae): - row = self.table.getSelectedRow() - if row < 0: - print "Trying to send IM to person, but no person selected" - else: - person = self.onlineContacts[self.data.getValueAt(row, 0)] - self.chat.getConversation(person) - - def addContact(self, ae): - _AccountAdder(self) - - def quit(self, ae): - sys.exit() - - -class ConversationWindow(Conversation): - """A GUI window of a conversation with a specific person""" - def __init__(self, person, chatui): - """ConversationWindow(basesupport.AbstractPerson:person)""" - Conversation.__init__(self, person, chatui) - self.mainframe = JFrame("Conversation with "+person.name) - self.display = JTextArea(columns=100, - rows=15, - editable=0, - lineWrap=1) - self.typepad = JTextField() - self.buildpane() - self.lentext = 0 - - def buildpane(self): - buttons = JPanel(doublebuffered) - buttons.add(JButton("Send", actionPerformed=self.send)) - buttons.add(JButton("Hide", actionPerformed=self.hidewindow)) - - mainpane = self.mainframe.getContentPane() - mainpane.setLayout(BoxLayout(mainpane, BoxLayout.Y_AXIS)) - mainpane.add(JScrollPane(self.display)) - self.typepad.actionPerformed = self.send - mainpane.add(self.typepad) - mainpane.add(buttons) - - def show(self): - self.mainframe.pack() - self.mainframe.show() - - def hide(self): - self.mainframe.hide() - - def sendText(self, text): - self.displayText("\n"+self.person.client.name+": "+text) - Conversation.sendText(self, text) - - def showMessage(self, text, metadata=None): - self.displayText("\n"+self.person.name+": "+text) - - def contactChangedNick(self, person, newnick): - Conversation.contactChangedNick(self, person, newnick) - self.mainframe.setTitle("Conversation with "+newnick) - - #GUI code - def displayText(self, text): - self.lentext = self.lentext + len(text) - self.display.append(text) - self.display.setCaretPosition(self.lentext) - - #actionlisteners - def hidewindow(self, ae): - self.hide() - - def send(self, ae): - text = self.typepad.getText() - self.typepad.setText("") - if text != "" and text != None: - self.sendText(text) - - -class GroupConversationWindow(GroupConversation): - """A GUI window of a conversation witha group of people""" - def __init__(self, group, chatui): - GroupConversation.__init__(self, group, chatui) - self.mainframe = JFrame(self.group.name) - self.headers = ["Member"] - self.memberdata = UneditableTableModel([], self.headers) - self.display = JTextArea(columns=100, rows=15, editable=0, lineWrap=1) - self.typepad = JTextField() - self.buildpane() - self.lentext = 0 - - def show(self): - self.mainframe.pack() - self.mainframe.show() - - def hide(self): - self.mainframe.hide() - - def showGroupMessage(self, sender, text, metadata=None): - self.displayText(sender + ": " + text) - - def setGroupMembers(self, members): - GroupConversation.setGroupMembers(self, members) - self.updatelist() - - def setTopic(self, topic, author): - topictext = "Topic: " + topic + ", set by " + author - self.mainframe.setTitle(self.group.name + ": " + topictext) - self.displayText(topictext) - - def memberJoined(self, member): - GroupConversation.memberJoined(self, member) - self.updatelist() - - def memberChangedNick(self, oldnick, newnick): - GroupConversation.memberChangedNick(self, oldnick, newnick) - self.updatelist() - - def memberLeft(self, member): - GroupConversation.memberLeft(self, member) - self.updatelist() - - #GUI code - def buildpane(self): - buttons = JPanel(doublebuffered) - buttons.add(JButton("Hide", actionPerformed=self.hidewindow)) - - memberpane = JTable(self.memberdata) - memberframe = JScrollPane(memberpane) - - chat = JPanel(doublebuffered) - chat.setLayout(BoxLayout(chat, BoxLayout.Y_AXIS)) - chat.add(JScrollPane(self.display)) - self.typepad.actionPerformed = self.send - chat.add(self.typepad) - chat.add(buttons) - - mainpane = self.mainframe.getContentPane() - mainpane.setLayout(BoxLayout(mainpane, BoxLayout.X_AXIS)) - mainpane.add(chat) - mainpane.add(memberframe) - - def displayText(self, text): - self.lentext = self.lentext + len(text) - self.display.append(text) - self.display.setCaretPosition(self.lentext) - - def updatelist(self): - self.memberdata.setDataVector([self.members], self.headers) - - #actionListener - def send(self, ae): - text = self.typepad.getText() - self.typepad.setText("") - if text != "" and text != None: - GroupConversation.sendText(self, text) - - def hidewindow(self, ae): - self.hide() - -class JyChatUI(ChatUI): - def __init__(self): - ChatUI.__init__(self) - self.contactsList = ContactsListGUI(self) - - def getConversation(self, person, stayHidden=0): - return ChatUI.getGroupConversation(self, person, ConversationWindow, - stayHidden) - - def getGroupConversation(self, group, stayHidden=0): - return ChatUI.getGroupConversation(self, group, - GroupConversationWindow, - stayHidden) diff --git a/tools/buildbot/pylibs/twisted/words/im/locals.py b/tools/buildbot/pylibs/twisted/words/im/locals.py deleted file mode 100644 index 02025f9..0000000 --- a/tools/buildbot/pylibs/twisted/words/im/locals.py +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -class Enum: - group = None - - def __init__(self, label): - self.label = label - - def __repr__(self): - return '<%s: %s>' % (self.group, self.label) - - def __str__(self): - return self.label - - -class StatusEnum(Enum): - group = 'Status' - -OFFLINE = Enum('Offline') -ONLINE = Enum('Online') -AWAY = Enum('Away') - -class OfflineError(Exception): - """The requested action can't happen while offline.""" diff --git a/tools/buildbot/pylibs/twisted/words/im/pbsupport.py b/tools/buildbot/pylibs/twisted/words/im/pbsupport.py deleted file mode 100644 index 7e750b73..0000000 --- a/tools/buildbot/pylibs/twisted/words/im/pbsupport.py +++ /dev/null @@ -1,260 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""L{twisted.words} support for Instance Messenger.""" - -from __future__ import nested_scopes - -from twisted.internet import defer -from twisted.internet import error -from twisted.python import log -from twisted.python.failure import Failure -from twisted.spread import pb - -from twisted.words.im.locals import ONLINE, OFFLINE, AWAY - -from twisted.words.im import basesupport, interfaces -from zope.interface import implements - - -class TwistedWordsPerson(basesupport.AbstractPerson): - """I a facade for a person you can talk to through a twisted.words service. - """ - def __init__(self, name, wordsAccount): - basesupport.AbstractPerson.__init__(self, name, wordsAccount) - self.status = OFFLINE - - def isOnline(self): - return ((self.status == ONLINE) or - (self.status == AWAY)) - - def getStatus(self): - return self.status - - def sendMessage(self, text, metadata): - """Return a deferred... - """ - if metadata: - d=self.account.client.perspective.directMessage(self.name, - text, metadata) - d.addErrback(self.metadataFailed, "* "+text) - return d - else: - return self.account.client.perspective.callRemote('directMessage',self.name, text) - - def metadataFailed(self, result, text): - print "result:",result,"text:",text - return self.account.client.perspective.directMessage(self.name, text) - - def setStatus(self, status): - self.status = status - self.chat.getContactsList().setContactStatus(self) - -class TwistedWordsGroup(basesupport.AbstractGroup): - implements(interfaces.IGroup) - def __init__(self, name, wordsClient): - basesupport.AbstractGroup.__init__(self, name, wordsClient) - self.joined = 0 - - def sendGroupMessage(self, text, metadata=None): - """Return a deferred. - """ - #for backwards compatibility with older twisted.words servers. - if metadata: - d=self.account.client.perspective.callRemote( - 'groupMessage', self.name, text, metadata) - d.addErrback(self.metadataFailed, "* "+text) - return d - else: - return self.account.client.perspective.callRemote('groupMessage', - self.name, text) - - def setTopic(self, text): - self.account.client.perspective.callRemote( - 'setGroupMetadata', - {'topic': text, 'topic_author': self.client.name}, - self.name) - - def metadataFailed(self, result, text): - print "result:",result,"text:",text - return self.account.client.perspective.callRemote('groupMessage', - self.name, text) - - def joining(self): - self.joined = 1 - - def leaving(self): - self.joined = 0 - - def leave(self): - return self.account.client.perspective.callRemote('leaveGroup', - self.name) - - - -class TwistedWordsClient(pb.Referenceable, basesupport.AbstractClientMixin): - """In some cases, this acts as an Account, since it a source of text - messages (multiple Words instances may be on a single PB connection) - """ - def __init__(self, acct, serviceName, perspectiveName, chatui, - _logonDeferred=None): - self.accountName = "%s (%s:%s)" % (acct.accountName, serviceName, perspectiveName) - self.name = perspectiveName - print "HELLO I AM A PB SERVICE", serviceName, perspectiveName - self.chat = chatui - self.account = acct - self._logonDeferred = _logonDeferred - - def getPerson(self, name): - return self.chat.getPerson(name, self) - - def getGroup(self, name): - return self.chat.getGroup(name, self) - - def getGroupConversation(self, name): - return self.chat.getGroupConversation(self.getGroup(name)) - - def addContact(self, name): - self.perspective.callRemote('addContact', name) - - def remote_receiveGroupMembers(self, names, group): - print 'received group members:', names, group - self.getGroupConversation(group).setGroupMembers(names) - - def remote_receiveGroupMessage(self, sender, group, message, metadata=None): - print 'received a group message', sender, group, message, metadata - self.getGroupConversation(group).showGroupMessage(sender, message, metadata) - - def remote_memberJoined(self, member, group): - print 'member joined', member, group - self.getGroupConversation(group).memberJoined(member) - - def remote_memberLeft(self, member, group): - print 'member left' - self.getGroupConversation(group).memberLeft(member) - - def remote_notifyStatusChanged(self, name, status): - self.chat.getPerson(name, self).setStatus(status) - - def remote_receiveDirectMessage(self, name, message, metadata=None): - self.chat.getConversation(self.chat.getPerson(name, self)).showMessage(message, metadata) - - def remote_receiveContactList(self, clist): - for name, status in clist: - self.chat.getPerson(name, self).setStatus(status) - - def remote_setGroupMetadata(self, dict_, groupName): - if dict_.has_key("topic"): - self.getGroupConversation(groupName).setTopic(dict_["topic"], dict_.get("topic_author", None)) - - def joinGroup(self, name): - self.getGroup(name).joining() - return self.perspective.callRemote('joinGroup', name).addCallback(self._cbGroupJoined, name) - - def leaveGroup(self, name): - self.getGroup(name).leaving() - return self.perspective.callRemote('leaveGroup', name).addCallback(self._cbGroupLeft, name) - - def _cbGroupJoined(self, result, name): - groupConv = self.chat.getGroupConversation(self.getGroup(name)) - groupConv.showGroupMessage("sys", "you joined") - self.perspective.callRemote('getGroupMembers', name) - - def _cbGroupLeft(self, result, name): - print 'left',name - groupConv = self.chat.getGroupConversation(self.getGroup(name), 1) - groupConv.showGroupMessage("sys", "you left") - - def connected(self, perspective): - print 'Connected Words Client!', perspective - if self._logonDeferred is not None: - self._logonDeferred.callback(self) - self.perspective = perspective - self.chat.getContactsList() - - -pbFrontEnds = { - "twisted.words": TwistedWordsClient, - "twisted.reality": None - } - - -class PBAccount(basesupport.AbstractAccount): - implements(interfaces.IAccount) - gatewayType = "PB" - _groupFactory = TwistedWordsGroup - _personFactory = TwistedWordsPerson - - def __init__(self, accountName, autoLogin, username, password, host, port, - services=None): - """ - @param username: The name of your PB Identity. - @type username: string - """ - basesupport.AbstractAccount.__init__(self, accountName, autoLogin, - username, password, host, port) - self.services = [] - if not services: - services = [('twisted.words', 'twisted.words', username)] - for serviceType, serviceName, perspectiveName in services: - self.services.append([pbFrontEnds[serviceType], serviceName, - perspectiveName]) - - def logOn(self, chatui): - """ - @returns: this breaks with L{interfaces.IAccount} - @returntype: DeferredList of L{interfaces.IClient}s - """ - # Overriding basesupport's implementation on account of the - # fact that _startLogOn tends to return a deferredList rather - # than a simple Deferred, and we need to do registerAccountClient. - if (not self._isConnecting) and (not self._isOnline): - self._isConnecting = 1 - d = self._startLogOn(chatui) - d.addErrback(self._loginFailed) - def registerMany(results): - for success, result in results: - if success: - chatui.registerAccountClient(result) - self._cb_logOn(result) - else: - log.err(result) - d.addCallback(registerMany) - return d - else: - raise error.ConnectionError("Connection in progress") - - - def _startLogOn(self, chatui): - print 'Connecting...', - d = pb.getObjectAt(self.host, self.port) - d.addCallbacks(self._cbConnected, self._ebConnected, - callbackArgs=(chatui,)) - return d - - def _cbConnected(self, root, chatui): - print 'Connected!' - print 'Identifying...', - d = pb.authIdentity(root, self.username, self.password) - d.addCallbacks(self._cbIdent, self._ebConnected, - callbackArgs=(chatui,)) - return d - - def _cbIdent(self, ident, chatui): - if not ident: - print 'falsely identified.' - return self._ebConnected(Failure(Exception("username or password incorrect"))) - print 'Identified!' - dl = [] - for handlerClass, sname, pname in self.services: - d = defer.Deferred() - dl.append(d) - handler = handlerClass(self, sname, pname, chatui, d) - ident.callRemote('attach', sname, pname, handler).addCallback(handler.connected) - return defer.DeferredList(dl) - - def _ebConnected(self, error): - print 'Not connected.' - return error - diff --git a/tools/buildbot/pylibs/twisted/words/im/proxyui.py b/tools/buildbot/pylibs/twisted/words/im/proxyui.py deleted file mode 100644 index de11bf7..0000000 --- a/tools/buildbot/pylibs/twisted/words/im/proxyui.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -from twisted.words.protocols.irc import IRC -from twisted.python import log -from twisted.internet.protocol import Factory - -class IRCUserInterface(IRC): - def connectionLost(self): - del self.factory.ircui - -class IRCUIFactory(Factory): - ircui = None - def buildProtocol(self): - if self.ircui: - log.msg("already logged in") - return None - i = IRCUserInterface() - i.factory = self - self.ircui = i - return i - diff --git a/tools/buildbot/pylibs/twisted/words/im/tap.py b/tools/buildbot/pylibs/twisted/words/im/tap.py deleted file mode 100644 index 64bddce..0000000 --- a/tools/buildbot/pylibs/twisted/words/im/tap.py +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -from twisted.words.im.proxyui import IRCUIFactory -from twisted.python import usage - -class Options(usage.Options): - optParameters = [["ircport", "p", "6667", - "Port to start the IRC server on."]] - -def updateApplication(app, config): - factory = IRCUIFactory() - app.listenTCP(int(config.opts['ircport']), IRCUIFactory()) diff --git a/tools/buildbot/pylibs/twisted/words/im/tocsupport.py b/tools/buildbot/pylibs/twisted/words/im/tocsupport.py deleted file mode 100644 index 36ac2cd..0000000 --- a/tools/buildbot/pylibs/twisted/words/im/tocsupport.py +++ /dev/null @@ -1,220 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""TOC (i.e. AIM) support for Instance Messenger.""" - -# System Imports -import string, re -from zope.interface import implements - -# Twisted Imports -from twisted.words.protocols import toc -from twisted.words.im.locals import ONLINE, OFFLINE, AWAY -from twisted.internet import defer, reactor, protocol -from twisted.internet.defer import succeed - -# Sibling Imports -from twisted.words.im import basesupport, interfaces, locals - -def dehtml(text): - text=string.replace(text,"
                    ","\n") - text=string.replace(text,"
                    ","\n") - text=string.replace(text,"
                    ","\n") # XXX make this a regexp - text=string.replace(text,"
                    ","\n") - text=re.sub('<.*?>','',text) - text=string.replace(text,'>','>') - text=string.replace(text,'<','<') - text=string.replace(text,'&','&') - text=string.replace(text,' ',' ') - text=string.replace(text,'"','"') - return text - -def html(text): - text=string.replace(text,'"','"') - text=string.replace(text,'&','&') - text=string.replace(text,'<','<') - text=string.replace(text,'>','>') - text=string.replace(text,"\n","
                    ") - return '%s'%text - -class TOCPerson(basesupport.AbstractPerson): - def isOnline(self): - return self.status != OFFLINE - - def getStatus(self): - return self.status - - def getIdleTime(self): - return str(self.idletime) - - def setStatusAndIdle(self, status, idletime): - if self.account.client is None: - raise locals.OfflineError - self.status = status - self.idletime = idletime - self.account.client.chat.getContactsList().setContactStatus(self) - - def sendMessage(self, text, meta=None): - if self.account.client is None: - raise locals.OfflineError - if meta: - if meta.get("style", None) == "emote": - text="* "+text+"* " - self.account.client.say(self.name,html(text)) - return succeed(text) - -class TOCGroup(basesupport.AbstractGroup): - implements(interfaces.IGroup) - def __init__(self, name, tocAccount): - basesupport.AbstractGroup.__init__(self, name, tocAccount) - self.roomID = self.client.roomID[self.name] - - def sendGroupMessage(self, text, meta=None): - if self.account.client is None: - raise locals.OfflineError - if meta: - if meta.get("style", None) == "emote": - text="* "+text+"* " - self.account.client.chat_say(self.roomID,html(text)) - return succeed(text) - - def leave(self): - if self.account.client is None: - raise locals.OfflineError - self.account.client.chat_leave(self.roomID) - - -class TOCProto(basesupport.AbstractClientMixin, toc.TOCClient): - def __init__(self, account, chatui, logonDeferred): - toc.TOCClient.__init__(self, account.username, account.password) - basesupport.AbstractClientMixin.__init__(self, account, chatui, - logonDeferred) - self.roomID = {} - self.roomIDreverse = {} - - def _debug(self, m): - pass #print '', repr(m) - - def getGroupConversation(self, name, hide=0): - return self.chat.getGroupConversation( - self.chat.getGroup(name, self), hide) - - def addContact(self, name): - self.add_buddy([name]) - if not self._buddylist.has_key('TwistedIM'): - self._buddylist['TwistedIM'] = [] - if name in self._buddylist['TwistedIM']: - # whoops, don't add again - return - self._buddylist['TwistedIM'].append(name) - self.set_config(self._config_mode, self._buddylist, self._permit, self._deny) - - def getPerson(self,name): - return self.chat.getPerson(name, self) - - def onLine(self): - self.account._isOnline = 1 - #print '$$!&*$&!(@$*& TOC ONLINE *!#@&$(!*%&' - - def gotConfig(self, mode, buddylist, permit, deny): - #print 'got toc config', repr(mode), repr(buddylist), repr(permit), repr(deny) - self._config_mode = mode - self._buddylist = buddylist - self._permit = permit - self._deny = deny - if permit: - self._debug('adding permit') - self.add_permit(permit) - if deny: - self._debug('adding deny') - self.add_deny(deny) - clist=[] - for k in buddylist.keys(): - self.add_buddy(buddylist[k]) - for name in buddylist[k]: - self.getPerson(name).setStatusAndIdle(OFFLINE, '--') - self.signon() - name = None - def tocNICK(self,data): - if not self.name: - print 'Waiting for second NICK', data - self.name=data[0] - self.accountName = '%s (TOC)' % self.name - self.chat.getContactsList() - else: - print 'reregistering...?', data - self.name=data[0] - # self.accountName = "%s (TOC)"%data[0] - if self._logonDeferred is not None: - self._logonDeferred.callback(self) - self._logonDeferred = None - - ### Error Messages - def hearError(self, code, args): - print '*** TOC ERROR ***', repr(code), repr(args) - def hearWarning(self, newamount, username): - print '*** TOC WARNING ***', repr(newamount), repr(username) - ### Buddy Messages - def hearMessage(self,username,message,autoreply): - if autoreply: - message=': '+message - self.chat.getConversation(self.getPerson(username) - ).showMessage(dehtml(message)) - def updateBuddy(self,username,online,evilness,signontime,idletime,userclass,away): - if away: - status=AWAY - elif online: - status=ONLINE - else: - status=OFFLINE - self.getPerson(username).setStatusAndIdle(status, idletime) - - ### Group Chat - def chatJoined(self, roomid, roomname, users): - self.roomID[roomname]=roomid - self.roomIDreverse[roomid]=roomname - self.getGroupConversation(roomname).setGroupMembers(users) - def chatUpdate(self,roomid,member,inroom): - group=self.roomIDreverse[roomid] - if inroom: - self.getGroupConversation(group).memberJoined(member) - else: - self.getGroupConversation(group).memberLeft(member) - def chatHearMessage(self, roomid, username, message): - if toc.normalize(username) == toc.normalize(self.name): - return # ignore the message - group=self.roomIDreverse[roomid] - self.getGroupConversation(group).showGroupMessage(username, dehtml(message)) - def chatHearWhisper(self, roomid, username, message): - print '*** user whispered *** ', roomid, username, message - def chatInvited(self, roomid, roomname, username, message): - print '*** user invited us to chat *** ',roomid, roomname, username, message - def chatLeft(self, roomid): - group=self.roomIDreverse[roomid] - self.getGroupConversation(group,1) - del self.roomID[group] - del self.roomIDreverse[roomid] - def rvousProposal(self,type,cookie,user,vip,port,**kw): - print '*** rendezvous. ***', type, cookie, user, vip, port, kw - def receiveBytes(self, user, file, chunk, sofar, total): - print '*** File transfer! ***', user, file, chunk, sofar, total - - def joinGroup(self,name): - self.chat_join(4,toc.normalize(name)) - -class TOCAccount(basesupport.AbstractAccount): - implements(interfaces.IAccount) - gatewayType = "AIM (TOC)" - - _groupFactory = TOCGroup - _personFactory = TOCPerson - - def _startLogOn(self, chatui): - logonDeferred = defer.Deferred() - cc = protocol.ClientCreator(reactor, TOCProto, self, chatui, - logonDeferred) - d = cc.connectTCP(self.host, self.port) - d.addErrback(logonDeferred.errback) - return logonDeferred - diff --git a/tools/buildbot/pylibs/twisted/words/iwords.py b/tools/buildbot/pylibs/twisted/words/iwords.py deleted file mode 100644 index 1b9da07..0000000 --- a/tools/buildbot/pylibs/twisted/words/iwords.py +++ /dev/null @@ -1,266 +0,0 @@ -# -*- test-case-name: twisted.words.test -*- -# Copyright (c) 2001-2005 Twisted Matrix Laboratories. -# See LICENSE for details. - -from zope.interface import Interface, Attribute, implements - -class IProtocolPlugin(Interface): - """Interface for plugins providing an interface to a Words service - """ - - name = Attribute("A single word describing what kind of interface this is (eg, irc or web)") - - def getFactory(realm, portal): - """Retrieve a C{twisted.internet.interfaces.IServerFactory} provider - - @param realm: An object providing C{twisted.cred.portal.IRealm} and - C{IChatService}, with which service information should be looked up. - - @param portal: An object providing C{twisted.cred.portal.IPortal}, - through which logins should be performed. - """ - - -class IGroup(Interface): - name = Attribute("A short string, unique among groups.") - - def add(user): - """Include the given user in this group. - - @type user: L{IUser} - """ - - def remove(user, reason=None): - """Remove the given user from this group. - - @type user: L{IUser} - @type reason: C{unicode} - """ - - def size(): - """Return the number of participants in this group. - - @rtype: L{twisted.internet.defer.Deferred} - @return: A Deferred which fires with an C{int} representing the the - number of participants in this group. - """ - - def receive(sender, recipient, message): - """ - Broadcast the given message from the given sender to other - users in group. - - The message is not re-transmitted to the sender. - - @param sender: L{IUser} - - @type recipient: L{IGroup} - @param recipient: This is probably a wart. Maybe it will be removed - in the future. For now, it should be the group object the message - is being delivered to. - - @param message: C{dict} - - @rtype: L{twisted.internet.defer.Deferred} - @return: A Deferred which fires with None when delivery has been - attempted for all users. - """ - - def setMetadata(meta): - """Change the metadata associated with this group. - - @type meta: C{dict} - """ - - def iterusers(): - """Return an iterator of all users in this group. - """ - - -class IChatClient(Interface): - """Interface through which IChatService interacts with clients. - """ - - name = Attribute("A short string, unique among users. This will be set by the L{IChatService} at login time.") - - def receive(sender, recipient, message): - """ - Callback notifying this user of the given message sent by the - given user. - - This will be invoked whenever another user sends a message to a - group this user is participating in, or whenever another user sends - a message directly to this user. In the former case, C{recipient} - will be the group to which the message was sent; in the latter, it - will be the same object as the user who is receiving the message. - - @type sender: L{IUser} - @type recipient: L{IUser} or L{IGroup} - @type message: C{dict} - - @rtype: L{twisted.internet.defer.Deferred} - @return: A Deferred which fires when the message has been delivered, - or which fails in some way. If the Deferred fails and the message - was directed at a group, this user will be removed from that group. - """ - - def groupMetaUpdate(group, meta): - """ - Callback notifying this user that the metadata for the given - group has changed. - - @type group: L{IGroup} - @type meta: C{dict} - - @rtype: L{twisted.internet.defer.Deferred} - """ - - def userJoined(group, user): - """ - Callback notifying this user that the given user has joined - the given group. - - @type group: L{IGroup} - @type user: L{IUser} - - @rtype: L{twisted.internet.defer.Deferred} - """ - - def userLeft(group, user, reason=None): - """ - Callback notifying this user that the given user has left the - given group for the given reason. - - @type group: L{IGroup} - @type user: L{IUser} - @type reason: C{unicode} - - @rtype: L{twisted.internet.defer.Deferred} - """ - - -class IUser(Interface): - """Interface through which clients interact with IChatService. - """ - - realm = Attribute("A reference to the Realm to which this user belongs. Set if and only if the user is logged in.") - mind = Attribute("A reference to the mind which logged in to this user. Set if and only if the user is logged in.") - name = Attribute("A short string, unique among users.") - - lastMessage = Attribute("A POSIX timestamp indicating the time of the last message received from this user.") - signOn = Attribute("A POSIX timestamp indicating this user's most recent sign on time.") - - def loggedIn(realm, mind): - """Invoked by the associated L{IChatService} when login occurs. - - @param realm: The L{IChatService} through which login is occurring. - @param mind: The mind object used for cred login. - """ - - def send(recipient, message): - """Send the given message to the given user or group. - - @type recipient: Either L{IUser} or L{IGroup} - @type message: C{dict} - """ - - def join(group): - """Attempt to join the given group. - - @type group: L{IGroup} - @rtype: L{twisted.internet.defer.Deferred} - """ - - def leave(group): - """Discontinue participation in the given group. - - @type group: L{IGroup} - @rtype: L{twisted.internet.defer.Deferred} - """ - - def itergroups(): - """ - Return an iterator of all groups of which this user is a - member. - """ - - -class IChatService(Interface): - name = Attribute("A short string identifying this chat service (eg, a hostname)") - - createGroupOnRequest = Attribute( - "A boolean indicating whether L{getGroup} should implicitly " - "create groups which are requested but which do not yet exist.") - - createUserOnRequest = Attribute( - "A boolean indicating whether L{getUser} should implicitly " - "create users which are requested but which do not yet exist.") - - def itergroups(): - """Return all groups available on this service. - - @rtype: C{twisted.internet.defer.Deferred} - @return: A Deferred which fires with a list of C{IGroup} providers. - """ - - def getGroup(name): - """Retrieve the group by the given name. - - @type name: C{str} - - @rtype: L{twisted.internet.defer.Deferred} - @return: A Deferred which fires with the group with the given - name if one exists (or if one is created due to the setting of - L{createGroupOnRequest}, or which fails with - L{twisted.words.ewords.NoSuchGroup} if no such group exists. - """ - - def createGroup(name): - """Create a new group with the given name. - - @type name: C{str} - - @rtype: L{twisted.internet.defer.Deferred} - @return: A Deferred which fires with the created group, or - with fails with L{twisted.words.ewords.DuplicateGroup} if a - group by that name exists already. - """ - - def lookupGroup(name): - """Retrieve a group by name. - - Unlike C{getGroup}, this will never implicitly create a group. - - @type name: C{str} - - @rtype: L{twisted.internet.defer.Deferred} - @return: A Deferred which fires with the group by the given - name, or which fails with L{twisted.words.ewords.NoSuchGroup}. - """ - - def getUser(name): - """Retrieve the user by the given name. - - @type name: C{str} - - @rtype: L{twisted.internet.defer.Deferred} - @return: A Deferred which fires with the user with the given - name if one exists (or if one is created due to the setting of - L{createUserOnRequest}, or which fails with - L{twisted.words.ewords.NoSuchUser} if no such user exists. - """ - - def createUser(name): - """Create a new user with the given name. - - @type name: C{str} - - @rtype: L{twisted.internet.defer.Deferred} - @return: A Deferred which fires with the created user, or - with fails with L{twisted.words.ewords.DuplicateUser} if a - user by that name exists already. - """ - -__all__ = [ - 'IChatInterface', 'IGroup', 'IChatClient', 'IUser', 'IChatService', - ] diff --git a/tools/buildbot/pylibs/twisted/words/protocols/__init__.py b/tools/buildbot/pylibs/twisted/words/protocols/__init__.py deleted file mode 100644 index 5b4f7e5..0000000 --- a/tools/buildbot/pylibs/twisted/words/protocols/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"Chat protocols" diff --git a/tools/buildbot/pylibs/twisted/words/protocols/irc.py b/tools/buildbot/pylibs/twisted/words/protocols/irc.py deleted file mode 100644 index fb38339..0000000 --- a/tools/buildbot/pylibs/twisted/words/protocols/irc.py +++ /dev/null @@ -1,2329 +0,0 @@ -# -*- test-case-name: twisted.words.test.test_irc -*- -# Copyright (c) 2001-2005 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Internet Relay Chat Protocol for client and server. - -Future Plans -============ - -The way the IRCClient class works here encourages people to implement -IRC clients by subclassing the ephemeral protocol class, and it tends -to end up with way more state than it should for an object which will -be destroyed as soon as the TCP transport drops. Someone oughta do -something about that, ya know? - -The DCC support needs to have more hooks for the client for it to be -able to ask the user things like \"Do you want to accept this session?\" -and \"Transfer #2 is 67% done.\" and otherwise manage the DCC sessions. - -Test coverage needs to be better. - -@author: U{Kevin Turner} - -@see: RFC 1459: Internet Relay Chat Protocol -@see: RFC 2812: Internet Relay Chat: Client Protocol -@see: U{The Client-To-Client-Protocol -} -""" - -__version__ = '$Revision: 1.94 $'[11:-2] - -from twisted.internet import reactor, protocol -from twisted.persisted import styles -from twisted.protocols import basic -from twisted.python import log, reflect, text - -# System Imports - -import errno -import os -import random -import re -import stat -import string -import struct -import sys -import time -import types -import traceback -import socket - -from os import path - -NUL = chr(0) -CR = chr(015) -NL = chr(012) -LF = NL -SPC = chr(040) - -CHANNEL_PREFIXES = '&#!+' - -class IRCBadMessage(Exception): - pass - -class IRCPasswordMismatch(Exception): - pass - -def parsemsg(s): - """Breaks a message from an IRC server into its prefix, command, and arguments. - """ - prefix = '' - trailing = [] - if not s: - raise IRCBadMessage("Empty line.") - if s[0] == ':': - prefix, s = s[1:].split(' ', 1) - if s.find(' :') != -1: - s, trailing = s.split(' :', 1) - args = s.split() - args.append(trailing) - else: - args = s.split() - command = args.pop(0) - return prefix, command, args - - -def split(str, length = 80): - """I break a message into multiple lines. - - I prefer to break at whitespace near str[length]. I also break at \\n. - - @returns: list of strings - """ - if length <= 0: - raise ValueError("Length must be a number greater than zero") - r = [] - while len(str) > length: - w, n = str[:length].rfind(' '), str[:length].find('\n') - if w == -1 and n == -1: - line, str = str[:length], str[length:] - else: - i = n == -1 and w or n - line, str = str[:i], str[i+1:] - r.append(line) - if len(str): - r.extend(str.split('\n')) - return r - -class IRC(protocol.Protocol): - """Internet Relay Chat server protocol. - """ - - buffer = "" - hostname = None - - encoding = None - - def connectionMade(self): - self.channels = [] - if self.hostname is None: - self.hostname = socket.getfqdn() - - - def sendLine(self, line): - if self.encoding is not None: - if isinstance(line, unicode): - line = line.encode(self.encoding) - self.transport.write("%s%s%s" % (line, CR, LF)) - - - def sendMessage(self, command, *parameter_list, **prefix): - """Send a line formatted as an IRC message. - - First argument is the command, all subsequent arguments - are parameters to that command. If a prefix is desired, - it may be specified with the keyword argument 'prefix'. - """ - - if not command: - raise ValueError, "IRC message requires a command." - - if ' ' in command or command[0] == ':': - # Not the ONLY way to screw up, but provides a little - # sanity checking to catch likely dumb mistakes. - raise ValueError, "Somebody screwed up, 'cuz this doesn't" \ - " look like a command to me: %s" % command - - line = string.join([command] + list(parameter_list)) - if prefix.has_key('prefix'): - line = ":%s %s" % (prefix['prefix'], line) - self.sendLine(line) - - if len(parameter_list) > 15: - log.msg("Message has %d parameters (RFC allows 15):\n%s" % - (len(parameter_list), line)) - - - def dataReceived(self, data): - """This hack is to support mIRC, which sends LF only, - even though the RFC says CRLF. (Also, the flexibility - of LineReceiver to turn "line mode" on and off was not - required.) - """ - lines = (self.buffer + data).split(LF) - # Put the (possibly empty) element after the last LF back in the - # buffer - self.buffer = lines.pop() - - for line in lines: - if len(line) <= 2: - # This is a blank line, at best. - continue - if line[-1] == CR: - line = line[:-1] - prefix, command, params = parsemsg(line) - # mIRC is a big pile of doo-doo - command = command.upper() - # DEBUG: log.msg( "%s %s %s" % (prefix, command, params)) - - self.handleCommand(command, prefix, params) - - - def handleCommand(self, command, prefix, params): - """Determine the function to call for the given command and call - it with the given arguments. - """ - method = getattr(self, "irc_%s" % command, None) - try: - if method is not None: - method(prefix, params) - else: - self.irc_unknown(prefix, command, params) - except: - log.deferr() - - - def irc_unknown(self, prefix, command, params): - """Implement me!""" - raise NotImplementedError(command, prefix, params) - - - # Helper methods - def privmsg(self, sender, recip, message): - """Send a message to a channel or user - - @type sender: C{str} or C{unicode} - @param sender: Who is sending this message. Should be of the form - username!ident@hostmask (unless you know better!). - - @type recip: C{str} or C{unicode} - @param recip: The recipient of this message. If a channel, it - must start with a channel prefix. - - @type message: C{str} or C{unicode} - @param message: The message being sent. - """ - self.sendLine(":%s PRIVMSG %s :%s" % (sender, recip, lowQuote(message))) - - - def notice(self, sender, recip, message): - """Send a \"notice\" to a channel or user. - - Notices differ from privmsgs in that the RFC claims they are different. - Robots are supposed to send notices and not respond to them. Clients - typically display notices differently from privmsgs. - - @type sender: C{str} or C{unicode} - @param sender: Who is sending this message. Should be of the form - username!ident@hostmask (unless you know better!). - - @type recip: C{str} or C{unicode} - @param recip: The recipient of this message. If a channel, it - must start with a channel prefix. - - @type message: C{str} or C{unicode} - @param message: The message being sent. - """ - self.sendLine(":%s NOTICE %s :%s" % (sender, recip, message)) - - - def action(self, sender, recip, message): - """Send an action to a channel or user. - - @type sender: C{str} or C{unicode} - @param sender: Who is sending this message. Should be of the form - username!ident@hostmask (unless you know better!). - - @type recip: C{str} or C{unicode} - @param recip: The recipient of this message. If a channel, it - must start with a channel prefix. - - @type message: C{str} or C{unicode} - @param message: The action being sent. - """ - self.sendLine(":%s ACTION %s :%s" % (sender, recip, message)) - - - def topic(self, user, channel, topic, author=None): - """Send the topic to a user. - - @type user: C{str} or C{unicode} - @param user: The user receiving the topic. Only their nick name, not - the full hostmask. - - @type channel: C{str} or C{unicode} - @param channel: The channel for which this is the topic. - - @type topic: C{str} or C{unicode} or C{None} - @param topic: The topic string, unquoted, or None if there is - no topic. - - @type author: C{str} or C{unicode} - @param author: If the topic is being changed, the full username and hostmask - of the person changing it. - """ - if author is None: - if topic is None: - self.sendLine(':%s %s %s %s :%s' % ( - self.hostname, RPL_NOTOPIC, user, channel, 'No topic is set.')) - else: - self.sendLine(":%s %s %s %s :%s" % ( - self.hostname, RPL_TOPIC, user, channel, lowQuote(topic))) - else: - self.sendLine(":%s TOPIC %s :%s" % (author, channel, lowQuote(topic))) - - - def topicAuthor(self, user, channel, author, date): - """ - Send the author of and time at which a topic was set for the given - channel. - - This sends a 333 reply message, which is not part of the IRC RFC. - - @type user: C{str} or C{unicode} - @param user: The user receiving the topic. Only their nick name, not - the full hostmask. - - @type channel: C{str} or C{unicode} - @param channel: The channel for which this information is relevant. - - @type author: C{str} or C{unicode} - @param author: The nickname (without hostmask) of the user who last - set the topic. - - @type date: C{int} - @param date: A POSIX timestamp (number of seconds since the epoch) - at which the topic was last set. - """ - self.sendLine(':%s %d %s %s %s %d' % ( - self.hostname, 333, user, channel, author, date)) - - - def names(self, user, channel, names): - """Send the names of a channel's participants to a user. - - @type user: C{str} or C{unicode} - @param user: The user receiving the name list. Only their nick - name, not the full hostmask. - - @type channel: C{str} or C{unicode} - @param channel: The channel for which this is the namelist. - - @type names: C{list} of C{str} or C{unicode} - @param names: The names to send. - """ - # XXX If unicode is given, these limits are not quite correct - prefixLength = len(channel) + len(user) + 10 - namesLength = 512 - prefixLength - - L = [] - count = 0 - for n in names: - if count + len(n) + 1 > namesLength: - self.sendLine(":%s %s %s = %s :%s" % ( - self.hostname, RPL_NAMREPLY, user, channel, ' '.join(L))) - L = [n] - count = len(n) - else: - L.append(n) - count += len(n) + 1 - if L: - self.sendLine(":%s %s %s = %s :%s" % ( - self.hostname, RPL_NAMREPLY, user, channel, ' '.join(L))) - self.sendLine(":%s %s %s %s :End of /NAMES list" % ( - self.hostname, RPL_ENDOFNAMES, user, channel)) - - - def who(self, user, channel, memberInfo): - """ - Send a list of users participating in a channel. - - @type user: C{str} or C{unicode} - @param user: The user receiving this member information. Only their - nick name, not the full hostmask. - - @type channel: C{str} or C{unicode} - @param channel: The channel for which this is the member - information. - - @type memberInfo: C{list} of C{tuples} - @param memberInfo: For each member of the given channel, a 7-tuple - containing their username, their hostmask, the server to which they - are connected, their nickname, the letter "H" or "G" (wtf do these - mean?), the hopcount from C{user} to this member, and this member's - real name. - """ - for info in memberInfo: - (username, hostmask, server, nickname, flag, hops, realName) = info - assert flag in ("H", "G") - self.sendLine(":%s %s %s %s %s %s %s %s %s :%d %s" % ( - self.hostname, RPL_WHOREPLY, user, channel, - username, hostmask, server, nickname, flag, hops, realName)) - - self.sendLine(":%s %s %s %s :End of /WHO list." % ( - self.hostname, RPL_ENDOFWHO, user, channel)) - - - def whois(self, user, nick, username, hostname, realName, server, serverInfo, oper, idle, signOn, channels): - """ - Send information about the state of a particular user. - - @type user: C{str} or C{unicode} - @param user: The user receiving this information. Only their nick - name, not the full hostmask. - - @type nick: C{str} or C{unicode} - @param nick: The nickname of the user this information describes. - - @type username: C{str} or C{unicode} - @param username: The user's username (eg, ident response) - - @type hostname: C{str} - @param hostname: The user's hostmask - - @type realName: C{str} or C{unicode} - @param realName: The user's real name - - @type server: C{str} or C{unicode} - @param server: The name of the server to which the user is connected - - @type serverInfo: C{str} or C{unicode} - @param serverInfo: A descriptive string about that server - - @type oper: C{bool} - @param oper: Indicates whether the user is an IRC operator - - @type idle: C{int} - @param idle: The number of seconds since the user last sent a message - - @type signOn: C{int} - @param signOn: A POSIX timestamp (number of seconds since the epoch) - indicating the time the user signed on - - @type channels: C{list} of C{str} or C{unicode} - @param channels: A list of the channels which the user is participating in - """ - self.sendLine(":%s %s %s %s %s %s * :%s" % ( - self.hostname, RPL_WHOISUSER, user, nick, username, hostname, realName)) - self.sendLine(":%s %s %s %s %s :%s" % ( - self.hostname, RPL_WHOISSERVER, user, nick, server, serverInfo)) - if oper: - self.sendLine(":%s %s %s %s :is an IRC operator" % ( - self.hostname, RPL_WHOISOPERATOR, user, nick)) - self.sendLine(":%s %s %s %s %d %d :seconds idle, signon time" % ( - self.hostname, RPL_WHOISIDLE, user, nick, idle, signOn)) - self.sendLine(":%s %s %s %s :%s" % ( - self.hostname, RPL_WHOISCHANNELS, user, nick, ' '.join(channels))) - self.sendLine(":%s %s %s %s :End of WHOIS list." % ( - self.hostname, RPL_ENDOFWHOIS, user, nick)) - - - def join(self, who, where): - """Send a join message. - - @type who: C{str} or C{unicode} - @param who: The name of the user joining. Should be of the form - username!ident@hostmask (unless you know better!). - - @type where: C{str} or C{unicode} - @param where: The channel the user is joining. - """ - self.sendLine(":%s JOIN %s" % (who, where)) - - - def part(self, who, where, reason=None): - """Send a part message. - - @type who: C{str} or C{unicode} - @param who: The name of the user joining. Should be of the form - username!ident@hostmask (unless you know better!). - - @type where: C{str} or C{unicode} - @param where: The channel the user is joining. - - @type reason: C{str} or C{unicode} - @param reason: A string describing the misery which caused - this poor soul to depart. - """ - if reason: - self.sendLine(":%s PART %s :%s" % (who, where, reason)) - else: - self.sendLine(":%s PART %s" % (who, where)) - - - def channelMode(self, user, channel, mode, *args): - """ - Send information about the mode of a channel. - - @type user: C{str} or C{unicode} - @param user: The user receiving the name list. Only their nick - name, not the full hostmask. - - @type channel: C{str} or C{unicode} - @param channel: The channel for which this is the namelist. - - @type mode: C{str} - @param mode: A string describing this channel's modes. - - @param args: Any additional arguments required by the modes. - """ - self.sendLine(":%s %s %s %s %s %s" % ( - self.hostname, RPL_CHANNELMODEIS, user, channel, mode, ' '.join(args))) - - -class IRCClient(basic.LineReceiver): - """Internet Relay Chat client protocol, with sprinkles. - - In addition to providing an interface for an IRC client protocol, - this class also contains reasonable implementations of many common - CTCP methods. - - TODO - ==== - - Limit the length of messages sent (because the IRC server probably - does). - - Add flood protection/rate limiting for my CTCP replies. - - NickServ cooperation. (a mix-in?) - - Heartbeat. The transport may die in such a way that it does not realize - it is dead until it is written to. Sending something (like \"PING - this.irc-host.net\") during idle peroids would alleviate that. If - you're concerned with the stability of the host as well as that of the - transport, you might care to watch for the corresponding PONG. - - @ivar nickname: Nickname the client will use. - @ivar password: Password used to log on to the server. May be C{None}. - @ivar realname: Supplied to the server during login as the \"Real name\" - or \"ircname\". May be C{None}. - @ivar username: Supplied to the server during login as the \"User name\". - May be C{None} - - @ivar userinfo: Sent in reply to a X{USERINFO} CTCP query. If C{None}, no - USERINFO reply will be sent. - \"This is used to transmit a string which is settable by - the user (and never should be set by the client).\" - @ivar fingerReply: Sent in reply to a X{FINGER} CTCP query. If C{None}, no - FINGER reply will be sent. - @type fingerReply: Callable or String - - @ivar versionName: CTCP VERSION reply, client name. If C{None}, no VERSION - reply will be sent. - @ivar versionNum: CTCP VERSION reply, client version, - @ivar versionEnv: CTCP VERSION reply, environment the client is running in. - - @ivar sourceURL: CTCP SOURCE reply, a URL where the source code of this - client may be found. If C{None}, no SOURCE reply will be sent. - - @ivar lineRate: Minimum delay between lines sent to the server. If - C{None}, no delay will be imposed. - @type lineRate: Number of Seconds. - """ - - motd = "" - nickname = 'irc' - password = None - realname = None - username = None - ### Responses to various CTCP queries. - - userinfo = None - # fingerReply is a callable returning a string, or a str()able object. - fingerReply = None - versionName = None - versionNum = None - versionEnv = None - - sourceURL = "http://twistedmatrix.com/downloads/" - - dcc_destdir = '.' - dcc_sessions = None - - # If this is false, no attempt will be made to identify - # ourself to the server. - performLogin = 1 - - lineRate = None - _queue = None - _queueEmptying = None - - delimiter = '\n' # '\r\n' will also work (see dataReceived) - - __pychecker__ = 'unusednames=params,prefix,channel' - - - def _reallySendLine(self, line): - return basic.LineReceiver.sendLine(self, lowQuote(line) + '\r') - - def sendLine(self, line): - if self.lineRate is None: - self._reallySendLine(line) - else: - self._queue.append(line) - if not self._queueEmptying: - self._sendLine() - - def _sendLine(self): - if self._queue: - self._reallySendLine(self._queue.pop(0)) - self._queueEmptying = reactor.callLater(self.lineRate, - self._sendLine) - else: - self._queueEmptying = None - - - ### Interface level client->user output methods - ### - ### You'll want to override these. - - ### Methods relating to the server itself - - def created(self, when): - """Called with creation date information about the server, usually at logon. - - @type when: C{str} - @param when: A string describing when the server was created, probably. - """ - - def yourHost(self, info): - """Called with daemon information about the server, usually at logon. - - @type info: C{str} - @param when: A string describing what software the server is running, probably. - """ - - def myInfo(self, servername, version, umodes, cmodes): - """Called with information about the server, usually at logon. - - @type servername: C{str} - @param servername: The hostname of this server. - - @type version: C{str} - @param version: A description of what software this server runs. - - @type umodes: C{str} - @param umodes: All the available user modes. - - @type cmodes: C{str} - @param cmodes: All the available channel modes. - """ - - def luserClient(self, info): - """Called with information about the number of connections, usually at logon. - - @type info: C{str} - @param info: A description of the number of clients and servers - connected to the network, probably. - """ - - def bounce(self, info): - """Called with information about where the client should reconnect. - - @type info: C{str} - @param info: A plaintext description of the address that should be - connected to. - """ - - def isupport(self, options): - """Called with various information about what the server supports. - - @type options: C{list} of C{str} - @param options: Descriptions of features or limits of the server, possibly - in the form "NAME=VALUE". - """ - - def luserChannels(self, channels): - """Called with the number of channels existant on the server. - - @type channels: C{int} - """ - - def luserOp(self, ops): - """Called with the number of ops logged on to the server. - - @type ops: C{int} - """ - - def luserMe(self, info): - """Called with information about the server connected to. - - @type info: C{str} - @param info: A plaintext string describing the number of users and servers - connected to this server. - """ - - ### Methods involving me directly - - def privmsg(self, user, channel, message): - """Called when I have a message from a user to me or a channel. - """ - pass - - def joined(self, channel): - """Called when I finish joining a channel. - - channel has the starting character (# or &) intact. - """ - pass - - def left(self, channel): - """Called when I have left a channel. - - channel has the starting character (# or &) intact. - """ - pass - - def noticed(self, user, channel, message): - """Called when I have a notice from a user to me or a channel. - - By default, this is equivalent to IRCClient.privmsg, but if your - client makes any automated replies, you must override this! - From the RFC:: - - The difference between NOTICE and PRIVMSG is that - automatic replies MUST NEVER be sent in response to a - NOTICE message. [...] The object of this rule is to avoid - loops between clients automatically sending something in - response to something it received. - """ - self.privmsg(user, channel, message) - - def modeChanged(self, user, channel, set, modes, args): - """Called when a channel's modes are changed - - @type user: C{str} - @param user: The user and hostmask which instigated this change. - - @type channel: C{str} - @param channel: The channel for which the modes are changing. - - @type set: C{bool} or C{int} - @param set: true if the mode is being added, false if it is being - removed. - - @type modes: C{str} - @param modes: The mode or modes which are being changed. - - @type args: C{tuple} - @param args: Any additional information required for the mode - change. - """ - - def pong(self, user, secs): - """Called with the results of a CTCP PING query. - """ - pass - - def signedOn(self): - """Called after sucessfully signing on to the server. - """ - pass - - def kickedFrom(self, channel, kicker, message): - """Called when I am kicked from a channel. - """ - pass - - def nickChanged(self, nick): - """Called when my nick has been changed. - """ - self.nickname = nick - - - ### Things I observe other people doing in a channel. - - def userJoined(self, user, channel): - """Called when I see another user joining a channel. - """ - pass - - def userLeft(self, user, channel): - """Called when I see another user leaving a channel. - """ - pass - - def userQuit(self, user, quitMessage): - """Called when I see another user disconnect from the network. - """ - pass - - def userKicked(self, kickee, channel, kicker, message): - """Called when I observe someone else being kicked from a channel. - """ - pass - - def action(self, user, channel, data): - """Called when I see a user perform an ACTION on a channel. - """ - pass - - def topicUpdated(self, user, channel, newTopic): - """In channel, user changed the topic to newTopic. - - Also called when first joining a channel. - """ - pass - - def userRenamed(self, oldname, newname): - """A user changed their name from oldname to newname. - """ - pass - - ### Information from the server. - - def receivedMOTD(self, motd): - """I received a message-of-the-day banner from the server. - - motd is a list of strings, where each string was sent as a seperate - message from the server. To display, you might want to use:: - - string.join(motd, '\\n') - - to get a nicely formatted string. - """ - pass - - ### user input commands, client->server - ### Your client will want to invoke these. - - def join(self, channel, key=None): - if channel[0] not in '&#!+': channel = '#' + channel - if key: - self.sendLine("JOIN %s %s" % (channel, key)) - else: - self.sendLine("JOIN %s" % (channel,)) - - def leave(self, channel, reason=None): - if channel[0] not in '&#!+': channel = '#' + channel - if reason: - self.sendLine("PART %s :%s" % (channel, reason)) - else: - self.sendLine("PART %s" % (channel,)) - - def kick(self, channel, user, reason=None): - if channel[0] not in '&#!+': channel = '#' + channel - if reason: - self.sendLine("KICK %s %s :%s" % (channel, user, reason)) - else: - self.sendLine("KICK %s %s" % (channel, user)) - - part = leave - - def topic(self, channel, topic=None): - """Attempt to set the topic of the given channel, or ask what it is. - - If topic is None, then I sent a topic query instead of trying to set - the topic. The server should respond with a TOPIC message containing - the current topic of the given channel. - """ - # << TOPIC #xtestx :fff - if channel[0] not in '&#!+': channel = '#' + channel - if topic != None: - self.sendLine("TOPIC %s :%s" % (channel, topic)) - else: - self.sendLine("TOPIC %s" % (channel,)) - - def mode(self, chan, set, modes, limit = None, user = None, mask = None): - """Change the modes on a user or channel.""" - if set: - line = 'MODE %s +%s' % (chan, modes) - else: - line = 'MODE %s -%s' % (chan, modes) - if limit is not None: - line = '%s %d' % (line, limit) - elif user is not None: - line = '%s %s' % (line, user) - elif mask is not None: - line = '%s %s' % (line, mask) - self.sendLine(line) - - - def say(self, channel, message, length = None): - if channel[0] not in '&#!+': channel = '#' + channel - self.msg(channel, message, length) - - def msg(self, user, message, length = None): - """Send a message to a user or channel. - - @type user: C{str} - @param user: The username or channel name to which to direct the - message. - - @type message: C{str} - @param message: The text to send - - @type length: C{int} - @param length: The maximum number of octets to send at a time. This - has the effect of turning a single call to msg() into multiple - commands to the server. This is useful when long messages may be - sent that would otherwise cause the server to kick us off or silently - truncate the text we are sending. If None is passed, the entire - message is always send in one command. - """ - - fmt = "PRIVMSG %s :%%s" % (user,) - - if length is None: - self.sendLine(fmt % (message,)) - else: - # NOTE: minimumLength really equals len(fmt) - 2 (for '%s') + n - # where n is how many bytes sendLine sends to end the line. - # n was magic numbered to 2, I think incorrectly - minimumLength = len(fmt) - if length <= minimumLength: - raise ValueError("Maximum length must exceed %d for message " - "to %s" % (minimumLength, user)) - lines = split(message, length - minimumLength) - map(lambda line, self=self, fmt=fmt: self.sendLine(fmt % line), - lines) - - def notice(self, user, message): - self.sendLine("NOTICE %s :%s" % (user, message)) - - def away(self, message=''): - self.sendLine("AWAY :%s" % message) - - def register(self, nickname, hostname='foo', servername='bar'): - if self.password is not None: - self.sendLine("PASS %s" % self.password) - self.setNick(nickname) - if self.username is None: - self.username = nickname - self.sendLine("USER %s %s %s :%s" % (self.username, hostname, servername, self.realname)) - - def setNick(self, nickname): - self.nickname = nickname - self.sendLine("NICK %s" % nickname) - - def quit(self, message = ''): - self.sendLine("QUIT :%s" % message) - - ### user input commands, client->client - - def me(self, channel, action): - """Strike a pose. - """ - if channel[0] not in '&#!+': channel = '#' + channel - self.ctcpMakeQuery(channel, [('ACTION', action)]) - - _pings = None - _MAX_PINGRING = 12 - - def ping(self, user, text = None): - """Measure round-trip delay to another IRC client. - """ - if self._pings is None: - self._pings = {} - - if text is None: - chars = string.letters + string.digits + string.punctuation - key = ''.join([random.choice(chars) for i in range(12)]) - else: - key = str(text) - self._pings[(user, key)] = time.time() - self.ctcpMakeQuery(user, [('PING', key)]) - - if len(self._pings) > self._MAX_PINGRING: - # Remove some of the oldest entries. - byValue = [(v, k) for (k, v) in self._pings.items()] - byValue.sort() - excess = self._MAX_PINGRING - len(self._pings) - for i in xrange(excess): - del self._pings[byValue[i][1]] - - def dccSend(self, user, file): - if type(file) == types.StringType: - file = open(file, 'r') - - size = fileSize(file) - - name = getattr(file, "name", "file@%s" % (id(file),)) - - factory = DccSendFactory(file) - port = reactor.listenTCP(0, factory, 1) - - raise NotImplementedError,( - "XXX!!! Help! I need to bind a socket, have it listen, and tell me its address. " - "(and stop accepting once we've made a single connection.)") - - my_address = struct.pack("!I", my_address) - - args = ['SEND', name, my_address, str(port)] - - if not (size is None): - args.append(size) - - args = string.join(args, ' ') - - self.ctcpMakeQuery(user, [('DCC', args)]) - - def dccResume(self, user, fileName, port, resumePos): - """Send a DCC RESUME request to another user.""" - self.ctcpMakeQuery(user, [ - ('DCC', ['RESUME', fileName, port, resumePos])]) - - def dccAcceptResume(self, user, fileName, port, resumePos): - """Send a DCC ACCEPT response to clients who have requested a resume. - """ - self.ctcpMakeQuery(user, [ - ('DCC', ['ACCEPT', fileName, port, resumePos])]) - - ### server->client messages - ### You might want to fiddle with these, - ### but it is safe to leave them alone. - - def irc_ERR_NICKNAMEINUSE(self, prefix, params): - self.register(self.nickname+'_') - - def irc_ERR_PASSWDMISMATCH(self, prefix, params): - raise IRCPasswordMismatch("Password Incorrect.") - - def irc_RPL_WELCOME(self, prefix, params): - self.signedOn() - - def irc_JOIN(self, prefix, params): - nick = string.split(prefix,'!')[0] - channel = params[-1] - if nick == self.nickname: - self.joined(channel) - else: - self.userJoined(nick, channel) - - def irc_PART(self, prefix, params): - nick = string.split(prefix,'!')[0] - channel = params[0] - if nick == self.nickname: - self.left(channel) - else: - self.userLeft(nick, channel) - - def irc_QUIT(self, prefix, params): - nick = string.split(prefix,'!')[0] - self.userQuit(nick, params[0]) - - def irc_MODE(self, prefix, params): - channel, rest = params[0], params[1:] - set = rest[0][0] == '+' - modes = rest[0][1:] - args = rest[1:] - self.modeChanged(prefix, channel, set, modes, tuple(args)) - - def irc_PING(self, prefix, params): - self.sendLine("PONG %s" % params[-1]) - - def irc_PRIVMSG(self, prefix, params): - user = prefix - channel = params[0] - message = params[-1] - - if not message: return # don't raise an exception if some idiot sends us a blank message - - if message[0]==X_DELIM: - m = ctcpExtract(message) - if m['extended']: - self.ctcpQuery(user, channel, m['extended']) - - if not m['normal']: - return - - message = string.join(m['normal'], ' ') - - self.privmsg(user, channel, message) - - def irc_NOTICE(self, prefix, params): - user = prefix - channel = params[0] - message = params[-1] - - if message[0]==X_DELIM: - m = ctcpExtract(message) - if m['extended']: - self.ctcpReply(user, channel, m['extended']) - - if not m['normal']: - return - - message = string.join(m['normal'], ' ') - - self.noticed(user, channel, message) - - def irc_NICK(self, prefix, params): - nick = string.split(prefix,'!', 1)[0] - if nick == self.nickname: - self.nickChanged(params[0]) - else: - self.userRenamed(nick, params[0]) - - def irc_KICK(self, prefix, params): - """Kicked? Who? Not me, I hope. - """ - kicker = string.split(prefix,'!')[0] - channel = params[0] - kicked = params[1] - message = params[-1] - if string.lower(kicked) == string.lower(self.nickname): - # Yikes! - self.kickedFrom(channel, kicker, message) - else: - self.userKicked(kicked, channel, kicker, message) - - def irc_TOPIC(self, prefix, params): - """Someone in the channel set the topic. - """ - user = string.split(prefix, '!')[0] - channel = params[0] - newtopic = params[1] - self.topicUpdated(user, channel, newtopic) - - def irc_RPL_TOPIC(self, prefix, params): - """I just joined the channel, and the server is telling me the current topic. - """ - user = string.split(prefix, '!')[0] - channel = params[1] - newtopic = params[2] - self.topicUpdated(user, channel, newtopic) - - def irc_RPL_NOTOPIC(self, prefix, params): - user = string.split(prefix, '!')[0] - channel = params[1] - newtopic = "" - self.topicUpdated(user, channel, newtopic) - - def irc_RPL_MOTDSTART(self, prefix, params): - if params[-1].startswith("- "): - params[-1] = params[-1][2:] - self.motd = [params[-1]] - - def irc_RPL_MOTD(self, prefix, params): - if params[-1].startswith("- "): - params[-1] = params[-1][2:] - self.motd.append(params[-1]) - - def irc_RPL_ENDOFMOTD(self, prefix, params): - self.receivedMOTD(self.motd) - - def irc_RPL_CREATED(self, prefix, params): - self.created(params[1]) - - def irc_RPL_YOURHOST(self, prefix, params): - self.yourHost(params[1]) - - def irc_RPL_MYINFO(self, prefix, params): - info = params[1].split(None, 3) - while len(info) < 4: - info.append(None) - self.myInfo(*info) - - def irc_RPL_BOUNCE(self, prefix, params): - # 005 is doubly assigned. Piece of crap dirty trash protocol. - if params[-1] == "are available on this server": - self.isupport(params[1:-1]) - else: - self.bounce(params[1]) - - def irc_RPL_LUSERCLIENT(self, prefix, params): - self.luserClient(params[1]) - - def irc_RPL_LUSEROP(self, prefix, params): - try: - self.luserOp(int(params[1])) - except ValueError: - pass - - def irc_RPL_LUSERCHANNELS(self, prefix, params): - try: - self.luserChannels(int(params[1])) - except ValueError: - pass - - def irc_RPL_LUSERME(self, prefix, params): - self.luserMe(params[1]) - - def irc_unknown(self, prefix, command, params): - pass - - ### Receiving a CTCP query from another party - ### It is safe to leave these alone. - - def ctcpQuery(self, user, channel, messages): - """Dispatch method for any CTCP queries received. - """ - for m in messages: - method = getattr(self, "ctcpQuery_%s" % m[0], None) - if method: - method(user, channel, m[1]) - else: - self.ctcpUnknownQuery(user, channel, m[0], m[1]) - - def ctcpQuery_ACTION(self, user, channel, data): - self.action(user, channel, data) - - def ctcpQuery_PING(self, user, channel, data): - nick = string.split(user,"!")[0] - self.ctcpMakeReply(nick, [("PING", data)]) - - def ctcpQuery_FINGER(self, user, channel, data): - if data is not None: - self.quirkyMessage("Why did %s send '%s' with a FINGER query?" - % (user, data)) - if not self.fingerReply: - return - - if callable(self.fingerReply): - reply = self.fingerReply() - else: - reply = str(self.fingerReply) - - nick = string.split(user,"!")[0] - self.ctcpMakeReply(nick, [('FINGER', reply)]) - - def ctcpQuery_VERSION(self, user, channel, data): - if data is not None: - self.quirkyMessage("Why did %s send '%s' with a VERSION query?" - % (user, data)) - - if self.versionName: - nick = string.split(user,"!")[0] - self.ctcpMakeReply(nick, [('VERSION', '%s:%s:%s' % - (self.versionName, - self.versionNum, - self.versionEnv))]) - - def ctcpQuery_SOURCE(self, user, channel, data): - if data is not None: - self.quirkyMessage("Why did %s send '%s' with a SOURCE query?" - % (user, data)) - if self.sourceURL: - nick = string.split(user,"!")[0] - # The CTCP document (Zeuge, Rollo, Mesander 1994) says that SOURCE - # replies should be responded to with the location of an anonymous - # FTP server in host:directory:file format. I'm taking the liberty - # of bringing it into the 21st century by sending a URL instead. - self.ctcpMakeReply(nick, [('SOURCE', self.sourceURL), - ('SOURCE', None)]) - - def ctcpQuery_USERINFO(self, user, channel, data): - if data is not None: - self.quirkyMessage("Why did %s send '%s' with a USERINFO query?" - % (user, data)) - if self.userinfo: - nick = string.split(user,"!")[0] - self.ctcpMakeReply(nick, [('USERINFO', self.userinfo)]) - - def ctcpQuery_CLIENTINFO(self, user, channel, data): - """A master index of what CTCP tags this client knows. - - If no arguments are provided, respond with a list of known tags. - If an argument is provided, provide human-readable help on - the usage of that tag. - """ - - nick = string.split(user,"!")[0] - if not data: - # XXX: prefixedMethodNames gets methods from my *class*, - # but it's entirely possible that this *instance* has more - # methods. - names = reflect.prefixedMethodNames(self.__class__, - 'ctcpQuery_') - - self.ctcpMakeReply(nick, [('CLIENTINFO', - string.join(names, ' '))]) - else: - args = string.split(data) - method = getattr(self, 'ctcpQuery_%s' % (args[0],), None) - if not method: - self.ctcpMakeReply(nick, [('ERRMSG', - "CLIENTINFO %s :" - "Unknown query '%s'" - % (data, args[0]))]) - return - doc = getattr(method, '__doc__', '') - self.ctcpMakeReply(nick, [('CLIENTINFO', doc)]) - - - def ctcpQuery_ERRMSG(self, user, channel, data): - # Yeah, this seems strange, but that's what the spec says to do - # when faced with an ERRMSG query (not a reply). - nick = string.split(user,"!")[0] - self.ctcpMakeReply(nick, [('ERRMSG', - "%s :No error has occoured." % data)]) - - def ctcpQuery_TIME(self, user, channel, data): - if data is not None: - self.quirkyMessage("Why did %s send '%s' with a TIME query?" - % (user, data)) - nick = string.split(user,"!")[0] - self.ctcpMakeReply(nick, - [('TIME', ':%s' % - time.asctime(time.localtime(time.time())))]) - - def ctcpQuery_DCC(self, user, channel, data): - """Initiate a Direct Client Connection - """ - - if not data: return - dcctype = data.split(None, 1)[0].upper() - handler = getattr(self, "dcc_" + dcctype, None) - if handler: - if self.dcc_sessions is None: - self.dcc_sessions = [] - data = data[len(dcctype)+1:] - handler(user, channel, data) - else: - nick = string.split(user,"!")[0] - self.ctcpMakeReply(nick, [('ERRMSG', - "DCC %s :Unknown DCC type '%s'" - % (data, dcctype))]) - self.quirkyMessage("%s offered unknown DCC type %s" - % (user, dcctype)) - - def dcc_SEND(self, user, channel, data): - # Use splitQuoted for those who send files with spaces in the names. - data = text.splitQuoted(data) - if len(data) < 3: - raise IRCBadMessage, "malformed DCC SEND request: %r" % (data,) - - (filename, address, port) = data[:3] - - address = dccParseAddress(address) - try: - port = int(port) - except ValueError: - raise IRCBadMessage, "Indecipherable port %r" % (port,) - - size = -1 - if len(data) >= 4: - try: - size = int(data[3]) - except ValueError: - pass - - # XXX Should we bother passing this data? - self.dccDoSend(user, address, port, filename, size, data) - - def dcc_ACCEPT(self, user, channel, data): - data = text.splitQuoted(data) - if len(data) < 3: - raise IRCBadMessage, "malformed DCC SEND ACCEPT request: %r" % (data,) - (filename, port, resumePos) = data[:3] - try: - port = int(port) - resumePos = int(resumePos) - except ValueError: - return - - self.dccDoAcceptResume(user, filename, port, resumePos) - - def dcc_RESUME(self, user, channel, data): - data = text.splitQuoted(data) - if len(data) < 3: - raise IRCBadMessage, "malformed DCC SEND RESUME request: %r" % (data,) - (filename, port, resumePos) = data[:3] - try: - port = int(port) - resumePos = int(resumePos) - except ValueError: - return - self.dccDoResume(user, filename, port, resumePos) - - def dcc_CHAT(self, user, channel, data): - data = text.splitQuoted(data) - if len(data) < 3: - raise IRCBadMessage, "malformed DCC CHAT request: %r" % (data,) - - (filename, address, port) = data[:3] - - address = dccParseAddress(address) - try: - port = int(port) - except ValueError: - raise IRCBadMessage, "Indecipherable port %r" % (port,) - - self.dccDoChat(user, channel, address, port, data) - - ### The dccDo methods are the slightly higher-level siblings of - ### common dcc_ methods; the arguments have been parsed for them. - - def dccDoSend(self, user, address, port, fileName, size, data): - """Called when I receive a DCC SEND offer from a client. - - By default, I do nothing here.""" - ## filename = path.basename(arg) - ## protocol = DccFileReceive(filename, size, - ## (user,channel,data),self.dcc_destdir) - ## reactor.clientTCP(address, port, protocol) - ## self.dcc_sessions.append(protocol) - pass - - def dccDoResume(self, user, file, port, resumePos): - """Called when a client is trying to resume an offered file - via DCC send. It should be either replied to with a DCC - ACCEPT or ignored (default).""" - pass - - def dccDoAcceptResume(self, user, file, port, resumePos): - """Called when a client has verified and accepted a DCC resume - request made by us. By default it will do nothing.""" - pass - - def dccDoChat(self, user, channel, address, port, data): - pass - #factory = DccChatFactory(self, queryData=(user, channel, data)) - #reactor.connectTCP(address, port, factory) - #self.dcc_sessions.append(factory) - - #def ctcpQuery_SED(self, user, data): - # """Simple Encryption Doodoo - # - # Feel free to implement this, but no specification is available. - # """ - # raise NotImplementedError - - def ctcpUnknownQuery(self, user, channel, tag, data): - nick = string.split(user,"!")[0] - self.ctcpMakeReply(nick, [('ERRMSG', - "%s %s: Unknown query '%s'" - % (tag, data, tag))]) - - log.msg("Unknown CTCP query from %s: %s %s\n" - % (user, tag, data)) - - def ctcpMakeReply(self, user, messages): - """Send one or more X{extended messages} as a CTCP reply. - - @type messages: a list of extended messages. An extended - message is a (tag, data) tuple, where 'data' may be C{None}. - """ - self.notice(user, ctcpStringify(messages)) - - ### client CTCP query commands - - def ctcpMakeQuery(self, user, messages): - """Send one or more X{extended messages} as a CTCP query. - - @type messages: a list of extended messages. An extended - message is a (tag, data) tuple, where 'data' may be C{None}. - """ - self.msg(user, ctcpStringify(messages)) - - ### Receiving a response to a CTCP query (presumably to one we made) - ### You may want to add methods here, or override UnknownReply. - - def ctcpReply(self, user, channel, messages): - """Dispatch method for any CTCP replies received. - """ - for m in messages: - method = getattr(self, "ctcpReply_%s" % m[0], None) - if method: - method(user, channel, m[1]) - else: - self.ctcpUnknownReply(user, channel, m[0], m[1]) - - def ctcpReply_PING(self, user, channel, data): - nick = user.split('!', 1)[0] - if (not self._pings) or (not self._pings.has_key((nick, data))): - raise IRCBadMessage,\ - "Bogus PING response from %s: %s" % (user, data) - - t0 = self._pings[(nick, data)] - self.pong(user, time.time() - t0) - - def ctcpUnknownReply(self, user, channel, tag, data): - """Called when a fitting ctcpReply_ method is not found. - - XXX: If the client makes arbitrary CTCP queries, - this method should probably show the responses to - them instead of treating them as anomolies. - """ - log.msg("Unknown CTCP reply from %s: %s %s\n" - % (user, tag, data)) - - ### Error handlers - ### You may override these with something more appropriate to your UI. - - def badMessage(self, line, excType, excValue, tb): - """When I get a message that's so broken I can't use it. - """ - log.msg(line) - log.msg(string.join(traceback.format_exception(excType, - excValue, - tb),'')) - - def quirkyMessage(self, s): - """This is called when I receive a message which is peculiar, - but not wholly indecipherable. - """ - log.msg(s + '\n') - - ### Protocool methods - - def connectionMade(self): - self._queue = [] - if self.performLogin: - self.register(self.nickname) - - def dataReceived(self, data): - basic.LineReceiver.dataReceived(self, data.replace('\r', '')) - - def lineReceived(self, line): - line = lowDequote(line) - try: - prefix, command, params = parsemsg(line) - if numeric_to_symbolic.has_key(command): - command = numeric_to_symbolic[command] - self.handleCommand(command, prefix, params) - except IRCBadMessage: - self.badMessage(line, *sys.exc_info()) - - - def handleCommand(self, command, prefix, params): - """Determine the function to call for the given command and call - it with the given arguments. - """ - method = getattr(self, "irc_%s" % command, None) - try: - if method is not None: - method(prefix, params) - else: - self.irc_unknown(prefix, command, params) - except: - log.deferr() - - - def __getstate__(self): - dct = self.__dict__.copy() - dct['dcc_sessions'] = None - dct['_pings'] = None - return dct - - -def dccParseAddress(address): - if '.' in address: - pass - else: - try: - address = long(address) - except ValueError: - raise IRCBadMessage,\ - "Indecipherable address %r" % (address,) - else: - address = ( - (address >> 24) & 0xFF, - (address >> 16) & 0xFF, - (address >> 8) & 0xFF, - address & 0xFF, - ) - address = '.'.join(map(str,address)) - return address - - -class DccFileReceiveBasic(protocol.Protocol, styles.Ephemeral): - """Bare protocol to receive a Direct Client Connection SEND stream. - - This does enough to keep the other guy talking, but you'll want to - extend my dataReceived method to *do* something with the data I get. - """ - - bytesReceived = 0 - - def __init__(self, resumeOffset=0): - self.bytesReceived = resumeOffset - self.resume = (resumeOffset != 0) - - def dataReceived(self, data): - """Called when data is received. - - Warning: This just acknowledges to the remote host that the - data has been received; it doesn't *do* anything with the - data, so you'll want to override this. - """ - self.bytesReceived = self.bytesReceived + len(data) - self.transport.write(struct.pack('!i', self.bytesReceived)) - - -class DccSendProtocol(protocol.Protocol, styles.Ephemeral): - """Protocol for an outgoing Direct Client Connection SEND. - """ - - blocksize = 1024 - file = None - bytesSent = 0 - completed = 0 - connected = 0 - - def __init__(self, file): - if type(file) is types.StringType: - self.file = open(file, 'r') - - def connectionMade(self): - self.connected = 1 - self.sendBlock() - - def dataReceived(self, data): - # XXX: Do we need to check to see if len(data) != fmtsize? - - bytesShesGot = struct.unpack("!I", data) - if bytesShesGot < self.bytesSent: - # Wait for her. - # XXX? Add some checks to see if we've stalled out? - return - elif bytesShesGot > self.bytesSent: - # self.transport.log("DCC SEND %s: She says she has %d bytes " - # "but I've only sent %d. I'm stopping " - # "this screwy transfer." - # % (self.file, - # bytesShesGot, self.bytesSent)) - self.transport.loseConnection() - return - - self.sendBlock() - - def sendBlock(self): - block = self.file.read(self.blocksize) - if block: - self.transport.write(block) - self.bytesSent = self.bytesSent + len(block) - else: - # Nothing more to send, transfer complete. - self.transport.loseConnection() - self.completed = 1 - - def connectionLost(self, reason): - self.connected = 0 - if hasattr(self.file, "close"): - self.file.close() - - -class DccSendFactory(protocol.Factory): - protocol = DccSendProtocol - def __init__(self, file): - self.file = file - - def buildProtocol(self, connection): - p = self.protocol(self.file) - p.factory = self - return p - - -def fileSize(file): - """I'll try my damndest to determine the size of this file object. - """ - size = None - if hasattr(file, "fileno"): - fileno = file.fileno() - try: - stat_ = os.fstat(fileno) - size = stat_[stat.ST_SIZE] - except: - pass - else: - return size - - if hasattr(file, "name") and path.exists(file.name): - try: - size = path.getsize(file.name) - except: - pass - else: - return size - - if hasattr(file, "seek") and hasattr(file, "tell"): - try: - try: - file.seek(0, 2) - size = file.tell() - finally: - file.seek(0, 0) - except: - pass - else: - return size - - return size - -class DccChat(basic.LineReceiver, styles.Ephemeral): - """Direct Client Connection protocol type CHAT. - - DCC CHAT is really just your run o' the mill basic.LineReceiver - protocol. This class only varies from that slightly, accepting - either LF or CR LF for a line delimeter for incoming messages - while always using CR LF for outgoing. - - The lineReceived method implemented here uses the DCC connection's - 'client' attribute (provided upon construction) to deliver incoming - lines from the DCC chat via IRCClient's normal privmsg interface. - That's something of a spoof, which you may well want to override. - """ - - queryData = None - delimiter = CR + NL - client = None - remoteParty = None - buffer = "" - - def __init__(self, client, queryData=None): - """Initialize a new DCC CHAT session. - - queryData is a 3-tuple of - (fromUser, targetUserOrChannel, data) - as received by the CTCP query. - - (To be honest, fromUser is the only thing that's currently - used here. targetUserOrChannel is potentially useful, while - the 'data' argument is soley for informational purposes.) - """ - self.client = client - if queryData: - self.queryData = queryData - self.remoteParty = self.queryData[0] - - def dataReceived(self, data): - self.buffer = self.buffer + data - lines = string.split(self.buffer, LF) - # Put the (possibly empty) element after the last LF back in the - # buffer - self.buffer = lines.pop() - - for line in lines: - if line[-1] == CR: - line = line[:-1] - self.lineReceived(line) - - def lineReceived(self, line): - log.msg("DCC CHAT<%s> %s" % (self.remoteParty, line)) - self.client.privmsg(self.remoteParty, - self.client.nickname, line) - - -class DccChatFactory(protocol.ClientFactory): - protocol = DccChat - noisy = 0 - def __init__(self, client, queryData): - self.client = client - self.queryData = queryData - - def buildProtocol(self, addr): - p = self.protocol(client=self.client, queryData=self.queryData) - p.factory = self - - def clientConnectionFailed(self, unused_connector, unused_reason): - self.client.dcc_sessions.remove(self) - - def clientConnectionLost(self, unused_connector, unused_reason): - self.client.dcc_sessions.remove(self) - - -def dccDescribe(data): - """Given the data chunk from a DCC query, return a descriptive string. - """ - - orig_data = data - data = string.split(data) - if len(data) < 4: - return orig_data - - (dcctype, arg, address, port) = data[:4] - - if '.' in address: - pass - else: - try: - address = long(address) - except ValueError: - pass - else: - address = ( - (address >> 24) & 0xFF, - (address >> 16) & 0xFF, - (address >> 8) & 0xFF, - address & 0xFF, - ) - # The mapping to 'int' is to get rid of those accursed - # "L"s which python 1.5.2 puts on the end of longs. - address = string.join(map(str,map(int,address)), ".") - - if dcctype == 'SEND': - filename = arg - - size_txt = '' - if len(data) >= 5: - try: - size = int(data[4]) - size_txt = ' of size %d bytes' % (size,) - except ValueError: - pass - - dcc_text = ("SEND for file '%s'%s at host %s, port %s" - % (filename, size_txt, address, port)) - elif dcctype == 'CHAT': - dcc_text = ("CHAT for host %s, port %s" - % (address, port)) - else: - dcc_text = orig_data - - return dcc_text - - -class DccFileReceive(DccFileReceiveBasic): - """Higher-level coverage for getting a file from DCC SEND. - - I allow you to change the file's name and destination directory. - I won't overwrite an existing file unless I've been told it's okay - to do so. If passed the resumeOffset keyword argument I will attempt to - resume the file from that amount of bytes. - - XXX: I need to let the client know when I am finished. - XXX: I need to decide how to keep a progress indicator updated. - XXX: Client needs a way to tell me \"Do not finish until I say so.\" - XXX: I need to make sure the client understands if the file cannot be written. - """ - - filename = 'dcc' - fileSize = -1 - destDir = '.' - overwrite = 0 - fromUser = None - queryData = None - - def __init__(self, filename, fileSize=-1, queryData=None, - destDir='.', resumeOffset=0): - DccFileReceiveBasic.__init__(self, resumeOffset=resumeOffset) - self.filename = filename - self.destDir = destDir - self.fileSize = fileSize - - if queryData: - self.queryData = queryData - self.fromUser = self.queryData[0] - - def set_directory(self, directory): - """Set the directory where the downloaded file will be placed. - - May raise OSError if the supplied directory path is not suitable. - """ - if not path.exists(directory): - raise OSError(errno.ENOENT, "You see no directory there.", - directory) - if not path.isdir(directory): - raise OSError(errno.ENOTDIR, "You cannot put a file into " - "something which is not a directory.", - directory) - if not os.access(directory, os.X_OK | os.W_OK): - raise OSError(errno.EACCES, - "This directory is too hard to write in to.", - directory) - self.destDir = directory - - def set_filename(self, filename): - """Change the name of the file being transferred. - - This replaces the file name provided by the sender. - """ - self.filename = filename - - def set_overwrite(self, boolean): - """May I overwrite existing files? - """ - self.overwrite = boolean - - - # Protocol-level methods. - - def connectionMade(self): - dst = path.abspath(path.join(self.destDir,self.filename)) - exists = path.exists(dst) - if self.resume and exists: - # I have been told I want to resume, and a file already - # exists - Here we go - self.file = open(dst, 'ab') - log.msg("Attempting to resume %s - starting from %d bytes" % - (self.file, self.file.tell())) - elif self.overwrite or not exists: - self.file = open(dst, 'wb') - else: - raise OSError(errno.EEXIST, - "There's a file in the way. " - "Perhaps that's why you cannot open it.", - dst) - - def dataReceived(self, data): - self.file.write(data) - DccFileReceiveBasic.dataReceived(self, data) - - # XXX: update a progress indicator here? - - def connectionLost(self, reason): - """When the connection is lost, I close the file. - """ - self.connected = 0 - logmsg = ("%s closed." % (self,)) - if self.fileSize > 0: - logmsg = ("%s %d/%d bytes received" - % (logmsg, self.bytesReceived, self.fileSize)) - if self.bytesReceived == self.fileSize: - pass # Hooray! - elif self.bytesReceived < self.fileSize: - logmsg = ("%s (Warning: %d bytes short)" - % (logmsg, self.fileSize - self.bytesReceived)) - else: - logmsg = ("%s (file larger than expected)" - % (logmsg,)) - else: - logmsg = ("%s %d bytes received" - % (logmsg, self.bytesReceived)) - - if hasattr(self, 'file'): - logmsg = "%s and written to %s.\n" % (logmsg, self.file.name) - if hasattr(self.file, 'close'): self.file.close() - - # self.transport.log(logmsg) - - def __str__(self): - if not self.connected: - return "" % (id(self),) - from_ = self.transport.getPeer() - if self.fromUser: - from_ = "%s (%s)" % (self.fromUser, from_) - - s = ("DCC transfer of '%s' from %s" % (self.filename, from_)) - return s - - def __repr__(self): - s = ("<%s at %x: GET %s>" - % (self.__class__, id(self), self.filename)) - return s - - -# CTCP constants and helper functions - -X_DELIM = chr(001) - -def ctcpExtract(message): - """Extract CTCP data from a string. - - Returns a dictionary with two items: - - - C{'extended'}: a list of CTCP (tag, data) tuples - - C{'normal'}: a list of strings which were not inside a CTCP delimeter - """ - - extended_messages = [] - normal_messages = [] - retval = {'extended': extended_messages, - 'normal': normal_messages } - - messages = string.split(message, X_DELIM) - odd = 0 - - # X1 extended data X2 nomal data X3 extended data X4 normal... - while messages: - if odd: - extended_messages.append(messages.pop(0)) - else: - normal_messages.append(messages.pop(0)) - odd = not odd - - extended_messages[:] = filter(None, extended_messages) - normal_messages[:] = filter(None, normal_messages) - - extended_messages[:] = map(ctcpDequote, extended_messages) - for i in xrange(len(extended_messages)): - m = string.split(extended_messages[i], SPC, 1) - tag = m[0] - if len(m) > 1: - data = m[1] - else: - data = None - - extended_messages[i] = (tag, data) - - return retval - -# CTCP escaping - -M_QUOTE= chr(020) - -mQuoteTable = { - NUL: M_QUOTE + '0', - NL: M_QUOTE + 'n', - CR: M_QUOTE + 'r', - M_QUOTE: M_QUOTE + M_QUOTE - } - -mDequoteTable = {} -for k, v in mQuoteTable.items(): - mDequoteTable[v[-1]] = k -del k, v - -mEscape_re = re.compile('%s.' % (re.escape(M_QUOTE),), re.DOTALL) - -def lowQuote(s): - for c in (M_QUOTE, NUL, NL, CR): - s = string.replace(s, c, mQuoteTable[c]) - return s - -def lowDequote(s): - def sub(matchobj, mDequoteTable=mDequoteTable): - s = matchobj.group()[1] - try: - s = mDequoteTable[s] - except KeyError: - s = s - return s - - return mEscape_re.sub(sub, s) - -X_QUOTE = '\\' - -xQuoteTable = { - X_DELIM: X_QUOTE + 'a', - X_QUOTE: X_QUOTE + X_QUOTE - } - -xDequoteTable = {} - -for k, v in xQuoteTable.items(): - xDequoteTable[v[-1]] = k - -xEscape_re = re.compile('%s.' % (re.escape(X_QUOTE),), re.DOTALL) - -def ctcpQuote(s): - for c in (X_QUOTE, X_DELIM): - s = string.replace(s, c, xQuoteTable[c]) - return s - -def ctcpDequote(s): - def sub(matchobj, xDequoteTable=xDequoteTable): - s = matchobj.group()[1] - try: - s = xDequoteTable[s] - except KeyError: - s = s - return s - - return xEscape_re.sub(sub, s) - -def ctcpStringify(messages): - """ - @type messages: a list of extended messages. An extended - message is a (tag, data) tuple, where 'data' may be C{None}, a - string, or a list of strings to be joined with whitespace. - - @returns: String - """ - coded_messages = [] - for (tag, data) in messages: - if data: - if not isinstance(data, types.StringType): - try: - # data as list-of-strings - data = " ".join(map(str, data)) - except TypeError: - # No? Then use it's %s representation. - pass - m = "%s %s" % (tag, data) - else: - m = str(tag) - m = ctcpQuote(m) - m = "%s%s%s" % (X_DELIM, m, X_DELIM) - coded_messages.append(m) - - line = string.join(coded_messages, '') - return line - - -# Constants (from RFC 2812) -RPL_WELCOME = '001' -RPL_YOURHOST = '002' -RPL_CREATED = '003' -RPL_MYINFO = '004' -RPL_BOUNCE = '005' -RPL_USERHOST = '302' -RPL_ISON = '303' -RPL_AWAY = '301' -RPL_UNAWAY = '305' -RPL_NOWAWAY = '306' -RPL_WHOISUSER = '311' -RPL_WHOISSERVER = '312' -RPL_WHOISOPERATOR = '313' -RPL_WHOISIDLE = '317' -RPL_ENDOFWHOIS = '318' -RPL_WHOISCHANNELS = '319' -RPL_WHOWASUSER = '314' -RPL_ENDOFWHOWAS = '369' -RPL_LISTSTART = '321' -RPL_LIST = '322' -RPL_LISTEND = '323' -RPL_UNIQOPIS = '325' -RPL_CHANNELMODEIS = '324' -RPL_NOTOPIC = '331' -RPL_TOPIC = '332' -RPL_INVITING = '341' -RPL_SUMMONING = '342' -RPL_INVITELIST = '346' -RPL_ENDOFINVITELIST = '347' -RPL_EXCEPTLIST = '348' -RPL_ENDOFEXCEPTLIST = '349' -RPL_VERSION = '351' -RPL_WHOREPLY = '352' -RPL_ENDOFWHO = '315' -RPL_NAMREPLY = '353' -RPL_ENDOFNAMES = '366' -RPL_LINKS = '364' -RPL_ENDOFLINKS = '365' -RPL_BANLIST = '367' -RPL_ENDOFBANLIST = '368' -RPL_INFO = '371' -RPL_ENDOFINFO = '374' -RPL_MOTDSTART = '375' -RPL_MOTD = '372' -RPL_ENDOFMOTD = '376' -RPL_YOUREOPER = '381' -RPL_REHASHING = '382' -RPL_YOURESERVICE = '383' -RPL_TIME = '391' -RPL_USERSSTART = '392' -RPL_USERS = '393' -RPL_ENDOFUSERS = '394' -RPL_NOUSERS = '395' -RPL_TRACELINK = '200' -RPL_TRACECONNECTING = '201' -RPL_TRACEHANDSHAKE = '202' -RPL_TRACEUNKNOWN = '203' -RPL_TRACEOPERATOR = '204' -RPL_TRACEUSER = '205' -RPL_TRACESERVER = '206' -RPL_TRACESERVICE = '207' -RPL_TRACENEWTYPE = '208' -RPL_TRACECLASS = '209' -RPL_TRACERECONNECT = '210' -RPL_TRACELOG = '261' -RPL_TRACEEND = '262' -RPL_STATSLINKINFO = '211' -RPL_STATSCOMMANDS = '212' -RPL_ENDOFSTATS = '219' -RPL_STATSUPTIME = '242' -RPL_STATSOLINE = '243' -RPL_UMODEIS = '221' -RPL_SERVLIST = '234' -RPL_SERVLISTEND = '235' -RPL_LUSERCLIENT = '251' -RPL_LUSEROP = '252' -RPL_LUSERUNKNOWN = '253' -RPL_LUSERCHANNELS = '254' -RPL_LUSERME = '255' -RPL_ADMINME = '256' -RPL_ADMINLOC = '257' -RPL_ADMINLOC = '258' -RPL_ADMINEMAIL = '259' -RPL_TRYAGAIN = '263' -ERR_NOSUCHNICK = '401' -ERR_NOSUCHSERVER = '402' -ERR_NOSUCHCHANNEL = '403' -ERR_CANNOTSENDTOCHAN = '404' -ERR_TOOMANYCHANNELS = '405' -ERR_WASNOSUCHNICK = '406' -ERR_TOOMANYTARGETS = '407' -ERR_NOSUCHSERVICE = '408' -ERR_NOORIGIN = '409' -ERR_NORECIPIENT = '411' -ERR_NOTEXTTOSEND = '412' -ERR_NOTOPLEVEL = '413' -ERR_WILDTOPLEVEL = '414' -ERR_BADMASK = '415' -ERR_UNKNOWNCOMMAND = '421' -ERR_NOMOTD = '422' -ERR_NOADMININFO = '423' -ERR_FILEERROR = '424' -ERR_NONICKNAMEGIVEN = '431' -ERR_ERRONEUSNICKNAME = '432' -ERR_NICKNAMEINUSE = '433' -ERR_NICKCOLLISION = '436' -ERR_UNAVAILRESOURCE = '437' -ERR_USERNOTINCHANNEL = '441' -ERR_NOTONCHANNEL = '442' -ERR_USERONCHANNEL = '443' -ERR_NOLOGIN = '444' -ERR_SUMMONDISABLED = '445' -ERR_USERSDISABLED = '446' -ERR_NOTREGISTERED = '451' -ERR_NEEDMOREPARAMS = '461' -ERR_ALREADYREGISTRED = '462' -ERR_NOPERMFORHOST = '463' -ERR_PASSWDMISMATCH = '464' -ERR_YOUREBANNEDCREEP = '465' -ERR_YOUWILLBEBANNED = '466' -ERR_KEYSET = '467' -ERR_CHANNELISFULL = '471' -ERR_UNKNOWNMODE = '472' -ERR_INVITEONLYCHAN = '473' -ERR_BANNEDFROMCHAN = '474' -ERR_BADCHANNELKEY = '475' -ERR_BADCHANMASK = '476' -ERR_NOCHANMODES = '477' -ERR_BANLISTFULL = '478' -ERR_NOPRIVILEGES = '481' -ERR_CHANOPRIVSNEEDED = '482' -ERR_CANTKILLSERVER = '483' -ERR_RESTRICTED = '484' -ERR_UNIQOPPRIVSNEEDED = '485' -ERR_NOOPERHOST = '491' -ERR_NOSERVICEHOST = '492' -ERR_UMODEUNKNOWNFLAG = '501' -ERR_USERSDONTMATCH = '502' - -# And hey, as long as the strings are already intern'd... -symbolic_to_numeric = { - "RPL_WELCOME": '001', - "RPL_YOURHOST": '002', - "RPL_CREATED": '003', - "RPL_MYINFO": '004', - "RPL_BOUNCE": '005', - "RPL_USERHOST": '302', - "RPL_ISON": '303', - "RPL_AWAY": '301', - "RPL_UNAWAY": '305', - "RPL_NOWAWAY": '306', - "RPL_WHOISUSER": '311', - "RPL_WHOISSERVER": '312', - "RPL_WHOISOPERATOR": '313', - "RPL_WHOISIDLE": '317', - "RPL_ENDOFWHOIS": '318', - "RPL_WHOISCHANNELS": '319', - "RPL_WHOWASUSER": '314', - "RPL_ENDOFWHOWAS": '369', - "RPL_LISTSTART": '321', - "RPL_LIST": '322', - "RPL_LISTEND": '323', - "RPL_UNIQOPIS": '325', - "RPL_CHANNELMODEIS": '324', - "RPL_NOTOPIC": '331', - "RPL_TOPIC": '332', - "RPL_INVITING": '341', - "RPL_SUMMONING": '342', - "RPL_INVITELIST": '346', - "RPL_ENDOFINVITELIST": '347', - "RPL_EXCEPTLIST": '348', - "RPL_ENDOFEXCEPTLIST": '349', - "RPL_VERSION": '351', - "RPL_WHOREPLY": '352', - "RPL_ENDOFWHO": '315', - "RPL_NAMREPLY": '353', - "RPL_ENDOFNAMES": '366', - "RPL_LINKS": '364', - "RPL_ENDOFLINKS": '365', - "RPL_BANLIST": '367', - "RPL_ENDOFBANLIST": '368', - "RPL_INFO": '371', - "RPL_ENDOFINFO": '374', - "RPL_MOTDSTART": '375', - "RPL_MOTD": '372', - "RPL_ENDOFMOTD": '376', - "RPL_YOUREOPER": '381', - "RPL_REHASHING": '382', - "RPL_YOURESERVICE": '383', - "RPL_TIME": '391', - "RPL_USERSSTART": '392', - "RPL_USERS": '393', - "RPL_ENDOFUSERS": '394', - "RPL_NOUSERS": '395', - "RPL_TRACELINK": '200', - "RPL_TRACECONNECTING": '201', - "RPL_TRACEHANDSHAKE": '202', - "RPL_TRACEUNKNOWN": '203', - "RPL_TRACEOPERATOR": '204', - "RPL_TRACEUSER": '205', - "RPL_TRACESERVER": '206', - "RPL_TRACESERVICE": '207', - "RPL_TRACENEWTYPE": '208', - "RPL_TRACECLASS": '209', - "RPL_TRACERECONNECT": '210', - "RPL_TRACELOG": '261', - "RPL_TRACEEND": '262', - "RPL_STATSLINKINFO": '211', - "RPL_STATSCOMMANDS": '212', - "RPL_ENDOFSTATS": '219', - "RPL_STATSUPTIME": '242', - "RPL_STATSOLINE": '243', - "RPL_UMODEIS": '221', - "RPL_SERVLIST": '234', - "RPL_SERVLISTEND": '235', - "RPL_LUSERCLIENT": '251', - "RPL_LUSEROP": '252', - "RPL_LUSERUNKNOWN": '253', - "RPL_LUSERCHANNELS": '254', - "RPL_LUSERME": '255', - "RPL_ADMINME": '256', - "RPL_ADMINLOC": '257', - "RPL_ADMINLOC": '258', - "RPL_ADMINEMAIL": '259', - "RPL_TRYAGAIN": '263', - "ERR_NOSUCHNICK": '401', - "ERR_NOSUCHSERVER": '402', - "ERR_NOSUCHCHANNEL": '403', - "ERR_CANNOTSENDTOCHAN": '404', - "ERR_TOOMANYCHANNELS": '405', - "ERR_WASNOSUCHNICK": '406', - "ERR_TOOMANYTARGETS": '407', - "ERR_NOSUCHSERVICE": '408', - "ERR_NOORIGIN": '409', - "ERR_NORECIPIENT": '411', - "ERR_NOTEXTTOSEND": '412', - "ERR_NOTOPLEVEL": '413', - "ERR_WILDTOPLEVEL": '414', - "ERR_BADMASK": '415', - "ERR_UNKNOWNCOMMAND": '421', - "ERR_NOMOTD": '422', - "ERR_NOADMININFO": '423', - "ERR_FILEERROR": '424', - "ERR_NONICKNAMEGIVEN": '431', - "ERR_ERRONEUSNICKNAME": '432', - "ERR_NICKNAMEINUSE": '433', - "ERR_NICKCOLLISION": '436', - "ERR_UNAVAILRESOURCE": '437', - "ERR_USERNOTINCHANNEL": '441', - "ERR_NOTONCHANNEL": '442', - "ERR_USERONCHANNEL": '443', - "ERR_NOLOGIN": '444', - "ERR_SUMMONDISABLED": '445', - "ERR_USERSDISABLED": '446', - "ERR_NOTREGISTERED": '451', - "ERR_NEEDMOREPARAMS": '461', - "ERR_ALREADYREGISTRED": '462', - "ERR_NOPERMFORHOST": '463', - "ERR_PASSWDMISMATCH": '464', - "ERR_YOUREBANNEDCREEP": '465', - "ERR_YOUWILLBEBANNED": '466', - "ERR_KEYSET": '467', - "ERR_CHANNELISFULL": '471', - "ERR_UNKNOWNMODE": '472', - "ERR_INVITEONLYCHAN": '473', - "ERR_BANNEDFROMCHAN": '474', - "ERR_BADCHANNELKEY": '475', - "ERR_BADCHANMASK": '476', - "ERR_NOCHANMODES": '477', - "ERR_BANLISTFULL": '478', - "ERR_NOPRIVILEGES": '481', - "ERR_CHANOPRIVSNEEDED": '482', - "ERR_CANTKILLSERVER": '483', - "ERR_RESTRICTED": '484', - "ERR_UNIQOPPRIVSNEEDED": '485', - "ERR_NOOPERHOST": '491', - "ERR_NOSERVICEHOST": '492', - "ERR_UMODEUNKNOWNFLAG": '501', - "ERR_USERSDONTMATCH": '502', -} - -numeric_to_symbolic = {} -for k, v in symbolic_to_numeric.items(): - numeric_to_symbolic[v] = k diff --git a/tools/buildbot/pylibs/twisted/words/protocols/jabber/__init__.py b/tools/buildbot/pylibs/twisted/words/protocols/jabber/__init__.py deleted file mode 100644 index 53c765c..0000000 --- a/tools/buildbot/pylibs/twisted/words/protocols/jabber/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -# -*- test-case-name: twisted.words.test -*- -# Copyright (c) 2001-2006 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Twisted Jabber: Jabber Protocol Helpers -""" diff --git a/tools/buildbot/pylibs/twisted/words/protocols/jabber/client.py b/tools/buildbot/pylibs/twisted/words/protocols/jabber/client.py deleted file mode 100644 index 1cd1266..0000000 --- a/tools/buildbot/pylibs/twisted/words/protocols/jabber/client.py +++ /dev/null @@ -1,369 +0,0 @@ -# -*- test-case-name: twisted.words.test.test_jabberclient -*- -# -# Copyright (c) 2001-2005 Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.internet import defer -from twisted.words.xish import domish, xpath, utility -from twisted.words.protocols.jabber import xmlstream, sasl, error -from twisted.words.protocols.jabber.jid import JID - -NS_XMPP_STREAMS = 'urn:ietf:params:xml:ns:xmpp-streams' -NS_XMPP_BIND = 'urn:ietf:params:xml:ns:xmpp-bind' -NS_XMPP_SESSION = 'urn:ietf:params:xml:ns:xmpp-session' -NS_IQ_AUTH_FEATURE = 'http://jabber.org/features/iq-auth' - -DigestAuthQry = xpath.internQuery("/iq/query/digest") -PlaintextAuthQry = xpath.internQuery("/iq/query/password") - -def basicClientFactory(jid, secret): - a = BasicAuthenticator(jid, secret) - return xmlstream.XmlStreamFactory(a) - -class IQ(domish.Element): - """ - Wrapper for a Info/Query packet. - - This provides the necessary functionality to send IQs and get notified when - a result comes back. It's a subclass from L{domish.Element}, so you can use - the standard DOM manipulation calls to add data to the outbound request. - - @type callbacks: L{utility.CallbackList} - @cvar callbacks: Callback list to be notified when response comes back - - """ - def __init__(self, xmlstream, type = "set"): - """ - @type xmlstream: L{xmlstream.XmlStream} - @param xmlstream: XmlStream to use for transmission of this IQ - - @type type: L{str} - @param type: IQ type identifier ('get' or 'set') - """ - - domish.Element.__init__(self, ("jabber:client", "iq")) - self.addUniqueId() - self["type"] = type - self._xmlstream = xmlstream - self.callbacks = utility.CallbackList() - - def addCallback(self, fn, *args, **kwargs): - """ - Register a callback for notification when the IQ result is available. - """ - - self.callbacks.addCallback(True, fn, *args, **kwargs) - - def send(self, to = None): - """ - Call this method to send this IQ request via the associated XmlStream. - - @param to: Jabber ID of the entity to send the request to - @type to: L{str} - - @returns: Callback list for this IQ. Any callbacks added to this list - will be fired when the result comes back. - """ - if to != None: - self["to"] = to - self._xmlstream.addOnetimeObserver("/iq[@id='%s']" % self["id"], \ - self._resultEvent) - self._xmlstream.send(self) - - def _resultEvent(self, iq): - self.callbacks.callback(iq) - self.callbacks = None - - - -class IQAuthInitializer(object): - """ - Non-SASL Authentication initializer for the initiating entity. - - This protocol is defined in - U{JEP-0078} and mainly serves for - compatibility with pre-XMPP-1.0 server implementations. - """ - - INVALID_USER_EVENT = "//event/client/basicauth/invaliduser" - AUTH_FAILED_EVENT = "//event/client/basicauth/authfailed" - - def __init__(self, xs): - self.xmlstream = xs - - - def initialize(self): - # Send request for auth fields - iq = xmlstream.IQ(self.xmlstream, "get") - iq.addElement(("jabber:iq:auth", "query")) - jid = self.xmlstream.authenticator.jid - iq.query.addElement("username", content = jid.user) - - d = iq.send() - d.addCallbacks(self._cbAuthQuery, self._ebAuthQuery) - return d - - - def _cbAuthQuery(self, iq): - jid = self.xmlstream.authenticator.jid - password = self.xmlstream.authenticator.password - - # Construct auth request - reply = xmlstream.IQ(self.xmlstream, "set") - reply.addElement(("jabber:iq:auth", "query")) - reply.query.addElement("username", content = jid.user) - reply.query.addElement("resource", content = jid.resource) - - # Prefer digest over plaintext - if DigestAuthQry.matches(iq): - digest = xmlstream.hashPassword(self.xmlstream.sid, password) - reply.query.addElement("digest", content = digest) - else: - reply.query.addElement("password", content = password) - - d = reply.send() - d.addCallbacks(self._cbAuth, self._ebAuth) - return d - - - def _ebAuthQuery(self, failure): - failure.trap(error.StanzaError) - e = failure.value - if e.condition == 'not-authorized': - self.xmlstream.dispatch(e.stanza, self.INVALID_USER_EVENT) - else: - self.xmlstream.dispatch(e.stanza, self.AUTH_FAILED_EVENT) - - return failure - - - def _cbAuth(self, iq): - pass - - - def _ebAuth(self, failure): - failure.trap(error.StanzaError) - self.xmlstream.dispatch(failure.value.stanza, self.AUTH_FAILED_EVENT) - return failure - - - -class BasicAuthenticator(xmlstream.ConnectAuthenticator): - """ - Authenticates an XmlStream against a Jabber server as a Client. - - This only implements non-SASL authentication, per - U{JEP-0078}. Additionally, this - authenticator provides the ability to perform inline registration, per - U{JEP-0077}. - - Under normal circumstances, the BasicAuthenticator generates the - L{xmlstream.STREAM_AUTHD_EVENT} once the stream has authenticated. However, - it can also generate other events, such as: - - L{INVALID_USER_EVENT} : Authentication failed, due to invalid username - - L{AUTH_FAILED_EVENT} : Authentication failed, due to invalid password - - L{REGISTER_FAILED_EVENT} : Registration failed - - If authentication fails for any reason, you can attempt to register by - calling the L{registerAccount} method. If the registration succeeds, a - L{xmlstream.STREAM_AUTHD_EVENT} will be fired. Otherwise, one of the above - errors will be generated (again). - """ - - namespace = "jabber:client" - - INVALID_USER_EVENT = IQAuthInitializer.INVALID_USER_EVENT - AUTH_FAILED_EVENT = IQAuthInitializer.AUTH_FAILED_EVENT - REGISTER_FAILED_EVENT = "//event/client/basicauth/registerfailed" - - def __init__(self, jid, password): - xmlstream.ConnectAuthenticator.__init__(self, jid.host) - self.jid = jid - self.password = password - - def associateWithStream(self, xs): - xs.version = (0, 0) - xmlstream.ConnectAuthenticator.associateWithStream(self, xs) - - inits = [ (xmlstream.TLSInitiatingInitializer, False), - (IQAuthInitializer, True), - ] - - for initClass, required in inits: - init = initClass(xs) - init.required = required - xs.initializers.append(init) - - # TODO: move registration into an Initializer? - - def registerAccount(self, username = None, password = None): - if username: - self.jid.user = username - if password: - self.password = password - - iq = IQ(self.xmlstream, "set") - iq.addElement(("jabber:iq:register", "query")) - iq.query.addElement("username", content = self.jid.user) - iq.query.addElement("password", content = self.password) - - iq.addCallback(self._registerResultEvent) - - iq.send() - - def _registerResultEvent(self, iq): - if iq["type"] == "result": - # Registration succeeded -- go ahead and auth - self.streamStarted() - else: - # Registration failed - self.xmlstream.dispatch(iq, self.REGISTER_FAILED_EVENT) - - - -class CheckVersionInitializer(object): - """ - Initializer that checks if the minimum common stream version number is 1.0. - """ - - def __init__(self, xs): - self.xmlstream = xs - - - def initialize(self): - if self.xmlstream.version < (1, 0): - raise error.StreamError('unsupported-version') - - - -class BindInitializer(xmlstream.BaseFeatureInitiatingInitializer): - """ - Initializer that implements Resource Binding for the initiating entity. - - This protocol is documented in U{RFC 3920, section - 7}. - """ - - feature = (NS_XMPP_BIND, 'bind') - - def start(self): - iq = xmlstream.IQ(self.xmlstream, 'set') - bind = iq.addElement((NS_XMPP_BIND, 'bind')) - resource = self.xmlstream.authenticator.jid.resource - if resource: - bind.addElement('resource', content=resource) - d = iq.send() - d.addCallback(self.onBind) - return d - - - def onBind(self, iq): - if iq.bind: - self.xmlstream.authenticator.jid = JID(unicode(iq.bind.jid)) - - - -class SessionInitializer(xmlstream.BaseFeatureInitiatingInitializer): - """ - Initializer that implements session establishment for the initiating - entity. - - This protocol is defined in U{RFC 3921, section - 3}. - """ - - feature = (NS_XMPP_SESSION, 'session') - - def start(self): - iq = xmlstream.IQ(self.xmlstream, 'set') - session = iq.addElement((NS_XMPP_SESSION, 'session')) - return iq.send() - - - -def XMPPClientFactory(jid, password): - """ - Client factory for XMPP 1.0 (only). - - This returns a L{xmlstream.XmlStreamFactory} with an L{XMPPAuthenticator} - object to perform the stream initialization steps (such as authentication). - - @see: The notes at L{XMPPAuthenticator} describe how the L{jid} and - L{password} parameters are to be used. - - @param jid: Jabber ID to connect with. - @type jid: L{jid.JID} - @param password: password to authenticate with. - @type password: L{unicode} - @return: XML stream factory. - @rtype: L{xmlstream.XmlStreamFactory} - """ - a = XMPPAuthenticator(jid, password) - return xmlstream.XmlStreamFactory(a) - - - -class XMPPAuthenticator(xmlstream.ConnectAuthenticator): - """ - Initializes an XmlStream connecting to an XMPP server as a Client. - - This authenticator performs the initialization steps needed to start - exchanging XML stanzas with an XMPP server as an XMPP client. It checks if - the server advertises XML stream version 1.0, negotiates TLS (when - available), performs SASL authentication, binds a resource and establishes - a session. - - Upon successful stream initialization, the L{xmlstream.STREAM_AUTHD_EVENT} - event will be dispatched through the XML stream object. Otherwise, the - L{xmlstream.INIT_FAILED_EVENT} event will be dispatched with a failure - object. - - After inspection of the failure, initialization can then be restarted by - calling L{initializeStream}. For example, in case of authentication - failure, a user may be given the opportunity to input the correct password. - By setting the L{password} instance variable and restarting initialization, - the stream authentication step is then retried, and subsequent steps are - performed if succesful. - - @ivar jid: Jabber ID to authenticate with. This may contain a resource - part, as a suggestion to the server for resource binding. A - server may override this, though. If the resource part is left - off, the server will generate a unique resource identifier. - The server will always return the full Jabber ID in the - resource binding step, and this is stored in this instance - variable. - @type jid: L{jid.JID} - @ivar password: password to be used during SASL authentication. - @type password: L{unicode} - """ - - namespace = 'jabber:client' - - def __init__(self, jid, password): - xmlstream.ConnectAuthenticator.__init__(self, jid.host) - self.jid = jid - self.password = password - - - def associateWithStream(self, xs): - """ - Register with the XML stream. - - Populates stream's list of initializers, along with their - requiredness. This list is used by - L{ConnectAuthenticator.initializeStream} to perform the initalization - steps. - """ - xmlstream.ConnectAuthenticator.associateWithStream(self, xs) - - xs.initializers = [CheckVersionInitializer(xs)] - inits = [ (xmlstream.TLSInitiatingInitializer, False), - (sasl.SASLInitiatingInitializer, True), - (BindInitializer, False), - (SessionInitializer, False), - ] - - for initClass, required in inits: - init = initClass(xs) - init.required = required - xs.initializers.append(init) diff --git a/tools/buildbot/pylibs/twisted/words/protocols/jabber/component.py b/tools/buildbot/pylibs/twisted/words/protocols/jabber/component.py deleted file mode 100644 index c6be76c..0000000 --- a/tools/buildbot/pylibs/twisted/words/protocols/jabber/component.py +++ /dev/null @@ -1,229 +0,0 @@ -# -*- test-case-name: twisted.words.test.test_jabbercomponent -*- -# -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -External server-side components. - -Most Jabber server implementations allow for add-on components that act as a -seperate entity on the Jabber network, but use the server-to-server -functionality of a regular Jabber IM server. These so-called 'external -components' are connected to the Jabber server using the Jabber Component -Protocol as defined in U{JEP-0114}. - -This module allows for writing external server-side component by assigning one -or more services implementing L{ijabber.IService} up to L{ServiceManager}. The -ServiceManager connects to the Jabber server and is responsible for the -corresponding XML stream. -""" - -from zope.interface import implements - -from twisted.application import service -from twisted.internet import defer -from twisted.words.xish import domish -from twisted.words.protocols.jabber import ijabber, jstrports, xmlstream - -def componentFactory(componentid, password): - """ - XML stream factory for external server-side components. - - @param componentid: JID of the component. - @type componentid: L{unicode} - @param password: password used to authenticate to the server. - @type password: L{str} - """ - a = ConnectComponentAuthenticator(componentid, password) - return xmlstream.XmlStreamFactory(a) - -class ComponentInitiatingInitializer(object): - """ - External server-side component authentication initializer for the - initiating entity. - - @ivar xmlstream: XML stream between server and component. - @type xmlstream: L{xmlstream.XmlStream} - """ - - def __init__(self, xs): - self.xmlstream = xs - self._deferred = None - - def initialize(self): - xs = self.xmlstream - hs = domish.Element((self.xmlstream.namespace, "handshake")) - hs.addContent(xmlstream.hashPassword(xs.sid, - xs.authenticator.password)) - - # Setup observer to watch for handshake result - xs.addOnetimeObserver("/handshake", self._cbHandshake) - xs.send(hs) - self._deferred = defer.Deferred() - return self._deferred - - def _cbHandshake(self, _): - # we have successfully shaken hands and can now consider this - # entity to represent the component JID. - self.xmlstream.thisEntity = self.xmlstream.otherEntity - self._deferred.callback(None) - -class ConnectComponentAuthenticator(xmlstream.ConnectAuthenticator): - """ - Authenticator to permit an XmlStream to authenticate against a Jabber - server as an external component (where the Authenticator is initiating the - stream). - """ - namespace = 'jabber:component:accept' - - def __init__(self, componentjid, password): - """ - @type componentjid: L{str} - @param componentjid: Jabber ID that this component wishes to bind to. - - @type password: L{str} - @param password: Password/secret this component uses to authenticate. - """ - # Note that we are sending 'to' our desired component JID. - xmlstream.ConnectAuthenticator.__init__(self, componentjid) - self.password = password - - def associateWithStream(self, xs): - xs.version = (0, 0) - xmlstream.ConnectAuthenticator.associateWithStream(self, xs) - - xs.initializers = [ComponentInitiatingInitializer(xs)] - -class ListenComponentAuthenticator(xmlstream.Authenticator): - """ - Placeholder for listening components. - """ - -class Service(service.Service): - """ - External server-side component service. - """ - - implements(ijabber.IService) - - def componentConnected(self, xs): - pass - - def componentDisconnected(self): - pass - - def transportConnected(self, xs): - pass - - def send(self, obj): - """ - Send data over service parent's XML stream. - - @note: L{ServiceManager} maintains a queue for data sent using this - method when there is no current established XML stream. This data is - then sent as soon as a new stream has been established and initialized. - Subsequently, L{componentConnected} will be called again. If this - queueing is not desired, use C{send} on the XmlStream object (passed to - L{componentConnected}) directly. - - @param obj: data to be sent over the XML stream. This is usually an - object providing L{domish.IElement}, or serialized XML. See - L{xmlstream.XmlStream} for details. - """ - - self.parent.send(obj) - -class ServiceManager(service.MultiService): - """ - Business logic representing a managed component connection to a Jabber - router. - - This service maintains a single connection to a Jabber router and provides - facilities for packet routing and transmission. Business logic modules are - services implementing L{ijabber.IService} (like subclasses of L{Service}), and - added as sub-service. - """ - - def __init__(self, jid, password): - service.MultiService.__init__(self) - - # Setup defaults - self.jabberId = jid - self.xmlstream = None - - # Internal buffer of packets - self._packetQueue = [] - - # Setup the xmlstream factory - self._xsFactory = componentFactory(self.jabberId, password) - - # Register some lambda functions to keep the self.xmlstream var up to - # date - self._xsFactory.addBootstrap(xmlstream.STREAM_CONNECTED_EVENT, - self._connected) - self._xsFactory.addBootstrap(xmlstream.STREAM_AUTHD_EVENT, self._authd) - self._xsFactory.addBootstrap(xmlstream.STREAM_END_EVENT, - self._disconnected) - - # Map addBootstrap and removeBootstrap to the underlying factory -- is - # this right? I have no clue...but it'll work for now, until i can - # think about it more. - self.addBootstrap = self._xsFactory.addBootstrap - self.removeBootstrap = self._xsFactory.removeBootstrap - - def getFactory(self): - return self._xsFactory - - def _connected(self, xs): - self.xmlstream = xs - for c in self: - if ijabber.IService.providedBy(c): - c.transportConnected(xs) - - def _authd(self, xs): - # Flush all pending packets - for p in self._packetQueue: - self.xmlstream.send(p) - self._packetQueue = [] - - # Notify all child services which implement the IService interface - for c in self: - if ijabber.IService.providedBy(c): - c.componentConnected(xs) - - def _disconnected(self, _): - self.xmlstream = None - - # Notify all child services which implement - # the IService interface - for c in self: - if ijabber.IService.providedBy(c): - c.componentDisconnected() - - def send(self, obj): - """ - Send data over the XML stream. - - When there is no established XML stream, the data is queued and sent - out when a new XML stream has been established and initialized. - - @param obj: data to be sent over the XML stream. This is usually an - object providing L{domish.IElement}, or serialized XML. See - L{xmlstream.XmlStream} for details. - """ - - if self.xmlstream != None: - self.xmlstream.send(obj) - else: - self._packetQueue.append(obj) - -def buildServiceManager(jid, password, strport): - """ - Constructs a pre-built L{ServiceManager}, using the specified strport - string. - """ - - svc = ServiceManager(jid, password) - client_svc = jstrports.client(strport, svc.getFactory()) - client_svc.setServiceParent(svc) - return svc diff --git a/tools/buildbot/pylibs/twisted/words/protocols/jabber/error.py b/tools/buildbot/pylibs/twisted/words/protocols/jabber/error.py deleted file mode 100644 index 64fbe28..0000000 --- a/tools/buildbot/pylibs/twisted/words/protocols/jabber/error.py +++ /dev/null @@ -1,336 +0,0 @@ -# -*- test-case-name: twisted.words.test.test_jabbererror -*- -# -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -XMPP Error support. -""" - -import copy - -from twisted.words.xish import domish - -NS_XML = "http://www.w3.org/XML/1998/namespace" -NS_XMPP_STREAMS = "urn:ietf:params:xml:ns:xmpp-streams" -NS_XMPP_STANZAS = "urn:ietf:params:xml:ns:xmpp-stanzas" - -STANZA_CONDITIONS = { - 'bad-request': {'code': '400', 'type': 'modify'}, - 'conflict': {'code': '409', 'type': 'cancel'}, - 'feature-not-implemented': {'code': '501', 'type': 'cancel'}, - 'forbidden': {'code': '403', 'type': 'auth'}, - 'gone': {'code': '302', 'type': 'modify'}, - 'internal-server-error': {'code': '500', 'type': 'wait'}, - 'item-not-found': {'code': '404', 'type': 'cancel'}, - 'jid-malformed': {'code': '400', 'type': 'modify'}, - 'not-acceptable': {'code': '406', 'type': 'modify'}, - 'not-allowed': {'code': '405', 'type': 'cancel'}, - 'not-authorized': {'code': '401', 'type': 'auth'}, - 'payment-required': {'code': '402', 'type': 'auth'}, - 'recipient-unavailable': {'code': '404', 'type': 'wait'}, - 'redirect': {'code': '302', 'type': 'modify'}, - 'registration-required': {'code': '407', 'type': 'auth'}, - 'remote-server-not-found': {'code': '404', 'type': 'cancel'}, - 'remove-server-timeout': {'code': '504', 'type': 'wait'}, - 'resource-constraint': {'code': '500', 'type': 'wait'}, - 'service-unavailable': {'code': '503', 'type': 'cancel'}, - 'subscription-required': {'code': '407', 'type': 'auth'}, - 'undefined-condition': {'code': '500', 'type': None}, - 'unexpected-request': {'code': '400', 'type': 'wait'}, -} - -CODES_TO_CONDITIONS = { - '302': ('gone', 'modify'), - '400': ('bad-request', 'modify'), - '401': ('not-authorized', 'auth'), - '402': ('payment-required', 'auth'), - '403': ('forbidden', 'auth'), - '404': ('item-not-found', 'cancel'), - '405': ('not-allowed', 'cancel'), - '406': ('not-acceptable', 'modify'), - '407': ('registration-required', 'auth'), - '408': ('remote-server-timeout', 'wait'), - '409': ('conflict', 'cancel'), - '500': ('internal-server-error', 'wait'), - '501': ('feature-not-implemented', 'cancel'), - '502': ('service-unavailable', 'wait'), - '503': ('service-unavailable', 'cancel'), - '504': ('remote-server-timeout', 'wait'), - '510': ('service-unavailable', 'cancel'), -} - -class BaseError(Exception): - """ - Base class for XMPP error exceptions. - - @cvar namespace: The namespace of the C{error} element generated by - C{getElement}. - @type namespace: C{str} - @ivar condition: The error condition. The valid values are defined by - subclasses of L{BaseError}. - @type contition: C{str} - @ivar text: Optional text message to supplement the condition or application - specific condition. - @type text: C{unicode} - @ivar textLang: Identifier of the language used for the message in C{text}. - Values are as described in RFC 3066. - @type textLang: C{str} - @ivar appCondition: Application specific condition element, supplementing - the error condition in C{condition}. - @type appCondition: object providing L{domish.IElement}. - """ - - namespace = None - - def __init__(self, condition, text=None, textLang=None, appCondition=None): - Exception.__init__(self) - self.condition = condition - self.text = text - self.textLang = textLang - self.appCondition = appCondition - - - def __str__(self): - message = "%s with condition %r" % (self.__class__.__name__, - self.condition) - - if self.text: - message += ': ' + self.text - - return message - - - def getElement(self): - """ - Get XML representation from self. - - The method creates an L{domish} representation of the - error data contained in this exception. - - @rtype: L{domish.Element} - """ - error = domish.Element((None, 'error')) - error.addElement((self.namespace, self.condition)) - if self.text: - text = error.addElement((self.namespace, 'text'), - content=self.text) - if self.textLang: - text[(NS_XML, 'lang')] = self.textLang - if self.appCondition: - error.addChild(self.appCondition) - return error - - - -class StreamError(BaseError): - """ - Stream Error exception. - - Refer to RFC 3920, section 4.7.3, for the allowed values for C{condition}. - """ - - namespace = NS_XMPP_STREAMS - - def getElement(self): - """ - Get XML representation from self. - - Overrides the base L{BaseError.getElement} to make sure the returned - element is in the XML Stream namespace. - - @rtype: L{domish.Element} - """ - from twisted.words.protocols.jabber.xmlstream import NS_STREAMS - - error = BaseError.getElement(self) - error.uri = NS_STREAMS - return error - - - -class StanzaError(BaseError): - """ - Stanza Error exception. - - Refer to RFC 3920, section 9.3, for the allowed values for C{condition} and - C{type}. - - @ivar type: The stanza error type. Gives a suggestion to the recipient - of the error on how to proceed. - @type type: C{str} - @ivar code: A numeric identifier for the error condition for backwards - compatibility with pre-XMPP Jabber implementations. - """ - - namespace = NS_XMPP_STANZAS - - def __init__(self, condition, type=None, text=None, textLang=None, - appCondition=None): - BaseError.__init__(self, condition, text, textLang, appCondition) - - if type is None: - try: - type = STANZA_CONDITIONS[condition]['type'] - except KeyError: - pass - self.type = type - - try: - self.code = STANZA_CONDITIONS[condition]['code'] - except KeyError: - self.code = None - - self.children = [] - self.iq = None - - - def getElement(self): - """ - Get XML representation from self. - - Overrides the base L{BaseError.getElement} to make sure the returned - element has a C{type} attribute and optionally a legacy C{code} - attribute. - - @rtype: L{domish.Element} - """ - error = BaseError.getElement(self) - error['type'] = self.type - if self.code: - error['code'] = self.code - return error - - - def toResponse(self, stanza): - """ - Construct error response stanza. - - The C{stanza} is transformed into an error response stanza by - swapping the C{to} and C{from} addresses and inserting an error - element. - - @note: This creates a shallow copy of the list of child elements of the - stanza. The child elements themselves are not copied themselves, - and references to their parent element will still point to the - original stanza element. - - The serialization of an element does not use the reference to - its parent, so the typical use case of immediately sending out - the constructed error response is not affected. - - @param stanza: the stanza to respond to - @type stanza: L{domish.Element} - """ - from twisted.words.protocols.jabber.xmlstream import toResponse - response = toResponse(stanza, stanzaType='error') - response.children = copy.copy(stanza.children) - response.addChild(self.getElement()) - return response - - -def _getText(element): - for child in element.children: - if isinstance(child, basestring): - return unicode(child) - - return None - - - -def _parseError(error, errorNamespace): - """ - Parses an error element. - - @param error: The error element to be parsed - @type error: L{domish.Element} - @param errorNamespace: The namespace of the elements that hold the error - condition and text. - @type errorNamespace: C{str} - @return: Dictionary with extracted error information. If present, keys - C{condition}, C{text}, C{textLang} have a string value, - and C{appCondition} has an L{domish.Element} value. - @rtype: L{dict} - """ - condition = None - text = None - textLang = None - appCondition = None - - for element in error.elements(): - if element.uri == errorNamespace: - if element.name == 'text': - text = _getText(element) - textLang = element.getAttribute((NS_XML, 'lang')) - else: - condition = element.name - else: - appCondition = element - - return { - 'condition': condition, - 'text': text, - 'textLang': textLang, - 'appCondition': appCondition, - } - - - -def exceptionFromStreamError(element): - """ - Build an exception object from a stream error. - - @param element: the stream error - @type element: L{domish.Element} - @return: the generated exception object - @rtype: L{StreamError} - """ - error = _parseError(element, NS_XMPP_STREAMS) - - exception = StreamError(error['condition'], - error['text'], - error['textLang'], - error['appCondition']) - - return exception - - - -def exceptionFromStanza(stanza): - """ - Build an exception object from an error stanza. - - @param stanza: the error stanza - @type stanza: L{domish.Element} - @return: the generated exception object - @rtype: L{StanzaError} - """ - children = [] - condition = text = textLang = appCondition = type = code = None - - for element in stanza.elements(): - if element.name == 'error' and element.uri == stanza.uri: - code = element.getAttribute('code') - type = element.getAttribute('type') - error = _parseError(element, NS_XMPP_STANZAS) - condition = error['condition'] - text = error['text'] - textLang = error['textLang'] - appCondition = error['appCondition'] - - if not condition and code: - condition, type = CODES_TO_CONDITIONS[code] - text = _getText(stanza.error) - else: - children.append(element) - - if condition is None: - # TODO: raise exception instead? - return StanzaError(None) - - exception = StanzaError(condition, type, text, textLang, appCondition) - - exception.children = children - exception.stanza = stanza - - return exception diff --git a/tools/buildbot/pylibs/twisted/words/protocols/jabber/ijabber.py b/tools/buildbot/pylibs/twisted/words/protocols/jabber/ijabber.py deleted file mode 100644 index 1e50179..0000000 --- a/tools/buildbot/pylibs/twisted/words/protocols/jabber/ijabber.py +++ /dev/null @@ -1,199 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Public Jabber Interfaces. -""" - -from zope.interface import Attribute, Interface - -class IInitializer(Interface): - """ - Interface for XML stream initializers. - - Initializers perform a step in getting the XML stream ready to be - used for the exchange of XML stanzas. - """ - - - -class IInitiatingInitializer(IInitializer): - """ - Interface for XML stream initializers for the initiating entity. - """ - - xmlstream = Attribute("""The associated XML stream""") - - def initialize(): - """ - Initiate the initialization step. - - May return a deferred when the initialization is done asynchronously. - """ - - - -class IIQResponseTracker(Interface): - """ - IQ response tracker interface. - - The XMPP stanza C{iq} has a request-response nature that fits - naturally with deferreds. You send out a request and when the response - comes back a deferred is fired. - - The L{IQ} class implements a C{send} method that returns a deferred. This - deferred is put in a dictionary that is kept in an L{XmlStream} object, - keyed by the request stanzas C{id} attribute. - - An object providing this interface (usually an instance of L{XmlStream}), - keeps the said dictionary and sets observers on the iq stanzas of type - C{result} and C{error} and lets the callback fire the associated deferred. - """ - iqDeferreds = Attribute("Dictionary of deferreds waiting for an iq " - "response") - - - -class IXMPPHandler(Interface): - """ - Interface for XMPP protocol handlers. - - Objects that provide this interface can be added to a stream manager to - handle of (part of) an XMPP extension protocol. - """ - - parent = Attribute("""XML stream manager for this handler""") - xmlstream = Attribute("""The managed XML stream""") - - def setHandlerParent(parent): - """ - Set the parent of the handler. - - @type parent: L{IXMPPHandlerCollection} - """ - - - def disownHandlerParent(parent): - """ - Remove the parent of the handler. - - @type parent: L{IXMPPHandlerCollection} - """ - - - def makeConnection(xs): - """ - A connection over the underlying transport of the XML stream has been - established. - - At this point, no traffic has been exchanged over the XML stream - given in C{xs}. - - This should setup L{xmlstream} and call L{connectionMade}. - - @type xs: L{XmlStream} - """ - - - def connectionMade(): - """ - Called after a connection has been established. - - This method can be used to change properties of the XML Stream, its - authenticator or the stream manager prior to stream initialization - (including authentication). - """ - - - def connectionInitialized(): - """ - The XML stream has been initialized. - - At this point, authentication was successful, and XML stanzas can be - exchanged over the XML stream L{xmlstream}. This method can be - used to setup observers for incoming stanzas. - """ - - - def connectionLost(reason): - """ - The XML stream has been closed. - - Subsequent use of L{parent.send} will result in data being queued - until a new connection has been established. - - @type reason: L{twisted.python.failure.Failure} - """ - - - -class IXMPPHandlerCollection(Interface): - """ - Collection of handlers. - - Contain several handlers and manage their connection. - """ - - def __iter__(): - """ - Get an iterator over all child handlers. - """ - - - def addHandler(handler): - """ - Add a child handler. - - @type handler: L{IXMPPHandler} - """ - - - def removeHandler(handler): - """ - Remove a child handler. - - @type handler: L{IXMPPHandler} - """ - - - -class IService(Interface): - """ - External server-side component service interface. - - Services that provide this interface can be added to L{ServiceManager} to - implement (part of) the functionality of the server-side component. - """ - - def componentConnected(xs): - """ - Parent component has established a connection. - - At this point, authentication was succesful, and XML stanzas - can be exchanged over the XML stream L{xs}. This method can be used - to setup observers for incoming stanzas. - - @param xs: XML Stream that represents the established connection. - @type xs: L{xmlstream.XmlStream} - """ - - - def componentDisconnected(): - """ - Parent component has lost the connection to the Jabber server. - - Subsequent use of C{self.parent.send} will result in data being - queued until a new connection has been established. - """ - - - def transportConnected(xs): - """ - Parent component has established a connection over the underlying - transport. - - At this point, no traffic has been exchanged over the XML stream. This - method can be used to change properties of the XML Stream (in L{xs}), - the service manager or it's authenticator prior to stream - initialization (including authentication). - """ diff --git a/tools/buildbot/pylibs/twisted/words/protocols/jabber/jid.py b/tools/buildbot/pylibs/twisted/words/protocols/jabber/jid.py deleted file mode 100644 index 2604685..0000000 --- a/tools/buildbot/pylibs/twisted/words/protocols/jabber/jid.py +++ /dev/null @@ -1,249 +0,0 @@ -# -*- test-case-name: twisted.words.test.test_jabberjid -*- -# -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Jabber Identifier support. - -This module provides an object to represent Jabber Identifiers (JIDs) and -parse string representations into them with proper checking for illegal -characters, case folding and canonicalisation through L{stringprep}. -""" - -from twisted.words.protocols.jabber.xmpp_stringprep import nodeprep, resourceprep, nameprep - -class InvalidFormat(Exception): - """ - The given string could not be parsed into a valid Jabber Identifier (JID). - """ - -def parse(jidstring): - """ - Parse given JID string into its respective parts and apply stringprep. - - @param jidstring: string representation of a JID. - @type jidstring: C{unicode} - @return: tuple of (user, host, resource), each of type C{unicode} as - the parsed and stringprep'd parts of the given JID. If the - given string did not have a user or resource part, the respective - field in the tuple will hold C{None}. - @rtype: C{tuple} - """ - user = None - host = None - resource = None - - # Search for delimiters - user_sep = jidstring.find("@") - res_sep = jidstring.find("/") - - if user_sep == -1: - if res_sep == -1: - # host - host = jidstring - else: - # host/resource - host = jidstring[0:res_sep] - resource = jidstring[res_sep + 1:] or None - else: - if res_sep == -1: - # user@host - user = jidstring[0:user_sep] or None - host = jidstring[user_sep + 1:] - else: - if user_sep < res_sep: - # user@host/resource - user = jidstring[0:user_sep] or None - host = jidstring[user_sep + 1:user_sep + (res_sep - user_sep)] - resource = jidstring[res_sep + 1:] or None - else: - # host/resource (with an @ in resource) - host = jidstring[0:res_sep] - resource = jidstring[res_sep + 1:] or None - - return prep(user, host, resource) - -def prep(user, host, resource): - """ - Perform stringprep on all JID fragments. - - @param user: The user part of the JID. - @type user: C{unicode} - @param host: The host part of the JID. - @type host: C{unicode} - @param resource: The resource part of the JID. - @type resource: C{unicode} - @return: The given parts with stringprep applied. - @rtype: C{tuple} - """ - - if user: - try: - user = nodeprep.prepare(unicode(user)) - except UnicodeError: - raise InvalidFormat, "Invalid character in username" - else: - user = None - - if not host: - raise InvalidFormat, "Server address required." - else: - try: - host = nameprep.prepare(unicode(host)) - except UnicodeError: - raise InvalidFormat, "Invalid character in hostname" - - if resource: - try: - resource = resourceprep.prepare(unicode(resource)) - except UnicodeError: - raise InvalidFormat, "Invalid character in resource" - else: - resource = None - - return (user, host, resource) - -__internJIDs = {} - -def internJID(jidstring): - """ - Return interned JID. - - @rtype: L{JID} - """ - - if jidstring in __internJIDs: - return __internJIDs[jidstring] - else: - j = JID(jidstring) - __internJIDs[jidstring] = j - return j - -class JID(object): - """ - Represents a stringprep'd Jabber ID. - - JID objects are hashable so they can be used in sets and as keys in - dictionaries. - """ - - def __init__(self, str=None, tuple=None): - if not (str or tuple): - raise RuntimeError("You must provide a value for either 'str' or " - "'tuple' arguments.") - - if str: - user, host, res = parse(str) - else: - user, host, res = prep(*tuple) - - self.user = user - self.host = host - self.resource = res - - def userhost(self): - """ - Extract the bare JID as a unicode string. - - A bare JID does not have a resource part, so this returns either - C{user@host} or just C{host}. - - @rtype: C{unicode} - """ - if self.user: - return u"%s@%s" % (self.user, self.host) - else: - return self.host - - def userhostJID(self): - """ - Extract the bare JID. - - A bare JID does not have a resource part, so this returns a - L{JID} object representing either C{user@host} or just C{host}. - - If the object this method is called upon doesn't have a resource - set, it will return itself. Otherwise, the bare JID object will - be created, interned using L{internJID}. - - @rtype: L{JID} - """ - if self.resource: - return internJID(self.userhost()) - else: - return self - - def full(self): - """ - Return the string representation of this JID. - - @rtype: C{unicode} - """ - if self.user: - if self.resource: - return u"%s@%s/%s" % (self.user, self.host, self.resource) - else: - return u"%s@%s" % (self.user, self.host) - else: - if self.resource: - return u"%s/%s" % (self.host, self.resource) - else: - return self.host - - def __eq__(self, other): - """ - Equality comparison. - - L{JID}s compare equal if their user, host and resource parts all - compare equal. When comparing against instances of other types, it - uses the default comparison. - """ - if isinstance(other, JID): - return (self.user == other.user and - self.host == other.host and - self.resource == other.resource) - else: - return NotImplemented - - def __ne__(self, other): - """ - Inequality comparison. - - This negates L{__eq__} for comparison with JIDs and uses the default - comparison for other types. - """ - result = self.__eq__(other) - if result is NotImplemented: - return result - else: - return not result - - def __hash__(self): - """ - Calculate hash. - - L{JID}s with identical constituent user, host and resource parts have - equal hash values. In combination with the comparison defined on JIDs, - this allows for using L{JID}s in sets and as dictionary keys. - """ - return hash((self.user, self.host, self.resource)) - - def __unicode__(self): - """ - Get unicode representation. - - Return the string representation of this JID as a unicode string. - @see: L{full} - """ - - return self.full() - - def __repr__(self): - """ - Get object representation. - - Returns a string that would create a new JID object that compares equal - to this one. - """ - return 'JID(%r)' % self.full() diff --git a/tools/buildbot/pylibs/twisted/words/protocols/jabber/jstrports.py b/tools/buildbot/pylibs/twisted/words/protocols/jabber/jstrports.py deleted file mode 100644 index dbecbdd..0000000 --- a/tools/buildbot/pylibs/twisted/words/protocols/jabber/jstrports.py +++ /dev/null @@ -1,31 +0,0 @@ -# -*- test-case-name: twisted.words.test -*- -# Copyright (c) 2001-2005 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" A temporary placeholder for client-capable strports, until we -sufficient use cases get identified """ - -from twisted.application import strports - -def _parseTCPSSL(factory, domain, port): - """ For the moment, parse TCP or SSL connections the same """ - return (domain, int(port), factory), {} - -def _parseUNIX(factory, address): - return (address, factory), {} - - -_funcs = { "tcp" : _parseTCPSSL, - "unix" : _parseUNIX, - "ssl" : _parseTCPSSL } - - -def parse(description, factory): - args, kw = strports._parse(description) - return (args[0].upper(),) + _funcs[args[0]](factory, *args[1:], **kw) - -def client(description, factory): - from twisted.application import internet - name, args, kw = parse(description, factory) - return getattr(internet, name + 'Client')(*args, **kw) diff --git a/tools/buildbot/pylibs/twisted/words/protocols/jabber/sasl.py b/tools/buildbot/pylibs/twisted/words/protocols/jabber/sasl.py deleted file mode 100644 index 9a9b8e3..0000000 --- a/tools/buildbot/pylibs/twisted/words/protocols/jabber/sasl.py +++ /dev/null @@ -1,225 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -XMPP-specific SASL profile. -""" - -import re -from twisted.internet import defer -from twisted.words.protocols.jabber import sasl_mechanisms, xmlstream -from twisted.words.xish import domish - -# The b64decode and b64encode functions from the base64 module are new in -# Python 2.4. For Python 2.3 compatibility, the legacy interface is used while -# working around MIMEisms. - -try: - from base64 import b64decode, b64encode -except ImportError: - import base64 - - def b64encode(s): - return "".join(base64.encodestring(s).split("\n")) - - b64decode = base64.decodestring - -NS_XMPP_SASL = 'urn:ietf:params:xml:ns:xmpp-sasl' - -def get_mechanisms(xs): - """ - Parse the SASL feature to extract the available mechanism names. - """ - mechanisms = [] - for element in xs.features[(NS_XMPP_SASL, 'mechanisms')].elements(): - if element.name == 'mechanism': - mechanisms.append(str(element)) - - return mechanisms - - -class SASLError(Exception): - """ - SASL base exception. - """ - - -class SASLNoAcceptableMechanism(SASLError): - """ - The server did not present an acceptable SASL mechanism. - """ - - -class SASLAuthError(SASLError): - """ - SASL Authentication failed. - """ - def __init__(self, condition=None): - self.condition = condition - - - def __str__(self): - return "SASLAuthError with condition %r" % self.condition - - -class SASLIncorrectEncodingError(SASLError): - """ - SASL base64 encoding was incorrect. - - RFC 3920 specifies that any characters not in the base64 alphabet - and padding characters present elsewhere than at the end of the string - MUST be rejected. See also L{fromBase64}. - - This exception is raised whenever the encoded string does not adhere - to these additional restrictions or when the decoding itself fails. - - The recommended behaviour for so-called receiving entities (like servers in - client-to-server connections, see RFC 3920 for terminology) is to fail the - SASL negotiation with a C{'incorrect-encoding'} condition. For initiating - entities, one should assume the receiving entity to be either buggy or - malevolent. The stream should be terminated and reconnecting is not - advised. - """ - -base64Pattern = re.compile("^[0-9A-Za-z+/]*[0-9A-Za-z+/=]{,2}$") - -def fromBase64(s): - """ - Decode base64 encoded string. - - This helper performs regular decoding of a base64 encoded string, but also - rejects any characters that are not in the base64 alphabet and padding - occurring elsewhere from the last or last two characters, as specified in - section 14.9 of RFC 3920. This safeguards against various attack vectors - among which the creation of a covert channel that "leaks" information. - """ - - if base64Pattern.match(s) is None: - raise SASLIncorrectEncodingError() - - try: - return b64decode(s) - except Exception, e: - raise SASLIncorrectEncodingError(str(e)) - -class SASLInitiatingInitializer(xmlstream.BaseFeatureInitiatingInitializer): - """ - Stream initializer that performs SASL authentication. - - The supported mechanisms by this initializer are C{DIGEST-MD5} and C{PLAIN} - which are attemped in that order. - """ - feature = (NS_XMPP_SASL, 'mechanisms') - _deferred = None - - def setMechanism(self): - """ - Select and setup authentication mechanism. - - Uses the authenticator's C{jid} and C{password} attribute for the - authentication credentials. If no supported SASL mechanisms are - advertized by the receiving party, a failing deferred is returned with - a L{SASLNoAcceptableMechanism} exception. - """ - - jid = self.xmlstream.authenticator.jid - password = self.xmlstream.authenticator.password - - mechanisms = get_mechanisms(self.xmlstream) - if 'DIGEST-MD5' in mechanisms: - self.mechanism = sasl_mechanisms.DigestMD5('xmpp', jid.host, None, - jid.user, password) - elif 'PLAIN' in mechanisms: - self.mechanism = sasl_mechanisms.Plain(None, jid.user, password) - else: - raise SASLNoAcceptableMechanism() - - def start(self): - """ - Start SASL authentication exchange. - """ - - self.setMechanism() - self._deferred = defer.Deferred() - self.xmlstream.addObserver('/challenge', self.onChallenge) - self.xmlstream.addOnetimeObserver('/success', self.onSuccess) - self.xmlstream.addOnetimeObserver('/failure', self.onFailure) - self.sendAuth(self.mechanism.getInitialResponse()) - return self._deferred - - def sendAuth(self, data=None): - """ - Initiate authentication protocol exchange. - - If an initial client response is given in C{data}, it will be - sent along. - - @param data: initial client response. - @type data: L{str} or L{None}. - """ - - auth = domish.Element((NS_XMPP_SASL, 'auth')) - auth['mechanism'] = self.mechanism.name - if data is not None: - auth.addContent(b64encode(data) or '=') - self.xmlstream.send(auth) - - def sendResponse(self, data=''): - """ - Send response to a challenge. - - @param data: client response. - @type data: L{str}. - """ - - response = domish.Element((NS_XMPP_SASL, 'response')) - if data: - response.addContent(b64encode(data)) - self.xmlstream.send(response) - - def onChallenge(self, element): - """ - Parse challenge and send response from the mechanism. - - @param element: the challenge protocol element. - @type element: L{domish.Element}. - """ - - try: - challenge = fromBase64(str(element)) - except SASLIncorrectEncodingError: - self._deferred.errback() - else: - self.sendResponse(self.mechanism.getResponse(challenge)) - - def onSuccess(self, success): - """ - Clean up observers, reset the XML stream and send a new header. - - @param success: the success protocol element. For now unused, but - could hold additional data. - @type success: L{domish.Element} - """ - - self.xmlstream.removeObserver('/challenge', self.onChallenge) - self.xmlstream.removeObserver('/failure', self.onFailure) - self.xmlstream.reset() - self.xmlstream.sendHeader() - self._deferred.callback(xmlstream.Reset) - - def onFailure(self, failure): - """ - Clean up observers, parse the failure and errback the deferred. - - @param failure: the failure protocol element. Holds details on - the error condition. - @type failure: L{domish.Element} - """ - - self.xmlstream.removeObserver('/challenge', self.onChallenge) - self.xmlstream.removeObserver('/success', self.onSuccess) - try: - condition = failure.firstChildElement().name - except AttributeError: - condition = None - self._deferred.errback(SASLAuthError(condition)) diff --git a/tools/buildbot/pylibs/twisted/words/protocols/jabber/sasl_mechanisms.py b/tools/buildbot/pylibs/twisted/words/protocols/jabber/sasl_mechanisms.py deleted file mode 100644 index 841b168..0000000 --- a/tools/buildbot/pylibs/twisted/words/protocols/jabber/sasl_mechanisms.py +++ /dev/null @@ -1,224 +0,0 @@ -# -*- test-case-name: twisted.words.test.test_jabbersaslmechanisms -*- -# -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Protocol agnostic implementations of SASL authentication mechanisms. -""" - -import md5, binascii, random, time, os - -from zope.interface import Interface, Attribute, implements - -class ISASLMechanism(Interface): - name = Attribute("""Common name for the SASL Mechanism.""") - - def getInitialResponse(): - """ - Get the initial client response, if defined for this mechanism. - - @return: initial client response string. - @rtype: L{str}. - """ - - - def getResponse(challenge): - """ - Get the response to a server challenge. - - @param challenge: server challenge. - @type challenge: L{str}. - @return: client response. - @rtype: L{str}. - """ - - - -class Plain(object): - """ - Implements the PLAIN SASL authentication mechanism. - - The PLAIN SASL authentication mechanism is defined in RFC 2595. - """ - implements(ISASLMechanism) - - name = 'PLAIN' - - def __init__(self, authzid, authcid, password): - self.authzid = authzid or '' - self.authcid = authcid or '' - self.password = password or '' - - - def getInitialResponse(self): - return "%s\x00%s\x00%s" % (self.authzid.encode('utf-8'), - self.authcid.encode('utf-8'), - self.password.encode('utf-8')) - - - -class DigestMD5(object): - """ - Implements the DIGEST-MD5 SASL authentication mechanism. - - The DIGEST-MD5 SASL authentication mechanism is defined in RFC 2831. - """ - implements(ISASLMechanism) - - name = 'DIGEST-MD5' - - def __init__(self, serv_type, host, serv_name, username, password): - self.username = username - self.password = password - self.defaultRealm = host - - self.digest_uri = '%s/%s' % (serv_type, host) - if serv_name is not None: - self.digest_uri += '/%s' % serv_name - - - def getInitialResponse(self): - return None - - - def getResponse(self, challenge): - directives = self._parse(challenge) - - # Compat for implementations that do not send this along with - # a succesful authentication. - if 'rspauth' in directives: - return '' - - try: - realm = directives['realm'] - except KeyError: - realm = self.defaultRealm - - return self._gen_response(directives['charset'], - realm, - directives['nonce']) - - def _parse(self, challenge): - """ - Parses the server challenge. - - Splits the challenge into a dictionary of directives with values. - - @return: challenge directives and their values. - @rtype: L{dict} of L{str} to L{str}. - """ - s = challenge - paramDict = {} - cur = 0 - remainingParams = True - while remainingParams: - # Parse a param. We can't just split on commas, because there can - # be some commas inside (quoted) param values, e.g.: - # qop="auth,auth-int" - - middle = s.index("=", cur) - name = s[cur:middle].lstrip() - middle += 1 - if s[middle] == '"': - middle += 1 - end = s.index('"', middle) - value = s[middle:end] - cur = s.find(',', end) + 1 - if cur == 0: - remainingParams = False - else: - end = s.find(',', middle) - if end == -1: - value = s[middle:].rstrip() - remainingParams = False - else: - value = s[middle:end].rstrip() - cur = end + 1 - paramDict[name] = value - - for param in ('qop', 'cipher'): - if param in paramDict: - paramDict[param] = paramDict[param].split(',') - - return paramDict - - def _unparse(self, directives): - """ - Create message string from directives. - - @param directives: dictionary of directives (names to their values). - For certain directives, extra quotes are added, as - needed. - @type directives: L{dict} of L{str} to L{str} - @return: message string. - @rtype: L{str}. - """ - - directive_list = [] - for name, value in directives.iteritems(): - if name in ('username', 'realm', 'cnonce', - 'nonce', 'digest-uri', 'authzid', 'cipher'): - directive = '%s="%s"' % (name, value) - else: - directive = '%s=%s' % (name, value) - - directive_list.append(directive) - - return ','.join(directive_list) - - - def _gen_response(self, charset, realm, nonce): - """ - Generate response-value. - - Creates a response to a challenge according to section 2.1.2.1 of - RFC 2831 using the L{charset}, L{realm} and L{nonce} directives - from the challenge. - """ - - def H(s): - return md5.new(s).digest() - - def HEX(n): - return binascii.b2a_hex(n) - - def KD(k, s): - return H('%s:%s' % (k, s)) - - try: - username = self.username.encode(charset) - password = self.password.encode(charset) - except UnicodeError: - # TODO - add error checking - raise - - nc = '%08x' % 1 # TODO: support subsequent auth. - cnonce = self._gen_nonce() - qop = 'auth' - - # TODO - add support for authzid - a1 = "%s:%s:%s" % (H("%s:%s:%s" % (username, realm, password)), - nonce, - cnonce) - a2 = "AUTHENTICATE:%s" % self.digest_uri - - response = HEX( KD ( HEX(H(a1)), - "%s:%s:%s:%s:%s" % (nonce, nc, - cnonce, "auth", HEX(H(a2))))) - - directives = {'username': username, - 'realm' : realm, - 'nonce' : nonce, - 'cnonce' : cnonce, - 'nc' : nc, - 'qop' : qop, - 'digest-uri': self.digest_uri, - 'response': response, - 'charset': charset} - - return self._unparse(directives) - - - def _gen_nonce(self): - return md5.new("%s:%s:%s" % (str(random.random()) , str(time.gmtime()),str(os.getpid()))).hexdigest() diff --git a/tools/buildbot/pylibs/twisted/words/protocols/jabber/xmlstream.py b/tools/buildbot/pylibs/twisted/words/protocols/jabber/xmlstream.py deleted file mode 100644 index fe0d142..0000000 --- a/tools/buildbot/pylibs/twisted/words/protocols/jabber/xmlstream.py +++ /dev/null @@ -1,1078 +0,0 @@ -# -*- test-case-name: twisted.words.test.test_jabberxmlstream -*- -# -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -XMPP XML Streams - -Building blocks for setting up XML Streams, including helping classes for -doing authentication on either client or server side, and working with XML -Stanzas. -""" - -from zope.interface import directlyProvides, implements - -from twisted.internet import defer -from twisted.internet.error import ConnectionLost -from twisted.python import failure, log -from twisted.words.protocols.jabber import error, ijabber, jid -from twisted.words.xish import domish, xmlstream -from twisted.words.xish.xmlstream import STREAM_CONNECTED_EVENT -from twisted.words.xish.xmlstream import STREAM_START_EVENT -from twisted.words.xish.xmlstream import STREAM_END_EVENT -from twisted.words.xish.xmlstream import STREAM_ERROR_EVENT - -try: - from twisted.internet import ssl -except ImportError: - ssl = None -if ssl and not ssl.supported: - ssl = None - -STREAM_AUTHD_EVENT = intern("//event/stream/authd") -INIT_FAILED_EVENT = intern("//event/xmpp/initfailed") - -NS_STREAMS = 'http://etherx.jabber.org/streams' -NS_XMPP_TLS = 'urn:ietf:params:xml:ns:xmpp-tls' - -Reset = object() - -def hashPassword(sid, password): - """ - Create a SHA1-digest string of a session identifier and password. - """ - import sha - return sha.new("%s%s" % (sid, password)).hexdigest() - - - -class Authenticator: - """ - Base class for business logic of initializing an XmlStream - - Subclass this object to enable an XmlStream to initialize and authenticate - to different types of stream hosts (such as clients, components, etc.). - - Rules: - 1. The Authenticator MUST dispatch a L{STREAM_AUTHD_EVENT} when the - stream has been completely initialized. - 2. The Authenticator SHOULD reset all state information when - L{associateWithStream} is called. - 3. The Authenticator SHOULD override L{streamStarted}, and start - initialization there. - - @type xmlstream: L{XmlStream} - @ivar xmlstream: The XmlStream that needs authentication - - @note: the term authenticator is historical. Authenticators perform - all steps required to prepare the stream for the exchange - of XML stanzas. - """ - - def __init__(self): - self.xmlstream = None - - - def connectionMade(self): - """ - Called by the XmlStream when the underlying socket connection is - in place. - - This allows the Authenticator to send an initial root element, if it's - connecting, or wait for an inbound root from the peer if it's accepting - the connection. - - Subclasses can use self.xmlstream.send() to send any initial data to - the peer. - """ - - - def streamStarted(self, rootElement): - """ - Called by the XmlStream when the stream has started. - - A stream is considered to have started when the start tag of the root - element has been received. - - This examines L{rootElement} to see if there is a version attribute. - If absent, C{0.0} is assumed per RFC 3920. Subsequently, the - minimum of the version from the received stream header and the - value stored in L{xmlstream} is taken and put back in {xmlstream}. - - Extensions of this method can extract more information from the - stream header and perform checks on them, optionally sending - stream errors and closing the stream. - """ - if rootElement.hasAttribute("version"): - version = rootElement["version"].split(".") - try: - version = (int(version[0]), int(version[1])) - except (IndexError, ValueError): - version = (0, 0) - else: - version = (0, 0) - - self.xmlstream.version = min(self.xmlstream.version, version) - - - def associateWithStream(self, xmlstream): - """ - Called by the XmlStreamFactory when a connection has been made - to the requested peer, and an XmlStream object has been - instantiated. - - The default implementation just saves a handle to the new - XmlStream. - - @type xmlstream: L{XmlStream} - @param xmlstream: The XmlStream that will be passing events to this - Authenticator. - - """ - self.xmlstream = xmlstream - - - -class ConnectAuthenticator(Authenticator): - """ - Authenticator for initiating entities. - """ - - namespace = None - - def __init__(self, otherHost): - self.otherHost = otherHost - - - def connectionMade(self): - self.xmlstream.namespace = self.namespace - self.xmlstream.otherEntity = jid.internJID(self.otherHost) - self.xmlstream.sendHeader() - - - def initializeStream(self): - """ - Perform stream initialization procedures. - - An L{XmlStream} holds a list of initializer objects in its - C{initializers} attribute. This method calls these initializers in - order and dispatches the C{STREAM_AUTHD_EVENT} event when the list has - been successfully processed. Otherwise it dispatches the - C{INIT_FAILED_EVENT} event with the failure. - - Initializers may return the special L{Reset} object to halt the - initialization processing. It signals that the current initializer was - successfully processed, but that the XML Stream has been reset. An - example is the TLSInitiatingInitializer. - """ - - def remove_first(result): - self.xmlstream.initializers.pop(0) - - return result - - def do_next(result): - """ - Take the first initializer and process it. - - On success, the initializer is removed from the list and - then next initializer will be tried. - """ - - if result is Reset: - return None - - try: - init = self.xmlstream.initializers[0] - except IndexError: - self.xmlstream.dispatch(self.xmlstream, STREAM_AUTHD_EVENT) - return None - else: - d = defer.maybeDeferred(init.initialize) - d.addCallback(remove_first) - d.addCallback(do_next) - return d - - d = defer.succeed(None) - d.addCallback(do_next) - d.addErrback(self.xmlstream.dispatch, INIT_FAILED_EVENT) - - - def streamStarted(self, rootElement): - """ - Called by the XmlStream when the stream has started. - - This extends L{Authenticator.streamStarted} to extract further stream - headers from L{rootElement}, optionally wait for stream features being - received and then call C{initializeStream}. - """ - - Authenticator.streamStarted(self, rootElement) - - self.xmlstream.sid = rootElement.getAttribute("id") - - if rootElement.hasAttribute("from"): - self.xmlstream.otherEntity = jid.internJID(rootElement["from"]) - - # Setup observer for stream features, if applicable - if self.xmlstream.version >= (1, 0): - def onFeatures(element): - features = {} - for feature in element.elements(): - features[(feature.uri, feature.name)] = feature - - self.xmlstream.features = features - self.initializeStream() - - self.xmlstream.addOnetimeObserver('/features[@xmlns="%s"]' % - NS_STREAMS, - onFeatures) - else: - self.initializeStream() - - - -class ListenAuthenticator(Authenticator): - """ - Authenticator for receiving entities. - """ - - namespace = None - - def associateWithStream(self, xmlstream): - """ - Called by the XmlStreamFactory when a connection has been made. - - Extend L{Authenticator.associateWithStream} to set the L{XmlStream} - to be non-initiating. - """ - Authenticator.associateWithStream(self, xmlstream) - self.xmlstream.initiating = False - - - def streamStarted(self, rootElement): - """ - Called by the XmlStream when the stream has started. - - This extends L{Authenticator.streamStarted} to extract further - information from the stream headers from L{rootElement}. - """ - Authenticator.streamStarted(self, rootElement) - - self.xmlstream.namespace = rootElement.defaultUri - - if rootElement.hasAttribute("to"): - self.xmlstream.thisEntity = jid.internJID(rootElement["to"]) - - self.xmlstream.prefixes = {} - for prefix, uri in rootElement.localPrefixes.iteritems(): - self.xmlstream.prefixes[uri] = prefix - - - -class FeatureNotAdvertized(Exception): - """ - Exception indicating a stream feature was not advertized, while required by - the initiating entity. - """ - - - -class BaseFeatureInitiatingInitializer(object): - """ - Base class for initializers with a stream feature. - - This assumes the associated XmlStream represents the initiating entity - of the connection. - - @cvar feature: tuple of (uri, name) of the stream feature root element. - @type feature: tuple of (L{str}, L{str}) - @ivar required: whether the stream feature is required to be advertized - by the receiving entity. - @type required: L{bool} - """ - - implements(ijabber.IInitiatingInitializer) - - feature = None - required = False - - def __init__(self, xs): - self.xmlstream = xs - - - def initialize(self): - """ - Initiate the initialization. - - Checks if the receiving entity advertizes the stream feature. If it - does, the initialization is started. If it is not advertized, and the - C{required} instance variable is L{True}, it raises - L{FeatureNotAdvertized}. Otherwise, the initialization silently - succeeds. - """ - - if self.feature in self.xmlstream.features: - return self.start() - elif self.required: - raise FeatureNotAdvertized - else: - return None - - - def start(self): - """ - Start the actual initialization. - - May return a deferred for asynchronous initialization. - """ - - - -class TLSError(Exception): - """ - TLS base exception. - """ - - - -class TLSFailed(TLSError): - """ - Exception indicating failed TLS negotiation - """ - - - -class TLSRequired(TLSError): - """ - Exception indicating required TLS negotiation. - - This exception is raised when the receiving entity requires TLS - negotiation and the initiating does not desire to negotiate TLS. - """ - - - -class TLSNotSupported(TLSError): - """ - Exception indicating missing TLS support. - - This exception is raised when the initiating entity wants and requires to - negotiate TLS when the OpenSSL library is not available. - """ - - - -class TLSInitiatingInitializer(BaseFeatureInitiatingInitializer): - """ - TLS stream initializer for the initiating entity. - - It is strongly required to include this initializer in the list of - initializers for an XMPP stream. By default it will try to negotiate TLS. - An XMPP server may indicate that TLS is required. If TLS is not desired, - set the C{wanted} attribute to False instead of removing it from the list - of initializers, so a proper exception L{TLSRequired} can be raised. - - @cvar wanted: indicates if TLS negotiation is wanted. - @type wanted: L{bool} - """ - - feature = (NS_XMPP_TLS, 'starttls') - wanted = True - _deferred = None - - def onProceed(self, obj): - """ - Proceed with TLS negotiation and reset the XML stream. - """ - - self.xmlstream.removeObserver('/failure', self.onFailure) - ctx = ssl.CertificateOptions() - self.xmlstream.transport.startTLS(ctx) - self.xmlstream.reset() - self.xmlstream.sendHeader() - self._deferred.callback(Reset) - - - def onFailure(self, obj): - self.xmlstream.removeObserver('/proceed', self.onProceed) - self._deferred.errback(TLSFailed()) - - - def start(self): - """ - Start TLS negotiation. - - This checks if the receiving entity requires TLS, the SSL library is - available and uses the C{required} and C{wanted} instance variables to - determine what to do in the various different cases. - - For example, if the SSL library is not available, and wanted and - required by the user, it raises an exception. However if it is not - required by both parties, initialization silently succeeds, moving - on to the next step. - """ - if self.wanted: - if ssl is None: - if self.required: - return defer.fail(TLSNotSupported()) - else: - return defer.succeed(None) - else: - pass - elif self.xmlstream.features[self.feature].required: - return defer.fail(TLSRequired()) - else: - return defer.succeed(None) - - self._deferred = defer.Deferred() - self.xmlstream.addOnetimeObserver("/proceed", self.onProceed) - self.xmlstream.addOnetimeObserver("/failure", self.onFailure) - self.xmlstream.send(domish.Element((NS_XMPP_TLS, "starttls"))) - return self._deferred - - - -class XmlStream(xmlstream.XmlStream): - """ - XMPP XML Stream protocol handler. - - @ivar version: XML stream version as a tuple (major, minor). Initially, - this is set to the minimally supported version. Upon - receiving the stream header of the peer, it is set to the - minimum of that value and the version on the received - header. - @type version: (L{int}, L{int}) - @ivar namespace: default namespace URI for stream - @type namespace: L{str} - @ivar thisEntity: JID of this entity - @type thisEntity: L{JID} - @ivar otherEntity: JID of the peer entity - @type otherEntity: L{JID} - @ivar sid: session identifier - @type sid: L{str} - @ivar initiating: True if this is the initiating stream - @type initiating: L{bool} - @ivar features: map of (uri, name) to stream features element received from - the receiving entity. - @type features: L{dict} of (L{str}, L{str}) to L{domish.Element}. - @ivar prefixes: map of URI to prefixes that are to appear on stream - header. - @type prefixes: L{dict} of L{str} to L{str} - @ivar initializers: list of stream initializer objects - @type initializers: L{list} of objects that provide L{IInitializer} - @ivar authenticator: associated authenticator that uses C{initializers} to - initialize the XML stream. - """ - - version = (1, 0) - namespace = 'invalid' - thisEntity = None - otherEntity = None - sid = None - initiating = True - - _headerSent = False # True if the stream header has been sent - - def __init__(self, authenticator): - xmlstream.XmlStream.__init__(self) - - self.prefixes = {NS_STREAMS: 'stream'} - self.authenticator = authenticator - self.initializers = [] - self.features = {} - - # Reset the authenticator - authenticator.associateWithStream(self) - - - def _callLater(self, *args, **kwargs): - from twisted.internet import reactor - return reactor.callLater(*args, **kwargs) - - - def reset(self): - """ - Reset XML Stream. - - Resets the XML Parser for incoming data. This is to be used after - successfully negotiating a new layer, e.g. TLS and SASL. Note that - registered event observers will continue to be in place. - """ - self._headerSent = False - self._initializeStream() - - - def onStreamError(self, errelem): - """ - Called when a stream:error element has been received. - - Dispatches a L{STREAM_ERROR_EVENT} event with the error element to - allow for cleanup actions and drops the connection. - - @param errelem: The received error element. - @type errelem: L{domish.Element} - """ - self.dispatch(failure.Failure(error.exceptionFromStreamError(errelem)), - STREAM_ERROR_EVENT) - self.transport.loseConnection() - - - def sendHeader(self): - """ - Send stream header. - """ - # set up optional extra namespaces - localPrefixes = {} - for uri, prefix in self.prefixes.iteritems(): - if uri != NS_STREAMS: - localPrefixes[prefix] = uri - - rootElement = domish.Element((NS_STREAMS, 'stream'), self.namespace, - localPrefixes=localPrefixes) - - if self.otherEntity: - rootElement['to'] = self.otherEntity.userhost() - - if self.thisEntity: - rootElement['from'] = self.thisEntity.userhost() - - if not self.initiating and self.sid: - rootElement['id'] = self.sid - - if self.version >= (1, 0): - rootElement['version'] = "%d.%d" % self.version - - self.send(rootElement.toXml(prefixes=self.prefixes, closeElement=0)) - self._headerSent = True - - - def sendFooter(self): - """ - Send stream footer. - """ - self.send('') - - - def sendStreamError(self, streamError): - """ - Send stream level error. - - If we are the receiving entity, and haven't sent the header yet, - we sent one first. - - After sending the stream error, the stream is closed and the transport - connection dropped. - - @param streamError: stream error instance - @type streamError: L{error.StreamError} - """ - if not self._headerSent and not self.initiating: - self.sendHeader() - - if self._headerSent: - self.send(streamError.getElement()) - self.sendFooter() - - self.transport.loseConnection() - - - def send(self, obj): - """ - Send data over the stream. - - This overrides L{xmlstream.Xmlstream.send} to use the default namespace - of the stream header when serializing L{domish.IElement}s. It is - assumed that if you pass an object that provides L{domish.IElement}, - it represents a direct child of the stream's root element. - """ - if domish.IElement.providedBy(obj): - obj = obj.toXml(prefixes=self.prefixes, - defaultUri=self.namespace, - prefixesInScope=self.prefixes.values()) - - xmlstream.XmlStream.send(self, obj) - - - def connectionMade(self): - """ - Called when a connection is made. - - Notifies the authenticator when a connection has been made. - """ - xmlstream.XmlStream.connectionMade(self) - self.authenticator.connectionMade() - - - def onDocumentStart(self, rootElement): - """ - Called when the stream header has been received. - - Extracts the header's C{id} and C{version} attributes from the root - element. The C{id} attribute is stored in our C{sid} attribute and the - C{version} attribute is parsed and the minimum of the version we sent - and the parsed C{version} attribute is stored as a tuple (major, minor) - in this class' C{version} attribute. If no C{version} attribute was - present, we assume version 0.0. - - If appropriate (we are the initiating stream and the minimum of our and - the other party's version is at least 1.0), a one-time observer is - registered for getting the stream features. The registered function is - C{onFeatures}. - - Ultimately, the authenticator's C{streamStarted} method will be called. - - @param rootElement: The root element. - @type rootElement: L{domish.Element} - """ - xmlstream.XmlStream.onDocumentStart(self, rootElement) - - # Setup observer for stream errors - self.addOnetimeObserver("/error[@xmlns='%s']" % NS_STREAMS, - self.onStreamError) - - self.authenticator.streamStarted(rootElement) - - - -class XmlStreamFactory(xmlstream.XmlStreamFactory): - """ - Factory for Jabber XmlStream objects as a reconnecting client. - - Note that this differs from L{xmlstream.XmlStreamFactory} in that - it generates Jabber specific L{XmlStream} instances that have - authenticators. - """ - - protocol = XmlStream - - def __init__(self, authenticator): - xmlstream.XmlStreamFactory.__init__(self, authenticator) - self.authenticator = authenticator - - - -class TimeoutError(Exception): - """ - Exception raised when no IQ response has been received before the - configured timeout. - """ - - - -def upgradeWithIQResponseTracker(xs): - """ - Enhances an XmlStream for iq response tracking. - - This makes an L{XmlStream} object provide L{IIQResponseTracker}. When a - response is an error iq stanza, the deferred has its errback invoked with a - failure that holds a L{StanzaException} that is - easier to examine. - """ - def callback(iq): - """ - Handle iq response by firing associated deferred. - """ - if getattr(iq, 'handled', False): - return - - try: - d = xs.iqDeferreds[iq["id"]] - except KeyError: - pass - else: - del xs.iqDeferreds[iq["id"]] - iq.handled = True - if iq['type'] == 'error': - d.errback(error.exceptionFromStanza(iq)) - else: - d.callback(iq) - - - def disconnected(_): - """ - Make sure deferreds do not linger on after disconnect. - - This errbacks all deferreds of iq's for which no response has been - received with a L{ConnectionLost} failure. Otherwise, the deferreds - will never be fired. - """ - iqDeferreds = xs.iqDeferreds - xs.iqDeferreds = {} - for d in iqDeferreds.itervalues(): - d.errback(ConnectionLost()) - - xs.iqDeferreds = {} - xs.iqDefaultTimeout = getattr(xs, 'iqDefaultTimeout', None) - xs.addObserver(xmlstream.STREAM_END_EVENT, disconnected) - xs.addObserver('/iq[@type="result"]', callback) - xs.addObserver('/iq[@type="error"]', callback) - directlyProvides(xs, ijabber.IIQResponseTracker) - - - -class IQ(domish.Element): - """ - Wrapper for an iq stanza. - - Iq stanzas are used for communications with a request-response behaviour. - Each iq request is associated with an XML stream and has its own unique id - to be able to track the response. - - @ivar timeout: if set, a timeout period after which the deferred returned - by C{send} will have its errback called with a - L{TimeoutError} failure. - @type timeout: C{float} - """ - - timeout = None - - def __init__(self, xmlstream, stanzaType="set"): - """ - @type xmlstream: L{xmlstream.XmlStream} - @param xmlstream: XmlStream to use for transmission of this IQ - - @type stanzaType: L{str} - @param stanzaType: IQ type identifier ('get' or 'set') - """ - domish.Element.__init__(self, (None, "iq")) - self.addUniqueId() - self["type"] = stanzaType - self._xmlstream = xmlstream - - - def send(self, to=None): - """ - Send out this iq. - - Returns a deferred that is fired when an iq response with the same id - is received. Result responses will be passed to the deferred callback. - Error responses will be transformed into a - L{StanzaError} and result in the errback of the - deferred being invoked. - - @rtype: L{defer.Deferred} - """ - if to is not None: - self["to"] = to - - if not ijabber.IIQResponseTracker.providedBy(self._xmlstream): - upgradeWithIQResponseTracker(self._xmlstream) - - d = defer.Deferred() - self._xmlstream.iqDeferreds[self['id']] = d - - timeout = self.timeout or self._xmlstream.iqDefaultTimeout - if timeout is not None: - def onTimeout(): - del self._xmlstream.iqDeferreds[self['id']] - d.errback(TimeoutError("IQ timed out")) - - call = self._xmlstream._callLater(timeout, onTimeout) - - def cancelTimeout(result): - if call.active(): - call.cancel() - - return result - - d.addBoth(cancelTimeout) - - self._xmlstream.send(self) - return d - - - -def toResponse(stanza, stanzaType=None): - """ - Create a response stanza from another stanza. - - This takes the addressing and id attributes from a stanza to create a (new, - empty) response stanza. The addressing attributes are swapped and the id - copied. Optionally, the stanza type of the response can be specified. - - @param stanza: the original stanza - @type stanza: L{domish.Element} - @param stanzaType: optional response stanza type - @type stanzaType: C{str} - @return: the response stanza. - @rtype: L{domish.Element} - """ - - toAddr = stanza.getAttribute('from') - fromAddr = stanza.getAttribute('to') - stanzaID = stanza.getAttribute('id') - - response = domish.Element((None, stanza.name)) - if toAddr: - response['to'] = toAddr - if fromAddr: - response['from'] = fromAddr - if stanzaID: - response['id'] = stanzaID - if type: - response['type'] = stanzaType - - return response - - - -class XMPPHandler(object): - """ - XMPP protocol handler. - - Classes derived from this class implement (part of) one or more XMPP - extension protocols, and are referred to as a subprotocol implementation. - """ - - implements(ijabber.IXMPPHandler) - - def __init__(self): - self.parent = None - self.xmlstream = None - - - def setHandlerParent(self, parent): - self.parent = parent - self.parent.addHandler(self) - - - def disownHandlerParent(self, parent): - self.parent.removeHandler(self) - self.parent = None - - - def makeConnection(self, xs): - self.xmlstream = xs - self.connectionMade() - - - def connectionMade(self): - """ - Called after a connection has been established. - - Can be overridden to perform work before stream initialization. - """ - - - def connectionInitialized(self): - """ - The XML stream has been initialized. - - Can be overridden to perform work after stream initialization, e.g. to - set up observers and start exchanging XML stanzas. - """ - - - def connectionLost(self, reason): - """ - The XML stream has been closed. - - This method can be extended to inspect the C{reason} argument and - act on it. - """ - self.xmlstream = None - - - def send(self, obj): - """ - Send data over the managed XML stream. - - @note: The stream manager maintains a queue for data sent using this - method when there is no current initialized XML stream. This - data is then sent as soon as a new stream has been established - and initialized. Subsequently, L{connectionInitialized} will be - called again. If this queueing is not desired, use C{send} on - C{self.xmlstream}. - - @param obj: data to be sent over the XML stream. This is usually an - object providing L{domish.IElement}, or serialized XML. See - L{xmlstream.XmlStream} for details. - """ - self.parent.send(obj) - - - -class XMPPHandlerCollection(object): - """ - Collection of XMPP subprotocol handlers. - - This allows for grouping of subprotocol handlers, but is not an - L{XMPPHandler} itself, so this is not recursive. - - @ivar handlers: List of protocol handlers. - @type handlers: L{list} of objects providing - L{IXMPPHandler} - """ - - implements(ijabber.IXMPPHandlerCollection) - - def __init__(self): - self.handlers = [] - - - def __iter__(self): - """ - Act as a container for handlers. - """ - return iter(self.handlers) - - - def addHandler(self, handler): - """ - Add protocol handler. - - Protocol handlers are expected to provide L{ijabber.IXMPPHandler}. - """ - self.handlers.append(handler) - - - def removeHandler(self, handler): - """ - Remove protocol handler. - """ - self.handlers.remove(handler) - - - -class StreamManager(XMPPHandlerCollection): - """ - Business logic representing a managed XMPP connection. - - This maintains a single XMPP connection and provides facilities for packet - routing and transmission. Business logic modules are objects providing - L{ijabber.IXMPPHandler} (like subclasses of L{XMPPHandler}), and added - using L{addHandler}. - - @ivar xmlstream: currently managed XML stream - @type xmlstream: L{XmlStream} - @ivar logTraffic: if true, log all traffic. - @type logTraffic: L{bool} - @ivar _initialized: Whether the stream represented by L{xmlstream} has - been initialized. This is used when caching outgoing - stanzas. - @type _initialized: C{bool} - @ivar _packetQueue: internal buffer of unsent data. See L{send} for details. - @type _packetQueue: L{list} - """ - - logTraffic = False - - def __init__(self, factory): - XMPPHandlerCollection.__init__(self) - self.xmlstream = None - self._packetQueue = [] - self._initialized = False - - factory.addBootstrap(STREAM_CONNECTED_EVENT, self._connected) - factory.addBootstrap(STREAM_AUTHD_EVENT, self._authd) - factory.addBootstrap(INIT_FAILED_EVENT, self.initializationFailed) - factory.addBootstrap(STREAM_END_EVENT, self._disconnected) - self.factory = factory - - - def addHandler(self, handler): - """ - Add protocol handler. - - When an XML stream has already been established, the handler's - C{connectionInitialized} will be called to get it up to speed. - """ - XMPPHandlerCollection.addHandler(self, handler) - - # get protocol handler up to speed when a connection has already - # been established - if self.xmlstream and self._initialized: - handler.makeConnection(self.xmlstream) - handler.connectionInitialized() - - - def _connected(self, xs): - """ - Called when the transport connection has been established. - - Here we optionally set up traffic logging (depending on L{logTraffic}) - and call each handler's C{makeConnection} method with the L{XmlStream} - instance. - """ - def logDataIn(buf): - log.msg("RECV: %r" % buf) - - def logDataOut(buf): - log.msg("SEND: %r" % buf) - - if self.logTraffic: - xs.rawDataInFn = logDataIn - xs.rawDataOutFn = logDataOut - - self.xmlstream = xs - - for e in self: - e.makeConnection(xs) - - - def _authd(self, xs): - """ - Called when the stream has been initialized. - - Send out cached stanzas and call each handler's - C{connectionInitialized} method. - """ - # Flush all pending packets - for p in self._packetQueue: - xs.send(p) - self._packetQueue = [] - self._initialized = True - - # Notify all child services which implement - # the IService interface - for e in self: - e.connectionInitialized() - - - def initializationFailed(self, reason): - """ - Called when stream initialization has failed. - - Stream initialization has halted, with the reason indicated by - C{reason}. It may be retried by calling the authenticator's - C{initializeStream}. See the respective authenticators for details. - - @param reason: A failure instance indicating why stream initialization - failed. - @type reason: L{failure.Failure} - """ - - - def _disconnected(self, _): - """ - Called when the stream has been closed. - - From this point on, the manager doesn't interact with the - L{XmlStream} anymore and notifies each handler that the connection - was lost by calling its C{connectionLost} method. - """ - self.xmlstream = None - self._initialized = False - - # Notify all child services which implement - # the IService interface - for e in self: - e.connectionLost(None) - - - def send(self, obj): - """ - Send data over the XML stream. - - When there is no established XML stream, the data is queued and sent - out when a new XML stream has been established and initialized. - - @param obj: data to be sent over the XML stream. See - L{xmlstream.XmlStream.send} for details. - """ - if self._initialized: - self.xmlstream.send(obj) - else: - self._packetQueue.append(obj) diff --git a/tools/buildbot/pylibs/twisted/words/protocols/jabber/xmpp_stringprep.py b/tools/buildbot/pylibs/twisted/words/protocols/jabber/xmpp_stringprep.py deleted file mode 100644 index 87025fb..0000000 --- a/tools/buildbot/pylibs/twisted/words/protocols/jabber/xmpp_stringprep.py +++ /dev/null @@ -1,248 +0,0 @@ -# -*- test-case-name: twisted.words.test.test_jabberxmppstringprep -*- -# -# Copyright (c) 2001-2005 Twisted Matrix Laboratories. -# See LICENSE for details. - -import sys, warnings -from zope.interface import Interface, implements - -if sys.version_info < (2,3,2): - import re - - class IDNA: - dots = re.compile(u"[\u002E\u3002\uFF0E\uFF61]") - def nameprep(self, label): - return label.lower() - - idna = IDNA() - - crippled = True - - warnings.warn("Accented and non-Western Jabber IDs will not be properly " - "case-folded with this version of Python, resulting in " - "incorrect protocol-level behavior. It is strongly " - "recommended you upgrade to Python 2.3.2 or newer if you " - "intend to use Twisted's Jabber support.") - -else: - import stringprep - import unicodedata - from encodings import idna - - crippled = False - -del sys, warnings - -class ILookupTable(Interface): - """ Interface for character lookup classes. """ - - def lookup(c): - """ Return whether character is in this table. """ - -class IMappingTable(Interface): - """ Interface for character mapping classes. """ - - def map(c): - """ Return mapping for character. """ - -class LookupTableFromFunction: - - implements(ILookupTable) - - def __init__(self, in_table_function): - self.lookup = in_table_function - -class LookupTable: - - implements(ILookupTable) - - def __init__(self, table): - self._table = table - - def lookup(self, c): - return c in self._table - -class MappingTableFromFunction: - - implements(IMappingTable) - - def __init__(self, map_table_function): - self.map = map_table_function - -class EmptyMappingTable: - - implements(IMappingTable) - - def __init__(self, in_table_function): - self._in_table_function = in_table_function - - def map(self, c): - if self._in_table_function(c): - return None - else: - return c - -class Profile: - def __init__(self, mappings=[], normalize=True, prohibiteds=[], - check_unassigneds=True, check_bidi=True): - self.mappings = mappings - self.normalize = normalize - self.prohibiteds = prohibiteds - self.do_check_unassigneds = check_unassigneds - self.do_check_bidi = check_bidi - - def prepare(self, string): - result = self.map(string) - if self.normalize: - result = unicodedata.normalize("NFKC", result) - self.check_prohibiteds(result) - if self.do_check_unassigneds: - self.check_unassigneds(result) - if self.do_check_bidi: - self.check_bidirectionals(result) - return result - - def map(self, string): - result = [] - - for c in string: - result_c = c - - for mapping in self.mappings: - result_c = mapping.map(c) - if result_c != c: - break - - if result_c is not None: - result.append(result_c) - - return u"".join(result) - - def check_prohibiteds(self, string): - for c in string: - for table in self.prohibiteds: - if table.lookup(c): - raise UnicodeError, "Invalid character %s" % repr(c) - - def check_unassigneds(self, string): - for c in string: - if stringprep.in_table_a1(c): - raise UnicodeError, "Unassigned code point %s" % repr(c) - - def check_bidirectionals(self, string): - found_LCat = False - found_RandALCat = False - - for c in string: - if stringprep.in_table_d1(c): - found_RandALCat = True - if stringprep.in_table_d2(c): - found_LCat = True - - if found_LCat and found_RandALCat: - raise UnicodeError, "Violation of BIDI Requirement 2" - - if found_RandALCat and not (stringprep.in_table_d1(string[0]) and - stringprep.in_table_d1(string[-1])): - raise UnicodeError, "Violation of BIDI Requirement 3" - - -class NamePrep: - """ Implements preparation of internationalized domain names. - - This class implements preparing internationalized domain names using the - rules defined in RFC 3491, section 4 (Conversion operations). - - We do not perform step 4 since we deal with unicode representations of - domain names and do not convert from or to ASCII representations using - punycode encoding. When such a conversion is needed, the L{idna} standard - library provides the C{ToUnicode()} and C{ToASCII()} functions. Note that - L{idna} itself assumes UseSTD3ASCIIRules to be false. - - The following steps are performed by C{prepare()}: - - - Split the domain name in labels at the dots (RFC 3490, 3.1) - - Apply nameprep proper on each label (RFC 3491) - - Enforce the restrictions on ASCII characters in host names by - assuming STD3ASCIIRules to be true. (STD 3) - - Rejoin the labels using the label separator U+002E (full stop). - - """ - - # Prohibited characters. - prohibiteds = [unichr(n) for n in range(0x00, 0x2c + 1) + - range(0x2e, 0x2f + 1) + - range(0x3a, 0x40 + 1) + - range(0x5b, 0x60 + 1) + - range(0x7b, 0x7f + 1) ] - - def prepare(self, string): - result = [] - - labels = idna.dots.split(string) - - if labels and len(labels[-1]) == 0: - trailing_dot = '.' - del labels[-1] - else: - trailing_dot = '' - - for label in labels: - result.append(self.nameprep(label)) - - return ".".join(result) + trailing_dot - - def check_prohibiteds(self, string): - for c in string: - if c in self.prohibiteds: - raise UnicodeError, "Invalid character %s" % repr(c) - - def nameprep(self, label): - label = idna.nameprep(label) - self.check_prohibiteds(label) - if label[0] == '-': - raise UnicodeError, "Invalid leading hyphen-minus" - if label[-1] == '-': - raise UnicodeError, "Invalid trailing hyphen-minus" - return label - -if crippled: - case_map = MappingTableFromFunction(lambda c: c.lower()) - nodeprep = Profile(mappings=[case_map], - normalize=False, - prohibiteds=[LookupTable([u' ', u'"', u'&', u"'", u'/', - u':', u'<', u'>', u'@'])], - check_unassigneds=False, - check_bidi=False) - - resourceprep = Profile(normalize=False, - check_unassigneds=False, - check_bidi=False) - -else: - C_11 = LookupTableFromFunction(stringprep.in_table_c11) - C_12 = LookupTableFromFunction(stringprep.in_table_c12) - C_21 = LookupTableFromFunction(stringprep.in_table_c21) - C_22 = LookupTableFromFunction(stringprep.in_table_c22) - C_3 = LookupTableFromFunction(stringprep.in_table_c3) - C_4 = LookupTableFromFunction(stringprep.in_table_c4) - C_5 = LookupTableFromFunction(stringprep.in_table_c5) - C_6 = LookupTableFromFunction(stringprep.in_table_c6) - C_7 = LookupTableFromFunction(stringprep.in_table_c7) - C_8 = LookupTableFromFunction(stringprep.in_table_c8) - C_9 = LookupTableFromFunction(stringprep.in_table_c9) - - B_1 = EmptyMappingTable(stringprep.in_table_b1) - B_2 = MappingTableFromFunction(stringprep.map_table_b2) - - nodeprep = Profile(mappings=[B_1, B_2], - prohibiteds=[C_11, C_12, C_21, C_22, - C_3, C_4, C_5, C_6, C_7, C_8, C_9, - LookupTable([u'"', u'&', u"'", u'/', - u':', u'<', u'>', u'@'])]) - - resourceprep = Profile(mappings=[B_1,], - prohibiteds=[C_12, C_21, C_22, - C_3, C_4, C_5, C_6, C_7, C_8, C_9]) - -nameprep = NamePrep() diff --git a/tools/buildbot/pylibs/twisted/words/protocols/msn.py b/tools/buildbot/pylibs/twisted/words/protocols/msn.py deleted file mode 100644 index 9f7c620..0000000 --- a/tools/buildbot/pylibs/twisted/words/protocols/msn.py +++ /dev/null @@ -1,2457 +0,0 @@ -# -*- test-case-name: twisted.words.test -*- -# Copyright (c) 2001-2005 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -""" -MSNP8 Protocol (client only) - semi-experimental - -This module provides support for clients using the MSN Protocol (MSNP8). -There are basically 3 servers involved in any MSN session: - -I{Dispatch server} - -The DispatchClient class handles connections to the -dispatch server, which basically delegates users to a -suitable notification server. - -You will want to subclass this and handle the gotNotificationReferral -method appropriately. - -I{Notification Server} - -The NotificationClient class handles connections to the -notification server, which acts as a session server -(state updates, message negotiation etc...) - -I{Switcboard Server} - -The SwitchboardClient handles connections to switchboard -servers which are used to conduct conversations with other users. - -There are also two classes (FileSend and FileReceive) used -for file transfers. - -Clients handle events in two ways. - - - each client request requiring a response will return a Deferred, - the callback for same will be fired when the server sends the - required response - - Events which are not in response to any client request have - respective methods which should be overridden and handled in - an adequate manner - -Most client request callbacks require more than one argument, -and since Deferreds can only pass the callback one result, -most of the time the callback argument will be a tuple of -values (documented in the respective request method). -To make reading/writing code easier, callbacks can be defined in -a number of ways to handle this 'cleanly'. One way would be to -define methods like: def callBack(self, (arg1, arg2, arg)): ... -another way would be to do something like: -d.addCallback(lambda result: myCallback(*result)). - -If the server sends an error response to a client request, -the errback of the corresponding Deferred will be called, -the argument being the corresponding error code. - -B{NOTE}: -Due to the lack of an official spec for MSNP8, extra checking -than may be deemed necessary often takes place considering the -server is never 'wrong'. Thus, if gotBadLine (in any of the 3 -main clients) is called, or an MSNProtocolError is raised, it's -probably a good idea to submit a bug report. ;) -Use of this module requires that PyOpenSSL is installed. - -TODO -==== -- check message hooks with invalid x-msgsinvite messages. -- font handling -- switchboard factory - -@author: U{Sam Jordan} -""" - -from __future__ import nested_scopes - - -# Twisted imports -from twisted.internet import reactor -from twisted.internet.defer import Deferred -from twisted.internet.protocol import ClientFactory -from twisted.internet.ssl import ClientContextFactory -from twisted.python import failure, log - -from twisted.protocols.basic import LineReceiver -from twisted.web.http import HTTPClient - -# System imports -import types, operator, os, md5 -from random import randint -from urllib import quote, unquote - -MSN_PROTOCOL_VERSION = "MSNP8 CVR0" # protocol version -MSN_PORT = 1863 # default dispatch server port -MSN_MAX_MESSAGE = 1664 # max message length -MSN_CHALLENGE_STR = "Q1P7W2E4J9R8U3S5" # used for server challenges -MSN_CVR_STR = "0x0409 win 4.10 i386 MSNMSGR 5.0.0544 MSMSGS" # :( - -# auth constants -LOGIN_SUCCESS = 1 -LOGIN_FAILURE = 2 -LOGIN_REDIRECT = 3 - -# list constants -FORWARD_LIST = 1 -ALLOW_LIST = 2 -BLOCK_LIST = 4 -REVERSE_LIST = 8 - -# phone constants -HOME_PHONE = "PHH" -WORK_PHONE = "PHW" -MOBILE_PHONE = "PHM" -HAS_PAGER = "MOB" - -# status constants -STATUS_ONLINE = 'NLN' -STATUS_OFFLINE = 'FLN' -STATUS_HIDDEN = 'HDN' -STATUS_IDLE = 'IDL' -STATUS_AWAY = 'AWY' -STATUS_BUSY = 'BSY' -STATUS_BRB = 'BRB' -STATUS_PHONE = 'PHN' -STATUS_LUNCH = 'LUN' - -CR = "\r" -LF = "\n" - -def checkParamLen(num, expected, cmd, error=None): - if error == None: - error = "Invalid Number of Parameters for %s" % cmd - if num != expected: - raise MSNProtocolError, error - -def _parseHeader(h, v): - """ - Split a certin number of known - header values with the format: - field1=val,field2=val,field3=val into - a dict mapping fields to values. - @param h: the header's key - @param v: the header's value as a string - """ - - if h in ('passporturls','authentication-info','www-authenticate'): - v = v.replace('Passport1.4','').lstrip() - fields = {} - for fieldPair in v.split(','): - try: - field,value = fieldPair.split('=',1) - fields[field.lower()] = value - except ValueError: - fields[field.lower()] = '' - return fields - else: - return v - -def _parsePrimitiveHost(host): - # Ho Ho Ho - h,p = host.replace('https://','').split('/',1) - p = '/' + p - return h,p - -def _login(userHandle, passwd, nexusServer, cached=0, authData=''): - """ - This function is used internally and should not ever be called - directly. - """ - cb = Deferred() - def _cb(server, auth): - loginFac = ClientFactory() - loginFac.protocol = lambda : PassportLogin(cb, userHandle, passwd, server, auth) - reactor.connectSSL(_parsePrimitiveHost(server)[0], 443, loginFac, ClientContextFactory()) - - if cached: - _cb(nexusServer, authData) - else: - fac = ClientFactory() - d = Deferred() - d.addCallbacks(_cb, callbackArgs=(authData,)) - d.addErrback(lambda f: cb.errback(f)) - fac.protocol = lambda : PassportNexus(d, nexusServer) - reactor.connectSSL(_parsePrimitiveHost(nexusServer)[0], 443, fac, ClientContextFactory()) - return cb - - -class PassportNexus(HTTPClient): - - """ - Used to obtain the URL of a valid passport - login HTTPS server. - - This class is used internally and should - not be instantiated directly -- that is, - The passport logging in process is handled - transparantly by NotificationClient. - """ - - def __init__(self, deferred, host): - self.deferred = deferred - self.host, self.path = _parsePrimitiveHost(host) - - def connectionMade(self): - HTTPClient.connectionMade(self) - self.sendCommand('GET', self.path) - self.sendHeader('Host', self.host) - self.endHeaders() - self.headers = {} - - def handleHeader(self, header, value): - h = header.lower() - self.headers[h] = _parseHeader(h, value) - - def handleEndHeaders(self): - if self.connected: - self.transport.loseConnection() - if not self.headers.has_key('passporturls') or not self.headers['passporturls'].has_key('dalogin'): - self.deferred.errback(failure.Failure(failure.DefaultException("Invalid Nexus Reply"))) - self.deferred.callback('https://' + self.headers['passporturls']['dalogin']) - - def handleResponse(self, r): - pass - -class PassportLogin(HTTPClient): - """ - This class is used internally to obtain - a login ticket from a passport HTTPS - server -- it should not be used directly. - """ - - _finished = 0 - - def __init__(self, deferred, userHandle, passwd, host, authData): - self.deferred = deferred - self.userHandle = userHandle - self.passwd = passwd - self.authData = authData - self.host, self.path = _parsePrimitiveHost(host) - - def connectionMade(self): - self.sendCommand('GET', self.path) - self.sendHeader('Authorization', 'Passport1.4 OrgVerb=GET,OrgURL=http://messenger.msn.com,' + - 'sign-in=%s,pwd=%s,%s' % (quote(self.userHandle), self.passwd,self.authData)) - self.sendHeader('Host', self.host) - self.endHeaders() - self.headers = {} - - def handleHeader(self, header, value): - h = header.lower() - self.headers[h] = _parseHeader(h, value) - - def handleEndHeaders(self): - if self._finished: - return - self._finished = 1 # I think we need this because of HTTPClient - if self.connected: - self.transport.loseConnection() - authHeader = 'authentication-info' - _interHeader = 'www-authenticate' - if self.headers.has_key(_interHeader): - authHeader = _interHeader - try: - info = self.headers[authHeader] - status = info['da-status'] - handler = getattr(self, 'login_%s' % (status,), None) - if handler: - handler(info) - else: - raise Exception() - except Exception, e: - self.deferred.errback(failure.Failure(e)) - - def handleResponse(self, r): - pass - - def login_success(self, info): - ticket = info['from-pp'] - ticket = ticket[1:len(ticket)-1] - self.deferred.callback((LOGIN_SUCCESS, ticket)) - - def login_failed(self, info): - self.deferred.callback((LOGIN_FAILURE, unquote(info['cbtxt']))) - - def login_redir(self, info): - self.deferred.callback((LOGIN_REDIRECT, self.headers['location'], self.authData)) - - -class MSNProtocolError(Exception): - """ - This Exception is basically used for debugging - purposes, as the official MSN server should never - send anything _wrong_ and nobody in their right - mind would run their B{own} MSN server. - If it is raised by default command handlers - (handle_BLAH) the error will be logged. - """ - pass - - -class MSNCommandFailed(Exception): - """ - The server said that the command failed. - """ - - def __init__(self, errorCode): - self.errorCode = errorCode - - def __str__(self): - return ("Command failed: %s (error code %d)" - % (errorCodes[self.errorCode], self.errorCode)) - - -class MSNMessage: - """ - I am the class used to represent an 'instant' message. - - @ivar userHandle: The user handle (passport) of the sender - (this is only used when receiving a message) - @ivar screenName: The screen name of the sender (this is only used - when receiving a message) - @ivar message: The message - @ivar headers: The message headers - @type headers: dict - @ivar length: The message length (including headers and line endings) - @ivar ack: This variable is used to tell the server how to respond - once the message has been sent. If set to MESSAGE_ACK - (default) the server will respond with an ACK upon receiving - the message, if set to MESSAGE_NACK the server will respond - with a NACK upon failure to receive the message. - If set to MESSAGE_ACK_NONE the server will do nothing. - This is relevant for the return value of - SwitchboardClient.sendMessage (which will return - a Deferred if ack is set to either MESSAGE_ACK or MESSAGE_NACK - and will fire when the respective ACK or NACK is received). - If set to MESSAGE_ACK_NONE sendMessage will return None. - """ - MESSAGE_ACK = 'A' - MESSAGE_NACK = 'N' - MESSAGE_ACK_NONE = 'U' - - ack = MESSAGE_ACK - - def __init__(self, length=0, userHandle="", screenName="", message=""): - self.userHandle = userHandle - self.screenName = screenName - self.message = message - self.headers = {'MIME-Version' : '1.0', 'Content-Type' : 'text/plain'} - self.length = length - self.readPos = 0 - - def _calcMessageLen(self): - """ - used to calculte the number to send - as the message length when sending a message. - """ - return reduce(operator.add, [len(x[0]) + len(x[1]) + 4 for x in self.headers.items()]) + len(self.message) + 2 - - def setHeader(self, header, value): - """ set the desired header """ - self.headers[header] = value - - def getHeader(self, header): - """ - get the desired header value - @raise KeyError: if no such header exists. - """ - return self.headers[header] - - def hasHeader(self, header): - """ check to see if the desired header exists """ - return self.headers.has_key(header) - - def getMessage(self): - """ return the message - not including headers """ - return self.message - - def setMessage(self, message): - """ set the message text """ - self.message = message - -class MSNContact: - - """ - This class represents a contact (user). - - @ivar userHandle: The contact's user handle (passport). - @ivar screenName: The contact's screen name. - @ivar groups: A list of all the group IDs which this - contact belongs to. - @ivar lists: An integer representing the sum of all lists - that this contact belongs to. - @ivar status: The contact's status code. - @type status: str if contact's status is known, None otherwise. - - @ivar homePhone: The contact's home phone number. - @type homePhone: str if known, otherwise None. - @ivar workPhone: The contact's work phone number. - @type workPhone: str if known, otherwise None. - @ivar mobilePhone: The contact's mobile phone number. - @type mobilePhone: str if known, otherwise None. - @ivar hasPager: Whether or not this user has a mobile pager - (true=yes, false=no) - """ - - def __init__(self, userHandle="", screenName="", lists=0, groups=[], status=None): - self.userHandle = userHandle - self.screenName = screenName - self.lists = lists - self.groups = [] # if applicable - self.status = status # current status - - # phone details - self.homePhone = None - self.workPhone = None - self.mobilePhone = None - self.hasPager = None - - def setPhone(self, phoneType, value): - """ - set phone numbers/values for this specific user. - for phoneType check the *_PHONE constants and HAS_PAGER - """ - - t = phoneType.upper() - if t == HOME_PHONE: - self.homePhone = value - elif t == WORK_PHONE: - self.workPhone = value - elif t == MOBILE_PHONE: - self.mobilePhone = value - elif t == HAS_PAGER: - self.hasPager = value - else: - raise ValueError, "Invalid Phone Type" - - def addToList(self, listType): - """ - Update the lists attribute to - reflect being part of the - given list. - """ - self.lists |= listType - - def removeFromList(self, listType): - """ - Update the lists attribute to - reflect being removed from the - given list. - """ - self.lists ^= listType - -class MSNContactList: - """ - This class represents a basic MSN contact list. - - @ivar contacts: All contacts on my various lists - @type contacts: dict (mapping user handles to MSNContact objects) - @ivar version: The current contact list version (used for list syncing) - @ivar groups: a mapping of group ids to group names - (groups can only exist on the forward list) - @type groups: dict - - B{Note}: - This is used only for storage and doesn't effect the - server's contact list. - """ - - def __init__(self): - self.contacts = {} - self.version = 0 - self.groups = {} - self.autoAdd = 0 - self.privacy = 0 - - def _getContactsFromList(self, listType): - """ - Obtain all contacts which belong - to the given list type. - """ - return dict([(uH,obj) for uH,obj in self.contacts.items() if obj.lists & listType]) - - def addContact(self, contact): - """ - Add a contact - """ - self.contacts[contact.userHandle] = contact - - def remContact(self, userHandle): - """ - Remove a contact - """ - try: - del self.contacts[userHandle] - except KeyError: - pass - - def getContact(self, userHandle): - """ - Obtain the MSNContact object - associated with the given - userHandle. - @return: the MSNContact object if - the user exists, or None. - """ - try: - return self.contacts[userHandle] - except KeyError: - return None - - def getBlockedContacts(self): - """ - Obtain all the contacts on my block list - """ - return self._getContactsFromList(BLOCK_LIST) - - def getAuthorizedContacts(self): - """ - Obtain all the contacts on my auth list. - (These are contacts which I have verified - can view my state changes). - """ - return self._getContactsFromList(ALLOW_LIST) - - def getReverseContacts(self): - """ - Get all contacts on my reverse list. - (These are contacts which have added me - to their forward list). - """ - return self._getContactsFromList(REVERSE_LIST) - - def getContacts(self): - """ - Get all contacts on my forward list. - (These are the contacts which I have added - to my list). - """ - return self._getContactsFromList(FORWARD_LIST) - - def setGroup(self, id, name): - """ - Keep a mapping from the given id - to the given name. - """ - self.groups[id] = name - - def remGroup(self, id): - """ - Removed the stored group - mapping for the given id. - """ - try: - del self.groups[id] - except KeyError: - pass - for c in self.contacts: - if id in c.groups: - c.groups.remove(id) - - -class MSNEventBase(LineReceiver): - """ - This class provides support for handling / dispatching events and is the - base class of the three main client protocols (DispatchClient, - NotificationClient, SwitchboardClient) - """ - - def __init__(self): - self.ids = {} # mapping of ids to Deferreds - self.currentID = 0 - self.connected = 0 - self.setLineMode() - self.currentMessage = None - - def connectionLost(self, reason): - self.ids = {} - self.connected = 0 - - def connectionMade(self): - self.connected = 1 - - def _fireCallback(self, id, *args): - """ - Fire the callback for the given id - if one exists and return 1, else return false - """ - if self.ids.has_key(id): - self.ids[id][0].callback(args) - del self.ids[id] - return 1 - return 0 - - def _nextTransactionID(self): - """ return a usable transaction ID """ - self.currentID += 1 - if self.currentID > 1000: - self.currentID = 1 - return self.currentID - - def _createIDMapping(self, data=None): - """ - return a unique transaction ID that is mapped internally to a - deferred .. also store arbitrary data if it is needed - """ - id = self._nextTransactionID() - d = Deferred() - self.ids[id] = (d, data) - return (id, d) - - def checkMessage(self, message): - """ - process received messages to check for file invitations and - typing notifications and other control type messages - """ - raise NotImplementedError - - def lineReceived(self, line): - if self.currentMessage: - self.currentMessage.readPos += len(line+CR+LF) - if line == "": - self.setRawMode() - if self.currentMessage.readPos == self.currentMessage.length: - self.rawDataReceived("") # :( - return - try: - header, value = line.split(':') - except ValueError: - raise MSNProtocolError, "Invalid Message Header" - self.currentMessage.setHeader(header, unquote(value).lstrip()) - return - try: - cmd, params = line.split(' ', 1) - except ValueError: - raise MSNProtocolError, "Invalid Message, %s" % repr(line) - - if len(cmd) != 3: - raise MSNProtocolError, "Invalid Command, %s" % repr(cmd) - if cmd.isdigit(): - errorCode = int(cmd) - id = int(params.split()[0]) - if id in self.ids: - self.ids[id][0].errback(MSNCommandFailed(errorCode)) - del self.ids[id] - return - else: # we received an error which doesn't map to a sent command - self.gotError(errorCode) - return - - handler = getattr(self, "handle_%s" % cmd.upper(), None) - if handler: - try: - handler(params.split()) - except MSNProtocolError, why: - self.gotBadLine(line, why) - else: - self.handle_UNKNOWN(cmd, params.split()) - - def rawDataReceived(self, data): - extra = "" - self.currentMessage.readPos += len(data) - diff = self.currentMessage.readPos - self.currentMessage.length - if diff > 0: - self.currentMessage.message += data[:-diff] - extra = data[-diff:] - elif diff == 0: - self.currentMessage.message += data - else: - self.currentMessage += data - return - del self.currentMessage.readPos - m = self.currentMessage - self.currentMessage = None - self.setLineMode(extra) - if not self.checkMessage(m): - return - self.gotMessage(m) - - ### protocol command handlers - no need to override these. - - def handle_MSG(self, params): - checkParamLen(len(params), 3, 'MSG') - try: - messageLen = int(params[2]) - except ValueError: - raise MSNProtocolError, "Invalid Parameter for MSG length argument" - self.currentMessage = MSNMessage(length=messageLen, userHandle=params[0], screenName=unquote(params[1])) - - def handle_UNKNOWN(self, cmd, params): - """ implement me in subclasses if you want to handle unknown events """ - log.msg("Received unknown command (%s), params: %s" % (cmd, params)) - - ### callbacks - - def gotMessage(self, message): - """ - called when we receive a message - override in notification - and switchboard clients - """ - raise NotImplementedError - - def gotBadLine(self, line, why): - """ called when a handler notifies me that this line is broken """ - log.msg('Error in line: %s (%s)' % (line, why)) - - def gotError(self, errorCode): - """ - called when the server sends an error which is not in - response to a sent command (ie. it has no matching transaction ID) - """ - log.msg('Error %s' % (errorCodes[errorCode])) - -class DispatchClient(MSNEventBase): - """ - This class provides support for clients connecting to the dispatch server - @ivar userHandle: your user handle (passport) needed before connecting. - """ - - # eventually this may become an attribute of the - # factory. - userHandle = "" - - def connectionMade(self): - MSNEventBase.connectionMade(self) - self.sendLine('VER %s %s' % (self._nextTransactionID(), MSN_PROTOCOL_VERSION)) - - ### protocol command handlers ( there is no need to override these ) - - def handle_VER(self, params): - versions = params[1:] - if versions is None or ' '.join(versions) != MSN_PROTOCOL_VERSION: - self.transport.loseConnection() - raise MSNProtocolError, "Invalid version response" - id = self._nextTransactionID() - self.sendLine("CVR %s %s %s" % (id, MSN_CVR_STR, self.userHandle)) - - def handle_CVR(self, params): - self.sendLine("USR %s TWN I %s" % (self._nextTransactionID(), self.userHandle)) - - def handle_XFR(self, params): - if len(params) < 4: - raise MSNProtocolError, "Invalid number of parameters for XFR" - id, refType, addr = params[:3] - # was addr a host:port pair? - try: - host, port = addr.split(':') - except ValueError: - host = addr - port = MSN_PORT - if refType == "NS": - self.gotNotificationReferral(host, int(port)) - - ### callbacks - - def gotNotificationReferral(self, host, port): - """ - called when we get a referral to the notification server. - - @param host: the notification server's hostname - @param port: the port to connect to - """ - pass - - -class NotificationClient(MSNEventBase): - """ - This class provides support for clients connecting - to the notification server. - """ - - factory = None # sssh pychecker - - def __init__(self, currentID=0): - MSNEventBase.__init__(self) - self.currentID = currentID - self._state = ['DISCONNECTED', {}] - - def _setState(self, state): - self._state[0] = state - - def _getState(self): - return self._state[0] - - def _getStateData(self, key): - return self._state[1][key] - - def _setStateData(self, key, value): - self._state[1][key] = value - - def _remStateData(self, *args): - for key in args: - del self._state[1][key] - - def connectionMade(self): - MSNEventBase.connectionMade(self) - self._setState('CONNECTED') - self.sendLine("VER %s %s" % (self._nextTransactionID(), MSN_PROTOCOL_VERSION)) - - def connectionLost(self, reason): - self._setState('DISCONNECTED') - self._state[1] = {} - MSNEventBase.connectionLost(self, reason) - - def checkMessage(self, message): - """ hook used for detecting specific notification messages """ - cTypes = [s.lstrip() for s in message.getHeader('Content-Type').split(';')] - if 'text/x-msmsgsprofile' in cTypes: - self.gotProfile(message) - return 0 - return 1 - - ### protocol command handlers - no need to override these - - def handle_VER(self, params): - versions = params[1:] - if versions is None or ' '.join(versions) != MSN_PROTOCOL_VERSION: - self.transport.loseConnection() - raise MSNProtocolError, "Invalid version response" - self.sendLine("CVR %s %s %s" % (self._nextTransactionID(), MSN_CVR_STR, self.factory.userHandle)) - - def handle_CVR(self, params): - self.sendLine("USR %s TWN I %s" % (self._nextTransactionID(), self.factory.userHandle)) - - def handle_USR(self, params): - if len(params) != 4 and len(params) != 6: - raise MSNProtocolError, "Invalid Number of Parameters for USR" - - mechanism = params[1] - if mechanism == "OK": - self.loggedIn(params[2], unquote(params[3]), int(params[4])) - elif params[2].upper() == "S": - # we need to obtain auth from a passport server - f = self.factory - d = _login(f.userHandle, f.password, f.passportServer, authData=params[3]) - d.addCallback(self._passportLogin) - d.addErrback(self._passportError) - - def _passportLogin(self, result): - if result[0] == LOGIN_REDIRECT: - d = _login(self.factory.userHandle, self.factory.password, - result[1], cached=1, authData=result[2]) - d.addCallback(self._passportLogin) - d.addErrback(self._passportError) - elif result[0] == LOGIN_SUCCESS: - self.sendLine("USR %s TWN S %s" % (self._nextTransactionID(), result[1])) - elif result[0] == LOGIN_FAILURE: - self.loginFailure(result[1]) - - def _passportError(self, failure): - self.loginFailure("Exception while authenticating: %s" % failure) - - def handle_CHG(self, params): - checkParamLen(len(params), 3, 'CHG') - id = int(params[0]) - if not self._fireCallback(id, params[1]): - self.statusChanged(params[1]) - - def handle_ILN(self, params): - checkParamLen(len(params), 5, 'ILN') - self.gotContactStatus(params[1], params[2], unquote(params[3])) - - def handle_CHL(self, params): - checkParamLen(len(params), 2, 'CHL') - self.sendLine("QRY %s msmsgs@msnmsgr.com 32" % self._nextTransactionID()) - self.transport.write(md5.md5(params[1] + MSN_CHALLENGE_STR).hexdigest()) - - def handle_QRY(self, params): - pass - - def handle_NLN(self, params): - checkParamLen(len(params), 4, 'NLN') - self.contactStatusChanged(params[0], params[1], unquote(params[2])) - - def handle_FLN(self, params): - checkParamLen(len(params), 1, 'FLN') - self.contactOffline(params[0]) - - def handle_LST(self, params): - # support no longer exists for manually - # requesting lists - why do I feel cleaner now? - if self._getState() != 'SYNC': - return - contact = MSNContact(userHandle=params[0], screenName=unquote(params[1]), - lists=int(params[2])) - if contact.lists & FORWARD_LIST: - contact.groups.extend(map(int, params[3].split(','))) - self._getStateData('list').addContact(contact) - self._setStateData('last_contact', contact) - sofar = self._getStateData('lst_sofar') + 1 - if sofar == self._getStateData('lst_reply'): - # this is the best place to determine that - # a syn realy has finished - msn _may_ send - # BPR information for the last contact - # which is unfortunate because it means - # that the real end of a syn is non-deterministic. - # to handle this we'll keep 'last_contact' hanging - # around in the state data and update it if we need - # to later. - self._setState('SESSION') - contacts = self._getStateData('list') - phone = self._getStateData('phone') - id = self._getStateData('synid') - self._remStateData('lst_reply', 'lsg_reply', 'lst_sofar', 'phone', 'synid', 'list') - self._fireCallback(id, contacts, phone) - else: - self._setStateData('lst_sofar',sofar) - - def handle_BLP(self, params): - # check to see if this is in response to a SYN - if self._getState() == 'SYNC': - self._getStateData('list').privacy = listCodeToID[params[0].lower()] - else: - id = int(params[0]) - self._fireCallback(id, int(params[1]), listCodeToID[params[2].lower()]) - - def handle_GTC(self, params): - # check to see if this is in response to a SYN - if self._getState() == 'SYNC': - if params[0].lower() == "a": - self._getStateData('list').autoAdd = 0 - elif params[0].lower() == "n": - self._getStateData('list').autoAdd = 1 - else: - raise MSNProtocolError, "Invalid Paramater for GTC" # debug - else: - id = int(params[0]) - if params[1].lower() == "a": - self._fireCallback(id, 0) - elif params[1].lower() == "n": - self._fireCallback(id, 1) - else: - raise MSNProtocolError, "Invalid Paramater for GTC" # debug - - def handle_SYN(self, params): - id = int(params[0]) - if len(params) == 2: - self._setState('SESSION') - self._fireCallback(id, None, None) - else: - contacts = MSNContactList() - contacts.version = int(params[1]) - self._setStateData('list', contacts) - self._setStateData('lst_reply', int(params[2])) - self._setStateData('lsg_reply', int(params[3])) - self._setStateData('lst_sofar', 0) - self._setStateData('phone', []) - - def handle_LSG(self, params): - if self._getState() == 'SYNC': - self._getStateData('list').groups[int(params[0])] = unquote(params[1]) - - # Please see the comment above the requestListGroups / requestList methods - # regarding support for this - # - #else: - # self._getStateData('groups').append((int(params[4]), unquote(params[5]))) - # if params[3] == params[4]: # this was the last group - # self._fireCallback(int(params[0]), self._getStateData('groups'), int(params[1])) - # self._remStateData('groups') - - def handle_PRP(self, params): - if self._getState() == 'SYNC': - self._getStateData('phone').append((params[0], unquote(params[1]))) - else: - self._fireCallback(int(params[0]), int(params[1]), unquote(params[3])) - - def handle_BPR(self, params): - numParams = len(params) - if numParams == 2: # part of a syn - self._getStateData('last_contact').setPhone(params[0], unquote(params[1])) - elif numParams == 4: - self.gotPhoneNumber(int(params[0]), params[1], params[2], unquote(params[3])) - - def handle_ADG(self, params): - checkParamLen(len(params), 5, 'ADG') - id = int(params[0]) - if not self._fireCallback(id, int(params[1]), unquote(params[2]), int(params[3])): - raise MSNProtocolError, "ADG response does not match up to a request" # debug - - def handle_RMG(self, params): - checkParamLen(len(params), 3, 'RMG') - id = int(params[0]) - if not self._fireCallback(id, int(params[1]), int(params[2])): - raise MSNProtocolError, "RMG response does not match up to a request" # debug - - def handle_REG(self, params): - checkParamLen(len(params), 5, 'REG') - id = int(params[0]) - if not self._fireCallback(id, int(params[1]), int(params[2]), unquote(params[3])): - raise MSNProtocolError, "REG response does not match up to a request" # debug - - def handle_ADD(self, params): - numParams = len(params) - if numParams < 5 or params[1].upper() not in ('AL','BL','RL','FL'): - raise MSNProtocolError, "Invalid Paramaters for ADD" # debug - id = int(params[0]) - listType = params[1].lower() - listVer = int(params[2]) - userHandle = params[3] - groupID = None - if numParams == 6: # they sent a group id - if params[1].upper() != "FL": - raise MSNProtocolError, "Only forward list can contain groups" # debug - groupID = int(params[5]) - if not self._fireCallback(id, listCodeToID[listType], userHandle, listVer, groupID): - self.userAddedMe(userHandle, unquote(params[4]), listVer) - - def handle_REM(self, params): - numParams = len(params) - if numParams < 4 or params[1].upper() not in ('AL','BL','FL','RL'): - raise MSNProtocolError, "Invalid Paramaters for REM" # debug - id = int(params[0]) - listType = params[1].lower() - listVer = int(params[2]) - userHandle = params[3] - groupID = None - if numParams == 5: - if params[1] != "FL": - raise MSNProtocolError, "Only forward list can contain groups" # debug - groupID = int(params[4]) - if not self._fireCallback(id, listCodeToID[listType], userHandle, listVer, groupID): - if listType.upper() == "RL": - self.userRemovedMe(userHandle, listVer) - - def handle_REA(self, params): - checkParamLen(len(params), 4, 'REA') - id = int(params[0]) - self._fireCallback(id, int(params[1]), unquote(params[3])) - - def handle_XFR(self, params): - checkParamLen(len(params), 5, 'XFR') - id = int(params[0]) - # check to see if they sent a host/port pair - try: - host, port = params[2].split(':') - except ValueError: - host = params[2] - port = MSN_PORT - - if not self._fireCallback(id, host, int(port), params[4]): - raise MSNProtocolError, "Got XFR (referral) that I didn't ask for .. should this happen?" # debug - - def handle_RNG(self, params): - checkParamLen(len(params), 6, 'RNG') - # check for host:port pair - try: - host, port = params[1].split(":") - port = int(port) - except ValueError: - host = params[1] - port = MSN_PORT - self.gotSwitchboardInvitation(int(params[0]), host, port, params[3], params[4], - unquote(params[5])) - - def handle_OUT(self, params): - checkParamLen(len(params), 1, 'OUT') - if params[0] == "OTH": - self.multipleLogin() - elif params[0] == "SSD": - self.serverGoingDown() - else: - raise MSNProtocolError, "Invalid Parameters received for OUT" # debug - - # callbacks - - def loggedIn(self, userHandle, screenName, verified): - """ - Called when the client has logged in. - The default behaviour of this method is to - update the factory with our screenName and - to sync the contact list (factory.contacts). - When this is complete self.listSynchronized - will be called. - - @param userHandle: our userHandle - @param screenName: our screenName - @param verified: 1 if our passport has been (verified), 0 if not. - (i'm not sure of the significace of this) - @type verified: int - """ - self.factory.screenName = screenName - if not self.factory.contacts: - listVersion = 0 - else: - listVersion = self.factory.contacts.version - self.syncList(listVersion).addCallback(self.listSynchronized) - - def loginFailure(self, message): - """ - Called when the client fails to login. - - @param message: a message indicating the problem that was encountered - """ - pass - - def gotProfile(self, message): - """ - Called after logging in when the server sends an initial - message with MSN/passport specific profile information - such as country, number of kids, etc. - Check the message headers for the specific values. - - @param message: The profile message - """ - pass - - def listSynchronized(self, *args): - """ - Lists are now synchronized by default upon logging in, this - method is called after the synchronization has finished - and the factory now has the up-to-date contacts. - """ - pass - - def statusChanged(self, statusCode): - """ - Called when our status changes and it isn't in response to - a client command. By default we will update the status - attribute of the factory. - - @param statusCode: 3-letter status code - """ - self.factory.status = statusCode - - def gotContactStatus(self, statusCode, userHandle, screenName): - """ - Called after loggin in when the server sends status of online contacts. - By default we will update the status attribute of the contact stored - on the factory. - - @param statusCode: 3-letter status code - @param userHandle: the contact's user handle (passport) - @param screenName: the contact's screen name - """ - self.factory.contacts.getContact(userHandle).status = statusCode - - def contactStatusChanged(self, statusCode, userHandle, screenName): - """ - Called when we're notified that a contact's status has changed. - By default we will update the status attribute of the contact - stored on the factory. - - @param statusCode: 3-letter status code - @param userHandle: the contact's user handle (passport) - @param screenName: the contact's screen name - """ - self.factory.contacts.getContact(userHandle).status = statusCode - - def contactOffline(self, userHandle): - """ - Called when a contact goes offline. By default this method - will update the status attribute of the contact stored - on the factory. - - @param userHandle: the contact's user handle - """ - self.factory.contacts.getContact(userHandle).status = STATUS_OFFLINE - - def gotPhoneNumber(self, listVersion, userHandle, phoneType, number): - """ - Called when the server sends us phone details about - a specific user (for example after a user is added - the server will send their status, phone details etc. - By default we will update the list version for the - factory's contact list and update the phone details - for the specific user. - - @param listVersion: the new list version - @param userHandle: the contact's user handle (passport) - @param phoneType: the specific phoneType - (*_PHONE constants or HAS_PAGER) - @param number: the value/phone number. - """ - self.factory.contacts.version = listVersion - self.factory.contacts.getContact(userHandle).setPhone(phoneType, number) - - def userAddedMe(self, userHandle, screenName, listVersion): - """ - Called when a user adds me to their list. (ie. they have been added to - the reverse list. By default this method will update the version of - the factory's contact list -- that is, if the contact already exists - it will update the associated lists attribute, otherwise it will create - a new MSNContact object and store it. - - @param userHandle: the userHandle of the user - @param screenName: the screen name of the user - @param listVersion: the new list version - @type listVersion: int - """ - self.factory.contacts.version = listVersion - c = self.factory.contacts.getContact(userHandle) - if not c: - c = MSNContact(userHandle=userHandle, screenName=screenName) - self.factory.contacts.addContact(c) - c.addToList(REVERSE_LIST) - - def userRemovedMe(self, userHandle, listVersion): - """ - Called when a user removes us from their contact list - (they are no longer on our reverseContacts list. - By default this method will update the version of - the factory's contact list -- that is, the user will - be removed from the reverse list and if they are no longer - part of any lists they will be removed from the contact - list entirely. - - @param userHandle: the contact's user handle (passport) - @param listVersion: the new list version - """ - self.factory.contacts.version = listVersion - c = self.factory.contacts.getContact(userHandle) - c.removeFromList(REVERSE_LIST) - if c.lists == 0: - self.factory.contacts.remContact(c.userHandle) - - def gotSwitchboardInvitation(self, sessionID, host, port, - key, userHandle, screenName): - """ - Called when we get an invitation to a switchboard server. - This happens when a user requests a chat session with us. - - @param sessionID: session ID number, must be remembered for logging in - @param host: the hostname of the switchboard server - @param port: the port to connect to - @param key: used for authorization when connecting - @param userHandle: the user handle of the person who invited us - @param screenName: the screen name of the person who invited us - """ - pass - - def multipleLogin(self): - """ - Called when the server says there has been another login - under our account, the server should disconnect us right away. - """ - pass - - def serverGoingDown(self): - """ - Called when the server has notified us that it is going down for - maintenance. - """ - pass - - # api calls - - def changeStatus(self, status): - """ - Change my current status. This method will add - a default callback to the returned Deferred - which will update the status attribute of the - factory. - - @param status: 3-letter status code (as defined by - the STATUS_* constants) - @return: A Deferred, the callback of which will be - fired when the server confirms the change - of status. The callback argument will be - a tuple with the new status code as the - only element. - """ - - id, d = self._createIDMapping() - self.sendLine("CHG %s %s" % (id, status)) - def _cb(r): - self.factory.status = r[0] - return r - return d.addCallback(_cb) - - # I am no longer supporting the process of manually requesting - # lists or list groups -- as far as I can see this has no use - # if lists are synchronized and updated correctly, which they - # should be. If someone has a specific justified need for this - # then please contact me and i'll re-enable/fix support for it. - - #def requestList(self, listType): - # """ - # request the desired list type - # - # @param listType: (as defined by the *_LIST constants) - # @return: A Deferred, the callback of which will be - # fired when the list has been retrieved. - # The callback argument will be a tuple with - # the only element being a list of MSNContact - # objects. - # """ - # # this doesn't need to ever be used if syncing of the lists takes place - # # i.e. please don't use it! - # warnings.warn("Please do not use this method - use the list syncing process instead") - # id, d = self._createIDMapping() - # self.sendLine("LST %s %s" % (id, listIDToCode[listType].upper())) - # self._setStateData('list',[]) - # return d - - def setPrivacyMode(self, privLevel): - """ - Set my privacy mode on the server. - - B{Note}: - This only keeps the current privacy setting on - the server for later retrieval, it does not - effect the way the server works at all. - - @param privLevel: This parameter can be true, in which - case the server will keep the state as - 'al' which the official client interprets - as -> allow messages from only users on - the allow list. Alternatively it can be - false, in which case the server will keep - the state as 'bl' which the official client - interprets as -> allow messages from all - users except those on the block list. - - @return: A Deferred, the callback of which will be fired when - the server replies with the new privacy setting. - The callback argument will be a tuple, the 2 elements - of which being the list version and either 'al' - or 'bl' (the new privacy setting). - """ - - id, d = self._createIDMapping() - if privLevel: - self.sendLine("BLP %s AL" % id) - else: - self.sendLine("BLP %s BL" % id) - return d - - def syncList(self, version): - """ - Used for keeping an up-to-date contact list. - A callback is added to the returned Deferred - that updates the contact list on the factory - and also sets my state to STATUS_ONLINE. - - B{Note}: - This is called automatically upon signing - in using the version attribute of - factory.contacts, so you may want to persist - this object accordingly. Because of this there - is no real need to ever call this method - directly. - - @param version: The current known list version - - @return: A Deferred, the callback of which will be - fired when the server sends an adequate reply. - The callback argument will be a tuple with two - elements, the new list (MSNContactList) and - your current state (a dictionary). If the version - you sent _was_ the latest list version, both elements - will be None. To just request the list send a version of 0. - """ - - self._setState('SYNC') - id, d = self._createIDMapping(data=str(version)) - self._setStateData('synid',id) - self.sendLine("SYN %s %s" % (id, version)) - def _cb(r): - self.changeStatus(STATUS_ONLINE) - if r[0] is not None: - self.factory.contacts = r[0] - return r - return d.addCallback(_cb) - - - # I am no longer supporting the process of manually requesting - # lists or list groups -- as far as I can see this has no use - # if lists are synchronized and updated correctly, which they - # should be. If someone has a specific justified need for this - # then please contact me and i'll re-enable/fix support for it. - - #def requestListGroups(self): - # """ - # Request (forward) list groups. - # - # @return: A Deferred, the callback for which will be called - # when the server responds with the list groups. - # The callback argument will be a tuple with two elements, - # a dictionary mapping group IDs to group names and the - # current list version. - # """ - # - # # this doesn't need to be used if syncing of the lists takes place (which it SHOULD!) - # # i.e. please don't use it! - # warnings.warn("Please do not use this method - use the list syncing process instead") - # id, d = self._createIDMapping() - # self.sendLine("LSG %s" % id) - # self._setStateData('groups',{}) - # return d - - def setPhoneDetails(self, phoneType, value): - """ - Set/change my phone numbers stored on the server. - - @param phoneType: phoneType can be one of the following - constants - HOME_PHONE, WORK_PHONE, - MOBILE_PHONE, HAS_PAGER. - These are pretty self-explanatory, except - maybe HAS_PAGER which refers to whether or - not you have a pager. - @param value: for all of the *_PHONE constants the value is a - phone number (str), for HAS_PAGER accepted values - are 'Y' (for yes) and 'N' (for no). - - @return: A Deferred, the callback for which will be fired when - the server confirms the change has been made. The - callback argument will be a tuple with 2 elements, the - first being the new list version (int) and the second - being the new phone number value (str). - """ - # XXX: Add a default callback which updates - # factory.contacts.version and the relevant phone - # number - id, d = self._createIDMapping() - self.sendLine("PRP %s %s %s" % (id, phoneType, quote(value))) - return d - - def addListGroup(self, name): - """ - Used to create a new list group. - A default callback is added to the - returned Deferred which updates the - contacts attribute of the factory. - - @param name: The desired name of the new group. - - @return: A Deferred, the callbacck for which will be called - when the server clarifies that the new group has been - created. The callback argument will be a tuple with 3 - elements: the new list version (int), the new group name - (str) and the new group ID (int). - """ - - id, d = self._createIDMapping() - self.sendLine("ADG %s %s 0" % (id, quote(name))) - def _cb(r): - self.factory.contacts.version = r[0] - self.factory.contacts.setGroup(r[1], r[2]) - return r - return d.addCallback(_cb) - - def remListGroup(self, groupID): - """ - Used to remove a list group. - A default callback is added to the - returned Deferred which updates the - contacts attribute of the factory. - - @param groupID: the ID of the desired group to be removed. - - @return: A Deferred, the callback for which will be called when - the server clarifies the deletion of the group. - The callback argument will be a tuple with 2 elements: - the new list version (int) and the group ID (int) of - the removed group. - """ - - id, d = self._createIDMapping() - self.sendLine("RMG %s %s" % (id, groupID)) - def _cb(r): - self.factory.contacts.version = r[0] - self.factory.contacts.remGroup(r[1]) - return r - return d.addCallback(_cb) - - def renameListGroup(self, groupID, newName): - """ - Used to rename an existing list group. - A default callback is added to the returned - Deferred which updates the contacts attribute - of the factory. - - @param groupID: the ID of the desired group to rename. - @param newName: the desired new name for the group. - - @return: A Deferred, the callback for which will be called - when the server clarifies the renaming. - The callback argument will be a tuple of 3 elements, - the new list version (int), the group id (int) and - the new group name (str). - """ - - id, d = self._createIDMapping() - self.sendLine("REG %s %s %s 0" % (id, groupID, quote(newName))) - def _cb(r): - self.factory.contacts.version = r[0] - self.factory.contacts.setGroup(r[1], r[2]) - return r - return d.addCallback(_cb) - - def addContact(self, listType, userHandle, groupID=0): - """ - Used to add a contact to the desired list. - A default callback is added to the returned - Deferred which updates the contacts attribute of - the factory with the new contact information. - If you are adding a contact to the forward list - and you want to associate this contact with multiple - groups then you will need to call this method for each - group you would like to add them to, changing the groupID - parameter. The default callback will take care of updating - the group information on the factory's contact list. - - @param listType: (as defined by the *_LIST constants) - @param userHandle: the user handle (passport) of the contact - that is being added - @param groupID: the group ID for which to associate this contact - with. (default 0 - default group). Groups are only - valid for FORWARD_LIST. - - @return: A Deferred, the callback for which will be called when - the server has clarified that the user has been added. - The callback argument will be a tuple with 4 elements: - the list type, the contact's user handle, the new list - version, and the group id (if relevant, otherwise it - will be None) - """ - - id, d = self._createIDMapping() - listType = listIDToCode[listType].upper() - if listType == "FL": - self.sendLine("ADD %s FL %s %s %s" % (id, userHandle, userHandle, groupID)) - else: - self.sendLine("ADD %s %s %s %s" % (id, listType, userHandle, userHandle)) - - def _cb(r): - self.factory.contacts.version = r[2] - c = self.factory.contacts.getContact(r[1]) - if not c: - c = MSNContact(userHandle=r[1]) - if r[3]: - c.groups.append(r[3]) - c.addToList(r[0]) - return r - return d.addCallback(_cb) - - def remContact(self, listType, userHandle, groupID=0): - """ - Used to remove a contact from the desired list. - A default callback is added to the returned deferred - which updates the contacts attribute of the factory - to reflect the new contact information. If you are - removing from the forward list then you will need to - supply a groupID, if the contact is in more than one - group then they will only be removed from this group - and not the entire forward list, but if this is their - only group they will be removed from the whole list. - - @param listType: (as defined by the *_LIST constants) - @param userHandle: the user handle (passport) of the - contact being removed - @param groupID: the ID of the group to which this contact - belongs (only relevant for FORWARD_LIST, - default is 0) - - @return: A Deferred, the callback for which will be called when - the server has clarified that the user has been removed. - The callback argument will be a tuple of 4 elements: - the list type, the contact's user handle, the new list - version, and the group id (if relevant, otherwise it will - be None) - """ - - id, d = self._createIDMapping() - listType = listIDToCode[listType].upper() - if listType == "FL": - self.sendLine("REM %s FL %s %s" % (id, userHandle, groupID)) - else: - self.sendLine("REM %s %s %s" % (id, listType, userHandle)) - - def _cb(r): - l = self.factory.contacts - l.version = r[2] - c = l.getContact(r[1]) - group = r[3] - shouldRemove = 1 - if group: # they may not have been removed from the list - c.groups.remove(group) - if c.groups: - shouldRemove = 0 - if shouldRemove: - c.removeFromList(r[0]) - if c.lists == 0: - l.remContact(c.userHandle) - return r - return d.addCallback(_cb) - - def changeScreenName(self, newName): - """ - Used to change your current screen name. - A default callback is added to the returned - Deferred which updates the screenName attribute - of the factory and also updates the contact list - version. - - @param newName: the new screen name - - @return: A Deferred, the callback for which will be called - when the server sends an adequate reply. - The callback argument will be a tuple of 2 elements: - the new list version and the new screen name. - """ - - id, d = self._createIDMapping() - self.sendLine("REA %s %s %s" % (id, self.factory.userHandle, quote(newName))) - def _cb(r): - self.factory.contacts.version = r[0] - self.factory.screenName = r[1] - return r - return d.addCallback(_cb) - - def requestSwitchboardServer(self): - """ - Used to request a switchboard server to use for conversations. - - @return: A Deferred, the callback for which will be called when - the server responds with the switchboard information. - The callback argument will be a tuple with 3 elements: - the host of the switchboard server, the port and a key - used for logging in. - """ - - id, d = self._createIDMapping() - self.sendLine("XFR %s SB" % id) - return d - - def logOut(self): - """ - Used to log out of the notification server. - After running the method the server is expected - to close the connection. - """ - - self.sendLine("OUT") - -class NotificationFactory(ClientFactory): - """ - Factory for the NotificationClient protocol. - This is basically responsible for keeping - the state of the client and thus should be used - in a 1:1 situation with clients. - - @ivar contacts: An MSNContactList instance reflecting - the current contact list -- this is - generally kept up to date by the default - command handlers. - @ivar userHandle: The client's userHandle, this is expected - to be set by the client and is used by the - protocol (for logging in etc). - @ivar screenName: The client's current screen-name -- this is - generally kept up to date by the default - command handlers. - @ivar password: The client's password -- this is (obviously) - expected to be set by the client. - @ivar passportServer: This must point to an msn passport server - (the whole URL is required) - @ivar status: The status of the client -- this is generally kept - up to date by the default command handlers - """ - - contacts = None - userHandle = '' - screenName = '' - password = '' - passportServer = 'https://nexus.passport.com/rdr/pprdr.asp' - status = 'FLN' - protocol = NotificationClient - - -# XXX: A lot of the state currently kept in -# instances of SwitchboardClient is likely to -# be moved into a factory at some stage in the -# future - -class SwitchboardClient(MSNEventBase): - """ - This class provides support for clients connecting to a switchboard server. - - Switchboard servers are used for conversations with other people - on the MSN network. This means that the number of conversations at - any given time will be directly proportional to the number of - connections to varioius switchboard servers. - - MSN makes no distinction between single and group conversations, - so any number of users may be invited to join a specific conversation - taking place on a switchboard server. - - @ivar key: authorization key, obtained when receiving - invitation / requesting switchboard server. - @ivar userHandle: your user handle (passport) - @ivar sessionID: unique session ID, used if you are replying - to a switchboard invitation - @ivar reply: set this to 1 in connectionMade or before to signifiy - that you are replying to a switchboard invitation. - """ - - key = 0 - userHandle = "" - sessionID = "" - reply = 0 - - _iCookie = 0 - - def __init__(self): - MSNEventBase.__init__(self) - self.pendingUsers = {} - self.cookies = {'iCookies' : {}, 'external' : {}} # will maybe be moved to a factory in the future - - def connectionMade(self): - MSNEventBase.connectionMade(self) - print 'sending initial stuff' - self._sendInit() - - def connectionLost(self, reason): - self.cookies['iCookies'] = {} - self.cookies['external'] = {} - MSNEventBase.connectionLost(self, reason) - - def _sendInit(self): - """ - send initial data based on whether we are replying to an invitation - or starting one. - """ - id = self._nextTransactionID() - if not self.reply: - self.sendLine("USR %s %s %s" % (id, self.userHandle, self.key)) - else: - self.sendLine("ANS %s %s %s %s" % (id, self.userHandle, self.key, self.sessionID)) - - def _newInvitationCookie(self): - self._iCookie += 1 - if self._iCookie > 1000: - self._iCookie = 1 - return self._iCookie - - def _checkTyping(self, message, cTypes): - """ helper method for checkMessage """ - if 'text/x-msmsgscontrol' in cTypes and message.hasHeader('TypingUser'): - self.userTyping(message) - return 1 - - def _checkFileInvitation(self, message, info): - """ helper method for checkMessage """ - guid = info.get('Application-GUID', '').lower() - name = info.get('Application-Name', '').lower() - - # Both fields are required, but we'll let some lazy clients get away - # with only sending a name, if it is easy for us to recognize the - # name (the name is localized, so this check might fail for lazy, - # non-english clients, but I'm not about to include "file transfer" - # in 80 different languages here). - - if name != "file transfer" and guid != classNameToGUID["file transfer"]: - return 0 - try: - cookie = int(info['Invitation-Cookie']) - fileName = info['Application-File'] - fileSize = int(info['Application-FileSize']) - except KeyError: - log.msg('Received munged file transfer request ... ignoring.') - return 0 - self.gotSendRequest(fileName, fileSize, cookie, message) - return 1 - - def _checkFileResponse(self, message, info): - """ helper method for checkMessage """ - try: - cmd = info['Invitation-Command'].upper() - cookie = int(info['Invitation-Cookie']) - except KeyError: - return 0 - accept = (cmd == 'ACCEPT') and 1 or 0 - requested = self.cookies['iCookies'].get(cookie) - if not requested: - return 1 - requested[0].callback((accept, cookie, info)) - del self.cookies['iCookies'][cookie] - return 1 - - def _checkFileInfo(self, message, info): - """ helper method for checkMessage """ - try: - ip = info['IP-Address'] - iCookie = int(info['Invitation-Cookie']) - aCookie = int(info['AuthCookie']) - cmd = info['Invitation-Command'].upper() - port = int(info['Port']) - except KeyError: - return 0 - accept = (cmd == 'ACCEPT') and 1 or 0 - requested = self.cookies['external'].get(iCookie) - if not requested: - return 1 # we didn't ask for this - requested[0].callback((accept, ip, port, aCookie, info)) - del self.cookies['external'][iCookie] - return 1 - - def checkMessage(self, message): - """ - hook for detecting any notification type messages - (e.g. file transfer) - """ - cTypes = [s.lstrip() for s in message.getHeader('Content-Type').split(';')] - if self._checkTyping(message, cTypes): - return 0 - if 'text/x-msmsgsinvite' in cTypes: - # header like info is sent as part of the message body. - info = {} - for line in message.message.split('\r\n'): - try: - key, val = line.split(':') - info[key] = val.lstrip() - except ValueError: - continue - if self._checkFileInvitation(message, info) or self._checkFileInfo(message, info) or self._checkFileResponse(message, info): - return 0 - elif 'text/x-clientcaps' in cTypes: - # do something with capabilities - return 0 - return 1 - - # negotiation - def handle_USR(self, params): - checkParamLen(len(params), 4, 'USR') - if params[1] == "OK": - self.loggedIn() - - # invite a user - def handle_CAL(self, params): - checkParamLen(len(params), 3, 'CAL') - id = int(params[0]) - if params[1].upper() == "RINGING": - self._fireCallback(id, int(params[2])) # session ID as parameter - - # user joined - def handle_JOI(self, params): - checkParamLen(len(params), 2, 'JOI') - self.userJoined(params[0], unquote(params[1])) - - # users participating in the current chat - def handle_IRO(self, params): - checkParamLen(len(params), 5, 'IRO') - self.pendingUsers[params[3]] = unquote(params[4]) - if params[1] == params[2]: - self.gotChattingUsers(self.pendingUsers) - self.pendingUsers = {} - - # finished listing users - def handle_ANS(self, params): - checkParamLen(len(params), 2, 'ANS') - if params[1] == "OK": - self.loggedIn() - - def handle_ACK(self, params): - checkParamLen(len(params), 1, 'ACK') - self._fireCallback(int(params[0]), None) - - def handle_NAK(self, params): - checkParamLen(len(params), 1, 'NAK') - self._fireCallback(int(params[0]), None) - - def handle_BYE(self, params): - #checkParamLen(len(params), 1, 'BYE') # i've seen more than 1 param passed to this - self.userLeft(params[0]) - - # callbacks - - def loggedIn(self): - """ - called when all login details have been negotiated. - Messages can now be sent, or new users invited. - """ - pass - - def gotChattingUsers(self, users): - """ - called after connecting to an existing chat session. - - @param users: A dict mapping user handles to screen names - (current users taking part in the conversation) - """ - pass - - def userJoined(self, userHandle, screenName): - """ - called when a user has joined the conversation. - - @param userHandle: the user handle (passport) of the user - @param screenName: the screen name of the user - """ - pass - - def userLeft(self, userHandle): - """ - called when a user has left the conversation. - - @param userHandle: the user handle (passport) of the user. - """ - pass - - def gotMessage(self, message): - """ - called when we receive a message. - - @param message: the associated MSNMessage object - """ - pass - - def userTyping(self, message): - """ - called when we receive the special type of message notifying - us that a user is typing a message. - - @param message: the associated MSNMessage object - """ - pass - - def gotSendRequest(self, fileName, fileSize, iCookie, message): - """ - called when a contact is trying to send us a file. - To accept or reject this transfer see the - fileInvitationReply method. - - @param fileName: the name of the file - @param fileSize: the size of the file - @param iCookie: the invitation cookie, used so the client can - match up your reply with this request. - @param message: the MSNMessage object which brought about this - invitation (it may contain more information) - """ - pass - - # api calls - - def inviteUser(self, userHandle): - """ - used to invite a user to the current switchboard server. - - @param userHandle: the user handle (passport) of the desired user. - - @return: A Deferred, the callback for which will be called - when the server notifies us that the user has indeed - been invited. The callback argument will be a tuple - with 1 element, the sessionID given to the invited user. - I'm not sure if this is useful or not. - """ - - id, d = self._createIDMapping() - self.sendLine("CAL %s %s" % (id, userHandle)) - return d - - def sendMessage(self, message): - """ - used to send a message. - - @param message: the corresponding MSNMessage object. - - @return: Depending on the value of message.ack. - If set to MSNMessage.MESSAGE_ACK or - MSNMessage.MESSAGE_NACK a Deferred will be returned, - the callback for which will be fired when an ACK or - NACK is received - the callback argument will be - (None,). If set to MSNMessage.MESSAGE_ACK_NONE then - the return value is None. - """ - - if message.ack not in ('A','N'): - id, d = self._nextTransactionID(), None - else: - id, d = self._createIDMapping() - if message.length == 0: - message.length = message._calcMessageLen() - self.sendLine("MSG %s %s %s" % (id, message.ack, message.length)) - # apparently order matters with at least MIME-Version and Content-Type - self.sendLine('MIME-Version: %s' % message.getHeader('MIME-Version')) - self.sendLine('Content-Type: %s' % message.getHeader('Content-Type')) - # send the rest of the headers - for header in [h for h in message.headers.items() if h[0].lower() not in ('mime-version','content-type')]: - self.sendLine("%s: %s" % (header[0], header[1])) - self.transport.write(CR+LF) - self.transport.write(message.message) - return d - - def sendTypingNotification(self): - """ - used to send a typing notification. Upon receiving this - message the official client will display a 'user is typing' - message to all other users in the chat session for 10 seconds. - The official client sends one of these every 5 seconds (I think) - as long as you continue to type. - """ - m = MSNMessage() - m.ack = m.MESSAGE_ACK_NONE - m.setHeader('Content-Type', 'text/x-msmsgscontrol') - m.setHeader('TypingUser', self.userHandle) - m.message = "\r\n" - self.sendMessage(m) - - def sendFileInvitation(self, fileName, fileSize): - """ - send an notification that we want to send a file. - - @param fileName: the file name - @param fileSize: the file size - - @return: A Deferred, the callback of which will be fired - when the user responds to this invitation with an - appropriate message. The callback argument will be - a tuple with 3 elements, the first being 1 or 0 - depending on whether they accepted the transfer - (1=yes, 0=no), the second being an invitation cookie - to identify your follow-up responses and the third being - the message 'info' which is a dict of information they - sent in their reply (this doesn't really need to be used). - If you wish to proceed with the transfer see the - sendTransferInfo method. - """ - cookie = self._newInvitationCookie() - d = Deferred() - m = MSNMessage() - m.setHeader('Content-Type', 'text/x-msmsgsinvite; charset=UTF-8') - m.message += 'Application-Name: File Transfer\r\n' - m.message += 'Application-GUID: %s\r\n' % (classNameToGUID["file transfer"],) - m.message += 'Invitation-Command: INVITE\r\n' - m.message += 'Invitation-Cookie: %s\r\n' % str(cookie) - m.message += 'Application-File: %s\r\n' % fileName - m.message += 'Application-FileSize: %s\r\n\r\n' % str(fileSize) - m.ack = m.MESSAGE_ACK_NONE - self.sendMessage(m) - self.cookies['iCookies'][cookie] = (d, m) - return d - - def fileInvitationReply(self, iCookie, accept=1): - """ - used to reply to a file transfer invitation. - - @param iCookie: the invitation cookie of the initial invitation - @param accept: whether or not you accept this transfer, - 1 = yes, 0 = no, default = 1. - - @return: A Deferred, the callback for which will be fired when - the user responds with the transfer information. - The callback argument will be a tuple with 5 elements, - whether or not they wish to proceed with the transfer - (1=yes, 0=no), their ip, the port, the authentication - cookie (see FileReceive/FileSend) and the message - info (dict) (in case they send extra header-like info - like Internal-IP, this doesn't necessarily need to be - used). If you wish to proceed with the transfer see - FileReceive. - """ - d = Deferred() - m = MSNMessage() - m.setHeader('Content-Type', 'text/x-msmsgsinvite; charset=UTF-8') - m.message += 'Invitation-Command: %s\r\n' % (accept and 'ACCEPT' or 'CANCEL') - m.message += 'Invitation-Cookie: %s\r\n' % str(iCookie) - if not accept: - m.message += 'Cancel-Code: REJECT\r\n' - m.message += 'Launch-Application: FALSE\r\n' - m.message += 'Request-Data: IP-Address:\r\n' - m.message += '\r\n' - m.ack = m.MESSAGE_ACK_NONE - self.sendMessage(m) - self.cookies['external'][iCookie] = (d, m) - return d - - def sendTransferInfo(self, accept, iCookie, authCookie, ip, port): - """ - send information relating to a file transfer session. - - @param accept: whether or not to go ahead with the transfer - (1=yes, 0=no) - @param iCookie: the invitation cookie of previous replies - relating to this transfer - @param authCookie: the authentication cookie obtained from - an FileSend instance - @param ip: your ip - @param port: the port on which an FileSend protocol is listening. - """ - m = MSNMessage() - m.setHeader('Content-Type', 'text/x-msmsgsinvite; charset=UTF-8') - m.message += 'Invitation-Command: %s\r\n' % (accept and 'ACCEPT' or 'CANCEL') - m.message += 'Invitation-Cookie: %s\r\n' % iCookie - m.message += 'IP-Address: %s\r\n' % ip - m.message += 'Port: %s\r\n' % port - m.message += 'AuthCookie: %s\r\n' % authCookie - m.message += '\r\n' - m.ack = m.MESSAGE_NACK - self.sendMessage(m) - -class FileReceive(LineReceiver): - """ - This class provides support for receiving files from contacts. - - @ivar fileSize: the size of the receiving file. (you will have to set this) - @ivar connected: true if a connection has been established. - @ivar completed: true if the transfer is complete. - @ivar bytesReceived: number of bytes (of the file) received. - This does not include header data. - """ - - def __init__(self, auth, myUserHandle, file, directory="", overwrite=0): - """ - @param auth: auth string received in the file invitation. - @param myUserHandle: your userhandle. - @param file: A string or file object represnting the file - to save data to. - @param directory: optional parameter specifiying the directory. - Defaults to the current directory. - @param overwrite: if true and a file of the same name exists on - your system, it will be overwritten. (0 by default) - """ - self.auth = auth - self.myUserHandle = myUserHandle - self.fileSize = 0 - self.connected = 0 - self.completed = 0 - self.directory = directory - self.bytesReceived = 0 - self.overwrite = overwrite - - # used for handling current received state - self.state = 'CONNECTING' - self.segmentLength = 0 - self.buffer = '' - - if isinstance(file, types.StringType): - path = os.path.join(directory, file) - if os.path.exists(path) and not self.overwrite: - log.msg('File already exists...') - raise IOError, "File Exists" # is this all we should do here? - self.file = open(os.path.join(directory, file), 'wb') - else: - self.file = file - - def connectionMade(self): - self.connected = 1 - self.state = 'INHEADER' - self.sendLine('VER MSNFTP') - - def connectionLost(self, reason): - self.connected = 0 - self.file.close() - - def parseHeader(self, header): - """ parse the header of each 'message' to obtain the segment length """ - - if ord(header[0]) != 0: # they requested that we close the connection - self.transport.loseConnection() - return - try: - extra, factor = header[1:] - except ValueError: - # munged header, ending transfer - self.transport.loseConnection() - raise - extra = ord(extra) - factor = ord(factor) - return factor * 256 + extra - - def lineReceived(self, line): - temp = line.split() - if len(temp) == 1: - params = [] - else: - params = temp[1:] - cmd = temp[0] - handler = getattr(self, "handle_%s" % cmd.upper(), None) - if handler: - handler(params) # try/except - else: - self.handle_UNKNOWN(cmd, params) - - def rawDataReceived(self, data): - bufferLen = len(self.buffer) - if self.state == 'INHEADER': - delim = 3-bufferLen - self.buffer += data[:delim] - if len(self.buffer) == 3: - self.segmentLength = self.parseHeader(self.buffer) - if not self.segmentLength: - return # hrm - self.buffer = "" - self.state = 'INSEGMENT' - extra = data[delim:] - if len(extra) > 0: - self.rawDataReceived(extra) - return - - elif self.state == 'INSEGMENT': - dataSeg = data[:(self.segmentLength-bufferLen)] - self.buffer += dataSeg - self.bytesReceived += len(dataSeg) - if len(self.buffer) == self.segmentLength: - self.gotSegment(self.buffer) - self.buffer = "" - if self.bytesReceived == self.fileSize: - self.completed = 1 - self.buffer = "" - self.file.close() - self.sendLine("BYE 16777989") - return - self.state = 'INHEADER' - extra = data[(self.segmentLength-bufferLen):] - if len(extra) > 0: - self.rawDataReceived(extra) - return - - def handle_VER(self, params): - checkParamLen(len(params), 1, 'VER') - if params[0].upper() == "MSNFTP": - self.sendLine("USR %s %s" % (self.myUserHandle, self.auth)) - else: - log.msg('they sent the wrong version, time to quit this transfer') - self.transport.loseConnection() - - def handle_FIL(self, params): - checkParamLen(len(params), 1, 'FIL') - try: - self.fileSize = int(params[0]) - except ValueError: # they sent the wrong file size - probably want to log this - self.transport.loseConnection() - return - self.setRawMode() - self.sendLine("TFR") - - def handle_UNKNOWN(self, cmd, params): - log.msg('received unknown command (%s), params: %s' % (cmd, params)) - - def gotSegment(self, data): - """ called when a segment (block) of data arrives. """ - self.file.write(data) - -class FileSend(LineReceiver): - """ - This class provides support for sending files to other contacts. - - @ivar bytesSent: the number of bytes that have currently been sent. - @ivar completed: true if the send has completed. - @ivar connected: true if a connection has been established. - @ivar targetUser: the target user (contact). - @ivar segmentSize: the segment (block) size. - @ivar auth: the auth cookie (number) to use when sending the - transfer invitation - """ - - def __init__(self, file): - """ - @param file: A string or file object represnting the file to send. - """ - - if isinstance(file, types.StringType): - self.file = open(file, 'rb') - else: - self.file = file - - self.fileSize = 0 - self.bytesSent = 0 - self.completed = 0 - self.connected = 0 - self.targetUser = None - self.segmentSize = 2045 - self.auth = randint(0, 2**30) - self._pendingSend = None # :( - - def connectionMade(self): - self.connected = 1 - - def connectionLost(self, reason): - if self._pendingSend.active(): - self._pendingSend.cancel() - self._pendingSend = None - if self.bytesSent == self.fileSize: - self.completed = 1 - self.connected = 0 - self.file.close() - - def lineReceived(self, line): - temp = line.split() - if len(temp) == 1: - params = [] - else: - params = temp[1:] - cmd = temp[0] - handler = getattr(self, "handle_%s" % cmd.upper(), None) - if handler: - handler(params) - else: - self.handle_UNKNOWN(cmd, params) - - def handle_VER(self, params): - checkParamLen(len(params), 1, 'VER') - if params[0].upper() == "MSNFTP": - self.sendLine("VER MSNFTP") - else: # they sent some weird version during negotiation, i'm quitting. - self.transport.loseConnection() - - def handle_USR(self, params): - checkParamLen(len(params), 2, 'USR') - self.targetUser = params[0] - if self.auth == int(params[1]): - self.sendLine("FIL %s" % (self.fileSize)) - else: # they failed the auth test, disconnecting. - self.transport.loseConnection() - - def handle_TFR(self, params): - checkParamLen(len(params), 0, 'TFR') - # they are ready for me to start sending - self.sendPart() - - def handle_BYE(self, params): - self.completed = (self.bytesSent == self.fileSize) - self.transport.loseConnection() - - def handle_CCL(self, params): - self.completed = (self.bytesSent == self.fileSize) - self.transport.loseConnection() - - def handle_UNKNOWN(self, cmd, params): - log.msg('received unknown command (%s), params: %s' % (cmd, params)) - - def makeHeader(self, size): - """ make the appropriate header given a specific segment size. """ - quotient, remainder = divmod(size, 256) - return chr(0) + chr(remainder) + chr(quotient) - - def sendPart(self): - """ send a segment of data """ - if not self.connected: - self._pendingSend = None - return # may be buggy (if handle_CCL/BYE is called but self.connected is still 1) - data = self.file.read(self.segmentSize) - if data: - dataSize = len(data) - header = self.makeHeader(dataSize) - self.bytesSent += dataSize - self.transport.write(header + data) - self._pendingSend = reactor.callLater(0, self.sendPart) - else: - self._pendingSend = None - self.completed = 1 - -# mapping of error codes to error messages -errorCodes = { - - 200 : "Syntax error", - 201 : "Invalid parameter", - 205 : "Invalid user", - 206 : "Domain name missing", - 207 : "Already logged in", - 208 : "Invalid username", - 209 : "Invalid screen name", - 210 : "User list full", - 215 : "User already there", - 216 : "User already on list", - 217 : "User not online", - 218 : "Already in mode", - 219 : "User is in the opposite list", - 223 : "Too many groups", - 224 : "Invalid group", - 225 : "User not in group", - 229 : "Group name too long", - 230 : "Cannot remove group 0", - 231 : "Invalid group", - 280 : "Switchboard failed", - 281 : "Transfer to switchboard failed", - - 300 : "Required field missing", - 301 : "Too many FND responses", - 302 : "Not logged in", - - 500 : "Internal server error", - 501 : "Database server error", - 502 : "Command disabled", - 510 : "File operation failed", - 520 : "Memory allocation failed", - 540 : "Wrong CHL value sent to server", - - 600 : "Server is busy", - 601 : "Server is unavaliable", - 602 : "Peer nameserver is down", - 603 : "Database connection failed", - 604 : "Server is going down", - 605 : "Server unavailable", - - 707 : "Could not create connection", - 710 : "Invalid CVR parameters", - 711 : "Write is blocking", - 712 : "Session is overloaded", - 713 : "Too many active users", - 714 : "Too many sessions", - 715 : "Not expected", - 717 : "Bad friend file", - 731 : "Not expected", - - 800 : "Requests too rapid", - - 910 : "Server too busy", - 911 : "Authentication failed", - 912 : "Server too busy", - 913 : "Not allowed when offline", - 914 : "Server too busy", - 915 : "Server too busy", - 916 : "Server too busy", - 917 : "Server too busy", - 918 : "Server too busy", - 919 : "Server too busy", - 920 : "Not accepting new users", - 921 : "Server too busy", - 922 : "Server too busy", - 923 : "No parent consent", - 924 : "Passport account not yet verified" - -} - -# mapping of status codes to readable status format -statusCodes = { - - STATUS_ONLINE : "Online", - STATUS_OFFLINE : "Offline", - STATUS_HIDDEN : "Appear Offline", - STATUS_IDLE : "Idle", - STATUS_AWAY : "Away", - STATUS_BUSY : "Busy", - STATUS_BRB : "Be Right Back", - STATUS_PHONE : "On the Phone", - STATUS_LUNCH : "Out to Lunch" - -} - -# mapping of list ids to list codes -listIDToCode = { - - FORWARD_LIST : 'fl', - BLOCK_LIST : 'bl', - ALLOW_LIST : 'al', - REVERSE_LIST : 'rl' - -} - -# mapping of list codes to list ids -listCodeToID = {} -for id,code in listIDToCode.items(): - listCodeToID[code] = id - -del id, code - -# Mapping of class GUIDs to simple english names -guidToClassName = { - "{5D3E02AB-6190-11d3-BBBB-00C04F795683}": "file transfer", - } - -# Reverse of the above -classNameToGUID = {} -for guid, name in guidToClassName.iteritems(): - classNameToGUID[name] = guid diff --git a/tools/buildbot/pylibs/twisted/words/protocols/oscar.py b/tools/buildbot/pylibs/twisted/words/protocols/oscar.py deleted file mode 100644 index 9298777..0000000 --- a/tools/buildbot/pylibs/twisted/words/protocols/oscar.py +++ /dev/null @@ -1,1238 +0,0 @@ -# -*- test-case-name: twisted.words.test -*- -# Copyright (c) 2001-2005 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -An implementation of the OSCAR protocol, which AIM and ICQ use to communcate. - -Maintainer: U{Paul Swartz} -""" - -from __future__ import nested_scopes - -from twisted.internet import reactor, defer, protocol -from twisted.python import log - -import struct -import md5 -import string -import socket -import random -import time -import types -import re - -def logPacketData(data): - lines = len(data)/16 - if lines*16 != len(data): lines=lines+1 - for i in range(lines): - d = tuple(data[16*i:16*i+16]) - hex = map(lambda x: "%02X"%ord(x),d) - text = map(lambda x: (len(repr(x))>3 and '.') or x, d) - log.msg(' '.join(hex)+ ' '*3*(16-len(d)) +''.join(text)) - log.msg('') - -def SNAC(fam,sub,id,data,flags=[0,0]): - header="!HHBBL" - head=struct.pack(header,fam,sub, - flags[0],flags[1], - id) - return head+str(data) - -def readSNAC(data): - header="!HHBBL" - head=list(struct.unpack(header,data[:10])) - return head+[data[10:]] - -def TLV(type,value): - header="!HH" - head=struct.pack(header,type,len(value)) - return head+str(value) - -def readTLVs(data,count=None): - header="!HH" - dict={} - while data and len(dict)!=count: - head=struct.unpack(header,data[:4]) - dict[head[0]]=data[4:4+head[1]] - data=data[4+head[1]:] - if not count: - return dict - return dict,data - -def encryptPasswordMD5(password,key): - m=md5.new() - m.update(key) - m.update(md5.new(password).digest()) - m.update("AOL Instant Messenger (SM)") - return m.digest() - -def encryptPasswordICQ(password): - key=[0xF3,0x26,0x81,0xC4,0x39,0x86,0xDB,0x92,0x71,0xA3,0xB9,0xE6,0x53,0x7A,0x95,0x7C] - bytes=map(ord,password) - r="" - for i in range(len(bytes)): - r=r+chr(bytes[i]^key[i%len(key)]) - return r - -def dehtml(text): - text=string.replace(text,"
                    ","\n") - text=string.replace(text,"
                    ","\n") - text=string.replace(text,"
                    ","\n") # XXX make this a regexp - text=string.replace(text,"
                    ","\n") - text=re.sub('<.*?>','',text) - text=string.replace(text,'>','>') - text=string.replace(text,'<','<') - text=string.replace(text,' ',' ') - text=string.replace(text,'"','"') - text=string.replace(text,'&','&') - return text - -def html(text): - text=string.replace(text,'"','"') - text=string.replace(text,'&','&') - text=string.replace(text,'<','<') - text=string.replace(text,'>','>') - text=string.replace(text,"\n","
                    ") - return '%s'%text - -class OSCARUser: - def __init__(self, name, warn, tlvs): - self.name = name - self.warning = warn - self.flags = [] - self.caps = [] - for k,v in tlvs.items(): - if k == 1: # user flags - v=struct.unpack('!H',v)[0] - for o, f in [(1,'trial'), - (2,'unknown bit 2'), - (4,'aol'), - (8,'unknown bit 4'), - (16,'aim'), - (32,'away'), - (1024,'activebuddy')]: - if v&o: self.flags.append(f) - elif k == 2: # member since date - self.memberSince = struct.unpack('!L',v)[0] - elif k == 3: # on-since - self.onSince = struct.unpack('!L',v)[0] - elif k == 4: # idle time - self.idleTime = struct.unpack('!H',v)[0] - elif k == 5: # unknown - pass - elif k == 6: # icq online status - if v[2] == '\x00': - self.icqStatus = 'online' - elif v[2] == '\x01': - self.icqStatus = 'away' - elif v[2] == '\x02': - self.icqStatus = 'dnd' - elif v[2] == '\x04': - self.icqStatus = 'out' - elif v[2] == '\x10': - self.icqStatus = 'busy' - else: - self.icqStatus = 'unknown' - elif k == 10: # icq ip address - self.icqIPaddy = socket.inet_ntoa(v) - elif k == 12: # icq random stuff - self.icqRandom = v - elif k == 13: # capabilities - caps=[] - while v: - c=v[:16] - if c==CAP_ICON: caps.append("icon") - elif c==CAP_IMAGE: caps.append("image") - elif c==CAP_VOICE: caps.append("voice") - elif c==CAP_CHAT: caps.append("chat") - elif c==CAP_GET_FILE: caps.append("getfile") - elif c==CAP_SEND_FILE: caps.append("sendfile") - elif c==CAP_SEND_LIST: caps.append("sendlist") - elif c==CAP_GAMES: caps.append("games") - else: caps.append(("unknown",c)) - v=v[16:] - caps.sort() - self.caps=caps - elif k == 14: pass - elif k == 15: # session length (aim) - self.sessionLength = struct.unpack('!L',v)[0] - elif k == 16: # session length (aol) - self.sessionLength = struct.unpack('!L',v)[0] - elif k == 30: # no idea - pass - else: - log.msg("unknown tlv for user %s\nt: %s\nv: %s"%(self.name,k,repr(v))) - - def __str__(self): - s = '' - return s - - -class SSIGroup: - def __init__(self, name, tlvs = {}): - self.name = name - #self.tlvs = [] - #self.userIDs = [] - self.usersToID = {} - self.users = [] - #if not tlvs.has_key(0xC8): return - #buddyIDs = tlvs[0xC8] - #while buddyIDs: - # bid = struct.unpack('!H',buddyIDs[:2])[0] - # buddyIDs = buddyIDs[2:] - # self.users.append(bid) - - def findIDFor(self, user): - return self.usersToID[user] - - def addUser(self, buddyID, user): - self.usersToID[user] = buddyID - self.users.append(user) - user.group = self - - def oscarRep(self, groupID, buddyID): - tlvData = TLV(0xc8, reduce(lambda x,y:x+y, [struct.pack('!H',self.usersToID[x]) for x in self.users])) - return struct.pack('!H', len(self.name)) + self.name + \ - struct.pack('!HH', groupID, buddyID) + '\000\001' + tlvData - - -class SSIBuddy: - def __init__(self, name, tlvs = {}): - self.name = name - self.tlvs = tlvs - for k,v in tlvs.items(): - if k == 0x013c: # buddy comment - self.buddyComment = v - elif k == 0x013d: # buddy alerts - actionFlag = ord(v[0]) - whenFlag = ord(v[1]) - self.alertActions = [] - self.alertWhen = [] - if actionFlag&1: - self.alertActions.append('popup') - if actionFlag&2: - self.alertActions.append('sound') - if whenFlag&1: - self.alertWhen.append('online') - if whenFlag&2: - self.alertWhen.append('unidle') - if whenFlag&4: - self.alertWhen.append('unaway') - elif k == 0x013e: - self.alertSound = v - - def oscarRep(self, groupID, buddyID): - tlvData = reduce(lambda x,y: x+y, map(lambda (k,v):TLV(k,v), self.tlvs.items()), '\000\000') - return struct.pack('!H', len(self.name)) + self.name + \ - struct.pack('!HH', groupID, buddyID) + '\000\000' + tlvData - - -class OscarConnection(protocol.Protocol): - def connectionMade(self): - self.state="" - self.seqnum=0 - self.buf='' - self.stopKeepAliveID = None - self.setKeepAlive(4*60) # 4 minutes - - def connectionLost(self, reason): - log.msg("Connection Lost! %s" % self) - self.stopKeepAlive() - -# def connectionFailed(self): -# log.msg("Connection Failed! %s" % self) -# self.stopKeepAlive() - - def sendFLAP(self,data,channel = 0x02): - header="!cBHH" - self.seqnum=(self.seqnum+1)%0xFFFF - seqnum=self.seqnum - head=struct.pack(header,'*', channel, - seqnum, len(data)) - self.transport.write(head+str(data)) -# if isinstance(self, ChatService): -# logPacketData(head+str(data)) - - def readFlap(self): - header="!cBHH" - if len(self.buf)<6: return - flap=struct.unpack(header,self.buf[:6]) - if len(self.buf)<6+flap[3]: return - data,self.buf=self.buf[6:6+flap[3]],self.buf[6+flap[3]:] - return [flap[1],data] - - def dataReceived(self,data): -# if isinstance(self, ChatService): -# logPacketData(data) - self.buf=self.buf+data - flap=self.readFlap() - while flap: - func=getattr(self,"oscar_%s"%self.state,None) - if not func: - log.msg("no func for state: %s" % self.state) - state=func(flap) - if state: - self.state=state - flap=self.readFlap() - - def setKeepAlive(self,t): - self.keepAliveDelay=t - self.stopKeepAlive() - self.stopKeepAliveID = reactor.callLater(t, self.sendKeepAlive) - - def sendKeepAlive(self): - self.sendFLAP("",0x05) - self.stopKeepAliveID = reactor.callLater(self.keepAliveDelay, self.sendKeepAlive) - - def stopKeepAlive(self): - if self.stopKeepAliveID: - self.stopKeepAliveID.cancel() - self.stopKeepAliveID = None - - def disconnect(self): - """ - send the disconnect flap, and sever the connection - """ - self.sendFLAP('', 0x04) - def f(reason): pass - self.connectionLost = f - self.transport.loseConnection() - - -class SNACBased(OscarConnection): - snacFamilies = { - # family : (version, toolID, toolVersion) - } - def __init__(self,cookie): - self.cookie=cookie - self.lastID=0 - self.supportedFamilies = () - self.requestCallbacks={} # request id:Deferred - - def sendSNAC(self,fam,sub,data,flags=[0,0]): - """ - send a snac and wait for the response by returning a Deferred. - """ - reqid=self.lastID - self.lastID=reqid+1 - d = defer.Deferred() - d.reqid = reqid - - #d.addErrback(self._ebDeferredError,fam,sub,data) # XXX for testing - - self.requestCallbacks[reqid] = d - self.sendFLAP(SNAC(fam,sub,reqid,data)) - return d - - def _ebDeferredError(self, error, fam, sub, data): - log.msg('ERROR IN DEFERRED %s' % error) - log.msg('on sending of message, family 0x%02x, subtype 0x%02x' % (fam, sub)) - log.msg('data: %s' % repr(data)) - - def sendSNACnr(self,fam,sub,data,flags=[0,0]): - """ - send a snac, but don't bother adding a deferred, we don't care. - """ - self.sendFLAP(SNAC(fam,sub,0x10000*fam+sub,data)) - - def oscar_(self,data): - self.sendFLAP("\000\000\000\001"+TLV(6,self.cookie), 0x01) - return "Data" - - def oscar_Data(self,data): - snac=readSNAC(data[1]) - if self.requestCallbacks.has_key(snac[4]): - d = self.requestCallbacks[snac[4]] - del self.requestCallbacks[snac[4]] - if snac[1]!=1: - d.callback(snac) - else: - d.errback(snac) - return - func=getattr(self,'oscar_%02X_%02X'%(snac[0],snac[1]),None) - if not func: - self.oscar_unknown(snac) - else: - func(snac[2:]) - return "Data" - - def oscar_unknown(self,snac): - log.msg("unknown for %s" % self) - log.msg(snac) - - - def oscar_01_03(self, snac): - numFamilies = len(snac[3])/2 - self.supportedFamilies = struct.unpack("!"+str(numFamilies)+'H', snac[3]) - d = '' - for fam in self.supportedFamilies: - if self.snacFamilies.has_key(fam): - d=d+struct.pack('!2H',fam,self.snacFamilies[fam][0]) - self.sendSNACnr(0x01,0x17, d) - - def oscar_01_0A(self,snac): - """ - change of rate information. - """ - # this can be parsed, maybe we can even work it in - pass - - def oscar_01_18(self,snac): - """ - host versions, in the same format as we sent - """ - self.sendSNACnr(0x01,0x06,"") #pass - - def clientReady(self): - """ - called when the client is ready to be online - """ - d = '' - for fam in self.supportedFamilies: - if self.snacFamilies.has_key(fam): - version, toolID, toolVersion = self.snacFamilies[fam] - d = d + struct.pack('!4H',fam,version,toolID,toolVersion) - self.sendSNACnr(0x01,0x02,d) - -class BOSConnection(SNACBased): - snacFamilies = { - 0x01:(3, 0x0110, 0x059b), - 0x13:(3, 0x0110, 0x059b), - 0x02:(1, 0x0110, 0x059b), - 0x03:(1, 0x0110, 0x059b), - 0x04:(1, 0x0110, 0x059b), - 0x06:(1, 0x0110, 0x059b), - 0x08:(1, 0x0104, 0x0001), - 0x09:(1, 0x0110, 0x059b), - 0x0a:(1, 0x0110, 0x059b), - 0x0b:(1, 0x0104, 0x0001), - 0x0c:(1, 0x0104, 0x0001) - } - - capabilities = None - - def __init__(self,username,cookie): - SNACBased.__init__(self,cookie) - self.username=username - self.profile = None - self.awayMessage = None - self.services = {} - - if not self.capabilities: - self.capabilities = [CAP_CHAT] - - def parseUser(self,data,count=None): - l=ord(data[0]) - name=data[1:1+l] - warn,foo=struct.unpack("!HH",data[1+l:5+l]) - warn=int(warn/10) - tlvs=data[5+l:] - if count: - tlvs,rest = readTLVs(tlvs,foo) - else: - tlvs,rest = readTLVs(tlvs), None - u = OSCARUser(name, warn, tlvs) - if rest == None: - return u - else: - return u, rest - - def oscar_01_05(self, snac, d = None): - """ - data for a new service connection - d might be a deferred to be called back when the service is ready - """ - tlvs = readTLVs(snac[3][2:]) - service = struct.unpack('!H',tlvs[0x0d])[0] - ip = tlvs[5] - cookie = tlvs[6] - #c = serviceClasses[service](self, cookie, d) - c = protocol.ClientCreator(reactor, serviceClasses[service], self, cookie, d) - def addService(x): - self.services[service] = x - c.connectTCP(ip, 5190).addCallback(addService) - #self.services[service] = c - - def oscar_01_07(self,snac): - """ - rate paramaters - """ - self.sendSNACnr(0x01,0x08,"\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05") # ack - self.initDone() - self.sendSNACnr(0x13,0x02,'') # SSI rights info - self.sendSNACnr(0x02,0x02,'') # location rights info - self.sendSNACnr(0x03,0x02,'') # buddy list rights - self.sendSNACnr(0x04,0x04,'') # ICBM parms - self.sendSNACnr(0x09,0x02,'') # BOS rights - - def oscar_01_10(self,snac): - """ - we've been warned - """ - skip = struct.unpack('!H',snac[3][:2])[0] - newLevel = struct.unpack('!H',snac[3][2+skip:4+skip])[0]/10 - if len(snac[3])>4+skip: - by = self.parseUser(snac[3][4+skip:]) - else: - by = None - self.receiveWarning(newLevel, by) - - def oscar_01_13(self,snac): - """ - MOTD - """ - pass # we don't care for now - - def oscar_02_03(self, snac): - """ - location rights response - """ - tlvs = readTLVs(snac[3]) - self.maxProfileLength = tlvs[1] - - def oscar_03_03(self, snac): - """ - buddy list rights response - """ - tlvs = readTLVs(snac[3]) - self.maxBuddies = tlvs[1] - self.maxWatchers = tlvs[2] - - def oscar_03_0B(self, snac): - """ - buddy update - """ - self.updateBuddy(self.parseUser(snac[3])) - - def oscar_03_0C(self, snac): - """ - buddy offline - """ - self.offlineBuddy(self.parseUser(snac[3])) - -# def oscar_04_03(self, snac): - - def oscar_04_05(self, snac): - """ - ICBM parms response - """ - self.sendSNACnr(0x04,0x02,'\x00\x00\x00\x00\x00\x0b\x1f@\x03\xe7\x03\xe7\x00\x00\x00\x00') # IM rights - - def oscar_04_07(self, snac): - """ - ICBM message (instant message) - """ - data = snac[3] - cookie, data = data[:8], data[8:] - channel = struct.unpack('!H',data[:2])[0] - data = data[2:] - user, data = self.parseUser(data, 1) - tlvs = readTLVs(data) - if channel == 1: # message - flags = [] - multiparts = [] - for k, v in tlvs.items(): - if k == 2: - while v: - v = v[2:] # skip bad data - messageLength, charSet, charSubSet = struct.unpack('!3H', v[:6]) - messageLength -= 4 - message = [v[6:6+messageLength]] - if charSet == 0: - pass # don't add anything special - elif charSet == 2: - message.append('unicode') - elif charSet == 3: - message.append('iso-8859-1') - elif charSet == 0xffff: - message.append('none') - if charSubSet == 0xb: - message.append('macintosh') - if messageLength > 0: multiparts.append(tuple(message)) - v = v[6+messageLength:] - elif k == 3: - flags.append('acknowledge') - elif k == 4: - flags.append('auto') - elif k == 6: - flags.append('offline') - elif k == 8: - iconLength, foo, iconSum, iconStamp = struct.unpack('!LHHL',v) - if iconLength: - flags.append('icon') - flags.append((iconLength, iconSum, iconStamp)) - elif k == 9: - flags.append('buddyrequest') - elif k == 0xb: # unknown - pass - elif k == 0x17: - flags.append('extradata') - flags.append(v) - else: - log.msg('unknown TLV for incoming IM, %04x, %s' % (k,repr(v))) - -# unknown tlv for user SNewdorf -# t: 29 -# v: '\x00\x00\x00\x05\x02\x01\xd2\x04r\x00\x01\x01\x10/\x8c\x8b\x8a\x1e\x94*\xbc\x80}\x8d\xc4;\x1dEM' -# XXX what is this? - self.receiveMessage(user, multiparts, flags) - elif channel == 2: # rondevouz - status = struct.unpack('!H',tlvs[5][:2])[0] - requestClass = tlvs[5][10:26] - moreTLVs = readTLVs(tlvs[5][26:]) - if requestClass == CAP_CHAT: # a chat request - exchange = struct.unpack('!H',moreTLVs[10001][:2])[0] - name = moreTLVs[10001][3:-2] - instance = struct.unpack('!H',moreTLVs[10001][-2:])[0] - if not self.services.has_key(SERVICE_CHATNAV): - self.connectService(SERVICE_CHATNAV,1).addCallback(lambda x: self.services[SERVICE_CHATNAV].getChatInfo(exchange, name, instance).\ - addCallback(self._cbGetChatInfoForInvite, user, moreTLVs[12])) - else: - self.services[SERVICE_CHATNAV].getChatInfo(exchange, name, instance).\ - addCallback(self._cbGetChatInfoForInvite, user, moreTLVs[12]) - elif requestClass == CAP_SEND_FILE: - if moreTLVs.has_key(11): # cancel - log.msg('cancelled file request') - log.msg(status) - return # handle this later - name = moreTLVs[10001][9:-7] - desc = moreTLVs[12] - log.msg('file request from %s, %s, %s' % (user, name, desc)) - self.receiveSendFileRequest(user, name, desc, cookie) - else: - log.msg('unsupported rondevouz: %s' % requestClass) - log.msg(repr(moreTLVs)) - else: - log.msg('unknown channel %02x' % channel) - log.msg(tlvs) - - def _cbGetChatInfoForInvite(self, info, user, message): - apply(self.receiveChatInvite, (user,message)+info) - - def oscar_09_03(self, snac): - """ - BOS rights response - """ - tlvs = readTLVs(snac[3]) - self.maxPermitList = tlvs[1] - self.maxDenyList = tlvs[2] - - def oscar_0B_02(self, snac): - """ - stats reporting interval - """ - self.reportingInterval = struct.unpack('!H',snac[3][:2])[0] - - def oscar_13_03(self, snac): - """ - SSI rights response - """ - #tlvs = readTLVs(snac[3]) - pass # we don't know how to parse this - - # methods to be called by the client, and their support methods - def requestSelfInfo(self): - """ - ask for the OSCARUser for ourselves - """ - d = defer.Deferred() - self.sendSNAC(0x01, 0x0E, '').addCallback(self._cbRequestSelfInfo, d) - return d - - def _cbRequestSelfInfo(self, snac, d): - d.callback(self.parseUser(snac[5])) - - def initSSI(self): - """ - this sends the rate request for family 0x13 (Server Side Information) - so we can then use it - """ - return self.sendSNAC(0x13, 0x02, '').addCallback(self._cbInitSSI) - - def _cbInitSSI(self, snac, d): - return {} # don't even bother parsing this - - def requestSSI(self, timestamp = 0, revision = 0): - """ - request the server side information - if the deferred gets None, it means the SSI is the same - """ - return self.sendSNAC(0x13, 0x05, - struct.pack('!LH',timestamp,revision)).addCallback(self._cbRequestSSI) - - def _cbRequestSSI(self, snac, args = ()): - if snac[1] == 0x0f: # same SSI as we have - return - itemdata = snac[5][3:] - if args: - revision, groups, permit, deny, permitMode, visibility = args - else: - version, revision = struct.unpack('!BH', snac[5][:3]) - groups = {} - permit = [] - deny = [] - permitMode = None - visibility = None - while len(itemdata)>4: - nameLength = struct.unpack('!H', itemdata[:2])[0] - name = itemdata[2:2+nameLength] - groupID, buddyID, itemType, restLength = \ - struct.unpack('!4H', itemdata[2+nameLength:10+nameLength]) - tlvs = readTLVs(itemdata[10+nameLength:10+nameLength+restLength]) - itemdata = itemdata[10+nameLength+restLength:] - if itemType == 0: # buddies - groups[groupID].addUser(buddyID, SSIBuddy(name, tlvs)) - elif itemType == 1: # group - g = SSIGroup(name, tlvs) - if groups.has_key(0): groups[0].addUser(groupID, g) - groups[groupID] = g - elif itemType == 2: # permit - permit.append(name) - elif itemType == 3: # deny - deny.append(name) - elif itemType == 4: # permit deny info - if not tlvs.has_key(0xcb): - continue # this happens with ICQ - permitMode = {1:'permitall',2:'denyall',3:'permitsome',4:'denysome',5:'permitbuddies'}[ord(tlvs[0xca])] - visibility = {'\xff\xff\xff\xff':'all','\x00\x00\x00\x04':'notaim'}[tlvs[0xcb]] - elif itemType == 5: # unknown (perhaps idle data)? - pass - else: - log.msg('%s %s %s %s %s' % (name, groupID, buddyID, itemType, tlvs)) - timestamp = struct.unpack('!L',itemdata)[0] - if not timestamp: # we've got more packets coming - # which means add some deferred stuff - d = defer.Deferred() - self.requestCallbacks[snac[4]] = d - d.addCallback(self._cbRequestSSI, (revision, groups, permit, deny, permitMode, visibility)) - return d - return (groups[0].users,permit,deny,permitMode,visibility,timestamp,revision) - - def activateSSI(self): - """ - active the data stored on the server (use buddy list, permit deny settings, etc.) - """ - self.sendSNACnr(0x13,0x07,'') - - def startModifySSI(self): - """ - tell the OSCAR server to be on the lookout for SSI modifications - """ - self.sendSNACnr(0x13,0x11,'') - - def addItemSSI(self, item, groupID = None, buddyID = None): - """ - add an item to the SSI server. if buddyID == 0, then this should be a group. - this gets a callback when it's finished, but you can probably ignore it. - """ - if groupID is None: - if isinstance(item, SSIGroup): - groupID = 0 - else: - groupID = item.group.group.findIDFor(item.group) - if buddyID is None: - buddyID = item.group.findIDFor(item) - return self.sendSNAC(0x13,0x08, item.oscarRep(groupID, buddyID)) - - def modifyItemSSI(self, item, groupID = None, buddyID = None): - if groupID is None: - if isinstance(item, SSIGroup): - groupID = 0 - else: - groupID = item.group.group.findIDFor(item.group) - if buddyID is None: - buddyID = item.group.findIDFor(item) - return self.sendSNAC(0x13,0x09, item.oscarRep(groupID, buddyID)) - - def delItemSSI(self, item, groupID = None, buddyID = None): - if groupID is None: - if isinstance(item, SSIGroup): - groupID = 0 - else: - groupID = item.group.group.findIDFor(item.group) - if buddyID is None: - buddyID = item.group.findIDFor(item) - return self.sendSNAC(0x13,0x0A, item.oscarRep(groupID, buddyID)) - - def endModifySSI(self): - self.sendSNACnr(0x13,0x12,'') - - def setProfile(self, profile): - """ - set the profile. - send None to not set a profile (different from '' for a blank one) - """ - self.profile = profile - tlvs = '' - if self.profile is not None: - tlvs = TLV(1,'text/aolrtf; charset="us-ascii"') + \ - TLV(2,self.profile) - - tlvs = tlvs + TLV(5, ''.join(self.capabilities)) - self.sendSNACnr(0x02, 0x04, tlvs) - - def setAway(self, away = None): - """ - set the away message, or return (if away == None) - """ - self.awayMessage = away - tlvs = TLV(3,'text/aolrtf; charset="us-ascii"') + \ - TLV(4,away or '') - self.sendSNACnr(0x02, 0x04, tlvs) - - def setIdleTime(self, idleTime): - """ - set our idle time. don't call more than once with a non-0 idle time. - """ - self.sendSNACnr(0x01, 0x11, struct.pack('!L',idleTime)) - - def sendMessage(self, user, message, wantAck = 0, autoResponse = 0, offline = 0 ): \ - #haveIcon = 0, ): - """ - send a message to user (not an OSCARUseR). - message can be a string, or a multipart tuple. - if wantAck, we return a Deferred that gets a callback when the message is sent. - if autoResponse, this message is an autoResponse, as if from an away message. - if offline, this is an offline message (ICQ only, I think) - """ - data = ''.join([chr(random.randrange(0, 127)) for i in range(8)]) # cookie - data = data + '\x00\x01' + chr(len(user)) + user - if not type(message) in (types.TupleType, types.ListType): - message = [[message,]] - if type(message[0][0]) == types.UnicodeType: - message[0].append('unicode') - messageData = '' - for part in message: - charSet = 0 - if 'unicode' in part[1:]: - charSet = 2 - part[0] = part[0].encode('utf-8') - elif 'iso-8859-1' in part[1:]: - charSet = 3 - part[0] = part[0].encode('iso-8859-1') - elif 'none' in part[1:]: - charSet = 0xffff - if 'macintosh' in part[1:]: - charSubSet = 0xb - else: - charSubSet = 0 - messageData = messageData + '\x01\x01' + \ - struct.pack('!3H',len(part[0])+4,charSet,charSubSet) - messageData = messageData + part[0] - data = data + TLV(2, '\x05\x01\x00\x03\x01\x01\x02'+messageData) - if wantAck: - data = data + TLV(3,'') - if autoResponse: - data = data + TLV(4,'') - if offline: - data = data + TLV(6,'') - if wantAck: - return self.sendSNAC(0x04, 0x06, data).addCallback(self._cbSendMessageAck, user, message) - self.sendSNACnr(0x04, 0x06, data) - - def _cbSendMessageAck(self, snac, user, message): - return user, message - - def connectService(self, service, wantCallback = 0, extraData = ''): - """ - connect to another service - if wantCallback, we return a Deferred that gets called back when the service is online. - if extraData, append that to our request. - """ - if wantCallback: - d = defer.Deferred() - self.sendSNAC(0x01,0x04,struct.pack('!H',service) + extraData).addCallback(self._cbConnectService, d) - return d - else: - self.sendSNACnr(0x01,0x04,struct.pack('!H',service)) - - def _cbConnectService(self, snac, d): - self.oscar_01_05(snac[2:], d) - - def createChat(self, shortName): - """ - create a chat room - """ - if self.services.has_key(SERVICE_CHATNAV): - return self.services[SERVICE_CHATNAV].createChat(shortName) - else: - return self.connectService(SERVICE_CHATNAV,1).addCallback(lambda s: s.createChat(shortName)) - - - def joinChat(self, exchange, fullName, instance): - """ - join a chat room - """ - #d = defer.Deferred() - return self.connectService(0x0e, 1, TLV(0x01, struct.pack('!HB',exchange, len(fullName)) + fullName + - struct.pack('!H', instance))).addCallback(self._cbJoinChat) #, d) - #return d - - def _cbJoinChat(self, chat): - del self.services[SERVICE_CHAT] - return chat - - def warnUser(self, user, anon = 0): - return self.sendSNAC(0x04, 0x08, '\x00'+chr(anon)+chr(len(user))+user).addCallback(self._cbWarnUser) - - def _cbWarnUser(self, snac): - oldLevel, newLevel = struct.unpack('!2H', snac[5]) - return oldLevel, newLevel - - def getInfo(self, user): - #if user. - return self.sendSNAC(0x02, 0x05, '\x00\x01'+chr(len(user))+user).addCallback(self._cbGetInfo) - - def _cbGetInfo(self, snac): - user, rest = self.parseUser(snac[5],1) - tlvs = readTLVs(rest) - return tlvs.get(0x02,None) - - def getAway(self, user): - return self.sendSNAC(0x02, 0x05, '\x00\x03'+chr(len(user))+user).addCallback(self._cbGetAway) - - def _cbGetAway(self, snac): - user, rest = self.parseUser(snac[5],1) - tlvs = readTLVs(rest) - return tlvs.get(0x04,None) # return None if there is no away message - - #def acceptSendFileRequest(self, - - # methods to be overriden by the client - def initDone(self): - """ - called when we get the rate information, which means we should do other init. stuff. - """ - log.msg('%s initDone' % self) - pass - - def updateBuddy(self, user): - """ - called when a buddy changes status, with the OSCARUser for that buddy. - """ - log.msg('%s updateBuddy %s' % (self, user)) - pass - - def offlineBuddy(self, user): - """ - called when a buddy goes offline - """ - log.msg('%s offlineBuddy %s' % (self, user)) - pass - - def receiveMessage(self, user, multiparts, flags): - """ - called when someone sends us a message - """ - pass - - def receiveWarning(self, newLevel, user): - """ - called when someone warns us. - user is either None (if it was anonymous) or an OSCARUser - """ - pass - - def receiveChatInvite(self, user, message, exchange, fullName, instance, shortName, inviteTime): - """ - called when someone invites us to a chat room - """ - pass - - def chatReceiveMessage(self, chat, user, message): - """ - called when someone in a chatroom sends us a message in the chat - """ - pass - - def chatMemberJoined(self, chat, member): - """ - called when a member joins the chat - """ - pass - - def chatMemberLeft(self, chat, member): - """ - called when a member leaves the chat - """ - pass - - def receiveSendFileRequest(self, user, file, description, cookie): - """ - called when someone tries to send a file to us - """ - pass - -class OSCARService(SNACBased): - def __init__(self, bos, cookie, d = None): - SNACBased.__init__(self, cookie) - self.bos = bos - self.d = d - - def connectionLost(self, reason): - for k,v in self.bos.services.items(): - if v == self: - del self.bos.services[k] - return - - def clientReady(self): - SNACBased.clientReady(self) - if self.d: - self.d.callback(self) - self.d = None - -class ChatNavService(OSCARService): - snacFamilies = { - 0x01:(3, 0x0010, 0x059b), - 0x0d:(1, 0x0010, 0x059b) - } - def oscar_01_07(self, snac): - # rate info - self.sendSNACnr(0x01, 0x08, '\000\001\000\002\000\003\000\004\000\005') - self.sendSNACnr(0x0d, 0x02, '') - - def oscar_0D_09(self, snac): - self.clientReady() - - def getChatInfo(self, exchange, name, instance): - d = defer.Deferred() - self.sendSNAC(0x0d,0x04,struct.pack('!HB',exchange,len(name)) + \ - name + struct.pack('!HB',instance,2)). \ - addCallback(self._cbGetChatInfo, d) - return d - - def _cbGetChatInfo(self, snac, d): - data = snac[5][4:] - exchange, length = struct.unpack('!HB',data[:3]) - fullName = data[3:3+length] - instance = struct.unpack('!H',data[3+length:5+length])[0] - tlvs = readTLVs(data[8+length:]) - shortName = tlvs[0x6a] - inviteTime = struct.unpack('!L',tlvs[0xca])[0] - info = (exchange,fullName,instance,shortName,inviteTime) - d.callback(info) - - def createChat(self, shortName): - #d = defer.Deferred() - data = '\x00\x04\x06create\xff\xff\x01\x00\x03' - data = data + TLV(0xd7, 'en') - data = data + TLV(0xd6, 'us-ascii') - data = data + TLV(0xd3, shortName) - return self.sendSNAC(0x0d, 0x08, data).addCallback(self._cbCreateChat) - #return d - - def _cbCreateChat(self, snac): #d): - exchange, length = struct.unpack('!HB',snac[5][4:7]) - fullName = snac[5][7:7+length] - instance = struct.unpack('!H',snac[5][7+length:9+length])[0] - #d.callback((exchange, fullName, instance)) - return exchange, fullName, instance - -class ChatService(OSCARService): - snacFamilies = { - 0x01:(3, 0x0010, 0x059b), - 0x0E:(1, 0x0010, 0x059b) - } - def __init__(self,bos,cookie, d = None): - OSCARService.__init__(self,bos,cookie,d) - self.exchange = None - self.fullName = None - self.instance = None - self.name = None - self.members = None - - clientReady = SNACBased.clientReady # we'll do our own callback - - def oscar_01_07(self,snac): - self.sendSNAC(0x01,0x08,"\000\001\000\002\000\003\000\004\000\005") - self.clientReady() - - def oscar_0E_02(self, snac): -# try: # this is EVIL -# data = snac[3][4:] -# self.exchange, length = struct.unpack('!HB',data[:3]) -# self.fullName = data[3:3+length] -# self.instance = struct.unpack('!H',data[3+length:5+length])[0] -# tlvs = readTLVs(data[8+length:]) -# self.name = tlvs[0xd3] -# self.d.callback(self) -# except KeyError: - data = snac[3] - self.exchange, length = struct.unpack('!HB',data[:3]) - self.fullName = data[3:3+length] - self.instance = struct.unpack('!H',data[3+length:5+length])[0] - tlvs = readTLVs(data[8+length:]) - self.name = tlvs[0xd3] - self.d.callback(self) - - def oscar_0E_03(self,snac): - users=[] - rest=snac[3] - while rest: - user, rest = self.bos.parseUser(rest, 1) - users.append(user) - if not self.fullName: - self.members = users - else: - self.members.append(users[0]) - self.bos.chatMemberJoined(self,users[0]) - - def oscar_0E_04(self,snac): - user=self.bos.parseUser(snac[3]) - for u in self.members: - if u.name == user.name: # same person! - self.members.remove(u) - self.bos.chatMemberLeft(self,user) - - def oscar_0E_06(self,snac): - data = snac[3] - user,rest=self.bos.parseUser(snac[3][14:],1) - tlvs = readTLVs(rest[8:]) - message=tlvs[1] - self.bos.chatReceiveMessage(self,user,message) - - def sendMessage(self,message): - tlvs=TLV(0x02,"us-ascii")+TLV(0x03,"en")+TLV(0x01,message) - self.sendSNAC(0x0e,0x05, - "\x46\x30\x38\x30\x44\x00\x63\x00\x00\x03\x00\x01\x00\x00\x00\x06\x00\x00\x00\x05"+ - struct.pack("!H",len(tlvs))+ - tlvs) - - def leaveChat(self): - self.disconnect() - -class OscarAuthenticator(OscarConnection): - BOSClass = BOSConnection - def __init__(self,username,password,deferred=None,icq=0): - self.username=username - self.password=password - self.deferred=deferred - self.icq=icq # icq mode is disabled - #if icq and self.BOSClass==BOSConnection: - # self.BOSClass=ICQConnection - - def oscar_(self,flap): - if not self.icq: - self.sendFLAP("\000\000\000\001", 0x01) - self.sendFLAP(SNAC(0x17,0x06,0, - TLV(TLV_USERNAME,self.username)+ - TLV(0x004B,''))) - self.state="Key" - else: - encpass=encryptPasswordICQ(self.password) - self.sendFLAP('\000\000\000\001'+ - TLV(0x01,self.username)+ - TLV(0x02,encpass)+ - TLV(0x03,'ICQ Inc. - Product of ICQ (TM).2001b.5.18.1.3659.85')+ - TLV(0x16,"\x01\x0a")+ - TLV(0x17,"\x00\x05")+ - TLV(0x18,"\x00\x12")+ - TLV(0x19,"\000\001")+ - TLV(0x1a,"\x0eK")+ - TLV(0x14,"\x00\x00\x00U")+ - TLV(0x0f,"en")+ - TLV(0x0e,"us"),0x01) - self.state="Cookie" - - def oscar_Key(self,data): - snac=readSNAC(data[1]) - key=snac[5][2:] - encpass=encryptPasswordMD5(self.password,key) - self.sendFLAP(SNAC(0x17,0x02,0, - TLV(TLV_USERNAME,self.username)+ - TLV(TLV_PASSWORD,encpass)+ - TLV(0x004C, '')+ # unknown - TLV(TLV_CLIENTNAME,"AOL Instant Messenger (SM), version 4.8.2790/WIN32")+ - TLV(0x0016,"\x01\x09")+ - TLV(TLV_CLIENTMAJOR,"\000\004")+ - TLV(TLV_CLIENTMINOR,"\000\010")+ - TLV(0x0019,"\000\000")+ - TLV(TLV_CLIENTSUB,"\x0A\xE6")+ - TLV(0x0014,"\x00\x00\x00\xBB")+ - TLV(TLV_LANG,"en")+ - TLV(TLV_COUNTRY,"us")+ - TLV(TLV_USESSI,"\001"))) - return "Cookie" - - def oscar_Cookie(self,data): - snac=readSNAC(data[1]) - if self.icq: - i=snac[5].find("\000") - snac[5]=snac[5][i:] - tlvs=readTLVs(snac[5]) - if tlvs.has_key(6): - self.cookie=tlvs[6] - server,port=string.split(tlvs[5],":") - d = self.connectToBOS(server, int(port)) - d.addErrback(lambda x: log.msg("Connection Failed! Reason: %s" % x)) - if self.deferred: - d.chainDeferred(self.deferred) - self.disconnect() - elif tlvs.has_key(8): - errorcode=tlvs[8] - errorurl=tlvs[4] - if errorcode=='\000\030': - error="You are attempting to sign on again too soon. Please try again later." - elif errorcode=='\000\005': - error="Invalid Username or Password." - else: error=repr(errorcode) - self.error(error,errorurl) - else: - log.msg('hmm, weird tlvs for %s cookie packet' % str(self)) - log.msg(tlvs) - log.msg('snac') - log.msg(str(snac)) - return "None" - - def oscar_None(self,data): pass - - def connectToBOS(self, server, port): - c = protocol.ClientCreator(reactor, self.BOSClass, self.username, self.cookie) - return c.connectTCP(server, int(port)) - - def error(self,error,url): - log.msg("ERROR! %s %s" % (error,url)) - if self.deferred: self.deferred.errback((error,url)) - self.transport.loseConnection() - -FLAP_CHANNEL_NEW_CONNECTION = 0x01 -FLAP_CHANNEL_DATA = 0x02 -FLAP_CHANNEL_ERROR = 0x03 -FLAP_CHANNEL_CLOSE_CONNECTION = 0x04 - -SERVICE_CHATNAV = 0x0d -SERVICE_CHAT = 0x0e -serviceClasses = { - SERVICE_CHATNAV:ChatNavService, - SERVICE_CHAT:ChatService -} -TLV_USERNAME = 0x0001 -TLV_CLIENTNAME = 0x0003 -TLV_COUNTRY = 0x000E -TLV_LANG = 0x000F -TLV_CLIENTMAJOR = 0x0017 -TLV_CLIENTMINOR = 0x0018 -TLV_CLIENTSUB = 0x001A -TLV_PASSWORD = 0x0025 -TLV_USESSI = 0x004A - -CAP_ICON = '\011F\023FL\177\021\321\202"DEST\000\000' -CAP_VOICE = '\011F\023AL\177\021\321\202"DEST\000\000' -CAP_IMAGE = '\011F\023EL\177\021\321\202"DEST\000\000' -CAP_CHAT = 't\217$ b\207\021\321\202"DEST\000\000' -CAP_GET_FILE = '\011F\023HL\177\021\321\202"DEST\000\000' -CAP_SEND_FILE = '\011F\023CL\177\021\321\202"DEST\000\000' -CAP_GAMES = '\011F\023GL\177\021\321\202"DEST\000\000' -CAP_SEND_LIST = '\011F\023KL\177\021\321\202"DEST\000\000' -CAP_SERV_REL = '\011F\023IL\177\021\321\202"DEST\000\000' diff --git a/tools/buildbot/pylibs/twisted/words/protocols/toc.py b/tools/buildbot/pylibs/twisted/words/protocols/toc.py deleted file mode 100644 index 1e46646..0000000 --- a/tools/buildbot/pylibs/twisted/words/protocols/toc.py +++ /dev/null @@ -1,1615 +0,0 @@ -# -*- test-case-name: twisted.words.test -*- -# Copyright (c) 2001-2005 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Implements a AOL Instant Messenger TOC server and client, using the Twisted -framework. - -TODO: -info,dir: see how gaim connects for this...it may never work if it tries to -connect to the aim server automatically - -This module is deprecated. - -Maintainer: U{Paul Swartz} -""" - -# twisted imports -from twisted.internet import reactor, protocol -from twisted.python import log - -# base imports -import struct -import string -import time -import base64 -import os -import StringIO - -SIGNON,DATA,ERROR,SIGNOFF,KEEP_ALIVE=range(1,6) -PERMITALL,DENYALL,PERMITSOME,DENYSOME=range(1,5) - -DUMMY_CHECKSUM = -559038737 # 0xdeadbeef - -def quote(s): - rep=['\\','$','{','}','[',']','(',')','"'] - for r in rep: - s=string.replace(s,r,"\\"+r) - return "\""+s+"\"" - -def unquote(s): - if s=="": return "" - if s[0]!='"': return s - r=string.replace - s=s[1:-1] - s=r(s,"\\\\","\\") - s=r(s,"\\$","$") - s=r(s,"\\{","{") - s=r(s,"\\}","}") - s=r(s,"\\[","[") - s=r(s,"\\]","]") - s=r(s,"\\(","(") - s=r(s,"\\)",")") - s=r(s,"\\\"","\"") - return s - -def unquotebeg(s): - for i in range(1,len(s)): - if s[i]=='"' and s[i-1]!='\\': - q=unquote(s[:i+1]) - return [q,s[i+2:]] - -def unroast(pw): - roaststring="Tic/Toc" - pw=string.lower(pw[2:]) - r="" - count=0 - hex=["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"] - while pw: - st,pw=pw[:2],pw[2:] - value=(16*hex.index(st[0]))+hex.index(st[1]) - xor=ord(roaststring[count]) - count=(count+1)%len(roaststring) - r=r+chr(value^xor) - return r - -def roast(pw): - # contributed by jemfinch on #python - key="Tic/Toc" - ro="0x" - i=0 - ascii=map(ord,pw) - for c in ascii: - ro=ro+'%02x'%(c^ord(key[i%len(key)])) - i=i+1 - return string.lower(ro) - -def checksum(b): - return DUMMY_CHECKSUM # do it like gaim does, since the checksum - # formula doesn't work -## # used in file transfers -## check0 = check1 = 0x00ff -## for i in range(len(b)): -## if i%2: -## if ord(b[i])>check1: -## check1=check1+0x100 # wrap -## if check0==0: -## check0=0x00ff -## if check1==0x100: -## check1=check1-1 -## else: -## check0=check0-1 -## check1=check1-ord(b[i]) -## else: -## if ord(b[i])>check0: # wrap -## check0=check0+0x100 -## if check1==0: -## check1=0x00ff -## if check0==0x100: -## check0=check0-1 -## else: -## check1=check1-1 -## check0=check0-ord(b[i]) -## check0=check0 & 0xff -## check1=check1 & 0xff -## checksum=(long(check0)*0x1000000)+(long(check1)*0x10000) -## return checksum - -def checksum_file(f): - return DUMMY_CHECKSUM # do it like gaim does, since the checksum - # formula doesn't work -## check0=check1=0x00ff -## i=0 -## while 1: -## b=f.read() -## if not b: break -## for char in b: -## i=not i -## if i: -## if ord(char)>check1: -## check1=check1+0x100 # wrap -## if check0==0: -## check0=0x00ff -## if check1==0x100: -## check1=check1-1 -## else: -## check0=check0-1 -## check1=check1-ord(char) -## else: -## if ord(char)>check0: # wrap -## check0=check0+0x100 -## if check1==0: -## check1=0x00ff -## if check0==0x100: -## check0=check0-1 -## else: -## check1=check1-1 -## check0=check0-ord(char) -## check0=check0 & 0xff -## check1=check1 & 0xff -## checksum=(long(check0)*0x1000000)+(long(check1)*0x10000) -## return checksum - -def normalize(s): - s=string.lower(s) - s=string.replace(s," ","") - return s - - -class TOCParseError(ValueError): - pass - - -class TOC(protocol.Protocol): - users={} - - def connectionMade(self): - # initialization of protocol - self._buf="" - self._ourseqnum=0L - self._theirseqnum=0L - self._mode="Flapon" - self._onlyflaps=0 - self._laststatus={} # the last status for a user - self.username=None - self.permitmode=PERMITALL - self.permitlist=[] - self.denylist=[] - self.buddylist=[] - self.signontime=0 - self.idletime=0 - self.userinfo="
                    " - self.userclass=" O" - self.away="" - self.saved=None - - def _debug(self,data): - log.msg(data) - - def connectionLost(self, reason): - self._debug("dropped connection from %s" % self.username) - try: - del self.factory.users[self.username] - except: - pass - for k in self.factory.chatroom.keys(): - try: - self.factory.chatroom[k].leave(self) - except TOCParseError: - pass - if self.saved: - self.factory.savedusers[self.username]=self.saved - self.updateUsers() - - def sendFlap(self,type,data): - """ - send a FLAP to the client - """ - send="*" - self._debug(data) - if type==DATA: - data=data+"\000" - length=len(data) - send=send+struct.pack("!BHH",type,self._ourseqnum,length) - send=send+data - self._ourseqnum=self._ourseqnum+1 - if self._ourseqnum>(256L**4): - self._ourseqnum=0 - self.transport.write(send) - - def dataReceived(self,data): - self._buf=self._buf+data - try: - func=getattr(self,"mode%s"%self._mode) - except: - return - self._mode=func() - if self._onlyflaps and self.isFlap(): self.dataReceived("") - - def isFlap(self): - """ - tests to see if a flap is actually on the buffer - """ - if self._buf=='': return 0 - if self._buf[0]!="*": return 0 - if len(self._buf)<6: return 0 - foo,type,seqnum,length=struct.unpack("!BBHH",self._buf[:6]) - if type not in range(1,6): return 0 - if len(self._buf)<6+length: return 0 - return 1 - - def readFlap(self): - """ - read the first FLAP off self._buf, raising errors if it isn't in the right form. - the FLAP is the basic TOC message format, and is logically equivilant to a packet in TCP - """ - if self._buf=='': return None - if self._buf[0]!="*": - raise TOCParseError - if len(self._buf)<6: return None - foo,type,seqnum,length=struct.unpack("!BBHH",self._buf[:6]) - if len(self._buf)<6+length: return None - data=self._buf[6:6+length] - self._buf=self._buf[6+length:] - if data and data[-1]=="\000": - data=data[:-1] - self._debug([type,data]) - return [type,data] - - #def modeWeb(self): - # try: - # line,rest=string.split(self._buf,"\n",1) - # get,username,http=string.split(line," ",2) - # except: - # return "Web" # not enough data - # foo,type,username=string.split(username,"/") - # if type=="info": - # user=self.factory.users[username] - # text="User Information for %sUsername: %s
                    \nWarning Level: %s%
                    \n Online Since: %s
                    \nIdle Minutes: %s
                    \n

                    \n%s\n

                    \n"%(user.saved.nick, user.saved.nick, user.saved.evilness, time.asctime(user.signontime), int((time.time()-user.idletime)/60), user.userinfo) - # self.transport.write("HTTP/1.1 200 OK\n") - # self.transport.write("Content-Type: text/html\n") - # self.transport.write("Content-Length: %s\n\n"%len(text)) - # self.transport.write(text) - # self.loseConnection() - - def modeFlapon(self): - #if self._buf[:3]=="GET": self.modeWeb() # TODO: get this working - if len(self._buf)<10: return "Flapon" # not enough bytes - flapon,self._buf=self._buf[:10],self._buf[10:] - if flapon!="FLAPON\r\n\r\n": - raise TOCParseError - self.sendFlap(SIGNON,"\000\000\000\001") - self._onlyflaps=1 - return "Signon" - - def modeSignon(self): - flap=self.readFlap() - if flap==None: - return "Signon" - if flap[0]!=SIGNON: raise TOCParseError - version,tlv,unlength=struct.unpack("!LHH",flap[1][:8]) - if version!=1 or tlv!=1 or unlength+8!=len(flap[1]): - raise TOCParseError - self.username=normalize(flap[1][8:]) - if self.username in self.factory.savedusers.keys(): - self.saved=self.factory.savedusers[self.username] - else: - self.saved=SavedUser() - self.saved.nick=self.username - return "TocSignon" - - def modeTocSignon(self): - flap=self.readFlap() - if flap==None: - return "TocSignon" - if flap[0]!=DATA: raise TOCParseError - data=string.split(flap[1]," ") - if data[0]!="toc_signon": raise TOCParseError - for i in data: - if not i:data.remove(i) - password=unroast(data[4]) - if not(self.authorize(data[1],int(data[2]),data[3],password)): - self.sendError(BAD_NICKNAME) - self.transport.loseConnection() - return - self.sendFlap(DATA,"SIGN_ON:TOC1.0") - self.sendFlap(DATA,"NICK:%s"%self.saved.nick) - self.sendFlap(DATA,"CONFIG:%s"%self.saved.config) - # sending user configuration goes here - return "Connected" - - def authorize(self,server,port,username,password): - if self.saved.password=="": - self.saved.password=password - return 1 - else: - return self.saved.password==password - - def modeConnected(self): - flap=self.readFlap() - while flap!=None: - if flap[0] not in [DATA,KEEP_ALIVE]: raise TOCParseError - flapdata=string.split(flap[1]," ",1) - tocname=flapdata[0][4:] - if len(flapdata)==2: - data=flapdata[1] - else: - data="" - func=getattr(self,"toc_"+tocname,None) - if func!=None: - func(data) - else: - self.toc_unknown(tocname,data) - flap=self.readFlap() - return "Connected" - - def toc_unknown(self,tocname,data): - self._debug("unknown! %s %s" % (tocname,data)) - - def toc_init_done(self,data): - """ - called when all the setup is done. - - toc_init_done - """ - self.signontime=int(time.time()) - self.factory.users[self.username]=self - self.updateUsers() - - def toc_add_permit(self,data): - """ - adds users to the permit list. if the list is null, then set the mode to DENYALL - """ - if data=="": - self.permitmode=DENYALL - self.permitlist=[] - self.denylist=[] - else: - self.permitmode=PERMITSOME - self.denylist=[] - users=string.split(data," ") - map(self.permitlist.append,users) - self.updateUsers() - - def toc_add_deny(self,data): - """ - adds users to the deny list. if the list is null, then set the mode to PERMITALL - """ - if data=="": - self.permitmode=PERMITALL - self.permitlist=[] - self.denylist=[] - else: - self.permitmode=DENYSOME - self.permitlist=[] - users=string.split(data," ") - map(self.denylist.append,users) - self.updateUsers() - - def toc_evil(self,data): - """ - warns a user. - - toc_evil - """ - username,nora=string.split(data," ") - if nora=="anon": - user="" - else: - user=self.saved.nick - if not(self.factory.users.has_key(username)): - self.sendError(CANT_WARN,username) - return - if self.factory.users[username].saved.evilness>=100: - self.sendError(CANT_WARN,username) - return - self.factory.users[username].evilFrom(user) - - def toc_add_buddy(self,data): - """ - adds users to the buddy list - - toc_add_buddy [] []... - """ - buddies=map(normalize,string.split(data," ")) - for b in buddies: - if b not in self.buddylist: - self.buddylist.append(b) - for buddy in buddies: - try: - buddy=self.factory.users[buddy] - except: - pass - else: - self.buddyUpdate(buddy) - - def toc_remove_buddy(self,data): - """ - removes users from the buddy list - - toc_remove_buddy [] []... - """ - buddies=string.split(data," ") - for buddy in buddies: - try: - self.buddylist.remove(normalize(buddy)) - except: pass - - def toc_send_im(self,data): - """ - incoming instant message - - toc_send_im [auto] - """ - username,data=string.split(data," ",1) - auto=0 - if data[-4:]=="auto": - auto=1 - data=data[:-5] - data=unquote(data) - if not(self.factory.users.has_key(username)): - self.sendError(NOT_AVAILABLE,username) - return - user=self.factory.users[username] - if not(self.canContact(user)): - self.sendError(NOT_AVAILABLE,username) - return - user.hearWhisper(self,data,auto) - - def toc_set_info(self,data): - """ - set the users information, retrivable with toc_get_info - - toc_set_info - """ - info=unquote(data) - self._userinfo=info - - def toc_set_idle(self,data): - """ - set/unset idle - - toc_set_idle - """ - seconds=int(data) - self.idletime=time.time()-seconds # time when they started being idle - self.updateUsers() - - def toc_set_away(self,data): - """ - set/unset away message - - toc_set_away [] - """ - away=unquote(data) - if not self.away and away: # setting an away message - self.away=away - self.userclass=self.userclass+'U' - self.updateUsers() - elif self.away and not away: # coming back - self.away="" - self.userclass=self.userclass[:2] - self.updateUsers() - else: - raise TOCParseError - - def toc_chat_join(self,data): - """ - joins the chat room. - - toc_chat_join - """ - exchange,name=string.split(data," ",1) - self.factory.getChatroom(int(exchange),unquote(name)).join(self) - - def toc_chat_invite(self,data): - """ - invite others to the room. - - toc_chat_invite []... - """ - id,data=string.split(data," ",1) - id=int(id) - message,data=unquotebeg(data) - buddies=string.split(data," ") - for b in buddies: - room=self.factory.chatroom[id] - bud=self.factory.users[b] - bud.chatInvite(room,self,message) - - def toc_chat_accept(self,data): - """ - accept an invitation. - - toc_chat_accept - """ - id=int(data) - self.factory.chatroom[id].join(self) - - def toc_chat_send(self,data): - """ - send a message to the chat room. - - toc_chat_send - """ - id,message=string.split(data," ",1) - id=int(id) - message=unquote(message) - self.factory.chatroom[id].say(self,message) - - def toc_chat_whisper(self,data): - id,user,message=string.split(data," ",2) - id=int(id) - room=self.factory.chatroom[id] - message=unquote(message) - self.factory.users[user].chatWhisper(room,self,message) - - def toc_chat_leave(self,data): - """ - leave the room. - - toc_chat_leave - """ - id=int(data) - self.factory.chatroom[id].leave(self) - - def toc_set_config(self,data): - """ - set the saved config. this gets send when you log in. - - toc_set_config - """ - self.saved.config=unquote(data) - - def toc_get_info(self,data): - """ - get the user info for a user - - toc_get_info - """ - if not self.factory.users.has_key(data): - self.sendError(901,data) - return - self.sendFlap(2,"GOTO_URL:TIC:info/%s"%data) - - def toc_format_nickname(self,data): - """ - change the format of your nickname. - - toc_format_nickname - """ - # XXX may not work - nick=unquote(data) - if normalize(nick)==self.username: - self.saved.nick=nick - self.sendFlap(2,"ADMIN_NICK_STATUS:0") - else: - self.sendError(BAD_INPUT) - - def toc_change_passwd(self,data): - orig,data=unquotebeg(data) - new=unquote(data) - if orig==self.saved.password: - self.saved.password=new - self.sendFlap(2,"ADMIN_PASSWD_STATUS:0") - else: - self.sendError(BAD_INPUT) - - def sendError(self,code,*varargs): - """ - send an error to the user. listing of error messages is below. - """ - send="ERROR:%s"%code - for v in varargs: - send=send+":"+v - self.sendFlap(DATA,send) - - def updateUsers(self): - """ - Update the users who have us on their buddylist. - Called when the user changes anything (idle,away) so people can get updates. - """ - for user in self.factory.users.values(): - if self.username in user.buddylist and self.canContact(user): - user.buddyUpdate(self) - - def getStatus(self,user): - if self.canContact(user): - if self in self.factory.users.values():ol='T' - else: ol='F' - idle=0 - if self.idletime: - idle=int((time.time()-self.idletime)/60) - return (self.saved.nick,ol,self.saved.evilness,self.signontime,idle,self.userclass) - else: - return (self.saved.nick,'F',0,0,0,self.userclass) - - def canContact(self,user): - if self.permitmode==PERMITALL: return 1 - elif self.permitmode==DENYALL: return 0 - elif self.permitmode==PERMITSOME: - if user.username in self.permitlist: return 1 - else: return 0 - elif self.permitmode==DENYSOME: - if user.username in self.denylist: return 0 - else: return 1 - else: - assert 0,"bad permitmode %s" % self.permitmode - - def buddyUpdate(self,user): - """ - Update the buddy. Called from updateUsers() - """ - if not self.canContact(user): return - status=user.getStatus(self) - if not self._laststatus.has_key(user): - self._laststatus[user]=() - if self._laststatus[user]!=status: - send="UPDATE_BUDDY:%s:%s:%s:%s:%s:%s"%status - self.sendFlap(DATA,send) - self._laststatus[user]=status - - def hearWhisper(self,user,data,auto=0): - """ - Called when you get an IM. If auto=1, it's an autoreply from an away message. - """ - if not self.canContact(user): return - if auto: auto='T' - else: auto='F' - send="IM_IN:%s:%s:%s"%(user.saved.nick,auto,data) - self.sendFlap(DATA,send) - - def evilFrom(self,user): - if user=="": - percent=0.03 - else: - percent=0.1 - self.saved.evilness=self.saved.evilness+int((100-self.saved.evilness)*percent) - self.sendFlap(2,"EVILED:%s:%s"%(self.saved.evilness,user)) - self.updateUsers() - - def chatJoin(self,room): - self.sendFlap(2,"CHAT_JOIN:%s:%s"%(room.id,room.name)) - f="CHAT_UPDATE_BUDDY:%s:T"%room.id - for u in room.users: - if u!=self: - u.chatUserUpdate(room,self) - f=f+":"+u.saved.nick - self.sendFlap(2,f) - - def chatInvite(self,room,user,message): - if not self.canContact(user): return - self.sendFlap(2,"CHAT_INVITE:%s:%s:%s:%s"%(room.name,room.id,user.saved.nick,message)) - - def chatUserUpdate(self,room,user): - if user in room.users: - inroom='T' - else: - inroom='F' - self.sendFlap(2,"CHAT_UPDATE_BUDDY:%s:%s:%s"%(room.id,inroom,user.saved.nick)) - - def chatMessage(self,room,user,message): - if not self.canContact(user): return - self.sendFlap(2,"CHAT_IN:%s:%s:F:%s"%(room.id,user.saved.nick,message)) - - def chatWhisper(self,room,user,message): - if not self.canContact(user): return - self.sendFlap(2,"CHAT_IN:%s:%s:T:%s"%(room.id,user.saved.nick,message)) - - def chatLeave(self,room): - self.sendFlap(2,"CHAT_LEFT:%s"%(room.id)) - - -class Chatroom: - def __init__(self,fac,exchange,name,id): - self.exchange=exchange - self.name=name - self.id=id - self.factory=fac - self.users=[] - - def join(self,user): - if user in self.users: - return - self.users.append(user) - user.chatJoin(self) - - def leave(self,user): - if user not in self.users: - raise TOCParseError - self.users.remove(user) - user.chatLeave(self) - for u in self.users: - u.chatUserUpdate(self,user) - if len(self.users)==0: - self.factory.remChatroom(self) - - def say(self,user,message): - for u in self.users: - u.chatMessage(self,user,message) - - -class SavedUser: - def __init__(self): - self.config="" - self.nick="" - self.password="" - self.evilness=0 - - -class TOCFactory(protocol.Factory): - def __init__(self): - self.users={} - self.savedusers={} - self.chatroom={} - self.chatroomid=0 - - def buildProtocol(self,addr): - p=TOC() - p.factory=self - return p - - def getChatroom(self,exchange,name): - for i in self.chatroom.values(): - if normalize(i.name)==normalize(name): - return i - self.chatroom[self.chatroomid]=Chatroom(self,exchange,name,self.chatroomid) - self.chatroomid=self.chatroomid+1 - return self.chatroom[self.chatroomid-1] - - def remChatroom(self,room): - id=room.id - del self.chatroom[id] - -MAXARGS={} -MAXARGS["CONFIG"]=0 -MAXARGS["NICK"]=0 -MAXARGS["IM_IN"]=2 -MAXARGS["UPDATE_BUDDY"]=5 -MAXARGS["ERROR"]=-1 -MAXARGS["EVILED"]=1 -MAXARGS["CHAT_JOIN"]=1 -MAXARGS["CHAT_IN"]=3 -MAXARGS["CHAT_UPDATE_BUDDY"]=-1 -MAXARGS["CHAT_INVITE"]=3 -MAXARGS["CHAT_LEFT"]=0 -MAXARGS["ADMIN_NICK_STATUS"]=0 -MAXARGS["ADMIN_PASSWD_STATUS"]=0 - - -class TOCClient(protocol.Protocol): - def __init__(self,username,password,authhost="login.oscar.aol.com",authport=5190): - - self.username=normalize(username) # our username - self._password=password # our password - self._mode="SendNick" # current mode - self._ourseqnum=19071 # current sequence number (for sendFlap) - self._authhost=authhost # authorization host - self._authport=authport # authorization port - self._online=0 # are we online? - self._buddies=[] # the current buddy list - self._privacymode=PERMITALL # current privacy mode - self._permitlist=[] # list of users on the permit list - self._roomnames={} # the names for each of the rooms we're in - self._receivedchatmembers={} # have we gotten who's in our room yet? - self._denylist=[] - self._cookies={} # for file transfers - self._buf='' # current data buffer - self._awaymessage='' - - def _debug(self,data): - log.msg(data) - - def sendFlap(self,type,data): - if type==DATA: - data=data+"\000" - length=len(data) - s="*" - s=s+struct.pack("!BHH",type,self._ourseqnum,length) - s=s+data - self._ourseqnum=self._ourseqnum+1 - if self._ourseqnum>(256*256+256): - self._ourseqnum=0 - self._debug(data) - self.transport.write(s) - - def isFlap(self): - """ - tests to see if a flap is actually on the buffer - """ - if self._buf=='': return 0 - if self._buf[0]!="*": return 0 - if len(self._buf)<6: return 0 - foo,type,seqnum,length=struct.unpack("!BBHH",self._buf[:6]) - if type not in range(1,6): return 0 - if len(self._buf)<6+length: return 0 - return 1 - - def readFlap(self): - if self._buf=='': return None - if self._buf[0]!="*": - raise TOCParseError - if len(self._buf)<6: return None - foo,type,seqnum,length=struct.unpack("!BBHH",self._buf[:6]) - if len(self._buf)<6+length: return None - data=self._buf[6:6+length] - self._buf=self._buf[6+length:] - if data and data[-1]=="\000": - data=data[:-1] - return [type,data] - - def connectionMade(self): - self._debug("connection made! %s" % self.transport) - self.transport.write("FLAPON\r\n\r\n") - - def connectionLost(self, reason): - self._debug("connection lost!") - self._online=0 - - def dataReceived(self,data): - self._buf=self._buf+data - while self.isFlap(): - flap=self.readFlap() - func=getattr(self,"mode%s"%self._mode) - func(flap) - - def modeSendNick(self,flap): - if flap!=[1,"\000\000\000\001"]: raise TOCParseError - s="\000\000\000\001\000\001"+struct.pack("!H",len(self.username))+self.username - self.sendFlap(1,s) - s="toc_signon %s %s %s %s english \"penguin\""%(self._authhost,\ - self._authport,self.username,roast(self._password)) - self.sendFlap(2,s) - self._mode="Data" - - def modeData(self,flap): - if not flap[1]: - return - if not ':' in flap[1]: - self._debug("bad SNAC:%s"%(flap[1])) - return - command,rest=string.split(flap[1],":",1) - if MAXARGS.has_key(command): - maxsplit=MAXARGS[command] - else: - maxsplit=-1 - if maxsplit==-1: - l=tuple(string.split(rest,":")) - elif maxsplit==0: - l=(rest,) - else: - l=tuple(string.split(rest,":",maxsplit)) - self._debug("%s %s"%(command,l)) - try: - func=getattr(self,"toc%s"%command) - self._debug("calling %s"%func) - except: - self._debug("calling %s"%self.tocUNKNOWN) - self.tocUNKNOWN(command,l) - return - func(l) - - def tocUNKNOWN(self,command,data): - pass - - def tocSIGN_ON(self,data): - if data!=("TOC1.0",): raise TOCParseError - self._debug("Whee, signed on!") - if self._buddies: self.add_buddy(self._buddies) - self._online=1 - self.onLine() - - def tocNICK(self,data): - """ - Handle a message that looks like:: - - NICK: - """ - self.username=data[0] - - def tocCONFIG(self,data): - """ - Handle a message that looks like:: - - CONFIG: - - Format of config data: - - - g: group. all users until next g or end of config are in this group - - b: buddy - - p: person on the permit list - - d: person on the deny list - - m: permit/deny mode (1: permit all, 2: deny all, 3: permit some, 4: deny some) - """ - data=data[0] - if data and data[0]=="{":data=data[1:-1] - lines=string.split(data,"\n") - buddylist={} - currentgroup="" - permit=[] - deny=[] - mode=1 - for l in lines: - if l: - code,data=l[0],l[2:] - if code=='g': # group - currentgroup=data - buddylist[currentgroup]=[] - elif code=='b': - buddylist[currentgroup].append(data) - elif code=='p': - permit.append(data) - elif code=='d': - deny.append(data) - elif code=='m': - mode=int(data) - self.gotConfig(mode,buddylist,permit,deny) - - def tocIM_IN(self,data): - """ - Handle a message that looks like:: - - IM_IN:::message - """ - user=data[0] - autoreply=(data[1]=='T') - message=data[2] - self.hearMessage(user,message,autoreply) - - def tocUPDATE_BUDDY(self,data): - """ - Handle a message that looks like:: - - UPDATE_BUDDY:::::: - """ - data=list(data) - online=(data[1]=='T') - if len(data[5])==2: - data[5]=data[5]+" " - away=(data[5][-1]=='U') - if data[5][-1]=='U': - data[5]=data[5][:-1] - self.updateBuddy(data[0],online,int(data[2]),int(data[3]),int(data[4]),data[5],away) - - def tocERROR(self,data): - """ - Handle a message that looks like:: - - ERROR:: - """ - code,args=data[0],data[1:] - self.hearError(int(code),args) - - def tocEVILED(self,data): - """ - Handle a message that looks like:: - - EVILED:: - """ - self.hearWarning(data[0],data[1]) - - def tocCHAT_JOIN(self,data): - """ - Handle a message that looks like:: - - CHAT_JOIN:: - """ - #self.chatJoined(int(data[0]),data[1]) - self._roomnames[int(data[0])]=data[1] - self._receivedchatmembers[int(data[0])]=0 - - def tocCHAT_UPDATE_BUDDY(self,data): - """ - Handle a message that looks like:: - - CHAT_UPDATE_BUDDY::::... - """ - roomid=int(data[0]) - inroom=(data[1]=='T') - if self._receivedchatmembers[roomid]: - for u in data[2:]: - self.chatUpdate(roomid,u,inroom) - else: - self._receivedchatmembers[roomid]=1 - self.chatJoined(roomid,self._roomnames[roomid],list(data[2:])) - - def tocCHAT_IN(self,data): - """ - Handle a message that looks like:: - - CHAT_IN:::: - - whisper isn't used - """ - whisper=(data[2]=='T') - if whisper: - self.chatHearWhisper(int(data[0]),data[1],data[3]) - else: - self.chatHearMessage(int(data[0]),data[1],data[3]) - - def tocCHAT_INVITE(self,data): - """ - Handle a message that looks like:: - - CHAT_INVITE:::: - """ - self.chatInvited(int(data[1]),data[0],data[2],data[3]) - - def tocCHAT_LEFT(self,data): - """ - Handle a message that looks like:: - - CHAT_LEFT: - """ - self.chatLeft(int(data[0])) - del self._receivedchatmembers[int(data[0])] - del self._roomnames[int(data[0])] - - def tocRVOUS_PROPOSE(self,data): - """ - Handle a message that looks like:: - - RVOUS_PROPOSE:::::::: - [:tlv tag1:tlv value1[:tlv tag2:tlv value2[:...]]] - """ - user,uid,cookie,seq,rip,pip,vip,port=data[:8] - cookie=base64.decodestring(cookie) - port=int(port) - tlvs={} - for i in range(8,len(data),2): - key=data[i] - value=base64.decodestring(data[i+1]) - tlvs[key]=value - name=UUIDS[uid] - try: - func=getattr(self,"toc%s"%name) - except: - self._debug("no function for UID %s" % uid) - return - func(user,cookie,seq,pip,vip,port,tlvs) - - def tocSEND_FILE(self,user,cookie,seq,pip,vip,port,tlvs): - if tlvs.has_key('12'): - description=tlvs['12'] - else: - description="" - subtype,numfiles,size=struct.unpack("!HHI",tlvs['10001'][:8]) - name=tlvs['10001'][8:-4] - while name[-1]=='\000': - name=name[:-1] - self._cookies[cookie]=[user,SEND_FILE_UID,pip,port,{'name':name}] - self.rvousProposal("send",cookie,user,vip,port,description=description, - name=name,files=numfiles,size=size) - - def tocGET_FILE(self,user,cookie,seq,pip,vip,port,tlvs): - return - # XXX add this back in - #reactor.clientTCP(pip,port,GetFileTransfer(self,cookie,os.path.expanduser("~"))) - #self.rvous_accept(user,cookie,GET_FILE_UID) - - def onLine(self): - """ - called when we are first online - """ - pass - - def gotConfig(self,mode,buddylist,permit,deny): - """ - called when we get a configuration from the server - mode := permit/deny mode - buddylist := current buddylist - permit := permit list - deny := deny list - """ - pass - - def hearError(self,code,args): - """ - called when an error is received - code := error code - args := misc. arguments (username, etc.) - """ - pass - - def hearWarning(self,newamount,username): - """ - called when we get warned - newamount := the current warning level - username := the user who warned us, or '' if it's anonymous - """ - pass - - def hearMessage(self,username,message,autoreply): - """ - called when you receive an IM - username := the user who the IM is from - message := the message - autoreply := true if the message is an autoreply from an away message - """ - pass - - def updateBuddy(self,username,online,evilness,signontime,idletime,userclass,away): - """ - called when a buddy changes state - username := the user whos state changed - online := true if the user is online - evilness := the users current warning level - signontime := the time the user signed on (UNIX epoch) - idletime := the time the user has been idle (minutes) - away := true if the user is away - userclass := the class of the user (generally " O") - """ - pass - - def chatJoined(self,roomid,roomname,users): - """ - we just joined a chat room - roomid := the AIM id for the room - roomname := the name for the room - users := a list of the users already in the room - """ - pass - - def chatUpdate(self,roomid,username,inroom): - """ - a user has joined the room - roomid := the AIM id for the room - username := the username - inroom := true if the user is in the room - """ - pass - - def chatHearMessage(self,roomid,username,message): - """ - a message was sent to the room - roomid := the AIM id for the room - username := the user who sent the message - message := the message - """ - pass - - def chatHearWhisper(self,roomid,username,message): - """ - someone whispered to us in a chatroom - roomid := the AIM for the room - username := the user who whispered to us - message := the message - """ - pass - - def chatInvited(self,roomid,roomname,username,message): - """ - we were invited to a chat room - roomid := the AIM id for the room - roomname := the name of the room - username := the user who invited us - message := the invite message - """ - pass - - def chatLeft(self,roomid): - """ - we left the room - roomid := the AIM id for the room - """ - pass - - def rvousProposal(self,type,cookie,user,vip,port,**kw): - """ - we were asked for a rondevouz - type := the type of rondevous. currently, one of ["send"] - cookie := the cookie. pass this to rvous_accept() - user := the user who asked us - vip := their verified_ip - port := the port they want us to conenct to - kw := misc. args - """ - pass #self.rvous_accept(cookie) - - def receiveBytes(self,user,file,chunk,sofar,total): - """ - we received part of a file from a file transfer - file := the name of the file - chunk := the chunk of data - sofar := how much data we've gotten so far - total := the total amount of data - """ - pass #print user,file,sofar,total - - def isaway(self): - """ - return our away status - """ - return len(self._awaymessage)>0 - - def set_config(self,mode,buddylist,permit,deny): - """ - set the server configuration - mode := permit mode - buddylist := buddy list - permit := permit list - deny := deny list - """ - s="m %s\n"%mode - for g in buddylist.keys(): - s=s+"g %s\n"%g - for u in buddylist[g]: - s=s+"b %s\n"%u - for p in permit: - s=s+"p %s\n"%p - for d in deny: - s=s+"d %s\n"%d - #s="{\n"+s+"\n}" - self.sendFlap(2,"toc_set_config %s"%quote(s)) - - def add_buddy(self,buddies): - s="" - if type(buddies)==type(""): buddies=[buddies] - for b in buddies: - s=s+" "+normalize(b) - self.sendFlap(2,"toc_add_buddy%s"%s) - - def del_buddy(self,buddies): - s="" - if type(buddies)==type(""): buddies=[buddies] - for b in buddies: - s=s+" "+b - self.sendFlap(2,"toc_remove_buddy%s"%s) - - def add_permit(self,users): - if type(users)==type(""): users=[users] - s="" - if self._privacymode!=PERMITSOME: - self._privacymode=PERMITSOME - self._permitlist=[] - for u in users: - u=normalize(u) - if u not in self._permitlist:self._permitlist.append(u) - s=s+" "+u - if not s: - self._privacymode=DENYALL - self._permitlist=[] - self._denylist=[] - self.sendFlap(2,"toc_add_permit"+s) - - def del_permit(self,users): - if type(users)==type(""): users=[users] - p=self._permitlist[:] - for u in users: - u=normalize(u) - if u in p: - p.remove(u) - self.add_permit([]) - self.add_permit(p) - - def add_deny(self,users): - if type(users)==type(""): users=[users] - s="" - if self._privacymode!=DENYSOME: - self._privacymode=DENYSOME - self._denylist=[] - for u in users: - u=normalize(u) - if u not in self._denylist:self._denylist.append(u) - s=s+" "+u - if not s: - self._privacymode=PERMITALL - self._permitlist=[] - self._denylist=[] - self.sendFlap(2,"toc_add_deny"+s) - - def del_deny(self,users): - if type(users)==type(""): users=[users] - d=self._denylist[:] - for u in users: - u=normalize(u) - if u in d: - d.remove(u) - self.add_deny([]) - if d: - self.add_deny(d) - - def signon(self): - """ - called to finish the setup, and signon to the network - """ - self.sendFlap(2,"toc_init_done") - self.sendFlap(2,"toc_set_caps %s" % (SEND_FILE_UID,)) # GET_FILE_UID) - - def say(self,user,message,autoreply=0): - """ - send a message - user := the user to send to - message := the message - autoreply := true if the message is an autoreply (good for away messages) - """ - if autoreply: a=" auto" - else: a='' - self.sendFlap(2,"toc_send_im %s %s%s"%(normalize(user),quote(message),a)) - - def idle(self,idletime=0): - """ - change idle state - idletime := the seconds that the user has been away, or 0 if they're back - """ - self.sendFlap(2,"toc_set_idle %s" % int(idletime)) - - def evil(self,user,anon=0): - """ - warn a user - user := the user to warn - anon := if true, an anonymous warning - """ - self.sendFlap(2,"toc_evil %s %s"%(normalize(user), (not anon and "anon") or "norm")) - - def away(self,message=''): - """ - change away state - message := the message, or '' to come back from awayness - """ - self._awaymessage=message - if message: - message=' '+quote(message) - self.sendFlap(2,"toc_set_away%s"%message) - - def chat_join(self,exchange,roomname): - """ - join a chat room - exchange := should almost always be 4 - roomname := room name - """ - roomname=string.replace(roomname," ","") - self.sendFlap(2,"toc_chat_join %s %s"%(int(exchange),roomname)) - - def chat_say(self,roomid,message): - """ - send a message to a chatroom - roomid := the AIM id for the room - message := the message to send - """ - self.sendFlap(2,"toc_chat_send %s %s"%(int(roomid),quote(message))) - - def chat_whisper(self,roomid,user,message): - """ - whisper to another user in a chatroom - roomid := the AIM id for the room - user := the user to whisper to - message := the message to send - """ - self.sendFlap(2,"toc_chat_whisper %s %s %s"%(int(roomid),normalize(user),quote(message))) - - def chat_leave(self,roomid): - """ - leave a chat room. - roomid := the AIM id for the room - """ - self.sendFlap(2,"toc_chat_leave %s" % int(roomid)) - - def chat_invite(self,roomid,usernames,message): - """ - invite a user[s] to the chat room - roomid := the AIM id for the room - usernames := either a string (one username) or a list (more than one) - message := the message to invite them with - """ - if type(usernames)==type(""): # a string, one username - users=usernames - else: - users="" - for u in usernames: - users=users+u+" " - users=users[:-1] - self.sendFlap(2,"toc_chat_invite %s %s %s" % (int(roomid),quote(message),users)) - - def chat_accept(self,roomid): - """ - accept an invite to a chat room - roomid := the AIM id for the room - """ - self.sendFlap(2,"toc_chat_accept %s"%int(roomid)) - - def rvous_accept(self,cookie): - user,uuid,pip,port,d=self._cookies[cookie] - self.sendFlap(2,"toc_rvous_accept %s %s %s" % (normalize(user), - cookie,uuid)) - if uuid==SEND_FILE_UID: - protocol.ClientCreator(reactor, SendFileTransfer,self,cookie,user,d["name"]).connectTCP(pip,port) - - def rvous_cancel(self,cookie): - user,uuid,pip,port,d=self._cookies[cookie] - self.sendFlap(2,"toc_rvous_accept %s %s %s" % (normalize(user), - cookie,uuid)) - del self._cookies[cookie] - - -class SendFileTransfer(protocol.Protocol): - header_fmt="!4s2H8s6H10I32s3c69s16s2H64s" - - def __init__(self,client,cookie,user,filename): - self.client=client - self.cookie=cookie - self.user=user - self.filename=filename - self.hdr=[0,0,0] - self.sofar=0 - - def dataReceived(self,data): - if not self.hdr[2]==0x202: - self.hdr=list(struct.unpack(self.header_fmt,data[:256])) - self.hdr[2]=0x202 - self.hdr[3]=self.cookie - self.hdr[4]=0 - self.hdr[5]=0 - self.transport.write(apply(struct.pack,[self.header_fmt]+self.hdr)) - data=data[256:] - if self.hdr[6]==1: - self.name=self.filename - else: - self.name=self.filename+self.hdr[-1] - while self.name[-1]=="\000": - self.name=self.name[:-1] - if not data: return - self.sofar=self.sofar+len(data) - self.client.receiveBytes(self.user,self.name,data,self.sofar,self.hdr[11]) - if self.sofar==self.hdr[11]: # end of this file - self.hdr[2]=0x204 - self.hdr[7]=self.hdr[7]-1 - self.hdr[9]=self.hdr[9]-1 - self.hdr[19]=DUMMY_CHECKSUM # XXX really calculate this - self.hdr[18]=self.hdr[18]+1 - self.hdr[21]="\000" - self.transport.write(apply(struct.pack,[self.header_fmt]+self.hdr)) - self.sofar=0 - if self.hdr[7]==0: - self.transport.loseConnection() - - -class GetFileTransfer(protocol.Protocol): - header_fmt="!4s 2H 8s 6H 10I 32s 3c 69s 16s 2H 64s" - def __init__(self,client,cookie,dir): - self.client=client - self.cookie=cookie - self.dir=dir - self.buf="" - - def connectionMade(self): - def func(f,path,names): - names.sort(lambda x,y:cmp(string.lower(x),string.lower(y))) - for n in names: - name=os.path.join(path,n) - lt=time.localtime(os.path.getmtime(name)) - size=os.path.getsize(name) - f[1]=f[1]+size - f.append("%02d/%02d/%4d %02d:%02d %8d %s" % - (lt[1],lt[2],lt[0],lt[3],lt[4],size,name[f[0]:])) - f=[len(self.dir)+1,0] - os.path.walk(self.dir,func,f) - size=f[1] - self.listing=string.join(f[2:],"\r\n")+"\r\n" - open("\\listing.txt","w").write(self.listing) - hdr=["OFT2",256,0x1108,self.cookie,0,0,len(f)-2,len(f)-2,1,1,size, - len(self.listing),os.path.getmtime(self.dir), - checksum(self.listing),0,0,0,0,0,0,"OFT_Windows ICBMFT V1.1 32", - "\002",chr(0x1a),chr(0x10),"","",0,0,""] - self.transport.write(apply(struct.pack,[self.header_fmt]+hdr)) - - def dataReceived(self,data): - self.buf=self.buf+data - while len(self.buf)>=256: - hdr=list(struct.unpack(self.header_fmt,self.buf[:256])) - self.buf=self.buf[256:] - if hdr[2]==0x1209: - self.file=StringIO.StringIO(self.listing) - self.transport.registerProducer(self,0) - elif hdr[2]==0x120b: pass - elif hdr[2]==0x120c: # file request - file=hdr[-1] - for k,v in [["\000",""],["\001",os.sep]]: - file=string.replace(file,k,v) - self.name=os.path.join(self.dir,file) - self.file=open(self.name,'rb') - hdr[2]=0x0101 - hdr[6]=hdr[7]=1 - hdr[10]=hdr[11]=os.path.getsize(self.name) - hdr[12]=os.path.getmtime(self.name) - hdr[13]=checksum_file(self.file) - self.file.seek(0) - hdr[18]=hdr[19]=0 - hdr[21]=chr(0x20) - self.transport.write(apply(struct.pack,[self.header_fmt]+hdr)) - log.msg("got file request for %s"%file,hex(hdr[13])) - elif hdr[2]==0x0202: - log.msg("sending file") - self.transport.registerProducer(self,0) - elif hdr[2]==0x0204: - log.msg("real checksum: %s"%hex(hdr[19])) - del self.file - elif hdr[2]==0x0205: # resume - already=hdr[18] - if already: - data=self.file.read(already) - else: - data="" - log.msg("restarting at %s"%already) - hdr[2]=0x0106 - hdr[19]=checksum(data) - self.transport.write(apply(struct.pack,[self.header_fmt]+hdr)) - elif hdr[2]==0x0207: - self.transport.registerProducer(self,0) - else: - log.msg("don't understand 0x%04x"%hdr[2]) - log.msg(hdr) - - def resumeProducing(self): - data=self.file.read(4096) - log.msg(len(data)) - if not data: - self.transport.unregisterProducer() - self.transport.write(data) - - def pauseProducing(self): pass - - def stopProducing(self): del self.file - -# UUIDs -SEND_FILE_UID = "09461343-4C7F-11D1-8222-444553540000" -GET_FILE_UID = "09461348-4C7F-11D1-8222-444553540000" -UUIDS={ - SEND_FILE_UID:"SEND_FILE", - GET_FILE_UID:"GET_FILE" -} - -# ERRORS -# general -NOT_AVAILABLE=901 -CANT_WARN=902 -MESSAGES_TOO_FAST=903 -# admin -BAD_INPUT=911 -BAD_ACCOUNT=912 -REQUEST_ERROR=913 -SERVICE_UNAVAILABLE=914 -# chat -NO_CHAT_IN=950 -# im and info -SEND_TOO_FAST=960 -MISSED_BIG_IM=961 -MISSED_FAST_IM=962 -# directory -DIR_FAILURE=970 -TOO_MANY_MATCHES=971 -NEED_MORE_QUALIFIERS=972 -DIR_UNAVAILABLE=973 -NO_EMAIL_LOOKUP=974 -KEYWORD_IGNORED=975 -NO_KEYWORDS=976 -BAD_LANGUAGE=977 -BAD_COUNTRY=978 -DIR_FAIL_UNKNOWN=979 -# authorization -BAD_NICKNAME=980 -SERVICE_TEMP_UNAVAILABLE=981 -WARNING_TOO_HIGH=982 -CONNECTING_TOO_QUICK=983 -UNKNOWN_SIGNON=989 - -STD_MESSAGE={} -STD_MESSAGE[NOT_AVAILABLE]="%s not currently available" -STD_MESSAGE[CANT_WARN]="Warning of %s not currently available" -STD_MESSAGE[MESSAGES_TOO_FAST]="A message has been dropped, you are exceeding the server speed limit" -STD_MESSAGE[BAD_INPUT]="Error validating input" -STD_MESSAGE[BAD_ACCOUNT]="Invalid account" -STD_MESSAGE[REQUEST_ERROR]="Error encountered while processing request" -STD_MESSAGE[SERVICE_UNAVAILABLE]="Service unavailable" -STD_MESSAGE[NO_CHAT_IN]="Chat in %s is unavailable" -STD_MESSAGE[SEND_TOO_FAST]="You are sending messages too fast to %s" -STD_MESSAGE[MISSED_BIG_IM]="You missed an IM from %s because it was too big" -STD_MESSAGE[MISSED_FAST_IM]="You missed an IM from %s because it was sent too fast" -# skipping directory for now -STD_MESSAGE[BAD_NICKNAME]="Incorrect nickname or password" -STD_MESSAGE[SERVICE_TEMP_UNAVAILABLE]="The service is temporarily unavailable" -STD_MESSAGE[WARNING_TOO_HIGH]="Your warning level is currently too high to sign on" -STD_MESSAGE[CONNECTING_TOO_QUICK]="You have been connecting and disconnecting too frequently. Wait 10 minutes and try again. If you continue to try, you will need to wait even longer." -STD_MESSAGE[UNKNOWN_SIGNON]="An unknown signon error has occurred %s" diff --git a/tools/buildbot/pylibs/twisted/words/scripts/__init__.py b/tools/buildbot/pylibs/twisted/words/scripts/__init__.py deleted file mode 100644 index eb82317..0000000 --- a/tools/buildbot/pylibs/twisted/words/scripts/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"words scripts" diff --git a/tools/buildbot/pylibs/twisted/words/scripts/im.py b/tools/buildbot/pylibs/twisted/words/scripts/im.py deleted file mode 100644 index 1c11de8..0000000 --- a/tools/buildbot/pylibs/twisted/words/scripts/im.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -import os - -def run(): - if os.name == 'java': - from twisted.internet import javareactor - javareactor.install() - from twisted.words.im.jyaccount import AccountManagementGUI - AccountManagementGUI() - else: - from twisted.internet import gtkreactor - gtkreactor.install() - from twisted.words.im.gtkaccount import AccountManager - AccountManager() - - from twisted.internet import reactor - reactor.run() - -if __name__ == '__main__': - run() diff --git a/tools/buildbot/pylibs/twisted/words/service.py b/tools/buildbot/pylibs/twisted/words/service.py deleted file mode 100644 index f85d874..0000000 --- a/tools/buildbot/pylibs/twisted/words/service.py +++ /dev/null @@ -1,1195 +0,0 @@ -# -*- test-case-name: twisted.words.test.test_service -*- -# Copyright (c) 2001-2005 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -A module that needs a better name. - -Implements new cred things for words. - -How does this thing work? - - - Network connection on some port expecting to speak some protocol - - - Protocol-specific authentication, resulting in some kind of credentials object - - - twisted.cred.portal login using those credentials for the interface - IUser and with something implementing IChatClient as the mind - - - successful login results in an IUser avatar the protocol can call - methods on, and state added to the realm such that the mind will have - methods called on it as is necessary - - - protocol specific actions lead to calls onto the avatar; remote events - lead to calls onto the mind - - - protocol specific hangup, realm is notified, user is removed from active - play, the end. -""" - -from time import time, ctime - -from zope.interface import implements - -from twisted.words import iwords, ewords - -from twisted.python.components import registerAdapter -from twisted.cred import portal, credentials, error as ecred -from twisted.spread import pb -from twisted.words.protocols import irc -from twisted.internet import defer, protocol -from twisted.python import log, failure, reflect -from twisted import copyright - - -class Group(object): - implements(iwords.IGroup) - - def __init__(self, name): - self.name = name - self.users = {} - self.meta = { - "topic": "", - "topic_author": "", - } - - - def _ebUserCall(self, err, p): - return failure.Failure(Exception(p, err)) - - - def _cbUserCall(self, results): - for (success, result) in results: - if not success: - user, err = result.value # XXX - self.remove(user, err.getErrorMessage()) - - - def add(self, user): - assert iwords.IChatClient.providedBy(user), "%r is not a chat client" % (user,) - if user.name not in self.users: - additions = [] - self.users[user.name] = user - for p in self.users.itervalues(): - if p is not user: - d = defer.maybeDeferred(p.userJoined, self, user) - d.addErrback(self._ebUserCall, p=p) - additions.append(d) - defer.DeferredList(additions).addCallback(self._cbUserCall) - return defer.succeed(None) - - - def remove(self, user, reason=None): - assert reason is None or isinstance(reason, unicode) - try: - del self.users[user.name] - except KeyError: - pass - else: - removals = [] - for p in self.users.itervalues(): - if p is not user: - d = defer.maybeDeferred(p.userLeft, self, user, reason) - d.addErrback(self._ebUserCall, p=p) - removals.append(d) - defer.DeferredList(removals).addCallback(self._cbUserCall) - return defer.succeed(None) - - - def size(self): - return defer.succeed(len(self.users)) - - - def receive(self, sender, recipient, message): - assert recipient is self - receives = [] - for p in self.users.itervalues(): - if p is not sender: - d = defer.maybeDeferred(p.receive, sender, self, message) - d.addErrback(self._ebUserCall, p=p) - receives.append(d) - defer.DeferredList(receives).addCallback(self._cbUserCall) - return defer.succeed(None) - - - def setMetadata(self, meta): - self.meta = meta - sets = [] - for p in self.users.itervalues(): - d = defer.maybeDeferred(p.groupMetaUpdate, self, meta) - d.addErrback(self._ebUserCall, p=p) - sets.append(d) - defer.DeferredList(sets).addCallback(self._cbUserCall) - return defer.succeed(None) - - - def iterusers(self): - # XXX Deferred? - return iter(self.users.values()) - - -class User(object): - implements(iwords.IUser) - - realm = None - mind = None - - def __init__(self, name): - self.name = name - self.groups = [] - self.lastMessage = time() - - - def loggedIn(self, realm, mind): - self.realm = realm - self.mind = mind - self.signOn = time() - - - def join(self, group): - def cbJoin(result): - self.groups.append(group) - return result - return group.add(self.mind).addCallback(cbJoin) - - - def leave(self, group, reason=None): - def cbLeave(result): - self.groups.remove(group) - return result - return group.remove(self.mind, reason).addCallback(cbLeave) - - - def send(self, recipient, message): - self.lastMessage = time() - return recipient.receive(self.mind, recipient, message) - - - def itergroups(self): - return iter(self.groups) - - - def logout(self): - for g in self.groups[:]: - self.leave(g) - - -NICKSERV = 'NickServ!NickServ@services' -class IRCUser(irc.IRC): - implements(iwords.IChatClient) - - # A list of IGroups in which I am participating - groups = None - - # A no-argument callable I should invoke when I go away - logout = None - - # An IUser we use to interact with the chat service - avatar = None - - # To whence I belong - realm = None - - # How to handle unicode (TODO: Make this customizable on a per-user basis) - encoding = 'utf-8' - - # Twisted callbacks - def connectionMade(self): - self.irc_PRIVMSG = self.irc_NICKSERV_PRIVMSG - - - def connectionLost(self, reason): - if self.logout is not None: - self.logout() - self.avatar = None - - - # Make sendMessage a bit more useful to us - def sendMessage(self, command, *parameter_list, **kw): - if not kw.has_key('prefix'): - kw['prefix'] = self.hostname - if not kw.has_key('to'): - kw['to'] = self.name.encode(self.encoding) - - arglist = [self, command, kw['to']] + list(parameter_list) - irc.IRC.sendMessage(*arglist, **kw) - - - # IChatClient implementation - def userJoined(self, group, user): - self.join( - "%s!%s@%s" % (user.name, user.name, self.hostname), - '#' + group.name) - - - def userLeft(self, group, user, reason=None): - assert reason is None or isinstance(reason, unicode) - self.part( - "%s!%s@%s" % (user.name, user.name, self.hostname), - '#' + group.name, - (reason or u"leaving").encode(self.encoding, 'replace')) - - - def receive(self, sender, recipient, message): - #>> :glyph!glyph@adsl-64-123-27-108.dsl.austtx.swbell.net PRIVMSG glyph_ :hello - - # omg??????????? - if iwords.IGroup.providedBy(recipient): - recipientName = '#' + recipient.name - else: - recipientName = recipient.name - - text = message.get('text', '') - for L in text.splitlines(): - self.privmsg( - '%s!%s@%s' % (sender.name, sender.name, self.hostname), - recipientName, - L) - - - def groupMetaUpdate(self, group, meta): - if 'topic' in meta: - topic = meta['topic'] - author = meta.get('topic_author', '') - self.topic( - self.name, - '#' + group.name, - topic, - '%s!%s@%s' % (author, author, self.hostname) - ) - - # irc.IRC callbacks - starting with login related stuff. - nickname = None - password = None - - def irc_PASS(self, prefix, params): - """Password message -- Register a password. - - Parameters: - - [REQUIRED] - - Note that IRC requires the client send this *before* NICK - and USER. - """ - self.password = params[-1] - - - def irc_NICK(self, prefix, params): - """Nick message -- Set your nickname. - - Parameters: - - [REQUIRED] - """ - try: - nickname = params[0].decode(self.encoding) - except UnicodeDecodeError: - self.privmsg( - NICKSERV, - nickname, - 'Your nickname is cannot be decoded. Please use ASCII or UTF-8.') - self.transport.loseConnection() - return - - if self.password is None: - self.nickname = nickname - self.privmsg( - NICKSERV, - nickname, - 'Password?') - else: - password = self.password - self.password = None - self.logInAs(nickname, password) - - - def irc_USER(self, prefix, params): - """User message -- Set your realname. - - Parameters: - """ - # Note: who gives a crap about this? The IUser has the real - # information we care about. Save it anyway, I guess, just - # for fun. - self.realname = params[-1] - - - def irc_NICKSERV_PRIVMSG(self, prefix, params): - """Send a (private) message. - - Parameters: - """ - target = params[0] - password = params[-1] - - if self.nickname is None: - # XXX Send an error response here - self.transport.loseConnection() - elif target.lower() != "nickserv": - self.privmsg( - NICKSERV, - self.nickname, - "Denied. Please send me (NickServ) your password.") - else: - nickname = self.nickname - self.nickname = None - self.logInAs(nickname, password) - - - def logInAs(self, nickname, password): - d = self.factory.portal.login( - credentials.UsernamePassword(nickname, password), - self, - iwords.IUser) - d.addCallbacks(self._cbLogin, self._ebLogin, errbackArgs=(nickname,)) - - - _welcomeMessages = [ - (irc.RPL_WELCOME, - ":connected to Twisted IRC"), - (irc.RPL_YOURHOST, - ":Your host is %(serviceName)s, running version %(serviceVersion)s"), - (irc.RPL_CREATED, - ":This server was created on %(creationDate)s"), - - # "Bummer. This server returned a worthless 004 numeric. - # I'll have to guess at all the values" - # -- epic - (irc.RPL_MYINFO, - # w and n are the currently supported channel and user modes - # -- specify this better - "%(serviceName)s %(serviceVersion)s w n"), - ] - - - def _cbLogin(self, (iface, avatar, logout)): - assert iface is iwords.IUser, "Realm is buggy, got %r" % (iface,) - - # Let them send messages to the world - del self.irc_PRIVMSG - - self.avatar = avatar - self.logout = logout - self.realm = avatar.realm - self.hostname = self.realm.name - - info = { - "serviceName": self.hostname, - "serviceVersion": copyright.version, - "creationDate": ctime(), # XXX - } - for code, text in self._welcomeMessages: - self.sendMessage(code, text % info) - - - def _ebLogin(self, err, nickname): - if err.check(ewords.AlreadyLoggedIn): - self.privmsg( - NICKSERV, - nickname, - "Already logged in. No pod people allowed!") - elif err.check(ecred.UnauthorizedLogin): - self.privmsg( - NICKSERV, - nickname, - "Login failed. Goodbye.") - else: - log.msg("Unhandled error during login:") - log.err(err) - self.privmsg( - NICKSERV, - nickname, - "Server error during login. Sorry.") - self.transport.loseConnection() - - - # Great, now that's out of the way, here's some of the interesting - # bits - def irc_PING(self, prefix, params): - """Ping message - - Parameters: [ ] - """ - if self.realm is not None: - self.sendMessage('PONG', self.hostname) - - - def irc_QUIT(self, prefix, params): - """Quit - - Parameters: [ ] - """ - self.transport.loseConnection() - - - def _channelMode(self, group, modes=None, *args): - if modes: - self.sendMessage( - irc.ERR_UNKNOWNMODE, - ":Unknown MODE flag.") - else: - self.channelMode(self.name, '#' + group.name, '+') - - - def _userMode(self, user, modes=None): - if modes: - self.sendMessage( - irc.ERR_UNKNOWNMODE, - ":Unknown MODE flag.") - elif user is self.avatar: - self.sendMessage( - irc.RPL_UMODEIS, - "+") - else: - self.sendMessage( - irc.ERR_USERSDONTMATCH, - ":You can't look at someone else's modes.") - - - def irc_MODE(self, prefix, params): - """User mode message - - Parameters: - *( ( "+" / "-" ) *( "i" / "w" / "o" / "O" / "r" ) ) - - """ - try: - channelOrUser = params[0].decode(self.encoding) - except UnicodeDecodeError: - self.sendMessage( - irc.ERR_NOSUCHNICK, params[0], - ":No such nickname (could not decode your unicode!)") - return - - if channelOrUser.startswith('#'): - def ebGroup(err): - err.trap(ewords.NoSuchGroup) - self.sendMessage( - irc.ERR_NOSUCHCHANNEL, params[0], - ":That channel doesn't exist.") - d = self.realm.lookupGroup(channelOrUser[1:]) - d.addCallbacks( - self._channelMode, - ebGroup, - callbackArgs=tuple(params[1:])) - else: - def ebUser(err): - self.sendMessage( - irc.ERR_NOSUCHNICK, - ":No such nickname.") - - d = self.realm.lookupUser(channelOrUser) - d.addCallbacks( - self._userMode, - ebUser, - callbackArgs=tuple(params[1:])) - - - def irc_USERHOST(self, prefix, params): - """Userhost message - - Parameters: *( SPACE ) - - [Optional] - """ - pass - - - def irc_PRIVMSG(self, prefix, params): - """Send a (private) message. - - Parameters: - """ - try: - targetName = params[0].decode(self.encoding) - except UnicodeDecodeError: - self.sendMessage( - irc.ERR_NOSUCHNICK, targetName, - ":No such nick/channel (could not decode your unicode!)") - return - - messageText = params[-1] - if targetName.startswith('#'): - target = self.realm.lookupGroup(targetName[1:]) - else: - target = self.realm.lookupUser(targetName).addCallback(lambda user: user.mind) - - def cbTarget(targ): - if targ is not None: - return self.avatar.send(targ, {"text": messageText}) - - def ebTarget(err): - self.sendMessage( - irc.ERR_NOSUCHNICK, targetName, - ":No such nick/channel.") - - target.addCallbacks(cbTarget, ebTarget) - - - def irc_JOIN(self, prefix, params): - """Join message - - Parameters: ( *( "," ) [ *( "," ) ] ) - """ - try: - groupName = params[0].decode(self.encoding) - except UnicodeDecodeError: - self.sendMessage( - irc.IRC_NOSUCHCHANNEL, params[0], - ":No such channel (could not decode your unicode!)") - return - - if groupName.startswith('#'): - groupName = groupName[1:] - - def cbGroup(group): - def cbJoin(ign): - self.userJoined(group, self) - self.names( - self.name, - '#' + group.name, - [user.name for user in group.iterusers()]) - self._sendTopic(group) - return self.avatar.join(group).addCallback(cbJoin) - - def ebGroup(err): - self.sendMessage( - irc.ERR_NOSUCHCHANNEL, '#' + groupName, - ":No such channel.") - - self.realm.getGroup(groupName).addCallbacks(cbGroup, ebGroup) - - - def irc_PART(self, prefix, params): - """Part message - - Parameters: *( "," ) [ ] - """ - try: - groupName = params[0].decode(self.encoding) - except UnicodeDecodeError: - self.sendMessage( - irc.ERR_NOTONCHANNEL, params[0], - ":Could not decode your unicode!") - return - - if groupName.startswith('#'): - groupName = groupName[1:] - - if len(params) > 1: - reason = params[1].decode('utf-8') - else: - reason = None - - def cbGroup(group): - def cbLeave(result): - self.userLeft(group, self, reason) - return self.avatar.leave(group, reason).addCallback(cbLeave) - - def ebGroup(err): - err.trap(ewords.NoSuchGroup) - self.sendMessage( - irc.ERR_NOTONCHANNEL, - '#' + groupName, - ":" + err.getErrorMessage()) - - self.realm.lookupGroup(groupName).addCallbacks(cbGroup, ebGroup) - - - def irc_NAMES(self, prefix, params): - """Names message - - Parameters: [ *( "," ) [ ] ] - """ - #<< NAMES #python - #>> :benford.openprojects.net 353 glyph = #python :Orban ... @glyph ... Zymurgy skreech - #>> :benford.openprojects.net 366 glyph #python :End of /NAMES list. - try: - channel = params[-1].decode(self.encoding) - except UnicodeDecodeError: - self.sendMessage( - irc.ERR_NOSUCHCHANNEL, params[-1], - ":No such channel (could not decode your unicode!)") - return - - if channel.startswith('#'): - channel = channel[1:] - - def cbGroup(group): - self.names( - self.name, - '#' + group.name, - [user.name for user in group.iterusers()]) - - def ebGroup(err): - err.trap(ewords.NoSuchGroup) - # No group? Fine, no names! - self.names( - self.name, - '#' + channel, - []) - - self.realm.lookupGroup(channel).addCallbacks(cbGroup, ebGroup) - - - def irc_TOPIC(self, prefix, params): - """Topic message - - Parameters: [ ] - """ - try: - channel = params[0].decode(self.encoding) - except UnicodeDecodeError: - self.sendMessage( - irc.ERR_NOSUCHCHANNEL, - ":That channel doesn't exist (could not decode your unicode!)") - return - - if channel.startswith('#'): - channel = channel[1:] - - if len(params) > 1: - self._setTopic(channel, params[1]) - else: - self._getTopic(channel) - - - def _sendTopic(self, group): - topic = group.meta.get("topic") - author = group.meta.get("topic_author") or "" - date = group.meta.get("topic_date", 0) - self.topic(self.name, '#' + group.name, topic) - self.topicAuthor(self.name, '#' + group.name, author, date) - - - def _getTopic(self, channel): - #<< TOPIC #python - #>> :benford.openprojects.net 332 glyph #python : I really did. I sprained all my toes. - #>> :benford.openprojects.net 333 glyph #python itamar|nyc 994713482 - def ebGroup(err): - err.trap(ewords.NoSuchGroup) - self.sendMessage( - irc.ERR_NOSUCHCHANNEL, '=', channel, - ":That channel doesn't exist.") - - self.realm.lookupGroup(channel).addCallbacks(self._sendTopic, ebGroup) - - - def _setTopic(self, channel, topic): - #<< TOPIC #divunal :foo - #>> :glyph!glyph@adsl-64-123-27-108.dsl.austtx.swbell.net TOPIC #divunal :foo - - def cbGroup(group): - newMeta = group.meta.copy() - newMeta['topic'] = topic - newMeta['topic_author'] = self.name - newMeta['topic_date'] = int(time()) - - def ebSet(err): - self.sendMessage( - irc.ERR_CHANOPRIVSNEEDED, - "#" + group.name, - ":You need to be a channel operator to do that.") - - return group.setMetadata(newMeta).addErrback(ebSet) - - def ebGroup(err): - err.trap(ewords.NoSuchGroup) - self.sendMessage( - irc.ERR_NOSUCHCHANNEL, '=', channel, - ":That channel doesn't exist.") - - self.realm.lookupGroup(channel).addCallbacks(cbGroup, ebGroup) - - - def list(self, channels): - """Send a group of LIST response lines - - @type channel: C{list} of C{(str, int, str)} - @param channel: Information about the channels being sent: - their name, the number of participants, and their topic. - """ - for (name, size, topic) in channels: - self.sendMessage(irc.RPL_LIST, name, str(size), ":" + topic) - self.sendMessage(irc.RPL_LISTEND, ":End of /LIST") - - - def irc_LIST(self, prefix, params): - """List query - - Return information about the indicated channels, or about all - channels if none are specified. - - Parameters: [ *( "," ) [ ] ] - """ - #<< list #python - #>> :orwell.freenode.net 321 exarkun Channel :Users Name - #>> :orwell.freenode.net 322 exarkun #python 358 :The Python programming language - #>> :orwell.freenode.net 323 exarkun :End of /LIST - if params: - # Return information about indicated channels - try: - channels = params[0].decode(self.encoding).split(',') - except UnicodeDecodeError: - self.sendMessage( - irc.ERR_NOSUCHCHANNEL, params[0], - ":No such channel (could not decode your unicode!)") - return - - groups = [] - for ch in channels: - if ch.startswith('#'): - ch = ch[1:] - groups.append(self.realm.lookupGroup(ch)) - - groups = defer.DeferredList(groups, consumeErrors=True) - groups.addCallback(lambda gs: [r for (s, r) in gs if s]) - else: - # Return information about all channels - groups = self.realm.itergroups() - - def cbGroups(groups): - def gotSize(size, group): - return group.name, size, group.meta.get('topic') - d = defer.DeferredList([ - group.size().addCallback(gotSize, group) for group in groups]) - d.addCallback(lambda results: self.list([r for (s, r) in results if s])) - return d - groups.addCallback(cbGroups) - - - def _channelWho(self, group): - self.who(self.name, '#' + group.name, - [(m.name, self.hostname, self.realm.name, m.name, "H", 0, m.name) for m in group.iterusers()]) - - - def _userWho(self, user): - self.sendMessage(irc.RPL_ENDOFWHO, - ":User /WHO not implemented") - - - def irc_WHO(self, prefix, params): - """Who query - - Parameters: [ [ "o" ] ] - """ - #<< who #python - #>> :x.opn 352 glyph #python aquarius pc-62-31-193-114-du.blueyonder.co.uk y.opn Aquarius H :3 Aquarius - # ... - #>> :x.opn 352 glyph #python foobar europa.tranquility.net z.opn skreech H :0 skreech - #>> :x.opn 315 glyph #python :End of /WHO list. - ### also - #<< who glyph - #>> :x.opn 352 glyph #python glyph adsl-64-123-27-108.dsl.austtx.swbell.net x.opn glyph H :0 glyph - #>> :x.opn 315 glyph glyph :End of /WHO list. - if not params: - self.sendMessage(irc.RPL_ENDOFWHO, ":/WHO not supported.") - return - - try: - channelOrUser = params[0].decode(self.encoding) - except UnicodeDecodeError: - self.sendMessage( - irc.RPL_ENDOFWHO, params[0], - ":End of /WHO list (could not decode your unicode!)") - return - - if channelOrUser.startswith('#'): - def ebGroup(err): - err.trap(ewords.NoSuchGroup) - self.sendMessage( - irc.RPL_ENDOFWHO, channelOrUser, - ":End of /WHO list.") - d = self.realm.lookupGroup(channelOrUser[1:]) - d.addCallbacks(self._channelWho, ebGroup) - else: - def ebUser(err): - err.trap(ewords.NoSuchUser) - self.sendMessage( - irc.RPL_ENDOFWHO, channelOrUser, - ":End of /WHO list.") - d = self.realm.lookupUser(channelOrUser) - d.addCallbacks(self._userWho, ebUser) - - - - def irc_WHOIS(self, prefix, params): - """Whois query - - Parameters: [ ] *( "," ) - """ - def cbUser(user): - self.whois( - self.name, - user.name, user.name, self.realm.name, - user.name, self.realm.name, 'Hi mom!', False, - int(time() - user.lastMessage), user.signOn, - ['#' + group.name for group in user.itergroups()]) - - def ebUser(err): - err.trap(ewords.NoSuchUser) - self.sendMessage( - irc.ERR_NOSUCHNICK, - params[0], - ":No such nick/channel") - - try: - user = params[0].decode(self.encoding) - except UnicodeDecodeError: - self.sendMessage( - irc.ERR_NOSUCHNICK, - params[0], - ":No such nick/channel") - return - - self.realm.lookupUser(user).addCallbacks(cbUser, ebUser) - - - # Unsupported commands, here for legacy compatibility - def irc_OPER(self, prefix, params): - """Oper message - - Parameters: - """ - self.sendMessage(irc.ERR_NOOPERHOST, ":O-lines not applicable") - - -class IRCFactory(protocol.ServerFactory): - protocol = IRCUser - - def __init__(self, realm, portal): - self.realm = realm - self.portal = portal - - -class PBMind(pb.Referenceable): - def __init__(self): - pass - - def jellyFor(self, jellier): - return reflect.qual(PBMind), jellier.invoker.registerReference(self) - - def remote_userJoined(self, user, group): - pass - - def remote_userLeft(self, user, group, reason): - pass - - def remote_receive(self, sender, recipient, message): - pass - - def remote_groupMetaUpdate(self, group, meta): - pass - - -class PBMindReference(pb.RemoteReference): - implements(iwords.IChatClient) - - def receive(self, sender, recipient, message): - if iwords.IGroup.providedBy(recipient): - rec = PBGroup(self.realm, self.avatar, recipient) - else: - rec = PBUser(self.realm, self.avatar, recipient) - return self.callRemote( - 'receive', - PBUser(self.realm, self.avatar, sender), - rec, - message) - - def groupMetaUpdate(self, group, meta): - return self.callRemote( - 'groupMetaUpdate', - PBGroup(self.realm, self.avatar, group), - meta) - - def userJoined(self, group, user): - return self.callRemote( - 'userJoined', - PBGroup(self.realm, self.avatar, group), - PBUser(self.realm, self.avatar, user)) - - def userLeft(self, group, user, reason=None): - assert reason is None or isinstance(reason, unicode) - return self.callRemote( - 'userLeft', - PBGroup(self.realm, self.avatar, group), - PBUser(self.realm, self.avatar, user), - reason) -pb.setUnjellyableForClass(PBMind, PBMindReference) - - -class PBGroup(pb.Referenceable): - def __init__(self, realm, avatar, group): - self.realm = realm - self.avatar = avatar - self.group = group - - - def processUniqueID(self): - return hash((self.realm.name, self.avatar.name, self.group.name)) - - - def jellyFor(self, jellier): - return reflect.qual(self.__class__), self.group.name.encode('utf-8'), jellier.invoker.registerReference(self) - - - def remote_leave(self, reason=None): - return self.avatar.leave(self.group, reason) - - - def remote_send(self, message): - return self.avatar.send(self.group, message) - - -class PBGroupReference(pb.RemoteReference): - implements(iwords.IGroup) - - def unjellyFor(self, unjellier, unjellyList): - clsName, name, ref = unjellyList - self.name = name.decode('utf-8') - return pb.RemoteReference.unjellyFor(self, unjellier, [clsName, ref]) - - def leave(self, reason=None): - return self.callRemote("leave", reason) - - def send(self, message): - return self.callRemote("send", message) -pb.setUnjellyableForClass(PBGroup, PBGroupReference) - -class PBUser(pb.Referenceable): - def __init__(self, realm, avatar, user): - self.realm = realm - self.avatar = avatar - self.user = user - - def processUniqueID(self): - return hash((self.realm.name, self.avatar.name, self.user.name)) - - -class ChatAvatar(pb.Referenceable): - implements(iwords.IChatClient) - - def __init__(self, avatar): - self.avatar = avatar - - - def jellyFor(self, jellier): - return reflect.qual(self.__class__), jellier.invoker.registerReference(self) - - - def remote_join(self, groupName): - assert isinstance(groupName, unicode) - def cbGroup(group): - def cbJoin(ignored): - return PBGroup(self.avatar.realm, self.avatar, group) - d = self.avatar.join(group) - d.addCallback(cbJoin) - return d - d = self.avatar.realm.getGroup(groupName) - d.addCallback(cbGroup) - return d -registerAdapter(ChatAvatar, iwords.IUser, pb.IPerspective) - -class AvatarReference(pb.RemoteReference): - def join(self, groupName): - return self.callRemote('join', groupName) - - def quit(self): - d = defer.Deferred() - self.broker.notifyOnDisconnect(lambda: d.callback(None)) - self.broker.transport.loseConnection() - return d - -pb.setUnjellyableForClass(ChatAvatar, AvatarReference) - - -class WordsRealm(object): - implements(portal.IRealm, iwords.IChatService) - - _encoding = 'utf-8' - - def __init__(self, name): - self.name = name - - - def userFactory(self, name): - return User(name) - - - def groupFactory(self, name): - return Group(name) - - - def logoutFactory(self, avatar, facet): - def logout(): - # XXX Deferred support here - getattr(facet, 'logout', lambda: None)() - avatar.realm = avatar.mind = None - return logout - - - def requestAvatar(self, avatarId, mind, *interfaces): - if isinstance(avatarId, str): - avatarId = avatarId.decode(self._encoding) - - def gotAvatar(avatar): - if avatar.realm is not None: - raise ewords.AlreadyLoggedIn() - for iface in interfaces: - facet = iface(avatar, None) - if facet is not None: - avatar.loggedIn(self, mind) - mind.name = avatarId - mind.realm = self - mind.avatar = avatar - return iface, facet, self.logoutFactory(avatar, facet) - raise NotImplementedError(self, interfaces) - - return self.getUser(avatarId).addCallback(gotAvatar) - - - # IChatService, mostly. - createGroupOnRequest = False - createUserOnRequest = True - - def lookupUser(self, name): - raise NotImplementedError - - - def lookupGroup(self, group): - raise NotImplementedError - - - def addUser(self, user): - """Add the given user to this service. - - This is an internal method intented to be overridden by - L{WordsRealm} subclasses, not called by external code. - - @type user: L{IUser} - - @rtype: L{twisted.internet.defer.Deferred} - @return: A Deferred which fires with C{None} when the user is - added, or which fails with - L{twisted.words.ewords.DuplicateUser} if a user with the - same name exists already. - """ - raise NotImplementedError - - - def addGroup(self, group): - """Add the given group to this service. - - @type group: L{IGroup} - - @rtype: L{twisted.internet.defer.Deferred} - @return: A Deferred which fires with C{None} when the group is - added, or which fails with - L{twisted.words.ewords.DuplicateGroup} if a group with the - same name exists already. - """ - raise NotImplementedError - - - def getGroup(self, name): - assert isinstance(name, unicode) - if self.createGroupOnRequest: - def ebGroup(err): - err.trap(ewords.DuplicateGroup) - return self.lookupGroup(name) - return self.createGroup(name).addErrback(ebGroup) - return self.lookupGroup(name) - - - def getUser(self, name): - assert isinstance(name, unicode) - if self.createUserOnRequest: - def ebUser(err): - err.trap(ewords.DuplicateUser) - return self.lookupUser(name) - return self.createUser(name).addErrback(ebUser) - return self.lookupUser(name) - - - def createUser(self, name): - assert isinstance(name, unicode) - def cbLookup(user): - return failure.Failure(ewords.DuplicateUser(name)) - def ebLookup(err): - err.trap(ewords.NoSuchUser) - return self.userFactory(name) - - name = name.lower() - d = self.lookupUser(name) - d.addCallbacks(cbLookup, ebLookup) - d.addCallback(self.addUser) - return d - - - def createGroup(self, name): - assert isinstance(name, unicode) - def cbLookup(group): - return failure.Failure(ewords.DuplicateGroup(name)) - def ebLookup(err): - err.trap(ewords.NoSuchGroup) - return self.groupFactory(name) - - name = name.lower() - d = self.lookupGroup(name) - d.addCallbacks(cbLookup, ebLookup) - d.addCallback(self.addGroup) - return d - - -class InMemoryWordsRealm(WordsRealm): - def __init__(self, *a, **kw): - super(InMemoryWordsRealm, self).__init__(*a, **kw) - self.users = {} - self.groups = {} - - - def itergroups(self): - return defer.succeed(self.groups.itervalues()) - - - def addUser(self, user): - if user.name in self.users: - return defer.fail(failure.Failure(ewords.DuplicateUser())) - self.users[user.name] = user - return defer.succeed(user) - - - def addGroup(self, group): - if group.name in self.groups: - return defer.fail(failure.Failure(ewords.DuplicateGroup())) - self.groups[group.name] = group - return defer.succeed(group) - - - def lookupUser(self, name): - assert isinstance(name, unicode) - name = name.lower() - try: - user = self.users[name] - except KeyError: - return defer.fail(failure.Failure(ewords.NoSuchUser(name))) - else: - return defer.succeed(user) - - - def lookupGroup(self, name): - assert isinstance(name, unicode) - name = name.lower() - try: - group = self.groups[name] - except KeyError: - return defer.fail(failure.Failure(ewords.NoSuchGroup(name))) - else: - return defer.succeed(group) - -__all__ = [ - 'Group', 'User', - - 'WordsRealm', 'InMemoryWordsRealm', - ] diff --git a/tools/buildbot/pylibs/twisted/words/tap.py b/tools/buildbot/pylibs/twisted/words/tap.py deleted file mode 100644 index 2a6656e..0000000 --- a/tools/buildbot/pylibs/twisted/words/tap.py +++ /dev/null @@ -1,72 +0,0 @@ -# -*- test-case-name: twisted.words.test.test_tap -*- -# Copyright (c) 2001-2005 Twisted Matrix Laboratories. -# See LICENSE for details. -""" -Shiny new words service maker -""" - -import sys, socket - -from twisted.application import strports -from twisted.application.service import MultiService -from twisted.python import usage -from twisted import plugin - -from twisted.words import iwords, service -from twisted.cred import checkers, credentials, portal, strcred - -class Options(usage.Options, strcred.AuthOptionMixin): - supportedInterfaces = [credentials.IUsernamePassword] - optParameters = [ - ('hostname', None, socket.gethostname(), - 'Name of this server; purely an informative')] - - interfacePlugins = {} - plg = None - for plg in plugin.getPlugins(iwords.IProtocolPlugin): - assert plg.name not in interfacePlugins - interfacePlugins[plg.name] = plg - optParameters.append(( - plg.name + '-port', - None, None, - 'strports description of the port to bind for the ' + plg.name + ' server')) - del plg - - def __init__(self, *a, **kw): - usage.Options.__init__(self, *a, **kw) - self['groups'] = [] - - def opt_group(self, name): - """Specify a group which should exist - """ - self['groups'].append(name.decode(sys.stdin.encoding)) - - def opt_passwd(self, filename): - """ - Name of a passwd-style file. (This is for - backwards-compatibility only; you should use the --auth - command instead.) - """ - self.addChecker(checkers.FilePasswordDB(filename)) - -def makeService(config): - credCheckers = config.get('credCheckers', []) - wordsRealm = service.InMemoryWordsRealm(config['hostname']) - wordsPortal = portal.Portal(wordsRealm, credCheckers) - - msvc = MultiService() - - # XXX Attribute lookup on config is kind of bad - hrm. - for plgName in config.interfacePlugins: - port = config.get(plgName + '-port') - if port is not None: - factory = config.interfacePlugins[plgName].getFactory(wordsRealm, wordsPortal) - svc = strports.service(port, factory) - svc.setServiceParent(msvc) - - # This is bogus. createGroup is async. makeService must be - # allowed to return a Deferred or some crap. - for g in config['groups']: - wordsRealm.createGroup(g) - - return msvc diff --git a/tools/buildbot/pylibs/twisted/words/test/__init__.py b/tools/buildbot/pylibs/twisted/words/test/__init__.py deleted file mode 100644 index d599f20..0000000 --- a/tools/buildbot/pylibs/twisted/words/test/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"Words tests" diff --git a/tools/buildbot/pylibs/twisted/words/test/test_basesupport.py b/tools/buildbot/pylibs/twisted/words/test/test_basesupport.py deleted file mode 100644 index 00b852b..0000000 --- a/tools/buildbot/pylibs/twisted/words/test/test_basesupport.py +++ /dev/null @@ -1,97 +0,0 @@ -# Copyright (c) 2001-2006 Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.trial import unittest -from twisted.words.im import basesupport -from twisted.internet import error, defer - -class DummyAccount(basesupport.AbstractAccount): - """ - An account object that will do nothing when asked to start to log on. - """ - - loginHasFailed = False - loginCallbackCalled = False - - def _startLogOn(self, *args): - """ - Set self.loginDeferred to the same as the deferred returned, allowing a - testcase to .callback or .errback. - - @return: A deferred. - """ - self.loginDeferred = defer.Deferred() - return self.loginDeferred - - def _loginFailed(self, result): - self.loginHasFailed = True - return basesupport.AbstractAccount._loginFailed(self, result) - - def _cb_logOn(self, result): - self.loginCallbackCalled = True - return basesupport.AbstractAccount._cb_logOn(self, result) - -class DummyUI(object): - """ - Provide just the interface required to be passed to AbstractAccount.logOn. - """ - clientRegistered = False - - def registerAccountClient(self, result): - self.clientRegistered = True - -class ClientMsgTests(unittest.TestCase): - def makeUI(self): - return DummyUI() - - def makeAccount(self): - return DummyAccount('la', False, 'la', None, 'localhost', 6667) - - def test_connect(self): - """ - Test that account.logOn works, and it calls the right callback when a - connection is established. - """ - account = self.makeAccount() - ui = self.makeUI() - d = account.logOn(ui) - account.loginDeferred.callback(None) - - def check(result): - self.assert_(not account.loginHasFailed, - "Login shouldn't have failed") - self.assert_(account.loginCallbackCalled, - "We should be logged in") - d.addCallback(check) - return d - - def test_failedConnect(self): - """ - Test that account.logOn works, and it calls the right callback when a - connection is established. - """ - account = self.makeAccount() - ui = self.makeUI() - d = account.logOn(ui) - account.loginDeferred.errback(Exception()) - - def err(reason): - self.assert_(account.loginHasFailed, "Login should have failed") - self.assert_(not account.loginCallbackCalled, - "We shouldn't be logged in") - self.assert_(not ui.clientRegistered, - "Client shouldn't be registered in the UI") - cb = lambda r: self.assert_(False, "Shouldn't get called back") - d.addCallbacks(cb, err) - return d - - def test_alreadyConnecting(self): - """ - Test that it can fail sensibly when someone tried to connect before - we did. - """ - account = self.makeAccount() - ui = self.makeUI() - account.logOn(ui) - self.assertRaises(error.ConnectError, account.logOn, ui) - diff --git a/tools/buildbot/pylibs/twisted/words/test/test_domish.py b/tools/buildbot/pylibs/twisted/words/test/test_domish.py deleted file mode 100644 index cbb4b9b..0000000 --- a/tools/buildbot/pylibs/twisted/words/test/test_domish.py +++ /dev/null @@ -1,369 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.words.xish.domish}. -""" - -from twisted.trial import unittest -from twisted.words.xish import domish - -class DomishTestCase(unittest.TestCase): - def testEscaping(self): - s = "&<>'\"" - self.assertEquals(domish.escapeToXml(s), "&<>'\"") - self.assertEquals(domish.escapeToXml(s, 1), "&<>'"") - - def testNamespaceObject(self): - ns = domish.Namespace("testns") - self.assertEquals(ns.foo, ("testns", "foo")) - - def testElementInit(self): - e = domish.Element((None, "foo")) - self.assertEquals(e.name, "foo") - self.assertEquals(e.uri, None) - self.assertEquals(e.defaultUri, None) - self.assertEquals(e.parent, None) - - e = domish.Element(("", "foo")) - self.assertEquals(e.name, "foo") - self.assertEquals(e.uri, "") - self.assertEquals(e.defaultUri, "") - self.assertEquals(e.parent, None) - - e = domish.Element(("testns", "foo")) - self.assertEquals(e.name, "foo") - self.assertEquals(e.uri, "testns") - self.assertEquals(e.defaultUri, "testns") - self.assertEquals(e.parent, None) - - e = domish.Element(("testns", "foo"), "test2ns") - self.assertEquals(e.name, "foo") - self.assertEquals(e.uri, "testns") - self.assertEquals(e.defaultUri, "test2ns") - - def testChildOps(self): - e = domish.Element(("testns", "foo")) - e.addContent("somecontent") - b2 = e.addElement(("testns2", "bar2")) - e["attrib1"] = "value1" - e[("testns2", "attrib2")] = "value2" - e.addElement("bar") - e.addElement("bar") - e.addContent("abc") - e.addContent("123") - - # Check content merging - self.assertEquals(e.children[-1], "abc123") - - # Check str()/content extraction - self.assertEquals(str(e), "somecontent") - - # Check direct child accessor - self.assertEquals(e.bar2, b2) - e.bar2.addContent("subcontent") - e.bar2["bar2value"] = "somevalue" - - # Check child ops - self.assertEquals(e.children[1], e.bar2) - self.assertEquals(e.children[2], e.bar) - - # Check attribute ops - self.assertEquals(e["attrib1"], "value1") - del e["attrib1"] - self.assertEquals(e.hasAttribute("attrib1"), 0) - self.assertEquals(e.hasAttribute("attrib2"), 0) - self.assertEquals(e[("testns2", "attrib2")], "value2") - -class DomishStreamTests: - def setUp(self): - self.doc_started = False - self.doc_ended = False - self.root = None - self.elements = [] - self.stream = self.streamClass() - self.stream.DocumentStartEvent = self._docStarted - self.stream.ElementEvent = self.elements.append - self.stream.DocumentEndEvent = self._docEnded - - def _docStarted(self, root): - self.root = root - self.doc_started = True - - def _docEnded(self): - self.doc_ended = True - - def doTest(self, xml): - self.stream.parse(xml) - - def testHarness(self): - xml = "" - self.stream.parse(xml) - self.assertEquals(self.doc_started, True) - self.assertEquals(self.root.name, 'root') - self.assertEquals(self.elements[0].name, 'child') - self.assertEquals(self.elements[1].name, 'child2') - self.assertEquals(self.doc_ended, True) - - def testBasic(self): - xml = "\n" + \ - " " + \ - " some&data>" + \ - " " + \ - "" - - self.stream.parse(xml) - self.assertEquals(self.root.name, 'stream') - self.assertEquals(self.root.uri, 'etherx') - self.assertEquals(self.elements[0].name, 'message') - self.assertEquals(self.elements[0].uri, 'jabber') - self.assertEquals(self.elements[0]['to'], 'bar') - self.assertEquals(self.elements[0].x.uri, 'xdelay') - self.assertEquals(unicode(self.elements[0].x), 'some&data>') - - def testNoRootNS(self): - xml = "" - - self.stream.parse(xml) - self.assertEquals(self.root.uri, '') - self.assertEquals(self.elements[0].uri, 'etherx') - - def testNoDefaultNS(self): - xml = """" - - self.stream.parse(xml) - self.assertEquals(self.root.uri, 'etherx') - self.assertEquals(self.root.defaultUri, '') - self.assertEquals(self.elements[0].uri, '') - self.assertEquals(self.elements[0].defaultUri, '') - - def testChildDefaultNS(self): - xml = "" - - self.stream.parse(xml) - self.assertEquals(self.root.uri, 'testns') - self.assertEquals(self.elements[0].uri, 'testns') - - def testEmptyChildNS(self): - xml = "" - - self.stream.parse(xml) - self.assertEquals(self.elements[0].child2.uri, '') - - def testChildPrefix(self): - xml = "" - - self.stream.parse(xml) - self.assertEquals(self.root.localPrefixes['foo'], 'testns2') - self.assertEquals(self.elements[0].uri, 'testns2') - - def testUnclosedElement(self): - self.assertRaises(domish.ParserError, self.stream.parse, - "") - - def test_namespaceReuse(self): - """ - Test that reuse of namespaces does affect an element's serialization. - - When one element uses a prefix for a certain namespace, this is - stored in the C{localPrefixes} attribute of the element. We want - to make sure that elements created after such use, won't have this - prefix end up in their C{localPrefixes} attribute, too. - """ - - xml = """ - - - """ - - self.stream.parse(xml) - self.assertEquals('child1', self.elements[0].name) - self.assertEquals('testns', self.elements[0].uri) - self.assertEquals('', self.elements[0].defaultUri) - self.assertEquals({'foo': 'testns'}, self.elements[0].localPrefixes) - self.assertEquals('child2', self.elements[1].name) - self.assertEquals('testns', self.elements[1].uri) - self.assertEquals('testns', self.elements[1].defaultUri) - self.assertEquals({}, self.elements[1].localPrefixes) - -class DomishExpatStreamTestCase(unittest.TestCase, DomishStreamTests): - def setUp(self): - DomishStreamTests.setUp(self) - - def setUpClass(self): - try: - import pyexpat - except ImportError: - raise unittest.SkipTest, "Skipping ExpatElementStream test, since no expat wrapper is available." - - self.streamClass = domish.ExpatElementStream - -class DomishSuxStreamTestCase(unittest.TestCase, DomishStreamTests): - def setUp(self): - DomishStreamTests.setUp(self) - - def setUpClass(self): - if domish.SuxElementStream is None: - raise unittest.SkipTest, "Skipping SuxElementStream test, since twisted.web is not available." - - self.streamClass = domish.SuxElementStream - - - -class SerializerTests(unittest.TestCase): - def testNoNamespace(self): - e = domish.Element((None, "foo")) - self.assertEquals(e.toXml(), "") - self.assertEquals(e.toXml(closeElement = 0), "") - - def testDefaultNamespace(self): - e = domish.Element(("testns", "foo")) - self.assertEquals(e.toXml(), "") - - def testOtherNamespace(self): - e = domish.Element(("testns", "foo"), "testns2") - self.assertEquals(e.toXml({'testns': 'bar'}), - "") - - def testChildDefaultNamespace(self): - e = domish.Element(("testns", "foo")) - e.addElement("bar") - self.assertEquals(e.toXml(), "") - - def testChildSameNamespace(self): - e = domish.Element(("testns", "foo")) - e.addElement(("testns", "bar")) - self.assertEquals(e.toXml(), "") - - def testChildSameDefaultNamespace(self): - e = domish.Element(("testns", "foo")) - e.addElement("bar", "testns") - self.assertEquals(e.toXml(), "") - - def testChildOtherDefaultNamespace(self): - e = domish.Element(("testns", "foo")) - e.addElement(("testns2", "bar"), 'testns2') - self.assertEquals(e.toXml(), "") - - def testOnlyChildDefaultNamespace(self): - e = domish.Element((None, "foo")) - e.addElement(("ns2", "bar"), 'ns2') - self.assertEquals(e.toXml(), "") - - def testOnlyChildDefaultNamespace2(self): - e = domish.Element((None, "foo")) - e.addElement("bar") - self.assertEquals(e.toXml(), "") - - def testChildInDefaultNamespace(self): - e = domish.Element(("testns", "foo"), "testns2") - e.addElement(("testns2", "bar")) - self.assertEquals(e.toXml(), "") - - def testQualifiedAttribute(self): - e = domish.Element((None, "foo"), - attribs = {("testns2", "bar"): "baz"}) - self.assertEquals(e.toXml(), "") - - def testQualifiedAttributeDefaultNS(self): - e = domish.Element(("testns", "foo"), - attribs = {("testns", "bar"): "baz"}) - self.assertEquals(e.toXml(), "") - - def testTwoChilds(self): - e = domish.Element(('', "foo")) - child1 = e.addElement(("testns", "bar"), "testns2") - child1.addElement(('testns2', 'quux')) - child2 = e.addElement(("testns3", "baz"), "testns4") - child2.addElement(('testns', 'quux')) - self.assertEquals(e.toXml(), "") - - def testXMLNamespace(self): - e = domish.Element((None, "foo"), - attribs = {("http://www.w3.org/XML/1998/namespace", - "lang"): "en_US"}) - self.assertEquals(e.toXml(), "") - - def testQualifiedAttributeGivenListOfPrefixes(self): - e = domish.Element((None, "foo"), - attribs = {("testns2", "bar"): "baz"}) - self.assertEquals(e.toXml({"testns2": "qux"}), - "") - - def testNSPrefix(self): - e = domish.Element((None, "foo"), - attribs = {("testns2", "bar"): "baz"}) - c = e.addElement(("testns2", "qux")) - c[("testns2", "bar")] = "quux" - - self.assertEquals(e.toXml(), "") - - def testDefaultNSPrefix(self): - e = domish.Element((None, "foo"), - attribs = {("testns2", "bar"): "baz"}) - c = e.addElement(("testns2", "qux")) - c[("testns2", "bar")] = "quux" - c.addElement('foo') - - self.assertEquals(e.toXml(), "") - - def testPrefixScope(self): - e = domish.Element(('testns', 'foo')) - - self.assertEquals(e.toXml(prefixes={'testns': 'bar'}, - prefixesInScope=['bar']), - "") - - def testLocalPrefixes(self): - e = domish.Element(('testns', 'foo'), localPrefixes={'bar': 'testns'}) - self.assertEquals(e.toXml(), "") - - def testLocalPrefixesWithChild(self): - e = domish.Element(('testns', 'foo'), localPrefixes={'bar': 'testns'}) - e.addElement('baz') - self.assertIdentical(e.baz.defaultUri, None) - self.assertEquals(e.toXml(), "") - - def test_prefixesReuse(self): - """ - Test that prefixes passed to serialization are not modified. - - This test makes sure that passing a dictionary of prefixes repeatedly - to C{toXml} of elements does not cause serialization errors. A - previous implementation changed the passed in dictionary internally, - causing havoc later on. - """ - prefixes = {'testns': 'foo'} - - # test passing of dictionary - s = domish.SerializerClass(prefixes=prefixes) - self.assertNotIdentical(prefixes, s.prefixes) - - # test proper serialization on prefixes reuse - e = domish.Element(('testns2', 'foo'), - localPrefixes={'quux': 'testns2'}) - self.assertEquals("", - e.toXml(prefixes=prefixes)) - e = domish.Element(('testns2', 'foo')) - self.assertEquals("", - e.toXml(prefixes=prefixes)) - - def testRawXMLSerialization(self): - e = domish.Element((None, "foo")) - e.addRawXml("") - # The testcase below should NOT generate valid XML -- that's - # the whole point of using the raw XML call -- it's the callers - # responsiblity to ensure that the data inserted is valid - self.assertEquals(e.toXml(), "") - - def testRawXMLWithUnicodeSerialization(self): - e = domish.Element((None, "foo")) - e.addRawXml(u"\u00B0") - self.assertEquals(e.toXml(), u"\u00B0") - - def testUnicodeSerialization(self): - e = domish.Element((None, "foo")) - e["test"] = u"my value\u0221e" - e.addContent(u"A degree symbol...\u00B0") - self.assertEquals(e.toXml(), - u"A degree symbol...\u00B0") diff --git a/tools/buildbot/pylibs/twisted/words/test/test_irc.py b/tools/buildbot/pylibs/twisted/words/test/test_irc.py deleted file mode 100644 index 87f15ae..0000000 --- a/tools/buildbot/pylibs/twisted/words/test/test_irc.py +++ /dev/null @@ -1,451 +0,0 @@ -# Copyright (c) 2001-2005 Twisted Matrix Laboratories. -# See LICENSE for details. - -from StringIO import StringIO -import time - -from twisted.trial import unittest -from twisted.trial.unittest import TestCase -from twisted.words.protocols import irc -from twisted.words.protocols.irc import IRCClient -from twisted.internet import protocol - - -class StringIOWithoutClosing(StringIO): - def close(self): - pass - -stringSubjects = [ - "Hello, this is a nice string with no complications.", - "xargs%(NUL)smight%(NUL)slike%(NUL)sthis" % {'NUL': irc.NUL }, - "embedded%(CR)snewline%(CR)s%(NL)sFUN%(NL)s" % {'CR': irc.CR, - 'NL': irc.NL}, - "escape!%(X)s escape!%(M)s %(X)s%(X)sa %(M)s0" % {'X': irc.X_QUOTE, - 'M': irc.M_QUOTE} - ] - - -class QuotingTest(unittest.TestCase): - def test_lowquoteSanity(self): - """Testing client-server level quote/dequote""" - for s in stringSubjects: - self.failUnlessEqual(s, irc.lowDequote(irc.lowQuote(s))) - - def test_ctcpquoteSanity(self): - """Testing CTCP message level quote/dequote""" - for s in stringSubjects: - self.failUnlessEqual(s, irc.ctcpDequote(irc.ctcpQuote(s))) - - -class IRCClientWithoutLogin(irc.IRCClient): - performLogin = 0 - - -class CTCPTest(unittest.TestCase): - def setUp(self): - self.file = StringIOWithoutClosing() - self.transport = protocol.FileWrapper(self.file) - self.client = IRCClientWithoutLogin() - self.client.makeConnection(self.transport) - - def test_ERRMSG(self): - """Testing CTCP query ERRMSG. - - Not because this is this is an especially important case in the - field, but it does go through the entire dispatch/decode/encode - process. - """ - - errQuery = (":nick!guy@over.there PRIVMSG #theChan :" - "%(X)cERRMSG t%(X)c%(EOL)s" - % {'X': irc.X_DELIM, - 'EOL': irc.CR + irc.LF}) - - errReply = ("NOTICE nick :%(X)cERRMSG t :" - "No error has occoured.%(X)c%(EOL)s" - % {'X': irc.X_DELIM, - 'EOL': irc.CR + irc.LF}) - - self.client.dataReceived(errQuery) - reply = self.file.getvalue() - - self.failUnlessEqual(errReply, reply) - - def tearDown(self): - self.transport.loseConnection() - self.client.connectionLost() - del self.client - del self.transport - -class NoticingClient(object, IRCClientWithoutLogin): - methods = { - 'created': ('when',), - 'yourHost': ('info',), - 'myInfo': ('servername', 'version', 'umodes', 'cmodes'), - 'luserClient': ('info',), - 'bounce': ('info',), - 'isupport': ('options',), - 'luserChannels': ('channels',), - 'luserOp': ('ops',), - 'luserMe': ('info',), - 'receivedMOTD': ('motd',), - - 'privmsg': ('user', 'channel', 'message'), - 'joined': ('channel',), - 'left': ('channel',), - 'noticed': ('user', 'channel', 'message'), - 'modeChanged': ('user', 'channel', 'set', 'modes', 'args'), - 'pong': ('user', 'secs'), - 'signedOn': (), - 'kickedFrom': ('channel', 'kicker', 'message'), - 'nickChanged': ('nick',), - - 'userJoined': ('user', 'channel'), - 'userLeft': ('user', 'channel'), - 'userKicked': ('user', 'channel', 'kicker', 'message'), - 'action': ('user', 'channel', 'data'), - 'topicUpdated': ('user', 'channel', 'newTopic'), - 'userRenamed': ('oldname', 'newname')} - - def __init__(self, *a, **kw): - object.__init__(self) - self.calls = [] - - def __getattribute__(self, name): - if name.startswith('__') and name.endswith('__'): - return super(NoticingClient, self).__getattribute__(name) - try: - args = super(NoticingClient, self).__getattribute__('methods')[name] - except KeyError: - return super(NoticingClient, self).__getattribute__(name) - else: - return self.makeMethod(name, args) - - def makeMethod(self, fname, args): - def method(*a, **kw): - if len(a) > len(args): - raise TypeError("TypeError: %s() takes %d arguments " - "(%d given)" % (fname, len(args), len(a))) - for (name, value) in zip(args, a): - if name in kw: - raise TypeError("TypeError: %s() got multiple values " - "for keyword argument '%s'" % (fname, name)) - else: - kw[name] = value - if len(kw) != len(args): - raise TypeError("TypeError: %s() takes %d arguments " - "(%d given)" % (fname, len(args), len(a))) - self.calls.append((fname, kw)) - return method - -def pop(dict, key, default): - try: - value = dict[key] - except KeyError: - return default - else: - del dict[key] - return value - -class ModeTestCase(unittest.TestCase): - def setUp(self): - self.file = StringIOWithoutClosing() - self.transport = protocol.FileWrapper(self.file) - self.client = NoticingClient() - self.client.makeConnection(self.transport) - - def tearDown(self): - self.transport.loseConnection() - self.client.connectionLost() - del self.client - del self.transport - - def testModeChange(self): - message = ":ChanServ!ChanServ@services. MODE #tanstaafl +o exarkun\r\n" - self.client.dataReceived(message) - self.assertEquals( - self.client.calls, - [('modeChanged', {'user': "ChanServ!ChanServ@services.", - 'channel': '#tanstaafl', - 'set': True, - 'modes': 'o', - 'args': ('exarkun',)})]) - - def _serverTestImpl(self, code, msg, func, **kw): - host = pop(kw, 'host', 'server.host') - nick = pop(kw, 'nick', 'nickname') - args = pop(kw, 'args', '') - - message = (":" + - host + " " + - code + " " + - nick + " " + - args + " :" + - msg + "\r\n") - - self.client.dataReceived(message) - self.assertEquals( - self.client.calls, - [(func, kw)]) - - def testYourHost(self): - msg = "Your host is some.host[blah.blah/6667], running version server-version-3" - self._serverTestImpl("002", msg, "yourHost", info=msg) - - def testCreated(self): - msg = "This server was cobbled together Fri Aug 13 18:00:25 UTC 2004" - self._serverTestImpl("003", msg, "created", when=msg) - - def testMyInfo(self): - msg = "server.host server-version abcDEF bcdEHI" - self._serverTestImpl("004", msg, "myInfo", - servername="server.host", - version="server-version", - umodes="abcDEF", - cmodes="bcdEHI") - - def testLuserClient(self): - msg = "There are 9227 victims and 9542 hiding on 24 servers" - self._serverTestImpl("251", msg, "luserClient", - info=msg) - - def testISupport(self): - args = ("MODES=4 CHANLIMIT=#:20 NICKLEN=16 USERLEN=10 HOSTLEN=63 " - "TOPICLEN=450 KICKLEN=450 CHANNELLEN=30 KEYLEN=23 CHANTYPES=# " - "PREFIX=(ov)@+ CASEMAPPING=ascii CAPAB IRCD=dancer") - msg = "are available on this server" - self._serverTestImpl("005", msg, "isupport", args=args, - options=['MODES=4', - 'CHANLIMIT=#:20', - 'NICKLEN=16', - 'USERLEN=10', - 'HOSTLEN=63', - 'TOPICLEN=450', - 'KICKLEN=450', - 'CHANNELLEN=30', - 'KEYLEN=23', - 'CHANTYPES=#', - 'PREFIX=(ov)@+', - 'CASEMAPPING=ascii', - 'CAPAB', - 'IRCD=dancer']) - - def testBounce(self): - msg = "Try server some.host, port 321" - self._serverTestImpl("005", msg, "bounce", - info=msg) - - def testLuserChannels(self): - args = "7116" - msg = "channels formed" - self._serverTestImpl("254", msg, "luserChannels", args=args, - channels=int(args)) - - def testLuserOp(self): - args = "34" - msg = "flagged staff members" - self._serverTestImpl("252", msg, "luserOp", args=args, - ops=int(args)) - - def testLuserMe(self): - msg = "I have 1937 clients and 0 servers" - self._serverTestImpl("255", msg, "luserMe", - info=msg) - - def testMOTD(self): - lines = [ - ":host.name 375 nickname :- host.name Message of the Day -", - ":host.name 372 nickname :- Welcome to host.name", - ":host.name 376 nickname :End of /MOTD command."] - for L in lines: - self.assertEquals(self.client.calls, []) - self.client.dataReceived(L + '\r\n') - - self.assertEquals( - self.client.calls, - [("receivedMOTD", {"motd": ["host.name Message of the Day -", "Welcome to host.name"]})]) - - - def _clientTestImpl(self, sender, group, type, msg, func, **kw): - ident = pop(kw, 'ident', 'ident') - host = pop(kw, 'host', 'host') - - wholeUser = sender + '!' + ident + '@' + host - message = (":" + - wholeUser + " " + - type + " " + - group + " :" + - msg + "\r\n") - self.client.dataReceived(message) - self.assertEquals( - self.client.calls, - [(func, kw)]) - self.client.calls = [] - - def testPrivmsg(self): - msg = "Tooty toot toot." - self._clientTestImpl("sender", "#group", "PRIVMSG", msg, "privmsg", - ident="ident", host="host", - # Expected results below - user="sender!ident@host", - channel="#group", - message=msg) - - self._clientTestImpl("sender", "recipient", "PRIVMSG", msg, "privmsg", - ident="ident", host="host", - # Expected results below - user="sender!ident@host", - channel="recipient", - message=msg) - -class BasicServerFunctionalityTestCase(unittest.TestCase): - def setUp(self): - self.f = StringIOWithoutClosing() - self.t = protocol.FileWrapper(self.f) - self.p = irc.IRC() - self.p.makeConnection(self.t) - - def check(self, s): - self.assertEquals(self.f.getvalue(), s) - - def testPrivmsg(self): - self.p.privmsg("this-is-sender", "this-is-recip", "this is message") - self.check(":this-is-sender PRIVMSG this-is-recip :this is message\r\n") - - def testNotice(self): - self.p.notice("this-is-sender", "this-is-recip", "this is notice") - self.check(":this-is-sender NOTICE this-is-recip :this is notice\r\n") - - def testAction(self): - self.p.action("this-is-sender", "this-is-recip", "this is action") - self.check(":this-is-sender ACTION this-is-recip :this is action\r\n") - - def testJoin(self): - self.p.join("this-person", "#this-channel") - self.check(":this-person JOIN #this-channel\r\n") - - def testPart(self): - self.p.part("this-person", "#that-channel") - self.check(":this-person PART #that-channel\r\n") - - def testWhois(self): - """ - Verify that a whois by the client receives the right protocol actions - from the server. - """ - timestamp = int(time.time()-100) - hostname = self.p.hostname - req = 'requesting-nick' - targ = 'target-nick' - self.p.whois(req, targ, 'target', 'host.com', - 'Target User', 'irc.host.com', 'A fake server', False, - 12, timestamp, ['#fakeusers', '#fakemisc']) - expected = '\r\n'.join([ -':%(hostname)s 311 %(req)s %(targ)s target host.com * :Target User', -':%(hostname)s 312 %(req)s %(targ)s irc.host.com :A fake server', -':%(hostname)s 317 %(req)s %(targ)s 12 %(timestamp)s :seconds idle, signon time', -':%(hostname)s 319 %(req)s %(targ)s :#fakeusers #fakemisc', -':%(hostname)s 318 %(req)s %(targ)s :End of WHOIS list.', -'']) % dict(hostname=hostname, timestamp=timestamp, req=req, targ=targ) - self.check(expected) - - -class DummyClient(irc.IRCClient): - def __init__(self): - self.lines = [] - def sendLine(self, m): - self.lines.append(m) - - -class ClientMsgTests(unittest.TestCase): - def setUp(self): - self.client = DummyClient() - - def testSingleLine(self): - self.client.msg('foo', 'bar') - self.assertEquals(self.client.lines, ['PRIVMSG foo :bar']) - - def testDodgyMaxLength(self): - self.assertRaises(ValueError, self.client.msg, 'foo', 'bar', 0) - self.assertRaises(ValueError, self.client.msg, 'foo', 'bar', 3) - - def testMultipleLine(self): - maxLen = len('PRIVMSG foo :') + 3 + 2 # 2 for line endings - self.client.msg('foo', 'barbazbo', maxLen) - self.assertEquals(self.client.lines, ['PRIVMSG foo :bar', - 'PRIVMSG foo :baz', - 'PRIVMSG foo :bo']) - - def testSufficientWidth(self): - msg = 'barbazbo' - maxLen = len('PRIVMSG foo :%s' % (msg,)) + 2 - self.client.msg('foo', msg, maxLen) - self.assertEquals(self.client.lines, ['PRIVMSG foo :%s' % (msg,)]) - self.client.lines = [] - self.client.msg('foo', msg, maxLen-1) - self.assertEquals(2, len(self.client.lines)) - self.client.lines = [] - self.client.msg('foo', msg, maxLen+1) - self.assertEquals(1, len(self.client.lines)) - - def testSplitSanity(self): - # Whiteboxing - self.assertRaises(ValueError, irc.split, 'foo', -1) - self.assertRaises(ValueError, irc.split, 'foo', 0) - self.assertEquals([], irc.split('', 1)) - self.assertEquals([], irc.split('')) - - -class ClientTests(TestCase): - """ - Tests for the protocol-level behavior of IRCClient methods intended to - be called by application code. - """ - def setUp(self): - self.transport = StringIO() - self.protocol = IRCClient() - self.protocol.performLogin = False - self.protocol.makeConnection(self.transport) - - # Sanity check - we don't want anything to have happened at this - # point, since we're not in a test yet. - self.failIf(self.transport.getvalue()) - - - def test_register(self): - """ - Verify that the L{IRCClient.register} method sends a a USER command - with the correct arguments. - """ - username = 'testuser' - hostname = 'testhost' - servername = 'testserver' - self.protocol.realname = 'testname' - self.protocol.password = None - self.protocol.register(username, hostname, servername) - expected = [ - 'NICK %s' % (username,), - 'USER %s %s %s :%s' % ( - username, hostname, servername, self.protocol.realname), - ''] - self.assertEqual(self.transport.getvalue().split('\r\n'), expected) - - - def test_registerWithPassword(self): - """ - Verify that if the C{password} attribute of L{IRCClient} is not - C{None}, the C{register} method also authenticates using it. - """ - username = 'testuser' - hostname = 'testhost' - servername = 'testserver' - self.protocol.realname = 'testname' - self.protocol.password = 'testpass' - self.protocol.register(username, hostname, servername) - expected = [ - 'PASS %s' % (self.protocol.password,), - 'NICK %s' % (username,), - 'USER %s %s %s :%s' % ( - username, hostname, servername, self.protocol.realname), - ''] - self.assertEqual(self.transport.getvalue().split('\r\n'), expected) diff --git a/tools/buildbot/pylibs/twisted/words/test/test_jabberclient.py b/tools/buildbot/pylibs/twisted/words/test/test_jabberclient.py deleted file mode 100644 index 3da3788..0000000 --- a/tools/buildbot/pylibs/twisted/words/test/test_jabberclient.py +++ /dev/null @@ -1,272 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.words.protocols.jabber.client} -""" - -import sha -from twisted.trial import unittest -from twisted.words.protocols.jabber import client, error, jid, xmlstream -from twisted.words.protocols.jabber.sasl import SASLInitiatingInitializer - -class CheckVersionInitializerTest(unittest.TestCase): - def setUp(self): - a = xmlstream.Authenticator() - xs = xmlstream.XmlStream(a) - self.init = client.CheckVersionInitializer(xs) - - def testSupported(self): - """ - Test supported version number 1.0 - """ - self.init.xmlstream.version = (1, 0) - self.init.initialize() - - def testNotSupported(self): - """ - Test unsupported version number 0.0, and check exception. - """ - self.init.xmlstream.version = (0, 0) - exc = self.assertRaises(error.StreamError, self.init.initialize) - self.assertEquals('unsupported-version', exc.condition) - - -class InitiatingInitializerHarness(object): - def setUp(self): - self.output = [] - self.authenticator = xmlstream.ConnectAuthenticator('example.org') - self.xmlstream = xmlstream.XmlStream(self.authenticator) - self.xmlstream.send = self.output.append - self.xmlstream.connectionMade() - self.xmlstream.dataReceived("") - - -class IQAuthInitializerTest(InitiatingInitializerHarness, unittest.TestCase): - def setUp(self): - super(IQAuthInitializerTest, self).setUp() - self.init = client.IQAuthInitializer(self.xmlstream) - self.authenticator.jid = jid.JID('user@example.com/resource') - self.authenticator.password = 'secret' - - def testBasic(self): - """ - Test basic operations with plain text authentication. - - Set up a stream, and act as if authentication succeeds. - """ - d = self.init.initialize() - - # The initializer should have sent query to find out auth methods. - - # Examine query. - iq = self.output[-1] - self.assertEquals('iq', iq.name) - self.assertEquals('get', iq['type']) - self.assertEquals(('jabber:iq:auth', 'query'), - (iq.children[0].uri, iq.children[0].name)) - - # Send server response - iq['type'] = 'result' - iq.query.addElement('username') - iq.query.addElement('password') - iq.query.addElement('resource') - self.xmlstream.dataReceived(iq.toXml()) - - # Upon receiving the response, the initializer can start authentication - - iq = self.output[-1] - self.assertEquals('iq', iq.name) - self.assertEquals('set', iq['type']) - self.assertEquals(('jabber:iq:auth', 'query'), - (iq.children[0].uri, iq.children[0].name)) - self.assertEquals('user', unicode(iq.query.username)) - self.assertEquals('secret', unicode(iq.query.password)) - self.assertEquals('resource', unicode(iq.query.resource)) - - # Send server response - self.xmlstream.dataReceived("" % iq['id']) - return d - - def testDigest(self): - """ - Test digest authentication. - - Set up a stream, and act as if authentication succeeds. - """ - d = self.init.initialize() - - # The initializer should have sent query to find out auth methods. - - iq = self.output[-1] - - # Send server response - iq['type'] = 'result' - iq.query.addElement('username') - iq.query.addElement('digest') - iq.query.addElement('resource') - self.xmlstream.dataReceived(iq.toXml()) - - # Upon receiving the response, the initializer can start authentication - - iq = self.output[-1] - self.assertEquals('iq', iq.name) - self.assertEquals('set', iq['type']) - self.assertEquals(('jabber:iq:auth', 'query'), - (iq.children[0].uri, iq.children[0].name)) - self.assertEquals('user', unicode(iq.query.username)) - self.assertEquals(sha.new('12345secret').hexdigest(), - unicode(iq.query.digest)) - self.assertEquals('resource', unicode(iq.query.resource)) - - # Send server response - self.xmlstream.dataReceived("" % iq['id']) - return d - - def testFailRequestFields(self): - """ - Test failure of request for fields. - """ - d = self.init.initialize() - iq = self.output[-1] - response = error.StanzaError('not-authorized').toResponse(iq) - self.xmlstream.dataReceived(response.toXml()) - self.assertFailure(d, error.StanzaError) - return d - - def testFailAuth(self): - """ - Test failure of request for fields. - """ - d = self.init.initialize() - iq = self.output[-1] - iq['type'] = 'result' - iq.query.addElement('username') - iq.query.addElement('password') - iq.query.addElement('resource') - self.xmlstream.dataReceived(iq.toXml()) - iq = self.output[-1] - response = error.StanzaError('not-authorized').toResponse(iq) - self.xmlstream.dataReceived(response.toXml()) - self.assertFailure(d, error.StanzaError) - return d - - -class BindInitializerTest(InitiatingInitializerHarness, unittest.TestCase): - def setUp(self): - super(BindInitializerTest, self).setUp() - self.init = client.BindInitializer(self.xmlstream) - self.authenticator.jid = jid.JID('user@example.com/resource') - - def testBasic(self): - """ - Test basic operations. - - Set up a stream, and act as if resource binding succeeds. - """ - def cb(result): - self.assertEquals(jid.JID('user@example.com/other resource'), - self.authenticator.jid) - - d = self.init.start().addCallback(cb) - iq = self.output[-1] - self.assertEquals('iq', iq.name) - self.assertEquals('set', iq['type']) - self.assertEquals(('urn:ietf:params:xml:ns:xmpp-bind', 'bind'), - (iq.children[0].uri, iq.children[0].name)) - iq['type'] = 'result' - iq.bind.children = [] - iq.bind.addElement('jid', content='user@example.com/other resource') - self.xmlstream.dataReceived(iq.toXml()) - return d - - def testFailure(self): - """ - Test basic operations. - - Set up a stream, and act as if resource binding fails. - """ - def cb(result): - self.assertEquals(jid.JID('user@example.com/resource'), - self.authenticator.jid) - - d = self.init.start() - id = self.output[-1]['id'] - self.xmlstream.dataReceived("" % id) - self.assertFailure(d, error.StanzaError) - return d - - -class SessionInitializerTest(InitiatingInitializerHarness, unittest.TestCase): - - def setUp(self): - super(SessionInitializerTest, self).setUp() - self.init = client.SessionInitializer(self.xmlstream) - - def testSuccess(self): - """ - Test basic operations. - - Set up a stream, and act as if resource binding succeeds. - """ - d = self.init.start() - iq = self.output[-1] - self.assertEquals('iq', iq.name) - self.assertEquals('set', iq['type']) - self.assertEquals(('urn:ietf:params:xml:ns:xmpp-session', 'session'), - (iq.children[0].uri, iq.children[0].name)) - self.xmlstream.dataReceived("" % iq['id']) - return d - - def testFailure(self): - """ - Test basic operations. - - Set up a stream, and act as if session establishment succeeds. - """ - d = self.init.start() - id = self.output[-1]['id'] - self.xmlstream.dataReceived("" % id) - self.assertFailure(d, error.StanzaError) - return d - - -class XMPPAuthenticatorTest(unittest.TestCase): - """ - Test for both XMPPAuthenticator and XMPPClientFactory. - """ - def testBasic(self): - """ - Test basic operations. - - Setup an XMPPClientFactory, which sets up an XMPPAuthenticator, and let - it produce a protocol instance. Then inspect the instance variables of - the authenticator and XML stream objects. - """ - self.client_jid = jid.JID('user@example.com/resource') - - # Get an XmlStream instance. Note that it gets initialized with the - # XMPPAuthenticator (that has its associateWithXmlStream called) that - # is in turn initialized with the arguments to the factory. - xs = client.XMPPClientFactory(self.client_jid, - 'secret').buildProtocol(None) - - # test authenticator's instance variables - self.assertEqual('example.com', xs.authenticator.otherHost) - self.assertEqual(self.client_jid, xs.authenticator.jid) - self.assertEqual('secret', xs.authenticator.password) - - # test list of initializers - version, tls, sasl, bind, session = xs.initializers - - self.assert_(isinstance(tls, xmlstream.TLSInitiatingInitializer)) - self.assert_(isinstance(sasl, SASLInitiatingInitializer)) - self.assert_(isinstance(bind, client.BindInitializer)) - self.assert_(isinstance(session, client.SessionInitializer)) - - self.assertFalse(tls.required) - self.assertTrue(sasl.required) - self.assertFalse(bind.required) - self.assertFalse(session.required) diff --git a/tools/buildbot/pylibs/twisted/words/test/test_jabbercomponent.py b/tools/buildbot/pylibs/twisted/words/test/test_jabbercomponent.py deleted file mode 100644 index ce0f177..0000000 --- a/tools/buildbot/pylibs/twisted/words/test/test_jabbercomponent.py +++ /dev/null @@ -1,137 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.words.protocols.jabber.component} -""" - -import sha -from twisted.trial import unittest - -from twisted.words.protocols.jabber import component -from twisted.words.protocols import jabber -from twisted.words.protocols.jabber import xmlstream - -class DummyTransport: - def __init__(self, list): - self.list = list - - def write(self, bytes): - self.list.append(bytes) - -class ComponentInitiatingInitializerTest(unittest.TestCase): - def setUp(self): - self.output = [] - - self.authenticator = xmlstream.Authenticator() - self.authenticator.password = 'secret' - self.xmlstream = xmlstream.XmlStream(self.authenticator) - self.xmlstream.namespace = 'test:component' - self.xmlstream.send = self.output.append - self.xmlstream.connectionMade() - self.xmlstream.dataReceived( - "") - self.xmlstream.sid = '12345' - self.init = component.ComponentInitiatingInitializer(self.xmlstream) - - def testHandshake(self): - """ - Test basic operations of component handshake. - """ - - d = self.init.initialize() - - # the initializer should have sent the handshake request - - handshake = self.output[-1] - self.assertEquals('handshake', handshake.name) - self.assertEquals('test:component', handshake.uri) - self.assertEquals(sha.new("%s%s" % ('12345', 'secret')).hexdigest(), - unicode(handshake)) - - # successful authentication - - handshake.children = [] - self.xmlstream.dataReceived(handshake.toXml()) - - return d - -class ComponentAuthTest(unittest.TestCase): - def authPassed(self, stream): - self.authComplete = True - - def testAuth(self): - self.authComplete = False - outlist = [] - - ca = component.ConnectComponentAuthenticator("cjid", "secret") - xs = xmlstream.XmlStream(ca) - xs.transport = DummyTransport(outlist) - - xs.addObserver(xmlstream.STREAM_AUTHD_EVENT, - self.authPassed) - - # Go... - xs.connectionMade() - xs.dataReceived("") - - # Calculate what we expect the handshake value to be - hv = sha.new("%s%s" % ("12345", "secret")).hexdigest() - - self.assertEquals(outlist[1], "%s" % (hv)) - - xs.dataReceived("") - - self.assertEquals(self.authComplete, True) - - -class JabberServiceHarness(jabber.component.Service): - def __init__(self): - self.componentConnectedFlag = False - self.componentDisconnectedFlag = False - self.transportConnectedFlag = False - - def componentConnected(self, xmlstream): - self.componentConnectedFlag = True - - def componentDisconnected(self): - self.componentDisconnectedFlag = True - - def transportConnected(self, xmlstream): - self.transportConnectedFlag = True - - -class TestJabberServiceManager(unittest.TestCase): - def testSM(self): - # Setup service manager and test harnes - sm = jabber.component.ServiceManager("foo", "password") - svc = JabberServiceHarness() - svc.setServiceParent(sm) - - # Create a write list - wlist = [] - - # Setup a XmlStream - xs = sm.getFactory().buildProtocol(None) - xs.transport = self - xs.transport.write = wlist.append - - # Indicate that it's connected - xs.connectionMade() - - # Ensure the test service harness got notified - self.assertEquals(True, svc.transportConnectedFlag) - - # Jump ahead and pretend like the stream got auth'd - xs.dispatch(xs, xmlstream.STREAM_AUTHD_EVENT) - - # Ensure the test service harness got notified - self.assertEquals(True, svc.componentConnectedFlag) - - # Pretend to drop the connection - xs.connectionLost(None) - - # Ensure the test service harness got notified - self.assertEquals(True, svc.componentDisconnectedFlag) diff --git a/tools/buildbot/pylibs/twisted/words/test/test_jabbererror.py b/tools/buildbot/pylibs/twisted/words/test/test_jabbererror.py deleted file mode 100644 index 9b4643d..0000000 --- a/tools/buildbot/pylibs/twisted/words/test/test_jabbererror.py +++ /dev/null @@ -1,308 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.words.protocols.jabber.error}. -""" - -from twisted.trial import unittest - -from twisted.words.protocols.jabber import error -from twisted.words.xish import domish - -NS_XML = 'http://www.w3.org/XML/1998/namespace' -NS_STREAMS = 'http://etherx.jabber.org/streams' -NS_XMPP_STREAMS = 'urn:ietf:params:xml:ns:xmpp-streams' -NS_XMPP_STANZAS = 'urn:ietf:params:xml:ns:xmpp-stanzas' - -class BaseErrorTest(unittest.TestCase): - - def test_getElementPlain(self): - """ - Test getting an element for a plain error. - """ - e = error.BaseError('feature-not-implemented') - element = e.getElement() - self.assertIdentical(element.uri, None) - self.assertEquals(len(element.children), 1) - - def test_getElementText(self): - """ - Test getting an element for an error with a text. - """ - e = error.BaseError('feature-not-implemented', 'text') - element = e.getElement() - self.assertEquals(len(element.children), 2) - self.assertEquals(unicode(element.text), 'text') - self.assertEquals(element.text.getAttribute((NS_XML, 'lang')), None) - - def test_getElementTextLang(self): - """ - Test getting an element for an error with a text and language. - """ - e = error.BaseError('feature-not-implemented', 'text', 'en_US') - element = e.getElement() - self.assertEquals(len(element.children), 2) - self.assertEquals(unicode(element.text), 'text') - self.assertEquals(element.text[(NS_XML, 'lang')], 'en_US') - - def test_getElementAppCondition(self): - """ - Test getting an element for an error with an app specific condition. - """ - ac = domish.Element(('testns', 'myerror')) - e = error.BaseError('feature-not-implemented', appCondition=ac) - element = e.getElement() - self.assertEquals(len(element.children), 2) - self.assertEquals(element.myerror, ac) - -class StreamErrorTest(unittest.TestCase): - - def test_getElementPlain(self): - """ - Test namespace of the element representation of an error. - """ - e = error.StreamError('feature-not-implemented') - element = e.getElement() - self.assertEquals(element.uri, NS_STREAMS) - - def test_getElementConditionNamespace(self): - """ - Test that the error condition element has the correct namespace. - """ - e = error.StreamError('feature-not-implemented') - element = e.getElement() - self.assertEquals(NS_XMPP_STREAMS, getattr(element, 'feature-not-implemented').uri) - - def test_getElementTextNamespace(self): - """ - Test that the error text element has the correct namespace. - """ - e = error.StreamError('feature-not-implemented', 'text') - element = e.getElement() - self.assertEquals(NS_XMPP_STREAMS, element.text.uri) - -class StanzaErrorTest(unittest.TestCase): - - def test_getElementPlain(self): - """ - Test getting an element for a plain stanza error. - """ - e = error.StanzaError('feature-not-implemented') - element = e.getElement() - self.assertEquals(element.uri, None) - self.assertEquals(element['type'], 'cancel') - self.assertEquals(element['code'], '501') - - def test_getElementType(self): - """ - Test getting an element for a stanza error with a given type. - """ - e = error.StanzaError('feature-not-implemented', 'auth') - element = e.getElement() - self.assertEquals(element.uri, None) - self.assertEquals(element['type'], 'auth') - self.assertEquals(element['code'], '501') - - def test_getElementConditionNamespace(self): - """ - Test that the error condition element has the correct namespace. - """ - e = error.StanzaError('feature-not-implemented') - element = e.getElement() - self.assertEquals(NS_XMPP_STANZAS, getattr(element, 'feature-not-implemented').uri) - - def test_getElementTextNamespace(self): - """ - Test that the error text element has the correct namespace. - """ - e = error.StanzaError('feature-not-implemented', text='text') - element = e.getElement() - self.assertEquals(NS_XMPP_STANZAS, element.text.uri) - - def test_toResponse(self): - """ - Test an error response is generated from a stanza. - - The addressing on the (new) response stanza should be reversed, an - error child (with proper properties) added and the type set to - C{'error'}. - """ - stanza = domish.Element(('jabber:client', 'message')) - stanza['type'] = 'chat' - stanza['to'] = 'user1@example.com' - stanza['from'] = 'user2@example.com/resource' - e = error.StanzaError('service-unavailable') - response = e.toResponse(stanza) - self.assertNotIdentical(response, stanza) - self.assertEqual(response['from'], 'user1@example.com') - self.assertEqual(response['to'], 'user2@example.com/resource') - self.assertEqual(response['type'], 'error') - self.assertEqual(response.error.children[0].name, - 'service-unavailable') - self.assertEqual(response.error['type'], 'cancel') - self.assertNotEqual(stanza.children, response.children) - -class ParseErrorTest(unittest.TestCase): - - def setUp(self): - self.error = domish.Element((None, 'error')) - - def test_empty(self): - """ - Test parsing of the empty error element. - """ - result = error._parseError(self.error, 'errorns') - self.assertEqual({'condition': None, - 'text': None, - 'textLang': None, - 'appCondition': None}, result) - - def test_condition(self): - """ - Test parsing of an error element with a condition. - """ - self.error.addElement(('errorns', 'bad-request')) - result = error._parseError(self.error, 'errorns') - self.assertEqual('bad-request', result['condition']) - - def test_text(self): - """ - Test parsing of an error element with a text. - """ - text = self.error.addElement(('errorns', 'text')) - text.addContent('test') - result = error._parseError(self.error, 'errorns') - self.assertEqual('test', result['text']) - self.assertEqual(None, result['textLang']) - - def test_textLang(self): - """ - Test parsing of an error element with a text with a defined language. - """ - text = self.error.addElement(('errorns', 'text')) - text[NS_XML, 'lang'] = 'en_US' - text.addContent('test') - result = error._parseError(self.error, 'errorns') - self.assertEqual('en_US', result['textLang']) - - def test_textLangInherited(self): - """ - Test parsing of an error element with a text with inherited language. - """ - text = self.error.addElement(('errorns', 'text')) - self.error[NS_XML, 'lang'] = 'en_US' - text.addContent('test') - result = error._parseError(self.error, 'errorns') - self.assertEqual('en_US', result['textLang']) - test_textLangInherited.todo = "xml:lang inheritance not implemented" - - def test_appCondition(self): - """ - Test parsing of an error element with an app specific condition. - """ - condition = self.error.addElement(('testns', 'condition')) - result = error._parseError(self.error, 'errorns') - self.assertEqual(condition, result['appCondition']) - - def test_appConditionMultiple(self): - """ - Test parsing of an error element with multiple app specific conditions. - """ - condition = self.error.addElement(('testns', 'condition')) - condition2 = self.error.addElement(('testns', 'condition2')) - result = error._parseError(self.error, 'errorns') - self.assertEqual(condition2, result['appCondition']) - -class ExceptionFromStanzaTest(unittest.TestCase): - - def test_basic(self): - """ - Test basic operations of exceptionFromStanza. - - Given a realistic stanza, check if a sane exception is returned. - - Using this stanza:: - - - - - - - - - - - """ - - stanza = domish.Element((None, 'stanza')) - p = stanza.addElement(('http://jabber.org/protocol/pubsub', 'pubsub')) - p.addElement('subscriptions') - e = stanza.addElement('error') - e['type'] = 'cancel' - e.addElement((NS_XMPP_STANZAS, 'feature-not-implemented')) - uc = e.addElement(('http://jabber.org/protocol/pubsub#errors', - 'unsupported')) - uc['feature'] = 'retrieve-subscriptions' - - result = error.exceptionFromStanza(stanza) - self.assert_(isinstance(result, error.StanzaError)) - self.assertEquals('feature-not-implemented', result.condition) - self.assertEquals('cancel', result.type) - self.assertEquals(uc, result.appCondition) - self.assertEquals([p], result.children) - - def test_legacy(self): - """ - Test legacy operations of exceptionFromStanza. - - Given a realistic stanza with only legacy (pre-XMPP) error information, - check if a sane exception is returned. - - Using this stanza:: - - - Are you there? - Unable to resolve hostname. - - """ - stanza = domish.Element((None, 'stanza')) - p = stanza.addElement('body', content='Are you there?') - e = stanza.addElement('error', content='Unable to resolve hostname.') - e['code'] = '502' - - result = error.exceptionFromStanza(stanza) - self.assert_(isinstance(result, error.StanzaError)) - self.assertEquals('service-unavailable', result.condition) - self.assertEquals('wait', result.type) - self.assertEquals('Unable to resolve hostname.', result.text) - self.assertEquals([p], result.children) - -class ExceptionFromStreamErrorTest(unittest.TestCase): - - def test_basic(self): - """ - Test basic operations of exceptionFromStreamError. - - Given a realistic stream error, check if a sane exception is returned. - - Using this error:: - - - - - """ - - e = domish.Element(('http://etherx.jabber.org/streams', 'error')) - e.addElement((NS_XMPP_STREAMS, 'xml-not-well-formed')) - - result = error.exceptionFromStreamError(e) - self.assert_(isinstance(result, error.StreamError)) - self.assertEquals('xml-not-well-formed', result.condition) diff --git a/tools/buildbot/pylibs/twisted/words/test/test_jabberjid.py b/tools/buildbot/pylibs/twisted/words/test/test_jabberjid.py deleted file mode 100644 index dbb42e5..0000000 --- a/tools/buildbot/pylibs/twisted/words/test/test_jabberjid.py +++ /dev/null @@ -1,225 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.words.protocols.jabber.jid}. -""" - -from twisted.trial import unittest - -from twisted.words.protocols.jabber import jid - -class JIDParsingTest(unittest.TestCase): - def test_parse(self): - """ - Test different forms of JIDs. - """ - # Basic forms - self.assertEquals(jid.parse("user@host/resource"), - ("user", "host", "resource")) - self.assertEquals(jid.parse("user@host"), - ("user", "host", None)) - self.assertEquals(jid.parse("host"), - (None, "host", None)) - self.assertEquals(jid.parse("host/resource"), - (None, "host", "resource")) - - # More interesting forms - self.assertEquals(jid.parse("foo/bar@baz"), - (None, "foo", "bar@baz")) - self.assertEquals(jid.parse("boo@foo/bar@baz"), - ("boo", "foo", "bar@baz")) - self.assertEquals(jid.parse("boo@foo/bar/baz"), - ("boo", "foo", "bar/baz")) - self.assertEquals(jid.parse("boo/foo@bar@baz"), - (None, "boo", "foo@bar@baz")) - self.assertEquals(jid.parse("boo/foo/bar"), - (None, "boo", "foo/bar")) - self.assertEquals(jid.parse("boo//foo"), - (None, "boo", "/foo")) - - def test_noHost(self): - """ - Test for failure on no host part. - """ - self.assertRaises(jid.InvalidFormat, jid.parse, "user@") - - def test_doubleAt(self): - """ - Test for failure on double @ signs. - - This should fail because @ is not a valid character for the host - part of the JID. - """ - self.assertRaises(jid.InvalidFormat, jid.parse, "user@@host") - - def test_multipleAt(self): - """ - Test for failure on two @ signs. - - This should fail because @ is not a valid character for the host - part of the JID. - """ - self.assertRaises(jid.InvalidFormat, jid.parse, "user@host@host") - - # Basic tests for case mapping. These are fallback tests for the - # prepping done in twisted.words.protocols.jabber.xmpp_stringprep - - def test_prepCaseMapUser(self): - """ - Test case mapping of the user part of the JID. - """ - self.assertEquals(jid.prep("UsEr", "host", "resource"), - ("user", "host", "resource")) - - def test_prepCaseMapHost(self): - """ - Test case mapping of the host part of the JID. - """ - self.assertEquals(jid.prep("user", "hoST", "resource"), - ("user", "host", "resource")) - - def test_prepNoCaseMapResource(self): - """ - Test no case mapping of the resourcce part of the JID. - """ - self.assertEquals(jid.prep("user", "hoST", "resource"), - ("user", "host", "resource")) - self.assertNotEquals(jid.prep("user", "host", "Resource"), - ("user", "host", "resource")) - -class JIDTest(unittest.TestCase): - - def test_noneArguments(self): - """ - Test that using no arguments raises an exception. - """ - self.assertRaises(RuntimeError, jid.JID) - - def test_attributes(self): - """ - Test that the attributes correspond with the JID parts. - """ - j = jid.JID("user@host/resource") - self.assertEquals(j.user, "user") - self.assertEquals(j.host, "host") - self.assertEquals(j.resource, "resource") - - def test_userhost(self): - """ - Test the extraction of the bare JID. - """ - j = jid.JID("user@host/resource") - self.assertEquals("user@host", j.userhost()) - - def test_userhostOnlyHost(self): - """ - Test the extraction of the bare JID of the full form host/resource. - """ - j = jid.JID("host/resource") - self.assertEquals("host", j.userhost()) - - def test_userhostJID(self): - """ - Test getting a JID object of the bare JID. - """ - j1 = jid.JID("user@host/resource") - j2 = jid.internJID("user@host") - self.assertIdentical(j2, j1.userhostJID()) - - def test_userhostJIDNoResource(self): - """ - Test getting a JID object of the bare JID when there was no resource. - """ - j = jid.JID("user@host") - self.assertIdentical(j, j.userhostJID()) - - def test_fullHost(self): - """ - Test giving a string representation of the JID with only a host part. - """ - j = jid.JID(tuple=(None, 'host', None)) - self.assertEqual('host', j.full()) - - def test_fullHostResource(self): - """ - Test giving a string representation of the JID with host, resource. - """ - j = jid.JID(tuple=(None, 'host', 'resource')) - self.assertEqual('host/resource', j.full()) - - def test_fullUserHost(self): - """ - Test giving a string representation of the JID with user, host. - """ - j = jid.JID(tuple=('user', 'host', None)) - self.assertEqual('user@host', j.full()) - - def test_fullAll(self): - """ - Test giving a string representation of the JID. - """ - j = jid.JID(tuple=('user', 'host', 'resource')) - self.assertEqual('user@host/resource', j.full()) - - def test_equality(self): - """ - Test JID equality. - """ - j1 = jid.JID("user@host/resource") - j2 = jid.JID("user@host/resource") - self.assertNotIdentical(j1, j2) - self.assertEqual(j1, j2) - - def test_equalityWithNonJIDs(self): - """ - Test JID equality. - """ - j = jid.JID("user@host/resource") - self.assertFalse(j == 'user@host/resource') - - def test_inequality(self): - """ - Test JID inequality. - """ - j1 = jid.JID("user1@host/resource") - j2 = jid.JID("user2@host/resource") - self.assertNotEqual(j1, j2) - - def test_inequalityWithNonJIDs(self): - """ - Test JID equality. - """ - j = jid.JID("user@host/resource") - self.assertNotEqual(j, 'user@host/resource') - - def test_hashable(self): - """ - Test JID hashability. - """ - j1 = jid.JID("user@host/resource") - j2 = jid.JID("user@host/resource") - self.assertEqual(hash(j1), hash(j2)) - - def test_unicode(self): - """ - Test unicode representation of JIDs. - """ - j = jid.JID(tuple=('user', 'host', 'resource')) - self.assertEquals("user@host/resource", unicode(j)) - - def test_repr(self): - """ - Test representation of JID objects. - """ - j = jid.JID(tuple=('user', 'host', 'resource')) - self.assertEquals("JID(u'user@host/resource')", repr(j)) - -class InternJIDTest(unittest.TestCase): - def test_identity(self): - """ - Test that two interned JIDs yield the same object. - """ - j1 = jid.internJID("user@host") - j2 = jid.internJID("user@host") - self.assertIdentical(j1, j2) diff --git a/tools/buildbot/pylibs/twisted/words/test/test_jabbersasl.py b/tools/buildbot/pylibs/twisted/words/test/test_jabbersasl.py deleted file mode 100644 index 81b2484..0000000 --- a/tools/buildbot/pylibs/twisted/words/test/test_jabbersasl.py +++ /dev/null @@ -1,171 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -from zope.interface import implements -from twisted.internet import defer -from twisted.trial import unittest -from twisted.words.protocols.jabber import sasl, sasl_mechanisms, xmlstream -from twisted.words.xish import domish - -NS_XMPP_SASL = 'urn:ietf:params:xml:ns:xmpp-sasl' - -class DummySASLMechanism(object): - """ - Dummy SASL mechanism. - - This just returns the initialResponse passed on creation, stores any - challenges and replies with an empty response. - - @ivar challenge: Last received challenge. - @type challenge: C{unicode}. - @ivar initialResponse: Initial response to be returned when requested - via C{getInitialResponse} or C{None}. - @type initialResponse: C{unicode} - """ - - implements(sasl_mechanisms.ISASLMechanism) - - challenge = None - name = "DUMMY" - - def __init__(self, initialResponse): - self.initialResponse = initialResponse - - def getInitialResponse(self): - return self.initialResponse - - def getResponse(self, challenge): - self.challenge = challenge - return "" - -class DummySASLInitiatingInitializer(sasl.SASLInitiatingInitializer): - """ - Dummy SASL Initializer for initiating entities. - - This hardwires the SASL mechanism to L{DummySASLMechanism}, that is - instantiated with the value of C{initialResponse}. - - @ivar initialResponse: The initial response to be returned by the - dummy SASL mechanism or C{None}. - @type initialResponse: C{unicode}. - """ - - initialResponse = None - - def setMechanism(self): - self.mechanism = DummySASLMechanism(self.initialResponse) - -class SASLInitiatingInitializerTest(unittest.TestCase): - - def setUp(self): - self.output = [] - - self.authenticator = xmlstream.Authenticator() - self.xmlstream = xmlstream.XmlStream(self.authenticator) - self.xmlstream.send = self.output.append - self.xmlstream.connectionMade() - self.xmlstream.dataReceived("") - self.init = DummySASLInitiatingInitializer(self.xmlstream) - - def test_onFailure(self): - """ - Test that the SASL error condition is correctly extracted. - """ - failure = domish.Element(('urn:ietf:params:xml:ns:xmpp-sasl', - 'failure')) - failure.addElement('not-authorized') - self.init._deferred = defer.Deferred() - self.init.onFailure(failure) - self.assertFailure(self.init._deferred, sasl.SASLAuthError) - self.init._deferred.addCallback(lambda e: - self.assertEquals('not-authorized', - e.condition)) - return self.init._deferred - - def test_sendAuthInitialResponse(self): - """ - Test starting authentication with an initial response. - """ - self.init.initialResponse = "dummy" - self.init.start() - auth = self.output[0] - self.assertEquals(NS_XMPP_SASL, auth.uri) - self.assertEquals('auth', auth.name) - self.assertEquals('DUMMY', auth['mechanism']) - self.assertEquals('ZHVtbXk=', str(auth)) - - def test_sendAuthNoInitialResponse(self): - """ - Test starting authentication without an initial response. - """ - self.init.initialResponse = None - self.init.start() - auth = self.output[0] - self.assertEquals('', str(auth)) - - def test_sendAuthEmptyInitialResponse(self): - """ - Test starting authentication where the initial response is empty. - """ - self.init.initialResponse = "" - self.init.start() - auth = self.output[0] - self.assertEquals('=', str(auth)) - - def test_onChallenge(self): - """ - Test receiving a challenge message. - """ - d = self.init.start() - challenge = domish.Element((NS_XMPP_SASL, 'challenge')) - challenge.addContent('bXkgY2hhbGxlbmdl') - self.init.onChallenge(challenge) - self.assertEqual('my challenge', self.init.mechanism.challenge) - self.init.onSuccess(None) - return d - - def test_onChallengeEmpty(self): - """ - Test receiving an empty challenge message. - """ - d = self.init.start() - challenge = domish.Element((NS_XMPP_SASL, 'challenge')) - self.init.onChallenge(challenge) - self.assertEqual('', self.init.mechanism.challenge) - self.init.onSuccess(None) - return d - - def test_onChallengeIllegalPadding(self): - """ - Test receiving a challenge message with illegal padding. - """ - d = self.init.start() - challenge = domish.Element((NS_XMPP_SASL, 'challenge')) - challenge.addContent('bXkg=Y2hhbGxlbmdl') - self.init.onChallenge(challenge) - self.assertFailure(d, sasl.SASLIncorrectEncodingError) - return d - - def test_onChallengeIllegalCharacters(self): - """ - Test receiving a challenge message with illegal characters. - """ - d = self.init.start() - challenge = domish.Element((NS_XMPP_SASL, 'challenge')) - challenge.addContent('bXkg*Y2hhbGxlbmdl') - self.init.onChallenge(challenge) - self.assertFailure(d, sasl.SASLIncorrectEncodingError) - return d - - def test_onChallengeMalformed(self): - """ - Test receiving a malformed challenge message. - """ - d = self.init.start() - challenge = domish.Element((NS_XMPP_SASL, 'challenge')) - challenge.addContent('a') - self.init.onChallenge(challenge) - self.assertFailure(d, sasl.SASLIncorrectEncodingError) - return d diff --git a/tools/buildbot/pylibs/twisted/words/test/test_jabbersaslmechanisms.py b/tools/buildbot/pylibs/twisted/words/test/test_jabbersaslmechanisms.py deleted file mode 100644 index 67b9876..0000000 --- a/tools/buildbot/pylibs/twisted/words/test/test_jabbersaslmechanisms.py +++ /dev/null @@ -1,75 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.words.protocols.jabber.sasl_mechanisms}. -""" - -from twisted.trial import unittest - -from twisted.words.protocols.jabber import sasl_mechanisms - -class PlainTest(unittest.TestCase): - def test_getInitialResponse(self): - """ - Test the initial response. - """ - m = sasl_mechanisms.Plain(None, 'test', 'secret') - self.assertEquals(m.getInitialResponse(), '\x00test\x00secret') - -class DigestMD5Test(unittest.TestCase): - def setUp(self): - self.mechanism = sasl_mechanisms.DigestMD5('xmpp', 'example.org', None, - 'test', 'secret') - - - def test_getInitialResponse(self): - """ - Test that no initial response is generated. - """ - self.assertIdentical(self.mechanism.getInitialResponse(), None) - - def test_getResponse(self): - """ - Partially test challenge response. - - Does not actually test the response-value, yet. - """ - - challenge = 'realm="localhost",nonce="1234",qop="auth",charset=utf-8,algorithm=md5-sess' - directives = self.mechanism._parse(self.mechanism.getResponse(challenge)) - self.assertEqual(directives['username'], 'test') - self.assertEqual(directives['nonce'], '1234') - self.assertEqual(directives['nc'], '00000001') - self.assertEqual(directives['qop'], ['auth']) - self.assertEqual(directives['charset'], 'utf-8') - self.assertEqual(directives['digest-uri'], 'xmpp/example.org') - self.assertEqual(directives['realm'], 'localhost') - - def test_getResponseNoRealm(self): - """ - Test that we accept challenges without realm. - - The realm should default to the host part of the JID. - """ - - challenge = 'nonce="1234",qop="auth",charset=utf-8,algorithm=md5-sess' - directives = self.mechanism._parse(self.mechanism.getResponse(challenge)) - self.assertEqual(directives['realm'], 'example.org') - - def test__parse(self): - """ - Test challenge decoding. - - Specifically, check for multiple values for the C{qop} and C{cipher} - directives. - """ - challenge = 'nonce="1234",qop="auth,auth-conf",charset=utf-8,' \ - 'algorithm=md5-sess,cipher="des,3des"' - directives = self.mechanism._parse(challenge) - self.assertEqual('1234', directives['nonce']) - self.assertEqual('utf-8', directives['charset']) - self.assertIn('auth', directives['qop']) - self.assertIn('auth-conf', directives['qop']) - self.assertIn('des', directives['cipher']) - self.assertIn('3des', directives['cipher']) diff --git a/tools/buildbot/pylibs/twisted/words/test/test_jabberxmlstream.py b/tools/buildbot/pylibs/twisted/words/test/test_jabberxmlstream.py deleted file mode 100644 index 2313b0d..0000000 --- a/tools/buildbot/pylibs/twisted/words/test/test_jabberxmlstream.py +++ /dev/null @@ -1,1174 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.words.protocols.jabber.xmlstream}. -""" - -from twisted.trial import unittest - -from zope.interface.verify import verifyObject - -from twisted.internet import defer, task -from twisted.internet.error import ConnectionLost -from twisted.test import proto_helpers -from twisted.words.xish import domish -from twisted.words.protocols.jabber import error, ijabber, jid, xmlstream - - - -NS_XMPP_TLS = 'urn:ietf:params:xml:ns:xmpp-tls' - - - -class IQTest(unittest.TestCase): - """ - Tests both IQ and the associated IIQResponseTracker callback. - """ - - def setUp(self): - authenticator = xmlstream.ConnectAuthenticator('otherhost') - authenticator.namespace = 'testns' - self.xmlstream = xmlstream.XmlStream(authenticator) - self.clock = task.Clock() - self.xmlstream._callLater = self.clock.callLater - self.xmlstream.makeConnection(proto_helpers.StringTransport()) - self.xmlstream.dataReceived( - "") - self.iq = xmlstream.IQ(self.xmlstream, 'get') - - - def testBasic(self): - self.assertEquals(self.iq['type'], 'get') - self.assertTrue(self.iq['id']) - - - def testSend(self): - self.xmlstream.transport.clear() - self.iq.send() - self.assertEquals("" % self.iq['id'], - self.xmlstream.transport.value()) - - - def testResultResponse(self): - def cb(result): - self.assertEquals(result['type'], 'result') - - d = self.iq.send() - d.addCallback(cb) - - xs = self.xmlstream - xs.dataReceived("" % self.iq['id']) - return d - - - def testErrorResponse(self): - d = self.iq.send() - self.assertFailure(d, error.StanzaError) - - xs = self.xmlstream - xs.dataReceived("" % self.iq['id']) - return d - - - def testNonTrackedResponse(self): - """ - Test that untracked iq responses don't trigger any action. - - Untracked means that the id of the incoming response iq is not - in the stream's C{iqDeferreds} dictionary. - """ - xs = self.xmlstream - xmlstream.upgradeWithIQResponseTracker(xs) - - # Make sure we aren't tracking any iq's. - self.failIf(xs.iqDeferreds) - - # Set up a fallback handler that checks the stanza's handled attribute. - # If that is set to True, the iq tracker claims to have handled the - # response. - def cb(iq): - self.failIf(getattr(iq, 'handled', False)) - - xs.addObserver("/iq", cb, -1) - - # Receive an untracked iq response - xs.dataReceived("") - - - def testCleanup(self): - """ - Test if the deferred associated with an iq request is removed - from the list kept in the L{XmlStream} object after it has - been fired. - """ - - d = self.iq.send() - xs = self.xmlstream - xs.dataReceived("" % self.iq['id']) - self.assertNotIn(self.iq['id'], xs.iqDeferreds) - return d - - - def testDisconnectCleanup(self): - """ - Test if deferreds for iq's that haven't yet received a response - have their errback called on stream disconnect. - """ - - d = self.iq.send() - xs = self.xmlstream - xs.connectionLost("Closed by peer") - self.assertFailure(d, ConnectionLost) - return d - - - def testNoModifyingDict(self): - """ - Test to make sure the errbacks cannot cause the iteration of the - iqDeferreds to blow up in our face. - """ - - def eb(failure): - d = xmlstream.IQ(self.xmlstream).send() - d.addErrback(eb) - - d = self.iq.send() - d.addErrback(eb) - self.xmlstream.connectionLost("Closed by peer") - return d - - - def testRequestTimingOut(self): - """ - Test that an iq request with a defined timeout times out. - """ - self.iq.timeout = 60 - d = self.iq.send() - self.assertFailure(d, xmlstream.TimeoutError) - - self.clock.pump([1, 60]) - self.failIf(self.clock.calls) - self.failIf(self.xmlstream.iqDeferreds) - return d - - - def testRequestNotTimingOut(self): - """ - Test that an iq request with a defined timeout does not time out - when a response was received before the timeout period elapsed. - """ - self.iq.timeout = 60 - d = self.iq.send() - self.clock.callLater(1, self.xmlstream.dataReceived, - "" % self.iq['id']) - self.clock.pump([1, 1]) - self.failIf(self.clock.calls) - return d - - - def testDisconnectTimeoutCancellation(self): - """ - Test if timeouts for iq's that haven't yet received a response - are cancelled on stream disconnect. - """ - - self.iq.timeout = 60 - d = self.iq.send() - - xs = self.xmlstream - xs.connectionLost("Closed by peer") - self.assertFailure(d, ConnectionLost) - self.failIf(self.clock.calls) - return d - - - -class XmlStreamTest(unittest.TestCase): - - def onStreamStart(self, obj): - self.gotStreamStart = True - - - def onStreamEnd(self, obj): - self.gotStreamEnd = True - - - def onStreamError(self, obj): - self.gotStreamError = True - - - def setUp(self): - """ - Set up XmlStream and several observers. - """ - self.gotStreamStart = False - self.gotStreamEnd = False - self.gotStreamError = False - xs = xmlstream.XmlStream(xmlstream.Authenticator()) - xs.addObserver('//event/stream/start', self.onStreamStart) - xs.addObserver('//event/stream/end', self.onStreamEnd) - xs.addObserver('//event/stream/error', self.onStreamError) - xs.makeConnection(proto_helpers.StringTransportWithDisconnection()) - xs.transport.protocol = xs - xs.namespace = 'testns' - xs.version = (1, 0) - self.xmlstream = xs - - - def test_sendHeaderBasic(self): - """ - Basic test on the header sent by sendHeader. - """ - xs = self.xmlstream - xs.sendHeader() - splitHeader = self.xmlstream.transport.value()[0:-1].split(' ') - self.assertIn("") - xs.dataReceived("") - self.assertTrue(self.gotStreamError) - self.assertTrue(self.gotStreamEnd) - - - def test_sendStreamErrorInitiating(self): - """ - Test sendStreamError on an initiating xmlstream with a header sent. - - An error should be sent out and the connection lost. - """ - xs = self.xmlstream - xs.initiating = True - xs.sendHeader() - xs.transport.clear() - xs.sendStreamError(error.StreamError('version-unsupported')) - self.assertNotEqual('', xs.transport.value()) - self.assertTrue(self.gotStreamEnd) - - - def test_sendStreamErrorInitiatingNoHeader(self): - """ - Test sendStreamError on an initiating xmlstream without having sent a - header. - - In this case, no header should be generated. Also, the error should - not be sent out on the stream. Just closing the connection. - """ - xs = self.xmlstream - xs.initiating = True - xs.transport.clear() - xs.sendStreamError(error.StreamError('version-unsupported')) - self.assertNot(xs._headerSent) - self.assertEqual('', xs.transport.value()) - self.assertTrue(self.gotStreamEnd) - - - def test_sendStreamErrorReceiving(self): - """ - Test sendStreamError on a receiving xmlstream with a header sent. - - An error should be sent out and the connection lost. - """ - xs = self.xmlstream - xs.initiating = False - xs.sendHeader() - xs.transport.clear() - xs.sendStreamError(error.StreamError('version-unsupported')) - self.assertNotEqual('', xs.transport.value()) - self.assertTrue(self.gotStreamEnd) - - - def test_sendStreamErrorReceivingNoHeader(self): - """ - Test sendStreamError on a receiving xmlstream without having sent a - header. - - In this case, a header should be generated. Then, the error should - be sent out on the stream followed by closing the connection. - """ - xs = self.xmlstream - xs.initiating = False - xs.transport.clear() - xs.sendStreamError(error.StreamError('version-unsupported')) - self.assertTrue(xs._headerSent) - self.assertNotEqual('', xs.transport.value()) - self.assertTrue(self.gotStreamEnd) - - - def test_reset(self): - """ - Test resetting the XML stream to start a new layer. - """ - xs = self.xmlstream - xs.sendHeader() - stream = xs.stream - xs.reset() - self.assertNotEqual(stream, xs.stream) - self.assertNot(xs._headerSent) - - - def test_send(self): - """ - Test send with various types of objects. - """ - xs = self.xmlstream - xs.send('') - self.assertEqual(xs.transport.value(), '') - - xs.transport.clear() - el = domish.Element(('testns', 'presence')) - xs.send(el) - self.assertEqual(xs.transport.value(), '') - - xs.transport.clear() - el = domish.Element(('http://etherx.jabber.org/streams', 'features')) - xs.send(el) - self.assertEqual(xs.transport.value(), '') - - - def test_authenticator(self): - """ - Test that the associated authenticator is correctly called. - """ - connectionMadeCalls = [] - streamStartedCalls = [] - associateWithStreamCalls = [] - - class TestAuthenticator: - def connectionMade(self): - connectionMadeCalls.append(None) - - def streamStarted(self, rootElement): - streamStartedCalls.append(rootElement) - - def associateWithStream(self, xs): - associateWithStreamCalls.append(xs) - - a = TestAuthenticator() - xs = xmlstream.XmlStream(a) - self.assertEqual([xs], associateWithStreamCalls) - xs.connectionMade() - self.assertEqual([None], connectionMadeCalls) - xs.dataReceived("") - self.assertEqual(1, len(streamStartedCalls)) - xs.reset() - self.assertEqual([None], connectionMadeCalls) - - - -class TestError(Exception): - pass - - - -class AuthenticatorTest(unittest.TestCase): - def setUp(self): - self.authenticator = xmlstream.ListenAuthenticator() - self.xmlstream = xmlstream.XmlStream(self.authenticator) - - - def test_streamStart(self): - """ - Test streamStart to fill the appropriate attributes from the - stream header. - """ - xs = self.xmlstream - xs.makeConnection(proto_helpers.StringTransport()) - xs.dataReceived("") - self.assertEqual((1, 0), xs.version) - self.assertIdentical(None, xs.sid) - self.assertEqual('jabber:client', xs.namespace) - self.assertIdentical(None, xs.otherEntity) - self.assertEqual('example.com', xs.thisEntity.host) - - - def test_streamStartLegacy(self): - """ - Test streamStart to fill the appropriate attributes from the - stream header for a pre-XMPP-1.0 header. - """ - xs = self.xmlstream - xs.makeConnection(proto_helpers.StringTransport()) - xs.dataReceived("") - self.assertEqual((0, 0), xs.version) - - - def test_streamBadVersionOneDigit(self): - """ - Test streamStart to fill the appropriate attributes from the - stream header for a version with only one digit. - """ - xs = self.xmlstream - xs.makeConnection(proto_helpers.StringTransport()) - xs.dataReceived("") - self.assertEqual((0, 0), xs.version) - - - def test_streamBadVersionNoNumber(self): - """ - Test streamStart to fill the appropriate attributes from the - stream header for a malformed version. - """ - xs = self.xmlstream - xs.makeConnection(proto_helpers.StringTransport()) - xs.dataReceived("") - self.assertEqual((0, 0), xs.version) - - - -class ConnectAuthenticatorTest(unittest.TestCase): - - def setUp(self): - self.gotAuthenticated = False - self.initFailure = None - self.authenticator = xmlstream.ConnectAuthenticator('otherHost') - self.xmlstream = xmlstream.XmlStream(self.authenticator) - self.xmlstream.addObserver('//event/stream/authd', self.onAuthenticated) - self.xmlstream.addObserver('//event/xmpp/initfailed', self.onInitFailed) - - - def onAuthenticated(self, obj): - self.gotAuthenticated = True - - - def onInitFailed(self, failure): - self.initFailure = failure - - - def testSucces(self): - """ - Test successful completion of an initialization step. - """ - class Initializer: - def initialize(self): - pass - - init = Initializer() - self.xmlstream.initializers = [init] - - self.authenticator.initializeStream() - self.assertEqual([], self.xmlstream.initializers) - self.assertTrue(self.gotAuthenticated) - - - def testFailure(self): - """ - Test failure of an initialization step. - """ - class Initializer: - def initialize(self): - raise TestError - - init = Initializer() - self.xmlstream.initializers = [init] - - self.authenticator.initializeStream() - self.assertEqual([init], self.xmlstream.initializers) - self.assertFalse(self.gotAuthenticated) - self.assertNotIdentical(None, self.initFailure) - self.assertTrue(self.initFailure.check(TestError)) - - - def test_streamStart(self): - """ - Test streamStart to fill the appropriate attributes from the - stream header. - """ - self.authenticator.namespace = 'testns' - xs = self.xmlstream - xs.makeConnection(proto_helpers.StringTransport()) - xs.dataReceived("") - self.assertEqual((1, 0), xs.version) - self.assertEqual('12345', xs.sid) - self.assertEqual('testns', xs.namespace) - self.assertEqual('example.com', xs.otherEntity.host) - self.assertIdentical(None, xs.thisEntity) - self.assertNot(self.gotAuthenticated) - xs.dataReceived("" - "" - "") - self.assertIn(('testns', 'test'), xs.features) - self.assertTrue(self.gotAuthenticated) - - - -class ListenAuthenticatorTest(unittest.TestCase): - def setUp(self): - self.authenticator = xmlstream.ListenAuthenticator() - self.xmlstream = xmlstream.XmlStream(self.authenticator) - - - def test_streamStart(self): - """ - Test streamStart to fill the appropriate attributes from the - stream header. - """ - xs = self.xmlstream - xs.makeConnection(proto_helpers.StringTransport()) - xs.dataReceived("") - self.assertEqual((1, 0), xs.version) - self.assertIdentical(None, xs.sid) - self.assertEqual('jabber:client', xs.namespace) - self.assertIdentical(None, xs.otherEntity) - self.assertEqual('example.com', xs.thisEntity.host) - - - -class TLSInitiatingInitializerTest(unittest.TestCase): - def setUp(self): - self.output = [] - self.done = [] - - self.savedSSL = xmlstream.ssl - - self.authenticator = xmlstream.Authenticator() - self.xmlstream = xmlstream.XmlStream(self.authenticator) - self.xmlstream.send = self.output.append - self.xmlstream.connectionMade() - self.xmlstream.dataReceived("") - self.init = xmlstream.TLSInitiatingInitializer(self.xmlstream) - - - def tearDown(self): - xmlstream.ssl = self.savedSSL - - - def testWantedSupported(self): - """ - Test start when TLS is wanted and the SSL library available. - """ - self.xmlstream.transport = proto_helpers.StringTransport() - self.xmlstream.transport.startTLS = lambda ctx: self.done.append('TLS') - self.xmlstream.reset = lambda: self.done.append('reset') - self.xmlstream.sendHeader = lambda: self.done.append('header') - - d = self.init.start() - d.addCallback(self.assertEquals, xmlstream.Reset) - starttls = self.output[0] - self.assertEquals('starttls', starttls.name) - self.assertEquals(NS_XMPP_TLS, starttls.uri) - self.xmlstream.dataReceived("" % NS_XMPP_TLS) - self.assertEquals(['TLS', 'reset', 'header'], self.done) - - return d - - if not xmlstream.ssl: - testWantedSupported.skip = "SSL not available" - - - def testWantedNotSupportedNotRequired(self): - """ - Test start when TLS is wanted and the SSL library available. - """ - xmlstream.ssl = None - - d = self.init.start() - d.addCallback(self.assertEquals, None) - self.assertEquals([], self.output) - - return d - - - def testWantedNotSupportedRequired(self): - """ - Test start when TLS is wanted and the SSL library available. - """ - xmlstream.ssl = None - self.init.required = True - - d = self.init.start() - self.assertFailure(d, xmlstream.TLSNotSupported) - self.assertEquals([], self.output) - - return d - - - def testNotWantedRequired(self): - """ - Test start when TLS is not wanted, but required by the server. - """ - tls = domish.Element(('urn:ietf:params:xml:ns:xmpp-tls', 'starttls')) - tls.addElement('required') - self.xmlstream.features = {(tls.uri, tls.name): tls} - self.init.wanted = False - - d = self.init.start() - self.assertEquals([], self.output) - self.assertFailure(d, xmlstream.TLSRequired) - - return d - - - def testNotWantedNotRequired(self): - """ - Test start when TLS is not wanted, but required by the server. - """ - tls = domish.Element(('urn:ietf:params:xml:ns:xmpp-tls', 'starttls')) - self.xmlstream.features = {(tls.uri, tls.name): tls} - self.init.wanted = False - - d = self.init.start() - d.addCallback(self.assertEqual, None) - self.assertEquals([], self.output) - return d - - - def testFailed(self): - """ - Test failed TLS negotiation. - """ - # Pretend that ssl is supported, it isn't actually used when the - # server starts out with a failure in response to our initial - # C{starttls} stanza. - xmlstream.ssl = 1 - - d = self.init.start() - self.assertFailure(d, xmlstream.TLSFailed) - self.xmlstream.dataReceived("" % NS_XMPP_TLS) - return d - - - -class TestFeatureInitializer(xmlstream.BaseFeatureInitiatingInitializer): - feature = ('testns', 'test') - - def start(self): - return defer.succeed(None) - - - -class BaseFeatureInitiatingInitializerTest(unittest.TestCase): - - def setUp(self): - self.xmlstream = xmlstream.XmlStream(xmlstream.Authenticator()) - self.init = TestFeatureInitializer(self.xmlstream) - - - def testAdvertized(self): - """ - Test that an advertized feature results in successful initialization. - """ - self.xmlstream.features = {self.init.feature: - domish.Element(self.init.feature)} - return self.init.initialize() - - - def testNotAdvertizedRequired(self): - """ - Test that when the feature is not advertized, but required by the - initializer, an exception is raised. - """ - self.init.required = True - self.assertRaises(xmlstream.FeatureNotAdvertized, self.init.initialize) - - - def testNotAdvertizedNotRequired(self): - """ - Test that when the feature is not advertized, and not required by the - initializer, the initializer silently succeeds. - """ - self.init.required = False - self.assertIdentical(None, self.init.initialize()) - - - -class ToResponseTest(unittest.TestCase): - - def test_toResponse(self): - """ - Test that a response stanza is generated with addressing swapped. - """ - stanza = domish.Element(('jabber:client', 'iq')) - stanza['type'] = 'get' - stanza['to'] = 'user1@example.com' - stanza['from'] = 'user2@example.com/resource' - stanza['id'] = 'stanza1' - response = xmlstream.toResponse(stanza, 'result') - self.assertNotIdentical(stanza, response) - self.assertEqual(response['from'], 'user1@example.com') - self.assertEqual(response['to'], 'user2@example.com/resource') - self.assertEqual(response['type'], 'result') - self.assertEqual(response['id'], 'stanza1') - - - def test_toResponseNoFrom(self): - """ - Test that a response is generated from a stanza without a from address. - """ - stanza = domish.Element(('jabber:client', 'iq')) - stanza['type'] = 'get' - stanza['to'] = 'user1@example.com' - response = xmlstream.toResponse(stanza) - self.assertEqual(response['from'], 'user1@example.com') - self.failIf(response.hasAttribute('to')) - - - def test_toResponseNoTo(self): - """ - Test that a response is generated from a stanza without a to address. - """ - stanza = domish.Element(('jabber:client', 'iq')) - stanza['type'] = 'get' - stanza['from'] = 'user2@example.com/resource' - response = xmlstream.toResponse(stanza) - self.failIf(response.hasAttribute('from')) - self.assertEqual(response['to'], 'user2@example.com/resource') - - - def test_toResponseNoAddressing(self): - """ - Test that a response is generated from a stanza without any addressing. - """ - stanza = domish.Element(('jabber:client', 'message')) - stanza['type'] = 'chat' - response = xmlstream.toResponse(stanza) - self.failIf(response.hasAttribute('to')) - self.failIf(response.hasAttribute('from')) - - - def test_noID(self): - """ - Test that a proper response is generated without id attribute. - """ - stanza = domish.Element(('jabber:client', 'message')) - response = xmlstream.toResponse(stanza) - self.failIf(response.hasAttribute('id')) - - - -class DummyFactory(object): - """ - Dummy XmlStream factory that only registers bootstrap observers. - """ - def __init__(self): - self.callbacks = {} - - - def addBootstrap(self, event, callback): - self.callbacks[event] = callback - - - -class DummyXMPPHandler(xmlstream.XMPPHandler): - """ - Dummy XMPP subprotocol handler to count the methods are called on it. - """ - def __init__(self): - self.doneMade = 0 - self.doneInitialized = 0 - self.doneLost = 0 - - - def makeConnection(self, xs): - self.connectionMade() - - - def connectionMade(self): - self.doneMade += 1 - - - def connectionInitialized(self): - self.doneInitialized += 1 - - - def connectionLost(self, reason): - self.doneLost += 1 - - - -class XMPPHandlerTest(unittest.TestCase): - """ - Tests for L{xmlstream.XMPPHandler}. - """ - - def test_interface(self): - """ - L{xmlstream.XMPPHandler} implements L{ijabber.IXMPPHandler}. - """ - verifyObject(ijabber.IXMPPHandler, xmlstream.XMPPHandler()) - - - def test_send(self): - """ - Test that data is passed on for sending by the stream manager. - """ - class DummyStreamManager(object): - def __init__(self): - self.outlist = [] - - def send(self, data): - self.outlist.append(data) - - handler = xmlstream.XMPPHandler() - handler.parent = DummyStreamManager() - handler.send('') - self.assertEquals([''], handler.parent.outlist) - - - def test_makeConnection(self): - """ - Test that makeConnection saves the XML stream and calls connectionMade. - """ - class TestXMPPHandler(xmlstream.XMPPHandler): - def connectionMade(self): - self.doneMade = True - - handler = TestXMPPHandler() - xs = xmlstream.XmlStream(xmlstream.Authenticator()) - handler.makeConnection(xs) - self.assertTrue(handler.doneMade) - self.assertIdentical(xs, handler.xmlstream) - - - def test_connectionLost(self): - """ - Test that connectionLost forgets the XML stream. - """ - handler = xmlstream.XMPPHandler() - xs = xmlstream.XmlStream(xmlstream.Authenticator()) - handler.makeConnection(xs) - handler.connectionLost(Exception()) - self.assertIdentical(None, handler.xmlstream) - - - -class XMPPHandlerCollectionTest(unittest.TestCase): - """ - Tests for L{xmlstream.XMPPHandlerCollection}. - """ - - def setUp(self): - self.collection = xmlstream.XMPPHandlerCollection() - - - def test_interface(self): - """ - L{xmlstream.StreamManager} implements L{ijabber.IXMPPHandlerCollection}. - """ - verifyObject(ijabber.IXMPPHandlerCollection, self.collection) - - - def test_addHandler(self): - """ - Test the addition of a protocol handler. - """ - handler = DummyXMPPHandler() - handler.setHandlerParent(self.collection) - self.assertIn(handler, self.collection) - self.assertIdentical(self.collection, handler.parent) - - - def test_removeHandler(self): - """ - Test removal of a protocol handler. - """ - handler = DummyXMPPHandler() - handler.setHandlerParent(self.collection) - handler.disownHandlerParent(self.collection) - self.assertNotIn(handler, self.collection) - self.assertIdentical(None, handler.parent) - - - -class StreamManagerTest(unittest.TestCase): - """ - Tests for L{xmlstream.StreamManager}. - """ - - def setUp(self): - factory = DummyFactory() - self.streamManager = xmlstream.StreamManager(factory) - - - def test_basic(self): - """ - Test correct initialization and setup of factory observers. - """ - sm = self.streamManager - self.assertIdentical(None, sm.xmlstream) - self.assertEquals([], sm.handlers) - self.assertEquals(sm._connected, - sm.factory.callbacks['//event/stream/connected']) - self.assertEquals(sm._authd, - sm.factory.callbacks['//event/stream/authd']) - self.assertEquals(sm._disconnected, - sm.factory.callbacks['//event/stream/end']) - self.assertEquals(sm.initializationFailed, - sm.factory.callbacks['//event/xmpp/initfailed']) - - - def test_connected(self): - """ - Test that protocol handlers have their connectionMade method called - when the XML stream is connected. - """ - sm = self.streamManager - handler = DummyXMPPHandler() - handler.setHandlerParent(sm) - xs = xmlstream.XmlStream(xmlstream.Authenticator()) - sm._connected(xs) - self.assertEquals(1, handler.doneMade) - self.assertEquals(0, handler.doneInitialized) - self.assertEquals(0, handler.doneLost) - - - def test_connectedLogTrafficFalse(self): - """ - Test raw data functions unset when logTraffic is set to False. - """ - sm = self.streamManager - handler = DummyXMPPHandler() - handler.setHandlerParent(sm) - xs = xmlstream.XmlStream(xmlstream.Authenticator()) - sm._connected(xs) - self.assertIdentical(None, xs.rawDataInFn) - self.assertIdentical(None, xs.rawDataOutFn) - - - def test_connectedLogTrafficTrue(self): - """ - Test raw data functions set when logTraffic is set to True. - """ - sm = self.streamManager - sm.logTraffic = True - handler = DummyXMPPHandler() - handler.setHandlerParent(sm) - xs = xmlstream.XmlStream(xmlstream.Authenticator()) - sm._connected(xs) - self.assertNotIdentical(None, xs.rawDataInFn) - self.assertNotIdentical(None, xs.rawDataOutFn) - - - def test_authd(self): - """ - Test that protocol handlers have their connectionInitialized method - called when the XML stream is initialized. - """ - sm = self.streamManager - handler = DummyXMPPHandler() - handler.setHandlerParent(sm) - xs = xmlstream.XmlStream(xmlstream.Authenticator()) - sm._authd(xs) - self.assertEquals(0, handler.doneMade) - self.assertEquals(1, handler.doneInitialized) - self.assertEquals(0, handler.doneLost) - - - def test_disconnected(self): - """ - Test that protocol handlers have their connectionLost method - called when the XML stream is disconnected. - """ - sm = self.streamManager - handler = DummyXMPPHandler() - handler.setHandlerParent(sm) - xs = xmlstream.XmlStream(xmlstream.Authenticator()) - sm._disconnected(xs) - self.assertEquals(0, handler.doneMade) - self.assertEquals(0, handler.doneInitialized) - self.assertEquals(1, handler.doneLost) - - - def test_addHandler(self): - """ - Test the addition of a protocol handler while not connected. - """ - sm = self.streamManager - handler = DummyXMPPHandler() - handler.setHandlerParent(sm) - - self.assertEquals(0, handler.doneMade) - self.assertEquals(0, handler.doneInitialized) - self.assertEquals(0, handler.doneLost) - - - def test_addHandlerInitialized(self): - """ - Test the addition of a protocol handler after the stream - have been initialized. - - Make sure that the handler will have the connected stream - passed via C{makeConnection} and have C{connectionInitialized} - called. - """ - sm = self.streamManager - xs = xmlstream.XmlStream(xmlstream.Authenticator()) - sm._connected(xs) - sm._authd(xs) - handler = DummyXMPPHandler() - handler.setHandlerParent(sm) - - self.assertEquals(1, handler.doneMade) - self.assertEquals(1, handler.doneInitialized) - self.assertEquals(0, handler.doneLost) - - - def test_sendInitialized(self): - """ - Test send when the stream has been initialized. - - The data should be sent directly over the XML stream. - """ - factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator()) - sm = xmlstream.StreamManager(factory) - xs = factory.buildProtocol(None) - xs.transport = proto_helpers.StringTransport() - xs.connectionMade() - xs.dataReceived("") - xs.dispatch(xs, "//event/stream/authd") - sm.send("") - self.assertEquals("", xs.transport.value()) - - - def test_sendNotConnected(self): - """ - Test send when there is no established XML stream. - - The data should be cached until an XML stream has been established and - initialized. - """ - factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator()) - sm = xmlstream.StreamManager(factory) - handler = DummyXMPPHandler() - sm.addHandler(handler) - - xs = factory.buildProtocol(None) - xs.transport = proto_helpers.StringTransport() - sm.send("") - self.assertEquals("", xs.transport.value()) - self.assertEquals("", sm._packetQueue[0]) - - xs.connectionMade() - self.assertEquals("", xs.transport.value()) - self.assertEquals("", sm._packetQueue[0]) - - xs.dataReceived("") - xs.dispatch(xs, "//event/stream/authd") - - self.assertEquals("", xs.transport.value()) - self.failIf(sm._packetQueue) - - - def test_sendNotInitialized(self): - """ - Test send when the stream is connected but not yet initialized. - - The data should be cached until the XML stream has been initialized. - """ - factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator()) - sm = xmlstream.StreamManager(factory) - xs = factory.buildProtocol(None) - xs.transport = proto_helpers.StringTransport() - xs.connectionMade() - xs.dataReceived("") - sm.send("") - self.assertEquals("", xs.transport.value()) - self.assertEquals("", sm._packetQueue[0]) - - - def test_sendDisconnected(self): - """ - Test send after XML stream disconnection. - - The data should be cached until a new XML stream has been established - and initialized. - """ - factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator()) - sm = xmlstream.StreamManager(factory) - handler = DummyXMPPHandler() - sm.addHandler(handler) - - xs = factory.buildProtocol(None) - xs.connectionMade() - xs.transport = proto_helpers.StringTransport() - xs.connectionLost(None) - - sm.send("") - self.assertEquals("", xs.transport.value()) - self.assertEquals("", sm._packetQueue[0]) diff --git a/tools/buildbot/pylibs/twisted/words/test/test_jabberxmppstringprep.py b/tools/buildbot/pylibs/twisted/words/test/test_jabberxmppstringprep.py deleted file mode 100644 index e42c0d6..0000000 --- a/tools/buildbot/pylibs/twisted/words/test/test_jabberxmppstringprep.py +++ /dev/null @@ -1,84 +0,0 @@ -# Copyright (c) 2005 Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.trial import unittest - -from twisted.words.protocols.jabber.xmpp_stringprep import nodeprep, resourceprep, nameprep, crippled - -class XMPPStringPrepTest(unittest.TestCase): - """ - - The nodeprep stringprep profile is similar to the resourceprep profile, - but does an extra mapping of characters (table B.2) and disallows - more characters (table C.1.1 and eight extra punctuation characters). - Due to this similarity, the resourceprep tests are more extensive, and - the nodeprep tests only address the mappings additional restrictions. - - The nameprep profile is nearly identical to the nameprep implementation in - L{encodings.idna}, but that implementation assumes the C{UseSTD4ASCIIRules} - flag to be false. This implementation assumes it to be true, and restricts - the allowed set of characters. The tests here only check for the - differences. - - """ - - def testResourcePrep(self): - self.assertEquals(resourceprep.prepare(u'resource'), u'resource') - self.assertNotEquals(resourceprep.prepare(u'Resource'), u'resource') - self.assertEquals(resourceprep.prepare(u' '), u' ') - - if crippled: - return - - self.assertEquals(resourceprep.prepare(u'Henry \u2163'), u'Henry IV') - self.assertEquals(resourceprep.prepare(u'foo\xad\u034f\u1806\u180b' - u'bar\u200b\u2060' - u'baz\ufe00\ufe08\ufe0f\ufeff'), - u'foobarbaz') - self.assertEquals(resourceprep.prepare(u'\u00a0'), u' ') - self.assertRaises(UnicodeError, resourceprep.prepare, u'\u1680') - self.assertEquals(resourceprep.prepare(u'\u2000'), u' ') - self.assertEquals(resourceprep.prepare(u'\u200b'), u'') - self.assertRaises(UnicodeError, resourceprep.prepare, u'\u0010\u007f') - self.assertRaises(UnicodeError, resourceprep.prepare, u'\u0085') - self.assertRaises(UnicodeError, resourceprep.prepare, u'\u180e') - self.assertEquals(resourceprep.prepare(u'\ufeff'), u'') - self.assertRaises(UnicodeError, resourceprep.prepare, u'\uf123') - self.assertRaises(UnicodeError, resourceprep.prepare, u'\U000f1234') - self.assertRaises(UnicodeError, resourceprep.prepare, u'\U0010f234') - self.assertRaises(UnicodeError, resourceprep.prepare, u'\U0008fffe') - self.assertRaises(UnicodeError, resourceprep.prepare, u'\U0010ffff') - self.assertRaises(UnicodeError, resourceprep.prepare, u'\udf42') - self.assertRaises(UnicodeError, resourceprep.prepare, u'\ufffd') - self.assertRaises(UnicodeError, resourceprep.prepare, u'\u2ff5') - self.assertEquals(resourceprep.prepare(u'\u0341'), u'\u0301') - self.assertRaises(UnicodeError, resourceprep.prepare, u'\u200e') - self.assertRaises(UnicodeError, resourceprep.prepare, u'\u202a') - self.assertRaises(UnicodeError, resourceprep.prepare, u'\U000e0001') - self.assertRaises(UnicodeError, resourceprep.prepare, u'\U000e0042') - self.assertRaises(UnicodeError, resourceprep.prepare, u'foo\u05bebar') - self.assertRaises(UnicodeError, resourceprep.prepare, u'foo\ufd50bar') - #self.assertEquals(resourceprep.prepare(u'foo\ufb38bar'), - # u'foo\u064ebar') - self.assertRaises(UnicodeError, resourceprep.prepare, u'\u06271') - self.assertEquals(resourceprep.prepare(u'\u06271\u0628'), - u'\u06271\u0628') - self.assertRaises(UnicodeError, resourceprep.prepare, u'\U000e0002') - - def testNodePrep(self): - self.assertEquals(nodeprep.prepare(u'user'), u'user') - self.assertEquals(nodeprep.prepare(u'User'), u'user') - self.assertRaises(UnicodeError, nodeprep.prepare, u'us&er') - - def testNamePrep(self): - self.assertEquals(nameprep.prepare(u'example.com'), u'example.com') - self.assertEquals(nameprep.prepare(u'Example.com'), u'example.com') - self.assertRaises(UnicodeError, nameprep.prepare, u'ex@mple.com') - self.assertRaises(UnicodeError, nameprep.prepare, u'-example.com') - self.assertRaises(UnicodeError, nameprep.prepare, u'example-.com') - - if crippled: - return - - self.assertEquals(nameprep.prepare(u'stra\u00dfe.example.com'), - u'strasse.example.com') diff --git a/tools/buildbot/pylibs/twisted/words/test/test_msn.py b/tools/buildbot/pylibs/twisted/words/test/test_msn.py deleted file mode 100644 index 97e486c..0000000 --- a/tools/buildbot/pylibs/twisted/words/test/test_msn.py +++ /dev/null @@ -1,379 +0,0 @@ -# Copyright (c) 2001-2005 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test cases for twisted.words.protocols.msn -""" - -# System imports -import StringIO, sys - -# Twisted imports - -# t.w.p.msn requires an HTTP client -try: - # So try to get one - do it directly instead of catching an ImportError - # from t.w.p.msn so that other problems which cause that module to fail - # to import don't cause the tests to be skipped. - from twisted.web import client -except ImportError: - # If there isn't one, we're going to skip all the tests. - msn = None -else: - # Otherwise importing it should work, so do it. - from twisted.words.protocols import msn - - -from twisted.protocols import loopback -from twisted.internet.defer import Deferred -from twisted.trial import unittest - -def printError(f): - print f - -class StringIOWithoutClosing(StringIO.StringIO): - disconnecting = 0 - def close(self): pass - def loseConnection(self): pass - -class PassportTests(unittest.TestCase): - - def setUp(self): - self.result = [] - self.deferred = Deferred() - self.deferred.addCallback(lambda r: self.result.append(r)) - self.deferred.addErrback(printError) - - def testNexus(self): - protocol = msn.PassportNexus(self.deferred, 'https://foobar.com/somepage.quux') - headers = { - 'Content-Length' : '0', - 'Content-Type' : 'text/html', - 'PassportURLs' : 'DARealm=Passport.Net,DALogin=login.myserver.com/,DAReg=reg.myserver.com' - } - transport = StringIOWithoutClosing() - protocol.makeConnection(transport) - protocol.dataReceived('HTTP/1.0 200 OK\r\n') - for (h,v) in headers.items(): protocol.dataReceived('%s: %s\r\n' % (h,v)) - protocol.dataReceived('\r\n') - self.failUnless(self.result[0] == "https://login.myserver.com/") - - def _doLoginTest(self, response, headers): - protocol = msn.PassportLogin(self.deferred,'foo@foo.com','testpass','https://foo.com/', 'a') - protocol.makeConnection(StringIOWithoutClosing()) - protocol.dataReceived(response) - for (h,v) in headers.items(): protocol.dataReceived('%s: %s\r\n' % (h,v)) - protocol.dataReceived('\r\n') - - def testPassportLoginSuccess(self): - headers = { - 'Content-Length' : '0', - 'Content-Type' : 'text/html', - 'Authentication-Info' : "Passport1.4 da-status=success,tname=MSPAuth," + - "tname=MSPProf,tname=MSPSec,from-PP='somekey'," + - "ru=http://messenger.msn.com" - } - self._doLoginTest('HTTP/1.1 200 OK\r\n', headers) - self.failUnless(self.result[0] == (msn.LOGIN_SUCCESS, 'somekey')) - - def testPassportLoginFailure(self): - headers = { - 'Content-Type' : 'text/html', - 'WWW-Authenticate' : 'Passport1.4 da-status=failed,' + - 'srealm=Passport.NET,ts=-3,prompt,cburl=http://host.com,' + - 'cbtxt=the%20error%20message' - } - self._doLoginTest('HTTP/1.1 401 Unauthorized\r\n', headers) - self.failUnless(self.result[0] == (msn.LOGIN_FAILURE, 'the error message')) - - def testPassportLoginRedirect(self): - headers = { - 'Content-Type' : 'text/html', - 'Authentication-Info' : 'Passport1.4 da-status=redir', - 'Location' : 'https://newlogin.host.com/' - } - self._doLoginTest('HTTP/1.1 302 Found\r\n', headers) - self.failUnless(self.result[0] == (msn.LOGIN_REDIRECT, 'https://newlogin.host.com/', 'a')) - - -if msn is not None: - class DummySwitchboardClient(msn.SwitchboardClient): - def userTyping(self, message): - self.state = 'TYPING' - - def gotSendRequest(self, fileName, fileSize, cookie, message): - if fileName == 'foobar.ext' and fileSize == 31337 and cookie == 1234: self.state = 'INVITATION' - - - class DummyNotificationClient(msn.NotificationClient): - def loggedIn(self, userHandle, screenName, verified): - if userHandle == 'foo@bar.com' and screenName == 'Test Screen Name' and verified: - self.state = 'LOGIN' - - def gotProfile(self, message): - self.state = 'PROFILE' - - def gotContactStatus(self, code, userHandle, screenName): - if code == msn.STATUS_AWAY and userHandle == "foo@bar.com" and screenName == "Test Screen Name": - self.state = 'INITSTATUS' - - def contactStatusChanged(self, code, userHandle, screenName): - if code == msn.STATUS_LUNCH and userHandle == "foo@bar.com" and screenName == "Test Name": - self.state = 'NEWSTATUS' - - def contactOffline(self, userHandle): - if userHandle == "foo@bar.com": self.state = 'OFFLINE' - - def statusChanged(self, code): - if code == msn.STATUS_HIDDEN: self.state = 'MYSTATUS' - - def listSynchronized(self, *args): - self.state = 'GOTLIST' - - def gotPhoneNumber(self, listVersion, userHandle, phoneType, number): - msn.NotificationClient.gotPhoneNumber(self, listVersion, userHandle, phoneType, number) - self.state = 'GOTPHONE' - - def userRemovedMe(self, userHandle, listVersion): - msn.NotificationClient.userRemovedMe(self, userHandle, listVersion) - c = self.factory.contacts.getContact(userHandle) - if not c and self.factory.contacts.version == listVersion: self.state = 'USERREMOVEDME' - - def userAddedMe(self, userHandle, screenName, listVersion): - msn.NotificationClient.userAddedMe(self, userHandle, screenName, listVersion) - c = self.factory.contacts.getContact(userHandle) - if c and (c.lists | msn.REVERSE_LIST) and (self.factory.contacts.version == listVersion) and \ - (screenName == 'Screen Name'): - self.state = 'USERADDEDME' - - def gotSwitchboardInvitation(self, sessionID, host, port, key, userHandle, screenName): - if sessionID == 1234 and \ - host == '192.168.1.1' and \ - port == 1863 and \ - key == '123.456' and \ - userHandle == 'foo@foo.com' and \ - screenName == 'Screen Name': - self.state = 'SBINVITED' - -class NotificationTests(unittest.TestCase): - """ testing the various events in NotificationClient """ - - def setUp(self): - self.client = DummyNotificationClient() - self.client.factory = msn.NotificationFactory() - self.client.state = 'START' - - def tearDown(self): - self.client = None - - def testLogin(self): - self.client.lineReceived('USR 1 OK foo@bar.com Test%20Screen%20Name 1 0') - self.failUnless((self.client.state == 'LOGIN'), msg='Failed to detect successful login') - - def testProfile(self): - m = 'MSG Hotmail Hotmail 353\r\nMIME-Version: 1.0\r\nContent-Type: text/x-msmsgsprofile; charset=UTF-8\r\n' - m += 'LoginTime: 1016941010\r\nEmailEnabled: 1\r\nMemberIdHigh: 40000\r\nMemberIdLow: -600000000\r\nlang_preference: 1033\r\n' - m += 'preferredEmail: foo@bar.com\r\ncountry: AU\r\nPostalCode: 90210\r\nGender: M\r\nKid: 0\r\nAge:\r\nsid: 400\r\n' - m += 'kv: 2\r\nMSPAuth: 2CACCBCCADMoV8ORoz64BVwmjtksIg!kmR!Rj5tBBqEaW9hc4YnPHSOQ$$\r\n\r\n' - map(self.client.lineReceived, m.split('\r\n')[:-1]) - self.failUnless((self.client.state == 'PROFILE'), msg='Failed to detect initial profile') - - def testStatus(self): - t = [('ILN 1 AWY foo@bar.com Test%20Screen%20Name 0', 'INITSTATUS', 'Failed to detect initial status report'), - ('NLN LUN foo@bar.com Test%20Name 0', 'NEWSTATUS', 'Failed to detect contact status change'), - ('FLN foo@bar.com', 'OFFLINE', 'Failed to detect contact signing off'), - ('CHG 1 HDN 0', 'MYSTATUS', 'Failed to detect my status changing')] - for i in t: - self.client.lineReceived(i[0]) - self.failUnless((self.client.state == i[1]), msg=i[2]) - - def testListSync(self): - # currently this test does not take into account the fact - # that BPRs sent as part of the SYN reply may not be interpreted - # as such if they are for the last LST -- maybe I should - # factor this in later. - self.client.makeConnection(StringIOWithoutClosing()) - msn.NotificationClient.loggedIn(self.client, 'foo@foo.com', 'foobar', 1) - lines = [ - "SYN %s 100 1 1" % self.client.currentID, - "GTC A", - "BLP AL", - "LSG 0 Other%20Contacts 0", - "LST userHandle@email.com Some%20Name 11 0" - ] - map(self.client.lineReceived, lines) - contacts = self.client.factory.contacts - contact = contacts.getContact('userHandle@email.com') - self.failUnless(contacts.version == 100, "Invalid contact list version") - self.failUnless(contact.screenName == 'Some Name', "Invalid screen-name for user") - self.failUnless(contacts.groups == {0 : 'Other Contacts'}, "Did not get proper group list") - self.failUnless(contact.groups == [0] and contact.lists == 11, "Invalid contact list/group info") - self.failUnless(self.client.state == 'GOTLIST', "Failed to call list sync handler") - - def testAsyncPhoneChange(self): - c = msn.MSNContact(userHandle='userHandle@email.com') - self.client.factory.contacts = msn.MSNContactList() - self.client.factory.contacts.addContact(c) - self.client.makeConnection(StringIOWithoutClosing()) - self.client.lineReceived("BPR 101 userHandle@email.com PHH 123%20456") - c = self.client.factory.contacts.getContact('userHandle@email.com') - self.failUnless(self.client.state == 'GOTPHONE', "Did not fire phone change callback") - self.failUnless(c.homePhone == '123 456', "Did not update the contact's phone number") - self.failUnless(self.client.factory.contacts.version == 101, "Did not update list version") - - def testLateBPR(self): - """ - This test makes sure that if a BPR response that was meant - to be part of a SYN response (but came after the last LST) - is received, the correct contact is updated and all is well - """ - self.client.makeConnection(StringIOWithoutClosing()) - msn.NotificationClient.loggedIn(self.client, 'foo@foo.com', 'foo', 1) - lines = [ - "SYN %s 100 1 1" % self.client.currentID, - "GTC A", - "BLP AL", - "LSG 0 Other%20Contacts 0", - "LST userHandle@email.com Some%20Name 11 0", - "BPR PHH 123%20456" - ] - map(self.client.lineReceived, lines) - contact = self.client.factory.contacts.getContact('userHandle@email.com') - self.failUnless(contact.homePhone == '123 456', "Did not update contact's phone number") - - def testUserRemovedMe(self): - self.client.factory.contacts = msn.MSNContactList() - contact = msn.MSNContact(userHandle='foo@foo.com') - contact.addToList(msn.REVERSE_LIST) - self.client.factory.contacts.addContact(contact) - self.client.lineReceived("REM 0 RL 100 foo@foo.com") - self.failUnless(self.client.state == 'USERREMOVEDME', "Failed to remove user from reverse list") - - def testUserAddedMe(self): - self.client.factory.contacts = msn.MSNContactList() - self.client.lineReceived("ADD 0 RL 100 foo@foo.com Screen%20Name") - self.failUnless(self.client.state == 'USERADDEDME', "Failed to add user to reverse lise") - - def testAsyncSwitchboardInvitation(self): - self.client.lineReceived("RNG 1234 192.168.1.1:1863 CKI 123.456 foo@foo.com Screen%20Name") - self.failUnless(self.client.state == "SBINVITED") - - def testCommandFailed(self): - """ - Ensures that error responses from the server fires an errback with - MSNCommandFailed. - """ - id, d = self.client._createIDMapping() - self.client.lineReceived("201 %s" % id) - d = self.assertFailure(d, msn.MSNCommandFailed) - def assertErrorCode(exception): - self.assertEqual(201, exception.errorCode) - return d.addCallback(assertErrorCode) - - -class MessageHandlingTests(unittest.TestCase): - """ testing various message handling methods from SwichboardClient """ - - def setUp(self): - self.client = DummySwitchboardClient() - self.client.state = 'START' - - def tearDown(self): - self.client = None - - def testClientCapabilitiesCheck(self): - m = msn.MSNMessage() - m.setHeader('Content-Type', 'text/x-clientcaps') - self.assertEquals(self.client.checkMessage(m), 0, 'Failed to detect client capability message') - - def testTypingCheck(self): - m = msn.MSNMessage() - m.setHeader('Content-Type', 'text/x-msmsgscontrol') - m.setHeader('TypingUser', 'foo@bar') - self.client.checkMessage(m) - self.failUnless((self.client.state == 'TYPING'), msg='Failed to detect typing notification') - - def testFileInvitation(self, lazyClient=False): - m = msn.MSNMessage() - m.setHeader('Content-Type', 'text/x-msmsgsinvite; charset=UTF-8') - m.message += 'Application-Name: File Transfer\r\n' - if not lazyClient: - m.message += 'Application-GUID: {5D3E02AB-6190-11d3-BBBB-00C04F795683}\r\n' - m.message += 'Invitation-Command: Invite\r\n' - m.message += 'Invitation-Cookie: 1234\r\n' - m.message += 'Application-File: foobar.ext\r\n' - m.message += 'Application-FileSize: 31337\r\n\r\n' - self.client.checkMessage(m) - self.failUnless((self.client.state == 'INVITATION'), msg='Failed to detect file transfer invitation') - - def testFileInvitationMissingGUID(self): - return self.testFileInvitation(True) - - def testFileResponse(self): - d = Deferred() - d.addCallback(self.fileResponse) - self.client.cookies['iCookies'][1234] = (d, None) - m = msn.MSNMessage() - m.setHeader('Content-Type', 'text/x-msmsgsinvite; charset=UTF-8') - m.message += 'Invitation-Command: ACCEPT\r\n' - m.message += 'Invitation-Cookie: 1234\r\n\r\n' - self.client.checkMessage(m) - self.failUnless((self.client.state == 'RESPONSE'), msg='Failed to detect file transfer response') - - def testFileInfo(self): - d = Deferred() - d.addCallback(self.fileInfo) - self.client.cookies['external'][1234] = (d, None) - m = msn.MSNMessage() - m.setHeader('Content-Type', 'text/x-msmsgsinvite; charset=UTF-8') - m.message += 'Invitation-Command: ACCEPT\r\n' - m.message += 'Invitation-Cookie: 1234\r\n' - m.message += 'IP-Address: 192.168.0.1\r\n' - m.message += 'Port: 6891\r\n' - m.message += 'AuthCookie: 4321\r\n\r\n' - self.client.checkMessage(m) - self.failUnless((self.client.state == 'INFO'), msg='Failed to detect file transfer info') - - def fileResponse(self, (accept, cookie, info)): - if accept and cookie == 1234: self.client.state = 'RESPONSE' - - def fileInfo(self, (accept, ip, port, aCookie, info)): - if accept and ip == '192.168.0.1' and port == 6891 and aCookie == 4321: self.client.state = 'INFO' - - -class FileTransferTestCase(unittest.TestCase): - """ test FileSend against FileReceive """ - - def setUp(self): - self.input = StringIOWithoutClosing() - self.input.writelines(['a'] * 7000) - self.input.seek(0) - self.output = StringIOWithoutClosing() - - def tearDown(self): - self.input = None - self.output = None - - def testFileTransfer(self): - auth = 1234 - sender = msn.FileSend(self.input) - sender.auth = auth - sender.fileSize = 7000 - client = msn.FileReceive(auth, "foo@bar.com", self.output) - client.fileSize = 7000 - def check(ignored): - self.failUnless((client.completed and sender.completed), - msg="send failed to complete") - self.failUnless((self.input.getvalue() == self.output.getvalue()), - msg="saved file does not match original") - d = loopback.loopbackAsync(sender, client) - d.addCallback(check) - return d - - -if msn is None: - for testClass in [PassportTests, NotificationTests, - MessageHandlingTests, FileTransferTestCase]: - testClass.skip = ( - "MSN requires an HTTP client but none is available, " - "skipping tests.") diff --git a/tools/buildbot/pylibs/twisted/words/test/test_service.py b/tools/buildbot/pylibs/twisted/words/test/test_service.py deleted file mode 100644 index 3313663..0000000 --- a/tools/buildbot/pylibs/twisted/words/test/test_service.py +++ /dev/null @@ -1,936 +0,0 @@ -# Copyright (c) 2001-2005 Twisted Matrix Laboratories. -# See LICENSE for details. - -from __future__ import generators - -import time - -from zope.interface import implements - -from twisted.trial import unittest -from twisted.test import proto_helpers - -from twisted.cred import portal, credentials, checkers -from twisted.words import ewords, iwords, service -from twisted.words.protocols import irc -from twisted.spread import pb -from twisted.internet.defer import Deferred, DeferredList, maybeDeferred, succeed -from twisted.internet.defer import deferredGenerator as dG, waitForDeferred as wFD -from twisted.internet import address, reactor - -class RealmTestCase(unittest.TestCase): - def _entityCreationTest(self, kind): - # Kind is "user" or "group" - realm = service.InMemoryWordsRealm("realmname") - - name = u'test' + kind.lower() - create = getattr(realm, 'create' + kind.title()) - get = getattr(realm, 'get' + kind.title()) - flag = 'create' + kind.title() + 'OnRequest' - dupExc = getattr(ewords, 'Duplicate' + kind.title()) - noSuchExc = getattr(ewords, 'NoSuch' + kind.title()) - - # Creating should succeed - d = wFD(create(name)) - yield d - p = d.getResult() - self.assertEquals(p.name, name) - - # Creating the same user again should not - d = wFD(create(name)) - yield d - self.assertRaises(dupExc, d.getResult) - - # Getting a non-existent user should succeed if createUserOnRequest is True - setattr(realm, flag, True) - d = wFD(get(u"new" + kind.lower())) - yield d - p = d.getResult() - self.assertEquals(p.name, "new" + kind.lower()) - - # Getting that user again should return the same object - d = wFD(get(u"new" + kind.lower())) - yield d - newp = d.getResult() - self.assertIdentical(p, newp) - - # Getting a non-existent user should fail if createUserOnRequest is False - setattr(realm, flag, False) - d = wFD(get(u"another" + kind.lower())) - yield d - self.assertRaises(noSuchExc, d.getResult) - _entityCreationTest = dG(_entityCreationTest) - - - def testUserCreation(self): - return self._entityCreationTest("User") - - - def testGroupCreation(self): - return self._entityCreationTest("Group") - - - def testUserRetrieval(self): - realm = service.InMemoryWordsRealm("realmname") - - # Make a user to play around with - d = wFD(realm.createUser(u"testuser")) - yield d - user = d.getResult() - - # Make sure getting the user returns the same object - d = wFD(realm.getUser(u"testuser")) - yield d - retrieved = d.getResult() - self.assertIdentical(user, retrieved) - - # Make sure looking up the user also returns the same object - d = wFD(realm.lookupUser(u"testuser")) - yield d - lookedUp = d.getResult() - self.assertIdentical(retrieved, lookedUp) - - # Make sure looking up a user who does not exist fails - d = wFD(realm.lookupUser(u"nosuchuser")) - yield d - self.assertRaises(ewords.NoSuchUser, d.getResult) - testUserRetrieval = dG(testUserRetrieval) - - - def testUserAddition(self): - realm = service.InMemoryWordsRealm("realmname") - - # Create and manually add a user to the realm - p = service.User("testuser") - d = wFD(realm.addUser(p)) - yield d - user = d.getResult() - self.assertIdentical(p, user) - - # Make sure getting that user returns the same object - d = wFD(realm.getUser(u"testuser")) - yield d - retrieved = d.getResult() - self.assertIdentical(user, retrieved) - - # Make sure looking up that user returns the same object - d = wFD(realm.lookupUser(u"testuser")) - yield d - lookedUp = d.getResult() - self.assertIdentical(retrieved, lookedUp) - testUserAddition = dG(testUserAddition) - - - def testGroupRetrieval(self): - realm = service.InMemoryWordsRealm("realmname") - - d = wFD(realm.createGroup(u"testgroup")) - yield d - group = d.getResult() - - d = wFD(realm.getGroup(u"testgroup")) - yield d - retrieved = d.getResult() - - self.assertIdentical(group, retrieved) - - d = wFD(realm.getGroup(u"nosuchgroup")) - yield d - self.assertRaises(ewords.NoSuchGroup, d.getResult) - testGroupRetrieval = dG(testGroupRetrieval) - - - def testGroupAddition(self): - realm = service.InMemoryWordsRealm("realmname") - - p = service.Group("testgroup") - d = wFD(realm.addGroup(p)) - yield d - d.getResult() - - d = wFD(realm.getGroup(u"testGroup")) - yield d - group = d.getResult() - - self.assertIdentical(p, group) - testGroupAddition = dG(testGroupAddition) - - - def testGroupUsernameCollision(self): - """ - Try creating a group with the same name as an existing user and - assert that it succeeds, since users and groups should not be in the - same namespace and collisions should be impossible. - """ - realm = service.InMemoryWordsRealm("realmname") - - d = wFD(realm.createUser(u"test")) - yield d - user = d.getResult() - - d = wFD(realm.createGroup(u"test")) - yield d - group = d.getResult() - testGroupUsernameCollision = dG(testGroupUsernameCollision) - - - def testEnumeration(self): - realm = service.InMemoryWordsRealm("realmname") - d = wFD(realm.createGroup(u"groupone")) - yield d - d.getResult() - - d = wFD(realm.createGroup(u"grouptwo")) - yield d - d.getResult() - - groups = wFD(realm.itergroups()) - yield groups - groups = groups.getResult() - - n = [g.name for g in groups] - n.sort() - self.assertEquals(n, ["groupone", "grouptwo"]) - testEnumeration = dG(testEnumeration) - - -class TestGroup(object): - def __init__(self, name, size, topic): - self.name = name - self.size = lambda: size - self.meta = {'topic': topic} - - -class TestUser(object): - def __init__(self, name, groups, signOn, lastMessage): - self.name = name - self.itergroups = lambda: iter([TestGroup(g, 3, 'Hello') for g in groups]) - self.signOn = signOn - self.lastMessage = lastMessage - - -class TestPortal(object): - def __init__(self): - self.logins = [] - - def login(self, credentials, mind, *interfaces): - d = Deferred() - self.logins.append((credentials, mind, interfaces, d)) - return d - - -class TestCaseUserAgg(object): - def __init__(self, user, realm, factory, address=address.IPv4Address('TCP', '127.0.0.1', 54321)): - self.user = user - self.transport = proto_helpers.StringTransportWithDisconnection() - self.protocol = factory.buildProtocol(address) - self.transport.protocol = self.protocol - self.user.mind = self.protocol - self.protocol.makeConnection(self.transport) - - def write(self, stuff): - if isinstance(stuff, unicode): - stuff = stuff.encode('utf-8') - self.protocol.dataReceived(stuff) - - -class IRCProtocolTestCase(unittest.TestCase): - STATIC_USERS = [ - u'useruser', u'otheruser', u'someguy', u'firstuser', u'username', - u'userone', u'usertwo', u'userthree', u'someuser'] - - def setUp(self): - self.realm = service.InMemoryWordsRealm("realmname") - self.checker = checkers.InMemoryUsernamePasswordDatabaseDontUse() - self.portal = portal.Portal(self.realm, [self.checker]) - self.factory = service.IRCFactory(self.realm, self.portal) - - c = [] - for nick in self.STATIC_USERS: - c.append(self.realm.createUser(nick)) - self.checker.addUser(nick.encode('ascii'), nick + "_password") - return DeferredList(c) - - - def _assertGreeting(self, user): - # Make sure we get 1-4 at least - response = self._response(user) - expected = range(1, 5) - for (prefix, command, args) in response: - try: - expected.remove(int(command)) - except KeyError: - pass - self.failIf(expected, "Missing responses for %r" % (expected,)) - - - def _login(self, user, nick, password=None): - if password is None: - password = nick + "_password" - user.write('PASS %s\r\n' % (password,)) - user.write('NICK %s extrainfo\r\n' % (nick,)) - - - def _loggedInUser(self, name): - d = wFD(self.realm.lookupUser(name)) - yield d - user = d.getResult() - agg = TestCaseUserAgg(user, self.realm, self.factory) - self._login(agg, name) - yield agg - _loggedInUser = dG(_loggedInUser) - - - def _response(self, user): - response = user.transport.value().splitlines() - user.transport.clear() - return map(irc.parsemsg, response) - - - def testPASSLogin(self): - user = wFD(self._loggedInUser(u'firstuser')) - yield user - user = user.getResult() - self._assertGreeting(user) - testPASSLogin = dG(testPASSLogin) - - - def testNickServLogin(self): - firstuser = wFD(self.realm.lookupUser(u'firstuser')) - yield firstuser - firstuser = firstuser.getResult() - - user = TestCaseUserAgg(firstuser, self.realm, self.factory) - user.write('NICK firstuser extrainfo\r\n') - response = self._response(user) - self.assertEquals(len(response), 1) - self.assertEquals(response[0][0], service.NICKSERV) - self.assertEquals(response[0][1], 'PRIVMSG') - self.assertEquals(response[0][2], ['firstuser', 'Password?']) - user.transport.clear() - - user.write('PRIVMSG nickserv firstuser_password\r\n') - self._assertGreeting(user) - testNickServLogin = dG(testNickServLogin) - - - def testFailedLogin(self): - firstuser = wFD(self.realm.lookupUser(u'firstuser')) - yield firstuser - firstuser = firstuser.getResult() - - user = TestCaseUserAgg(firstuser, self.realm, self.factory) - self._login(user, "firstuser", "wrongpass") - response = self._response(user) - self.assertEquals(len(response), 1) - self.assertEquals(response[0][2], ['firstuser', 'Login failed. Goodbye.']) - testFailedLogin = dG(testFailedLogin) - - - def testLogout(self): - logout = [] - firstuser = wFD(self.realm.lookupUser(u'firstuser')) - yield firstuser - firstuser = firstuser.getResult() - - user = TestCaseUserAgg(firstuser, self.realm, self.factory) - self._login(user, "firstuser") - user.protocol.logout = lambda: logout.append(True) - user.write('QUIT\r\n') - self.assertEquals(logout, [True]) - testLogout = dG(testLogout) - - - def testJoin(self): - firstuser = wFD(self.realm.lookupUser(u'firstuser')) - yield firstuser - firstuser = firstuser.getResult() - - somechannel = wFD(self.realm.createGroup(u"somechannel")) - yield somechannel - somechannel = somechannel.getResult() - - # Bring in one user, make sure he gets into the channel sanely - user = TestCaseUserAgg(firstuser, self.realm, self.factory) - self._login(user, "firstuser") - user.transport.clear() - user.write('JOIN #somechannel\r\n') - - response = self._response(user) - self.assertEquals(len(response), 5) - - # Join message - self.assertEquals(response[0][0], 'firstuser!firstuser@realmname') - self.assertEquals(response[0][1], 'JOIN') - self.assertEquals(response[0][2], ['#somechannel']) - - # User list - self.assertEquals(response[1][1], '353') - self.assertEquals(response[2][1], '366') - - # Topic (or lack thereof, as the case may be) - self.assertEquals(response[3][1], '332') - self.assertEquals(response[4][1], '333') - - - # Hook up another client! It is a CHAT SYSTEM!!!!!!! - other = wFD(self._loggedInUser(u'otheruser')) - yield other - other = other.getResult() - - other.transport.clear() - user.transport.clear() - other.write('JOIN #somechannel\r\n') - - # At this point, both users should be in the channel - response = self._response(other) - - event = self._response(user) - self.assertEquals(len(event), 1) - self.assertEquals(event[0][0], 'otheruser!otheruser@realmname') - self.assertEquals(event[0][1], 'JOIN') - self.assertEquals(event[0][2], ['#somechannel']) - - self.assertEquals(response[1][0], 'realmname') - self.assertEquals(response[1][1], '353') - self.assertEquals(response[1][2], ['otheruser', '=', '#somechannel', 'firstuser otheruser']) - testJoin = dG(testJoin) - - - def testLeave(self): - user = wFD(self._loggedInUser(u'useruser')) - yield user - user = user.getResult() - - somechannel = wFD(self.realm.createGroup(u"somechannel")) - yield somechannel - somechannel = somechannel.getResult() - - user.write('JOIN #somechannel\r\n') - user.transport.clear() - - other = wFD(self._loggedInUser(u'otheruser')) - yield other - other = other.getResult() - - other.write('JOIN #somechannel\r\n') - - user.transport.clear() - other.transport.clear() - - user.write('PART #somechannel\r\n') - - response = self._response(user) - event = self._response(other) - - self.assertEquals(len(response), 1) - self.assertEquals(response[0][0], 'useruser!useruser@realmname') - self.assertEquals(response[0][1], 'PART') - self.assertEquals(response[0][2], ['#somechannel', 'leaving']) - self.assertEquals(response, event) - - # Now again, with a part message - user.write('JOIN #somechannel\r\n') - - user.transport.clear() - other.transport.clear() - - user.write('PART #somechannel :goodbye stupidheads\r\n') - - response = self._response(user) - event = self._response(other) - - self.assertEquals(len(response), 1) - self.assertEquals(response[0][0], 'useruser!useruser@realmname') - self.assertEquals(response[0][1], 'PART') - self.assertEquals(response[0][2], ['#somechannel', 'goodbye stupidheads']) - self.assertEquals(response, event) - testLeave = dG(testLeave) - - - def testGetTopic(self): - user = wFD(self._loggedInUser(u'useruser')) - yield user - user = user.getResult() - - group = service.Group("somechannel") - group.meta["topic"] = "This is a test topic." - group.meta["topic_author"] = "some_fellow" - group.meta["topic_date"] = 77777777 - - add = wFD(self.realm.addGroup(group)) - yield add - add.getResult() - - user.transport.clear() - user.write("JOIN #somechannel\r\n") - - response = self._response(user) - - self.assertEquals(response[3][0], 'realmname') - self.assertEquals(response[3][1], '332') - - # XXX Sigh. irc.parsemsg() is not as correct as one might hope. - self.assertEquals(response[3][2], ['useruser', '#somechannel', 'This is a test topic.']) - self.assertEquals(response[4][1], '333') - self.assertEquals(response[4][2], ['useruser', '#somechannel', 'some_fellow', '77777777']) - - user.transport.clear() - - user.write('TOPIC #somechannel\r\n') - - response = self._response(user) - - self.assertEquals(response[0][1], '332') - self.assertEquals(response[0][2], ['useruser', '#somechannel', 'This is a test topic.']) - self.assertEquals(response[1][1], '333') - self.assertEquals(response[1][2], ['useruser', '#somechannel', 'some_fellow', '77777777']) - testGetTopic = dG(testGetTopic) - - - def testSetTopic(self): - user = wFD(self._loggedInUser(u'useruser')) - yield user - user = user.getResult() - - add = wFD(self.realm.createGroup(u"somechannel")) - yield add - somechannel = add.getResult() - - user.write("JOIN #somechannel\r\n") - - other = wFD(self._loggedInUser(u'otheruser')) - yield other - other = other.getResult() - - other.write("JOIN #somechannel\r\n") - - user.transport.clear() - other.transport.clear() - - other.write('TOPIC #somechannel :This is the new topic.\r\n') - - response = self._response(other) - event = self._response(user) - - self.assertEquals(response, event) - - self.assertEquals(response[0][0], 'otheruser!otheruser@realmname') - self.assertEquals(response[0][1], 'TOPIC') - self.assertEquals(response[0][2], ['#somechannel', 'This is the new topic.']) - - other.transport.clear() - - somechannel.meta['topic_date'] = 12345 - other.write('TOPIC #somechannel\r\n') - - response = self._response(other) - self.assertEquals(response[0][1], '332') - self.assertEquals(response[0][2], ['otheruser', '#somechannel', 'This is the new topic.']) - self.assertEquals(response[1][1], '333') - self.assertEquals(response[1][2], ['otheruser', '#somechannel', 'otheruser', '12345']) - - other.transport.clear() - other.write('TOPIC #asdlkjasd\r\n') - - response = self._response(other) - self.assertEquals(response[0][1], '403') - testSetTopic = dG(testSetTopic) - - - def testGroupMessage(self): - user = wFD(self._loggedInUser(u'useruser')) - yield user - user = user.getResult() - - add = wFD(self.realm.createGroup(u"somechannel")) - yield add - somechannel = add.getResult() - - user.write("JOIN #somechannel\r\n") - - other = wFD(self._loggedInUser(u'otheruser')) - yield other - other = other.getResult() - - other.write("JOIN #somechannel\r\n") - - user.transport.clear() - other.transport.clear() - - user.write('PRIVMSG #somechannel :Hello, world.\r\n') - - response = self._response(user) - event = self._response(other) - - self.failIf(response) - self.assertEquals(len(event), 1) - self.assertEquals(event[0][0], 'useruser!useruser@realmname') - self.assertEquals(event[0][1], 'PRIVMSG', -1) - self.assertEquals(event[0][2], ['#somechannel', 'Hello, world.']) - testGroupMessage = dG(testGroupMessage) - - - def testPrivateMessage(self): - user = wFD(self._loggedInUser(u'useruser')) - yield user - user = user.getResult() - - other = wFD(self._loggedInUser(u'otheruser')) - yield other - other = other.getResult() - - user.transport.clear() - other.transport.clear() - - user.write('PRIVMSG otheruser :Hello, monkey.\r\n') - - response = self._response(user) - event = self._response(other) - - self.failIf(response) - self.assertEquals(len(event), 1) - self.assertEquals(event[0][0], 'useruser!useruser@realmname') - self.assertEquals(event[0][1], 'PRIVMSG') - self.assertEquals(event[0][2], ['otheruser', 'Hello, monkey.']) - - user.write('PRIVMSG nousernamedthis :Hello, monkey.\r\n') - - response = self._response(user) - - self.assertEquals(len(response), 1) - self.assertEquals(response[0][0], 'realmname') - self.assertEquals(response[0][1], '401') - self.assertEquals(response[0][2], ['useruser', 'nousernamedthis', 'No such nick/channel.']) - testPrivateMessage = dG(testPrivateMessage) - - - def testOper(self): - user = wFD(self._loggedInUser(u'useruser')) - yield user - user = user.getResult() - - user.transport.clear() - user.write('OPER user pass\r\n') - response = self._response(user) - - self.assertEquals(len(response), 1) - self.assertEquals(response[0][1], '491') - testOper = dG(testOper) - - - def testGetUserMode(self): - user = wFD(self._loggedInUser(u'useruser')) - yield user - user = user.getResult() - - user.transport.clear() - user.write('MODE useruser\r\n') - - response = self._response(user) - self.assertEquals(len(response), 1) - self.assertEquals(response[0][0], 'realmname') - self.assertEquals(response[0][1], '221') - self.assertEquals(response[0][2], ['useruser', '+']) - testGetUserMode = dG(testGetUserMode) - - - def testSetUserMode(self): - user = wFD(self._loggedInUser(u'useruser')) - yield user - user = user.getResult() - - user.transport.clear() - user.write('MODE useruser +abcd\r\n') - - response = self._response(user) - self.assertEquals(len(response), 1) - self.assertEquals(response[0][1], '472') - testSetUserMode = dG(testSetUserMode) - - - def testGetGroupMode(self): - user = wFD(self._loggedInUser(u'useruser')) - yield user - user = user.getResult() - - add = wFD(self.realm.createGroup(u"somechannel")) - yield add - somechannel = add.getResult() - - user.write('JOIN #somechannel\r\n') - - user.transport.clear() - user.write('MODE #somechannel\r\n') - - response = self._response(user) - self.assertEquals(len(response), 1) - self.assertEquals(response[0][1], '324') - testGetGroupMode = dG(testGetGroupMode) - - - def testSetGroupMode(self): - user = wFD(self._loggedInUser(u'useruser')) - yield user - user = user.getResult() - - group = wFD(self.realm.createGroup(u"groupname")) - yield group - group = group.getResult() - - user.write('JOIN #groupname\r\n') - - user.transport.clear() - user.write('MODE #groupname +abcd\r\n') - - response = self._response(user) - self.assertEquals(len(response), 1) - self.assertEquals(response[0][1], '472') - testSetGroupMode = dG(testSetGroupMode) - - - def testWho(self): - group = service.Group('groupname') - add = wFD(self.realm.addGroup(group)) - yield add - add.getResult() - - users = [] - for nick in u'userone', u'usertwo', u'userthree': - u = wFD(self._loggedInUser(nick)) - yield u - u = u.getResult() - users.append(u) - users[-1].write('JOIN #groupname\r\n') - for user in users: - user.transport.clear() - - users[0].write('WHO #groupname\r\n') - - r = self._response(users[0]) - self.failIf(self._response(users[1])) - self.failIf(self._response(users[2])) - - wantusers = ['userone', 'usertwo', 'userthree'] - for (prefix, code, stuff) in r[:-1]: - self.assertEquals(prefix, 'realmname') - self.assertEquals(code, '352') - - (myname, group, theirname, theirhost, theirserver, theirnick, flag, extra) = stuff - self.assertEquals(myname, 'userone') - self.assertEquals(group, '#groupname') - self.failUnless(theirname in wantusers) - self.assertEquals(theirhost, 'realmname') - self.assertEquals(theirserver, 'realmname') - wantusers.remove(theirnick) - self.assertEquals(flag, 'H') - self.assertEquals(extra, '0 ' + theirnick) - self.failIf(wantusers) - - prefix, code, stuff = r[-1] - self.assertEquals(prefix, 'realmname') - self.assertEquals(code, '315') - myname, channel, extra = stuff - self.assertEquals(myname, 'userone') - self.assertEquals(channel, '#groupname') - self.assertEquals(extra, 'End of /WHO list.') - testWho = dG(testWho) - - - def testList(self): - user = wFD(self._loggedInUser(u"someuser")) - yield user - user = user.getResult() - user.transport.clear() - - somegroup = wFD(self.realm.createGroup(u"somegroup")) - yield somegroup - somegroup = somegroup.getResult() - somegroup.size = lambda: succeed(17) - somegroup.meta['topic'] = 'this is the topic woo' - - # Test one group - user.write('LIST #somegroup\r\n') - - r = self._response(user) - self.assertEquals(len(r), 2) - resp, end = r - - self.assertEquals(resp[0], 'realmname') - self.assertEquals(resp[1], '322') - self.assertEquals(resp[2][0], 'someuser') - self.assertEquals(resp[2][1], 'somegroup') - self.assertEquals(resp[2][2], '17') - self.assertEquals(resp[2][3], 'this is the topic woo') - - self.assertEquals(end[0], 'realmname') - self.assertEquals(end[1], '323') - self.assertEquals(end[2][0], 'someuser') - self.assertEquals(end[2][1], 'End of /LIST') - - user.transport.clear() - # Test all groups - - user.write('LIST\r\n') - r = self._response(user) - self.assertEquals(len(r), 2) - - fg1, end = r - - self.assertEquals(fg1[1], '322') - self.assertEquals(fg1[2][1], 'somegroup') - self.assertEquals(fg1[2][2], '17') - self.assertEquals(fg1[2][3], 'this is the topic woo') - - self.assertEquals(end[1], '323') - testList = dG(testList) - - - def testWhois(self): - user = wFD(self._loggedInUser(u'someguy')) - yield user - user = user.getResult() - - otherguy = service.User("otherguy") - otherguy.itergroups = lambda: iter([ - service.Group('groupA'), - service.Group('groupB')]) - otherguy.signOn = 10 - otherguy.lastMessage = time.time() - 15 - - add = wFD(self.realm.addUser(otherguy)) - yield add - add.getResult() - - user.transport.clear() - user.write('WHOIS otherguy\r\n') - r = self._response(user) - - self.assertEquals(len(r), 5) - wuser, wserver, idle, channels, end = r - - self.assertEquals(wuser[0], 'realmname') - self.assertEquals(wuser[1], '311') - self.assertEquals(wuser[2][0], 'someguy') - self.assertEquals(wuser[2][1], 'otherguy') - self.assertEquals(wuser[2][2], 'otherguy') - self.assertEquals(wuser[2][3], 'realmname') - self.assertEquals(wuser[2][4], '*') - self.assertEquals(wuser[2][5], 'otherguy') - - self.assertEquals(wserver[0], 'realmname') - self.assertEquals(wserver[1], '312') - self.assertEquals(wserver[2][0], 'someguy') - self.assertEquals(wserver[2][1], 'otherguy') - self.assertEquals(wserver[2][2], 'realmname') - self.assertEquals(wserver[2][3], 'Hi mom!') - - self.assertEquals(idle[0], 'realmname') - self.assertEquals(idle[1], '317') - self.assertEquals(idle[2][0], 'someguy') - self.assertEquals(idle[2][1], 'otherguy') - self.assertEquals(idle[2][2], '15') - self.assertEquals(idle[2][3], '10') - self.assertEquals(idle[2][4], "seconds idle, signon time") - - self.assertEquals(channels[0], 'realmname') - self.assertEquals(channels[1], '319') - self.assertEquals(channels[2][0], 'someguy') - self.assertEquals(channels[2][1], 'otherguy') - self.assertEquals(channels[2][2], '#groupA #groupB') - - self.assertEquals(end[0], 'realmname') - self.assertEquals(end[1], '318') - self.assertEquals(end[2][0], 'someguy') - self.assertEquals(end[2][1], 'otherguy') - self.assertEquals(end[2][2], 'End of WHOIS list.') - testWhois = dG(testWhois) - - -class TestMind(service.PBMind): - def __init__(self, *a, **kw): - self.joins = [] - self.parts = [] - self.messages = [] - self.meta = [] - - def remote_userJoined(self, user, group): - self.joins.append((user, group)) - - def remote_userLeft(self, user, group, reason): - self.parts.append((user, group, reason)) - - def remote_receive(self, sender, recipient, message): - self.messages.append((sender, recipient, message)) - - def remote_groupMetaUpdate(self, group, meta): - self.meta.append((group, meta)) -pb.setUnjellyableForClass(TestMind, service.PBMindReference) - - -class PBProtocolTestCase(unittest.TestCase): - def setUp(self): - self.realm = service.InMemoryWordsRealm("realmname") - self.checker = checkers.InMemoryUsernamePasswordDatabaseDontUse() - self.portal = portal.Portal( - self.realm, [self.checker]) - self.serverFactory = pb.PBServerFactory(self.portal) - self.serverFactory.protocol = self._protocolFactory - self.serverFactory.unsafeTracebacks = True - self.clientFactory = pb.PBClientFactory() - self.clientFactory.unsafeTracebacks = True - self.serverPort = reactor.listenTCP(0, self.serverFactory) - self.clientConn = reactor.connectTCP( - '127.0.0.1', - self.serverPort.getHost().port, - self.clientFactory) - - def _protocolFactory(self, *args, **kw): - self._serverProtocol = pb.Broker(0) - return self._serverProtocol - - def tearDown(self): - d3 = Deferred() - self._serverProtocol.notifyOnDisconnect(lambda: d3.callback(None)) - return DeferredList([ - maybeDeferred(self.serverPort.stopListening), - maybeDeferred(self.clientConn.disconnect), d3]) - - def _loggedInAvatar(self, name, password, mind): - creds = credentials.UsernamePassword(name, password) - self.checker.addUser(name.encode('ascii'), password) - d = self.realm.createUser(name) - d.addCallback(lambda ign: self.clientFactory.login(creds, mind)) - return d - - def testGroups(self): - mindone = TestMind() - one = wFD(self._loggedInAvatar(u"one", "p1", mindone)) - yield one - one = one.getResult() - - mindtwo = TestMind() - two = wFD(self._loggedInAvatar(u"two", "p2", mindtwo)) - yield two - two = two.getResult() - - add = wFD(self.realm.createGroup(u"foobar")) - yield add - add.getResult() - - groupone = wFD(one.join(u"foobar")) - yield groupone - groupone = groupone.getResult() - - grouptwo = wFD(two.join(u"foobar")) - yield grouptwo - grouptwo = grouptwo.getResult() - - msg = wFD(groupone.send({"text": "hello, monkeys"})) - yield msg - msg = msg.getResult() - - leave = wFD(groupone.leave()) - yield leave - leave = leave.getResult() - testGroups = dG(testGroups) diff --git a/tools/buildbot/pylibs/twisted/words/test/test_tap.py b/tools/buildbot/pylibs/twisted/words/test/test_tap.py deleted file mode 100644 index 142d681..0000000 --- a/tools/buildbot/pylibs/twisted/words/test/test_tap.py +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright (c) 2001-2005 Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.cred import credentials, error -from twisted.words import tap -from twisted.trial import unittest - - - -class WordsTap(unittest.TestCase): - """ - Ensures that the twisted.words.tap API works. - """ - - PASSWD_TEXT = "admin:admin\njoe:foo\n" - admin = credentials.UsernamePassword('admin', 'admin') - joeWrong = credentials.UsernamePassword('joe', 'bar') - - - def setUp(self): - """ - Create a file with two users. - """ - self.filename = self.mktemp() - self.file = open(self.filename, 'w') - self.file.write(self.PASSWD_TEXT) - self.file.flush() - - - def tearDown(self): - """ - Close the dummy user database. - """ - self.file.close() - - - def test_hostname(self): - """ - Tests that the --hostname parameter gets passed to Options. - """ - opt = tap.Options() - opt.parseOptions(['--hostname', 'myhost']) - self.assertEquals(opt['hostname'], 'myhost') - - - def test_passwd(self): - """ - Tests the --passwd command for backwards-compatibility. - """ - opt = tap.Options() - opt.parseOptions(['--passwd', self.file.name]) - self._loginTest(opt) - - - def test_auth(self): - """ - Tests that the --auth command generates a checker. - """ - opt = tap.Options() - opt.parseOptions(['--auth', 'file:'+self.file.name]) - self._loginTest(opt) - - - def _loginTest(self, opt): - """ - This method executes both positive and negative authentication - tests against whatever credentials checker has been stored in - the Options class. - - @param opt: An instance of L{tap.Options}. - """ - self.assertEquals(len(opt['credCheckers']), 1) - checker = opt['credCheckers'][0] - self.assertFailure(checker.requestAvatarId(self.joeWrong), - error.UnauthorizedLogin) - def _gotAvatar(username): - self.assertEquals(username, self.admin.username) - return checker.requestAvatarId(self.admin).addCallback(_gotAvatar) diff --git a/tools/buildbot/pylibs/twisted/words/test/test_toc.py b/tools/buildbot/pylibs/twisted/words/test/test_toc.py deleted file mode 100644 index 16929a6..0000000 --- a/tools/buildbot/pylibs/twisted/words/test/test_toc.py +++ /dev/null @@ -1,343 +0,0 @@ -# Copyright (c) 2001-2005 Twisted Matrix Laboratories. -# See LICENSE for details. - - -from twisted.trial import unittest - -from twisted.words.protocols import toc -from twisted.internet import protocol, main -from twisted.python import failure - -import StringIO -from struct import pack,unpack - -class StringIOWithoutClosing(StringIO.StringIO): - def close(self): - pass - -class DummyTOC(toc.TOC): - """ - used to override authentication, now overrides printing. - """ - def _debug(self,data): - pass -SEQID=1001 -def flap(type,data): - global SEQID - send="*" - send=send+pack("!BHH",type,SEQID,len(data)) - send=send+data - SEQID=SEQID+1 - return send -def readFlap(data): - if data=="": return [None,""] - null,type,seqid,length=unpack("!BBHH",data[:6]) - val=data[6:6+length] - return [[type,val],data[6+length:]] - -class TOCGeneralTestCase(unittest.TestCase): - """ - general testing of TOC functions. - """ - def testTOC(self): - self.runTest() - def runTest(self): - USERS=2 - data=range(USERS) - data[0]=("FLAPON\r\n\r\n",\ - flap(1,"\000\000\000\001\000\001\000\004test"),\ - flap(2,"toc_signon localhost 9999 test 0x100000 english \"penguin 0.1\"\000"),\ - flap(2,"toc_add_buddy test\000"),\ - flap(2,"toc_init_done\000"),\ - flap(2,"toc_send_im test \"hi\"\000"),\ - flap(2,"toc_send_im test2 \"hello\"\000"),\ - flap(2,"toc_set_away \"not here\"\000"),\ - flap(2,"toc_set_idle 602\000"),\ - flap(2,"toc_set_idle 0\000"),\ - flap(2,"toc_set_away\000"),\ - flap(2,"toc_evil test norm\000"),\ - flap(2,"toc_chat_join 4 \"Test Chat\"\000"),\ - flap(2,"toc_chat_send 0 \"hello\"\000"),\ - #flap(2,"toc_chat_leave 0\000")) #,\ - flap(2,"toc_chat_invite 0 \"come\" ooga\000"),\ - #flap(2,"toc_chat_accept 0\000"),\ - flap(5,"\000"),\ - flap(2,"toc_chat_whisper 0 ooga \"boo ga\"\000"),\ - flap(2,"toc_chat_leave 0"),\ - flap(5,"\000")) - data[1]=("FLAPON\r\n\r\n",\ - flap(1,"\000\000\000\001\000\001\000\004ooga"),\ - flap(2,"toc_signon localhost 9999 ooga 0x100000 english \"penguin 0.1\"\000"),\ - flap(2,"toc_add_buddy test\000"),\ - flap(2,"toc_init_done\000"),\ - flap(5,"\000"),\ - flap(5,"\000"),\ - #flap(5,"\000"),\ - #flap(5,"\000"),\ - #flap(5,"\000"),\ - flap(5,"\000"),\ - flap(5,"\000"),\ - flap(5,"\000"),\ - flap(5,"\000"),\ - flap(5,"\000"),\ - flap(5,"\000"),\ - flap(5,"\000"),\ - #flap(5,"\000"),\ - flap(2,"toc_chat_accept 0\000"),\ - flap(2,"toc_chat_send 0 \"hi test\"\000"),\ - flap(5,"\000"),\ - flap(2,"toc_chat_leave 0\000")) - strings=range(USERS) - for i in strings: - strings[i]=StringIOWithoutClosing() - fac=toc.TOCFactory() - dummy=range(USERS) - for i in dummy: - dummy[i]=DummyTOC() - dummy[i].factory=fac - dummy[i].makeConnection(protocol.FileWrapper(strings[i])) - while reduce(lambda x,y:x+y,map(lambda x:x==(),data))!=USERS: - for i in range(USERS): - d=data[i] - if len(d)>0: - k,data[i]=d[0],d[1:] - for j in k: - dummy[i].dataReceived(j) # test by doing a character at a time - else: - dummy[i].connectionLost(failure.Failure(main.CONNECTION_DONE)) - values=range(USERS) - for i in values: - values[i]=strings[i].getvalue() - flaps=map(lambda x:[],range(USERS)) - for value in values: - i=values.index(value) - f,value=readFlap(value) - while f: - flaps[i].append(f) - f,value=readFlap(value) - ts=range(USERS) - for t in ts: - ts[t]=dummy[t].signontime - shouldequal=range(USERS) - shouldequal[0]=[ \ - [1,"\000\000\000\001"],\ - [2,"SIGN_ON:TOC1.0\000"],\ - [2,"NICK:test\000"],\ - [2,"CONFIG:\00"],\ - [2,"UPDATE_BUDDY:test:T:0:%s:0: O\000"%ts[0]],\ - [2,"IM_IN:test:F:hi\000"],\ - [2,"ERROR:901:test2\000"],\ - #[2,"UPDATE_BUDDY:test:T:0:%s:0: O\000"%ts[0]],\ - [2,"UPDATE_BUDDY:test:T:0:%s:0: OU\000"%ts[0]],\ - [2,"UPDATE_BUDDY:test:T:0:%s:10: OU\000"%ts[0]],\ - [2,"UPDATE_BUDDY:test:T:0:%s:0: OU\000"%ts[0]],\ - [2,"UPDATE_BUDDY:test:T:0:%s:0: O\000"%ts[0]],\ - [2,"EVILED:10:test\000"],\ - [2,"UPDATE_BUDDY:test:T:10:%s:0: O\000"%ts[0]],\ - [2,"CHAT_JOIN:0:Test Chat\000"],\ - [2,"CHAT_UPDATE_BUDDY:0:T:test\000"],\ - [2,"CHAT_IN:0:test:F:hello\000"],\ - [2,"CHAT_UPDATE_BUDDY:0:T:ooga\000"],\ - [2,"CHAT_IN:0:ooga:F:hi test\000"],\ - [2,"CHAT_LEFT:0\000"]] - shouldequal[1]=[ \ - [1,"\000\000\000\001"],\ - [2,"SIGN_ON:TOC1.0\000"],\ - [2,"NICK:ooga\000"],\ - [2,"CONFIG:\000"],\ - #[2,"UPDATE_BUDDY:test:T:0:%s:0: O\000"%ts[0]],\ - [2,"UPDATE_BUDDY:test:T:0:%s:0: OU\000"%ts[0]],\ - [2,"UPDATE_BUDDY:test:T:0:%s:10: OU\000"%ts[0]],\ - [2,"UPDATE_BUDDY:test:T:0:%s:0: OU\000"%ts[0]],\ - [2,"UPDATE_BUDDY:test:T:0:%s:0: O\000"%ts[0]],\ - [2,"UPDATE_BUDDY:test:T:10:%s:0: O\000"%ts[0]],\ - [2,"CHAT_INVITE:Test Chat:0:test:come\000"],\ - [2,"CHAT_JOIN:0:Test Chat\000"],\ - [2,"CHAT_UPDATE_BUDDY:0:T:test:ooga\000"],\ - [2,"CHAT_IN:0:ooga:F:hi test\000"],\ - [2,"CHAT_IN:0:test:T:boo ga\000"],\ - [2,"CHAT_UPDATE_BUDDY:0:F:test\000"],\ - [2,"CHAT_LEFT:0\000"]] - if flaps!=shouldequal: - for i in range(len(shouldequal)): - for j in range(len(shouldequal[i])): - if shouldequal[i][j]!=flaps[i][j]: - raise AssertionError("GeneralTest Failed!\nUser %s Line %s\nactual:%s\nshould be:%s"%(i,j,flaps[i][j],shouldequal[i][j])) - raise AssertionError("GeneralTest Failed with incorrect lengths!") -class TOCMultiPacketTestCase(unittest.TestCase): - """ - i saw this problem when using GAIM. It only read the flaps onces per dataReceived, and would basically block if it ever received two packets together in one dataReceived. this tests for that occurance. - """ - def testTOC(self): - self.runTest() - def runTest(self): - packets=["FLAPON\r\n\r\n",\ - flap(1,"\000\000\000\001\000\001\000\004test"),\ - flap(2,"toc_signon null 9999 test 0x100000 english \"penguin 0.1\"\000"),\ - flap(2,"toc_init_done\000"),\ - flap(2,"toc_send_im test hi\000")] - shouldbe=[[1,"\000\000\000\001"],\ - [2,"SIGN_ON:TOC1.0\000"],\ - [2,"NICK:test\000"],\ - [2,"CONFIG:\000"],\ - [2,"IM_IN:test:F:hi\000"]] - data="" - for i in packets: - data=data+i - s=StringIOWithoutClosing() - d=DummyTOC() - fac=toc.TOCFactory() - d.factory=fac - d.makeConnection(protocol.FileWrapper(s)) - d.dataReceived(data) - d.connectionLost(failure.Failure(main.CONNECTION_DONE)) - value=s.getvalue() - flaps=[] - f,value=readFlap(value) - while f: - flaps.append(f) - f,value=readFlap(value) - if flaps!=shouldbe: - for i in range(len(flaps)): - if flaps[i]!=shouldbe[i]:raise AssertionError("MultiPacketTest Failed!\nactual:%s\nshould be:%s"%(flaps[i],shouldbe[i])) - raise AssertionError("MultiPacketTest Failed with incorrect length!, printing both lists\nactual:%s\nshould be:%s"%(flaps,shouldbe)) -class TOCSavedValuesTestCase(unittest.TestCase): - def testTOC(self): - self.runTest() - def runTest(self): - password1=toc.roast("test pass") - password2=toc.roast("pass test") - beforesend=[\ - "FLAPON\r\n\r\n",\ - flap(1,"\000\000\000\001\000\001\000\004test"),\ - flap(2,"toc_signon localhost 9999 test %s english \"penguin 0.1\"\000"%password1),\ - flap(2,"toc_init_done\000"),\ - flap(2,"toc_set_config \"{m 4}\"\000"),\ - flap(2,"toc_format_nickname BOOGA\000"),\ - flap(2,"toc_format_nickname \"T E S T\"\000"),\ - flap(2,"toc_change_passwd \"testpass\" \"pass test\"\000"),\ - flap(2,"toc_change_passwd \"test pass\" \"pass test\"\000")] - beforeexpect=[\ - [1,"\000\000\000\001"],\ - [2,"SIGN_ON:TOC1.0\000"],\ - [2,"NICK:test\000"],\ - [2,"CONFIG:\000"],\ - [2,"ERROR:911\000"],\ - [2,"ADMIN_NICK_STATUS:0\000"],\ - [2,"ERROR:911\000"],\ - [2,"ADMIN_PASSWD_STATUS:0\000"]] - badpasssend=[\ - "FLAPON\r\n\r\n",\ - flap(1,"\000\000\000\001\000\001\000\004test"),\ - flap(2,"toc_signon localhost 9999 test 0x1000 english \"penguin 0.1\"\000"),\ - flap(2,"toc_init_done")] - badpassexpect=[\ - [1,"\000\00\000\001"],\ - [2,"ERROR:980\000"]] - goodpasssend=[\ - "FLAPON\r\n\r\n",\ - flap(1,"\000\000\000\001\000\001\000\004test"),\ - flap(2,"toc_signon localhost 9999 test %s english \"penguin 0.1\"\000"%password2),\ - flap(2,"toc_init_done")] - goodpassexpect=[\ - [1,"\000\000\000\001"],\ - [2,"SIGN_ON:TOC1.0\000"],\ - [2,"NICK:T E S T\000"],\ - [2,"CONFIG:{m 4}\000"]] - fac=toc.TOCFactory() - d=DummyTOC() - d.factory=fac - s=StringIOWithoutClosing() - d.makeConnection(protocol.FileWrapper(s)) - for i in beforesend: - d.dataReceived(i) - d.connectionLost(failure.Failure(main.CONNECTION_DONE)) - v=s.getvalue() - flaps=[] - f,v=readFlap(v) - while f: - flaps.append(f) - f,v=readFlap(v) - if flaps!=beforeexpect: - for i in range(len(flaps)): - if flaps[i]!=beforeexpect[i]: - raise AssertionError("SavedValuesTest Before Failed!\nactual:%s\nshould be:%s"%(flaps[i],beforeexpect[i])) - raise AssertionError("SavedValuesTest Before Failed with incorrect length!\nactual:%s\nshould be:%s"%(flaps,beforeexpect)) - d=DummyTOC() - d.factory=fac - s=StringIOWithoutClosing() - d.makeConnection(protocol.FileWrapper(s)) - for i in badpasssend: - d.dataReceived(i) - d.connectionLost(failure.Failure(main.CONNECTION_DONE)) - v=s.getvalue() - flaps=[] - f,v=readFlap(v) - while f: - flaps.append(f) - f,v=readFlap(v) - if flaps!=badpassexpect: - for i in range(len(flaps)): - if flaps[i]!=badpassexpect[i]: - raise AssertionError("SavedValuesTest BadPass Failed!\nactual:%s\nshould be:%s"%(flaps[i],badpassexpect[i])) - raise AssertionError("SavedValuesTest BadPass Failed with incorrect length!\nactual:%s\nshould be:%s"%(flaps,badpassexpect)) - d=DummyTOC() - d.factory=fac - s=StringIOWithoutClosing() - d.makeConnection(protocol.FileWrapper(s)) - for i in goodpasssend: - d.dataReceived(i) - d.connectionLost(failure.Failure(main.CONNECTION_DONE)) - v=s.getvalue() - flaps=[] - f,v=readFlap(v) - while f: - flaps.append(f) - f,v=readFlap(v) - if flaps!=goodpassexpect: - for i in range(len(flaps)): - if flaps[i]!=goodpassexpect[i]: - raise AssertionError("SavedValuesTest GoodPass Failed!\nactual:%s\nshould be:%s"%(flaps[i],goodpassexpect[i])) - raise AssertionError("SavedValuesTest GoodPass Failed with incorrect length!\nactual:%s\nshould be:%s"%(flaps,beforeexpect)) -class TOCPrivacyTestCase(unittest.TestCase): - def runTest(self): - sends=["FLAPON\r\n\r\n",\ - flap(1,"\000\000\000\001\000\001\000\004test"),\ - flap(2,"toc_signon localhost 9999 test 0x00 english penguin\000"),\ - flap(2,"toc_init_done\000"),\ - flap(2,"toc_add_deny\000"),\ - flap(2,"toc_send_im test 1\000"),\ - flap(2,"toc_add_deny test\000"),\ - flap(2,"toc_send_im test 2\000"),\ - flap(2,"toc_add_permit\000"),\ - flap(2,"toc_send_im test 3\000"),\ - flap(2,"toc_add_permit test\000"),\ - flap(2,"toc_send_im test 4\000")] - expect=[[1,"\000\000\000\001"],\ - [2,"SIGN_ON:TOC1.0\000"],\ - [2,"NICK:test\000"],\ - [2,"CONFIG:\000"],\ - [2,"IM_IN:test:F:1\000"],\ - [2,"ERROR:901:test\000"],\ - [2,"ERROR:901:test\000"],\ - [2,"IM_IN:test:F:4\000"]] - d=DummyTOC() - d.factory=toc.TOCFactory() - s=StringIOWithoutClosing() - d.makeConnection(protocol.FileWrapper(s)) - for i in sends: - d.dataReceived(i) - d.connectionLost(failure.Failure(main.CONNECTION_DONE)) - v=s.getvalue() - flaps=[] - f,v=readFlap(v) - while f: - flaps.append(f) - f,v=readFlap(v) - if flaps!=expect: - for i in range(len(flaps)): - if flaps[i]!=expect[i]: - raise AssertionError("PrivacyTest Before Failed!\nactual:%s\nshould be:%s"%(flaps[i],expect[i])) - raise AssertionError("PrivacyTest Before Failed with incorrect length!\nactual:%s\nshould be:%s"%(flaps,expect)) -testCases=[TOCGeneralTestCase,TOCMultiPacketTestCase,TOCSavedValuesTestCase,TOCPrivacyTestCase] - diff --git a/tools/buildbot/pylibs/twisted/words/test/test_xishutil.py b/tools/buildbot/pylibs/twisted/words/test/test_xishutil.py deleted file mode 100644 index d9e55d0..0000000 --- a/tools/buildbot/pylibs/twisted/words/test/test_xishutil.py +++ /dev/null @@ -1,307 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test cases for twisted.words.xish.utility -""" - -from twisted.trial import unittest - -from twisted.python.util import OrderedDict -from twisted.words.xish import utility -from twisted.words.xish.domish import Element -from twisted.words.xish.utility import EventDispatcher - -class CallbackTracker: - """ - Test helper for tracking callbacks. - - Increases a counter on each call to L{call} and stores the object - passed in the call. - """ - - def __init__(self): - self.called = 0 - self.obj = None - - - def call(self, obj): - self.called = self.called + 1 - self.obj = obj - - - -class OrderedCallbackTracker: - """ - Test helper for tracking callbacks and their order. - """ - - def __init__(self): - self.callList = [] - - - def call1(self, object): - self.callList.append(self.call1) - - - def call2(self, object): - self.callList.append(self.call2) - - - def call3(self, object): - self.callList.append(self.call3) - - - -class EventDispatcherTest(unittest.TestCase): - """ - Tests for L{EventDispatcher}. - """ - - def testStuff(self): - d = EventDispatcher() - cb1 = CallbackTracker() - cb2 = CallbackTracker() - cb3 = CallbackTracker() - - d.addObserver("/message/body", cb1.call) - d.addObserver("/message", cb1.call) - d.addObserver("/presence", cb2.call) - d.addObserver("//event/testevent", cb3.call) - - msg = Element(("ns", "message")) - msg.addElement("body") - - pres = Element(("ns", "presence")) - pres.addElement("presence") - - d.dispatch(msg) - self.assertEquals(cb1.called, 2) - self.assertEquals(cb1.obj, msg) - self.assertEquals(cb2.called, 0) - - d.dispatch(pres) - self.assertEquals(cb1.called, 2) - self.assertEquals(cb2.called, 1) - self.assertEquals(cb2.obj, pres) - self.assertEquals(cb3.called, 0) - - d.dispatch(d, "//event/testevent") - self.assertEquals(cb3.called, 1) - self.assertEquals(cb3.obj, d) - - d.removeObserver("/presence", cb2.call) - d.dispatch(pres) - self.assertEquals(cb2.called, 1) - - - def test_addObserverTwice(self): - """ - Test adding two observers for the same query. - - When the event is dispath both of the observers need to be called. - """ - d = EventDispatcher() - cb1 = CallbackTracker() - cb2 = CallbackTracker() - - d.addObserver("//event/testevent", cb1.call) - d.addObserver("//event/testevent", cb2.call) - d.dispatch(d, "//event/testevent") - - self.assertEquals(cb1.called, 1) - self.assertEquals(cb1.obj, d) - self.assertEquals(cb2.called, 1) - self.assertEquals(cb2.obj, d) - - - def test_addObserverInDispatch(self): - """ - Test for registration of an observer during dispatch. - """ - d = EventDispatcher() - msg = Element(("ns", "message")) - cb = CallbackTracker() - - def onMessage(_): - d.addObserver("/message", cb.call) - - d.addOnetimeObserver("/message", onMessage) - - d.dispatch(msg) - self.assertEquals(cb.called, 0) - - d.dispatch(msg) - self.assertEquals(cb.called, 1) - - d.dispatch(msg) - self.assertEquals(cb.called, 2) - - - def test_addOnetimeObserverInDispatch(self): - """ - Test for registration of a onetime observer during dispatch. - """ - d = EventDispatcher() - msg = Element(("ns", "message")) - cb = CallbackTracker() - - def onMessage(msg): - d.addOnetimeObserver("/message", cb.call) - - d.addOnetimeObserver("/message", onMessage) - - d.dispatch(msg) - self.assertEquals(cb.called, 0) - - d.dispatch(msg) - self.assertEquals(cb.called, 1) - - d.dispatch(msg) - self.assertEquals(cb.called, 1) - - - def testOnetimeDispatch(self): - d = EventDispatcher() - msg = Element(("ns", "message")) - cb = CallbackTracker() - - d.addOnetimeObserver("/message", cb.call) - d.dispatch(msg) - self.assertEquals(cb.called, 1) - d.dispatch(msg) - self.assertEquals(cb.called, 1) - - - def testDispatcherResult(self): - d = EventDispatcher() - msg = Element(("ns", "message")) - pres = Element(("ns", "presence")) - cb = CallbackTracker() - - d.addObserver("/presence", cb.call) - result = d.dispatch(msg) - self.assertEquals(False, result) - - result = d.dispatch(pres) - self.assertEquals(True, result) - - - def testOrderedXPathDispatch(self): - d = EventDispatcher() - cb = OrderedCallbackTracker() - d.addObserver("/message/body", cb.call2) - d.addObserver("/message", cb.call3, -1) - d.addObserver("/message/body", cb.call1, 1) - - msg = Element(("ns", "message")) - msg.addElement("body") - d.dispatch(msg) - self.assertEquals(cb.callList, [cb.call1, cb.call2, cb.call3], - "Calls out of order: %s" % - repr([c.__name__ for c in cb.callList])) - - - # Observers are put into CallbackLists that are then put into dictionaries - # keyed by the event trigger. Upon removal of the last observer for a - # particular event trigger, the (now empty) CallbackList and corresponding - # event trigger should be removed from those dictionaries to prevent - # slowdown and memory leakage. - - def test_cleanUpRemoveEventObserver(self): - """ - Test observer clean-up after removeObserver for named events. - """ - - d = EventDispatcher() - cb = CallbackTracker() - - d.addObserver('//event/test', cb.call) - d.dispatch(None, '//event/test') - self.assertEqual(1, cb.called) - d.removeObserver('//event/test', cb.call) - self.assertEqual(0, len(d._eventObservers.pop(0))) - - - def test_cleanUpRemoveXPathObserver(self): - """ - Test observer clean-up after removeObserver for XPath events. - """ - - d = EventDispatcher() - cb = CallbackTracker() - msg = Element((None, "message")) - - d.addObserver('/message', cb.call) - d.dispatch(msg) - self.assertEqual(1, cb.called) - d.removeObserver('/message', cb.call) - self.assertEqual(0, len(d._xpathObservers.pop(0))) - - - def test_cleanUpOnetimeEventObserver(self): - """ - Test observer clean-up after onetime named events. - """ - - d = EventDispatcher() - cb = CallbackTracker() - - d.addOnetimeObserver('//event/test', cb.call) - d.dispatch(None, '//event/test') - self.assertEqual(1, cb.called) - self.assertEqual(0, len(d._eventObservers.pop(0))) - - - def test_cleanUpOnetimeXPathObserver(self): - """ - Test observer clean-up after onetime XPath events. - """ - - d = EventDispatcher() - cb = CallbackTracker() - msg = Element((None, "message")) - - d.addOnetimeObserver('/message', cb.call) - d.dispatch(msg) - self.assertEqual(1, cb.called) - self.assertEqual(0, len(d._xpathObservers.pop(0))) - - - def test_observerRaisingException(self): - """ - Test that exceptions in observers do not bubble up to dispatch. - - The exceptions raised in observers should be logged and other - observers should be called as if nothing happened. - """ - - class OrderedCallbackList(utility.CallbackList): - def __init__(self): - self.callbacks = OrderedDict() - - class TestError(Exception): - pass - - def raiseError(_): - raise TestError() - - d = EventDispatcher() - cb = CallbackTracker() - - originalCallbackList = utility.CallbackList - - try: - utility.CallbackList = OrderedCallbackList - - d.addObserver('//event/test', raiseError) - d.addObserver('//event/test', cb.call) - try: - d.dispatch(None, '//event/test') - except TestError: - self.fail("TestError raised. Should have been logged instead.") - - self.assertEqual(1, len(self.flushLoggedErrors(TestError))) - self.assertEqual(1, cb.called) - finally: - utility.CallbackList = originalCallbackList diff --git a/tools/buildbot/pylibs/twisted/words/test/test_xmlstream.py b/tools/buildbot/pylibs/twisted/words/test/test_xmlstream.py deleted file mode 100644 index 63ab877..0000000 --- a/tools/buildbot/pylibs/twisted/words/test/test_xmlstream.py +++ /dev/null @@ -1,110 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.words.xish.xmlstream}. -""" - -from twisted.internet import defer, protocol -from twisted.trial import unittest -from twisted.words.xish import utility, xmlstream - -class XmlStreamTest(unittest.TestCase): - def setUp(self): - self.errorOccurred = False - self.streamStarted = False - self.streamEnded = False - self.outlist = [] - self.xmlstream = xmlstream.XmlStream() - self.xmlstream.transport = self - self.xmlstream.transport.write = self.outlist.append - - # Auxilary methods - def loseConnection(self): - self.xmlstream.connectionLost("no reason") - - def streamStartEvent(self, rootelem): - self.streamStarted = True - - def streamErrorEvent(self, errelem): - self.errorOccurred = True - - def streamEndEvent(self, _): - self.streamEnded = True - - def testBasicOp(self): - xs = self.xmlstream - xs.addObserver(xmlstream.STREAM_START_EVENT, - self.streamStartEvent) - xs.addObserver(xmlstream.STREAM_ERROR_EVENT, - self.streamErrorEvent) - xs.addObserver(xmlstream.STREAM_END_EVENT, - self.streamEndEvent) - - # Go... - xs.connectionMade() - xs.send("") - self.assertEquals(self.outlist[0], "") - - xs.dataReceived("") - self.assertEquals(self.streamStarted, True) - - self.assertEquals(self.errorOccurred, False) - self.assertEquals(self.streamEnded, False) - xs.dataReceived("") - self.assertEquals(self.errorOccurred, True) - self.assertEquals(self.streamEnded, True) - - -class DummyProtocol(protocol.Protocol, utility.EventDispatcher): - """ - I am a protocol with an event dispatcher without further processing. - - This protocol is only used for testing XmlStreamFactoryMixin to make - sure the bootstrap observers are added to the protocol instance. - """ - - def __init__(self, *args, **kwargs): - self.args = args - self.kwargs = kwargs - self.observers = [] - - utility.EventDispatcher.__init__(self) - - -class XmlStreamFactoryMixinTest(unittest.TestCase): - - def test_buildProtocol(self): - """ - Test building of protocol. - - Arguments passed to Factory should be passed to protocol on - instantiation. Bootstrap observers should be setup. - """ - d = defer.Deferred() - - f = xmlstream.XmlStreamFactoryMixin(None, test=None) - f.protocol = DummyProtocol - f.addBootstrap('//event/myevent', d.callback) - xs = f.buildProtocol(None) - - self.assertEquals(f, xs.factory) - self.assertEquals((None,), xs.args) - self.assertEquals({'test': None}, xs.kwargs) - xs.dispatch(None, '//event/myevent') - return d - - def test_addAndRemoveBootstrap(self): - """ - Test addition and removal of a bootstrap event handler. - """ - def cb(self): - pass - - f = xmlstream.XmlStreamFactoryMixin(None, test=None) - - f.addBootstrap('//event/myevent', cb) - self.assertIn(('//event/myevent', cb), f.bootstraps) - - f.removeBootstrap('//event/myevent', cb) - self.assertNotIn(('//event/myevent', cb), f.bootstraps) diff --git a/tools/buildbot/pylibs/twisted/words/test/test_xpath.py b/tools/buildbot/pylibs/twisted/words/test/test_xpath.py deleted file mode 100644 index ad9ef67..0000000 --- a/tools/buildbot/pylibs/twisted/words/test/test_xpath.py +++ /dev/null @@ -1,260 +0,0 @@ -# Copyright (c) 2001-2005 Twisted Matrix Laboratories. -# See LICENSE for details. - - -from twisted.trial import unittest -import sys, os - -from twisted.words.xish.domish import Element -from twisted.words.xish.xpath import XPathQuery -from twisted.words.xish import xpath - -class XPathTest(unittest.TestCase): - def setUp(self): - # Build element: - # - # somecontent - # - # - # DEF - # - # - # somemorecontent - # - # - # - # ABC - # - # - # - # - # JKL - # - # - # - # MNO - # - # - # - self.e = Element(("testns", "foo")) - self.e["attrib1"] = "value1" - self.e["attrib3"] = "user@host/resource" - self.e.addContent("somecontent") - self.bar1 = self.e.addElement("bar") - self.subfoo = self.bar1.addElement("foo") - self.gar1 = self.subfoo.addElement("gar") - self.gar1.addContent("DEF") - self.e.addContent("somemorecontent") - self.bar2 = self.e.addElement("bar") - self.bar2["attrib2"] = "value2" - self.bar3 = self.bar2.addElement("bar") - self.subfoo2 = self.bar3.addElement("foo") - self.gar2 = self.bar3.addElement("gar") - self.gar2.addContent("ABC") - self.bar4 = self.e.addElement("bar") - self.bar5 = self.e.addElement("bar") - self.bar5["attrib4"] = "value4" - self.bar5["attrib5"] = "value5" - self.subfoo3 = self.bar5.addElement("foo") - self.gar3 = self.bar5.addElement("gar") - self.gar3.addContent("JKL") - self.bar6 = self.e.addElement("bar") - self.bar6["attrib4"] = "value4" - self.bar6["attrib5"] = "value4" - self.subfoo4 = self.bar6.addElement("foo") - self.gar4 = self.bar6.addElement("gar") - self.gar4.addContent("MNO") - self.bar7 = self.e.addElement("bar") - self.bar7["attrib4"] = "value4" - self.bar7["attrib5"] = "value6" - - def test_staticMethods(self): - """ - Test basic operation of the static methods. - """ - self.assertEquals(xpath.matches("/foo/bar", self.e), - True) - self.assertEquals(xpath.queryForNodes("/foo/bar", self.e), - [self.bar1, self.bar2, self.bar4, - self.bar5, self.bar6, self.bar7]) - self.assertEquals(xpath.queryForString("/foo", self.e), - "somecontent") - self.assertEquals(xpath.queryForStringList("/foo", self.e), - ["somecontent", "somemorecontent"]) - - def test_locationFooBar(self): - """ - Test matching foo with child bar. - """ - xp = XPathQuery("/foo/bar") - self.assertEquals(xp.matches(self.e), 1) - - def test_locationFooBarFoo(self): - """ - Test finding foos at the second level. - """ - xp = XPathQuery("/foo/bar/foo") - self.assertEquals(xp.matches(self.e), 1) - self.assertEquals(xp.queryForNodes(self.e), [self.subfoo, - self.subfoo3, - self.subfoo4]) - - def test_locationNoBar3(self): - """ - Test not finding bar3. - """ - xp = XPathQuery("/foo/bar3") - self.assertEquals(xp.matches(self.e), 0) - - def test_locationAllChilds(self): - """ - Test finding childs of foo. - """ - xp = XPathQuery("/foo/*") - self.assertEquals(xp.matches(self.e), True) - self.assertEquals(xp.queryForNodes(self.e), [self.bar1, self.bar2, - self.bar4, self.bar5, - self.bar6, self.bar7]) - - def test_attribute(self): - """ - Test matching foo with attribute. - """ - xp = XPathQuery("/foo[@attrib1]") - self.assertEquals(xp.matches(self.e), True) - - def test_attributeWithValueAny(self): - """ - Test find nodes with attribute having value. - """ - xp = XPathQuery("/foo/*[@attrib2='value2']") - self.assertEquals(xp.matches(self.e), True) - self.assertEquals(xp.queryForNodes(self.e), [self.bar2]) - - def test_position(self): - """ - Test finding element at position. - """ - xp = XPathQuery("/foo/bar[2]") - self.assertEquals(xp.matches(self.e), 1) - self.assertEquals(xp.queryForNodes(self.e), [self.bar1]) - - test_position.todo = "XPath queries with position are not working." - - def test_namespaceFound(self): - """ - Test matching node with namespace. - """ - xp = XPathQuery("/foo[@xmlns='testns']/bar") - self.assertEquals(xp.matches(self.e), 1) - - def test_namespaceNotFound(self): - """ - Test not matching node with wrong namespace. - """ - xp = XPathQuery("/foo[@xmlns='badns']/bar2") - self.assertEquals(xp.matches(self.e), 0) - - def test_attributeWithValue(self): - """ - Test matching node with attribute having value. - """ - xp = XPathQuery("/foo[@attrib1='value1']") - self.assertEquals(xp.matches(self.e), 1) - - def test_queryForString(self): - """ - Test for queryForString and queryForStringList. - """ - xp = XPathQuery("/foo") - self.assertEquals(xp.queryForString(self.e), "somecontent") - self.assertEquals(xp.queryForStringList(self.e), - ["somecontent", "somemorecontent"]) - - def test_queryForNodes(self): - """ - Test finding nodes. - """ - xp = XPathQuery("/foo/bar") - self.assertEquals(xp.queryForNodes(self.e), [self.bar1, self.bar2, - self.bar4, self.bar5, - self.bar6, self.bar7]) - - def test_textCondition(self): - """ - Test matching a node with given text. - """ - xp = XPathQuery("/foo[text() = 'somecontent']") - self.assertEquals(xp.matches(self.e), True) - - def test_textNotOperator(self): - """ - Test for not operator. - """ - xp = XPathQuery("/foo[not(@nosuchattrib)]") - self.assertEquals(xp.matches(self.e), True) - - def test_anyLocationAndText(self): - """ - Test finding any nodes named gar and getting their text contents. - """ - xp = XPathQuery("//gar") - self.assertEquals(xp.matches(self.e), True) - self.assertEquals(xp.queryForNodes(self.e), [self.gar1, self.gar2, - self.gar3, self.gar4]) - self.assertEquals(xp.queryForStringList(self.e), ["DEF", "ABC", - "JKL", "MNO"]) - - def test_anyLocation(self): - """ - Test finding any nodes named bar. - """ - xp = XPathQuery("//bar") - self.assertEquals(xp.matches(self.e), True) - self.assertEquals(xp.queryForNodes(self.e), [self.bar1, self.bar2, - self.bar3, self.bar4, - self.bar5, self.bar6, - self.bar7]) - - def test_anyLocationQueryForString(self): - """ - L{XPathQuery.queryForString} should raise a L{NotImplementedError} - for any location. - """ - xp = XPathQuery("//bar") - self.assertRaises(NotImplementedError, xp.queryForString, None) - - def test_andOperator(self): - """ - Test boolean and operator in condition. - """ - xp = XPathQuery("//bar[@attrib4='value4' and @attrib5='value5']") - self.assertEquals(xp.matches(self.e), True) - self.assertEquals(xp.queryForNodes(self.e), [self.bar5]) - - def test_orOperator(self): - """ - Test boolean or operator in condition. - """ - xp = XPathQuery("//bar[@attrib5='value4' or @attrib5='value5']") - self.assertEquals(xp.matches(self.e), True) - self.assertEquals(xp.queryForNodes(self.e), [self.bar5, self.bar6]) - - def test_booleanOperatorsParens(self): - """ - Test multiple boolean operators in condition with parens. - """ - xp = XPathQuery("""//bar[@attrib4='value4' and - (@attrib5='value4' or @attrib5='value6')]""") - self.assertEquals(xp.matches(self.e), True) - self.assertEquals(xp.queryForNodes(self.e), [self.bar6, self.bar7]) - - def test_booleanOperatorsNoParens(self): - """ - Test multiple boolean operators in condition without parens. - """ - xp = XPathQuery("""//bar[@attrib5='value4' or - @attrib5='value5' or - @attrib5='value6']""") - self.assertEquals(xp.matches(self.e), True) - self.assertEquals(xp.queryForNodes(self.e), [self.bar5, self.bar6, self.bar7]) diff --git a/tools/buildbot/pylibs/twisted/words/toctap.py b/tools/buildbot/pylibs/twisted/words/toctap.py deleted file mode 100644 index 245e4d5..0000000 --- a/tools/buildbot/pylibs/twisted/words/toctap.py +++ /dev/null @@ -1,20 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Support module for making TOC servers with mktap. -""" - -from twisted.words.protocols import toc -from twisted.python import usage -from twisted.application import strports - -class Options(usage.Options): - synopsis = "Usage: mktap toc [-p ]" - optParameters = [["port", "p", "5190"]] - longdesc = "Makes a TOC server." - -def makeService(config): - return strports.service(config['port'], toc.TOCFactory()) diff --git a/tools/buildbot/pylibs/twisted/words/topfiles/NEWS b/tools/buildbot/pylibs/twisted/words/topfiles/NEWS deleted file mode 100644 index 459a4d0..0000000 --- a/tools/buildbot/pylibs/twisted/words/topfiles/NEWS +++ /dev/null @@ -1,135 +0,0 @@ -8.1.0 (2008-05-18) -================== - -Features --------- - - JID objects now have a nice __repr__ (#3156) - - Extending XMPP protocols is now easier (#2178) - -Fixes ------ - - The deprecated mktap API is no longer used (#3127) - - A bug whereby one-time XMPP observers would be enabled permanently was fixed - (#3066) - - -8.0.0 (2008-03-17) -================== - -Features --------- - - Provide function for creating XMPP response stanzas. (#2614, #2614) - - Log exceptions raised in Xish observers. (#2616) - - Add 'and' and 'or' operators for Xish XPath expressions. (#2502) - - Make JIDs hashable. (#2770) - -Fixes ------ - - Respect the hostname and servername parameters to IRCClient.register. (#1649) - - Make EventDispatcher remove empty callback lists. (#1652) - - Use legacy base64 API to support Python 2.3 (#2461) - - Fix support of DIGEST-MD5 challenge parsing with multi-valued directives. - (#2606) - - Fix reuse of dict of prefixes in domish.Element.toXml (#2609) - - Properly process XMPP stream headers (#2615) - - Use proper namespace for XMPP stream errors. (#2630) - - Properly parse XMPP stream errors. (#2771) - - Fix toResponse for XMPP stanzas without an id attribute. (#2773) - - Move XMPP stream header procesing to authenticators. (#2772) - -Misc ----- - - #2617, #2640, #2741, #2063, #2570, #2847 - - -0.5.0 (2007-01-06) -================== - -Features --------- - - (Jabber) IQ.send now optionally has a 'timeout' parameter which - specifies a time at which to errback the Deferred with a - TimeoutError (#2218) - - (Jabber) SASL authentication, resource binding and session - establishment were added. (#1046) The following were done in - support of this change: - - Rework ConnectAuthenticator to work with initializer objects that - provide a stream initialization step. - - Reimplement iq:auth as an initializer. - - Reimplement TLS negotiation as an initializer. - - Add XMPPAuthenticator as a XMPP 1.0 client authenticator (only), along - with XMPPClientFactory. - - Add support for working with pre-XMPP-1.0 error stanzas. - - Remove hasFeature() from XmlStream as you can test (uri, name) in - xs.features. - - Add sendFooter() and sendStreamError() to XmlStream - -Fixes ------ - - (Jabber) Deferreds from queries which were never resolved before - a lost connection are now errbacked (#2006) - - (Jabber) servers which didn't send a 'realm' directive in - authentication challenges no longer cause the Jabber client to - choke (#2098) - - (MSN) error responses are now properly turned into errbacks (#2019) - - (IRC) A trivial bug in IRCClient which would cause whois(oper=True) - to always raise an exception was fixed (#2089) - - (IM) Bugs in the error handling and already-connecting cases of - AbstractAccount.logOn were fixed (#2086) - -Misc ----- - - #1734, #1735, #1636, #1936, #1883, #1995, #2171, #2165, #2177 - - -0.4.0 (2006-05-21) -================== - -Features --------- - - Jabber: - - Add support for stream and stanza level errors - - Create new IQ stanza helper that works with deferreds - - Add TLS support for initiating entities to XmlStream - - Fix account registration - - Xish: - - Fix various namespace issues - - Add IElement - - Store namespace declarations in parsed XML for later serialization - - Fix user name/group collision in server service (#1655). - - Correctly recognize MSN capability messages (#861). - -Fixes ------ - - Misc: #1283, #1296, #1302, #1424 - - Fix unicode/str confusion in IRC server service. - - -0.3.0: - - Jabber: - - - Fix digest authentication in Jabber - - Add Jabber xmlstream module that contains the Jabber specific bits that - got factored out of Twisted Xish's xmlstream, and make it suitable for - implementing full XMPP support. - - Xish: - - Fixed serialization in _ListSerializer - - Removed unneeded extra whitespace generated in serialization - - Removed _Serializer in favour of _ListSerializer - - Use unicode objects for representing serialized XML, instead of utf-8 - encoded str objects. - - Properly catch XML parser errors - - Rework and fix element stream test cases - - Strip xmlstream from all Jabber specifics that moved to Twisted Words - - Added exhaustive docstrings to xmlstream. - - Words Service: - - Complete rewrite - - Not backwards compatible - -0.1.0: - - Fix some miscellaneous bugs in OSCAR - - Add QUIT notification for IRC - - Fix message wrapping - - Misc Jabber fixes - - Add stringprep support for Jabber IDs - This only works properly on 2.3.2 or higher diff --git a/tools/buildbot/pylibs/twisted/words/topfiles/README b/tools/buildbot/pylibs/twisted/words/topfiles/README deleted file mode 100644 index ae23cfb..0000000 --- a/tools/buildbot/pylibs/twisted/words/topfiles/README +++ /dev/null @@ -1,4 +0,0 @@ -Twisted Words 8.1.0 - -Twisted Words depends on Twisted Core and Twisted Web. The Twisted Web -dependency is only necessary for MSN support. diff --git a/tools/buildbot/pylibs/twisted/words/topfiles/setup.py b/tools/buildbot/pylibs/twisted/words/topfiles/setup.py deleted file mode 100644 index 73b09cb..0000000 --- a/tools/buildbot/pylibs/twisted/words/topfiles/setup.py +++ /dev/null @@ -1,51 +0,0 @@ -import sys - -try: - from twisted.python import dist -except ImportError: - raise SystemExit("twisted.python.dist module not found. Make sure you " - "have installed the Twisted core package before " - "attempting to install any other Twisted projects.") - -if __name__ == '__main__': - if sys.version_info[:2] >= (2, 4): - extraMeta = dict( - classifiers=[ - "Development Status :: 4 - Beta", - "Environment :: No Input/Output (Daemon)", - "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", - "Programming Language :: Python", - "Topic :: Communications :: Chat", - "Topic :: Communications :: Chat :: AOL Instant Messenger", - "Topic :: Communications :: Chat :: ICQ", - "Topic :: Communications :: Chat :: Internet Relay Chat", - "Topic :: Internet", - "Topic :: Software Development :: Libraries :: Python Modules", - ]) - else: - extraMeta = {} - - dist.setup( - twisted_subproject="words", - scripts=dist.getScripts("words"), - # metadata - name="Twisted Words", - description="Twisted Words contains Instant Messaging implementations.", - author="Twisted Matrix Laboratories", - author_email="twisted-python@twistedmatrix.com", - maintainer="Jp Calderone", - maintainer_email="exarkun@divmod.com", - url="http://twistedmatrix.com/trac/wiki/TwistedWords", - license="MIT", - long_description="""\ -Twisted Words contains implementations of many Instant Messaging -protocols, including IRC, Jabber, MSN, OSCAR (AIM & ICQ), TOC (AOL), -and some functionality for creating bots, inter-protocol gateways, and -a client application for many of the protocols. - -In support of Jabber, Twisted Words also contains X-ish, a library for -processing XML with Twisted and Python, with support for a Pythonic DOM and -an XPath-like toolkit. -""", - **extraMeta) diff --git a/tools/buildbot/pylibs/twisted/words/xish/__init__.py b/tools/buildbot/pylibs/twisted/words/xish/__init__.py deleted file mode 100644 index 747d943..0000000 --- a/tools/buildbot/pylibs/twisted/words/xish/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -# -*- test-case-name: twisted.words.test -*- -# Copyright (c) 2001-2005 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" - -Twisted X-ish: XML-ish DOM and XPath-ish engine - -""" diff --git a/tools/buildbot/pylibs/twisted/words/xish/domish.py b/tools/buildbot/pylibs/twisted/words/xish/domish.py deleted file mode 100644 index 2341fb2..0000000 --- a/tools/buildbot/pylibs/twisted/words/xish/domish.py +++ /dev/null @@ -1,831 +0,0 @@ -# -*- test-case-name: twisted.words.test.test_domish -*- -# -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -DOM-like XML processing support. - -This module provides support for parsing XML into DOM-like object structures -and serializing such structures to an XML string representation, optimized -for use in streaming XML applications. -""" - -import types - -from zope.interface import implements, Interface, Attribute - -def _splitPrefix(name): - """ Internal method for splitting a prefixed Element name into its - respective parts """ - ntok = name.split(":", 1) - if len(ntok) == 2: - return ntok - else: - return (None, ntok[0]) - -# Global map of prefixes that always get injected -# into the serializers prefix map (note, that doesn't -# mean they're always _USED_) -G_PREFIXES = { "http://www.w3.org/XML/1998/namespace":"xml" } - -class _ListSerializer: - """ Internal class which serializes an Element tree into a buffer """ - def __init__(self, prefixes=None, prefixesInScope=None): - self.writelist = [] - self.prefixes = {} - if prefixes: - self.prefixes.update(prefixes) - self.prefixes.update(G_PREFIXES) - self.prefixStack = [G_PREFIXES.values()] + (prefixesInScope or []) - self.prefixCounter = 0 - - def getValue(self): - return u"".join(self.writelist) - - def getPrefix(self, uri): - if not self.prefixes.has_key(uri): - self.prefixes[uri] = "xn%d" % (self.prefixCounter) - self.prefixCounter = self.prefixCounter + 1 - return self.prefixes[uri] - - def prefixInScope(self, prefix): - stack = self.prefixStack - for i in range(-1, (len(self.prefixStack)+1) * -1, -1): - if prefix in stack[i]: - return True - return False - - def serialize(self, elem, closeElement=1, defaultUri=''): - # Optimization shortcuts - write = self.writelist.append - - # Shortcut, check to see if elem is actually a chunk o' serialized XML - if isinstance(elem, SerializedXML): - write(elem) - return - - # Shortcut, check to see if elem is actually a string (aka Cdata) - if isinstance(elem, types.StringTypes): - write(escapeToXml(elem)) - return - - # Further optimizations - parent = elem.parent - name = elem.name - uri = elem.uri - defaultUri, currentDefaultUri = elem.defaultUri, defaultUri - - for p, u in elem.localPrefixes.iteritems(): - self.prefixes[u] = p - self.prefixStack.append(elem.localPrefixes.keys()) - - # Inherit the default namespace - if defaultUri is None: - defaultUri = currentDefaultUri - - if uri is None: - uri = defaultUri - - prefix = None - if uri != defaultUri or uri in self.prefixes: - prefix = self.getPrefix(uri) - inScope = self.prefixInScope(prefix) - - # Create the starttag - - if not prefix: - write("<%s" % (name)) - else: - write("<%s:%s" % (prefix, name)) - - if not inScope: - write(" xmlns:%s='%s'" % (prefix, uri)) - self.prefixStack[-1].append(prefix) - inScope = True - - if defaultUri != currentDefaultUri and \ - (uri != defaultUri or not prefix or not inScope): - write(" xmlns='%s'" % (defaultUri)) - - for p, u in elem.localPrefixes.iteritems(): - write(" xmlns:%s='%s'" % (p, u)) - - # Serialize attributes - for k,v in elem.attributes.items(): - # If the attribute name is a tuple, it's a qualified attribute - if isinstance(k, types.TupleType): - attr_uri, attr_name = k - attr_prefix = self.getPrefix(attr_uri) - - if not self.prefixInScope(attr_prefix): - write(" xmlns:%s='%s'" % (attr_prefix, attr_uri)) - self.prefixStack[-1].append(attr_prefix) - - write(" %s:%s='%s'" % (attr_prefix, attr_name, - escapeToXml(v, 1))) - else: - write((" %s='%s'" % ( k, escapeToXml(v, 1)))) - - # Shortcut out if this is only going to return - # the element (i.e. no children) - if closeElement == 0: - write(">") - return - - # Serialize children - if len(elem.children) > 0: - write(">") - for c in elem.children: - self.serialize(c, defaultUri=defaultUri) - # Add closing tag - if not prefix: - write("" % (name)) - else: - write("" % (prefix, name)) - else: - write("/>") - - self.prefixStack.pop() - - -SerializerClass = _ListSerializer - -def escapeToXml(text, isattrib = 0): - """ Escape text to proper XML form, per section 2.3 in the XML specification. - - @type text: L{str} - @param text: Text to escape - - @type isattrib: L{bool} - @param isattrib: Triggers escaping of characters necessary for use as - attribute values - """ - text = text.replace("&", "&") - text = text.replace("<", "<") - text = text.replace(">", ">") - if isattrib == 1: - text = text.replace("'", "'") - text = text.replace("\"", """) - return text - -def unescapeFromXml(text): - text = text.replace("<", "<") - text = text.replace(">", ">") - text = text.replace("'", "'") - text = text.replace(""", "\"") - text = text.replace("&", "&") - return text - -def generateOnlyInterface(list, int): - """ Filters items in a list by class - """ - for n in list: - if int.providedBy(n): - yield n - -def generateElementsQNamed(list, name, uri): - """ Filters Element items in a list with matching name and URI. """ - for n in list: - if IElement.providedBy(n) and n.name == name and n.uri == uri: - yield n - -def generateElementsNamed(list, name): - """ Filters Element items in a list with matching name, regardless of URI. - """ - for n in list: - if IElement.providedBy(n) and n.name == name: - yield n - - -class SerializedXML(unicode): - """ Marker class for pre-serialized XML in the DOM. """ - pass - - -class Namespace: - """ Convenience object for tracking namespace declarations. """ - def __init__(self, uri): - self._uri = uri - def __getattr__(self, n): - return (self._uri, n) - def __getitem__(self, n): - return (self._uri, n) - -class IElement(Interface): - """ - Interface to XML element nodes. - - See L{Element} for a detailed example of its general use. - - Warning: this Interface is not yet complete! - """ - - uri = Attribute(""" Element's namespace URI """) - name = Attribute(""" Element's local name """) - defaultUri = Attribute(""" Default namespace URI of child elements """) - attributes = Attribute(""" Dictionary of element attributes """) - children = Attribute(""" List of child nodes """) - parent = Attribute(""" Reference to element's parent element """) - localPrefixes = Attribute(""" Dictionary of local prefixes """) - - def toXml(prefixes=None, closeElement=1, defaultUri='', - prefixesInScope=None): - """ Serializes object to a (partial) XML document - - @param prefixes: dictionary that maps namespace URIs to suggested - prefix names. - @type prefixes: L{dict} - @param closeElement: flag that determines whether to include the - closing tag of the element in the serialized - string. A value of C{0} only generates the - element's start tag. A value of C{1} yields a - complete serialization. - @type closeElement: L{int} - @param defaultUri: Initial default namespace URI. This is most useful - for partial rendering, where the logical parent - element (of which the starttag was already - serialized) declares a default namespace that should - be inherited. - @type defaultUri: L{str} - @param prefixesInScope: list of prefixes that are assumed to be - declared by ancestors. - @type prefixesInScope: L{list} - @return: (partial) serialized XML - @rtype: L{unicode} - """ - - def addElement(name, defaultUri = None, content = None): - """ Create an element and add as child. - - The new element is added to this element as a child, and will have - this element as its parent. - - @param name: element name. This can be either a L{unicode} object that - contains the local name, or a tuple of (uri, local_name) - for a fully qualified name. In the former case, - the namespace URI is inherited from this element. - @type name: L{unicode} or L{tuple} of (L{unicode}, L{unicode}) - @param defaultUri: default namespace URI for child elements. If - C{None}, this is inherited from this element. - @type defaultUri: L{unicode} - @param content: text contained by the new element. - @type content: L{unicode} - @return: the created element - @rtype: object providing L{IElement} - """ - - def addChild(node): - """ Adds a node as child of this element. - - The C{node} will be added to the list of childs of this element, and - will have this element set as its parent when C{node} provides - L{IElement}. - - @param node: the child node. - @type node: L{unicode} or object implementing L{IElement} - """ - -class Element(object): - """ Represents an XML element node. - - An Element contains a series of attributes (name/value pairs), content - (character data), and other child Element objects. When building a document - with markup (such as HTML or XML), use this object as the starting point. - - Element objects fully support XML Namespaces. The fully qualified name of - the XML Element it represents is stored in the C{uri} and C{name} - attributes, where C{uri} holds the namespace URI. There is also a default - namespace, for child elements. This is stored in the C{defaultUri} - attribute. Note that C{''} means the empty namespace. - - Serialization of Elements through C{toXml()} will use these attributes - for generating proper serialized XML. When both C{uri} and C{defaultUri} - are not None in the Element and all of its descendents, serialization - proceeds as expected: - - >>> from twisted.words.xish import domish - >>> root = domish.Element(('myns', 'root')) - >>> root.addElement('child', content='test') - - >>> root.toXml() - u"test" - - For partial serialization, needed for streaming XML, a special value for - namespace URIs can be used: C{None}. - - Using C{None} as the value for C{uri} means: this element is in whatever - namespace inherited by the closest logical ancestor when the complete XML - document has been serialized. The serialized start tag will have a - non-prefixed name, and no xmlns declaration will be generated. - - Similarly, C{None} for C{defaultUri} means: the default namespace for my - child elements is inherited from the logical ancestors of this element, - when the complete XML document has been serialized. - - To illustrate, an example from a Jabber stream. Assume the start tag of the - root element of the stream has already been serialized, along with several - complete child elements, and sent off, looking like this:: - - - ... - - Now suppose we want to send a complete element represented by an - object C{message} created like: - - >>> message = domish.Element((None, 'message')) - >>> message['to'] = 'user@example.com' - >>> message.addElement('body', content='Hi!') - - >>> message.toXml() - u"Hi!" - - As, you can see, this XML snippet has no xmlns declaration. When sent - off, it inherits the C{jabber:client} namespace from the root element. - Note that this renders the same as using C{''} instead of C{None}: - - >>> presence = domish.Element(('', 'presence')) - >>> presence.toXml() - u"" - - However, if this object has a parent defined, the difference becomes - clear: - - >>> child = message.addElement(('http://example.com/', 'envelope')) - >>> child.addChild(presence) - - >>> message.toXml() - u"Hi!" - - As, you can see, the element is now in the empty namespace, not - in the default namespace of the parent or the streams'. - - @type uri: L{unicode} or None - @ivar uri: URI of this Element's name - - @type name: L{unicode} - @ivar name: Name of this Element - - @type defaultUri: L{unicode} or None - @ivar defaultUri: URI this Element exists within - - @type children: L{list} - @ivar children: List of child Elements and content - - @type parent: L{Element} - @ivar parent: Reference to the parent Element, if any. - - @type attributes: L{dict} - @ivar attributes: Dictionary of attributes associated with this Element. - - @type localPrefixes: L{dict} - @ivar localPrefixes: Dictionary of namespace declarations on this - element. The key is the prefix to bind the - namespace uri to. - """ - - implements(IElement) - - _idCounter = 0 - - def __init__(self, qname, defaultUri=None, attribs=None, - localPrefixes=None): - """ - @param qname: Tuple of (uri, name) - @param defaultUri: The default URI of the element; defaults to the URI - specified in L{qname} - @param attribs: Dictionary of attributes - @param localPrefixes: Dictionary of namespace declarations on this - element. The key is the prefix to bind the - namespace uri to. - """ - self.localPrefixes = localPrefixes or {} - self.uri, self.name = qname - if defaultUri is None and \ - self.uri not in self.localPrefixes.itervalues(): - self.defaultUri = self.uri - else: - self.defaultUri = defaultUri - self.attributes = attribs or {} - self.children = [] - self.parent = None - - def __getattr__(self, key): - # Check child list for first Element with a name matching the key - for n in self.children: - if IElement.providedBy(n) and n.name == key: - return n - - # Tweak the behaviour so that it's more friendly about not - # finding elements -- we need to document this somewhere :) - if key.startswith('_'): - raise AttributeError(key) - else: - return None - - def __getitem__(self, key): - return self.attributes[self._dqa(key)] - - def __delitem__(self, key): - del self.attributes[self._dqa(key)]; - - def __setitem__(self, key, value): - self.attributes[self._dqa(key)] = value - - def __str__(self): - """ Retrieve the first CData (content) node - """ - for n in self.children: - if isinstance(n, types.StringTypes): return n - return "" - - def _dqa(self, attr): - """ Dequalify an attribute key as needed """ - if isinstance(attr, types.TupleType) and not attr[0]: - return attr[1] - else: - return attr - - def getAttribute(self, attribname, default = None): - """ Retrieve the value of attribname, if it exists """ - return self.attributes.get(attribname, default) - - def hasAttribute(self, attrib): - """ Determine if the specified attribute exists """ - return self.attributes.has_key(self._dqa(attrib)) - - def compareAttribute(self, attrib, value): - """ Safely compare the value of an attribute against a provided value. - - C{None}-safe. - """ - return self.attributes.get(self._dqa(attrib), None) == value - - def swapAttributeValues(self, left, right): - """ Swap the values of two attribute. """ - d = self.attributes - l = d[left] - d[left] = d[right] - d[right] = l - - def addChild(self, node): - """ Add a child to this Element. """ - if IElement.providedBy(node): - node.parent = self - self.children.append(node) - return self.children[-1] - - def addContent(self, text): - """ Add some text data to this Element. """ - c = self.children - if len(c) > 0 and isinstance(c[-1], types.StringTypes): - c[-1] = c[-1] + text - else: - c.append(text) - return c[-1] - - def addElement(self, name, defaultUri = None, content = None): - result = None - if isinstance(name, type(())): - if defaultUri is None: - defaultUri = name[0] - self.children.append(Element(name, defaultUri)) - else: - if defaultUri is None: - defaultUri = self.defaultUri - self.children.append(Element((defaultUri, name), defaultUri)) - - result = self.children[-1] - result.parent = self - - if content: - result.children.append(content) - - return result - - def addRawXml(self, rawxmlstring): - """ Add a pre-serialized chunk o' XML as a child of this Element. """ - self.children.append(SerializedXML(rawxmlstring)) - - def addUniqueId(self): - """ Add a unique (across a given Python session) id attribute to this - Element. - """ - self.attributes["id"] = "H_%d" % Element._idCounter - Element._idCounter = Element._idCounter + 1 - - def elements(self): - """ Iterate across all children of this Element that are Elements. """ - return generateOnlyInterface(self.children, IElement) - - def toXml(self, prefixes=None, closeElement=1, defaultUri='', - prefixesInScope=None): - """ Serialize this Element and all children to a string. """ - s = SerializerClass(prefixes=prefixes, prefixesInScope=prefixesInScope) - s.serialize(self, closeElement=closeElement, defaultUri=defaultUri) - return s.getValue() - - def firstChildElement(self): - for c in self.children: - if IElement.providedBy(c): - return c - return None - - -class ParserError(Exception): - """ Exception thrown when a parsing error occurs """ - pass - -def elementStream(): - """ Preferred method to construct an ElementStream - - Uses Expat-based stream if available, and falls back to Sux if necessary. - """ - try: - es = ExpatElementStream() - return es - except ImportError: - if SuxElementStream is None: - raise Exception("No parsers available :(") - es = SuxElementStream() - return es - -try: - from twisted.web import sux -except: - SuxElementStream = None -else: - class SuxElementStream(sux.XMLParser): - def __init__(self): - self.connectionMade() - self.DocumentStartEvent = None - self.ElementEvent = None - self.DocumentEndEvent = None - self.currElem = None - self.rootElem = None - self.documentStarted = False - self.defaultNsStack = [] - self.prefixStack = [] - - def parse(self, buffer): - try: - self.dataReceived(buffer) - except sux.ParseError, e: - raise ParserError, str(e) - - - def findUri(self, prefix): - # Walk prefix stack backwards, looking for the uri - # matching the specified prefix - stack = self.prefixStack - for i in range(-1, (len(self.prefixStack)+1) * -1, -1): - if prefix in stack[i]: - return stack[i][prefix] - return None - - def gotTagStart(self, name, attributes): - defaultUri = None - localPrefixes = {} - attribs = {} - uri = None - - # Pass 1 - Identify namespace decls - for k, v in attributes.items(): - if k.startswith("xmlns"): - x, p = _splitPrefix(k) - if (x is None): # I.e. default declaration - defaultUri = v - else: - localPrefixes[p] = v - del attributes[k] - - # Push namespace decls onto prefix stack - self.prefixStack.append(localPrefixes) - - # Determine default namespace for this element; if there - # is one - if defaultUri is None: - if len(self.defaultNsStack) > 0: - defaultUri = self.defaultNsStack[-1] - else: - defaultUri = '' - - # Fix up name - prefix, name = _splitPrefix(name) - if prefix is None: # This element is in the default namespace - uri = defaultUri - else: - # Find the URI for the prefix - uri = self.findUri(prefix) - - # Pass 2 - Fix up and escape attributes - for k, v in attributes.items(): - p, n = _splitPrefix(k) - if p is None: - attribs[n] = v - else: - attribs[(self.findUri(p)), n] = unescapeFromXml(v) - - # Construct the actual Element object - e = Element((uri, name), defaultUri, attribs, localPrefixes) - - # Save current default namespace - self.defaultNsStack.append(defaultUri) - - # Document already started - if self.documentStarted: - # Starting a new packet - if self.currElem is None: - self.currElem = e - # Adding to existing element - else: - self.currElem = self.currElem.addChild(e) - # New document - else: - self.rootElem = e - self.documentStarted = True - self.DocumentStartEvent(e) - - def gotText(self, data): - if self.currElem != None: - self.currElem.addContent(data) - - def gotCData(self, data): - if self.currElem != None: - self.currElem.addContent(data) - - def gotComment(self, data): - # Ignore comments for the moment - pass - - entities = { "amp" : "&", - "lt" : "<", - "gt" : ">", - "apos": "'", - "quot": "\"" } - - def gotEntityReference(self, entityRef): - # If this is an entity we know about, add it as content - # to the current element - if entityRef in SuxElementStream.entities: - self.currElem.addContent(SuxElementStream.entities[entityRef]) - - def gotTagEnd(self, name): - # Ensure the document hasn't already ended - if self.rootElem is None: - # XXX: Write more legible explanation - raise ParserError, "Element closed after end of document." - - # Fix up name - prefix, name = _splitPrefix(name) - if prefix is None: - uri = self.defaultNsStack[-1] - else: - uri = self.findUri(prefix) - - # End of document - if self.currElem is None: - # Ensure element name and uri matches - if self.rootElem.name != name or self.rootElem.uri != uri: - raise ParserError, "Mismatched root elements" - self.DocumentEndEvent() - self.rootElem = None - - # Other elements - else: - # Ensure the tag being closed matches the name of the current - # element - if self.currElem.name != name or self.currElem.uri != uri: - # XXX: Write more legible explanation - raise ParserError, "Malformed element close" - - # Pop prefix and default NS stack - self.prefixStack.pop() - self.defaultNsStack.pop() - - # Check for parent null parent of current elem; - # that's the top of the stack - if self.currElem.parent is None: - self.currElem.parent = self.rootElem - self.ElementEvent(self.currElem) - self.currElem = None - - # Anything else is just some element wrapping up - else: - self.currElem = self.currElem.parent - - -class ExpatElementStream: - def __init__(self): - import pyexpat - self.DocumentStartEvent = None - self.ElementEvent = None - self.DocumentEndEvent = None - self.error = pyexpat.error - self.parser = pyexpat.ParserCreate("UTF-8", " ") - self.parser.StartElementHandler = self._onStartElement - self.parser.EndElementHandler = self._onEndElement - self.parser.CharacterDataHandler = self._onCdata - self.parser.StartNamespaceDeclHandler = self._onStartNamespace - self.parser.EndNamespaceDeclHandler = self._onEndNamespace - self.currElem = None - self.defaultNsStack = [''] - self.documentStarted = 0 - self.localPrefixes = {} - - def parse(self, buffer): - try: - self.parser.Parse(buffer) - except self.error, e: - raise ParserError, str(e) - - def _onStartElement(self, name, attrs): - # Generate a qname tuple from the provided name - qname = name.split(" ") - if len(qname) == 1: - qname = ('', name) - - # Process attributes - for k, v in attrs.items(): - if k.find(" ") != -1: - aqname = k.split(" ") - attrs[(aqname[0], aqname[1])] = v - del attrs[k] - - # Construct the new element - e = Element(qname, self.defaultNsStack[-1], attrs, self.localPrefixes) - self.localPrefixes = {} - - # Document already started - if self.documentStarted == 1: - if self.currElem != None: - self.currElem.children.append(e) - e.parent = self.currElem - self.currElem = e - - # New document - else: - self.documentStarted = 1 - self.DocumentStartEvent(e) - - def _onEndElement(self, _): - # Check for null current elem; end of doc - if self.currElem is None: - self.DocumentEndEvent() - - # Check for parent that is None; that's - # the top of the stack - elif self.currElem.parent is None: - self.ElementEvent(self.currElem) - self.currElem = None - - # Anything else is just some element in the current - # packet wrapping up - else: - self.currElem = self.currElem.parent - - def _onCdata(self, data): - if self.currElem != None: - self.currElem.addContent(data) - - def _onStartNamespace(self, prefix, uri): - # If this is the default namespace, put - # it on the stack - if prefix is None: - self.defaultNsStack.append(uri) - else: - self.localPrefixes[prefix] = uri - - def _onEndNamespace(self, prefix): - # Remove last element on the stack - if prefix is None: - self.defaultNsStack.pop() - -## class FileParser(ElementStream): -## def __init__(self): -## ElementStream.__init__(self) -## self.DocumentStartEvent = self.docStart -## self.ElementEvent = self.elem -## self.DocumentEndEvent = self.docEnd -## self.done = 0 - -## def docStart(self, elem): -## self.document = elem - -## def elem(self, elem): -## self.document.addChild(elem) - -## def docEnd(self): -## self.done = 1 - -## def parse(self, filename): -## for l in open(filename).readlines(): -## self.parser.Parse(l) -## assert self.done == 1 -## return self.document - -## def parseFile(filename): -## return FileParser().parse(filename) - - diff --git a/tools/buildbot/pylibs/twisted/words/xish/utility.py b/tools/buildbot/pylibs/twisted/words/xish/utility.py deleted file mode 100644 index 48a610f..0000000 --- a/tools/buildbot/pylibs/twisted/words/xish/utility.py +++ /dev/null @@ -1,335 +0,0 @@ -# -*- test-case-name: twisted.words.test.test_xishutil -*- -# -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Event Dispatching and Callback utilities. -""" - -from twisted.python import log -from twisted.words.xish import xpath - -class _MethodWrapper(object): - """ - Internal class for tracking method calls. - """ - def __init__(self, method, *args, **kwargs): - self.method = method - self.args = args - self.kwargs = kwargs - - - def __call__(self, *args, **kwargs): - nargs = self.args + args - nkwargs = self.kwargs.copy() - nkwargs.update(kwargs) - self.method(*nargs, **nkwargs) - - -class CallbackList: - """ - Container for callbacks. - - Event queries are linked to lists of callables. When a matching event - occurs, these callables are called in sequence. One-time callbacks - are removed from the list after the first time the event was triggered. - - Arguments to callbacks are split spread across two sets. The first set, - callback specific, is passed to C{addCallback} and is used for all - subsequent event triggers. The second set is passed to C{callback} and is - event specific. Positional arguments in the second set come after the - positional arguments of the first set. Keyword arguments in the second set - override those in the first set. - - @ivar callbacks: The registered callbacks as mapping from the callable to a - tuple of a wrapper for that callable that keeps the - callback specific arguments and a boolean that signifies - if it is to be called only once. - @type callbacks: C{dict} - """ - - def __init__(self): - self.callbacks = {} - - - def addCallback(self, onetime, method, *args, **kwargs): - """ - Add callback. - - The arguments passed are used as callback specific arguments. - - @param onetime: If C{True}, this callback is called at most once. - @type onetime: C{bool} - @param method: The callback callable to be added. - @param args: Positional arguments to the callable. - @type args: C{list} - @param kwargs: Keyword arguments to the callable. - @type kwargs: C{dict} - """ - - if not method in self.callbacks: - self.callbacks[method] = (_MethodWrapper(method, *args, **kwargs), - onetime) - - - def removeCallback(self, method): - """ - Remove callback. - - @param method: The callable to be removed. - """ - - if method in self.callbacks: - del self.callbacks[method] - - - def callback(self, *args, **kwargs): - """ - Call all registered callbacks. - - The passed arguments are event specific and augment and override - the callback specific arguments as described above. - - @note: Exceptions raised by callbacks are trapped and logged. They will - not propagate up to make sure other callbacks will still be - called, and the event dispatching allways succeeds. - - @param args: Positional arguments to the callable. - @type args: C{list} - @param kwargs: Keyword arguments to the callable. - @type kwargs: C{dict} - """ - - for key, (methodwrapper, onetime) in self.callbacks.items(): - try: - methodwrapper(*args, **kwargs) - except: - log.err() - - if onetime: - del self.callbacks[key] - - - def isEmpty(self): - """ - Return if list of registered callbacks is empty. - - @rtype: C{bool} - """ - - return len(self.callbacks) == 0 - - - -class EventDispatcher: - """ - Event dispatching service. - - The C{EventDispatcher} allows observers to be registered for certain events - that are dispatched. There are two types of events: XPath events and Named - events. - - Every dispatch is triggered by calling L{dispatch} with a data object and, - for named events, the name of the event. - - When an XPath type event is dispatched, the associated object is assumed to - be an L{Element} instance, which is - matched against all registered XPath queries. For every match, the - respective observer will be called with the data object. - - A named event will simply call each registered observer for that particular - event name, with the data object. Unlike XPath type events, the data object - is not restricted to L{Element}, but can - be anything. - - When registering observers, the event that is to be observed is specified - using an L{xpath.XPathQuery} instance or a string. In the latter case, the - string can also contain the string representation of an XPath expression. - To distinguish these from named events, each named event should start with - a special prefix that is stored in C{self.prefix}. It defaults to - C{//event/}. - - Observers registered using L{addObserver} are persistent: after the - observer has been triggered by a dispatch, it remains registered for a - possible next dispatch. If instead L{addOnetimeObserver} was used to - observe an event, the observer is removed from the list of observers after - the first observed event. - - Obsevers can also prioritized, by providing an optional C{priority} - parameter to the L{addObserver} and L{addOnetimeObserver} methods. Higher - priority observers are then called before lower priority observers. - - Finally, observers can be unregistered by using L{removeObserver}. - """ - - def __init__(self, eventprefix="//event/"): - self.prefix = eventprefix - self._eventObservers = {} - self._xpathObservers = {} - self._dispatchDepth = 0 # Flag indicating levels of dispatching - # in progress - self._updateQueue = [] # Queued updates for observer ops - - - def _getEventAndObservers(self, event): - if isinstance(event, xpath.XPathQuery): - # Treat as xpath - observers = self._xpathObservers - else: - if self.prefix == event[:len(self.prefix)]: - # Treat as event - observers = self._eventObservers - else: - # Treat as xpath - event = xpath.internQuery(event) - observers = self._xpathObservers - - return event, observers - - - def addOnetimeObserver(self, event, observerfn, priority=0, *args, **kwargs): - """ - Register a one-time observer for an event. - - Like L{addObserver}, but is only triggered at most once. See there - for a description of the parameters. - """ - self._addObserver(True, event, observerfn, priority, *args, **kwargs) - - - def addObserver(self, event, observerfn, priority=0, *args, **kwargs): - """ - Register an observer for an event. - - Each observer will be registered with a certain priority. Higher - priority observers get called before lower priority observers. - - @param event: Name or XPath query for the event to be monitored. - @type event: C{str} or L{xpath.XPathQuery}. - @param observerfn: Function to be called when the specified event - has been triggered. This callable takes - one parameter: the data object that triggered - the event. When specified, the C{*args} and - C{**kwargs} parameters to addObserver are being used - as additional parameters to the registered observer - callable. - @param priority: (Optional) priority of this observer in relation to - other observer that match the same event. Defaults to - C{0}. - @type priority: C{int} - """ - self._addObserver(False, event, observerfn, priority, *args, **kwargs) - - - def _addObserver(self, onetime, event, observerfn, priority, *args, **kwargs): - # If this is happening in the middle of the dispatch, queue - # it up for processing after the dispatch completes - if self._dispatchDepth > 0: - self._updateQueue.append(lambda:self._addObserver(onetime, event, observerfn, priority, *args, **kwargs)) - return - - event, observers = self._getEventAndObservers(event) - - if priority not in observers: - cbl = CallbackList() - observers[priority] = {event: cbl} - else: - priorityObservers = observers[priority] - if event not in priorityObservers: - cbl = CallbackList() - observers[priority][event] = cbl - else: - cbl = priorityObservers[event] - - cbl.addCallback(onetime, observerfn, *args, **kwargs) - - - def removeObserver(self, event, observerfn): - """ - Remove callable as observer for an event. - - The observer callable is removed for all priority levels for the - specified event. - - @param event: Event for which the observer callable was registered. - @type event: C{str} or L{xpath.XPathQuery} - @param observerfn: Observer callable to be unregistered. - """ - - # If this is happening in the middle of the dispatch, queue - # it up for processing after the dispatch completes - if self._dispatchDepth > 0: - self._updateQueue.append(lambda:self.removeObserver(event, observerfn)) - return - - event, observers = self._getEventAndObservers(event) - - emptyLists = [] - for priority, priorityObservers in observers.iteritems(): - for query, callbacklist in priorityObservers.iteritems(): - if event == query: - callbacklist.removeCallback(observerfn) - if callbacklist.isEmpty(): - emptyLists.append((priority, query)) - - for priority, query in emptyLists: - del observers[priority][query] - - - def dispatch(self, obj, event=None): - """ - Dispatch an event. - - When C{event} is C{None}, an XPath type event is triggered, and - C{obj} is assumed to be an instance of - L{Element}. Otherwise, C{event} - holds the name of the named event being triggered. In the latter case, - C{obj} can be anything. - - @param obj: The object to be dispatched. - @param event: Optional event name. - @type event: C{str} - """ - - foundTarget = False - - self._dispatchDepth += 1 - - if event != None: - # Named event - observers = self._eventObservers - match = lambda query, obj: query == event - else: - # XPath event - observers = self._xpathObservers - match = lambda query, obj: query.matches(obj) - - priorities = observers.keys() - priorities.sort() - priorities.reverse() - - emptyLists = [] - for priority in priorities: - for query, callbacklist in observers[priority].iteritems(): - if match(query, obj): - callbacklist.callback(obj) - foundTarget = True - if callbacklist.isEmpty(): - emptyLists.append((priority, query)) - - for priority, query in emptyLists: - del observers[priority][query] - - self._dispatchDepth -= 1 - - # If this is a dispatch within a dispatch, don't - # do anything with the updateQueue -- it needs to - # wait until we've back all the way out of the stack - if self._dispatchDepth == 0: - # Deal with pending update operations - for f in self._updateQueue: - f() - self._updateQueue = [] - - return foundTarget diff --git a/tools/buildbot/pylibs/twisted/words/xish/xmlstream.py b/tools/buildbot/pylibs/twisted/words/xish/xmlstream.py deleted file mode 100644 index 950a392..0000000 --- a/tools/buildbot/pylibs/twisted/words/xish/xmlstream.py +++ /dev/null @@ -1,211 +0,0 @@ -# -*- test-case-name: twisted.words.test.test_xmlstream -*- -# -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -XML Stream processing. - -An XML Stream is defined as a connection over which two XML documents are -exchanged during the lifetime of the connection, one for each direction. The -unit of interaction is a direct child element of the root element (stanza). - -The most prominent use of XML Streams is Jabber, but this module is generically -usable. See Twisted Words for Jabber specific protocol support. - -Maintainer: U{Ralph Meijer} -""" - -from twisted.internet import protocol -from twisted.words.xish import domish, utility - -STREAM_CONNECTED_EVENT = intern("//event/stream/connected") -STREAM_START_EVENT = intern("//event/stream/start") -STREAM_END_EVENT = intern("//event/stream/end") -STREAM_ERROR_EVENT = intern("//event/stream/error") - -class XmlStream(protocol.Protocol, utility.EventDispatcher): - """ Generic Streaming XML protocol handler. - - This protocol handler will parse incoming data as XML and dispatch events - accordingly. Incoming stanzas can be handled by registering observers using - XPath-like expressions that are matched against each stanza. See - L{utility.EventDispatcher} for details. - """ - def __init__(self): - utility.EventDispatcher.__init__(self) - self.stream = None - self.rawDataOutFn = None - self.rawDataInFn = None - - def _initializeStream(self): - """ Sets up XML Parser. """ - self.stream = domish.elementStream() - self.stream.DocumentStartEvent = self.onDocumentStart - self.stream.ElementEvent = self.onElement - self.stream.DocumentEndEvent = self.onDocumentEnd - - ### -------------------------------------------------------------- - ### - ### Protocol events - ### - ### -------------------------------------------------------------- - - def connectionMade(self): - """ Called when a connection is made. - - Sets up the XML parser and dispatches the L{STREAM_CONNECTED_EVENT} - event indicating the connection has been established. - """ - self._initializeStream() - self.dispatch(self, STREAM_CONNECTED_EVENT) - - def dataReceived(self, data): - """ Called whenever data is received. - - Passes the data to the XML parser. This can result in calls to the - DOM handlers. If a parse error occurs, the L{STREAM_ERROR_EVENT} event - is called to allow for cleanup actions, followed by dropping the - connection. - """ - try: - if self.rawDataInFn: - self.rawDataInFn(data) - self.stream.parse(data) - except domish.ParserError: - self.dispatch(self, STREAM_ERROR_EVENT) - self.transport.loseConnection() - - def connectionLost(self, reason): - """ Called when the connection is shut down. - - Dispatches the L{STREAM_END_EVENT}. - """ - self.dispatch(self, STREAM_END_EVENT) - self.stream = None - - ### -------------------------------------------------------------- - ### - ### DOM events - ### - ### -------------------------------------------------------------- - - def onDocumentStart(self, rootElement): - """ Called whenever the start tag of a root element has been received. - - Dispatches the L{STREAM_START_EVENT}. - """ - self.dispatch(self, STREAM_START_EVENT) - - def onElement(self, element): - """ Called whenever a direct child element of the root element has - been received. - - Dispatches the received element. - """ - self.dispatch(element) - - def onDocumentEnd(self): - """ Called whenever the end tag of the root element has been received. - - Closes the connection. This causes C{connectionLost} being called. - """ - self.transport.loseConnection() - - def setDispatchFn(self, fn): - """ Set another function to handle elements. """ - self.stream.ElementEvent = fn - - def resetDispatchFn(self): - """ Set the default function (C{onElement}) to handle elements. """ - self.stream.ElementEvent = self.onElement - - def send(self, obj): - """ Send data over the stream. - - Sends the given C{obj} over the connection. C{obj} may be instances of - L{domish.Element}, L{unicode} and L{str}. The first two will be - properly serialized and/or encoded. L{str} objects must be in UTF-8 - encoding. - - Note: because it is easy to make mistakes in maintaining a properly - encoded L{str} object, it is advised to use L{unicode} objects - everywhere when dealing with XML Streams. - - @param obj: Object to be sent over the stream. - @type obj: L{domish.Element}, L{domish} or L{str} - - """ - if domish.IElement.providedBy(obj): - obj = obj.toXml() - - if isinstance(obj, unicode): - obj = obj.encode('utf-8') - - if self.rawDataOutFn: - self.rawDataOutFn(obj) - - self.transport.write(obj) - - -class XmlStreamFactoryMixin(object): - """ - XmlStream factory mixin that takes care of event handlers. - - To make sure certain event observers are set up before incoming data is - processed, you can set up bootstrap event observers using C{addBootstrap}. - - The C{event} and C{fn} parameters correspond with the C{event} and - C{observerfn} arguments to L{utility.EventDispatcher.addObserver}. - """ - - def __init__(self, *args, **kwargs): - self.bootstraps = [] - self.args = args - self.kwargs = kwargs - - def buildProtocol(self, addr): - """ - Create an instance of XmlStream. - - The returned instance will have bootstrap event observers registered - and will proceed to handle input on an incoming connection. - """ - xs = self.protocol(*self.args, **self.kwargs) - xs.factory = self - for event, fn in self.bootstraps: - xs.addObserver(event, fn) - return xs - - def addBootstrap(self, event, fn): - """ - Add a bootstrap event handler. - """ - self.bootstraps.append((event, fn)) - - def removeBootstrap(self, event, fn): - """ - Remove a bootstrap event handler. - """ - self.bootstraps.remove((event, fn)) - - -class XmlStreamFactory(XmlStreamFactoryMixin, - protocol.ReconnectingClientFactory): - """ - Factory for XmlStream protocol objects as a reconnection client. - """ - - protocol = XmlStream - - def buildProtocol(self, addr): - """ - Create a protocol instance. - - Overrides L{XmlStreamFactoryMixin.buildProtocol} to work with - a L{ReconnectingClientFactory}. As this is called upon having an - connection established, we are resetting the delay for reconnection - attempts when the connection is lost again. - """ - self.resetDelay() - return XmlStreamFactoryMixin.buildProtocol(self, addr) diff --git a/tools/buildbot/pylibs/twisted/words/xish/xpath.py b/tools/buildbot/pylibs/twisted/words/xish/xpath.py deleted file mode 100644 index 9505c38..0000000 --- a/tools/buildbot/pylibs/twisted/words/xish/xpath.py +++ /dev/null @@ -1,333 +0,0 @@ -# -*- test-case-name: twisted.words.test.test_xpath -*- -# -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -XPath query support. - -This module provides L{XPathQuery} to match -L{domish.Element} instances against -XPath-like expressions. -""" - -try: - import cStringIO as StringIO -except ImportError: - import StringIO - -class LiteralValue(str): - def value(self, elem): - return self - - -class IndexValue: - def __init__(self, index): - self.index = int(index) - 1 - - def value(self, elem): - return elem.children[self.index] - - -class AttribValue: - def __init__(self, attribname): - self.attribname = attribname - if self.attribname == "xmlns": - self.value = self.value_ns - - def value_ns(self, elem): - return elem.uri - - def value(self, elem): - if self.attribname in elem.attributes: - return elem.attributes[self.attribname] - else: - return None - - -class CompareValue: - def __init__(self, lhs, op, rhs): - self.lhs = lhs - self.rhs = rhs - if op == "=": - self.value = self._compareEqual - else: - self.value = self._compareNotEqual - - def _compareEqual(self, elem): - return self.lhs.value(elem) == self.rhs.value(elem) - - def _compareNotEqual(self, elem): - return self.lhs.value(elem) != self.rhs.value(elem) - - -class BooleanValue: - """ - Provide boolean XPath expression operators. - - @ivar lhs: Left hand side expression of the operator. - @ivar op: The operator. One of C{'and'}, C{'or'}. - @ivar rhs: Right hand side expression of the operator. - @ivar value: Reference to the method that will calculate the value of - this expression given an element. - """ - def __init__(self, lhs, op, rhs): - self.lhs = lhs - self.rhs = rhs - if op == "and": - self.value = self._booleanAnd - else: - self.value = self._booleanOr - - def _booleanAnd(self, elem): - """ - Calculate boolean and of the given expressions given an element. - - @param elem: The element to calculate the value of the expression from. - """ - return self.lhs.value(elem) and self.rhs.value(elem) - - def _booleanOr(self, elem): - """ - Calculate boolean or of the given expressions given an element. - - @param elem: The element to calculate the value of the expression from. - """ - return self.lhs.value(elem) or self.rhs.value(elem) - - -def Function(fname): - """ - Internal method which selects the function object - """ - klassname = "_%s_Function" % fname - c = globals()[klassname]() - return c - - -class _not_Function: - def __init__(self): - self.baseValue = None - - def setParams(self, baseValue): - self.baseValue = baseValue - - def value(self, elem): - return not self.baseValue.value(elem) - - -class _text_Function: - def setParams(self): - pass - - def value(self, elem): - return str(elem) - - -class _Location: - def __init__(self): - self.predicates = [] - self.elementName = None - self.childLocation = None - - def matchesPredicates(self, elem): - if self.elementName != None and self.elementName != elem.name: - return 0 - - for p in self.predicates: - if not p.value(elem): - return 0 - - return 1 - - def matches(self, elem): - if not self.matchesPredicates(elem): - return 0 - - if self.childLocation != None: - for c in elem.elements(): - if self.childLocation.matches(c): - return 1 - else: - return 1 - - return 0 - - def queryForString(self, elem, resultbuf): - if not self.matchesPredicates(elem): - return - - if self.childLocation != None: - for c in elem.elements(): - self.childLocation.queryForString(c, resultbuf) - else: - resultbuf.write(str(elem)) - - def queryForNodes(self, elem, resultlist): - if not self.matchesPredicates(elem): - return - - if self.childLocation != None: - for c in elem.elements(): - self.childLocation.queryForNodes(c, resultlist) - else: - resultlist.append(elem) - - def queryForStringList(self, elem, resultlist): - if not self.matchesPredicates(elem): - return - - if self.childLocation != None: - for c in elem.elements(): - self.childLocation.queryForStringList(c, resultlist) - else: - for c in elem.children: - if isinstance(c, (str, unicode)): - resultlist.append(c) - - -class _AnyLocation: - def __init__(self): - self.predicates = [] - self.elementName = None - self.childLocation = None - - def matchesPredicates(self, elem): - for p in self.predicates: - if not p.value(elem): - return 0 - return 1 - - def listParents(self, elem, parentlist): - if elem.parent != None: - self.listParents(elem.parent, parentlist) - parentlist.append(elem.name) - - def isRootMatch(self, elem): - if (self.elementName == None or self.elementName == elem.name) and \ - self.matchesPredicates(elem): - if self.childLocation != None: - for c in elem.elements(): - if self.childLocation.matches(c): - return True - else: - return True - return False - - def findFirstRootMatch(self, elem): - if (self.elementName == None or self.elementName == elem.name) and \ - self.matchesPredicates(elem): - # Thus far, the name matches and the predicates match, - # now check into the children and find the first one - # that matches the rest of the structure - # the rest of the structure - if self.childLocation != None: - for c in elem.elements(): - if self.childLocation.matches(c): - return c - return None - else: - # No children locations; this is a match! - return elem - else: - # Ok, predicates or name didn't match, so we need to start - # down each child and treat it as the root and try - # again - for c in elem.elements(): - if self.matches(c): - return c - # No children matched... - return None - - def matches(self, elem): - if self.isRootMatch(elem): - return True - else: - # Ok, initial element isn't an exact match, walk - # down each child and treat it as the root and try - # again - for c in elem.elements(): - if self.matches(c): - return True - # No children matched... - return False - - def queryForString(self, elem, resultbuf): - raise NotImplementedError( - "queryForString is not implemented for any location") - - def queryForNodes(self, elem, resultlist): - # First check to see if _this_ element is a root - if self.isRootMatch(elem): - resultlist.append(elem) - - # Now check each child - for c in elem.elements(): - self.queryForNodes(c, resultlist) - - - def queryForStringList(self, elem, resultlist): - if self.isRootMatch(elem): - for c in elem.children: - if isinstance(c, (str, unicode)): - resultlist.append(c) - for c in elem.elements(): - self.queryForStringList(c, resultlist) - - -class XPathQuery: - def __init__(self, queryStr): - self.queryStr = queryStr - from twisted.words.xish.xpathparser import parse - self.baseLocation = parse('XPATH', queryStr) - - def __hash__(self): - return self.queryStr.__hash__() - - def matches(self, elem): - return self.baseLocation.matches(elem) - - def queryForString(self, elem): - result = StringIO.StringIO() - self.baseLocation.queryForString(elem, result) - return result.getvalue() - - def queryForNodes(self, elem): - result = [] - self.baseLocation.queryForNodes(elem, result) - if len(result) == 0: - return None - else: - return result - - def queryForStringList(self, elem): - result = [] - self.baseLocation.queryForStringList(elem, result) - if len(result) == 0: - return None - else: - return result - - -__internedQueries = {} - -def internQuery(queryString): - if queryString not in __internedQueries: - __internedQueries[queryString] = XPathQuery(queryString) - return __internedQueries[queryString] - - -def matches(xpathstr, elem): - return internQuery(xpathstr).matches(elem) - - -def queryForStringList(xpathstr, elem): - return internQuery(xpathstr).queryForStringList(elem) - - -def queryForString(xpathstr, elem): - return internQuery(xpathstr).queryForString(elem) - - -def queryForNodes(xpathstr, elem): - return internQuery(xpathstr).queryForNodes(elem) diff --git a/tools/buildbot/pylibs/twisted/words/xish/xpathparser.g b/tools/buildbot/pylibs/twisted/words/xish/xpathparser.g deleted file mode 100644 index 4e51636..0000000 --- a/tools/buildbot/pylibs/twisted/words/xish/xpathparser.g +++ /dev/null @@ -1,375 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -# DO NOT EDIT xpathparser.py! -# -# It is generated from xpathparser.g using Yapps. Make needed changes there. -# This also means that the generated Python may not conform to Twisted's coding -# standards. - -# HOWTO Generate me: -# -# 1.) Grab a copy of yapps2, version 2.1.1: -# http://theory.stanford.edu/~amitp/Yapps/ -# -# Note: Do NOT use the package in debian/ubuntu as it has incompatible -# modifications. -# -# 2.) Generate the grammar: -# -# yapps2 xpathparser.g xpathparser.py.proto -# -# 3.) Edit the output to depend on the embedded runtime, not yappsrt. -# -# sed -e '/^import yapps/d' -e '/^[^#]/s/yappsrt\.//g' \ -# xpathparser.py.proto > xpathparser.py - -""" -XPath Parser. - -Besides the parser code produced by Yapps, this module also defines the -parse-time exception classes, a scanner class, a base class for parsers -produced by Yapps, and a context class that keeps track of the parse stack. -These have been copied from the Yapps runtime. -""" - -import sys, re - -class SyntaxError(Exception): - """When we run into an unexpected token, this is the exception to use""" - def __init__(self, charpos=-1, msg="Bad Token", context=None): - Exception.__init__(self) - self.charpos = charpos - self.msg = msg - self.context = context - - def __str__(self): - if self.charpos < 0: return 'SyntaxError' - else: return 'SyntaxError@char%s(%s)' % (repr(self.charpos), self.msg) - -class NoMoreTokens(Exception): - """Another exception object, for when we run out of tokens""" - pass - -class Scanner: - """Yapps scanner. - - The Yapps scanner can work in context sensitive or context - insensitive modes. The token(i) method is used to retrieve the - i-th token. It takes a restrict set that limits the set of tokens - it is allowed to return. In context sensitive mode, this restrict - set guides the scanner. In context insensitive mode, there is no - restriction (the set is always the full set of tokens). - - """ - - def __init__(self, patterns, ignore, input): - """Initialize the scanner. - - @param patterns: [(terminal, uncompiled regex), ...] or C{None} - @param ignore: [terminal,...] - @param input: string - - If patterns is C{None}, we assume that the subclass has defined - C{self.patterns} : [(terminal, compiled regex), ...]. Note that the - patterns parameter expects uncompiled regexes, whereas the - C{self.patterns} field expects compiled regexes. - """ - self.tokens = [] # [(begin char pos, end char pos, token name, matched text), ...] - self.restrictions = [] - self.input = input - self.pos = 0 - self.ignore = ignore - self.first_line_number = 1 - - if patterns is not None: - # Compile the regex strings into regex objects - self.patterns = [] - for terminal, regex in patterns: - self.patterns.append( (terminal, re.compile(regex)) ) - - def get_token_pos(self): - """Get the current token position in the input text.""" - return len(self.tokens) - - def get_char_pos(self): - """Get the current char position in the input text.""" - return self.pos - - def get_prev_char_pos(self, i=None): - """Get the previous position (one token back) in the input text.""" - if self.pos == 0: return 0 - if i is None: i = -1 - return self.tokens[i][0] - - def get_line_number(self): - """Get the line number of the current position in the input text.""" - # TODO: make this work at any token/char position - return self.first_line_number + self.get_input_scanned().count('\n') - - def get_column_number(self): - """Get the column number of the current position in the input text.""" - s = self.get_input_scanned() - i = s.rfind('\n') # may be -1, but that's okay in this case - return len(s) - (i+1) - - def get_input_scanned(self): - """Get the portion of the input that has been tokenized.""" - return self.input[:self.pos] - - def get_input_unscanned(self): - """Get the portion of the input that has not yet been tokenized.""" - return self.input[self.pos:] - - def token(self, i, restrict=None): - """Get the i'th token in the input. - - If C{i} is one past the end, then scan for another token. - - @param i: token index - - @param restrict: [token, ...] or C{None}; if restrict is - C{None}, then any token is allowed. You may call - token(i) more than once. However, the restrict set - may never be larger than what was passed in on the - first call to token(i). - """ - if i == len(self.tokens): - self.scan(restrict) - if i < len(self.tokens): - # Make sure the restriction is more restricted. This - # invariant is needed to avoid ruining tokenization at - # position i+1 and higher. - if restrict and self.restrictions[i]: - for r in restrict: - if r not in self.restrictions[i]: - raise NotImplementedError("Unimplemented: restriction set changed") - return self.tokens[i] - raise NoMoreTokens() - - def __repr__(self): - """Print the last 10 tokens that have been scanned in""" - output = '' - for t in self.tokens[-10:]: - output = '%s\n (@%s) %s = %s' % (output,t[0],t[2],repr(t[3])) - return output - - def scan(self, restrict): - """Should scan another token and add it to the list, self.tokens, - and add the restriction to self.restrictions""" - # Keep looking for a token, ignoring any in self.ignore - while 1: - # Search the patterns for the longest match, with earlier - # tokens in the list having preference - best_match = -1 - best_pat = '(error)' - for p, regexp in self.patterns: - # First check to see if we're ignoring this token - if restrict and p not in restrict and p not in self.ignore: - continue - m = regexp.match(self.input, self.pos) - if m and len(m.group(0)) > best_match: - # We got a match that's better than the previous one - best_pat = p - best_match = len(m.group(0)) - - # If we didn't find anything, raise an error - if best_pat == '(error)' and best_match < 0: - msg = 'Bad Token' - if restrict: - msg = 'Trying to find one of '+', '.join(restrict) - raise SyntaxError(self.pos, msg) - - # If we found something that isn't to be ignored, return it - if best_pat not in self.ignore: - # Create a token with this data - token = (self.pos, self.pos+best_match, best_pat, - self.input[self.pos:self.pos+best_match]) - self.pos = self.pos + best_match - # Only add this token if it's not in the list - # (to prevent looping) - if not self.tokens or token != self.tokens[-1]: - self.tokens.append(token) - self.restrictions.append(restrict) - return - else: - # This token should be ignored .. - self.pos = self.pos + best_match - -class Parser: - """Base class for Yapps-generated parsers. - - """ - - def __init__(self, scanner): - self._scanner = scanner - self._pos = 0 - - def _peek(self, *types): - """Returns the token type for lookahead; if there are any args - then the list of args is the set of token types to allow""" - tok = self._scanner.token(self._pos, types) - return tok[2] - - def _scan(self, type): - """Returns the matched text, and moves to the next token""" - tok = self._scanner.token(self._pos, [type]) - if tok[2] != type: - raise SyntaxError(tok[0], 'Trying to find '+type+' :'+ ' ,'.join(self._scanner.restrictions[self._pos])) - self._pos = 1 + self._pos - return tok[3] - -class Context: - """Class to represent the parser's call stack. - - Every rule creates a Context that links to its parent rule. The - contexts can be used for debugging. - - """ - - def __init__(self, parent, scanner, tokenpos, rule, args=()): - """Create a new context. - - @param parent: Context object or C{None} - @param scanner: Scanner object - @param tokenpos: scanner token position - @type tokenpos: L{int} - @param rule: name of the rule - @type rule: L{str} - @param args: tuple listing parameters to the rule - - """ - self.parent = parent - self.scanner = scanner - self.tokenpos = tokenpos - self.rule = rule - self.args = args - - def __str__(self): - output = '' - if self.parent: output = str(self.parent) + ' > ' - output += self.rule - return output - -def print_line_with_pointer(text, p): - """Print the line of 'text' that includes position 'p', - along with a second line with a single caret (^) at position p""" - - # TODO: separate out the logic for determining the line/character - # location from the logic for determining how to display an - # 80-column line to stderr. - - # Now try printing part of the line - text = text[max(p-80, 0):p+80] - p = p - max(p-80, 0) - - # Strip to the left - i = text[:p].rfind('\n') - j = text[:p].rfind('\r') - if i < 0 or (0 <= j < i): i = j - if 0 <= i < p: - p = p - i - 1 - text = text[i+1:] - - # Strip to the right - i = text.find('\n', p) - j = text.find('\r', p) - if i < 0 or (0 <= j < i): i = j - if i >= 0: - text = text[:i] - - # Now shorten the text - while len(text) > 70 and p > 60: - # Cut off 10 chars - text = "..." + text[10:] - p = p - 7 - - # Now print the string, along with an indicator - print >>sys.stderr, '> ',text - print >>sys.stderr, '> ',' '*p + '^' - -def print_error(input, err, scanner): - """Print error messages, the parser stack, and the input text -- for human-readable error messages.""" - # NOTE: this function assumes 80 columns :-( - # Figure out the line number - line_number = scanner.get_line_number() - column_number = scanner.get_column_number() - print >>sys.stderr, '%d:%d: %s' % (line_number, column_number, err.msg) - - context = err.context - if not context: - print_line_with_pointer(input, err.charpos) - - while context: - # TODO: add line number - print >>sys.stderr, 'while parsing %s%s:' % (context.rule, tuple(context.args)) - print_line_with_pointer(input, context.scanner.get_prev_char_pos(context.tokenpos)) - context = context.parent - -def wrap_error_reporter(parser, rule): - try: - return getattr(parser, rule)() - except SyntaxError, e: - input = parser._scanner.input - print_error(input, e, parser._scanner) - except NoMoreTokens: - print >>sys.stderr, 'Could not complete parsing; stopped around here:' - print >>sys.stderr, parser._scanner - - -from twisted.words.xish.xpath import AttribValue, BooleanValue, CompareValue -from twisted.words.xish.xpath import Function, IndexValue, LiteralValue -from twisted.words.xish.xpath import _AnyLocation, _Location - -%% -parser XPathParser: - ignore: "\\s+" - token INDEX: "[0-9]+" - token WILDCARD: "\*" - token IDENTIFIER: "[a-zA-Z][a-zA-Z0-9_\-]*" - token ATTRIBUTE: "\@[a-zA-Z][a-zA-Z0-9_\-]*" - token FUNCNAME: "[a-zA-Z][a-zA-Z0-9_]*" - token CMP_EQ: "\=" - token CMP_NE: "\!\=" - token STR_DQ: '"([^"]|(\\"))*?"' - token STR_SQ: "'([^']|(\\'))*?'" - token OP_AND: "and" - token OP_OR: "or" - token END: "$" - - rule XPATH: PATH {{ result = PATH; current = result }} - ( PATH {{ current.childLocation = PATH; current = current.childLocation }} ) * END - {{ return result }} - - rule PATH: ("/" {{ result = _Location() }} | "//" {{ result = _AnyLocation() }} ) - ( IDENTIFIER {{ result.elementName = IDENTIFIER }} | WILDCARD {{ result.elementName = None }} ) - ( "\[" PREDICATE {{ result.predicates.append(PREDICATE) }} "\]")* - {{ return result }} - - rule PREDICATE: EXPR {{ return EXPR }} | - INDEX {{ return IndexValue(INDEX) }} - - rule EXPR: FACTOR {{ e = FACTOR }} - ( BOOLOP FACTOR {{ e = BooleanValue(e, BOOLOP, FACTOR) }} )* - {{ return e }} - - rule BOOLOP: ( OP_AND {{ return OP_AND }} | OP_OR {{ return OP_OR }} ) - - rule FACTOR: TERM {{ return TERM }} - | "\(" EXPR "\)" {{ return EXPR }} - - rule TERM: VALUE {{ t = VALUE }} - [ CMP VALUE {{ t = CompareValue(t, CMP, VALUE) }} ] - {{ return t }} - - rule VALUE: "@" IDENTIFIER {{ return AttribValue(IDENTIFIER) }} | - FUNCNAME {{ f = Function(FUNCNAME); args = [] }} - "\(" [ VALUE {{ args.append(VALUE) }} - ( - "," VALUE {{ args.append(VALUE) }} - )* - ] "\)" {{ f.setParams(*args); return f }} | - STR {{ return LiteralValue(STR[1:len(STR)-1]) }} - - rule CMP: (CMP_EQ {{ return CMP_EQ }} | CMP_NE {{ return CMP_NE }}) - rule STR: (STR_DQ {{ return STR_DQ }} | STR_SQ {{ return STR_SQ }}) diff --git a/tools/buildbot/pylibs/twisted/words/xish/xpathparser.py b/tools/buildbot/pylibs/twisted/words/xish/xpathparser.py deleted file mode 100644 index c6b235c..0000000 --- a/tools/buildbot/pylibs/twisted/words/xish/xpathparser.py +++ /dev/null @@ -1,508 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -# DO NOT EDIT xpathparser.py! -# -# It is generated from xpathparser.g using Yapps. Make needed changes there. -# This also means that the generated Python may not conform to Twisted's coding -# standards. - -# HOWTO Generate me: -# -# 1.) Grab a copy of yapps2, version 2.1.1: -# http://theory.stanford.edu/~amitp/Yapps/ -# -# Note: Do NOT use the package in debian/ubuntu as it has incompatible -# modifications. -# -# 2.) Generate the grammar: -# -# yapps2 xpathparser.g xpathparser.py.proto -# -# 3.) Edit the output to depend on the embedded runtime, not yappsrt. -# -# sed -e '/^import yapps/d' -e '/^[^#]/s/yappsrt\.//g' \ -# xpathparser.py.proto > xpathparser.py - -""" -XPath Parser. - -Besides the parser code produced by Yapps, this module also defines the -parse-time exception classes, a scanner class, a base class for parsers -produced by Yapps, and a context class that keeps track of the parse stack. -These have been copied from the Yapps runtime. -""" - -import sys, re - -class SyntaxError(Exception): - """When we run into an unexpected token, this is the exception to use""" - def __init__(self, charpos=-1, msg="Bad Token", context=None): - Exception.__init__(self) - self.charpos = charpos - self.msg = msg - self.context = context - - def __str__(self): - if self.charpos < 0: return 'SyntaxError' - else: return 'SyntaxError@char%s(%s)' % (repr(self.charpos), self.msg) - -class NoMoreTokens(Exception): - """Another exception object, for when we run out of tokens""" - pass - -class Scanner: - """Yapps scanner. - - The Yapps scanner can work in context sensitive or context - insensitive modes. The token(i) method is used to retrieve the - i-th token. It takes a restrict set that limits the set of tokens - it is allowed to return. In context sensitive mode, this restrict - set guides the scanner. In context insensitive mode, there is no - restriction (the set is always the full set of tokens). - - """ - - def __init__(self, patterns, ignore, input): - """Initialize the scanner. - - @param patterns: [(terminal, uncompiled regex), ...] or C{None} - @param ignore: [terminal,...] - @param input: string - - If patterns is C{None}, we assume that the subclass has defined - C{self.patterns} : [(terminal, compiled regex), ...]. Note that the - patterns parameter expects uncompiled regexes, whereas the - C{self.patterns} field expects compiled regexes. - """ - self.tokens = [] # [(begin char pos, end char pos, token name, matched text), ...] - self.restrictions = [] - self.input = input - self.pos = 0 - self.ignore = ignore - self.first_line_number = 1 - - if patterns is not None: - # Compile the regex strings into regex objects - self.patterns = [] - for terminal, regex in patterns: - self.patterns.append( (terminal, re.compile(regex)) ) - - def get_token_pos(self): - """Get the current token position in the input text.""" - return len(self.tokens) - - def get_char_pos(self): - """Get the current char position in the input text.""" - return self.pos - - def get_prev_char_pos(self, i=None): - """Get the previous position (one token back) in the input text.""" - if self.pos == 0: return 0 - if i is None: i = -1 - return self.tokens[i][0] - - def get_line_number(self): - """Get the line number of the current position in the input text.""" - # TODO: make this work at any token/char position - return self.first_line_number + self.get_input_scanned().count('\n') - - def get_column_number(self): - """Get the column number of the current position in the input text.""" - s = self.get_input_scanned() - i = s.rfind('\n') # may be -1, but that's okay in this case - return len(s) - (i+1) - - def get_input_scanned(self): - """Get the portion of the input that has been tokenized.""" - return self.input[:self.pos] - - def get_input_unscanned(self): - """Get the portion of the input that has not yet been tokenized.""" - return self.input[self.pos:] - - def token(self, i, restrict=None): - """Get the i'th token in the input. - - If C{i} is one past the end, then scan for another token. - - @param i: token index - - @param restrict: [token, ...] or C{None}; if restrict is - C{None}, then any token is allowed. You may call - token(i) more than once. However, the restrict set - may never be larger than what was passed in on the - first call to token(i). - """ - if i == len(self.tokens): - self.scan(restrict) - if i < len(self.tokens): - # Make sure the restriction is more restricted. This - # invariant is needed to avoid ruining tokenization at - # position i+1 and higher. - if restrict and self.restrictions[i]: - for r in restrict: - if r not in self.restrictions[i]: - raise NotImplementedError("Unimplemented: restriction set changed") - return self.tokens[i] - raise NoMoreTokens() - - def __repr__(self): - """Print the last 10 tokens that have been scanned in""" - output = '' - for t in self.tokens[-10:]: - output = '%s\n (@%s) %s = %s' % (output,t[0],t[2],repr(t[3])) - return output - - def scan(self, restrict): - """Should scan another token and add it to the list, self.tokens, - and add the restriction to self.restrictions""" - # Keep looking for a token, ignoring any in self.ignore - while 1: - # Search the patterns for the longest match, with earlier - # tokens in the list having preference - best_match = -1 - best_pat = '(error)' - for p, regexp in self.patterns: - # First check to see if we're ignoring this token - if restrict and p not in restrict and p not in self.ignore: - continue - m = regexp.match(self.input, self.pos) - if m and len(m.group(0)) > best_match: - # We got a match that's better than the previous one - best_pat = p - best_match = len(m.group(0)) - - # If we didn't find anything, raise an error - if best_pat == '(error)' and best_match < 0: - msg = 'Bad Token' - if restrict: - msg = 'Trying to find one of '+', '.join(restrict) - raise SyntaxError(self.pos, msg) - - # If we found something that isn't to be ignored, return it - if best_pat not in self.ignore: - # Create a token with this data - token = (self.pos, self.pos+best_match, best_pat, - self.input[self.pos:self.pos+best_match]) - self.pos = self.pos + best_match - # Only add this token if it's not in the list - # (to prevent looping) - if not self.tokens or token != self.tokens[-1]: - self.tokens.append(token) - self.restrictions.append(restrict) - return - else: - # This token should be ignored .. - self.pos = self.pos + best_match - -class Parser: - """Base class for Yapps-generated parsers. - - """ - - def __init__(self, scanner): - self._scanner = scanner - self._pos = 0 - - def _peek(self, *types): - """Returns the token type for lookahead; if there are any args - then the list of args is the set of token types to allow""" - tok = self._scanner.token(self._pos, types) - return tok[2] - - def _scan(self, type): - """Returns the matched text, and moves to the next token""" - tok = self._scanner.token(self._pos, [type]) - if tok[2] != type: - raise SyntaxError(tok[0], 'Trying to find '+type+' :'+ ' ,'.join(self._scanner.restrictions[self._pos])) - self._pos = 1 + self._pos - return tok[3] - -class Context: - """Class to represent the parser's call stack. - - Every rule creates a Context that links to its parent rule. The - contexts can be used for debugging. - - """ - - def __init__(self, parent, scanner, tokenpos, rule, args=()): - """Create a new context. - - @param parent: Context object or C{None} - @param scanner: Scanner object - @param tokenpos: scanner token position - @type tokenpos: L{int} - @param rule: name of the rule - @type rule: L{str} - @param args: tuple listing parameters to the rule - - """ - self.parent = parent - self.scanner = scanner - self.tokenpos = tokenpos - self.rule = rule - self.args = args - - def __str__(self): - output = '' - if self.parent: output = str(self.parent) + ' > ' - output += self.rule - return output - -def print_line_with_pointer(text, p): - """Print the line of 'text' that includes position 'p', - along with a second line with a single caret (^) at position p""" - - # TODO: separate out the logic for determining the line/character - # location from the logic for determining how to display an - # 80-column line to stderr. - - # Now try printing part of the line - text = text[max(p-80, 0):p+80] - p = p - max(p-80, 0) - - # Strip to the left - i = text[:p].rfind('\n') - j = text[:p].rfind('\r') - if i < 0 or (0 <= j < i): i = j - if 0 <= i < p: - p = p - i - 1 - text = text[i+1:] - - # Strip to the right - i = text.find('\n', p) - j = text.find('\r', p) - if i < 0 or (0 <= j < i): i = j - if i >= 0: - text = text[:i] - - # Now shorten the text - while len(text) > 70 and p > 60: - # Cut off 10 chars - text = "..." + text[10:] - p = p - 7 - - # Now print the string, along with an indicator - print >>sys.stderr, '> ',text - print >>sys.stderr, '> ',' '*p + '^' - -def print_error(input, err, scanner): - """Print error messages, the parser stack, and the input text -- for human-readable error messages.""" - # NOTE: this function assumes 80 columns :-( - # Figure out the line number - line_number = scanner.get_line_number() - column_number = scanner.get_column_number() - print >>sys.stderr, '%d:%d: %s' % (line_number, column_number, err.msg) - - context = err.context - if not context: - print_line_with_pointer(input, err.charpos) - - while context: - # TODO: add line number - print >>sys.stderr, 'while parsing %s%s:' % (context.rule, tuple(context.args)) - print_line_with_pointer(input, context.scanner.get_prev_char_pos(context.tokenpos)) - context = context.parent - -def wrap_error_reporter(parser, rule): - try: - return getattr(parser, rule)() - except SyntaxError, e: - input = parser._scanner.input - print_error(input, e, parser._scanner) - except NoMoreTokens: - print >>sys.stderr, 'Could not complete parsing; stopped around here:' - print >>sys.stderr, parser._scanner - - -from twisted.words.xish.xpath import AttribValue, BooleanValue, CompareValue -from twisted.words.xish.xpath import Function, IndexValue, LiteralValue -from twisted.words.xish.xpath import _AnyLocation, _Location - - -# Begin -- grammar generated by Yapps -import sys, re - -class XPathParserScanner(Scanner): - patterns = [ - ('","', re.compile(',')), - ('"@"', re.compile('@')), - ('"\\)"', re.compile('\\)')), - ('"\\("', re.compile('\\(')), - ('"\\]"', re.compile('\\]')), - ('"\\["', re.compile('\\[')), - ('"//"', re.compile('//')), - ('"/"', re.compile('/')), - ('\\s+', re.compile('\\s+')), - ('INDEX', re.compile('[0-9]+')), - ('WILDCARD', re.compile('\\*')), - ('IDENTIFIER', re.compile('[a-zA-Z][a-zA-Z0-9_\\-]*')), - ('ATTRIBUTE', re.compile('\\@[a-zA-Z][a-zA-Z0-9_\\-]*')), - ('FUNCNAME', re.compile('[a-zA-Z][a-zA-Z0-9_]*')), - ('CMP_EQ', re.compile('\\=')), - ('CMP_NE', re.compile('\\!\\=')), - ('STR_DQ', re.compile('"([^"]|(\\"))*?"')), - ('STR_SQ', re.compile("'([^']|(\\'))*?'")), - ('OP_AND', re.compile('and')), - ('OP_OR', re.compile('or')), - ('END', re.compile('$')), - ] - def __init__(self, str): - Scanner.__init__(self,None,['\\s+'],str) - -class XPathParser(Parser): - Context = Context - def XPATH(self, _parent=None): - _context = self.Context(_parent, self._scanner, self._pos, 'XPATH', []) - PATH = self.PATH(_context) - result = PATH; current = result - while self._peek('END', '"/"', '"//"') != 'END': - PATH = self.PATH(_context) - current.childLocation = PATH; current = current.childLocation - if self._peek() not in ['END', '"/"', '"//"']: - raise SyntaxError(charpos=self._scanner.get_prev_char_pos(), context=_context, msg='Need one of ' + ', '.join(['END', '"/"', '"//"'])) - END = self._scan('END') - return result - - def PATH(self, _parent=None): - _context = self.Context(_parent, self._scanner, self._pos, 'PATH', []) - _token = self._peek('"/"', '"//"') - if _token == '"/"': - self._scan('"/"') - result = _Location() - else: # == '"//"' - self._scan('"//"') - result = _AnyLocation() - _token = self._peek('IDENTIFIER', 'WILDCARD') - if _token == 'IDENTIFIER': - IDENTIFIER = self._scan('IDENTIFIER') - result.elementName = IDENTIFIER - else: # == 'WILDCARD' - WILDCARD = self._scan('WILDCARD') - result.elementName = None - while self._peek('"\\["', 'END', '"/"', '"//"') == '"\\["': - self._scan('"\\["') - PREDICATE = self.PREDICATE(_context) - result.predicates.append(PREDICATE) - self._scan('"\\]"') - if self._peek() not in ['"\\["', 'END', '"/"', '"//"']: - raise SyntaxError(charpos=self._scanner.get_prev_char_pos(), context=_context, msg='Need one of ' + ', '.join(['"\\["', 'END', '"/"', '"//"'])) - return result - - def PREDICATE(self, _parent=None): - _context = self.Context(_parent, self._scanner, self._pos, 'PREDICATE', []) - _token = self._peek('INDEX', '"\\("', '"@"', 'FUNCNAME', 'STR_DQ', 'STR_SQ') - if _token != 'INDEX': - EXPR = self.EXPR(_context) - return EXPR - else: # == 'INDEX' - INDEX = self._scan('INDEX') - return IndexValue(INDEX) - - def EXPR(self, _parent=None): - _context = self.Context(_parent, self._scanner, self._pos, 'EXPR', []) - FACTOR = self.FACTOR(_context) - e = FACTOR - while self._peek('OP_AND', 'OP_OR', '"\\)"', '"\\]"') in ['OP_AND', 'OP_OR']: - BOOLOP = self.BOOLOP(_context) - FACTOR = self.FACTOR(_context) - e = BooleanValue(e, BOOLOP, FACTOR) - if self._peek() not in ['OP_AND', 'OP_OR', '"\\)"', '"\\]"']: - raise SyntaxError(charpos=self._scanner.get_prev_char_pos(), context=_context, msg='Need one of ' + ', '.join(['OP_AND', 'OP_OR', '"\\)"', '"\\]"'])) - return e - - def BOOLOP(self, _parent=None): - _context = self.Context(_parent, self._scanner, self._pos, 'BOOLOP', []) - _token = self._peek('OP_AND', 'OP_OR') - if _token == 'OP_AND': - OP_AND = self._scan('OP_AND') - return OP_AND - else: # == 'OP_OR' - OP_OR = self._scan('OP_OR') - return OP_OR - - def FACTOR(self, _parent=None): - _context = self.Context(_parent, self._scanner, self._pos, 'FACTOR', []) - _token = self._peek('"\\("', '"@"', 'FUNCNAME', 'STR_DQ', 'STR_SQ') - if _token != '"\\("': - TERM = self.TERM(_context) - return TERM - else: # == '"\\("' - self._scan('"\\("') - EXPR = self.EXPR(_context) - self._scan('"\\)"') - return EXPR - - def TERM(self, _parent=None): - _context = self.Context(_parent, self._scanner, self._pos, 'TERM', []) - VALUE = self.VALUE(_context) - t = VALUE - if self._peek('CMP_EQ', 'CMP_NE', 'OP_AND', 'OP_OR', '"\\)"', '"\\]"') in ['CMP_EQ', 'CMP_NE']: - CMP = self.CMP(_context) - VALUE = self.VALUE(_context) - t = CompareValue(t, CMP, VALUE) - return t - - def VALUE(self, _parent=None): - _context = self.Context(_parent, self._scanner, self._pos, 'VALUE', []) - _token = self._peek('"@"', 'FUNCNAME', 'STR_DQ', 'STR_SQ') - if _token == '"@"': - self._scan('"@"') - IDENTIFIER = self._scan('IDENTIFIER') - return AttribValue(IDENTIFIER) - elif _token == 'FUNCNAME': - FUNCNAME = self._scan('FUNCNAME') - f = Function(FUNCNAME); args = [] - self._scan('"\\("') - if self._peek('"\\)"', '"@"', 'FUNCNAME', '","', 'STR_DQ', 'STR_SQ') not in ['"\\)"', '","']: - VALUE = self.VALUE(_context) - args.append(VALUE) - while self._peek('","', '"\\)"') == '","': - self._scan('","') - VALUE = self.VALUE(_context) - args.append(VALUE) - if self._peek() not in ['","', '"\\)"']: - raise SyntaxError(charpos=self._scanner.get_prev_char_pos(), context=_context, msg='Need one of ' + ', '.join(['","', '"\\)"'])) - self._scan('"\\)"') - f.setParams(*args); return f - else: # in ['STR_DQ', 'STR_SQ'] - STR = self.STR(_context) - return LiteralValue(STR[1:len(STR)-1]) - - def CMP(self, _parent=None): - _context = self.Context(_parent, self._scanner, self._pos, 'CMP', []) - _token = self._peek('CMP_EQ', 'CMP_NE') - if _token == 'CMP_EQ': - CMP_EQ = self._scan('CMP_EQ') - return CMP_EQ - else: # == 'CMP_NE' - CMP_NE = self._scan('CMP_NE') - return CMP_NE - - def STR(self, _parent=None): - _context = self.Context(_parent, self._scanner, self._pos, 'STR', []) - _token = self._peek('STR_DQ', 'STR_SQ') - if _token == 'STR_DQ': - STR_DQ = self._scan('STR_DQ') - return STR_DQ - else: # == 'STR_SQ' - STR_SQ = self._scan('STR_SQ') - return STR_SQ - - -def parse(rule, text): - P = XPathParser(XPathParserScanner(text)) - return wrap_error_reporter(P, rule) - -if __name__ == '__main__': - from sys import argv, stdin - if len(argv) >= 2: - if len(argv) >= 3: - f = open(argv[2],'r') - else: - f = stdin - print parse(argv[1], f.read()) - else: print >>sys.stderr, 'Args: []' -# End -- grammar generated by Yapps diff --git a/tools/buildbot/pylibs/zope/PUBLICATION.cfg b/tools/buildbot/pylibs/zope/PUBLICATION.cfg deleted file mode 100644 index 1a15149..0000000 --- a/tools/buildbot/pylibs/zope/PUBLICATION.cfg +++ /dev/null @@ -1,9 +0,0 @@ -Metadata-Version: 1.0 -Name: zope -Summary: Zope Project Container Package -Author: Zope Corporation and Contributors -Author-email: zope3-dev@zope.org -License: ZPL 2.1 -Description: - This is a pure container package intended to hold code from - the Zope 3 project. diff --git a/tools/buildbot/pylibs/zope/README.google b/tools/buildbot/pylibs/zope/README.google deleted file mode 100644 index f3cd68ed..0000000 --- a/tools/buildbot/pylibs/zope/README.google +++ /dev/null @@ -1,7 +0,0 @@ -URL: http://www.zope.org/Products/Zope3/ -Version: 3.3.1 -License: Zope Public License, Version 2.1 (ZPL) - -Local Modifications: -Only kept zope.exceptions-Zope-3.x, zope.interface-Zope-3.x and -zope.testing-Zope-3.x. diff --git a/tools/buildbot/pylibs/zope/README.txt b/tools/buildbot/pylibs/zope/README.txt deleted file mode 100644 index 1a0553d..0000000 --- a/tools/buildbot/pylibs/zope/README.txt +++ /dev/null @@ -1,18 +0,0 @@ -===================== -Zope Project Packages -===================== - -The ``zope`` package is a pure namespace package holding packages -developed as part of the Zope 3 project. - -Generally, the immediate subpackages of the ``zope`` package should be -useful and usable outside of the Zope application server. Subpackages -of the ``zope`` package should have minimal interdependencies, -although most depend on ``zope.interface``. - -The one subpackage that's not usable outside the application server is -the ``app`` subpackage, ``zope.app``, which *is* the application -server. Sub-packages of ``zope.app`` are not usable outside of the -application server. If there's something in ``zope.app`` you want to -use elsewhere, let us know and we can talk about abstracting some of -it up out of ``zope.app``. diff --git a/tools/buildbot/pylibs/zope/__init__.py b/tools/buildbot/pylibs/zope/__init__.py deleted file mode 100644 index c0ea74d..0000000 --- a/tools/buildbot/pylibs/zope/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -############################################################################## -# -# Copyright (c) 2004 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -# -# This file is necessary to make this directory a package. - -try: - # Declare this a namespace package if pkg_resources is available. - import pkg_resources - pkg_resources.declare_namespace('zope') -except ImportError: - pass diff --git a/tools/buildbot/pylibs/zope/exceptions/DEPENDENCIES.cfg b/tools/buildbot/pylibs/zope/exceptions/DEPENDENCIES.cfg deleted file mode 100644 index 0ca105a..0000000 --- a/tools/buildbot/pylibs/zope/exceptions/DEPENDENCIES.cfg +++ /dev/null @@ -1,2 +0,0 @@ -zope.interface -zope.testing diff --git a/tools/buildbot/pylibs/zope/exceptions/__init__.py b/tools/buildbot/pylibs/zope/exceptions/__init__.py deleted file mode 100644 index 01b3562..0000000 --- a/tools/buildbot/pylibs/zope/exceptions/__init__.py +++ /dev/null @@ -1,34 +0,0 @@ -############################################################################## -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""General exceptions that wish they were standard exceptions - -These exceptions are so general purpose that they don't belong in Zope -application-specific packages. - -$Id: __init__.py 67636 2006-04-27 11:31:54Z srichter $ -""" -from zope.exceptions.interfaces import DuplicationError, IDuplicationError -from zope.exceptions.interfaces import UserError, IUserError - -# avoid dependency on zope.security: -try: - import zope.security -except ImportError, v: - # "ImportError: No module named security" - if not str(v).endswith(' security'): - raise -else: - from zope.security.interfaces import IUnauthorized, Unauthorized - from zope.security.interfaces import IForbidden, IForbiddenAttribute - from zope.security.interfaces import Forbidden, ForbiddenAttribute diff --git a/tools/buildbot/pylibs/zope/exceptions/exceptionformatter.py b/tools/buildbot/pylibs/zope/exceptions/exceptionformatter.py deleted file mode 100644 index 7bc14cd..0000000 --- a/tools/buildbot/pylibs/zope/exceptions/exceptionformatter.py +++ /dev/null @@ -1,240 +0,0 @@ -############################################################################## -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""An exception formatter that shows traceback supplements and traceback info, -optionally in HTML. - -$Id: exceptionformatter.py 68429 2006-06-01 10:54:18Z mgedmin $ -""" -import sys -import cgi -import linecache -import traceback - -DEBUG_EXCEPTION_FORMATTER = 1 - -class TextExceptionFormatter(object): - - line_sep = '\n' - show_revisions = 0 - - def __init__(self, limit=None, with_filenames=False): - self.limit = limit - self.with_filenames = with_filenames - - def escape(self, s): - return s - - def getPrefix(self): - return 'Traceback (most recent call last):' - - def getLimit(self): - limit = self.limit - if limit is None: - limit = getattr(sys, 'tracebacklimit', 200) - return limit - - def formatSupplementLine(self, line): - return ' - %s' % line - - def formatSourceURL(self, url): - return [self.formatSupplementLine(url)] - - def formatSupplement(self, supplement, tb): - result = [] - fmtLine = self.formatSupplementLine - - url = getattr(supplement, 'source_url', None) - if url is not None: - result.extend(self.formatSourceURL(url)) - - line = getattr(supplement, 'line', 0) - if line == -1: - line = tb.tb_lineno - col = getattr(supplement, 'column', -1) - if line: - if col is not None and col >= 0: - result.append(fmtLine('Line %s, Column %s' % ( - line, col))) - else: - result.append(fmtLine('Line %s' % line)) - elif col is not None and col >= 0: - result.append(fmtLine('Column %s' % col)) - - expr = getattr(supplement, 'expression', None) - if expr: - result.append(fmtLine('Expression: %s' % expr)) - - warnings = getattr(supplement, 'warnings', None) - if warnings: - for warning in warnings: - result.append(fmtLine('Warning: %s' % warning)) - - getInfo = getattr(supplement, 'getInfo', None) - if getInfo is not None: - try: - extra = getInfo() - if extra: - extra = self.escape(extra) - if self.line_sep != "\n": - extra = extra.replace(" ", " ") - extra = extra.replace("\n", self.line_sep) - result.append(extra) - except: - if DEBUG_EXCEPTION_FORMATTER: - import traceback - traceback.print_exc() - # else just swallow the exception. - return result - - def formatTracebackInfo(self, tbi): - return self.formatSupplementLine('__traceback_info__: %s' % (tbi, )) - - def formatLine(self, tb): - f = tb.tb_frame - lineno = tb.tb_lineno - co = f.f_code - filename = co.co_filename - name = co.co_name - locals = f.f_locals - globals = f.f_globals - - if self.with_filenames: - s = ' File "%s", line %d' % (filename, lineno) - else: - modname = globals.get('__name__', filename) - s = ' Module %s, line %d' % (modname, lineno) - - s = s + ', in %s' % name - - result = [] - result.append(self.escape(s)) - - # Append the source line, if available - line = linecache.getline(filename, lineno) - if line: - result.append(" " + self.escape(line.strip())) - - # Output a traceback supplement, if any. - if '__traceback_supplement__' in locals: - # Use the supplement defined in the function. - tbs = locals['__traceback_supplement__'] - elif '__traceback_supplement__' in globals: - # Use the supplement defined in the module. - # This is used by Scripts (Python). - tbs = globals['__traceback_supplement__'] - else: - tbs = None - if tbs is not None: - factory = tbs[0] - args = tbs[1:] - try: - supp = factory(*args) - result.extend(self.formatSupplement(supp, tb)) - except: - if DEBUG_EXCEPTION_FORMATTER: - traceback.print_exc() - # else just swallow the exception. - - try: - tbi = locals.get('__traceback_info__', None) - if tbi is not None: - result.append(self.formatTracebackInfo(tbi)) - except: - if DEBUG_EXCEPTION_FORMATTER: - traceback.print_exc() - # else just swallow the exception. - - return self.line_sep.join(result) - - def formatExceptionOnly(self, etype, value): - result = ''.join(traceback.format_exception_only(etype, value)) - return result.replace('\n', self.line_sep) - - def formatLastLine(self, exc_line): - return self.escape(exc_line) - - def formatException(self, etype, value, tb): - # The next line provides a way to detect recursion. - __exception_formatter__ = 1 - result = [self.getPrefix() + '\n'] - limit = self.getLimit() - n = 0 - while tb is not None and (limit is None or n < limit): - if tb.tb_frame.f_locals.get('__exception_formatter__'): - # Stop recursion. - result.append('(Recursive formatException() stopped)\n') - break - line = self.formatLine(tb) - result.append(line + '\n') - tb = tb.tb_next - n = n + 1 - exc_line = self.formatExceptionOnly(etype, value) - result.append(self.formatLastLine(exc_line)) - return result - - -class HTMLExceptionFormatter(TextExceptionFormatter): - - line_sep = '
                    \r\n' - - def escape(self, s): - return cgi.escape(s) - - def getPrefix(self): - return '

                    Traceback (most recent call last):\r\n

                      ' - - def formatSupplementLine(self, line): - return '%s' % self.escape(str(line)) - - def formatTracebackInfo(self, tbi): - s = self.escape(str(tbi)) - s = s.replace('\n', self.line_sep) - return '__traceback_info__: %s' % (s, ) - - def formatLine(self, tb): - line = TextExceptionFormatter.formatLine(self, tb) - return '
                    • %s
                    • ' % line - - def formatLastLine(self, exc_line): - return '
                    %s

                    ' % self.escape(exc_line) - - -def format_exception(t, v, tb, limit=None, as_html=False, - with_filenames=False): - """Format a stack trace and the exception information. - - Similar to 'traceback.format_exception', but adds supplemental - information to the traceback and accepts two options, 'as_html' - and 'with_filenames'. - """ - if as_html: - fmt = HTMLExceptionFormatter(limit, with_filenames) - else: - fmt = TextExceptionFormatter(limit, with_filenames) - return fmt.formatException(t, v, tb) - - -def print_exception(t, v, tb, limit=None, file=None, as_html=False, - with_filenames=True): - """Print exception up to 'limit' stack trace entries from 'tb' to 'file'. - - Similar to 'traceback.print_exception', but adds supplemental - information to the traceback and accepts two options, 'as_html' - and 'with_filenames'. - """ - if file is None: - file = sys.stderr - lines = format_exception(t, v, tb, limit, as_html, with_filenames) - for line in lines: - file.write(line) diff --git a/tools/buildbot/pylibs/zope/exceptions/interfaces.py b/tools/buildbot/pylibs/zope/exceptions/interfaces.py deleted file mode 100644 index f4278a3..0000000 --- a/tools/buildbot/pylibs/zope/exceptions/interfaces.py +++ /dev/null @@ -1,114 +0,0 @@ -############################################################################## -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""ITracebackSupplement interface definition. - -$Id: interfaces.py 67630 2006-04-27 00:54:03Z jim $ - -When zope.exceptionformatter generates a traceback, it looks for local -variables named __traceback_info__ or __traceback_supplement__. It -includes the information provided by those local variables in the -traceback. - -__traceback_info__ is for arbitrary information. -repr(__traceback_info__) gets dumped to the traceback. - -__traceback_supplement__ is more structured. It should be a tuple. -The first item of the tuple is a callable that produces an object that -implements ITracebackSupplement, and the rest of the tuple contains -arguments to pass to the factory. The traceback formatter makes an -effort to clearly present the information provided by the -ITracebackSupplement. -""" -from zope.interface import Interface, Attribute, implements - -class IDuplicationError(Interface): - pass - -class DuplicationError(Exception): - """A duplicate registration was attempted""" - implements(IDuplicationError) - -class IUserError(Interface): - """User error exceptions - """ - -class UserError(Exception): - """User errors - - These exceptions should generally be displayed to users unless - they are handled. - """ - implements(IUserError) - -class ITracebackSupplement(Interface): - """Provides valuable information to supplement an exception traceback. - - The interface is geared toward providing meaningful feedback when - exceptions occur in user code written in mini-languages like - Zope page templates and restricted Python scripts. - """ - - source_url = Attribute( - 'source_url', - """Optional. Set to URL of the script where the exception occurred. - - Normally this generates a URL in the traceback that the user - can visit to manage the object. Set to None if unknown or - not available. - """ - ) - - line = Attribute( - 'line', - """Optional. Set to the line number (>=1) where the exception - occurred. - - Set to 0 or None if the line number is unknown. - """ - ) - - column = Attribute( - 'column', - """Optional. Set to the column offset (>=0) where the exception - occurred. - - Set to None if the column number is unknown. - """ - ) - - expression = Attribute( - 'expression', - """Optional. Set to the expression that was being evaluated. - - Set to None if not available or not applicable. - """ - ) - - warnings = Attribute( - 'warnings', - """Optional. Set to a sequence of warning messages. - - Set to None if not available, not applicable, or if the exception - itself provides enough information. - """ - ) - - - def getInfo(as_html=0): - """Optional. Returns a string containing any other useful info. - - If as_html is set, the implementation must HTML-quote the result - (normally using cgi.escape()). Returns None to provide no - extra info. - """ diff --git a/tools/buildbot/pylibs/zope/exceptions/log.py b/tools/buildbot/pylibs/zope/exceptions/log.py deleted file mode 100644 index 0fa282f..0000000 --- a/tools/buildbot/pylibs/zope/exceptions/log.py +++ /dev/null @@ -1,35 +0,0 @@ -############################################################################## -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Log formatter that enhances tracebacks with extra information. - -$Id: $ -""" - -import logging -import cStringIO -from zope.exceptions.exceptionformatter import print_exception - -class Formatter(logging.Formatter): - - def formatException(self, ei): - """Format and return the specified exception information as a string. - - Uses zope.exceptions.exceptionformatter to generate the traceback. - """ - sio = cStringIO.StringIO() - print_exception(ei[0], ei[1], ei[2], file=sio, with_filenames=True) - s = sio.getvalue() - if s.endswith("\n"): - s = s[:-1] - return s diff --git a/tools/buildbot/pylibs/zope/exceptions/tests/__init__.py b/tools/buildbot/pylibs/zope/exceptions/tests/__init__.py deleted file mode 100644 index b711d36..0000000 --- a/tools/buildbot/pylibs/zope/exceptions/tests/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# -# This file is necessary to make this directory a package. diff --git a/tools/buildbot/pylibs/zope/exceptions/tests/test_exceptionformatter.py b/tools/buildbot/pylibs/zope/exceptions/tests/test_exceptionformatter.py deleted file mode 100644 index 70d9c1c..0000000 --- a/tools/buildbot/pylibs/zope/exceptions/tests/test_exceptionformatter.py +++ /dev/null @@ -1,168 +0,0 @@ -############################################################################## -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""ExceptionFormatter tests. - -$Id: test_exceptionformatter.py 68429 2006-06-01 10:54:18Z mgedmin $ -""" -import sys -from unittest import TestCase, main, makeSuite - -from zope.exceptions.exceptionformatter import format_exception -from zope.testing.cleanup import CleanUp # Base class w registry cleanup - -def tb(as_html=0): - t, v, b = sys.exc_info() - try: - return ''.join(format_exception(t, v, b, as_html=as_html)) - finally: - del b - - -class ExceptionForTesting (Exception): - pass - - - -class TestingTracebackSupplement(object): - - source_url = '/somepath' - line = 634 - column = 57 - warnings = ['Repent, for the end is nigh'] - - def __init__(self, expression): - self.expression = expression - - - -class Test(CleanUp, TestCase): - - def testBasicNamesText(self, as_html=0): - try: - raise ExceptionForTesting - except ExceptionForTesting: - s = tb(as_html) - # The traceback should include the name of this function. - self.assert_(s.find('testBasicNamesText') >= 0) - # The traceback should include the name of the exception. - self.assert_(s.find('ExceptionForTesting') >= 0) - else: - self.fail('no exception occurred') - - def testBasicNamesHTML(self): - self.testBasicNamesText(1) - - def testSupplement(self, as_html=0): - try: - __traceback_supplement__ = (TestingTracebackSupplement, - "You're one in a million") - raise ExceptionForTesting - except ExceptionForTesting: - s = tb(as_html) - # The source URL - self.assert_(s.find('/somepath') >= 0, s) - # The line number - self.assert_(s.find('634') >= 0, s) - # The column number - self.assert_(s.find('57') >= 0, s) - # The expression - self.assert_(s.find("You're one in a million") >= 0, s) - # The warning - self.assert_(s.find("Repent, for the end is nigh") >= 0, s) - else: - self.fail('no exception occurred') - - def testSupplementHTML(self): - self.testSupplement(1) - - def testTracebackInfo(self, as_html=0): - try: - __traceback_info__ = "Adam & Eve" - raise ExceptionForTesting - except ExceptionForTesting: - s = tb(as_html) - if as_html: - # Be sure quoting is happening. - self.assert_(s.find('Adam & Eve') >= 0, s) - else: - self.assert_(s.find('Adam & Eve') >= 0, s) - else: - self.fail('no exception occurred') - - def testTracebackInfoHTML(self): - self.testTracebackInfo(1) - - def testTracebackInfoTuple(self): - try: - __traceback_info__ = ("Adam", "Eve") - raise ExceptionForTesting - except ExceptionForTesting: - s = tb() - self.assert_(s.find('Adam') >= 0, s) - self.assert_(s.find('Eve') >= 0, s) - else: - self.fail('no exception occurred') - - def testMultipleLevels(self): - # Makes sure many levels are shown in a traceback. - def f(n): - """Produces a (n + 1)-level traceback.""" - __traceback_info__ = 'level%d' % n - if n > 0: - f(n - 1) - else: - raise ExceptionForTesting - - try: - f(10) - except ExceptionForTesting: - s = tb() - for n in range(11): - self.assert_(s.find('level%d' % n) >= 0, s) - else: - self.fail('no exception occurred') - - def testQuoteLastLine(self): - class C(object): pass - try: raise TypeError(C()) - except: - s = tb(1) - else: - self.fail('no exception occurred') - self.assert_(s.find('<') >= 0, s) - self.assert_(s.find('>') >= 0, s) - - def testMultilineException(self): - try: - exec 'syntax error' - except: - s = tb() - # Traceback (most recent call last): - # Module zope.exceptions.tests.test_exceptionformatter, line ??, in testMultilineException - # exec \'syntax error\' - # File "", line 1 - # syntax error - # ^ - # SyntaxError: unexpected EOF while parsing - self.assertEquals(s.splitlines()[-3:], - [' syntax error', - ' ^', - 'SyntaxError: unexpected EOF while parsing']) - - -def test_suite(): - return makeSuite(Test) - -if __name__=='__main__': - main(defaultTest='test_suite') diff --git a/tools/buildbot/pylibs/zope/interface/DEPENDENCIES.cfg b/tools/buildbot/pylibs/zope/interface/DEPENDENCIES.cfg deleted file mode 100644 index 94e5452..0000000 --- a/tools/buildbot/pylibs/zope/interface/DEPENDENCIES.cfg +++ /dev/null @@ -1 +0,0 @@ -zope.testing diff --git a/tools/buildbot/pylibs/zope/interface/PUBLICATION.cfg b/tools/buildbot/pylibs/zope/interface/PUBLICATION.cfg deleted file mode 100644 index 304fa61..0000000 --- a/tools/buildbot/pylibs/zope/interface/PUBLICATION.cfg +++ /dev/null @@ -1,8 +0,0 @@ -Metadata-Version: 1.0 -Name: zope.interface -Summary: Zope 3 Interface Infrastructure -Author: Zope Corporation and Contributors -Author-email: zope3-dev@zope.org -License: ZPL 2.1 -Description: - The implementation of interface definitions for Zope 3. diff --git a/tools/buildbot/pylibs/zope/interface/README.ru.txt b/tools/buildbot/pylibs/zope/interface/README.ru.txt deleted file mode 100644 index 07d681f..0000000 --- a/tools/buildbot/pylibs/zope/interface/README.ru.txt +++ /dev/null @@ -1,689 +0,0 @@ -========== -ИнтерфейÑÑ‹ -========== - -.. contents:: - -ИнтерфейÑÑ‹ - Ñто объекты Ñпецифицирующие (документирующие) внешнее поведение -объектов которые их "предоÑтавлÑÑŽÑ‚". ИнтерфейÑÑ‹ определÑÑŽÑ‚ поведение через -Ñледующие ÑоÑтавлÑющие: - -- Ðеформальную документацию в Ñтроках документации - -- ÐžÐ¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ð°Ñ‚Ñ€Ð¸Ð±ÑƒÑ‚Ð¾Ð² - -- Инварианты, предÑтавленные уÑловиÑми которые должны быть Ñоблюдены - Ð´Ð»Ñ Ð¾Ð±ÑŠÐµÐºÑ‚Ð¾Ð² предоÑтавлÑющих Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ - -ÐžÐ¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ð°Ñ‚Ñ€Ð¸Ð±ÑƒÑ‚Ð¾Ð² опиÑывают конкретные атрибуты. Они определÑÑŽÑ‚ -Ð¸Ð¼Ñ Ð°Ñ‚Ñ€Ð¸Ð±ÑƒÑ‚Ð° и предоÑтавлÑÑŽÑ‚ документацию и Ð¾Ð³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ð¹ -атрибута. ÐžÐ¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ð°Ñ‚Ñ€Ð¸Ð±ÑƒÑ‚Ð¾Ð² могут быть заданы неÑколькими путÑми -как мы увидим ниже. - -Определение интерфейÑов -======================= - -ИнтерфейÑÑ‹ определÑÑŽÑ‚ÑÑ Ñ Ð¸Ñпользованием ключевого Ñлова class: - - >>> import zope.interface - >>> class IFoo(zope.interface.Interface): - ... """Foo blah blah""" - ... - ... x = zope.interface.Attribute("""X blah blah""") - ... - ... def bar(q, r=None): - ... """bar blah blah""" - -Ð’ примере выше мы Ñоздали Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ `IFoo`. Мы наÑледуем его от -клаÑÑа `zope.interface.Interface`, который ÑвлÑетÑÑ Ñ€Ð¾Ð´Ð¸Ñ‚ÐµÐ»ÑŒÑким интерфейÑом -Ð´Ð»Ñ Ð²Ñех интерфейÑов, как `object` - Ñто родительÑкий клаÑÑ Ð´Ð»Ñ Ð²Ñех новых -клаÑÑов [#create]_. Данный Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ Ð½Ðµ ÑвлÑетÑÑ ÐºÐ»Ð°ÑÑом, а ÑвлÑетÑÑ -ИнтерфейÑом, ÑкземплÑром `InterfaceClass`:: - - >>> type(IFoo) - - -Мы можем запроÑить у интерфейÑа его документацию:: - - >>> IFoo.__doc__ - 'Foo blah blah' - -и его имÑ:: - - >>> IFoo.__name__ - 'IFoo' - -и даже модуль в котором он определен:: - - >>> IFoo.__module__ - '__main__' - -Ðаш Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»Ñет два атрибута: - -`x` - Это проÑÑ‚ÐµÐ¹ÑˆÐ°Ñ Ñ„Ð¾Ñ€Ð¼Ð° Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ð°Ñ‚Ñ€Ð¸Ð±ÑƒÑ‚Ð¾Ð². ОпределÑÑŽÑ‚ÑÑ Ð¸Ð¼Ñ - и Ñтрока документации. Формально здеÑÑŒ не определÑетÑÑ Ð½Ð¸Ñ‡ÐµÐ³Ð¾ более. - -`bar` - Это метод. Методы определÑÑŽÑ‚ÑÑ ÐºÐ°Ðº обычные функции. Метод - Ñто проÑто - атрибут который должен быть вызываемым Ñ ÑƒÐºÐ°Ð·Ð°Ð½Ð¸ÐµÐ¼ Ñигнатуры, - предоÑтавлÑемой определением функции. - - Ðадо отметить, что аргумент `self` не указываетÑÑ Ð´Ð»Ñ `bar`. Ð˜Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ - документирует как объект *иÑпользуетÑÑ*. Когда методы ÑкземплÑров клаÑÑов - вызываютÑÑ Ð¼Ñ‹ не передаем аргумент `self`, таким образом аргумент `self` - не включаетÑÑ Ð¸ в Ñигнатуру интерфейÑа. Ðргумент `self` в методах - ÑкземплÑров клаÑÑов на Ñамом деле деталь реализации ÑкземплÑров клаÑÑов - в Python. Другие объекты кроме ÑкземплÑров клаÑÑов могут предоÑтавлÑÑ‚ÑŒ - интерфейÑÑ‹ и их методы могут не быть методами ÑкземплÑров клаÑÑов. Ð”Ð»Ñ - примера модули могут предоÑтавлÑÑ‚ÑŒ интерфейÑÑ‹ и их методы обычно проÑто - функции. Даже ÑкземплÑры могут иметь методы не ÑвлÑющиеÑÑ Ð¼ÐµÑ‚Ð¾Ð´Ð°Ð¼Ð¸ - ÑкземплÑров клаÑÑа. - -Мы можем получить доÑтуп к атрибутам определенным интерфейÑом иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ -ÑÐ¸Ð½Ñ‚Ð°ÐºÑ Ð´Ð¾Ñтупа к Ñлементам маÑÑива:: - - >>> x = IFoo['x'] - >>> type(x) - - >>> x.__name__ - 'x' - >>> x.__doc__ - 'X blah blah' - - >>> IFoo.get('x').__name__ - 'x' - - >>> IFoo.get('y') - -Можно иÑпользовать `in` Ð´Ð»Ñ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ñодержит ли Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ -определенное имÑ:: - - >>> 'x' in IFoo - True - -Мы можем иÑпользовать итератор Ð´Ð»Ñ Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñов что бы получить вÑе имена -которые интерфейÑÑ‹ определÑÑŽÑ‚:: - - >>> names = list(IFoo) - >>> names.sort() - >>> names - ['bar', 'x'] - -Ðадо помнить, что интерфейÑÑ‹ не ÑвлÑÑŽÑ‚ÑÑ ÐºÐ»Ð°ÑÑами. Мы не можем получить -доÑтуп к определениÑм атрибутов через доÑтуп к атрибутам интерфейÑов:: - - >>> IFoo.x - Traceback (most recent call last): - File "", line 1, in ? - AttributeError: 'InterfaceClass' object has no attribute 'x' - -Методы также предоÑтавлÑÑŽÑ‚ доÑтуп к Ñигнатуре метода:: - - >>> bar = IFoo['bar'] - >>> bar.getSignatureString() - '(q, r=None)' - - (Методы должны иметь лучший API. Это то, что должно быть улучшено.) - -ОбъÑвление интерфейÑов -====================== - -Определив Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÑ Ð¼Ñ‹ можем теперь *объÑвить*, что объекты предоÑтавлÑÑŽÑ‚ их. -Перед опиÑанием деталей определим некоторые термины: - -*предоÑтавлÑÑ‚ÑŒ* - Мы говорим, что объекты *предоÑтавлÑÑŽÑ‚* интерфейÑÑ‹. ЕÑли объект - предоÑтавлÑет интерфейÑ, тогда Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ Ñпецифицирует поведение объекта. - Другими Ñловами, интерфейÑÑ‹ Ñпецифицируют поведение объектов которые - предоÑтавлÑÑŽÑ‚ их. - -*реализовать* - Мы обычно говорим что клаÑÑÑ‹ *реализуют* интерфейÑÑ‹. ЕÑли клаÑÑ - реализует интерфейÑ, тогда ÑкземплÑры Ñтого клаÑÑа предоÑтавлÑÑŽÑ‚ - данный интерфейÑ. Объекты предоÑтавлÑÑŽÑ‚ интерфейÑÑ‹ которые их клаÑÑÑ‹ - реализуют [#factory]_. (Объекты также могут предоÑтавлÑÑ‚ÑŒ интерфейÑÑ‹ напрÑмую - Ð¿Ð»ÑŽÑ Ðº тем которые реализуют их клаÑÑÑ‹.) - - Важно помнить, что клаÑÑÑ‹ обычно не предоÑтавлÑÑŽÑ‚ интерфейÑÑ‹ которые - они реализуют. - - Мы можем обобщить Ñто до фабрик. Ð”Ð»Ñ Ð»ÑŽÐ±Ð¾Ð³Ð¾ вызываемого объекта мы можем - объÑвить что он производит объекты которые предоÑтавлÑÑŽÑ‚ какие-либо - интерфейÑÑ‹ Ñказав, что фабрика реализует данные интерфейÑÑ‹. - -Теперь поÑле того как мы определили Ñти термины мы можем поговорить об -API Ð´Ð»Ñ Ð¾Ð±ÑŠÑÐ²Ð»ÐµÐ½Ð¸Ñ Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñов. - -ОбÑвление реализуемых интерфеÑов --------------------------------- - -Ðаиболее чаÑто иÑпользуемый путь Ð´Ð»Ñ Ð¾Ð±ÑŠÑÐ²Ð»ÐµÐ½Ð¸Ñ Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñов - Ñто иÑпользование -функции implements в определении клаÑÑа:: - - >>> class Foo: - ... zope.interface.implements(IFoo) - ... - ... def __init__(self, x=None): - ... self.x = x - ... - ... def bar(self, q, r=None): - ... return q, r, self.x - ... - ... def __repr__(self): - ... return "Foo(%s)" % self.x - -Ð’ Ñтом примере мы объÑвили, что `Foo` реализует `IFoo`. Это значит, что -ÑкземплÑры `Foo` предоÑтавлÑÑŽÑ‚ `IFoo`. ПоÑле данного объÑÐ²Ð»ÐµÐ½Ð¸Ñ ÐµÑÑ‚ÑŒ -неÑколько путей Ð´Ð»Ñ Ð°Ð½Ð°Ð»Ð¸Ð·Ð° объÑвлений. Во-первых мы можем ÑпроÑить -что Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ Ñ€ÐµÐ°Ð»Ð¸Ð·Ð¾Ð²Ð°Ð½ клаÑÑом:: - - >>> IFoo.implementedBy(Foo) - True - -Также мы можем ÑпроÑить еÑли Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ Ð¿Ñ€ÐµÐ´Ð¾ÑтавлÑетÑÑ Ð¾Ð±ÑŠÐµÐºÑ‚Ð°Ð¼Ð¸ клаÑÑа:: - - >>> foo = Foo() - >>> IFoo.providedBy(foo) - True - -Конечно `Foo` не предоÑтавлÑет `IFoo`, он реализует его:: - - >>> IFoo.providedBy(Foo) - False - -Мы можем также узнать какие интерфейÑÑ‹ реализуютÑÑ Ð¾Ð±ÑŠÐµÐºÑ‚Ð°Ð¼Ð¸:: - - >>> list(zope.interface.implementedBy(Foo)) - [] - -Это ошибка Ñпрашивать про интерфейÑÑ‹ реализуемые невызываемым объектом:: - - >>> IFoo.implementedBy(foo) - Traceback (most recent call last): - ... - TypeError: ('ImplementedBy called for non-factory', Foo(None)) - - >>> list(zope.interface.implementedBy(foo)) - Traceback (most recent call last): - ... - TypeError: ('ImplementedBy called for non-factory', Foo(None)) - -Также можно узнать какие интерфейÑÑ‹ предоÑтавлÑÑŽÑ‚ÑÑ Ð¾Ð±ÑŠÐµÐºÑ‚Ð°Ð¼Ð¸:: - - >>> list(zope.interface.providedBy(foo)) - [] - >>> list(zope.interface.providedBy(Foo)) - [] - -Мы можем объÑвить интерфейÑÑ‹ реализуемые другими фабриками (кроме клаÑÑов). -Это можно Ñделать иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ Ð´ÐµÐºÐ¾Ñ€Ð°Ñ‚Ð¾Ñ€ `implementer` (в Ñтиле Python 2.4). -Ð”Ð»Ñ Ð²ÐµÑ€Ñий Python ниже 2.4 Ñто будет выглÑдеть Ñледующим образом: - - >>> def yfoo(y): - ... foo = Foo() - ... foo.y = y - ... return foo - >>> yfoo = zope.interface.implementer(IFoo)(yfoo) - - >>> list(zope.interface.implementedBy(yfoo)) - [] - -Ðадо заметить, что декоратор implementer может модифицировать Ñвои аргументы. -Ð’Ñ‹Ð·Ñ‹Ð²Ð°ÑŽÑ‰Ð°Ñ Ñторона не должна предполагать, что вÑегда будет ÑоздаватьÑÑ -новый объект. - -Также надо отметить, что как минимум ÑÐµÐ¹Ñ‡Ð°Ñ implementer не может иÑпользоватьÑÑ -Ð´Ð»Ñ ÐºÐ»Ð°ÑÑов: - - >>> zope.interface.implementer(IFoo)(Foo) - ... # doctest: +NORMALIZE_WHITESPACE - Traceback (most recent call last): - ... - TypeError: Can't use implementer with classes. - Use one of the class-declaration functions instead. - -ОбъÑвление предоÑтавлÑемых интерфейÑов --------------------------------------- - -Мы можем объÑвлÑÑ‚ÑŒ интерфейÑÑ‹ напрÑмую предоÑтавлÑемые объектами. Предположим -что мы хотим документировать что делает метод `__init__` клаÑÑа `Foo`. Это -*точно* не чаÑÑ‚ÑŒ `IFoo`. Обычно мы не должны напрÑмую вызывать метод `__init__` -Ð´Ð»Ñ ÑкземплÑров Foo. Скорее метод `__init__` ÑвлÑетÑÑ Ñ‡Ð°Ñтью метода `__call__` -клаÑÑа `Foo`:: - - >>> class IFooFactory(zope.interface.Interface): - ... """Create foos""" - ... - ... def __call__(x=None): - ... """Create a foo - ... - ... The argument provides the initial value for x ... - ... """ - -У Ð½Ð°Ñ ÐµÑÑ‚ÑŒ клаÑÑ Ð¿Ñ€ÐµÐ´Ð¾ÑтавлÑющий данный интерфейÑ, таким образом мы можем -объÑвить Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ ÐºÐ»Ð°ÑÑа:: - - >>> zope.interface.directlyProvides(Foo, IFooFactory) - -Теперь мы видим, что Foo уже предоÑтавлÑет интерфейÑÑ‹:: - - >>> list(zope.interface.providedBy(Foo)) - [] - >>> IFooFactory.providedBy(Foo) - True - -ОбъÑвление интерфейÑов клаÑÑа доÑтаточно чаÑÑ‚Ð°Ñ Ð¾Ð¿ÐµÑ€Ð°Ñ†Ð¸Ñ Ð¸ Ð´Ð»Ñ Ð½ÐµÐµ еÑÑ‚ÑŒ -ÑÐ¿ÐµÑ†Ð¸Ð°Ð»ÑŒÐ½Ð°Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¾Ð±ÑŠÑÐ²Ð»ÐµÐ½Ð¸Ñ `classProvides`, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð¿Ð¾Ð·Ð²Ð¾Ð»Ñет объÑвлÑÑ‚ÑŒ -интерфейÑÑ‹ при определении клаÑÑа:: - - >>> class Foo2: - ... zope.interface.implements(IFoo) - ... zope.interface.classProvides(IFooFactory) - ... - ... def __init__(self, x=None): - ... self.x = x - ... - ... def bar(self, q, r=None): - ... return q, r, self.x - ... - ... def __repr__(self): - ... return "Foo(%s)" % self.x - - >>> list(zope.interface.providedBy(Foo2)) - [] - >>> IFooFactory.providedBy(Foo2) - True - -ÐŸÐ¾Ñ…Ð¾Ð¶Ð°Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ `moduleProvides` поддерживает объÑвление интерфейÑов при -определении модулÑ. Ð”Ð»Ñ Ð¿Ñ€Ð¸Ð¼ÐµÑ€Ð° Ñмотрите иÑпользование вызова -`moduleProvides` в `zope.interface.__init__`, который объÑвлÑет, что -пакет `zope.interface` предоÑтавлÑет `IInterfaceDeclaration`. - -Иногда мы хотим объÑвить интерфейÑÑ‹ ÑкземплÑров, даже еÑли Ñти ÑкземплÑры -уже берут интерфейÑÑ‹ от Ñвоих клаÑÑов. Предположим, что мы Ñоздаем новый -Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ `ISpecial`:: - - >>> class ISpecial(zope.interface.Interface): - ... reason = zope.interface.Attribute("Reason why we're special") - ... def brag(): - ... "Brag about being special" - -Мы можем Ñделать Ñозданный ÑкземплÑÑ€ foo Ñпециальным предоÑтавив атрибуты -`reason` и `brag`:: - - >>> foo.reason = 'I just am' - >>> def brag(): - ... return "I'm special!" - >>> foo.brag = brag - >>> foo.reason - 'I just am' - >>> foo.brag() - "I'm special!" - -и объÑвив интерфейÑ:: - - >>> zope.interface.directlyProvides(foo, ISpecial) - -таким образом новый Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ Ð²ÐºÐ»ÑŽÑ‡Ð°ÐµÑ‚ÑÑ Ð² ÑпиÑок предоÑтавлÑемых интерфейÑов:: - - >>> ISpecial.providedBy(foo) - True - >>> list(zope.interface.providedBy(foo)) - [, ] - -Мы также можем определить, что интерфейÑÑ‹ напрÑмую предоÑтавлÑÑŽÑ‚ÑÑ -объектами:: - - >>> list(zope.interface.directlyProvidedBy(foo)) - [] - - >>> newfoo = Foo() - >>> list(zope.interface.directlyProvidedBy(newfoo)) - [] - -ÐаÑледуемые объÑÐ²Ð»ÐµÐ½Ð¸Ñ ----------------------- - -Обычно объÑÐ²Ð»ÐµÐ½Ð¸Ñ Ð½Ð°ÑледуютÑÑ:: - - >>> class SpecialFoo(Foo): - ... zope.interface.implements(ISpecial) - ... reason = 'I just am' - ... def brag(self): - ... return "I'm special because %s" % self.reason - - >>> list(zope.interface.implementedBy(SpecialFoo)) - [, ] - - >>> list(zope.interface.providedBy(SpecialFoo())) - [, ] - -Иногда мы не хотим наÑледовать объÑвлениÑ. Ð’ Ñтом Ñлучае мы можем -иÑпользовать `implementsOnly` вмеÑто `implements`:: - - >>> class Special(Foo): - ... zope.interface.implementsOnly(ISpecial) - ... reason = 'I just am' - ... def brag(self): - ... return "I'm special because %s" % self.reason - - >>> list(zope.interface.implementedBy(Special)) - [] - - >>> list(zope.interface.providedBy(Special())) - [] - -Внешние объÑÐ²Ð»ÐµÐ½Ð¸Ñ ------------------- - -Обычно мы Ñоздаем объÑÐ²Ð»ÐµÐ½Ð¸Ñ Ñ€ÐµÐ°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ð¸ как чаÑÑ‚ÑŒ объÑÐ²Ð»ÐµÐ½Ð¸Ñ ÐºÐ»Ð°ÑÑа. Иногда -мы можем захотеть Ñоздать объÑÐ²Ð»ÐµÐ½Ð¸Ñ Ð²Ð½Ðµ объÑÐ²Ð»ÐµÐ½Ð¸Ñ ÐºÐ»Ð°ÑÑа. Ð”Ð»Ñ Ð¿Ñ€Ð¸Ð¼ÐµÑ€Ð°, -мы можем хотеть объÑвить интерфейÑÑ‹ Ð´Ð»Ñ ÐºÐ»Ð°ÑÑов которые пиÑали не мы. -Ð”Ð»Ñ Ñтого может иÑпользоватьÑÑ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ `classImplements`:: - - >>> class C: - ... pass - - >>> zope.interface.classImplements(C, IFoo) - >>> list(zope.interface.implementedBy(C)) - [] - -Мы можем иÑпользовать `classImplementsOnly` Ð´Ð»Ñ Ð¸ÑÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ð½Ð°Ñледуемых -интерфейÑов:: - - >>> class C(Foo): - ... pass - - >>> zope.interface.classImplementsOnly(C, ISpecial) - >>> list(zope.interface.implementedBy(C)) - [] - -Объекты объÑвлений ------------------- - -Когда мы объÑвлÑем интерфейÑÑ‹ мы Ñоздаем объект *объÑвлениÑ*. Когда мы -запрашиваем объÑÐ²Ð»ÐµÐ½Ð¸Ñ Ð²Ð¾Ð·Ð²Ñ€Ð°Ñ‰Ð°ÐµÑ‚ÑÑ Ð¾Ð±ÑŠÐµÐºÑ‚ объÑвлениÑ:: - - >>> type(zope.interface.implementedBy(Special)) - - -Объекты объÑÐ²Ð»ÐµÐ½Ð¸Ñ Ð¸ объекты интерфейÑов во многом похожи друг на друга. -Ðа Ñамом деле они даже имеют общий базовый клаÑÑ. Важно понÑÑ‚ÑŒ, что они могут -иÑпользоватьÑÑ Ñ‚Ð°Ð¼ где в объÑвлениÑÑ… ожидаютÑÑ Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹ÑÑ‹. Вот проÑтой -пример:: - - >>> class Special2(Foo): - ... zope.interface.implementsOnly( - ... zope.interface.implementedBy(Foo), - ... ISpecial, - ... ) - ... reason = 'I just am' - ... def brag(self): - ... return "I'm special because %s" % self.reason - -ОбъÑвление здеÑÑŒ практичеÑки такое же как -``zope.interface.implements(ISpecial)``, отличие только в порÑдке -интерфейÑов в итоговом объÑвлениÑ:: - - >>> list(zope.interface.implementedBy(Special2)) - [, ] - -ÐаÑледование интерфейÑов -======================== - -ИнтерфейÑÑ‹ могут раÑширÑÑ‚ÑŒ другие интерфейÑÑ‹. Они делают Ñто проÑто -Ð¿Ð¾ÐºÐ°Ð·Ñ‹Ð²Ð°Ñ Ñти интерфейÑÑ‹ как базовые:: - - >>> class IBlat(zope.interface.Interface): - ... """Blat blah blah""" - ... - ... y = zope.interface.Attribute("y blah blah") - ... def eek(): - ... """eek blah blah""" - - >>> IBlat.__bases__ - (,) - - >>> class IBaz(IFoo, IBlat): - ... """Baz blah""" - ... def eek(a=1): - ... """eek in baz blah""" - ... - - >>> IBaz.__bases__ - (, ) - - >>> names = list(IBaz) - >>> names.sort() - >>> names - ['bar', 'eek', 'x', 'y'] - -Заметим, что `IBaz` переопределÑет eek:: - - >>> IBlat['eek'].__doc__ - 'eek blah blah' - >>> IBaz['eek'].__doc__ - 'eek in baz blah' - -Мы были оÑторожны переопределÑÑ eek ÑовмеÑтимым путем. Когда Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ -раÑширÑетÑÑ, раÑширенный Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ Ð´Ð¾Ð»Ð¶ÐµÐ½ быть ÑовмеÑтимым [#compat]_ Ñ -раÑширÑемыми интерфейÑами. - -Мы можем запроÑить раÑширÑет ли один из интерфейÑов другой:: - - >>> IBaz.extends(IFoo) - True - >>> IBlat.extends(IFoo) - False - -Заметим, что интерфейÑÑ‹ не раÑширÑÑŽÑ‚ Ñами ÑебÑ:: - - >>> IBaz.extends(IBaz) - False - -Иногда мы можем хотеть что бы они раÑширÑли Ñами ÑебÑ, но вмеÑто Ñтого -мы можем иÑпользовать `isOrExtends`:: - - >>> IBaz.isOrExtends(IBaz) - True - >>> IBaz.isOrExtends(IFoo) - True - >>> IFoo.isOrExtends(IBaz) - False - -Когда мы применÑем итерацию к интерфеÑу мы получаем вÑе имена которые он -определÑет Ð²ÐºÐ»ÑŽÑ‡Ð°Ñ Ð¸Ð¼ÐµÐ½Ð° определенные Ð´Ð»Ñ Ð±Ð°Ð·Ð¾Ð²Ñ‹Ñ… интерфеÑов. Иногда -мы хотим получить *только* имена определенные интерфейÑом напрÑмую. -Ð”Ð»Ñ Ñтого мы иÑпользуем метод `names`:: - - >>> list(IBaz.names()) - ['eek'] - -ÐаÑледование в Ñлучае Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ð°Ñ‚Ñ€Ð¸Ð±ÑƒÑ‚Ð¾Ð² --------------------------------------------- - -Ð˜Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ Ð¼Ð¾Ð¶ÐµÑ‚ переопределÑÑ‚ÑŒ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ð°Ñ‚Ñ€Ð¸Ð±ÑƒÑ‚Ð¾Ð² из базовых интерфейÑов. -ЕÑли два базовых интерфейÑа определÑÑŽÑ‚ один и тот же атрибут атрибут -наÑледуетÑÑ Ð¾Ñ‚ более Ñпецифичного интерфейÑа. Ð”Ð»Ñ Ð¿Ñ€Ð¸Ð¼ÐµÑ€Ð°: - - >>> class IBase(zope.interface.Interface): - ... - ... def foo(): - ... "base foo doc" - - >>> class IBase1(IBase): - ... pass - - >>> class IBase2(IBase): - ... - ... def foo(): - ... "base2 foo doc" - - >>> class ISub(IBase1, IBase2): - ... pass - -Определение ISub Ð´Ð»Ñ foo будет из IBase2 Ñ‚.к. IBase2 более Ñпецифичен Ð´Ð»Ñ -IBase: - - >>> ISub['foo'].__doc__ - 'base2 foo doc' - -Заметим, что Ñто отличаетÑÑ Ð¾Ñ‚ поиÑка в глубину. - -Иногда полезно узнать, что Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»Ñет атрибут напрÑмую. Мы можем -иÑпользовать метод direct Ð´Ð»Ñ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ð½Ð°Ð¿Ñ€Ñмую определенных атрибутов: - - >>> IBase.direct('foo').__doc__ - 'base foo doc' - - >>> ISub.direct('foo') - -Спецификации ------------- - -ИнтерфейÑÑ‹ и объÑÐ²Ð»ÐµÐ½Ð¸Ñ - Ñто Ñпециальные Ñлучаи Ñпецификаций. ОпиÑание -выше Ð´Ð»Ñ Ð½Ð°ÑÐ»ÐµÐ´Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñов можно применить и к объÑвлениÑм и -к ÑпецификациÑм. ОбъÑÐ²Ð»ÐµÐ½Ð¸Ñ Ñ„Ð°ÐºÑ‚Ð¸Ñ‡ÐµÑки раÑширÑÑŽÑ‚ интерфейÑÑ‹ которые они -объÑвлÑÑŽÑ‚: - - >>> class Baz: - ... zope.interface.implements(IBaz) - - >>> baz_implements = zope.interface.implementedBy(Baz) - >>> baz_implements.__bases__ - (,) - - >>> baz_implements.extends(IFoo) - True - - >>> baz_implements.isOrExtends(IFoo) - True - >>> baz_implements.isOrExtends(baz_implements) - True - -Спецификации (интерфейÑÑ‹ и объÑвлениÑ) предоÑтавлÑÑŽÑ‚ атрибут `__sro__` -который опиÑывает Ñпецификацию и вÑех ее предков: - - >>> baz_implements.__sro__ - (, - , - , - , - ) - -Помеченные Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ -=================== - -ИнтерфейÑÑ‹ и опиÑÐ°Ð½Ð¸Ñ Ð°Ñ‚Ñ€Ð¸Ð±ÑƒÑ‚Ð¾Ð² поддерживают механизм раÑÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ -заимÑтвованный из UML и называемый "помеченные значениÑ" который позволÑет -ÑохранÑÑ‚ÑŒ дополнительные данные:: - - >>> IFoo.setTaggedValue('date-modified', '2004-04-01') - >>> IFoo.setTaggedValue('author', 'Jim Fulton') - >>> IFoo.getTaggedValue('date-modified') - '2004-04-01' - >>> IFoo.queryTaggedValue('date-modified') - '2004-04-01' - >>> IFoo.queryTaggedValue('datemodified') - >>> tags = list(IFoo.getTaggedValueTags()) - >>> tags.sort() - >>> tags - ['author', 'date-modified'] - -Ðтрибуты функций конвертируютÑÑ Ð² помеченные Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ ÐºÐ¾Ð³Ð´Ð° ÑоздаютÑÑ -Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ð°Ñ‚Ñ€Ð¸Ð±ÑƒÑ‚Ð¾Ð² метода:: - - >>> class IBazFactory(zope.interface.Interface): - ... def __call__(): - ... "create one" - ... __call__.return_type = IBaz - - >>> IBazFactory['__call__'].getTaggedValue('return_type') - - -Инварианты -========== - -ИнтерфейÑÑ‹ могут опиÑывать уÑÐ»Ð¾Ð²Ð¸Ñ ÐºÐ¾Ñ‚Ð¾Ñ€Ñ‹Ðµ должны быть Ñоблюдены Ð´Ð»Ñ Ð¾Ð±ÑŠÐµÐºÑ‚Ð¾Ð² -которые их предоÑтавлÑÑŽÑ‚. Эти уÑÐ»Ð¾Ð²Ð¸Ñ Ð¾Ð¿Ð¸ÑываютÑÑ Ð¸ÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ Ð¾Ð´Ð¸Ð½ или более -инвариантов. Инварианты - Ñто вызываемые объекты которые будут вызваны -Ñ Ð¾Ð±ÑŠÐµÐºÑ‚Ð¾Ð¼ предоÑтавлÑющим Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ Ð² качеÑтве параметра. Инвариант -должен выкинуть иÑключение `Invalid` еÑли уÑловие не Ñоблюдено. Ðапример:: - - >>> class RangeError(zope.interface.Invalid): - ... """A range has invalid limits""" - ... def __repr__(self): - ... return "RangeError(%r)" % self.args - - >>> def range_invariant(ob): - ... if ob.max < ob.min: - ... raise RangeError(ob) - -Определив Ñтот инвариант мы можем иÑпользовать его в определении интерфейÑов:: - - >>> class IRange(zope.interface.Interface): - ... min = zope.interface.Attribute("Lower bound") - ... max = zope.interface.Attribute("Upper bound") - ... - ... zope.interface.invariant(range_invariant) - -ИнтерфейÑÑ‹ имеют метод Ð´Ð»Ñ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÐ¸ Ñвоих инвариантов:: - - >>> class Range(object): - ... zope.interface.implements(IRange) - ... - ... def __init__(self, min, max): - ... self.min, self.max = min, max - ... - ... def __repr__(self): - ... return "Range(%s, %s)" % (self.min, self.max) - - >>> IRange.validateInvariants(Range(1,2)) - >>> IRange.validateInvariants(Range(1,1)) - >>> IRange.validateInvariants(Range(2,1)) - Traceback (most recent call last): - ... - RangeError: Range(2, 1) - -Ð’ Ñлучае неÑкольких инвариантов мы можем захотеть оÑтановить проверку поÑле -первой ошибки. ЕÑли мы передадим в `validateInvariants` пуÑтой ÑпиÑок тогда -будет выкинуто единÑтвенное иÑключение `Invalid` Ñо ÑпиÑком иÑключений -как аргументом:: - - >>> errors = [] - >>> IRange.validateInvariants(Range(2,1), errors) - Traceback (most recent call last): - ... - Invalid: [RangeError(Range(2, 1))] - -И ÑпиÑок будет заполнен индивидуальными иÑключениÑми:: - - >>> errors - [RangeError(Range(2, 1))] - - -.. [#create] ОÑÐ½Ð¾Ð²Ð½Ð°Ñ Ð¿Ñ€Ð¸Ñ‡Ð¸Ð½Ð° по которой мы наÑледуемÑÑ Ð¾Ñ‚ `Interface` - Ñто - что бы быть уверенными в том, что ключевое Ñлово class будет - Ñоздавать интерфейÑ, а не клаÑÑ. - - ЕÑÑ‚ÑŒ возможноÑÑ‚ÑŒ Ñоздать интерфейÑÑ‹ вызвав Ñпециальный - клаÑÑ Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñа напрÑмую. Ð”ÐµÐ»Ð°Ñ Ñто, возможно (и в редких - ÑлучаÑÑ… полезно) Ñоздать интерфейÑÑ‹ которые не наÑледуютÑÑ - от `Interface`. Однако иÑпользование Ñтой техники выходит - за рамки данного документа. - -.. [#factory] КлаÑÑÑ‹ - Ñто фабрики. Они могут быть вызваны Ð´Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ - Ñвоих ÑкземплÑров. Мы ожидаем что в итоге мы раÑширим - концепцию реализации на другие типы фабрик, таким образом - мы Ñможем объÑвлÑÑ‚ÑŒ интерфейÑÑ‹ предоÑтавлÑемые Ñозданными - фабриками объектами. - -.. [#compat] Цель - заменÑемоÑÑ‚ÑŒ. Объект который предоÑтавлÑет раÑширенный - Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ Ð´Ð¾Ð»Ð¶ÐµÐ½ быть заменÑем в качеÑтве объектов которые - предоÑтавлÑÑŽÑ‚ раÑширÑемый интерфейÑ. Ð’ нашем примере объект - который предоÑтавлÑет IBaz должен быть иÑпользуемым и - в Ñлучае еÑли ожидаетÑÑ Ð¾Ð±ÑŠÐµÐºÑ‚ который предоÑтавлÑет IBlat. - - Ð ÐµÐ°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñа не требует Ñтого. Ðо возможно в дальнейшем - она должна будет делать какие-либо проверки. diff --git a/tools/buildbot/pylibs/zope/interface/README.txt b/tools/buildbot/pylibs/zope/interface/README.txt deleted file mode 100644 index ab19e62..0000000 --- a/tools/buildbot/pylibs/zope/interface/README.txt +++ /dev/null @@ -1,807 +0,0 @@ -========== -Interfaces -========== - -.. contents:: - -Interfaces are objects that specify (document) the external behavior -of objects that "provide" them. An interface specifies behavior -through: - -- Informal documentation in a doc string - -- Attribute definitions - -- Invariants, which are conditions that must hold for objects that - provide the interface - -Attribute definitions specify specific attributes. They define the -attribute name and provide documentation and constraints of attribute -values. Attribute definitions can take a number of forms, as we'll -see below. - -Defining interfaces -=================== - -Interfaces are defined using Python class statements: - - >>> import zope.interface - >>> class IFoo(zope.interface.Interface): - ... """Foo blah blah""" - ... - ... x = zope.interface.Attribute("""X blah blah""") - ... - ... def bar(q, r=None): - ... """bar blah blah""" - -In the example above, we've created an interface, `IFoo`. We -subclassed `zope.interface.Interface`, which is an ancestor interface for -all interfaces, much as `object` is an ancestor of all new-style -classes [#create]_. The interface is not a class, it's an Interface, -an instance of `InterfaceClass`:: - - >>> type(IFoo) - - -We can ask for the interface's documentation:: - - >>> IFoo.__doc__ - 'Foo blah blah' - -and its name:: - - >>> IFoo.__name__ - 'IFoo' - -and even its module:: - - >>> IFoo.__module__ - '__main__' - -The interface defined two attributes: - -`x` - This is the simplest form of attribute definition. It has a name - and a doc string. It doesn't formally specify anything else. - -`bar` - This is a method. A method is defined via a function definition. A - method is simply an attribute constrained to be a callable with a - particular signature, as provided by the function definition. - - Note that `bar` doesn't take a `self` argument. Interfaces document - how an object is *used*. When calling instance methods, you don't - pass a `self` argument, so a `self` argument isn't included in the - interface signature. The `self` argument in instance methods is - really an implementation detail of Python instances. Other objects, - besides instances can provide interfaces and their methods might not - be instance methods. For example, modules can provide interfaces and - their methods are usually just functions. Even instances can have - methods that are not instance methods. - -You can access the attributes defined by an interface using mapping -syntax:: - - >>> x = IFoo['x'] - >>> type(x) - - >>> x.__name__ - 'x' - >>> x.__doc__ - 'X blah blah' - - >>> IFoo.get('x').__name__ - 'x' - - >>> IFoo.get('y') - -You can use `in` to determine if an interface defines a name:: - - >>> 'x' in IFoo - True - -You can iterate over interfaces to get the names they define:: - - >>> names = list(IFoo) - >>> names.sort() - >>> names - ['bar', 'x'] - -Remember that interfaces aren't classes. You can't access attribute -definitions as attributes of interfaces:: - - >>> IFoo.x - Traceback (most recent call last): - File "", line 1, in ? - AttributeError: 'InterfaceClass' object has no attribute 'x' - -Methods provide access to the method signature:: - - >>> bar = IFoo['bar'] - >>> bar.getSignatureString() - '(q, r=None)' - -TODO - Methods really should have a better API. This is something that - needs to be improved. - -Declaring interfaces -==================== - -Having defined interfaces, we can *declare* that objects provide -them. Before we describe the details, lets define some terms: - -*provide* - We say that objects *provide* interfaces. If an object provides an - interface, then the interface specifies the behavior of the - object. In other words, interfaces specify the behavior of the - objects that provide them. - -*implement* - We normally say that classes *implement* interfaces. If a class - implements an interface, then the instances of the class provide - the interface. Objects provide interfaces that their classes - implement [#factory]_. (Objects can provide interfaces directly, - in addition to what their classes implement.) - - It is important to note that classes don't usually provide the - interfaces that they implement. - - We can generalize this to factories. For any callable object we - can declare that it produces objects that provide some interfaces - by saying that the factory implements the interfaces. - -Now that we've defined these terms, we can talk about the API for -declaring interfaces. - -Declaring implemented interfaces --------------------------------- - -The most common way to declare interfaces is using the implements -function in a class statement:: - - >>> class Foo: - ... zope.interface.implements(IFoo) - ... - ... def __init__(self, x=None): - ... self.x = x - ... - ... def bar(self, q, r=None): - ... return q, r, self.x - ... - ... def __repr__(self): - ... return "Foo(%s)" % self.x - - -In this example, we declared that `Foo` implements `IFoo`. This means -that instances of `Foo` provide `IFoo`. Having made this declaration, -there are several ways we can introspect the declarations. First, we -can ask an interface whether it is implemented by a class:: - - >>> IFoo.implementedBy(Foo) - True - -And we can ask whether an interface is provided by an object:: - - >>> foo = Foo() - >>> IFoo.providedBy(foo) - True - -Of course, `Foo` doesn't provide `IFoo`, it implements it:: - - >>> IFoo.providedBy(Foo) - False - -We can also ask what interfaces are implemented by an object:: - - >>> list(zope.interface.implementedBy(Foo)) - [] - -It's an error to ask for interfaces implemented by a non-callable -object:: - - >>> IFoo.implementedBy(foo) - Traceback (most recent call last): - ... - TypeError: ('ImplementedBy called for non-factory', Foo(None)) - - >>> list(zope.interface.implementedBy(foo)) - Traceback (most recent call last): - ... - TypeError: ('ImplementedBy called for non-factory', Foo(None)) - -Similarly, we can ask what interfaces are provided by an object:: - - >>> list(zope.interface.providedBy(foo)) - [] - >>> list(zope.interface.providedBy(Foo)) - [] - -We can declare interfaces implemented by other factories (besides -classes). We do this using a Python-2.4-style decorator named -`implementer`. In versions of Python before 2.4, this looks like: - - - >>> def yfoo(y): - ... foo = Foo() - ... foo.y = y - ... return foo - >>> yfoo = zope.interface.implementer(IFoo)(yfoo) - - >>> list(zope.interface.implementedBy(yfoo)) - [] - -Note that the implementer decorator may modify it's argument. Callers -should not assume that a new object is created. - -Also note that, at least for now, implementer can't be used with -classes: - - >>> zope.interface.implementer(IFoo)(Foo) - ... # doctest: +NORMALIZE_WHITESPACE - Traceback (most recent call last): - ... - TypeError: Can't use implementer with classes. - Use one of the class-declaration functions instead. - -Declaring provided interfaces ------------------------------ - -We can declare interfaces directly provided by objects. Suppose that -we want to document what the `__init__` method of the `Foo` class -does. It's not *really* part of `IFoo`. You wouldn't normally call -the `__init__` method on Foo instances. Rather, the `__init__` method -is part of the `Foo`'s `__call__` method:: - - >>> class IFooFactory(zope.interface.Interface): - ... """Create foos""" - ... - ... def __call__(x=None): - ... """Create a foo - ... - ... The argument provides the initial value for x ... - ... """ - -It's the class that provides this interface, so we declare the -interface on the class:: - - >>> zope.interface.directlyProvides(Foo, IFooFactory) - -And then, we'll see that Foo provides some interfaces:: - - >>> list(zope.interface.providedBy(Foo)) - [] - >>> IFooFactory.providedBy(Foo) - True - -Declaring class interfaces is common enough that there's a special -declaration function for it, `classProvides`, that allows the -declaration from within a class statement:: - - >>> class Foo2: - ... zope.interface.implements(IFoo) - ... zope.interface.classProvides(IFooFactory) - ... - ... def __init__(self, x=None): - ... self.x = x - ... - ... def bar(self, q, r=None): - ... return q, r, self.x - ... - ... def __repr__(self): - ... return "Foo(%s)" % self.x - - >>> list(zope.interface.providedBy(Foo2)) - [] - >>> IFooFactory.providedBy(Foo2) - True - -There's a similar function, `moduleProvides`, that supports interface -declarations from within module definitions. For example, see the use -of `moduleProvides` call in `zope.interface.__init__`, which declares that -the package `zope.interface` provides `IInterfaceDeclaration`. - -Sometimes, we want to declare interfaces on instances, even though -those instances get interfaces from their classes. Suppose we create -a new interface, `ISpecial`:: - - >>> class ISpecial(zope.interface.Interface): - ... reason = zope.interface.Attribute("Reason why we're special") - ... def brag(): - ... "Brag about being special" - -We can make an existing foo instance special by providing `reason` -and `brag` attributes:: - - >>> foo.reason = 'I just am' - >>> def brag(): - ... return "I'm special!" - >>> foo.brag = brag - >>> foo.reason - 'I just am' - >>> foo.brag() - "I'm special!" - -and by declaring the interface:: - - >>> zope.interface.directlyProvides(foo, ISpecial) - -then the new interface is included in the provided interfaces:: - - >>> ISpecial.providedBy(foo) - True - >>> list(zope.interface.providedBy(foo)) - [, ] - -We can find out what interfaces are directly provided by an object:: - - >>> list(zope.interface.directlyProvidedBy(foo)) - [] - - >>> newfoo = Foo() - >>> list(zope.interface.directlyProvidedBy(newfoo)) - [] - -Inherited declarations ----------------------- - -Normally, declarations are inherited:: - - >>> class SpecialFoo(Foo): - ... zope.interface.implements(ISpecial) - ... reason = 'I just am' - ... def brag(self): - ... return "I'm special because %s" % self.reason - - >>> list(zope.interface.implementedBy(SpecialFoo)) - [, ] - - >>> list(zope.interface.providedBy(SpecialFoo())) - [, ] - -Sometimes, you don't want to inherit declarations. In that case, you -can use `implementsOnly`, instead of `implements`:: - - >>> class Special(Foo): - ... zope.interface.implementsOnly(ISpecial) - ... reason = 'I just am' - ... def brag(self): - ... return "I'm special because %s" % self.reason - - >>> list(zope.interface.implementedBy(Special)) - [] - - >>> list(zope.interface.providedBy(Special())) - [] - -External declarations ---------------------- - -Normally, we make implementation declarations as part of a class -definition. Sometimes, we may want to make declarations from outside -the class definition. For example, we might want to declare interfaces -for classes that we didn't write. The function `classImplements` can -be used for this purpose:: - - >>> class C: - ... pass - - >>> zope.interface.classImplements(C, IFoo) - >>> list(zope.interface.implementedBy(C)) - [] - -We can use `classImplementsOnly` to exclude inherited interfaces:: - - >>> class C(Foo): - ... pass - - >>> zope.interface.classImplementsOnly(C, ISpecial) - >>> list(zope.interface.implementedBy(C)) - [] - - - -Declaration Objects -------------------- - -When we declare interfaces, we create *declaration* objects. When we -query declarations, declaration objects are returned:: - - >>> type(zope.interface.implementedBy(Special)) - - -Declaration objects and interface objects are similar in many ways. In -fact, they share a common base class. The important thing to realize -about them is that they can be used where interfaces are expected in -declarations. Here's a silly example:: - - >>> class Special2(Foo): - ... zope.interface.implementsOnly( - ... zope.interface.implementedBy(Foo), - ... ISpecial, - ... ) - ... reason = 'I just am' - ... def brag(self): - ... return "I'm special because %s" % self.reason - -The declaration here is almost the same as -``zope.interface.implements(ISpecial)``, except that the order of -interfaces in the resulting declaration is different:: - - >>> list(zope.interface.implementedBy(Special2)) - [, ] - - -Interface Inheritance -===================== - -Interfaces can extend other interfaces. They do this simply by listing -the other interfaces as base interfaces:: - - >>> class IBlat(zope.interface.Interface): - ... """Blat blah blah""" - ... - ... y = zope.interface.Attribute("y blah blah") - ... def eek(): - ... """eek blah blah""" - - >>> IBlat.__bases__ - (,) - - >>> class IBaz(IFoo, IBlat): - ... """Baz blah""" - ... def eek(a=1): - ... """eek in baz blah""" - ... - - >>> IBaz.__bases__ - (, ) - - >>> names = list(IBaz) - >>> names.sort() - >>> names - ['bar', 'eek', 'x', 'y'] - -Note that `IBaz` overrides eek:: - - >>> IBlat['eek'].__doc__ - 'eek blah blah' - >>> IBaz['eek'].__doc__ - 'eek in baz blah' - -We were careful to override eek in a compatible way. When extending -an interface, the extending interface should be compatible [#compat]_ -with the extended interfaces. - -We can ask whether one interface extends another:: - - >>> IBaz.extends(IFoo) - True - >>> IBlat.extends(IFoo) - False - -Note that interfaces don't extend themselves:: - - >>> IBaz.extends(IBaz) - False - -Sometimes we wish they did, but we can, instead use `isOrExtends`:: - - >>> IBaz.isOrExtends(IBaz) - True - >>> IBaz.isOrExtends(IFoo) - True - >>> IFoo.isOrExtends(IBaz) - False - -When we iterate over an interface, we get all of the names it defines, -including names defined by base interfaces. Sometimes, we want *just* -the names defined by the interface directly. We bane use the `names` -method for that:: - - >>> list(IBaz.names()) - ['eek'] - -Inheritance of attribute specifications ---------------------------------------- - -An interface may override attribute definitions from base interfaces. -If two base interfaces define the same attribute, the attribute is -inherited from the most specific interface. For example, with: - - >>> class IBase(zope.interface.Interface): - ... - ... def foo(): - ... "base foo doc" - - >>> class IBase1(IBase): - ... pass - - >>> class IBase2(IBase): - ... - ... def foo(): - ... "base2 foo doc" - - >>> class ISub(IBase1, IBase2): - ... pass - -ISub's definition of foo is the one from IBase2, since IBase2 is more -specific that IBase: - - >>> ISub['foo'].__doc__ - 'base2 foo doc' - -Note that this differs from a depth-first search. - -Sometimes, it's useful to ask whether an interface defines an -attribute directly. You can use the direct method to get a directly -defined definitions: - - >>> IBase.direct('foo').__doc__ - 'base foo doc' - - >>> ISub.direct('foo') - -Specifications --------------- - -Interfaces and declarations are both special cases of specifications. -What we described above for interface inheritance applies to both -declarations and specifications. Declarations actually extend the -interfaces that they declare: - - >>> class Baz: - ... zope.interface.implements(IBaz) - - >>> baz_implements = zope.interface.implementedBy(Baz) - >>> baz_implements.__bases__ - (,) - - >>> baz_implements.extends(IFoo) - True - - >>> baz_implements.isOrExtends(IFoo) - True - >>> baz_implements.isOrExtends(baz_implements) - True - -Specifications (interfaces and declarations) provide an `__sro__` -that lists the specification and all of it's ancestors: - - >>> baz_implements.__sro__ - (, - , - , - , - ) - - -Tagged Values -============= - -Interfaces and attribute descriptions support an extension mechanism, -borrowed from UML, called "tagged values" that lets us store extra -data:: - - >>> IFoo.setTaggedValue('date-modified', '2004-04-01') - >>> IFoo.setTaggedValue('author', 'Jim Fulton') - >>> IFoo.getTaggedValue('date-modified') - '2004-04-01' - >>> IFoo.queryTaggedValue('date-modified') - '2004-04-01' - >>> IFoo.queryTaggedValue('datemodified') - >>> tags = list(IFoo.getTaggedValueTags()) - >>> tags.sort() - >>> tags - ['author', 'date-modified'] - -Function attributes are converted to tagged values when method -attribute definitions are created:: - - >>> class IBazFactory(zope.interface.Interface): - ... def __call__(): - ... "create one" - ... __call__.return_type = IBaz - - >>> IBazFactory['__call__'].getTaggedValue('return_type') - - - -Invariants -========== - -Interfaces can express conditions that must hold for objects that -provide them. These conditions are expressed using one or more -invariants. Invariants are callable objects that will be called with -an object that provides an interface. An invariant raises an `Invalid` -exception if the condition doesn't hold. Here's an example:: - - >>> class RangeError(zope.interface.Invalid): - ... """A range has invalid limits""" - ... def __repr__(self): - ... return "RangeError(%r)" % self.args - - >>> def range_invariant(ob): - ... if ob.max < ob.min: - ... raise RangeError(ob) - -Given this invariant, we can use it in an interface definition:: - - >>> class IRange(zope.interface.Interface): - ... min = zope.interface.Attribute("Lower bound") - ... max = zope.interface.Attribute("Upper bound") - ... - ... zope.interface.invariant(range_invariant) - -Interfaces have a method for checking their invariants:: - - >>> class Range(object): - ... zope.interface.implements(IRange) - ... - ... def __init__(self, min, max): - ... self.min, self.max = min, max - ... - ... def __repr__(self): - ... return "Range(%s, %s)" % (self.min, self.max) - - >>> IRange.validateInvariants(Range(1,2)) - >>> IRange.validateInvariants(Range(1,1)) - >>> IRange.validateInvariants(Range(2,1)) - Traceback (most recent call last): - ... - RangeError: Range(2, 1) - -If you have multiple invariants, you may not want to stop checking -after the first error. If you pass a list to `validateInvariants`, -then a single `Invalid` exception will be raised with the list of -exceptions as it's argument:: - - >>> errors = [] - >>> IRange.validateInvariants(Range(2,1), errors) - Traceback (most recent call last): - ... - Invalid: [RangeError(Range(2, 1))] - -And the list will be filled with the individual exceptions:: - - >>> errors - [RangeError(Range(2, 1))] - - - >>> del errors[:] - -========== -Adaptation -========== - -Interfaces can be called to perform adaptation. - -The sematics based on those of the PEP 246 adapt function. - -If an object cannot be adapted, then a TypeError is raised:: - - >>> class I(zope.interface.Interface): - ... pass - - >>> I(0) - Traceback (most recent call last): - ... - TypeError: ('Could not adapt', 0, ) - - - -unless an alternate value is provided as a second positional argument:: - - >>> I(0, 'bob') - 'bob' - -If an object already implements the interface, then it will be returned:: - - >>> class C(object): - ... zope.interface.implements(I) - - >>> obj = C() - >>> I(obj) is obj - True - -If an object implements __conform__, then it will be used:: - - >>> class C(object): - ... zope.interface.implements(I) - ... def __conform__(self, proto): - ... return 0 - - >>> I(C()) - 0 - -Adapter hooks (see __adapt__) will also be used, if present: - - >>> from zope.interface.interface import adapter_hooks - >>> def adapt_0_to_42(iface, obj): - ... if obj == 0: - ... return 42 - - >>> adapter_hooks.append(adapt_0_to_42) - >>> I(0) - 42 - - >>> adapter_hooks.remove(adapt_0_to_42) - >>> I(0) - Traceback (most recent call last): - ... - TypeError: ('Could not adapt', 0, ) - -__adapt__ -========= - - >>> class I(zope.interface.Interface): - ... pass - -Interfaces implement the PEP 246 __adapt__ method. - -This method is normally not called directly. It is called by the PEP -246 adapt framework and by the interface __call__ operator. - -The adapt method is responsible for adapting an object to the -reciever. - -The default version returns None:: - - >>> I.__adapt__(0) - -unless the object given provides the interface:: - - >>> class C(object): - ... zope.interface.implements(I) - - >>> obj = C() - >>> I.__adapt__(obj) is obj - True - -Adapter hooks can be provided (or removed) to provide custom -adaptation. We'll install a silly hook that adapts 0 to 42. -We install a hook by simply adding it to the adapter_hooks -list:: - - >>> from zope.interface.interface import adapter_hooks - >>> def adapt_0_to_42(iface, obj): - ... if obj == 0: - ... return 42 - - >>> adapter_hooks.append(adapt_0_to_42) - >>> I.__adapt__(0) - 42 - -Hooks must either return an adapter, or None if no adapter can -be found. - -Hooks can be uninstalled by removing them from the list:: - - >>> adapter_hooks.remove(adapt_0_to_42) - >>> I.__adapt__(0) - - -.. [#create] The main reason we subclass `Interface` is to cause the - Python class statement to create an interface, rather - than a class. - - It's possible to create interfaces by calling a special - interface class directly. Doing this, it's possible - (and, on rare occasions, useful) to create interfaces - that don't descend from `Interface`. Using this - technique is beyond the scope of this document. - -.. [#factory] Classes are factories. They can be called to create - their instances. We expect that we will eventually - extend the concept of implementation to other kinds of - factories, so that we can declare the interfaces - provided by the objects created. - -.. [#compat] The goal is substitutability. An object that provides an - extending interface should be substitutable for an object - that provides the extended interface. In our example, an - object that provides IBaz should be usable whereever an - object that provides IBlat is expected. - - The interface implementation doesn't enforce this. - but maybe it should do some checks. diff --git a/tools/buildbot/pylibs/zope/interface/SETUP.cfg b/tools/buildbot/pylibs/zope/interface/SETUP.cfg deleted file mode 100644 index 6efb798..0000000 --- a/tools/buildbot/pylibs/zope/interface/SETUP.cfg +++ /dev/null @@ -1,5 +0,0 @@ -# Extension information for zpkg: - - - source _zope_interface_coptimizations.c - diff --git a/tools/buildbot/pylibs/zope/interface/__init__.py b/tools/buildbot/pylibs/zope/interface/__init__.py deleted file mode 100644 index f45079b..0000000 --- a/tools/buildbot/pylibs/zope/interface/__init__.py +++ /dev/null @@ -1,80 +0,0 @@ -############################################################################## -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Interfaces - -This package implements the Python "scarecrow" proposal. - -The package exports two objects, `Interface` and `Attribute` directly. It also -exports several helper methods. Interface is used to create an interface with -a class statement, as in: - - class IMyInterface(Interface): - '''Interface documentation - ''' - - def meth(arg1, arg2): - '''Documentation for meth - ''' - - # Note that there is no self argument - -To find out what you can do with interfaces, see the interface -interface, `IInterface` in the `interfaces` module. - -The package has several public modules: - - o `declarations` provides utilities to declare interfaces on objects. It - also provides a wide range of helpful utilities that aid in managing - declared interfaces. Most of its public names are however imported here. - - o `document` has a utility for documenting an interface as structured text. - - o `exceptions` has the interface-defined exceptions - - o `interfaces` contains a list of all public interfaces for this package. - - o `verify` has utilities for verifying implementations of interfaces. - -See the module doc strings for more information. - -$Id: __init__.py 67630 2006-04-27 00:54:03Z jim $ -""" -__docformat__ = 'restructuredtext' - -from zope.interface.interface import Interface, _wire - -# Need to actually get the interface elements to implement the right interfaces -_wire() -del _wire - -from zope.interface.interface import Attribute, invariant - -from zope.interface.declarations import providedBy, implementedBy -from zope.interface.declarations import classImplements, classImplementsOnly -from zope.interface.declarations import directlyProvidedBy, directlyProvides -from zope.interface.declarations import alsoProvides, implementer -from zope.interface.declarations import implements, implementsOnly -from zope.interface.declarations import classProvides, moduleProvides -from zope.interface.declarations import noLongerProvides, Declaration -from zope.interface.exceptions import Invalid - -# The following are to make spec pickles cleaner -from zope.interface.declarations import Provides - - -from zope.interface.interfaces import IInterfaceDeclaration - -moduleProvides(IInterfaceDeclaration) - -__all__ = ('Interface', 'Attribute') + tuple(IInterfaceDeclaration) diff --git a/tools/buildbot/pylibs/zope/interface/_flatten.py b/tools/buildbot/pylibs/zope/interface/_flatten.py deleted file mode 100644 index f0df3a3..0000000 --- a/tools/buildbot/pylibs/zope/interface/_flatten.py +++ /dev/null @@ -1,37 +0,0 @@ -############################################################################## -# -# Copyright (c) 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Adapter-style interface registry - -See Adapter class. - -$Id: _flatten.py 26551 2004-07-15 07:06:37Z srichter $ -""" -from zope.interface import Declaration - -def _flatten(implements, include_None=0): - - try: - r = implements.flattened() - except AttributeError: - if implements is None: - r=() - else: - r = Declaration(implements).flattened() - - if not include_None: - return r - - r = list(r) - r.append(None) - return r diff --git a/tools/buildbot/pylibs/zope/interface/_zope_interface_coptimizations.pyd b/tools/buildbot/pylibs/zope/interface/_zope_interface_coptimizations.pyd deleted file mode 100644 index 15958a5..0000000 Binary files a/tools/buildbot/pylibs/zope/interface/_zope_interface_coptimizations.pyd and /dev/null differ diff --git a/tools/buildbot/pylibs/zope/interface/adapter.py b/tools/buildbot/pylibs/zope/interface/adapter.py deleted file mode 100644 index 0cb8949..0000000 --- a/tools/buildbot/pylibs/zope/interface/adapter.py +++ /dev/null @@ -1,644 +0,0 @@ -############################################################################## -# -# Copyright (c) 2004 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Adapter management - -$Id: adapter.py 67796 2006-05-01 13:55:44Z jim $ -""" - -import weakref -from zope.interface import providedBy, Interface, ro - -_marker = object -class BaseAdapterRegistry(object): - - # List of methods copied from lookup sub-objects: - _delegated = ('lookup', 'queryMultiAdapter', 'lookup1', 'queryAdapter', - 'adapter_hook', 'lookupAll', 'names', - 'subscriptions', 'subscribers') - - # All registries maintain a generation that can be used by verifying - # registries - _generation = 0 - - def __init__(self, bases=()): - - # {order -> {required -> {provided -> {name -> value}}}} - # where "interfaces" is really a nested key. So, for example: - # for order == 0, we have: - # {provided -> {name -> valie}} - # but for order == 2, we have: - # {r1 -> {r2 -> {provided -> {name -> valie}}}} - self._adapters = [] - - # {order -> {required -> {provided -> {name -> [value]}}}} - # where the remarks about adapters above apply - self._subscribers = [] - - # Set, with a reference count, keeping track of the interfaces - # for which we have provided components: - self._provided = {} - - # Looup object to perform lookup. We make this a separate object to - # to make it easier, in the furture, to implement just the lookup - # functionality in C. - self._createLookup() - - # Cache invalidation data. There are really 2 kinds of registries: - - # Invalidating registries have caches that are invalidated - # when they or when base registies change. An invalidating - # registry can only have invalidating registries as bases. - - # Verifying registies can't rely on getting invalidation message, - # so have to check the generations of base registries to determine - # if their cache data are current - - # Base registries: - self.__bases__ = bases - - def _setBases(self, bases): - self.__dict__['__bases__'] = bases - self.ro = ro.ro(self) - self.changed(self) - - __bases__ = property(lambda self: self.__dict__['__bases__'], - lambda self, bases: self._setBases(bases), - ) - - def _createLookup(self): - self._v_lookup = self.LookupClass(self) - for name in self._delegated: - self.__dict__[name] = getattr(self._v_lookup, name) - - def changed(self, originally_changed): - self._generation += 1 - self._v_lookup.changed(originally_changed) - - def register(self, required, provided, name, value): - if value is None: - self.unregister(required, provided, name, value) - return - - required = tuple(map(_convert_None_to_Interface, required)) - name = _normalize_name(name) - order = len(required) - byorder = self._adapters - while len(byorder) <= order: - byorder.append({}) - components = byorder[order] - key = required + (provided,) - - for k in key: - d = components.get(k) - if d is None: - d = {} - components[k] = d - components = d - - if components.get(name) == value: - return - - components[name] = value - - n = self._provided.get(provided, 0) + 1 - self._provided[provided] = n - if n == 1: - self._v_lookup.add_extendor(provided) - - self.changed(self) - - def registered(self, required, provided, name=u''): - required = tuple(map(_convert_None_to_Interface, required)) - name = _normalize_name(name) - order = len(required) - byorder = self._adapters - if len(byorder) <= order: - return None - - components = byorder[order] - key = required + (provided,) - - for k in key: - d = components.get(k) - if d is None: - return None - components = d - - return components.get(name) - - def unregister(self, required, provided, name, value=None): - required = tuple(map(_convert_None_to_Interface, required)) - order = len(required) - byorder = self._adapters - if order >= len(byorder): - return False - components = byorder[order] - key = required + (provided,) - - for k in key: - d = components.get(k) - if d is None: - return - components = d - - old = components.get(name) - if old is None: - return - if (value is not None) and (old != value): - return - - del components[name] - n = self._provided[provided] - 1 - if n == 0: - del self._provided[provided] - self._v_lookup.remove_extendor(provided) - else: - self._provided[provided] = n - - self.changed(self) - - return - - - def subscribe(self, required, provided, value): - required = tuple(map(_convert_None_to_Interface, required)) - name = u'' - order = len(required) - byorder = self._subscribers - while len(byorder) <= order: - byorder.append({}) - components = byorder[order] - key = required + (provided,) - - for k in key: - d = components.get(k) - if d is None: - d = {} - components[k] = d - components = d - - components[name] = components.get(name, ()) + (value, ) - - if provided is not None: - n = self._provided.get(provided, 0) + 1 - self._provided[provided] = n - if n == 1: - self._v_lookup.add_extendor(provided) - - self.changed(self) - - def unsubscribe(self, required, provided, value=None): - required = tuple(map(_convert_None_to_Interface, required)) - order = len(required) - byorder = self._subscribers - if order >= len(byorder): - return - components = byorder[order] - key = required + (provided,) - - for k in key: - d = components.get(k) - if d is None: - return - components = d - - old = components.get(u'') - if not old: - return - - if value is None: - new = () - else: - new = tuple([v for v in old if v != value]) - - if new == old: - return - - components[u''] = new - - if provided is not None: - n = self._provided[provided] + len(new) - len(old) - if n == 0: - del self._provided[provided] - self._v_lookup.remove_extendor(provided) - - self.changed(self) - - # XXX hack to fake out twisted's use of a private api. We need to get them - # to use the new registed method. - def get(self, _): - class XXXTwistedFakeOut: - selfImplied = {} - return XXXTwistedFakeOut - - -_not_in_mapping = object() -class LookupBasePy(object): - - def __init__(self): - self._cache = {} - self._mcache = {} - self._scache = {} - - def changed(self, ignored=None): - self._cache.clear() - self._mcache.clear() - self._scache.clear() - - def _getcache(self, provided, name): - cache = self._cache.get(provided) - if cache is None: - cache = {} - self._cache[provided] = cache - if name: - c = cache.get(name) - if c is None: - c = {} - cache[name] = c - cache = c - return cache - - def lookup(self, required, provided, name=u'', default=None): - cache = self._getcache(provided, name) - if len(required) == 1: - result = cache.get(required[0], _not_in_mapping) - else: - result = cache.get(tuple(required), _not_in_mapping) - - if result is _not_in_mapping: - result = self._uncached_lookup(required, provided, name) - if len(required) == 1: - cache[required[0]] = result - else: - cache[tuple(required)] = result - - if result is None: - return default - - return result - - def lookup1(self, required, provided, name=u'', default=None): - cache = self._getcache(provided, name) - result = cache.get(required, _not_in_mapping) - if result is _not_in_mapping: - return self.lookup((required, ), provided, name, default) - - if result is None: - return default - - return result - - def queryAdapter(self, object, provided, name=u'', default=None): - return self.adapter_hook(provided, object, name, default) - - def adapter_hook(self, provided, object, name=u'', default=None): - required = providedBy(object) - cache = self._getcache(provided, name) - factory = cache.get(required, _not_in_mapping) - if factory is _not_in_mapping: - factory = self.lookup((required, ), provided, name) - - if factory is not None: - result = factory(object) - if result is not None: - return result - - return default - - def lookupAll(self, required, provided): - cache = self._mcache.get(provided) - if cache is None: - cache = {} - self._mcache[provided] = cache - - required = tuple(required) - result = cache.get(required, _not_in_mapping) - if result is _not_in_mapping: - result = self._uncached_lookupAll(required, provided) - cache[required] = result - - return result - - - def subscriptions(self, required, provided): - cache = self._scache.get(provided) - if cache is None: - cache = {} - self._scache[provided] = cache - - required = tuple(required) - result = cache.get(required, _not_in_mapping) - if result is _not_in_mapping: - result = self._uncached_subscriptions(required, provided) - cache[required] = result - - return result - -LookupBase = LookupBasePy - -class VerifyingBasePy(LookupBasePy): - - def changed(self, originally_changed): - LookupBasePy.changed(self, originally_changed) - self._verify_ro = self._registry.ro[1:] - self._verify_generations = [r._generation for r in self._verify_ro] - - def _verify(self): - if ([r._generation for r in self._verify_ro] - != self._verify_generations): - self.changed(None) - - def _getcache(self, provided, name): - self._verify() - return LookupBasePy._getcache(self, provided, name) - - def lookupAll(self, required, provided): - self._verify() - return LookupBasePy.lookupAll(self, required, provided) - - def subscriptions(self, required, provided): - self._verify() - return LookupBasePy.subscriptions(self, required, provided) - -VerifyingBase = VerifyingBasePy - - -try: - import _zope_interface_coptimizations -except ImportError: - pass -else: - from _zope_interface_coptimizations import LookupBase, VerifyingBase - -class AdapterLookupBase(object): - - def __init__(self, registry): - self._registry = registry - self._required = {} - self.init_extendors() - super(AdapterLookupBase, self).__init__() - - def changed(self, ignored=None): - super(AdapterLookupBase, self).changed(None) - for r in self._required.keys(): - r = r() - if r is not None: - r.unsubscribe(self) - self._required.clear() - - - # Extendors - # --------- - - # When given an target interface for an adapter lookup, we need to consider - # adapters for interfaces that extend the target interface. This is - # what the extendors dictionary is about. It tells us all of the - # interfaces that extend an interface for which there are adapters - # registered. - - # We could separate this by order and name, thus reducing the - # number of provided interfaces to search at run time. The tradeoff, - # however, is that we have to store more information. For example, - # is the same interface is provided for multiple names and if the - # interface extends many interfaces, we'll have to keep track of - # a fair bit of information for each name. It's better to - # be space efficient here and be time efficient in the cache - # implementation. - - # TODO: add invalidation when a provided interface changes, in case - # the interface's __iro__ has changed. This is unlikely enough that - # we'll take our chances for now. - - def init_extendors(self): - self._extendors = {} - for p in self._registry._provided: - self.add_extendor(p) - - def add_extendor(self, provided): - _extendors = self._extendors - for i in provided.__iro__: - extendors = _extendors.get(i, ()) - _extendors[i] = ( - [e for e in extendors if provided.isOrExtends(e)] - + - [provided] - + - [e for e in extendors if not provided.isOrExtends(e)] - ) - - def remove_extendor(self, provided): - _extendors = self._extendors - for i in provided.__iro__: - _extendors[i] = [e for e in _extendors.get(i, ()) - if e != provided] - - - def _subscribe(self, *required): - _refs = self._required - for r in required: - ref = r.weakref() - if ref not in _refs: - r.subscribe(self) - _refs[ref] = 1 - - def _uncached_lookup(self, required, provided, name=u''): - result = None - order = len(required) - for registry in self._registry.ro: - byorder = registry._adapters - if order >= len(byorder): - continue - - extendors = registry._v_lookup._extendors.get(provided) - if not extendors: - continue - - components = byorder[order] - result = _lookup(components, required, extendors, name, 0, - order) - if result is not None: - break - - self._subscribe(*required) - - return result - - def queryMultiAdapter(self, objects, provided, name=u'', default=None): - factory = self.lookup(map(providedBy, objects), provided, name) - if factory is None: - return default - - result = factory(*objects) - if result is None: - return default - - return result - - def _uncached_lookupAll(self, required, provided): - order = len(required) - result = {} - for registry in reversed(self._registry.ro): - byorder = registry._adapters - if order >= len(byorder): - continue - extendors = registry._v_lookup._extendors.get(provided) - if not extendors: - continue - components = byorder[order] - _lookupAll(components, required, extendors, result, 0, order) - - self._subscribe(*required) - - return tuple(result.iteritems()) - - def names(self, required, provided): - return [c[0] for c in self.lookupAll(required, provided)] - - def _uncached_subscriptions(self, required, provided): - order = len(required) - result = [] - for registry in reversed(self._registry.ro): - byorder = registry._subscribers - if order >= len(byorder): - continue - - if provided is None: - extendors = (provided, ) - else: - extendors = registry._v_lookup._extendors.get(provided) - if extendors is None: - continue - - _subscriptions(byorder[order], required, extendors, u'', - result, 0, order) - - self._subscribe(*required) - - return result - - def subscribers(self, objects, provided): - subscriptions = self.subscriptions(map(providedBy, objects), provided) - if provided is None: - result = () - for subscription in subscriptions: - subscription(*objects) - else: - result = [] - for subscription in subscriptions: - subscriber = subscription(*objects) - if subscriber is not None: - result.append(subscriber) - return result - -class AdapterLookup(AdapterLookupBase, LookupBase): - pass - -class AdapterRegistry(BaseAdapterRegistry): - - LookupClass = AdapterLookup - - def __init__(self, bases=()): - # AdapterRegisties are invalidating registries, so - # we need to keep track of out invalidating subregistries. - self._v_subregistries = weakref.WeakKeyDictionary() - - super(AdapterRegistry, self).__init__(bases) - - def _addSubregistry(self, r): - self._v_subregistries[r] = 1 - - def _removeSubregistry(self, r): - if r in self._v_subregistries: - del self._v_subregistries[r] - - def _setBases(self, bases): - old = self.__dict__.get('__bases__', ()) - for r in old: - if r not in bases: - r._removeSubregistry(self) - for r in bases: - if r not in old: - r._addSubregistry(self) - - super(AdapterRegistry, self)._setBases(bases) - - def changed(self, originally_changed): - super(AdapterRegistry, self).changed(originally_changed) - - for sub in self._v_subregistries.keys(): - sub.changed(originally_changed) - - -class VerifyingAdapterLookup(AdapterLookupBase, VerifyingBase): - pass - -class VerifyingAdapterRegistry(BaseAdapterRegistry): - - LookupClass = VerifyingAdapterLookup - -def _convert_None_to_Interface(x): - if x is None: - return Interface - else: - return x - -def _normalize_name(name): - if isinstance(name, basestring): - return unicode(name) - - raise TypeError("name must be a regular or unicode string") - -def _lookup(components, specs, provided, name, i, l): - if i < l: - for spec in specs[i].__sro__: - comps = components.get(spec) - if comps: - r = _lookup(comps, specs, provided, name, i+1, l) - if r is not None: - return r - else: - for iface in provided: - comps = components.get(iface) - if comps: - r = comps.get(name) - if r is not None: - return r - - return None - -def _lookupAll(components, specs, provided, result, i, l): - if i < l: - for spec in reversed(specs[i].__sro__): - comps = components.get(spec) - if comps: - _lookupAll(comps, specs, provided, result, i+1, l) - else: - for iface in reversed(provided): - comps = components.get(iface) - if comps: - result.update(comps) - -def _subscriptions(components, specs, provided, name, result, i, l): - if i < l: - for spec in reversed(specs[i].__sro__): - comps = components.get(spec) - if comps: - _subscriptions(comps, specs, provided, name, result, i+1, l) - else: - for iface in reversed(provided): - comps = components.get(iface) - if comps: - comps = comps.get(name) - if comps: - result.extend(comps) diff --git a/tools/buildbot/pylibs/zope/interface/adapter.txt b/tools/buildbot/pylibs/zope/interface/adapter.txt deleted file mode 100644 index c065475..0000000 --- a/tools/buildbot/pylibs/zope/interface/adapter.txt +++ /dev/null @@ -1,546 +0,0 @@ -================ -Adapter Registry -================ - -Adapter registries provide a way to register objects that depend on -one or more interface specifications and provide (perhaps indirectly) -some interface. In addition, the registrations have names. (You can -think of the names as qualifiers of the provided interfaces.) - -The term "interface specification" refers both to interfaces and to -interface declarations, such as declarations of interfaces implemented -by a class. - - -Single Adapters -=============== - -Let's look at a simple example, using a single required specification:: - - >>> from zope.interface.adapter import AdapterRegistry - >>> import zope.interface - - >>> class IR1(zope.interface.Interface): - ... pass - >>> class IP1(zope.interface.Interface): - ... pass - >>> class IP2(IP1): - ... pass - - >>> registry = AdapterRegistry() - -We'll register an object that depends on IR1 and "provides" IP2:: - - >>> registry.register([IR1], IP2, '', 12) - -Given the registration, we can look it up again:: - - >>> registry.lookup([IR1], IP2, '') - 12 - -Note that we used an integer in the example. In real applications, -one would use some objects that actually depend on or provide -interfaces. The registry doesn't care about what gets registered, so -we'll use integers and strings to keep the examples simple. There is -one exception. Registering a value of None unregisters any -previously-registered value. - -If an object depends on a specification, it can be looked up with a -specification that extends the specification that it depends on:: - - >>> class IR2(IR1): - ... pass - >>> registry.lookup([IR2], IP2, '') - 12 - -We can use a class implementation specification to look up the object:: - - >>> class C2: - ... zope.interface.implements(IR2) - - >>> registry.lookup([zope.interface.implementedBy(C2)], IP2, '') - 12 - - -and it can be looked up for interfaces that its provided interface -extends:: - - >>> registry.lookup([IR1], IP1, '') - 12 - >>> registry.lookup([IR2], IP1, '') - 12 - -But if you require a specification that doesn't extend the specification the -object depends on, you won't get anything:: - - >>> registry.lookup([zope.interface.Interface], IP1, '') - -By the way, you can pass a default value to lookup:: - - >>> registry.lookup([zope.interface.Interface], IP1, '', 42) - 42 - -If you try to get an interface the object doesn't provide, you also -won't get anything:: - - >>> class IP3(IP2): - ... pass - >>> registry.lookup([IR1], IP3, '') - -You also won't get anything if you use the wrong name:: - - >>> registry.lookup([IR1], IP1, 'bob') - >>> registry.register([IR1], IP2, 'bob', "Bob's 12") - >>> registry.lookup([IR1], IP1, 'bob') - "Bob's 12" - -You can leave the name off when doing a lookup:: - - >>> registry.lookup([IR1], IP1) - 12 - -If we register an object that provides IP1:: - - >>> registry.register([IR1], IP1, '', 11) - -then that object will be prefered over O(12):: - - >>> registry.lookup([IR1], IP1, '') - 11 - -Also, if we register an object for IR2, then that will be prefered -when using IR2:: - - >>> registry.register([IR2], IP1, '', 21) - >>> registry.lookup([IR2], IP1, '') - 21 - -Finding out what, if anything, is registered --------------------------------------------- - -We can ask if there is an adapter registered for a collection of -interfaces. This is different than lookup, because it looks for an -exact match. - - >>> print registry.registered([IR1], IP1) - 11 - - >>> print registry.registered([IR1], IP2) - 12 - - >>> print registry.registered([IR1], IP2, 'bob') - Bob's 12 - - - >>> print registry.registered([IR2], IP1) - 21 - - >>> print registry.registered([IR2], IP2) - None - -In the last example, None was returned because nothing was registered -exactly for the given interfaces. - -lookup1 -------- - -Lookup of single adapters is common enough that there is a specialized -version of lookup that takes a single required interface:: - - >>> registry.lookup1(IR2, IP1, '') - 21 - >>> registry.lookup1(IR2, IP1) - 21 - -Actual Adaptation ------------------ - -The adapter registry is intended to support adaptation, where one -object that implements an interface is adapted to another object that -supports a different interface. The adapter registry supports the -computation of adapters. In this case, we have to register adapter -factories:: - - >>> class IR(zope.interface.Interface): - ... pass - - >>> class X: - ... zope.interface.implements(IR) - - >>> class Y: - ... zope.interface.implements(IP1) - ... def __init__(self, context): - ... self.context = context - - >>> registry.register([IR], IP1, '', Y) - -In this case, we registered a class as the factory. Now we can call -`queryAdapter` to get the adapted object:: - - >>> x = X() - >>> y = registry.queryAdapter(x, IP1) - >>> y.__class__.__name__ - 'Y' - >>> y.context is x - True - -We can register and lookup by name too:: - - >>> class Y2(Y): - ... pass - - >>> registry.register([IR], IP1, 'bob', Y2) - >>> y = registry.queryAdapter(x, IP1, 'bob') - >>> y.__class__.__name__ - 'Y2' - >>> y.context is x - True - -When the adapter factory produces `None`, then this is treated as if no -adapter has been found. This allows us to prevent adaptation (when desired) -and let the adapter factory determine whether adaptation is possible based on -the state of the object being adapted. - - >>> def factory(context): - ... if context.name == 'object': - ... return 'adapter' - ... return None - - >>> class Object(object): - ... zope.interface.implements(IR) - ... name = 'object' - - >>> registry.register([IR], IP1, 'conditional', factory) - >>> obj = Object() - >>> registry.queryAdapter(obj, IP1, 'conditional') - 'adapter' - >>> obj.name = 'no object' - >>> registry.queryAdapter(obj, IP1, 'conditional') is None - True - >>> registry.queryAdapter(obj, IP1, 'conditional', 'default') - 'default' - -An alternate method that provides the same function as `queryAdapter()` is -`adapter_hook()`:: - - >>> y = registry.adapter_hook(IP1, x) - >>> y.__class__.__name__ - 'Y' - >>> y.context is x - True - >>> y = registry.adapter_hook(IP1, x, 'bob') - >>> y.__class__.__name__ - 'Y2' - >>> y.context is x - True - -The `adapter_hook()` simply switches the order of the object and -interface arguments. It is used to hook into the interface call -mechanism. - - -Default Adapters ----------------- - -Sometimes, you want to provide an adapter that will adapt anything. -For that, provide None as the required interface:: - - >>> registry.register([None], IP1, '', 1) - -then we can use that adapter for interfaces we don't have specific -adapters for:: - - >>> class IQ(zope.interface.Interface): - ... pass - >>> registry.lookup([IQ], IP1, '') - 1 - -Of course, specific adapters are still used when applicable:: - - >>> registry.lookup([IR2], IP1, '') - 21 - -Class adapters --------------- - -You can register adapters for class declarations, which is almost the -same as registering them for a class:: - - >>> registry.register([zope.interface.implementedBy(C2)], IP1, '', 'C21') - >>> registry.lookup([zope.interface.implementedBy(C2)], IP1, '') - 'C21' - -Dict adapters -------------- - -At some point it was impossible to register dictionary-based adapters due a -bug. Let's make sure this works now: - - >>> adapter = {} - >>> registry.register((), IQ, '', adapter) - >>> registry.lookup((), IQ, '') is adapter - True - -Unregistering -------------- - -You can unregister by registering None, rather than an object:: - - >>> registry.register([zope.interface.implementedBy(C2)], IP1, '', None) - >>> registry.lookup([zope.interface.implementedBy(C2)], IP1, '') - 21 - -Of course, this means that None can't be registered. This is an -exception to the statement, made earlier, that the registry doesn't -care what gets registered. - -Multi-adapters -============== - -You can adapt multiple specifications:: - - >>> registry.register([IR1, IQ], IP2, '', '1q2') - >>> registry.lookup([IR1, IQ], IP2, '') - '1q2' - >>> registry.lookup([IR2, IQ], IP1, '') - '1q2' - - >>> class IS(zope.interface.Interface): - ... pass - >>> registry.lookup([IR2, IS], IP1, '') - - >>> class IQ2(IQ): - ... pass - - >>> registry.lookup([IR2, IQ2], IP1, '') - '1q2' - - >>> registry.register([IR1, IQ2], IP2, '', '1q22') - >>> registry.lookup([IR2, IQ2], IP1, '') - '1q22' - -Multi-adaptation ----------------- - -You can adapt multiple objects:: - - >>> class Q: - ... zope.interface.implements(IQ) - -As with single adapters, we register a factory, which is often a class:: - - >>> class IM(zope.interface.Interface): - ... pass - >>> class M: - ... zope.interface.implements(IM) - ... def __init__(self, x, q): - ... self.x, self.q = x, q - >>> registry.register([IR, IQ], IM, '', M) - -And then we can call `queryMultiAdapter` to compute an adapter:: - - >>> q = Q() - >>> m = registry.queryMultiAdapter((x, q), IM) - >>> m.__class__.__name__ - 'M' - >>> m.x is x and m.q is q - True - -and, of course, we can use names:: - - >>> class M2(M): - ... pass - >>> registry.register([IR, IQ], IM, 'bob', M2) - >>> m = registry.queryMultiAdapter((x, q), IM, 'bob') - >>> m.__class__.__name__ - 'M2' - >>> m.x is x and m.q is q - True - -Default Adapters ----------------- - -As with single adapters, you can define default adapters by specifying -None for the *first* specification:: - - >>> registry.register([None, IQ], IP2, '', 'q2') - >>> registry.lookup([IS, IQ], IP2, '') - 'q2' - -Null Adapters -============= - -You can also adapt no specification:: - - >>> registry.register([], IP2, '', 2) - >>> registry.lookup([], IP2, '') - 2 - >>> registry.lookup([], IP1, '') - 2 - -Listing named adapters ----------------------- - -Adapters are named. Sometimes, it's useful to get all of the named -adapters for given interfaces:: - - >>> adapters = list(registry.lookupAll([IR1], IP1)) - >>> adapters.sort() - >>> adapters - [(u'', 11), (u'bob', "Bob's 12")] - -This works for multi-adapters too:: - - >>> registry.register([IR1, IQ2], IP2, 'bob', '1q2 for bob') - >>> adapters = list(registry.lookupAll([IR2, IQ2], IP1)) - >>> adapters.sort() - >>> adapters - [(u'', '1q22'), (u'bob', '1q2 for bob')] - -And even null adapters:: - - >>> registry.register([], IP2, 'bob', 3) - >>> adapters = list(registry.lookupAll([], IP1)) - >>> adapters.sort() - >>> adapters - [(u'', 2), (u'bob', 3)] - -Subscriptions -============= - -Normally, we want to look up an object that most-closely matches a -specification. Sometimes, we want to get all of the objects that -match some specification. We use subscriptions for this. We -subscribe objects against specifications and then later find all of -the subscribed objects:: - - >>> registry.subscribe([IR1], IP2, 'sub12 1') - >>> registry.subscriptions([IR1], IP2) - ['sub12 1'] - -Note that, unlike regular adapters, subscriptions are unnamed. - -You can have multiple subscribers for the same specification:: - - >>> registry.subscribe([IR1], IP2, 'sub12 2') - >>> registry.subscriptions([IR1], IP2) - ['sub12 1', 'sub12 2'] - -If subscribers are registered for the same required interfaces, they -are returned in the order of definition. - -You can register subscribers for all specifications using None:: - - >>> registry.subscribe([None], IP1, 'sub_1') - >>> registry.subscriptions([IR2], IP1) - ['sub_1', 'sub12 1', 'sub12 2'] - -Note that the new subscriber is returned first. Subscribers defined -for more general required interfaces are returned before subscribers -for more general interfaces. - -Subscriptions may be combined over multiple compatible specifications:: - - >>> registry.subscriptions([IR2], IP1) - ['sub_1', 'sub12 1', 'sub12 2'] - >>> registry.subscribe([IR1], IP1, 'sub11') - >>> registry.subscriptions([IR2], IP1) - ['sub_1', 'sub12 1', 'sub12 2', 'sub11'] - >>> registry.subscribe([IR2], IP2, 'sub22') - >>> registry.subscriptions([IR2], IP1) - ['sub_1', 'sub12 1', 'sub12 2', 'sub11', 'sub22'] - >>> registry.subscriptions([IR2], IP2) - ['sub12 1', 'sub12 2', 'sub22'] - -Subscriptions can be on multiple specifications:: - - >>> registry.subscribe([IR1, IQ], IP2, 'sub1q2') - >>> registry.subscriptions([IR1, IQ], IP2) - ['sub1q2'] - -As with single subscriptions and non-subscription adapters, you can -specify None for the first required interface, to specify a default:: - - >>> registry.subscribe([None, IQ], IP2, 'sub_q2') - >>> registry.subscriptions([IS, IQ], IP2) - ['sub_q2'] - >>> registry.subscriptions([IR1, IQ], IP2) - ['sub_q2', 'sub1q2'] - -You can have subscriptions that are indepenent of any specifications:: - - >>> list(registry.subscriptions([], IP1)) - [] - - >>> registry.subscribe([], IP2, 'sub2') - >>> registry.subscriptions([], IP1) - ['sub2'] - >>> registry.subscribe([], IP1, 'sub1') - >>> registry.subscriptions([], IP1) - ['sub2', 'sub1'] - >>> registry.subscriptions([], IP2) - ['sub2'] - -Unregistering subscribers -------------------------- - -We can unregister subscribers. When unregistering a subscriber, we -can unregister a specific subscriber: - - >>> registry.unsubscribe([IR1], IP1, 'sub11') - >>> registry.subscriptions([IR1], IP1) - ['sub_1', 'sub12 1', 'sub12 2'] - -If we don't specify a value, then all subscribers matching the given -interfaces will be unsubscribed: - - >>> registry.unsubscribe([IR1], IP2) - >>> registry.subscriptions([IR1], IP1) - ['sub_1'] - - -Subscription adapters ---------------------- - -We normally register adapter factories, which then allow us to compute -adapters, but with subscriptions, we get multiple adapters. Here's an -example of multiple-object subscribers:: - - >>> registry.subscribe([IR, IQ], IM, M) - >>> registry.subscribe([IR, IQ], IM, M2) - - >>> subscribers = registry.subscribers((x, q), IM) - >>> len(subscribers) - 2 - >>> class_names = [s.__class__.__name__ for s in subscribers] - >>> class_names.sort() - >>> class_names - ['M', 'M2'] - >>> [(s.x is x and s.q is q) for s in subscribers] - [True, True] - -adapter factory subcribers can't return None values - - >>> def M3(x, y): - ... return None - - >>> registry.subscribe([IR, IQ], IM, M3) - >>> subscribers = registry.subscribers((x, q), IM) - >>> len(subscribers) - 2 - -Handlers --------- - -A handler is a subscriber factory that doesn't produce any normal -output. It returns None. A handler is unlike adapters in that it does -all of its work when the factory is called. - -To register a handler, simply provide None as the provided interface:: - - >>> def handler(event): - ... print 'handler', event - - >>> registry.subscribe([IR1], None, handler) - >>> registry.subscriptions([IR1], None) == [handler] - True diff --git a/tools/buildbot/pylibs/zope/interface/advice.py b/tools/buildbot/pylibs/zope/interface/advice.py deleted file mode 100644 index 2d9e038..0000000 --- a/tools/buildbot/pylibs/zope/interface/advice.py +++ /dev/null @@ -1,192 +0,0 @@ -############################################################################## -# -# Copyright (c) 2003 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Class advice. - -This module was adapted from 'protocols.advice', part of the Python -Enterprise Application Kit (PEAK). Please notify the PEAK authors -(pje@telecommunity.com and tsarna@sarna.org) if bugs are found or -Zope-specific changes are required, so that the PEAK version of this module -can be kept in sync. - -PEAK is a Python application framework that interoperates with (but does -not require) Zope 3 and Twisted. It provides tools for manipulating UML -models, object-relational persistence, aspect-oriented programming, and more. -Visit the PEAK home page at http://peak.telecommunity.com for more information. - -$Id: advice.py 25177 2004-06-02 13:17:31Z jim $ -""" - -from types import ClassType, FunctionType -import sys - -def getFrameInfo(frame): - """Return (kind,module,locals,globals) for a frame - - 'kind' is one of "exec", "module", "class", "function call", or "unknown". - """ - - f_locals = frame.f_locals - f_globals = frame.f_globals - - sameNamespace = f_locals is f_globals - hasModule = '__module__' in f_locals - hasName = '__name__' in f_globals - - sameName = hasModule and hasName - sameName = sameName and f_globals['__name__']==f_locals['__module__'] - - module = hasName and sys.modules.get(f_globals['__name__']) or None - - namespaceIsModule = module and module.__dict__ is f_globals - - if not namespaceIsModule: - # some kind of funky exec - kind = "exec" - elif sameNamespace and not hasModule: - kind = "module" - elif sameName and not sameNamespace: - kind = "class" - elif not sameNamespace: - kind = "function call" - else: - # How can you have f_locals is f_globals, and have '__module__' set? - # This is probably module-level code, but with a '__module__' variable. - kind = "unknown" - return kind, module, f_locals, f_globals - - -def addClassAdvisor(callback, depth=2): - """Set up 'callback' to be passed the containing class upon creation - - This function is designed to be called by an "advising" function executed - in a class suite. The "advising" function supplies a callback that it - wishes to have executed when the containing class is created. The - callback will be given one argument: the newly created containing class. - The return value of the callback will be used in place of the class, so - the callback should return the input if it does not wish to replace the - class. - - The optional 'depth' argument to this function determines the number of - frames between this function and the targeted class suite. 'depth' - defaults to 2, since this skips this function's frame and one calling - function frame. If you use this function from a function called directly - in the class suite, the default will be correct, otherwise you will need - to determine the correct depth yourself. - - This function works by installing a special class factory function in - place of the '__metaclass__' of the containing class. Therefore, only - callbacks *after* the last '__metaclass__' assignment in the containing - class will be executed. Be sure that classes using "advising" functions - declare any '__metaclass__' *first*, to ensure all callbacks are run.""" - - frame = sys._getframe(depth) - kind, module, caller_locals, caller_globals = getFrameInfo(frame) - - # This causes a problem when zope interfaces are used from doctest. - # In these cases, kind == "exec". - # - #if kind != "class": - # raise SyntaxError( - # "Advice must be in the body of a class statement" - # ) - - previousMetaclass = caller_locals.get('__metaclass__') - defaultMetaclass = caller_globals.get('__metaclass__', ClassType) - - - def advise(name, bases, cdict): - - if '__metaclass__' in cdict: - del cdict['__metaclass__'] - - if previousMetaclass is None: - if bases: - # find best metaclass or use global __metaclass__ if no bases - meta = determineMetaclass(bases) - else: - meta = defaultMetaclass - - elif isClassAdvisor(previousMetaclass): - # special case: we can't compute the "true" metaclass here, - # so we need to invoke the previous metaclass and let it - # figure it out for us (and apply its own advice in the process) - meta = previousMetaclass - - else: - meta = determineMetaclass(bases, previousMetaclass) - - newClass = meta(name,bases,cdict) - - # this lets the callback replace the class completely, if it wants to - return callback(newClass) - - # introspection data only, not used by inner function - advise.previousMetaclass = previousMetaclass - advise.callback = callback - - # install the advisor - caller_locals['__metaclass__'] = advise - - -def isClassAdvisor(ob): - """True if 'ob' is a class advisor function""" - return isinstance(ob,FunctionType) and hasattr(ob,'previousMetaclass') - - -def determineMetaclass(bases, explicit_mc=None): - """Determine metaclass from 1+ bases and optional explicit __metaclass__""" - - meta = [getattr(b,'__class__',type(b)) for b in bases] - - if explicit_mc is not None: - # The explicit metaclass needs to be verified for compatibility - # as well, and allowed to resolve the incompatible bases, if any - meta.append(explicit_mc) - - if len(meta)==1: - # easy case - return meta[0] - - candidates = minimalBases(meta) # minimal set of metaclasses - - if not candidates: - # they're all "classic" classes - return ClassType - - elif len(candidates)>1: - # We could auto-combine, but for now we won't... - raise TypeError("Incompatible metatypes",bases) - - # Just one, return it - return candidates[0] - - -def minimalBases(classes): - """Reduce a list of base classes to its ordered minimum equivalent""" - - classes = [c for c in classes if c is not ClassType] - candidates = [] - - for m in classes: - for n in classes: - if issubclass(n,m) and m is not n: - break - else: - # m has no subclasses in 'classes' - if m in candidates: - candidates.remove(m) # ensure that we're later in the list - candidates.append(m) - - return candidates - diff --git a/tools/buildbot/pylibs/zope/interface/common/__init__.py b/tools/buildbot/pylibs/zope/interface/common/__init__.py deleted file mode 100644 index b711d36..0000000 --- a/tools/buildbot/pylibs/zope/interface/common/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# -# This file is necessary to make this directory a package. diff --git a/tools/buildbot/pylibs/zope/interface/common/idatetime.py b/tools/buildbot/pylibs/zope/interface/common/idatetime.py deleted file mode 100644 index c77ea15..0000000 --- a/tools/buildbot/pylibs/zope/interface/common/idatetime.py +++ /dev/null @@ -1,577 +0,0 @@ -############################################################################## -# Copyright (c) 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -############################################################################## -"""Datetime interfaces. - -This module is called idatetime because if it were called datetime the import -of the real datetime would fail. - -$Id: idatetime.py 25177 2004-06-02 13:17:31Z jim $ -""" - -from zope.interface import Interface, Attribute -from zope.interface import classImplements, directlyProvides - -from datetime import timedelta, date, datetime, time, tzinfo - - -class ITimeDeltaClass(Interface): - """This is the timedelta class interface.""" - - min = Attribute("The most negative timedelta object") - - max = Attribute("The most positive timedelta object") - - resolution = Attribute( - "The smallest difference between non-equal timedelta objects") - - -class ITimeDelta(ITimeDeltaClass): - """Represent the difference between two datetime objects. - - Supported operators: - - - add, subtract timedelta - - unary plus, minus, abs - - compare to timedelta - - multiply, divide by int/long - - In addition, datetime supports subtraction of two datetime objects - returning a timedelta, and addition or subtraction of a datetime - and a timedelta giving a datetime. - - Representation: (days, seconds, microseconds). - """ - - days = Attribute("Days between -999999999 and 999999999 inclusive") - - seconds = Attribute("Seconds between 0 and 86399 inclusive") - - microseconds = Attribute("Microseconds between 0 and 999999 inclusive") - - -class IDateClass(Interface): - """This is the date class interface.""" - - min = Attribute("The earliest representable date") - - max = Attribute("The latest representable date") - - resolution = Attribute( - "The smallest difference between non-equal date objects") - - def today(): - """Return the current local time. - - This is equivalent to date.fromtimestamp(time.time())""" - - def fromtimestamp(timestamp): - """Return the local date from a POSIX timestamp (like time.time()) - - This may raise ValueError, if the timestamp is out of the range of - values supported by the platform C localtime() function. It's common - for this to be restricted to years from 1970 through 2038. Note that - on non-POSIX systems that include leap seconds in their notion of a - timestamp, leap seconds are ignored by fromtimestamp(). - """ - - def fromordinal(ordinal): - """Return the date corresponding to the proleptic Gregorian ordinal. - - January 1 of year 1 has ordinal 1. ValueError is raised unless - 1 <= ordinal <= date.max.toordinal(). - For any date d, date.fromordinal(d.toordinal()) == d. - """ - - -class IDate(IDateClass): - """Represents a date (year, month and day) in an idealized calendar. - - Operators: - - __repr__, __str__ - __cmp__, __hash__ - __add__, __radd__, __sub__ (add/radd only with timedelta arg) - """ - - year = Attribute("Between MINYEAR and MAXYEAR inclusive.") - - month = Attribute("Between 1 and 12 inclusive") - - day = Attribute( - "Between 1 and the number of days in the given month of the given year.") - - def replace(year, month, day): - """Return a date with the same value. - - Except for those members given new values by whichever keyword - arguments are specified. For example, if d == date(2002, 12, 31), then - d.replace(day=26) == date(2000, 12, 26). - """ - - def timetuple(): - """Return a 9-element tuple of the form returned by time.localtime(). - - The hours, minutes and seconds are 0, and the DST flag is -1. - d.timetuple() is equivalent to - (d.year, d.month, d.day, 0, 0, 0, d.weekday(), d.toordinal() - - date(d.year, 1, 1).toordinal() + 1, -1) - """ - - def toordinal(): - """Return the proleptic Gregorian ordinal of the date - - January 1 of year 1 has ordinal 1. For any date object d, - date.fromordinal(d.toordinal()) == d. - """ - - def weekday(): - """Return the day of the week as an integer. - - Monday is 0 and Sunday is 6. For example, - date(2002, 12, 4).weekday() == 2, a Wednesday. - - See also isoweekday(). - """ - - def isoweekday(): - """Return the day of the week as an integer. - - Monday is 1 and Sunday is 7. For example, - date(2002, 12, 4).isoweekday() == 3, a Wednesday. - - See also weekday(), isocalendar(). - """ - - def isocalendar(): - """Return a 3-tuple, (ISO year, ISO week number, ISO weekday). - - The ISO calendar is a widely used variant of the Gregorian calendar. - See http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm for a good - explanation. - - The ISO year consists of 52 or 53 full weeks, and where a week starts - on a Monday and ends on a Sunday. The first week of an ISO year is the - first (Gregorian) calendar week of a year containing a Thursday. This - is called week number 1, and the ISO year of that Thursday is the same - as its Gregorian year. - - For example, 2004 begins on a Thursday, so the first week of ISO year - 2004 begins on Monday, 29 Dec 2003 and ends on Sunday, 4 Jan 2004, so - that date(2003, 12, 29).isocalendar() == (2004, 1, 1) and - date(2004, 1, 4).isocalendar() == (2004, 1, 7). - """ - - def isoformat(): - """Return a string representing the date in ISO 8601 format. - - This is 'YYYY-MM-DD'. - For example, date(2002, 12, 4).isoformat() == '2002-12-04'. - """ - - def __str__(): - """For a date d, str(d) is equivalent to d.isoformat().""" - - def ctime(): - """Return a string representing the date. - - For example date(2002, 12, 4).ctime() == 'Wed Dec 4 00:00:00 2002'. - d.ctime() is equivalent to time.ctime(time.mktime(d.timetuple())) - on platforms where the native C ctime() function - (which time.ctime() invokes, but which date.ctime() does not invoke) - conforms to the C standard. - """ - - def strftime(format): - """Return a string representing the date. - - Controlled by an explicit format string. Format codes referring to - hours, minutes or seconds will see 0 values. - """ - - -class IDateTimeClass(Interface): - """This is the datetime class interface.""" - - min = Attribute("The earliest representable datetime") - - max = Attribute("The latest representable datetime") - - resolution = Attribute( - "The smallest possible difference between non-equal datetime objects") - - def today(): - """Return the current local datetime, with tzinfo None. - - This is equivalent to datetime.fromtimestamp(time.time()). - See also now(), fromtimestamp(). - """ - - def now(tz=None): - """Return the current local date and time. - - If optional argument tz is None or not specified, this is like today(), - but, if possible, supplies more precision than can be gotten from going - through a time.time() timestamp (for example, this may be possible on - platforms supplying the C gettimeofday() function). - - Else tz must be an instance of a class tzinfo subclass, and the current - date and time are converted to tz's time zone. In this case the result - is equivalent to tz.fromutc(datetime.utcnow().replace(tzinfo=tz)). - - See also today(), utcnow(). - """ - - def utcnow(): - """Return the current UTC date and time, with tzinfo None. - - This is like now(), but returns the current UTC date and time, as a - naive datetime object. - - See also now(). - """ - - def fromtimestamp(timestamp, tz=None): - """Return the local date and time corresponding to the POSIX timestamp. - - Same as is returned by time.time(). If optional argument tz is None or - not specified, the timestamp is converted to the platform's local date - and time, and the returned datetime object is naive. - - Else tz must be an instance of a class tzinfo subclass, and the - timestamp is converted to tz's time zone. In this case the result is - equivalent to - tz.fromutc(datetime.utcfromtimestamp(timestamp).replace(tzinfo=tz)). - - fromtimestamp() may raise ValueError, if the timestamp is out of the - range of values supported by the platform C localtime() or gmtime() - functions. It's common for this to be restricted to years in 1970 - through 2038. Note that on non-POSIX systems that include leap seconds - in their notion of a timestamp, leap seconds are ignored by - fromtimestamp(), and then it's possible to have two timestamps - differing by a second that yield identical datetime objects. - - See also utcfromtimestamp(). - """ - - def utcfromtimestamp(timestamp): - """Return the UTC datetime from the POSIX timestamp with tzinfo None. - - This may raise ValueError, if the timestamp is out of the range of - values supported by the platform C gmtime() function. It's common for - this to be restricted to years in 1970 through 2038. - - See also fromtimestamp(). - """ - - def fromordinal(ordinal): - """Return the datetime from the proleptic Gregorian ordinal. - - January 1 of year 1 has ordinal 1. ValueError is raised unless - 1 <= ordinal <= datetime.max.toordinal(). - The hour, minute, second and microsecond of the result are all 0, and - tzinfo is None. - """ - - def combine(date, time): - """Return a new datetime object. - - Its date members are equal to the given date object's, and whose time - and tzinfo members are equal to the given time object's. For any - datetime object d, d == datetime.combine(d.date(), d.timetz()). - If date is a datetime object, its time and tzinfo members are ignored. - """ - - -class IDateTime(IDate, IDateTimeClass): - """Object contains all the information from a date object and a time object. - """ - - year = Attribute("Year between MINYEAR and MAXYEAR inclusive") - - month = Attribute("Month between 1 and 12 inclusive") - - day = Attribute( - "Day between 1 and the number of days in the given month of the year") - - hour = Attribute("Hour in range(24)") - - minute = Attribute("Minute in range(60)") - - second = Attribute("Second in range(60)") - - microsecond = Attribute("Microsecond in range(1000000)") - - tzinfo = Attribute( - """The object passed as the tzinfo argument to the datetime constructor - or None if none was passed""") - - def date(): - """Return date object with same year, month and day.""" - - def time(): - """Return time object with same hour, minute, second, microsecond. - - tzinfo is None. See also method timetz(). - """ - - def timetz(): - """Return time object with same hour, minute, second, microsecond, - and tzinfo. - - See also method time(). - """ - - def replace(year, month, day, hour, minute, second, microsecond, tzinfo): - """Return a datetime with the same members, except for those members - given new values by whichever keyword arguments are specified. - - Note that tzinfo=None can be specified to create a naive datetime from - an aware datetime with no conversion of date and time members. - """ - - def astimezone(tz): - """Return a datetime object with new tzinfo member tz, adjusting the - date and time members so the result is the same UTC time as self, but - in tz's local time. - - tz must be an instance of a tzinfo subclass, and its utcoffset() and - dst() methods must not return None. self must be aware (self.tzinfo - must not be None, and self.utcoffset() must not return None). - - If self.tzinfo is tz, self.astimezone(tz) is equal to self: no - adjustment of date or time members is performed. Else the result is - local time in time zone tz, representing the same UTC time as self: - after astz = dt.astimezone(tz), astz - astz.utcoffset() - will usually have the same date and time members as dt - dt.utcoffset(). - The discussion of class tzinfo explains the cases at Daylight Saving - Time transition boundaries where this cannot be achieved (an issue only - if tz models both standard and daylight time). - - If you merely want to attach a time zone object tz to a datetime dt - without adjustment of date and time members, use dt.replace(tzinfo=tz). - If you merely want to remove the time zone object from an aware - datetime dt without conversion of date and time members, use - dt.replace(tzinfo=None). - - Note that the default tzinfo.fromutc() method can be overridden in a - tzinfo subclass to effect the result returned by astimezone(). - """ - - def utcoffset(): - """Return the timezone offset in minutes east of UTC (negative west of - UTC).""" - - def dst(): - """Return 0 if DST is not in effect, or the DST offset (in minutes - eastward) if DST is in effect. - """ - - def tzname(): - """Return the timezone name.""" - - def timetuple(): - """Return a 9-element tuple of the form returned by time.localtime().""" - - def utctimetuple(): - """Return UTC time tuple compatilble with time.gmtimr().""" - - def toordinal(): - """Return the proleptic Gregorian ordinal of the date. - - The same as self.date().toordinal(). - """ - - def weekday(): - """Return the day of the week as an integer. - - Monday is 0 and Sunday is 6. The same as self.date().weekday(). - See also isoweekday(). - """ - - def isoweekday(): - """Return the day of the week as an integer. - - Monday is 1 and Sunday is 7. The same as self.date().isoweekday. - See also weekday(), isocalendar(). - """ - - def isocalendar(): - """Return a 3-tuple, (ISO year, ISO week number, ISO weekday). - - The same as self.date().isocalendar(). - """ - - def isoformat(sep='T'): - """Return a string representing the date and time in ISO 8601 format. - - YYYY-MM-DDTHH:MM:SS.mmmmmm or YYYY-MM-DDTHH:MM:SS if microsecond is 0 - - If utcoffset() does not return None, a 6-character string is appended, - giving the UTC offset in (signed) hours and minutes: - - YYYY-MM-DDTHH:MM:SS.mmmmmm+HH:MM or YYYY-MM-DDTHH:MM:SS+HH:MM - if microsecond is 0. - - The optional argument sep (default 'T') is a one-character separator, - placed between the date and time portions of the result. - """ - - def __str__(): - """For a datetime instance d, str(d) is equivalent to d.isoformat(' '). - """ - - def ctime(): - """Return a string representing the date and time. - - datetime(2002, 12, 4, 20, 30, 40).ctime() == 'Wed Dec 4 20:30:40 2002'. - d.ctime() is equivalent to time.ctime(time.mktime(d.timetuple())) on - platforms where the native C ctime() function (which time.ctime() - invokes, but which datetime.ctime() does not invoke) conforms to the - C standard. - """ - - def strftime(format): - """Return a string representing the date and time. - - This is controlled by an explicit format string. - """ - - -class ITimeClass(Interface): - """This is the time class interface.""" - - min = Attribute("The earliest representable time") - - max = Attribute("The latest representable time") - - resolution = Attribute( - "The smallest possible difference between non-equal time objects") - - -class ITime(ITimeClass): - """Represent time with time zone. - - Operators: - - __repr__, __str__ - __cmp__, __hash__ - """ - - hour = Attribute("Hour in range(24)") - - minute = Attribute("Minute in range(60)") - - second = Attribute("Second in range(60)") - - microsecond = Attribute("Microsecond in range(1000000)") - - tzinfo = Attribute( - """The object passed as the tzinfo argument to the time constructor - or None if none was passed.""") - - def replace(hour, minute, second, microsecond, tzinfo): - """Return a time with the same value. - - Except for those members given new values by whichever keyword - arguments are specified. Note that tzinfo=None can be specified - to create a naive time from an aware time, without conversion of the - time members. - """ - - def isoformat(): - """Return a string representing the time in ISO 8601 format. - - That is HH:MM:SS.mmmmmm or, if self.microsecond is 0, HH:MM:SS - If utcoffset() does not return None, a 6-character string is appended, - giving the UTC offset in (signed) hours and minutes: - HH:MM:SS.mmmmmm+HH:MM or, if self.microsecond is 0, HH:MM:SS+HH:MM - """ - - def __str__(): - """For a time t, str(t) is equivalent to t.isoformat().""" - - def strftime(format): - """Return a string representing the time. - - This is controlled by an explicit format string. - """ - - def utcoffset(): - """Return the timezone offset in minutes east of UTC (negative west of - UTC). - - If tzinfo is None, returns None, else returns - self.tzinfo.utcoffset(None), and raises an exception if the latter - doesn't return None or a timedelta object representing a whole number - of minutes with magnitude less than one day. - """ - - def dst(): - """Return 0 if DST is not in effect, or the DST offset (in minutes - eastward) if DST is in effect. - - If tzinfo is None, returns None, else returns self.tzinfo.dst(None), - and raises an exception if the latter doesn't return None, or a - timedelta object representing a whole number of minutes with - magnitude less than one day. - """ - - def tzname(): - """Return the timezone name. - - If tzinfo is None, returns None, else returns self.tzinfo.tzname(None), - or raises an exception if the latter doesn't return None or a string - object. - """ - - -class ITZInfo(Interface): - """Time zone info class. - """ - - def utcoffset(dt): - """Return offset of local time from UTC, in minutes east of UTC. - - If local time is west of UTC, this should be negative. - Note that this is intended to be the total offset from UTC; - for example, if a tzinfo object represents both time zone and DST - adjustments, utcoffset() should return their sum. If the UTC offset - isn't known, return None. Else the value returned must be a timedelta - object specifying a whole number of minutes in the range -1439 to 1439 - inclusive (1440 = 24*60; the magnitude of the offset must be less - than one day). - """ - - def dst(dt): - """Return the daylight saving time (DST) adjustment, in minutes east - of UTC, or None if DST information isn't known. - """ - - def tzname(dt): - """Return the time zone name corresponding to the datetime object as - a string. - """ - - def fromutc(dt): - """Return an equivalent datetime in self's local time.""" - - -classImplements(timedelta, ITimeDelta) -classImplements(date, IDate) -classImplements(datetime, IDateTime) -classImplements(time, ITime) -classImplements(tzinfo, ITZInfo) - -## directlyProvides(timedelta, ITimeDeltaClass) -## directlyProvides(date, IDateClass) -## directlyProvides(datetime, IDateTimeClass) -## directlyProvides(time, ITimeClass) diff --git a/tools/buildbot/pylibs/zope/interface/common/interfaces.py b/tools/buildbot/pylibs/zope/interface/common/interfaces.py deleted file mode 100644 index a8585b0..0000000 --- a/tools/buildbot/pylibs/zope/interface/common/interfaces.py +++ /dev/null @@ -1,98 +0,0 @@ -############################################################################## -# -# Copyright (c) 2003 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Interfaces for standard python exceptions - -$Id: interfaces.py 25177 2004-06-02 13:17:31Z jim $ -""" -from zope.interface import Interface -from zope.interface import classImplements - -class IException(Interface): pass -class IStandardError(IException): pass -class IWarning(IException): pass -class ISyntaxError(IStandardError): pass -class ILookupError(IStandardError): pass -class IValueError(IStandardError): pass -class IRuntimeError(IStandardError): pass -class IArithmeticError(IStandardError): pass -class IAssertionError(IStandardError): pass -class IAttributeError(IStandardError): pass -class IDeprecationWarning(IWarning): pass -class IEOFError(IStandardError): pass -class IEnvironmentError(IStandardError): pass -class IFloatingPointError(IArithmeticError): pass -class IIOError(IEnvironmentError): pass -class IImportError(IStandardError): pass -class IIndentationError(ISyntaxError): pass -class IIndexError(ILookupError): pass -class IKeyError(ILookupError): pass -class IKeyboardInterrupt(IStandardError): pass -class IMemoryError(IStandardError): pass -class INameError(IStandardError): pass -class INotImplementedError(IRuntimeError): pass -class IOSError(IEnvironmentError): pass -class IOverflowError(IArithmeticError): pass -class IOverflowWarning(IWarning): pass -class IReferenceError(IStandardError): pass -class IRuntimeWarning(IWarning): pass -class IStopIteration(IException): pass -class ISyntaxWarning(IWarning): pass -class ISystemError(IStandardError): pass -class ISystemExit(IException): pass -class ITabError(IIndentationError): pass -class ITypeError(IStandardError): pass -class IUnboundLocalError(INameError): pass -class IUnicodeError(IValueError): pass -class IUserWarning(IWarning): pass -class IZeroDivisionError(IArithmeticError): pass - -classImplements(ArithmeticError, IArithmeticError) -classImplements(AssertionError, IAssertionError) -classImplements(AttributeError, IAttributeError) -classImplements(DeprecationWarning, IDeprecationWarning) -classImplements(EnvironmentError, IEnvironmentError) -classImplements(EOFError, IEOFError) -classImplements(Exception, IException) -classImplements(FloatingPointError, IFloatingPointError) -classImplements(ImportError, IImportError) -classImplements(IndentationError, IIndentationError) -classImplements(IndexError, IIndexError) -classImplements(IOError, IIOError) -classImplements(KeyboardInterrupt, IKeyboardInterrupt) -classImplements(KeyError, IKeyError) -classImplements(LookupError, ILookupError) -classImplements(MemoryError, IMemoryError) -classImplements(NameError, INameError) -classImplements(NotImplementedError, INotImplementedError) -classImplements(OSError, IOSError) -classImplements(OverflowError, IOverflowError) -classImplements(OverflowWarning, IOverflowWarning) -classImplements(ReferenceError, IReferenceError) -classImplements(RuntimeError, IRuntimeError) -classImplements(RuntimeWarning, IRuntimeWarning) -classImplements(StandardError, IStandardError) -classImplements(StopIteration, IStopIteration) -classImplements(SyntaxError, ISyntaxError) -classImplements(SyntaxWarning, ISyntaxWarning) -classImplements(SystemError, ISystemError) -classImplements(SystemExit, ISystemExit) -classImplements(TabError, ITabError) -classImplements(TypeError, ITypeError) -classImplements(UnboundLocalError, IUnboundLocalError) -classImplements(UnicodeError, IUnicodeError) -classImplements(UserWarning, IUserWarning) -classImplements(ValueError, IValueError) -classImplements(Warning, IWarning) -classImplements(ZeroDivisionError, IZeroDivisionError) - diff --git a/tools/buildbot/pylibs/zope/interface/common/mapping.py b/tools/buildbot/pylibs/zope/interface/common/mapping.py deleted file mode 100644 index ba29fd8..0000000 --- a/tools/buildbot/pylibs/zope/interface/common/mapping.py +++ /dev/null @@ -1,127 +0,0 @@ -############################################################################## -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Mapping Interfaces - -$Id: mapping.py 29359 2005-03-01 15:45:04Z poster $ -""" -from zope.interface import Interface - -class IItemMapping(Interface): - """Simplest readable mapping object - """ - - def __getitem__(key): - """Get a value for a key - - A KeyError is raised if there is no value for the key. - """ - - -class IReadMapping(IItemMapping): - """Basic mapping interface - """ - - def get(key, default=None): - """Get a value for a key - - The default is returned if there is no value for the key. - """ - - def __contains__(key): - """Tell if a key exists in the mapping.""" - - -class IWriteMapping(Interface): - """Mapping methods for changing data""" - - def __delitem__(key): - """Delete a value from the mapping using the key.""" - - def __setitem__(key, value): - """Set a new item in the mapping.""" - - -class IEnumerableMapping(IReadMapping): - """Mapping objects whose items can be enumerated. - """ - - def keys(): - """Return the keys of the mapping object. - """ - - def __iter__(): - """Return an iterator for the keys of the mapping object. - """ - - def values(): - """Return the values of the mapping object. - """ - - def items(): - """Return the items of the mapping object. - """ - - def __len__(): - """Return the number of items. - """ - -class IMapping(IWriteMapping, IEnumerableMapping): - ''' Simple mapping interface ''' - -class IIterableMapping(IEnumerableMapping): - - def iterkeys(): - "iterate over keys; equivalent to __iter__" - - def itervalues(): - "iterate over values" - - def iteritems(): - "iterate over items" - -class IClonableMapping(Interface): - - def copy(): - "return copy of dict" - -class IExtendedReadMapping(IIterableMapping): - - def has_key(key): - """Tell if a key exists in the mapping; equivalent to __contains__""" - -class IExtendedWriteMapping(IWriteMapping): - - def clear(): - "delete all items" - - def update(d): - " Update D from E: for k in E.keys(): D[k] = E[k]" - - def setdefault(key, default=None): - "D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D" - - def pop(k, *args): - """remove specified key and return the corresponding value - *args may contain a single default value, or may not be supplied. - If key is not found, default is returned if given, otherwise - KeyError is raised""" - - def popitem(): - """remove and return some (key, value) pair as a - 2-tuple; but raise KeyError if mapping is empty""" - -class IFullMapping( - IExtendedReadMapping, IExtendedWriteMapping, IClonableMapping, IMapping): - ''' Full mapping interface ''' # IMapping included so tests for IMapping - # succeed with IFullMapping diff --git a/tools/buildbot/pylibs/zope/interface/common/sequence.py b/tools/buildbot/pylibs/zope/interface/common/sequence.py deleted file mode 100644 index 054d137..0000000 --- a/tools/buildbot/pylibs/zope/interface/common/sequence.py +++ /dev/null @@ -1,152 +0,0 @@ -############################################################################## -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Sequence Interfaces - -$Id: sequence.py 39752 2005-10-30 20:16:09Z srichter $ -""" -__docformat__ = 'restructuredtext' -from zope import interface - -class IMinimalSequence(interface.Interface): - - def __getitem__(index): - """`x.__getitem__(index)` <==> `x[index]` - - Declaring this interface does not specify whether `__getitem__` - supports slice objects.""" - - def __iter__(): - """`x.__iter__()` <==> `iter(x)`""" - -class IFiniteSequence(IMinimalSequence): - - def __len__(): - """`x.__len__()` <==> `len(x)`""" - -class IReadSequence(IFiniteSequence): - """read interface shared by tuple and list""" - - def __contains__(item): - """`x.__contains__(item)` <==> `item in x`""" - - def __lt__(other): - """`x.__lt__(other)` <==> `x < other`""" - - def __le__(other): - """`x.__le__(other)` <==> `x <= other`""" - - def __eq__(other): - """`x.__eq__(other)` <==> `x == other`""" - - def __ne__(other): - """`x.__ne__(other)` <==> `x != other`""" - - def __gt__(other): - """`x.__gt__(other)` <==> `x > other`""" - - def __ge__(other): - """`x.__ge__(other)` <==> `x >= other`""" - - def __add__(other): - """`x.__add__(other)` <==> `x + other`""" - - def __mul__(n): - """`x.__mul__(n)` <==> `x * n`""" - - def __rmul__(n): - """`x.__rmul__(n)` <==> `n * x`""" - - def __getslice__(i, j): - """`x.__getslice__(i, j)` <==> `x[i:j]` - - Use of negative indices is not supported. - - Deprecated since Python 2.0 but still a part of `UserList`. - """ - -class IExtendedReadSequence(IReadSequence): - """Full read interface for lists""" - - def count(item): - """Return number of occurrences of value""" - - def index(item, *args): - """Return first index of value - - `L.index(value, [start, [stop]])` -> integer""" - -class IUniqueMemberWriteSequence(interface.Interface): - """The write contract for a sequence that may enforce unique members""" - - def __setitem__(index, item): - """`x.__setitem__(index, item)` <==> `x[index] = item` - - Declaring this interface does not specify whether `__setitem__` - supports slice objects. - """ - - def __delitem__(index): - """`x.__delitem__(index)` <==> `del x[index]` - - Declaring this interface does not specify whether `__delitem__` - supports slice objects. - """ - - def __setslice__(i, j, other): - """`x.__setslice__(i, j, other)` <==> `x[i:j]=other` - - Use of negative indices is not supported. - - Deprecated since Python 2.0 but still a part of `UserList`. - """ - - def __delslice__(i, j): - """`x.__delslice__(i, j)` <==> `del x[i:j]` - - Use of negative indices is not supported. - - Deprecated since Python 2.0 but still a part of `UserList`. - """ - def __iadd__(y): - """`x.__iadd__(y)` <==> `x += y`""" - - def append(item): - """Append item to end""" - - def insert(index, item): - """Insert item before index""" - - def pop(index=-1): - """Remove and return item at index (default last)""" - - def remove(item): - """Remove first occurrence of value""" - - def reverse(): - """Reverse *IN PLACE*""" - - def sort(cmpfunc=None): - """Stable sort *IN PLACE*; `cmpfunc(x, y)` -> -1, 0, 1""" - - def extend(iterable): - """Extend list by appending elements from the iterable""" - -class IWriteSequence(IUniqueMemberWriteSequence): - """Full write contract for sequences""" - - def __imul__(n): - """`x.__imul__(n)` <==> `x *= n`""" - -class ISequence(IReadSequence, IWriteSequence): - """Full sequence contract""" diff --git a/tools/buildbot/pylibs/zope/interface/common/tests/__init__.py b/tools/buildbot/pylibs/zope/interface/common/tests/__init__.py deleted file mode 100644 index b711d36..0000000 --- a/tools/buildbot/pylibs/zope/interface/common/tests/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# -# This file is necessary to make this directory a package. diff --git a/tools/buildbot/pylibs/zope/interface/common/tests/basemapping.py b/tools/buildbot/pylibs/zope/interface/common/tests/basemapping.py deleted file mode 100644 index 02438b3..0000000 --- a/tools/buildbot/pylibs/zope/interface/common/tests/basemapping.py +++ /dev/null @@ -1,115 +0,0 @@ -############################################################################## -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Base Mapping tests - -$Id: basemapping.py 26560 2004-07-15 21:38:42Z srichter $ -""" -from operator import __getitem__ - -def testIReadMapping(self, inst, state, absent): - for key in state: - self.assertEqual(inst[key], state[key]) - self.assertEqual(inst.get(key, None), state[key]) - self.failUnless(key in inst) - - for key in absent: - self.assertEqual(inst.get(key, None), None) - self.assertEqual(inst.get(key), None) - self.assertEqual(inst.get(key, self), self) - self.assertRaises(KeyError, __getitem__, inst, key) - - -def test_keys(self, inst, state): - # Return the keys of the mapping object - inst_keys = list(inst.keys()); inst_keys.sort() - state_keys = list(state.keys()) ; state_keys.sort() - self.assertEqual(inst_keys, state_keys) - -def test_iter(self, inst, state): - # Return the keys of the mapping object - inst_keys = list(inst); inst_keys.sort() - state_keys = list(state.keys()) ; state_keys.sort() - self.assertEqual(inst_keys, state_keys) - -def test_values(self, inst, state): - # Return the values of the mapping object - inst_values = list(inst.values()); inst_values.sort() - state_values = list(state.values()) ; state_values.sort() - self.assertEqual(inst_values, state_values) - -def test_items(self, inst, state): - # Return the items of the mapping object - inst_items = list(inst.items()); inst_items.sort() - state_items = list(state.items()) ; state_items.sort() - self.assertEqual(inst_items, state_items) - -def test___len__(self, inst, state): - # Return the number of items - self.assertEqual(len(inst), len(state)) - -def testIEnumerableMapping(self, inst, state): - test_keys(self, inst, state) - test_items(self, inst, state) - test_values(self, inst, state) - test___len__(self, inst, state) - - -class BaseTestIReadMapping(object): - def testIReadMapping(self): - inst = self._IReadMapping__sample() - state = self._IReadMapping__stateDict() - absent = self._IReadMapping__absentKeys() - testIReadMapping(self, inst, state, absent) - - -class BaseTestIEnumerableMapping(BaseTestIReadMapping): - # Mapping objects whose items can be enumerated - def test_keys(self): - # Return the keys of the mapping object - inst = self._IEnumerableMapping__sample() - state = self._IEnumerableMapping__stateDict() - test_keys(self, inst, state) - - def test_values(self): - # Return the values of the mapping object - inst = self._IEnumerableMapping__sample() - state = self._IEnumerableMapping__stateDict() - test_values(self, inst, state) - - def test_values(self): - # Return the values of the mapping object - inst = self._IEnumerableMapping__sample() - state = self._IEnumerableMapping__stateDict() - test_iter(self, inst, state) - - def test_items(self): - # Return the items of the mapping object - inst = self._IEnumerableMapping__sample() - state = self._IEnumerableMapping__stateDict() - test_items(self, inst, state) - - def test___len__(self): - # Return the number of items - inst = self._IEnumerableMapping__sample() - state = self._IEnumerableMapping__stateDict() - test___len__(self, inst, state) - - def _IReadMapping__stateDict(self): - return self._IEnumerableMapping__stateDict() - - def _IReadMapping__sample(self): - return self._IEnumerableMapping__sample() - - def _IReadMapping__absentKeys(self): - return self._IEnumerableMapping__absentKeys() diff --git a/tools/buildbot/pylibs/zope/interface/common/tests/test_idatetime.py b/tools/buildbot/pylibs/zope/interface/common/tests/test_idatetime.py deleted file mode 100644 index 1e1f3e7..0000000 --- a/tools/buildbot/pylibs/zope/interface/common/tests/test_idatetime.py +++ /dev/null @@ -1,49 +0,0 @@ -############################################################################## -# -# Copyright (c) 2003 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Test for datetime interfaces - -$Id: test_idatetime.py 25177 2004-06-02 13:17:31Z jim $ -""" - -import unittest - -from zope.interface.verify import verifyObject, verifyClass -from zope.interface.common.idatetime import ITimeDelta, ITimeDeltaClass -from zope.interface.common.idatetime import IDate, IDateClass -from zope.interface.common.idatetime import IDateTime, IDateTimeClass -from zope.interface.common.idatetime import ITime, ITimeClass, ITZInfo -from datetime import timedelta, date, datetime, time, tzinfo - -class TestDateTimeInterfaces(unittest.TestCase): - - def test_interfaces(self): - verifyObject(ITimeDelta, timedelta(minutes=20)) - verifyObject(IDate, date(2000, 1, 2)) - verifyObject(IDateTime, datetime(2000, 1, 2, 10, 20)) - verifyObject(ITime, time(20, 30, 15, 1234)) - verifyObject(ITZInfo, tzinfo()) - verifyClass(ITimeDeltaClass, timedelta) - verifyClass(IDateClass, date) - verifyClass(IDateTimeClass, datetime) - verifyClass(ITimeClass, time) - - -def test_suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(TestDateTimeInterfaces)) - return suite - - -if __name__ == '__main__': - unittest.main() diff --git a/tools/buildbot/pylibs/zope/interface/declarations.py b/tools/buildbot/pylibs/zope/interface/declarations.py deleted file mode 100644 index 99e7898..0000000 --- a/tools/buildbot/pylibs/zope/interface/declarations.py +++ /dev/null @@ -1,1386 +0,0 @@ -############################################################################## -# Copyright (c) 2003 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -############################################################################## -"""Implementation of interface declarations - -There are three flavors of declarations: - - - Declarations are used to simply name declared interfaces. - - - ImplementsDeclarations are used to express the interfaces that a - class implements (that instances of the class provides). - - Implements specifications support inheriting interfaces. - - - ProvidesDeclarations are used to express interfaces directly - provided by objects. - - -$Id: declarations.py 70112 2006-09-12 04:51:16Z baijum $ -""" -__docformat__ = 'restructuredtext' - -import sys -import types -import weakref -from zope.interface.interface import InterfaceClass, Specification -from ro import mergeOrderings, ro -import exceptions -from types import ClassType, ModuleType -from zope.interface.advice import addClassAdvisor - -# Registry of class-implementation specifications -BuiltinImplementationSpecifications = {} - -class Declaration(Specification): - """Interface declarations""" - - def __init__(self, *interfaces): - Specification.__init__(self, _normalizeargs(interfaces)) - - def changed(self, originally_changed): - Specification.changed(self, originally_changed) - try: - del self._v_attrs - except AttributeError: - pass - - def __contains__(self, interface): - """Test whether an interface is in the specification - - for example: - - >>> from zope.interface import Interface - >>> class I1(Interface): pass - ... - >>> class I2(I1): pass - ... - >>> class I3(Interface): pass - ... - >>> class I4(I3): pass - ... - >>> spec = Declaration(I2, I3) - >>> spec = Declaration(I4, spec) - >>> int(I1 in spec) - 0 - >>> int(I2 in spec) - 1 - >>> int(I3 in spec) - 1 - >>> int(I4 in spec) - 1 - """ - return self.extends(interface) and interface in self.interfaces() - - def __iter__(self): - """Return an iterator for the interfaces in the specification - - for example: - - >>> from zope.interface import Interface - >>> class I1(Interface): pass - ... - >>> class I2(I1): pass - ... - >>> class I3(Interface): pass - ... - >>> class I4(I3): pass - ... - >>> spec = Declaration(I2, I3) - >>> spec = Declaration(I4, spec) - >>> i = iter(spec) - >>> i.next().getName() - 'I4' - >>> i.next().getName() - 'I2' - >>> i.next().getName() - 'I3' - >>> list(i) - [] - """ - return self.interfaces() - - def flattened(self): - """Return an iterator of all included and extended interfaces - - for example: - - >>> from zope.interface import Interface - >>> class I1(Interface): pass - ... - >>> class I2(I1): pass - ... - >>> class I3(Interface): pass - ... - >>> class I4(I3): pass - ... - >>> spec = Declaration(I2, I3) - >>> spec = Declaration(I4, spec) - >>> i = spec.flattened() - >>> i.next().getName() - 'I4' - >>> i.next().getName() - 'I2' - >>> i.next().getName() - 'I1' - >>> i.next().getName() - 'I3' - >>> i.next().getName() - 'Interface' - >>> list(i) - [] - - """ - return iter(self.__iro__) - - def __sub__(self, other): - """Remove interfaces from a specification - - Examples: - - >>> from zope.interface import Interface - >>> class I1(Interface): pass - ... - >>> class I2(I1): pass - ... - >>> class I3(Interface): pass - ... - >>> class I4(I3): pass - ... - >>> spec = Declaration() - >>> [iface.getName() for iface in spec] - [] - >>> spec -= I1 - >>> [iface.getName() for iface in spec] - [] - >>> spec -= Declaration(I1, I2) - >>> [iface.getName() for iface in spec] - [] - >>> spec = Declaration(I2, I4) - >>> [iface.getName() for iface in spec] - ['I2', 'I4'] - >>> [iface.getName() for iface in spec - I4] - ['I2'] - >>> [iface.getName() for iface in spec - I1] - ['I4'] - >>> [iface.getName() for iface - ... in spec - Declaration(I3, I4)] - ['I2'] - - """ - - return Declaration( - *[i for i in self.interfaces() - if not [j for j in other.interfaces() - if i.extends(j, 0)] - ] - ) - - def __add__(self, other): - """Add two specifications or a specification and an interface - - Examples: - - >>> from zope.interface import Interface - >>> class I1(Interface): pass - ... - >>> class I2(I1): pass - ... - >>> class I3(Interface): pass - ... - >>> class I4(I3): pass - ... - >>> spec = Declaration() - >>> [iface.getName() for iface in spec] - [] - >>> [iface.getName() for iface in spec+I1] - ['I1'] - >>> [iface.getName() for iface in I1+spec] - ['I1'] - >>> spec2 = spec - >>> spec += I1 - >>> [iface.getName() for iface in spec] - ['I1'] - >>> [iface.getName() for iface in spec2] - [] - >>> spec2 += Declaration(I3, I4) - >>> [iface.getName() for iface in spec2] - ['I3', 'I4'] - >>> [iface.getName() for iface in spec+spec2] - ['I1', 'I3', 'I4'] - >>> [iface.getName() for iface in spec2+spec] - ['I3', 'I4', 'I1'] - - """ - - seen = {} - result = [] - for i in self.interfaces(): - if i not in seen: - seen[i] = 1 - result.append(i) - for i in other.interfaces(): - if i not in seen: - seen[i] = 1 - result.append(i) - - return Declaration(*result) - - __radd__ = __add__ - - -############################################################################## -# -# Implementation specifications -# -# These specify interfaces implemented by instances of classes - -class Implements(Declaration): - - # class whose specification should be used as additional base - inherit = None - - # interfaces actually declared for a class - declared = () - - __name__ = '?' - - def __repr__(self): - return '' % (self.__name__) - - def __reduce__(self): - return implementedBy, (self.inherit, ) - -def implementedByFallback(cls): - """Return the interfaces implemented for a class' instances - - The value returned is an IDeclaration. - - for example: - - >>> from zope.interface import Interface - >>> class I1(Interface): pass - ... - >>> class I2(I1): pass - ... - >>> class I3(Interface): pass - ... - >>> class I4(I3): pass - ... - >>> class C1(object): - ... implements(I2) - >>> class C2(C1): - ... implements(I3) - >>> [i.getName() for i in implementedBy(C2)] - ['I3', 'I2'] - - Really, any object should be able to receive a successful answer, even - an instance: - - >>> class Callable(object): - ... def __call__(self): - ... return self - - >>> implementedBy(Callable()) - - - Note that the name of the spec ends with a '?', because the `Callable` - instance does not have a `__name__` attribute. - """ - # This also manages storage of implementation specifications - - try: - spec = cls.__dict__.get('__implemented__') - except AttributeError: - - # we can't get the class dict. This is probably due to a - # security proxy. If this is the case, then probably no - # descriptor was installed for the class. - - # We don't want to depend directly on zope.security in - # zope.interface, but we'll try to make reasonable - # accommodations in an indirect way. - - # We'll check to see if there's an implements: - - spec = getattr(cls, '__implemented__', None) - if spec is None: - # There's no spec stred in the class. Maybe its a builtin: - spec = BuiltinImplementationSpecifications.get(cls) - if spec is not None: - return spec - return _empty - - if spec.__class__ == Implements: - # we defaulted to _empty or there was a spec. Good enough. - # Return it. - return spec - - # TODO: need old style __implements__ compatibility? - # Hm, there's an __implemented__, but it's not a spec. Must be - # an old-style declaration. Just compute a spec for it - return Declaration(*_normalizeargs((spec, ))) - - if isinstance(spec, Implements): - return spec - - if spec is None: - spec = BuiltinImplementationSpecifications.get(cls) - if spec is not None: - return spec - - # TODO: need old style __implements__ compatibility? - if spec is not None: - # old-style __implemented__ = foo declaration - spec = (spec, ) # tuplefy, as it might be just an int - spec = Implements(*_normalizeargs(spec)) - spec.inherit = None # old-style implies no inherit - del cls.__implemented__ # get rid of the old-style declaration - else: - try: - bases = cls.__bases__ - except AttributeError: - if not callable(cls): - raise TypeError("ImplementedBy called for non-factory", cls) - bases = () - - spec = Implements(*[implementedBy(c) for c in bases]) - spec.inherit = cls - - spec.__name__ = (getattr(cls, '__module__', '?') or '?') + \ - '.' + (getattr(cls, '__name__', '?') or '?') - - try: - cls.__implemented__ = spec - if not hasattr(cls, '__providedBy__'): - cls.__providedBy__ = objectSpecificationDescriptor - - if (isinstance(cls, DescriptorAwareMetaClasses) - and - '__provides__' not in cls.__dict__): - # Make sure we get a __provides__ descriptor - cls.__provides__ = ClassProvides( - cls, - getattr(cls, '__class__', type(cls)), - ) - - except TypeError: - if not isinstance(cls, type): - raise TypeError("ImplementedBy called for non-type", cls) - BuiltinImplementationSpecifications[cls] = spec - - return spec - -implementedBy = implementedByFallback - -def classImplementsOnly(cls, *interfaces): - """Declare the only interfaces implemented by instances of a class - - The arguments after the class are one or more interfaces or interface - specifications (``IDeclaration`` objects). - - The interfaces given (including the interfaces in the specifications) - replace any previous declarations. - - Consider the following example: - - >>> from zope.interface import Interface - >>> class I1(Interface): pass - ... - >>> class I2(Interface): pass - ... - >>> class I3(Interface): pass - ... - >>> class I4(Interface): pass - ... - >>> class A(object): - ... implements(I3) - >>> class B(object): - ... implements(I4) - >>> class C(A, B): - ... pass - >>> classImplementsOnly(C, I1, I2) - >>> [i.getName() for i in implementedBy(C)] - ['I1', 'I2'] - - Instances of ``C`` provide only ``I1``, ``I2``, and regardless of - whatever interfaces instances of ``A`` and ``B`` implement. - """ - spec = implementedBy(cls) - spec.declared = () - spec.inherit = None - classImplements(cls, *interfaces) - -def classImplements(cls, *interfaces): - """Declare additional interfaces implemented for instances of a class - - The arguments after the class are one or more interfaces or - interface specifications (``IDeclaration`` objects). - - The interfaces given (including the interfaces in the specifications) - are added to any interfaces previously declared. - - Consider the following example: - - >>> from zope.interface import Interface - >>> class I1(Interface): pass - ... - >>> class I2(Interface): pass - ... - >>> class I3(Interface): pass - ... - >>> class I4(Interface): pass - ... - >>> class I5(Interface): pass - ... - >>> class A(object): - ... implements(I3) - >>> class B(object): - ... implements(I4) - >>> class C(A, B): - ... pass - >>> classImplements(C, I1, I2) - >>> [i.getName() for i in implementedBy(C)] - ['I1', 'I2', 'I3', 'I4'] - >>> classImplements(C, I5) - >>> [i.getName() for i in implementedBy(C)] - ['I1', 'I2', 'I5', 'I3', 'I4'] - - Instances of ``C`` provide ``I1``, ``I2``, ``I5``, and whatever - interfaces instances of ``A`` and ``B`` provide. - """ - - spec = implementedBy(cls) - spec.declared += tuple(_normalizeargs(interfaces)) - - # compute the bases - bases = [] - seen = {} - for b in spec.declared: - if b not in seen: - seen[b] = 1 - bases.append(b) - - if spec.inherit is not None: - - for c in spec.inherit.__bases__: - b = implementedBy(c) - if b not in seen: - seen[b] = 1 - bases.append(b) - - spec.__bases__ = tuple(bases) - -def _implements_advice(cls): - interfaces, classImplements = cls.__dict__['__implements_advice_data__'] - del cls.__implements_advice_data__ - classImplements(cls, *interfaces) - return cls - - -class implementer: - - def __init__(self, *interfaces): - self.interfaces = interfaces - - def __call__(self, ob): - if isinstance(ob, DescriptorAwareMetaClasses): - raise TypeError("Can't use implementer with classes. Use one of " - "the class-declaration functions instead." - ) - spec = Implements(*self.interfaces) - try: - ob.__implemented__ = spec - except AttributeError: - raise TypeError("Can't declare implements", ob) - return ob - -def _implements(name, interfaces, classImplements): - frame = sys._getframe(2) - locals = frame.f_locals - - # Try to make sure we were called from a class def. In 2.2.0 we can't - # check for __module__ since it doesn't seem to be added to the locals - # until later on. - if (locals is frame.f_globals) or ( - ('__module__' not in locals) and sys.version_info[:3] > (2, 2, 0)): - raise TypeError(name+" can be used only from a class definition.") - - if '__implements_advice_data__' in locals: - raise TypeError(name+" can be used only once in a class definition.") - - locals['__implements_advice_data__'] = interfaces, classImplements - addClassAdvisor(_implements_advice, depth=3) - -def implements(*interfaces): - """Declare interfaces implemented by instances of a class - - This function is called in a class definition. - - The arguments are one or more interfaces or interface - specifications (IDeclaration objects). - - The interfaces given (including the interfaces in the - specifications) are added to any interfaces previously - declared. - - Previous declarations include declarations for base classes - unless implementsOnly was used. - - This function is provided for convenience. It provides a more - convenient way to call classImplements. For example:: - - implements(I1) - - is equivalent to calling:: - - classImplements(C, I1) - - after the class has been created. - - Consider the following example:: - - - >>> from zope.interface import Interface - >>> class IA1(Interface): pass - ... - >>> class IA2(Interface): pass - ... - >>> class IB(Interface): pass - ... - >>> class IC(Interface): pass - ... - >>> class A(object): implements(IA1, IA2) - ... - >>> class B(object): implements(IB) - ... - - >>> class C(A, B): - ... implements(IC) - - >>> ob = C() - >>> int(IA1 in providedBy(ob)) - 1 - >>> int(IA2 in providedBy(ob)) - 1 - >>> int(IB in providedBy(ob)) - 1 - >>> int(IC in providedBy(ob)) - 1 - - Instances of ``C`` implement ``I1``, ``I2``, and whatever interfaces - instances of ``A`` and ``B`` implement. - - """ - _implements("implements", interfaces, classImplements) - -def implementsOnly(*interfaces): - """Declare the only interfaces implemented by instances of a class - - This function is called in a class definition. - - The arguments are one or more interfaces or interface - specifications (IDeclaration objects). - - Previous declarations including declarations for base classes - are overridden. - - This function is provided for convenience. It provides a more - convenient way to call classImplementsOnly. For example:: - - implementsOnly(I1) - - is equivalent to calling:: - - classImplementsOnly(I1) - - after the class has been created. - - Consider the following example:: - - >>> from zope.interface import Interface - >>> class IA1(Interface): pass - ... - >>> class IA2(Interface): pass - ... - >>> class IB(Interface): pass - ... - >>> class IC(Interface): pass - ... - >>> class A(object): implements(IA1, IA2) - ... - >>> class B(object): implements(IB) - ... - - >>> class C(A, B): - ... implementsOnly(IC) - - >>> ob = C() - >>> int(IA1 in providedBy(ob)) - 0 - >>> int(IA2 in providedBy(ob)) - 0 - >>> int(IB in providedBy(ob)) - 0 - >>> int(IC in providedBy(ob)) - 1 - - - Instances of ``C`` implement ``IC``, regardless of what - instances of ``A`` and ``B`` implement. - - """ - _implements("implementsOnly", interfaces, classImplementsOnly) - -############################################################################## -# -# Instance declarations - -class Provides(Declaration): # Really named ProvidesClass - """Implement __provides__, the instance-specific specification - - When an object is pickled, we pickle the interfaces that it implements. - """ - - def __init__(self, cls, *interfaces): - self.__args = (cls, ) + interfaces - self._cls = cls - Declaration.__init__(self, *(interfaces + (implementedBy(cls), ))) - - def __reduce__(self): - return Provides, self.__args - - __module__ = 'zope.interface' - - def __get__(self, inst, cls): - """Make sure that a class __provides__ doesn't leak to an instance - - For example: - - >>> from zope.interface import Interface - >>> class IFooFactory(Interface): pass - ... - - >>> class C(object): - ... pass - - >>> C.__provides__ = ProvidesClass(C, IFooFactory) - >>> [i.getName() for i in C.__provides__] - ['IFooFactory'] - >>> getattr(C(), '__provides__', 0) - 0 - - """ - if inst is None and cls is self._cls: - # We were accessed through a class, so we are the class' - # provides spec. Just return this object, but only if we are - # being called on the same class that we were defined for: - return self - - raise AttributeError('__provides__') - -ProvidesClass = Provides - -# Registry of instance declarations -# This is a memory optimization to allow objects to share specifications. -InstanceDeclarations = weakref.WeakValueDictionary() - -def Provides(*interfaces): - """Cache instance declarations - - Instance declarations are shared among instances that have the same - declaration. The declarations are cached in a weak value dictionary. - - (Note that, in the examples below, we are going to make assertions about - the size of the weakvalue dictionary. For the assertions to be - meaningful, we need to force garbage collection to make sure garbage - objects are, indeed, removed from the system. Depending on how Python - is run, we may need to make multiple calls to be sure. We provide a - collect function to help with this: - - >>> import gc - >>> def collect(): - ... for i in range(4): - ... gc.collect() - - ) - - >>> collect() - >>> before = len(InstanceDeclarations) - - >>> class C(object): - ... pass - - >>> from zope.interface import Interface - >>> class I(Interface): - ... pass - - >>> c1 = C() - >>> c2 = C() - - >>> len(InstanceDeclarations) == before - 1 - - >>> directlyProvides(c1, I) - >>> len(InstanceDeclarations) == before + 1 - 1 - - >>> directlyProvides(c2, I) - >>> len(InstanceDeclarations) == before + 1 - 1 - - >>> del c1 - >>> collect() - >>> len(InstanceDeclarations) == before + 1 - 1 - - >>> del c2 - >>> collect() - >>> len(InstanceDeclarations) == before - 1 - """ - - spec = InstanceDeclarations.get(interfaces) - if spec is None: - spec = ProvidesClass(*interfaces) - InstanceDeclarations[interfaces] = spec - - return spec -Provides.__safe_for_unpickling__ = True - - -DescriptorAwareMetaClasses = ClassType, type -def directlyProvides(object, *interfaces): - """Declare interfaces declared directly for an object - - The arguments after the object are one or more interfaces or interface - specifications (``IDeclaration`` objects). - - The interfaces given (including the interfaces in the specifications) - replace interfaces previously declared for the object. - - Consider the following example: - - >>> from zope.interface import Interface - >>> class I1(Interface): pass - ... - >>> class I2(Interface): pass - ... - >>> class IA1(Interface): pass - ... - >>> class IA2(Interface): pass - ... - >>> class IB(Interface): pass - ... - >>> class IC(Interface): pass - ... - >>> class A(object): implements(IA1, IA2) - ... - >>> class B(object): implements(IB) - ... - - >>> class C(A, B): - ... implements(IC) - - >>> ob = C() - >>> directlyProvides(ob, I1, I2) - >>> int(I1 in providedBy(ob)) - 1 - >>> int(I2 in providedBy(ob)) - 1 - >>> int(IA1 in providedBy(ob)) - 1 - >>> int(IA2 in providedBy(ob)) - 1 - >>> int(IB in providedBy(ob)) - 1 - >>> int(IC in providedBy(ob)) - 1 - - The object, ``ob`` provides ``I1``, ``I2``, and whatever interfaces - instances have been declared for instances of ``C``. - - To remove directly provided interfaces, use ``directlyProvidedBy`` and - subtract the unwanted interfaces. For example: - - >>> directlyProvides(ob, directlyProvidedBy(ob)-I2) - >>> int(I1 in providedBy(ob)) - 1 - >>> int(I2 in providedBy(ob)) - 0 - - removes I2 from the interfaces directly provided by ``ob``. The object, - ``ob`` no longer directly provides ``I2``, although it might still - provide ``I2`` if it's class implements ``I2``. - - To add directly provided interfaces, use ``directlyProvidedBy`` and - include additional interfaces. For example: - - >>> int(I2 in providedBy(ob)) - 0 - >>> directlyProvides(ob, directlyProvidedBy(ob), I2) - - adds ``I2`` to the interfaces directly provided by ob:: - - >>> int(I2 in providedBy(ob)) - 1 - - """ - - # We need to avoid setting this attribute on meta classes that - # don't support descriptors. - # We can do away with this check when we get rid of the old EC - cls = getattr(object, '__class__', None) - if cls is not None and getattr(cls, '__class__', None) is cls: - # It's a meta class (well, at least it it could be an extension class) - if not isinstance(object, DescriptorAwareMetaClasses): - raise TypeError("Attempt to make an interface declaration on a " - "non-descriptor-aware class") - - interfaces = _normalizeargs(interfaces) - if cls is None: - cls = type(object) - - issub = False - for damc in DescriptorAwareMetaClasses: - if issubclass(cls, damc): - issub = True - break - if issub: - # we have a class or type. We'll use a special descriptor - # that provides some extra caching - object.__provides__ = ClassProvides(object, cls, *interfaces) - else: - object.__provides__ = Provides(cls, *interfaces) - - -def alsoProvides(object, *interfaces): - """Declare interfaces declared directly for an object - - The arguments after the object are one or more interfaces or interface - specifications (``IDeclaration`` objects). - - The interfaces given (including the interfaces in the specifications) are - added to the interfaces previously declared for the object. - - Consider the following example: - - >>> from zope.interface import Interface - >>> class I1(Interface): pass - ... - >>> class I2(Interface): pass - ... - >>> class IA1(Interface): pass - ... - >>> class IA2(Interface): pass - ... - >>> class IB(Interface): pass - ... - >>> class IC(Interface): pass - ... - >>> class A(object): implements(IA1, IA2) - ... - >>> class B(object): implements(IB) - ... - - >>> class C(A, B): - ... implements(IC) - - >>> ob = C() - >>> directlyProvides(ob, I1) - >>> int(I1 in providedBy(ob)) - 1 - >>> int(I2 in providedBy(ob)) - 0 - >>> int(IA1 in providedBy(ob)) - 1 - >>> int(IA2 in providedBy(ob)) - 1 - >>> int(IB in providedBy(ob)) - 1 - >>> int(IC in providedBy(ob)) - 1 - - >>> alsoProvides(ob, I2) - >>> int(I1 in providedBy(ob)) - 1 - >>> int(I2 in providedBy(ob)) - 1 - >>> int(IA1 in providedBy(ob)) - 1 - >>> int(IA2 in providedBy(ob)) - 1 - >>> int(IB in providedBy(ob)) - 1 - >>> int(IC in providedBy(ob)) - 1 - - The object, ``ob`` provides ``I1``, ``I2``, and whatever interfaces - instances have been declared for instances of ``C``. Notice that the - alsoProvides just extends the provided interfaces. - """ - directlyProvides(object, directlyProvidedBy(object), *interfaces) - -def noLongerProvides(object, interface): - """ - This removes a directly provided interface from an object. - Consider the following two interfaces: - - >>> from zope.interface import Interface - >>> class I1(Interface): pass - ... - >>> class I2(Interface): pass - ... - - ``I1`` is provided through the class, ``I2`` is directly provided - by the object: - - >>> class C(object): - ... implements(I1) - >>> c = C() - >>> alsoProvides(c, I2) - >>> I2.providedBy(c) - True - - Remove I2 from c again: - - >>> noLongerProvides(c, I2) - >>> I2.providedBy(c) - False - - Removing an interface that is provided through the class is not possible: - - >>> noLongerProvides(c, I1) - Traceback (most recent call last): - ... - ValueError: Can only remove directly provided interfaces. - - """ - directlyProvides(object, directlyProvidedBy(object)-interface) - if interface.providedBy(object): - raise ValueError("Can only remove directly provided interfaces.") - -class ClassProvidesBasePy(object): - - def __get__(self, inst, cls): - if cls is self._cls: - # We only work if called on the class we were defined for - - if inst is None: - # We were accessed through a class, so we are the class' - # provides spec. Just return this object as is: - return self - - return self._implements - - raise AttributeError('__provides__') - -ClassProvidesBase = ClassProvidesBasePy - -# Try to get C base: -try: - import _zope_interface_coptimizations -except ImportError: - pass -else: - from _zope_interface_coptimizations import ClassProvidesBase - - -class ClassProvides(Declaration, ClassProvidesBase): - """Special descriptor for class __provides__ - - The descriptor caches the implementedBy info, so that - we can get declarations for objects without instance-specific - interfaces a bit quicker. - - For example: - - >>> from zope.interface import Interface - >>> class IFooFactory(Interface): - ... pass - >>> class IFoo(Interface): - ... pass - >>> class C(object): - ... implements(IFoo) - ... classProvides(IFooFactory) - >>> [i.getName() for i in C.__provides__] - ['IFooFactory'] - - >>> [i.getName() for i in C().__provides__] - ['IFoo'] - """ - - def __init__(self, cls, metacls, *interfaces): - self._cls = cls - self._implements = implementedBy(cls) - self.__args = (cls, metacls, ) + interfaces - Declaration.__init__(self, *(interfaces + (implementedBy(metacls), ))) - - def __reduce__(self): - return self.__class__, self.__args - - # Copy base-class method for speed - __get__ = ClassProvidesBase.__get__ - -def directlyProvidedBy(object): - """Return the interfaces directly provided by the given object - - The value returned is an ``IDeclaration``. - """ - provides = getattr(object, "__provides__", None) - if (provides is None # no spec - or - # We might have gotten the implements spec, as an - # optimization. If so, it's like having only one base, that we - # lop off to exclude class-supplied declarations: - isinstance(provides, Implements) - ): - return _empty - - # Strip off the class part of the spec: - return Declaration(provides.__bases__[:-1]) - -def classProvides(*interfaces): - """Declare interfaces provided directly by a class - - This function is called in a class definition. - - The arguments are one or more interfaces or interface specifications - (``IDeclaration`` objects). - - The given interfaces (including the interfaces in the specifications) - are used to create the class's direct-object interface specification. - An error will be raised if the module class has an direct interface - specification. In other words, it is an error to call this function more - than once in a class definition. - - Note that the given interfaces have nothing to do with the interfaces - implemented by instances of the class. - - This function is provided for convenience. It provides a more convenient - way to call directlyProvidedByProvides for a class. For example:: - - classProvides(I1) - - is equivalent to calling:: - - directlyProvides(theclass, I1) - - after the class has been created. - - For example: - - >>> from zope.interface import Interface - >>> class IFoo(Interface): pass - ... - >>> class IFooFactory(Interface): pass - ... - >>> class C(object): - ... implements(IFoo) - ... classProvides(IFooFactory) - >>> [i.getName() for i in C.__providedBy__] - ['IFooFactory'] - >>> [i.getName() for i in C().__providedBy__] - ['IFoo'] - - if equivalent to: - - >>> from zope.interface import Interface - >>> class IFoo(Interface): pass - ... - >>> class IFooFactory(Interface): pass - ... - >>> class C(object): - ... implements(IFoo) - >>> directlyProvides(C, IFooFactory) - >>> [i.getName() for i in C.__providedBy__] - ['IFooFactory'] - >>> [i.getName() for i in C().__providedBy__] - ['IFoo'] - - If classProvides is called outside of a class definition, it fails. - - >>> classProvides(IFooFactory) - Traceback (most recent call last): - ... - TypeError: classProvides can be used only from a class definition. - - """ - frame = sys._getframe(1) - locals = frame.f_locals - - # Try to make sure we were called from a class def - if (locals is frame.f_globals) or ('__module__' not in locals): - raise TypeError("classProvides can be used only from a class definition.") - - if '__provides__' in locals: - raise TypeError( - "classProvides can only be used once in a class definition.") - - locals["__provides__"] = _normalizeargs(interfaces) - - addClassAdvisor(_classProvides_advice, depth=2) - -def _classProvides_advice(cls): - interfaces = cls.__dict__['__provides__'] - del cls.__provides__ - directlyProvides(cls, *interfaces) - return cls - -def moduleProvides(*interfaces): - """Declare interfaces provided by a module - - This function is used in a module definition. - - The arguments are one or more interfaces or interface specifications - (``IDeclaration`` objects). - - The given interfaces (including the interfaces in the specifications) are - used to create the module's direct-object interface specification. An - error will be raised if the module already has an interface specification. - In other words, it is an error to call this function more than once in a - module definition. - - This function is provided for convenience. It provides a more convenient - way to call directlyProvides. For example:: - - moduleImplements(I1) - - is equivalent to:: - - directlyProvides(sys.modules[__name__], I1) - """ - frame = sys._getframe(1) - locals = frame.f_locals - - # Try to make sure we were called from a class def - if (locals is not frame.f_globals) or ('__name__' not in locals): - raise TypeError( - "moduleProvides can only be used from a module definition.") - - if '__provides__' in locals: - raise TypeError( - "moduleProvides can only be used once in a module definition.") - - locals["__provides__"] = Provides(ModuleType, - *_normalizeargs(interfaces)) - -############################################################################## -# -# Declaration querying support - -def ObjectSpecification(direct, cls): - """Provide object specifications - - These combine information for the object and for it's classes. - - For example: - - >>> from zope.interface import Interface - >>> class I1(Interface): pass - ... - >>> class I2(Interface): pass - ... - >>> class I3(Interface): pass - ... - >>> class I31(I3): pass - ... - >>> class I4(Interface): pass - ... - >>> class I5(Interface): pass - ... - >>> class A(object): implements(I1) - ... - >>> class B(object): __implemented__ = I2 - ... - >>> class C(A, B): implements(I31) - ... - >>> c = C() - >>> directlyProvides(c, I4) - >>> [i.getName() for i in providedBy(c)] - ['I4', 'I31', 'I1', 'I2'] - >>> [i.getName() for i in providedBy(c).flattened()] - ['I4', 'I31', 'I3', 'I1', 'I2', 'Interface'] - >>> int(I1 in providedBy(c)) - 1 - >>> int(I3 in providedBy(c)) - 0 - >>> int(providedBy(c).extends(I3)) - 1 - >>> int(providedBy(c).extends(I31)) - 1 - >>> int(providedBy(c).extends(I5)) - 0 - >>> class COnly(A, B): implementsOnly(I31) - ... - >>> class D(COnly): implements(I5) - ... - >>> c = D() - >>> directlyProvides(c, I4) - >>> [i.getName() for i in providedBy(c)] - ['I4', 'I5', 'I31'] - >>> [i.getName() for i in providedBy(c).flattened()] - ['I4', 'I5', 'I31', 'I3', 'Interface'] - >>> int(I1 in providedBy(c)) - 0 - >>> int(I3 in providedBy(c)) - 0 - >>> int(providedBy(c).extends(I3)) - 1 - >>> int(providedBy(c).extends(I1)) - 0 - >>> int(providedBy(c).extends(I31)) - 1 - >>> int(providedBy(c).extends(I5)) - 1 - """ - - return Provides(cls, direct) - -def getObjectSpecification(ob): - - provides = getattr(ob, '__provides__', None) - if provides is not None: - return provides - - try: - cls = ob.__class__ - except AttributeError: - # We can't get the class, so just consider provides - return _empty - - return implementedBy(cls) - -def providedBy(ob): - - # Here we have either a special object, an old-style declaration - # or a descriptor - - # Try to get __providedBy__ - try: - r = ob.__providedBy__ - except AttributeError: - # Not set yet. Fall back to lower-level thing that computes it - return getObjectSpecification(ob) - - try: - # We might have gotten a descriptor from an instance of a - # class (like an ExtensionClass) that doesn't support - # descriptors. We'll make sure we got one by trying to get - # the only attribute, which all specs have. - r.extends - - except AttributeError: - - # The object's class doesn't understand descriptors. - # Sigh. We need to get an object descriptor, but we have to be - # careful. We want to use the instance's __provides__, if - # there is one, but only if it didn't come from the class. - - try: - r = ob.__provides__ - except AttributeError: - # No __provides__, so just fall back to implementedBy - return implementedBy(ob.__class__) - - # We need to make sure we got the __provides__ from the - # instance. We'll do this by making sure we don't get the same - # thing from the class: - - try: - cp = ob.__class__.__provides__ - except AttributeError: - # The ob doesn't have a class or the class has no - # provides, assume we're done: - return r - - if r is cp: - # Oops, we got the provides from the class. This means - # the object doesn't have it's own. We should use implementedBy - return implementedBy(ob.__class__) - - return r - -class ObjectSpecificationDescriptorPy(object): - """Implement the `__providedBy__` attribute - - The `__providedBy__` attribute computes the interfaces peovided by - an object. - """ - - def __get__(self, inst, cls): - """Get an object specification for an object - - For example: - - >>> from zope.interface import Interface - >>> class IFoo(Interface): pass - ... - >>> class IFooFactory(Interface): pass - ... - >>> class C(object): - ... implements(IFoo) - ... classProvides(IFooFactory) - >>> [i.getName() for i in C.__providedBy__] - ['IFooFactory'] - >>> [i.getName() for i in C().__providedBy__] - ['IFoo'] - - """ - - # Get an ObjectSpecification bound to either an instance or a class, - # depending on how we were accessed. - - if inst is None: - return getObjectSpecification(cls) - - provides = getattr(inst, '__provides__', None) - if provides is not None: - return provides - - return implementedBy(cls) - -ObjectSpecificationDescriptor = ObjectSpecificationDescriptorPy - -############################################################################## - -def _normalizeargs(sequence, output = None): - """Normalize declaration arguments - - Normalization arguments might contain Declarions, tuples, or single - interfaces. - - Anything but individial interfaces or implements specs will be expanded. - """ - if output is None: - output = [] - - cls = sequence.__class__ - if InterfaceClass in cls.__mro__ or Implements in cls.__mro__: - output.append(sequence) - else: - for v in sequence: - _normalizeargs(v, output) - - return output - -_empty = Declaration() - -try: - import _zope_interface_coptimizations -except ImportError: - pass -else: - from _zope_interface_coptimizations import implementedBy, providedBy - from _zope_interface_coptimizations import getObjectSpecification - from _zope_interface_coptimizations import ObjectSpecificationDescriptor - -objectSpecificationDescriptor = ObjectSpecificationDescriptor() diff --git a/tools/buildbot/pylibs/zope/interface/document.py b/tools/buildbot/pylibs/zope/interface/document.py deleted file mode 100644 index 282dadf..0000000 --- a/tools/buildbot/pylibs/zope/interface/document.py +++ /dev/null @@ -1,107 +0,0 @@ -############################################################################## -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" Pretty-Print an Interface object as structured text (Yum) - -This module provides a function, asStructuredText, for rendering an -interface as structured text. - -$Id: document.py 39768 2005-10-31 13:57:35Z tlotze $ -""" -import zope.interface - -def asStructuredText(I, munge=0): - """ Output structured text format. Note, this will whack any existing - 'structured' format of the text. """ - - r = [I.getName()] - outp = r.append - level = 1 - - if I.getDoc(): - outp(_justify_and_indent(_trim_doc_string(I.getDoc()), level)) - - bases = [base - for base in I.__bases__ - if base is not zope.interface.Interface - ] - if bases: - outp(_justify_and_indent("This interface extends:", level, munge)) - level += 1 - for b in bases: - item = "o %s" % b.getName() - outp(_justify_and_indent(_trim_doc_string(item), level, munge)) - level -= 1 - - namesAndDescriptions = I.namesAndDescriptions() - namesAndDescriptions.sort() - - outp(_justify_and_indent("Attributes:", level, munge)) - level += 1 - for name, desc in namesAndDescriptions: - if not hasattr(desc, 'getSignatureString'): # ugh... - item = "%s -- %s" % (desc.getName(), - desc.getDoc() or 'no documentation') - outp(_justify_and_indent(_trim_doc_string(item), level, munge)) - level -= 1 - - outp(_justify_and_indent("Methods:", level, munge)) - level += 1 - for name, desc in namesAndDescriptions: - if hasattr(desc, 'getSignatureString'): # ugh... - item = "%s%s -- %s" % (desc.getName(), - desc.getSignatureString(), - desc.getDoc() or 'no documentation') - outp(_justify_and_indent(_trim_doc_string(item), level, munge)) - - return "\n\n".join(r) + "\n\n" - - -def _trim_doc_string(text): - """ Trims a doc string to make it format - correctly with structured text. """ - - lines = text.replace('\r\n', '\n').split('\n') - nlines = [lines.pop(0)] - if lines: - min_indent = min([len(line) - len(line.lstrip()) - for line in lines]) - for line in lines: - nlines.append(line[min_indent:]) - - return '\n'.join(nlines) - - -def _justify_and_indent(text, level, munge=0, width=72): - """ indent and justify text, rejustify (munge) if specified """ - - indent = " " * level - - if munge: - lines = [] - line = indent - text = text.split() - - for word in text: - line = ' '.join([line, word]) - if len(line) > width: - lines.append(line) - line = indent - else: - lines.append(line) - - return '\n'.join(lines) - - else: - return indent + \ - text.strip().replace("\r\n", "\n") .replace("\n", "\n" + indent) diff --git a/tools/buildbot/pylibs/zope/interface/exceptions.py b/tools/buildbot/pylibs/zope/interface/exceptions.py deleted file mode 100644 index c19171b..0000000 --- a/tools/buildbot/pylibs/zope/interface/exceptions.py +++ /dev/null @@ -1,69 +0,0 @@ -############################################################################## -# -# Copyright (c) 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Interface-specific exceptions - -$Id: exceptions.py 67174 2006-04-20 14:11:55Z flindner $ -""" - -class Invalid(Exception): - """A specification is violated - """ - -class DoesNotImplement(Invalid): - """ This object does not implement """ - def __init__(self, interface): - self.interface = interface - - def __str__(self): - return """An object does not implement interface %(interface)s - - """ % self.__dict__ - -class BrokenImplementation(Invalid): - """An attribute is not completely implemented. - """ - - def __init__(self, interface, name): - self.interface=interface - self.name=name - - def __str__(self): - return """An object has failed to implement interface %(interface)s - - The %(name)s attribute was not provided. - """ % self.__dict__ - -class BrokenMethodImplementation(Invalid): - """An method is not completely implemented. - """ - - def __init__(self, method, mess): - self.method=method - self.mess=mess - - def __str__(self): - return """The implementation of %(method)s violates its contract - because %(mess)s. - """ % self.__dict__ - -class InvalidInterface(Exception): - """The interface has invalid contents - """ - -class BadImplements(TypeError): - """An implementation assertion is invalid - - because it doesn't contain an interface or a sequence of valid - implementation assertions. - """ diff --git a/tools/buildbot/pylibs/zope/interface/human.ru.txt b/tools/buildbot/pylibs/zope/interface/human.ru.txt deleted file mode 100644 index 36e7f3c..0000000 --- a/tools/buildbot/pylibs/zope/interface/human.ru.txt +++ /dev/null @@ -1,154 +0,0 @@ -=============================== -ИÑпользование рееÑтра адаптеров -=============================== - -Данный документ Ñодержит небольшую демонÑтрацию пакета ``zope.interface`` и его -рееÑтра адаптеров. Документ раÑÑчитывалÑÑ ÐºÐ°Ðº конкретный, но более узкий пример -того как иÑпользовать интерфейÑÑ‹ и адаптеры вне Zope 3. - -Сначала нам необходимо импортировать пакет Ð´Ð»Ñ Ñ€Ð°Ð±Ð¾Ñ‚Ñ‹ Ñ Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñами. - - >>> import zope.interface - -Теперь мы разработаем Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ Ð´Ð»Ñ Ð½Ð°ÑˆÐµÐ³Ð¾ объекта - проÑтого файла. Ðаш файл -будет Ñодержать вÑего один атрибут - body, в котором фактичеÑки будет Ñохранено -Ñодержимое файла. - - >>> class IFile(zope.interface.Interface): - ... - ... body = zope.interface.Attribute(u'Содержимое файла.') - ... - -Ð”Ð»Ñ ÑтатиÑтики нам чаÑто необходимо знать размер файла. Ðо было бы неÑколько -топорно релизовывать определение размера прÑмо Ð´Ð»Ñ Ð¾Ð±ÑŠÐµÐºÑ‚Ð° файла, Ñ‚.к. размер -больше отноÑитÑÑ Ðº мета-данным. Таким образом мы Ñоздаем еще один Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ Ð´Ð»Ñ -предÑÑ‚Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ñ€Ð°Ð·Ð¼ÐµÑ€Ð° какого-либо объекта. - - >>> class ISize(zope.interface.Interface): - ... - ... def getSize(): - ... 'Return the size of an object.' - ... - -Теперь мы должны Ñоздать клаÑÑ Ñ€ÐµÐ°Ð»Ð¸Ð·ÑƒÑŽÑ‰Ð¸Ð¹ наш файл. Ðеобходимо что бы наш -объект хранил информацию о том, что он реализует Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ `IFile`. Мы также -Ñоздаем атрибут Ñ Ñодержимым файла по умолчанию (Ð´Ð»Ñ ÑƒÐ¿Ñ€Ð¾Ñ‰ÐµÐ½Ð¸Ñ Ð½Ð°ÑˆÐµÐ³Ð¾ примера). - - >>> class File(object): - ... - ... zope.interface.implements(IFile) - ... body = 'foo bar' - ... - -Дальше мы Ñоздаем адаптер, который будет предоÑтавлÑÑ‚ÑŒ Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ `ISize` -Ð¿Ð¾Ð»ÑƒÑ‡Ð°Ñ Ð»ÑŽÐ±Ð¾Ð¹ объект предоÑтавлÑющий Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ `IFile`. По Ñоглашению мы -иÑпользуем атрибут `__used_for__` Ð´Ð»Ñ ÑƒÐºÐ°Ð·Ð°Ð½Ð¸Ñ Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñа который как мы -ожидаем предоÑтавлÑет адаптируемый объект, `IFile` в нашем Ñлучае. Ðа Ñамом -деле Ñтот атрибут иÑпользуетÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ Ð´Ð»Ñ Ð´Ð¾ÐºÑƒÐ¼ÐµÐ½Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ. Ð’ Ñлучае еÑли -адаптер иÑпользуетÑÑ Ð´Ð»Ñ Ð½ÐµÑкольких интерфейÑов можно указать их вÑе в виде -кортежа. - -ОпÑÑ‚ÑŒ же по Ñоглашению конÑтруктор адаптера получает один аргумент - context -(контекÑÑ‚). Ð’ нашем Ñлучае контекÑÑ‚ - Ñто ÑкземплÑÑ€ `IFile` (объект, -предоÑтавлÑющий `IFile`) который иÑпользуетÑÑ Ð´Ð»Ñ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ð¸Ð· него размера. -Так же по Ñоглашению контекÑÑ‚ ÑохранÑетÑÑ Ð° адаптере в атрибуте Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼ -`context`. Twisted комьюнити ÑÑылаетÑÑ Ð½Ð° контекÑÑ‚ как на объект `original`. -Таким образом можно также дать аргументу любое подходÑщее имÑ, например `file`. - - >>> class FileSize(object): - ... - ... zope.interface.implements(ISize) - ... __used_for__ = IFile - ... - ... def __init__(self, context): - ... self.context = context - ... - ... def getSize(self): - ... return len(self.context.body) - ... - -Теперь когда мы напиÑали наш адаптер мы должны зарегиÑтрировать его в рееÑтре -адаптеров, что бы его можно было запроÑить когда он понадобитÑÑ. ЗдеÑÑŒ нет -какого-либо глобального рееÑтра адаптеров, таким образом мы должны -ÑамоÑтоÑтельно Ñоздать Ð´Ð»Ñ Ð½Ð°ÑˆÐµÐ³Ð¾ примера рееÑÑ‚Ñ€. - - >>> from zope.interface.adapter import AdapterRegistry - >>> registry = AdapterRegistry() - -РееÑÑ‚Ñ€ Ñодержит отображение того, что адаптер реализует на оÑнове другого -интерфейÑа который предоÑтавлÑет объект. ПоÑтому дальше мы региÑтрируем адаптер -который адаптирует Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ `IFile` к интерфейÑу `ISize`. Первый аргумент к -методу `register()` рееÑтра - Ñто ÑпиÑок адаптируемых интерфейÑов. Ð’ нашем -Ñлучае мы имеем только один адаптируемый Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ - `IFile`. СпиÑок -интерфейÑов имеет ÑмыÑл Ð´Ð»Ñ Ð¸ÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ ÐºÐ¾Ð½Ñ†ÐµÐ¿Ñ†Ð¸Ð¸ мульти-адаптеров, которые -требуют неÑкольких оригинальных объектов Ð´Ð»Ñ Ð°Ð´Ð°Ð¿Ñ‚Ð°Ñ†Ð¸Ð¸ к новому интерфейÑу. Ð’ -Ñтой Ñитуации конÑтруктор адаптера будет требовать новый аргумент Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ -оригинального интерфейÑа. - -Второй аргумент метода `register()` - Ñто Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ ÐºÐ¾Ñ‚Ð¾Ñ€Ñ‹Ð¹ предоÑтавлÑет -адаптер, в нашем Ñлучае `ISize`. Третий аргумент - Ð¸Ð¼Ñ Ð°Ð´Ð°Ð¿Ñ‚ÐµÑ€Ð°. Ð¡ÐµÐ¹Ñ‡Ð°Ñ Ð½Ð°Ð¼ не -важно Ð¸Ð¼Ñ Ð°Ð´Ð°Ð¿Ñ‚ÐµÑ€Ð° и мы передаем его как пуÑтую Ñтроку. Обычно имена полезны -еÑли иÑпользуютÑÑ Ð°Ð´Ð°Ð¿Ñ‚ÐµÑ€Ñ‹ Ð´Ð»Ñ Ð¾Ð´Ð¸Ð½Ð°ÐºÐ¾Ð²Ð¾Ð³Ð¾ набора интерфейÑов, но в различных -ÑитуациÑÑ…. ПоÑледний аргумент - Ñто клаÑÑ Ð°Ð´Ð°Ð¿Ñ‚ÐµÑ€Ð°. - - >>> registry.register([IFile], ISize, '', FileSize) - -Теперь мы можем иÑпользовать рееÑÑ‚Ñ€ Ð´Ð»Ñ Ð·Ð°Ð¿Ñ€Ð¾Ñа адаптера. - - >>> registry.lookup1(IFile, ISize, '') - - -Попробуем более практичный пример. Создадим ÑкземплÑÑ€ `File` и Ñоздадим адаптер -иÑпользующий Ð·Ð°Ð¿Ñ€Ð¾Ñ Ñ€ÐµÐµÑтра. Затем мы увидим возвращает ли адаптер корректный -размер при вызове `getSize()`. - - >>> file = File() - >>> size = registry.lookup1(IFile, ISize, '')(file) - >>> size.getSize() - 7 - -Ðа Ñамом деле Ñто не очень практично, Ñ‚.к. нам нужно Ñамим передавать вÑе -аргументы методу запроÑа. СущеÑтвует некоторый "ÑинтакÑичеÑкий лединец" который -позволÑет нам получить ÑкземплÑÑ€ адаптера проÑто вызвав `ISize(file)`. Что бы -иÑпользовать Ñту функциональноÑÑ‚ÑŒ нам понадобитÑÑ Ð´Ð¾Ð±Ð°Ð²Ð¸Ñ‚ÑŒ наш рееÑÑ‚Ñ€ к ÑпиÑку -adapter_hooks, который находитÑÑ Ð² модуле Ñ Ð°Ð´Ð°Ð¿Ñ‚ÐµÑ€Ð°Ð¼Ð¸. Этот ÑпиÑок хранит -коллекцию вызываемых объектов которые вызываютÑÑ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡ÐµÑки когда вызываетÑÑ -IFoo(obj); их предназначение - найти адаптеры которые реализуют Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ -Ð´Ð»Ñ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð½Ð¾Ð³Ð¾ ÑкземплÑра контекÑта. - -Ðеобходимо реализовать Ñвою ÑобÑтвенную функцию Ð´Ð»Ñ Ð¿Ð¾Ð¸Ñка адаптера; данный -пример опиÑывает одну из проÑтейших функций Ð´Ð»Ñ Ð¸ÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ Ñ€ÐµÐµÑтром, но -также можно реализовать поиÑковые функции которые, например, иÑпользуют -кÑширование, или адаптеры ÑохранÑемые в базе. Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¿Ð¾Ð¸Ñка должна принимать -желаемый на выходе Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ (в нашем Ñлучае `ISize`) как первый аргумент и -контекÑÑ‚ Ð´Ð»Ñ Ð°Ð´Ð°Ð¿Ñ‚Ð°Ñ†Ð¸Ð¸ (`file`) как второй. Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° вернуть адаптер, -Ñ‚.е. ÑкзмеплÑÑ€ `FileSize`. - - >>> def hook(provided, object): - ... adapter = registry.lookup1(zope.interface.providedBy(object), - ... provided, '') - ... return adapter(object) - ... - -Теперь мы проÑто добавлÑем нашу функцию к ÑпиÑку `adapter_hooks`. - - >>> from zope.interface.interface import adapter_hooks - >>> adapter_hooks.append(hook) - -Как только Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð·Ð°Ñ€ÐµÐ³Ð¸Ñтрирована мы можем иÑпользовать желаемый ÑинтакÑиÑ. - - >>> size = ISize(file) - >>> size.getSize() - 7 - -ПоÑле нам нужно прибратьÑÑ Ð·Ð° Ñобой, что бы другие получили чиÑтый ÑпиÑок -`adaper_hooks` поÑле наÑ. - - >>> adapter_hooks.remove(hook) - -Это вÑе. ЗдеÑÑŒ намеренно отложена диÑкуÑÑÐ¸Ñ Ð¾Ð± именованных и мульти-адаптерах, -Ñ‚.к. данный текÑÑ‚ раÑÑчитан как практичеÑкое и проÑтое введение в интерфейÑÑ‹ и -адаптеры Zope 3. Ð”Ð»Ñ Ð±Ð¾Ð»ÐµÐµ подробной информации имеет ÑмыÑл прочитать -`adapter.txt` из пакета `zope.interface`, что бы получить более формальное, -Ñправочное и полное трактование пакета. Внимание: многие жаловалиÑÑŒ, что -`adapter.txt` приводит их мозг к раÑплавленному ÑоÑтоÑнию! diff --git a/tools/buildbot/pylibs/zope/interface/human.txt b/tools/buildbot/pylibs/zope/interface/human.txt deleted file mode 100644 index 1660893..0000000 --- a/tools/buildbot/pylibs/zope/interface/human.txt +++ /dev/null @@ -1,152 +0,0 @@ -========================== -Using the Adapter Registry -========================== - -This is a small demonstration of the ``zope.interface`` package including its -adapter registry. It is intended to provide a concrete but narrow example on -how to use interfaces and adapters outside of Zope 3. - -First we have to import the interface package. - - >>> import zope.interface - -We now develop an interface for our object, which is a simple file in this -case. For now we simply support one attribute, the body, which contains the -actual file contents. - - >>> class IFile(zope.interface.Interface): - ... - ... body = zope.interface.Attribute('Contents of the file.') - ... - -For statistical reasons we often want to know the size of a file. However, it -would be clumsy to implement the size directly in the file object, since the -size really represents meta-data. Thus we create another interface that -provides the size of something. - - >>> class ISize(zope.interface.Interface): - ... - ... def getSize(): - ... 'Return the size of an object.' - ... - -Now we need to implement the file. It is essential that the object states -that it implements the `IFile` interface. We also provide a default body -value (just to make things simpler for this example). - - >>> class File(object): - ... - ... zope.interface.implements(IFile) - ... body = 'foo bar' - ... - -Next we implement an adapter that can provide the `ISize` interface given any -object providing `IFile`. By convention we use `__used_for__` to specify the -interface that we expect the adapted object to provide, in our case -`IFile`. However, this attribute is not used for anything. If you have -multiple interfaces for which an adapter is used, just specify the interfaces -via a tuple. - -Again by convention, the constructor of an adapter takes one argument, the -context. The context in this case is an instance of `File` (providing `IFile`) -that is used to extract the size from. Also by convention the context is -stored in an attribute named `context` on the adapter. The twisted community -refers to the context as the `original` object. However, you may feel free to -use a specific argument name, such as `file`. - - >>> class FileSize(object): - ... - ... zope.interface.implements(ISize) - ... __used_for__ = IFile - ... - ... def __init__(self, context): - ... self.context = context - ... - ... def getSize(self): - ... return len(self.context.body) - ... - -Now that we have written our adapter, we have to register it with an adapter -registry, so that it can be looked up when needed. There is no such thing as a -global registry; thus we have to instantiate one for our example manually. - - >>> from zope.interface.adapter import AdapterRegistry - >>> registry = AdapterRegistry() - - -The registry keeps a map of what adapters implement based on another -interface, the object already provides. Therefore, we next have to register an -adapter that adapts from `IFile` to `ISize`. The first argument to -the registry's `register()` method is a list of original interfaces.In our -cause we have only one original interface, `IFile`. A list makes sense, since -the interface package has the concept of multi-adapters, which are adapters -that require multiple objects to adapt to a new interface. In these -situations, your adapter constructor will require an argument for each -specified interface. - -The second argument is the interface the adapter provides, in our case -`ISize`. The third argument is the name of the adapter. Since we do not care -about names, we simply leave it as an empty string. Names are commonly useful, -if you have adapters for the same set of interfaces, but they are useful in -different situations. The last argument is simply the adapter class. - - >>> registry.register([IFile], ISize, '', FileSize) - -You can now use the the registry to lookup the adapter. - - >>> registry.lookup1(IFile, ISize, '') - - -Let's get a little bit more practical. Let's create a `File` instance and -create the adapter using a registry lookup. Then we see whether the adapter -returns the correct size by calling `getSize()`. - - >>> file = File() - >>> size = registry.lookup1(IFile, ISize, '')(file) - >>> size.getSize() - 7 - -However, this is not very practical, since I have to manually pass in the -arguments to the lookup method. There is some syntactic candy that will allow -us to get an adapter instance by simply calling `ISize(file)`. To make use of -this functionality, we need to add our registry to the adapter_hooks list, -which is a member of the adapters module. This list stores a collection of -callables that are automatically invoked when IFoo(obj) is called; their -purpose is to locate adapters that implement an interface for a certain -context instance. - -You are required to implement your own adapter hook; this example covers one -of the simplest hooks that use the registry, but you could implement one that -used an adapter cache or persistent adapters, for instance. The helper hook is -required to expect as first argument the desired output interface (for us -`ISize`) and as the second argument the context of the adapter (here -`file`). The function returns an adapter, i.e. a `FileSize` instance. - - >>> def hook(provided, object): - ... adapter = registry.lookup1(zope.interface.providedBy(object), - ... provided, '') - ... return adapter(object) - ... - -We now just add the hook to an `adapter_hooks` list. - - >>> from zope.interface.interface import adapter_hooks - >>> adapter_hooks.append(hook) - -Once the hook is registered, you can use the desired syntax. - - >>> size = ISize(file) - >>> size.getSize() - 7 - -Now we have to cleanup after ourselves, so that others after us have a clean -`adapter_hooks` list. - - >>> adapter_hooks.remove(hook) - -That's it. I have intentionally left out a discussion of named adapters and -multi-adapters, since this text is intended as a practical and simple -introduction to Zope 3 interfaces and adapters. You might want to read the -`adapter.txt` in the `zope.interface` package for a more formal, referencial -and complete treatment of the package. Warning: People have reported that -`adapter.txt` makes their brain feel soft! diff --git a/tools/buildbot/pylibs/zope/interface/interface.py b/tools/buildbot/pylibs/zope/interface/interface.py deleted file mode 100644 index 3eff8b6..0000000 --- a/tools/buildbot/pylibs/zope/interface/interface.py +++ /dev/null @@ -1,821 +0,0 @@ -############################################################################## -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Interface object implementation - -$Id: interface.py 67761 2006-04-30 13:56:44Z jim $ -""" - -from __future__ import generators - -import sys -import warnings -import weakref -from types import FunctionType -from ro import ro -from zope.interface.exceptions import Invalid - -CO_VARARGS = 4 -CO_VARKEYWORDS = 8 -TAGGED_DATA = '__interface_tagged_values__' - -_decorator_non_return = object() - -def invariant(call): - f_locals = sys._getframe(1).f_locals - tags = f_locals.setdefault(TAGGED_DATA, {}) - invariants = tags.setdefault('invariants', []) - invariants.append(call) - return _decorator_non_return - -class Element(object): - - # We can't say this yet because we don't have enough - # infrastructure in place. - # - #implements(IElement) - - def __init__(self, __name__, __doc__=''): - """Create an 'attribute' description - """ - if not __doc__ and __name__.find(' ') >= 0: - __doc__ = __name__ - __name__ = None - - self.__name__=__name__ - self.__doc__=__doc__ - self.__tagged_values = {} - - def getName(self): - """ Returns the name of the object. """ - return self.__name__ - - def getDoc(self): - """ Returns the documentation for the object. """ - return self.__doc__ - - def getTaggedValue(self, tag): - """ Returns the value associated with 'tag'. """ - return self.__tagged_values[tag] - - def queryTaggedValue(self, tag, default=None): - """ Returns the value associated with 'tag'. """ - return self.__tagged_values.get(tag, default) - - def getTaggedValueTags(self): - """ Returns a list of all tags. """ - return self.__tagged_values.keys() - - def setTaggedValue(self, tag, value): - """ Associates 'value' with 'key'. """ - self.__tagged_values[tag] = value - -class SpecificationBasePy(object): - - def providedBy(self, ob): - """Is the interface implemented by an object - - >>> from zope.interface import * - >>> class I1(Interface): - ... pass - >>> class C(object): - ... implements(I1) - >>> c = C() - >>> class X(object): - ... pass - >>> x = X() - >>> I1.providedBy(x) - False - >>> I1.providedBy(C) - False - >>> I1.providedBy(c) - True - >>> directlyProvides(x, I1) - >>> I1.providedBy(x) - True - >>> directlyProvides(C, I1) - >>> I1.providedBy(C) - True - - """ - spec = providedBy(ob) - return self in spec._implied - - def implementedBy(self, cls): - """Test whether the specification is implemented by a class or factory. - Raise TypeError if argument is neither a class nor a callable.""" - spec = implementedBy(cls) - return self in spec._implied - - def isOrExtends(self, interface): - """Is the interface the same as or extend the given interface - - Examples:: - - >>> from zope.interface import Interface - >>> from zope.interface.declarations import Declaration - >>> class I1(Interface): pass - ... - >>> class I2(I1): pass - ... - >>> class I3(Interface): pass - ... - >>> class I4(I3): pass - ... - >>> spec = Declaration() - >>> int(spec.extends(Interface)) - 1 - >>> spec = Declaration(I2) - >>> int(spec.extends(Interface)) - 1 - >>> int(spec.extends(I1)) - 1 - >>> int(spec.extends(I2)) - 1 - >>> int(spec.extends(I3)) - 0 - >>> int(spec.extends(I4)) - 0 - - """ - return interface in self._implied - - __call__ = isOrExtends - -SpecificationBase = SpecificationBasePy - -_marker = object() -class InterfaceBasePy(object): - """Base class that wants to be replaced with a C base :) - """ - - def __call__(self, obj, alternate=_marker): - """Adapt an object to the interface - """ - conform = getattr(obj, '__conform__', None) - if conform is not None: - adapter = self._call_conform(conform) - if adapter is not None: - return adapter - - adapter = self.__adapt__(obj) - - if adapter is not None: - return adapter - elif alternate is not _marker: - return alternate - else: - raise TypeError("Could not adapt", obj, self) - - def __adapt__(self, obj): - """Adapt an object to the reciever - """ - if self.providedBy(obj): - return obj - - for hook in adapter_hooks: - adapter = hook(self, obj) - if adapter is not None: - return adapter - -InterfaceBase = InterfaceBasePy - -adapter_hooks = [] - -try: - import _zope_interface_coptimizations -except ImportError: - pass -else: - from _zope_interface_coptimizations import SpecificationBase - from _zope_interface_coptimizations import InterfaceBase, adapter_hooks - -class Specification(SpecificationBase): - """Specifications - - An interface specification is used to track interface declarations - and component registrations. - - This class is a base class for both interfaces themselves and for - interface specifications (declarations). - - Specifications are mutable. If you reassign their cases, their - relations with other specifications are adjusted accordingly. - - For example: - - >>> from zope.interface import Interface - >>> class I1(Interface): - ... pass - >>> class I2(I1): - ... pass - >>> class I3(I2): - ... pass - - >>> [i.__name__ for i in I1.__bases__] - ['Interface'] - - >>> [i.__name__ for i in I2.__bases__] - ['I1'] - - >>> I3.extends(I1) - 1 - - >>> I2.__bases__ = (Interface, ) - - >>> [i.__name__ for i in I2.__bases__] - ['Interface'] - - >>> I3.extends(I1) - 0 - - """ - - # Copy some base class methods for speed - isOrExtends = SpecificationBase.isOrExtends - providedBy = SpecificationBase.providedBy - - ######################################################################### - # BBB 2004-07-13: Backward compatabilty. These methods have been - # deprecated in favour of providedBy and implementedBy. - - def isImplementedByInstancesOf(self, cls): - warnings.warn( - "isImplementedByInstancesOf has been renamed to implementedBy", - DeprecationWarning, stacklevel=2, - ) - return self.implementedBy(cls) - - def isImplementedBy(self, ob): - warnings.warn( - "isImplementedBy has been renamed to providedBy", - DeprecationWarning, stacklevel=2, - ) - return self.providedBy(ob) - # - ######################################################################### - - def __init__(self, bases=()): - self._implied = {} - self.dependents = weakref.WeakKeyDictionary() - self.__bases__ = tuple(bases) - - def subscribe(self, dependent): - self.dependents[dependent] = self.dependents.get(dependent, 0) + 1 - - def unsubscribe(self, dependent): - n = self.dependents.get(dependent, 0) - 1 - if not n: - del self.dependents[dependent] - elif n > 0: - self.dependents[dependent] = n - else: - raise KeyError(dependent) - - def __setBases(self, bases): - # Register ourselves as a dependent of our old bases - for b in self.__bases__: - b.unsubscribe(self) - - # Register ourselves as a dependent of our bases - self.__dict__['__bases__'] = bases - for b in bases: - b.subscribe(self) - - self.changed(self) - - __bases__ = property( - - lambda self: self.__dict__.get('__bases__', ()), - __setBases, - ) - - def changed(self, originally_changed): - """We, or something we depend on, have changed - """ - - implied = self._implied - implied.clear() - - ancestors = ro(self) - - try: - if Interface not in ancestors: - ancestors.append(Interface) - except NameError: - pass # defining Interface itself - - self.__sro__ = tuple(ancestors) - self.__iro__ = tuple([ancestor for ancestor in ancestors - if isinstance(ancestor, InterfaceClass) - ]) - - for ancestor in ancestors: - # We directly imply our ancestors: - implied[ancestor] = () - - # Now, advise our dependents of change: - for dependent in self.dependents.keys(): - dependent.changed(originally_changed) - - - def interfaces(self): - """Return an iterator for the interfaces in the specification - - for example:: - - >>> from zope.interface import Interface - >>> class I1(Interface): pass - ... - >>> class I2(I1): pass - ... - >>> class I3(Interface): pass - ... - >>> class I4(I3): pass - ... - >>> spec = Specification((I2, I3)) - >>> spec = Specification((I4, spec)) - >>> i = spec.interfaces() - >>> i.next().getName() - 'I4' - >>> i.next().getName() - 'I2' - >>> i.next().getName() - 'I3' - >>> list(i) - [] - """ - seen = {} - for base in self.__bases__: - for interface in base.interfaces(): - if interface not in seen: - seen[interface] = 1 - yield interface - - - def extends(self, interface, strict=True): - """Does the specification extend the given interface? - - Test whether an interface in the specification extends the - given interface - - Examples:: - - >>> from zope.interface import Interface - >>> from zope.interface.declarations import Declaration - >>> class I1(Interface): pass - ... - >>> class I2(I1): pass - ... - >>> class I3(Interface): pass - ... - >>> class I4(I3): pass - ... - >>> spec = Declaration() - >>> int(spec.extends(Interface)) - 1 - >>> spec = Declaration(I2) - >>> int(spec.extends(Interface)) - 1 - >>> int(spec.extends(I1)) - 1 - >>> int(spec.extends(I2)) - 1 - >>> int(spec.extends(I3)) - 0 - >>> int(spec.extends(I4)) - 0 - >>> I2.extends(I2) - 0 - >>> I2.extends(I2, False) - 1 - >>> I2.extends(I2, strict=False) - 1 - - """ - return ((interface in self._implied) - and - ((not strict) or (self != interface)) - ) - - def weakref(self, callback=None): - return weakref.ref(self, callback) - - def get(self, name, default=None): - """Query for an attribute description - """ - try: - attrs = self._v_attrs - except AttributeError: - attrs = self._v_attrs = {} - attr = attrs.get(name) - if attr is None: - for iface in self.__iro__: - attr = iface.direct(name) - if attr is not None: - attrs[name] = attr - break - - if attr is None: - return default - else: - return attr - -class InterfaceClass(Element, InterfaceBase, Specification): - """Prototype (scarecrow) Interfaces Implementation.""" - - # We can't say this yet because we don't have enough - # infrastructure in place. - # - #implements(IInterface) - - def __init__(self, name, bases=(), attrs=None, __doc__=None, - __module__=None): - - if attrs is None: - attrs = {} - - if __module__ is None: - __module__ = attrs.get('__module__') - if isinstance(__module__, str): - del attrs['__module__'] - else: - try: - # Figure out what module defined the interface. - # This is how cPython figures out the module of - # a class, but of course it does it in C. :-/ - __module__ = sys._getframe(1).f_globals['__name__'] - except (AttributeError, KeyError): - pass - - self.__module__ = __module__ - - d = attrs.get('__doc__') - if d is not None: - if not isinstance(d, Attribute): - if __doc__ is None: - __doc__ = d - del attrs['__doc__'] - - if __doc__ is None: - __doc__ = '' - - Element.__init__(self, name, __doc__) - - tagged_data = attrs.pop(TAGGED_DATA, None) - if tagged_data is not None: - for key, val in tagged_data.items(): - self.setTaggedValue(key, val) - - for base in bases: - if not isinstance(base, InterfaceClass): - raise TypeError('Expected base interfaces') - - Specification.__init__(self, bases) - - # Make sure that all recorded attributes (and methods) are of type - # `Attribute` and `Method` - for name, attr in attrs.items(): - if isinstance(attr, Attribute): - attr.interface = self - if not attr.__name__: - attr.__name__ = name - elif isinstance(attr, FunctionType): - attrs[name] = fromFunction(attr, self, name=name) - elif attr is _decorator_non_return: - del attrs[name] - else: - raise InvalidInterface("Concrete attribute, " + name) - - self.__attrs = attrs - - self.__identifier__ = "%s.%s" % (self.__module__, self.__name__) - - def interfaces(self): - """Return an iterator for the interfaces in the specification - - for example:: - - >>> from zope.interface import Interface - >>> class I1(Interface): pass - ... - >>> - >>> i = I1.interfaces() - >>> i.next().getName() - 'I1' - >>> list(i) - [] - """ - yield self - - def getBases(self): - return self.__bases__ - - def isEqualOrExtendedBy(self, other): - """Same interface or extends?""" - return self == other or other.extends(self) - - def names(self, all=False): - """Return the attribute names defined by the interface.""" - if not all: - return self.__attrs.keys() - - r = self.__attrs.copy() - - for base in self.__bases__: - r.update(dict.fromkeys(base.names(all))) - - return r.keys() - - def __iter__(self): - return iter(self.names(all=True)) - - def namesAndDescriptions(self, all=False): - """Return attribute names and descriptions defined by interface.""" - if not all: - return self.__attrs.items() - - r = {} - for base in self.__bases__[::-1]: - r.update(dict(base.namesAndDescriptions(all))) - - r.update(self.__attrs) - - return r.items() - - def getDescriptionFor(self, name): - """Return the attribute description for the given name.""" - r = self.get(name) - if r is not None: - return r - - raise KeyError(name) - - __getitem__ = getDescriptionFor - - def __contains__(self, name): - return self.get(name) is not None - - def direct(self, name): - return self.__attrs.get(name) - - def queryDescriptionFor(self, name, default=None): - return self.get(name, default) - - def deferred(self): - """Return a defered class corresponding to the interface.""" - if hasattr(self, "_deferred"): return self._deferred - - klass={} - exec "class %s: pass" % self.__name__ in klass - klass=klass[self.__name__] - - self.__d(klass.__dict__) - - self._deferred=klass - - return klass - - def validateInvariants(self, obj, errors=None): - """validate object to defined invariants.""" - for call in self.queryTaggedValue('invariants', []): - try: - call(obj) - except Invalid, e: - if errors is None: - raise - else: - errors.append(e) - for base in self.__bases__: - try: - base.validateInvariants(obj, errors) - except Invalid: - if errors is None: - raise - if errors: - raise Invalid(errors) - - def _getInterface(self, ob, name): - """Retrieve a named interface.""" - return None - - def __d(self, dict): - - for k, v in self.__attrs.items(): - if isinstance(v, Method) and not (k in dict): - dict[k]=v - - for b in self.__bases__: - b.__d(dict) - - def __repr__(self): - try: - return self._v_repr - except AttributeError: - name = self.__name__ - m = self.__module__ - if m: - name = '%s.%s' % (m, name) - r = "<%s %s>" % (self.__class__.__name__, name) - self._v_repr = r - return r - - def _call_conform(self, conform): - try: - return conform(self) - except TypeError: - # We got a TypeError. It might be an error raised by - # the __conform__ implementation, or *we* may have - # made the TypeError by calling an unbound method - # (object is a class). In the later case, we behave - # as though there is no __conform__ method. We can - # detect this case by checking whether there is more - # than one traceback object in the traceback chain: - if sys.exc_info()[2].tb_next is not None: - # There is more than one entry in the chain, so - # reraise the error: - raise - # This clever trick is from Phillip Eby - - return None - - def __reduce__(self): - return self.__name__ - - def __cmp(self, o1, o2): - # Yes, I did mean to name this __cmp, rather than __cmp__. - # It is a private method used by __lt__ and __gt__. - # I don't want to override __eq__ because I want the default - # __eq__, which is really fast. - """Make interfaces sortable - - TODO: It would ne nice if: - - More specific interfaces should sort before less specific ones. - Otherwise, sort on name and module. - - But this is too complicated, and we're going to punt on it - for now. - - For now, sort on interface and module name. - - None is treated as a pseudo interface that implies the loosest - contact possible, no contract. For that reason, all interfaces - sort before None. - - """ - if o1 == o2: - return 0 - - if o1 is None: - return 1 - if o2 is None: - return -1 - - n1 = (getattr(o1, '__name__', ''), - getattr(getattr(o1, '__module__', None), '__name__', '')) - n2 = (getattr(o2, '__name__', ''), - getattr(getattr(o2, '__module__', None), '__name__', '')) - - return cmp(n1, n2) - - def __lt__(self, other): - c = self.__cmp(self, other) - #print '<', self, other, c < 0, c - return c < 0 - - def __gt__(self, other): - c = self.__cmp(self, other) - #print '>', self, other, c > 0, c - return c > 0 - - -Interface = InterfaceClass("Interface", __module__ = 'zope.interface') - -class Attribute(Element): - """Attribute descriptions - """ - - # We can't say this yet because we don't have enough - # infrastructure in place. - # - # implements(IAttribute) - - interface = None - - -class Method(Attribute): - """Method interfaces - - The idea here is that you have objects that describe methods. - This provides an opportunity for rich meta-data. - """ - - # We can't say this yet because we don't have enough - # infrastructure in place. - # - # implements(IMethod) - - def __call__(self, *args, **kw): - raise BrokenImplementation(self.interface, self.__name__) - - def getSignatureInfo(self): - return {'positional': self.positional, - 'required': self.required, - 'optional': self.optional, - 'varargs': self.varargs, - 'kwargs': self.kwargs, - } - - def getSignatureString(self): - sig = [] - for v in self.positional: - sig.append(v) - if v in self.optional.keys(): - sig[-1] += "=" + `self.optional[v]` - if self.varargs: - sig.append("*" + self.varargs) - if self.kwargs: - sig.append("**" + self.kwargs) - - return "(%s)" % ", ".join(sig) - - -def fromFunction(func, interface=None, imlevel=0, name=None): - name = name or func.__name__ - method = Method(name, func.__doc__) - defaults = func.func_defaults or () - code = func.func_code - # Number of positional arguments - na = code.co_argcount-imlevel - names = code.co_varnames[imlevel:] - opt = {} - # Number of required arguments - nr = na-len(defaults) - if nr < 0: - defaults=defaults[-nr:] - nr = 0 - - # Determine the optional arguments. - opt.update(dict(zip(names[nr:], defaults))) - - method.positional = names[:na] - method.required = names[:nr] - method.optional = opt - - argno = na - - # Determine the function's variable argument's name (i.e. *args) - if code.co_flags & CO_VARARGS: - method.varargs = names[argno] - argno = argno + 1 - else: - method.varargs = None - - # Determine the function's keyword argument's name (i.e. **kw) - if code.co_flags & CO_VARKEYWORDS: - method.kwargs = names[argno] - else: - method.kwargs = None - - method.interface = interface - - for key, value in func.__dict__.items(): - method.setTaggedValue(key, value) - - return method - - -def fromMethod(meth, interface=None, name=None): - func = meth.im_func - return fromFunction(func, interface, imlevel=1, name=name) - - -# Now we can create the interesting interfaces and wire them up: -def _wire(): - from zope.interface.declarations import classImplements - - from zope.interface.interfaces import IAttribute - classImplements(Attribute, IAttribute) - - from zope.interface.interfaces import IMethod - classImplements(Method, IMethod) - - from zope.interface.interfaces import IInterface, ISpecification - classImplements(InterfaceClass, IInterface) - classImplements(Specification, ISpecification) - -# We import this here to deal with module dependencies. -from zope.interface.declarations import providedBy, implementedBy -from zope.interface.exceptions import InvalidInterface -from zope.interface.exceptions import BrokenImplementation diff --git a/tools/buildbot/pylibs/zope/interface/interfaces.py b/tools/buildbot/pylibs/zope/interface/interfaces.py deleted file mode 100644 index 6deac8c..0000000 --- a/tools/buildbot/pylibs/zope/interface/interfaces.py +++ /dev/null @@ -1,730 +0,0 @@ -############################################################################## -# -# Copyright (c) 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Interface Package Interfaces - -$Id: interfaces.py 67803 2006-05-01 15:20:47Z jim $ -""" -__docformat__ = 'restructuredtext' - - -from zope.interface import Interface -from zope.interface.interface import Attribute - -class IElement(Interface): - """Objects that have basic documentation and tagged values. - """ - - __name__ = Attribute('__name__', 'The object name') - __doc__ = Attribute('__doc__', 'The object doc string') - - def getTaggedValue(tag): - """Returns the value associated with `tag`. - - Raise a `KeyError` of the tag isn't set. - """ - - def queryTaggedValue(tag, default=None): - """Returns the value associated with `tag`. - - Return the default value of the tag isn't set. - """ - - def getTaggedValueTags(): - """Returns a list of all tags.""" - - def setTaggedValue(tag, value): - """Associates `value` with `key`.""" - - -class IAttribute(IElement): - """Attribute descriptors""" - - interface = Attribute('interface', - 'Stores the interface instance in which the ' - 'attribute is located.') - - -class IMethod(IAttribute): - """Method attributes""" - - def getSignatureInfo(): - """Returns the signature information. - - This method returns a dictionary with the following keys: - - o `positional` - All positional arguments. - - o `required` - A list of all required arguments. - - o `optional` - A list of all optional arguments. - - o `varargs` - The name of the varargs argument. - - o `kwargs` - The name of the kwargs argument. - """ - - def getSignatureString(): - """Return a signature string suitable for inclusion in documentation. - - This method returns the function signature string. For example, if you - have `func(a, b, c=1, d='f')`, then the signature string is `(a, b, - c=1, d='f')`. - """ - -class ISpecification(Interface): - """Object Behavioral specifications""" - - def extends(other, strict=True): - """Test whether a specification extends another - - The specification extends other if it has other as a base - interface or if one of it's bases extends other. - - If strict is false, then the specification extends itself. - """ - - def isOrExtends(other): - """Test whether the specification is or extends another - """ - - def weakref(callback=None): - """Return a weakref to the specification - - This method is, regrettably, needed to allow weakrefs to be - computed to security-proxied specifications. While the - zope.interface package does not require zope.security or - zope.proxy, it has to be able to coexist with it. - - """ - - __bases__ = Attribute("""Base specifications - - A tuple if specifications from which this specification is - directly derived. - - """) - - __sro__ = Attribute("""Specification-resolution order - - A tuple of the specification and all of it's ancestor - specifications from most specific to least specific. - - (This is similar to the method-resolution order for new-style classes.) - """) - - def get(name, default=None): - """Look up the description for a name - - If the named attribute is not defined, the default is - returned. - """ - - -class IInterface(ISpecification, IElement): - """Interface objects - - Interface objects describe the behavior of an object by containing - useful information about the object. This information includes: - - o Prose documentation about the object. In Python terms, this - is called the "doc string" of the interface. In this element, - you describe how the object works in prose language and any - other useful information about the object. - - o Descriptions of attributes. Attribute descriptions include - the name of the attribute and prose documentation describing - the attributes usage. - - o Descriptions of methods. Method descriptions can include: - - - Prose "doc string" documentation about the method and its - usage. - - - A description of the methods arguments; how many arguments - are expected, optional arguments and their default values, - the position or arguments in the signature, whether the - method accepts arbitrary arguments and whether the method - accepts arbitrary keyword arguments. - - o Optional tagged data. Interface objects (and their attributes and - methods) can have optional, application specific tagged data - associated with them. Examples uses for this are examples, - security assertions, pre/post conditions, and other possible - information you may want to associate with an Interface or its - attributes. - - Not all of this information is mandatory. For example, you may - only want the methods of your interface to have prose - documentation and not describe the arguments of the method in - exact detail. Interface objects are flexible and let you give or - take any of these components. - - Interfaces are created with the Python class statement using - either Interface.Interface or another interface, as in:: - - from zope.interface import Interface - - class IMyInterface(Interface): - '''Interface documentation''' - - def meth(arg1, arg2): - '''Documentation for meth''' - - # Note that there is no self argument - - class IMySubInterface(IMyInterface): - '''Interface documentation''' - - def meth2(): - '''Documentation for meth2''' - - You use interfaces in two ways: - - o You assert that your object implement the interfaces. - - There are several ways that you can assert that an object - implements an interface: - - 1. Call zope.interface.implements in your class definition. - - 2. Call zope.interfaces.directlyProvides on your object. - - 3. Call 'zope.interface.classImplements' to assert that instances - of a class implement an interface. - - For example:: - - from zope.interface import classImplements - - classImplements(some_class, some_interface) - - This approach is useful when it is not an option to modify - the class source. Note that this doesn't affect what the - class itself implements, but only what its instances - implement. - - o You query interface meta-data. See the IInterface methods and - attributes for details. - - """ - - def providedBy(object): - """Test whether the interface is implemented by the object - - Return true of the object asserts that it implements the - interface, including asserting that it implements an extended - interface. - """ - - def implementedBy(class_): - """Test whether the interface is implemented by instances of the class - - Return true of the class asserts that its instances implement the - interface, including asserting that they implement an extended - interface. - """ - - def names(all=False): - """Get the interface attribute names - - Return a sequence of the names of the attributes, including - methods, included in the interface definition. - - Normally, only directly defined attributes are included. If - a true positional or keyword argument is given, then - attributes defined by base classes will be included. - """ - - def namesAndDescriptions(all=False): - """Get the interface attribute names and descriptions - - Return a sequence of the names and descriptions of the - attributes, including methods, as name-value pairs, included - in the interface definition. - - Normally, only directly defined attributes are included. If - a true positional or keyword argument is given, then - attributes defined by base classes will be included. - """ - - def __getitem__(name): - """Get the description for a name - - If the named attribute is not defined, a KeyError is raised. - """ - - def direct(name): - """Get the description for the name if it was defined by the interface - - If the interface doesn't define the name, returns None. - """ - - def validateInvariants(obj, errors=None): - """Validate invariants - - Validate object to defined invariants. If errors is None, - raises first Invalid error; if errors is a list, appends all errors - to list, then raises Invalid with the errors as the first element - of the "args" tuple.""" - - def __contains__(name): - """Test whether the name is defined by the interface""" - - def __iter__(): - """Return an iterator over the names defined by the interface - - The names iterated include all of the names defined by the - interface directly and indirectly by base interfaces. - """ - - __module__ = Attribute("""The name of the module defining the interface""") - -class IDeclaration(ISpecification): - """Interface declaration - - Declarations are used to express the interfaces implemented by - classes or provided by objects. - """ - - def __contains__(interface): - """Test whether an interface is in the specification - - Return true if the given interface is one of the interfaces in - the specification and false otherwise. - """ - - def __iter__(): - """Return an iterator for the interfaces in the specification - """ - - def flattened(): - """Return an iterator of all included and extended interfaces - - An iterator is returned for all interfaces either included in - or extended by interfaces included in the specifications - without duplicates. The interfaces are in "interface - resolution order". The interface resolution order is such that - base interfaces are listed after interfaces that extend them - and, otherwise, interfaces are included in the order that they - were defined in the specification. - """ - - def __sub__(interfaces): - """Create an interface specification with some interfaces excluded - - The argument can be an interface or an interface - specifications. The interface or interfaces given in a - specification are subtracted from the interface specification. - - Removing an interface that is not in the specification does - not raise an error. Doing so has no effect. - - Removing an interface also removes sub-interfaces of the interface. - - """ - - def __add__(interfaces): - """Create an interface specification with some interfaces added - - The argument can be an interface or an interface - specifications. The interface or interfaces given in a - specification are added to the interface specification. - - Adding an interface that is already in the specification does - not raise an error. Doing so has no effect. - """ - - def __nonzero__(): - """Return a true value of the interface specification is non-empty - """ - -class IInterfaceDeclaration(Interface): - """Declare and check the interfaces of objects - - The functions defined in this interface are used to declare the - interfaces that objects provide and to query the interfaces that have - been declared. - - Interfaces can be declared for objects in two ways: - - - Interfaces are declared for instances of the object's class - - - Interfaces are declared for the object directly. - - The interfaces declared for an object are, therefore, the union of - interfaces declared for the object directly and the interfaces - declared for instances of the object's class. - - Note that we say that a class implements the interfaces provided - by it's instances. An instance can also provide interfaces - directly. The interfaces provided by an object are the union of - the interfaces provided directly and the interfaces implemented by - the class. - """ - - def providedBy(ob): - """Return the interfaces provided by an object - - This is the union of the interfaces directly provided by an - object and interfaces implemented by it's class. - - The value returned is an IDeclaration. - """ - - def implementedBy(class_): - """Return the interfaces implemented for a class' instances - - The value returned is an IDeclaration. - """ - - def classImplements(class_, *interfaces): - """Declare additional interfaces implemented for instances of a class - - The arguments after the class are one or more interfaces or - interface specifications (IDeclaration objects). - - The interfaces given (including the interfaces in the - specifications) are added to any interfaces previously - declared. - - Consider the following example:: - - class C(A, B): - ... - - classImplements(C, I1, I2) - - - Instances of ``C`` provide ``I1``, ``I2``, and whatever interfaces - instances of ``A`` and ``B`` provide. - """ - - def implementer(*interfaces): - """Create a decorator for declaring interfaces implemented by a facory - - A callable is returned that makes an implements declaration on - objects passed to it. - """ - - def classImplementsOnly(class_, *interfaces): - """Declare the only interfaces implemented by instances of a class - - The arguments after the class are one or more interfaces or - interface specifications (IDeclaration objects). - - The interfaces given (including the interfaces in the - specifications) replace any previous declarations. - - Consider the following example:: - - class C(A, B): - ... - - classImplements(C, IA, IB. IC) - classImplementsOnly(C. I1, I2) - - Instances of ``C`` provide only ``I1``, ``I2``, and regardless of - whatever interfaces instances of ``A`` and ``B`` implement. - """ - - def directlyProvidedBy(object): - """Return the interfaces directly provided by the given object - - The value returned is an IDeclaration. - """ - - def directlyProvides(object, *interfaces): - """Declare interfaces declared directly for an object - - The arguments after the object are one or more interfaces or - interface specifications (IDeclaration objects). - - The interfaces given (including the interfaces in the - specifications) replace interfaces previously - declared for the object. - - Consider the following example:: - - class C(A, B): - ... - - ob = C() - directlyProvides(ob, I1, I2) - - The object, ``ob`` provides ``I1``, ``I2``, and whatever interfaces - instances have been declared for instances of ``C``. - - To remove directly provided interfaces, use ``directlyProvidedBy`` and - subtract the unwanted interfaces. For example:: - - directlyProvides(ob, directlyProvidedBy(ob)-I2) - - removes I2 from the interfaces directly provided by - ``ob``. The object, ``ob`` no longer directly provides ``I2``, - although it might still provide ``I2`` if it's class - implements ``I2``. - - To add directly provided interfaces, use ``directlyProvidedBy`` and - include additional interfaces. For example:: - - directlyProvides(ob, directlyProvidedBy(ob), I2) - - adds I2 to the interfaces directly provided by ob. - """ - - def alsoProvides(object, *interfaces): - """Declare additional interfaces directly for an object:: - - alsoProvides(ob, I1) - - is equivalent to:: - - directivelyProvides(ob, directlyProvidedBy(ob), I1) - """ - - def noLongerProvides(object, interface): - """Remove an interface from the list of an object's directly - provided interfaces:: - - noLongerProvides(ob, I1) - - is equivalent to:: - - directlyProvides(ob, directlyProvidedBy(ob)-I1) - - with the exception that if ``I1`` is an interface that is - provided by ``ob`` through the class's implementation, - ValueError is raised. - """ - - def implements(*interfaces): - """Declare interfaces implemented by instances of a class - - This function is called in a class definition. - - The arguments are one or more interfaces or interface - specifications (IDeclaration objects). - - The interfaces given (including the interfaces in the - specifications) are added to any interfaces previously - declared. - - Previous declarations include declarations for base classes - unless implementsOnly was used. - - This function is provided for convenience. It provides a more - convenient way to call classImplements. For example:: - - implements(I1) - - is equivalent to calling:: - - classImplements(C, I1) - - after the class has been created. - - Consider the following example:: - - class C(A, B): - implements(I1, I2) - - - Instances of ``C`` implement ``I1``, ``I2``, and whatever interfaces - instances of ``A`` and ``B`` implement. - """ - - def implementsOnly(*interfaces): - """Declare the only interfaces implemented by instances of a class - - This function is called in a class definition. - - The arguments are one or more interfaces or interface - specifications (IDeclaration objects). - - Previous declarations including declarations for base classes - are overridden. - - This function is provided for convenience. It provides a more - convenient way to call classImplementsOnly. For example:: - - implementsOnly(I1) - - is equivalent to calling:: - - classImplementsOnly(I1) - - after the class has been created. - - Consider the following example:: - - class C(A, B): - implementsOnly(I1, I2) - - - Instances of ``C`` implement ``I1``, ``I2``, regardless of what - instances of ``A`` and ``B`` implement. - """ - - def classProvides(*interfaces): - """Declare interfaces provided directly by a class - - This function is called in a class definition. - - The arguments are one or more interfaces or interface - specifications (IDeclaration objects). - - The given interfaces (including the interfaces in the - specifications) are used to create the class's direct-object - interface specification. An error will be raised if the module - class has an direct interface specification. In other words, it is - an error to call this function more than once in a class - definition. - - Note that the given interfaces have nothing to do with the - interfaces implemented by instances of the class. - - This function is provided for convenience. It provides a more - convenient way to call directlyProvides for a class. For example:: - - classProvides(I1) - - is equivalent to calling:: - - directlyProvides(theclass, I1) - - after the class has been created. - """ - - def moduleProvides(*interfaces): - """Declare interfaces provided by a module - - This function is used in a module definition. - - The arguments are one or more interfaces or interface - specifications (IDeclaration objects). - - The given interfaces (including the interfaces in the - specifications) are used to create the module's direct-object - interface specification. An error will be raised if the module - already has an interface specification. In other words, it is - an error to call this function more than once in a module - definition. - - This function is provided for convenience. It provides a more - convenient way to call directlyProvides for a module. For example:: - - moduleImplements(I1) - - is equivalent to:: - - directlyProvides(sys.modules[__name__], I1) - """ - - def Declaration(*interfaces): - """Create an interface specification - - The arguments are one or more interfaces or interface - specifications (IDeclaration objects). - - A new interface specification (IDeclaration) with - the given interfaces is returned. - """ - -class IAdapterRegistry(Interface): - """Provide an interface-based registry for adapters - - This registry registers objects that are in some sense "from" a - sequence of specification to an interface and a name. - - No specific semantics are assumed for the registered objects, - however, the most common application will be to register factories - that adapt objects providing required specifications to a provided - interface. - """ - - def register(required, provided, name, value): - """Register a value - - A value is registered for a *sequence* of required specifications, a - provided interface, and a name. - """ - - def registered(required, provided, name=u''): - """Return the component registered for the given interfaces and name - - Unlike the lookup method, this methods won't retrieve - components registered for more specific required interfaces or - less specific provided interfaces. - - If no component was registered exactly for the given - interfaces and name, then None is returned. - - """ - - def lookup(required, provided, name='', default=None): - """Lookup a value - - A value is looked up based on a *sequence* of required - specifications, a provided interface, and a name. - """ - - def queryMultiAdapter(objects, provided, name=u'', default=None): - """Adapt a sequence of objects to a named, provided, interface - """ - - def lookup1(required, provided, name=u'', default=None): - """Lookup a value using a single required interface - - A value is looked up based on a single required - specifications, a provided interface, and a name. - """ - - def queryAdapter(object, provided, name=u'', default=None): - """Adapt an object using a registered adapter factory. - """ - - def adapter_hook(provided, object, name=u'', default=None): - """Adapt an object using a registered adapter factory. - """ - - def lookupAll(required, provided): - """Find all adapters from the required to the provided interfaces - - An iterable object is returned that provides name-value two-tuples. - """ - - def names(required, provided): - """Return the names for which there are registered objects - """ - - def subscribe(required, provided, subscriber, name=u''): - """Register a subscriber - - A subscriber is registered for a *sequence* of required - specifications, a provided interface, and a name. - - Multiple subscribers may be registered for the same (or - equivalent) interfaces. - """ - - def subscriptions(required, provided, name=u''): - """Get a sequence of subscribers - - Subscribers for a *sequence* of required interfaces, and a provided - interface are returned. - """ - - def subscribers(objects, provided, name=u''): - """Get a sequence of subscription adapters - """ diff --git a/tools/buildbot/pylibs/zope/interface/ro.py b/tools/buildbot/pylibs/zope/interface/ro.py deleted file mode 100644 index e8e6115..0000000 --- a/tools/buildbot/pylibs/zope/interface/ro.py +++ /dev/null @@ -1,63 +0,0 @@ -############################################################################## -# -# Copyright (c) 2003 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Compute a resolution order for an object and it's bases - -$Id: ro.py 25177 2004-06-02 13:17:31Z jim $ -""" - -def ro(object): - """Compute a "resolution order" for an object - """ - return mergeOrderings([_flatten(object, [])]) - -def mergeOrderings(orderings, seen=None): - """Merge multiple orderings so that within-ordering order is preserved - - Orderings are constrained in such a way that if an object appears - in two or more orderings, then the suffix that begins with the - object must be in both orderings. - - For example: - - >>> _mergeOrderings([ - ... ['x', 'y', 'z'], - ... ['q', 'z'], - ... [1, 3, 5], - ... ['z'] - ... ]) - ['x', 'y', 'q', 1, 3, 5, 'z'] - - """ - - if seen is None: - seen = {} - result = [] - orderings.reverse() - for ordering in orderings: - ordering = list(ordering) - ordering.reverse() - for o in ordering: - if o not in seen: - seen[o] = 1 - result.append(o) - - result.reverse() - return result - -def _flatten(ob, result): - result.append(ob) - for base in ob.__bases__: - _flatten(base, result) - - return result diff --git a/tools/buildbot/pylibs/zope/interface/tests/__init__.py b/tools/buildbot/pylibs/zope/interface/tests/__init__.py deleted file mode 100644 index b711d36..0000000 --- a/tools/buildbot/pylibs/zope/interface/tests/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# -# This file is necessary to make this directory a package. diff --git a/tools/buildbot/pylibs/zope/interface/tests/dummy.py b/tools/buildbot/pylibs/zope/interface/tests/dummy.py deleted file mode 100644 index f4a4f9d..0000000 --- a/tools/buildbot/pylibs/zope/interface/tests/dummy.py +++ /dev/null @@ -1,25 +0,0 @@ -############################################################################## -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Dummy Module - -$Id$ -""" -from zope.interface import moduleProvides -from zope.interface.tests.ifoo import IFoo -from zope.interface import moduleProvides - -moduleProvides(IFoo) - -def bar(baz): - pass diff --git a/tools/buildbot/pylibs/zope/interface/tests/foodforthought.txt b/tools/buildbot/pylibs/zope/interface/tests/foodforthought.txt deleted file mode 100644 index 45d961b..0000000 --- a/tools/buildbot/pylibs/zope/interface/tests/foodforthought.txt +++ /dev/null @@ -1,61 +0,0 @@ -================================ -Food-based subscription examples -================================ - - -This file gives more subscription examples using a cooking-based example:: - - >>> from zope.interface.adapter import AdapterRegistry - >>> registry = AdapterRegistry() - - >>> import zope.interface - >>> class IAnimal(zope.interface.Interface): - ... pass - >>> class IPoultry(IAnimal): - ... pass - >>> class IChicken(IPoultry): - ... pass - >>> class ISeafood(IAnimal): - ... pass - -Adapting to some other interface for which there is no -subscription adapter returns an empty sequence:: - - >>> class IRecipe(zope.interface.Interface): - ... pass - >>> class ISausages(IRecipe): - ... pass - >>> class INoodles(IRecipe): - ... pass - >>> class IKFC(IRecipe): - ... pass - - >>> list(registry.subscriptions([IPoultry], IRecipe)) - [] - -unless we define a subscription:: - - >>> registry.subscribe([IAnimal], ISausages, 'sausages') - >>> list(registry.subscriptions([IPoultry], ISausages)) - ['sausages'] - -And define another subscription adapter:: - - >>> registry.subscribe([IPoultry], INoodles, 'noodles') - >>> meals = list(registry.subscriptions([IPoultry], IRecipe)) - >>> meals.sort() - >>> meals - ['noodles', 'sausages'] - - >>> registry.subscribe([IChicken], IKFC, 'kfc') - >>> meals = list(registry.subscriptions([IChicken], IRecipe)) - >>> meals.sort() - >>> meals - ['kfc', 'noodles', 'sausages'] - -And the answer for poultry hasn't changed:: - - >>> meals = list(registry.subscriptions([IPoultry], IRecipe)) - >>> meals.sort() - >>> meals - ['noodles', 'sausages'] diff --git a/tools/buildbot/pylibs/zope/interface/tests/ifoo.py b/tools/buildbot/pylibs/zope/interface/tests/ifoo.py deleted file mode 100644 index 6ae2231..0000000 --- a/tools/buildbot/pylibs/zope/interface/tests/ifoo.py +++ /dev/null @@ -1,28 +0,0 @@ -############################################################################## -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""IFoo test module - -$Id$ -""" -from zope.interface import Interface - -class IFoo(Interface): - """ - Dummy interface for unit tests. - """ - - def bar(baz): - """ - Just a note. - """ diff --git a/tools/buildbot/pylibs/zope/interface/tests/m1.py b/tools/buildbot/pylibs/zope/interface/tests/m1.py deleted file mode 100644 index 86adad2..0000000 --- a/tools/buildbot/pylibs/zope/interface/tests/m1.py +++ /dev/null @@ -1,23 +0,0 @@ -############################################################################## -# -# Copyright (c) 2004 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Test module that declares an interface - -$Id$ -""" -from zope.interface import Interface, moduleProvides - -class I1(Interface): pass -class I2(Interface): pass - -moduleProvides(I1, I2) diff --git a/tools/buildbot/pylibs/zope/interface/tests/m2.py b/tools/buildbot/pylibs/zope/interface/tests/m2.py deleted file mode 100644 index 16762dd..0000000 --- a/tools/buildbot/pylibs/zope/interface/tests/m2.py +++ /dev/null @@ -1,17 +0,0 @@ -############################################################################## -# -# Copyright (c) 2004 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Test module that doesn't declare an interface - -$Id$ -""" diff --git a/tools/buildbot/pylibs/zope/interface/tests/odd.py b/tools/buildbot/pylibs/zope/interface/tests/odd.py deleted file mode 100644 index 7e31f30..0000000 --- a/tools/buildbot/pylibs/zope/interface/tests/odd.py +++ /dev/null @@ -1,129 +0,0 @@ -############################################################################## -# -# Copyright (c) 2003 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Odd meta class that doesn't subclass type. - -This is used for testing support for ExtensionClass in new interfaces. - - >>> class A(object): - ... __metaclass__ = MetaClass - ... a = 1 - ... - >>> A.__name__ - 'A' - >>> A.__bases__ - () - >>> class B(object): - ... __metaclass__ = MetaClass - ... b = 1 - ... - >>> class C(A, B): pass - ... - >>> C.__name__ - 'C' - >>> int(C.__bases__ == (A, B)) - 1 - >>> a = A() - >>> aa = A() - >>> a.a - 1 - >>> aa.a - 1 - >>> aa.a = 2 - >>> a.a - 1 - >>> aa.a - 2 - >>> c = C() - >>> c.a - 1 - >>> c.b - 1 - >>> c.b = 2 - >>> c.b - 2 - >>> C.c = 1 - >>> c.c - 1 - >>> from types import ClassType - >>> int(isinstance(C, (type, ClassType))) - 0 - >>> int(C.__class__.__class__ is C.__class__) - 1 - -$Id: odd.py 38178 2005-08-30 21:50:19Z mj $ -""" - -# class OddClass is an odd meta class - -class MetaMetaClass(type): - - def __getattribute__(self, name): - if name == '__class__': - return self - return type.__getattribute__(self, name) - - -class MetaClass(object): - """Odd classes - """ - __metaclass__ = MetaMetaClass - - def __init__(self, name, bases, dict): - self.__name__ = name - self.__bases__ = bases - self.__dict__.update(dict) - - def __call__(self): - return OddInstance(self) - - def __getattr__(self, name): - for b in self.__bases__: - v = getattr(b, name, self) - if v is not self: - return v - raise AttributeError(name) - - def __repr__(self): - return "" % (self.__name__, hex(id(self))) - -class OddInstance(object): - - def __init__(self, cls): - self.__dict__['__class__'] = cls - - def __getattribute__(self, name): - dict = object.__getattribute__(self, '__dict__') - if name == '__dict__': - return dict - v = dict.get(name, self) - if v is not self: - return v - return getattr(dict['__class__'], name) - - def __setattr__(self, name, v): - self.__dict__[name] = v - - def __delattr__(self, name): - del self.__dict__[name] - - def __repr__(self): - return "" % ( - self.__class__.__name__, hex(id(self))) - - - -# DocTest: -if __name__ == "__main__": - import doctest, __main__ - doctest.testmod(__main__, isprivate=lambda *a: False) diff --git a/tools/buildbot/pylibs/zope/interface/tests/test_adapter.py b/tools/buildbot/pylibs/zope/interface/tests/test_adapter.py deleted file mode 100644 index a8d1d94..0000000 --- a/tools/buildbot/pylibs/zope/interface/tests/test_adapter.py +++ /dev/null @@ -1,335 +0,0 @@ -############################################################################## -# -# Copyright (c) 2003 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Adapter registry tests - -$Id: test_adapter.py 67795 2006-05-01 13:55:42Z jim $ -""" -import unittest -import zope.interface -from zope.interface.adapter import AdapterRegistry -import zope.interface - - -class IF0(zope.interface.Interface): - pass -class IF1(IF0): - pass - -class IB0(zope.interface.Interface): - pass -class IB1(IB0): - pass - -class IR0(zope.interface.Interface): - pass -class IR1(IR0): - pass - -def test_multi_adapter_get_best_match(): - """ - >>> registry = AdapterRegistry() - - >>> class IB2(IB0): - ... pass - >>> class IB3(IB2, IB1): - ... pass - >>> class IB4(IB1, IB2): - ... pass - - >>> registry.register([None, IB1], IR0, '', 'A1') - >>> registry.register([None, IB0], IR0, '', 'A0') - >>> registry.register([None, IB2], IR0, '', 'A2') - - >>> registry.lookup((IF1, IB1), IR0, '') - 'A1' - >>> registry.lookup((IF1, IB2), IR0, '') - 'A2' - >>> registry.lookup((IF1, IB0), IR0, '') - 'A0' - >>> registry.lookup((IF1, IB3), IR0, '') - 'A2' - >>> registry.lookup((IF1, IB4), IR0, '') - 'A1' - """ - -def test_multi_adapter_lookupAll_get_best_matches(): - """ - >>> registry = AdapterRegistry() - - >>> class IB2(IB0): - ... pass - >>> class IB3(IB2, IB1): - ... pass - >>> class IB4(IB1, IB2): - ... pass - - >>> registry.register([None, IB1], IR0, '', 'A1') - >>> registry.register([None, IB0], IR0, '', 'A0') - >>> registry.register([None, IB2], IR0, '', 'A2') - - >>> tuple(registry.lookupAll((IF1, IB1), IR0))[0][1] - 'A1' - >>> tuple(registry.lookupAll((IF1, IB2), IR0))[0][1] - 'A2' - >>> tuple(registry.lookupAll((IF1, IB0), IR0))[0][1] - 'A0' - >>> tuple(registry.lookupAll((IF1, IB3), IR0))[0][1] - 'A2' - >>> tuple(registry.lookupAll((IF1, IB4), IR0))[0][1] - 'A1' - """ - - -def test_multi_adapter_w_default(): - """ - >>> registry = AdapterRegistry() - - >>> registry.register([None, None], IB1, 'bob', 'A0') - - >>> registry.lookup((IF1, IR1), IB0, 'bob') - 'A0' - - >>> registry.register([None, IR0], IB1, 'bob', 'A1') - - >>> registry.lookup((IF1, IR1), IB0, 'bob') - 'A1' - - >>> registry.lookup((IF1, IR1), IB0, 'bruce') - - >>> registry.register([None, IR1], IB1, 'bob', 'A2') - >>> registry.lookup((IF1, IR1), IB0, 'bob') - 'A2' - """ - -def test_multi_adapter_w_inherited_and_multiple_registrations(): - """ - >>> registry = AdapterRegistry() - - >>> class IX(zope.interface.Interface): - ... pass - - >>> registry.register([IF0, IR0], IB1, 'bob', 'A1') - >>> registry.register([IF1, IX], IB1, 'bob', 'AX') - - >>> registry.lookup((IF1, IR1), IB0, 'bob') - 'A1' - """ - -def test_named_adapter_with_default(): - """Query a named simple adapter - - >>> registry = AdapterRegistry() - - If we ask for a named adapter, we won't get a result unless there - is a named adapter, even if the object implements the interface: - - >>> registry.lookup([IF1], IF0, 'bob') - - >>> registry.register([None], IB1, 'bob', 'A1') - >>> registry.lookup([IF1], IB0, 'bob') - 'A1' - - >>> registry.lookup([IF1], IB0, 'bruce') - - >>> registry.register([None], IB0, 'bob', 'A2') - >>> registry.lookup([IF1], IB0, 'bob') - 'A2' - """ - -def test_multi_adapter_gets_closest_provided(): - """ - >>> registry = AdapterRegistry() - >>> registry.register([IF1, IR0], IB0, 'bob', 'A1') - >>> registry.register((IF1, IR0), IB1, 'bob', 'A2') - >>> registry.lookup((IF1, IR1), IB0, 'bob') - 'A1' - - >>> registry = AdapterRegistry() - >>> registry.register([IF1, IR0], IB1, 'bob', 'A2') - >>> registry.register([IF1, IR0], IB0, 'bob', 'A1') - >>> registry.lookup([IF1, IR0], IB0, 'bob') - 'A1' - - >>> registry = AdapterRegistry() - >>> registry.register([IF1, IR0], IB0, 'bob', 'A1') - >>> registry.register([IF1, IR1], IB1, 'bob', 'A2') - >>> registry.lookup([IF1, IR1], IB0, 'bob') - 'A2' - - >>> registry = AdapterRegistry() - >>> registry.register([IF1, IR1], IB1, 'bob', 2) - >>> registry.register([IF1, IR0], IB0, 'bob', 1) - >>> registry.lookup([IF1, IR1], IB0, 'bob') - 2 - """ - -def test_multi_adapter_check_non_default_dont_hide_default(): - """ - >>> registry = AdapterRegistry() - - >>> class IX(zope.interface.Interface): - ... pass - - - >>> registry.register([None, IR0], IB0, 'bob', 1) - >>> registry.register([IF1, IX], IB0, 'bob', 2) - >>> registry.lookup([IF1, IR1], IB0, 'bob') - 1 - """ - -def test_adapter_hook_with_factory_producing_None(): - """ - >>> registry = AdapterRegistry() - >>> default = object() - - >>> class Object1(object): - ... zope.interface.implements(IF0) - >>> class Object2(object): - ... zope.interface.implements(IF0) - - >>> def factory(context): - ... if isinstance(context, Object1): - ... return 'adapter' - ... return None - - >>> registry.register([IF0], IB0, '', factory) - - >>> registry.adapter_hook(IB0, Object1()) - 'adapter' - >>> registry.adapter_hook(IB0, Object2()) is None - True - >>> registry.adapter_hook(IB0, Object2(), default=default) is default - True - """ - -def test_adapter_registry_update_upon_interface_bases_change(): - """ - Let's first create a adapter registry and a simple adaptation hook: - - >>> globalRegistry = AdapterRegistry() - - >>> def _hook(iface, ob, lookup=globalRegistry.lookup1): - ... factory = lookup(zope.interface.providedBy(ob), iface) - ... if factory is None: - ... return None - ... else: - ... return factory(ob) - - >>> zope.interface.interface.adapter_hooks.append(_hook) - - Now we create some interfaces and an implementation: - - >>> class IX(zope.interface.Interface): - ... pass - - >>> class IY(zope.interface.Interface): - ... pass - - >>> class X(object): - ... pass - - >>> class Y(object): - ... zope.interface.implements(IY) - ... def __init__(self, original): - ... self.original=original - - and register an adapter: - - >>> globalRegistry.register((IX,), IY, '', Y) - - at first, we still expect the adapter lookup from `X` to `IY` to fail: - - >>> IY(X()) #doctest: +NORMALIZE_WHITESPACE +ELLIPSIS - Traceback (most recent call last): - ... - TypeError: ('Could not adapt', - , - ) - - But after we declare an interface on the class `X`, it should pass: - - >>> zope.interface.classImplementsOnly(X, IX) - - >>> IY(X()) #doctest: +ELLIPSIS - - - >>> hook = zope.interface.interface.adapter_hooks.pop() - """ - - -def test_changing_declarations(): - """ - - If we change declarations for a class, those adapter lookup should - eflect the changes: - - >>> class I1(zope.interface.Interface): - ... pass - >>> class I2(zope.interface.Interface): - ... pass - - >>> registry = AdapterRegistry() - >>> registry.register([I1], I2, '', 42) - - >>> class C: - ... pass - - >>> registry.lookup([zope.interface.implementedBy(C)], I2, '') - - >>> zope.interface.classImplements(C, I1) - - >>> registry.lookup([zope.interface.implementedBy(C)], I2, '') - 42 - """ - -def test_correct_multi_adapter_lookup(): - """ - >>> registry = AdapterRegistry() - >>> registry.register([IF0, IB1], IR0, '', 'A01') - >>> registry.register([IF1, IB0], IR0, '', 'A10') - >>> registry.lookup((IF1, IB1), IR0, '') - 'A10' - """ - -def test_duplicate_bases(): - """ -There was a bug that caused problems if a spec had multiple bases: - - >>> class I(zope.interface.Interface): - ... pass - >>> class I2(I, I): - ... pass - >>> registry = AdapterRegistry() - >>> registry.register([I2], IR0, 'x', 'X') - >>> registry.lookup((I2, ), IR0, 'x') - 'X' - >>> registry.register([I2], IR0, 'y', 'Y') - >>> registry.lookup((I2, ), IR0, 'x') - 'X' - >>> registry.lookup((I2, ), IR0, 'y') - 'Y' -""" - - -def test_suite(): - from zope.testing import doctest, doctestunit - return unittest.TestSuite(( - doctestunit.DocFileSuite('../adapter.txt', '../human.txt', - '../human.ru.txt', 'foodforthought.txt', - globs={'__name__': '__main__'}), - doctest.DocTestSuite(), - )) - -if __name__ == '__main__': - unittest.main(defaultTest='test_suite') diff --git a/tools/buildbot/pylibs/zope/interface/tests/test_advice.py b/tools/buildbot/pylibs/zope/interface/tests/test_advice.py deleted file mode 100644 index 7f61a06..0000000 --- a/tools/buildbot/pylibs/zope/interface/tests/test_advice.py +++ /dev/null @@ -1,178 +0,0 @@ - -############################################################################## -# -# Copyright (c) 2003 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Tests for advice - -This module was adapted from 'protocols.tests.advice', part of the Python -Enterprise Application Kit (PEAK). Please notify the PEAK authors -(pje@telecommunity.com and tsarna@sarna.org) if bugs are found or -Zope-specific changes are required, so that the PEAK version of this module -can be kept in sync. - -PEAK is a Python application framework that interoperates with (but does -not require) Zope 3 and Twisted. It provides tools for manipulating UML -models, object-relational persistence, aspect-oriented programming, and more. -Visit the PEAK home page at http://peak.telecommunity.com for more information. - -$Id: test_advice.py 40836 2005-12-16 22:40:51Z benji_york $ -""" - -import unittest -from unittest import TestCase, makeSuite, TestSuite -from zope.interface.advice import * -from types import ClassType -import sys - -def ping(log, value): - - def pong(klass): - log.append((value,klass)) - return [klass] - - addClassAdvisor(pong) - -class ClassicClass: - __metaclass__ = ClassType - classLevelFrameInfo = getFrameInfo(sys._getframe()) - -class NewStyleClass: - __metaclass__ = type - classLevelFrameInfo = getFrameInfo(sys._getframe()) - -moduleLevelFrameInfo = getFrameInfo(sys._getframe()) - -class FrameInfoTest(TestCase): - - classLevelFrameInfo = getFrameInfo(sys._getframe()) - - def checkModuleInfo(self): - kind, module, f_locals, f_globals = moduleLevelFrameInfo - self.assertEquals(kind, "module") - for d in module.__dict__, f_locals, f_globals: - self.assert_(d is globals()) - - def checkClassicClassInfo(self): - kind, module, f_locals, f_globals = ClassicClass.classLevelFrameInfo - self.assertEquals(kind, "class") - - self.assert_(f_locals is ClassicClass.__dict__) # ??? - for d in module.__dict__, f_globals: - self.assert_(d is globals()) - - def checkNewStyleClassInfo(self): - kind, module, f_locals, f_globals = NewStyleClass.classLevelFrameInfo - self.assertEquals(kind, "class") - - for d in module.__dict__, f_globals: - self.assert_(d is globals()) - - def checkCallInfo(self): - kind, module, f_locals, f_globals = getFrameInfo(sys._getframe()) - self.assertEquals(kind, "function call") - self.assert_(f_locals is locals()) # ??? - for d in module.__dict__, f_globals: - self.assert_(d is globals()) - - -class AdviceTests(TestCase): - - def checkOrder(self): - log = [] - class Foo(object): - ping(log, 1) - ping(log, 2) - ping(log, 3) - - # Strip the list nesting - for i in 1,2,3: - self.assert_(isinstance(Foo, list)) - Foo, = Foo - - self.assertEquals(log, [(1, Foo), (2, [Foo]), (3, [[Foo]])]) - - def TODOcheckOutside(self): - # Disabled because the check does not work with doctest tests. - try: - ping([], 1) - except SyntaxError: - pass - else: - raise AssertionError( - "Should have detected advice outside class body" - ) - - def checkDoubleType(self): - if sys.hexversion >= 0x02030000: - return # you can't duplicate bases in 2.3 - class aType(type,type): - ping([],1) - aType, = aType - self.assert_(aType.__class__ is type) - - def checkSingleExplicitMeta(self): - - class M(type): - pass - - class C(M): - __metaclass__ = M - ping([],1) - - C, = C - self.assert_(C.__class__ is M) - - - def checkMixedMetas(self): - - class M1(type): pass - class M2(type): pass - - class B1: __metaclass__ = M1 - class B2: __metaclass__ = M2 - - try: - class C(B1,B2): - ping([],1) - except TypeError: - pass - else: - raise AssertionError("Should have gotten incompatibility error") - - class M3(M1,M2): pass - - class C(B1,B2): - __metaclass__ = M3 - ping([],1) - - self.assert_(isinstance(C,list)) - C, = C - self.assert_(isinstance(C,M3)) - - def checkMetaOfClass(self): - - class metameta(type): - pass - - class meta(type): - __metaclass__ = metameta - - self.assertEquals(determineMetaclass((meta, type)), metameta) - -TestClasses = (AdviceTests, FrameInfoTest) - -def test_suite(): - return TestSuite([makeSuite(t,'check') for t in TestClasses]) - -if __name__ == '__main__': - unittest.main(defaultTest='test_suite') diff --git a/tools/buildbot/pylibs/zope/interface/tests/test_declarations.py b/tools/buildbot/pylibs/zope/interface/tests/test_declarations.py deleted file mode 100644 index 29a7270..0000000 --- a/tools/buildbot/pylibs/zope/interface/tests/test_declarations.py +++ /dev/null @@ -1,416 +0,0 @@ -############################################################################## -# -# Copyright (c) 2003 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Test the new API for making and checking interface declarations - -$Id: test_declarations.py 67630 2006-04-27 00:54:03Z jim $ -""" -import unittest -from zope.interface import * -from zope.testing.doctestunit import DocTestSuite -from zope.interface import Interface - -class I1(Interface): pass -class I2(Interface): pass -class I3(Interface): pass -class I4(Interface): pass -class I5(Interface): pass - -class A(object): - implements(I1) -class B(object): - implements(I2) -class C(A, B): - implements(I3) - -class COnly(A, B): - implementsOnly(I3) - -class COnly_old(A, B): - __implemented__ = I3 - -class D(COnly): - implements(I5) - -def test_ObjectSpecification_Simple(): - """ - >>> c = C() - >>> directlyProvides(c, I4) - >>> [i.__name__ for i in providedBy(c)] - ['I4', 'I3', 'I1', 'I2'] - """ - -def test_ObjectSpecification_Simple_w_only(): - """ - >>> c = COnly() - >>> directlyProvides(c, I4) - >>> [i.__name__ for i in providedBy(c)] - ['I4', 'I3'] - """ - -def test_ObjectSpecification_Simple_old_style(): - """ - >>> c = COnly_old() - >>> directlyProvides(c, I4) - >>> [i.__name__ for i in providedBy(c)] - ['I4', 'I3'] - """ - - -class Test(unittest.TestCase): - - # Note that most of the tests are in the doc strings of the - # declarations module. - - def test_backward_compat(self): - - class C1(object): __implemented__ = I1 - class C2(C1): __implemented__ = I2, I5 - class C3(C2): __implemented__ = I3, C2.__implemented__ - - self.assert_(C3.__implemented__.__class__ is tuple) - - self.assertEqual( - [i.getName() for i in providedBy(C3())], - ['I3', 'I2', 'I5'], - ) - - class C4(C3): - implements(I4) - - self.assertEqual( - [i.getName() for i in providedBy(C4())], - ['I4', 'I3', 'I2', 'I5'], - ) - - self.assertEqual( - [i.getName() for i in C4.__implemented__], - ['I4', 'I3', 'I2', 'I5'], - ) - - # Note that C3.__implemented__ should now be a sequence of interfaces - self.assertEqual( - [i.getName() for i in C3.__implemented__], - ['I3', 'I2', 'I5'], - ) - self.failIf(C3.__implemented__.__class__ is tuple) - - def test_module(self): - import zope.interface.tests.m1 - import zope.interface.tests.m2 - directlyProvides(zope.interface.tests.m2, - zope.interface.tests.m1.I1, - zope.interface.tests.m1.I2, - ) - self.assertEqual(list(providedBy(zope.interface.tests.m1)), - list(providedBy(zope.interface.tests.m2)), - ) - - def test_builtins(self): - # Setup - - intspec = implementedBy(int) - olddeclared = intspec.declared - - classImplements(int, I1) - class myint(int): - implements(I2) - - x = 42 - self.assertEqual([i.getName() for i in providedBy(x)], - ['I1']) - - x = myint(42) - directlyProvides(x, I3) - self.assertEqual([i.getName() for i in providedBy(x)], - ['I3', 'I2', 'I1']) - - # cleanup - intspec.declared = olddeclared - classImplements(int) - - x = 42 - self.assertEqual([i.getName() for i in providedBy(x)], - []) - - -def test_signature_w_no_class_interfaces(): - """ - >>> from zope.interface import * - >>> class C(object): - ... pass - >>> c = C() - >>> list(providedBy(c)) - [] - - >>> class I(Interface): - ... pass - >>> directlyProvides(c, I) - >>> list(providedBy(c)) == list(directlyProvidedBy(c)) - 1 - """ - -def test_classImplement_on_deeply_nested_classes(): - """This test is in response to a bug found, which is why it's a bit - contrived - - >>> from zope.interface import * - >>> class B1(object): - ... pass - >>> class B2(B1): - ... pass - >>> class B3(B2): - ... pass - >>> class D(object): - ... implements() - >>> class S(B3, D): - ... implements() - - This failed due to a bug in the code for finding __providedBy__ - descriptors for old-style classes. - - """ - -def test_pickle_provides_specs(): - """ - >>> from pickle import dumps, loads - >>> a = A() - >>> I2.providedBy(a) - 0 - >>> directlyProvides(a, I2) - >>> I2.providedBy(a) - 1 - >>> a2 = loads(dumps(a)) - >>> I2.providedBy(a2) - 1 - - """ - -def test_that_we_dont_inherit_class_provides(): - """ - >>> class X(object): - ... classProvides(I1) - >>> class Y(X): - ... pass - >>> [i.__name__ for i in X.__provides__] - ['I1'] - >>> Y.__provides__ - Traceback (most recent call last): - ... - AttributeError: __provides__ - - """ - -def test_that_we_dont_inherit_provides_optimizations(): - """ - - When we make a declaration for a class, we install a __provides__ - descriptors that provides a default for instances that don't have - instance-specific declarations: - - >>> class A(object): - ... implements(I1) - - >>> class B(object): - ... implements(I2) - - >>> [i.__name__ for i in A().__provides__] - ['I1'] - >>> [i.__name__ for i in B().__provides__] - ['I2'] - - But it's important that we don't use this for subclasses without - declarations. This would cause incorrect results: - - >>> class X(A, B): - ... pass - - >>> X().__provides__ - Traceback (most recent call last): - ... - AttributeError: __provides__ - - However, if we "induce" a declaration, by calling implementedBy - (even indirectly through providedBy): - - >>> [i.__name__ for i in providedBy(X())] - ['I1', 'I2'] - - - then the optimization will work: - - >>> [i.__name__ for i in X().__provides__] - ['I1', 'I2'] - - """ - -def test_classProvides_before_implements(): - """Special descriptor for class __provides__ - - The descriptor caches the implementedBy info, so that - we can get declarations for objects without instance-specific - interfaces a bit quicker. - - For example:: - - >>> from zope.interface import Interface - >>> class IFooFactory(Interface): - ... pass - >>> class IFoo(Interface): - ... pass - >>> class C(object): - ... classProvides(IFooFactory) - ... implements(IFoo) - >>> [i.getName() for i in C.__provides__] - ['IFooFactory'] - - >>> [i.getName() for i in C().__provides__] - ['IFoo'] - """ - -def test_getting_spec_for_proxied_builtin_class(): - """ - - In general, we should be able to get a spec - for a proxied class if someone has declared or - asked for a spec before. - - We don't want to depend on proxies in this (zope.interface) - package, but we do want to work with proxies. Proxies have the - effect that a class's __dict__ cannot be gotten. Further, for - built-in classes, we can't save, and thus, cannot get, any class - attributes. We'll emulate this by treating a plain object as a class: - - >>> cls = object() - - We'll create an implements specification: - - >>> import zope.interface.declarations - >>> impl = zope.interface.declarations.Implements(I1, I2) - - Now, we'll emulate a declaration for a built-in type by putting - it in BuiltinImplementationSpecifications: - - >>> zope.interface.declarations.BuiltinImplementationSpecifications[ - ... cls] = impl - - Now, we should be able to get it back: - - >>> implementedBy(cls) is impl - True - - Of course, we don't want to leave it there. :) - - >>> del zope.interface.declarations.BuiltinImplementationSpecifications[ - ... cls] - - """ - -def test_declaration_get(): - """ - We can get definitions from a declaration: - - >>> import zope.interface - >>> class I1(zope.interface.Interface): - ... a11 = zope.interface.Attribute('a11') - ... a12 = zope.interface.Attribute('a12') - >>> class I2(zope.interface.Interface): - ... a21 = zope.interface.Attribute('a21') - ... a22 = zope.interface.Attribute('a22') - ... a12 = zope.interface.Attribute('a212') - >>> class I11(I1): - ... a11 = zope.interface.Attribute('a111') - - >>> decl = Declaration(I11, I2) - >>> decl.get('a11') is I11.get('a11') - True - >>> decl.get('a12') is I1.get('a12') - True - >>> decl.get('a21') is I2.get('a21') - True - >>> decl.get('a22') is I2.get('a22') - True - >>> decl.get('a') - >>> decl.get('a', 42) - 42 - - We get None even with no interfaces: - - >>> decl = Declaration() - >>> decl.get('a11') - >>> decl.get('a11', 42) - 42 - - We get new data if e change interface bases: - - >>> decl.__bases__ = I11, I2 - >>> decl.get('a11') is I11.get('a11') - True - """ - -def test_classImplements_after_classImplementsOnly_issue_402(): - """http://www.zope.org/Collectors/Zope3-dev/402 - ->>> from zope.interface import * ->>> class I1(Interface): -... pass ->>> class I2(Interface): -... pass ->>> class C: -... implements(I1) ->>> class C2: -... implementsOnly(I2) ->>> class I3(Interface): -... pass - ->>> [i.__name__ for i in providedBy(C2()).__iro__] -['I2', 'Interface'] - ->>> classImplements(C2, I3) ->>> [i.__name__ for i in providedBy(C2()).__iro__] -['I2', 'I3', 'Interface'] - ->>> class I4(Interface): -... pass ->>> classImplements(C2, I4) ->>> [i.__name__ for i in providedBy(C2()).__iro__] -['I2', 'I3', 'I4', 'Interface'] - - -""" - -def test_picklability_of_implements_specifications(): - """ - - Sometimes, we need to pickle implements specs. We should be able - to do so as long as the class is picklable. - - >>> import pickle - >>> pickle.loads(pickle.dumps(implementedBy(C))) is implementedBy(C) - True - - - """ - - -def test_suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(Test)) - suite.addTest(DocTestSuite("zope.interface.declarations")) - suite.addTest(DocTestSuite()) - - return suite - - -if __name__ == '__main__': - unittest.main() diff --git a/tools/buildbot/pylibs/zope/interface/tests/test_document.py b/tools/buildbot/pylibs/zope/interface/tests/test_document.py deleted file mode 100644 index a5bd879..0000000 --- a/tools/buildbot/pylibs/zope/interface/tests/test_document.py +++ /dev/null @@ -1,71 +0,0 @@ -############################################################################## -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Documentation tests. - -$Id: test_document.py 26560 2004-07-15 21:38:42Z srichter $ -""" -from unittest import TestCase, main, makeSuite - -from zope.interface import Interface, Attribute - -class Test(TestCase): - - def testBlech(self): - from zope.interface.document import asStructuredText - - self.assertEqual(asStructuredText(I2), '''\ -I2 - - I2 doc - - This interface extends: - - o _I1 - - Attributes: - - a1 -- no documentation - - a2 -- a2 doc - - Methods: - - f21() -- f21 doc - - f22() -- no documentation - - f23() -- f23 doc - -''') - - -def test_suite(): - return makeSuite(Test) - -class _I1(Interface): - def f11(): pass - def f12(): pass - -class I2(_I1): - "I2 doc" - - a1 = Attribute('a1') - a2 = Attribute('a2', 'a2 doc') - - def f21(): "f21 doc" - def f22(): pass - def f23(): "f23 doc" - -if __name__=='__main__': - main(defaultTest='test_suite') diff --git a/tools/buildbot/pylibs/zope/interface/tests/test_element.py b/tools/buildbot/pylibs/zope/interface/tests/test_element.py deleted file mode 100644 index 33edc3f..0000000 --- a/tools/buildbot/pylibs/zope/interface/tests/test_element.py +++ /dev/null @@ -1,43 +0,0 @@ -############################################################################## -# -# Copyright (c) 2003 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Test Element meta-class. - -$Id: test_element.py 39768 2005-10-31 13:57:35Z tlotze $ -""" - -import unittest -from zope.interface.interface import Element - -class TestElement(unittest.TestCase): - - def test_taggedValues(self): - """Test that we can update tagged values of more than one element - """ - - e1 = Element("foo") - e2 = Element("bar") - e1.setTaggedValue("x", 1) - e2.setTaggedValue("x", 2) - self.assertEqual(e1.getTaggedValue("x"), 1) - self.assertEqual(e2.getTaggedValue("x"), 2) - - -def test_suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(TestElement)) - return suite - - -if __name__ == '__main__': - unittest.main(defaultTest='test_suite') diff --git a/tools/buildbot/pylibs/zope/interface/tests/test_interface.py b/tools/buildbot/pylibs/zope/interface/tests/test_interface.py deleted file mode 100644 index f444c51..0000000 --- a/tools/buildbot/pylibs/zope/interface/tests/test_interface.py +++ /dev/null @@ -1,352 +0,0 @@ -############################################################################## -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Test Interface implementation - -$Id: test_interface.py 67761 2006-04-30 13:56:44Z jim $ -""" -import sys -import unittest -from zope.testing.doctestunit import DocTestSuite -from zope.interface.tests.unitfixtures import * # hehehe -from zope.interface.exceptions import BrokenImplementation, Invalid -from zope.interface import implementedBy, providedBy -from zope.interface import Interface, directlyProvides, Attribute -from zope import interface - -class InterfaceTests(unittest.TestCase): - - def testInterfaceSetOnAttributes(self): - self.assertEqual(FooInterface['foobar'].interface, - FooInterface) - self.assertEqual(FooInterface['aMethod'].interface, - FooInterface) - - def testClassImplements(self): - self.assert_(IC.implementedBy(C)) - - self.assert_(I1.implementedBy(A)) - self.assert_(I1.implementedBy(B)) - self.assert_(not I1.implementedBy(C)) - self.assert_(I1.implementedBy(D)) - self.assert_(I1.implementedBy(E)) - - self.assert_(not I2.implementedBy(A)) - self.assert_(I2.implementedBy(B)) - self.assert_(not I2.implementedBy(C)) - - # No longer after interfacegeddon - # self.assert_(not I2.implementedBy(D)) - - self.assert_(not I2.implementedBy(E)) - - def testUtil(self): - self.assert_(IC in implementedBy(C)) - self.assert_(I1 in implementedBy(A)) - self.assert_(not I1 in implementedBy(C)) - self.assert_(I2 in implementedBy(B)) - self.assert_(not I2 in implementedBy(C)) - - self.assert_(IC in providedBy(C())) - self.assert_(I1 in providedBy(A())) - self.assert_(not I1 in providedBy(C())) - self.assert_(I2 in providedBy(B())) - self.assert_(not I2 in providedBy(C())) - - - def testObjectImplements(self): - self.assert_(IC.providedBy(C())) - - self.assert_(I1.providedBy(A())) - self.assert_(I1.providedBy(B())) - self.assert_(not I1.providedBy(C())) - self.assert_(I1.providedBy(D())) - self.assert_(I1.providedBy(E())) - - self.assert_(not I2.providedBy(A())) - self.assert_(I2.providedBy(B())) - self.assert_(not I2.providedBy(C())) - - # Not after interface geddon - # self.assert_(not I2.providedBy(D())) - - self.assert_(not I2.providedBy(E())) - - def testDeferredClass(self): - a = A() - self.assertRaises(BrokenImplementation, a.ma) - - - def testInterfaceExtendsInterface(self): - self.assert_(BazInterface.extends(BobInterface)) - self.assert_(BazInterface.extends(BarInterface)) - self.assert_(BazInterface.extends(FunInterface)) - self.assert_(not BobInterface.extends(FunInterface)) - self.assert_(not BobInterface.extends(BarInterface)) - self.assert_(BarInterface.extends(FunInterface)) - self.assert_(not BarInterface.extends(BazInterface)) - - def testVerifyImplementation(self): - from zope.interface.verify import verifyClass - self.assert_(verifyClass(FooInterface, Foo)) - self.assert_(Interface.providedBy(I1)) - - def test_names(self): - names = list(_I2.names()); names.sort() - self.assertEqual(names, ['f21', 'f22', 'f23']) - names = list(_I2.names(all=True)); names.sort() - self.assertEqual(names, ['a1', 'f11', 'f12', 'f21', 'f22', 'f23']) - - def test_namesAndDescriptions(self): - names = [nd[0] for nd in _I2.namesAndDescriptions()]; names.sort() - self.assertEqual(names, ['f21', 'f22', 'f23']) - names = [nd[0] for nd in _I2.namesAndDescriptions(1)]; names.sort() - self.assertEqual(names, ['a1', 'f11', 'f12', 'f21', 'f22', 'f23']) - - for name, d in _I2.namesAndDescriptions(1): - self.assertEqual(name, d.__name__) - - def test_getDescriptionFor(self): - self.assertEqual(_I2.getDescriptionFor('f11').__name__, 'f11') - self.assertEqual(_I2.getDescriptionFor('f22').__name__, 'f22') - self.assertEqual(_I2.queryDescriptionFor('f33', self), self) - self.assertRaises(KeyError, _I2.getDescriptionFor, 'f33') - - def test___getitem__(self): - self.assertEqual(_I2['f11'].__name__, 'f11') - self.assertEqual(_I2['f22'].__name__, 'f22') - self.assertEqual(_I2.get('f33', self), self) - self.assertRaises(KeyError, _I2.__getitem__, 'f33') - - def test___contains__(self): - self.failUnless('f11' in _I2) - self.failIf('f33' in _I2) - - def test___iter__(self): - names = list(iter(_I2)) - names.sort() - self.assertEqual(names, ['a1', 'f11', 'f12', 'f21', 'f22', 'f23']) - - def testAttr(self): - description = _I2.getDescriptionFor('a1') - self.assertEqual(description.__name__, 'a1') - self.assertEqual(description.__doc__, 'This is an attribute') - - def testFunctionAttributes(self): - # Make sure function attributes become tagged values. - meth = _I1['f12'] - self.assertEqual(meth.getTaggedValue('optional'), 1) - - def testInvariant(self): - # set up - o = InvariantC() - directlyProvides(o, IInvariant) - # a helper - def errorsEqual(self, o, error_len, error_msgs, interface=None): - if interface is None: - interface = IInvariant - self.assertRaises(Invalid, interface.validateInvariants, o) - e = [] - try: - interface.validateInvariants(o, e) - except Invalid, error: - self.assertEquals(error.args[0], e) - else: - self._assert(0) # validateInvariants should always raise - # Invalid - self.assertEquals(len(e), error_len) - msgs = [error.args[0] for error in e] - msgs.sort() - for msg in msgs: - self.assertEquals(msg, error_msgs.pop(0)) - # the tests - self.assertEquals(IInvariant.getTaggedValue('invariants'), - [ifFooThenBar]) - self.assertEquals(IInvariant.validateInvariants(o), None) - o.bar = 27 - self.assertEquals(IInvariant.validateInvariants(o), None) - o.foo = 42 - self.assertEquals(IInvariant.validateInvariants(o), None) - del o.bar - errorsEqual(self, o, 1, ['If Foo, then Bar!']) - # nested interfaces with invariants: - self.assertEquals(ISubInvariant.getTaggedValue('invariants'), - [BarGreaterThanFoo]) - o = InvariantC() - directlyProvides(o, ISubInvariant) - o.foo = 42 - # even though the interface has changed, we should still only have one - # error. - errorsEqual(self, o, 1, ['If Foo, then Bar!'], ISubInvariant) - # however, if we set foo to 0 (Boolean False) and bar to a negative - # number then we'll get the new error - o.foo = 2 - o.bar = 1 - errorsEqual(self, o, 1, ['Please, Boo MUST be greater than Foo!'], - ISubInvariant) - # and if we set foo to a positive number and boo to 0, we'll - # get both errors! - o.foo = 1 - o.bar = 0 - errorsEqual(self, o, 2, ['If Foo, then Bar!', - 'Please, Boo MUST be greater than Foo!'], - ISubInvariant) - # for a happy ending, we'll make the invariants happy - o.foo = 1 - o.bar = 2 - self.assertEquals(IInvariant.validateInvariants(o), None) # woohoo - # now we'll do two invariants on the same interface, - # just to make sure that a small - # multi-invariant interface is at least minimally tested. - o = InvariantC() - directlyProvides(o, IInvariant) - o.foo = 42 - old_invariants = IInvariant.getTaggedValue('invariants') - invariants = old_invariants[:] - invariants.append(BarGreaterThanFoo) # if you really need to mutate, - # then this would be the way to do it. Probably a bad idea, though. :-) - IInvariant.setTaggedValue('invariants', invariants) - # - # even though the interface has changed, we should still only have one - # error. - errorsEqual(self, o, 1, ['If Foo, then Bar!']) - # however, if we set foo to 0 (Boolean False) and bar to a negative - # number then we'll get the new error - o.foo = 2 - o.bar = 1 - errorsEqual(self, o, 1, ['Please, Boo MUST be greater than Foo!']) - # and if we set foo to a positive number and boo to 0, we'll - # get both errors! - o.foo = 1 - o.bar = 0 - errorsEqual(self, o, 2, ['If Foo, then Bar!', - 'Please, Boo MUST be greater than Foo!']) - # for another happy ending, we'll make the invariants happy again - o.foo = 1 - o.bar = 2 - self.assertEquals(IInvariant.validateInvariants(o), None) # bliss - # clean up - IInvariant.setTaggedValue('invariants', old_invariants) - - def test___doc___element(self): - class I(Interface): - "xxx" - - self.assertEqual(I.__doc__, "xxx") - self.assertEqual(list(I), []) - - class I(Interface): - "xxx" - - __doc__ = Attribute('the doc') - - self.assertEqual(I.__doc__, "") - self.assertEqual(list(I), ['__doc__']) - - def testIssue228(self): - # Test for http://collector.zope.org/Zope3-dev/228 - class I(Interface): - "xxx" - class Bad: - __providedBy__ = None - # Old style classes don't have a '__class__' attribute - self.failUnlessRaises(AttributeError, I.providedBy, Bad) - - -class _I1(Interface): - - a1 = Attribute("This is an attribute") - - def f11(): pass - def f12(): pass - f12.optional = 1 - -class _I1_(_I1): pass -class _I1__(_I1_): pass - -class _I2(_I1__): - def f21(): pass - def f22(): pass - f23 = f22 - - - -if sys.version_info >= (2, 4): - def test_invariant_as_decorator(): - """Invaiants can be deined in line - - >>> class IRange(interface.Interface): - ... min = interface.Attribute("Lower bound") - ... max = interface.Attribute("Upper bound") - ... - ... @interface.invariant - ... def range_invariant(ob): - ... if ob.max < ob.min: - ... raise Invalid('max < min') - - - >>> class Range(object): - ... interface.implements(IRange) - ... - ... def __init__(self, min, max): - ... self.min, self.max = min, max - - >>> IRange.validateInvariants(Range(1,2)) - >>> IRange.validateInvariants(Range(1,1)) - >>> IRange.validateInvariants(Range(2,1)) - Traceback (most recent call last): - ... - Invalid: max < min - - - """ - -def duplicate_bases_management(): - """ -There was a bug that surfaced when an interface was repeated in -a set of bases and the bases were changed: - - >>> class I(interface.Interface): - ... pass - - >>> class I2(I, I): - ... pass - - >>> I2.__bases__ = (I,) - - -""" - -def test_suite(): - from zope.testing import doctest - suite = unittest.makeSuite(InterfaceTests) - suite.addTest(doctest.DocTestSuite("zope.interface.interface")) - if sys.version_info >= (2, 4): - suite.addTest(doctest.DocTestSuite()) - suite.addTest(doctest.DocFileSuite( - '../README.txt', - globs={'__name__': '__main__'}, - optionflags=doctest.NORMALIZE_WHITESPACE, - )) - suite.addTest(doctest.DocFileSuite( - '../README.ru.txt', - globs={'__name__': '__main__'}, - optionflags=doctest.NORMALIZE_WHITESPACE, - )) - return suite - -def main(): - unittest.TextTestRunner().run(test_suite()) - -if __name__=="__main__": - main() diff --git a/tools/buildbot/pylibs/zope/interface/tests/test_odd_declarations.py b/tools/buildbot/pylibs/zope/interface/tests/test_odd_declarations.py deleted file mode 100644 index 4b6f399..0000000 --- a/tools/buildbot/pylibs/zope/interface/tests/test_odd_declarations.py +++ /dev/null @@ -1,204 +0,0 @@ -############################################################################## -# -# Copyright (c) 2003 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Test interface declarations against ExtensionClass-like classes. - -These tests are to make sure we do something sane in the presense of -classic ExtensionClass classes and instances. - -$Id: test_odd_declarations.py 40836 2005-12-16 22:40:51Z benji_york $ -""" -import unittest, odd -from zope.interface import Interface, implements, implementsOnly -from zope.interface import directlyProvides, providedBy, directlyProvidedBy -from zope.interface import classImplements, classImplementsOnly, implementedBy - -class I1(Interface): pass -class I2(Interface): pass -class I3(Interface): pass -class I31(I3): pass -class I4(Interface): pass -class I5(Interface): pass - -class Odd(object): __metaclass__ = odd.MetaClass - -class B(Odd): __implemented__ = I2 - - -# TODO: We are going to need more magic to make classProvides work with odd -# classes. This will work in the next iteration. For now, we'll use -# a different mechanism. - -# from zope.interface import classProvides - -class A(Odd): - implements(I1) - -class C(A, B): - implements(I31) - - -class Test(unittest.TestCase): - - def test_ObjectSpecification(self): - c = C() - directlyProvides(c, I4) - self.assertEqual([i.getName() for i in providedBy(c)], - ['I4', 'I31', 'I1', 'I2'] - ) - self.assertEqual([i.getName() for i in providedBy(c).flattened()], - ['I4', 'I31', 'I3', 'I1', 'I2', 'Interface'] - ) - self.assert_(I1 in providedBy(c)) - self.failIf(I3 in providedBy(c)) - self.assert_(providedBy(c).extends(I3)) - self.assert_(providedBy(c).extends(I31)) - self.failIf(providedBy(c).extends(I5)) - - class COnly(A, B): - implementsOnly(I31) - - class D(COnly): - implements(I5) - - classImplements(D, I5) - - c = D() - directlyProvides(c, I4) - self.assertEqual([i.getName() for i in providedBy(c)], - ['I4', 'I5', 'I31']) - self.assertEqual([i.getName() for i in providedBy(c).flattened()], - ['I4', 'I5', 'I31', 'I3', 'Interface']) - self.failIf(I1 in providedBy(c)) - self.failIf(I3 in providedBy(c)) - self.assert_(providedBy(c).extends(I3)) - self.failIf(providedBy(c).extends(I1)) - self.assert_(providedBy(c).extends(I31)) - self.assert_(providedBy(c).extends(I5)) - - class COnly(A, B): __implemented__ = I31 - class D(COnly): - implements(I5) - - classImplements(D, I5) - c = D() - directlyProvides(c, I4) - self.assertEqual([i.getName() for i in providedBy(c)], - ['I4', 'I5', 'I31']) - self.assertEqual([i.getName() for i in providedBy(c).flattened()], - ['I4', 'I5', 'I31', 'I3', 'Interface']) - self.failIf(I1 in providedBy(c)) - self.failIf(I3 in providedBy(c)) - self.assert_(providedBy(c).extends(I3)) - self.failIf(providedBy(c).extends(I1)) - self.assert_(providedBy(c).extends(I31)) - self.assert_(providedBy(c).extends(I5)) - - def test_classImplements(self): - class A(Odd): - implements(I3) - - class B(Odd): - implements(I4) - - class C(A, B): - pass - classImplements(C, I1, I2) - self.assertEqual([i.getName() for i in implementedBy(C)], - ['I1', 'I2', 'I3', 'I4']) - classImplements(C, I5) - self.assertEqual([i.getName() for i in implementedBy(C)], - ['I1', 'I2', 'I5', 'I3', 'I4']) - - def test_classImplementsOnly(self): - class A(Odd): - implements(I3) - - class B(Odd): - implements(I4) - - class C(A, B): - pass - classImplementsOnly(C, I1, I2) - self.assertEqual([i.__name__ for i in implementedBy(C)], - ['I1', 'I2']) - - - def test_directlyProvides(self): - class IA1(Interface): pass - class IA2(Interface): pass - class IB(Interface): pass - class IC(Interface): pass - class A(Odd): - implements(IA1, IA2) - - class B(Odd): - implements(IB) - - class C(A, B): - implements(IC) - - - ob = C() - directlyProvides(ob, I1, I2) - self.assert_(I1 in providedBy(ob)) - self.assert_(I2 in providedBy(ob)) - self.assert_(IA1 in providedBy(ob)) - self.assert_(IA2 in providedBy(ob)) - self.assert_(IB in providedBy(ob)) - self.assert_(IC in providedBy(ob)) - - directlyProvides(ob, directlyProvidedBy(ob)-I2) - self.assert_(I1 in providedBy(ob)) - self.failIf(I2 in providedBy(ob)) - self.failIf(I2 in providedBy(ob)) - directlyProvides(ob, directlyProvidedBy(ob), I2) - self.assert_(I2 in providedBy(ob)) - - def test_directlyProvides_fails_for_odd_class(self): - self.assertRaises(TypeError, directlyProvides, C, I5) - - # see above - def TODO_test_classProvides_fails_for_odd_class(self): - try: - class A(Odd): - classProvides(I1) - except TypeError: - pass # Sucess - self.assert_(False, - "Shouldn't be able to use directlyProvides on odd class." - ) - - def test_implementedBy(self): - class I2(I1): pass - - class C1(Odd): - implements(I2) - - class C2(C1): - implements(I3) - - self.assertEqual([i.getName() for i in implementedBy(C2)], - ['I3', 'I2']) - - - - -def test_suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(Test)) - return suite - - -if __name__ == '__main__': - unittest.main() diff --git a/tools/buildbot/pylibs/zope/interface/tests/test_sorting.py b/tools/buildbot/pylibs/zope/interface/tests/test_sorting.py deleted file mode 100644 index 004485e..0000000 --- a/tools/buildbot/pylibs/zope/interface/tests/test_sorting.py +++ /dev/null @@ -1,49 +0,0 @@ -############################################################################## -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Test interface sorting - -$Id: test_sorting.py 25177 2004-06-02 13:17:31Z jim $ -""" - -from unittest import TestCase, TestSuite, main, makeSuite - -from zope.interface import Interface - -class I1(Interface): pass -class I2(I1): pass -class I3(I1): pass -class I4(Interface): pass -class I5(I4): pass -class I6(I2): pass - - -class Test(TestCase): - - def test(self): - l = [I1, I3, I5, I6, I4, I2] - l.sort() - self.assertEqual(l, [I1, I2, I3, I4, I5, I6]) - - def test_w_None(self): - l = [I1, None, I3, I5, None, I6, I4, I2] - l.sort() - self.assertEqual(l, [I1, I2, I3, I4, I5, I6, None, None]) - -def test_suite(): - return TestSuite(( - makeSuite(Test), - )) - -if __name__=='__main__': - main(defaultTest='test_suite') diff --git a/tools/buildbot/pylibs/zope/interface/tests/test_verify.py b/tools/buildbot/pylibs/zope/interface/tests/test_verify.py deleted file mode 100644 index d4fac9a..0000000 --- a/tools/buildbot/pylibs/zope/interface/tests/test_verify.py +++ /dev/null @@ -1,196 +0,0 @@ -############################################################################## -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Interface Verify tests - -$Id: test_verify.py 26866 2004-08-02 20:57:00Z jim $ -""" -from zope.interface import Interface, implements, classImplements, Attribute -from zope.interface.verify import verifyClass, verifyObject -from zope.interface.exceptions import DoesNotImplement, BrokenImplementation -from zope.interface.exceptions import BrokenMethodImplementation - -import unittest - -class Test(unittest.TestCase): - - def testNotImplemented(self): - - class C(object): pass - - class I(Interface): pass - - self.assertRaises(DoesNotImplement, verifyClass, I, C) - - classImplements(C, I) - - verifyClass(I, C) - - def testMissingAttr(self): - - class I(Interface): - def f(): pass - - class C(object): - implements(I) - - self.assertRaises(BrokenImplementation, verifyClass, I, C) - - C.f=lambda self: None - - verifyClass(I, C) - - def testMissingAttr_with_Extended_Interface(self): - - class II(Interface): - def f(): - pass - - class I(II): - pass - - class C(object): - implements(I) - - self.assertRaises(BrokenImplementation, verifyClass, I, C) - - C.f=lambda self: None - - verifyClass(I, C) - - def testWrongArgs(self): - - class I(Interface): - def f(a): pass - - class C(object): - def f(self, b): pass - - implements(I) - - # We no longer require names to match. - #self.assertRaises(BrokenMethodImplementation, verifyClass, I, C) - - C.f=lambda self, a: None - - verifyClass(I, C) - - C.f=lambda self, **kw: None - - self.assertRaises(BrokenMethodImplementation, verifyClass, I, C) - - C.f=lambda self, a, *args: None - - verifyClass(I, C) - - C.f=lambda self, a, *args, **kw: None - - verifyClass(I, C) - - C.f=lambda self, *args: None - - verifyClass(I, C) - - def testExtraArgs(self): - - class I(Interface): - def f(a): pass - - class C(object): - def f(self, a, b): pass - - implements(I) - - self.assertRaises(BrokenMethodImplementation, verifyClass, I, C) - - C.f=lambda self, a: None - - verifyClass(I, C) - - C.f=lambda self, a, b=None: None - - verifyClass(I, C) - - def testNoVar(self): - - class I(Interface): - def f(a, *args): pass - - class C(object): - def f(self, a): pass - - implements(I) - - self.assertRaises(BrokenMethodImplementation, verifyClass, I, C) - - C.f=lambda self, a, *foo: None - - verifyClass(I, C) - - def testNoKW(self): - - class I(Interface): - def f(a, **args): pass - - class C(object): - def f(self, a): pass - - implements(I) - - self.assertRaises(BrokenMethodImplementation, verifyClass, I, C) - - C.f=lambda self, a, **foo: None - - verifyClass(I, C) - - def testModule(self): - - from zope.interface.tests.ifoo import IFoo - from zope.interface.tests import dummy - - verifyObject(IFoo, dummy) - - def testMethodForAttr(self): - - class IFoo(Interface): - foo = Attribute("The foo Attribute") - - - class Foo: - implements(IFoo) - - def foo(self): - pass - - verifyClass(IFoo, Foo) - - def testNonMethodForMethod(self): - - class IBar(Interface): - def foo(): - pass - - class Bar: - implements(IBar) - - foo = 1 - - self.assertRaises(BrokenMethodImplementation, verifyClass, IBar, Bar) - - -def test_suite(): - loader=unittest.TestLoader() - return loader.loadTestsFromTestCase(Test) - -if __name__=='__main__': - unittest.TextTestRunner().run(test_suite()) diff --git a/tools/buildbot/pylibs/zope/interface/tests/unitfixtures.py b/tools/buildbot/pylibs/zope/interface/tests/unitfixtures.py deleted file mode 100644 index 1007b19..0000000 --- a/tools/buildbot/pylibs/zope/interface/tests/unitfixtures.py +++ /dev/null @@ -1,142 +0,0 @@ -############################################################################## -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Unit Test Fixtures - -$Id: unitfixtures.py 26898 2004-08-04 09:38:12Z hdima $ -""" -from zope.interface import Interface, invariant -from zope.interface.interface import Attribute -from zope.interface.exceptions import Invalid - -class mytest(Interface): - pass - -class C(object): - def m1(self, a, b): - "return 1" - return 1 - - def m2(self, a, b): - "return 2" - return 2 - -# testInstancesOfClassImplements - -# YAGNI IC=Interface.impliedInterface(C) -class IC(Interface): - def m1(a, b): - "return 1" - - def m2(a, b): - "return 2" - - - -C.__implemented__=IC - -class I1(Interface): - def ma(): - "blah" - -class I2(I1): pass - -class I3(Interface): pass - -class I4(Interface): pass - -class A(I1.deferred()): - __implemented__=I1 - -class B(object): - __implemented__=I2, I3 - -class D(A, B): pass - -class E(A, B): - __implemented__ = A.__implemented__, C.__implemented__ - - -class FooInterface(Interface): - """ This is an Abstract Base Class """ - - foobar = Attribute("fuzzed over beyond all recognition") - - def aMethod(foo, bar, bingo): - """ This is aMethod """ - - def anotherMethod(foo=6, bar="where you get sloshed", bingo=(1,3,)): - """ This is anotherMethod """ - - def wammy(zip, *argues): - """ yadda yadda """ - - def useless(**keywords): - """ useless code is fun! """ - -class Foo(object): - """ A concrete class """ - - __implemented__ = FooInterface, - - foobar = "yeah" - - def aMethod(self, foo, bar, bingo): - """ This is aMethod """ - return "barf!" - - def anotherMethod(self, foo=6, bar="where you get sloshed", bingo=(1,3,)): - """ This is anotherMethod """ - return "barf!" - - def wammy(self, zip, *argues): - """ yadda yadda """ - return "barf!" - - def useless(self, **keywords): - """ useless code is fun! """ - return "barf!" - -foo_instance = Foo() - -class Blah(object): - pass - -new = Interface.__class__ -FunInterface = new('FunInterface') -BarInterface = new('BarInterface', [FunInterface]) -BobInterface = new('BobInterface') -BazInterface = new('BazInterface', [BobInterface, BarInterface]) - -# fixtures for invariant tests -def ifFooThenBar(obj): - if getattr(obj, 'foo', None) and not getattr(obj, 'bar', None): - raise Invalid('If Foo, then Bar!') -class IInvariant(Interface): - foo = Attribute('foo') - bar = Attribute('bar; must eval to Boolean True if foo does') - invariant(ifFooThenBar) -def BarGreaterThanFoo(obj): - foo = getattr(obj, 'foo', None) - bar = getattr(obj, 'bar', None) - if foo is not None and isinstance(foo, type(bar)): - # type checking should be handled elsewhere (like, say, - # schema); these invariants should be intra-interface - # constraints. This is a hacky way to do it, maybe, but you - # get the idea - if not bar > foo: - raise Invalid('Please, Boo MUST be greater than Foo!') -class ISubInvariant(IInvariant): - invariant(BarGreaterThanFoo) -class InvariantC(object): - pass diff --git a/tools/buildbot/pylibs/zope/interface/verify.py b/tools/buildbot/pylibs/zope/interface/verify.py deleted file mode 100644 index ae1b37a..0000000 --- a/tools/buildbot/pylibs/zope/interface/verify.py +++ /dev/null @@ -1,111 +0,0 @@ -############################################################################## -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Verify interface implementations - -$Id: verify.py 37426 2005-07-26 06:24:15Z hdima $ -""" -from zope.interface.exceptions import BrokenImplementation, DoesNotImplement -from zope.interface.exceptions import BrokenMethodImplementation -from types import FunctionType, MethodType -from zope.interface.interface import fromMethod, fromFunction, Method - -# This will be monkey-patched when running under Zope 2, so leave this -# here: -MethodTypes = (MethodType, ) - - -def _verify(iface, candidate, tentative=0, vtype=None): - """Verify that 'candidate' might correctly implements 'iface'. - - This involves: - - o Making sure the candidate defines all the necessary methods - - o Making sure the methods have the correct signature - - o Making sure the candidate asserts that it implements the interface - - Note that this isn't the same as verifying that the class does - implement the interface. - - If optional tentative is true, suppress the "is implemented by" test. - """ - - if vtype == 'c': - tester = iface.implementedBy - else: - tester = iface.providedBy - - if not tentative and not tester(candidate): - raise DoesNotImplement(iface) - - # Here the `desc` is either an `Attribute` or `Method` instance - for name, desc in iface.namesAndDescriptions(1): - if not hasattr(candidate, name): - if (not isinstance(desc, Method)) and vtype == 'c': - # We can't verify non-methods on classes, since the - # class may provide attrs in it's __init__. - continue - - raise BrokenImplementation(iface, name) - - attr = getattr(candidate, name) - if not isinstance(desc, Method): - # If it's not a method, there's nothing else we can test - continue - - if isinstance(attr, FunctionType): - # should never get here, since classes should not provide functions - meth = fromFunction(attr, iface, name=name) - elif (isinstance(attr, MethodTypes) - and type(attr.im_func) is FunctionType): - meth = fromMethod(attr, iface, name) - else: - if not callable(attr): - raise BrokenMethodImplementation(name, "Not a method") - # sigh, it's callable, but we don't know how to intrspect it, so - # we have to give it a pass. - continue - - # Make sure that the required and implemented method signatures are - # the same. - desc = desc.getSignatureInfo() - meth = meth.getSignatureInfo() - - mess = _incompat(desc, meth) - if mess: - raise BrokenMethodImplementation(name, mess) - - return True - -def verifyClass(iface, candidate, tentative=0): - return _verify(iface, candidate, tentative, vtype='c') - -def verifyObject(iface, candidate, tentative=0): - return _verify(iface, candidate, tentative, vtype='o') - -def _incompat(required, implemented): - #if (required['positional'] != - # implemented['positional'][:len(required['positional'])] - # and implemented['kwargs'] is None): - # return 'imlementation has different argument names' - if len(implemented['required']) > len(required['required']): - return 'implementation requires too many arguments' - if ((len(implemented['positional']) < len(required['positional'])) - and not implemented['varargs']): - return "implementation doesn't allow enough arguments" - if required['kwargs'] and not implemented['kwargs']: - return "implementation doesn't support keyword arguments" - if required['varargs'] and not implemented['varargs']: - return "implementation doesn't support variable arguments" diff --git a/tools/buildbot/pylibs/zope/testing/DEPENDENCIES.cfg b/tools/buildbot/pylibs/zope/testing/DEPENDENCIES.cfg deleted file mode 100644 index dbc80ba..0000000 --- a/tools/buildbot/pylibs/zope/testing/DEPENDENCIES.cfg +++ /dev/null @@ -1 +0,0 @@ -zope.exceptions diff --git a/tools/buildbot/pylibs/zope/testing/__init__.py b/tools/buildbot/pylibs/zope/testing/__init__.py deleted file mode 100644 index 1ac0138..0000000 --- a/tools/buildbot/pylibs/zope/testing/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -############################################################################## -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Set up testing environment - -$Id: __init__.py 65557 2006-02-28 00:34:34Z nathan $ -""" diff --git a/tools/buildbot/pylibs/zope/testing/cleanup.py b/tools/buildbot/pylibs/zope/testing/cleanup.py deleted file mode 100644 index 448ce69..0000000 --- a/tools/buildbot/pylibs/zope/testing/cleanup.py +++ /dev/null @@ -1,65 +0,0 @@ -############################################################################## -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Provide a standard cleanup registry - -Unit tests that change global data should include the CleanUp base -class, which provides simpler setUp and tearDown methods that call -global-data cleanup routines:: - - class Test(CleanUp, unittest.TestCase): - - .... - -If custom setUp or tearDown are needed, then the base routines should -be called, as in:: - - def tearDown(self): - super(Test, self).tearDown() - .... - -Cleanup routines for global data should be registered by passing them to -addCleanup:: - - - addCleanUp(pigRegistry._clear) - - -$Id: cleanup.py 29143 2005-02-14 22:43:16Z srichter $ -""" -_cleanups = [] - -def addCleanUp(func, args=(), kw={}): - """Register a cleanup routines - - Pass a function to be called to cleanup global data. - Optional argument tuple and keyword arguments may be passed. - """ - _cleanups.append((func, args, kw)) - -class CleanUp(object): - """Mix-in class providing clean-up setUp and tearDown routines.""" - - def cleanUp(self): - """Clean up global data.""" - cleanUp() - - setUp = tearDown = cleanUp - - -def cleanUp(): - """Clean up global data.""" - for func, args, kw in _cleanups: - func(*args, **kw) - -setUp = tearDown = cleanUp diff --git a/tools/buildbot/pylibs/zope/testing/doctest.py b/tools/buildbot/pylibs/zope/testing/doctest.py deleted file mode 100644 index 81372e8..0000000 --- a/tools/buildbot/pylibs/zope/testing/doctest.py +++ /dev/null @@ -1,2745 +0,0 @@ -# Module doctest. -# Released to the public domain 16-Jan-2001, by Tim Peters (tim@python.org). -# Major enhancements and refactoring by: -# Jim Fulton -# Edward Loper - -# Provided as-is; use at your own risk; no warranty; no promises; enjoy! - -r"""Module doctest -- a framework for running examples in docstrings. - -In simplest use, end each module M to be tested with: - -def _test(): - import doctest - doctest.testmod() - -if __name__ == "__main__": - _test() - -Then running the module as a script will cause the examples in the -docstrings to get executed and verified: - -python M.py - -This won't display anything unless an example fails, in which case the -failing example(s) and the cause(s) of the failure(s) are printed to stdout -(why not stderr? because stderr is a lame hack <0.2 wink>), and the final -line of output is "Test failed.". - -Run it with the -v switch instead: - -python M.py -v - -and a detailed report of all examples tried is printed to stdout, along -with assorted summaries at the end. - -You can force verbose mode by passing "verbose=True" to testmod, or prohibit -it by passing "verbose=False". In either of those cases, sys.argv is not -examined by testmod. - -There are a variety of other ways to run doctests, including integration -with the unittest framework, and support for running non-Python text -files containing doctests. There are also many ways to override parts -of doctest's default behaviors. See the Library Reference Manual for -details. -""" - -__docformat__ = 'reStructuredText en' - -__all__ = [ - # 0, Option Flags - 'register_optionflag', - 'DONT_ACCEPT_TRUE_FOR_1', - 'DONT_ACCEPT_BLANKLINE', - 'NORMALIZE_WHITESPACE', - 'ELLIPSIS', - 'IGNORE_EXCEPTION_DETAIL', - 'COMPARISON_FLAGS', - 'REPORT_UDIFF', - 'REPORT_CDIFF', - 'REPORT_NDIFF', - 'REPORT_ONLY_FIRST_FAILURE', - 'REPORTING_FLAGS', - # 1. Utility Functions - 'is_private', - # 2. Example & DocTest - 'Example', - 'DocTest', - # 3. Doctest Parser - 'DocTestParser', - # 4. Doctest Finder - 'DocTestFinder', - # 5. Doctest Runner - 'DocTestRunner', - 'OutputChecker', - 'DocTestFailure', - 'UnexpectedException', - 'DebugRunner', - # 6. Test Functions - 'testmod', - 'testfile', - 'run_docstring_examples', - # 7. Tester - 'Tester', - # 8. Unittest Support - 'DocTestSuite', - 'DocFileSuite', - 'set_unittest_reportflags', - # 9. Debugging Support - 'script_from_examples', - 'testsource', - 'debug_src', - 'debug', -] - -import __future__ - -import sys, traceback, inspect, linecache, os, re, types -import unittest, difflib, pdb, tempfile -import warnings -from StringIO import StringIO - -# Don't whine about the deprecated is_private function in this -# module's tests. -warnings.filterwarnings("ignore", "is_private", DeprecationWarning, - __name__, 0) - -real_pdb_set_trace = pdb.set_trace - -# There are 4 basic classes: -# - Example: a pair, plus an intra-docstring line number. -# - DocTest: a collection of examples, parsed from a docstring, plus -# info about where the docstring came from (name, filename, lineno). -# - DocTestFinder: extracts DocTests from a given object's docstring and -# its contained objects' docstrings. -# - DocTestRunner: runs DocTest cases, and accumulates statistics. -# -# So the basic picture is: -# -# list of: -# +------+ +---------+ +-------+ -# |object| --DocTestFinder-> | DocTest | --DocTestRunner-> |results| -# +------+ +---------+ +-------+ -# | Example | -# | ... | -# | Example | -# +---------+ - -# Option constants. - -OPTIONFLAGS_BY_NAME = {} -def register_optionflag(name): - flag = 1 << len(OPTIONFLAGS_BY_NAME) - OPTIONFLAGS_BY_NAME[name] = flag - return flag - -DONT_ACCEPT_TRUE_FOR_1 = register_optionflag('DONT_ACCEPT_TRUE_FOR_1') -DONT_ACCEPT_BLANKLINE = register_optionflag('DONT_ACCEPT_BLANKLINE') -NORMALIZE_WHITESPACE = register_optionflag('NORMALIZE_WHITESPACE') -ELLIPSIS = register_optionflag('ELLIPSIS') -IGNORE_EXCEPTION_DETAIL = register_optionflag('IGNORE_EXCEPTION_DETAIL') - -COMPARISON_FLAGS = (DONT_ACCEPT_TRUE_FOR_1 | - DONT_ACCEPT_BLANKLINE | - NORMALIZE_WHITESPACE | - ELLIPSIS | - IGNORE_EXCEPTION_DETAIL) - -REPORT_UDIFF = register_optionflag('REPORT_UDIFF') -REPORT_CDIFF = register_optionflag('REPORT_CDIFF') -REPORT_NDIFF = register_optionflag('REPORT_NDIFF') -REPORT_ONLY_FIRST_FAILURE = register_optionflag('REPORT_ONLY_FIRST_FAILURE') - -REPORTING_FLAGS = (REPORT_UDIFF | - REPORT_CDIFF | - REPORT_NDIFF | - REPORT_ONLY_FIRST_FAILURE) - -# Special string markers for use in `want` strings: -BLANKLINE_MARKER = '' -ELLIPSIS_MARKER = '...' - -###################################################################### -## Table of Contents -###################################################################### -# 1. Utility Functions -# 2. Example & DocTest -- store test cases -# 3. DocTest Parser -- extracts examples from strings -# 4. DocTest Finder -- extracts test cases from objects -# 5. DocTest Runner -- runs test cases -# 6. Test Functions -- convenient wrappers for testing -# 7. Tester Class -- for backwards compatibility -# 8. Unittest Support -# 9. Debugging Support -# 10. Example Usage - -###################################################################### -## 1. Utility Functions -###################################################################### - -def is_private(prefix, base): - """prefix, base -> true iff name prefix + "." + base is "private". - - Prefix may be an empty string, and base does not contain a period. - Prefix is ignored (although functions you write conforming to this - protocol may make use of it). - Return true iff base begins with an (at least one) underscore, but - does not both begin and end with (at least) two underscores. - - >>> is_private("a.b", "my_func") - False - >>> is_private("____", "_my_func") - True - >>> is_private("someclass", "__init__") - False - >>> is_private("sometypo", "__init_") - True - >>> is_private("x.y.z", "_") - True - >>> is_private("_x.y.z", "__") - False - >>> is_private("", "") # senseless but consistent - False - """ - warnings.warn("is_private is deprecated; it wasn't useful; " - "examine DocTestFinder.find() lists instead", - DeprecationWarning, stacklevel=2) - return base[:1] == "_" and not base[:2] == "__" == base[-2:] - -def _extract_future_flags(globs): - """ - Return the compiler-flags associated with the future features that - have been imported into the given namespace (globs). - """ - flags = 0 - for fname in __future__.all_feature_names: - feature = globs.get(fname, None) - if feature is getattr(__future__, fname): - flags |= feature.compiler_flag - return flags - -def _normalize_module(module, depth=2): - """ - Return the module specified by `module`. In particular: - - If `module` is a module, then return module. - - If `module` is a string, then import and return the - module with that name. - - If `module` is None, then return the calling module. - The calling module is assumed to be the module of - the stack frame at the given depth in the call stack. - """ - if inspect.ismodule(module): - return module - elif isinstance(module, (str, unicode)): - return __import__(module, globals(), locals(), ["*"]) - elif module is None: - return sys.modules[sys._getframe(depth).f_globals['__name__']] - else: - raise TypeError("Expected a module, string, or None") - -def _indent(s, indent=4): - """ - Add the given number of space characters to the beginning every - non-blank line in `s`, and return the result. - """ - # This regexp matches the start of non-blank lines: - return re.sub('(?m)^(?!$)', indent*' ', s) - -def _exception_traceback(exc_info): - """ - Return a string containing a traceback message for the given - exc_info tuple (as returned by sys.exc_info()). - """ - # Get a traceback message. - excout = StringIO() - exc_type, exc_val, exc_tb = exc_info - traceback.print_exception(exc_type, exc_val, exc_tb, file=excout) - return excout.getvalue() - -# Override some StringIO methods. -class _SpoofOut(StringIO): - def getvalue(self): - result = StringIO.getvalue(self) - # If anything at all was written, make sure there's a trailing - # newline. There's no way for the expected output to indicate - # that a trailing newline is missing. - if result and not result.endswith("\n"): - result += "\n" - # Prevent softspace from screwing up the next test case, in - # case they used print with a trailing comma in an example. - if hasattr(self, "softspace"): - del self.softspace - return result - - def truncate(self, size=None): - StringIO.truncate(self, size) - if hasattr(self, "softspace"): - del self.softspace - -# Worst-case linear-time ellipsis matching. -def _ellipsis_match(want, got): - """ - Essentially the only subtle case: - >>> _ellipsis_match('aa...aa', 'aaa') - False - """ - if ELLIPSIS_MARKER not in want: - return want == got - - # Find "the real" strings. - ws = want.split(ELLIPSIS_MARKER) - assert len(ws) >= 2 - - # Deal with exact matches possibly needed at one or both ends. - startpos, endpos = 0, len(got) - w = ws[0] - if w: # starts with exact match - if got.startswith(w): - startpos = len(w) - del ws[0] - else: - return False - w = ws[-1] - if w: # ends with exact match - if got.endswith(w): - endpos -= len(w) - del ws[-1] - else: - return False - - if startpos > endpos: - # Exact end matches required more characters than we have, as in - # _ellipsis_match('aa...aa', 'aaa') - return False - - # For the rest, we only need to find the leftmost non-overlapping - # match for each piece. If there's no overall match that way alone, - # there's no overall match period. - for w in ws: - # w may be '' at times, if there are consecutive ellipses, or - # due to an ellipsis at the start or end of `want`. That's OK. - # Search for an empty string succeeds, and doesn't change startpos. - startpos = got.find(w, startpos, endpos) - if startpos < 0: - return False - startpos += len(w) - - return True - -def _comment_line(line): - "Return a commented form of the given line" - line = line.rstrip() - if line: - return '# '+line - else: - return '#' - -class _OutputRedirectingPdb(pdb.Pdb): - """ - A specialized version of the python debugger that redirects stdout - to a given stream when interacting with the user. Stdout is *not* - redirected when traced code is executed. - """ - def __init__(self, out): - self.__out = out - self.__debugger_used = False - pdb.Pdb.__init__(self) - - def set_trace(self): - self.__debugger_used = True - pdb.Pdb.set_trace(self) - - def set_continue(self): - # Calling set_continue unconditionally would break unit test coverage - # reporting, as Bdb.set_continue calls sys.settrace(None). - if self.__debugger_used: - pdb.Pdb.set_continue(self) - - def trace_dispatch(self, *args): - # Redirect stdout to the given stream. - save_stdout = sys.stdout - sys.stdout = self.__out - # Call Pdb's trace dispatch method. - result = pdb.Pdb.trace_dispatch(self, *args) - # Restore stdout. - sys.stdout = save_stdout - return result - -# [XX] Normalize with respect to os.path.pardir? -def _module_relative_path(module, path): - if not inspect.ismodule(module): - raise TypeError('Expected a module: %r' % module) - if path.startswith('/'): - raise ValueError('Module-relative files may not have absolute paths') - - # Find the base directory for the path. - if hasattr(module, '__file__'): - # A normal module/package - basedir = os.path.split(module.__file__)[0] - elif module.__name__ == '__main__': - # An interactive session. - if len(sys.argv)>0 and sys.argv[0] != '': - basedir = os.path.split(sys.argv[0])[0] - else: - basedir = os.curdir - else: - # A module w/o __file__ (this includes builtins) - raise ValueError("Can't resolve paths relative to the module " + - module + " (it has no __file__)") - - # Combine the base directory and the path. - return os.path.join(basedir, *(path.split('/'))) - -###################################################################### -## 2. Example & DocTest -###################################################################### -## - An "example" is a pair, where "source" is a -## fragment of source code, and "want" is the expected output for -## "source." The Example class also includes information about -## where the example was extracted from. -## -## - A "doctest" is a collection of examples, typically extracted from -## a string (such as an object's docstring). The DocTest class also -## includes information about where the string was extracted from. - -class Example: - """ - A single doctest example, consisting of source code and expected - output. `Example` defines the following attributes: - - - source: A single Python statement, always ending with a newline. - The constructor adds a newline if needed. - - - want: The expected output from running the source code (either - from stdout, or a traceback in case of exception). `want` ends - with a newline unless it's empty, in which case it's an empty - string. The constructor adds a newline if needed. - - - exc_msg: The exception message generated by the example, if - the example is expected to generate an exception; or `None` if - it is not expected to generate an exception. This exception - message is compared against the return value of - `traceback.format_exception_only()`. `exc_msg` ends with a - newline unless it's `None`. The constructor adds a newline - if needed. - - - lineno: The line number within the DocTest string containing - this Example where the Example begins. This line number is - zero-based, with respect to the beginning of the DocTest. - - - indent: The example's indentation in the DocTest string. - I.e., the number of space characters that preceed the - example's first prompt. - - - options: A dictionary mapping from option flags to True or - False, which is used to override default options for this - example. Any option flags not contained in this dictionary - are left at their default value (as specified by the - DocTestRunner's optionflags). By default, no options are set. - """ - def __init__(self, source, want, exc_msg=None, lineno=0, indent=0, - options=None): - # Normalize inputs. - if not source.endswith('\n'): - source += '\n' - if want and not want.endswith('\n'): - want += '\n' - if exc_msg is not None and not exc_msg.endswith('\n'): - exc_msg += '\n' - # Store properties. - self.source = source - self.want = want - self.lineno = lineno - self.indent = indent - if options is None: options = {} - self.options = options - self.exc_msg = exc_msg - -class DocTest: - """ - A collection of doctest examples that should be run in a single - namespace. Each `DocTest` defines the following attributes: - - - examples: the list of examples. - - - globs: The namespace (aka globals) that the examples should - be run in. - - - name: A name identifying the DocTest (typically, the name of - the object whose docstring this DocTest was extracted from). - - - filename: The name of the file that this DocTest was extracted - from, or `None` if the filename is unknown. - - - lineno: The line number within filename where this DocTest - begins, or `None` if the line number is unavailable. This - line number is zero-based, with respect to the beginning of - the file. - - - docstring: The string that the examples were extracted from, - or `None` if the string is unavailable. - """ - def __init__(self, examples, globs, name, filename, lineno, docstring): - """ - Create a new DocTest containing the given examples. The - DocTest's globals are initialized with a copy of `globs`. - """ - assert not isinstance(examples, basestring), \ - "DocTest no longer accepts str; use DocTestParser instead" - self.examples = examples - self.docstring = docstring - self.globs = globs.copy() - self.name = name - self.filename = filename - self.lineno = lineno - - def __repr__(self): - if len(self.examples) == 0: - examples = 'no examples' - elif len(self.examples) == 1: - examples = '1 example' - else: - examples = '%d examples' % len(self.examples) - return ('' % - (self.name, self.filename, self.lineno, examples)) - - - # This lets us sort tests by name: - def __cmp__(self, other): - if not isinstance(other, DocTest): - return -1 - return cmp((self.name, self.filename, self.lineno, id(self)), - (other.name, other.filename, other.lineno, id(other))) - -###################################################################### -## 3. DocTestParser -###################################################################### - -class DocTestParser: - """ - A class used to parse strings containing doctest examples. - """ - # This regular expression is used to find doctest examples in a - # string. It defines three groups: `source` is the source code - # (including leading indentation and prompts); `indent` is the - # indentation of the first (PS1) line of the source code; and - # `want` is the expected output (including leading indentation). - _EXAMPLE_RE = re.compile(r''' - # Source consists of a PS1 line followed by zero or more PS2 lines. - (?P - (?:^(?P [ ]*) >>> .*) # PS1 line - (?:\n [ ]* \.\.\. .*)*) # PS2 lines - \n? - # Want consists of any non-blank lines that do not start with PS1. - (?P (?:(?![ ]*$) # Not a blank line - (?![ ]*>>>) # Not a line starting with PS1 - .*$\n? # But any other line - )*) - ''', re.MULTILINE | re.VERBOSE) - - # A regular expression for handling `want` strings that contain - # expected exceptions. It divides `want` into three pieces: - # - the traceback header line (`hdr`) - # - the traceback stack (`stack`) - # - the exception message (`msg`), as generated by - # traceback.format_exception_only() - # `msg` may have multiple lines. We assume/require that the - # exception message is the first non-indented line starting with a word - # character following the traceback header line. - _EXCEPTION_RE = re.compile(r""" - # Grab the traceback header. Different versions of Python have - # said different things on the first traceback line. - ^(?P Traceback\ \( - (?: most\ recent\ call\ last - | innermost\ last - ) \) : - ) - \s* $ # toss trailing whitespace on the header. - (?P .*?) # don't blink: absorb stuff until... - ^ (?P \w+ .*) # a line *starts* with alphanum. - """, re.VERBOSE | re.MULTILINE | re.DOTALL) - - # A callable returning a true value iff its argument is a blank line - # or contains a single comment. - _IS_BLANK_OR_COMMENT = re.compile(r'^[ ]*(#.*)?$').match - - def parse(self, string, name=''): - """ - Divide the given string into examples and intervening text, - and return them as a list of alternating Examples and strings. - Line numbers for the Examples are 0-based. The optional - argument `name` is a name identifying this string, and is only - used for error messages. - """ - string = string.expandtabs() - # If all lines begin with the same indentation, then strip it. - min_indent = self._min_indent(string) - if min_indent > 0: - string = '\n'.join([l[min_indent:] for l in string.split('\n')]) - - output = [] - charno, lineno = 0, 0 - # Find all doctest examples in the string: - for m in self._EXAMPLE_RE.finditer(string): - # Add the pre-example text to `output`. - output.append(string[charno:m.start()]) - # Update lineno (lines before this example) - lineno += string.count('\n', charno, m.start()) - # Extract info from the regexp match. - (source, options, want, exc_msg) = \ - self._parse_example(m, name, lineno) - # Create an Example, and add it to the list. - if not self._IS_BLANK_OR_COMMENT(source): - output.append( Example(source, want, exc_msg, - lineno=lineno, - indent=min_indent+len(m.group('indent')), - options=options) ) - # Update lineno (lines inside this example) - lineno += string.count('\n', m.start(), m.end()) - # Update charno. - charno = m.end() - # Add any remaining post-example text to `output`. - output.append(string[charno:]) - return output - - def get_doctest(self, string, globs, name, filename, lineno): - """ - Extract all doctest examples from the given string, and - collect them into a `DocTest` object. - - `globs`, `name`, `filename`, and `lineno` are attributes for - the new `DocTest` object. See the documentation for `DocTest` - for more information. - """ - return DocTest(self.get_examples(string, name), globs, - name, filename, lineno, string) - - def get_examples(self, string, name=''): - """ - Extract all doctest examples from the given string, and return - them as a list of `Example` objects. Line numbers are - 0-based, because it's most common in doctests that nothing - interesting appears on the same line as opening triple-quote, - and so the first interesting line is called \"line 1\" then. - - The optional argument `name` is a name identifying this - string, and is only used for error messages. - """ - return [x for x in self.parse(string, name) - if isinstance(x, Example)] - - def _parse_example(self, m, name, lineno): - """ - Given a regular expression match from `_EXAMPLE_RE` (`m`), - return a pair `(source, want)`, where `source` is the matched - example's source code (with prompts and indentation stripped); - and `want` is the example's expected output (with indentation - stripped). - - `name` is the string's name, and `lineno` is the line number - where the example starts; both are used for error messages. - """ - # Get the example's indentation level. - indent = len(m.group('indent')) - - # Divide source into lines; check that they're properly - # indented; and then strip their indentation & prompts. - source_lines = m.group('source').split('\n') - self._check_prompt_blank(source_lines, indent, name, lineno) - self._check_prefix(source_lines[1:], ' '*indent + '.', name, lineno) - source = '\n'.join([sl[indent+4:] for sl in source_lines]) - - # Divide want into lines; check that it's properly indented; and - # then strip the indentation. Spaces before the last newline should - # be preserved, so plain rstrip() isn't good enough. - want = m.group('want') - want_lines = want.split('\n') - if len(want_lines) > 1 and re.match(r' *$', want_lines[-1]): - del want_lines[-1] # forget final newline & spaces after it - self._check_prefix(want_lines, ' '*indent, name, - lineno + len(source_lines)) - want = '\n'.join([wl[indent:] for wl in want_lines]) - - # If `want` contains a traceback message, then extract it. - m = self._EXCEPTION_RE.match(want) - if m: - exc_msg = m.group('msg') - else: - exc_msg = None - - # Extract options from the source. - options = self._find_options(source, name, lineno) - - return source, options, want, exc_msg - - # This regular expression looks for option directives in the - # source code of an example. Option directives are comments - # starting with "doctest:". Warning: this may give false - # positives for string-literals that contain the string - # "#doctest:". Eliminating these false positives would require - # actually parsing the string; but we limit them by ignoring any - # line containing "#doctest:" that is *followed* by a quote mark. - _OPTION_DIRECTIVE_RE = re.compile(r'#\s*doctest:\s*([^\n\'"]*)$', - re.MULTILINE) - - def _find_options(self, source, name, lineno): - """ - Return a dictionary containing option overrides extracted from - option directives in the given source string. - - `name` is the string's name, and `lineno` is the line number - where the example starts; both are used for error messages. - """ - options = {} - # (note: with the current regexp, this will match at most once:) - for m in self._OPTION_DIRECTIVE_RE.finditer(source): - option_strings = m.group(1).replace(',', ' ').split() - for option in option_strings: - if (option[0] not in '+-' or - option[1:] not in OPTIONFLAGS_BY_NAME): - raise ValueError('line %r of the doctest for %s ' - 'has an invalid option: %r' % - (lineno+1, name, option)) - flag = OPTIONFLAGS_BY_NAME[option[1:]] - options[flag] = (option[0] == '+') - if options and self._IS_BLANK_OR_COMMENT(source): - raise ValueError('line %r of the doctest for %s has an option ' - 'directive on a line with no example: %r' % - (lineno, name, source)) - return options - - # This regular expression finds the indentation of every non-blank - # line in a string. - _INDENT_RE = re.compile('^([ ]*)(?=\S)', re.MULTILINE) - - def _min_indent(self, s): - "Return the minimum indentation of any non-blank line in `s`" - indents = [len(indent) for indent in self._INDENT_RE.findall(s)] - if len(indents) > 0: - return min(indents) - else: - return 0 - - def _check_prompt_blank(self, lines, indent, name, lineno): - """ - Given the lines of a source string (including prompts and - leading indentation), check to make sure that every prompt is - followed by a space character. If any line is not followed by - a space character, then raise ValueError. - """ - for i, line in enumerate(lines): - if len(line) >= indent+4 and line[indent+3] != ' ': - raise ValueError('line %r of the docstring for %s ' - 'lacks blank after %s: %r' % - (lineno+i+1, name, - line[indent:indent+3], line)) - - def _check_prefix(self, lines, prefix, name, lineno): - """ - Check that every line in the given list starts with the given - prefix; if any line does not, then raise a ValueError. - """ - for i, line in enumerate(lines): - if line and not line.startswith(prefix): - raise ValueError('line %r of the docstring for %s has ' - 'inconsistent leading whitespace: %r' % - (lineno+i+1, name, line)) - - -###################################################################### -## 4. DocTest Finder -###################################################################### - -class DocTestFinder: - """ - A class used to extract the DocTests that are relevant to a given - object, from its docstring and the docstrings of its contained - objects. Doctests can currently be extracted from the following - object types: modules, functions, classes, methods, staticmethods, - classmethods, and properties. - """ - - def __init__(self, verbose=False, parser=DocTestParser(), - recurse=True, _namefilter=None, exclude_empty=True): - """ - Create a new doctest finder. - - The optional argument `parser` specifies a class or - function that should be used to create new DocTest objects (or - objects that implement the same interface as DocTest). The - signature for this factory function should match the signature - of the DocTest constructor. - - If the optional argument `recurse` is false, then `find` will - only examine the given object, and not any contained objects. - - If the optional argument `exclude_empty` is false, then `find` - will include tests for objects with empty docstrings. - """ - self._parser = parser - self._verbose = verbose - self._recurse = recurse - self._exclude_empty = exclude_empty - # _namefilter is undocumented, and exists only for temporary backward- - # compatibility support of testmod's deprecated isprivate mess. - self._namefilter = _namefilter - - def find(self, obj, name=None, module=None, globs=None, - extraglobs=None): - """ - Return a list of the DocTests that are defined by the given - object's docstring, or by any of its contained objects' - docstrings. - - The optional parameter `module` is the module that contains - the given object. If the module is not specified or is None, then - the test finder will attempt to automatically determine the - correct module. The object's module is used: - - - As a default namespace, if `globs` is not specified. - - To prevent the DocTestFinder from extracting DocTests - from objects that are imported from other modules. - - To find the name of the file containing the object. - - To help find the line number of the object within its - file. - - Contained objects whose module does not match `module` are ignored. - - If `module` is False, no attempt to find the module will be made. - This is obscure, of use mostly in tests: if `module` is False, or - is None but cannot be found automatically, then all objects are - considered to belong to the (non-existent) module, so all contained - objects will (recursively) be searched for doctests. - - The globals for each DocTest is formed by combining `globs` - and `extraglobs` (bindings in `extraglobs` override bindings - in `globs`). A new copy of the globals dictionary is created - for each DocTest. If `globs` is not specified, then it - defaults to the module's `__dict__`, if specified, or {} - otherwise. If `extraglobs` is not specified, then it defaults - to {}. - - """ - # If name was not specified, then extract it from the object. - if name is None: - name = getattr(obj, '__name__', None) - if name is None: - raise ValueError("DocTestFinder.find: name must be given " - "when obj.__name__ doesn't exist: %r" % - (type(obj),)) - - # Find the module that contains the given object (if obj is - # a module, then module=obj.). Note: this may fail, in which - # case module will be None. - if module is False: - module = None - elif module is None: - module = inspect.getmodule(obj) - - # Read the module's source code. This is used by - # DocTestFinder._find_lineno to find the line number for a - # given object's docstring. - try: - file = inspect.getsourcefile(obj) or inspect.getfile(obj) - source_lines = linecache.getlines(file) - if not source_lines: - source_lines = None - except TypeError: - source_lines = None - - # Initialize globals, and merge in extraglobs. - if globs is None: - if module is None: - globs = {} - else: - globs = module.__dict__.copy() - else: - globs = globs.copy() - if extraglobs is not None: - globs.update(extraglobs) - - # Recursively expore `obj`, extracting DocTests. - tests = [] - self._find(tests, obj, name, module, source_lines, globs, {}) - return tests - - def _filter(self, obj, prefix, base): - """ - Return true if the given object should not be examined. - """ - return (self._namefilter is not None and - self._namefilter(prefix, base)) - - def _from_module(self, module, object): - """ - Return true if the given object is defined in the given - module. - """ - if module is None: - return True - elif inspect.isfunction(object): - return module.__dict__ is object.func_globals - elif inspect.isclass(object): - return module.__name__ == object.__module__ - elif inspect.getmodule(object) is not None: - return module is inspect.getmodule(object) - elif hasattr(object, '__module__'): - return module.__name__ == object.__module__ - elif isinstance(object, property): - return True # [XX] no way not be sure. - else: - raise ValueError("object must be a class or function") - - def _find(self, tests, obj, name, module, source_lines, globs, seen): - """ - Find tests for the given object and any contained objects, and - add them to `tests`. - """ - if self._verbose: - print 'Finding tests in %s' % name - - # If we've already processed this object, then ignore it. - if id(obj) in seen: - return - seen[id(obj)] = 1 - - # Find a test for this object, and add it to the list of tests. - test = self._get_test(obj, name, module, globs, source_lines) - if test is not None: - tests.append(test) - - # Look for tests in a module's contained objects. - if inspect.ismodule(obj) and self._recurse: - for valname, val in obj.__dict__.items(): - # Check if this contained object should be ignored. - if self._filter(val, name, valname): - continue - valname = '%s.%s' % (name, valname) - # Recurse to functions & classes. - if ((inspect.isfunction(val) or inspect.isclass(val)) and - self._from_module(module, val)): - self._find(tests, val, valname, module, source_lines, - globs, seen) - - # Look for tests in a module's __test__ dictionary. - if inspect.ismodule(obj) and self._recurse: - for valname, val in getattr(obj, '__test__', {}).items(): - if not isinstance(valname, basestring): - raise ValueError("DocTestFinder.find: __test__ keys " - "must be strings: %r" % - (type(valname),)) - if not (inspect.isfunction(val) or inspect.isclass(val) or - inspect.ismethod(val) or inspect.ismodule(val) or - isinstance(val, basestring)): - raise ValueError("DocTestFinder.find: __test__ values " - "must be strings, functions, methods, " - "classes, or modules: %r" % - (type(val),)) - valname = '%s.__test__.%s' % (name, valname) - self._find(tests, val, valname, module, source_lines, - globs, seen) - - # Look for tests in a class's contained objects. - if inspect.isclass(obj) and self._recurse: - for valname, val in obj.__dict__.items(): - # Check if this contained object should be ignored. - if self._filter(val, name, valname): - continue - # Special handling for staticmethod/classmethod. - if isinstance(val, staticmethod): - val = getattr(obj, valname) - if isinstance(val, classmethod): - val = getattr(obj, valname).im_func - - # Recurse to methods, properties, and nested classes. - if ((inspect.isfunction(val) or inspect.isclass(val) or - isinstance(val, property)) and - self._from_module(module, val)): - valname = '%s.%s' % (name, valname) - self._find(tests, val, valname, module, source_lines, - globs, seen) - - def _get_test(self, obj, name, module, globs, source_lines): - """ - Return a DocTest for the given object, if it defines a docstring; - otherwise, return None. - """ - # Extract the object's docstring. If it doesn't have one, - # then return None (no test for this object). - if isinstance(obj, basestring): - docstring = obj - else: - try: - if obj.__doc__ is None: - docstring = '' - else: - docstring = obj.__doc__ - if not isinstance(docstring, basestring): - docstring = str(docstring) - except (TypeError, AttributeError): - docstring = '' - - # Find the docstring's location in the file. - lineno = self._find_lineno(obj, source_lines) - - # Don't bother if the docstring is empty. - if self._exclude_empty and not docstring: - return None - - # Return a DocTest for this object. - if module is None: - filename = None - else: - filename = getattr(module, '__file__', module.__name__) - if filename[-4:] in (".pyc", ".pyo"): - filename = filename[:-1] - return self._parser.get_doctest(docstring, globs, name, - filename, lineno) - - def _find_lineno(self, obj, source_lines): - """ - Return a line number of the given object's docstring. Note: - this method assumes that the object has a docstring. - """ - lineno = None - - # Find the line number for modules. - if inspect.ismodule(obj): - lineno = 0 - - # Find the line number for classes. - # Note: this could be fooled if a class is defined multiple - # times in a single file. - if inspect.isclass(obj): - if source_lines is None: - return None - pat = re.compile(r'^\s*class\s*%s\b' % - getattr(obj, '__name__', '-')) - for i, line in enumerate(source_lines): - if pat.match(line): - lineno = i - break - - # Find the line number for functions & methods. - if inspect.ismethod(obj): obj = obj.im_func - if inspect.isfunction(obj): obj = obj.func_code - if inspect.istraceback(obj): obj = obj.tb_frame - if inspect.isframe(obj): obj = obj.f_code - if inspect.iscode(obj): - lineno = getattr(obj, 'co_firstlineno', None)-1 - - # Find the line number where the docstring starts. Assume - # that it's the first line that begins with a quote mark. - # Note: this could be fooled by a multiline function - # signature, where a continuation line begins with a quote - # mark. - if lineno is not None: - if source_lines is None: - return lineno+1 - pat = re.compile('(^|.*:)\s*\w*("|\')') - for lineno in range(lineno, len(source_lines)): - if pat.match(source_lines[lineno]): - return lineno - - # We couldn't find the line number. - return None - -###################################################################### -## 5. DocTest Runner -###################################################################### - -class DocTestRunner: - """ - A class used to run DocTest test cases, and accumulate statistics. - The `run` method is used to process a single DocTest case. It - returns a tuple `(f, t)`, where `t` is the number of test cases - tried, and `f` is the number of test cases that failed. - - >>> tests = DocTestFinder().find(_TestClass) - >>> runner = DocTestRunner(verbose=False) - >>> for test in tests: - ... print runner.run(test) - (0, 2) - (0, 1) - (0, 2) - (0, 2) - - The `summarize` method prints a summary of all the test cases that - have been run by the runner, and returns an aggregated `(f, t)` - tuple: - - >>> runner.summarize(verbose=1) - 4 items passed all tests: - 2 tests in _TestClass - 2 tests in _TestClass.__init__ - 2 tests in _TestClass.get - 1 tests in _TestClass.square - 7 tests in 4 items. - 7 passed and 0 failed. - Test passed. - (0, 7) - - The aggregated number of tried examples and failed examples is - also available via the `tries` and `failures` attributes: - - >>> runner.tries - 7 - >>> runner.failures - 0 - - The comparison between expected outputs and actual outputs is done - by an `OutputChecker`. This comparison may be customized with a - number of option flags; see the documentation for `testmod` for - more information. If the option flags are insufficient, then the - comparison may also be customized by passing a subclass of - `OutputChecker` to the constructor. - - The test runner's display output can be controlled in two ways. - First, an output function (`out) can be passed to - `TestRunner.run`; this function will be called with strings that - should be displayed. It defaults to `sys.stdout.write`. If - capturing the output is not sufficient, then the display output - can be also customized by subclassing DocTestRunner, and - overriding the methods `report_start`, `report_success`, - `report_unexpected_exception`, and `report_failure`. - """ - # This divider string is used to separate failure messages, and to - # separate sections of the summary. - DIVIDER = "*" * 70 - - def __init__(self, checker=None, verbose=None, optionflags=0): - """ - Create a new test runner. - - Optional keyword arg `checker` is the `OutputChecker` that - should be used to compare the expected outputs and actual - outputs of doctest examples. - - Optional keyword arg 'verbose' prints lots of stuff if true, - only failures if false; by default, it's true iff '-v' is in - sys.argv. - - Optional argument `optionflags` can be used to control how the - test runner compares expected output to actual output, and how - it displays failures. See the documentation for `testmod` for - more information. - """ - self._checker = checker or OutputChecker() - if verbose is None: - verbose = '-v' in sys.argv - self._verbose = verbose - self.optionflags = optionflags - self.original_optionflags = optionflags - - # Keep track of the examples we've run. - self.tries = 0 - self.failures = 0 - self._name2ft = {} - - # Create a fake output target for capturing doctest output. - self._fakeout = _SpoofOut() - - #///////////////////////////////////////////////////////////////// - # Reporting methods - #///////////////////////////////////////////////////////////////// - - def report_start(self, out, test, example): - """ - Report that the test runner is about to process the given - example. (Only displays a message if verbose=True) - """ - if self._verbose: - if example.want: - out('Trying:\n' + _indent(example.source) + - 'Expecting:\n' + _indent(example.want)) - else: - out('Trying:\n' + _indent(example.source) + - 'Expecting nothing\n') - - def report_success(self, out, test, example, got): - """ - Report that the given example ran successfully. (Only - displays a message if verbose=True) - """ - if self._verbose: - out("ok\n") - - def report_failure(self, out, test, example, got): - """ - Report that the given example failed. - """ - out(self._failure_header(test, example) + - self._checker.output_difference(example, got, self.optionflags)) - - def report_unexpected_exception(self, out, test, example, exc_info): - """ - Report that the given example raised an unexpected exception. - """ - out(self._failure_header(test, example) + - 'Exception raised:\n' + _indent(_exception_traceback(exc_info))) - - def _failure_header(self, test, example): - out = [self.DIVIDER] - if test.filename: - if test.lineno is not None and example.lineno is not None: - lineno = test.lineno + example.lineno + 1 - else: - lineno = '?' - out.append('File "%s", line %s, in %s' % - (test.filename, lineno, test.name)) - else: - out.append('Line %s, in %s' % (example.lineno+1, test.name)) - out.append('Failed example:') - source = example.source - out.append(_indent(source)) - return '\n'.join(out) - - #///////////////////////////////////////////////////////////////// - # DocTest Running - #///////////////////////////////////////////////////////////////// - - def __run(self, test, compileflags, out): - """ - Run the examples in `test`. Write the outcome of each example - with one of the `DocTestRunner.report_*` methods, using the - writer function `out`. `compileflags` is the set of compiler - flags that should be used to execute examples. Return a tuple - `(f, t)`, where `t` is the number of examples tried, and `f` - is the number of examples that failed. The examples are run - in the namespace `test.globs`. - """ - # Keep track of the number of failures and tries. - failures = tries = 0 - - # Save the option flags (since option directives can be used - # to modify them). - original_optionflags = self.optionflags - - SUCCESS, FAILURE, BOOM = range(3) # `outcome` state - - check = self._checker.check_output - - # Process each example. - for examplenum, example in enumerate(test.examples): - - # If REPORT_ONLY_FIRST_FAILURE is set, then supress - # reporting after the first failure. - quiet = (self.optionflags & REPORT_ONLY_FIRST_FAILURE and - failures > 0) - - # Merge in the example's options. - self.optionflags = original_optionflags - if example.options: - for (optionflag, val) in example.options.items(): - if val: - self.optionflags |= optionflag - else: - self.optionflags &= ~optionflag - - # Record that we started this example. - tries += 1 - if not quiet: - self.report_start(out, test, example) - - # Use a special filename for compile(), so we can retrieve - # the source code during interactive debugging (see - # __patched_linecache_getlines). - filename = '' % (test.name, examplenum) - - # Run the example in the given context (globs), and record - # any exception that gets raised. (But don't intercept - # keyboard interrupts.) - try: - # Don't blink! This is where the user's code gets run. - exec compile(example.source, filename, "single", - compileflags, 1) in test.globs - self.debugger.set_continue() # ==== Example Finished ==== - exception = None - except KeyboardInterrupt: - raise - except: - exception = sys.exc_info() - self.debugger.set_continue() # ==== Example Finished ==== - - got = self._fakeout.getvalue() # the actual output - self._fakeout.truncate(0) - outcome = FAILURE # guilty until proved innocent or insane - - # If the example executed without raising any exceptions, - # verify its output. - if exception is None: - if check(example.want, got, self.optionflags): - outcome = SUCCESS - - # The example raised an exception: check if it was expected. - else: - exc_info = sys.exc_info() - exc_msg = traceback.format_exception_only(*exc_info[:2])[-1] - if not quiet: - got += _exception_traceback(exc_info) - - # If `example.exc_msg` is None, then we weren't expecting - # an exception. - if example.exc_msg is None: - outcome = BOOM - - # We expected an exception: see whether it matches. - elif check(example.exc_msg, exc_msg, self.optionflags): - outcome = SUCCESS - - # Another chance if they didn't care about the detail. - elif self.optionflags & IGNORE_EXCEPTION_DETAIL: - m1 = re.match(r'[^:]*:', example.exc_msg) - m2 = re.match(r'[^:]*:', exc_msg) - if m1 and m2 and check(m1.group(0), m2.group(0), - self.optionflags): - outcome = SUCCESS - - # Report the outcome. - if outcome is SUCCESS: - if not quiet: - self.report_success(out, test, example, got) - elif outcome is FAILURE: - if not quiet: - self.report_failure(out, test, example, got) - failures += 1 - elif outcome is BOOM: - if not quiet: - self.report_unexpected_exception(out, test, example, - exc_info) - failures += 1 - else: - assert False, ("unknown outcome", outcome) - - # Restore the option flags (in case they were modified) - self.optionflags = original_optionflags - - # Record and return the number of failures and tries. - self.__record_outcome(test, failures, tries) - return failures, tries - - def __record_outcome(self, test, f, t): - """ - Record the fact that the given DocTest (`test`) generated `f` - failures out of `t` tried examples. - """ - f2, t2 = self._name2ft.get(test.name, (0,0)) - self._name2ft[test.name] = (f+f2, t+t2) - self.failures += f - self.tries += t - - __LINECACHE_FILENAME_RE = re.compile(r'[\w\.]+)' - r'\[(?P\d+)\]>$') - def __patched_linecache_getlines(self, filename, module_globals=None): - m = self.__LINECACHE_FILENAME_RE.match(filename) - if m and m.group('name') == self.test.name: - example = self.test.examples[int(m.group('examplenum'))] - return example.source.splitlines(True) - else: - if module_globals is None: - return self.save_linecache_getlines(filename) - else: - return self.save_linecache_getlines(filename, module_globals) - - def run(self, test, compileflags=None, out=None, clear_globs=True): - """ - Run the examples in `test`, and display the results using the - writer function `out`. - - The examples are run in the namespace `test.globs`. If - `clear_globs` is true (the default), then this namespace will - be cleared after the test runs, to help with garbage - collection. If you would like to examine the namespace after - the test completes, then use `clear_globs=False`. - - `compileflags` gives the set of flags that should be used by - the Python compiler when running the examples. If not - specified, then it will default to the set of future-import - flags that apply to `globs`. - - The output of each example is checked using - `DocTestRunner.check_output`, and the results are formatted by - the `DocTestRunner.report_*` methods. - """ - self.test = test - - if compileflags is None: - compileflags = _extract_future_flags(test.globs) - - save_stdout = sys.stdout - if out is None: - out = save_stdout.write - sys.stdout = self._fakeout - - # Patch pdb.set_trace to restore sys.stdout during interactive - # debugging (so it's not still redirected to self._fakeout). - # Note that the interactive output will go to *our* - # save_stdout, even if that's not the real sys.stdout; this - # allows us to write test cases for the set_trace behavior. - save_set_trace = pdb.set_trace - self.debugger = _OutputRedirectingPdb(save_stdout) - self.debugger.reset() - pdb.set_trace = self.debugger.set_trace - - # Patch linecache.getlines, so we can see the example's source - # when we're inside the debugger. - self.save_linecache_getlines = linecache.getlines - linecache.getlines = self.__patched_linecache_getlines - - try: - return self.__run(test, compileflags, out) - finally: - sys.stdout = save_stdout - pdb.set_trace = save_set_trace - linecache.getlines = self.save_linecache_getlines - if clear_globs: - test.globs.clear() - - #///////////////////////////////////////////////////////////////// - # Summarization - #///////////////////////////////////////////////////////////////// - def summarize(self, verbose=None): - """ - Print a summary of all the test cases that have been run by - this DocTestRunner, and return a tuple `(f, t)`, where `f` is - the total number of failed examples, and `t` is the total - number of tried examples. - - The optional `verbose` argument controls how detailed the - summary is. If the verbosity is not specified, then the - DocTestRunner's verbosity is used. - """ - if verbose is None: - verbose = self._verbose - notests = [] - passed = [] - failed = [] - totalt = totalf = 0 - for x in self._name2ft.items(): - name, (f, t) = x - assert f <= t - totalt += t - totalf += f - if t == 0: - notests.append(name) - elif f == 0: - passed.append( (name, t) ) - else: - failed.append(x) - if verbose: - if notests: - print len(notests), "items had no tests:" - notests.sort() - for thing in notests: - print " ", thing - if passed: - print len(passed), "items passed all tests:" - passed.sort() - for thing, count in passed: - print " %3d tests in %s" % (count, thing) - if failed: - print self.DIVIDER - print len(failed), "items had failures:" - failed.sort() - for thing, (f, t) in failed: - print " %3d of %3d in %s" % (f, t, thing) - if verbose: - print totalt, "tests in", len(self._name2ft), "items." - print totalt - totalf, "passed and", totalf, "failed." - if totalf: - print "***Test Failed***", totalf, "failures." - elif verbose: - print "Test passed." - return totalf, totalt - - #///////////////////////////////////////////////////////////////// - # Backward compatibility cruft to maintain doctest.master. - #///////////////////////////////////////////////////////////////// - def merge(self, other): - d = self._name2ft - for name, (f, t) in other._name2ft.items(): - if name in d: - print "*** DocTestRunner.merge: '" + name + "' in both" \ - " testers; summing outcomes." - f2, t2 = d[name] - f = f + f2 - t = t + t2 - d[name] = f, t - -class OutputChecker: - """ - A class used to check the whether the actual output from a doctest - example matches the expected output. `OutputChecker` defines two - methods: `check_output`, which compares a given pair of outputs, - and returns true if they match; and `output_difference`, which - returns a string describing the differences between two outputs. - """ - def check_output(self, want, got, optionflags): - """ - Return True iff the actual output from an example (`got`) - matches the expected output (`want`). These strings are - always considered to match if they are identical; but - depending on what option flags the test runner is using, - several non-exact match types are also possible. See the - documentation for `TestRunner` for more information about - option flags. - """ - # Handle the common case first, for efficiency: - # if they're string-identical, always return true. - if got == want: - return True - - # The values True and False replaced 1 and 0 as the return - # value for boolean comparisons in Python 2.3. - if not (optionflags & DONT_ACCEPT_TRUE_FOR_1): - if (got,want) == ("True\n", "1\n"): - return True - if (got,want) == ("False\n", "0\n"): - return True - - # can be used as a special sequence to signify a - # blank line, unless the DONT_ACCEPT_BLANKLINE flag is used. - if not (optionflags & DONT_ACCEPT_BLANKLINE): - # Replace in want with a blank line. - want = re.sub('(?m)^%s\s*?$' % re.escape(BLANKLINE_MARKER), - '', want) - # If a line in got contains only spaces, then remove the - # spaces. - got = re.sub('(?m)^\s*?$', '', got) - if got == want: - return True - - # This flag causes doctest to ignore any differences in the - # contents of whitespace strings. Note that this can be used - # in conjunction with the ELLIPSIS flag. - if optionflags & NORMALIZE_WHITESPACE: - got = ' '.join(got.split()) - want = ' '.join(want.split()) - if got == want: - return True - - # The ELLIPSIS flag says to let the sequence "..." in `want` - # match any substring in `got`. - if optionflags & ELLIPSIS: - if _ellipsis_match(want, got): - return True - - # We didn't find any match; return false. - return False - - # Should we do a fancy diff? - def _do_a_fancy_diff(self, want, got, optionflags): - # Not unless they asked for a fancy diff. - if not optionflags & (REPORT_UDIFF | - REPORT_CDIFF | - REPORT_NDIFF): - return False - - # If expected output uses ellipsis, a meaningful fancy diff is - # too hard ... or maybe not. In two real-life failures Tim saw, - # a diff was a major help anyway, so this is commented out. - # [todo] _ellipsis_match() knows which pieces do and don't match, - # and could be the basis for a kick-ass diff in this case. - ##if optionflags & ELLIPSIS and ELLIPSIS_MARKER in want: - ## return False - - # ndiff does intraline difference marking, so can be useful even - # for 1-line differences. - if optionflags & REPORT_NDIFF: - return True - - # The other diff types need at least a few lines to be helpful. - return want.count('\n') > 2 and got.count('\n') > 2 - - def output_difference(self, example, got, optionflags): - """ - Return a string describing the differences between the - expected output for a given example (`example`) and the actual - output (`got`). `optionflags` is the set of option flags used - to compare `want` and `got`. - """ - want = example.want - # If s are being used, then replace blank lines - # with in the actual output string. - if not (optionflags & DONT_ACCEPT_BLANKLINE): - got = re.sub('(?m)^[ ]*(?=\n)', BLANKLINE_MARKER, got) - - # Check if we should use diff. - if self._do_a_fancy_diff(want, got, optionflags): - # Split want & got into lines. - want_lines = want.splitlines(True) # True == keep line ends - got_lines = got.splitlines(True) - # Use difflib to find their differences. - if optionflags & REPORT_UDIFF: - diff = difflib.unified_diff(want_lines, got_lines, n=2) - diff = list(diff)[2:] # strip the diff header - kind = 'unified diff with -expected +actual' - elif optionflags & REPORT_CDIFF: - diff = difflib.context_diff(want_lines, got_lines, n=2) - diff = list(diff)[2:] # strip the diff header - kind = 'context diff with expected followed by actual' - elif optionflags & REPORT_NDIFF: - engine = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK) - diff = list(engine.compare(want_lines, got_lines)) - kind = 'ndiff with -expected +actual' - else: - assert 0, 'Bad diff option' - # Remove trailing whitespace on diff output. - diff = [line.rstrip() + '\n' for line in diff] - return 'Differences (%s):\n' % kind + _indent(''.join(diff)) - - # If we're not using diff, then simply list the expected - # output followed by the actual output. - if want and got: - return 'Expected:\n%sGot:\n%s' % (_indent(want), _indent(got)) - elif want: - return 'Expected:\n%sGot nothing\n' % _indent(want) - elif got: - return 'Expected nothing\nGot:\n%s' % _indent(got) - else: - return 'Expected nothing\nGot nothing\n' - -class DocTestFailure(Exception): - """A DocTest example has failed in debugging mode. - - The exception instance has variables: - - - test: the DocTest object being run - - - excample: the Example object that failed - - - got: the actual output - """ - def __init__(self, test, example, got): - self.test = test - self.example = example - self.got = got - - def __str__(self): - return str(self.test) - -class UnexpectedException(Exception): - """A DocTest example has encountered an unexpected exception - - The exception instance has variables: - - - test: the DocTest object being run - - - excample: the Example object that failed - - - exc_info: the exception info - """ - def __init__(self, test, example, exc_info): - self.test = test - self.example = example - self.exc_info = exc_info - - def __str__(self): - return str(self.test) - -class DebugRunner(DocTestRunner): - r"""Run doc tests but raise an exception as soon as there is a failure. - - If an unexpected exception occurs, an UnexpectedException is raised. - It contains the test, the example, and the original exception: - - >>> runner = DebugRunner(verbose=False) - >>> test = DocTestParser().get_doctest('>>> raise KeyError\n42', - ... {}, 'foo', 'foo.py', 0) - >>> try: - ... runner.run(test) - ... except UnexpectedException, failure: - ... pass - - >>> failure.test is test - True - - >>> failure.example.want - '42\n' - - >>> exc_info = failure.exc_info - >>> raise exc_info[0], exc_info[1], exc_info[2] - Traceback (most recent call last): - ... - KeyError - - We wrap the original exception to give the calling application - access to the test and example information. - - If the output doesn't match, then a DocTestFailure is raised: - - >>> test = DocTestParser().get_doctest(''' - ... >>> x = 1 - ... >>> x - ... 2 - ... ''', {}, 'foo', 'foo.py', 0) - - >>> try: - ... runner.run(test) - ... except DocTestFailure, failure: - ... pass - - DocTestFailure objects provide access to the test: - - >>> failure.test is test - True - - As well as to the example: - - >>> failure.example.want - '2\n' - - and the actual output: - - >>> failure.got - '1\n' - - If a failure or error occurs, the globals are left intact: - - >>> del test.globs['__builtins__'] - >>> test.globs - {'x': 1} - - >>> test = DocTestParser().get_doctest(''' - ... >>> x = 2 - ... >>> raise KeyError - ... ''', {}, 'foo', 'foo.py', 0) - - >>> runner.run(test) - Traceback (most recent call last): - ... - UnexpectedException: - - >>> del test.globs['__builtins__'] - >>> test.globs - {'x': 2} - - But the globals are cleared if there is no error: - - >>> test = DocTestParser().get_doctest(''' - ... >>> x = 2 - ... ''', {}, 'foo', 'foo.py', 0) - - >>> runner.run(test) - (0, 1) - - >>> test.globs - {} - - """ - - def run(self, test, compileflags=None, out=None, clear_globs=True): - r = DocTestRunner.run(self, test, compileflags, out, False) - if clear_globs: - test.globs.clear() - return r - - def report_unexpected_exception(self, out, test, example, exc_info): - raise UnexpectedException(test, example, exc_info) - - def report_failure(self, out, test, example, got): - raise DocTestFailure(test, example, got) - -###################################################################### -## 6. Test Functions -###################################################################### -# These should be backwards compatible. - -# For backward compatibility, a global instance of a DocTestRunner -# class, updated by testmod. -master = None - -def testmod(m=None, name=None, globs=None, verbose=None, isprivate=None, - report=True, optionflags=0, extraglobs=None, - raise_on_error=False, exclude_empty=False): - """m=None, name=None, globs=None, verbose=None, isprivate=None, - report=True, optionflags=0, extraglobs=None, raise_on_error=False, - exclude_empty=False - - Test examples in docstrings in functions and classes reachable - from module m (or the current module if m is not supplied), starting - with m.__doc__. Unless isprivate is specified, private names - are not skipped. - - Also test examples reachable from dict m.__test__ if it exists and is - not None. m.__test__ maps names to functions, classes and strings; - function and class docstrings are tested even if the name is private; - strings are tested directly, as if they were docstrings. - - Return (#failures, #tests). - - See doctest.__doc__ for an overview. - - Optional keyword arg "name" gives the name of the module; by default - use m.__name__. - - Optional keyword arg "globs" gives a dict to be used as the globals - when executing examples; by default, use m.__dict__. A copy of this - dict is actually used for each docstring, so that each docstring's - examples start with a clean slate. - - Optional keyword arg "extraglobs" gives a dictionary that should be - merged into the globals that are used to execute examples. By - default, no extra globals are used. This is new in 2.4. - - Optional keyword arg "verbose" prints lots of stuff if true, prints - only failures if false; by default, it's true iff "-v" is in sys.argv. - - Optional keyword arg "report" prints a summary at the end when true, - else prints nothing at the end. In verbose mode, the summary is - detailed, else very brief (in fact, empty if all tests passed). - - Optional keyword arg "optionflags" or's together module constants, - and defaults to 0. This is new in 2.3. Possible values (see the - docs for details): - - DONT_ACCEPT_TRUE_FOR_1 - DONT_ACCEPT_BLANKLINE - NORMALIZE_WHITESPACE - ELLIPSIS - IGNORE_EXCEPTION_DETAIL - REPORT_UDIFF - REPORT_CDIFF - REPORT_NDIFF - REPORT_ONLY_FIRST_FAILURE - - Optional keyword arg "raise_on_error" raises an exception on the - first unexpected exception or failure. This allows failures to be - post-mortem debugged. - - Deprecated in Python 2.4: - Optional keyword arg "isprivate" specifies a function used to - determine whether a name is private. The default function is - treat all functions as public. Optionally, "isprivate" can be - set to doctest.is_private to skip over functions marked as private - using the underscore naming convention; see its docs for details. - - Advanced tomfoolery: testmod runs methods of a local instance of - class doctest.Tester, then merges the results into (or creates) - global Tester instance doctest.master. Methods of doctest.master - can be called directly too, if you want to do something unusual. - Passing report=0 to testmod is especially useful then, to delay - displaying a summary. Invoke doctest.master.summarize(verbose) - when you're done fiddling. - """ - global master - - if isprivate is not None: - warnings.warn("the isprivate argument is deprecated; " - "examine DocTestFinder.find() lists instead", - DeprecationWarning) - - # If no module was given, then use __main__. - if m is None: - # DWA - m will still be None if this wasn't invoked from the command - # line, in which case the following TypeError is about as good an error - # as we should expect - m = sys.modules.get('__main__') - - # Check that we were actually given a module. - if not inspect.ismodule(m): - raise TypeError("testmod: module required; %r" % (m,)) - - # If no name was given, then use the module's name. - if name is None: - name = m.__name__ - - # Find, parse, and run all tests in the given module. - finder = DocTestFinder(_namefilter=isprivate, exclude_empty=exclude_empty) - - if raise_on_error: - runner = DebugRunner(verbose=verbose, optionflags=optionflags) - else: - runner = DocTestRunner(verbose=verbose, optionflags=optionflags) - - for test in finder.find(m, name, globs=globs, extraglobs=extraglobs): - runner.run(test) - - if report: - runner.summarize() - - if master is None: - master = runner - else: - master.merge(runner) - - return runner.failures, runner.tries - -def testfile(filename, module_relative=True, name=None, package=None, - globs=None, verbose=None, report=True, optionflags=0, - extraglobs=None, raise_on_error=False, parser=DocTestParser(), - encoding=None): - """ - Test examples in the given file. Return (#failures, #tests). - - Optional keyword arg "module_relative" specifies how filenames - should be interpreted: - - - If "module_relative" is True (the default), then "filename" - specifies a module-relative path. By default, this path is - relative to the calling module's directory; but if the - "package" argument is specified, then it is relative to that - package. To ensure os-independence, "filename" should use - "/" characters to separate path segments, and should not - be an absolute path (i.e., it may not begin with "/"). - - - If "module_relative" is False, then "filename" specifies an - os-specific path. The path may be absolute or relative (to - the current working directory). - - Optional keyword arg "name" gives the name of the test; by default - use the file's basename. - - Optional keyword argument "package" is a Python package or the - name of a Python package whose directory should be used as the - base directory for a module relative filename. If no package is - specified, then the calling module's directory is used as the base - directory for module relative filenames. It is an error to - specify "package" if "module_relative" is False. - - Optional keyword arg "globs" gives a dict to be used as the globals - when executing examples; by default, use {}. A copy of this dict - is actually used for each docstring, so that each docstring's - examples start with a clean slate. - - Optional keyword arg "extraglobs" gives a dictionary that should be - merged into the globals that are used to execute examples. By - default, no extra globals are used. - - Optional keyword arg "verbose" prints lots of stuff if true, prints - only failures if false; by default, it's true iff "-v" is in sys.argv. - - Optional keyword arg "report" prints a summary at the end when true, - else prints nothing at the end. In verbose mode, the summary is - detailed, else very brief (in fact, empty if all tests passed). - - Optional keyword arg "optionflags" or's together module constants, - and defaults to 0. Possible values (see the docs for details): - - DONT_ACCEPT_TRUE_FOR_1 - DONT_ACCEPT_BLANKLINE - NORMALIZE_WHITESPACE - ELLIPSIS - IGNORE_EXCEPTION_DETAIL - REPORT_UDIFF - REPORT_CDIFF - REPORT_NDIFF - REPORT_ONLY_FIRST_FAILURE - - Optional keyword arg "raise_on_error" raises an exception on the - first unexpected exception or failure. This allows failures to be - post-mortem debugged. - - Optional keyword arg "parser" specifies a DocTestParser (or - subclass) that should be used to extract tests from the files. - - Optional keyword arg "encoding" specifies an encoding that should - be used to convert the file to unicode. - - Advanced tomfoolery: testmod runs methods of a local instance of - class doctest.Tester, then merges the results into (or creates) - global Tester instance doctest.master. Methods of doctest.master - can be called directly too, if you want to do something unusual. - Passing report=0 to testmod is especially useful then, to delay - displaying a summary. Invoke doctest.master.summarize(verbose) - when you're done fiddling. - """ - global master - - if package and not module_relative: - raise ValueError("Package may only be specified for module-" - "relative paths.") - - # Relativize the path - if module_relative: - package = _normalize_module(package) - filename = _module_relative_path(package, filename) - - # If no name was given, then use the file's name. - if name is None: - name = os.path.basename(filename) - - # Assemble the globals. - if globs is None: - globs = {} - else: - globs = globs.copy() - if extraglobs is not None: - globs.update(extraglobs) - - if raise_on_error: - runner = DebugRunner(verbose=verbose, optionflags=optionflags) - else: - runner = DocTestRunner(verbose=verbose, optionflags=optionflags) - - # Read the file, convert it to a test, and run it. - s = open(filename).read() - if encoding is None: - encoding = pep263_encoding(s) - if encoding is not None: - s = s.decode(encoding) - test = parser.get_doctest(s, globs, name, filename, 0) - runner.run(test) - - if report: - runner.summarize() - - if master is None: - master = runner - else: - master.merge(runner) - - return runner.failures, runner.tries - -pep263_re_search = re.compile("coding[:=]\s*([-\w.]+)").search -def pep263_encoding(s): - """Try to find the encoding of a string by looking for a pep263 coding. - """ - for line in s.split('\n')[:2]: - r = pep263_re_search(line) - if r: - return r.group(1) - - - -def run_docstring_examples(f, globs, verbose=False, name="NoName", - compileflags=None, optionflags=0): - """ - Test examples in the given object's docstring (`f`), using `globs` - as globals. Optional argument `name` is used in failure messages. - If the optional argument `verbose` is true, then generate output - even if there are no failures. - - `compileflags` gives the set of flags that should be used by the - Python compiler when running the examples. If not specified, then - it will default to the set of future-import flags that apply to - `globs`. - - Optional keyword arg `optionflags` specifies options for the - testing and output. See the documentation for `testmod` for more - information. - """ - # Find, parse, and run all tests in the given module. - finder = DocTestFinder(verbose=verbose, recurse=False) - runner = DocTestRunner(verbose=verbose, optionflags=optionflags) - for test in finder.find(f, name, globs=globs): - runner.run(test, compileflags=compileflags) - -###################################################################### -## 7. Tester -###################################################################### -# This is provided only for backwards compatibility. It's not -# actually used in any way. - -class Tester: - def __init__(self, mod=None, globs=None, verbose=None, - isprivate=None, optionflags=0): - - warnings.warn("class Tester is deprecated; " - "use class doctest.DocTestRunner instead", - DeprecationWarning, stacklevel=2) - if mod is None and globs is None: - raise TypeError("Tester.__init__: must specify mod or globs") - if mod is not None and not inspect.ismodule(mod): - raise TypeError("Tester.__init__: mod must be a module; %r" % - (mod,)) - if globs is None: - globs = mod.__dict__ - self.globs = globs - - self.verbose = verbose - self.isprivate = isprivate - self.optionflags = optionflags - self.testfinder = DocTestFinder(_namefilter=isprivate) - self.testrunner = DocTestRunner(verbose=verbose, - optionflags=optionflags) - - def runstring(self, s, name): - test = DocTestParser().get_doctest(s, self.globs, name, None, None) - if self.verbose: - print "Running string", name - (f,t) = self.testrunner.run(test) - if self.verbose: - print f, "of", t, "examples failed in string", name - return (f,t) - - def rundoc(self, object, name=None, module=None): - f = t = 0 - tests = self.testfinder.find(object, name, module=module, - globs=self.globs) - for test in tests: - (f2, t2) = self.testrunner.run(test) - (f,t) = (f+f2, t+t2) - return (f,t) - - def rundict(self, d, name, module=None): - import new - m = new.module(name) - m.__dict__.update(d) - if module is None: - module = False - return self.rundoc(m, name, module) - - def run__test__(self, d, name): - import new - m = new.module(name) - m.__test__ = d - return self.rundoc(m, name) - - def summarize(self, verbose=None): - return self.testrunner.summarize(verbose) - - def merge(self, other): - self.testrunner.merge(other.testrunner) - -###################################################################### -## 8. Unittest Support -###################################################################### - -_unittest_reportflags = 0 - -def set_unittest_reportflags(flags): - """Sets the unittest option flags. - - The old flag is returned so that a runner could restore the old - value if it wished to: - - >>> old = _unittest_reportflags - >>> set_unittest_reportflags(REPORT_NDIFF | - ... REPORT_ONLY_FIRST_FAILURE) == old - True - - >>> import doctest - >>> doctest._unittest_reportflags == (REPORT_NDIFF | - ... REPORT_ONLY_FIRST_FAILURE) - True - - Only reporting flags can be set: - - >>> set_unittest_reportflags(ELLIPSIS) - Traceback (most recent call last): - ... - ValueError: ('Only reporting flags allowed', 8) - - >>> set_unittest_reportflags(old) == (REPORT_NDIFF | - ... REPORT_ONLY_FIRST_FAILURE) - True - """ - global _unittest_reportflags - - if (flags & REPORTING_FLAGS) != flags: - raise ValueError("Only reporting flags allowed", flags) - old = _unittest_reportflags - _unittest_reportflags = flags - return old - -_para_re = re.compile(r'\s*\n\s*\n\s*') -def _unittest_count(docstring): - words = 0 - count = 0 - for p in _para_re.split(docstring): - p = p.strip() - if not p: - continue - if p.startswith('>>> '): - if words: - count += 1 - words = 0 - else: - words = 1 - - return count or 1 - - -class DocTestFailureException(AssertionError): - """Use custom exception for doctest unit test failures - """ - -class DocTestCase(unittest.TestCase): - - def __init__(self, test, optionflags=0, setUp=None, tearDown=None, - checker=None): - - unittest.TestCase.__init__(self) - self._dt_optionflags = optionflags - self._dt_checker = checker - self._dt_test = test - self._dt_globs = test.globs.copy() - self._dt_setUp = setUp - self._dt_tearDown = tearDown - - self._dt_count = _unittest_count(test.docstring) - - def countTestCases(self): - return self._dt_count - - def setUp(self): - test = self._dt_test - - if self._dt_setUp is not None: - self._dt_setUp(test) - - def tearDown(self): - test = self._dt_test - - if self._dt_tearDown is not None: - self._dt_tearDown(test) - - # restore the original globs - test.globs.clear() - test.globs.update(self._dt_globs) - - failureException = DocTestFailureException - - def runTest(self): - test = self._dt_test - old = sys.stdout - new = StringIO() - optionflags = self._dt_optionflags - - if not (optionflags & REPORTING_FLAGS): - # The option flags don't include any reporting flags, - # so add the default reporting flags - optionflags |= _unittest_reportflags - - runner = DocTestRunner(optionflags=optionflags, - checker=self._dt_checker, verbose=False) - - try: - runner.DIVIDER = "-"*70 - failures, tries = runner.run( - test, out=new.write, clear_globs=False) - finally: - sys.stdout = old - - if failures: - raise self.failureException(self.format_failure(new.getvalue())) - - def format_failure(self, err): - test = self._dt_test - if test.lineno is None: - lineno = 'unknown line number' - else: - lineno = '%s' % test.lineno - lname = '.'.join(test.name.split('.')[-1:]) - return ('Failed doctest test for %s\n' - ' File "%s", line %s, in %s\n\n%s' - % (test.name, test.filename, lineno, lname, err) - ) - - def debug(self): - r"""Run the test case without results and without catching exceptions - - The unit test framework includes a debug method on test cases - and test suites to support post-mortem debugging. The test code - is run in such a way that errors are not caught. This way a - caller can catch the errors and initiate post-mortem debugging. - - The DocTestCase provides a debug method that raises - UnexpectedException errors if there is an unexepcted - exception: - - >>> test = DocTestParser().get_doctest('>>> raise KeyError\n42', - ... {}, 'foo', 'foo.py', 0) - >>> case = DocTestCase(test) - >>> try: - ... case.debug() - ... except UnexpectedException, failure: - ... pass - - The UnexpectedException contains the test, the example, and - the original exception: - - >>> failure.test is test - True - - >>> failure.example.want - '42\n' - - >>> exc_info = failure.exc_info - >>> raise exc_info[0], exc_info[1], exc_info[2] - Traceback (most recent call last): - ... - KeyError - - If the output doesn't match, then a DocTestFailure is raised: - - >>> test = DocTestParser().get_doctest(''' - ... >>> x = 1 - ... >>> x - ... 2 - ... ''', {}, 'foo', 'foo.py', 0) - >>> case = DocTestCase(test) - - >>> try: - ... case.debug() - ... except DocTestFailure, failure: - ... pass - - DocTestFailure objects provide access to the test: - - >>> failure.test is test - True - - As well as to the example: - - >>> failure.example.want - '2\n' - - and the actual output: - - >>> failure.got - '1\n' - - """ - - self.setUp() - runner = DebugRunner(optionflags=self._dt_optionflags, - checker=self._dt_checker, verbose=False) - runner.run(self._dt_test, clear_globs=False) - self.tearDown() - - def id(self): - return self._dt_test.name - - def __repr__(self): - name = self._dt_test.name.split('.') - return "%s (%s)" % (name[-1], '.'.join(name[:-1])) - - __str__ = __repr__ - - def shortDescription(self): - return "Doctest: " + self._dt_test.name - -def DocTestSuite(module=None, globs=None, extraglobs=None, test_finder=None, - **options): - """ - Convert doctest tests for a module to a unittest test suite. - - This converts each documentation string in a module that - contains doctest tests to a unittest test case. If any of the - tests in a doc string fail, then the test case fails. An exception - is raised showing the name of the file containing the test and a - (sometimes approximate) line number. - - The `module` argument provides the module to be tested. The argument - can be either a module or a module name. - - If no argument is given, the calling module is used. - - A number of options may be provided as keyword arguments: - - setUp - A set-up function. This is called before running the - tests in each file. The setUp function will be passed a DocTest - object. The setUp function can access the test globals as the - globs attribute of the test passed. - - tearDown - A tear-down function. This is called after running the - tests in each file. The tearDown function will be passed a DocTest - object. The tearDown function can access the test globals as the - globs attribute of the test passed. - - globs - A dictionary containing initial global variables for the tests. - - optionflags - A set of doctest option flags expressed as an integer. - """ - - if test_finder is None: - test_finder = DocTestFinder() - - module = _normalize_module(module) - tests = test_finder.find(module, globs=globs, extraglobs=extraglobs) - if globs is None: - globs = module.__dict__ - if not tests: - # Why do we want to do this? Because it reveals a bug that might - # otherwise be hidden. - raise ValueError(module, "has no tests") - - tests.sort() - suite = unittest.TestSuite() - for test in tests: - if len(test.examples) == 0: - continue - if not test.filename: - filename = module.__file__ - if filename[-4:] in (".pyc", ".pyo"): - filename = filename[:-1] - test.filename = filename - suite.addTest(DocTestCase(test, **options)) - - return suite - -class DocFileCase(DocTestCase): - - def id(self): - return '_'.join(self._dt_test.name.split('.')) - - def __repr__(self): - return self._dt_test.filename - __str__ = __repr__ - - def format_failure(self, err): - return ('Failed doctest test for %s\n File "%s", line 0\n\n%s' - % (self._dt_test.name, self._dt_test.filename, err) - ) - -def DocFileTest(path, module_relative=True, package=None, - globs=None, parser=DocTestParser(), - encoding=None, **options): - if globs is None: - globs = {} - else: - globs = globs.copy() - - if package and not module_relative: - raise ValueError("Package may only be specified for module-" - "relative paths.") - - # Relativize the path. - if module_relative: - package = _normalize_module(package) - path = _module_relative_path(package, path) - if "__file__" not in globs: - globs["__file__"] = path - - # Find the file and read it. - name = os.path.basename(path) - doc = open(path).read() - - # If an encoding is specified, use it to convert the file to unicode - if encoding is None: - encoding = pep263_encoding(doc) - if encoding is not None: - doc = doc.decode(encoding) - - # Convert it to a test, and wrap it in a DocFileCase. - test = parser.get_doctest(doc, globs, name, path, 0) - return DocFileCase(test, **options) - -def DocFileSuite(*paths, **kw): - """A unittest suite for one or more doctest files. - - The path to each doctest file is given as a string; the - interpretation of that string depends on the keyword argument - "module_relative". - - A number of options may be provided as keyword arguments: - - module_relative - If "module_relative" is True, then the given file paths are - interpreted as os-independent module-relative paths. By - default, these paths are relative to the calling module's - directory; but if the "package" argument is specified, then - they are relative to that package. To ensure os-independence, - "filename" should use "/" characters to separate path - segments, and may not be an absolute path (i.e., it may not - begin with "/"). - - If "module_relative" is False, then the given file paths are - interpreted as os-specific paths. These paths may be absolute - or relative (to the current working directory). - - package - A Python package or the name of a Python package whose directory - should be used as the base directory for module relative paths. - If "package" is not specified, then the calling module's - directory is used as the base directory for module relative - filenames. It is an error to specify "package" if - "module_relative" is False. - - setUp - A set-up function. This is called before running the - tests in each file. The setUp function will be passed a DocTest - object. The setUp function can access the test globals as the - globs attribute of the test passed. - - tearDown - A tear-down function. This is called after running the - tests in each file. The tearDown function will be passed a DocTest - object. The tearDown function can access the test globals as the - globs attribute of the test passed. - - globs - A dictionary containing initial global variables for the tests. - - optionflags - A set of doctest option flags expressed as an integer. - - parser - A DocTestParser (or subclass) that should be used to extract - tests from the files. - - encoding - An encoding that will be used to convert the files to unicode. - """ - suite = unittest.TestSuite() - - # We do this here so that _normalize_module is called at the right - # level. If it were called in DocFileTest, then this function - # would be the caller and we might guess the package incorrectly. - if kw.get('module_relative', True): - kw['package'] = _normalize_module(kw.get('package')) - - for path in paths: - suite.addTest(DocFileTest(path, **kw)) - - return suite - -###################################################################### -## 9. Debugging Support -###################################################################### - -def script_from_examples(s): - r"""Extract script from text with examples. - - Converts text with examples to a Python script. Example input is - converted to regular code. Example output and all other words - are converted to comments: - - >>> text = ''' - ... Here are examples of simple math. - ... - ... Python has super accurate integer addition - ... - ... >>> 2 + 2 - ... 5 - ... - ... And very friendly error messages: - ... - ... >>> 1/0 - ... To Infinity - ... And - ... Beyond - ... - ... You can use logic if you want: - ... - ... >>> if 0: - ... ... blah - ... ... blah - ... ... - ... - ... Ho hum - ... ''' - - >>> print script_from_examples(text) - # Here are examples of simple math. - # - # Python has super accurate integer addition - # - 2 + 2 - # Expected: - ## 5 - # - # And very friendly error messages: - # - 1/0 - # Expected: - ## To Infinity - ## And - ## Beyond - # - # You can use logic if you want: - # - if 0: - blah - blah - # - # Ho hum - """ - output = [] - for piece in DocTestParser().parse(s): - if isinstance(piece, Example): - # Add the example's source code (strip trailing NL) - output.append(piece.source[:-1]) - # Add the expected output: - want = piece.want - if want: - output.append('# Expected:') - output += ['## '+l for l in want.split('\n')[:-1]] - else: - # Add non-example text. - output += [_comment_line(l) - for l in piece.split('\n')[:-1]] - - # Trim junk on both ends. - while output and output[-1] == '#': - output.pop() - while output and output[0] == '#': - output.pop(0) - # Combine the output, and return it. - return '\n'.join(output) - -def testsource(module, name): - """Extract the test sources from a doctest docstring as a script. - - Provide the module (or dotted name of the module) containing the - test to be debugged and the name (within the module) of the object - with the doc string with tests to be debugged. - """ - module = _normalize_module(module) - tests = DocTestFinder().find(module) - test = [t for t in tests if t.name == name] - if not test: - raise ValueError(name, "not found in tests") - test = test[0] - testsrc = script_from_examples(test.docstring) - return testsrc - -def debug_src(src, pm=False, globs=None): - """Debug a single doctest docstring, in argument `src`'""" - testsrc = script_from_examples(src) - debug_script(testsrc, pm, globs) - -def debug_script(src, pm=False, globs=None): - "Debug a test script. `src` is the script, as a string." - import pdb - - # Note that tempfile.NameTemporaryFile() cannot be used. As the - # docs say, a file so created cannot be opened by name a second time - # on modern Windows boxes, and execfile() needs to open it. - srcfilename = tempfile.mktemp(".py", "doctestdebug") - f = open(srcfilename, 'w') - f.write(src) - f.close() - - try: - if globs: - globs = globs.copy() - else: - globs = {} - - if pm: - try: - execfile(srcfilename, globs, globs) - except: - print sys.exc_info()[1] - pdb.post_mortem(sys.exc_info()[2]) - else: - # Note that %r is vital here. '%s' instead can, e.g., cause - # backslashes to get treated as metacharacters on Windows. - pdb.run("execfile(%r)" % srcfilename, globs, globs) - - finally: - os.remove(srcfilename) - -def debug(module, name, pm=False): - """Debug a single doctest docstring. - - Provide the module (or dotted name of the module) containing the - test to be debugged and the name (within the module) of the object - with the docstring with tests to be debugged. - """ - module = _normalize_module(module) - testsrc = testsource(module, name) - debug_script(testsrc, pm, module.__dict__) - -###################################################################### -## 10. Example Usage -###################################################################### -class _TestClass: - """ - A pointless class, for sanity-checking of docstring testing. - - Methods: - square() - get() - - >>> _TestClass(13).get() + _TestClass(-12).get() - 1 - >>> hex(_TestClass(13).square().get()) - '0xa9' - """ - - def __init__(self, val): - """val -> _TestClass object with associated value val. - - >>> t = _TestClass(123) - >>> print t.get() - 123 - """ - - self.val = val - - def square(self): - """square() -> square TestClass's associated value - - >>> _TestClass(13).square().get() - 169 - """ - - self.val = self.val ** 2 - return self - - def get(self): - """get() -> return TestClass's associated value. - - >>> x = _TestClass(-42) - >>> print x.get() - -42 - """ - - return self.val - -__test__ = {"_TestClass": _TestClass, - "string": r""" - Example of a string object, searched as-is. - >>> x = 1; y = 2 - >>> x + y, x * y - (3, 2) - """, - - "bool-int equivalence": r""" - In 2.2, boolean expressions displayed - 0 or 1. By default, we still accept - them. This can be disabled by passing - DONT_ACCEPT_TRUE_FOR_1 to the new - optionflags argument. - >>> 4 == 4 - 1 - >>> 4 == 4 - True - >>> 4 > 4 - 0 - >>> 4 > 4 - False - """, - - "blank lines": r""" - Blank lines can be marked with : - >>> print 'foo\n\nbar\n' - foo - - bar - - """, - - "ellipsis": r""" - If the ellipsis flag is used, then '...' can be used to - elide substrings in the desired output: - >>> print range(1000) #doctest: +ELLIPSIS - [0, 1, 2, ..., 999] - """, - - "whitespace normalization": r""" - If the whitespace normalization flag is used, then - differences in whitespace are ignored. - >>> print range(30) #doctest: +NORMALIZE_WHITESPACE - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, - 27, 28, 29] - """, - } - -def _test(): - r = unittest.TextTestRunner() - r.run(DocTestSuite()) - -if __name__ == "__main__": - _test() diff --git a/tools/buildbot/pylibs/zope/testing/doctestunit.py b/tools/buildbot/pylibs/zope/testing/doctestunit.py deleted file mode 100644 index 6f1e4a7..0000000 --- a/tools/buildbot/pylibs/zope/testing/doctestunit.py +++ /dev/null @@ -1,33 +0,0 @@ -############################################################################## -# -# Copyright (c) 2003 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Extension to use doctest tests as unit tests - -This module provides a DocTestSuite contructor for converting doctest -tests to unit tests. - -$Id: doctestunit.py 28304 2004-10-31 17:59:45Z jim $ -""" - -from doctest import DocFileSuite, DocTestSuite -from doctest import debug_src, debug - -def pprint(): - from pprint import PrettyPrinter - def pprint(ob, **opts): - if 'width' not in opts: - opts['width'] = 1 - return PrettyPrinter(**opts).pprint(ob) - return pprint - -pprint = pprint() diff --git a/tools/buildbot/pylibs/zope/testing/formparser.py b/tools/buildbot/pylibs/zope/testing/formparser.py deleted file mode 100644 index efd9979..0000000 --- a/tools/buildbot/pylibs/zope/testing/formparser.py +++ /dev/null @@ -1,234 +0,0 @@ -"""HTML parser that extracts form information. - -This is intended to support functional tests that need to extract -information from HTML forms returned by the publisher. - -See *formparser.txt* for documentation. - -This isn't intended to simulate a browser session; that's provided by -the `zope.testbrowser` package. - -""" -__docformat__ = "reStructuredText" - -import HTMLParser -import urlparse - - -def parse(data, base=None): - """Return a form collection parsed from `data`. - - `base` should be the URL from which `data` was retrieved. - - """ - parser = FormParser(data, base) - return parser.parse() - - -class FormParser(object): - - def __init__(self, data, base=None): - self.data = data - self.base = base - self._parser = HTMLParser.HTMLParser() - self._parser.handle_data = self._handle_data - self._parser.handle_endtag = self._handle_endtag - self._parser.handle_starttag = self._handle_starttag - self._parser.handle_startendtag = self._handle_starttag - self._buffer = [] - self.current = None # current form - self.forms = FormCollection() - - def parse(self): - """Parse the document, returning the collection of forms.""" - self._parser.feed(self.data) - self._parser.close() - return self.forms - - # HTMLParser handlers - - def _handle_data(self, data): - self._buffer.append(data) - - def _handle_endtag(self, tag): - if tag == "textarea": - self.textarea.value = "".join(self._buffer) - self.textarea = None - elif tag == "select": - self.select = None - elif tag == "option": - option = self.select.options[-1] - label = "".join(self._buffer) - if not option.label: - option.label = label - if not option.value: - option.value = label - if option.selected: - if self.select.multiple: - self.select.value.append(option.value) - else: - self.select.value = option.value - - def _handle_starttag(self, tag, attrs): - del self._buffer[:] - d = {} - for name, value in attrs: - d[name] = value - name = d.get("name") - id = d.get("id") or d.get("xml:id") - if tag == "form": - method = kwattr(d, "method", "get") - action = d.get("action", "").strip() or None - if self.base and action: - action = urlparse.urljoin(self.base, action) - enctype = kwattr(d, "enctype", "application/x-www-form-urlencoded") - self.current = Form(name, id, method, action, enctype) - self.forms.append(self.current) - elif tag == "input": - type = kwattr(d, "type", "text") - checked = "checked" in d - disabled = "disabled" in d - readonly = "readonly" in d - src = d.get("src", "").strip() or None - if self.base and src: - src = urlparse.urljoin(self.base, src) - value = d.get("value") - size = intattr(d, "size") - maxlength = intattr(d, "maxlength") - self._add_field( - Input(name, id, type, value, checked, - disabled, readonly, src, size, maxlength)) - elif tag == "button": - pass - elif tag == "textarea": - disabled = "disabled" in d - readonly = "readonly" in d - self.textarea = Input(name, id, "textarea", None, - None, disabled, readonly, - None, None, None) - self.textarea.rows = intattr(d, "rows") - self.textarea.cols = intattr(d, "cols") - self._add_field(self.textarea) - # The value will be set when the is seen. - elif tag == "base": - href = d.get("href", "").strip() - if href and self.base: - href = urlparse.urljoin(self.base, href) - self.base = href - elif tag == "select": - disabled = "disabled" in d - multiple = "multiple" in d - size = intattr(d, "size") - self.select = Select(name, id, disabled, multiple, size) - self._add_field(self.select) - elif tag == "option": - disabled = "disabled" in d - selected = "selected" in d - value = d.get("value") - label = d.get("label") - option = Option(id, value, selected, label, disabled) - self.select.options.append(option) - - # Helpers: - - def _add_field(self, field): - if field.name in self.current: - ob = self.current[field.name] - if isinstance(ob, list): - ob.append(field) - else: - self.current[field.name] = [ob, field] - else: - self.current[field.name] = field - - -def kwattr(d, name, default=None): - """Return attribute, converted to lowercase.""" - v = d.get(name, default) - if v != default and v is not None: - v = v.strip().lower() - v = v or default - return v - - -def intattr(d, name): - """Return attribute as an integer, or None.""" - if name in d: - v = d[name].strip() - return int(v) - else: - return None - - -class FormCollection(list): - """Collection of all forms from a page.""" - - def __getattr__(self, name): - for form in self: - if form.name == name: - return form - raise AttributeError(name) - - -class Form(dict): - """A specific form within a page.""" - - # This object should provide some method to prepare a dictionary - # that can be passed directly as the value of the `form` argument - # to the `http()` function of the Zope functional test. - # - # This is probably a low priority given the availability of the - # `zope.testbrowser` package. - - def __init__(self, name, id, method, action, enctype): - super(Form, self).__init__() - self.name = name - self.id = id - self.method = method - self.action = action - self.enctype = enctype - - -class Input(object): - """Input element.""" - - rows = None - cols = None - - def __init__(self, name, id, type, value, checked, disabled, readonly, - src, size, maxlength): - super(Input, self).__init__() - self.name = name - self.id = id - self.type = type - self.value = value - self.checked = checked - self.disabled = disabled - self.readonly = readonly - self.src = src - self.size = size - self.maxlength = maxlength - - -class Select(Input): - """Select element.""" - - def __init__(self, name, id, disabled, multiple, size): - super(Select, self).__init__(name, id, "select", None, None, - disabled, None, None, size, None) - self.options = [] - self.multiple = multiple - if multiple: - self.value = [] - - -class Option(object): - """Individual value representation for a select element.""" - - def __init__(self, id, value, selected, label, disabled): - super(Option, self).__init__() - self.id = id - self.value = value - self.selected = selected - self.label = label - self.disabled = disabled diff --git a/tools/buildbot/pylibs/zope/testing/formparser.txt b/tools/buildbot/pylibs/zope/testing/formparser.txt deleted file mode 100644 index 727506e..0000000 --- a/tools/buildbot/pylibs/zope/testing/formparser.txt +++ /dev/null @@ -1,143 +0,0 @@ -================== -Parsing HTML Forms -================== - -Sometimes in functional tests, information from a generated form must -be extracted in order to re-submit it as part of a subsequent request. -The `zope.testing.formparser` module can be used for this purpose. - -The scanner is implemented using the `FormParser` class. The -constructor arguments are the page data containing the form and -(optionally) the URL from which the page was retrieved: - - >>> import zope.testing.formparser - - >>> page_text = '''\ - ... - ...
                    - ... - ... - ... - ... - ...
                    - ... - ... Just for fun, a second form, after specifying a base: - ... - ...
                    - ... - ... - ... - ... - ...
                    - ... - ... ''' - - >>> parser = zope.testing.formparser.FormParser(page_text) - >>> forms = parser.parse() - - >>> len(forms) - 2 - >>> forms.form1 is forms[0] - True - >>> forms.form1 is forms[1] - False - -More often, the `parse()` convenience function is all that's needed: - - >>> forms = zope.testing.formparser.parse( - ... page_text, "http://cgi.example.com/somewhere/form.html") - - >>> len(forms) - 2 - >>> forms.form1 is forms[0] - True - >>> forms.form1 is forms[1] - False - -Once we have the form we're interested in, we can check form -attributes and individual field values: - - >>> form = forms.form1 - >>> form.enctype - 'application/x-www-form-urlencoded' - >>> form.method - 'post' - - >>> keys = form.keys() - >>> keys.sort() - >>> keys - ['do-it-now', 'f1', 'not-really', 'pick-two'] - - >>> not_really = form["not-really"] - >>> not_really.type - 'image' - >>> not_really.value - "Don't." - >>> not_really.readonly - False - >>> not_really.disabled - False - -Note that relative URLs are converted to absolute URLs based on the -```` element (if present) or using the base passed in to the -constructor. - - >>> form.action - 'http://cgi.example.com/cgi-bin/foobar.py' - >>> not_really.src - 'http://cgi.example.com/somewhere/dont.png' - - >>> forms[1].action - 'http://www.example.com/base/sproing/sprung.html' - >>> forms[1]["action"].src - 'http://www.example.com/base/else.png' - -Fields which are repeated are reported as lists of objects that -represent each instance of the field:: - - >>> field = forms[1]["multi"] - >>> type(field) - - >>> [o.value for o in field] - ['', ''] - >>> [o.size for o in field] - [2, 3] - -The ``