diff options
author | Jacek Antonelli | 2009-05-30 17:16:26 -0500 |
---|---|---|
committer | Jacek Antonelli | 2009-05-30 19:12:37 -0500 |
commit | 499afbab7be4c4136eea0e1897319c3ac4e9799d (patch) | |
tree | 95e9de524994eae69b0dd88b8c6608d5f45d030c /linden/indra/lib | |
parent | Fixed end-of-line style for Info-Imprudence.plist. (diff) | |
parent | Second Life viewer sources 1.22.11 (diff) | |
download | meta-impy-499afbab7be4c4136eea0e1897319c3ac4e9799d.zip meta-impy-499afbab7be4c4136eea0e1897319c3ac4e9799d.tar.gz meta-impy-499afbab7be4c4136eea0e1897319c3ac4e9799d.tar.bz2 meta-impy-499afbab7be4c4136eea0e1897319c3ac4e9799d.tar.xz |
Merged SL 1.22.11 into Imprudence 1.1 RC2.
Conflicts:
linden/doc/contributions.txt
linden/indra/cmake/APR.cmake
linden/indra/cmake/CopyWinLibs.cmake
linden/indra/cmake/LLKDU.cmake (removed)
linden/indra/cmake/LLMedia.cmake
linden/indra/cmake/OPENAL.cmake
linden/indra/cmake/QuickTime.cmake (removed)
linden/indra/develop.py
linden/indra/lib/python/indra/base/llsd.py
linden/indra/lib/python/indra/util/fastest_elementtree.py
linden/indra/lib/python/indra/util/llmanifest.py
linden/indra/lib/python/indra/util/named_query.py
linden/indra/llaudio/CMakeLists.txt
linden/indra/llaudio/audioengine.cpp
linden/indra/llaudio/audioengine.h
linden/indra/llaudio/audioengine_fmod.cpp
linden/indra/llaudio/audioengine_fmod.h
linden/indra/llaudio/audioengine_openal.cpp
linden/indra/llaudio/audioengine_openal.h
linden/indra/llaudio/listener_openal.cpp
linden/indra/llaudio/listener_openal.h
linden/indra/llaudio/windgen.h
linden/indra/llcrashlogger/llcrashlogger.cpp
linden/indra/llmedia/llmediaimplgstreamer.cpp
linden/indra/llmedia/llmediaimplgstreamer_syms.cpp (removed)
linden/indra/llmedia/llmediaimplgstreamer_syms.h (removed)
linden/indra/llmessage/llcircuit.h
linden/indra/llrender/llgl.cpp
linden/indra/llrender/llrender.h
linden/indra/llui/llfloater.cpp
linden/indra/llui/lltexteditor.cpp
linden/indra/llwindow/llwindowsdl.cpp
linden/indra/mac_crash_logger/CMakeLists.txt
linden/indra/mac_updater/CMakeLists.txt
linden/indra/newview/CMakeLists.txt
linden/indra/newview/English.lproj/InfoPlist.strings
linden/indra/newview/Info-Imprudence.plist
linden/indra/newview/installers/windows/installer_template.nsi
linden/indra/newview/installers/windows/lang_de.nsi
linden/indra/newview/installers/windows/lang_en-us.nsi
linden/indra/newview/installers/windows/lang_ja.nsi
linden/indra/newview/installers/windows/lang_ko.nsi
linden/indra/newview/llappviewer.cpp
linden/indra/newview/llaudiosourcevo.cpp
linden/indra/newview/llfloaterabout.cpp
linden/indra/newview/llfloaterhtml.cpp
linden/indra/newview/llfloaterhtml.h
linden/indra/newview/llfloaterinspect.cpp
linden/indra/newview/llfloatersnapshot.cpp
linden/indra/newview/llpanelgeneral.cpp
linden/indra/newview/llpanelgeneral.h
linden/indra/newview/llpanellogin.cpp
linden/indra/newview/llpanelobject.cpp
linden/indra/newview/llurlhistory.cpp
linden/indra/newview/llviewermenu.cpp
linden/indra/newview/llviewernetwork.cpp
linden/indra/newview/llviewernetwork.h
linden/indra/newview/llviewerobject.cpp
linden/indra/newview/llviewerwindow.cpp
linden/indra/newview/llvoavatar.cpp
linden/indra/newview/res/viewerRes.rc
linden/indra/newview/skins/default/xui/de/floater_env_settings.xml
linden/indra/newview/skins/default/xui/de/floater_html.xml
linden/indra/newview/skins/default/xui/de/floater_inspect.xml
linden/indra/newview/skins/default/xui/de/floater_instant_message_group.xml
linden/indra/newview/skins/default/xui/de/floater_lagmeter.xml
linden/indra/newview/skins/default/xui/de/floater_lsl_guide.xml
linden/indra/newview/skins/default/xui/de/floater_url_entry.xml
linden/indra/newview/skins/default/xui/de/floater_water.xml
linden/indra/newview/skins/default/xui/de/mime_types.xml
linden/indra/newview/skins/default/xui/de/need_to_long.xml
linden/indra/newview/skins/default/xui/de/need_to_translate.xml
linden/indra/newview/skins/default/xui/de/need_to_update.xml
linden/indra/newview/skins/default/xui/de/panel_friends.xml
linden/indra/newview/skins/default/xui/de/panel_media_remote_expanded.xml
linden/indra/newview/skins/default/xui/de/panel_preferences_voice.xml
linden/indra/newview/skins/default/xui/de/panel_voice_controls.xml
linden/indra/newview/skins/default/xui/de/panel_voice_enable.xml
linden/indra/newview/skins/default/xui/de/panel_voice_options.xml
linden/indra/newview/skins/default/xui/de/strings.xml
linden/indra/newview/skins/default/xui/en-us/floater_chat_history.xml
linden/indra/newview/skins/default/xui/en-us/floater_instant_message_ad_hoc.xml
linden/indra/newview/skins/default/xui/en-us/floater_instant_message_group.xml
linden/indra/newview/skins/default/xui/en-us/floater_lagmeter.xml
linden/indra/newview/skins/default/xui/en-us/menu_pie_object.xml
linden/indra/newview/skins/default/xui/en-us/menu_viewer.xml
linden/indra/newview/skins/default/xui/en-us/panel_audio_device.xml
linden/indra/newview/skins/default/xui/en-us/panel_preferences_general.xml
linden/indra/newview/skins/default/xui/en-us/panel_preferences_input.xml
linden/indra/newview/skins/default/xui/en-us/panel_preferences_voice.xml
linden/indra/newview/skins/default/xui/en-us/panel_voice_remote.xml
linden/indra/newview/skins/default/xui/en-us/panel_voice_remote_expanded.xml
linden/indra/newview/skins/default/xui/es/alerts.xml
linden/indra/newview/skins/default/xui/es/floater_about_land.xml
linden/indra/newview/skins/default/xui/es/floater_mute.xml
linden/indra/newview/skins/default/xui/es/menu_viewer.xml
linden/indra/newview/skins/default/xui/es/panel_group_land_money.xml
linden/indra/newview/skins/default/xui/es/panel_preferences_general.xml
linden/indra/newview/skins/default/xui/fr/alerts.xml
linden/indra/newview/skins/default/xui/fr/floater_about.xml
linden/indra/newview/skins/default/xui/fr/floater_about_land.xml
linden/indra/newview/skins/default/xui/fr/floater_active_speakers.xml
linden/indra/newview/skins/default/xui/fr/floater_animation_preview.xml
linden/indra/newview/skins/default/xui/fr/floater_avatar_picker.xml
linden/indra/newview/skins/default/xui/fr/floater_avatar_textures.xml
linden/indra/newview/skins/default/xui/fr/floater_buy_contents.xml
linden/indra/newview/skins/default/xui/fr/floater_buy_currency.xml
linden/indra/newview/skins/default/xui/fr/floater_buy_land.xml
linden/indra/newview/skins/default/xui/fr/floater_buy_object.xml
linden/indra/newview/skins/default/xui/fr/floater_chat_history.xml
linden/indra/newview/skins/default/xui/fr/floater_color_picker.xml
linden/indra/newview/skins/default/xui/fr/floater_customize.xml
linden/indra/newview/skins/default/xui/fr/floater_directory.xml
linden/indra/newview/skins/default/xui/fr/floater_env_settings.xml
linden/indra/newview/skins/default/xui/fr/floater_god_tools.xml
linden/indra/newview/skins/default/xui/fr/floater_group_info.xml
linden/indra/newview/skins/default/xui/fr/floater_hardware_settings.xml
linden/indra/newview/skins/default/xui/fr/floater_html.xml
linden/indra/newview/skins/default/xui/fr/floater_image_preview.xml
linden/indra/newview/skins/default/xui/fr/floater_import.xml
linden/indra/newview/skins/default/xui/fr/floater_instant_message.xml
linden/indra/newview/skins/default/xui/fr/floater_instant_message_ad_hoc.xml
linden/indra/newview/skins/default/xui/fr/floater_instant_message_group.xml
linden/indra/newview/skins/default/xui/fr/floater_inventory.xml
linden/indra/newview/skins/default/xui/fr/floater_inventory_item_properties.xml
linden/indra/newview/skins/default/xui/fr/floater_inventory_view_finder.xml
linden/indra/newview/skins/default/xui/fr/floater_joystick.xml
linden/indra/newview/skins/default/xui/fr/floater_lagmeter.xml
linden/indra/newview/skins/default/xui/fr/floater_land_holdings.xml
linden/indra/newview/skins/default/xui/fr/floater_lsl_guide.xml
linden/indra/newview/skins/default/xui/fr/floater_media_browser.xml
linden/indra/newview/skins/default/xui/fr/floater_moveview.xml
linden/indra/newview/skins/default/xui/fr/floater_mute.xml
linden/indra/newview/skins/default/xui/fr/floater_mute_object.xml
linden/indra/newview/skins/default/xui/fr/floater_name_description.xml
linden/indra/newview/skins/default/xui/fr/floater_new_outfit_dialog.xml
linden/indra/newview/skins/default/xui/fr/floater_openobject.xml
linden/indra/newview/skins/default/xui/fr/floater_pay.xml
linden/indra/newview/skins/default/xui/fr/floater_pay_object.xml
linden/indra/newview/skins/default/xui/fr/floater_preferences.xml
linden/indra/newview/skins/default/xui/fr/floater_preview_animation.xml
linden/indra/newview/skins/default/xui/fr/floater_preview_gesture.xml
linden/indra/newview/skins/default/xui/fr/floater_preview_notecard.xml
linden/indra/newview/skins/default/xui/fr/floater_preview_notecard_keep_discard.xml
linden/indra/newview/skins/default/xui/fr/floater_preview_sound.xml
linden/indra/newview/skins/default/xui/fr/floater_price_for_listing.xml
linden/indra/newview/skins/default/xui/fr/floater_region_info.xml
linden/indra/newview/skins/default/xui/fr/floater_report_abuse.xml
linden/indra/newview/skins/default/xui/fr/floater_report_bug.xml
linden/indra/newview/skins/default/xui/fr/floater_script_ed_panel.xml
linden/indra/newview/skins/default/xui/fr/floater_sell_land.xml
linden/indra/newview/skins/default/xui/fr/floater_settings_debug.xml
linden/indra/newview/skins/default/xui/fr/floater_skin_preview_template.xml
linden/indra/newview/skins/default/xui/fr/floater_snapshot.xml
linden/indra/newview/skins/default/xui/fr/floater_sound_preview.xml
linden/indra/newview/skins/default/xui/fr/floater_telehub.xml
linden/indra/newview/skins/default/xui/fr/floater_texture_ctrl.xml
linden/indra/newview/skins/default/xui/fr/floater_tools.xml
linden/indra/newview/skins/default/xui/fr/floater_top_objects.xml
linden/indra/newview/skins/default/xui/fr/floater_url_entry.xml
linden/indra/newview/skins/default/xui/fr/floater_windlight_options.xml
linden/indra/newview/skins/default/xui/fr/floater_world_map.xml
linden/indra/newview/skins/default/xui/fr/menu_inventory.xml
linden/indra/newview/skins/default/xui/fr/menu_pie_avatar.xml
linden/indra/newview/skins/default/xui/fr/menu_pie_land.xml
linden/indra/newview/skins/default/xui/fr/menu_pie_self.xml
linden/indra/newview/skins/default/xui/fr/menu_viewer.xml
linden/indra/newview/skins/default/xui/fr/mime_types.xml
linden/indra/newview/skins/default/xui/fr/notify.xml
linden/indra/newview/skins/default/xui/fr/panel_audio.xml
linden/indra/newview/skins/default/xui/fr/panel_audio_device.xml
linden/indra/newview/skins/default/xui/fr/panel_avatar.xml
linden/indra/newview/skins/default/xui/fr/panel_avatar_classified.xml
linden/indra/newview/skins/default/xui/fr/panel_chat_bar.xml
linden/indra/newview/skins/default/xui/fr/panel_classified.xml
linden/indra/newview/skins/default/xui/fr/panel_event.xml
linden/indra/newview/skins/default/xui/fr/panel_friends.xml
linden/indra/newview/skins/default/xui/fr/panel_group.xml
linden/indra/newview/skins/default/xui/fr/panel_group_finder.xml
linden/indra/newview/skins/default/xui/fr/panel_group_general.xml
linden/indra/newview/skins/default/xui/fr/panel_group_invite.xml
linden/indra/newview/skins/default/xui/fr/panel_group_land_money.xml
linden/indra/newview/skins/default/xui/fr/panel_group_notices.xml
linden/indra/newview/skins/default/xui/fr/panel_group_roles.xml
linden/indra/newview/skins/default/xui/fr/panel_group_voting.xml
linden/indra/newview/skins/default/xui/fr/panel_groups.xml
linden/indra/newview/skins/default/xui/fr/panel_login.xml
linden/indra/newview/skins/default/xui/fr/panel_master_volume.xml
linden/indra/newview/skins/default/xui/fr/panel_media_controls.xml
linden/indra/newview/skins/default/xui/fr/panel_media_remote.xml
linden/indra/newview/skins/default/xui/fr/panel_media_remote_expanded.xml
linden/indra/newview/skins/default/xui/fr/panel_overlaybar.xml
linden/indra/newview/skins/default/xui/fr/panel_place.xml
linden/indra/newview/skins/default/xui/fr/panel_place_small.xml
linden/indra/newview/skins/default/xui/fr/panel_preferences_audio.xml
linden/indra/newview/skins/default/xui/fr/panel_preferences_chat.xml
linden/indra/newview/skins/default/xui/fr/panel_preferences_general.xml
linden/indra/newview/skins/default/xui/fr/panel_preferences_graphics1.xml
linden/indra/newview/skins/default/xui/fr/panel_preferences_im.xml
linden/indra/newview/skins/default/xui/fr/panel_preferences_input.xml
linden/indra/newview/skins/default/xui/fr/panel_preferences_network.xml
linden/indra/newview/skins/default/xui/fr/panel_preferences_popups.xml
linden/indra/newview/skins/default/xui/fr/panel_preferences_voice.xml
linden/indra/newview/skins/default/xui/fr/panel_preferences_web.xml
linden/indra/newview/skins/default/xui/fr/panel_region_covenant.xml
linden/indra/newview/skins/default/xui/fr/panel_region_debug.xml
linden/indra/newview/skins/default/xui/fr/panel_region_estate.xml
linden/indra/newview/skins/default/xui/fr/panel_region_general.xml
linden/indra/newview/skins/default/xui/fr/panel_region_terrain.xml
linden/indra/newview/skins/default/xui/fr/panel_scrolling_param.xml
linden/indra/newview/skins/default/xui/fr/panel_speaker_controls.xml
linden/indra/newview/skins/default/xui/fr/panel_status_bar.xml
linden/indra/newview/skins/default/xui/fr/panel_toolbar.xml
linden/indra/newview/skins/default/xui/fr/panel_voice_controls.xml
linden/indra/newview/skins/default/xui/fr/panel_voice_enable.xml
linden/indra/newview/skins/default/xui/fr/panel_voice_options.xml
linden/indra/newview/skins/default/xui/fr/panel_voice_remote_expanded.xml
linden/indra/newview/skins/default/xui/fr/role_actions.xml
linden/indra/newview/skins/default/xui/fr/strings.xml
linden/indra/newview/skins/default/xui/ja/floater_hardware_settings.xml
linden/indra/newview/skins/default/xui/ja/floater_inspect.xml
linden/indra/newview/skins/default/xui/ja/floater_instant_message_group.xml
linden/indra/newview/skins/default/xui/ja/floater_lsl_guide.xml
linden/indra/newview/skins/default/xui/ja/floater_media_browser.xml
linden/indra/newview/skins/default/xui/ja/floater_mute_object.xml
linden/indra/newview/skins/default/xui/ja/floater_url_entry.xml
linden/indra/newview/skins/default/xui/ja/need_to_long.xml
linden/indra/newview/skins/default/xui/ja/need_to_translate.xml
linden/indra/newview/skins/default/xui/ja/need_to_update.xml
linden/indra/newview/skins/default/xui/ja/panel_audio.xml
linden/indra/newview/skins/default/xui/ja/panel_groups.xml
linden/indra/newview/skins/default/xui/ja/panel_preferences_voice.xml
linden/indra/newview/skins/default/xui/ja/panel_preferences_web.xml
linden/indra/newview/skins/default/xui/ja/strings.xml
linden/indra/newview/skins/default/xui/ko/need_to_long.xml
linden/indra/newview/skins/default/xui/ko/need_to_translate.xml
linden/indra/newview/skins/default/xui/ko/need_to_update.xml
linden/indra/newview/skins/default/xui/pt/alerts.xml
linden/indra/newview/skins/default/xui/pt/floater_about.xml
linden/indra/newview/skins/default/xui/pt/floater_about_land.xml
linden/indra/newview/skins/default/xui/pt/floater_animation_preview.xml
linden/indra/newview/skins/default/xui/pt/floater_avatar_picker.xml
linden/indra/newview/skins/default/xui/pt/floater_avatar_textures.xml
linden/indra/newview/skins/default/xui/pt/floater_build_options.xml
linden/indra/newview/skins/default/xui/pt/floater_buy_contents.xml
linden/indra/newview/skins/default/xui/pt/floater_buy_currency.xml
linden/indra/newview/skins/default/xui/pt/floater_buy_land.xml
linden/indra/newview/skins/default/xui/pt/floater_buy_object.xml
linden/indra/newview/skins/default/xui/pt/floater_chat_history.xml
linden/indra/newview/skins/default/xui/pt/floater_color_picker.xml
linden/indra/newview/skins/default/xui/pt/floater_customize.xml
linden/indra/newview/skins/default/xui/pt/floater_directory.xml
linden/indra/newview/skins/default/xui/pt/floater_gesture.xml
linden/indra/newview/skins/default/xui/pt/floater_html.xml
linden/indra/newview/skins/default/xui/pt/floater_im.xml
linden/indra/newview/skins/default/xui/pt/floater_image_preview.xml
linden/indra/newview/skins/default/xui/pt/floater_instant_message.xml
linden/indra/newview/skins/default/xui/pt/floater_instant_message_ad_hoc.xml
linden/indra/newview/skins/default/xui/pt/floater_inventory.xml
linden/indra/newview/skins/default/xui/pt/floater_inventory_item_properties.xml
linden/indra/newview/skins/default/xui/pt/floater_joystick.xml
linden/indra/newview/skins/default/xui/pt/floater_land_holdings.xml
linden/indra/newview/skins/default/xui/pt/floater_live_lsleditor.xml
linden/indra/newview/skins/default/xui/pt/floater_mute.xml
linden/indra/newview/skins/default/xui/pt/floater_new_outfit_dialog.xml
linden/indra/newview/skins/default/xui/pt/floater_openobject.xml
linden/indra/newview/skins/default/xui/pt/floater_pay.xml
linden/indra/newview/skins/default/xui/pt/floater_pay_object.xml
linden/indra/newview/skins/default/xui/pt/floater_postcard.xml
linden/indra/newview/skins/default/xui/pt/floater_preview_animation.xml
linden/indra/newview/skins/default/xui/pt/floater_preview_gesture.xml
linden/indra/newview/skins/default/xui/pt/floater_preview_notecard.xml
linden/indra/newview/skins/default/xui/pt/floater_preview_notecard_keep_discard.xml
linden/indra/newview/skins/default/xui/pt/floater_report_abuse.xml
linden/indra/newview/skins/default/xui/pt/floater_report_bug.xml
linden/indra/newview/skins/default/xui/pt/floater_script_debug.xml
linden/indra/newview/skins/default/xui/pt/floater_script_ed_panel.xml
linden/indra/newview/skins/default/xui/pt/floater_snapshot.xml
linden/indra/newview/skins/default/xui/pt/floater_texture_ctrl.xml
linden/indra/newview/skins/default/xui/pt/floater_tools.xml
linden/indra/newview/skins/default/xui/pt/floater_top_objects.xml
linden/indra/newview/skins/default/xui/pt/floater_tos.xml
linden/indra/newview/skins/default/xui/pt/floater_world_map.xml
linden/indra/newview/skins/default/xui/pt/menu_inventory.xml
linden/indra/newview/skins/default/xui/pt/menu_pie_avatar.xml
linden/indra/newview/skins/default/xui/pt/menu_viewer.xml
linden/indra/newview/skins/default/xui/pt/notify.xml
linden/indra/newview/skins/default/xui/pt/panel_avatar.xml
linden/indra/newview/skins/default/xui/pt/panel_avatar_classified.xml
linden/indra/newview/skins/default/xui/pt/panel_chat_bar.xml
linden/indra/newview/skins/default/xui/pt/panel_classified.xml
linden/indra/newview/skins/default/xui/pt/panel_event.xml
linden/indra/newview/skins/default/xui/pt/panel_group_general.xml
linden/indra/newview/skins/default/xui/pt/panel_group_invite.xml
linden/indra/newview/skins/default/xui/pt/panel_group_land_money.xml
linden/indra/newview/skins/default/xui/pt/panel_group_notices.xml
linden/indra/newview/skins/default/xui/pt/panel_group_roles.xml
linden/indra/newview/skins/default/xui/pt/panel_group_voting.xml
linden/indra/newview/skins/default/xui/pt/panel_login.xml
linden/indra/newview/skins/default/xui/pt/panel_overlaybar.xml
linden/indra/newview/skins/default/xui/pt/panel_place.xml
linden/indra/newview/skins/default/xui/pt/panel_place_small.xml
linden/indra/newview/skins/default/xui/pt/panel_preferences_audio.xml
linden/indra/newview/skins/default/xui/pt/panel_preferences_chat.xml
linden/indra/newview/skins/default/xui/pt/panel_preferences_general.xml
linden/indra/newview/skins/default/xui/pt/panel_preferences_graphics1.xml
linden/indra/newview/skins/default/xui/pt/panel_preferences_im.xml
linden/indra/newview/skins/default/xui/pt/panel_preferences_input.xml
linden/indra/newview/skins/default/xui/pt/panel_preferences_network.xml
linden/indra/newview/skins/default/xui/pt/panel_preferences_popups.xml
linden/indra/newview/skins/default/xui/pt/panel_preferences_web.xml
linden/indra/newview/skins/default/xui/pt/panel_region_covenant.xml
linden/indra/newview/skins/default/xui/pt/panel_region_debug.xml
linden/indra/newview/skins/default/xui/pt/panel_region_estate.xml
linden/indra/newview/skins/default/xui/pt/panel_region_general.xml
linden/indra/newview/skins/default/xui/pt/panel_status_bar.xml
linden/indra/newview/skins/default/xui/pt/panel_toolbar.xml
linden/indra/newview/skins/default/xui/pt/teleport_strings.xml
linden/indra/newview/skins/default/xui/zh/floater_account_history.xml
linden/indra/newview/skins/default/xui/zh/floater_god_tools.xml
linden/indra/newview/skins/default/xui/zh/floater_html.xml
linden/indra/newview/skins/default/xui/zh/floater_inspect.xml
linden/indra/newview/skins/default/xui/zh/floater_inventory_view_finder.xml
linden/indra/newview/skins/default/xui/zh/floater_preferences.xml
linden/indra/newview/skins/default/xui/zh/floater_sell_land.xml
linden/indra/newview/skins/default/xui/zh/floater_settings_debug.xml
linden/indra/newview/skins/default/xui/zh/menu_pie_attachment.xml
linden/indra/newview/skins/default/xui/zh/menu_pie_avatar.xml
linden/indra/newview/skins/default/xui/zh/menu_pie_land.xml
linden/indra/newview/skins/default/xui/zh/menu_pie_object.xml
linden/indra/newview/skins/default/xui/zh/menu_pie_self.xml
linden/indra/newview/skins/default/xui/zh/menu_viewer.xml
linden/indra/newview/skins/default/xui/zh/need_to_translate.xml
linden/indra/newview/skins/default/xui/zh/panel_account_details.xml
linden/indra/newview/skins/default/xui/zh/panel_account_planning.xml
linden/indra/newview/skins/default/xui/zh/panel_account_transactions.xml
linden/indra/newview/skins/default/xui/zh/panel_avatar.xml
linden/indra/newview/skins/default/xui/zh/panel_group.xml
linden/indra/newview/skins/default/xui/zh/panel_group_finder.xml
linden/indra/newview/skins/default/xui/zh/panel_group_general.xml
linden/indra/newview/skins/default/xui/zh/panel_group_invite.xml
linden/indra/newview/skins/default/xui/zh/panel_group_land_money.xml
linden/indra/newview/skins/default/xui/zh/panel_group_notices.xml
linden/indra/newview/skins/default/xui/zh/panel_group_roles.xml
linden/indra/newview/skins/default/xui/zh/panel_group_voting.xml
linden/indra/newview/skins/default/xui/zh/panel_preferences_audio.xml
linden/indra/newview/skins/default/xui/zh/panel_preferences_chat.xml
linden/indra/newview/skins/default/xui/zh/panel_preferences_im.xml
linden/indra/newview/skins/default/xui/zh/panel_preferences_popups.xml
linden/indra/newview/skins/default/xui/zh/panel_region_covenant.xml
linden/indra/newview/skins/default/xui/zh/strings.xml
linden/indra/newview/skins/default/xui/zh/strings_long.xml
linden/indra/newview/skins/silver/xui/en-us/floater_about_land.xml
linden/indra/newview/skins/silver/xui/en-us/panel_status_bar.xml
linden/indra/newview/viewer_manifest.py
linden/indra/win_updater/updater.cpp
linden/install.xml
Diffstat (limited to 'linden/indra/lib')
33 files changed, 993 insertions, 694 deletions
diff --git a/linden/indra/lib/python/indra/__init__.py b/linden/indra/lib/python/indra/__init__.py index b435e57..9daab34 100644 --- a/linden/indra/lib/python/indra/__init__.py +++ b/linden/indra/lib/python/indra/__init__.py | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | $LicenseInfo:firstyear=2006&license=internal$ | 5 | $LicenseInfo:firstyear=2006&license=internal$ |
6 | 6 | ||
7 | Copyright (c) 2006-2008, Linden Research, Inc. | 7 | Copyright (c) 2006-2009, Linden Research, Inc. |
8 | 8 | ||
9 | The following source code is PROPRIETARY AND CONFIDENTIAL. Use of | 9 | The following source code is PROPRIETARY AND CONFIDENTIAL. Use of |
10 | this source code is governed by the Linden Lab Source Code Disclosure | 10 | this source code is governed by the Linden Lab Source Code Disclosure |
diff --git a/linden/indra/lib/python/indra/base/__init__.py b/linden/indra/lib/python/indra/base/__init__.py index 46eabd7..2904fd3 100644 --- a/linden/indra/lib/python/indra/base/__init__.py +++ b/linden/indra/lib/python/indra/base/__init__.py | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | $LicenseInfo:firstyear=2007&license=mit$ | 5 | $LicenseInfo:firstyear=2007&license=mit$ |
6 | 6 | ||
7 | Copyright (c) 2007-2008, Linden Research, Inc. | 7 | Copyright (c) 2007-2009, Linden Research, Inc. |
8 | 8 | ||
9 | Permission is hereby granted, free of charge, to any person obtaining a copy | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | of this software and associated documentation files (the "Software"), to deal | 10 | of this software and associated documentation files (the "Software"), to deal |
diff --git a/linden/indra/lib/python/indra/base/config.py b/linden/indra/lib/python/indra/base/config.py index 9c37ecf..d6866fd 100644 --- a/linden/indra/lib/python/indra/base/config.py +++ b/linden/indra/lib/python/indra/base/config.py | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | $LicenseInfo:firstyear=2006&license=mit$ | 5 | $LicenseInfo:firstyear=2006&license=mit$ |
6 | 6 | ||
7 | Copyright (c) 2006-2008, Linden Research, Inc. | 7 | Copyright (c) 2006-2009, Linden Research, Inc. |
8 | 8 | ||
9 | Permission is hereby granted, free of charge, to any person obtaining a copy | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | of this software and associated documentation files (the "Software"), to deal | 10 | of this software and associated documentation files (the "Software"), to deal |
diff --git a/linden/indra/lib/python/indra/base/lllog.py b/linden/indra/lib/python/indra/base/lllog.py index 99c50ef..31000fc 100644 --- a/linden/indra/lib/python/indra/base/lllog.py +++ b/linden/indra/lib/python/indra/base/lllog.py | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | $LicenseInfo:firstyear=2008&license=mit$ | 5 | $LicenseInfo:firstyear=2008&license=mit$ |
6 | 6 | ||
7 | Copyright (c) 2008, Linden Research, Inc. | 7 | Copyright (c) 2008-2009, Linden Research, Inc. |
8 | 8 | ||
9 | Permission is hereby granted, free of charge, to any person obtaining a copy | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | of this software and associated documentation files (the "Software"), to deal | 10 | of this software and associated documentation files (the "Software"), to deal |
@@ -59,7 +59,7 @@ class Logger(object): | |||
59 | return self._sequence | 59 | return self._sequence |
60 | 60 | ||
61 | def log(self, msg, llsd): | 61 | def log(self, msg, llsd): |
62 | payload = 'LLLOGMESSAGE (%d) %s %s' % (self.next(), msg, | 62 | payload = 'INFO: log: LLLOGMESSAGE (%d) %s %s' % (self.next(), msg, |
63 | format_notation(llsd)) | 63 | format_notation(llsd)) |
64 | syslog.syslog(payload) | 64 | syslog.syslog(payload) |
65 | 65 | ||
diff --git a/linden/indra/lib/python/indra/base/llsd.py b/linden/indra/lib/python/indra/base/llsd.py index e6141b6..821a20b 100644 --- a/linden/indra/lib/python/indra/base/llsd.py +++ b/linden/indra/lib/python/indra/base/llsd.py | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | $LicenseInfo:firstyear=2006&license=mit$ | 5 | $LicenseInfo:firstyear=2006&license=mit$ |
6 | 6 | ||
7 | Copyright (c) 2006-2008, Linden Research, Inc. | 7 | Copyright (c) 2006-2009, Linden Research, Inc. |
8 | 8 | ||
9 | Permission is hereby granted, free of charge, to any person obtaining a copy | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | of this software and associated documentation files (the "Software"), to deal | 10 | of this software and associated documentation files (the "Software"), to deal |
@@ -36,13 +36,10 @@ import re | |||
36 | from indra.util.fastest_elementtree import ElementTreeError, fromstring | 36 | from indra.util.fastest_elementtree import ElementTreeError, fromstring |
37 | from indra.base import lluuid | 37 | from indra.base import lluuid |
38 | 38 | ||
39 | # cllsd.c in server/server-1.25 has memory leaks, | 39 | try: |
40 | # so disabling cllsd for now | 40 | import cllsd |
41 | #try: | 41 | except ImportError: |
42 | # import cllsd | 42 | cllsd = None |
43 | #except ImportError: | ||
44 | # cllsd = None | ||
45 | cllsd = None | ||
46 | 43 | ||
47 | int_regex = re.compile(r"[-+]?\d+") | 44 | int_regex = re.compile(r"[-+]?\d+") |
48 | real_regex = re.compile(r"[-+]?(\d+(\.\d*)?|\d*\.\d+)([eE][-+]?\d+)?") | 45 | real_regex = re.compile(r"[-+]?(\d+(\.\d*)?|\d*\.\d+)([eE][-+]?\d+)?") |
diff --git a/linden/indra/lib/python/indra/base/lluuid.py b/linden/indra/lib/python/indra/base/lluuid.py index 0756889..aceea29 100644 --- a/linden/indra/lib/python/indra/base/lluuid.py +++ b/linden/indra/lib/python/indra/base/lluuid.py | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | $LicenseInfo:firstyear=2004&license=mit$ | 5 | $LicenseInfo:firstyear=2004&license=mit$ |
6 | 6 | ||
7 | Copyright (c) 2004-2008, Linden Research, Inc. | 7 | Copyright (c) 2004-2009, Linden Research, Inc. |
8 | 8 | ||
9 | Permission is hereby granted, free of charge, to any person obtaining a copy | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | of this software and associated documentation files (the "Software"), to deal | 10 | of this software and associated documentation files (the "Software"), to deal |
diff --git a/linden/indra/lib/python/indra/base/metrics.py b/linden/indra/lib/python/indra/base/metrics.py index 04e6286..8f2a85c 100644 --- a/linden/indra/lib/python/indra/base/metrics.py +++ b/linden/indra/lib/python/indra/base/metrics.py | |||
@@ -6,7 +6,7 @@ | |||
6 | 6 | ||
7 | $LicenseInfo:firstyear=2007&license=mit$ | 7 | $LicenseInfo:firstyear=2007&license=mit$ |
8 | 8 | ||
9 | Copyright (c) 2007-2008, Linden Research, Inc. | 9 | Copyright (c) 2007-2009, Linden Research, Inc. |
10 | 10 | ||
11 | Permission is hereby granted, free of charge, to any person obtaining a copy | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy |
12 | of this software and associated documentation files (the "Software"), to deal | 12 | of this software and associated documentation files (the "Software"), to deal |
diff --git a/linden/indra/lib/python/indra/ipc/__init__.py b/linden/indra/lib/python/indra/ipc/__init__.py index fc1e654..302bbf4 100644 --- a/linden/indra/lib/python/indra/ipc/__init__.py +++ b/linden/indra/lib/python/indra/ipc/__init__.py | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | $LicenseInfo:firstyear=2006&license=mit$ | 5 | $LicenseInfo:firstyear=2006&license=mit$ |
6 | 6 | ||
7 | Copyright (c) 2006-2008, Linden Research, Inc. | 7 | Copyright (c) 2006-2009, Linden Research, Inc. |
8 | 8 | ||
9 | Permission is hereby granted, free of charge, to any person obtaining a copy | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | of this software and associated documentation files (the "Software"), to deal | 10 | of this software and associated documentation files (the "Software"), to deal |
diff --git a/linden/indra/lib/python/indra/ipc/compatibility.py b/linden/indra/lib/python/indra/ipc/compatibility.py index 07a4066..b9045c2 100644 --- a/linden/indra/lib/python/indra/ipc/compatibility.py +++ b/linden/indra/lib/python/indra/ipc/compatibility.py | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | $LicenseInfo:firstyear=2007&license=mit$ | 5 | $LicenseInfo:firstyear=2007&license=mit$ |
6 | 6 | ||
7 | Copyright (c) 2007-2008, Linden Research, Inc. | 7 | Copyright (c) 2007-2009, Linden Research, Inc. |
8 | 8 | ||
9 | Permission is hereby granted, free of charge, to any person obtaining a copy | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | of this software and associated documentation files (the "Software"), to deal | 10 | of this software and associated documentation files (the "Software"), to deal |
diff --git a/linden/indra/lib/python/indra/ipc/llmessage.py b/linden/indra/lib/python/indra/ipc/llmessage.py index 446679d..6161bad 100644 --- a/linden/indra/lib/python/indra/ipc/llmessage.py +++ b/linden/indra/lib/python/indra/ipc/llmessage.py | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | $LicenseInfo:firstyear=2007&license=mit$ | 5 | $LicenseInfo:firstyear=2007&license=mit$ |
6 | 6 | ||
7 | Copyright (c) 2007-2008, Linden Research, Inc. | 7 | Copyright (c) 2007-2009, Linden Research, Inc. |
8 | 8 | ||
9 | Permission is hereby granted, free of charge, to any person obtaining a copy | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | of this software and associated documentation files (the "Software"), to deal | 10 | of this software and associated documentation files (the "Software"), to deal |
@@ -88,7 +88,7 @@ class Message: | |||
88 | UDPDEPRECATED = "UDPDeprecated" | 88 | UDPDEPRECATED = "UDPDeprecated" |
89 | UDPBLACKLISTED = "UDPBlackListed" | 89 | UDPBLACKLISTED = "UDPBlackListed" |
90 | deprecations = [ NOTDEPRECATED, UDPDEPRECATED, UDPBLACKLISTED, DEPRECATED ] | 90 | deprecations = [ NOTDEPRECATED, UDPDEPRECATED, UDPBLACKLISTED, DEPRECATED ] |
91 | # in order of increasing deprecation | 91 | # in order of increasing deprecation |
92 | 92 | ||
93 | def __init__(self, name, number, priority, trust, coding): | 93 | def __init__(self, name, number, priority, trust, coding): |
94 | self.name = name | 94 | self.name = name |
diff --git a/linden/indra/lib/python/indra/ipc/llsdhttp.py b/linden/indra/lib/python/indra/ipc/llsdhttp.py index ed64899..cbe8ee1 100644 --- a/linden/indra/lib/python/indra/ipc/llsdhttp.py +++ b/linden/indra/lib/python/indra/ipc/llsdhttp.py | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | $LicenseInfo:firstyear=2006&license=mit$ | 5 | $LicenseInfo:firstyear=2006&license=mit$ |
6 | 6 | ||
7 | Copyright (c) 2006-2008, Linden Research, Inc. | 7 | Copyright (c) 2006-2009, Linden Research, Inc. |
8 | 8 | ||
9 | Permission is hereby granted, free of charge, to any person obtaining a copy | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | of this software and associated documentation files (the "Software"), to deal | 10 | of this software and associated documentation files (the "Software"), to deal |
diff --git a/linden/indra/lib/python/indra/ipc/mysql_pool.py b/linden/indra/lib/python/indra/ipc/mysql_pool.py index 25a66cf..e5855a3 100644 --- a/linden/indra/lib/python/indra/ipc/mysql_pool.py +++ b/linden/indra/lib/python/indra/ipc/mysql_pool.py | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | $LicenseInfo:firstyear=2007&license=mit$ | 5 | $LicenseInfo:firstyear=2007&license=mit$ |
6 | 6 | ||
7 | Copyright (c) 2007-2008, Linden Research, Inc. | 7 | Copyright (c) 2007-2009, Linden Research, Inc. |
8 | 8 | ||
9 | Permission is hereby granted, free of charge, to any person obtaining a copy | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | of this software and associated documentation files (the "Software"), to deal | 10 | of this software and associated documentation files (the "Software"), to deal |
diff --git a/linden/indra/lib/python/indra/ipc/russ.py b/linden/indra/lib/python/indra/ipc/russ.py index fbb1777..35d8afb 100644 --- a/linden/indra/lib/python/indra/ipc/russ.py +++ b/linden/indra/lib/python/indra/ipc/russ.py | |||
@@ -11,7 +11,7 @@ implementations section. | |||
11 | 11 | ||
12 | $LicenseInfo:firstyear=2007&license=mit$ | 12 | $LicenseInfo:firstyear=2007&license=mit$ |
13 | 13 | ||
14 | Copyright (c) 2007-2008, Linden Research, Inc. | 14 | Copyright (c) 2007-2009, Linden Research, Inc. |
15 | 15 | ||
16 | Permission is hereby granted, free of charge, to any person obtaining a copy | 16 | Permission is hereby granted, free of charge, to any person obtaining a copy |
17 | of this software and associated documentation files (the "Software"), to deal | 17 | of this software and associated documentation files (the "Software"), to deal |
diff --git a/linden/indra/lib/python/indra/ipc/saranwrap.py b/linden/indra/lib/python/indra/ipc/saranwrap.py deleted file mode 100644 index e0205bf..0000000 --- a/linden/indra/lib/python/indra/ipc/saranwrap.py +++ /dev/null | |||
@@ -1,651 +0,0 @@ | |||
1 | """\ | ||
2 | @file saranwrap.py | ||
3 | @author Phoenix | ||
4 | @date 2007-07-13 | ||
5 | @brief A simple, pickle based rpc mechanism which reflects python | ||
6 | objects and callables. | ||
7 | |||
8 | $LicenseInfo:firstyear=2007&license=mit$ | ||
9 | |||
10 | Copyright (c) 2007-2008, Linden Research, Inc. | ||
11 | |||
12 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
13 | of this software and associated documentation files (the "Software"), to deal | ||
14 | in the Software without restriction, including without limitation the rights | ||
15 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
16 | copies of the Software, and to permit persons to whom the Software is | ||
17 | furnished to do so, subject to the following conditions: | ||
18 | |||
19 | The above copyright notice and this permission notice shall be included in | ||
20 | all copies or substantial portions of the Software. | ||
21 | |||
22 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
23 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
24 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
25 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
26 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
27 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
28 | THE SOFTWARE. | ||
29 | $/LicenseInfo$ | ||
30 | |||
31 | This file provides classes and exceptions used for simple python level | ||
32 | remote procedure calls. This is achieved by intercepting the basic | ||
33 | getattr and setattr calls in a client proxy, which commnicates those | ||
34 | down to the server which will dispatch them to objects in it's process | ||
35 | space. | ||
36 | |||
37 | The basic protocol to get and set attributes is for the client proxy | ||
38 | to issue the command: | ||
39 | |||
40 | getattr $id $name | ||
41 | setattr $id $name $value | ||
42 | |||
43 | getitem $id $item | ||
44 | setitem $id $item $value | ||
45 | eq $id $rhs | ||
46 | del $id | ||
47 | |||
48 | When the get returns a callable, the client proxy will provide a | ||
49 | callable proxy which will invoke a remote procedure call. The command | ||
50 | issued from the callable proxy to server is: | ||
51 | |||
52 | call $id $name $args $kwargs | ||
53 | |||
54 | If the client supplies an id of None, then the get/set/call is applied | ||
55 | to the object(s) exported from the server. | ||
56 | |||
57 | The server will parse the get/set/call, take the action indicated, and | ||
58 | return back to the caller one of: | ||
59 | |||
60 | value $val | ||
61 | callable | ||
62 | object $id | ||
63 | exception $excp | ||
64 | |||
65 | To handle object expiration, the proxy will instruct the rpc server to | ||
66 | discard objects which are no longer in use. This is handled by | ||
67 | catching proxy deletion and sending the command: | ||
68 | |||
69 | del $id | ||
70 | |||
71 | The server will handle this by removing clearing it's own internal | ||
72 | references. This does not mean that the object will necessarily be | ||
73 | cleaned from the server, but no artificial references will remain | ||
74 | after successfully completing. On completion, the server will return | ||
75 | one of: | ||
76 | |||
77 | value None | ||
78 | exception $excp | ||
79 | |||
80 | The server also accepts a special command for debugging purposes: | ||
81 | |||
82 | status | ||
83 | |||
84 | Which will be intercepted by the server to write back: | ||
85 | |||
86 | status {...} | ||
87 | |||
88 | The wire protocol is to pickle the Request class in this file. The | ||
89 | request class is basically an action and a map of parameters' | ||
90 | """ | ||
91 | |||
92 | import os | ||
93 | import cPickle | ||
94 | import struct | ||
95 | import sys | ||
96 | |||
97 | try: | ||
98 | set = set | ||
99 | frozenset = frozenset | ||
100 | except NameError: | ||
101 | from sets import Set as set, ImmutableSet as frozenset | ||
102 | |||
103 | from eventlet.processes import Process | ||
104 | from eventlet import api | ||
105 | |||
106 | # | ||
107 | # debugging hooks | ||
108 | # | ||
109 | _g_debug_mode = False | ||
110 | if _g_debug_mode: | ||
111 | import traceback | ||
112 | |||
113 | def pythonpath_sync(): | ||
114 | """ | ||
115 | @brief apply the current sys.path to the environment variable PYTHONPATH, so that child processes have the same paths as the caller does. | ||
116 | """ | ||
117 | pypath = os.pathsep.join(sys.path) | ||
118 | os.environ['PYTHONPATH'] = pypath | ||
119 | |||
120 | def wrap(obj, dead_callback = None): | ||
121 | """ | ||
122 | @brief wrap in object in another process through a saranwrap proxy | ||
123 | @param object The object to wrap. | ||
124 | @param dead_callback A callable to invoke if the process exits.""" | ||
125 | |||
126 | if type(obj).__name__ == 'module': | ||
127 | return wrap_module(obj.__name__, dead_callback) | ||
128 | pythonpath_sync() | ||
129 | p = Process('python', [__file__, '--child'], dead_callback) | ||
130 | prox = Proxy(p, p) | ||
131 | prox.obj = obj | ||
132 | return prox.obj | ||
133 | |||
134 | def wrap_module(fqname, dead_callback = None): | ||
135 | """ | ||
136 | @brief wrap a module in another process through a saranwrap proxy | ||
137 | @param fqname The fully qualified name of the module. | ||
138 | @param dead_callback A callable to invoke if the process exits.""" | ||
139 | pythonpath_sync() | ||
140 | global _g_debug_mode | ||
141 | if _g_debug_mode: | ||
142 | p = Process('python', [__file__, '--module', fqname, '--logfile', '/tmp/saranwrap.log'], dead_callback) | ||
143 | else: | ||
144 | p = Process('python', [__file__, '--module', fqname,], dead_callback) | ||
145 | prox = Proxy(p, p) | ||
146 | return prox | ||
147 | |||
148 | def status(proxy): | ||
149 | """ | ||
150 | @brief get the status from the server through a proxy | ||
151 | @param proxy a saranwrap.Proxy object connected to a server.""" | ||
152 | _write_request(Request('status', {}), proxy.__local_dict['_out']) | ||
153 | return _read_response(None, None, proxy.__local_dict['_in'], proxy.__local_dict['_out'], None) | ||
154 | |||
155 | class BadResponse(Exception): | ||
156 | """"This exception is raised by an saranwrap client when it could | ||
157 | parse but cannot understand the response from the server.""" | ||
158 | pass | ||
159 | |||
160 | class BadRequest(Exception): | ||
161 | """"This exception is raised by a saranwrap server when it could parse | ||
162 | but cannot understand the response from the server.""" | ||
163 | pass | ||
164 | |||
165 | class UnrecoverableError(Exception): | ||
166 | pass | ||
167 | |||
168 | class Request(object): | ||
169 | "@brief A wrapper class for proxy requests to the server." | ||
170 | def __init__(self, action, param): | ||
171 | self._action = action | ||
172 | self._param = param | ||
173 | def __str__(self): | ||
174 | return "Request `"+self._action+"` "+str(self._param) | ||
175 | def __getitem__(self, name): | ||
176 | return self._param[name] | ||
177 | def action(self): | ||
178 | return self._action | ||
179 | |||
180 | def _read_lp_hunk(stream): | ||
181 | len_bytes = stream.read(4) | ||
182 | length = struct.unpack('I', len_bytes)[0] | ||
183 | body = stream.read(length) | ||
184 | return body | ||
185 | |||
186 | def _read_response(id, attribute, input, output, dead_list): | ||
187 | """@brief local helper method to read respones from the rpc server.""" | ||
188 | try: | ||
189 | str = _read_lp_hunk(input) | ||
190 | _prnt(`str`) | ||
191 | response = cPickle.loads(str) | ||
192 | except AttributeError, e: | ||
193 | raise UnrecoverableError(e) | ||
194 | _prnt("response: %s" % response) | ||
195 | if response[0] == 'value': | ||
196 | return response[1] | ||
197 | elif response[0] == 'callable': | ||
198 | return CallableProxy(id, attribute, input, output, dead_list) | ||
199 | elif response[0] == 'object': | ||
200 | return ObjectProxy(input, output, response[1], dead_list) | ||
201 | elif response[0] == 'exception': | ||
202 | exp = response[1] | ||
203 | raise exp | ||
204 | else: | ||
205 | raise BadResponse(response[0]) | ||
206 | |||
207 | def _write_lp_hunk(stream, hunk): | ||
208 | write_length = struct.pack('I', len(hunk)) | ||
209 | stream.write(write_length + hunk) | ||
210 | if hasattr(stream, 'flush'): | ||
211 | stream.flush() | ||
212 | |||
213 | def _write_request(param, output): | ||
214 | _prnt("request: %s" % param) | ||
215 | str = cPickle.dumps(param) | ||
216 | _write_lp_hunk(output, str) | ||
217 | |||
218 | def _is_local(attribute): | ||
219 | "Return true if the attribute should be handled locally" | ||
220 | # return attribute in ('_in', '_out', '_id', '__getattribute__', '__setattr__', '__dict__') | ||
221 | # good enough for now. :) | ||
222 | if '__local_dict' in attribute: | ||
223 | return True | ||
224 | return False | ||
225 | |||
226 | def _prnt(message): | ||
227 | global _g_debug_mode | ||
228 | if _g_debug_mode: | ||
229 | print message | ||
230 | |||
231 | _g_logfile = None | ||
232 | def _log(message): | ||
233 | global _g_logfile | ||
234 | if _g_logfile: | ||
235 | _g_logfile.write(str(os.getpid()) + ' ' + message) | ||
236 | _g_logfile.write('\n') | ||
237 | _g_logfile.flush() | ||
238 | |||
239 | def _unmunge_attr_name(name): | ||
240 | """ Sometimes attribute names come in with classname prepended, not sure why. | ||
241 | This function removes said classname, because we're huge hackers and we didn't | ||
242 | find out what the true right thing to do is. *FIX: find out. """ | ||
243 | if(name.startswith('_Proxy')): | ||
244 | name = name[len('_Proxy'):] | ||
245 | if(name.startswith('_ObjectProxy')): | ||
246 | name = name[len('_ObjectProxy'):] | ||
247 | return name | ||
248 | |||
249 | |||
250 | class Proxy(object): | ||
251 | """\ | ||
252 | @class Proxy | ||
253 | @brief This class wraps a remote python process, presumably available | ||
254 | in an instance of an Server. | ||
255 | |||
256 | This is the class you will typically use as a client to a child | ||
257 | process. Simply instantiate one around a file-like interface and start | ||
258 | calling methods on the thing that is exported. The dir() builtin is | ||
259 | not supported, so you have to know what has been exported. | ||
260 | """ | ||
261 | def __init__(self, input, output, dead_list = None): | ||
262 | """\ | ||
263 | @param input a file-like object which supports read(). | ||
264 | @param output a file-like object which supports write() and flush(). | ||
265 | @param id an identifier for the remote object. humans do not provide this. | ||
266 | """ | ||
267 | # default dead_list inside the function because all objects in method | ||
268 | # argument lists are init-ed only once globally | ||
269 | if dead_list is None: | ||
270 | dead_list = set() | ||
271 | #_prnt("Proxy::__init__") | ||
272 | self.__local_dict = dict( | ||
273 | _in = input, | ||
274 | _out = output, | ||
275 | _dead_list = dead_list, | ||
276 | _id = None) | ||
277 | |||
278 | def __getattribute__(self, attribute): | ||
279 | #_prnt("Proxy::__getattr__: %s" % attribute) | ||
280 | if _is_local(attribute): | ||
281 | # call base class getattribute so we actually get the local variable | ||
282 | attribute = _unmunge_attr_name(attribute) | ||
283 | return super(Proxy, self).__getattribute__(attribute) | ||
284 | else: | ||
285 | my_in = self.__local_dict['_in'] | ||
286 | my_out = self.__local_dict['_out'] | ||
287 | my_id = self.__local_dict['_id'] | ||
288 | |||
289 | _dead_list = self.__local_dict['_dead_list'] | ||
290 | for dead_object in _dead_list.copy(): | ||
291 | request = Request('del', {'id':dead_object}) | ||
292 | _write_request(request, my_out) | ||
293 | response = _read_response(my_id, attribute, my_in, my_out, _dead_list) | ||
294 | _dead_list.remove(dead_object) | ||
295 | |||
296 | # Pass all public attributes across to find out if it is | ||
297 | # callable or a simple attribute. | ||
298 | request = Request('getattr', {'id':my_id, 'attribute':attribute}) | ||
299 | _write_request(request, my_out) | ||
300 | return _read_response(my_id, attribute, my_in, my_out, _dead_list) | ||
301 | |||
302 | def __setattr__(self, attribute, value): | ||
303 | #_prnt("Proxy::__setattr__: %s" % attribute) | ||
304 | if _is_local(attribute): | ||
305 | # It must be local to this actual object, so we have to apply | ||
306 | # it to the dict in a roundabout way | ||
307 | attribute = _unmunge_attr_name(attribute) | ||
308 | super(Proxy, self).__getattribute__('__dict__')[attribute]=value | ||
309 | else: | ||
310 | my_in = self.__local_dict['_in'] | ||
311 | my_out = self.__local_dict['_out'] | ||
312 | my_id = self.__local_dict['_id'] | ||
313 | _dead_list = self.__local_dict['_dead_list'] | ||
314 | # Pass the set attribute across | ||
315 | request = Request('setattr', {'id':my_id, 'attribute':attribute, 'value':value}) | ||
316 | _write_request(request, my_out) | ||
317 | return _read_response(my_id, attribute, my_in, my_out, _dead_list) | ||
318 | |||
319 | class ObjectProxy(Proxy): | ||
320 | """\ | ||
321 | @class ObjectProxy | ||
322 | @brief This class wraps a remote object in the Server | ||
323 | |||
324 | This class will be created during normal operation, and users should | ||
325 | not need to deal with this class directly.""" | ||
326 | |||
327 | def __init__(self, input, output, id, dead_list): | ||
328 | """\ | ||
329 | @param input a file-like object which supports read(). | ||
330 | @param output a file-like object which supports write() and flush(). | ||
331 | @param id an identifier for the remote object. humans do not provide this. | ||
332 | """ | ||
333 | Proxy.__init__(self, input, output, dead_list) | ||
334 | self.__local_dict['_id'] = id | ||
335 | #_prnt("ObjectProxy::__init__ %s" % self._id) | ||
336 | |||
337 | def __del__(self): | ||
338 | my_id = self.__local_dict['_id'] | ||
339 | _prnt("ObjectProxy::__del__ %s" % my_id) | ||
340 | self.__local_dict['_dead_list'].add(my_id) | ||
341 | |||
342 | def __getitem__(self, key): | ||
343 | my_in = self.__local_dict['_in'] | ||
344 | my_out = self.__local_dict['_out'] | ||
345 | my_id = self.__local_dict['_id'] | ||
346 | _dead_list = self.__local_dict['_dead_list'] | ||
347 | request = Request('getitem', {'id':my_id, 'key':key}) | ||
348 | _write_request(request, my_out) | ||
349 | return _read_response(my_id, key, my_in, my_out, _dead_list) | ||
350 | |||
351 | def __setitem__(self, key, value): | ||
352 | my_in = self.__local_dict['_in'] | ||
353 | my_out = self.__local_dict['_out'] | ||
354 | my_id = self.__local_dict['_id'] | ||
355 | _dead_list = self.__local_dict['_dead_list'] | ||
356 | request = Request('setitem', {'id':my_id, 'key':key, 'value':value}) | ||
357 | _write_request(request, my_out) | ||
358 | return _read_response(my_id, key, my_in, my_out, _dead_list) | ||
359 | |||
360 | def __eq__(self, rhs): | ||
361 | my_in = self.__local_dict['_in'] | ||
362 | my_out = self.__local_dict['_out'] | ||
363 | my_id = self.__local_dict['_id'] | ||
364 | _dead_list = self.__local_dict['_dead_list'] | ||
365 | request = Request('eq', {'id':my_id, 'rhs':rhs.__local_dict['_id']}) | ||
366 | _write_request(request, my_out) | ||
367 | return _read_response(my_id, None, my_in, my_out, _dead_list) | ||
368 | |||
369 | def __repr__(self): | ||
370 | # apparently repr(obj) skips the whole getattribute thing and just calls __repr__ | ||
371 | # directly. Therefore we just pass it through the normal call pipeline, and | ||
372 | # tack on a little header so that you can tell it's an object proxy. | ||
373 | val = self.__repr__() | ||
374 | return "saran:%s" % val | ||
375 | |||
376 | def __str__(self): | ||
377 | # see description for __repr__, because str(obj) works the same. We don't | ||
378 | # tack anything on to the return value here because str values are used as data. | ||
379 | return self.__str__() | ||
380 | |||
381 | def __len__(self): | ||
382 | # see description for __repr__, len(obj) is the same. Unfortunately, __len__ is also | ||
383 | # used when determining whether an object is boolean or not, e.g. if proxied_object: | ||
384 | return self.__len__() | ||
385 | |||
386 | def proxied_type(self): | ||
387 | if type(self) is not ObjectProxy: | ||
388 | return type(self) | ||
389 | |||
390 | my_in = self.__local_dict['_in'] | ||
391 | my_out = self.__local_dict['_out'] | ||
392 | my_id = self.__local_dict['_id'] | ||
393 | request = Request('type', {'id':my_id}) | ||
394 | _write_request(request, my_out) | ||
395 | # dead list can be none because we know the result will always be | ||
396 | # a value and not an ObjectProxy itself | ||
397 | return _read_response(my_id, None, my_in, my_out, None) | ||
398 | |||
399 | class CallableProxy(object): | ||
400 | """\ | ||
401 | @class CallableProxy | ||
402 | @brief This class wraps a remote function in the Server | ||
403 | |||
404 | This class will be created by an Proxy during normal operation, | ||
405 | and users should not need to deal with this class directly.""" | ||
406 | |||
407 | def __init__(self, object_id, name, input, output, dead_list): | ||
408 | #_prnt("CallableProxy::__init__: %s, %s" % (object_id, name)) | ||
409 | self._object_id = object_id | ||
410 | self._name = name | ||
411 | self._in = input | ||
412 | self._out = output | ||
413 | self._dead_list = dead_list | ||
414 | |||
415 | def __call__(self, *args, **kwargs): | ||
416 | #_prnt("CallableProxy::__call__: %s, %s" % (args, kwargs)) | ||
417 | |||
418 | # Pass the call across. We never build a callable without | ||
419 | # having already checked if the method starts with '_' so we | ||
420 | # can safely pass this one to the remote object. | ||
421 | #_prnt("calling %s %s" % (self._object_id, self._name) | ||
422 | request = Request('call', {'id':self._object_id, 'name':self._name, 'args':args, 'kwargs':kwargs}) | ||
423 | _write_request(request, self._out) | ||
424 | return _read_response(self._object_id, self._name, self._in, self._out, self._dead_list) | ||
425 | |||
426 | class Server(object): | ||
427 | def __init__(self, input, output, export): | ||
428 | """\ | ||
429 | @param input a file-like object which supports read(). | ||
430 | @param output a file-like object which supports write() and flush(). | ||
431 | @param export an object, function, or map which is exported to clients | ||
432 | when the id is None.""" | ||
433 | #_log("Server::__init__") | ||
434 | self._in = input | ||
435 | self._out = output | ||
436 | self._export = export | ||
437 | self._next_id = 1 | ||
438 | self._objects = {} | ||
439 | |||
440 | def handle_status(self, object, req): | ||
441 | return { | ||
442 | 'object_count':len(self._objects), | ||
443 | 'next_id':self._next_id, | ||
444 | 'pid':os.getpid()} | ||
445 | |||
446 | def handle_getattr(self, object, req): | ||
447 | try: | ||
448 | return getattr(object, req['attribute']) | ||
449 | except AttributeError, e: | ||
450 | if hasattr(object, "__getitem__"): | ||
451 | return object[req['attribute']] | ||
452 | else: | ||
453 | raise e | ||
454 | #_log('getattr: %s' % str(response)) | ||
455 | |||
456 | def handle_setattr(self, object, req): | ||
457 | try: | ||
458 | return setattr(object, req['attribute'], req['value']) | ||
459 | except AttributeError, e: | ||
460 | if hasattr(object, "__setitem__"): | ||
461 | return object.__setitem__(req['attribute'], req['value']) | ||
462 | else: | ||
463 | raise e | ||
464 | |||
465 | def handle_getitem(self, object, req): | ||
466 | return object[req['key']] | ||
467 | |||
468 | def handle_setitem(self, object, req): | ||
469 | object[req['key']] = req['value'] | ||
470 | return None # *TODO figure out what the actual return value of __setitem__ should be | ||
471 | |||
472 | def handle_eq(self, object, req): | ||
473 | #_log("__eq__ %s %s" % (object, req)) | ||
474 | rhs = None | ||
475 | try: | ||
476 | rhs = self._objects[req['rhs']] | ||
477 | except KeyError, e: | ||
478 | return False | ||
479 | return (object == rhs) | ||
480 | |||
481 | def handle_call(self, object, req): | ||
482 | #_log("calling %s " % (req['name'])) | ||
483 | try: | ||
484 | fn = getattr(object, req['name']) | ||
485 | except AttributeError, e: | ||
486 | if hasattr(object, "__setitem__"): | ||
487 | fn = object[req['name']] | ||
488 | else: | ||
489 | raise e | ||
490 | |||
491 | return fn(*req['args'],**req['kwargs']) | ||
492 | |||
493 | def handle_del(self, object, req): | ||
494 | id = req['id'] | ||
495 | _log("del %s from %s" % (id, self._objects)) | ||
496 | |||
497 | # *TODO what does __del__ actually return? | ||
498 | del self._objects[id] | ||
499 | return None | ||
500 | |||
501 | def handle_type(self, object, req): | ||
502 | return type(object) | ||
503 | |||
504 | def loop(self): | ||
505 | """@brief Loop forever and respond to all requests.""" | ||
506 | _log("Server::loop") | ||
507 | while True: | ||
508 | try: | ||
509 | try: | ||
510 | str = _read_lp_hunk(self._in) | ||
511 | except EOFError: | ||
512 | sys.exit(0) # normal exit | ||
513 | request = cPickle.loads(str) | ||
514 | _log("request: %s (%s)" % (request, self._objects)) | ||
515 | req = request | ||
516 | id = None | ||
517 | object = None | ||
518 | try: | ||
519 | id = req['id'] | ||
520 | if id: | ||
521 | id = int(id) | ||
522 | object = self._objects[id] | ||
523 | #_log("id, object: %d %s" % (id, object)) | ||
524 | except Exception, e: | ||
525 | #_log("Exception %s" % str(e)) | ||
526 | pass | ||
527 | if object is None or id is None: | ||
528 | id = None | ||
529 | object = self._export | ||
530 | #_log("found object %s" % str(object)) | ||
531 | |||
532 | # Handle the request via a method with a special name on the server | ||
533 | handler_name = 'handle_%s' % request.action() | ||
534 | |||
535 | try: | ||
536 | handler = getattr(self, handler_name) | ||
537 | except AttributeError: | ||
538 | raise BadRequest, request.action() | ||
539 | |||
540 | response = handler(object, request) | ||
541 | |||
542 | # figure out what to do with the response, and respond | ||
543 | # apprpriately. | ||
544 | if request.action() in ['status', 'type']: | ||
545 | # have to handle these specially since we want to | ||
546 | # pickle up the actual value and not return a proxy | ||
547 | self.respond(['value', response]) | ||
548 | elif callable(response): | ||
549 | #_log("callable %s" % response) | ||
550 | self.respond(['callable']) | ||
551 | elif self.is_value(response): | ||
552 | self.respond(['value', response]) | ||
553 | else: | ||
554 | self._objects[self._next_id] = response | ||
555 | #_log("objects: %s" % str(self._objects)) | ||
556 | self.respond(['object', self._next_id]) | ||
557 | self._next_id += 1 | ||
558 | except SystemExit, e: | ||
559 | raise e | ||
560 | except Exception, e: | ||
561 | self.write_exception(e) | ||
562 | except: | ||
563 | self.write_exception(sys.exc_info()[0]) | ||
564 | |||
565 | def is_value(self, value): | ||
566 | """\ | ||
567 | @brief Test if value should be serialized as a simple dataset. | ||
568 | @param value The value to test. | ||
569 | @return Returns true if value is a simple serializeable set of data. | ||
570 | """ | ||
571 | return type(value) in (str,unicode,int,float,long,bool,type(None)) | ||
572 | |||
573 | def respond(self, body): | ||
574 | _log("responding with: %s" % body) | ||
575 | #_log("objects: %s" % self._objects) | ||
576 | s = cPickle.dumps(body) | ||
577 | _log(`s`) | ||
578 | str = _write_lp_hunk(self._out, s) | ||
579 | |||
580 | def write_exception(self, e): | ||
581 | """@brief Helper method to respond with an exception.""" | ||
582 | #_log("exception: %s" % sys.exc_info()[0]) | ||
583 | # TODO: serialize traceback using generalization of code from mulib.htmlexception | ||
584 | self.respond(['exception', e]) | ||
585 | global _g_debug_mode | ||
586 | if _g_debug_mode: | ||
587 | _log("traceback: %s" % traceback.format_tb(sys.exc_info()[2])) | ||
588 | |||
589 | |||
590 | # test function used for testing that final except clause | ||
591 | def raise_a_weird_error(): | ||
592 | raise "oh noes you can raise a string" | ||
593 | |||
594 | # test function used for testing return of unpicklable exceptions | ||
595 | def raise_an_unpicklable_error(): | ||
596 | class Unpicklable(Exception): | ||
597 | pass | ||
598 | raise Unpicklable() | ||
599 | |||
600 | # test function used for testing return of picklable exceptions | ||
601 | def raise_standard_error(): | ||
602 | raise FloatingPointError() | ||
603 | |||
604 | # test function to make sure print doesn't break the wrapper | ||
605 | def print_string(str): | ||
606 | print str | ||
607 | |||
608 | # test function to make sure printing on stdout doesn't break the | ||
609 | # wrapper | ||
610 | def err_string(str): | ||
611 | print >>sys.stderr, str | ||
612 | |||
613 | def main(): | ||
614 | import optparse | ||
615 | parser = optparse.OptionParser( | ||
616 | usage="usage: %prog [options]", | ||
617 | description="Simple saranwrap.Server wrapper") | ||
618 | parser.add_option( | ||
619 | '-c', '--child', default=False, action='store_true', | ||
620 | help='Wrap an object serialed via setattr.') | ||
621 | parser.add_option( | ||
622 | '-m', '--module', type='string', dest='module', default=None, | ||
623 | help='a module to load and export.') | ||
624 | parser.add_option( | ||
625 | '-l', '--logfile', type='string', dest='logfile', default=None, | ||
626 | help='file to log to.') | ||
627 | options, args = parser.parse_args() | ||
628 | global _g_logfile | ||
629 | if options.logfile: | ||
630 | _g_logfile = open(options.logfile, 'a') | ||
631 | if options.module: | ||
632 | export = api.named(options.module) | ||
633 | server = Server(sys.stdin, sys.stdout, export) | ||
634 | elif options.child: | ||
635 | server = Server(sys.stdin, sys.stdout, {}) | ||
636 | |||
637 | # *HACK: some modules may emit on stderr, which breaks everything. | ||
638 | class NullSTDOut(object): | ||
639 | def write(a, b): | ||
640 | pass | ||
641 | sys.stderr = NullSTDOut() | ||
642 | sys.stdout = NullSTDOut() | ||
643 | |||
644 | # Loop until EOF | ||
645 | server.loop() | ||
646 | if _g_logfile: | ||
647 | _g_logfile.close() | ||
648 | |||
649 | |||
650 | if __name__ == "__main__": | ||
651 | main() | ||
diff --git a/linden/indra/lib/python/indra/ipc/servicebuilder.py b/linden/indra/lib/python/indra/ipc/servicebuilder.py index 01f2c6f..04ccee7 100644 --- a/linden/indra/lib/python/indra/ipc/servicebuilder.py +++ b/linden/indra/lib/python/indra/ipc/servicebuilder.py | |||
@@ -5,7 +5,7 @@ | |||
5 | 5 | ||
6 | $LicenseInfo:firstyear=2007&license=mit$ | 6 | $LicenseInfo:firstyear=2007&license=mit$ |
7 | 7 | ||
8 | Copyright (c) 2007-2008, Linden Research, Inc. | 8 | Copyright (c) 2007-2009, Linden Research, Inc. |
9 | 9 | ||
10 | Permission is hereby granted, free of charge, to any person obtaining a copy | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy |
11 | of this software and associated documentation files (the "Software"), to deal | 11 | of this software and associated documentation files (the "Software"), to deal |
diff --git a/linden/indra/lib/python/indra/ipc/tokenstream.py b/linden/indra/lib/python/indra/ipc/tokenstream.py index 75c41a7..b96f26d 100644 --- a/linden/indra/lib/python/indra/ipc/tokenstream.py +++ b/linden/indra/lib/python/indra/ipc/tokenstream.py | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | $LicenseInfo:firstyear=2007&license=mit$ | 5 | $LicenseInfo:firstyear=2007&license=mit$ |
6 | 6 | ||
7 | Copyright (c) 2007-2008, Linden Research, Inc. | 7 | Copyright (c) 2007-2009, Linden Research, Inc. |
8 | 8 | ||
9 | Permission is hereby granted, free of charge, to any person obtaining a copy | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | of this software and associated documentation files (the "Software"), to deal | 10 | of this software and associated documentation files (the "Software"), to deal |
diff --git a/linden/indra/lib/python/indra/ipc/webdav.py b/linden/indra/lib/python/indra/ipc/webdav.py index de00efb..98b8499 100644 --- a/linden/indra/lib/python/indra/ipc/webdav.py +++ b/linden/indra/lib/python/indra/ipc/webdav.py | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | $LicenseInfo:firstyear=2007&license=mit$ | 5 | $LicenseInfo:firstyear=2007&license=mit$ |
6 | 6 | ||
7 | Copyright (c) 2007-2008, Linden Research, Inc. | 7 | Copyright (c) 2007-2009, Linden Research, Inc. |
8 | 8 | ||
9 | Permission is hereby granted, free of charge, to any person obtaining a copy | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | of this software and associated documentation files (the "Software"), to deal | 10 | of this software and associated documentation files (the "Software"), to deal |
diff --git a/linden/indra/lib/python/indra/ipc/xml_rpc.py b/linden/indra/lib/python/indra/ipc/xml_rpc.py index 7473d31..47536c1 100644 --- a/linden/indra/lib/python/indra/ipc/xml_rpc.py +++ b/linden/indra/lib/python/indra/ipc/xml_rpc.py | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | $LicenseInfo:firstyear=2006&license=mit$ | 5 | $LicenseInfo:firstyear=2006&license=mit$ |
6 | 6 | ||
7 | Copyright (c) 2006-2008, Linden Research, Inc. | 7 | Copyright (c) 2006-2009, Linden Research, Inc. |
8 | 8 | ||
9 | Permission is hereby granted, free of charge, to any person obtaining a copy | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | of this software and associated documentation files (the "Software"), to deal | 10 | of this software and associated documentation files (the "Software"), to deal |
diff --git a/linden/indra/lib/python/indra/util/__init__.py b/linden/indra/lib/python/indra/util/__init__.py index 3134c2d..b004e58 100644 --- a/linden/indra/lib/python/indra/util/__init__.py +++ b/linden/indra/lib/python/indra/util/__init__.py | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | $LicenseInfo:firstyear=2006&license=mit$ | 5 | $LicenseInfo:firstyear=2006&license=mit$ |
6 | 6 | ||
7 | Copyright (c) 2006-2008, Linden Research, Inc. | 7 | Copyright (c) 2006-2009, Linden Research, Inc. |
8 | 8 | ||
9 | Permission is hereby granted, free of charge, to any person obtaining a copy | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | of this software and associated documentation files (the "Software"), to deal | 10 | of this software and associated documentation files (the "Software"), to deal |
diff --git a/linden/indra/lib/python/indra/util/fastest_elementtree.py b/linden/indra/lib/python/indra/util/fastest_elementtree.py index 2470143..3e2189c 100644 --- a/linden/indra/lib/python/indra/util/fastest_elementtree.py +++ b/linden/indra/lib/python/indra/util/fastest_elementtree.py | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | $LicenseInfo:firstyear=2008&license=mit$ | 5 | $LicenseInfo:firstyear=2008&license=mit$ |
6 | 6 | ||
7 | Copyright (c) 2008, Linden Research, Inc. | 7 | Copyright (c) 2008-2009, Linden Research, Inc. |
8 | 8 | ||
9 | Permission is hereby granted, free of charge, to any person obtaining a copy | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | of this software and associated documentation files (the "Software"), to deal | 10 | of this software and associated documentation files (the "Software"), to deal |
diff --git a/linden/indra/lib/python/indra/util/helpformatter.py b/linden/indra/lib/python/indra/util/helpformatter.py index 8b86b87..ba5c9b6 100644 --- a/linden/indra/lib/python/indra/util/helpformatter.py +++ b/linden/indra/lib/python/indra/util/helpformatter.py | |||
@@ -5,7 +5,7 @@ | |||
5 | 5 | ||
6 | $LicenseInfo:firstyear=2007&license=mit$ | 6 | $LicenseInfo:firstyear=2007&license=mit$ |
7 | 7 | ||
8 | Copyright (c) 2007-2008, Linden Research, Inc. | 8 | Copyright (c) 2007-2009, Linden Research, Inc. |
9 | 9 | ||
10 | Permission is hereby granted, free of charge, to any person obtaining a copy | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy |
11 | of this software and associated documentation files (the "Software"), to deal | 11 | of this software and associated documentation files (the "Software"), to deal |
diff --git a/linden/indra/lib/python/indra/util/iterators.py b/linden/indra/lib/python/indra/util/iterators.py new file mode 100644 index 0000000..9013fa6 --- /dev/null +++ b/linden/indra/lib/python/indra/util/iterators.py | |||
@@ -0,0 +1,63 @@ | |||
1 | """\ | ||
2 | @file iterators.py | ||
3 | @brief Useful general-purpose iterators. | ||
4 | |||
5 | $LicenseInfo:firstyear=2008&license=mit$ | ||
6 | |||
7 | Copyright (c) 2008-2009, Linden Research, Inc. | ||
8 | |||
9 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
10 | of this software and associated documentation files (the "Software"), to deal | ||
11 | in the Software without restriction, including without limitation the rights | ||
12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | copies of the Software, and to permit persons to whom the Software is | ||
14 | furnished to do so, subject to the following conditions: | ||
15 | |||
16 | The above copyright notice and this permission notice shall be included in | ||
17 | all copies or substantial portions of the Software. | ||
18 | |||
19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
25 | THE SOFTWARE. | ||
26 | $/LicenseInfo$ | ||
27 | """ | ||
28 | |||
29 | from __future__ import nested_scopes | ||
30 | |||
31 | def iter_chunks(rows, aggregate_size=100): | ||
32 | """ | ||
33 | Given an iterable set of items (@p rows), produces lists of up to @p | ||
34 | aggregate_size items at a time, for example: | ||
35 | |||
36 | iter_chunks([1,2,3,4,5,6,7,8,9,10], 3) | ||
37 | |||
38 | Values for @p aggregate_size < 1 will raise ValueError. | ||
39 | |||
40 | Will return a generator that produces, in the following order: | ||
41 | - [1, 2, 3] | ||
42 | - [4, 5, 6] | ||
43 | - [7, 8, 9] | ||
44 | - [10] | ||
45 | """ | ||
46 | if aggregate_size < 1: | ||
47 | raise ValueError() | ||
48 | |||
49 | def iter_chunks_inner(): | ||
50 | row_iter = iter(rows) | ||
51 | done = False | ||
52 | agg = [] | ||
53 | while not done: | ||
54 | try: | ||
55 | row = row_iter.next() | ||
56 | agg.append(row) | ||
57 | except StopIteration: | ||
58 | done = True | ||
59 | if agg and (len(agg) >= aggregate_size or done): | ||
60 | yield agg | ||
61 | agg = [] | ||
62 | |||
63 | return iter_chunks_inner() | ||
diff --git a/linden/indra/lib/python/indra/util/iterators_test.py b/linden/indra/lib/python/indra/util/iterators_test.py new file mode 100755 index 0000000..66928c8 --- /dev/null +++ b/linden/indra/lib/python/indra/util/iterators_test.py | |||
@@ -0,0 +1,72 @@ | |||
1 | """\ | ||
2 | @file iterators_test.py | ||
3 | @brief Test cases for iterators module. | ||
4 | |||
5 | $LicenseInfo:firstyear=2008&license=mit$ | ||
6 | |||
7 | Copyright (c) 2008-2009, Linden Research, Inc. | ||
8 | |||
9 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
10 | of this software and associated documentation files (the "Software"), to deal | ||
11 | in the Software without restriction, including without limitation the rights | ||
12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | copies of the Software, and to permit persons to whom the Software is | ||
14 | furnished to do so, subject to the following conditions: | ||
15 | |||
16 | The above copyright notice and this permission notice shall be included in | ||
17 | all copies or substantial portions of the Software. | ||
18 | |||
19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
25 | THE SOFTWARE. | ||
26 | $/LicenseInfo$ | ||
27 | """ | ||
28 | |||
29 | import unittest | ||
30 | |||
31 | from indra.util.iterators import iter_chunks | ||
32 | |||
33 | class TestIterChunks(unittest.TestCase): | ||
34 | """Unittests for iter_chunks""" | ||
35 | def test_bad_agg_size(self): | ||
36 | rows = [1,2,3,4] | ||
37 | self.assertRaises(ValueError, iter_chunks, rows, 0) | ||
38 | self.assertRaises(ValueError, iter_chunks, rows, -1) | ||
39 | |||
40 | try: | ||
41 | for i in iter_chunks(rows, 0): | ||
42 | pass | ||
43 | except ValueError: | ||
44 | pass | ||
45 | else: | ||
46 | self.fail() | ||
47 | |||
48 | try: | ||
49 | result = list(iter_chunks(rows, 0)) | ||
50 | except ValueError: | ||
51 | pass | ||
52 | else: | ||
53 | self.fail() | ||
54 | def test_empty(self): | ||
55 | rows = [] | ||
56 | result = list(iter_chunks(rows)) | ||
57 | self.assertEqual(result, []) | ||
58 | def test_small(self): | ||
59 | rows = [[1]] | ||
60 | result = list(iter_chunks(rows, 2)) | ||
61 | self.assertEqual(result, [[[1]]]) | ||
62 | def test_size(self): | ||
63 | rows = [[1],[2]] | ||
64 | result = list(iter_chunks(rows, 2)) | ||
65 | self.assertEqual(result, [[[1],[2]]]) | ||
66 | def test_multi_agg(self): | ||
67 | rows = [[1],[2],[3],[4],[5]] | ||
68 | result = list(iter_chunks(rows, 2)) | ||
69 | self.assertEqual(result, [[[1],[2]],[[3],[4]],[[5]]]) | ||
70 | |||
71 | if __name__ == "__main__": | ||
72 | unittest.main() | ||
diff --git a/linden/indra/lib/python/indra/util/llmanifest.py b/linden/indra/lib/python/indra/util/llmanifest.py index a00d242..12e33f2 100644 --- a/linden/indra/lib/python/indra/util/llmanifest.py +++ b/linden/indra/lib/python/indra/util/llmanifest.py | |||
@@ -5,7 +5,7 @@ | |||
5 | 5 | ||
6 | $LicenseInfo:firstyear=2007&license=mit$ | 6 | $LicenseInfo:firstyear=2007&license=mit$ |
7 | 7 | ||
8 | Copyright (c) 2007-2008, Linden Research, Inc. | 8 | Copyright (c) 2007-2009, Linden Research, Inc. |
9 | 9 | ||
10 | Permission is hereby granted, free of charge, to any person obtaining a copy | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy |
11 | of this software and associated documentation files (the "Software"), to deal | 11 | of this software and associated documentation files (the "Software"), to deal |
@@ -452,7 +452,7 @@ class LLManifest(object): | |||
452 | # *TODO is this gonna be useful? | 452 | # *TODO is this gonna be useful? |
453 | print "Cleaning up " + c | 453 | print "Cleaning up " + c |
454 | 454 | ||
455 | def process_file(self, src, dst): | 455 | def process_file(self, src, dst, strip=False): |
456 | if self.includes(src, dst): | 456 | if self.includes(src, dst): |
457 | # print src, "=>", dst | 457 | # print src, "=>", dst |
458 | for action in self.actions: | 458 | for action in self.actions: |
@@ -460,7 +460,7 @@ class LLManifest(object): | |||
460 | method = getattr(self, methodname, None) | 460 | method = getattr(self, methodname, None) |
461 | if method is not None: | 461 | if method is not None: |
462 | method(src, dst) | 462 | method(src, dst) |
463 | self.file_list.append([src, dst]) | 463 | self.file_list.append([src, dst, strip]) |
464 | return 1 | 464 | return 1 |
465 | else: | 465 | else: |
466 | sys.stdout.write(" (excluding %r, %r)" % (src, dst)) | 466 | sys.stdout.write(" (excluding %r, %r)" % (src, dst)) |
@@ -607,7 +607,7 @@ class LLManifest(object): | |||
607 | d = src_re.sub(d_template, s.replace('\\', '/')) | 607 | d = src_re.sub(d_template, s.replace('\\', '/')) |
608 | yield os.path.normpath(s), os.path.normpath(d) | 608 | yield os.path.normpath(s), os.path.normpath(d) |
609 | 609 | ||
610 | def path(self, src, dst=None): | 610 | def path(self, src, dst=None, strip=False): |
611 | sys.stdout.write("Processing %s => %s ... " % (src, dst)) | 611 | sys.stdout.write("Processing %s => %s ... " % (src, dst)) |
612 | sys.stdout.flush() | 612 | sys.stdout.flush() |
613 | if src == None: | 613 | if src == None: |
@@ -622,7 +622,7 @@ class LLManifest(object): | |||
622 | if self.wildcard_pattern.search(src): | 622 | if self.wildcard_pattern.search(src): |
623 | for s,d in self.expand_globs(src, dst): | 623 | for s,d in self.expand_globs(src, dst): |
624 | assert(s != d) | 624 | assert(s != d) |
625 | count += self.process_file(s, d) | 625 | count += self.process_file(s, d, strip) |
626 | else: | 626 | else: |
627 | # if we're specifying a single path (not a glob), | 627 | # if we're specifying a single path (not a glob), |
628 | # we should error out if it doesn't exist | 628 | # we should error out if it doesn't exist |
@@ -631,7 +631,7 @@ class LLManifest(object): | |||
631 | if os.path.isdir(src): | 631 | if os.path.isdir(src): |
632 | count += self.process_directory(src, dst) | 632 | count += self.process_directory(src, dst) |
633 | else: | 633 | else: |
634 | count += self.process_file(src, dst) | 634 | count += self.process_file(src, dst, strip) |
635 | return count | 635 | return count |
636 | try: | 636 | try: |
637 | count = try_path(os.path.join(self.get_src_prefix(), src)) | 637 | count = try_path(os.path.join(self.get_src_prefix(), src)) |
diff --git a/linden/indra/lib/python/indra/util/llperformance.py b/linden/indra/lib/python/indra/util/llperformance.py new file mode 100755 index 0000000..7c52730 --- /dev/null +++ b/linden/indra/lib/python/indra/util/llperformance.py | |||
@@ -0,0 +1,158 @@ | |||
1 | #!/usr/bin/python | ||
2 | |||
3 | # ------------------------------------------------ | ||
4 | # Sim metrics utility functions. | ||
5 | |||
6 | import glob, os, time, sys, stat, exceptions | ||
7 | |||
8 | from indra.base import llsd | ||
9 | |||
10 | gBlockMap = {} #Map of performance metric data with function hierarchy information. | ||
11 | gCurrentStatPath = "" | ||
12 | |||
13 | gIsLoggingEnabled=False | ||
14 | |||
15 | class LLPerfStat: | ||
16 | def __init__(self,key): | ||
17 | self.mTotalTime = 0 | ||
18 | self.mNumRuns = 0 | ||
19 | self.mName=key | ||
20 | self.mTimeStamp = int(time.time()*1000) | ||
21 | self.mUTCTime = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()) | ||
22 | |||
23 | def __str__(self): | ||
24 | return "%f" % self.mTotalTime | ||
25 | |||
26 | def start(self): | ||
27 | self.mStartTime = int(time.time() * 1000000) | ||
28 | self.mNumRuns += 1 | ||
29 | |||
30 | def stop(self): | ||
31 | execution_time = int(time.time() * 1000000) - self.mStartTime | ||
32 | self.mTotalTime += execution_time | ||
33 | |||
34 | def get_map(self): | ||
35 | results={} | ||
36 | results['name']=self.mName | ||
37 | results['utc_time']=self.mUTCTime | ||
38 | results['timestamp']=self.mTimeStamp | ||
39 | results['us']=self.mTotalTime | ||
40 | results['count']=self.mNumRuns | ||
41 | return results | ||
42 | |||
43 | class PerfError(exceptions.Exception): | ||
44 | def __init__(self): | ||
45 | return | ||
46 | |||
47 | def __Str__(self): | ||
48 | print "","Unfinished LLPerfBlock" | ||
49 | |||
50 | class LLPerfBlock: | ||
51 | def __init__( self, key ): | ||
52 | global gBlockMap | ||
53 | global gCurrentStatPath | ||
54 | global gIsLoggingEnabled | ||
55 | |||
56 | #Check to see if we're running metrics right now. | ||
57 | if gIsLoggingEnabled: | ||
58 | self.mRunning = True #Mark myself as running. | ||
59 | |||
60 | self.mPreviousStatPath = gCurrentStatPath | ||
61 | gCurrentStatPath += "/" + key | ||
62 | if gCurrentStatPath not in gBlockMap: | ||
63 | gBlockMap[gCurrentStatPath] = LLPerfStat(key) | ||
64 | |||
65 | self.mStat = gBlockMap[gCurrentStatPath] | ||
66 | self.mStat.start() | ||
67 | |||
68 | def finish( self ): | ||
69 | global gBlockMap | ||
70 | global gIsLoggingEnabled | ||
71 | |||
72 | if gIsLoggingEnabled: | ||
73 | self.mStat.stop() | ||
74 | self.mRunning = False | ||
75 | gCurrentStatPath = self.mPreviousStatPath | ||
76 | |||
77 | # def __del__( self ): | ||
78 | # if self.mRunning: | ||
79 | # #SPATTERS FIXME | ||
80 | # raise PerfError | ||
81 | |||
82 | class LLPerformance: | ||
83 | #-------------------------------------------------- | ||
84 | # Determine whether or not we want to log statistics | ||
85 | |||
86 | def __init__( self, process_name = "python" ): | ||
87 | self.process_name = process_name | ||
88 | self.init_testing() | ||
89 | self.mTimeStamp = int(time.time()*1000) | ||
90 | self.mUTCTime = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()) | ||
91 | |||
92 | def init_testing( self ): | ||
93 | global gIsLoggingEnabled | ||
94 | |||
95 | host_performance_file = "/dev/shm/simperf/simperf_proc_config.llsd" | ||
96 | |||
97 | #If file exists, open | ||
98 | if os.path.exists(host_performance_file): | ||
99 | file = open (host_performance_file,'r') | ||
100 | |||
101 | #Read serialized LLSD from file. | ||
102 | body = llsd.parse(file.read()) | ||
103 | |||
104 | #Calculate time since file last modified. | ||
105 | stats = os.stat(host_performance_file) | ||
106 | now = time.time() | ||
107 | mod = stats[stat.ST_MTIME] | ||
108 | age = now - mod | ||
109 | |||
110 | if age < ( body['duration'] ): | ||
111 | gIsLoggingEnabled = True | ||
112 | |||
113 | |||
114 | def get ( self ): | ||
115 | global gIsLoggingEnabled | ||
116 | return gIsLoggingEnabled | ||
117 | |||
118 | #def output(self,ptr,path): | ||
119 | # if 'stats' in ptr: | ||
120 | # stats = ptr['stats'] | ||
121 | # self.mOutputPtr[path] = stats.get_map() | ||
122 | |||
123 | # if 'children' in ptr: | ||
124 | # children=ptr['children'] | ||
125 | |||
126 | # curptr = self.mOutputPtr | ||
127 | # curchildren={} | ||
128 | # curptr['children'] = curchildren | ||
129 | |||
130 | # for key in children: | ||
131 | # curchildren[key]={} | ||
132 | # self.mOutputPtr = curchildren[key] | ||
133 | # self.output(children[key],path + '/' + key) | ||
134 | |||
135 | def done(self): | ||
136 | global gBlockMap | ||
137 | |||
138 | if not self.get(): | ||
139 | return | ||
140 | |||
141 | output_name = "/dev/shm/simperf/%s_proc.%d.llsd" % (self.process_name, os.getpid()) | ||
142 | output_file = open(output_name, 'w') | ||
143 | process_info = { | ||
144 | "name" : self.process_name, | ||
145 | "pid" : os.getpid(), | ||
146 | "ppid" : os.getppid(), | ||
147 | "timestamp" : self.mTimeStamp, | ||
148 | "utc_time" : self.mUTCTime, | ||
149 | } | ||
150 | output_file.write(llsd.format_notation(process_info)) | ||
151 | output_file.write('\n') | ||
152 | |||
153 | for key in gBlockMap.keys(): | ||
154 | gBlockMap[key] = gBlockMap[key].get_map() | ||
155 | output_file.write(llsd.format_notation(gBlockMap)) | ||
156 | output_file.write('\n') | ||
157 | output_file.close() | ||
158 | |||
diff --git a/linden/indra/lib/python/indra/util/llsubprocess.py b/linden/indra/lib/python/indra/util/llsubprocess.py index 1c107d9..c4c4073 100644 --- a/linden/indra/lib/python/indra/util/llsubprocess.py +++ b/linden/indra/lib/python/indra/util/llsubprocess.py | |||
@@ -6,7 +6,7 @@ | |||
6 | 6 | ||
7 | $LicenseInfo:firstyear=2007&license=mit$ | 7 | $LicenseInfo:firstyear=2007&license=mit$ |
8 | 8 | ||
9 | Copyright (c) 2007-2008, Linden Research, Inc. | 9 | Copyright (c) 2007-2009, Linden Research, Inc. |
10 | 10 | ||
11 | Permission is hereby granted, free of charge, to any person obtaining a copy | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy |
12 | of this software and associated documentation files (the "Software"), to deal | 12 | of this software and associated documentation files (the "Software"), to deal |
diff --git a/linden/indra/lib/python/indra/util/llversion.py b/linden/indra/lib/python/indra/util/llversion.py index fe9448f..0e59c17 100644 --- a/linden/indra/lib/python/indra/util/llversion.py +++ b/linden/indra/lib/python/indra/util/llversion.py | |||
@@ -5,7 +5,7 @@ | |||
5 | 5 | ||
6 | $LicenseInfo:firstyear=2006&license=mit$ | 6 | $LicenseInfo:firstyear=2006&license=mit$ |
7 | 7 | ||
8 | Copyright (c) 2006-2008, Linden Research, Inc. | 8 | Copyright (c) 2006-2009, Linden Research, Inc. |
9 | 9 | ||
10 | Permission is hereby granted, free of charge, to any person obtaining a copy | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy |
11 | of this software and associated documentation files (the "Software"), to deal | 11 | of this software and associated documentation files (the "Software"), to deal |
diff --git a/linden/indra/lib/python/indra/util/named_query.py b/linden/indra/lib/python/indra/util/named_query.py index 788fb0e..822f783 100644 --- a/linden/indra/lib/python/indra/util/named_query.py +++ b/linden/indra/lib/python/indra/util/named_query.py | |||
@@ -6,7 +6,7 @@ | |||
6 | 6 | ||
7 | $LicenseInfo:firstyear=2007&license=mit$ | 7 | $LicenseInfo:firstyear=2007&license=mit$ |
8 | 8 | ||
9 | Copyright (c) 2007-2008, Linden Research, Inc. | 9 | Copyright (c) 2007-2009, Linden Research, Inc. |
10 | 10 | ||
11 | Permission is hereby granted, free of charge, to any person obtaining a copy | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy |
12 | of this software and associated documentation files (the "Software"), to deal | 12 | of this software and associated documentation files (the "Software"), to deal |
@@ -65,9 +65,7 @@ def _init_g_named_manager(sql_dir = None): | |||
65 | 65 | ||
66 | # extra fallback directory in case config doesn't return what we want | 66 | # extra fallback directory in case config doesn't return what we want |
67 | if sql_dir is None: | 67 | if sql_dir is None: |
68 | sql_dir = os.path.abspath( | 68 | sql_dir = os.path.join(os.path.dirname(__file__), "..", "..", "..", "..", "web", "dataservice", "sql") |
69 | os.path.join( | ||
70 | os.path.realpath(os.path.dirname(__file__)), "..", "..", "..", "..", "web", "dataservice", "sql")) | ||
71 | 69 | ||
72 | global _g_named_manager | 70 | global _g_named_manager |
73 | _g_named_manager = NamedQueryManager( | 71 | _g_named_manager = NamedQueryManager( |
diff --git a/linden/indra/lib/python/indra/util/shutil2.py b/linden/indra/lib/python/indra/util/shutil2.py index 2c504c2..9e2e7a6 100644 --- a/linden/indra/lib/python/indra/util/shutil2.py +++ b/linden/indra/lib/python/indra/util/shutil2.py | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | $LicenseInfo:firstyear=2007&license=mit$ | 5 | $LicenseInfo:firstyear=2007&license=mit$ |
6 | 6 | ||
7 | Copyright (c) 2007-2008, Linden Research, Inc. | 7 | Copyright (c) 2007-2009, Linden Research, Inc. |
8 | 8 | ||
9 | Permission is hereby granted, free of charge, to any person obtaining a copy | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | of this software and associated documentation files (the "Software"), to deal | 10 | of this software and associated documentation files (the "Software"), to deal |
diff --git a/linden/indra/lib/python/indra/util/simperf_host_xml_parser.py b/linden/indra/lib/python/indra/util/simperf_host_xml_parser.py new file mode 100755 index 0000000..672c105 --- /dev/null +++ b/linden/indra/lib/python/indra/util/simperf_host_xml_parser.py | |||
@@ -0,0 +1,338 @@ | |||
1 | #!/usr/bin/env python | ||
2 | """\ | ||
3 | @file simperf_host_xml_parser.py | ||
4 | @brief Digest collector's XML dump and convert to simple dict/list structure | ||
5 | |||
6 | $LicenseInfo:firstyear=2008&license=mit$ | ||
7 | |||
8 | Copyright (c) 2008-2009, Linden Research, Inc. | ||
9 | |||
10 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
11 | of this software and associated documentation files (the "Software"), to deal | ||
12 | in the Software without restriction, including without limitation the rights | ||
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
14 | copies of the Software, and to permit persons to whom the Software is | ||
15 | furnished to do so, subject to the following conditions: | ||
16 | |||
17 | The above copyright notice and this permission notice shall be included in | ||
18 | all copies or substantial portions of the Software. | ||
19 | |||
20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
26 | THE SOFTWARE. | ||
27 | $/LicenseInfo$ | ||
28 | """ | ||
29 | |||
30 | import sys, os, getopt, time | ||
31 | import simplejson | ||
32 | from xml import sax | ||
33 | |||
34 | |||
35 | def usage(): | ||
36 | print "Usage:" | ||
37 | print sys.argv[0] + " [options]" | ||
38 | print " Convert RRD's XML dump to JSON. Script to convert the simperf_host_collector-" | ||
39 | print " generated RRD dump into JSON. Steps include converting selected named" | ||
40 | print " fields from GAUGE type to COUNTER type by computing delta with preceding" | ||
41 | print " values. Top-level named fields are:" | ||
42 | |||
43 | print " lastupdate Time (javascript timestamp) of last data sample" | ||
44 | print " step Time in seconds between samples" | ||
45 | print " ds Data specification (name/type) for each column" | ||
46 | print " database Table of data samples, one time step per row" | ||
47 | |||
48 | print "Options:" | ||
49 | print " -i, --in Input settings filename. (Default: stdin)" | ||
50 | print " -o, --out Output settings filename. (Default: stdout)" | ||
51 | print " -h, --help Print this message and exit." | ||
52 | |||
53 | print "Example: %s -i rrddump.xml -o rrddump.json" % sys.argv[0] | ||
54 | |||
55 | print "Interfaces:" | ||
56 | print " class SimPerfHostXMLParser() # SAX content handler" | ||
57 | print " def simperf_host_xml_fixup(parser) # post-parse value fixup" | ||
58 | |||
59 | class SimPerfHostXMLParser(sax.handler.ContentHandler): | ||
60 | |||
61 | def __init__(self): | ||
62 | pass | ||
63 | |||
64 | def startDocument(self): | ||
65 | self.rrd_last_update = 0 # public | ||
66 | self.rrd_step = 0 # public | ||
67 | self.rrd_ds = [] # public | ||
68 | self.rrd_records = [] # public | ||
69 | self._rrd_level = 0 | ||
70 | self._rrd_parse_state = 0 | ||
71 | self._rrd_chars = "" | ||
72 | self._rrd_capture = False | ||
73 | self._rrd_ds_val = {} | ||
74 | self._rrd_data_row = [] | ||
75 | self._rrd_data_row_has_nan = False | ||
76 | |||
77 | def endDocument(self): | ||
78 | pass | ||
79 | |||
80 | # Nasty little ad-hoc state machine to extract the elements that are | ||
81 | # necessary from the 'rrdtool dump' XML output. The same element | ||
82 | # name '<ds>' is used for two different data sets so we need to pay | ||
83 | # some attention to the actual structure to get the ones we want | ||
84 | # and ignore the ones we don't. | ||
85 | |||
86 | def startElement(self, name, attrs): | ||
87 | self._rrd_level = self._rrd_level + 1 | ||
88 | self._rrd_capture = False | ||
89 | if self._rrd_level == 1: | ||
90 | if name == "rrd" and self._rrd_parse_state == 0: | ||
91 | self._rrd_parse_state = 1 # In <rrd> | ||
92 | self._rrd_capture = True | ||
93 | self._rrd_chars = "" | ||
94 | elif self._rrd_level == 2: | ||
95 | if self._rrd_parse_state == 1: | ||
96 | if name == "lastupdate": | ||
97 | self._rrd_parse_state = 2 # In <rrd><lastupdate> | ||
98 | self._rrd_capture = True | ||
99 | self._rrd_chars = "" | ||
100 | elif name == "step": | ||
101 | self._rrd_parse_state = 3 # In <rrd><step> | ||
102 | self._rrd_capture = True | ||
103 | self._rrd_chars = "" | ||
104 | elif name == "ds": | ||
105 | self._rrd_parse_state = 4 # In <rrd><ds> | ||
106 | self._rrd_ds_val = {} | ||
107 | self._rrd_chars = "" | ||
108 | elif name == "rra": | ||
109 | self._rrd_parse_state = 5 # In <rrd><rra> | ||
110 | elif self._rrd_level == 3: | ||
111 | if self._rrd_parse_state == 4: | ||
112 | if name == "name": | ||
113 | self._rrd_parse_state = 6 # In <rrd><ds><name> | ||
114 | self._rrd_capture = True | ||
115 | self._rrd_chars = "" | ||
116 | elif name == "type": | ||
117 | self._rrd_parse_state = 7 # In <rrd><ds><type> | ||
118 | self._rrd_capture = True | ||
119 | self._rrd_chars = "" | ||
120 | elif self._rrd_parse_state == 5: | ||
121 | if name == "database": | ||
122 | self._rrd_parse_state = 8 # In <rrd><rra><database> | ||
123 | elif self._rrd_level == 4: | ||
124 | if self._rrd_parse_state == 8: | ||
125 | if name == "row": | ||
126 | self._rrd_parse_state = 9 # In <rrd><rra><database><row> | ||
127 | self._rrd_data_row = [] | ||
128 | self._rrd_data_row_has_nan = False | ||
129 | elif self._rrd_level == 5: | ||
130 | if self._rrd_parse_state == 9: | ||
131 | if name == "v": | ||
132 | self._rrd_parse_state = 10 # In <rrd><rra><database><row><v> | ||
133 | self._rrd_capture = True | ||
134 | self._rrd_chars = "" | ||
135 | |||
136 | def endElement(self, name): | ||
137 | self._rrd_capture = False | ||
138 | if self._rrd_parse_state == 10: | ||
139 | self._rrd_capture = self._rrd_level == 6 | ||
140 | if self._rrd_level == 5: | ||
141 | if self._rrd_chars == "NaN": | ||
142 | self._rrd_data_row_has_nan = True | ||
143 | else: | ||
144 | self._rrd_data_row.append(self._rrd_chars) | ||
145 | self._rrd_parse_state = 9 # In <rrd><rra><database><row> | ||
146 | elif self._rrd_parse_state == 9: | ||
147 | if self._rrd_level == 4: | ||
148 | if not self._rrd_data_row_has_nan: | ||
149 | self.rrd_records.append(self._rrd_data_row) | ||
150 | self._rrd_parse_state = 8 # In <rrd><rra><database> | ||
151 | elif self._rrd_parse_state == 8: | ||
152 | if self._rrd_level == 3: | ||
153 | self._rrd_parse_state = 5 # In <rrd><rra> | ||
154 | elif self._rrd_parse_state == 7: | ||
155 | if self._rrd_level == 3: | ||
156 | self._rrd_ds_val["type"] = self._rrd_chars | ||
157 | self._rrd_parse_state = 4 # In <rrd><ds> | ||
158 | elif self._rrd_parse_state == 6: | ||
159 | if self._rrd_level == 3: | ||
160 | self._rrd_ds_val["name"] = self._rrd_chars | ||
161 | self._rrd_parse_state = 4 # In <rrd><ds> | ||
162 | elif self._rrd_parse_state == 5: | ||
163 | if self._rrd_level == 2: | ||
164 | self._rrd_parse_state = 1 # In <rrd> | ||
165 | elif self._rrd_parse_state == 4: | ||
166 | if self._rrd_level == 2: | ||
167 | self.rrd_ds.append(self._rrd_ds_val) | ||
168 | self._rrd_parse_state = 1 # In <rrd> | ||
169 | elif self._rrd_parse_state == 3: | ||
170 | if self._rrd_level == 2: | ||
171 | self.rrd_step = long(self._rrd_chars) | ||
172 | self._rrd_parse_state = 1 # In <rrd> | ||
173 | elif self._rrd_parse_state == 2: | ||
174 | if self._rrd_level == 2: | ||
175 | self.rrd_last_update = long(self._rrd_chars) | ||
176 | self._rrd_parse_state = 1 # In <rrd> | ||
177 | elif self._rrd_parse_state == 1: | ||
178 | if self._rrd_level == 1: | ||
179 | self._rrd_parse_state = 0 # At top | ||
180 | |||
181 | if self._rrd_level: | ||
182 | self._rrd_level = self._rrd_level - 1 | ||
183 | |||
184 | def characters(self, content): | ||
185 | if self._rrd_capture: | ||
186 | self._rrd_chars = self._rrd_chars + content.strip() | ||
187 | |||
188 | def _make_numeric(value): | ||
189 | try: | ||
190 | value = float(value) | ||
191 | except: | ||
192 | value = "" | ||
193 | return value | ||
194 | |||
195 | def simperf_host_xml_fixup(parser, filter_start_time = None, filter_end_time = None): | ||
196 | # Fixup for GAUGE fields that are really COUNTS. They | ||
197 | # were forced to GAUGE to try to disable rrdtool's | ||
198 | # data interpolation/extrapolation for non-uniform time | ||
199 | # samples. | ||
200 | fixup_tags = [ "cpu_user", | ||
201 | "cpu_nice", | ||
202 | "cpu_sys", | ||
203 | "cpu_idle", | ||
204 | "cpu_waitio", | ||
205 | "cpu_intr", | ||
206 | # "file_active", | ||
207 | # "file_free", | ||
208 | # "inode_active", | ||
209 | # "inode_free", | ||
210 | "netif_in_kb", | ||
211 | "netif_in_pkts", | ||
212 | "netif_in_errs", | ||
213 | "netif_in_drop", | ||
214 | "netif_out_kb", | ||
215 | "netif_out_pkts", | ||
216 | "netif_out_errs", | ||
217 | "netif_out_drop", | ||
218 | "vm_page_in", | ||
219 | "vm_page_out", | ||
220 | "vm_swap_in", | ||
221 | "vm_swap_out", | ||
222 | #"vm_mem_total", | ||
223 | #"vm_mem_used", | ||
224 | #"vm_mem_active", | ||
225 | #"vm_mem_inactive", | ||
226 | #"vm_mem_free", | ||
227 | #"vm_mem_buffer", | ||
228 | #"vm_swap_cache", | ||
229 | #"vm_swap_total", | ||
230 | #"vm_swap_used", | ||
231 | #"vm_swap_free", | ||
232 | "cpu_interrupts", | ||
233 | "cpu_switches", | ||
234 | "cpu_forks" ] | ||
235 | |||
236 | col_count = len(parser.rrd_ds) | ||
237 | row_count = len(parser.rrd_records) | ||
238 | |||
239 | # Process the last row separately, just to make all values numeric. | ||
240 | for j in range(col_count): | ||
241 | parser.rrd_records[row_count - 1][j] = _make_numeric(parser.rrd_records[row_count - 1][j]) | ||
242 | |||
243 | # Process all other row/columns. | ||
244 | last_different_row = row_count - 1 | ||
245 | current_row = row_count - 2 | ||
246 | while current_row >= 0: | ||
247 | # Check for a different value than the previous row. If everything is the same | ||
248 | # then this is probably just a filler/bogus entry. | ||
249 | is_different = False | ||
250 | for j in range(col_count): | ||
251 | parser.rrd_records[current_row][j] = _make_numeric(parser.rrd_records[current_row][j]) | ||
252 | if parser.rrd_records[current_row][j] != parser.rrd_records[last_different_row][j]: | ||
253 | # We're good. This is a different row. | ||
254 | is_different = True | ||
255 | |||
256 | if not is_different: | ||
257 | # This is a filler/bogus entry. Just ignore it. | ||
258 | for j in range(col_count): | ||
259 | parser.rrd_records[current_row][j] = float('nan') | ||
260 | else: | ||
261 | # Some tags need to be converted into deltas. | ||
262 | for j in range(col_count): | ||
263 | if parser.rrd_ds[j]["name"] in fixup_tags: | ||
264 | parser.rrd_records[last_different_row][j] = \ | ||
265 | parser.rrd_records[last_different_row][j] - parser.rrd_records[current_row][j] | ||
266 | last_different_row = current_row | ||
267 | |||
268 | current_row -= 1 | ||
269 | |||
270 | # Set fixup_tags in the first row to 'nan' since they aren't useful anymore. | ||
271 | for j in range(col_count): | ||
272 | if parser.rrd_ds[j]["name"] in fixup_tags: | ||
273 | parser.rrd_records[0][j] = float('nan') | ||
274 | |||
275 | # Add a timestamp to each row and to the catalog. Format and name | ||
276 | # chosen to match other simulator logging (hopefully). | ||
277 | start_time = parser.rrd_last_update - (parser.rrd_step * (row_count - 1)) | ||
278 | # Build a filtered list of rrd_records if we are limited to a time range. | ||
279 | filter_records = False | ||
280 | if filter_start_time is not None or filter_end_time is not None: | ||
281 | filter_records = True | ||
282 | filtered_rrd_records = [] | ||
283 | if filter_start_time is None: | ||
284 | filter_start_time = start_time * 1000 | ||
285 | if filter_end_time is None: | ||
286 | filter_end_time = parser.rrd_last_update * 1000 | ||
287 | |||
288 | for i in range(row_count): | ||
289 | record_timestamp = (start_time + (i * parser.rrd_step)) * 1000 | ||
290 | parser.rrd_records[i].insert(0, record_timestamp) | ||
291 | if filter_records: | ||
292 | if filter_start_time <= record_timestamp and record_timestamp <= filter_end_time: | ||
293 | filtered_rrd_records.append(parser.rrd_records[i]) | ||
294 | |||
295 | if filter_records: | ||
296 | parser.rrd_records = filtered_rrd_records | ||
297 | |||
298 | parser.rrd_ds.insert(0, {"type": "GAUGE", "name": "javascript_timestamp"}) | ||
299 | |||
300 | |||
301 | def main(argv=None): | ||
302 | opts, args = getopt.getopt(sys.argv[1:], "i:o:h", ["in=", "out=", "help"]) | ||
303 | input_file = sys.stdin | ||
304 | output_file = sys.stdout | ||
305 | for o, a in opts: | ||
306 | if o in ("-i", "--in"): | ||
307 | input_file = open(a, 'r') | ||
308 | if o in ("-o", "--out"): | ||
309 | output_file = open(a, 'w') | ||
310 | if o in ("-h", "--help"): | ||
311 | usage() | ||
312 | sys.exit(0) | ||
313 | |||
314 | # Using the SAX parser as it is at least 4X faster and far, far | ||
315 | # smaller on this dataset than the DOM-based interface in xml.dom.minidom. | ||
316 | # With SAX and a 5.4MB xml file, this requires about seven seconds of | ||
317 | # wall-clock time and 32MB VSZ. With the DOM interface, about 22 seconds | ||
318 | # and over 270MB VSZ. | ||
319 | |||
320 | handler = SimPerfHostXMLParser() | ||
321 | sax.parse(input_file, handler) | ||
322 | if input_file != sys.stdin: | ||
323 | input_file.close() | ||
324 | |||
325 | # Various format fixups: string-to-num, gauge-to-counts, add | ||
326 | # a time stamp, etc. | ||
327 | simperf_host_xml_fixup(handler) | ||
328 | |||
329 | # Create JSONable dict with interesting data and format/print it | ||
330 | print >>output_file, simplejson.dumps({ "step" : handler.rrd_step, | ||
331 | "lastupdate": handler.rrd_last_update * 1000, | ||
332 | "ds" : handler.rrd_ds, | ||
333 | "database" : handler.rrd_records }) | ||
334 | |||
335 | return 0 | ||
336 | |||
337 | if __name__ == "__main__": | ||
338 | sys.exit(main()) | ||
diff --git a/linden/indra/lib/python/indra/util/simperf_oprof_interface.py b/linden/indra/lib/python/indra/util/simperf_oprof_interface.py new file mode 100755 index 0000000..c8d0f74 --- /dev/null +++ b/linden/indra/lib/python/indra/util/simperf_oprof_interface.py | |||
@@ -0,0 +1,160 @@ | |||
1 | #!/usr/bin/env python | ||
2 | """\ | ||
3 | @file simperf_oprof_interface.py | ||
4 | @brief Manage OProfile data collection on a host | ||
5 | |||
6 | $LicenseInfo:firstyear=2008&license=internal$ | ||
7 | |||
8 | Copyright (c) 2008-2009, Linden Research, Inc. | ||
9 | |||
10 | The following source code is PROPRIETARY AND CONFIDENTIAL. Use of | ||
11 | this source code is governed by the Linden Lab Source Code Disclosure | ||
12 | Agreement ("Agreement") previously entered between you and Linden | ||
13 | Lab. By accessing, using, copying, modifying or distributing this | ||
14 | software, you acknowledge that you have been informed of your | ||
15 | obligations under the Agreement and agree to abide by those obligations. | ||
16 | |||
17 | ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
18 | WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
19 | COMPLETENESS OR PERFORMANCE. | ||
20 | $/LicenseInfo$ | ||
21 | """ | ||
22 | |||
23 | import sys, os, getopt | ||
24 | import simplejson | ||
25 | |||
26 | |||
27 | def usage(): | ||
28 | print "Usage:" | ||
29 | print sys.argv[0] + " [options]" | ||
30 | print " Digest the OProfile report forms that come out of the" | ||
31 | print " simperf_oprof_ctl program's -r/--report command. The result" | ||
32 | print " is an array of dictionaires with the following keys:" | ||
33 | |||
34 | print " symbol Name of sampled, calling, or called procedure" | ||
35 | print " file Executable or library where symbol resides" | ||
36 | print " percentage Percentage contribution to profile, calls or called" | ||
37 | print " samples Sample count" | ||
38 | print " calls Methods called by the method in question (full only)" | ||
39 | print " called_by Methods calling the method (full only)" | ||
40 | |||
41 | print " For 'full' reports the two keys 'calls' and 'called_by' are" | ||
42 | print " themselves arrays of dictionaries based on the first four keys." | ||
43 | |||
44 | print "Return Codes:" | ||
45 | print " None. Aggressively digests everything. Will likely mung results" | ||
46 | print " if a program or library has whitespace in its name." | ||
47 | |||
48 | print "Options:" | ||
49 | print " -i, --in Input settings filename. (Default: stdin)" | ||
50 | print " -o, --out Output settings filename. (Default: stdout)" | ||
51 | print " -h, --help Print this message and exit." | ||
52 | |||
53 | print "Interfaces:" | ||
54 | print " class SimPerfOProfileInterface()" | ||
55 | |||
56 | class SimPerfOProfileInterface: | ||
57 | def __init__(self): | ||
58 | self.isBrief = True # public | ||
59 | self.isValid = False # public | ||
60 | self.result = [] # public | ||
61 | |||
62 | def parse(self, input): | ||
63 | in_samples = False | ||
64 | for line in input: | ||
65 | if in_samples: | ||
66 | if line[0:6] == "------": | ||
67 | self.isBrief = False | ||
68 | self._parseFull(input) | ||
69 | else: | ||
70 | self._parseBrief(input, line) | ||
71 | self.isValid = True | ||
72 | return | ||
73 | try: | ||
74 | hd1, remain = line.split(None, 1) | ||
75 | if hd1 == "samples": | ||
76 | in_samples = True | ||
77 | except ValueError: | ||
78 | pass | ||
79 | |||
80 | def _parseBrief(self, input, line1): | ||
81 | try: | ||
82 | fld1, fld2, fld3, fld4 = line1.split(None, 3) | ||
83 | self.result.append({"samples" : fld1, | ||
84 | "percentage" : fld2, | ||
85 | "file" : fld3, | ||
86 | "symbol" : fld4.strip("\n")}) | ||
87 | except ValueError: | ||
88 | pass | ||
89 | for line in input: | ||
90 | try: | ||
91 | fld1, fld2, fld3, fld4 = line.split(None, 3) | ||
92 | self.result.append({"samples" : fld1, | ||
93 | "percentage" : fld2, | ||
94 | "file" : fld3, | ||
95 | "symbol" : fld4.strip("\n")}) | ||
96 | except ValueError: | ||
97 | pass | ||
98 | |||
99 | def _parseFull(self, input): | ||
100 | state = 0 # In 'called_by' section | ||
101 | calls = [] | ||
102 | called_by = [] | ||
103 | current = {} | ||
104 | for line in input: | ||
105 | if line[0:6] == "------": | ||
106 | if len(current): | ||
107 | current["calls"] = calls | ||
108 | current["called_by"] = called_by | ||
109 | self.result.append(current) | ||
110 | state = 0 | ||
111 | calls = [] | ||
112 | called_by = [] | ||
113 | current = {} | ||
114 | else: | ||
115 | try: | ||
116 | fld1, fld2, fld3, fld4 = line.split(None, 3) | ||
117 | tmp = {"samples" : fld1, | ||
118 | "percentage" : fld2, | ||
119 | "file" : fld3, | ||
120 | "symbol" : fld4.strip("\n")} | ||
121 | except ValueError: | ||
122 | continue | ||
123 | if line[0] != " ": | ||
124 | current = tmp | ||
125 | state = 1 # In 'calls' section | ||
126 | elif state == 0: | ||
127 | called_by.append(tmp) | ||
128 | else: | ||
129 | calls.append(tmp) | ||
130 | if len(current): | ||
131 | current["calls"] = calls | ||
132 | current["called_by"] = called_by | ||
133 | self.result.append(current) | ||
134 | |||
135 | |||
136 | def main(argv=None): | ||
137 | opts, args = getopt.getopt(sys.argv[1:], "i:o:h", ["in=", "out=", "help"]) | ||
138 | input_file = sys.stdin | ||
139 | output_file = sys.stdout | ||
140 | for o, a in opts: | ||
141 | if o in ("-i", "--in"): | ||
142 | input_file = open(a, 'r') | ||
143 | if o in ("-o", "--out"): | ||
144 | output_file = open(a, 'w') | ||
145 | if o in ("-h", "--help"): | ||
146 | usage() | ||
147 | sys.exit(0) | ||
148 | |||
149 | oprof = SimPerfOProfileInterface() | ||
150 | oprof.parse(input_file) | ||
151 | if input_file != sys.stdin: | ||
152 | input_file.close() | ||
153 | |||
154 | # Create JSONable dict with interesting data and format/print it | ||
155 | print >>output_file, simplejson.dumps(oprof.result) | ||
156 | |||
157 | return 0 | ||
158 | |||
159 | if __name__ == "__main__": | ||
160 | sys.exit(main()) | ||
diff --git a/linden/indra/lib/python/indra/util/simperf_proc_interface.py b/linden/indra/lib/python/indra/util/simperf_proc_interface.py new file mode 100755 index 0000000..62a63fa --- /dev/null +++ b/linden/indra/lib/python/indra/util/simperf_proc_interface.py | |||
@@ -0,0 +1,164 @@ | |||
1 | #!/usr/bin/python | ||
2 | |||
3 | # ---------------------------------------------------- | ||
4 | # Utility to extract log messages from *.<pid>.llsd | ||
5 | # files that contain performance statistics. | ||
6 | |||
7 | # ---------------------------------------------------- | ||
8 | import sys, os | ||
9 | |||
10 | if os.path.exists("setup-path.py"): | ||
11 | execfile("setup-path.py") | ||
12 | |||
13 | from indra.base import llsd | ||
14 | |||
15 | DEFAULT_PATH="/dev/shm/simperf/" | ||
16 | |||
17 | |||
18 | # ---------------------------------------------------- | ||
19 | # Pull out the stats and return a single document | ||
20 | def parse_logfile(filename, target_column=None, verbose=False): | ||
21 | full_doc = [] | ||
22 | # Open source temp log file. Let exceptions percolate up. | ||
23 | sourcefile = open( filename,'r') | ||
24 | |||
25 | if verbose: | ||
26 | print "Reading " + filename | ||
27 | |||
28 | # Parse and output all lines from the temp file | ||
29 | for line in sourcefile.xreadlines(): | ||
30 | partial_doc = llsd.parse(line) | ||
31 | if partial_doc is not None: | ||
32 | if target_column is None: | ||
33 | full_doc.append(partial_doc) | ||
34 | else: | ||
35 | trim_doc = { target_column: partial_doc[target_column] } | ||
36 | if target_column != "fps": | ||
37 | trim_doc[ 'fps' ] = partial_doc[ 'fps' ] | ||
38 | trim_doc[ '/total_time' ] = partial_doc[ '/total_time' ] | ||
39 | trim_doc[ 'utc_time' ] = partial_doc[ 'utc_time' ] | ||
40 | full_doc.append(trim_doc) | ||
41 | |||
42 | sourcefile.close() | ||
43 | return full_doc | ||
44 | |||
45 | # Extract just the meta info line, and the timestamp of the first/last frame entry. | ||
46 | def parse_logfile_info(filename, verbose=False): | ||
47 | # Open source temp log file. Let exceptions percolate up. | ||
48 | sourcefile = open(filename, 'rU') # U is to open with Universal newline support | ||
49 | |||
50 | if verbose: | ||
51 | print "Reading " + filename | ||
52 | |||
53 | # The first line is the meta info line. | ||
54 | info_line = sourcefile.readline() | ||
55 | if not info_line: | ||
56 | sourcefile.close() | ||
57 | return None | ||
58 | |||
59 | # The rest of the lines are frames. Read the first and last to get the time range. | ||
60 | info = llsd.parse( info_line ) | ||
61 | info['start_time'] = None | ||
62 | info['end_time'] = None | ||
63 | first_frame = sourcefile.readline() | ||
64 | if first_frame: | ||
65 | try: | ||
66 | info['start_time'] = int(llsd.parse(first_frame)['timestamp']) | ||
67 | except: | ||
68 | pass | ||
69 | |||
70 | # Read the file backwards to find the last two lines. | ||
71 | sourcefile.seek(0, 2) | ||
72 | file_size = sourcefile.tell() | ||
73 | offset = 1024 | ||
74 | num_attempts = 0 | ||
75 | end_time = None | ||
76 | if file_size < offset: | ||
77 | offset = file_size | ||
78 | while 1: | ||
79 | sourcefile.seek(-1*offset, 2) | ||
80 | read_str = sourcefile.read(offset) | ||
81 | # Remove newline at the end | ||
82 | if read_str[offset - 1] == '\n': | ||
83 | read_str = read_str[0:-1] | ||
84 | lines = read_str.split('\n') | ||
85 | full_line = None | ||
86 | if len(lines) > 2: # Got two line | ||
87 | try: | ||
88 | end_time = llsd.parse(lines[-1])['timestamp'] | ||
89 | except: | ||
90 | # We couldn't parse this line. Try once more. | ||
91 | try: | ||
92 | end_time = llsd.parse(lines[-2])['timestamp'] | ||
93 | except: | ||
94 | # Nope. Just move on. | ||
95 | pass | ||
96 | break | ||
97 | if len(read_str) == file_size: # Reached the beginning | ||
98 | break | ||
99 | offset += 1024 | ||
100 | |||
101 | info['end_time'] = int(end_time) | ||
102 | |||
103 | sourcefile.close() | ||
104 | return info | ||
105 | |||
106 | |||
107 | def parse_proc_filename(filename): | ||
108 | try: | ||
109 | name_as_list = filename.split(".") | ||
110 | cur_stat_type = name_as_list[0].split("_")[0] | ||
111 | cur_pid = name_as_list[1] | ||
112 | except IndexError, ValueError: | ||
113 | return (None, None) | ||
114 | return (cur_pid, cur_stat_type) | ||
115 | |||
116 | # ---------------------------------------------------- | ||
117 | def get_simstats_list(path=None): | ||
118 | """ Return stats (pid, type) listed in <type>_proc.<pid>.llsd """ | ||
119 | if path is None: | ||
120 | path = DEFAULT_PATH | ||
121 | simstats_list = [] | ||
122 | for file_name in os.listdir(path): | ||
123 | if file_name.endswith(".llsd") and file_name != "simperf_proc_config.llsd": | ||
124 | simstats_info = parse_logfile_info(path + file_name) | ||
125 | if simstats_info is not None: | ||
126 | simstats_list.append(simstats_info) | ||
127 | return simstats_list | ||
128 | |||
129 | def get_log_info_list(pid=None, stat_type=None, path=None, target_column=None, verbose=False): | ||
130 | """ Return data from all llsd files matching the pid and stat type """ | ||
131 | if path is None: | ||
132 | path = DEFAULT_PATH | ||
133 | log_info_list = {} | ||
134 | for file_name in os.listdir ( path ): | ||
135 | if file_name.endswith(".llsd") and file_name != "simperf_proc_config.llsd": | ||
136 | (cur_pid, cur_stat_type) = parse_proc_filename(file_name) | ||
137 | if cur_pid is None: | ||
138 | continue | ||
139 | if pid is not None and pid != cur_pid: | ||
140 | continue | ||
141 | if stat_type is not None and stat_type != cur_stat_type: | ||
142 | continue | ||
143 | log_info_list[cur_pid] = parse_logfile(path + file_name, target_column, verbose) | ||
144 | return log_info_list | ||
145 | |||
146 | def delete_simstats_files(pid=None, stat_type=None, path=None): | ||
147 | """ Delete *.<pid>.llsd files """ | ||
148 | if path is None: | ||
149 | path = DEFAULT_PATH | ||
150 | del_list = [] | ||
151 | for file_name in os.listdir(path): | ||
152 | if file_name.endswith(".llsd") and file_name != "simperf_proc_config.llsd": | ||
153 | (cur_pid, cur_stat_type) = parse_proc_filename(file_name) | ||
154 | if cur_pid is None: | ||
155 | continue | ||
156 | if pid is not None and pid != cur_pid: | ||
157 | continue | ||
158 | if stat_type is not None and stat_type != cur_stat_type: | ||
159 | continue | ||
160 | del_list.append(cur_pid) | ||
161 | # Allow delete related exceptions to percolate up if this fails. | ||
162 | os.unlink(os.path.join(DEFAULT_PATH, file_name)) | ||
163 | return del_list | ||
164 | |||
diff --git a/linden/indra/lib/python/indra/util/term.py b/linden/indra/lib/python/indra/util/term.py index 8238b78..8c316a1 100644 --- a/linden/indra/lib/python/indra/util/term.py +++ b/linden/indra/lib/python/indra/util/term.py | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | $LicenseInfo:firstyear=2007&license=mit$ | 5 | $LicenseInfo:firstyear=2007&license=mit$ |
6 | 6 | ||
7 | Copyright (c) 2007-2008, Linden Research, Inc. | 7 | Copyright (c) 2007-2009, Linden Research, Inc. |
8 | 8 | ||
9 | Permission is hereby granted, free of charge, to any person obtaining a copy | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | of this software and associated documentation files (the "Software"), to deal | 10 | of this software and associated documentation files (the "Software"), to deal |