This commit is contained in:
Shyotl
2019-07-03 19:42:40 -05:00
149 changed files with 3062 additions and 9386 deletions

View File

@@ -585,6 +585,40 @@
<key>version</key> <key>version</key>
<string>1</string> <string>1</string>
</map> </map>
<key>discord-rpc</key>
<map>
<key>canonical_repo</key>
<string>https://bitbucket.org/alchemyviewer/3p-discord-rpc</string>
<key>copyright</key>
<string>Copyright 2017 Discord, Inc.</string>
<key>description</key>
<string>Discord Remote Procedure Call library</string>
<key>license</key>
<string>MIT</string>
<key>license_file</key>
<string>LICENSES/discord-rpc.txt</string>
<key>name</key>
<string>discord-rpc</string>
<key>platforms</key>
<map>
<key>windows64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>76bd78e14034e9c518c1a201074d568a</string>
<key>hash_algorithm</key>
<string>md5</string>
<key>url</key>
<string>http://depot.alchemyviewer.org/pub/packages/windows64/msvc-1916/discord_rpc-3.4.0.190570542-windows64-190570542.tar.bz2</string>
</map>
<key>name</key>
<string>windows64</string>
</map>
</map>
<key>version</key>
<string>3.4.0.190570542</string>
</map>
<key>dullahan</key> <key>dullahan</key>
<map> <map>
<key>copyright</key> <key>copyright</key>
@@ -630,7 +664,7 @@
<key>archive</key> <key>archive</key>
<map> <map>
<key>hash</key> <key>hash</key>
<string>2ecc71350b30a1057091b9cd7af18b1c</string> <string>c3e093d40e93ff242e9b9c953ae7316c</string>
<key>url</key> <key>url</key>
<string>https://depot.alchemyviewer.org/pub/windows/lib-vc142/dullahan-1.1.930-3.3282.1733.g9091548-windows-201802202358.tar.bz2</string> <string>https://depot.alchemyviewer.org/pub/windows/lib-vc142/dullahan-1.1.930-3.3282.1733.g9091548-windows-201802202358.tar.bz2</string>
</map> </map>
@@ -768,7 +802,7 @@
<key>fmodstudio</key> <key>fmodstudio</key>
<map> <map>
<key>copyright</key> <key>copyright</key>
<string>FMOD Studio, copyright © Firelight Technologies Pty, Ltd., 1994-2015.</string> <string>FMOD Studio, copyright (c) Firelight Technologies Pty, Ltd., 2012-2017.</string>
<key>description</key> <key>description</key>
<string>FMOD Studio audio system library</string> <string>FMOD Studio audio system library</string>
<key>license</key> <key>license</key>
@@ -784,11 +818,11 @@
<key>archive</key> <key>archive</key>
<map> <map>
<key>hash</key> <key>hash</key>
<string>a2badcf46277f7547bab0963fe262696</string> <string>a3ccf7916d1e0b6f01370978b661c139</string>
<key>hash_algorithm</key> <key>hash_algorithm</key>
<string>md5</string> <string>md5</string>
<key>url</key> <key>url</key>
<string>https://bitbucket.org/alchemyviewer/publiclibs-darwin/downloads/fmodstudio-1.08.01-darwin-201604080928.tar.bz2</string> <string>https://depot.alchemyviewer.org/pub/darwin/lib/fmodstudio-1.10.02-darwin-201712262058.tar.bz2</string>
</map> </map>
<key>name</key> <key>name</key>
<string>darwin</string> <string>darwin</string>
@@ -812,11 +846,11 @@
<key>archive</key> <key>archive</key>
<map> <map>
<key>hash</key> <key>hash</key>
<string>be09dc1f144c936790236b94190815b4</string> <string>54dbd41322a08a1fc333ca6d96af5502</string>
<key>hash_algorithm</key> <key>hash_algorithm</key>
<string>md5</string> <string>md5</string>
<key>url</key> <key>url</key>
<string>https://depot.alchemyviewer.org/pub/linux64/lib/fmodstudio-1.08.04-linux64-201605301500.tar.bz2</string> <string>https://depot.alchemyviewer.org/pub/linux64/lib/fmodstudio-1.10.00-linux64-201709282320.tar.bz2</string>
</map> </map>
<key>name</key> <key>name</key>
<string>linux64</string> <string>linux64</string>
@@ -840,18 +874,18 @@
<key>archive</key> <key>archive</key>
<map> <map>
<key>hash</key> <key>hash</key>
<string>c2c45c2ebd9fd930098aa2a3b85bbe5f</string> <string>779ae33c6b84656295bd6cf50a69c830</string>
<key>hash_algorithm</key> <key>hash_algorithm</key>
<string>md5</string> <string>md5</string>
<key>url</key> <key>url</key>
<string>https://depot.alchemyviewer.org/pub/windows64/lib/fmodstudio-1.10.02-windows64-201712251435.tar.bz2</string> <string>http://depot.alchemyviewer.org/pub/packages/windows64/msvc/fmodstudio-1.10.10.190360453-windows64-190360453.tar.bz2</string>
</map> </map>
<key>name</key> <key>name</key>
<string>windows64</string> <string>windows64</string>
</map> </map>
</map> </map>
<key>version</key> <key>version</key>
<string>1.10.02</string> <string>1.10.10.190360453</string>
</map> </map>
<key>fontconfig</key> <key>fontconfig</key>
<map> <map>
@@ -1128,13 +1162,13 @@
<key>glod</key> <key>glod</key>
<map> <map>
<key>copyright</key> <key>copyright</key>
<string>Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University and David Luebke, Brenden Schubert, University of Virginia. All rights reserved.</string> <string>Copyright 2003 Jonathan Cohen, Nat Duca, David Luebke, Brenden Schubert - Johns Hopkins University and University of Virginia</string>
<key>description</key> <key>description</key>
<string>Geometric Level of Detail library</string> <string>Geometric Level of Detail library</string>
<key>license</key> <key>license</key>
<string>GLOD Open-Source License 1.0</string> <string>GLOD Open-Source License Version 1.0</string>
<key>license_file</key> <key>license_file</key>
<string>LICENSES/glod.txt</string> <string>LICENSES/GLOD.txt</string>
<key>name</key> <key>name</key>
<string>glod</string> <string>glod</string>
<key>platforms</key> <key>platforms</key>
@@ -1144,23 +1178,37 @@
<key>archive</key> <key>archive</key>
<map> <map>
<key>hash</key> <key>hash</key>
<string>6c6b3b06a4305c2da0aad1de132e6a07</string> <string>71e678d70e276fc42a56926fc28a7abd</string>
<key>hash_algorithm</key> <key>hash_algorithm</key>
<string>md5</string> <string>md5</string>
<key>url</key> <key>url</key>
<string>https://bitbucket.org/alchemyviewer/publiclibs-darwin/downloads/glod-1.0pre4-darwin-201511222034.tar.bz2</string> <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/glod_3p-update-glod/rev/296895/arch/Darwin/installer/glod-1.0pre4.296895-darwin-296895.tar.bz2</string>
</map> </map>
<key>name</key> <key>name</key>
<string>darwin</string> <string>darwin</string>
</map> </map>
<key>darwin64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>017ef34ddf14293099a90c6eaa3615ca</string>
<key>url</key>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/1626/3627/glod-1.0pre3.501614-darwin64-501614.tar.bz2</string>
</map>
<key>name</key>
<string>darwin64</string>
</map>
<key>linux</key> <key>linux</key>
<map> <map>
<key>archive</key> <key>archive</key>
<map> <map>
<key>hash</key> <key>hash</key>
<string>176736c52b3cde6ca8e7d9e173d91731</string> <string>58113bcbbacbaeb2d278f745867ae6f0</string>
<key>hash_algorithm</key>
<string>md5</string>
<key>url</key> <key>url</key>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-glod/rev/268002/arch/Linux/installer/glod-1.0pre4-linux-20121212.tar.bz2</string> <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-glod/rev/314201/arch/Linux/installer/glod-1.0pre4.314201-linux-314201.tar.bz2</string>
</map> </map>
<key>name</key> <key>name</key>
<string>linux</string> <string>linux</string>
@@ -1170,11 +1218,9 @@
<key>archive</key> <key>archive</key>
<map> <map>
<key>hash</key> <key>hash</key>
<string>f7172928ba2201d4b9aeb2c70d7a55b9</string> <string>9aef5cd576ace19568da01d9bc3db29c</string>
<key>hash_algorithm</key>
<string>md5</string>
<key>url</key> <key>url</key>
<string>http://depot.alchemyviewer.org/pub/linux64/lib-trusty/glod-1.0pre4-linux64-201603240031.tar.bz2</string> <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/1625/3628/glod-1.0pre3.501614-linux64-501614.tar.bz2</string>
</map> </map>
<key>name</key> <key>name</key>
<string>linux64</string> <string>linux64</string>
@@ -1184,11 +1230,11 @@
<key>archive</key> <key>archive</key>
<map> <map>
<key>hash</key> <key>hash</key>
<string>37035aad7d066dfe6f26dc009aa9dcea</string> <string>573e68f46f825a1c040daa4994ee2a61</string>
<key>hash_algorithm</key> <key>hash_algorithm</key>
<string>md5</string> <string>md5</string>
<key>url</key> <key>url</key>
<string>https://depot.alchemyviewer.org/pub/windows/lib-vc141/glod-1.0pre4-windows-201703090622.tar.bz2</string> <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/1627/3633/glod-1.0pre3.501614-windows-501614.tar.bz2</string>
</map> </map>
<key>name</key> <key>name</key>
<string>windows</string> <string>windows</string>
@@ -1198,18 +1244,18 @@
<key>archive</key> <key>archive</key>
<map> <map>
<key>hash</key> <key>hash</key>
<string>c5c04c164ff057a43928de2f2b83470e</string> <string>c122ba644e8ec146b4742428b799d749</string>
<key>hash_algorithm</key> <key>hash_algorithm</key>
<string>md5</string> <string>md5</string>
<key>url</key> <key>url</key>
<string>https://depot.alchemyviewer.org/pub/windows64/lib-vc142/glod-1.0pre4-windows64-201712251340.tar.bz2</string> <string>http://depot.alchemyviewer.org/pub/packages/windows64/msvc-1916/glod-1.0pre3.190390340-windows64-190390340.tar.bz2</string>
</map> </map>
<key>name</key> <key>name</key>
<string>windows64</string> <string>windows64</string>
</map> </map>
</map> </map>
<key>version</key> <key>version</key>
<string>1.0pre4</string> <string>1.0pre3.190390340</string>
</map> </map>
<key>google_breakpad</key> <key>google_breakpad</key>
<map> <map>
@@ -1218,7 +1264,7 @@
<key>description</key> <key>description</key>
<string>Breakpad is a crossplatform library for capturing crash callstacks and runtime data.</string> <string>Breakpad is a crossplatform library for capturing crash callstacks and runtime data.</string>
<key>license</key> <key>license</key>
<string>BSD</string> <string>bsd</string>
<key>license_file</key> <key>license_file</key>
<string>LICENSES/google_breakpad.txt</string> <string>LICENSES/google_breakpad.txt</string>
<key>name</key> <key>name</key>
@@ -1239,6 +1285,18 @@
<key>name</key> <key>name</key>
<string>darwin</string> <string>darwin</string>
</map> </map>
<key>darwin64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>2d43c6a149cd9c89ba19e884579b1e25</string>
<key>url</key>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/1836/4096/google_breakpad-1413.501824-darwin64-501824.tar.bz2</string>
</map>
<key>name</key>
<string>darwin64</string>
</map>
<key>linux</key> <key>linux</key>
<map> <map>
<key>archive</key> <key>archive</key>
@@ -2400,11 +2458,11 @@
<key>archive</key> <key>archive</key>
<map> <map>
<key>hash</key> <key>hash</key>
<string>68a8fab5ad3a180487598d3a3e0d57b1</string> <string>b1b0134bc55f55a7c1a04ee78d70c64d</string>
<key>hash_algorithm</key> <key>hash_algorithm</key>
<string>md5</string> <string>md5</string>
<key>url</key> <key>url</key>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/slvoice_3p-update-slvoice/rev/298329/arch/Darwin/installer/slvoice-4.6.0017.21209.298329-darwin-298329.tar.bz2</string> <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/12438/73598/slvoice-4.9.0002.27586.511884-darwin64-511884.tar.bz2</string>
</map> </map>
<key>name</key> <key>name</key>
<string>darwin</string> <string>darwin</string>
@@ -2440,18 +2498,32 @@
<key>archive</key> <key>archive</key>
<map> <map>
<key>hash</key> <key>hash</key>
<string>5a78539626b5f23522d0b466247f48b4</string> <string>ec50c31efce74bdedee470b5388aeeec</string>
<key>hash_algorithm</key> <key>hash_algorithm</key>
<string>md5</string> <string>md5</string>
<key>url</key> <key>url</key>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/21422/157291/slvoice-4.9.0002.30313.517593-windows-517593.tar.bz2</string> <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/12434/73576/slvoice-4.9.0002.27586.511884-windows-511884.tar.bz2</string>
</map> </map>
<key>name</key> <key>name</key>
<string>windows</string> <string>windows</string>
</map> </map>
<key>windows64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>4bf45d641bf5b2bd6b2cc39edcb01a6e</string>
<key>hash_algorithm</key>
<string>md5</string>
<key>url</key>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/12433/73570/slvoice-4.9.0002.27586.511884-windows64-511884.tar.bz2</string>
</map>
<key>name</key>
<string>windows64</string>
</map>
</map> </map>
<key>version</key> <key>version</key>
<string>4.6.0017.22050</string> <string>4.9.0002.27586.511884</string>
</map> </map>
<key>tut</key> <key>tut</key>
<map> <map>
@@ -2571,30 +2643,50 @@
<key>version</key> <key>version</key>
<string>0.8.4</string> <string>0.8.4</string>
</map> </map>
<key>vcredist</key> <key>vlc-bin</key>
<map> <map>
<key>copyright</key> <key>copyright</key>
<string>Copyright (c) Microsoft Corporation. All rights reserved.</string> <string>Copyright (C) 1998-2016 VLC authors and VideoLAN</string>
<key>description</key>
<string>The Visual Studio C and C++ runtime redistributable</string>
<key>license</key> <key>license</key>
<string>Proprietary</string> <string>GPL2</string>
<key>license_file</key> <key>license_file</key>
<string>LICENSES/vcredist.txt</string> <string>LICENSES/vlc.txt</string>
<key>name</key> <key>name</key>
<string>vcredist</string> <string>vlc-bin</string>
<key>platforms</key> <key>platforms</key>
<map> <map>
<key>darwin64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>e5635e173c75dc0675b48ab5f5e4868b</string>
<key>url</key>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/12143/71451/vlc_bin-2.2.8.511703-darwin64-511703.tar.bz2</string>
</map>
<key>name</key>
<string>darwin64</string>
</map>
<key>linux</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>2f410640df3f9812d1abff02a414cfa8</string>
<key>url</key>
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-vlc-bin/rev/315283/arch/Linux/vlc_bin-2.2.3-linux-201606011750-r10.tar.bz2</string>
</map>
<key>name</key>
<string>linux</string>
</map>
<key>windows</key> <key>windows</key>
<map> <map>
<key>archive</key> <key>archive</key>
<map> <map>
<key>hash</key> <key>hash</key>
<string>f193ec9e594d857d22c067c6e52622a9</string> <string>add560654a53cb1c554044a4fac3c718</string>
<key>hash_algorithm</key>
<string>md5</string>
<key>url</key> <key>url</key>
<string>https://depot.alchemyviewer.org/pub/windows/lib-vc141/vcredist-14.10.25017.0-windows-201705270440.tar.bz2</string> <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/12144/71458/vlc_bin-2.2.8.511703-windows-511703.tar.bz2</string>
</map> </map>
<key>name</key> <key>name</key>
<string>windows</string> <string>windows</string>
@@ -2604,18 +2696,16 @@
<key>archive</key> <key>archive</key>
<map> <map>
<key>hash</key> <key>hash</key>
<string>e895f4b5d24b372a360c3a8fe3bc0398</string> <string>94bf04b49acc1e1bf2c06e2232f8a083</string>
<key>hash_algorithm</key>
<string>md5</string>
<key>url</key> <key>url</key>
<string>https://depot.alchemyviewer.org/pub/windows64/lib-vc142/vcredist-14.12.25810.0-windows64-201712251445.tar.bz2</string> <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/12145/71463/vlc_bin-2.2.8.511703-windows64-511703.tar.bz2</string>
</map> </map>
<key>name</key> <key>name</key>
<string>windows64</string> <string>windows64</string>
</map> </map>
</map> </map>
<key>version</key> <key>version</key>
<string>14.12.25810.0</string> <string>2.2.8.511703</string>
</map> </map>
<key>xmlrpc-epi</key> <key>xmlrpc-epi</key>
<map> <map>
@@ -2821,7 +2911,7 @@
<key>options</key> <key>options</key>
<array> <array>
<string>-DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo</string> <string>-DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo</string>
<string>-DWORD_SIZE:STRING=32</string> <string>-DWORD_SIZE:STRING=$AUTOBUILD_ADDRSIZE</string>
<string>-DROOT_PROJECT_NAME:STRING=Singularity</string> <string>-DROOT_PROJECT_NAME:STRING=Singularity</string>
<string>-DINSTALL_PROPRIETARY=FALSE</string> <string>-DINSTALL_PROPRIETARY=FALSE</string>
</array> </array>
@@ -2842,7 +2932,7 @@
<key>options</key> <key>options</key>
<array> <array>
<string>-DCMAKE_BUILD_TYPE:STRING=Release</string> <string>-DCMAKE_BUILD_TYPE:STRING=Release</string>
<string>-DWORD_SIZE:STRING=32</string> <string>-DWORD_SIZE:STRING=$AUTOBUILD_ADDRSIZE</string>
<string>-DROOT_PROJECT_NAME:STRING=Singularity</string> <string>-DROOT_PROJECT_NAME:STRING=Singularity</string>
<string>-DINSTALL_PROPRIETARY=FALSE</string> <string>-DINSTALL_PROPRIETARY=FALSE</string>
</array> </array>
@@ -2936,7 +3026,7 @@
<key>options</key> <key>options</key>
<array> <array>
<string>-G</string> <string>-G</string>
<string>'Unix Makefiles'</string> <string>Unix Makefiles</string>
</array> </array>
</map> </map>
<key>default</key> <key>default</key>
@@ -2960,7 +3050,7 @@
<key>options</key> <key>options</key>
<array> <array>
<string>-G</string> <string>-G</string>
<string>'Unix Makefiles'</string> <string>Unix Makefiles</string>
</array> </array>
</map> </map>
<key>name</key> <key>name</key>
@@ -2992,7 +3082,7 @@
<key>options</key> <key>options</key>
<array> <array>
<string>-G</string> <string>-G</string>
<string>'Unix Makefiles'</string> <string>Unix Makefiles</string>
<string>-DWORD_SIZE:STRING=64</string> <string>-DWORD_SIZE:STRING=64</string>
</array> </array>
</map> </map>
@@ -3017,7 +3107,7 @@
<key>options</key> <key>options</key>
<array> <array>
<string>-G</string> <string>-G</string>
<string>'Unix Makefiles'</string> <string>Unix Makefiles</string>
<string>-DWORD_SIZE:STRING=64</string> <string>-DWORD_SIZE:STRING=64</string>
</array> </array>
</map> </map>
@@ -3031,7 +3121,7 @@
<key>windows</key> <key>windows</key>
<map> <map>
<key>build_directory</key> <key>build_directory</key>
<string>build-vc141</string> <string>build-vc$AUTOBUILD_WIN_VSVER-$AUTOBUILD_ADDRSIZE</string>
<key>configurations</key> <key>configurations</key>
<map> <map>
<key>RelWithDebInfo</key> <key>RelWithDebInfo</key>
@@ -3063,9 +3153,11 @@
<key>options</key> <key>options</key>
<array> <array>
<string>-G</string> <string>-G</string>
<string>"Visual Studio 15"</string> <string>${AUTOBUILD_WIN_CMAKE_GEN|NOTWIN}</string>
<string>-DCMAKE_SYSTEM_VERSION="10.0.16299.0"</string> <string>-A</string>
<string>-DINSTALL_PROPRIETARY=FALSE</string> <string>${AUTOBUILD_WIN_VSPLATFORM|NOTWIN}</string>
<string>-T</string>
<string>host=${AUTOBUILD_WIN_VSHOST|NOTWIN}</string>
</array> </array>
</map> </map>
<key>default</key> <key>default</key>
@@ -3086,7 +3178,7 @@
<key>options</key> <key>options</key>
<array> <array>
<string>/p:Configuration=Release</string> <string>/p:Configuration=Release</string>
<string>/p:Platform=Win32</string> <string>/p:Platform=${AUTOBUILD_WIN_VSPLATFORM|NOTWIN}</string>
<string>/t:Build</string> <string>/t:Build</string>
<string>/p:useenv=true</string> <string>/p:useenv=true</string>
<string>/verbosity:normal</string> <string>/verbosity:normal</string>
@@ -3102,96 +3194,11 @@
<key>options</key> <key>options</key>
<array> <array>
<string>-G</string> <string>-G</string>
<string>"Visual Studio 15"</string> <string>${AUTOBUILD_WIN_CMAKE_GEN|NOTWIN}</string>
<string>-DCMAKE_SYSTEM_VERSION="10.0.16299.0"</string> <string>-A</string>
<string>-DINSTALL_PROPRIETARY=FALSE</string> <string>${AUTOBUILD_WIN_VSPLATFORM|NOTWIN}</string>
</array> <string>-T</string>
</map> <string>host=${AUTOBUILD_WIN_VSHOST|NOTWIN}</string>
<key>name</key>
<string>Release</string>
</map>
</map>
<key>name</key>
<string>windows</string>
</map>
<key>windows64</key>
<map>
<key>build_directory</key>
<string>build-vc141-x86_64</string>
<key>configurations</key>
<map>
<key>RelWithDebInfo</key>
<map>
<key>build</key>
<map>
<key>arguments</key>
<array>
<string>Singularity.sln</string>
</array>
<key>command</key>
<string>msbuild.exe</string>
<key>options</key>
<array>
<string>/p:Configuration=RelWithDebInfo</string>
<string>/p:Platform=x64</string>
<string>/t:Build</string>
<string>/p:useenv=true</string>
<string>/verbosity:normal</string>
<string>/m</string>
</array>
</map>
<key>configure</key>
<map>
<key>arguments</key>
<array>
<string>..\indra</string>
</array>
<key>options</key>
<array>
<string>-G</string>
<string>"Visual Studio 15 Win64"</string>
<string>-DCMAKE_SYSTEM_VERSION="10.0.16299.0"</string>
<string>-DWORD_SIZE:STRING=64</string>
<string>-DINSTALL_PROPRIETARY=FALSE</string>
</array>
</map>
<key>default</key>
<string>True</string>
<key>name</key>
<string>RelWithDebInfo</string>
</map>
<key>Release</key>
<map>
<key>build</key>
<map>
<key>arguments</key>
<array>
<string>Singularity.sln</string>
</array>
<key>command</key>
<string>msbuild.exe</string>
<key>options</key>
<array>
<string>/p:Configuration=Release</string>
<string>/p:Platform=x64</string>
<string>/t:Build</string>
<string>/p:useenv=true</string>
<string>/verbosity:normal</string>
<string>/m</string>
</array>
</map>
<key>configure</key>
<map>
<key>arguments</key>
<array>
<string>..\indra</string>
</array>
<key>options</key>
<array>
<string>-G</string>
<string>"Visual Studio 15 Win64"</string>
<string>-DCMAKE_SYSTEM_VERSION="10.0.16299.0"</string>
<string>-DWORD_SIZE:STRING=64</string>
<string>-DINSTALL_PROPRIETARY=FALSE</string> <string>-DINSTALL_PROPRIETARY=FALSE</string>
</array> </array>
</map> </map>

View File

@@ -1,6 +1,6 @@
# -*- cmake -*- # -*- cmake -*-
if (WINDOWS) if (WINDOWS)
message(WARNING, ${CMAKE_CURRENT_BINARY_DIR}/newview/viewerRes.rc.in) #message(WARNING, ${CMAKE_CURRENT_BINARY_DIR}/newview/viewerRes.rc.in)
configure_file( configure_file(
${CMAKE_SOURCE_DIR}/newview/res/viewerRes.rc.in ${CMAKE_SOURCE_DIR}/newview/res/viewerRes.rc.in
${CMAKE_CURRENT_BINARY_DIR}/viewerRes.rc ${CMAKE_CURRENT_BINARY_DIR}/viewerRes.rc

View File

@@ -3,9 +3,18 @@
include(Python) include(Python)
include(Variables) include(Variables)
# packages-formatter.py runs autobuild install --versions, which needs to know
# the build_directory, which (on Windows) depends on AUTOBUILD_ADDRSIZE.
# Within an autobuild build, AUTOBUILD_ADDRSIZE is already set. But when
# building in an IDE, it probably isn't. Set it explicitly using
# run_build_test.py.
add_custom_command(OUTPUT packages-info.txt add_custom_command(OUTPUT packages-info.txt
COMMENT "Generating packages-info.txt for the about box" COMMENT Generating packages-info.txt for the about box
MAIN_DEPENDENCY ${CMAKE_SOURCE_DIR}/../autobuild.xml MAIN_DEPENDENCY ${CMAKE_SOURCE_DIR}/../autobuild.xml
DEPENDS ${CMAKE_SOURCE_DIR}/../scripts/packages-formatter.py DEPENDS ${CMAKE_SOURCE_DIR}/../scripts/packages-formatter.py
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/../scripts/packages-formatter.py -p=${AUTOBUILD_PLATFORM_NAME} > packages-info.txt ${CMAKE_SOURCE_DIR}/../autobuild.xml
COMMAND ${PYTHON_EXECUTABLE}
${CMAKE_SOURCE_DIR}/cmake/run_build_test.py -DAUTOBUILD_ADDRSIZE=${ADDRESS_SIZE}
${PYTHON_EXECUTABLE}
${CMAKE_SOURCE_DIR}/../scripts/packages-formatter.py "${VIEWER_CHANNEL}" "${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}" > packages-info.txt
) )

View File

@@ -46,7 +46,7 @@ if (NOT DEFINED VIEWER_SHORT_VERSION) # will be true in indra/, false in indra/n
set(VIEWER_CHANNEL_VERSION_DEFINES set(VIEWER_CHANNEL_VERSION_DEFINES
"LL_VIEWER_CHANNEL=\"${VIEWER_CHANNEL}\"" "LL_VIEWER_CHANNEL=\"${VIEWER_CHANNEL}\""
"LL_VIEWER_CHANNEL_GRK=\"${VIEWER_CHANNEL_GRK}\"" "LL_VIEWER_CHANNEL_GRK=L\"${VIEWER_CHANNEL_GRK}\""
"LL_VIEWER_VERSION_MAJOR=${VIEWER_VERSION_MAJOR}" "LL_VIEWER_VERSION_MAJOR=${VIEWER_VERSION_MAJOR}"
"LL_VIEWER_VERSION_MINOR=${VIEWER_VERSION_MINOR}" "LL_VIEWER_VERSION_MINOR=${VIEWER_VERSION_MINOR}"
"LL_VIEWER_VERSION_PATCH=${VIEWER_VERSION_PATCH}" "LL_VIEWER_VERSION_PATCH=${VIEWER_VERSION_PATCH}"

View File

@@ -18,16 +18,15 @@ set(cmake_SOURCE_FILES
CARes.cmake CARes.cmake
CEFPlugin.cmake CEFPlugin.cmake
CMakeCopyIfDifferent.cmake CMakeCopyIfDifferent.cmake
CURL.cmake
Colladadom.cmake Colladadom.cmake
ConfigurePkgConfig.cmake ConfigurePkgConfig.cmake
CURL.cmake
Copy3rdPartyLibs.cmake Copy3rdPartyLibs.cmake
Cwdebug.cmake Cwdebug.cmake
DBusGlib.cmake DBusGlib.cmake
DeploySharedLibs.cmake DeploySharedLibs.cmake
EXPAT.cmake EXPAT.cmake
ExamplePlugin.cmake ExamplePlugin.cmake
FMODSTUDIO.cmake
FindAPR.cmake FindAPR.cmake
FindAutobuild.cmake FindAutobuild.cmake
FindCARes.cmake FindCARes.cmake
@@ -39,8 +38,10 @@ set(cmake_SOURCE_FILES
FindNDOF.cmake FindNDOF.cmake
FindOpenJPEG.cmake FindOpenJPEG.cmake
FindTut.cmake FindTut.cmake
FindVCRedist.cmake
FindURIPARSER.cmake FindURIPARSER.cmake
FindXmlRpcEpi.cmake FindXmlRpcEpi.cmake
FMODSTUDIO.cmake
FreeType.cmake FreeType.cmake
GLOD.cmake GLOD.cmake
GStreamer010Plugin.cmake GStreamer010Plugin.cmake
@@ -85,8 +86,6 @@ set(cmake_SOURCE_FILES
Prebuilt.cmake Prebuilt.cmake
PulseAudio.cmake PulseAudio.cmake
Python.cmake Python.cmake
QuickTimePlugin.cmake
RunBuildTest.cmake
StateMachine.cmake StateMachine.cmake
TemplateCheck.cmake TemplateCheck.cmake
Tut.cmake Tut.cmake
@@ -96,6 +95,7 @@ set(cmake_SOURCE_FILES
Variables.cmake Variables.cmake
ViewerMiscLibs.cmake ViewerMiscLibs.cmake
WinManifest.cmake WinManifest.cmake
LibVLCPlugin.cmake
XmlRpcEpi.cmake XmlRpcEpi.cmake
ZLIB.cmake ZLIB.cmake
) )

View File

@@ -6,6 +6,8 @@
include(CMakeCopyIfDifferent) include(CMakeCopyIfDifferent)
include(Linking) include(Linking)
include(Variables)
include(LLCommon)
################################################################### ###################################################################
# set up platform specific lists of files that need to be copied # set up platform specific lists of files that need to be copied
@@ -20,10 +22,19 @@ if(WINDOWS)
set(vivox_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}") set(vivox_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}")
set(vivox_files set(vivox_files
SLVoice.exe SLVoice.exe
vivoxsdk.dll
ortp.dll
vivoxplatform.dll vivoxplatform.dll
) )
if (ADDRESS_SIZE EQUAL 64)
list(APPEND vivox_files
vivoxsdk_x64.dll
ortp_x64.dll
)
else (ADDRESS_SIZE EQUAL 64)
list(APPEND vivox_files
vivoxsdk.dll
ortp.dll
)
endif (ADDRESS_SIZE EQUAL 64)
#******************************* #*******************************
# Misc shared libs # Misc shared libs
@@ -46,7 +57,7 @@ if(WINDOWS)
libhunspell.dll libhunspell.dll
) )
if(WORD_SIZE STREQUAL 64) if(ADDRESS_SIZE EQUAL 64)
list(APPEND debug_files list(APPEND debug_files
libcrypto-1_1-x64.dll libcrypto-1_1-x64.dll
libssl-1_1-x64.dll libssl-1_1-x64.dll
@@ -55,7 +66,7 @@ if(WINDOWS)
libcrypto-1_1-x64.dll libcrypto-1_1-x64.dll
libssl-1_1-x64.dll libssl-1_1-x64.dll
) )
else(WORD_SIZE STREQUAL 64) else(ADDRESS_SIZE EQUAL 64)
list(APPEND debug_files list(APPEND debug_files
libcrypto-1_1.dll libcrypto-1_1.dll
libssl-1_1.dll libssl-1_1.dll
@@ -64,7 +75,7 @@ if(WINDOWS)
libcrypto-1_1.dll libcrypto-1_1.dll
libssl-1_1.dll libssl-1_1.dll
) )
endif(WORD_SIZE STREQUAL 64) endif(ADDRESS_SIZE EQUAL 64)
if(NOT DISABLE_TCMALLOC) if(NOT DISABLE_TCMALLOC)
set(debug_files ${debug_files} libtcmalloc_minimal-debug.dll) set(debug_files ${debug_files} libtcmalloc_minimal-debug.dll)
@@ -72,14 +83,15 @@ if(WINDOWS)
endif(NOT DISABLE_TCMALLOC) endif(NOT DISABLE_TCMALLOC)
if (FMODSTUDIO) if (FMODSTUDIO)
if(WORD_SIZE STREQUAL 64) if(ADDRESS_SIZE STREQUAL 64)
set(debug_files ${debug_files} fmodL64.dll) set(debug_files ${debug_files} fmodL64.dll)
set(release_files ${release_files} fmod64.dll) set(release_files ${release_files} fmod64.dll)
else(WORD_SIZE STREQUAL 64) else(ADDRESS_SIZE STREQUAL 64)
set(debug_files ${debug_files} fmodL.dll) set(debug_files ${debug_files} fmodL.dll)
set(release_files ${release_files} fmod.dll) set(release_files ${release_files} fmod.dll)
endif(WORD_SIZE STREQUAL 64) endif(ADDRESS_SIZE STREQUAL 64)
endif (FMODSTUDIO) endif (FMODSTUDIO)
elseif(DARWIN) elseif(DARWIN)
set(SHARED_LIB_STAGING_DIR_DEBUG "${SHARED_LIB_STAGING_DIR}/Debug/Resources") set(SHARED_LIB_STAGING_DIR_DEBUG "${SHARED_LIB_STAGING_DIR}/Debug/Resources")
set(SHARED_LIB_STAGING_DIR_RELWITHDEBINFO "${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/Resources") set(SHARED_LIB_STAGING_DIR_RELWITHDEBINFO "${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/Resources")
@@ -113,8 +125,8 @@ elseif(DARWIN)
) )
if (FMODSTUDIO) if (FMODSTUDIO)
set(debug_files ${debug_files} libfmodL.dylib) list(APPEND debug_files libfmodL.dylib)
set(release_files ${release_files} libfmod.dylib) list(APPEND release_files libfmod.dylib)
endif (FMODSTUDIO) endif (FMODSTUDIO)
elseif(LINUX) elseif(LINUX)
@@ -132,7 +144,6 @@ elseif(LINUX)
libvivoxplatform.so libvivoxplatform.so
libvivoxsdk.so libvivoxsdk.so
SLVoice SLVoice
# ca-bundle.crt #No cert for linux. It is actually still 3.2SDK.
) )
# *TODO - update this to use LIBS_PREBUILT_DIR and LL_ARCH_DIR variables # *TODO - update this to use LIBS_PREBUILT_DIR and LL_ARCH_DIR variables
# or ARCH_PREBUILT_DIRS # or ARCH_PREBUILT_DIRS
@@ -221,13 +232,13 @@ set(third_party_targets ${third_party_targets} ${out_targets})
copy_if_different( #copy_if_different(
${debug_src_dir} # ${debug_src_dir}
"${SHARED_LIB_STAGING_DIR_DEBUG}" # "${SHARED_LIB_STAGING_DIR_DEBUG}"
out_targets # out_targets
${debug_files} # ${debug_files}
) # )
set(third_party_targets ${third_party_targets} ${out_targets}) #set(third_party_targets ${third_party_targets} ${out_targets})
copy_if_different( copy_if_different(
${release_src_dir} ${release_src_dir}

View File

@@ -0,0 +1,34 @@
include(Variables)
if(WINDOWS)
if(MSVC_VERSION GREATER_EQUAL 1919 AND MSVC_VERSION LESS 1920)
set(VISUAL_STUDIO_VERSION 15.0)
set(VISUAL_STUDIO_VERSION_UPPER 16.0)
elseif(MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1940)
set(VISUAL_STUDIO_VERSION 16.0)
set(VISUAL_STUDIO_VERSION_UPPER 17.0)
endif ()
set(vswhere "$ENV{PROGRAMFILES\(X86\)}\\Microsoft Visual Studio\\Installer\\vswhere.exe")
if(EXISTS ${vswhere})
execute_process(COMMAND ${vswhere} -version "[${VISUAL_STUDIO_VERSION},${VISUAL_STUDIO_VERSION_UPPER})" -property "installationPath"
OUTPUT_VARIABLE installationPath
OUTPUT_STRIP_TRAILING_WHITESPACE)
file(TO_CMAKE_PATH ${installationPath} installationPath)
set(redistPath "${installationPath}/VC/Redist/MSVC")
file(GLOB redistPath "${installationPath}/VC/Redist/MSVC/*")
list(LENGTH redistPath length)
if(length EQUAL 1)
if(ADDRESS_SIZE EQUAL 64)
set(VISUAL_STUDIO_REDISTRIBUTABLE_NAME "vc_redist.x64.exe" CACHE FILEPATH "Name of Microsoft Visual Studio Redistributable")
set(redistPath "${redistPath}/${VISUAL_STUDIO_REDISTRIBUTABLE_NAME}")
else()
set(VISUAL_STUDIO_REDISTRIBUTABLE_NAME "vc_redist.x86.exe" CACHE FILEPATH "Name of Microsoft Visual Studio Redistributable")
set(redistPath "${redistPath}/${VISUAL_STUDIO_REDISTRIBUTABLE_NAME}")
endif()
if(EXISTS ${redistPath})
set(VISUAL_STUDIO_REDISTRIBUTABLE_PATH ${redistPath} CACHE FILEPATH "Path to the appropriate Microsoft Visual Studio Redistributable")
endif()
endif()
endif()
endif(WINDOWS)

View File

@@ -12,4 +12,5 @@ else (STANDALONE)
set(HUNSPELL_LIBRARY libhunspell) set(HUNSPELL_LIBRARY libhunspell)
endif (LINUX OR DARWIN) endif (LINUX OR DARWIN)
set(HUNSPELL_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/hunspell) set(HUNSPELL_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/hunspell)
use_prebuilt_binary(dictionaries)
endif (STANDALONE) endif (STANDALONE)

View File

@@ -105,17 +105,6 @@ MACRO(ADD_BUILD_TEST_INTERNAL name parent libraries source_files)
IF (NOT "$ENV{LD_LIBRARY_PATH}" STREQUAL "") IF (NOT "$ENV{LD_LIBRARY_PATH}" STREQUAL "")
SET(LD_LIBRARY_PATH "$ENV{LD_LIBRARY_PATH}:${LD_LIBRARY_PATH}") SET(LD_LIBRARY_PATH "$ENV{LD_LIBRARY_PATH}:${LD_LIBRARY_PATH}")
ENDIF (NOT "$ENV{LD_LIBRARY_PATH}" STREQUAL "") ENDIF (NOT "$ENV{LD_LIBRARY_PATH}" STREQUAL "")
ADD_CUSTOM_COMMAND(
OUTPUT ${TEST_OUTPUT}
COMMAND
${CMAKE_COMMAND}
"-DLD_LIBRARY_PATH=${LD_LIBRARY_PATH}"
"-DTEST_CMD:STRING=${TEST_CMD}"
-P ${CMAKE_SOURCE_DIR}/cmake/RunBuildTest.cmake
DEPENDS ${name}_test
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
VERBATIM
)
ADD_CUSTOM_TARGET(${name}_test_ok ALL DEPENDS ${TEST_OUTPUT}) ADD_CUSTOM_TARGET(${name}_test_ok ALL DEPENDS ${TEST_OUTPUT})
IF (${parent}) IF (${parent})

View File

@@ -1,32 +1,40 @@
# ll_deploy_sharedlibs_command # ll_deploy_sharedlibs_command
# target_exe: the cmake target of the executable for which the shared libs will be deployed. # target_exe: the cmake target of the executable for which the shared libs will be deployed.
macro(ll_deploy_sharedlibs_command target_exe) macro(ll_deploy_sharedlibs_command target_exe)
set(OUTPUT_PATH $<TARGET_FILE_DIR:${target_exe}>) set(TARGET_LOCATION $<TARGET_FILE:${target_exe}>)
get_filename_component(OUTPUT_PATH ${TARGET_LOCATION} PATH)
if(DARWIN) # It's not clear that this does anything useful for us on Darwin. It has
SET_TEST_PATH(SEARCH_DIRS) # been broken for some time now; the BIN_NAME was being constructed as a
get_target_property(IS_BUNDLE ${target_exe} MACOSX_BUNDLE) # ridiculous nonexistent path with duplicated segments. Fixing that only
if(IS_BUNDLE) # produces ominous spammy warnings: at the time the command below is run, we
set(OUTPUT_PATH ${OUTPUT_PATH}/../Resources) # have not yet populated the nested mac-crash-logger.app/Contents/Resources
endif(IS_BUNDLE) # with the .dylibs with which it was linked. Moreover, the form of the
elseif(WINDOWS) # embedded @executable_path/../Resources/mumble.dylib pathname confuses the
SET_TEST_PATH(SEARCH_DIRS) # GetPrerequisites.cmake tool invoked by DeploySharedLibs.cmake. It seems
LIST(APPEND SEARCH_DIRS "$ENV{SystemRoot}/system32") # clear that we have long since accomplished by other means what this was
elseif(LINUX) # originally supposed to do. Skipping it only eliminates an annoying
SET_TEST_PATH(SEARCH_DIRS) # non-fatal error.
set(OUTPUT_PATH ${OUTPUT_PATH}/lib) if(NOT DARWIN)
endif(DARWIN) if(WINDOWS)
SET_TEST_PATH(SEARCH_DIRS)
LIST(APPEND SEARCH_DIRS "$ENV{SystemRoot}/system32")
elseif(LINUX)
SET_TEST_PATH(SEARCH_DIRS)
set(OUTPUT_PATH ${OUTPUT_PATH}/lib)
endif(WINDOWS)
add_custom_command( add_custom_command(
TARGET ${target_exe} POST_BUILD TARGET ${target_exe} POST_BUILD
COMMAND ${CMAKE_COMMAND} COMMAND ${CMAKE_COMMAND}
ARGS ARGS
"-DBIN_NAME=\"$<TARGET_FILE:${target_exe}>\"" "-DBIN_NAME=\"${TARGET_LOCATION}\""
"-DSEARCH_DIRS=\"${SEARCH_DIRS}\"" "-DSEARCH_DIRS=\"${SEARCH_DIRS}\""
"-DDST_PATH=\"${OUTPUT_PATH}\"" "-DDST_PATH=\"${OUTPUT_PATH}\""
"-P" "-P"
"${CMAKE_SOURCE_DIR}/cmake/DeploySharedLibs.cmake" "${CMAKE_SOURCE_DIR}/cmake/DeploySharedLibs.cmake"
) )
endif(NOT DARWIN)
endmacro(ll_deploy_sharedlibs_command) endmacro(ll_deploy_sharedlibs_command)

View File

@@ -0,0 +1,30 @@
# -*- cmake -*-
include(Linking)
include(Prebuilt)
include(Variables)
if (LIBVLCPLUGIN)
if (USESYSTEMLIBS)
else (USESYSTEMLIBS)
use_prebuilt_binary(vlc-bin)
set(VLC_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/vlc)
endif (USESYSTEMLIBS)
if (WINDOWS)
set(VLC_PLUGIN_LIBRARIES
libvlc.lib
libvlccore.lib
)
elseif (DARWIN)
set(VLC_PLUGIN_LIBRARIES
libvlc.dylib
libvlccore.dylib
)
elseif (LINUX)
# Specify a full path to make sure we get a static link
set(VLC_PLUGIN_LIBRARIES
${LIBS_PREBUILT_DIR}/lib/libvlc.a
${LIBS_PREBUILT_DIR}/lib/libvlccore.a
)
endif (WINDOWS)
endif (LIBVLCPLUGIN)

View File

@@ -1,4 +1,6 @@
# -*- cmake -*- # -*- cmake -*-
include(Variables)
include(Prebuilt) include(Prebuilt)
if (NOT (STANDALONE OR DARWIN)) if (NOT (STANDALONE OR DARWIN))
@@ -8,3 +10,5 @@ if (NOT (STANDALONE OR DARWIN))
${LIBS_PREBUILT_LEGACY_DIR}/include ${LIBS_PREBUILT_LEGACY_DIR}/include
) )
endif (NOT (STANDALONE OR DARWIN)) endif (NOT (STANDALONE OR DARWIN))
include(FindOpenGL)

View File

@@ -4,7 +4,6 @@ if(NOT DEFINED ${CMAKE_CURRENT_LIST_FILE}_INCLUDED)
set(${CMAKE_CURRENT_LIST_FILE}_INCLUDED "YES") set(${CMAKE_CURRENT_LIST_FILE}_INCLUDED "YES")
include(FindAutobuild) include(FindAutobuild)
include(Variables)
if(INSTALL_PROPRIETARY) if(INSTALL_PROPRIETARY)
include(FindSCP) include(FindSCP)
endif(INSTALL_PROPRIETARY) endif(INSTALL_PROPRIETARY)
@@ -40,14 +39,13 @@ macro (use_prebuilt_binary _binary)
if(${PREBUILD_TRACKING_DIR}/sentinel_installed IS_NEWER_THAN ${PREBUILD_TRACKING_DIR}/${_binary}_installed OR NOT ${${_binary}_installed} EQUAL 0) if(${PREBUILD_TRACKING_DIR}/sentinel_installed IS_NEWER_THAN ${PREBUILD_TRACKING_DIR}/${_binary}_installed OR NOT ${${_binary}_installed} EQUAL 0)
if(DEBUG_PREBUILT) if(DEBUG_PREBUILT)
message("cd ${CMAKE_SOURCE_DIR} && ${AUTOBUILD_EXECUTABLE} install message(STATUS "cd ${CMAKE_SOURCE_DIR} && ${AUTOBUILD_EXECUTABLE} install
--install-dir=${AUTOBUILD_INSTALL_DIR} --install-dir=${AUTOBUILD_INSTALL_DIR}
${_binary} ") ${_binary} ")
endif(DEBUG_PREBUILT) endif(DEBUG_PREBUILT)
execute_process(COMMAND "${AUTOBUILD_EXECUTABLE}" execute_process(COMMAND "${AUTOBUILD_EXECUTABLE}"
install install
--install-dir=${AUTOBUILD_INSTALL_DIR} --install-dir=${AUTOBUILD_INSTALL_DIR}
-p ${AUTOBUILD_PLATFORM_NAME}
${_binary} ${_binary}
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
RESULT_VARIABLE ${_binary}_installed RESULT_VARIABLE ${_binary}_installed

View File

@@ -1,57 +0,0 @@
# -*- cmake -*-
if(INSTALL_PROPRIETARY OR USE_QUICKTIME_PREBUILT)
include(Prebuilt)
if (WINDOWS)
use_prebuilt_binary(quicktime)
endif (WINDOWS)
endif(INSTALL_PROPRIETARY OR USE_QUICKTIME_PREBUILT)
if (DARWIN)
include(CMakeFindFrameworks)
find_library(QUICKTIME_LIBRARY QuickTime)
elseif (WINDOWS AND WORD_SIZE EQUAL 32)
SET(program_files "ProgramFiles(x86)")
SET(program_files $ENV{${program_files}})
if(NOT program_files)
SET(program_files $ENV{ProgramW6432})
endif(NOT program_files)
if(NOT program_files)
SET(program_files $ENV{ProgramFiles})
endif(NOT program_files)
set(QUICKTIME_SDK_DIR "${program_files}/QuickTime SDK"
CACHE PATH "Location of the QuickTime SDK.")
find_library(DEBUG_QUICKTIME_LIBRARY qtmlclient
PATHS
${ARCH_PREBUILT_DIRS_DEBUG}
"${QUICKTIME_SDK_DIR}\\libraries"
)
find_library(RELEASE_QUICKTIME_LIBRARY qtmlclient
PATHS
${ARCH_PREBUILT_DIRS_RELEASE}
"${QUICKTIME_SDK_DIR}\\libraries"
)
if (DEBUG_QUICKTIME_LIBRARY AND RELEASE_QUICKTIME_LIBRARY)
set(QUICKTIME_LIBRARY
optimized ${RELEASE_QUICKTIME_LIBRARY}
debug ${DEBUG_QUICKTIME_LIBRARY}
)
endif (DEBUG_QUICKTIME_LIBRARY AND RELEASE_QUICKTIME_LIBRARY)
include_directories(
${LIBS_PREBUILT_DIR}/include/quicktime
"${QUICKTIME_SDK_DIR}\\CIncludes"
)
endif (DARWIN)
mark_as_advanced(QUICKTIME_LIBRARY)
if (QUICKTIME_LIBRARY)
set(QUICKTIME ON CACHE BOOL "Build with QuickTime streaming media support.")
endif (QUICKTIME_LIBRARY)

View File

@@ -1,20 +0,0 @@
#This cmake script is meant to be run as a build time custom command.
#The script is run using cmake w/ the -P option.
# parameters are passed to this scripts execution with the -D option.
# A full command line would look like this:
# cmake -D LD_LIBRARY_PATH=~/checkout/libraries -D TEST_CMD=./llunit_test -D ARGS=--touch=llunit_test_ok.txt -P RunBuildTest.cmake
# Parameters:
# LD_LIBRARY_PATH: string, What to set the LD_LIBRARY_PATH env var.
# TEST_CMD: string list, command to run the unit test with, followed by its args.
set(ENV{LD_LIBRARY_PATH} ${LD_LIBRARY_PATH})
#message("Running: ${TEST_CMD}")
execute_process(
COMMAND ${TEST_CMD}
RESULT_VARIABLE RES
)
if(NOT ${RES} STREQUAL 0)
message(STATUS "Failure running: ${TEST_CMD}")
message(FATAL_ERROR "Error: ${RES}")
endif(NOT ${RES} STREQUAL 0)

View File

@@ -24,14 +24,6 @@ set(VIEWER_PREFIX)
set(INTEGRATION_TESTS_PREFIX) set(INTEGRATION_TESTS_PREFIX)
option(LL_TESTS "Build and run unit and integration tests (disable for build timing runs to reduce variation" OFF) option(LL_TESTS "Build and run unit and integration tests (disable for build timing runs to reduce variation" OFF)
# Compiler and toolchain options
option(USESYSTEMLIBS "Use libraries from your system rather than Linden-supplied prebuilt libraries." OFF)
option(STANDALONE "Use libraries from your system rather than Linden-supplied prebuilt libraries." OFF)
if (USESYSTEMLIBS)
set(STANDALONE ON)
elseif (STANDALONE)
set(USESYSTEMLIBS ON)
endif (USESYSTEMLIBS)
option(INCREMENTAL_LINK "Use incremental linking on win32 builds (enable for faster links on some machines)" OFF) option(INCREMENTAL_LINK "Use incremental linking on win32 builds (enable for faster links on some machines)" OFF)
option(USE_PRECOMPILED_HEADERS "Enable use of precompiled header directives where supported." ON) option(USE_PRECOMPILED_HEADERS "Enable use of precompiled header directives where supported." ON)
option(USE_LTO "Enable Whole Program Optimization and related folding and binary reduction routines" OFF) option(USE_LTO "Enable Whole Program Optimization and related folding and binary reduction routines" OFF)
@@ -40,6 +32,7 @@ option(UNATTENDED "Disable use of uneeded tooling for automated builds" OFF)
# Media Plugins # Media Plugins
option(ENABLE_MEDIA_PLUGINS "Turn off building media plugins if they are imported by third-party library mechanism" ON) option(ENABLE_MEDIA_PLUGINS "Turn off building media plugins if they are imported by third-party library mechanism" ON)
option(LIBVLCPLUGIN "Turn off building support for libvlc plugin" ON) option(LIBVLCPLUGIN "Turn off building support for libvlc plugin" ON)
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR ${CMAKE_SYSTEM_NAME} MATCHES "Darwin") if (${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR ${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(LIBVLCPLUGIN OFF) set(LIBVLCPLUGIN OFF)
endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR ${CMAKE_SYSTEM_NAME} MATCHES "Darwin") endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR ${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
@@ -47,8 +40,9 @@ endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR ${CMAKE_SYSTEM_NAME} MATCHES "Dar
# Mallocs # Mallocs
set(DISABLE_TCMALLOC OFF CACHE BOOL "Disable linkage of TCMalloc. (64bit builds automatically disable TCMalloc)") set(DISABLE_TCMALLOC OFF CACHE BOOL "Disable linkage of TCMalloc. (64bit builds automatically disable TCMalloc)")
set(DISABLE_FATAL_WARNINGS TRUE CACHE BOOL "Set this to FALSE to enable fatal warnings.") set(DISABLE_FATAL_WARNINGS TRUE CACHE BOOL "Set this to FALSE to enable fatal warnings.")
# Audio Engines # Audio Engines
option(FMODSTUDIO "Build with support for the FMOD Studio audio engine" OFF) option(FMODSTUDIO "Build with support for the FMOD Studio audio engine" ON)
# Window implementation # Window implementation
option(LLWINDOW_SDL2 "Use SDL2 for window and input handling" OFF) option(LLWINDOW_SDL2 "Use SDL2 for window and input handling" OFF)
@@ -88,61 +82,56 @@ if (NOT CMAKE_BUILD_TYPE)
"Build type. One of: Debug Release RelWithDebInfo" FORCE) "Build type. One of: Debug Release RelWithDebInfo" FORCE)
endif (NOT CMAKE_BUILD_TYPE) endif (NOT CMAKE_BUILD_TYPE)
# If someone has specified an address size, use that to determine the
# architecture. Otherwise, let the architecture specify the address size.
set(ADDRESS_SIZE ${WORD_SIZE})
if (ADDRESS_SIZE EQUAL 32)
#message(STATUS "ADDRESS_SIZE is 32")
set(ARCH i686)
elseif (ADDRESS_SIZE EQUAL 64)
#message(STATUS "ADDRESS_SIZE is 64")
set(ARCH x86_64)
else (ADDRESS_SIZE EQUAL 32)
#message(STATUS "ADDRESS_SIZE is UNRECOGNIZED: '${ADDRESS_SIZE}'")
# Use Python's platform.machine() since uname -m isn't available everywhere.
# Even if you can assume cygwin uname -m, the answer depends on whether
# you're running 32-bit cygwin or 64-bit cygwin! But even 32-bit Python will
# report a 64-bit processor.
execute_process(COMMAND
"${Python2_EXECUTABLE}" "-c"
"import platform; print platform.machine()"
OUTPUT_VARIABLE ARCH OUTPUT_STRIP_TRAILING_WHITESPACE)
# We expect values of the form i386, i686, x86_64, AMD64.
# In CMake, expressing ARCH.endswith('64') is awkward:
string(LENGTH "${ARCH}" ARCH_LENGTH)
math(EXPR ARCH_LEN_2 "${ARCH_LENGTH} - 2")
string(SUBSTRING "${ARCH}" ${ARCH_LEN_2} 2 ARCH_LAST_2)
if (ARCH_LAST_2 STREQUAL 64)
#message(STATUS "ARCH is detected as 64; ARCH is ${ARCH}")
set(ADDRESS_SIZE 64)
else()
#message(STATUS "ARCH is detected as 32; ARCH is ${ARCH}")
set(ADDRESS_SIZE 32)
endif ()
endif (ADDRESS_SIZE EQUAL 32)
if (${CMAKE_SYSTEM_NAME} MATCHES "Windows") if (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
set(WINDOWS ON BOOL FORCE) set(WINDOWS ON BOOL FORCE)
if (WORD_SIZE EQUAL 64)
set(ARCH x86_64 CACHE STRING "Viewer Architecture")
set(LL_ARCH ${ARCH}_win64)
set(LL_ARCH_DIR ${ARCH}-win64)
set(WORD_SIZE 64)
set(AUTOBUILD_PLATFORM_NAME "windows64")
else (WORD_SIZE EQUAL 64)
set(ARCH i686 CACHE STRING "Viewer Architecture")
set(LL_ARCH ${ARCH}_win32) set(LL_ARCH ${ARCH}_win32)
set(LL_ARCH_DIR ${ARCH}-win32) set(LL_ARCH_DIR ${ARCH}-win32)
set(WORD_SIZE 32)
set(AUTOBUILD_PLATFORM_NAME "windows")
endif (WORD_SIZE EQUAL 64)
endif (${CMAKE_SYSTEM_NAME} MATCHES "Windows") endif (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
set(LINUX ON BOOL FORCE) set(LINUX ON BOOL FORCE)
# If someone has specified a word size, use that to determine the if (ADDRESS_SIZE EQUAL 32)
# architecture. Otherwise, let the architecture specify the word size.
if (WORD_SIZE EQUAL 32)
#message(STATUS "WORD_SIZE is 32")
set(ARCH i686)
set(AUTOBUILD_PLATFORM_NAME "linux")
elseif (WORD_SIZE EQUAL 64)
#message(STATUS "WORD_SIZE is 64")
set(ARCH x86_64)
set(AUTOBUILD_PLATFORM_NAME "linux64")
else (WORD_SIZE EQUAL 32)
#message(STATUS "WORD_SIZE is UNDEFINED")
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
message(STATUS "Size of void pointer is detected as 8; ARCH is 64-bit")
set(WORD_SIZE 64)
set(AUTOBUILD_PLATFORM_NAME "linux64")
elseif (CMAKE_SIZEOF_VOID_P EQUAL 4)
message(STATUS "Size of void pointer is detected as 4; ARCH is 32-bit")
set(WORD_SIZE 32)
set(AUTOBUILD_PLATFORM_NAME "linux")
else()
message(FATAL_ERROR "Unknown Architecture!")
endif (CMAKE_SIZEOF_VOID_P EQUAL 8)
endif (WORD_SIZE EQUAL 32)
if (NOT STANDALONE AND MULTIARCH_HACK)
if (WORD_SIZE EQUAL 32)
set(DEB_ARCHITECTURE i386) set(DEB_ARCHITECTURE i386)
set(FIND_LIBRARY_USE_LIB64_PATHS OFF) set(FIND_LIBRARY_USE_LIB64_PATHS OFF)
set(CMAKE_SYSTEM_LIBRARY_PATH /usr/lib32 ${CMAKE_SYSTEM_LIBRARY_PATH}) set(CMAKE_SYSTEM_LIBRARY_PATH /usr/lib32 ${CMAKE_SYSTEM_LIBRARY_PATH})
else (WORD_SIZE EQUAL 32) else (ADDRESS_SIZE EQUAL 32)
set(DEB_ARCHITECTURE amd64) set(DEB_ARCHITECTURE amd64)
set(FIND_LIBRARY_USE_LIB64_PATHS ON) set(FIND_LIBRARY_USE_LIB64_PATHS ON)
endif (WORD_SIZE EQUAL 32) endif (ADDRESS_SIZE EQUAL 32)
execute_process(COMMAND dpkg-architecture -a${DEB_ARCHITECTURE} -qDEB_HOST_MULTIARCH execute_process(COMMAND dpkg-architecture -a${DEB_ARCHITECTURE} -qDEB_HOST_MULTIARCH
RESULT_VARIABLE DPKG_RESULT RESULT_VARIABLE DPKG_RESULT
@@ -155,7 +144,6 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
endif (DPKG_RESULT EQUAL 0) endif (DPKG_RESULT EQUAL 0)
include(ConfigurePkgConfig) include(ConfigurePkgConfig)
endif (NOT STANDALONE AND MULTIARCH_HACK)
set(LL_ARCH ${ARCH}_linux) set(LL_ARCH ${ARCH}_linux)
set(LL_ARCH_DIR ${ARCH}-linux) set(LL_ARCH_DIR ${ARCH}-linux)
@@ -164,49 +152,42 @@ endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(DARWIN 1) set(DARWIN 1)
if (XCODE_VERSION LESS 8.0.0) # Architecture
message( FATAL_ERROR "Xcode 8.0.0 or greater is required." ) set(CMAKE_OSX_SYSROOT macosx10.14)
endif (XCODE_VERSION LESS 8.0.0) set(CMAKE_OSX_ARCHITECTURES "x86_64")
message( "Building with " ${CMAKE_OSX_SYSROOT} ) set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS "x86_64")
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.12)
# Build Options
set(CMAKE_XCODE_ATTRIBUTE_GCC_VERSION "com.apple.compilers.llvm.clang.1_0") set(CMAKE_XCODE_ATTRIBUTE_GCC_VERSION "com.apple.compilers.llvm.clang.1_0")
set(CMAKE_XCODE_ATTRIBUTE_GCC_OPTIMIZATION_LEVEL 3) set(CMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT[variant=Debug] "dwarf")
set(CMAKE_XCODE_ATTRIBUTE_GCC_STRICT_ALIASING NO) set(CMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT[variant=Release] "dwarf-with-dsym")
set(CMAKE_XCODE_ATTRIBUTE_GCC_FAST_MATH NO)
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++") # Deployment
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++14") set(CMAKE_OSX_DEPLOYMENT_TARGET 10.13)
if (USE_AVX2)
set(CMAKE_XCODE_ATTRIBUTE_CLANG_X86_VECTOR_INSTRUCTIONS avx2) # Linking
elseif (USE_AVX) set(CMAKE_XCODE_ATTRIBUTE_DEAD_CODE_STRIPPING YES)
set(CMAKE_XCODE_ATTRIBUTE_CLANG_X86_VECTOR_INSTRUCTIONS avx)
else () # Apple Clang - Code Gen
set(CMAKE_XCODE_ATTRIBUTE_GCC_GENERATE_DEBUGGING_SYMBOLS[variant=Release] YES)
set(CMAKE_XCODE_ATTRIBUTE_CLANG_X86_VECTOR_INSTRUCTIONS sse4.1) set(CMAKE_XCODE_ATTRIBUTE_CLANG_X86_VECTOR_INSTRUCTIONS sse4.1)
endif () set(CMAKE_XCODE_ATTRIBUTE_GCC_STRICT_ALIASING NO)
set(CMAKE_XCODE_ATTRIBUTE_GCC_OPTIMIZATION_LEVEL[variant=Debug] 0)
set(CMAKE_XCODE_ATTRIBUTE_GCC_OPTIMIZATION_LEVEL[variant=Release] 3)
set(CMAKE_XCODE_ATTRIBUTE_GCC_FAST_MATH NO)
if (${CMAKE_BUILD_TYPE} STREQUAL "Release") # Apple Clang - Custom Compiler Flags
set(CMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT dwarf-with-dsym) set(CMAKE_XCODE_ATTRIBUTE_WARNING_CFLAGS "-Wall -Wextra -Wno-reorder -Wno-sign-compare -Wno-ignored-qualifiers -Wno-unused-local-typedef -Wno-unused-parameter")
else (${CMAKE_BUILD_TYPE} STREQUAL "Release")
set(CMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT dwarf)
endif (${CMAKE_BUILD_TYPE} STREQUAL "Release")
set(ADDRESS_SIZE 64) # Apple Clang - Language - C++
if (NOT CMAKE_OSX_ARCHITECTURES) set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD c++14)
if (ADDRESS_SIZE EQUAL 64) set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++")
set(CMAKE_OSX_ARCHITECTURES x86_64)
else (ADDRESS_SIZE EQUAL 64) # Apple Clang - Warning Policies
set(CMAKE_OSX_ARCHITECTURES i386) set(CMAKE_XCODE_ATTRIBUTE_GCC_TREAT_WARNINGS_AS_ERRORS YES)
endif (ADDRESS_SIZE EQUAL 64)
endif (NOT CMAKE_OSX_ARCHITECTURES)
if (ADDRESS_SIZE EQUAL 64)
set(ARCH x86_64)
else (ADDRESS_SIZE EQUAL 64)
set(ARCH i386)
endif (ADDRESS_SIZE EQUAL 64)
set(LL_ARCH ${ARCH}_darwin) set(LL_ARCH ${ARCH}_darwin)
set(LL_ARCH_DIR universal-darwin) set(LL_ARCH_DIR universal-darwin)
set(AUTOBUILD_PLATFORM_NAME "darwin" CACHE STRING "Autobuild Platform Name")
endif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") endif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
# Default deploy grid # Default deploy grid
@@ -223,11 +204,11 @@ string(REPLACE " " "" VIEWER_CHANNEL_ONEWORD ${VIEWER_CHANNEL})
option(VIEWER_CHANNEL_GRK "Greek character(s) to represent the viewer channel for support purposes, override only for special branches" "") option(VIEWER_CHANNEL_GRK "Greek character(s) to represent the viewer channel for support purposes, override only for special branches" "")
if (NOT VIEWER_CHANNEL_GRK) if (NOT VIEWER_CHANNEL_GRK)
if (VIEWER_CHANNEL_BASE MATCHES "Test") if (VIEWER_CHANNEL_BASE MATCHES "Test")
set(VIEWER_CHANNEL_GRK "τ") set(VIEWER_CHANNEL_GRK "\\u03C4") # "τ"
elseif (VIEWER_CHANNEL_BASE MATCHES "Alpha") elseif (VIEWER_CHANNEL_BASE MATCHES "Alpha")
set(VIEWER_CHANNEL_GRK "α") set(VIEWER_CHANNEL_GRK "\\u03B1") # "α"
elseif (VIEWER_CHANNEL_BASE MATCHES "Beta") elseif (VIEWER_CHANNEL_BASE MATCHES "Beta")
set(VIEWER_CHANNEL_GRK "β") set(VIEWER_CHANNEL_GRK "\\u03B2") # "β"
endif () endif ()
endif (NOT VIEWER_CHANNEL_GRK) endif (NOT VIEWER_CHANNEL_GRK)
@@ -245,13 +226,21 @@ set(VIEWER_CHANNEL_NOSPACE ${VIEWER_CHANNEL_ONEWORD} CACHE STRING "Prefix used f
set(VIEWER_BRANDING_ID "singularity" CACHE STRING "Viewer branding id") set(VIEWER_BRANDING_ID "singularity" CACHE STRING "Viewer branding id")
set(VERSION_BUILD "0" CACHE STRING "Revision number passed in from the outside")
option(ENABLE_SIGNING "Enable signing the viewer" OFF) option(ENABLE_SIGNING "Enable signing the viewer" OFF)
set(SIGNING_IDENTITY "" CACHE STRING "Specifies the signing identity to use, if necessary.") set(SIGNING_IDENTITY "" CACHE STRING "Specifies the signing identity to use, if necessary.")
set(VERSION_BUILD "0" CACHE STRING "Revision number passed in from the outside")
# Compiler and toolchain options
option(USESYSTEMLIBS "Use libraries from your system rather than Linden-supplied prebuilt libraries." OFF)
option(STANDALONE "Use libraries from your system rather than Linden-supplied prebuilt libraries." OFF)
if (USESYSTEMLIBS)
set(STANDALONE ON)
elseif (STANDALONE)
set(USESYSTEMLIBS ON)
endif (USESYSTEMLIBS)
source_group("CMake Rules" FILES CMakeLists.txt) source_group("CMake Rules" FILES CMakeLists.txt)
mark_as_advanced(AUTOBUILD_PLATFORM_NAME)
endif(NOT DEFINED ${CMAKE_CURRENT_LIST_FILE}_INCLUDED) endif(NOT DEFINED ${CMAKE_CURRENT_LIST_FILE}_INCLUDED)

View File

@@ -0,0 +1,340 @@
#!/usr/bin/env python
"""\
@file run_build_test.py
@author Nat Goodspeed
@date 2009-09-03
@brief Helper script to allow CMake to run some command after setting
environment variables.
CMake has commands to run an external program. But remember that each CMake
command must be backed by multiple build-system implementations. Unfortunately
it seems CMake can't promise that every target build system can set specified
environment variables before running the external program of interest.
This helper script is a workaround. It simply sets the requested environment
variables and then executes the program specified on the rest of its command
line.
Example:
python run_build_test.py -DFOO=bar myprog somearg otherarg
sets environment variable FOO=bar, then runs:
myprog somearg otherarg
$LicenseInfo:firstyear=2009&license=viewerlgpl$
Second Life Viewer Source Code
Copyright (C) 2009-2010, Linden Research, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2.1 of the License only.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
$/LicenseInfo$
"""
import os
import sys
import errno
import HTMLParser
import re
import signal
import subprocess
import logging
def main(command, arguments=[], libpath=[], vars={}):
"""Pass:
command is the command to be executed
argument is a sequence (e.g. a list) of strings to be passed to command
libpath is a sequence of directory pathnames. These will be appended to
the platform-specific dynamic library search path environment variable.
vars is a dict of arbitrary (var, value) pairs to be added to the
environment before running 'command'.
This function runs the specified command, waits for it to terminate and
returns its return code. This will be negative if the command terminated
with a signal, else it will be the process's specified exit code.
"""
# Handle platform-dependent libpath first.
if sys.platform == "win32":
lpvars = ["PATH"]
elif sys.platform == "darwin":
lpvars = ["LD_LIBRARY_PATH", "DYLD_LIBRARY_PATH"]
elif sys.platform.startswith("linux"):
lpvars = ["LD_LIBRARY_PATH"]
else:
# No idea what the right pathname might be! But only crump if this
# feature is requested.
if libpath:
raise RuntimeError("run_build_test: unknown platform %s" % sys.platform)
lpvars = []
for var in lpvars:
# Split the existing path. Bear in mind that the variable in question
# might not exist; instead of KeyError, just use an empty string.
dirs = os.environ.get(var, "").split(os.pathsep)
# Append the sequence in libpath
log.info("%s += %r" % (var, libpath))
for dir in libpath:
# append system paths at the end
if dir in ('/lib', '/usr/lib'):
dirs.append(dir)
# prepend non-system paths
else:
dirs.insert(0, dir)
# Filter out some useless pieces
clean_dirs = []
for dir in dirs:
if dir and dir not in ('', '.'):
clean_dirs.append(dir)
# Now rebuild the path string. This way we use a minimum of separators
# -- and we avoid adding a pointless separator when libpath is empty.
os.environ[var] = os.pathsep.join(clean_dirs)
log.info("%s = %r" % (var, os.environ[var]))
# Now handle arbitrary environment variables. The tricky part is ensuring
# that all the keys and values we try to pass are actually strings.
if vars:
log.info("Setting: %s" % ("\n".join(["%s=%s" % (key, value) for key, value in vars.iteritems()])))
os.environ.update(dict([(str(key), str(value)) for key, value in vars.iteritems()]))
# Run the child process.
command_list = [command]
command_list.extend(arguments)
log.info("Running: %s" % " ".join(command_list))
# Make sure we see all relevant output *before* child-process output.
sys.stdout.flush()
try:
return subprocess.call(command_list)
except OSError as err:
# If the caller is trying to execute a test program that doesn't
# exist, we want to produce a reasonable error message rather than a
# traceback. This happens when the build is halted by errors, but
# CMake tries to proceed with testing anyway <eyeroll/>. However, do
# NOT attempt to handle any error but "doesn't exist."
if err.errno != errno.ENOENT:
raise
# In practice, the pathnames into CMake's build tree are so long as to
# obscure the name of the test program. Just log its basename.
log.warn("No such program %s; check for preceding build errors" % \
os.path.basename(command[0]))
# What rc should we simulate for missing executable? Windows produces
# 9009.
return 9009
# swiped from vita, sigh, seems like a Bad Idea to introduce dependency
def translate_rc(rc):
"""
Accept an rc encoded as for subprocess.Popen.returncode:
None means still running
int >= 0 means terminated voluntarily with specified rc
int < 0 means terminated by signal (-rc)
Return a string explaining the outcome. In case of a signal, try to
name the corresponding symbol from the 'signal' module.
"""
if rc is None:
return "still running"
if rc >= 0:
return "terminated with rc %s" % rc
if sys.platform.startswith("win"):
# From http://stackoverflow.com/questions/20629027/process-finished-with-exit-code-1073741571
# [-1073741571] is the signed integer representation of Microsoft's
# "stack overflow/stack exhaustion" error code 0xC00000FD.
# Anytime you see strange, large negative exit codes in windows, convert
# them to hex and then look them up in the ntstatus error codes
# http://msdn.microsoft.com/en-us/library/cc704588.aspx
# Python bends over backwards to give you all the integer precision
# you need, avoiding truncation. But only with 32-bit signed ints is
# -1073741571 equivalent to 0xC00000FD! Explicitly truncate before
# converting.
hexrc = "0x%X" % (rc & 0xFFFFFFFF)
# At this point, we're only trying to format the rc to make it easier
# for a human being to understand. Any exception here -- file doesn't
# exist, HTML parsing error, unrecognized table structure, unknown key
# -- should NOT kill the script! It should only cause us to shrug and
# present our caller with the best information available.
try:
table = get_windows_table()
symbol, desc = table[hexrc]
except Exception, err:
log.error("(%s -- carrying on)" % err)
log.error("terminated with rc %s (%s)" % (rc, hexrc))
else:
log.info("terminated with rc %s: %s: %s" % (hexrc, symbol, desc))
else:
# On Posix, negative rc means the child was terminated by signal -rc.
rc = -rc
for attr in dir(signal):
if attr.startswith('SIG') and getattr(signal, attr) == rc:
strc = attr
break
else:
strc = str(rc)
return "terminated by signal %s" % strc
class TableParser(HTMLParser.HTMLParser):
"""
This HTMLParser subclass is designed to parse the table we know exists
in windows-rcs.html, hopefully without building in too much knowledge of
the specific way that table is currently formatted.
"""
# regular expression matching any string containing only whitespace
whitespace = re.compile(r'\s*$')
def __init__(self):
# Because Python 2.x's HTMLParser is an old-style class, we must use
# old-style syntax to forward the __init__() call -- not super().
HTMLParser.HTMLParser.__init__(self)
# this will collect all the data, eventually
self.table = []
# Stack whose top (last item) indicates where to append current
# element data. When empty, don't collect data at all.
self.dest = []
def handle_starttag(self, tag, attrs):
if tag == "table":
# This is the outermost tag we recognize. Collect nested elements
# within self.table.
self.dest.append(self.table)
elif tag in ("tr", "td"):
# Nested elements whose contents we want to capture as sublists.
# To the list currently designated by the top of the dest stack,
# append a new empty sublist.
self.dest[-1].append([])
# Now push THAT new, empty list as the new top of the dest stack.
self.dest.append(self.dest[-1][-1])
elif tag == "p":
# We could handle <p> ... </p> just like <tr> or <td>, but that
# introduces an unnecessary extra level of nesting. Just skip.
pass
else:
# For any tag we don't recognize (notably <th>), push a new, empty
# list to the top of the dest stack. This new list is NOT
# referenced by anything in self.table; thus, when we pop it, any
# data we've collected inside that list will be discarded.
self.dest.append([])
def handle_endtag(self, tag):
# Because we avoid pushing self.dest for <p> in handle_starttag(), we
# must refrain from popping it for </p> here.
if tag != "p":
# For everything else, including unrecognized tags, pop the dest
# stack, reverting to outer collection.
self.dest.pop()
def handle_startendtag(self, tag, attrs):
# The table of interest contains <td> entries of the form:
# <p>0x00000000<br />STATUS_SUCCESS</p>
# The <br/> is very useful -- we definitely want two different data
# items for "0x00000000" and "STATUS_SUCCESS" -- but we don't need or
# want it to push, then discard, an empty list as it would if we let
# the default HTMLParser.handle_startendtag() call handle_starttag()
# followed by handle_endtag(). Just ignore <br/> or any other
# singleton tag.
pass
def handle_data(self, data):
# Outside the <table> of interest, self.dest is empty. Do not bother
# collecting data when self.dest is empty.
# HTMLParser calls handle_data() with every chunk of whitespace
# between tags. That would be lovely if our eventual goal was to
# reconstitute the original input stream with its existing formatting,
# but for us, whitespace only clutters the table. Ignore it.
if self.dest and not self.whitespace.match(data):
# Here we're within our <table> and we have non-whitespace data.
# Append it to the list designated by the top of the dest stack.
self.dest[-1].append(data)
# cache for get_windows_table()
_windows_table = None
def get_windows_table():
global _windows_table
# If we already loaded _windows_table, no need to load it all over again.
if _windows_table:
return _windows_table
# windows-rcs.html was fetched on 2015-03-24 with the following command:
# curl -o windows-rcs.html \
# https://msdn.microsoft.com/en-us/library/cc704588.aspx
parser = TableParser()
with open(os.path.join(os.path.dirname(__file__), "windows-rcs.html")) as hf:
# We tried feeding the file data to TableParser in chunks, to avoid
# buffering the entire file as a single string. Unfortunately its
# handle_data() cannot tell the difference between distinct calls
# separated by HTML tags, and distinct calls necessitated by a chunk
# boundary. Sigh! Read in the whole file. At the time this was
# written, it was only 500KB anyway.
parser.feed(hf.read())
parser.close()
table = parser.table
# With our parser, any <tr><th>...</th></tr> row leaves a table entry
# consisting only of an empty list. Remove any such.
while table and not table[0]:
table.pop(0)
# We expect rows of the form:
# [['0x00000000', 'STATUS_SUCCESS'],
# ['The operation completed successfully.']]
# The latter list will have multiple entries if Microsoft embedded <br/>
# or <p> ... </p> in the text, in which case joining with '\n' is
# appropriate.
# Turn that into a dict whose key is the hex string, and whose value is
# the pair (symbol, desc).
_windows_table = dict((key, (symbol, '\n'.join(desc)))
for (key, symbol), desc in table)
return _windows_table
log=logging.getLogger(__name__)
logging.basicConfig()
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-d", "--debug", dest="loglevel", action="store_const",
const=logging.DEBUG, default=logging.INFO)
parser.add_argument("-D", "--define", dest="vars", default=[], action="append",
metavar="VAR=value",
help="Add VAR=value to the env variables defined")
parser.add_argument("-l", "--libpath", dest="libpath", default=[], action="append",
metavar="DIR",
help="Add DIR to the platform-dependent DLL search path")
parser.add_argument("command")
parser.add_argument('args', nargs=argparse.REMAINDER)
args = parser.parse_args()
log.setLevel(args.loglevel)
# What we have in opts.vars is a list of strings of the form "VAR=value"
# or possibly just "VAR". What we want is a dict. We can build that dict by
# constructing a list of ["VAR", "value"] pairs -- so split each
# "VAR=value" string on the '=' sign (but only once, in case we have
# "VAR=some=user=string"). To handle the case of just "VAR", append "" to
# the list returned by split(), then slice off anything after the pair we
# want.
rc = main(command=args.command, arguments=args.args, libpath=args.libpath,
vars=dict([(pair.split('=', 1) + [""])[:2] for pair in args.vars]))
if rc not in (None, 0):
log.error("Failure running: %s" % " ".join([args.command] + args.args))
log.error("Error %s: %s" % (rc, translate_rc(rc)))
sys.exit((rc < 0) and 255 or rc)

View File

@@ -1,27 +0,0 @@
"""\
@file __init__.py
@brief Initialization file for the indra.base module.
$LicenseInfo:firstyear=2007&license=mit$
Copyright (c) 2007-2009, Linden Research, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
$/LicenseInfo$
"""

View File

@@ -1,73 +0,0 @@
#!/usr/bin/python
##
## $LicenseInfo:firstyear=2011&license=viewerlgpl$
## Second Life Viewer Source Code
## Copyright (C) 2011, Linden Research, Inc.
##
## This library is free software; you can redistribute it and/or
## modify it under the terms of the GNU Lesser General Public
## License as published by the Free Software Foundation;
## version 2.1 of the License only.
##
## This library is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
## Lesser General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public
## License along with this library; if not, write to the Free Software
## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
##
## Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
## $/LicenseInfo$
from indra.base import llsd, lluuid
from datetime import datetime
import cllsd
import time, sys
class myint(int):
pass
values = (
'&<>',
u'\u81acj',
llsd.uri('http://foo<'),
lluuid.UUID(),
llsd.LLSD(['thing']),
1,
myint(31337),
sys.maxint + 10,
llsd.binary('foo'),
[],
{},
{u'f&\u1212': 3},
3.1,
True,
None,
datetime.fromtimestamp(time.time()),
)
def valuator(values):
for v in values:
yield v
longvalues = () # (values, list(values), iter(values), valuator(values))
for v in values + longvalues:
print '%r => %r' % (v, cllsd.llsd_to_xml(v))
a = [[{'a':3}]] * 1000000
s = time.time()
print hash(cllsd.llsd_to_xml(a))
e = time.time()
t1 = e - s
print t1
s = time.time()
print hash(llsd.LLSDXMLFormatter()._format(a))
e = time.time()
t2 = e - s
print t2
print 'Speedup:', t2 / t1

View File

@@ -1,266 +0,0 @@
"""\
@file config.py
@brief Utility module for parsing and accessing the indra.xml config file.
$LicenseInfo:firstyear=2006&license=mit$
Copyright (c) 2006-2009, Linden Research, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
$/LicenseInfo$
"""
import copy
import errno
import os
import traceback
import time
import types
from os.path import dirname, getmtime, join, realpath
from indra.base import llsd
_g_config = None
class IndraConfig(object):
"""
IndraConfig loads a 'indra' xml configuration file
and loads into memory. This representation in memory
can get updated to overwrite values or add new values.
The xml configuration file is considered a live file and changes
to the file are checked and reloaded periodically. If a value had
been overwritten via the update or set method, the loaded values
from the file are ignored (the values from the update/set methods
override)
"""
def __init__(self, indra_config_file):
self._indra_config_file = indra_config_file
self._reload_check_interval = 30 # seconds
self._last_check_time = 0
self._last_mod_time = 0
self._config_overrides = {}
self._config_file_dict = {}
self._combined_dict = {}
self._load()
def _load(self):
# if you initialize the IndraConfig with None, no attempt
# is made to load any files
if self._indra_config_file is None:
return
config_file = open(self._indra_config_file)
self._config_file_dict = llsd.parse(config_file.read())
self._combine_dictionaries()
config_file.close()
self._last_mod_time = self._get_last_modified_time()
self._last_check_time = time.time() # now
def _get_last_modified_time(self):
"""
Returns the mtime (last modified time) of the config file,
if such exists.
"""
if self._indra_config_file is not None:
return os.path.getmtime(self._indra_config_file)
return 0
def _combine_dictionaries(self):
self._combined_dict = {}
self._combined_dict.update(self._config_file_dict)
self._combined_dict.update(self._config_overrides)
def _reload_if_necessary(self):
now = time.time()
if (now - self._last_check_time) > self._reload_check_interval:
self._last_check_time = now
try:
modtime = self._get_last_modified_time()
if modtime > self._last_mod_time:
self._load()
except OSError, e:
if e.errno == errno.ENOENT: # file not found
# someone messed with our internal state
# or removed the file
print 'WARNING: Configuration file has been removed ' + (self._indra_config_file)
print 'Disabling reloading of configuration file.'
traceback.print_exc()
self._indra_config_file = None
self._last_check_time = 0
self._last_mod_time = 0
else:
raise # pass the exception along to the caller
def __getitem__(self, key):
self._reload_if_necessary()
return self._combined_dict[key]
def get(self, key, default = None):
try:
return self.__getitem__(key)
except KeyError:
return default
def __setitem__(self, key, value):
"""
Sets the value of the config setting of key to be newval
Once any key/value pair is changed via the set method,
that key/value pair will remain set with that value until
change via the update or set method
"""
self._config_overrides[key] = value
self._combine_dictionaries()
def set(self, key, newval):
return self.__setitem__(key, newval)
def update(self, new_conf):
"""
Load an XML file and apply its map as overrides or additions
to the existing config. Update can be a file or a dict.
Once any key/value pair is changed via the update method,
that key/value pair will remain set with that value until
change via the update or set method
"""
if isinstance(new_conf, dict):
overrides = new_conf
else:
# assuming that it is a filename
config_file = open(new_conf)
overrides = llsd.parse(config_file.read())
config_file.close()
self._config_overrides.update(overrides)
self._combine_dictionaries()
def as_dict(self):
"""
Returns immutable copy of the IndraConfig as a dictionary
"""
return copy.deepcopy(self._combined_dict)
def load(config_xml_file = None):
global _g_config
load_default_files = config_xml_file is None
if load_default_files:
## going from:
## "/opt/linden/indra/lib/python/indra/base/config.py"
## to:
## "/opt/linden/etc/indra.xml"
config_xml_file = realpath(
dirname(realpath(__file__)) + "../../../../../../etc/indra.xml")
try:
_g_config = IndraConfig(config_xml_file)
except IOError:
# Failure to load passed in file
# or indra.xml default file
if load_default_files:
try:
config_xml_file = realpath(
dirname(realpath(__file__)) + "../../../../../../etc/globals.xml")
_g_config = IndraConfig(config_xml_file)
return
except IOError:
# Failure to load globals.xml
# fall to code below
pass
# Either failed to load passed in file
# or failed to load all default files
_g_config = IndraConfig(None)
def dump(indra_xml_file, indra_cfg = None, update_in_mem=False):
'''
Dump config contents into a file
Kindof reverse of load.
Optionally takes a new config to dump.
Does NOT update global config unless requested.
'''
global _g_config
if not indra_cfg:
if _g_config is None:
return
indra_cfg = _g_config.as_dict()
if not indra_cfg:
return
config_file = open(indra_xml_file, 'w')
_config_xml = llsd.format_xml(indra_cfg)
config_file.write(_config_xml)
config_file.close()
if update_in_mem:
update(indra_cfg)
def update(new_conf):
global _g_config
if _g_config is None:
# To keep with how this function behaved
# previously, a call to update
# before the global is defined
# make a new global config which does not
# load data from a file.
_g_config = IndraConfig(None)
return _g_config.update(new_conf)
def get(key, default = None):
global _g_config
if _g_config is None:
load()
return _g_config.get(key, default)
def set(key, newval):
"""
Sets the value of the config setting of key to be newval
Once any key/value pair is changed via the set method,
that key/value pair will remain set with that value until
change via the update or set method or program termination
"""
global _g_config
if _g_config is None:
_g_config = IndraConfig(None)
_g_config.set(key, newval)
def get_config():
global _g_config
return _g_config

File diff suppressed because it is too large Load Diff

View File

@@ -1,319 +0,0 @@
"""\
@file lluuid.py
@brief UUID parser/generator.
$LicenseInfo:firstyear=2004&license=mit$
Copyright (c) 2004-2009, Linden Research, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
$/LicenseInfo$
"""
import random, socket, string, time, re
import uuid
try:
# Python 2.6
from hashlib import md5
except ImportError:
# Python 2.5 and earlier
from md5 import new as md5
def _int2binstr(i,l):
s=''
for a in range(l):
s=chr(i&0xFF)+s
i>>=8
return s
def _binstr2int(s):
i = long(0)
for c in s:
i = (i<<8) + ord(c)
return i
class UUID(object):
"""
A class which represents a 16 byte integer. Stored as a 16 byte 8
bit character string.
The string version is to be of the form:
AAAAAAAA-AAAA-BBBB-BBBB-BBBBBBCCCCCC (a 128-bit number in hex)
where A=network address, B=timestamp, C=random.
"""
NULL_STR = "00000000-0000-0000-0000-000000000000"
# the UUIDREGEX_STRING is helpful for parsing UUID's in text
hex_wildcard = r"[0-9a-fA-F]"
word = hex_wildcard + r"{4,4}-"
long_word = hex_wildcard + r"{8,8}-"
very_long_word = hex_wildcard + r"{12,12}"
UUID_REGEX_STRING = long_word + word + word + word + very_long_word
uuid_regex = re.compile(UUID_REGEX_STRING)
rand = random.Random()
ip = ''
try:
ip = socket.gethostbyname(socket.gethostname())
except(socket.gaierror, socket.error):
# no ip address, so just default to somewhere in 10.x.x.x
ip = '10'
for i in range(3):
ip += '.' + str(rand.randrange(1,254))
hexip = ''.join(["%04x" % long(i) for i in ip.split('.')])
lastid = ''
def __init__(self, possible_uuid=None):
"""
Initialize to first valid UUID in argument (if a string),
or to null UUID if none found or argument is not supplied.
If the argument is a UUID, the constructed object will be a copy of it.
"""
self._bits = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
if possible_uuid is None:
return
if isinstance(possible_uuid, type(self)):
self.set(possible_uuid)
return
uuid_match = UUID.uuid_regex.search(possible_uuid)
if uuid_match:
uuid_string = uuid_match.group()
s = string.replace(uuid_string, '-', '')
self._bits = _int2binstr(string.atol(s[:8],16),4) + \
_int2binstr(string.atol(s[8:16],16),4) + \
_int2binstr(string.atol(s[16:24],16),4) + \
_int2binstr(string.atol(s[24:],16),4)
def __len__(self):
"""
Used by the len() builtin.
"""
return 36
def __nonzero__(self):
return self._bits != "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
def __str__(self):
uuid_string = self.toString()
return uuid_string
__repr__ = __str__
def __getitem__(self, index):
return str(self)[index]
def __eq__(self, other):
if isinstance(other, (str, unicode)):
return other == str(self)
return self._bits == getattr(other, '_bits', '')
def __ne__(self, other):
return not self.__eq__(other)
def __le__(self, other):
return self._bits <= other._bits
def __ge__(self, other):
return self._bits >= other._bits
def __lt__(self, other):
return self._bits < other._bits
def __gt__(self, other):
return self._bits > other._bits
def __hash__(self):
return hash(self._bits)
def set(self, uuid):
self._bits = uuid._bits
def setFromString(self, uuid_string):
"""
Given a string version of a uuid, set self bits
appropriately. Returns self.
"""
s = string.replace(uuid_string, '-', '')
self._bits = _int2binstr(string.atol(s[:8],16),4) + \
_int2binstr(string.atol(s[8:16],16),4) + \
_int2binstr(string.atol(s[16:24],16),4) + \
_int2binstr(string.atol(s[24:],16),4)
return self
def setFromMemoryDump(self, gdb_string):
"""
We expect to get gdb_string as four hex units. eg:
0x147d54db 0xc34b3f1b 0x714f989b 0x0a892fd2
Which will be translated to:
db547d14-1b3f4bc3-9b984f71-d22f890a
Returns self.
"""
s = string.replace(gdb_string, '0x', '')
s = string.replace(s, ' ', '')
t = ''
for i in range(8,40,8):
for j in range(0,8,2):
t = t + s[i-j-2:i-j]
self.setFromString(t)
def toString(self):
"""
Return as a string matching the LL standard
AAAAAAAA-AAAA-BBBB-BBBB-BBBBBBCCCCCC (a 128-bit number in hex)
where A=network address, B=timestamp, C=random.
"""
return uuid_bits_to_string(self._bits)
def getAsString(self):
"""
Return a different string representation of the form
AAAAAAAA-AAAABBBB-BBBBBBBB-BBCCCCCC (a 128-bit number in hex)
where A=network address, B=timestamp, C=random.
"""
i1 = _binstr2int(self._bits[0:4])
i2 = _binstr2int(self._bits[4:8])
i3 = _binstr2int(self._bits[8:12])
i4 = _binstr2int(self._bits[12:16])
return '%08lx-%08lx-%08lx-%08lx' % (i1,i2,i3,i4)
def generate(self):
"""
Generate a new uuid. This algorithm is slightly different
from c++ implementation for portability reasons.
Returns self.
"""
m = md5()
m.update(uuid.uuid1().bytes)
self._bits = m.digest()
return self
def isNull(self):
"""
Returns 1 if the uuid is null - ie, equal to default uuid.
"""
return (self._bits == "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0")
def xor(self, rhs):
"""
xors self with rhs.
"""
v1 = _binstr2int(self._bits[0:4]) ^ _binstr2int(rhs._bits[0:4])
v2 = _binstr2int(self._bits[4:8]) ^ _binstr2int(rhs._bits[4:8])
v3 = _binstr2int(self._bits[8:12]) ^ _binstr2int(rhs._bits[8:12])
v4 = _binstr2int(self._bits[12:16]) ^ _binstr2int(rhs._bits[12:16])
self._bits = _int2binstr(v1,4) + \
_int2binstr(v2,4) + \
_int2binstr(v3,4) + \
_int2binstr(v4,4)
# module-level null constant
NULL = UUID()
def printTranslatedMemory(four_hex_uints):
"""
We expect to get the string as four hex units. eg:
0x147d54db 0xc34b3f1b 0x714f989b 0x0a892fd2
Which will be translated to:
db547d14-1b3f4bc3-9b984f71-d22f890a
"""
uuid = UUID()
uuid.setFromMemoryDump(four_hex_uints)
print uuid.toString()
def isUUID(id_str):
"""
This function returns:
- 1 if the string passed is a UUID
- 0 is the string passed is not a UUID
- None if it neither of the if's below is satisfied
"""
if not id_str or len(id_str) < 5 or len(id_str) > 36:
return 0
if isinstance(id_str, UUID) or UUID.uuid_regex.match(id_str):
return 1
return None
def isPossiblyID(id_str):
"""
This function returns 1 if the string passed has some uuid-like
characteristics. Otherwise returns 0.
"""
is_uuid = isUUID(id_str)
if is_uuid is not None:
return is_uuid
# build a string which matches every character.
hex_wildcard = r"[0-9a-fA-F]"
chars = len(id_str)
next = min(chars, 8)
matcher = hex_wildcard+"{"+str(next)+","+str(next)+"}"
chars = chars - next
if chars > 0:
matcher = matcher + "-"
chars = chars - 1
for block in range(3):
next = max(min(chars, 4), 0)
if next:
matcher = matcher + hex_wildcard+"{"+str(next)+","+str(next)+"}"
chars = chars - next
if chars > 0:
matcher = matcher + "-"
chars = chars - 1
if chars > 0:
next = min(chars, 12)
matcher = matcher + hex_wildcard+"{"+str(next)+","+str(next)+"}"
#print matcher
uuid_matcher = re.compile(matcher)
if uuid_matcher.match(id_str):
return 1
return 0
def uuid_bits_to_string(bits):
i1 = _binstr2int(bits[0:4])
i2 = _binstr2int(bits[4:6])
i3 = _binstr2int(bits[6:8])
i4 = _binstr2int(bits[8:10])
i5 = _binstr2int(bits[10:12])
i6 = _binstr2int(bits[12:16])
return '%08lx-%04lx-%04lx-%04lx-%04lx%08lx' % (i1,i2,i3,i4,i5,i6)
def uuid_bits_to_uuid(bits):
return UUID(uuid_bits_to_string(bits))
try:
from mulib import stacked
stacked.NoProducer() # just to exercise stacked
except:
#print "Couldn't import mulib.stacked, not registering UUID converter"
pass
else:
def convertUUID(uuid, req):
req.write(str(uuid))
stacked.add_producer(UUID, convertUUID, "*/*")
stacked.add_producer(UUID, convertUUID, "text/html")

View File

@@ -1,121 +0,0 @@
"""\
@file metrics.py
@author Phoenix
@date 2007-11-27
@brief simple interface for logging metrics
$LicenseInfo:firstyear=2007&license=mit$
Copyright (c) 2007-2009, Linden Research, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
$/LicenseInfo$
"""
import sys
try:
import syslog
except ImportError:
# Windows
import sys
class syslog(object):
# wrap to a lame syslog for windows
_logfp = sys.stderr
def syslog(msg):
_logfp.write(msg)
if not msg.endswith('\n'):
_logfp.write('\n')
syslog = staticmethod(syslog)
from indra.base.llsd import format_notation
def record_metrics(table, stats):
"Write a standard metrics log"
_log("LLMETRICS", table, stats)
def record_event(table, data):
"Write a standard logmessage log"
_log("LLLOGMESSAGE", table, data)
def set_destination(dest):
"""Set the destination of metrics logs for this process.
If you do not call this function prior to calling a logging
method, that function will open sys.stdout as a destination.
Attempts to set dest to None will throw a RuntimeError.
@param dest a file-like object which will be the destination for logs."""
if dest is None:
raise RuntimeError("Attempt to unset metrics destination.")
global _destination
_destination = dest
def destination():
"""Get the destination of the metrics logs for this process.
Returns None if no destination is set"""
global _destination
return _destination
class SysLogger(object):
"A file-like object which writes to syslog."
def __init__(self, ident='indra', logopt = None, facility = None):
try:
if logopt is None:
logopt = syslog.LOG_CONS | syslog.LOG_PID
if facility is None:
facility = syslog.LOG_LOCAL0
syslog.openlog(ident, logopt, facility)
import atexit
atexit.register(syslog.closelog)
except AttributeError:
# No syslog module on Windows
pass
def write(str):
syslog.syslog(str)
write = staticmethod(write)
def flush():
pass
flush = staticmethod(flush)
#
# internal API
#
_sequence_id = 0
_destination = None
def _next_id():
global _sequence_id
next = _sequence_id
_sequence_id += 1
return next
def _dest():
global _destination
if _destination is None:
# this default behavior is documented in the metrics functions above.
_destination = sys.stdout
return _destination
def _log(header, table, data):
log_line = "%s (%d) %s %s" \
% (header, _next_id(), table, format_notation(data))
dest = _dest()
dest.write(log_line)
dest.flush()

View File

@@ -1,30 +0,0 @@
#!/usr/bin/python
## $LicenseInfo:firstyear=2011&license=viewerlgpl$
## Second Life Viewer Source Code
## Copyright (C) 2011, Linden Research, Inc.
##
## This library is free software; you can redistribute it and/or
## modify it under the terms of the GNU Lesser General Public
## License as published by the Free Software Foundation;
## version 2.1 of the License only.
##
## This library is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
## Lesser General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public
## License along with this library; if not, write to the Free Software
## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
##
## Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
## $/LicenseInfo$
import warnings
warnings.warn("indra.ipc.httputil has been deprecated; use eventlet.httpc instead", DeprecationWarning, 2)
from eventlet.httpc import *
makeConnection = make_connection

View File

@@ -1,100 +0,0 @@
"""\
@file llsdhttp.py
@brief Functions to ease moving llsd over http
$LicenseInfo:firstyear=2006&license=mit$
Copyright (c) 2006-2009, Linden Research, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
$/LicenseInfo$
"""
import os.path
import os
import urlparse
from indra.base import llsd
from eventlet import httpc
suite = httpc.HttpSuite(llsd.format_xml, llsd.parse, 'application/llsd+xml')
delete = suite.delete
delete_ = suite.delete_
get = suite.get
get_ = suite.get_
head = suite.head
head_ = suite.head_
post = suite.post
post_ = suite.post_
put = suite.put
put_ = suite.put_
request = suite.request
request_ = suite.request_
# import every httpc error exception into our namespace for convenience
for x in httpc.status_to_error_map.itervalues():
globals()[x.__name__] = x
ConnectionError = httpc.ConnectionError
Retriable = httpc.Retriable
for x in (httpc.ConnectionError,):
globals()[x.__name__] = x
def postFile(url, filename):
f = open(filename)
body = f.read()
f.close()
llsd_body = llsd.parse(body)
return post_(url, llsd_body)
# deprecated in favor of get_
def getStatus(url, use_proxy=False):
status, _headers, _body = get_(url, use_proxy=use_proxy)
return status
# deprecated in favor of put_
def putStatus(url, data):
status, _headers, _body = put_(url, data)
return status
# deprecated in favor of delete_
def deleteStatus(url):
status, _headers, _body = delete_(url)
return status
# deprecated in favor of post_
def postStatus(url, data):
status, _headers, _body = post_(url, data)
return status
def postFileStatus(url, filename):
status, _headers, body = postFile(url, filename)
return status, body
def getFromSimulator(path, use_proxy=False):
return get('http://' + simulatorHostAndPort + path, use_proxy=use_proxy)
def postToSimulator(path, data=None):
return post('http://' + simulatorHostAndPort + path, data)

View File

@@ -1,81 +0,0 @@
"""\
@file mysql_pool.py
@brief Thin wrapper around eventlet.db_pool that chooses MySQLdb and Tpool.
$LicenseInfo:firstyear=2007&license=mit$
Copyright (c) 2007-2009, Linden Research, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
$/LicenseInfo$
"""
import MySQLdb
from eventlet import db_pool
class DatabaseConnector(db_pool.DatabaseConnector):
def __init__(self, credentials, *args, **kwargs):
super(DatabaseConnector, self).__init__(MySQLdb, credentials,
conn_pool=db_pool.ConnectionPool,
*args, **kwargs)
# get is extended relative to eventlet.db_pool to accept a port argument
def get(self, host, dbname, port=3306):
key = (host, dbname, port)
if key not in self._databases:
new_kwargs = self._kwargs.copy()
new_kwargs['db'] = dbname
new_kwargs['host'] = host
new_kwargs['port'] = port
new_kwargs.update(self.credentials_for(host))
dbpool = ConnectionPool(*self._args, **new_kwargs)
self._databases[key] = dbpool
return self._databases[key]
class ConnectionPool(db_pool.TpooledConnectionPool):
"""A pool which gives out saranwrapped MySQLdb connections from a pool
"""
def __init__(self, *args, **kwargs):
super(ConnectionPool, self).__init__(MySQLdb, *args, **kwargs)
def get(self):
conn = super(ConnectionPool, self).get()
# annotate the connection object with the details on the
# connection; this is used elsewhere to check that you haven't
# suddenly changed databases in midstream while making a
# series of queries on a connection.
arg_names = ['host','user','passwd','db','port','unix_socket','conv','connect_timeout',
'compress', 'named_pipe', 'init_command', 'read_default_file', 'read_default_group',
'cursorclass', 'use_unicode', 'charset', 'sql_mode', 'client_flag', 'ssl',
'local_infile']
# you could have constructed this connectionpool with a mix of
# keyword and non-keyword arguments, but we want to annotate
# the connection object with a dict so it's easy to check
# against so here we are converting the list of non-keyword
# arguments (in self._args) into a dict of keyword arguments,
# and merging that with the actual keyword arguments
# (self._kwargs). The arg_names variable lists the
# constructor arguments for MySQLdb Connection objects.
converted_kwargs = dict([ (arg_names[i], arg) for i, arg in enumerate(self._args) ])
converted_kwargs.update(self._kwargs)
conn.connection_parameters = converted_kwargs
return conn

View File

@@ -1,165 +0,0 @@
"""\
@file russ.py
@brief Recursive URL Substitution Syntax helpers
@author Phoenix
Many details on how this should work is available on the wiki:
https://wiki.secondlife.com/wiki/Recursive_URL_Substitution_Syntax
Adding features to this should be reflected in that page in the
implementations section.
$LicenseInfo:firstyear=2007&license=mit$
Copyright (c) 2007-2009, Linden Research, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
$/LicenseInfo$
"""
import urllib
from indra.ipc import llsdhttp
class UnbalancedBraces(Exception):
pass
class UnknownDirective(Exception):
pass
class BadDirective(Exception):
pass
def format_value_for_path(value):
if type(value) in [list, tuple]:
# *NOTE: treat lists as unquoted path components so that the quoting
# doesn't get out-of-hand. This is a workaround for the fact that
# russ always quotes, even if the data it's given is already quoted,
# and it's not safe to simply unquote a path directly, so if we want
# russ to substitute urls parts inside other url parts we always
# have to do so via lists of unquoted path components.
return '/'.join([urllib.quote(str(item)) for item in value])
else:
return urllib.quote(str(value))
def format(format_str, context):
"""@brief Format format string according to rules for RUSS.
@see https://osiris.lindenlab.com/mediawiki/index.php/Recursive_URL_Substitution_Syntax
@param format_str The input string to format.
@param context A map used for string substitutions.
@return Returns the formatted string. If no match, the braces remain intact.
"""
while True:
#print "format_str:", format_str
all_matches = _find_sub_matches(format_str)
if not all_matches:
break
substitutions = 0
while True:
matches = all_matches.pop()
# we work from right to left to make sure we do not
# invalidate positions earlier in format_str
matches.reverse()
for pos in matches:
# Use index since _find_sub_matches should have raised
# an exception, and failure to find now is an exception.
end = format_str.index('}', pos)
#print "directive:", format_str[pos+1:pos+5]
if format_str[pos + 1] == '$':
value = context[format_str[pos + 2:end]]
if value is not None:
value = format_value_for_path(value)
elif format_str[pos + 1] == '%':
value = _build_query_string(
context.get(format_str[pos + 2:end]))
elif format_str[pos+1:pos+5] == 'http' or format_str[pos+1:pos+5] == 'file':
value = _fetch_url_directive(format_str[pos + 1:end])
else:
raise UnknownDirective, format_str[pos:end + 1]
if value is not None:
format_str = format_str[:pos]+str(value)+format_str[end+1:]
substitutions += 1
# If there were any substitutions at this depth, re-parse
# since this may have revealed new things to substitute
if substitutions:
break
if not all_matches:
break
# If there were no substitutions at all, and we have exhausted
# the possible matches, bail.
if not substitutions:
break
return format_str
def _find_sub_matches(format_str):
"""@brief Find all of the substitution matches.
@param format_str the RUSS conformant format string.
@return Returns an array of depths of arrays of positional matches in input.
"""
depth = 0
matches = []
for pos in range(len(format_str)):
if format_str[pos] == '{':
depth += 1
if not len(matches) == depth:
matches.append([])
matches[depth - 1].append(pos)
continue
if format_str[pos] == '}':
depth -= 1
continue
if not depth == 0:
raise UnbalancedBraces, format_str
return matches
def _build_query_string(query_dict):
"""\
@breif given a dict, return a query string. utility wrapper for urllib.
@param query_dict input query dict
@returns Returns an urlencoded query string including leading '?'.
"""
if query_dict:
keys = query_dict.keys()
keys.sort()
def stringize(value):
if type(value) in (str,unicode):
return value
else:
return str(value)
query_list = [urllib.quote(str(key)) + '=' + urllib.quote(stringize(query_dict[key])) for key in keys]
return '?' + '&'.join(query_list)
else:
return ''
def _fetch_url_directive(directive):
"*FIX: This only supports GET"
commands = directive.split('|')
resource = llsdhttp.get(commands[0])
if len(commands) == 3:
resource = _walk_resource(resource, commands[2])
return resource
def _walk_resource(resource, path):
path = path.split('/')
for child in path:
if not child:
continue
resource = resource[child]
return resource

View File

@@ -1,134 +0,0 @@
"""\
@file servicebuilder.py
@author Phoenix
@brief Class which will generate service urls.
$LicenseInfo:firstyear=2007&license=mit$
Copyright (c) 2007-2009, Linden Research, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
$/LicenseInfo$
"""
from indra.base import config
from indra.ipc import llsdhttp
from indra.ipc import russ
# *NOTE: agent presence relies on this variable existing and being current, it is a huge hack
services_config = {}
try:
services_config = llsdhttp.get(config.get('services-config'))
except:
pass
_g_builder = None
def _builder():
global _g_builder
if _g_builder is None:
_g_builder = ServiceBuilder()
return _g_builder
def build(name, context={}, **kwargs):
""" Convenience method for using a global, singleton, service builder. Pass arguments either via a dict or via python keyword arguments, or both!
Example use:
> context = {'channel':'Second Life Release', 'version':'1.18.2.0'}
> servicebuilder.build('version-manager-version', context)
'http://int.util.vaak.lindenlab.com/channel/Second%20Life%20Release/1.18.2.0'
> servicebuilder.build('version-manager-version', channel='Second Life Release', version='1.18.2.0')
'http://int.util.vaak.lindenlab.com/channel/Second%20Life%20Release/1.18.2.0'
> servicebuilder.build('version-manager-version', context, version='1.18.1.2')
'http://int.util.vaak.lindenlab.com/channel/Second%20Life%20Release/1.18.1.2'
"""
global _g_builder
if _g_builder is None:
_g_builder = ServiceBuilder()
return _g_builder.buildServiceURL(name, context, **kwargs)
def build_path(name, context={}, **kwargs):
context = context.copy() # shouldn't modify the caller's dictionary
context.update(kwargs)
return _builder().buildPath(name, context)
class ServiceBuilder(object):
def __init__(self, services_definition = services_config):
"""\
@brief
@brief Create a ServiceBuilder.
@param services_definition Complete services definition, services.xml.
"""
# no need to keep a copy of the services section of the
# complete services definition, but it doesn't hurt much.
self.services = services_definition['services']
self.builders = {}
for service in self.services:
service_builder = service.get('service-builder')
if not service_builder:
continue
if isinstance(service_builder, dict):
# We will be constructing several builders
for name, builder in service_builder.iteritems():
full_builder_name = service['name'] + '-' + name
self.builders[full_builder_name] = builder
else:
self.builders[service['name']] = service_builder
def buildPath(self, name, context):
"""\
@brief given the environment on construction, return a service path.
@param name The name of the service.
@param context A dict of name value lookups for the service.
@returns Returns the
"""
return russ.format(self.builders[name], context)
def buildServiceURL(self, name, context={}, **kwargs):
"""\
@brief given the environment on construction, return a service URL.
@param name The name of the service.
@param context A dict of name value lookups for the service.
@param kwargs Any keyword arguments are treated as members of the
context, this allows you to be all 31337 by writing shit like:
servicebuilder.build('name', param=value)
@returns Returns the
"""
context = context.copy() # shouldn't modify the caller's dictionary
context.update(kwargs)
base_url = config.get('services-base-url')
svc_path = russ.format(self.builders[name], context)
return base_url + svc_path
def on_in(query_name, host_key, schema_key):
"""\
@brief Constructs an on/in snippet (for running named queries)
from a schema name and two keys referencing values stored in
indra.xml.
@param query_name Name of the query.
@param host_key Logical name of destination host. Will be
looked up in indra.xml.
@param schema_key Logical name of destination schema. Will
be looked up in indra.xml.
"""
return "on/config:%s/in/config:%s/%s" % (host_key.strip('/'),
schema_key.strip('/'),
query_name.lstrip('/'))

View File

@@ -1,468 +0,0 @@
"""\
@file siesta.py
@brief A tiny llsd based RESTful web services framework
$LicenseInfo:firstyear=2008&license=mit$
Copyright (c) 2008, Linden Research, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
$/LicenseInfo$
"""
from indra.base import config
from indra.base import llsd
from webob import exc
import webob
import re, socket
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
try:
import cjson
json_decode = cjson.decode
json_encode = cjson.encode
JsonDecodeError = cjson.DecodeError
JsonEncodeError = cjson.EncodeError
except ImportError:
import simplejson
json_decode = simplejson.loads
json_encode = simplejson.dumps
JsonDecodeError = ValueError
JsonEncodeError = TypeError
llsd_parsers = {
'application/json': json_decode,
llsd.BINARY_MIME_TYPE: llsd.parse_binary,
'application/llsd+notation': llsd.parse_notation,
llsd.XML_MIME_TYPE: llsd.parse_xml,
'application/xml': llsd.parse_xml,
}
def mime_type(content_type):
'''Given a Content-Type header, return only the MIME type.'''
return content_type.split(';', 1)[0].strip().lower()
class BodyLLSD(object):
'''Give a webob Request or Response an llsd based "content" property.
Getting the content property parses the body, and caches the result.
Setting the content property formats a payload, and the body property
is set.'''
def _llsd__get(self):
'''Get, set, or delete the LLSD value stored in this object.'''
try:
return self._llsd
except AttributeError:
if not self.body:
raise AttributeError('No llsd attribute has been set')
else:
mtype = mime_type(self.content_type)
try:
parser = llsd_parsers[mtype]
except KeyError:
raise exc.HTTPUnsupportedMediaType(
'Content type %s not supported' % mtype).exception
try:
self._llsd = parser(self.body)
except (llsd.LLSDParseError, JsonDecodeError, TypeError), err:
raise exc.HTTPBadRequest(
'Could not parse body: %r' % err.args).exception
return self._llsd
def _llsd__set(self, val):
req = getattr(self, 'request', None)
if req is not None:
formatter, ctype = formatter_for_request(req)
self.content_type = ctype
else:
formatter, ctype = formatter_for_mime_type(
mime_type(self.content_type))
self.body = formatter(val)
def _llsd__del(self):
if hasattr(self, '_llsd'):
del self._llsd
content = property(_llsd__get, _llsd__set, _llsd__del)
class Response(webob.Response, BodyLLSD):
'''Response class with LLSD support.
A sensible default content type is used.
Setting the llsd property also sets the body. Getting the llsd
property parses the body if necessary.
If you set the body property directly, the llsd property will be
deleted.'''
default_content_type = 'application/llsd+xml'
def _body__set(self, body):
if hasattr(self, '_llsd'):
del self._llsd
super(Response, self)._body__set(body)
def cache_forever(self):
self.cache_expires(86400 * 365)
body = property(webob.Response._body__get, _body__set,
webob.Response._body__del,
webob.Response._body__get.__doc__)
class Request(webob.Request, BodyLLSD):
'''Request class with LLSD support.
Sensible content type and accept headers are used by default.
Setting the content property also sets the body. Getting the content
property parses the body if necessary.
If you set the body property directly, the content property will be
deleted.'''
default_content_type = 'application/llsd+xml'
default_accept = ('application/llsd+xml; q=0.5, '
'application/llsd+notation; q=0.3, '
'application/llsd+binary; q=0.2, '
'application/xml; q=0.1, '
'application/json; q=0.0')
def __init__(self, environ=None, *args, **kwargs):
if environ is None:
environ = {}
else:
environ = environ.copy()
if 'CONTENT_TYPE' not in environ:
environ['CONTENT_TYPE'] = self.default_content_type
if 'HTTP_ACCEPT' not in environ:
environ['HTTP_ACCEPT'] = self.default_accept
super(Request, self).__init__(environ, *args, **kwargs)
def _body__set(self, body):
if hasattr(self, '_llsd'):
del self._llsd
super(Request, self)._body__set(body)
def path_urljoin(self, *parts):
return '/'.join([path_url.rstrip('/')] + list(parts))
body = property(webob.Request._body__get, _body__set,
webob.Request._body__del, webob.Request._body__get.__doc__)
def create_response(self, content=None, status='200 OK',
conditional_response=webob.NoDefault):
resp = self.ResponseClass(status=status, request=self,
conditional_response=conditional_response)
resp.content = content
return resp
def curl(self):
'''Create and fill out a pycurl easy object from this request.'''
import pycurl
c = pycurl.Curl()
c.setopt(pycurl.URL, self.url())
if self.headers:
c.setopt(pycurl.HTTPHEADER,
['%s: %s' % (k, self.headers[k]) for k in self.headers])
c.setopt(pycurl.FOLLOWLOCATION, True)
c.setopt(pycurl.AUTOREFERER, True)
c.setopt(pycurl.MAXREDIRS, 16)
c.setopt(pycurl.NOSIGNAL, True)
c.setopt(pycurl.READFUNCTION, self.body_file.read)
c.setopt(pycurl.SSL_VERIFYHOST, 2)
if self.method == 'POST':
c.setopt(pycurl.POST, True)
post301 = getattr(pycurl, 'POST301', None)
if post301 is not None:
# Added in libcurl 7.17.1.
c.setopt(post301, True)
elif self.method == 'PUT':
c.setopt(pycurl.PUT, True)
elif self.method != 'GET':
c.setopt(pycurl.CUSTOMREQUEST, self.method)
return c
Request.ResponseClass = Response
Response.RequestClass = Request
llsd_formatters = {
'application/json': json_encode,
'application/llsd+binary': llsd.format_binary,
'application/llsd+notation': llsd.format_notation,
'application/llsd+xml': llsd.format_xml,
'application/xml': llsd.format_xml,
}
formatter_qualities = (
('application/llsd+xml', 1.0),
('application/llsd+notation', 0.5),
('application/llsd+binary', 0.4),
('application/xml', 0.3),
('application/json', 0.2),
)
def formatter_for_mime_type(mime_type):
'''Return a formatter that encodes to the given MIME type.
The result is a pair of function and MIME type.'''
try:
return llsd_formatters[mime_type], mime_type
except KeyError:
raise exc.HTTPInternalServerError(
'Could not use MIME type %r to format response' %
mime_type).exception
def formatter_for_request(req):
'''Return a formatter that encodes to the preferred type of the client.
The result is a pair of function and actual MIME type.'''
ctype = req.accept.best_match(formatter_qualities)
try:
return llsd_formatters[ctype], ctype
except KeyError:
raise exc.HTTPNotAcceptable().exception
def wsgi_adapter(func, environ, start_response):
'''Adapt a Siesta callable to act as a WSGI application.'''
# Process the request as appropriate.
try:
req = Request(environ)
#print req.urlvars
resp = func(req, **req.urlvars)
if not isinstance(resp, webob.Response):
try:
formatter, ctype = formatter_for_request(req)
resp = req.ResponseClass(formatter(resp), content_type=ctype)
resp._llsd = resp
except (JsonEncodeError, TypeError), err:
resp = exc.HTTPInternalServerError(
detail='Could not format response')
except exc.HTTPException, e:
resp = e
except socket.error, e:
resp = exc.HTTPInternalServerError(detail=e.args[1])
return resp(environ, start_response)
def llsd_callable(func):
'''Turn a callable into a Siesta application.'''
def replacement(environ, start_response):
return wsgi_adapter(func, environ, start_response)
return replacement
def llsd_method(http_method, func):
def replacement(environ, start_response):
if environ['REQUEST_METHOD'] == http_method:
return wsgi_adapter(func, environ, start_response)
return exc.HTTPMethodNotAllowed()(environ, start_response)
return replacement
http11_methods = 'OPTIONS GET HEAD POST PUT DELETE TRACE CONNECT'.split()
http11_methods.sort()
def llsd_class(cls):
'''Turn a class into a Siesta application.
A new instance is created for each request. A HTTP method FOO is
turned into a call to the handle_foo method of the instance.'''
def foo(req, **kwargs):
instance = cls()
method = req.method.lower()
try:
handler = getattr(instance, 'handle_' + method)
except AttributeError:
allowed = [m for m in http11_methods
if hasattr(instance, 'handle_' + m.lower())]
raise exc.HTTPMethodNotAllowed(
headers={'Allow': ', '.join(allowed)}).exception
#print "kwargs: ", kwargs
return handler(req, **kwargs)
def replacement(environ, start_response):
return wsgi_adapter(foo, environ, start_response)
return replacement
def curl(reqs):
import pycurl
m = pycurl.CurlMulti()
curls = [r.curl() for r in reqs]
io = {}
for c in curls:
fp = StringIO()
hdr = StringIO()
c.setopt(pycurl.WRITEFUNCTION, fp.write)
c.setopt(pycurl.HEADERFUNCTION, hdr.write)
io[id(c)] = fp, hdr
m.handles = curls
try:
while True:
ret, num_handles = m.perform()
if ret != pycurl.E_CALL_MULTI_PERFORM:
break
finally:
m.close()
for req, c in zip(reqs, curls):
fp, hdr = io[id(c)]
hdr.seek(0)
status = hdr.readline().rstrip()
headers = []
name, values = None, None
# XXX We don't currently handle bogus header data.
for line in hdr.readlines():
if not line[0].isspace():
if name:
headers.append((name, ' '.join(values)))
name, value = line.strip().split(':', 1)
value = [value]
else:
values.append(line.strip())
if name:
headers.append((name, ' '.join(values)))
resp = c.ResponseClass(fp.getvalue(), status, headers, request=req)
route_re = re.compile(r'''
\{ # exact character "{"
(\w*) # "config" or variable (restricted to a-z, 0-9, _)
(?:([:~])([^}]+))? # optional :type or ~regex part
\} # exact character "}"
''', re.VERBOSE)
predefined_regexps = {
'uuid': r'[a-f0-9][a-f0-9-]{31,35}',
'int': r'\d+',
'host': r'[a-z0-9][a-z0-9\-\.]*',
}
def compile_route(route):
fp = StringIO()
last_pos = 0
for match in route_re.finditer(route):
#print "matches: ", match.groups()
fp.write(re.escape(route[last_pos:match.start()]))
var_name = match.group(1)
sep = match.group(2)
expr = match.group(3)
if var_name == 'config':
expr = re.escape(str(config.get(var_name)))
else:
if expr:
if sep == ':':
expr = predefined_regexps[expr]
# otherwise, treat what follows '~' as a regexp
else:
expr = '[^/]+'
if var_name != '':
expr = '(?P<%s>%s)' % (var_name, expr)
else:
expr = '(%s)' % (expr,)
fp.write(expr)
last_pos = match.end()
fp.write(re.escape(route[last_pos:]))
compiled_route = '^%s$' % fp.getvalue()
#print route, "->", compiled_route
return compiled_route
class Router(object):
'''WSGI routing class. Parses a URL and hands off a request to
some other WSGI application. If no suitable application is found,
responds with a 404.'''
def __init__(self):
self._new_routes = []
self._routes = []
self._paths = []
def add(self, route, app, methods=None):
self._new_routes.append((route, app, methods))
def _create_routes(self):
for route, app, methods in self._new_routes:
self._paths.append(route)
self._routes.append(
(re.compile(compile_route(route)),
app,
methods and dict.fromkeys(methods)))
self._new_routes = []
def __call__(self, environ, start_response):
# load up the config from the config file. Only needs to be
# done once per interpreter. This is the entry point of all
# siesta applications, so this is where we trap it.
_conf = config.get_config()
if _conf is None:
import os.path
fname = os.path.join(
environ.get('ll.config_dir', '/local/linden/etc'),
'indra.xml')
config.load(fname)
# proceed with handling the request
self._create_routes()
path_info = environ['PATH_INFO']
request_method = environ['REQUEST_METHOD']
allowed = []
for regex, app, methods in self._routes:
m = regex.match(path_info)
if m:
#print "groupdict:",m.groupdict()
if not methods or request_method in methods:
environ['paste.urlvars'] = m.groupdict()
return app(environ, start_response)
else:
allowed += methods
if allowed:
allowed = dict.fromkeys(allows).keys()
allowed.sort()
resp = exc.HTTPMethodNotAllowed(
headers={'Allow': ', '.join(allowed)})
else:
resp = exc.HTTPNotFound()
return resp(environ, start_response)

View File

@@ -1,235 +0,0 @@
#!/usr/bin/python
## $LicenseInfo:firstyear=2011&license=viewerlgpl$
## Second Life Viewer Source Code
## Copyright (C) 2011, Linden Research, Inc.
##
## This library is free software; you can redistribute it and/or
## modify it under the terms of the GNU Lesser General Public
## License as published by the Free Software Foundation;
## version 2.1 of the License only.
##
## This library is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
## Lesser General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public
## License along with this library; if not, write to the Free Software
## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
##
## Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
## $/LicenseInfo$
from indra.base import llsd, lluuid
from indra.ipc import siesta
import datetime, math, unittest
from webob import exc
class ClassApp(object):
def handle_get(self, req):
pass
def handle_post(self, req):
return req.llsd
def callable_app(req):
if req.method == 'UNDERPANTS':
raise exc.HTTPMethodNotAllowed()
elif req.method == 'GET':
return None
return req.llsd
class TestBase:
def test_basic_get(self):
req = siesta.Request.blank('/')
self.assertEquals(req.get_response(self.server).body,
llsd.format_xml(None))
def test_bad_method(self):
req = siesta.Request.blank('/')
req.environ['REQUEST_METHOD'] = 'UNDERPANTS'
self.assertEquals(req.get_response(self.server).status_int,
exc.HTTPMethodNotAllowed.code)
json_safe = {
'none': None,
'bool_true': True,
'bool_false': False,
'int_zero': 0,
'int_max': 2147483647,
'int_min': -2147483648,
'long_zero': 0,
'long_max': 2147483647L,
'long_min': -2147483648L,
'float_zero': 0,
'float': math.pi,
'float_huge': 3.14159265358979323846e299,
'str_empty': '',
'str': 'foo',
u'unic\u1e51de_empty': u'',
u'unic\u1e51de': u'\u1e4exx\u10480',
}
json_safe['array'] = json_safe.values()
json_safe['tuple'] = tuple(json_safe.values())
json_safe['dict'] = json_safe.copy()
json_unsafe = {
'uuid_empty': lluuid.UUID(),
'uuid_full': lluuid.UUID('dc61ab0530200d7554d23510559102c1a98aab1b'),
'binary_empty': llsd.binary(),
'binary': llsd.binary('f\0\xff'),
'uri_empty': llsd.uri(),
'uri': llsd.uri('http://www.secondlife.com/'),
'datetime_empty': datetime.datetime(1970,1,1),
'datetime': datetime.datetime(1999,9,9,9,9,9),
}
json_unsafe.update(json_safe)
json_unsafe['array'] = json_unsafe.values()
json_unsafe['tuple'] = tuple(json_unsafe.values())
json_unsafe['dict'] = json_unsafe.copy()
json_unsafe['iter'] = iter(json_unsafe.values())
def _test_client_content_type_good(self, content_type, ll):
def run(ll):
req = siesta.Request.blank('/')
req.environ['REQUEST_METHOD'] = 'POST'
req.content_type = content_type
req.llsd = ll
req.accept = content_type
resp = req.get_response(self.server)
self.assertEquals(resp.status_int, 200)
return req, resp
if False and isinstance(ll, dict):
def fixup(v):
if isinstance(v, float):
return '%.5f' % v
if isinstance(v, long):
return int(v)
if isinstance(v, (llsd.binary, llsd.uri)):
return v
if isinstance(v, (tuple, list)):
return [fixup(i) for i in v]
if isinstance(v, dict):
return dict([(k, fixup(i)) for k, i in v.iteritems()])
return v
for k, v in ll.iteritems():
l = [k, v]
req, resp = run(l)
self.assertEquals(fixup(resp.llsd), fixup(l))
run(ll)
def test_client_content_type_json_good(self):
self._test_client_content_type_good('application/json', self.json_safe)
def test_client_content_type_llsd_xml_good(self):
self._test_client_content_type_good('application/llsd+xml',
self.json_unsafe)
def test_client_content_type_llsd_notation_good(self):
self._test_client_content_type_good('application/llsd+notation',
self.json_unsafe)
def test_client_content_type_llsd_binary_good(self):
self._test_client_content_type_good('application/llsd+binary',
self.json_unsafe)
def test_client_content_type_xml_good(self):
self._test_client_content_type_good('application/xml',
self.json_unsafe)
def _test_client_content_type_bad(self, content_type):
req = siesta.Request.blank('/')
req.environ['REQUEST_METHOD'] = 'POST'
req.body = '\0invalid nonsense under all encodings'
req.content_type = content_type
self.assertEquals(req.get_response(self.server).status_int,
exc.HTTPBadRequest.code)
def test_client_content_type_json_bad(self):
self._test_client_content_type_bad('application/json')
def test_client_content_type_llsd_xml_bad(self):
self._test_client_content_type_bad('application/llsd+xml')
def test_client_content_type_llsd_notation_bad(self):
self._test_client_content_type_bad('application/llsd+notation')
def test_client_content_type_llsd_binary_bad(self):
self._test_client_content_type_bad('application/llsd+binary')
def test_client_content_type_xml_bad(self):
self._test_client_content_type_bad('application/xml')
def test_client_content_type_bad(self):
req = siesta.Request.blank('/')
req.environ['REQUEST_METHOD'] = 'POST'
req.body = 'XXX'
req.content_type = 'application/nonsense'
self.assertEquals(req.get_response(self.server).status_int,
exc.HTTPUnsupportedMediaType.code)
def test_request_default_content_type(self):
req = siesta.Request.blank('/')
self.assertEquals(req.content_type, req.default_content_type)
def test_request_default_accept(self):
req = siesta.Request.blank('/')
from webob import acceptparse
self.assertEquals(str(req.accept).replace(' ', ''),
req.default_accept.replace(' ', ''))
def test_request_llsd_auto_body(self):
req = siesta.Request.blank('/')
req.llsd = {'a': 2}
self.assertEquals(req.body, '<?xml version="1.0" ?><llsd><map>'
'<key>a</key><integer>2</integer></map></llsd>')
def test_request_llsd_mod_body_changes_llsd(self):
req = siesta.Request.blank('/')
req.llsd = {'a': 2}
req.body = '<?xml version="1.0" ?><llsd><integer>1337</integer></llsd>'
self.assertEquals(req.llsd, 1337)
def test_request_bad_llsd_fails(self):
def crashme(ctype):
def boom():
class foo(object): pass
req = siesta.Request.blank('/')
req.content_type = ctype
req.llsd = foo()
for mime_type in siesta.llsd_parsers:
self.assertRaises(TypeError, crashme(mime_type))
class ClassServer(TestBase, unittest.TestCase):
def __init__(self, *args, **kwargs):
unittest.TestCase.__init__(self, *args, **kwargs)
self.server = siesta.llsd_class(ClassApp)
class CallableServer(TestBase, unittest.TestCase):
def __init__(self, *args, **kwargs):
unittest.TestCase.__init__(self, *args, **kwargs)
self.server = siesta.llsd_callable(callable_app)
class RouterServer(unittest.TestCase):
def test_router(self):
def foo(req, quux):
print quux
r = siesta.Router()
r.add('/foo/{quux:int}', siesta.llsd_callable(foo), methods=['GET'])
req = siesta.Request.blank('/foo/33')
req.get_response(r)
req = siesta.Request.blank('/foo/bar')
self.assertEquals(req.get_response(r).status_int,
exc.HTTPNotFound.code)
if __name__ == '__main__':
unittest.main()

View File

@@ -1,597 +0,0 @@
"""
@file webdav.py
@brief Classes to make manipulation of a webdav store easier.
$LicenseInfo:firstyear=2007&license=mit$
Copyright (c) 2007-2009, Linden Research, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
$/LicenseInfo$
"""
import sys, os, httplib, urlparse
import socket, time
import xml.dom.minidom
import syslog
# import signal
__revision__ = '0'
dav_debug = False
# def urlsafe_b64decode (enc):
# return base64.decodestring (enc.replace ('_', '/').replace ('-', '+'))
# def urlsafe_b64encode (str):
# return base64.encodestring (str).replace ('+', '-').replace ('/', '_')
class DAVError (Exception):
""" Base class for exceptions in this module. """
def __init__ (self, status=0, message='', body='', details=''):
self.status = status
self.message = message
self.body = body
self.details = details
Exception.__init__ (self, '%d:%s:%s%s' % (self.status, self.message,
self.body, self.details))
def print_to_stderr (self):
""" print_to_stderr docstring """
print >> sys.stderr, str (self.status) + ' ' + self.message
print >> sys.stderr, str (self.details)
class Timeout (Exception):
""" Timeout docstring """
def __init__ (self, arg=''):
Exception.__init__ (self, arg)
def alarm_handler (signum, frame):
""" alarm_handler docstring """
raise Timeout ('caught alarm')
class WebDAV:
""" WebDAV docstring """
def __init__ (self, url, proxy=None, retries_before_fail=6):
self.init_url = url
self.init_proxy = proxy
self.retries_before_fail = retries_before_fail
url_parsed = urlparse.urlsplit (url)
self.top_path = url_parsed[ 2 ]
# make sure top_path has a trailing /
if self.top_path == None or self.top_path == '':
self.top_path = '/'
elif len (self.top_path) > 1 and self.top_path[-1:] != '/':
self.top_path += '/'
if dav_debug:
syslog.syslog ('new WebDAV %s : %s' % (str (url), str (proxy)))
if proxy:
proxy_parsed = urlparse.urlsplit (proxy)
self.host_header = url_parsed[ 1 ]
host_and_port = proxy_parsed[ 1 ].split (':')
self.host = host_and_port[ 0 ]
if len (host_and_port) > 1:
self.port = int(host_and_port[ 1 ])
else:
self.port = 80
else: # no proxy
host_and_port = url_parsed[ 1 ].split (':')
self.host_header = None
self.host = host_and_port[ 0 ]
if len (host_and_port) > 1:
self.port = int(host_and_port[ 1 ])
else:
self.port = 80
self.connection = False
self.connect ()
def log (self, msg, depth=0):
""" log docstring """
if dav_debug and depth == 0:
host = str (self.init_url)
if host == 'http://int.tuco.lindenlab.com:80/asset/':
host = 'tuco'
if host == 'http://harriet.lindenlab.com/asset-keep/':
host = 'harriet/asset-keep'
if host == 'http://harriet.lindenlab.com/asset-flag/':
host = 'harriet/asset-flag'
if host == 'http://harriet.lindenlab.com/asset/':
host = 'harriet/asset'
if host == 'http://ozzy.lindenlab.com/asset/':
host = 'ozzy/asset'
if host == 'http://station11.lindenlab.com:12041/:':
host = 'station11:12041'
proxy = str (self.init_proxy)
if proxy == 'None':
proxy = ''
if proxy == 'http://int.tuco.lindenlab.com:3128/':
proxy = 'tuco'
syslog.syslog ('WebDAV (%s:%s) %s' % (host, proxy, str (msg)))
def connect (self):
""" connect docstring """
self.log ('connect')
self.connection = httplib.HTTPConnection (self.host, self.port)
def __err (self, response, details):
""" __err docstring """
raise DAVError (response.status, response.reason, response.read (),
str (self.init_url) + ':' + \
str (self.init_proxy) + ':' + str (details))
def request (self, method, path, body=None, headers=None,
read_all=True, body_hook = None, recurse=0, allow_cache=True):
""" request docstring """
# self.log ('request %s %s' % (method, path))
if headers == None:
headers = {}
if not allow_cache:
headers['Pragma'] = 'no-cache'
headers['cache-control'] = 'no-cache'
try:
if method.lower () != 'purge':
if path.startswith ('/'):
path = path[1:]
if self.host_header: # use proxy
headers[ 'host' ] = self.host_header
fullpath = 'http://%s%s%s' % (self.host_header,
self.top_path, path)
else: # no proxy
fullpath = self.top_path + path
else:
fullpath = path
self.connection.request (method, fullpath, body, headers)
if body_hook:
body_hook ()
# signal.signal (signal.SIGALRM, alarm_handler)
# try:
# signal.alarm (120)
# signal.alarm (0)
# except Timeout, e:
# if recurse < 6:
# return self.retry_request (method, path, body, headers,
# read_all, body_hook, recurse)
# else:
# raise DAVError (0, 'timeout', self.host,
# (method, path, body, headers, recurse))
response = self.connection.getresponse ()
if read_all:
while len (response.read (1024)) > 0:
pass
if (response.status == 500 or \
response.status == 503 or \
response.status == 403) and \
recurse < self.retries_before_fail:
return self.retry_request (method, path, body, headers,
read_all, body_hook, recurse)
return response
except (httplib.ResponseNotReady,
httplib.BadStatusLine,
socket.error):
# if the server hangs up on us (keepalive off, broken pipe),
# we need to reconnect and try again.
if recurse < self.retries_before_fail:
return self.retry_request (method, path, body, headers,
read_all, body_hook, recurse)
raise DAVError (0, 'reconnect failed', self.host,
(method, path, body, headers, recurse))
def retry_request (self, method, path, body, headers,
read_all, body_hook, recurse):
""" retry_request docstring """
time.sleep (10.0 * recurse)
self.connect ()
return self.request (method, path, body, headers,
read_all, body_hook, recurse+1)
def propfind (self, path, body=None, depth=1):
""" propfind docstring """
# self.log ('propfind %s' % path)
headers = {'Content-Type':'text/xml; charset="utf-8"',
'Depth':str(depth)}
response = self.request ('PROPFIND', path, body, headers, False)
if response.status == 207:
return response # Multi-Status
self.__err (response, ('PROPFIND', path, body, headers, 0))
def purge (self, path):
""" issue a squid purge command """
headers = {'Accept':'*/*'}
response = self.request ('PURGE', path, None, headers)
if response.status == 200 or response.status == 404:
# 200 if it was purge, 404 if it wasn't there.
return response
self.__err (response, ('PURGE', path, None, headers))
def get_file_size (self, path):
"""
Use propfind to ask a webdav server what the size of
a file is. If used on a directory (collection) return 0
"""
self.log ('get_file_size %s' % path)
# "getcontentlength" property
# 8.1.1 Example - Retrieving Named Properties
# http://docs.python.org/lib/module-xml.dom.html
nsurl = 'http://apache.org/dav/props/'
doc = xml.dom.minidom.Document ()
propfind_element = doc.createElementNS (nsurl, "D:propfind")
propfind_element.setAttributeNS (nsurl, 'xmlns:D', 'DAV:')
doc.appendChild (propfind_element)
prop_element = doc.createElementNS (nsurl, "D:prop")
propfind_element.appendChild (prop_element)
con_len_element = doc.createElementNS (nsurl, "D:getcontentlength")
prop_element.appendChild (con_len_element)
response = self.propfind (path, doc.toxml ())
doc.unlink ()
resp_doc = xml.dom.minidom.parseString (response.read ())
cln = resp_doc.getElementsByTagNameNS ('DAV:','getcontentlength')[ 0 ]
try:
content_length = int (cln.childNodes[ 0 ].nodeValue)
except IndexError:
return 0
resp_doc.unlink ()
return content_length
def file_exists (self, path):
"""
do an http head on the given file. return True if it succeeds
"""
self.log ('file_exists %s' % path)
expect_gzip = path.endswith ('.gz')
response = self.request ('HEAD', path)
got_gzip = response.getheader ('Content-Encoding', '').strip ()
if got_gzip.lower () == 'x-gzip' and expect_gzip == False:
# the asset server fakes us out if we ask for the non-gzipped
# version of an asset, but the server has the gzipped version.
return False
return response.status == 200
def mkdir (self, path):
""" mkdir docstring """
self.log ('mkdir %s' % path)
headers = {}
response = self.request ('MKCOL', path, None, headers)
if response.status == 201:
return # success
if response.status == 405:
return # directory already existed?
self.__err (response, ('MKCOL', path, None, headers, 0))
def delete (self, path):
""" delete docstring """
self.log ('delete %s' % path)
headers = {'Depth':'infinity'} # collections require infinity
response = self.request ('DELETE', path, None, headers)
if response.status == 204:
return # no content
if response.status == 404:
return # hmm
self.__err (response, ('DELETE', path, None, headers, 0))
def list_directory (self, path, dir_filter=None, allow_cache=True,
minimum_cache_time=False):
"""
Request an http directory listing and parse the filenames out of lines
like: '<LI><A HREF="X"> X</A>'. If a filter function is provided,
only return filenames that the filter returns True for.
This is sort of grody, but it seems faster than other ways of getting
this information from an isilon.
"""
self.log ('list_directory %s' % path)
def try_match (lline, before, after):
""" try_match docstring """
try:
blen = len (before)
asset_start_index = lline.index (before)
asset_end_index = lline.index (after, asset_start_index + blen)
asset = line[ asset_start_index + blen : asset_end_index ]
if not dir_filter or dir_filter (asset):
return [ asset ]
return []
except ValueError:
return []
if len (path) > 0 and path[-1:] != '/':
path += '/'
response = self.request ('GET', path, None, {}, False,
allow_cache=allow_cache)
if allow_cache and minimum_cache_time: # XXX
print response.getheader ('Date')
# s = "2005-12-06T12:13:14"
# from datetime import datetime
# from time import strptime
# datetime(*strptime(s, "%Y-%m-%dT%H:%M:%S")[0:6])
# datetime.datetime(2005, 12, 6, 12, 13, 14)
if response.status != 200:
self.__err (response, ('GET', path, None, {}, 0))
assets = []
for line in response.read ().split ('\n'):
lline = line.lower ()
if lline.find ("parent directory") == -1:
# isilon file
assets += try_match (lline, '<li><a href="', '"> ')
# apache dir
assets += try_match (lline, 'alt="[dir]"> <a href="', '/">')
# apache file
assets += try_match (lline, 'alt="[ ]"> <a href="', '">')
return assets
def __tmp_filename (self, path_and_file):
""" __tmp_filename docstring """
head, tail = os.path.split (path_and_file)
if head != '':
return head + '/.' + tail + '.' + str (os.getpid ())
else:
return head + '.' + tail + '.' + str (os.getpid ())
def __put__ (self, filesize, body_hook, remotefile):
""" __put__ docstring """
headers = {'Content-Length' : str (filesize)}
remotefile_tmp = self.__tmp_filename (remotefile)
response = self.request ('PUT', remotefile_tmp, None,
headers, True, body_hook)
if not response.status in (201, 204): # created, no content
self.__err (response, ('PUT', remotefile, None, headers, 0))
if filesize != self.get_file_size (remotefile_tmp):
try:
self.delete (remotefile_tmp)
except:
pass
raise DAVError (0, 'tmp upload error', remotefile_tmp)
# move the file to its final location
try:
self.rename (remotefile_tmp, remotefile)
except DAVError, exc:
if exc.status == 403: # try to clean up the tmp file
try:
self.delete (remotefile_tmp)
except:
pass
raise
if filesize != self.get_file_size (remotefile):
raise DAVError (0, 'file upload error', str (remotefile_tmp))
def put_string (self, strng, remotefile):
""" put_string docstring """
self.log ('put_string %d -> %s' % (len (strng), remotefile))
filesize = len (strng)
def body_hook ():
""" body_hook docstring """
self.connection.send (strng)
self.__put__ (filesize, body_hook, remotefile)
def put_file (self, localfile, remotefile):
"""
Send a local file to a remote webdav store. First, upload to
a temporary filename. Next make sure the file is the size we
expected. Next, move the file to its final location. Next,
check the file size at the final location.
"""
self.log ('put_file %s -> %s' % (localfile, remotefile))
filesize = os.path.getsize (localfile)
def body_hook ():
""" body_hook docstring """
handle = open (localfile)
while True:
data = handle.read (1300)
if len (data) == 0:
break
self.connection.send (data)
handle.close ()
self.__put__ (filesize, body_hook, remotefile)
def create_empty_file (self, remotefile):
""" create an empty file """
self.log ('touch_file %s' % (remotefile))
headers = {'Content-Length' : '0'}
response = self.request ('PUT', remotefile, None, headers)
if not response.status in (201, 204): # created, no content
self.__err (response, ('PUT', remotefile, None, headers, 0))
if self.get_file_size (remotefile) != 0:
raise DAVError (0, 'file upload error', str (remotefile))
def __get_file_setup (self, remotefile, check_size=True):
""" __get_file_setup docstring """
if check_size:
remotesize = self.get_file_size (remotefile)
response = self.request ('GET', remotefile, None, {}, False)
if response.status != 200:
self.__err (response, ('GET', remotefile, None, {}, 0))
try:
content_length = int (response.getheader ("Content-Length"))
except TypeError:
content_length = None
if check_size:
if content_length != remotesize:
raise DAVError (0, 'file DL size error', remotefile)
return (response, content_length)
def __get_file_read (self, writehandle, response, content_length):
""" __get_file_read docstring """
if content_length != None:
so_far_length = 0
while so_far_length < content_length:
data = response.read (content_length - so_far_length)
if len (data) == 0:
raise DAVError (0, 'short file download')
so_far_length += len (data)
writehandle.write (data)
while len (response.read ()) > 0:
pass
else:
while True:
data = response.read ()
if (len (data) < 1):
break
writehandle.write (data)
def get_file (self, remotefile, localfile, check_size=True):
"""
Get a remote file from a webdav server. Download to a local
tmp file, then move into place. Sanity check file sizes as
we go.
"""
self.log ('get_file %s -> %s' % (remotefile, localfile))
(response, content_length) = \
self.__get_file_setup (remotefile, check_size)
localfile_tmp = self.__tmp_filename (localfile)
handle = open (localfile_tmp, 'w')
self.__get_file_read (handle, response, content_length)
handle.close ()
if check_size:
if content_length != os.path.getsize (localfile_tmp):
raise DAVError (0, 'file DL size error',
remotefile+','+localfile)
os.rename (localfile_tmp, localfile)
def get_file_as_string (self, remotefile, check_size=True):
"""
download a file from a webdav server and return it as a string.
"""
self.log ('get_file_as_string %s' % remotefile)
(response, content_length) = \
self.__get_file_setup (remotefile, check_size)
# (tmp_handle, tmp_filename) = tempfile.mkstemp ()
tmp_handle = os.tmpfile ()
self.__get_file_read (tmp_handle, response, content_length)
tmp_handle.seek (0)
ret = tmp_handle.read ()
tmp_handle.close ()
# os.unlink (tmp_filename)
return ret
def get_post_as_string (self, remotefile, body):
"""
Do an http POST, send body, get response and return it.
"""
self.log ('get_post_as_string %s' % remotefile)
# headers = {'Content-Type':'application/x-www-form-urlencoded'}
headers = {'Content-Type':'text/xml; charset="utf-8"'}
# b64body = urlsafe_b64encode (asset_url)
response = self.request ('POST', remotefile, body, headers, False)
if response.status != 200:
self.__err (response, ('POST', remotefile, body, headers, 0))
try:
content_length = int (response.getheader ('Content-Length'))
except TypeError:
content_length = None
tmp_handle = os.tmpfile ()
self.__get_file_read (tmp_handle, response, content_length)
tmp_handle.seek (0)
ret = tmp_handle.read ()
tmp_handle.close ()
return ret
def __destination_command (self, verb, remotesrc, dstdav, remotedst):
"""
self and dstdav should point to the same http server.
"""
if len (remotedst) > 0 and remotedst[ 0 ] == '/':
remotedst = remotedst[1:]
headers = {'Destination': 'http://%s:%d%s%s' % (dstdav.host,
dstdav.port,
dstdav.top_path,
remotedst)}
response = self.request (verb, remotesrc, None, headers)
if response.status == 201:
return # created
if response.status == 204:
return # no content
self.__err (response, (verb, remotesrc, None, headers, 0))
def rename (self, remotesrc, remotedst):
""" rename a file on a webdav server """
self.log ('rename %s -> %s' % (remotesrc, remotedst))
self.__destination_command ('MOVE', remotesrc, self, remotedst)
def xrename (self, remotesrc, dstdav, remotedst):
""" rename a file on a webdav server """
self.log ('xrename %s -> %s' % (remotesrc, remotedst))
self.__destination_command ('MOVE', remotesrc, dstdav, remotedst)
def copy (self, remotesrc, remotedst):
""" copy a file on a webdav server """
self.log ('copy %s -> %s' % (remotesrc, remotedst))
self.__destination_command ('COPY', remotesrc, self, remotedst)
def xcopy (self, remotesrc, dstdav, remotedst):
""" copy a file on a webdav server """
self.log ('xcopy %s -> %s' % (remotesrc, remotedst))
self.__destination_command ('COPY', remotesrc, dstdav, remotedst)
def put_string (data, url):
"""
upload string s to a url
"""
url_parsed = urlparse.urlsplit (url)
dav = WebDAV ('%s://%s/' % (url_parsed[ 0 ], url_parsed[ 1 ]))
dav.put_string (data, url_parsed[ 2 ])
def get_string (url, check_size=True):
"""
return the contents of a url as a string
"""
url_parsed = urlparse.urlsplit (url)
dav = WebDAV ('%s://%s/' % (url_parsed[ 0 ], url_parsed[ 1 ]))
return dav.get_file_as_string (url_parsed[ 2 ], check_size)

View File

@@ -1,273 +0,0 @@
"""\
@file xml_rpc.py
@brief An implementation of a parser/generator for the XML-RPC xml format.
$LicenseInfo:firstyear=2006&license=mit$
Copyright (c) 2006-2009, Linden Research, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
$/LicenseInfo$
"""
from greenlet import greenlet
from mulib import mu
from xml.sax import handler
from xml.sax import parseString
# States
class Expected(object):
def __init__(self, tag):
self.tag = tag
def __getattr__(self, name):
return type(self)(name)
def __repr__(self):
return '%s(%r)' % (
type(self).__name__, self.tag)
class START(Expected):
pass
class END(Expected):
pass
class STR(object):
tag = ''
START = START('')
END = END('')
class Malformed(Exception):
pass
class XMLParser(handler.ContentHandler):
def __init__(self, state_machine, next_states):
handler.ContentHandler.__init__(self)
self.state_machine = state_machine
if not isinstance(next_states, tuple):
next_states = (next_states, )
self.next_states = next_states
self._character_buffer = ''
def assertState(self, state, name, *rest):
if not isinstance(self.next_states, tuple):
self.next_states = (self.next_states, )
for next in self.next_states:
if type(state) == type(next):
if next.tag and next.tag != name:
raise Malformed(
"Expected %s, got %s %s %s" % (
next, state, name, rest))
break
else:
raise Malformed(
"Expected %s, got %s %s %s" % (
self.next_states, state, name, rest))
def startElement(self, name, attrs):
self.assertState(START, name.lower(), attrs)
self.next_states = self.state_machine.switch(START, (name.lower(), dict(attrs)))
def endElement(self, name):
if self._character_buffer.strip():
characters = self._character_buffer.strip()
self._character_buffer = ''
self.assertState(STR, characters)
self.next_states = self.state_machine.switch(characters)
self.assertState(END, name.lower())
self.next_states = self.state_machine.switch(END, name.lower())
def error(self, exc):
self.bozo = 1
self.exc = exc
def fatalError(self, exc):
self.error(exc)
raise exc
def characters(self, characters):
self._character_buffer += characters
def parse(what):
child = greenlet(xml_rpc)
me = greenlet.getcurrent()
startup_states = child.switch(me)
parser = XMLParser(child, startup_states)
try:
parseString(what, parser)
except Malformed:
print what
raise
return child.switch()
def xml_rpc(yielder):
yielder.switch(START.methodcall)
yielder.switch(START.methodname)
methodName = yielder.switch(STR)
yielder.switch(END.methodname)
yielder.switch(START.params)
root = None
params = []
while True:
state, _ = yielder.switch(START.param, END.params)
if state == END:
break
yielder.switch(START.value)
params.append(
handle(yielder))
yielder.switch(END.value)
yielder.switch(END.param)
yielder.switch(END.methodcall)
## Resume parse
yielder.switch()
## Return result to parse
return methodName.strip(), params
def handle(yielder):
_, (tag, attrs) = yielder.switch(START)
if tag in ['int', 'i4']:
result = int(yielder.switch(STR))
elif tag == 'boolean':
result = bool(int(yielder.switch(STR)))
elif tag == 'string':
result = yielder.switch(STR)
elif tag == 'double':
result = float(yielder.switch(STR))
elif tag == 'datetime.iso8601':
result = yielder.switch(STR)
elif tag == 'base64':
result = base64.b64decode(yielder.switch(STR))
elif tag == 'struct':
result = {}
while True:
state, _ = yielder.switch(START.member, END.struct)
if state == END:
break
yielder.switch(START.name)
key = yielder.switch(STR)
yielder.switch(END.name)
yielder.switch(START.value)
result[key] = handle(yielder)
yielder.switch(END.value)
yielder.switch(END.member)
## We already handled </struct> above, don't want to handle it below
return result
elif tag == 'array':
result = []
yielder.switch(START.data)
while True:
state, _ = yielder.switch(START.value, END.data)
if state == END:
break
result.append(handle(yielder))
yielder.switch(END.value)
yielder.switch(getattr(END, tag))
return result
VALUE = mu.tag_factory('value')
BOOLEAN = mu.tag_factory('boolean')
INT = mu.tag_factory('int')
STRUCT = mu.tag_factory('struct')
MEMBER = mu.tag_factory('member')
NAME = mu.tag_factory('name')
ARRAY = mu.tag_factory('array')
DATA = mu.tag_factory('data')
STRING = mu.tag_factory('string')
DOUBLE = mu.tag_factory('double')
METHODRESPONSE = mu.tag_factory('methodResponse')
PARAMS = mu.tag_factory('params')
PARAM = mu.tag_factory('param')
mu.inline_elements['string'] = True
mu.inline_elements['boolean'] = True
mu.inline_elements['name'] = True
def _generate(something):
if isinstance(something, dict):
result = STRUCT()
for key, value in something.items():
result[
MEMBER[
NAME[key], _generate(value)]]
return VALUE[result]
elif isinstance(something, list):
result = DATA()
for item in something:
result[_generate(item)]
return VALUE[ARRAY[[result]]]
elif isinstance(something, basestring):
return VALUE[STRING[something]]
elif isinstance(something, bool):
if something:
return VALUE[BOOLEAN['1']]
return VALUE[BOOLEAN['0']]
elif isinstance(something, int):
return VALUE[INT[something]]
elif isinstance(something, float):
return VALUE[DOUBLE[something]]
def generate(*args):
params = PARAMS()
for arg in args:
params[PARAM[_generate(arg)]]
return METHODRESPONSE[params]
if __name__ == '__main__':
print parse("""<?xml version="1.0"?> <methodCall> <methodName>examples.getStateName</methodName> <params> <param> <value><i4>41</i4></value> </param> </params> </methodCall>
""")

View File

@@ -1,64 +0,0 @@
"""\
@file fastest_elementtree.py
@brief Concealing some gnarly import logic in here. This should export the interface of elementtree.
$LicenseInfo:firstyear=2008&license=mit$
Copyright (c) 2008-2009, Linden Research, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
$/LicenseInfo$
"""
# The parsing exception raised by the underlying library depends
# on the ElementTree implementation we're using, so we provide an
# alias here.
#
# Use ElementTreeError as the exception type for catching parsing
# errors.
# Using cElementTree might cause some unforeseen problems, so here's a
# convenient off switch.
use_celementree = True
try:
if not use_celementree:
raise ImportError()
# Python 2.3 and 2.4.
from cElementTree import *
ElementTreeError = SyntaxError
except ImportError:
try:
if not use_celementree:
raise ImportError()
# Python 2.5 and above.
from xml.etree.cElementTree import *
ElementTreeError = SyntaxError
except ImportError:
# Pure Python code.
try:
# Python 2.3 and 2.4.
from elementtree.ElementTree import *
except ImportError:
# Python 2.5 and above.
from xml.etree.ElementTree import *
# The pure Python ElementTree module uses Expat for parsing.
from xml.parsers.expat import ExpatError as ElementTreeError

View File

@@ -1,52 +0,0 @@
"""\
@file helpformatter.py
@author Phoenix
@brief Class for formatting optparse descriptions.
$LicenseInfo:firstyear=2007&license=mit$
Copyright (c) 2007-2009, Linden Research, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
$/LicenseInfo$
"""
import optparse
import textwrap
class Formatter(optparse.IndentedHelpFormatter):
def __init__(
self,
p_indentIncrement = 2,
p_maxHelpPosition = 24,
p_width = 79,
p_shortFirst = 1) :
optparse.HelpFormatter.__init__(
self,
p_indentIncrement,
p_maxHelpPosition,
p_width,
p_shortFirst)
def format_description(self, p_description):
t_descWidth = self.width - self.current_indent
t_indent = " " * (self.current_indent + 2)
return "\n".join(
[textwrap.fill(descr, t_descWidth, initial_indent = t_indent,
subsequent_indent = t_indent)
for descr in p_description.split("\n")] )

View File

@@ -1,63 +0,0 @@
"""\
@file iterators.py
@brief Useful general-purpose iterators.
$LicenseInfo:firstyear=2008&license=mit$
Copyright (c) 2008-2009, Linden Research, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
$/LicenseInfo$
"""
from __future__ import nested_scopes
def iter_chunks(rows, aggregate_size=100):
"""
Given an iterable set of items (@p rows), produces lists of up to @p
aggregate_size items at a time, for example:
iter_chunks([1,2,3,4,5,6,7,8,9,10], 3)
Values for @p aggregate_size < 1 will raise ValueError.
Will return a generator that produces, in the following order:
- [1, 2, 3]
- [4, 5, 6]
- [7, 8, 9]
- [10]
"""
if aggregate_size < 1:
raise ValueError()
def iter_chunks_inner():
row_iter = iter(rows)
done = False
agg = []
while not done:
try:
row = row_iter.next()
agg.append(row)
except StopIteration:
done = True
if agg and (len(agg) >= aggregate_size or done):
yield agg
agg = []
return iter_chunks_inner()

View File

@@ -1,72 +0,0 @@
"""\
@file iterators_test.py
@brief Test cases for iterators module.
$LicenseInfo:firstyear=2008&license=mit$
Copyright (c) 2008-2009, Linden Research, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
$/LicenseInfo$
"""
import unittest
from indra.util.iterators import iter_chunks
class TestIterChunks(unittest.TestCase):
"""Unittests for iter_chunks"""
def test_bad_agg_size(self):
rows = [1,2,3,4]
self.assertRaises(ValueError, iter_chunks, rows, 0)
self.assertRaises(ValueError, iter_chunks, rows, -1)
try:
for i in iter_chunks(rows, 0):
pass
except ValueError:
pass
else:
self.fail()
try:
result = list(iter_chunks(rows, 0))
except ValueError:
pass
else:
self.fail()
def test_empty(self):
rows = []
result = list(iter_chunks(rows))
self.assertEqual(result, [])
def test_small(self):
rows = [[1]]
result = list(iter_chunks(rows, 2))
self.assertEqual(result, [[[1]]])
def test_size(self):
rows = [[1],[2]]
result = list(iter_chunks(rows, 2))
self.assertEqual(result, [[[1],[2]]])
def test_multi_agg(self):
rows = [[1],[2],[3],[4],[5]]
result = list(iter_chunks(rows, 2))
self.assertEqual(result, [[[1],[2]],[[3],[4]],[[5]]])
if __name__ == "__main__":
unittest.main()

View File

@@ -33,21 +33,26 @@ import filecmp
import fnmatch import fnmatch
import getopt import getopt
import glob import glob
import itertools
import operator
import os import os
import re import re
import shutil import shutil
import subprocess
import sys import sys
import tarfile import tarfile
import errno
import subprocess
class ManifestError(RuntimeError): class ManifestError(RuntimeError):
"""Use an exception more specific than generic Python RuntimeError""" """Use an exception more specific than generic Python RuntimeError"""
pass def __init__(self, msg):
self.msg = msg
super(ManifestError, self).__init__(self.msg)
class MissingError(ManifestError): class MissingError(ManifestError):
"""You specified a file that doesn't exist""" """You specified a file that doesn't exist"""
pass def __init__(self, msg):
self.msg = msg
super(MissingError, self).__init__(self.msg)
def path_ancestors(path): def path_ancestors(path):
drive, path = os.path.splitdrive(os.path.normpath(path)) drive, path = os.path.splitdrive(os.path.normpath(path))
@@ -88,7 +93,7 @@ DEFAULT_SRCTREE = os.path.dirname(sys.argv[0])
CHANNEL_VENDOR_BASE = 'Singularity' CHANNEL_VENDOR_BASE = 'Singularity'
RELEASE_CHANNEL = CHANNEL_VENDOR_BASE + ' Release' RELEASE_CHANNEL = CHANNEL_VENDOR_BASE + ' Release'
ARGUMENTS=[ BASE_ARGUMENTS=[
dict(name='actions', dict(name='actions',
description="""This argument specifies the actions that are to be taken when the description="""This argument specifies the actions that are to be taken when the
script is run. The meaningful actions are currently: script is run. The meaningful actions are currently:
@@ -106,9 +111,17 @@ ARGUMENTS=[
Example use: %(name)s --arch=i686 Example use: %(name)s --arch=i686
On Linux this would try to use Linux_i686Manifest.""", On Linux this would try to use Linux_i686Manifest.""",
default=""), default=""),
dict(name='artwork', description='Artwork directory.', default=DEFAULT_SRCTREE),
dict(name='branding_id', description="Identifier for the branding set to use.", default='singularity'), dict(name='branding_id', description="Identifier for the branding set to use.", default='singularity'),
dict(name='build', description='Build directory.', default=DEFAULT_SRCTREE), dict(name='build', description='Build directory.', default=DEFAULT_SRCTREE),
dict(name='buildtype', description='Build type (i.e. Debug, Release, RelWithDebInfo).', default=None), dict(name='buildtype', description='Build type (i.e. Debug, Release, RelWithDebInfo).', default=None),
dict(name='channel',
description="""The channel to use for updates, packaging, settings name, etc.""",
default='CHANNEL UNSET'),
dict(name='channel_suffix',
description="""Addition to the channel for packaging and channel value,
but not application name (used internally)""",
default=None),
dict(name='configuration', dict(name='configuration',
description="""The build configuration used.""", description="""The build configuration used.""",
default="Release"), default="Release"),
@@ -116,12 +129,6 @@ ARGUMENTS=[
dict(name='grid', dict(name='grid',
description="""Which grid the client will try to connect to.""", description="""Which grid the client will try to connect to.""",
default=None), default=None),
dict(name='channel',
description="""The channel to use for updates, packaging, settings name, etc.""",
default='CHANNEL UNSET'),
dict(name='channel_suffix',
description="""Addition to the channel for packaging and channel value, but not application name (used internally)""",
default=None),
dict(name='installer_name', dict(name='installer_name',
description=""" The name of the file that the installer should be description=""" The name of the file that the installer should be
packaged up into. Only used on Linux at the moment.""", packaged up into. Only used on Linux at the moment.""",
@@ -133,13 +140,17 @@ ARGUMENTS=[
description="""The current platform, to be used for looking up which description="""The current platform, to be used for looking up which
manifest class to run.""", manifest class to run.""",
default=get_default_platform), default=get_default_platform),
dict(name='signature',
description="""This specifies an identity to sign the viewer with, if any.
If no value is supplied, the default signature will be used, if any. Currently
only used on Mac OS X.""",
default=None),
dict(name='source', dict(name='source',
description='Source directory.', description='Source directory.',
default=DEFAULT_SRCTREE), default=DEFAULT_SRCTREE),
dict(name='standalone', dict(name='standalone',
description='Set to ON if this is a standalone build.', description='Set to ON if this is a standalone build.',
default="OFF"), default="OFF"),
dict(name='artwork', description='Artwork directory.', default=DEFAULT_SRCTREE),
dict(name='touch', dict(name='touch',
description="""File to touch when action is finished. Touch file will description="""File to touch when action is finished. Touch file will
contain the name of the final package in a form suitable contain the name of the final package in a form suitable
@@ -147,20 +158,15 @@ ARGUMENTS=[
default=None), default=None),
dict(name='versionfile', dict(name='versionfile',
description="""The name of a file containing the full version number."""), description="""The name of a file containing the full version number."""),
dict(name='signature',
description="""This specifies an identity to sign the viewer with, if any.
If no value is supplied, the default signature will be used, if any. Currently
only used on Mac OS X.""",
default=None)
] ]
def usage(srctree=""): def usage(arguments, srctree=""):
nd = {'name':sys.argv[0]} nd = {'name':sys.argv[0]}
print """Usage: print """Usage:
%(name)s [options] [destdir] %(name)s [options] [destdir]
Options: Options:
""" % nd """ % nd
for arg in ARGUMENTS: for arg in arguments:
default = arg['default'] default = arg['default']
if hasattr(default, '__call__'): if hasattr(default, '__call__'):
default = "(computed value) \"" + str(default(srctree)) + '"' default = "(computed value) \"" + str(default(srctree)) + '"'
@@ -171,11 +177,15 @@ def usage(srctree=""):
default, default,
arg['description'] % nd) arg['description'] % nd)
def main(): def main(extra=[]):
## import itertools
## print ' '.join((("'%s'" % item) if ' ' in item else item) ## print ' '.join((("'%s'" % item) if ' ' in item else item)
## for item in itertools.chain([sys.executable], sys.argv)) ## for item in itertools.chain([sys.executable], sys.argv))
option_names = [arg['name'] + '=' for arg in ARGUMENTS] # Supplement our default command-line switches with any desired by
# application-specific caller.
arguments = list(itertools.chain(BASE_ARGUMENTS, extra))
# Alphabetize them by option name in case we display usage.
arguments.sort(key=operator.itemgetter('name'))
option_names = [arg['name'] + '=' for arg in arguments]
option_names.append('help') option_names.append('help')
options, remainder = getopt.getopt(sys.argv[1:], "", option_names) options, remainder = getopt.getopt(sys.argv[1:], "", option_names)
@@ -198,11 +208,11 @@ def main():
# early out for help # early out for help
if 'help' in args: if 'help' in args:
# *TODO: it is a huge hack to pass around the srctree like this # *TODO: it is a huge hack to pass around the srctree like this
usage(args['source']) usage(arguments, srctree=args['source'])
return return
# defaults # defaults
for arg in ARGUMENTS: for arg in arguments:
if arg['name'] not in args: if arg['name'] not in args:
default = arg['default'] default = arg['default']
if hasattr(default, '__call__'): if hasattr(default, '__call__'):
@@ -231,101 +241,68 @@ def main():
print "Option:", opt, "=", args[opt] print "Option:", opt, "=", args[opt]
# pass in sourceid as an argument now instead of an environment variable # pass in sourceid as an argument now instead of an environment variable
try: args['sourceid'] = os.environ.get("sourceid", "")
args['sourceid'] = os.environ["sourceid"]
except KeyError:
args['sourceid'] = ""
# Build base package. # Build base package.
touch = args.get('touch') touch = args.get('touch')
if touch: if touch:
print 'Creating base package' print '================ Creating base package'
args['package_id'] = "" # base package has no package ID else:
print '================ Starting base copy'
wm = LLManifest.for_platform(args['platform'], args.get('arch'))(args) wm = LLManifest.for_platform(args['platform'], args.get('arch'))(args)
wm.do(*args['actions']) wm.do(*args['actions'])
# Store package file for later if making touched file. # Store package file for later if making touched file.
base_package_file = "" base_package_file = ""
if touch: if touch:
print 'Created base package ', wm.package_file print '================ Created base package ', wm.package_file
base_package_file = "" + wm.package_file base_package_file = "" + wm.package_file
else:
print '================ Finished base copy'
# handle multiple packages if set # handle multiple packages if set
try: # ''.split() produces empty list
additional_packages = os.environ["additional_packages"] additional_packages = os.environ.get("additional_packages", "").split()
except KeyError:
additional_packages = ""
if additional_packages: if additional_packages:
# Determine destination prefix / suffix for additional packages. # Determine destination prefix / suffix for additional packages.
base_dest_postfix = args['dest'] base_dest_parts = list(os.path.split(args['dest']))
base_dest_prefix = "" base_dest_parts.insert(-1, "{}")
base_dest_parts = args['dest'].split(os.sep) base_dest_template = os.path.join(*base_dest_parts)
if len(base_dest_parts) > 1:
base_dest_postfix = base_dest_parts[len(base_dest_parts) - 1]
base_dest_prefix = base_dest_parts[0]
i = 1
while i < len(base_dest_parts) - 1:
base_dest_prefix = base_dest_prefix + os.sep + base_dest_parts[i]
i = i + 1
# Determine touched prefix / suffix for additional packages. # Determine touched prefix / suffix for additional packages.
base_touch_postfix = ""
base_touch_prefix = ""
if touch: if touch:
base_touch_postfix = touch base_touch_parts = list(os.path.split(touch))
base_touch_parts = touch.split('/') # Because of the special insert() logic below, we don't just want
# [dirpath, basename]; we want [dirpath, directory, basename].
# Further split the dirpath and replace it in the list.
base_touch_parts[0:1] = os.path.split(base_touch_parts[0])
if "arwin" in args['platform']: if "arwin" in args['platform']:
if len(base_touch_parts) > 1: base_touch_parts.insert(-1, "{}")
base_touch_postfix = base_touch_parts[len(base_touch_parts) - 1]
base_touch_prefix = base_touch_parts[0]
i = 1
while i < len(base_touch_parts) - 1:
base_touch_prefix = base_touch_prefix + '/' + base_touch_parts[i]
i = i + 1
else: else:
if len(base_touch_parts) > 2: base_touch_parts.insert(-2, "{}")
base_touch_postfix = base_touch_parts[len(base_touch_parts) - 2] + '/' + base_touch_parts[len(base_touch_parts) - 1] base_touch_template = os.path.join(*base_touch_parts)
base_touch_prefix = base_touch_parts[0] for package_id in additional_packages:
i = 1 args['channel_suffix'] = os.environ.get(package_id + "_viewer_channel_suffix")
while i < len(base_touch_parts) - 2: args['sourceid'] = os.environ.get(package_id + "_sourceid")
base_touch_prefix = base_touch_prefix + '/' + base_touch_parts[i] args['dest'] = base_dest_template.format(package_id)
i = i + 1 if touch:
# Store base channel name. print '================ Creating additional package for "', package_id, '" in ', args['dest']
base_channel_name = args['channel'] else:
# Build each additional package. print '================ Starting additional copy for "', package_id, '" in ', args['dest']
package_id_list = additional_packages.split(" ")
args['channel'] = base_channel_name
for package_id in package_id_list:
try: try:
if package_id + "_viewer_channel_suffix" in os.environ: wm = LLManifest.for_platform(args['platform'], args.get('arch'))(args)
args['channel_suffix'] = os.environ[package_id + "_viewer_channel_suffix"] wm.do(*args['actions'])
else: except Exception as err:
args['channel_suffix'] = None sys.exit(str(err))
if package_id + "_sourceid" in os.environ:
args['sourceid'] = os.environ[package_id + "_sourceid"]
else:
args['sourceid'] = None
args['dest'] = base_dest_prefix + os.sep + package_id + os.sep + base_dest_postfix
except KeyError:
sys.stderr.write("Failed to create package for package_id: %s" % package_id)
sys.stderr.flush()
continue
if touch: if touch:
print 'Creating additional package for "', package_id, '" in ', args['dest'] print '================ Created additional package ', wm.package_file, ' for ', package_id
wm = LLManifest.for_platform(args['platform'], args.get('arch'))(args) with open(base_touch_template.format(package_id), 'w') as fp:
wm.do(*args['actions']) fp.write('set package_file=%s\n' % wm.package_file)
if touch: else:
print 'Created additional package ', wm.package_file, ' for ', package_id print '================ Finished additional copy "', package_id, '" in ', args['dest']
faketouch = base_touch_prefix + '/' + package_id + '/' + base_touch_postfix
fp = open(faketouch, 'w')
fp.write('set package_file=%s\n' % wm.package_file)
fp.close()
# Write out the package file in this format, so that it can easily be called # Write out the package file in this format, so that it can easily be called
# and used in a .bat file - yeah, it sucks, but this is the simplest... # and used in a .bat file - yeah, it sucks, but this is the simplest...
touch = args.get('touch')
if touch: if touch:
fp = open(touch, 'w') with open(touch, 'w') as fp:
fp.write('set package_file=%s\n' % base_package_file) fp.write('set package_file=%s\n' % base_package_file)
fp.close()
print 'touched', touch print 'touched', touch
return 0 return 0
@@ -371,22 +348,113 @@ class LLManifest(object):
in the file list by path().""" in the file list by path()."""
self.excludes.append(glob) self.excludes.append(glob)
def prefix(self, src='', build=None, dst=None): def prefix(self, src='', build='', dst='', src_dst=None):
""" Pushes a prefix onto the stack. Until end_prefix is """
called, all relevant method calls (esp. to path()) will prefix Usage:
paths with the entire prefix stack. Source and destination
prefixes can be different, though if only one is provided they with self.prefix(...args as described...):
are both equal. To specify a no-op, use an empty string, not self.path(...)
None."""
if dst is None: For the duration of the 'with' block, pushes a prefix onto the stack.
dst = src Within that block, all relevant method calls (esp. to path()) will
if build is None: prefix paths with the entire prefix stack. Source and destination
build = src prefixes are independent; if omitted (or passed as the empty string),
the prefix has no effect. Thus:
with self.prefix(src='foo'):
# no effect on dst
with self.prefix(dst='bar'):
# no effect on src
If you want to set both at once, use src_dst:
with self.prefix(src_dst='subdir'):
# same as self.prefix(src='subdir', dst='subdir')
# Passing src_dst makes any src or dst argument in the same
# parameter list irrelevant.
Also supports the older (pre-Python-2.5) syntax:
if self.prefix(...args as described...):
self.path(...)
self.end_prefix(...)
Before the arrival of the 'with' statement, one was required to code
self.prefix() and self.end_prefix() in matching pairs to push and to
pop the prefix stacks, respectively. The older prefix() method
returned True specifically so that the caller could indent the
relevant block of code with 'if', just for aesthetic purposes.
"""
if src_dst is not None:
src = src_dst
dst = src_dst
self.src_prefix.append(src) self.src_prefix.append(src)
self.artwork_prefix.append(src) self.artwork_prefix.append(src)
self.build_prefix.append(build) self.build_prefix.append(build)
self.dst_prefix.append(dst) self.dst_prefix.append(dst)
return True # so that you can wrap it in an if to get indentation
## self.display_stacks()
# The above code is unchanged from the original implementation. What's
# new is the return value. We're going to return an instance of
# PrefixManager that binds this LLManifest instance and Does The Right
# Thing on exit.
return self.PrefixManager(self)
def display_stacks(self):
width = 1 + max(len(stack) for stack in self.PrefixManager.stacks)
for stack in self.PrefixManager.stacks:
print "{} {}".format((stack + ':').ljust(width),
os.path.join(*getattr(self, stack)))
class PrefixManager(object):
# stack attributes we manage in this LLManifest (sub)class
# instance
stacks = ("src_prefix", "artwork_prefix", "build_prefix", "dst_prefix")
def __init__(self, manifest):
self.manifest = manifest
# If the caller wrote:
# with self.prefix(...):
# as intended, then bind the state of each prefix stack as it was
# just BEFORE the call to prefix(). Since prefix() appended an
# entry to each prefix stack, capture len()-1.
self.prevlen = { stack: len(getattr(self.manifest, stack)) - 1
for stack in self.stacks }
def __nonzero__(self):
# If the caller wrote:
# if self.prefix(...):
# then a value of this class had better evaluate as 'True'.
return True
def __enter__(self):
# nobody uses 'with self.prefix(...) as variable:'
return None
def __exit__(self, type, value, traceback):
# First, if the 'with' block raised an exception, just propagate.
# Do NOT swallow it.
if type is not None:
return False
# Okay, 'with' block completed successfully. Restore previous
# state of each of the prefix stacks in self.stacks.
# Note that we do NOT simply call pop() on them as end_prefix()
# does. This is to cope with the possibility that the coder
# changed 'if self.prefix(...):' to 'with self.prefix(...):' yet
# forgot to remove the self.end_prefix(...) call at the bottom of
# the block. In that case, calling pop() again would be Bad! But
# if we restore the length of each stack to what it was before the
# current prefix() block, it doesn't matter whether end_prefix()
# was called or not.
for stack, prevlen in self.prevlen.items():
# find the attribute in 'self.manifest' named by 'stack', and
# truncate that list back to 'prevlen'
del getattr(self.manifest, stack)[prevlen:]
## self.manifest.display_stacks()
def end_prefix(self, descr=None): def end_prefix(self, descr=None):
"""Pops a prefix off the stack. If given an argument, checks """Pops a prefix off the stack. If given an argument, checks
@@ -433,6 +501,19 @@ class LLManifest(object):
relative to the destination directory.""" relative to the destination directory."""
return os.path.join(self.get_dst_prefix(), relpath) return os.path.join(self.get_dst_prefix(), relpath)
def _relative_dst_path(self, dstpath):
"""
Returns the path to a file or directory relative to the destination directory.
This should only be used for generating diagnostic output in the path method.
"""
dest_root=self.dst_prefix[0]
if dstpath.startswith(dest_root+os.path.sep):
return dstpath[len(dest_root)+1:]
elif dstpath.startswith(dest_root):
return dstpath[len(dest_root):]
else:
return dstpath
def ensure_src_dir(self, reldir): def ensure_src_dir(self, reldir):
"""Construct the path for a directory relative to the """Construct the path for a directory relative to the
source path, and ensures that it exists. Returns the source path, and ensures that it exists. Returns the
@@ -450,29 +531,17 @@ class LLManifest(object):
return path return path
def run_command(self, command): def run_command(self, command):
""" Runs an external command, and returns the output. Raises """
an exception if the command returns a nonzero status code. For Runs an external command.
debugging/informational purposes, prints out the command's Raises ManifestError exception if the command returns a nonzero status.
output as it is received.""" """
print "Running command:", command print "Running command:", command
sys.stdout.flush() sys.stdout.flush()
child = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, try:
shell=True) subprocess.check_call(command)
lines = [] except subprocess.CalledProcessError as err:
while True: raise ManifestError( "Command %s returned non-zero status (%s)"
lines.append(child.stdout.readline()) % (command, err.returncode) )
if lines[-1] == '':
break
else:
print lines[-1],
output = ''.join(lines)
child.stdout.close()
status = child.wait()
if status:
raise ManifestError(
"Command %s returned non-zero status (%s) \noutput:\n%s"
% (command, status, output) )
return output
def created_path(self, path): def created_path(self, path):
""" Declare that you've created a path in order to """ Declare that you've created a path in order to
@@ -485,6 +554,7 @@ class LLManifest(object):
def put_in_file(self, contents, dst, src=None): def put_in_file(self, contents, dst, src=None):
# write contents as dst # write contents as dst
dst_path = self.dst_path_of(dst) dst_path = self.dst_path_of(dst)
self.cmakedirs(os.path.dirname(dst_path))
f = open(dst_path, "wb") f = open(dst_path, "wb")
try: try:
f.write(contents) f.write(contents)
@@ -546,9 +616,16 @@ class LLManifest(object):
# *TODO is this gonna be useful? # *TODO is this gonna be useful?
print "Cleaning up " + c print "Cleaning up " + c
def process_either(self, src, dst):
# If it's a real directory, recurse through it --
# but not a symlink! Handle those like files.
if os.path.isdir(src) and not os.path.islink(src):
return self.process_directory(src, dst)
else:
return self.process_file(src, dst)
def process_file(self, src, dst): def process_file(self, src, dst):
if self.includes(src, dst): if self.includes(src, dst):
# print src, "=>", dst
for action in self.actions: for action in self.actions:
methodname = action + "_action" methodname = action + "_action"
method = getattr(self, methodname, None) method = getattr(self, methodname, None)
@@ -573,10 +650,7 @@ class LLManifest(object):
for name in names: for name in names:
srcname = os.path.join(src, name) srcname = os.path.join(src, name)
dstname = os.path.join(dst, name) dstname = os.path.join(dst, name)
if os.path.isdir(srcname): count += self.process_either(srcname, dstname)
count += self.process_directory(srcname, dstname)
else:
count += self.process_file(srcname, dstname)
return count return count
def includes(self, src, dst): def includes(self, src, dst):
@@ -616,16 +690,21 @@ class LLManifest(object):
# Don't recopy file if it's up-to-date. # Don't recopy file if it's up-to-date.
# If we seem to be not not overwriting files that have been # If we seem to be not not overwriting files that have been
# updated, set the last arg to False, but it will take longer. # updated, set the last arg to False, but it will take longer.
## reldst = (dst[len(self.dst_prefix[0]):]
## if dst.startswith(self.dst_prefix[0])
## else dst).lstrip(r'\/')
if os.path.exists(dst) and filecmp.cmp(src, dst, True): if os.path.exists(dst) and filecmp.cmp(src, dst, True):
## print "{} (skipping, {} exists)".format(src, reldst)
return return
# only copy if it's not excluded # only copy if it's not excluded
if self.includes(src, dst): if self.includes(src, dst):
try: try:
os.unlink(dst) os.unlink(dst)
except OSError, err: except OSError as err:
if err.errno != errno.ENOENT: if err.errno != errno.ENOENT:
raise raise
## print "{} => {}".format(src, reldst)
shutil.copy2(src, dst) shutil.copy2(src, dst)
def ccopytree(self, src, dst): def ccopytree(self, src, dst):
@@ -643,7 +722,7 @@ class LLManifest(object):
dstname = os.path.join(dst, name) dstname = os.path.join(dst, name)
try: try:
self.ccopymumble(srcname, dstname) self.ccopymumble(srcname, dstname)
except (IOError, os.error), why: except (IOError, os.error) as why:
errors.append((srcname, dstname, why)) errors.append((srcname, dstname, why))
if errors: if errors:
raise ManifestError, errors raise ManifestError, errors
@@ -724,13 +803,13 @@ class LLManifest(object):
return self.path(os.path.join(path, file), file) return self.path(os.path.join(path, file), file)
def path(self, src, dst=None): def path(self, src, dst=None):
sys.stdout.write("Processing %s => %s ... " % (src, dst))
sys.stdout.flush() sys.stdout.flush()
if src == None: if src == None:
raise ManifestError("No source file, dst is " + dst) raise ManifestError("No source file, dst is " + dst)
if dst == None: if dst == None:
dst = src dst = src
dst = os.path.join(self.get_dst_prefix(), dst) dst = os.path.join(self.get_dst_prefix(), dst)
sys.stdout.write("Processing %s => %s ... " % (src, self._relative_dst_path(dst)))
def try_path(src): def try_path(src):
# expand globs # expand globs
@@ -743,29 +822,21 @@ class LLManifest(object):
# if we're specifying a single path (not a glob), # if we're specifying a single path (not a glob),
# we should error out if it doesn't exist # we should error out if it doesn't exist
self.check_file_exists(src) self.check_file_exists(src)
# if it's a directory, recurse through it count += self.process_either(src, dst)
if os.path.isdir(src):
count += self.process_directory(src, dst)
else:
count += self.process_file(src, dst)
return count return count
for pfx in self.get_src_prefix(), self.get_artwork_prefix(), self.get_build_prefix(): try_prefixes = [self.get_src_prefix(), self.get_artwork_prefix(), self.get_build_prefix()]
tried=[]
count=0
while not count and try_prefixes:
pfx = try_prefixes.pop(0)
try: try:
count = try_path(os.path.join(pfx, src)) count = try_path(os.path.join(pfx, src))
except MissingError: except MissingError:
# If src isn't a wildcard, and if that file doesn't exist in tried.append(pfx)
# this pfx, try next pfx. if not try_prefixes:
count = 0 # no more prefixes left to try
continue print "unable to find '%s'; looked in:\n %s" % (src, '\n '.join(tried))
# Here try_path() didn't raise MissingError. Did it process any files?
if count:
break
# Even though try_path() didn't raise MissingError, it returned 0
# files. src is probably a wildcard meant for some other pfx. Loop
# back to try the next.
print "%d files" % count print "%d files" % count
# Let caller check whether we processed as many files as expected. In # Let caller check whether we processed as many files as expected. In

View File

@@ -1,182 +0,0 @@
#!/usr/bin/env python
"""\
@file llperformance.py
$LicenseInfo:firstyear=2010&license=viewerlgpl$
Second Life Viewer Source Code
Copyright (C) 2010-2011, Linden Research, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2.1 of the License only.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
$/LicenseInfo$
"""
# ------------------------------------------------
# Sim metrics utility functions.
import glob, os, time, sys, stat, exceptions
from indra.base import llsd
gBlockMap = {} #Map of performance metric data with function hierarchy information.
gCurrentStatPath = ""
gIsLoggingEnabled=False
class LLPerfStat:
def __init__(self,key):
self.mTotalTime = 0
self.mNumRuns = 0
self.mName=key
self.mTimeStamp = int(time.time()*1000)
self.mUTCTime = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
def __str__(self):
return "%f" % self.mTotalTime
def start(self):
self.mStartTime = int(time.time() * 1000000)
self.mNumRuns += 1
def stop(self):
execution_time = int(time.time() * 1000000) - self.mStartTime
self.mTotalTime += execution_time
def get_map(self):
results={}
results['name']=self.mName
results['utc_time']=self.mUTCTime
results['timestamp']=self.mTimeStamp
results['us']=self.mTotalTime
results['count']=self.mNumRuns
return results
class PerfError(exceptions.Exception):
def __init__(self):
return
def __Str__(self):
print "","Unfinished LLPerfBlock"
class LLPerfBlock:
def __init__( self, key ):
global gBlockMap
global gCurrentStatPath
global gIsLoggingEnabled
#Check to see if we're running metrics right now.
if gIsLoggingEnabled:
self.mRunning = True #Mark myself as running.
self.mPreviousStatPath = gCurrentStatPath
gCurrentStatPath += "/" + key
if gCurrentStatPath not in gBlockMap:
gBlockMap[gCurrentStatPath] = LLPerfStat(key)
self.mStat = gBlockMap[gCurrentStatPath]
self.mStat.start()
def finish( self ):
global gBlockMap
global gIsLoggingEnabled
if gIsLoggingEnabled:
self.mStat.stop()
self.mRunning = False
gCurrentStatPath = self.mPreviousStatPath
# def __del__( self ):
# if self.mRunning:
# #SPATTERS FIXME
# raise PerfError
class LLPerformance:
#--------------------------------------------------
# Determine whether or not we want to log statistics
def __init__( self, process_name = "python" ):
self.process_name = process_name
self.init_testing()
self.mTimeStamp = int(time.time()*1000)
self.mUTCTime = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
def init_testing( self ):
global gIsLoggingEnabled
host_performance_file = "/dev/shm/simperf/simperf_proc_config.llsd"
#If file exists, open
if os.path.exists(host_performance_file):
file = open (host_performance_file,'r')
#Read serialized LLSD from file.
body = llsd.parse(file.read())
#Calculate time since file last modified.
stats = os.stat(host_performance_file)
now = time.time()
mod = stats[stat.ST_MTIME]
age = now - mod
if age < ( body['duration'] ):
gIsLoggingEnabled = True
def get ( self ):
global gIsLoggingEnabled
return gIsLoggingEnabled
#def output(self,ptr,path):
# if 'stats' in ptr:
# stats = ptr['stats']
# self.mOutputPtr[path] = stats.get_map()
# if 'children' in ptr:
# children=ptr['children']
# curptr = self.mOutputPtr
# curchildren={}
# curptr['children'] = curchildren
# for key in children:
# curchildren[key]={}
# self.mOutputPtr = curchildren[key]
# self.output(children[key],path + '/' + key)
def done(self):
global gBlockMap
if not self.get():
return
output_name = "/dev/shm/simperf/%s_proc.%d.llsd" % (self.process_name, os.getpid())
output_file = open(output_name, 'w')
process_info = {
"name" : self.process_name,
"pid" : os.getpid(),
"ppid" : os.getppid(),
"timestamp" : self.mTimeStamp,
"utc_time" : self.mUTCTime,
}
output_file.write(llsd.format_notation(process_info))
output_file.write('\n')
for key in gBlockMap.keys():
gBlockMap[key] = gBlockMap[key].get_map()
output_file.write(llsd.format_notation(gBlockMap))
output_file.write('\n')
output_file.close()

View File

@@ -1,117 +0,0 @@
"""\
@file llsubprocess.py
@author Phoenix
@date 2008-01-18
@brief The simplest possible wrapper for a common sub-process paradigm.
$LicenseInfo:firstyear=2007&license=mit$
Copyright (c) 2007-2009, Linden Research, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
$/LicenseInfo$
"""
import os
import popen2
import time
import select
class Timeout(RuntimeError):
"Exception raised when a subprocess times out."
pass
def run(command, args=None, data=None, timeout=None):
"""\
@brief Run command with arguments
This is it. This is the function I want to run all the time when doing
subprocces, but end up copying the code everywhere. none of the
standard commands are secure and provide a way to specify input, get
all the output, and get the result.
@param command A string specifying a process to launch.
@param args Arguments to be passed to command. Must be list, tuple or None.
@param data input to feed to the command.
@param timeout Maximum number of many seconds to run.
@return Returns (result, stdout, stderr) from process.
"""
cmd = [command]
if args:
cmd.extend([str(arg) for arg in args])
#print "cmd: ","' '".join(cmd)
child = popen2.Popen3(cmd, True)
#print child.pid
out = []
err = []
result = -1
time_left = timeout
tochild = [child.tochild.fileno()]
while True:
time_start = time.time()
#print "time:",time_left
p_in, p_out, p_err = select.select(
[child.fromchild.fileno(), child.childerr.fileno()],
tochild,
[],
time_left)
if p_in:
new_line = os.read(child.fromchild.fileno(), 32 * 1024)
if new_line:
#print "line:",new_line
out.append(new_line)
new_line = os.read(child.childerr.fileno(), 32 * 1024)
if new_line:
#print "error:", new_line
err.append(new_line)
if p_out:
if data:
#print "p_out"
bytes = os.write(child.tochild.fileno(), data)
data = data[bytes:]
if len(data) == 0:
data = None
tochild = []
child.tochild.close()
result = child.poll()
if result != -1:
# At this point, the child process has exited and result
# is the return value from the process. Between the time
# we called select() and poll() the process may have
# exited so read all the data left on the child process
# stdout and stderr.
last = child.fromchild.read()
if last:
out.append(last)
last = child.childerr.read()
if last:
err.append(last)
child.tochild.close()
child.fromchild.close()
child.childerr.close()
break
if time_left is not None:
time_left -= (time.time() - time_start)
if time_left < 0:
raise Timeout
#print "result:",result
out = ''.join(out)
#print "stdout:", out
err = ''.join(err)
#print "stderr:", err
return result, out, err

View File

@@ -1,592 +0,0 @@
"""\
@file named_query.py
@author Ryan Williams, Phoenix
@date 2007-07-31
@brief An API for running named queries.
$LicenseInfo:firstyear=2007&license=mit$
Copyright (c) 2007-2009, Linden Research, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
$/LicenseInfo$
"""
import errno
import MySQLdb
import MySQLdb.cursors
import os
import os.path
import re
import time
from indra.base import llsd
from indra.base import config
DEBUG = False
NQ_FILE_SUFFIX = config.get('named-query-file-suffix', '.nq')
NQ_FILE_SUFFIX_LEN = len(NQ_FILE_SUFFIX)
_g_named_manager = None
def _init_g_named_manager(sql_dir = None):
"""Initializes a global NamedManager object to point at a
specified named queries hierarchy.
This function is intended entirely for testing purposes,
because it's tricky to control the config from inside a test."""
global NQ_FILE_SUFFIX
NQ_FILE_SUFFIX = config.get('named-query-file-suffix', '.nq')
global NQ_FILE_SUFFIX_LEN
NQ_FILE_SUFFIX_LEN = len(NQ_FILE_SUFFIX)
if sql_dir is None:
sql_dir = config.get('named-query-base-dir')
# extra fallback directory in case config doesn't return what we want
if sql_dir is None:
sql_dir = os.path.abspath(
os.path.join(
os.path.realpath(os.path.dirname(__file__)), "..", "..", "..", "..", "web", "dataservice", "sql"))
global _g_named_manager
_g_named_manager = NamedQueryManager(
os.path.abspath(os.path.realpath(sql_dir)))
def get(name, schema = None):
"Get the named query object to be used to perform queries"
if _g_named_manager is None:
_init_g_named_manager()
return _g_named_manager.get(name).for_schema(schema)
def sql(connection, name, params):
# use module-global NamedQuery object to perform default substitution
return get(name).sql(connection, params)
def run(connection, name, params, expect_rows = None):
"""\
@brief given a connection, run a named query with the params
Note that this function will fetch ALL rows.
@param connection The connection to use
@param name The name of the query to run
@param params The parameters passed into the query
@param expect_rows The number of rows expected. Set to 1 if return_as_map is true. Raises ExpectationFailed if the number of returned rows doesn't exactly match. Kind of a hack.
@return Returns the result set as a list of dicts.
"""
return get(name).run(connection, params, expect_rows)
class ExpectationFailed(Exception):
""" Exception that is raised when an expectation for an sql query
is not met."""
def __init__(self, message):
Exception.__init__(self, message)
self.message = message
class NamedQuery(object):
def __init__(self, name, filename):
""" Construct a NamedQuery object. The name argument is an
arbitrary name as a handle for the query, and the filename is
a path to a file or a file-like object containing an llsd named
query document."""
self._stat_interval_seconds = 5 # 5 seconds
self._name = name
if (filename is not None and isinstance(filename, (str, unicode))
and NQ_FILE_SUFFIX != filename[-NQ_FILE_SUFFIX_LEN:]):
filename = filename + NQ_FILE_SUFFIX
self._location = filename
self._alternative = dict()
self._last_mod_time = 0
self._last_check_time = 0
self.deleted = False
self.load_contents()
def name(self):
""" The name of the query. """
return self._name
def get_modtime(self):
""" Returns the mtime (last modified time) of the named query
filename. For file-like objects, expect a modtime of 0"""
if self._location and isinstance(self._location, (str, unicode)):
return os.path.getmtime(self._location)
return 0
def load_contents(self):
""" Loads and parses the named query file into self. Does
nothing if self.location is nonexistant."""
if self._location:
if isinstance(self._location, (str, unicode)):
contents = llsd.parse(open(self._location).read())
else:
# we probably have a file-like object. Godspeed!
contents = llsd.parse(self._location.read())
self._reference_contents(contents)
# Check for alternative implementations
try:
for name, alt in self._contents['alternative'].items():
nq = NamedQuery(name, None)
nq._reference_contents(alt)
self._alternative[name] = nq
except KeyError, e:
pass
self._last_mod_time = self.get_modtime()
self._last_check_time = time.time()
def _reference_contents(self, contents):
"Helper method which builds internal structure from parsed contents"
self._contents = contents
self._ttl = int(self._contents.get('ttl', 0))
self._return_as_map = bool(self._contents.get('return_as_map', False))
self._legacy_dbname = self._contents.get('legacy_dbname', None)
# reset these before doing the sql conversion because we will
# read them there. reset these while loading so we pick up
# changes.
self._around = set()
self._append = set()
self._integer = set()
self._options = self._contents.get('dynamic_where', {})
for key in self._options:
if isinstance(self._options[key], basestring):
self._options[key] = self._convert_sql(self._options[key])
elif isinstance(self._options[key], list):
lines = []
for line in self._options[key]:
lines.append(self._convert_sql(line))
self._options[key] = lines
else:
moreopt = {}
for kk in self._options[key]:
moreopt[kk] = self._convert_sql(self._options[key][kk])
self._options[key] = moreopt
self._base_query = self._convert_sql(self._contents['base_query'])
self._query_suffix = self._convert_sql(
self._contents.get('query_suffix', ''))
def _convert_sql(self, sql):
"""convert the parsed sql into a useful internal structure.
This function has to turn the named query format into a pyformat
style. It also has to look for %:name% and :name% and
ready them for use in LIKE statements"""
if sql:
# This first sub is to properly escape any % signs that
# are meant to be literally passed through to mysql in the
# query. It leaves any %'s that are used for
# like-expressions.
expr = re.compile("(?<=[^a-zA-Z0-9_-])%(?=[^:])")
sql = expr.sub('%%', sql)
# This should tackle the rest of the %'s in the query, by
# converting them to LIKE clauses.
expr = re.compile("(%?):([a-zA-Z][a-zA-Z0-9_-]*)%")
sql = expr.sub(self._prepare_like, sql)
expr = re.compile("#:([a-zA-Z][a-zA-Z0-9_-]*)")
sql = expr.sub(self._prepare_integer, sql)
expr = re.compile(":([a-zA-Z][a-zA-Z0-9_-]*)")
sql = expr.sub("%(\\1)s", sql)
return sql
def _prepare_like(self, match):
"""This function changes LIKE statement replace behavior
It works by turning %:name% to %(_name_around)s and :name% to
%(_name_append)s. Since a leading '_' is not a valid keyname
input (enforced via unit tests), it will never clash with
existing keys. Then, when building the statement, the query
runner will generate corrected strings."""
if match.group(1) == '%':
# there is a leading % so this is treated as prefix/suffix
self._around.add(match.group(2))
return "%(" + self._build_around_key(match.group(2)) + ")s"
else:
# there is no leading %, so this is suffix only
self._append.add(match.group(2))
return "%(" + self._build_append_key(match.group(2)) + ")s"
def _build_around_key(self, key):
return "_" + key + "_around"
def _build_append_key(self, key):
return "_" + key + "_append"
def _prepare_integer(self, match):
"""This function adjusts the sql for #:name replacements
It works by turning #:name to %(_name_as_integer)s. Since a
leading '_' is not a valid keyname input (enforced via unit
tests), it will never clash with existing keys. Then, when
building the statement, the query runner will generate
corrected strings."""
self._integer.add(match.group(1))
return "%(" + self._build_integer_key(match.group(1)) + ")s"
def _build_integer_key(self, key):
return "_" + key + "_as_integer"
def _strip_wildcards_to_list(self, value):
"""Take string, and strip out the LIKE special characters.
Technically, this is database dependant, but postgresql and
mysql use the same wildcards, and I am not aware of a general
way to handle this. I think you need a sql statement of the
form:
LIKE_STRING( [ANY,ONE,str]... )
which would treat ANY as their any string, and ONE as their
single glyph, and str as something that needs database
specific encoding to not allow any % or _ to affect the query.
As it stands, I believe it's impossible to write a named query
style interface which uses like to search the entire space of
text available. Imagine the query:
% of brain used by average linden
In order to search for %, it must be escaped, so once you have
escaped the string to not do wildcard searches, and be escaped
for the database, and then prepended the wildcard you come
back with one of:
1) %\% of brain used by average linden
2) %%% of brain used by average linden
Then, when passed to the database to be escaped to be database
safe, you get back:
1) %\\% of brain used by average linden
: which means search for any character sequence, followed by a
backslash, followed by any sequence, followed by ' of
brain...'
2) %%% of brain used by average linden
: which (I believe) means search for a % followed by any
character sequence followed by 'of brain...'
Neither of which is what we want!
So, we need a vendor (or extention) for LIKE_STRING. Anyone
want to write it?"""
if isinstance(value, unicode):
utf8_value = value
else:
utf8_value = unicode(value, "utf-8")
esc_list = []
remove_chars = set(u"%_")
for glyph in utf8_value:
if glyph in remove_chars:
continue
esc_list.append(glyph.encode("utf-8"))
return esc_list
def delete(self):
""" Makes this query unusable by deleting all the members and
setting the deleted member. This is desired when the on-disk
query has been deleted but the in-memory copy remains."""
# blow away all members except _name, _location, and deleted
name, location = self._name, self._location
for key in self.__dict__.keys():
del self.__dict__[key]
self.deleted = True
self._name, self._location = name, location
def ttl(self):
""" Estimated time to live of this query. Used for web
services to set the Expires header."""
return self._ttl
def legacy_dbname(self):
return self._legacy_dbname
def return_as_map(self):
""" Returns true if this query is configured to return its
results as a single map (as opposed to a list of maps, the
normal behavior)."""
return self._return_as_map
def for_schema(self, db_name):
"Look trough the alternates and return the correct query"
if db_name is None:
return self
try:
return self._alternative[db_name]
except KeyError, e:
pass
return self
def run(self, connection, params, expect_rows = None, use_dictcursor = True):
"""given a connection, run a named query with the params
Note that this function will fetch ALL rows. We do this because it
opens and closes the cursor to generate the values, and this
isn't a generator so the cursor has no life beyond the method call.
@param cursor The connection to use (this generates its own cursor for the query)
@param name The name of the query to run
@param params The parameters passed into the query
@param expect_rows The number of rows expected. Set to 1 if return_as_map is true. Raises ExpectationFailed if the number of returned rows doesn't exactly match. Kind of a hack.
@param use_dictcursor Set to false to use a normal cursor and manually convert the rows to dicts.
@return Returns the result set as a list of dicts, or, if the named query has return_as_map set to true, returns a single dict.
"""
if use_dictcursor:
cursor = connection.cursor(MySQLdb.cursors.DictCursor)
else:
cursor = connection.cursor()
full_query, params = self._construct_sql(params)
if DEBUG:
print "SQL:", self.sql(connection, params)
rows = cursor.execute(full_query, params)
# *NOTE: the expect_rows argument is a very cheesy way to get some
# validation on the result set. If you want to add more expectation
# logic, do something more object-oriented and flexible. Or use an ORM.
if(self._return_as_map):
expect_rows = 1
if expect_rows is not None and rows != expect_rows:
cursor.close()
raise ExpectationFailed("Statement expected %s rows, got %s. Sql: '%s' %s" % (
expect_rows, rows, full_query, params))
# convert to dicts manually if we're not using a dictcursor
if use_dictcursor:
result_set = cursor.fetchall()
else:
if cursor.description is None:
# an insert or something
x = cursor.fetchall()
cursor.close()
return x
names = [x[0] for x in cursor.description]
result_set = []
for row in cursor.fetchall():
converted_row = {}
for idx, col_name in enumerate(names):
converted_row[col_name] = row[idx]
result_set.append(converted_row)
cursor.close()
if self._return_as_map:
return result_set[0]
return result_set
def _construct_sql(self, params):
""" Returns a query string and a dictionary of parameters,
suitable for directly passing to the execute() method."""
self.refresh()
# build the query from the options available and the params
base_query = []
base_query.append(self._base_query)
for opt, extra_where in self._options.items():
if type(extra_where) in (dict, list, tuple):
if opt in params:
base_query.append(extra_where[params[opt]])
else:
if opt in params and params[opt]:
base_query.append(extra_where)
if self._query_suffix:
base_query.append(self._query_suffix)
full_query = '\n'.join(base_query)
# Go through the query and rewrite all of the ones with the
# @:name syntax.
rewrite = _RewriteQueryForArray(params)
expr = re.compile("@%\(([a-zA-Z][a-zA-Z0-9_-]*)\)s")
full_query = expr.sub(rewrite.operate, full_query)
params.update(rewrite.new_params)
# build out the params for like. We only have to do this
# parameters which were detected to have ued the where syntax
# during load.
#
# * treat the incoming string as utf-8
# * strip wildcards
# * append or prepend % as appropriate
new_params = {}
for key in params:
if key in self._around:
new_value = ['%']
new_value.extend(self._strip_wildcards_to_list(params[key]))
new_value.append('%')
new_params[self._build_around_key(key)] = ''.join(new_value)
if key in self._append:
new_value = self._strip_wildcards_to_list(params[key])
new_value.append('%')
new_params[self._build_append_key(key)] = ''.join(new_value)
if key in self._integer:
new_params[self._build_integer_key(key)] = int(params[key])
params.update(new_params)
return full_query, params
def sql(self, connection, params):
""" Generates an SQL statement from the named query document
and a dictionary of parameters.
*NOTE: Only use for debugging, because it uses the
non-standard MySQLdb 'literal' method.
"""
if not DEBUG:
import warnings
warnings.warn("Don't use named_query.sql() when not debugging. Used on %s" % self._location)
# do substitution using the mysql (non-standard) 'literal'
# function to do the escaping.
full_query, params = self._construct_sql(params)
return full_query % connection.literal(params)
def refresh(self):
""" Refresh self from the file on the filesystem.
This is optimized to be callable as frequently as you wish,
without adding too much load. It does so by only stat-ing the
file every N seconds, where N defaults to 5 and is
configurable through the member _stat_interval_seconds. If the stat
reveals that the file has changed, refresh will re-parse the
contents of the file and use them to update the named query
instance. If the stat reveals that the file has been deleted,
refresh will call self.delete to make the in-memory
representation unusable."""
now = time.time()
if(now - self._last_check_time > self._stat_interval_seconds):
self._last_check_time = now
try:
modtime = self.get_modtime()
if(modtime > self._last_mod_time):
self.load_contents()
except OSError, e:
if e.errno == errno.ENOENT: # file not found
self.delete() # clean up self
raise # pass the exception along to the caller so they know that this query disappeared
class NamedQueryManager(object):
""" Manages the lifespan of NamedQuery objects, drawing from a
directory hierarchy of named query documents.
In practice this amounts to a memory cache of NamedQuery objects."""
def __init__(self, named_queries_dir):
""" Initializes a manager to look for named queries in a
directory."""
self._dir = os.path.abspath(os.path.realpath(named_queries_dir))
self._cached_queries = {}
def sql(self, connection, name, params):
nq = self.get(name)
return nq.sql(connection, params)
def get(self, name):
""" Returns a NamedQuery instance based on the name, either
from memory cache, or by parsing from disk.
The name is simply a relative path to the directory associated
with the manager object. Before returning the instance, the
NamedQuery object is cached in memory, so that subsequent
accesses don't have to read from disk or do any parsing. This
means that NamedQuery objects returned by this method are
shared across all users of the manager object.
NamedQuery.refresh is used to bring the NamedQuery objects in
sync with the actual files on disk."""
nq = self._cached_queries.get(name)
if nq is None:
nq = NamedQuery(name, os.path.join(self._dir, name))
self._cached_queries[name] = nq
else:
try:
nq.refresh()
except OSError, e:
if e.errno == errno.ENOENT: # file not found
del self._cached_queries[name]
raise # pass exception along to caller so they know that the query disappeared
return nq
class _RewriteQueryForArray(object):
"Helper class for rewriting queries with the @:name syntax"
def __init__(self, params):
self.params = params
self.new_params = dict()
def operate(self, match):
"Given a match, return the string that should be in use"
key = match.group(1)
value = self.params[key]
if type(value) in (list,tuple):
rv = []
for idx in range(len(value)):
# if the value@idx is array-like, we are
# probably dealing with a VALUES
new_key = "_%s_%s"%(key, str(idx))
val_item = value[idx]
if type(val_item) in (list, tuple, dict):
if type(val_item) is dict:
# this is because in Python, the order of
# key, value retrieval from the dict is not
# guaranteed to match what the input intended
# and for VALUES, order is important.
# TODO: Implemented ordered dict in LLSD parser?
raise ExpectationFailed('Only lists/tuples allowed,\
received dict')
values_keys = []
for value_idx, item in enumerate(val_item):
# we want a key of the format :
# key_#replacement_#value_row_#value_col
# ugh... so if we are replacing 10 rows in user_note,
# the first values clause would read (for @:user_notes) :-
# ( :_user_notes_0_1_1, :_user_notes_0_1_2, :_user_notes_0_1_3 )
# the input LLSD for VALUES will look like:
# <llsd>...
# <map>
# <key>user_notes</key>
# <array>
# <array> <!-- row 1 for VALUES -->
# <string>...</string>
# <string>...</string>
# <string>...</string>
# </array>
# ...
# </array>
# </map>
# ... </llsd>
values_key = "%s_%s"%(new_key, value_idx)
self.new_params[values_key] = item
values_keys.append("%%(%s)s"%values_key)
# now collapse all these new place holders enclosed in ()
# from [':_key_0_1_1', ':_key_0_1_2', ':_key_0_1_3,...]
# rv will have [ '(:_key_0_1_1, :_key_0_1_2, :_key_0_1_3)', ]
# which is flattened a few lines below join(rv)
rv.append('(%s)' % ','.join(values_keys))
else:
self.new_params[new_key] = val_item
rv.append("%%(%s)s"%new_key)
return ','.join(rv)
else:
# not something that can be expanded, so just drop the
# leading @ in the front of the match. This will mean that
# the single value we have, be it a string, int, whatever
# (other than dict) will correctly show up, eg:
#
# where foo in (@:foobar) -- foobar is a string, so we get
# where foo in (:foobar)
return match.group(0)[1:]

View File

@@ -1,84 +0,0 @@
'''
@file shutil2.py
@brief a better shutil.copytree replacement
$LicenseInfo:firstyear=2007&license=mit$
Copyright (c) 2007-2009, Linden Research, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
$/LicenseInfo$
'''
#
# shutil2.py
# Taken from http://www.scons.org/wiki/AccumulateBuilder
# the stock copytree sucks because it insists that the
# target dir not exist
#
import os.path
import shutil
def copytree(src, dest, symlinks=False):
"""My own copyTree which does not fail if the directory exists.
Recursively copy a directory tree using copy2().
If the optional symlinks flag is true, symbolic links in the
source tree result in symbolic links in the destination tree; if
it is false, the contents of the files pointed to by symbolic
links are copied.
Behavior is meant to be identical to GNU 'cp -R'.
"""
def copyItems(src, dest, symlinks=False):
"""Function that does all the work.
It is necessary to handle the two 'cp' cases:
- destination does exist
- destination does not exist
See 'cp -R' documentation for more details
"""
for item in os.listdir(src):
srcPath = os.path.join(src, item)
if os.path.isdir(srcPath):
srcBasename = os.path.basename(srcPath)
destDirPath = os.path.join(dest, srcBasename)
if not os.path.exists(destDirPath):
os.makedirs(destDirPath)
copyItems(srcPath, destDirPath)
elif os.path.islink(item) and symlinks:
linkto = os.readlink(item)
os.symlink(linkto, dest)
else:
shutil.copy2(srcPath, dest)
# case 'cp -R src/ dest/' where dest/ already exists
if os.path.exists(dest):
destPath = os.path.join(dest, os.path.basename(src))
if not os.path.exists(destPath):
os.makedirs(destPath)
# case 'cp -R src/ dest/' where dest/ does not exist
else:
os.makedirs(dest)
destPath = dest
# actually copy the files
copyItems(src, destPath)

View File

@@ -1,338 +0,0 @@
#!/usr/bin/env python
"""\
@file simperf_host_xml_parser.py
@brief Digest collector's XML dump and convert to simple dict/list structure
$LicenseInfo:firstyear=2008&license=mit$
Copyright (c) 2008-2009, Linden Research, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
$/LicenseInfo$
"""
import sys, os, getopt, time
import simplejson
from xml import sax
def usage():
print "Usage:"
print sys.argv[0] + " [options]"
print " Convert RRD's XML dump to JSON. Script to convert the simperf_host_collector-"
print " generated RRD dump into JSON. Steps include converting selected named"
print " fields from GAUGE type to COUNTER type by computing delta with preceding"
print " values. Top-level named fields are:"
print
print " lastupdate Time (javascript timestamp) of last data sample"
print " step Time in seconds between samples"
print " ds Data specification (name/type) for each column"
print " database Table of data samples, one time step per row"
print
print "Options:"
print " -i, --in Input settings filename. (Default: stdin)"
print " -o, --out Output settings filename. (Default: stdout)"
print " -h, --help Print this message and exit."
print
print "Example: %s -i rrddump.xml -o rrddump.json" % sys.argv[0]
print
print "Interfaces:"
print " class SimPerfHostXMLParser() # SAX content handler"
print " def simperf_host_xml_fixup(parser) # post-parse value fixup"
class SimPerfHostXMLParser(sax.handler.ContentHandler):
def __init__(self):
pass
def startDocument(self):
self.rrd_last_update = 0 # public
self.rrd_step = 0 # public
self.rrd_ds = [] # public
self.rrd_records = [] # public
self._rrd_level = 0
self._rrd_parse_state = 0
self._rrd_chars = ""
self._rrd_capture = False
self._rrd_ds_val = {}
self._rrd_data_row = []
self._rrd_data_row_has_nan = False
def endDocument(self):
pass
# Nasty little ad-hoc state machine to extract the elements that are
# necessary from the 'rrdtool dump' XML output. The same element
# name '<ds>' is used for two different data sets so we need to pay
# some attention to the actual structure to get the ones we want
# and ignore the ones we don't.
def startElement(self, name, attrs):
self._rrd_level = self._rrd_level + 1
self._rrd_capture = False
if self._rrd_level == 1:
if name == "rrd" and self._rrd_parse_state == 0:
self._rrd_parse_state = 1 # In <rrd>
self._rrd_capture = True
self._rrd_chars = ""
elif self._rrd_level == 2:
if self._rrd_parse_state == 1:
if name == "lastupdate":
self._rrd_parse_state = 2 # In <rrd><lastupdate>
self._rrd_capture = True
self._rrd_chars = ""
elif name == "step":
self._rrd_parse_state = 3 # In <rrd><step>
self._rrd_capture = True
self._rrd_chars = ""
elif name == "ds":
self._rrd_parse_state = 4 # In <rrd><ds>
self._rrd_ds_val = {}
self._rrd_chars = ""
elif name == "rra":
self._rrd_parse_state = 5 # In <rrd><rra>
elif self._rrd_level == 3:
if self._rrd_parse_state == 4:
if name == "name":
self._rrd_parse_state = 6 # In <rrd><ds><name>
self._rrd_capture = True
self._rrd_chars = ""
elif name == "type":
self._rrd_parse_state = 7 # In <rrd><ds><type>
self._rrd_capture = True
self._rrd_chars = ""
elif self._rrd_parse_state == 5:
if name == "database":
self._rrd_parse_state = 8 # In <rrd><rra><database>
elif self._rrd_level == 4:
if self._rrd_parse_state == 8:
if name == "row":
self._rrd_parse_state = 9 # In <rrd><rra><database><row>
self._rrd_data_row = []
self._rrd_data_row_has_nan = False
elif self._rrd_level == 5:
if self._rrd_parse_state == 9:
if name == "v":
self._rrd_parse_state = 10 # In <rrd><rra><database><row><v>
self._rrd_capture = True
self._rrd_chars = ""
def endElement(self, name):
self._rrd_capture = False
if self._rrd_parse_state == 10:
self._rrd_capture = self._rrd_level == 6
if self._rrd_level == 5:
if self._rrd_chars == "NaN":
self._rrd_data_row_has_nan = True
else:
self._rrd_data_row.append(self._rrd_chars)
self._rrd_parse_state = 9 # In <rrd><rra><database><row>
elif self._rrd_parse_state == 9:
if self._rrd_level == 4:
if not self._rrd_data_row_has_nan:
self.rrd_records.append(self._rrd_data_row)
self._rrd_parse_state = 8 # In <rrd><rra><database>
elif self._rrd_parse_state == 8:
if self._rrd_level == 3:
self._rrd_parse_state = 5 # In <rrd><rra>
elif self._rrd_parse_state == 7:
if self._rrd_level == 3:
self._rrd_ds_val["type"] = self._rrd_chars
self._rrd_parse_state = 4 # In <rrd><ds>
elif self._rrd_parse_state == 6:
if self._rrd_level == 3:
self._rrd_ds_val["name"] = self._rrd_chars
self._rrd_parse_state = 4 # In <rrd><ds>
elif self._rrd_parse_state == 5:
if self._rrd_level == 2:
self._rrd_parse_state = 1 # In <rrd>
elif self._rrd_parse_state == 4:
if self._rrd_level == 2:
self.rrd_ds.append(self._rrd_ds_val)
self._rrd_parse_state = 1 # In <rrd>
elif self._rrd_parse_state == 3:
if self._rrd_level == 2:
self.rrd_step = long(self._rrd_chars)
self._rrd_parse_state = 1 # In <rrd>
elif self._rrd_parse_state == 2:
if self._rrd_level == 2:
self.rrd_last_update = long(self._rrd_chars)
self._rrd_parse_state = 1 # In <rrd>
elif self._rrd_parse_state == 1:
if self._rrd_level == 1:
self._rrd_parse_state = 0 # At top
if self._rrd_level:
self._rrd_level = self._rrd_level - 1
def characters(self, content):
if self._rrd_capture:
self._rrd_chars = self._rrd_chars + content.strip()
def _make_numeric(value):
try:
value = float(value)
except:
value = ""
return value
def simperf_host_xml_fixup(parser, filter_start_time = None, filter_end_time = None):
# Fixup for GAUGE fields that are really COUNTS. They
# were forced to GAUGE to try to disable rrdtool's
# data interpolation/extrapolation for non-uniform time
# samples.
fixup_tags = [ "cpu_user",
"cpu_nice",
"cpu_sys",
"cpu_idle",
"cpu_waitio",
"cpu_intr",
# "file_active",
# "file_free",
# "inode_active",
# "inode_free",
"netif_in_kb",
"netif_in_pkts",
"netif_in_errs",
"netif_in_drop",
"netif_out_kb",
"netif_out_pkts",
"netif_out_errs",
"netif_out_drop",
"vm_page_in",
"vm_page_out",
"vm_swap_in",
"vm_swap_out",
#"vm_mem_total",
#"vm_mem_used",
#"vm_mem_active",
#"vm_mem_inactive",
#"vm_mem_free",
#"vm_mem_buffer",
#"vm_swap_cache",
#"vm_swap_total",
#"vm_swap_used",
#"vm_swap_free",
"cpu_interrupts",
"cpu_switches",
"cpu_forks" ]
col_count = len(parser.rrd_ds)
row_count = len(parser.rrd_records)
# Process the last row separately, just to make all values numeric.
for j in range(col_count):
parser.rrd_records[row_count - 1][j] = _make_numeric(parser.rrd_records[row_count - 1][j])
# Process all other row/columns.
last_different_row = row_count - 1
current_row = row_count - 2
while current_row >= 0:
# Check for a different value than the previous row. If everything is the same
# then this is probably just a filler/bogus entry.
is_different = False
for j in range(col_count):
parser.rrd_records[current_row][j] = _make_numeric(parser.rrd_records[current_row][j])
if parser.rrd_records[current_row][j] != parser.rrd_records[last_different_row][j]:
# We're good. This is a different row.
is_different = True
if not is_different:
# This is a filler/bogus entry. Just ignore it.
for j in range(col_count):
parser.rrd_records[current_row][j] = float('nan')
else:
# Some tags need to be converted into deltas.
for j in range(col_count):
if parser.rrd_ds[j]["name"] in fixup_tags:
parser.rrd_records[last_different_row][j] = \
parser.rrd_records[last_different_row][j] - parser.rrd_records[current_row][j]
last_different_row = current_row
current_row -= 1
# Set fixup_tags in the first row to 'nan' since they aren't useful anymore.
for j in range(col_count):
if parser.rrd_ds[j]["name"] in fixup_tags:
parser.rrd_records[0][j] = float('nan')
# Add a timestamp to each row and to the catalog. Format and name
# chosen to match other simulator logging (hopefully).
start_time = parser.rrd_last_update - (parser.rrd_step * (row_count - 1))
# Build a filtered list of rrd_records if we are limited to a time range.
filter_records = False
if filter_start_time is not None or filter_end_time is not None:
filter_records = True
filtered_rrd_records = []
if filter_start_time is None:
filter_start_time = start_time * 1000
if filter_end_time is None:
filter_end_time = parser.rrd_last_update * 1000
for i in range(row_count):
record_timestamp = (start_time + (i * parser.rrd_step)) * 1000
parser.rrd_records[i].insert(0, record_timestamp)
if filter_records:
if filter_start_time <= record_timestamp and record_timestamp <= filter_end_time:
filtered_rrd_records.append(parser.rrd_records[i])
if filter_records:
parser.rrd_records = filtered_rrd_records
parser.rrd_ds.insert(0, {"type": "GAUGE", "name": "javascript_timestamp"})
def main(argv=None):
opts, args = getopt.getopt(sys.argv[1:], "i:o:h", ["in=", "out=", "help"])
input_file = sys.stdin
output_file = sys.stdout
for o, a in opts:
if o in ("-i", "--in"):
input_file = open(a, 'r')
if o in ("-o", "--out"):
output_file = open(a, 'w')
if o in ("-h", "--help"):
usage()
sys.exit(0)
# Using the SAX parser as it is at least 4X faster and far, far
# smaller on this dataset than the DOM-based interface in xml.dom.minidom.
# With SAX and a 5.4MB xml file, this requires about seven seconds of
# wall-clock time and 32MB VSZ. With the DOM interface, about 22 seconds
# and over 270MB VSZ.
handler = SimPerfHostXMLParser()
sax.parse(input_file, handler)
if input_file != sys.stdin:
input_file.close()
# Various format fixups: string-to-num, gauge-to-counts, add
# a time stamp, etc.
simperf_host_xml_fixup(handler)
# Create JSONable dict with interesting data and format/print it
print >>output_file, simplejson.dumps({ "step" : handler.rrd_step,
"lastupdate": handler.rrd_last_update * 1000,
"ds" : handler.rrd_ds,
"database" : handler.rrd_records })
return 0
if __name__ == "__main__":
sys.exit(main())

View File

@@ -1,167 +0,0 @@
#!/usr/bin/env python
"""\
@file simperf_oprof_interface.py
@brief Manage OProfile data collection on a host
$LicenseInfo:firstyear=2008&license=mit$
Copyright (c) 2008-2009, Linden Research, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
$/LicenseInfo$
"""
import sys, os, getopt
import simplejson
def usage():
print "Usage:"
print sys.argv[0] + " [options]"
print " Digest the OProfile report forms that come out of the"
print " simperf_oprof_ctl program's -r/--report command. The result"
print " is an array of dictionaires with the following keys:"
print
print " symbol Name of sampled, calling, or called procedure"
print " file Executable or library where symbol resides"
print " percentage Percentage contribution to profile, calls or called"
print " samples Sample count"
print " calls Methods called by the method in question (full only)"
print " called_by Methods calling the method (full only)"
print
print " For 'full' reports the two keys 'calls' and 'called_by' are"
print " themselves arrays of dictionaries based on the first four keys."
print
print "Return Codes:"
print " None. Aggressively digests everything. Will likely mung results"
print " if a program or library has whitespace in its name."
print
print "Options:"
print " -i, --in Input settings filename. (Default: stdin)"
print " -o, --out Output settings filename. (Default: stdout)"
print " -h, --help Print this message and exit."
print
print "Interfaces:"
print " class SimPerfOProfileInterface()"
class SimPerfOProfileInterface:
def __init__(self):
self.isBrief = True # public
self.isValid = False # public
self.result = [] # public
def parse(self, input):
in_samples = False
for line in input:
if in_samples:
if line[0:6] == "------":
self.isBrief = False
self._parseFull(input)
else:
self._parseBrief(input, line)
self.isValid = True
return
try:
hd1, remain = line.split(None, 1)
if hd1 == "samples":
in_samples = True
except ValueError:
pass
def _parseBrief(self, input, line1):
try:
fld1, fld2, fld3, fld4 = line1.split(None, 3)
self.result.append({"samples" : fld1,
"percentage" : fld2,
"file" : fld3,
"symbol" : fld4.strip("\n")})
except ValueError:
pass
for line in input:
try:
fld1, fld2, fld3, fld4 = line.split(None, 3)
self.result.append({"samples" : fld1,
"percentage" : fld2,
"file" : fld3,
"symbol" : fld4.strip("\n")})
except ValueError:
pass
def _parseFull(self, input):
state = 0 # In 'called_by' section
calls = []
called_by = []
current = {}
for line in input:
if line[0:6] == "------":
if len(current):
current["calls"] = calls
current["called_by"] = called_by
self.result.append(current)
state = 0
calls = []
called_by = []
current = {}
else:
try:
fld1, fld2, fld3, fld4 = line.split(None, 3)
tmp = {"samples" : fld1,
"percentage" : fld2,
"file" : fld3,
"symbol" : fld4.strip("\n")}
except ValueError:
continue
if line[0] != " ":
current = tmp
state = 1 # In 'calls' section
elif state == 0:
called_by.append(tmp)
else:
calls.append(tmp)
if len(current):
current["calls"] = calls
current["called_by"] = called_by
self.result.append(current)
def main(argv=None):
opts, args = getopt.getopt(sys.argv[1:], "i:o:h", ["in=", "out=", "help"])
input_file = sys.stdin
output_file = sys.stdout
for o, a in opts:
if o in ("-i", "--in"):
input_file = open(a, 'r')
if o in ("-o", "--out"):
output_file = open(a, 'w')
if o in ("-h", "--help"):
usage()
sys.exit(0)
oprof = SimPerfOProfileInterface()
oprof.parse(input_file)
if input_file != sys.stdin:
input_file.close()
# Create JSONable dict with interesting data and format/print it
print >>output_file, simplejson.dumps(oprof.result)
return 0
if __name__ == "__main__":
sys.exit(main())

View File

@@ -1,191 +0,0 @@
#!/usr/bin/env python
"""\
@file simperf_proc_interface.py
@brief Utility to extract log messages from *.<pid>.llsd files containing performance statistics.
$LicenseInfo:firstyear=2008&license=mit$
Copyright (c) 2008-2009, Linden Research, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
$/LicenseInfo$
"""
# ----------------------------------------------------
# Utility to extract log messages from *.<pid>.llsd
# files that contain performance statistics.
# ----------------------------------------------------
import sys, os
if os.path.exists("setup-path.py"):
execfile("setup-path.py")
from indra.base import llsd
DEFAULT_PATH="/dev/shm/simperf/"
# ----------------------------------------------------
# Pull out the stats and return a single document
def parse_logfile(filename, target_column=None, verbose=False):
full_doc = []
# Open source temp log file. Let exceptions percolate up.
sourcefile = open( filename,'r')
if verbose:
print "Reading " + filename
# Parse and output all lines from the temp file
for line in sourcefile.xreadlines():
partial_doc = llsd.parse(line)
if partial_doc is not None:
if target_column is None:
full_doc.append(partial_doc)
else:
trim_doc = { target_column: partial_doc[target_column] }
if target_column != "fps":
trim_doc[ 'fps' ] = partial_doc[ 'fps' ]
trim_doc[ '/total_time' ] = partial_doc[ '/total_time' ]
trim_doc[ 'utc_time' ] = partial_doc[ 'utc_time' ]
full_doc.append(trim_doc)
sourcefile.close()
return full_doc
# Extract just the meta info line, and the timestamp of the first/last frame entry.
def parse_logfile_info(filename, verbose=False):
# Open source temp log file. Let exceptions percolate up.
sourcefile = open(filename, 'rU') # U is to open with Universal newline support
if verbose:
print "Reading " + filename
# The first line is the meta info line.
info_line = sourcefile.readline()
if not info_line:
sourcefile.close()
return None
# The rest of the lines are frames. Read the first and last to get the time range.
info = llsd.parse( info_line )
info['start_time'] = None
info['end_time'] = None
first_frame = sourcefile.readline()
if first_frame:
try:
info['start_time'] = int(llsd.parse(first_frame)['timestamp'])
except:
pass
# Read the file backwards to find the last two lines.
sourcefile.seek(0, 2)
file_size = sourcefile.tell()
offset = 1024
num_attempts = 0
end_time = None
if file_size < offset:
offset = file_size
while 1:
sourcefile.seek(-1*offset, 2)
read_str = sourcefile.read(offset)
# Remove newline at the end
if read_str[offset - 1] == '\n':
read_str = read_str[0:-1]
lines = read_str.split('\n')
full_line = None
if len(lines) > 2: # Got two line
try:
end_time = llsd.parse(lines[-1])['timestamp']
except:
# We couldn't parse this line. Try once more.
try:
end_time = llsd.parse(lines[-2])['timestamp']
except:
# Nope. Just move on.
pass
break
if len(read_str) == file_size: # Reached the beginning
break
offset += 1024
info['end_time'] = int(end_time)
sourcefile.close()
return info
def parse_proc_filename(filename):
try:
name_as_list = filename.split(".")
cur_stat_type = name_as_list[0].split("_")[0]
cur_pid = name_as_list[1]
except IndexError, ValueError:
return (None, None)
return (cur_pid, cur_stat_type)
# ----------------------------------------------------
def get_simstats_list(path=None):
""" Return stats (pid, type) listed in <type>_proc.<pid>.llsd """
if path is None:
path = DEFAULT_PATH
simstats_list = []
for file_name in os.listdir(path):
if file_name.endswith(".llsd") and file_name != "simperf_proc_config.llsd":
simstats_info = parse_logfile_info(path + file_name)
if simstats_info is not None:
simstats_list.append(simstats_info)
return simstats_list
def get_log_info_list(pid=None, stat_type=None, path=None, target_column=None, verbose=False):
""" Return data from all llsd files matching the pid and stat type """
if path is None:
path = DEFAULT_PATH
log_info_list = {}
for file_name in os.listdir ( path ):
if file_name.endswith(".llsd") and file_name != "simperf_proc_config.llsd":
(cur_pid, cur_stat_type) = parse_proc_filename(file_name)
if cur_pid is None:
continue
if pid is not None and pid != cur_pid:
continue
if stat_type is not None and stat_type != cur_stat_type:
continue
log_info_list[cur_pid] = parse_logfile(path + file_name, target_column, verbose)
return log_info_list
def delete_simstats_files(pid=None, stat_type=None, path=None):
""" Delete *.<pid>.llsd files """
if path is None:
path = DEFAULT_PATH
del_list = []
for file_name in os.listdir(path):
if file_name.endswith(".llsd") and file_name != "simperf_proc_config.llsd":
(cur_pid, cur_stat_type) = parse_proc_filename(file_name)
if cur_pid is None:
continue
if pid is not None and pid != cur_pid:
continue
if stat_type is not None and stat_type != cur_stat_type:
continue
del_list.append(cur_pid)
# Allow delete related exceptions to percolate up if this fails.
os.unlink(os.path.join(DEFAULT_PATH, file_name))
return del_list

View File

@@ -1,222 +0,0 @@
'''
@file term.py
@brief a better shutil.copytree replacement
$LicenseInfo:firstyear=2007&license=mit$
Copyright (c) 2007-2009, Linden Research, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
$/LicenseInfo$
'''
#http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/475116
import sys, re
class TerminalController:
"""
A class that can be used to portably generate formatted output to
a terminal.
`TerminalController` defines a set of instance variables whose
values are initialized to the control sequence necessary to
perform a given action. These can be simply included in normal
output to the terminal:
>>> term = TerminalController()
>>> print 'This is '+term.GREEN+'green'+term.NORMAL
Alternatively, the `render()` method can used, which replaces
'${action}' with the string required to perform 'action':
>>> term = TerminalController()
>>> print term.render('This is ${GREEN}green${NORMAL}')
If the terminal doesn't support a given action, then the value of
the corresponding instance variable will be set to ''. As a
result, the above code will still work on terminals that do not
support color, except that their output will not be colored.
Also, this means that you can test whether the terminal supports a
given action by simply testing the truth value of the
corresponding instance variable:
>>> term = TerminalController()
>>> if term.CLEAR_SCREEN:
... print 'This terminal supports clearning the screen.'
Finally, if the width and height of the terminal are known, then
they will be stored in the `COLS` and `LINES` attributes.
"""
# Cursor movement:
BOL = '' #: Move the cursor to the beginning of the line
UP = '' #: Move the cursor up one line
DOWN = '' #: Move the cursor down one line
LEFT = '' #: Move the cursor left one char
RIGHT = '' #: Move the cursor right one char
# Deletion:
CLEAR_SCREEN = '' #: Clear the screen and move to home position
CLEAR_EOL = '' #: Clear to the end of the line.
CLEAR_BOL = '' #: Clear to the beginning of the line.
CLEAR_EOS = '' #: Clear to the end of the screen
# Output modes:
BOLD = '' #: Turn on bold mode
BLINK = '' #: Turn on blink mode
DIM = '' #: Turn on half-bright mode
REVERSE = '' #: Turn on reverse-video mode
NORMAL = '' #: Turn off all modes
# Cursor display:
HIDE_CURSOR = '' #: Make the cursor invisible
SHOW_CURSOR = '' #: Make the cursor visible
# Terminal size:
COLS = None #: Width of the terminal (None for unknown)
LINES = None #: Height of the terminal (None for unknown)
# Foreground colors:
BLACK = BLUE = GREEN = CYAN = RED = MAGENTA = YELLOW = WHITE = ''
# Background colors:
BG_BLACK = BG_BLUE = BG_GREEN = BG_CYAN = ''
BG_RED = BG_MAGENTA = BG_YELLOW = BG_WHITE = ''
_STRING_CAPABILITIES = """
BOL=cr UP=cuu1 DOWN=cud1 LEFT=cub1 RIGHT=cuf1
CLEAR_SCREEN=clear CLEAR_EOL=el CLEAR_BOL=el1 CLEAR_EOS=ed BOLD=bold
BLINK=blink DIM=dim REVERSE=rev UNDERLINE=smul NORMAL=sgr0
HIDE_CURSOR=cinvis SHOW_CURSOR=cnorm""".split()
_COLORS = """BLACK BLUE GREEN CYAN RED MAGENTA YELLOW WHITE""".split()
_ANSICOLORS = "BLACK RED GREEN YELLOW BLUE MAGENTA CYAN WHITE".split()
def __init__(self, term_stream=sys.stdout):
"""
Create a `TerminalController` and initialize its attributes
with appropriate values for the current terminal.
`term_stream` is the stream that will be used for terminal
output; if this stream is not a tty, then the terminal is
assumed to be a dumb terminal (i.e., have no capabilities).
"""
# Curses isn't available on all platforms
try: import curses
except: return
# If the stream isn't a tty, then assume it has no capabilities.
if not term_stream.isatty(): return
# Check the terminal type. If we fail, then assume that the
# terminal has no capabilities.
try: curses.setupterm()
except: return
# Look up numeric capabilities.
self.COLS = curses.tigetnum('cols')
self.LINES = curses.tigetnum('lines')
# Look up string capabilities.
for capability in self._STRING_CAPABILITIES:
(attrib, cap_name) = capability.split('=')
setattr(self, attrib, self._tigetstr(cap_name) or '')
# Colors
set_fg = self._tigetstr('setf')
if set_fg:
for i,color in zip(range(len(self._COLORS)), self._COLORS):
setattr(self, color, curses.tparm(set_fg, i) or '')
set_fg_ansi = self._tigetstr('setaf')
if set_fg_ansi:
for i,color in zip(range(len(self._ANSICOLORS)), self._ANSICOLORS):
setattr(self, color, curses.tparm(set_fg_ansi, i) or '')
set_bg = self._tigetstr('setb')
if set_bg:
for i,color in zip(range(len(self._COLORS)), self._COLORS):
setattr(self, 'BG_'+color, curses.tparm(set_bg, i) or '')
set_bg_ansi = self._tigetstr('setab')
if set_bg_ansi:
for i,color in zip(range(len(self._ANSICOLORS)), self._ANSICOLORS):
setattr(self, 'BG_'+color, curses.tparm(set_bg_ansi, i) or '')
def _tigetstr(self, cap_name):
# String capabilities can include "delays" of the form "$<2>".
# For any modern terminal, we should be able to just ignore
# these, so strip them out.
import curses
cap = curses.tigetstr(cap_name) or ''
return re.sub(r'\$<\d+>[/*]?', '', cap)
def render(self, template):
"""
Replace each $-substitutions in the given template string with
the corresponding terminal control string (if it's defined) or
'' (if it's not).
"""
return re.sub(r'\$\$|\${\w+}', self._render_sub, template)
def _render_sub(self, match):
s = match.group()
if s == '$$': return s
else: return getattr(self, s[2:-1])
#######################################################################
# Example use case: progress bar
#######################################################################
class ProgressBar:
"""
A 3-line progress bar, which looks like::
Header
20% [===========----------------------------------]
progress message
The progress bar is colored, if the terminal supports color
output; and adjusts to the width of the terminal.
"""
BAR = '%3d%% ${GREEN}[${BOLD}%s%s${NORMAL}${GREEN}]${NORMAL}\n'
HEADER = '${BOLD}${CYAN}%s${NORMAL}\n\n'
def __init__(self, term, header):
self.term = term
if not (self.term.CLEAR_EOL and self.term.UP and self.term.BOL):
raise ValueError("Terminal isn't capable enough -- you "
"should use a simpler progress dispaly.")
self.width = self.term.COLS or 75
self.bar = term.render(self.BAR)
self.header = self.term.render(self.HEADER % header.center(self.width))
self.cleared = 1 #: true if we haven't drawn the bar yet.
self.update(0, '')
def update(self, percent, message):
if self.cleared:
sys.stdout.write(self.header)
self.cleared = 0
n = int((self.width-10)*percent)
sys.stdout.write(
self.term.BOL + self.term.UP + self.term.CLEAR_EOL +
(self.bar % (100*percent, '='*n, '-'*(self.width-10-n))) +
self.term.CLEAR_EOL + message.center(self.width))
def clear(self):
if not self.cleared:
sys.stdout.write(self.term.BOL + self.term.CLEAR_EOL +
self.term.UP + self.term.CLEAR_EOL +
self.term.UP + self.term.CLEAR_EOL)
self.cleared = 1

View File

@@ -1,508 +0,0 @@
#!/usr/bin/python
## $LicenseInfo:firstyear=2011&license=viewerlgpl$
## Second Life Viewer Source Code
## Copyright (C) 2011, Linden Research, Inc.
##
## This library is free software; you can redistribute it and/or
## modify it under the terms of the GNU Lesser General Public
## License as published by the Free Software Foundation;
## version 2.1 of the License only.
##
## This library is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
## Lesser General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public
## License along with this library; if not, write to the Free Software
## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
##
## Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
## $/LicenseInfo$
r"""UUID objects (universally unique identifiers) according to RFC 4122.
This module provides immutable UUID objects (class UUID) and the functions
uuid1(), uuid3(), uuid4(), uuid5() for generating version 1, 3, 4, and 5
UUIDs as specified in RFC 4122.
If all you want is a unique ID, you should probably call uuid1() or uuid4().
Note that uuid1() may compromise privacy since it creates a UUID containing
the computer's network address. uuid4() creates a random UUID.
Typical usage:
>>> import uuid
# make a UUID based on the host ID and current time
>>> uuid.uuid1()
UUID('a8098c1a-f86e-11da-bd1a-00112444be1e')
# make a UUID using an MD5 hash of a namespace UUID and a name
>>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org')
UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e')
# make a random UUID
>>> uuid.uuid4()
UUID('16fd2706-8baf-433b-82eb-8c7fada847da')
# make a UUID using a SHA-1 hash of a namespace UUID and a name
>>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org')
UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d')
# make a UUID from a string of hex digits (braces and hyphens ignored)
>>> x = uuid.UUID('{00010203-0405-0607-0809-0a0b0c0d0e0f}')
# convert a UUID to a string of hex digits in standard form
>>> str(x)
'00010203-0405-0607-0809-0a0b0c0d0e0f'
# get the raw 16 bytes of the UUID
>>> x.bytes
'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f'
# make a UUID from a 16-byte string
>>> uuid.UUID(bytes=x.bytes)
UUID('00010203-0405-0607-0809-0a0b0c0d0e0f')
This module works with Python 2.3 or higher."""
__author__ = 'Ka-Ping Yee <ping@zesty.ca>'
__date__ = '$Date: 2006/06/12 23:15:40 $'.split()[1].replace('/', '-')
__version__ = '$Revision: 1.30 $'.split()[1]
RESERVED_NCS, RFC_4122, RESERVED_MICROSOFT, RESERVED_FUTURE = [
'reserved for NCS compatibility', 'specified in RFC 4122',
'reserved for Microsoft compatibility', 'reserved for future definition']
class UUID(object):
"""Instances of the UUID class represent UUIDs as specified in RFC 4122.
UUID objects are immutable, hashable, and usable as dictionary keys.
Converting a UUID to a string with str() yields something in the form
'12345678-1234-1234-1234-123456789abc'. The UUID constructor accepts
four possible forms: a similar string of hexadecimal digits, or a
string of 16 raw bytes as an argument named 'bytes', or a tuple of
six integer fields (with 32-bit, 16-bit, 16-bit, 8-bit, 8-bit, and
48-bit values respectively) as an argument named 'fields', or a single
128-bit integer as an argument named 'int'.
UUIDs have these read-only attributes:
bytes the UUID as a 16-byte string
fields a tuple of the six integer fields of the UUID,
which are also available as six individual attributes
and two derived attributes:
time_low the first 32 bits of the UUID
time_mid the next 16 bits of the UUID
time_hi_version the next 16 bits of the UUID
clock_seq_hi_variant the next 8 bits of the UUID
clock_seq_low the next 8 bits of the UUID
node the last 48 bits of the UUID
time the 60-bit timestamp
clock_seq the 14-bit sequence number
hex the UUID as a 32-character hexadecimal string
int the UUID as a 128-bit integer
urn the UUID as a URN as specified in RFC 4122
variant the UUID variant (one of the constants RESERVED_NCS,
RFC_4122, RESERVED_MICROSOFT, or RESERVED_FUTURE)
version the UUID version number (1 through 5, meaningful only
when the variant is RFC_4122)
"""
def __init__(self, hex=None, bytes=None, fields=None, int=None,
version=None):
r"""Create a UUID from either a string of 32 hexadecimal digits,
a string of 16 bytes as the 'bytes' argument, a tuple of six
integers (32-bit time_low, 16-bit time_mid, 16-bit time_hi_version,
8-bit clock_seq_hi_variant, 8-bit clock_seq_low, 48-bit node) as
the 'fields' argument, or a single 128-bit integer as the 'int'
argument. When a string of hex digits is given, curly braces,
hyphens, and a URN prefix are all optional. For example, these
expressions all yield the same UUID:
UUID('{12345678-1234-5678-1234-567812345678}')
UUID('12345678123456781234567812345678')
UUID('urn:uuid:12345678-1234-5678-1234-567812345678')
UUID(bytes='\x12\x34\x56\x78'*4)
UUID(fields=(0x12345678, 0x1234, 0x5678, 0x12, 0x34, 0x567812345678))
UUID(int=0x12345678123456781234567812345678)
Exactly one of 'hex', 'bytes', 'fields', or 'int' must be given.
The 'version' argument is optional; if given, the resulting UUID
will have its variant and version number set according to RFC 4122,
overriding bits in the given 'hex', 'bytes', 'fields', or 'int'.
"""
if [hex, bytes, fields, int].count(None) != 3:
raise TypeError('need just one of hex, bytes, fields, or int')
if hex is not None:
hex = hex.replace('urn:', '').replace('uuid:', '')
hex = hex.strip('{}').replace('-', '')
if len(hex) != 32:
raise ValueError('badly formed hexadecimal UUID string')
int = long(hex, 16)
if bytes is not None:
if len(bytes) != 16:
raise ValueError('bytes is not a 16-char string')
int = long(('%02x'*16) % tuple(map(ord, bytes)), 16)
if fields is not None:
if len(fields) != 6:
raise ValueError('fields is not a 6-tuple')
(time_low, time_mid, time_hi_version,
clock_seq_hi_variant, clock_seq_low, node) = fields
if not 0 <= time_low < 1<<32L:
raise ValueError('field 1 out of range (need a 32-bit value)')
if not 0 <= time_mid < 1<<16L:
raise ValueError('field 2 out of range (need a 16-bit value)')
if not 0 <= time_hi_version < 1<<16L:
raise ValueError('field 3 out of range (need a 16-bit value)')
if not 0 <= clock_seq_hi_variant < 1<<8L:
raise ValueError('field 4 out of range (need an 8-bit value)')
if not 0 <= clock_seq_low < 1<<8L:
raise ValueError('field 5 out of range (need an 8-bit value)')
if not 0 <= node < 1<<48L:
raise ValueError('field 6 out of range (need a 48-bit value)')
clock_seq = (clock_seq_hi_variant << 8L) | clock_seq_low
int = ((time_low << 96L) | (time_mid << 80L) |
(time_hi_version << 64L) | (clock_seq << 48L) | node)
if int is not None:
if not 0 <= int < 1<<128L:
raise ValueError('int is out of range (need a 128-bit value)')
if version is not None:
if not 1 <= version <= 5:
raise ValueError('illegal version number')
# Set the variant to RFC 4122.
int &= ~(0xc000 << 48L)
int |= 0x8000 << 48L
# Set the version number.
int &= ~(0xf000 << 64L)
int |= version << 76L
self.__dict__['int'] = int
def __cmp__(self, other):
if isinstance(other, UUID):
return cmp(self.int, other.int)
return NotImplemented
def __hash__(self):
return hash(self.int)
def __int__(self):
return self.int
def __repr__(self):
return 'UUID(%r)' % str(self)
def __setattr__(self, name, value):
raise TypeError('UUID objects are immutable')
def __str__(self):
hex = '%032x' % self.int
return '%s-%s-%s-%s-%s' % (
hex[:8], hex[8:12], hex[12:16], hex[16:20], hex[20:])
def get_bytes(self):
bytes = ''
for shift in range(0, 128, 8):
bytes = chr((self.int >> shift) & 0xff) + bytes
return bytes
bytes = property(get_bytes)
def get_fields(self):
return (self.time_low, self.time_mid, self.time_hi_version,
self.clock_seq_hi_variant, self.clock_seq_low, self.node)
fields = property(get_fields)
def get_time_low(self):
return self.int >> 96L
time_low = property(get_time_low)
def get_time_mid(self):
return (self.int >> 80L) & 0xffff
time_mid = property(get_time_mid)
def get_time_hi_version(self):
return (self.int >> 64L) & 0xffff
time_hi_version = property(get_time_hi_version)
def get_clock_seq_hi_variant(self):
return (self.int >> 56L) & 0xff
clock_seq_hi_variant = property(get_clock_seq_hi_variant)
def get_clock_seq_low(self):
return (self.int >> 48L) & 0xff
clock_seq_low = property(get_clock_seq_low)
def get_time(self):
return (((self.time_hi_version & 0x0fffL) << 48L) |
(self.time_mid << 32L) | self.time_low)
time = property(get_time)
def get_clock_seq(self):
return (((self.clock_seq_hi_variant & 0x3fL) << 8L) |
self.clock_seq_low)
clock_seq = property(get_clock_seq)
def get_node(self):
return self.int & 0xffffffffffff
node = property(get_node)
def get_hex(self):
return '%032x' % self.int
hex = property(get_hex)
def get_urn(self):
return 'urn:uuid:' + str(self)
urn = property(get_urn)
def get_variant(self):
if not self.int & (0x8000 << 48L):
return RESERVED_NCS
elif not self.int & (0x4000 << 48L):
return RFC_4122
elif not self.int & (0x2000 << 48L):
return RESERVED_MICROSOFT
else:
return RESERVED_FUTURE
variant = property(get_variant)
def get_version(self):
# The version bits are only meaningful for RFC 4122 UUIDs.
if self.variant == RFC_4122:
return int((self.int >> 76L) & 0xf)
version = property(get_version)
def _ifconfig_getnode():
"""Get the hardware address on Unix by running ifconfig."""
import os
for dir in ['', '/sbin/', '/usr/sbin']:
try:
path = os.path.join(dir, 'ifconfig')
if os.path.exists(path):
pipe = os.popen(path)
else:
continue
except IOError:
continue
for line in pipe:
words = line.lower().split()
for i in range(len(words)):
if words[i] in ['hwaddr', 'ether']:
return int(words[i + 1].replace(':', ''), 16)
def _ipconfig_getnode():
"""Get the hardware address on Windows by running ipconfig.exe."""
import os, re
dirs = ['', r'c:\windows\system32', r'c:\winnt\system32']
try:
import ctypes
buffer = ctypes.create_string_buffer(300)
ctypes.windll.kernel32.GetSystemDirectoryA(buffer, 300)
dirs.insert(0, buffer.value.decode('mbcs'))
except:
pass
for dir in dirs:
try:
pipe = os.popen(os.path.join(dir, 'ipconfig') + ' /all')
except IOError:
continue
for line in pipe:
value = line.split(':')[-1].strip().lower()
if re.match('([0-9a-f][0-9a-f]-){5}[0-9a-f][0-9a-f]', value):
return int(value.replace('-', ''), 16)
def _netbios_getnode():
"""Get the hardware address on Windows using NetBIOS calls.
See http://support.microsoft.com/kb/118623 for details."""
import win32wnet, netbios
ncb = netbios.NCB()
ncb.Command = netbios.NCBENUM
ncb.Buffer = adapters = netbios.LANA_ENUM()
adapters._pack()
if win32wnet.Netbios(ncb) != 0:
return
adapters._unpack()
for i in range(adapters.length):
ncb.Reset()
ncb.Command = netbios.NCBRESET
ncb.Lana_num = ord(adapters.lana[i])
if win32wnet.Netbios(ncb) != 0:
continue
ncb.Reset()
ncb.Command = netbios.NCBASTAT
ncb.Lana_num = ord(adapters.lana[i])
ncb.Callname = '*'.ljust(16)
ncb.Buffer = status = netbios.ADAPTER_STATUS()
if win32wnet.Netbios(ncb) != 0:
continue
status._unpack()
bytes = map(ord, status.adapter_address)
return ((bytes[0]<<40L) + (bytes[1]<<32L) + (bytes[2]<<24L) +
(bytes[3]<<16L) + (bytes[4]<<8L) + bytes[5])
# Thanks to Thomas Heller for ctypes and for his help with its use here.
# If ctypes is available, use it to find system routines for UUID generation.
_uuid_generate_random = _uuid_generate_time = _UuidCreate = None
try:
import ctypes, ctypes.util
_buffer = ctypes.create_string_buffer(16)
# The uuid_generate_* routines are provided by libuuid on at least
# Linux and FreeBSD, and provided by libc on Mac OS X.
for libname in ['uuid', 'c']:
try:
lib = ctypes.CDLL(ctypes.util.find_library(libname))
except:
continue
if hasattr(lib, 'uuid_generate_random'):
_uuid_generate_random = lib.uuid_generate_random
if hasattr(lib, 'uuid_generate_time'):
_uuid_generate_time = lib.uuid_generate_time
# On Windows prior to 2000, UuidCreate gives a UUID containing the
# hardware address. On Windows 2000 and later, UuidCreate makes a
# random UUID and UuidCreateSequential gives a UUID containing the
# hardware address. These routines are provided by the RPC runtime.
try:
lib = ctypes.windll.rpcrt4
except:
lib = None
_UuidCreate = getattr(lib, 'UuidCreateSequential',
getattr(lib, 'UuidCreate', None))
except:
pass
def _unixdll_getnode():
"""Get the hardware address on Unix using ctypes."""
_uuid_generate_time(_buffer)
return UUID(bytes=_buffer.raw).node
def _windll_getnode():
"""Get the hardware address on Windows using ctypes."""
if _UuidCreate(_buffer) == 0:
return UUID(bytes=_buffer.raw).node
def _random_getnode():
"""Get a random node ID, with eighth bit set as suggested by RFC 4122."""
import random
return random.randrange(0, 1<<48L) | 0x010000000000L
_node = None
def getnode():
"""Get the hardware address as a 48-bit integer. The first time this
runs, it may launch a separate program, which could be quite slow. If
all attempts to obtain the hardware address fail, we choose a random
48-bit number with its eighth bit set to 1 as recommended in RFC 4122."""
global _node
if _node is not None:
return _node
import sys
if sys.platform == 'win32':
getters = [_windll_getnode, _netbios_getnode, _ipconfig_getnode]
else:
getters = [_unixdll_getnode, _ifconfig_getnode]
for getter in getters + [_random_getnode]:
try:
_node = getter()
except:
continue
if _node is not None:
return _node
def uuid1(node=None, clock_seq=None):
"""Generate a UUID from a host ID, sequence number, and the current time.
If 'node' is not given, getnode() is used to obtain the hardware
address. If 'clock_seq' is given, it is used as the sequence number;
otherwise a random 14-bit sequence number is chosen."""
# When the system provides a version-1 UUID generator, use it (but don't
# use UuidCreate here because its UUIDs don't conform to RFC 4122).
if _uuid_generate_time and node is clock_seq is None:
_uuid_generate_time(_buffer)
return UUID(bytes=_buffer.raw)
import time
nanoseconds = int(time.time() * 1e9)
# 0x01b21dd213814000 is the number of 100-ns intervals between the
# UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00.
timestamp = int(nanoseconds/100) + 0x01b21dd213814000L
if clock_seq is None:
import random
clock_seq = random.randrange(1<<14L) # instead of stable storage
time_low = timestamp & 0xffffffffL
time_mid = (timestamp >> 32L) & 0xffffL
time_hi_version = (timestamp >> 48L) & 0x0fffL
clock_seq_low = clock_seq & 0xffL
clock_seq_hi_variant = (clock_seq >> 8L) & 0x3fL
if node is None:
node = getnode()
return UUID(fields=(time_low, time_mid, time_hi_version,
clock_seq_hi_variant, clock_seq_low, node), version=1)
def uuid3(namespace, name):
"""Generate a UUID from the MD5 hash of a namespace UUID and a name."""
try:
# Python 2.6
from hashlib import md5
except ImportError:
# Python 2.5 and earlier
from md5 import new as md5
hash = md5(namespace.bytes + name).digest()
return UUID(bytes=hash[:16], version=3)
def uuid4():
"""Generate a random UUID."""
# When the system provides a version-4 UUID generator, use it.
if _uuid_generate_random:
_uuid_generate_random(_buffer)
return UUID(bytes=_buffer.raw)
# Otherwise, get randomness from urandom or the 'random' module.
try:
import os
return UUID(bytes=os.urandom(16), version=4)
except:
import random
bytes = [chr(random.randrange(256)) for i in range(16)]
return UUID(bytes=bytes, version=4)
def uuid5(namespace, name):
"""Generate a UUID from the SHA-1 hash of a namespace UUID and a name."""
import sha
hash = sha.sha(namespace.bytes + name).digest()
return UUID(bytes=hash[:16], version=5)
# The following standard UUIDs are for use with uuid3() or uuid5().
NAMESPACE_DNS = UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
NAMESPACE_URL = UUID('6ba7b811-9dad-11d1-80b4-00c04fd430c8')
NAMESPACE_OID = UUID('6ba7b812-9dad-11d1-80b4-00c04fd430c8')
NAMESPACE_X500 = UUID('6ba7b814-9dad-11d1-80b4-00c04fd430c8')

View File

@@ -436,7 +436,7 @@ public:
} }
~MyMicroAllocator(void) virtual ~MyMicroAllocator()
{ {
if ( mMicroChunks ) if ( mMicroChunks )
{ {
@@ -746,7 +746,7 @@ public:
mMicro = createMicroAllocator(this,defaultChunkSize); mMicro = createMicroAllocator(this,defaultChunkSize);
} }
~MyHeapManager(void) virtual ~MyHeapManager()
{ {
releaseMicroAllocator(mMicro); releaseMicroAllocator(mMicro);
} }

View File

@@ -902,7 +902,7 @@ bool LLAudioBufferFMODSTUDIO::loadWAV(const std::string& filename)
} }
FMOD_MODE base_mode = FMOD_LOOP_NORMAL; FMOD_MODE base_mode = FMOD_LOOP_NORMAL;
FMOD_CREATESOUNDEXINFO exinfo = {0}; FMOD_CREATESOUNDEXINFO exinfo = { };
exinfo.cbsize = sizeof(exinfo); exinfo.cbsize = sizeof(exinfo);
exinfo.suggestedsoundtype = FMOD_SOUND_TYPE_WAV; //Hint to speed up loading. exinfo.suggestedsoundtype = FMOD_SOUND_TYPE_WAV; //Hint to speed up loading.
// Load up the wav file into an fmod sample // Load up the wav file into an fmod sample

View File

@@ -143,7 +143,7 @@ LLStreamingAudio_FMODSTUDIO::LLStreamingAudio_FMODSTUDIO(FMOD::System *system) :
Check_FMOD_Error(system->createChannelGroup("stream", &mStreamGroup), "FMOD::System::createChannelGroup"); Check_FMOD_Error(system->createChannelGroup("stream", &mStreamGroup), "FMOD::System::createChannelGroup");
FMOD_DSP_DESCRIPTION dspdesc = {0}; FMOD_DSP_DESCRIPTION dspdesc = { };
dspdesc.pluginsdkversion = FMOD_PLUGIN_SDK_VERSION; dspdesc.pluginsdkversion = FMOD_PLUGIN_SDK_VERSION;
strncpy(dspdesc.name, "Waveform", sizeof(dspdesc.name)); strncpy(dspdesc.name, "Waveform", sizeof(dspdesc.name));
dspdesc.numoutputbuffers = 1; dspdesc.numoutputbuffers = 1;
@@ -632,7 +632,7 @@ FMOD_RESULT LLAudioStreamManagerFMODSTUDIO::getOpenState(FMOD_OPENSTATE& state,
void LLStreamingAudio_FMODSTUDIO::setBufferSizes(U32 streambuffertime, U32 decodebuffertime) void LLStreamingAudio_FMODSTUDIO::setBufferSizes(U32 streambuffertime, U32 decodebuffertime)
{ {
Check_FMOD_Error(mSystem->setStreamBufferSize(streambuffertime / 1000 * 128 * 128, FMOD_TIMEUNIT_RAWBYTES), "FMOD::System::setStreamBufferSize"); Check_FMOD_Error(mSystem->setStreamBufferSize(streambuffertime / 1000 * 128 * 128, FMOD_TIMEUNIT_RAWBYTES), "FMOD::System::setStreamBufferSize");
FMOD_ADVANCEDSETTINGS settings = {0}; FMOD_ADVANCEDSETTINGS settings = { };
settings.cbSize=sizeof(settings); settings.cbSize=sizeof(settings);
settings.defaultDecodeBufferSize = decodebuffertime;//ms settings.defaultDecodeBufferSize = decodebuffertime;//ms
Check_FMOD_Error(mSystem->setAdvancedSettings(&settings), "FMOD::System::setAdvancedSettings"); Check_FMOD_Error(mSystem->setAdvancedSettings(&settings), "FMOD::System::setAdvancedSettings");

View File

@@ -72,7 +72,7 @@ const int LL_ERR_NOERR = 0;
#endif // !_DEBUG #endif // !_DEBUG
static const std::string liru_assert_strip(const std::string& file) { return file.substr(1+file.substr(0, file.find_last_of("/\\")).find_last_of("/\\")); } //return foo/bar.cpp or perhaps foo\bar.cpp inline const std::string liru_assert_strip(const std::string& file) { return file.substr(1+file.substr(0, file.find_last_of("/\\")).find_last_of("/\\")); } //return foo/bar.cpp or perhaps foo\bar.cpp
#define llassert_always_msg(func, msg) if (LL_UNLIKELY(!(func))) LL_ERRS() << "ASSERT (" << msg << ")\nfile:" << liru_assert_strip(__FILE__) << " line:" << std::dec << __LINE__ << LL_ENDL #define llassert_always_msg(func, msg) if (LL_UNLIKELY(!(func))) LL_ERRS() << "ASSERT (" << msg << ")\nfile:" << liru_assert_strip(__FILE__) << " line:" << std::dec << __LINE__ << LL_ENDL

View File

@@ -28,7 +28,7 @@
#ifndef LL_LLINSTANCETRACKER_H #ifndef LL_LLINSTANCETRACKER_H
#define LL_LLINSTANCETRACKER_H #define LL_LLINSTANCETRACKER_H
#include <map> #include <boost/unordered_map.hpp>
#include <typeinfo> #include <typeinfo>
#include "llstringtable.h" #include "llstringtable.h"
@@ -89,8 +89,7 @@ template<typename T, typename KEY = T*>
class LLInstanceTracker : public LLInstanceTrackerBase class LLInstanceTracker : public LLInstanceTrackerBase
{ {
typedef LLInstanceTracker<T, KEY> MyT; typedef LLInstanceTracker<T, KEY> MyT;
typedef typename std::map<KEY, T*> InstanceMap; typedef typename boost::unordered_map<KEY, T*> InstanceMap;
typedef typename InstanceMap::iterator::difference_type difference_type;
struct StaticData: public StaticBase struct StaticData: public StaticBase
{ {
InstanceMap sMap; InstanceMap sMap;
@@ -121,10 +120,6 @@ public:
void increment() { mIterator++; } void increment() { mIterator++; }
void decrement() { --mIterator; } void decrement() { --mIterator; }
difference_type distance_to(instance_iter const& other) const
{
return std::distance(mIterator, other.mIterator);
}
bool equal(instance_iter const& other) const bool equal(instance_iter const& other) const
{ {
return mIterator == other.mIterator; return mIterator == other.mIterator;
@@ -166,10 +161,6 @@ public:
void increment() { mIterator++; } void increment() { mIterator++; }
void decrement() { --mIterator; } void decrement() { --mIterator; }
difference_type distance_to(instance_iter const& other) const
{
return std::distance(mIterator, other.mIterator);
}
bool equal(key_iter const& other) const bool equal(key_iter const& other) const
{ {
return mIterator == other.mIterator; return mIterator == other.mIterator;

View File

@@ -144,6 +144,11 @@ LL_COMMON_API std::string llsd_matches(const LLSD& prototype, const LLSD& data,
/// is_approx_equal_fraction(). /// is_approx_equal_fraction().
LL_COMMON_API bool llsd_equals(const LLSD& lhs, const LLSD& rhs, int bits=-1); LL_COMMON_API bool llsd_equals(const LLSD& lhs, const LLSD& rhs, int bits=-1);
inline bool operator==(const LLSD& lhs, const LLSD& rhs)
{
return llsd_equals(lhs, rhs, 8);
}
// Simple function to copy data out of input & output iterators if // Simple function to copy data out of input & output iterators if
// there is no need for casting. // there is no need for casting.
template<typename Input> LLSD llsd_copy_array(Input iter, Input end) template<typename Input> LLSD llsd_copy_array(Input iter, Input end)

View File

@@ -809,7 +809,7 @@ wchar_t* ll_convert_string_to_wide(const std::string& in, unsigned int code_page
w_out[real_output_str_len] = 0; w_out[real_output_str_len] = 0;
return w_out; return w_out;
return {&w_out[0]}; // return {&w_out[0]};
} }
S32 wchartchars_to_llwchar(const std::wstring::value_type* inchars, llwchar* outchar) S32 wchartchars_to_llwchar(const std::wstring::value_type* inchars, llwchar* outchar)

View File

@@ -271,7 +271,7 @@ inline U32 LLUUID::getCRC32() const
// </alchemy> // </alchemy>
} }
static_assert(std::is_trivially_copyable<LLUUID>{}, "LLUUID must be a trivially copyable type"); static_assert(std::is_trivially_copyable<LLUUID>::value, "LLUUID must be a trivially copyable type");
typedef std::vector<LLUUID> uuid_vec_t; typedef std::vector<LLUUID> uuid_vec_t;
typedef boost::unordered_set<LLUUID> uuid_set_t; typedef boost::unordered_set<LLUUID> uuid_set_t;

View File

@@ -108,4 +108,16 @@ typedef U8 LLPCode;
#define LL_ARRAY_SIZE( _kArray ) ( sizeof( (_kArray) ) / sizeof( _kArray[0] ) ) #define LL_ARRAY_SIZE( _kArray ) ( sizeof( (_kArray) ) / sizeof( _kArray[0] ) )
#if __GNUG__ && __GNUC__ < 5
namespace std
{
template<typename T>
struct is_trivially_copyable
{
static const bool value = __has_trivial_copy(T);
operator bool() { return value; }
};
}
#endif
#endif #endif

View File

@@ -719,9 +719,9 @@ LLSD LLSettingsSky::defaults(const LLSettingsBase::TrackPosition& position)
moonquat = convert_azimuth_and_altitude_to_quat(altitude + (F_PI * 0.125f), azimuth + (F_PI * 0.125f)); moonquat = convert_azimuth_and_altitude_to_quat(altitude + (F_PI * 0.125f), azimuth + (F_PI * 0.125f));
// Magic constants copied form dfltsetting.xml // Magic constants copied form dfltsetting.xml
dfltsetting[SETTING_CLOUD_COLOR] = LLColor4(0.4099, 0.4099, 0.4099, 0.0).getValue(); dfltsetting[SETTING_CLOUD_COLOR] = LLColor4(0.4099f, 0.4099f, 0.4099f, 0.0f).getValue();
dfltsetting[SETTING_CLOUD_POS_DENSITY1] = LLColor4(1.0000, 0.5260, 1.0000, 0.0).getValue(); dfltsetting[SETTING_CLOUD_POS_DENSITY1] = LLColor4(1.0000f, 0.5260f, 1.0000f, 0.0f).getValue();
dfltsetting[SETTING_CLOUD_POS_DENSITY2] = LLColor4(1.0000, 0.5260, 1.0000, 0.0).getValue(); dfltsetting[SETTING_CLOUD_POS_DENSITY2] = LLColor4(1.0000f, 0.5260f, 1.0000f, 0.0f).getValue();
dfltsetting[SETTING_CLOUD_SCALE] = LLSD::Real(0.4199); dfltsetting[SETTING_CLOUD_SCALE] = LLSD::Real(0.4199);
dfltsetting[SETTING_CLOUD_SCROLL_RATE] = LLSDArray(0.0f)(0.0f); dfltsetting[SETTING_CLOUD_SCROLL_RATE] = LLSDArray(0.0f)(0.0f);
dfltsetting[SETTING_CLOUD_SHADOW] = LLSD::Real(0.2699); dfltsetting[SETTING_CLOUD_SHADOW] = LLSD::Real(0.2699);
@@ -730,14 +730,14 @@ LLSD LLSettingsSky::defaults(const LLSettingsBase::TrackPosition& position)
dfltsetting[SETTING_DOME_OFFSET] = LLSD::Real(0.96f); dfltsetting[SETTING_DOME_OFFSET] = LLSD::Real(0.96f);
dfltsetting[SETTING_DOME_RADIUS] = LLSD::Real(15000.f); dfltsetting[SETTING_DOME_RADIUS] = LLSD::Real(15000.f);
dfltsetting[SETTING_GAMMA] = LLSD::Real(1.0); dfltsetting[SETTING_GAMMA] = LLSD::Real(1.0);
dfltsetting[SETTING_GLOW] = LLColor4(5.000, 0.0010, -0.4799, 1.0).getValue(); dfltsetting[SETTING_GLOW] = LLColor4(5.000f, 0.0010f, -0.4799f, 1.0f).getValue();
dfltsetting[SETTING_MAX_Y] = LLSD::Real(1605); dfltsetting[SETTING_MAX_Y] = LLSD::Real(1605);
dfltsetting[SETTING_MOON_ROTATION] = moonquat.getValue(); dfltsetting[SETTING_MOON_ROTATION] = moonquat.getValue();
dfltsetting[SETTING_MOON_BRIGHTNESS] = LLSD::Real(0.5f); dfltsetting[SETTING_MOON_BRIGHTNESS] = LLSD::Real(0.5f);
dfltsetting[SETTING_STAR_BRIGHTNESS] = LLSD::Real(256.0000); dfltsetting[SETTING_STAR_BRIGHTNESS] = LLSD::Real(256.0000);
dfltsetting[SETTING_SUNLIGHT_COLOR] = LLColor4(0.7342, 0.7815, 0.8999, 0.0).getValue(); dfltsetting[SETTING_SUNLIGHT_COLOR] = LLColor4(0.7342f, 0.7815f, 0.8999f, 0.0f).getValue();
dfltsetting[SETTING_SUN_ROTATION] = sunquat.getValue(); dfltsetting[SETTING_SUN_ROTATION] = sunquat.getValue();
dfltsetting[SETTING_BLOOM_TEXTUREID] = GetDefaultBloomTextureId(); dfltsetting[SETTING_BLOOM_TEXTUREID] = GetDefaultBloomTextureId();

View File

@@ -127,6 +127,6 @@ public:
inline bool isOkRotation() const; inline bool isOkRotation() const;
} LL_ALIGN_POSTFIX(16); } LL_ALIGN_POSTFIX(16);
static_assert(std::is_trivially_copyable<LLMatrix3a>{}, "LLMatrix3a must be a trivially copyable type"); static_assert(std::is_trivially_copyable<LLMatrix3a>::value, "LLMatrix3a must be a trivially copyable type");
static_assert(std::is_trivially_copyable<LLRotation>{}, "LLRotation must be a trivially copyable type"); static_assert(std::is_trivially_copyable<LLRotation>::value, "LLRotation must be a trivially copyable type");
#endif #endif

View File

@@ -709,5 +709,5 @@ inline std::ostream& operator<<(std::ostream& s, const LLMatrix4a& m)
void matMulBoundBox(const LLMatrix4a &a, const LLVector4a *in_extents, LLVector4a *out_extents); void matMulBoundBox(const LLMatrix4a &a, const LLVector4a *in_extents, LLVector4a *out_extents);
static_assert(std::is_trivially_copyable<LLMatrix4a>{}, "LLMatrix4a must be a trivially copyable type"); static_assert(std::is_trivially_copyable<LLMatrix4a>::value, "LLMatrix4a must be a trivially copyable type");
#endif #endif

View File

@@ -191,7 +191,7 @@ inline void LLQuaternion::setValue(const LLSD& sd)
mQ[3] = sd[3].asReal(); mQ[3] = sd[3].asReal();
} }
static_assert(std::is_trivially_copyable<LLQuaternion>{}, "LLQuaternion must be a trivially copyable type"); static_assert(std::is_trivially_copyable<LLQuaternion>::value, "LLQuaternion must be a trivially copyable type");
// checker // checker
inline BOOL LLQuaternion::isFinite() const inline BOOL LLQuaternion::isFinite() const

View File

@@ -105,6 +105,6 @@ protected:
} LL_ALIGN_POSTFIX(16); } LL_ALIGN_POSTFIX(16);
static_assert(std::is_trivially_copyable<LLQuaternion2>{}, "LLQuaternion2 must be a trivially copyable type"); static_assert(std::is_trivially_copyable<LLQuaternion2>::value, "LLQuaternion2 must be a trivially copyable type");
#endif #endif

View File

@@ -121,7 +121,7 @@ private:
LLQuad mQ; LLQuad mQ;
}; };
static_assert(std::is_trivially_copyable<LLBool32>{}, "LLBool32 must be a trivially copyable type"); static_assert(std::is_trivially_copyable<LLBool32>::value, "LLBool32 must be a trivially copyable type");
static_assert(std::is_trivially_copyable<LLSimdScalar>{}, "LLSimdScalar must be a trivially copyable type"); static_assert(std::is_trivially_copyable<LLSimdScalar>::value, "LLSimdScalar must be a trivially copyable type");
#endif //LL_SIMD_TYPES_H #endif //LL_SIMD_TYPES_H

View File

@@ -346,5 +346,5 @@ inline std::ostream& operator<<(std::ostream& s, const LLVector4a& v)
return s; return s;
} }
static_assert(std::is_trivially_copyable<LLVector4a>{}, "LLVector4a must be a trivially copyable type"); static_assert(std::is_trivially_copyable<LLVector4a>::value, "LLVector4a must be a trivially copyable type");
#endif #endif

View File

@@ -144,7 +144,7 @@ class LLMatrix3
friend std::ostream& operator<<(std::ostream& s, const LLMatrix3 &a); // Stream a friend std::ostream& operator<<(std::ostream& s, const LLMatrix3 &a); // Stream a
}; };
static_assert(std::is_trivially_copyable<LLMatrix3>{}, "LLMatrix3 must be a trivially copyable type"); static_assert(std::is_trivially_copyable<LLMatrix3>::value, "LLMatrix3 must be a trivially copyable type");
inline LLMatrix3::LLMatrix3(void) inline LLMatrix3::LLMatrix3(void)
{ {

View File

@@ -246,7 +246,7 @@ public:
friend std::ostream& operator<<(std::ostream& s, const LLMatrix4 &a); // Stream a friend std::ostream& operator<<(std::ostream& s, const LLMatrix4 &a); // Stream a
}; };
static_assert(std::is_trivially_copyable<LLMatrix4>{}, "LLMatrix4 must be a trivially copyable type"); static_assert(std::is_trivially_copyable<LLMatrix4>::value, "LLMatrix4 must be a trivially copyable type");
inline const LLMatrix4& LLMatrix4::setIdentity() inline const LLMatrix4& LLMatrix4::setIdentity()
{ {

View File

@@ -110,7 +110,7 @@ class LLVector2
friend std::ostream& operator<<(std::ostream& s, const LLVector2 &a); // Stream a friend std::ostream& operator<<(std::ostream& s, const LLVector2 &a); // Stream a
}; };
static_assert(std::is_trivially_copyable<LLVector2>{}, "LLVector2 must be a trivially copyable type"); static_assert(std::is_trivially_copyable<LLVector2>::value, "LLVector2 must be a trivially copyable type");
// Non-member functions // Non-member functions

View File

@@ -140,7 +140,7 @@ public:
inline void exp(); // Do an exponential on the color inline void exp(); // Do an exponential on the color
}; };
static_assert(std::is_trivially_copyable<LLColor3>{}, "LLColor3 must be a trivially copyable type"); static_assert(std::is_trivially_copyable<LLColor3>::value, "LLColor3 must be a trivially copyable type");
LLColor3 lerp(const LLColor3 &a, const LLColor3 &b, F32 u); LLColor3 lerp(const LLColor3 &a, const LLColor3 &b, F32 u);

View File

@@ -130,7 +130,7 @@ class LLVector3d
}; };
static_assert(std::is_trivially_copyable<LLVector3d>{}, "LLVector3d must be a trivially copyable type"); static_assert(std::is_trivially_copyable<LLVector3d>::value, "LLVector3d must be a trivially copyable type");
typedef LLVector3d LLGlobalVec; typedef LLVector3d LLGlobalVec;

View File

@@ -149,7 +149,7 @@ class LLVector3
static BOOL parseVector3(const std::string& buf, LLVector3* value); static BOOL parseVector3(const std::string& buf, LLVector3* value);
}; };
static_assert(std::is_trivially_copyable<LLVector3>{}, "LLVector3 must be a trivially copyable type"); static_assert(std::is_trivially_copyable<LLVector3>::value, "LLVector3 must be a trivially copyable type");
typedef LLVector3 LLSimLocalVec; typedef LLVector3 LLSimLocalVec;

View File

@@ -222,7 +222,7 @@ class LLColor4
inline void clamp(); inline void clamp();
}; };
static_assert(std::is_trivially_copyable<LLColor4>{}, "LLColor4 must be a trivially copyable type"); static_assert(std::is_trivially_copyable<LLColor4>::value, "LLColor4 must be a trivially copyable type");
// Non-member functions // Non-member functions
F32 distVec(const LLColor4 &a, const LLColor4 &b); // Returns distance between a and b F32 distVec(const LLColor4 &a, const LLColor4 &b); // Returns distance between a and b

View File

@@ -139,7 +139,7 @@ public:
static LLColor4U blue; static LLColor4U blue;
}; };
static_assert(std::is_trivially_copyable<LLColor4U>{}, "LLColor4U must be a trivially copyable type"); static_assert(std::is_trivially_copyable<LLColor4U>::value, "LLColor4U must be a trivially copyable type");
// Non-member functions // Non-member functions
F32 distVec(const LLColor4U &a, const LLColor4U &b); // Returns distance between a and b F32 distVec(const LLColor4U &a, const LLColor4U &b); // Returns distance between a and b

View File

@@ -137,7 +137,7 @@ class LLVector4
friend LLVector4 operator-(const LLVector4 &a); // Return vector -a friend LLVector4 operator-(const LLVector4 &a); // Return vector -a
}; };
static_assert(std::is_trivially_copyable<LLVector4>{}, "LLVector4 must be a trivially copyable type"); static_assert(std::is_trivially_copyable<LLVector4>::value, "LLVector4 must be a trivially copyable type");
// Non-member functions // Non-member functions
F32 angle_between(const LLVector4 &a, const LLVector4 &b); // Returns angle (radians) between a and b F32 angle_between(const LLVector4 &a, const LLVector4 &b); // Returns angle (radians) between a and b

View File

@@ -32,6 +32,8 @@
#include "llstl.h" #include "llstl.h"
#include "llindexedvector.h" #include "llindexedvector.h"
#include <unordered_map>
extern U32 sMsgDataAllocSize; extern U32 sMsgDataAllocSize;
extern U32 sMsgdataAllocCount; extern U32 sMsgdataAllocCount;
class LLMsgVarData class LLMsgVarData
@@ -131,7 +133,7 @@ public:
void addDataFast(char *blockname, char *varname, const void *data, S32 size, EMsgVariableType type, S32 data_size = -1); void addDataFast(char *blockname, char *varname, const void *data, S32 size, EMsgVariableType type, S32 data_size = -1);
public: public:
typedef LLIndexedVector<LLMsgBlkData*, char*> msg_blk_data_map_t; typedef std::unordered_map<char*, LLMsgBlkData*> msg_blk_data_map_t;
msg_blk_data_map_t mMemberBlocks; msg_blk_data_map_t mMemberBlocks;
char *mName; char *mName;
S32 mTotalSize; S32 mTotalSize;

View File

@@ -182,7 +182,7 @@ const U32 ESTATE_ACCESS_MANAGER_ADD = 1 << 8;
const U32 ESTATE_ACCESS_MANAGER_REMOVE = 1 << 9; const U32 ESTATE_ACCESS_MANAGER_REMOVE = 1 << 9;
const U32 ESTATE_ACCESS_NO_REPLY = 1 << 10; const U32 ESTATE_ACCESS_NO_REPLY = 1 << 10;
const S32 ESTATE_MAX_MANAGERS = 10; const S32 ESTATE_MAX_MANAGERS = 15;
const S32 ESTATE_MAX_ACCESS_IDS = 500; // max for access, banned const S32 ESTATE_MAX_ACCESS_IDS = 500; // max for access, banned
const S32 ESTATE_MAX_GROUP_IDS = (S32) ESTATE_ACCESS_MAX_ENTRIES_PER_PACKET; const S32 ESTATE_MAX_GROUP_IDS = (S32) ESTATE_ACCESS_MAX_ENTRIES_PER_PACKET;

View File

@@ -73,7 +73,7 @@ private:
} ; } ;
static_assert(sizeof(LLMaterialID) == MATERIAL_ID_SIZE, "LLMaterialID must be sizeof(mID)"); static_assert(sizeof(LLMaterialID) == MATERIAL_ID_SIZE, "LLMaterialID must be sizeof(mID)");
static_assert(std::is_trivially_copyable<LLMaterialID>{}, "LLMaterialID must be a trivially copyable type"); static_assert(std::is_trivially_copyable<LLMaterialID>::value, "LLMaterialID must be a trivially copyable type");
#endif // LL_LLMATERIALID_H #endif // LL_LLMATERIALID_H

View File

@@ -5264,30 +5264,30 @@ void LLPieMenu::draw()
mHoverIndex = -1; mHoverIndex = -1;
} }
F32 width = (F32) getRect().getWidth(); const auto& rect = getRect();
F32 height = (F32) getRect().getHeight(); // correct for non-square pixels
mCurRadius = PIE_SCALE_FACTOR * llmax( width/2, height/2 ); F32 center_x = ((F32) rect.getWidth())/2;
F32 center_y = ((F32) rect.getHeight())/2;
constexpr S32 steps = 100;
mCurRadius = PIE_SCALE_FACTOR * llmax(center_x, center_y);
mOuterRingAlpha = mUseInfiniteRadius ? 0.f : 1.f; mOuterRingAlpha = mUseInfiniteRadius ? 0.f : 1.f;
if (mShrinkBorderTimer.getStarted()) if (mShrinkBorderTimer.getStarted())
{ {
mOuterRingAlpha = clamp_rescale(mShrinkBorderTimer.getElapsedTimeF32(), 0.f, PIE_SHRINK_TIME, 0.f, 1.f); const auto& elapsed = mShrinkBorderTimer.getElapsedTimeF32();
mCurRadius *= clamp_rescale(mShrinkBorderTimer.getElapsedTimeF32(), 0.f, PIE_SHRINK_TIME, 1.f, 1.f / PIE_SCALE_FACTOR); mOuterRingAlpha = clamp_rescale(elapsed, 0.f, PIE_SHRINK_TIME, 0.f, 1.f);
mCurRadius *= clamp_rescale(elapsed, 0.f, PIE_SHRINK_TIME, 1.f, 1.f / PIE_SCALE_FACTOR);
} }
// correct for non-square pixels
F32 center_x = width/2;
F32 center_y = height/2;
S32 steps = 100;
gGL.pushUIMatrix(); gGL.pushUIMatrix();
{ {
gGL.translateUI(center_x, center_y, 0.f); gGL.translateUI(center_x, center_y, 0.f);
F32 line_width = LLUI::sConfigGroup->getF32("PieMenuLineWidth"); static const LLUICachedControl<F32> line_width("PieMenuLineWidth");
LLColor4 line_color = LLUI::sColorsGroup->getColor("PieMenuLineColor"); static const LLCachedControl<LLColor4> line_color(*LLUI::sColorsGroup, "PieMenuLineColor");
LLColor4 bg_color = LLUI::sColorsGroup->getColor("PieMenuBgColor"); static const LLCachedControl<LLColor4> bg_color(*LLUI::sColorsGroup, "PieMenuBgColor");
LLColor4 selected_color = LLUI::sColorsGroup->getColor("PieMenuSelectedColor"); static const LLCachedControl<LLColor4> selected_color(*LLUI::sColorsGroup, "PieMenuSelectedColor");
// main body // main body
LLColor4 outer_color = bg_color; LLColor4 outer_color = bg_color;
@@ -5297,7 +5297,7 @@ void LLPieMenu::draw()
// selected wedge // selected wedge
if (mHoverItem) if (mHoverItem)
{ {
F32 arc_size = F_PI * 0.25f; constexpr F32 arc_size = F_PI * 0.25f;
F32 start_radians = (mHoverIndex * arc_size) - (arc_size * 0.5f); F32 start_radians = (mHoverIndex * arc_size) - (arc_size * 0.5f);
F32 end_radians = start_radians + arc_size; F32 end_radians = start_radians + arc_size;
@@ -5315,7 +5315,7 @@ void LLPieMenu::draw()
gl_washer_spokes_2d( mCurRadius, (F32)PIE_CENTER_SIZE, 8, line_color, outer_color ); gl_washer_spokes_2d( mCurRadius, (F32)PIE_CENTER_SIZE, 8, line_color, outer_color );
// inner circle // inner circle
gGL.color4fv( line_color.mV ); gGL.color4fv( line_color().mV );
gl_circle_2d( 0, 0, (F32)PIE_CENTER_SIZE, steps, FALSE ); gl_circle_2d( 0, 0, (F32)PIE_CENTER_SIZE, steps, FALSE );
// outer circle // outer circle

View File

@@ -62,7 +62,7 @@ std::vector<LLMenuGL*> LLScrollListCtrl::sMenus = {}; // List menus that recur,
// local structures & classes. // local structures & classes.
struct SortScrollListItem struct SortScrollListItem
{ {
SortScrollListItem(const std::vector<std::pair<S32, BOOL> >& sort_orders,const LLScrollListCtrl::sort_signal_t* sort_signal) SortScrollListItem(const std::vector<LLScrollListCtrl::sort_column_t >& sort_orders,const LLScrollListCtrl::sort_signal_t* sort_signal)
: mSortOrders(sort_orders) : mSortOrders(sort_orders)
, mSortSignal(sort_signal) , mSortSignal(sort_signal)
{} {}
@@ -102,7 +102,7 @@ struct SortScrollListItem
} }
typedef std::vector<std::pair<S32, BOOL> > sort_order_t; typedef std::vector<LLScrollListCtrl::sort_column_t > sort_order_t;
const LLScrollListCtrl::sort_signal_t* mSortSignal; const LLScrollListCtrl::sort_signal_t* mSortSignal;
const sort_order_t& mSortOrders; const sort_order_t& mSortOrders;
}; };
@@ -2294,7 +2294,7 @@ struct SameSortColumn
SameSortColumn(S32 column) : mColumn(column) {} SameSortColumn(S32 column) : mColumn(column) {}
S32 mColumn; S32 mColumn;
bool operator()(std::pair<S32, BOOL> sort_column) { return sort_column.first == mColumn; } bool operator()(LLScrollListCtrl::sort_column_t sort_column) { return sort_column.first == mColumn; }
}; };
BOOL LLScrollListCtrl::setSort(S32 column_idx, BOOL ascending) BOOL LLScrollListCtrl::setSort(S32 column_idx, BOOL ascending)
@@ -2392,7 +2392,7 @@ void LLScrollListCtrl::updateSort() const
// for one-shot sorts, does not save sort column/order // for one-shot sorts, does not save sort column/order
void LLScrollListCtrl::sortOnce(S32 column, BOOL ascending) void LLScrollListCtrl::sortOnce(S32 column, BOOL ascending)
{ {
std::vector<std::pair<S32, BOOL> > sort_column; std::vector<sort_column_t > sort_column;
sort_column.push_back(std::make_pair(column, ascending)); sort_column.push_back(std::make_pair(column, ascending));
// do stable sort to preserve any previous sorts // do stable sort to preserve any previous sorts
@@ -2733,15 +2733,15 @@ LLView* LLScrollListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFac
std::string value = row_child->getTextContents(); std::string value = row_child->getTextContents();
row["columns"][column_idx]["value"] = value; row["columns"][column_idx]["value"] = value;
std::string columnname(""); std::string columnname;
if (row_child->getAttributeString("name", columnname)) if (row_child->getAttributeString("name", columnname))
row["columns"][column_idx]["column"] = columnname; row["columns"][column_idx]["column"] = columnname;
std::string font(""); std::string font;
if (row_child->getAttributeString("font", font)) if (row_child->getAttributeString("font", font))
row["columns"][column_idx]["font"] = font; row["columns"][column_idx]["font"] = font;
std::string font_style(""); std::string font_style;
if (row_child->getAttributeString("font-style", font_style)) if (row_child->getAttributeString("font-style", font_style))
row["columns"][column_idx]["font-style"] = font_style; row["columns"][column_idx]["font-style"] = font_style;
@@ -2771,12 +2771,9 @@ LLView* LLScrollListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFac
void LLScrollListCtrl::copy() void LLScrollListCtrl::copy()
{ {
std::string buffer; std::string buffer;
for (auto item : getAllSelected())
std::vector<LLScrollListItem*> items = getAllSelected();
std::vector<LLScrollListItem*>::iterator itor;
for (itor = items.begin(); itor != items.end(); ++itor)
{ {
buffer += (*itor)->getContentsCSV() + "\n"; buffer += item->getContentsCSV() + '\n';
} }
gClipboard.copyFromSubstring(utf8str_to_wstring(buffer), 0, buffer.length()); gClipboard.copyFromSubstring(utf8str_to_wstring(buffer), 0, buffer.length());
} }

View File

@@ -320,6 +320,8 @@ public:
void updateStaticColumnWidth(LLScrollListColumn* col, S32 new_width); void updateStaticColumnWidth(LLScrollListColumn* col, S32 new_width);
S32 getTotalStaticColumnWidth() { return mTotalStaticColumnWidth; } S32 getTotalStaticColumnWidth() { return mTotalStaticColumnWidth; }
typedef std::pair<S32, bool> sort_column_t;
const std::vector<sort_column_t>& getSortColumns() const { return mSortColumns; }
std::string getSortColumnName(); std::string getSortColumnName();
BOOL getSortAscending() { return mSortColumns.empty() ? TRUE : mSortColumns.back().second; } BOOL getSortAscending() { return mSortColumns.empty() ? TRUE : mSortColumns.back().second; }
BOOL hasSortOrder() const; BOOL hasSortOrder() const;
@@ -354,7 +356,7 @@ public:
void setNeedsSortColumn(S32 col) void setNeedsSortColumn(S32 col)
{ {
if(!isSorted())return; if(!isSorted())return;
for(std::vector<std::pair<S32, BOOL> >::iterator it=mSortColumns.begin();it!=mSortColumns.end();++it) for(auto it=mSortColumns.begin();it!=mSortColumns.end();++it)
{ {
if((*it).first == col) if((*it).first == col)
{ {
@@ -482,7 +484,6 @@ private:
typedef std::vector<LLScrollListColumn*> ordered_columns_t; typedef std::vector<LLScrollListColumn*> ordered_columns_t;
ordered_columns_t mColumnsIndexed; ordered_columns_t mColumnsIndexed;
typedef std::pair<S32, BOOL> sort_column_t;
std::vector<sort_column_t> mSortColumns; std::vector<sort_column_t> mSortColumns;
sort_signal_t* mSortCallback; sort_signal_t* mSortCallback;

View File

@@ -293,6 +293,8 @@ LLTextEditor::LLTextEditor(
mMouseDownY(0), mMouseDownY(0),
mLastSelectionX(-1), mLastSelectionX(-1),
mLastSelectionY(-1), mLastSelectionY(-1),
mParseHTML(parse_html),
mParseHighlights(false),
mLastContextMenuX(-1), mLastContextMenuX(-1),
mLastContextMenuY(-1), mLastContextMenuY(-1),
mReflowNeeded(FALSE), mReflowNeeded(FALSE),
@@ -343,7 +345,6 @@ LLTextEditor::LLTextEditor(
mBorder = new LLViewBorder(std::string("text ed border"), LLRect(0, getRect().getHeight(), getRect().getWidth(), 0), LLViewBorder::BEVEL_IN, LLViewBorder::STYLE_LINE, UI_TEXTEDITOR_BORDER); mBorder = new LLViewBorder(std::string("text ed border"), LLRect(0, getRect().getHeight(), getRect().getWidth(), 0), LLViewBorder::BEVEL_IN, LLViewBorder::STYLE_LINE, UI_TEXTEDITOR_BORDER);
addChild(mBorder); addChild(mBorder);
mParseHTML = parse_html;
appendText(default_text, FALSE, FALSE); appendText(default_text, FALSE, FALSE);
resetDirty(); // Update saved text state resetDirty(); // Update saved text state
@@ -741,7 +742,7 @@ LLMenuGL* LLTextEditor::createUrlContextMenu(S32 x, S32 y, const std::string &in
return menu; return menu;
} }
void LLTextEditor::setText(const LLStringExplicit &utf8str) void LLTextEditor::setText(const LLStringExplicit &utf8str, bool force_replace_links)
{ {
// clear out the existing text and segments // clear out the existing text and segments
mWText.clear(); mWText.clear();
@@ -756,7 +757,7 @@ void LLTextEditor::setText(const LLStringExplicit &utf8str)
//LLStringUtil::removeCRLF(text); //LLStringUtil::removeCRLF(text);
// appendText modifies mCursorPos... // appendText modifies mCursorPos...
appendText(utf8str, false, false); appendText(utf8str, false, false, nullptr, force_replace_links);
// ...so move cursor to top after appending text // ...so move cursor to top after appending text
setCursorPos(0); setCursorPos(0);
@@ -766,9 +767,9 @@ void LLTextEditor::setText(const LLStringExplicit &utf8str)
mTextIsUpToDate = true; mTextIsUpToDate = true;
} }
void LLTextEditor::setWText(const LLWString& text) void LLTextEditor::setWText(const LLWString& text, bool force_replace_links)
{ {
setText(wstring_to_utf8str(text)); setText(wstring_to_utf8str(text), force_replace_links);
} }
// virtual // virtual
@@ -4274,7 +4275,7 @@ void LLTextEditor::appendText(const std::string &new_text, bool allow_undo, bool
return; return;
std::string text = prepend_newline && !mWText.empty() ? ('\n' + new_text) : new_text; std::string text = prepend_newline && !mWText.empty() ? ('\n' + new_text) : new_text;
appendTextImpl(text, style); appendTextImpl(text, style, force_replace_links);
if (!allow_undo) if (!allow_undo)
{ {
@@ -4317,7 +4318,7 @@ void LLTextEditor::appendTextImpl(const std::string &new_text, const LLStyleSP s
if (always_underline) link_style->mUnderline = true; if (always_underline) link_style->mUnderline = true;
appendAndHighlightText(link, part, link_style, !always_underline/*match.underlineOnHoverOnly()*/); appendAndHighlightText(link, part, link_style, !always_underline/*match.underlineOnHoverOnly()*/);
}; };
const auto&& cb = force_replace_links ? boost::bind(&LLTextEditor::replaceUrl, this, _1, _2, _3) : LLUrlLabelCallback::slot_function_type(); const auto&& cb = force_replace_links ? boost::bind(&LLTextEditor::replaceUrl, this, _1, _2, _3) : LLUrlLabelCallback();
while (!text.empty() && LLUrlRegistry::instance().findUrl(text, match, cb)) while (!text.empty() && LLUrlRegistry::instance().findUrl(text, match, cb))
{ {
start = match.getStart(); start = match.getStart();
@@ -4340,7 +4341,7 @@ void LLTextEditor::appendTextImpl(const std::string &new_text, const LLStyleSP s
auto url = match.getUrl(); auto url = match.getUrl();
const auto& label = match.getLabel(); const auto& label = match.getLabel();
if (force_replace_links || replace_links || url == label) if (force_replace_links || url == label)
{ {
// add icon before url if need // add icon before url if need
/* Singu TODO: Icons next to links? /* Singu TODO: Icons next to links?
@@ -4552,39 +4553,29 @@ void LLTextEditor::appendAndHighlightTextImpl(const std::string& new_text, S32 h
// This is where we appendHighlightedText // This is where we appendHighlightedText
// If LindenUserDir is empty then we didn't login yet. // If LindenUserDir is empty then we didn't login yet.
// In that case we can't instantiate LLTextParser, which is initialized per user. // In that case we can't instantiate LLTextParser, which is initialized per user.
if (mParseHighlights && !gDirUtilp->getLindenUserDir(true).empty()) LLTextParser* highlight = mParseHighlights && stylep && !gDirUtilp->getLindenUserDir(true).empty() ? LLTextParser::getInstance() : nullptr;
if (highlight)
{ {
LLTextParser* highlight = LLTextParser::getInstance(); const LLSD pieces = highlight->parsePartialLineHighlights(new_text, stylep->getColor(), (LLTextParser::EHighlightPosition)highlight_part);
auto cur_length = getLength();
if (highlight && stylep) for (auto i = pieces.beginArray(), end = pieces.endArray(); i < end; ++i)
{ {
LLStyleSP highlight_params(new LLStyle(*stylep)); const auto& piece = *i;
LLSD pieces = highlight->parsePartialLineHighlights(new_text, highlight_params->getColor(), (LLTextParser::EHighlightPosition)highlight_part); LLWString wide_text = utf8str_to_wstring(piece["text"].asString());
for (S32 i=0;i<pieces.size();i++)
{
LLSD color_llsd = pieces[i]["color"];
LLColor4 lcolor;
lcolor.setValue(color_llsd);
highlight_params->setColor(lcolor);
LLWString wide_text; insertStringNoUndo(cur_length, wide_text);
wide_text = utf8str_to_wstring(pieces[i]["text"].asString()); LLStyleSP sp(new LLStyle(*stylep));
sp->setColor(piece["color"]);
S32 cur_length = getLength(); auto wide_size = wide_text.size();
insertStringNoUndo(cur_length, wide_text); LLTextSegmentPtr segmentp = new LLTextSegment(sp, cur_length, cur_length + wide_size);
LLStyleSP sp(new LLStyle(*highlight_params)); cur_length += wide_size;
LLTextSegmentPtr segmentp; if (underline_on_hover) segmentp->setUnderlineOnHover(true);
segmentp = new LLTextSegment(sp, cur_length, cur_length + wide_text.size()); mSegments.push_back(segmentp);
if (underline_on_hover) segmentp->setUnderlineOnHover(true);
mSegments.push_back(segmentp);
}
return;
} }
} }
//else else
{ {
LLWString wide_text; LLWString wide_text = utf8str_to_wstring(new_text);
wide_text = utf8str_to_wstring(new_text);
auto length = getLength(); auto length = getLength();
auto insert_len = length + insertStringNoUndo(length, utf8str_to_wstring(new_text)); auto insert_len = length + insertStringNoUndo(length, utf8str_to_wstring(new_text));
@@ -4627,7 +4618,7 @@ void LLTextEditor::appendAndHighlightTextImpl(const std::string& new_text, S32 h
} }
endOfDoc(); endOfDoc();
} }
else if( selection_start != selection_end ) else if (was_selecting || selection_start != selection_end)
{ {
mSelectionStart = selection_start; mSelectionStart = selection_start;
mSelectionEnd = selection_end; mSelectionEnd = selection_end;
@@ -4690,8 +4681,61 @@ S32 LLTextEditor::insertStringNoUndo(const S32 pos, const LLWString &wstr)
S32 LLTextEditor::removeStringNoUndo(S32 pos, S32 length) S32 LLTextEditor::removeStringNoUndo(S32 pos, S32 length)
{ {
auto seg_iter = getSegIterContaining(pos);
S32 end = pos + length;
while(seg_iter != mSegments.end())
{
LLTextSegmentPtr segmentp = *seg_iter;
if (segmentp->getStart() < pos)
{
// deleting from middle of segment
if (segmentp->getEnd() > end)
{
segmentp->setEnd(segmentp->getEnd() - length);
}
// truncating segment
else
{
segmentp->setEnd(pos);
}
}
else if (segmentp->getStart() < end)
{
// deleting entire segment
if (segmentp->getEnd() <= end)
{
// remove segment
seg_iter = mSegments.erase(seg_iter);
continue;
}
// deleting head of segment
else
{
segmentp->setStart(pos);
segmentp->setEnd(segmentp->getEnd() - length);
}
}
else
{
// shifting segments backward to fill deleted portion
segmentp->setStart(segmentp->getStart() - length);
segmentp->setEnd(segmentp->getEnd() - length);
}
++seg_iter;
}
mWText.erase(pos, length); mWText.erase(pos, length);
// recreate default segment in case we erased everything
createDefaultSegment();
mTextIsUpToDate = FALSE; mTextIsUpToDate = FALSE;
/*needsReflow(pos);*/
// Singu Note: This kinda sucks for performance of delete, fix this later (with LLTextBase merge?)
updateLineStartList();
mReflowNeeded = false;
return -length; // This will be wrong if someone calls removeStringNoUndo with an excessive length return -length; // This will be wrong if someone calls removeStringNoUndo with an excessive length
} }
@@ -4966,6 +5010,34 @@ BOOL LLTextEditor::handleMouseUpOverSegment(S32 x, S32 y, MASK mask)
} }
LLTextEditor::segment_list_t::iterator LLTextEditor::getSegIterContaining(S32 index)
{
S32 text_len = getLength();
if (index > text_len) { return mSegments.end(); }
// when there are no segments, we return the end iterator, which must be checked by caller
if (mSegments.size() <= 1) { return mSegments.begin(); }
LLPointer<LLTextSegment> index_segment = new LLTextSegment(index);
auto it = std::lower_bound(mSegments.begin(), mSegments.end(), index_segment, LLTextSegment::compare());
return it;
}
LLTextEditor::segment_list_t::const_iterator LLTextEditor::getSegIterContaining(S32 index) const
{
S32 text_len = getLength();
if (index > text_len) { return mSegments.end(); }
// when there are no segments, we return the end iterator, which must be checked by caller
if (mSegments.size() <= 1) { return mSegments.begin(); }
LLPointer<LLTextSegment> index_segment = new LLTextSegment(index);
auto it = std::lower_bound(mSegments.begin(), mSegments.end(), index_segment, LLTextSegment::compare());
return it;
}
// Finds the text segment (if any) at the give local screen position // Finds the text segment (if any) at the give local screen position
LLTextSegment* LLTextEditor::getSegmentAtLocalPos( S32 x, S32 y ) const LLTextSegment* LLTextEditor::getSegmentAtLocalPos( S32 x, S32 y ) const
{ {

View File

@@ -276,8 +276,8 @@ public:
LLMenuGL* createUrlContextMenu(S32 x, S32 y, const std::string &url); // create a popup context menu for the given Url LLMenuGL* createUrlContextMenu(S32 x, S32 y, const std::string &url); // create a popup context menu for the given Url
// Non-undoable // Non-undoable
void setText(const LLStringExplicit &utf8str); void setText(const LLStringExplicit &utf8str, bool force_replace_links = true);
void setWText(const LLWString &wtext); void setWText(const LLWString &wtext, bool force_replace_links = true);
// Returns byte length limit // Returns byte length limit
S32 getMaxLength() const { return mMaxTextByteLength; } S32 getMaxLength() const { return mMaxTextByteLength; }
@@ -310,10 +310,10 @@ protected:
LLHandle<LLView> mPopupMenuHandle; LLHandle<LLView> mPopupMenuHandle;
S32 getLength() const { return mWText.length(); }
void getSegmentAndOffset( S32 startpos, S32* segidxp, S32* offsetp ) const; void getSegmentAndOffset( S32 startpos, S32* segidxp, S32* offsetp ) const;
void drawPreeditMarker(); void drawPreeditMarker();
public: public:
S32 getLength() const { return mWText.length(); }
void updateLineStartList(S32 startpos = 0); void updateLineStartList(S32 startpos = 0);
protected: protected:
void updateScrollFromCursor(); void updateScrollFromCursor();
@@ -415,7 +415,9 @@ protected:
S32 removeChar(S32 pos); S32 removeChar(S32 pos);
void removeWord(bool prev); void removeWord(bool prev);
S32 insert(const S32 pos, const LLWString &wstr, const BOOL group_with_next_op); S32 insert(const S32 pos, const LLWString &wstr, const BOOL group_with_next_op);
public:
S32 remove(const S32 pos, const S32 length, const BOOL group_with_next_op); S32 remove(const S32 pos, const S32 length, const BOOL group_with_next_op);
protected:
// Direct operations // Direct operations
S32 insertStringNoUndo(S32 pos, const LLWString &wstr); // returns num of chars actually inserted S32 insertStringNoUndo(S32 pos, const LLWString &wstr); // returns num of chars actually inserted
@@ -463,6 +465,10 @@ protected:
BOOL mParseHighlights; BOOL mParseHighlights;
typedef std::vector<LLTextSegmentPtr> segment_list_t; typedef std::vector<LLTextSegmentPtr> segment_list_t;
segment_list_t::iterator getSegIterContaining(S32 index);
segment_list_t::const_iterator getSegIterContaining(S32 index) const;
segment_list_t mSegments; segment_list_t mSegments;
LLTextSegmentPtr mHoverSegment; LLTextSegmentPtr mHoverSegment;

View File

@@ -41,6 +41,7 @@
//#include "lluicolortable.h" //#include "lluicolortable.h"
#include "message.h" #include "message.h"
#include <boost/algorithm/string.hpp>
#include <boost/format.hpp> // <alchemy/> #include <boost/format.hpp> // <alchemy/>
#define APP_HEADER_REGEX "((((x-grid-info://)|(x-grid-location-info://))[-\\w\\.]+(:\\d+)?/app)|(secondlife:///app))" #define APP_HEADER_REGEX "((((x-grid-info://)|(x-grid-location-info://))[-\\w\\.]+(:\\d+)?/app)|(secondlife:///app))"
@@ -120,11 +121,11 @@ std::string LLUrlEntryBase::getLabelFromWikiLink(const std::string &url) const
size_t start = 0; size_t start = 0;
while (! isspace(text[start])) while (! isspace(text[start]))
{ {
start++; ++start;
} }
while (text[start] == ' ' || text[start] == '\t') while (text[start] == ' ' || text[start] == '\t')
{ {
start++; ++start;
} }
return unescapeUrl(url.substr(start, url.size()-start-1)); return unescapeUrl(url.substr(start, url.size()-start-1));
} }
@@ -136,7 +137,7 @@ std::string LLUrlEntryBase::getUrlFromWikiLink(const std::string &string) const
size_t end = 0; size_t end = 0;
while (! isspace(text[end])) while (! isspace(text[end]))
{ {
end++; ++end;
} }
return escapeUrl(string.substr(1, end-1)); return escapeUrl(string.substr(1, end-1));
} }
@@ -273,7 +274,7 @@ std::string LLUrlEntryHTTP::getTooltip(const std::string &url) const
// //
LLUrlEntryHTTPLabel::LLUrlEntryHTTPLabel() LLUrlEntryHTTPLabel::LLUrlEntryHTTPLabel()
{ {
mPattern = boost::regex("\\[https?://\\S+[ \t]+[^\\]]+\\]", mPattern = boost::regex("\\[(https?://\\S+|\\S+\\.([^\\s<]*)?)[ \t]+[^\\]]+\\]",
boost::regex::perl|boost::regex::icase); boost::regex::perl|boost::regex::icase);
mMenuName = "menu_url_http.xml"; mMenuName = "menu_url_http.xml";
mTooltip = LLTrans::getString("TooltipHttpUrl"); mTooltip = LLTrans::getString("TooltipHttpUrl");
@@ -292,7 +293,10 @@ std::string LLUrlEntryHTTPLabel::getTooltip(const std::string &string) const
std::string LLUrlEntryHTTPLabel::getUrl(const std::string &string) const std::string LLUrlEntryHTTPLabel::getUrl(const std::string &string) const
{ {
return getUrlFromWikiLink(string); auto url = getUrlFromWikiLink(string);
if (!boost::istarts_with(url, "http"))
return "http://" + url;
return url;
} }
// //
@@ -334,7 +338,7 @@ std::string LLUrlEntryHTTPNoProtocol::getTooltip(const std::string &url) const
LLUrlEntryInvalidSLURL::LLUrlEntryInvalidSLURL() LLUrlEntryInvalidSLURL::LLUrlEntryInvalidSLURL()
: LLUrlEntryBase() : LLUrlEntryBase()
{ {
mPattern = boost::regex("(http://(maps.secondlife.com|slurl.com)/secondlife/|secondlife://(/app/(worldmap|teleport)/)?)[^ /]+(/-?[0-9]+){1,3}(/?(\\?title|\\?img|\\?msg)=\\S*)?/?", mPattern = boost::regex("(https?://(maps.secondlife.com|slurl.com)/secondlife/|secondlife://(/app/(worldmap|teleport)/)?)[^ /]+(/-?[0-9]+){1,3}(/?(\\?\\S*)?)?",
boost::regex::perl|boost::regex::icase); boost::regex::perl|boost::regex::icase);
mMenuName = "menu_url_http.xml"; mMenuName = "menu_url_http.xml";
mTooltip = LLTrans::getString("TooltipHttpUrl"); mTooltip = LLTrans::getString("TooltipHttpUrl");
@@ -421,7 +425,7 @@ bool LLUrlEntryInvalidSLURL::isSLURLvalid(const std::string &url) const
LLUrlEntrySLURL::LLUrlEntrySLURL() LLUrlEntrySLURL::LLUrlEntrySLURL()
{ {
// see http://slurl.com/about.php for details on the SLURL format // see http://slurl.com/about.php for details on the SLURL format
mPattern = boost::regex("http://(maps.secondlife.com|slurl.com)/secondlife/[^ /]+(/\\d+){0,3}(/?(\\?title|\\?img|\\?msg)=\\S*)?/?", mPattern = boost::regex("https?://(maps.secondlife.com|slurl.com)/secondlife/[^ /]+(/\\d+){0,3}(/?(\\?\\S*)?)?",
boost::regex::perl|boost::regex::icase); boost::regex::perl|boost::regex::icase);
mMenuName = "menu_url_slurl.xml"; mMenuName = "menu_url_slurl.xml";
mTooltip = LLTrans::getString("TooltipSLURL"); mTooltip = LLTrans::getString("TooltipSLURL");
@@ -669,9 +673,12 @@ std::string LLUrlEntryAgent::getLabel(const std::string &url, const LLUrlLabelCa
} }
else else
{ {
auto connection = LLAvatarNameCache::get(agent_id, boost::bind(&LLUrlEntryAgent::onAvatarNameCache, this, _1, _2)); if (cb)
mAvatarNameCacheConnections.emplace(agent_id, connection); {
addObserver(agent_id_string, url, cb); auto connection = LLAvatarNameCache::get(agent_id, boost::bind(&LLUrlEntryAgent::onAvatarNameCache, this, _1, _2));
mAvatarNameCacheConnections.emplace(agent_id, connection);
addObserver(agent_id_string, url, cb);
}
return LLTrans::getString("LoadingData"); return LLTrans::getString("LoadingData");
} }
} }
@@ -781,9 +788,12 @@ std::string LLUrlEntryAgentName::getLabel(const std::string &url, const LLUrlLab
} }
else else
{ {
auto connection = LLAvatarNameCache::get(agent_id, boost::bind(&LLUrlEntryAgentName::onAvatarNameCache, this, _1, _2)); if (cb)
mAvatarNameCacheConnections.emplace(agent_id, connection); {
addObserver(agent_id_string, url, cb); auto connection = LLAvatarNameCache::get(agent_id, boost::bind(&LLUrlEntryAgentName::onAvatarNameCache, this, _1, _2));
mAvatarNameCacheConnections.emplace(agent_id, connection);
addObserver(agent_id_string, url, cb);
}
return LLTrans::getString("LoadingData"); return LLTrans::getString("LoadingData");
} }
} }
@@ -917,10 +927,13 @@ std::string LLUrlEntryGroup::getLabel(const std::string &url, const LLUrlLabelCa
} }
else else
{ {
gCacheName->getGroup(group_id, if (cb)
boost::bind(&LLUrlEntryGroup::onGroupNameReceived, {
this, _1, _2, _3)); gCacheName->getGroup(group_id,
addObserver(group_id_string, url, cb); boost::bind(&LLUrlEntryGroup::onGroupNameReceived,
this, _1, _2, _3));
addObserver(group_id_string, url, cb);
}
return LLTrans::getString("LoadingData"); return LLTrans::getString("LoadingData");
} }
} }
@@ -1024,7 +1037,7 @@ std::string LLUrlEntryParcel::getLabel(const std::string &url, const LLUrlLabelC
std::string parcel_id_string = unescapeUrl(path_array[2]); // parcel id std::string parcel_id_string = unescapeUrl(path_array[2]); // parcel id
// Add an observer to call LLUrlLabelCallback when we have parcel name. // Add an observer to call LLUrlLabelCallback when we have parcel name.
addObserver(parcel_id_string, url, cb); if (cb) addObserver(parcel_id_string, url, cb);
LLUUID parcel_id(parcel_id_string); LLUUID parcel_id(parcel_id_string);

View File

@@ -42,7 +42,7 @@ class LLAvatarName;
typedef boost::signals2::signal<void (const std::string& url, typedef boost::signals2::signal<void (const std::string& url,
const std::string& label, const std::string& label,
const std::string& icon)> LLUrlLabelSignal; const std::string& icon)> LLUrlLabelSignal;
typedef LLUrlLabelSignal::slot_type LLUrlLabelCallback; typedef LLUrlLabelSignal::slot_function_type LLUrlLabelCallback;
/// ///
/// LLUrlEntryBase is the base class of all Url types registered in the /// LLUrlEntryBase is the base class of all Url types registered in the

View File

@@ -2831,6 +2831,10 @@ void LLView::initFromXML(LLXMLNodePtr node, LLView* parent)
node->getAttributeBOOL("mouse_opaque", mMouseOpaque); node->getAttributeBOOL("mouse_opaque", mMouseOpaque);
node->getAttributeS32("default_tab_group", mDefaultTabGroup); node->getAttributeS32("default_tab_group", mDefaultTabGroup);
if (node->hasAttribute("sound_flags"))
{
node->getAttributeU8("sound_flags", mSoundFlags);
}
reshape(view_rect.getWidth(), view_rect.getHeight()); reshape(view_rect.getWidth(), view_rect.getHeight());
} }

View File

@@ -9,9 +9,9 @@ include(BuildVersion)
include(BuildBranding) include(BuildBranding)
include(CMakeCopyIfDifferent) include(CMakeCopyIfDifferent)
include(DBusGlib) include(DBusGlib)
include(FindVCRedist)
include(FMODSTUDIO) include(FMODSTUDIO)
include(GLOD) include(GLOD)
include(FindOpenGL)
include(Hunspell) include(Hunspell)
include(Json) include(Json)
include(LLAddBuildTest) include(LLAddBuildTest)
@@ -36,6 +36,7 @@ include(Linking)
include(NDOF) include(NDOF)
include(NVAPI) include(NVAPI)
include(OPENAL) include(OPENAL)
include(OpenGL)
include(OpenSSL) include(OpenSSL)
include(StateMachine) include(StateMachine)
include(TemplateCheck) include(TemplateCheck)
@@ -45,10 +46,6 @@ include(WinManifest)
include(ZLIB) include(ZLIB)
include(URIPARSER) include(URIPARSER)
if (MSVC)
use_prebuilt_binary(vcredist)
endif (MSVC)
include_directories( include_directories(
${STATEMACHINE_INCLUDE_DIRS} ${STATEMACHINE_INCLUDE_DIRS}
${DBUSGLIB_INCLUDE_DIRS} ${DBUSGLIB_INCLUDE_DIRS}
@@ -1434,6 +1431,12 @@ endif (WINDOWS)
set_source_files_properties(llstartup.cpp PROPERTIES COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS}") set_source_files_properties(llstartup.cpp PROPERTIES COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS}")
if (LIBVLCPLUGIN)
set_source_files_properties(llfloaterabout.cpp PROPERTIES COMPILE_DEFINITIONS "VLCPLUGIN=1")
else (LIBVLCPLUGIN)
set_source_files_properties(llfloaterabout.cpp PROPERTIES COMPILE_DEFINITIONS "VLCPLUGIN=0")
endif (LIBVLCPLUGIN)
list(APPEND viewer_SOURCE_FILES ${viewer_HEADER_FILES}) list(APPEND viewer_SOURCE_FILES ${viewer_HEADER_FILES})
set_source_files_properties(${viewer_HEADER_FILES} set_source_files_properties(${viewer_HEADER_FILES}
@@ -1505,12 +1508,7 @@ if (WINDOWS)
${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/libhunspell.dll ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/libhunspell.dll
${SHARED_LIB_STAGING_DIR}/Debug/libhunspell.dll ${SHARED_LIB_STAGING_DIR}/Debug/libhunspell.dll
${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/SLVoice.exe ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/SLVoice.exe
${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/vivoxsdk.dll
${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/ortp.dll
${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/libsndfile-1.dll
${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/zlib1.dll
${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/vivoxplatform.dll ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/vivoxplatform.dll
${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/vivoxoal.dll
${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/ca-bundle.crt ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/ca-bundle.crt
${GOOGLE_PERF_TOOLS_SOURCE} ${GOOGLE_PERF_TOOLS_SOURCE}
${CMAKE_CURRENT_SOURCE_DIR}/licenses-win32.txt ${CMAKE_CURRENT_SOURCE_DIR}/licenses-win32.txt
@@ -1526,6 +1524,18 @@ if (WINDOWS)
windows-crash-logger windows-crash-logger
) )
if (ADDRESS_SIZE EQUAL 64)
list(APPEND COPY_INPUT_DEPENDENCIES
${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/vivoxsdk_x64.dll
${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/ortp_x64.dll
)
else (ADDRESS_SIZE EQUAL 64)
list(APPEND COPY_INPUT_DEPENDENCIES
${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/vivoxsdk.dll
${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/ortp.dll
)
endif (ADDRESS_SIZE EQUAL 64)
if (FMODSTUDIO) if (FMODSTUDIO)
if (WORD_SIZE EQUAL 64) if (WORD_SIZE EQUAL 64)
list(APPEND COPY_INPUT_DEPENDENCIES list(APPEND COPY_INPUT_DEPENDENCIES
@@ -1571,7 +1581,29 @@ if (WINDOWS)
add_custom_target(copy_w_viewer_manifest ALL DEPENDS ${CMAKE_CFG_INTDIR}/copy_touched.bat) add_custom_target(copy_w_viewer_manifest ALL DEPENDS ${CMAKE_CFG_INTDIR}/copy_touched.bat)
add_dependencies(${VIEWER_BINARY_NAME} stage_third_party_libs llcommon copy_w_viewer_manifest)
if(EXISTS ${VISUAL_STUDIO_REDISTRIBUTABLE_PATH})
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/redist
COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/redist"
DEPENDS copy_w_viewer_manifest
COMMENT "Creating redist dir"
)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/redist/${VISUAL_STUDIO_REDISTRIBUTABLE_NAME}
COMMAND ${CMAKE_COMMAND} -E copy_if_different
ARGS
${VISUAL_STUDIO_REDISTRIBUTABLE_PATH}
${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/redist/${VISUAL_STUDIO_REDISTRIBUTABLE_NAME}
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/redist
COMMENT "Copying ${VISUAL_STUDIO_REDISTRIBUTABLE_PATH} to redist dir"
)
add_custom_target(copy_w_redist ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/redist/${VISUAL_STUDIO_REDISTRIBUTABLE_NAME})
endif()
add_dependencies(${VIEWER_BINARY_NAME} stage_third_party_libs llcommon copy_w_viewer_manifest copy_w_redist)
if (EXISTS ${CMAKE_SOURCE_DIR}/copy_win_scripts) if (EXISTS ${CMAKE_SOURCE_DIR}/copy_win_scripts)
add_dependencies(${VIEWER_BINARY_NAME} copy_win_scripts) add_dependencies(${VIEWER_BINARY_NAME} copy_win_scripts)

View File

@@ -7493,22 +7493,6 @@ This should be as low as possible, but too low may break functionality</string>
<integer>0</integer> <integer>0</integer>
</array> </array>
</map> </map>
<key>FloaterFavoritesRect</key>
<map>
<key>Comment</key>
<string>Rectangle for favorites window</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Rect</string>
<key>Value</key>
<array>
<integer>0</integer>
<integer>400</integer>
<integer>250</integer>
<integer>0</integer>
</array>
</map>
<key>FloaterFindRect2</key> <key>FloaterFindRect2</key>
<map> <map>
<key>Comment</key> <key>Comment</key>
@@ -8048,6 +8032,20 @@ This should be as low as possible, but too low may break functionality</string>
<key>Value</key> <key>Value</key>
<integer>0</integer> <integer>0</integer>
</map> </map>
<key>RadarSortOrder</key>
<map>
<key>Comment</key>
<string>Sort order for the radar, map of column names to ascending boolean</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>LLSD</string>
<key>Value</key>
<array>
<string>distance</string>
<boolean>1</boolean>
</array>
</map>
<key>FloaterLandRect5</key> <key>FloaterLandRect5</key>
<map> <map>
<key>Comment</key> <key>Comment</key>
@@ -8160,22 +8158,6 @@ This should be as low as possible, but too low may break functionality</string>
<integer>0</integer> <integer>0</integer>
</array> </array>
</map> </map>
<key>FloaterMyOutfitsRect</key>
<map>
<key>Comment</key>
<string>Rectangle for My Outfits window</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Rect</string>
<key>Value</key>
<array>
<integer>0</integer>
<integer>400</integer>
<integer>250</integer>
<integer>0</integer>
</array>
</map>
<key>FloaterObjectIMInfo</key> <key>FloaterObjectIMInfo</key>
<map> <map>
<key>Comment</key> <key>Comment</key>

View File

@@ -1,7 +1,6 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; secondlife setup.nsi ;; Second Life setup.nsi
;; Copyright 2004-2011, Linden Research, Inc. ;; Copyright 2004-2015, Linden Research, Inc.
;; Copyright 2013-2015 Alchemy Viewer Project
;; ;;
;; This library is free software; you can redistribute it and/or ;; This library is free software; you can redistribute it and/or
;; modify it under the terms of the GNU Lesser General Public ;; modify it under the terms of the GNU Lesser General Public
@@ -19,8 +18,7 @@
;; ;;
;; Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA ;; Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
;; ;;
;; NSIS Unicode 2.46.5 or higher required ;; NSIS 3 or higher required for Unicode support
;; http://www.scratchpaper.com/
;; ;;
;; Author: James Cook, Don Kjer, Callum Prentice, Drake Arconis ;; Author: James Cook, Don Kjer, Callum Prentice, Drake Arconis
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -34,6 +32,8 @@
!include "LogicLib.nsh" !include "LogicLib.nsh"
!include "StdUtils.nsh" !include "StdUtils.nsh"
!include "FileFunc.nsh" !include "FileFunc.nsh"
!insertmacro GetParameters
!insertmacro GetOptions
!include "x64.nsh" !include "x64.nsh"
!include "WinVer.nsh" !include "WinVer.nsh"
!include "MUI2.nsh" !include "MUI2.nsh"
@@ -44,8 +44,8 @@
%%INST_VARS%% %%INST_VARS%%
%%WIN64_BIN_BUILD%% %%WIN64_BIN_BUILD%%
Var INSTPROG
Var INSTEXE Var INSTEXE
Var INSTPROG
Var INSTSHORTCUT Var INSTSHORTCUT
Var AUTOSTART Var AUTOSTART
Var COMMANDLINE ; command line passed to this installer, set in .onInit Var COMMANDLINE ; command line passed to this installer, set in .onInit
@@ -55,6 +55,14 @@
Var SKIP_AUTORUN ; skip automatic launch of viewer after install Var SKIP_AUTORUN ; skip automatic launch of viewer after install
Var STARTMENUFOLDER Var STARTMENUFOLDER
;--------------------------------
;Registry Keys
!define ALCHEMY_KEY "SOFTWARE\${VENDORSTR}"
!define INSTNAME_KEY "${ALCHEMY_KEY}\${APPNAMEONEWORD}"
!define MSCURRVER_KEY "SOFTWARE\Microsoft\Windows\CurrentVersion"
!define MSNTCURRVER_KEY "SOFTWARE\Microsoft\Windows NT\CurrentVersion"
!define MSUNINSTALL_KEY "${MSCURRVER_KEY}\Uninstall\${APPNAMEONEWORD}"
;-------------------------------- ;--------------------------------
;General ;General
@@ -73,7 +81,7 @@
;Get installation folder from registry if available and 32bit otherwise do it in init ;Get installation folder from registry if available and 32bit otherwise do it in init
!ifndef WIN64_BIN_BUILD !ifndef WIN64_BIN_BUILD
InstallDirRegKey HKLM "SOFTWARE\${VENDORSTR}\${APPNAMEONEWORD}" "" InstallDirRegKey HKLM "${INSTNAME_KEY}" ""
!endif !endif
;Request application privileges for Windows UAC ;Request application privileges for Windows UAC
@@ -90,12 +98,13 @@
;Version Information ;Version Information
VIProductVersion "${VERSION_LONG}" VIProductVersion "${VERSION_LONG}"
VIAddVersionKey "ProductName" "Singularity Viewer" VIAddVersionKey "ProductName" "Singularity Viewer Installer"
VIAddVersionKey "Comments" "A viewer for the meta-verse!" VIAddVersionKey "Comments" "A viewer for the meta-verse!"
VIAddVersionKey "CompanyName" "${VENDORSTR}" VIAddVersionKey "CompanyName" "${VENDORSTR}"
VIAddVersionKey "LegalCopyright" "Copyright © 2010-2016, ${VENDORSTR}" VIAddVersionKey "LegalCopyright" "Copyright © 2010-2019, ${VENDORSTR}"
VIAddVersionKey "FileDescription" "${APPNAME} Installer" VIAddVersionKey "FileDescription" "${APPNAME} Installer"
VIAddVersionKey "ProductVersion" "${VERSION_LONG}" VIAddVersionKey "ProductVersion" "${VERSION_LONG}"
VIAddVersionKey "FileVersion" "${VERSION_LONG}"
;-------------------------------- ;--------------------------------
;Interface Settings ;Interface Settings
@@ -118,7 +127,7 @@
;Remember the installer language ;Remember the installer language
!define MUI_LANGDLL_REGISTRY_ROOT "HKLM" !define MUI_LANGDLL_REGISTRY_ROOT "HKLM"
!define MUI_LANGDLL_REGISTRY_KEY "SOFTWARE\${VENDORSTR}\${APPNAMEONEWORD}" !define MUI_LANGDLL_REGISTRY_KEY "${INSTNAME_KEY}"
!define MUI_LANGDLL_REGISTRY_VALUENAME "InstallerLanguage" !define MUI_LANGDLL_REGISTRY_VALUENAME "InstallerLanguage"
;Always show the dialog ;Always show the dialog
@@ -140,7 +149,7 @@
;Start Menu Folder Page ;Start Menu Folder Page
!define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKLM" !define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKLM"
!define MUI_STARTMENUPAGE_REGISTRY_KEY "SOFTWARE\${VENDORSTR}\${APPNAMEONEWORD}" !define MUI_STARTMENUPAGE_REGISTRY_KEY "${INSTNAME_KEY}"
!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder" !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder"
!define MUI_PAGE_CUSTOMFUNCTION_PRE check_skip !define MUI_PAGE_CUSTOMFUNCTION_PRE check_skip
!ifdef WIN64_BIN_BUILD !ifdef WIN64_BIN_BUILD
@@ -177,10 +186,9 @@
;Languages ;Languages
!include "%%SOURCE%%\installers\windows\lang_en-us.nsi" !include "%%SOURCE%%\installers\windows\lang_en-us.nsi"
!include "%%SOURCE%%\installers\windows\lang_fr.nsi"
!include "%%SOURCE%%\installers\windows\lang_de.nsi" !include "%%SOURCE%%\installers\windows\lang_de.nsi"
!include "%%SOURCE%%\installers\windows\lang_es.nsi" !include "%%SOURCE%%\installers\windows\lang_es.nsi"
!include "%%SOURCE%%\installers\windows\lang_zh.nsi" !include "%%SOURCE%%\installers\windows\lang_fr.nsi"
!include "%%SOURCE%%\installers\windows\lang_ja.nsi" !include "%%SOURCE%%\installers\windows\lang_ja.nsi"
!include "%%SOURCE%%\installers\windows\lang_pl.nsi" !include "%%SOURCE%%\installers\windows\lang_pl.nsi"
!include "%%SOURCE%%\installers\windows\lang_it.nsi" !include "%%SOURCE%%\installers\windows\lang_it.nsi"
@@ -188,6 +196,7 @@
!include "%%SOURCE%%\installers\windows\lang_da.nsi" !include "%%SOURCE%%\installers\windows\lang_da.nsi"
!include "%%SOURCE%%\installers\windows\lang_ru.nsi" !include "%%SOURCE%%\installers\windows\lang_ru.nsi"
!include "%%SOURCE%%\installers\windows\lang_tr.nsi" !include "%%SOURCE%%\installers\windows\lang_tr.nsi"
!include "%%SOURCE%%\installers\windows\lang_zh.nsi"
;-------------------------------- ;--------------------------------
;Reserve Files ;Reserve Files
@@ -197,7 +206,7 @@
;because this will make your installer start faster. ;because this will make your installer start faster.
!insertmacro MUI_RESERVEFILE_LANGDLL !insertmacro MUI_RESERVEFILE_LANGDLL
ReserveFile "${NSISDIR}\Plugins\x86-unicode\NSISdl.dll" ReserveFile "${NSISDIR}\Plugins\x86-unicode\nsisdl.dll"
ReserveFile "${NSISDIR}\Plugins\x86-unicode\nsDialogs.dll" ReserveFile "${NSISDIR}\Plugins\x86-unicode\nsDialogs.dll"
ReserveFile "${NSISDIR}\Plugins\x86-unicode\StartMenu.dll" ReserveFile "${NSISDIR}\Plugins\x86-unicode\StartMenu.dll"
ReserveFile "${NSISDIR}\Plugins\x86-unicode\StdUtils.dll" ReserveFile "${NSISDIR}\Plugins\x86-unicode\StdUtils.dll"
@@ -374,39 +383,7 @@ Function un.CloseSecondLife
Return Return
FunctionEnd FunctionEnd
; Test our connection to secondlife.com
; Also allows us to count attempted installs by examining web logs.
; *TODO: Return current SL version info and have installer check
; if it is up to date.
Function CheckNetworkConnection
; Uneeded - LD
Return
Push $0
Push $1
Push $2 # Option value for GetOptions
DetailPrint $(CheckNetworkConnectionDP)
; Look for a tag value from the stub installer, used for statistics
; to correlate installs. Default to "" if not found on command line.
StrCpy $2 ""
${GetOptions} $COMMANDLINE "/STUBTAG=" $2
GetTempFileName $0
!define HTTP_TIMEOUT 5000 ; milliseconds
; Don't show secondary progress bar, this will be quick.
NSISdl::download_quiet \
/TIMEOUT=${HTTP_TIMEOUT} \
"http://install.secondlife.com/check/?stubtag=$2&version=${VERSION_LONG}" \
$0
Pop $1 ; Return value, either "success", "cancel" or an error message
; MessageBox MB_OK "Download result: $1"
; Result ignored for now
; StrCmp $1 "success" +2
; DetailPrint "Connection failed: $1"
Delete $0 ; temporary file
Pop $2
Pop $1
Pop $0
Return
FunctionEnd
;-------------------------------- ;--------------------------------
;Installer Sections ;Installer Sections
@@ -424,7 +401,6 @@ Section "Viewer"
Call CheckIfAlreadyCurrent Call CheckIfAlreadyCurrent
Call CloseSecondLife ; Make sure we're not running Call CloseSecondLife ; Make sure we're not running
Call CheckNetworkConnection ; ping secondlife.com
SetOutPath "$INSTDIR" SetOutPath "$INSTDIR"
;Remove old shader files first so fallbacks will work. ;Remove old shader files first so fallbacks will work.
@@ -455,7 +431,6 @@ Section "Viewer"
WriteINIStr "$SMPROGRAMS\$STARTMENUFOLDER\SL Create Account.url" "InternetShortcut" "URL" "http://join.secondlife.com/" WriteINIStr "$SMPROGRAMS\$STARTMENUFOLDER\SL Create Account.url" "InternetShortcut" "URL" "http://join.secondlife.com/"
WriteINIStr "$SMPROGRAMS\$STARTMENUFOLDER\SL Your Account.url" "InternetShortcut" "URL" "http://www.secondlife.com/account/" WriteINIStr "$SMPROGRAMS\$STARTMENUFOLDER\SL Your Account.url" "InternetShortcut" "URL" "http://www.secondlife.com/account/"
WriteINIStr "$SMPROGRAMS\$STARTMENUFOLDER\SL Scripting Language Help.url" "InternetShortcut" "URL" "http://wiki.secondlife.com/wiki/LSL_Portal" WriteINIStr "$SMPROGRAMS\$STARTMENUFOLDER\SL Scripting Language Help.url" "InternetShortcut" "URL" "http://wiki.secondlife.com/wiki/LSL_Portal"
!insertmacro MUI_STARTMENU_WRITE_END !insertmacro MUI_STARTMENU_WRITE_END
;Other shortcuts ;Other shortcuts
@@ -473,28 +448,28 @@ Section "Viewer"
!endif !endif
;Write registry ;Write registry
WriteRegStr HKLM "SOFTWARE\${VENDORSTR}\$INSTPROG" "" "$INSTDIR" WriteRegStr HKLM "${INSTNAME_KEY}" "" "$INSTDIR"
WriteRegStr HKLM "SOFTWARE\${VENDORSTR}\$INSTPROG" "Version" "${VERSION_LONG}" WriteRegStr HKLM "${INSTNAME_KEY}" "Version" "${VERSION_LONG}"
WriteRegStr HKLM "SOFTWARE\${VENDORSTR}\$INSTPROG" "Shortcut" "$INSTSHORTCUT" WriteRegStr HKLM "${INSTNAME_KEY}" "Shortcut" "$INSTSHORTCUT"
WriteRegStr HKLM "SOFTWARE\${VENDORSTR}\$INSTPROG" "Exe" "$INSTEXE" WriteRegStr HKLM "${INSTNAME_KEY}" "Exe" "$INSTEXE"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "Comments" "A viewer for the meta-verse!" WriteRegStr HKLM "${MSUNINSTALL_KEY}" "Comments" "A viewer for the meta-verse!"
!ifdef WIN64_BIN_BUILD !ifdef WIN64_BIN_BUILD
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "DisplayName" "$INSTSHORTCUT (64 bit) Viewer" WriteRegStr HKLM "${MSUNINSTALL_KEY}" "DisplayName" "$INSTSHORTCUT (64 bit) Viewer"
!else !else
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "DisplayName" "$INSTSHORTCUT Viewer" WriteRegStr HKLM "${MSUNINSTALL_KEY}" "DisplayName" "$INSTSHORTCUT Viewer"
!endif !endif
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "DisplayIcon" "$INSTDIR\$INSTEXE" WriteRegStr HKLM "${MSUNINSTALL_KEY}" "DisplayIcon" "$INSTDIR\$INSTEXE"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "DisplayVersion" "${VERSION_LONG}" WriteRegStr HKLM "${MSUNINSTALL_KEY}" "DisplayVersion" "${VERSION_LONG}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "InstallLocation" "$INSTDIR" WriteRegStr HKLM "${MSUNINSTALL_KEY}" "InstallLocation" "$INSTDIR"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "InstallSource" "$EXEDIR\" WriteRegStr HKLM "${MSUNINSTALL_KEY}" "InstallSource" "$EXEDIR\"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "HelpLink" "http://www.singularityviewer.org" WriteRegStr HKLM "${MSUNINSTALL_KEY}" "HelpLink" "http://www.singularityviewer.org"
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "NoModify" 1 WriteRegDWORD HKLM "${MSUNINSTALL_KEY}" "NoModify" 1
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "NoRepair" 1 WriteRegDWORD HKLM "${MSUNINSTALL_KEY}" "NoRepair" 1
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "Publisher" "${VENDORSTR}" WriteRegStr HKLM "${MSUNINSTALL_KEY}" "Publisher" "${VENDORSTR}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "URLInfoAbout" "http://www.singularityviewer.org" WriteRegStr HKLM "${MSUNINSTALL_KEY}" "URLInfoAbout" "http://www.singularityviewer.org"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "URLUpdateInfo" "http://www.singularityviewer.org/downloads" WriteRegStr HKLM "${MSUNINSTALL_KEY}" "URLUpdateInfo" "http://www.singularityviewer.org/downloads"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "UninstallString" "$\"$INSTDIR\uninst.exe$\"" WriteRegStr HKLM "${MSUNINSTALL_KEY}" "UninstallString" "$\"$INSTDIR\uninst.exe$\""
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "QuietUninstallString" "$\"$INSTDIR\uninst.exe$\" /S" WriteRegStr HKLM "${MSUNINSTALL_KEY}" "QuietUninstallString" "$\"$INSTDIR\uninst.exe$\" /S"
${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2 ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2
IntFmt $0 "0x%08X" $0 IntFmt $0 "0x%08X" $0
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "EstimatedSize" "$0" WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "EstimatedSize" "$0"
@@ -533,6 +508,7 @@ Section "Viewer"
WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info" "" "URL:Hypergrid legacy" WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info" "" "URL:Hypergrid legacy"
WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info" "URL Protocol" "" WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info" "URL Protocol" ""
WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info\DefaultIcon" "" "$\"$INSTDIR\$INSTEXE$\"" WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info\DefaultIcon" "" "$\"$INSTDIR\$INSTEXE$\""
;; URL param must be last item passed to viewer, it ignores subsequent params ;; URL param must be last item passed to viewer, it ignores subsequent params
;; to avoid parameter injection attacks. ;; to avoid parameter injection attacks.
WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info\shell" "" "open" WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info\shell" "" "open"
@@ -552,6 +528,9 @@ SectionEnd
;-------------------------------- ;--------------------------------
;Installer Functions ;Installer Functions
Function .onInit Function .onInit
!ifdef WIN64_BIN_BUILD
SetRegView 64
!endif
;Don't install on unsupported operating systems ;Don't install on unsupported operating systems
Call CheckWindowsVersion Call CheckWindowsVersion
;Don't install if not administator ;Don't install if not administator
@@ -563,7 +542,6 @@ Function .onInit
;Get installation folder from registry if available for 64bit ;Get installation folder from registry if available for 64bit
!ifdef WIN64_BIN_BUILD !ifdef WIN64_BIN_BUILD
SetRegView 64
ReadRegStr $0 HKLM "SOFTWARE\${VENDORSTR}\${APPNAMEONEWORD}" "" ReadRegStr $0 HKLM "SOFTWARE\${VENDORSTR}\${APPNAMEONEWORD}" ""
IfErrors +2 0 ; If error jump past setting SKIP_AUTORUN IfErrors +2 0 ; If error jump past setting SKIP_AUTORUN
StrCpy $INSTDIR $0 StrCpy $INSTDIR $0
@@ -583,6 +561,7 @@ Function .onInit
IfErrors +2 0 ; If error jump past setting AUTOSTART IfErrors +2 0 ; If error jump past setting AUTOSTART
StrCpy $AUTOSTART "true" StrCpy $AUTOSTART "true"
${GetOptions} $COMMANDLINE "/LANGID=" $0 ; /LANGID=1033 implies US English ${GetOptions} $COMMANDLINE "/LANGID=" $0 ; /LANGID=1033 implies US English
; If no language (error), then proceed ; If no language (error), then proceed
IfErrors lbl_configure_default_lang IfErrors lbl_configure_default_lang
@@ -613,7 +592,6 @@ Section "Uninstall"
!endif !endif
StrCpy $INSTPROG "${APPNAMEONEWORD}" StrCpy $INSTPROG "${APPNAMEONEWORD}"
StrCpy $INSTEXE "${INSTEXE}"
StrCpy $INSTSHORTCUT "${APPNAME}" StrCpy $INSTSHORTCUT "${APPNAME}"
Call un.CloseSecondLife Call un.CloseSecondLife
@@ -660,7 +638,9 @@ SectionEnd
;Uninstaller Functions ;Uninstaller Functions
Function un.onInit Function un.onInit
!ifdef WIN64_BIN_BUILD
SetRegView 64
!endif
Call un.CheckIfAdministrator Call un.CheckIfAdministrator
!insertmacro MUI_UNGETLANGUAGE !insertmacro MUI_UNGETLANGUAGE

View File

@@ -22,23 +22,53 @@
#include "lffloaterinvpanel.h" #include "lffloaterinvpanel.h"
#include <boost/algorithm/string/erase.hpp>
#include "llinventorypanel.h" #include "llinventorypanel.h"
#include "lluictrlfactory.h" #include "lluictrlfactory.h"
LFFloaterInvPanel::LFFloaterInvPanel(const LLUUID& cat_id, LLInventoryModel* model, const std::string& name) LFFloaterInvPanel::LFFloaterInvPanel(const LLSD& cat, const std::string& name, LLInventoryModel* model)
: LLInstanceTracker<LFFloaterInvPanel, LLUUID>(cat_id) : LLInstanceTracker<LFFloaterInvPanel, LLSD>(cat)
{ {
// Setup the floater first
mPanel = new LLInventoryPanel("inv_panel", LLInventoryPanel::DEFAULT_SORT_ORDER, cat, LLRect(), model ? model : &gInventory, true);
const auto& title = name.empty() ? gInventory.getCategory(mPanel->getRootFolderID())->getName() : name;
// Figure out a unique name for our rect control
const auto rect_control = llformat("FloaterInv%sRect", boost::algorithm::erase_all_copy(title, " ").data());
bool existed = gSavedSettings.controlExists(rect_control);
if (existed) // Set our initial rect to the stored control
setRectControl(rect_control);
// Load from XUI
mCommitCallbackRegistrar.add("InvPanel.Search", boost::bind(&LLInventoryPanel::setFilterSubString, boost::ref(mPanel), _2)); mCommitCallbackRegistrar.add("InvPanel.Search", boost::bind(&LLInventoryPanel::setFilterSubString, boost::ref(mPanel), _2));
LLUICtrlFactory::getInstance()->buildFloater(this, "floater_inv_panel.xml"); LLUICtrlFactory::getInstance()->buildFloater(this, "floater_inv_panel.xml");
// Now set the title
setTitle(title);
// If we haven't existed before, create and set our rect control now
if (!existed)
{
S32 left, top;
gFloaterView->getNewFloaterPosition(&left, &top);
LLRect rect = getRect();
rect.translate(left - rect.mLeft, top - rect.mTop);
setRect(rect);
gSavedSettings.declareRect(rect_control, rect, "Rectangle for " + title + " window");
setRectControl(rect_control);
}
// Now take care of the children
LLPanel* panel = getChild<LLPanel>("placeholder_panel"); LLPanel* panel = getChild<LLPanel>("placeholder_panel");
mPanel = new LLInventoryPanel("inv_panel", LLInventoryPanel::DEFAULT_SORT_ORDER, LLSD().with("id", cat_id), panel->getRect(), model, true); mPanel->setRect(panel->getRect());
mPanel->postBuild(); mPanel->postBuild();
mPanel->setFollows(FOLLOWS_ALL); mPanel->setFollows(FOLLOWS_ALL);
mPanel->setEnabled(true); mPanel->setEnabled(true);
addChild(mPanel); addChild(mPanel);
removeChild(panel); removeChild(panel);
setTitle(name);
} }
LFFloaterInvPanel::~LFFloaterInvPanel() LFFloaterInvPanel::~LFFloaterInvPanel()
@@ -47,10 +77,10 @@ LFFloaterInvPanel::~LFFloaterInvPanel()
} }
// static // static
void LFFloaterInvPanel::show(const LLUUID& cat_id, LLInventoryModel* model, const std::string& name) void LFFloaterInvPanel::show(const LLSD& cat, const std::string& name, LLInventoryModel* model)
{ {
LFFloaterInvPanel* floater = LFFloaterInvPanel::getInstance(cat_id); LFFloaterInvPanel* floater = LFFloaterInvPanel::getInstance(cat);
if (!floater) floater = new LFFloaterInvPanel(cat_id, model, name); if (!floater) floater = new LFFloaterInvPanel(cat, name, model);
floater->open(); floater->open();
} }
@@ -63,10 +93,10 @@ void LFFloaterInvPanel::closeAll()
{ {
cache.push_back(&*i); cache.push_back(&*i);
} }
// Now close all panels, without using instance_iter iterators. // Now close all, without using instance_iter iterators.
for (std::vector<LFFloaterInvPanel*>::iterator i = cache.begin(); i != cache.end(); ++i) for (auto& floater : cache)
{ {
(*i)->close(); floater->close();
} }
} }

View File

@@ -23,15 +23,23 @@
#include "llfloater.h" #include "llfloater.h"
#include "llinstancetracker.h" #include "llinstancetracker.h"
#include "llsdutil.h"
class LFFloaterInvPanel : public LLFloater, public LLInstanceTracker<LFFloaterInvPanel, LLUUID> class LFFloaterInvPanel : public LLFloater, public LLInstanceTracker<LFFloaterInvPanel, LLSD>
{ {
LFFloaterInvPanel(const LLUUID& cat_id, class LLInventoryModel* model, const std::string& name); LFFloaterInvPanel(const LLSD& cat, const std::string& name = LLStringUtil::null, class LLInventoryModel* model = nullptr);
~LFFloaterInvPanel(); ~LFFloaterInvPanel();
public: public:
static void show(const LLUUID& cat_id, LLInventoryModel* model, const std::string& name); // Show the floater for cat_id (create with other params if necessary) static void show(const LLSD& cat, const std::string& name = LLStringUtil::null, LLInventoryModel* model = nullptr); // Show the floater for cat (create with other params if necessary)
static void toggle(const LLSD& cat)
{
if (auto instance = getInstance(cat))
instance->close();
else
show(cat);
}
static void closeAll(); // Called when not allowed to have inventory open static void closeAll(); // Called when not allowed to have inventory open
/*virtual*/ BOOL handleKeyHere(KEY key, MASK mask); /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask);

View File

@@ -34,7 +34,7 @@ LFSimFeatureHandler::LFSimFeatureHandler()
{ {
if (!gHippoGridManager->getCurrentGrid()->isSecondLife()) // Remove this line if we ever handle SecondLife sim features if (!gHippoGridManager->getCurrentGrid()->isSecondLife()) // Remove this line if we ever handle SecondLife sim features
gAgent.addRegionChangedCallback(boost::bind(&LFSimFeatureHandler::handleRegionChange, this)); gAgent.addRegionChangedCallback(boost::bind(&LFSimFeatureHandler::handleRegionChange, this));
LLMuteList::instance().mGodLastNames.insert("Linden"); LLMuteList::instance().mGodLastNames = { "Linden", "ProductEngine" };
} }
ExportPolicy LFSimFeatureHandler::exportPolicy() const ExportPolicy LFSimFeatureHandler::exportPolicy() const
@@ -138,7 +138,7 @@ void LFSimFeatureHandler::setSupportedFeatures()
} }
else else
{ {
mute_list.mGodLastNames.insert("Linden"); mute_list.mGodLastNames = { "Linden", "ProductEngine" };
} }
} }
} }

View File

@@ -43,8 +43,54 @@
#include "llfloaterworldmap.h" #include "llfloaterworldmap.h"
#include "llagent.h" #include "llagent.h"
#include "llappviewer.h" // for gPacificDaylightTime #include "llappviewer.h" // for gPacificDaylightTime
#include "llcommandhandler.h" // secondlife:///app/... support
#include "llviewercontrol.h" #include "llviewercontrol.h"
class LLEventHandler : public LLCommandHandler
{
public:
// requires trusted browser to trigger
LLEventHandler() : LLCommandHandler("event", UNTRUSTED_THROTTLE) { }
bool handle(const LLSD& params, const LLSD& query_map,
LLMediaCtrl* web)
{
if (params.size() < 2)
{
return false;
}
std::string event_command = params[1].asString();
S32 event_id = params[0].asInteger();
if (event_command == "about" || event_command == "details")
{
LLFloaterEventInfo::show(event_id);
return true;
}
else if(event_command == "notify")
{
// we're adding or removing a notification, so grab the date, name and notification bool
if (params.size() < 3)
{
return false;
}
if(params[2].asString() == "enable")
{
gEventNotifier.add(event_id);
// tell the server to modify the database as this was a slurl event notification command
gEventNotifier.serverPushRequest(event_id, true);
}
else
{
gEventNotifier.remove(event_id);
}
return true;
}
return false;
}
};
LLEventHandler gEventHandler;
LLEventNotifier gEventNotifier; LLEventNotifier gEventNotifier;
LLEventNotifier::LLEventNotifier() LLEventNotifier::LLEventNotifier()

View File

@@ -977,12 +977,12 @@ void LLFace::getPlanarProjectedParams(LLQuaternion* face_rot, LLVector3* face_po
{ {
const LLMatrix4a& vol_mat = getWorldMatrix(); const LLMatrix4a& vol_mat = getWorldMatrix();
const LLVolumeFace& vf = getViewerObject()->getVolume()->getVolumeFace(mTEOffset); const LLVolumeFace& vf = getViewerObject()->getVolume()->getVolumeFace(mTEOffset);
const LLVector4a& normal = vf.mNormals[0]; if (!vf.mTangents)
const LLVector4a& tangent = vf.mTangents[0];
if (!&tangent)
{ {
return; return;
} }
const LLVector4a& normal = vf.mNormals[0];
const LLVector4a& tangent = vf.mTangents[0];
LLVector4a binormal; LLVector4a binormal;
binormal.setCross3(normal, tangent); binormal.setCross3(normal, tangent);

View File

@@ -71,6 +71,9 @@
#endif #endif
#include "cef/dullahan.h" #include "cef/dullahan.h"
#if VLCPLUGIN
#include "vlc/libvlc_version.h"
#endif // LL_WINDOWS
extern LLMemoryInfo gSysMemory; extern LLMemoryInfo gSysMemory;
extern U32 gPacketsIn; extern U32 gPacketsIn;
@@ -295,9 +298,20 @@ LLFloaterAbout::LLFloaterAbout()
<< DULLAHAN_VERSION_BUILD << DULLAHAN_VERSION_BUILD
<< " / CEF: " << CEF_VERSION << " / CEF: " << CEF_VERSION
<< " / Chrome: " << CHROME_VERSION_MAJOR; << " / Chrome: " << CHROME_VERSION_MAJOR
<< '\n';
#if VLCPLUGIN
supportstrm << "LibVLC: ";
supportstrm << LIBVLC_VERSION_MAJOR;
supportstrm << '.';
supportstrm << LIBVLC_VERSION_MINOR;
supportstrm << '.';
supportstrm << LIBVLC_VERSION_REVISION;
supportstrm << '\n';
#endif
support += supportstrm.str(); support += supportstrm.str();
support += '\n';
if (gPacketsIn > 0) if (gPacketsIn > 0)
{ {

View File

@@ -257,6 +257,14 @@ LLFloaterAvatarList::LLFloaterAvatarList() : LLFloater(std::string("radar")),
LLFloaterAvatarList::~LLFloaterAvatarList() LLFloaterAvatarList::~LLFloaterAvatarList()
{ {
mCleanup = true; mCleanup = true;
LLSD sort;
for (const auto& col : mAvatarList->getSortColumns())
{
sort.append(mAvatarList->getColumn(col.first)->mName);
sort.append(col.second);
}
gSavedSettings.setLLSD("RadarSortOrder", sort);
mAvatars.clear(); mAvatars.clear();
} }
@@ -425,7 +433,13 @@ BOOL LLFloaterAvatarList::postBuild()
// Get a pointer to the scroll list from the interface // Get a pointer to the scroll list from the interface
mAvatarList = getChild<LLScrollListCtrl>("avatar_list"); mAvatarList = getChild<LLScrollListCtrl>("avatar_list");
mAvatarList->sortByColumn("distance", true); const LLSD sort = gSavedSettings.getLLSD("RadarSortOrder");
for (auto it = sort.beginArray(), end = sort.endArray(); it < end; ++it)
{
const auto& column_name = (*it);
const auto& ascending = (*++it);
mAvatarList->sortByColumn(column_name.asStringRef(), ascending.asBoolean());
}
mAvatarList->setCommitOnSelectionChange(true); mAvatarList->setCommitOnSelectionChange(true);
mAvatarList->setCommitCallback(boost::bind(&LLFloaterAvatarList::onSelectName,this)); mAvatarList->setCommitCallback(boost::bind(&LLFloaterAvatarList::onSelectName,this));
mAvatarList->setDoubleClickCallback(boost::bind(&LLFloaterAvatarList::onClickFocus,this)); mAvatarList->setDoubleClickCallback(boost::bind(&LLFloaterAvatarList::onClickFocus,this));

View File

@@ -342,12 +342,13 @@ void LLFloaterBulkPermission::handleInventory(LLViewerObject* viewer_obj, LLInve
//status_text.setArg("[STATUS]", getString("status_ok_text")); //status_text.setArg("[STATUS]", getString("status_ok_text"));
status_text.setArg("[STATUS]", ""); status_text.setArg("[STATUS]", "");
} }
#if 0
else else
{ {
//status_text.setArg("[STATUS]", getString("status_bad_text")); //status_text.setArg("[STATUS]", getString("status_bad_text"));
status_text.setArg("[STATUS]", ""); status_text.setArg("[STATUS]", "");
} }
#endif
list->addSimpleElement(status_text.getString()); list->addSimpleElement(status_text.getString());
//TODO if we are an object inside an object we should check a recuse flag and if set //TODO if we are an object inside an object we should check a recuse flag and if set

View File

@@ -36,7 +36,6 @@
#include "llfloaterevent.h" #include "llfloaterevent.h"
// viewer project includes // viewer project includes
#include "llcommandhandler.h"
#include "llpanelevent.h" #include "llpanelevent.h"
// linden library includes // linden library includes
@@ -52,29 +51,6 @@
LLMap< U32, LLFloaterEventInfo* > gEventInfoInstances; LLMap< U32, LLFloaterEventInfo* > gEventInfoInstances;
class LLEventHandler : public LLCommandHandler
{
public:
// requires trusted browser to trigger
LLEventHandler() : LLCommandHandler("event", UNTRUSTED_THROTTLE) { }
bool handle(const LLSD& tokens, const LLSD& query_map,
LLMediaCtrl* web)
{
if (tokens.size() < 2)
{
return false;
}
U32 event_id = tokens[0].asInteger();
if (tokens[1].asString() == "about")
{
LLFloaterEventInfo::show(event_id);
return true;
}
return false;
}
};
LLEventHandler gEventHandler;
LLFloaterEventInfo::LLFloaterEventInfo(const std::string& name, const U32 event_id) LLFloaterEventInfo::LLFloaterEventInfo(const std::string& name, const U32 event_id)
: LLFloater(name), : LLFloater(name),
mEventID( event_id ) mEventID( event_id )

View File

@@ -715,7 +715,7 @@ void LLPanelLandGeneral::refresh()
); );
mEditName->setText( parcel->getName() ); mEditName->setText( parcel->getName() );
mEditDesc->setText( parcel->getDesc() ); mEditDesc->setText( parcel->getDesc(), false );
BOOL for_sale = parcel->getForSale(); BOOL for_sale = parcel->getForSale();
@@ -3070,7 +3070,7 @@ void LLPanelLandCovenant::updateCovenantText(const std::string &string)
{ {
LLViewerTextEditor* editor = self->getChild<LLViewerTextEditor>("covenant_editor"); LLViewerTextEditor* editor = self->getChild<LLViewerTextEditor>("covenant_editor");
editor->setHandleEditKeysDirectly(TRUE); editor->setHandleEditKeysDirectly(TRUE);
editor->setText(string); editor->setText(string, false);
} }
} }

Some files were not shown because too many files have changed in this diff Show More