diff options
| -rw-r--r-- | .hgtags | 89 | ||||
| -rw-r--r-- | indra/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | indra/mac_updater/AutoUpdater.nib/classes.nib | 4 | ||||
| -rw-r--r-- | indra/mac_updater/AutoUpdater.nib/info.nib | 14 | ||||
| -rw-r--r-- | indra/mac_updater/AutoUpdater.nib/objects.xib | 56 | ||||
| -rw-r--r-- | indra/mac_updater/CMakeLists.txt | 73 | ||||
| -rw-r--r-- | indra/mac_updater/Info.plist | 26 | ||||
| -rw-r--r-- | indra/mac_updater/mac_updater.cpp | 1257 | ||||
| -rw-r--r-- | indra/mac_updater/mac_updater.h | 91 | ||||
| -rw-r--r-- | indra/newview/CMakeLists.txt | 5 | ||||
| -rw-r--r-- | indra/newview/viewer_manifest.py | 7 | ||||
| -rw-r--r-- | indra/viewer_components/updater/llupdaterservice.cpp | 4 | ||||
| -rw-r--r-- | indra/viewer_components/updater/scripts/darwin/janitor.py | 133 | ||||
| -rw-r--r-- | indra/viewer_components/updater/scripts/darwin/messageframe.py | 66 | ||||
| -rw-r--r-- | indra/viewer_components/updater/scripts/darwin/update_install | 10 | ||||
| -rwxr-xr-x | indra/viewer_components/updater/scripts/darwin/update_install.py | 373 | 
16 files changed, 628 insertions, 1583 deletions
| @@ -72,35 +72,35 @@ b53a0576eec80614d7767ed72b40ed67aeff27c9 DRTVWR-38_2.5.2-release  461c8c65b5c799ddfe365422f9be9c0095d91e7d 2.6.0-beta1-tip  9e4641f4a7870c0f565a25a2971368d5a29516a1 2.6.0-beta2  9e4641f4a7870c0f565a25a2971368d5a29516a1 DRTVWR-41_2.6.0-beta2 +42f32494bac475d0737799346f6831558ae8bf5d 2.6.0-release +42f32494bac475d0737799346f6831558ae8bf5d DRTVWR-39_2.6.0-release  c5bdef3aaa2744626aef3c217ce29e1900d357b3 2.6.1-beta1  c5bdef3aaa2744626aef3c217ce29e1900d357b3 2.6.1-start  c5bdef3aaa2744626aef3c217ce29e1900d357b3 DRTVWR-43_2.6.1-beta1 +c9182ed77d427c759cfacf49a7b71a2e20d522aa 2.6.1-release +c9182ed77d427c759cfacf49a7b71a2e20d522aa DRTVWR-42_2.6.1-release  56b2778c743c2a964d82e1caf11084d76a87de2c 2.6.2-start  d1203046bb653b763f835b04d184646949d8dd5c 2.6.2-beta1  d1203046bb653b763f835b04d184646949d8dd5c DRTVWR-45_2.6.2-beta1 -42f32494bac475d0737799346f6831558ae8bf5d 2.6.0-release -42f32494bac475d0737799346f6831558ae8bf5d DRTVWR-39_2.6.0-release -c9182ed77d427c759cfacf49a7b71a2e20d522aa 2.6.1-release -c9182ed77d427c759cfacf49a7b71a2e20d522aa DRTVWR-42_2.6.1-release +214180ad5714ce8392b82bbebcc92f4babd98300 2.6.2-release +214180ad5714ce8392b82bbebcc92f4babd98300 DRTVWR-44_2.6.2-release  52b2263ab28f0976c689fd0b76c55a9eb027cdbf end-of-develop.py  ec32f1045e7c2644015245df3a9933620aa194b8 2.6.3-start  d7fcefabdf32bb61a9ea6d6037c1bb26190a85bc 2.6.3-beta1  d7fcefabdf32bb61a9ea6d6037c1bb26190a85bc DRTVWR-47_2.6.3-beta1  0630e977504af5ea320c58d33cae4e1ddee793e9 2.6.3-beta2  0630e977504af5ea320c58d33cae4e1ddee793e9 DRTVWR-48_2.6.3-beta2 +8f2da1701c81a62352df2b8d413d27fb2cade9a6 2.6.3-release +8f2da1701c81a62352df2b8d413d27fb2cade9a6 DRTVWR-46_2.6.3-release  3178e311da3a8739a85363665006ea3c4610cad4 dons-headless-hackathon-work -214180ad5714ce8392b82bbebcc92f4babd98300 2.6.2-release -214180ad5714ce8392b82bbebcc92f4babd98300 DRTVWR-44_2.6.2-release  7db558aaa7c176f2022b3e9cfe38ac72f6d1fccd 2.6.5-beta1  7db558aaa7c176f2022b3e9cfe38ac72f6d1fccd DRTVWR-50_2.6.5-beta1 -8f2da1701c81a62352df2b8d413d27fb2cade9a6 2.6.3-release -8f2da1701c81a62352df2b8d413d27fb2cade9a6 DRTVWR-46_2.6.3-release  800cefce8d364ffdd2f383cbecb91294da3ea424 2.6.6-start  bb1075286b3b147b1dae2e3d6b2d56f04ff03f35 2.6.6-beta1  bb1075286b3b147b1dae2e3d6b2d56f04ff03f35 DRTVWR-52_2.6.6-beta1 -5e349dbe9cc84ea5795af8aeb6d473a0af9d4953 2.6.8-start  dac76a711da5f1489a01c1fa62ec97d99c25736d 2.6.6-release  dac76a711da5f1489a01c1fa62ec97d99c25736d DRTVWR-51_2.6.6-release +5e349dbe9cc84ea5795af8aeb6d473a0af9d4953 2.6.8-start  beafa8a9bd1d1b670b7523d865204dc4a4b38eef 2.6.8-beta1  beafa8a9bd1d1b670b7523d865204dc4a4b38eef DRTVWR-55_2.6.8-beta1  be2000b946f8cb3de5f44b2d419287d4c48ec4eb 2.6.8-release @@ -119,50 +119,50 @@ e67da2c6e3125966dd49eef98b36317afac1fcfe 2.6.9-start  9f79a6ed8fdcd2f3dac33ea6b3236eeb278dccfe 2.7.2-start  e0dc8b741eaa27dcdfbc9e956bb2579b954d15eb 2.7.2-beta1  e0dc8b741eaa27dcdfbc9e956bb2579b954d15eb DRTVWR-63_2.7.2-beta1 -6a3e7e403bd19e45fdfc2fcc716867af3ab80861 2.7.3-start  fe3a8e7973072ea62043c08b19b66626c1a720eb 2.7.1-release  fe3a8e7973072ea62043c08b19b66626c1a720eb 2.7.2-release  fe3a8e7973072ea62043c08b19b66626c1a720eb DRTVWR-60_2.7.1-release  fe3a8e7973072ea62043c08b19b66626c1a720eb DRTVWR-62_2.7.2-release +6a3e7e403bd19e45fdfc2fcc716867af3ab80861 2.7.3-start  6af10678de4736222b2c3f7e010e984fb5b327de 2.7.4-start  be963a4eef635542f9617d7f5fd22ba48fb71958 2.7.4-beta1  be963a4eef635542f9617d7f5fd22ba48fb71958 DRTVWR-67_2.7.4-beta1 +057f319dd8eccdf63a54d99686c68cdcb31b6abc 2.7.4-release +057f319dd8eccdf63a54d99686c68cdcb31b6abc DRTVWR-66_2.7.4-release  19a498fa62570f352d7d246f17e3c81cc1d82d8b 2.7.5-start  09984bfa6cae17e0f72d02b75c1b7393c65eecfc 2.7.5-beta1  09984bfa6cae17e0f72d02b75c1b7393c65eecfc DRTVWR-69_2.7.5-beta1 +6866d9df6efbd441c66451debd376d21211de39c 2.7.5-release +6866d9df6efbd441c66451debd376d21211de39c DRTVWR-68_2.7.5-release  e1ed60913230dd64269a7f7fc52cbc6004f6d52c 2.8.0-beta1  e1ed60913230dd64269a7f7fc52cbc6004f6d52c 2.8.0-start  e1ed60913230dd64269a7f7fc52cbc6004f6d52c DRTVWR-71_2.8.0-beta1 -057f319dd8eccdf63a54d99686c68cdcb31b6abc 2.7.4-release -057f319dd8eccdf63a54d99686c68cdcb31b6abc DRTVWR-66_2.7.4-release -6866d9df6efbd441c66451debd376d21211de39c 2.7.5-release -6866d9df6efbd441c66451debd376d21211de39c DRTVWR-68_2.7.5-release +493d9127ee50e84ba08a736a65a23ca86f7a5b01 2.8.0-release +493d9127ee50e84ba08a736a65a23ca86f7a5b01 DRTVWR-70_2.8.0-release  502f6a5deca9365ddae57db4f1e30172668e171e 2.8.1-start  2c7e459e0c883f8e406b932e41e60097e9ee077e 2.8.1-beta1  2c7e459e0c883f8e406b932e41e60097e9ee077e DRTVWR-73_2.8.1-beta1 -493d9127ee50e84ba08a736a65a23ca86f7a5b01 2.8.0-release -493d9127ee50e84ba08a736a65a23ca86f7a5b01 DRTVWR-70_2.8.0-release -54bc7823ad4e3a436fef79710f685a7372bbf795 2.8.2-start -ac0f1a132d35c02a58861d37cca75b0429ac9137 2.8.3-start  29e93d7e19991011bd12b5748142b11a5dcb4370 2.8.1-release  29e93d7e19991011bd12b5748142b11a5dcb4370 DRTVWR-72_2.8.1-release  4780e3bd2b3042f91be3426151f28c30d199bb3b 2.8.1-hotfix  4780e3bd2b3042f91be3426151f28c30d199bb3b DRTVWR-76_2.8.1-hotfix +54bc7823ad4e3a436fef79710f685a7372bbf795 2.8.2-start +ac0f1a132d35c02a58861d37cca75b0429ac9137 2.8.3-start  599677276b227357140dda35bea4a2c18e2e67b5 2.8.3-beta1  599677276b227357140dda35bea4a2c18e2e67b5 DRTVWR-75_2.8.3-beta1 +fb85792b84bf28428889c4cc966469d92e5dac4c 2.8.3-release +fb85792b84bf28428889c4cc966469d92e5dac4c DRTVWR-74_2.8.3-release  6b678ea52f90d5c14181661dcd2546e25bde483e 3.0.0-start  b0be6ce3adfef3a014a2389d360539f8a86c5439 3.0.0-beta1  b0be6ce3adfef3a014a2389d360539f8a86c5439 DRTVWR-78_3.0.0-beta1 -fb85792b84bf28428889c4cc966469d92e5dac4c 2.8.3-release -fb85792b84bf28428889c4cc966469d92e5dac4c DRTVWR-74_2.8.3-release +1778f26b6d0ae762dec3ca37140f66620f2485d9 3.0.0-release +1778f26b6d0ae762dec3ca37140f66620f2485d9 DRTVWR-77_3.0.0-release  82a2079ffcb57ecb1b3849cb41376b443e1eb912 3.0.1-start  364fd63517fbacbbcb9129d096187171ba8c9e48 3.0.1-beta1  364fd63517fbacbbcb9129d096187171ba8c9e48 DRTVWR-81_3.0.1-beta1  f2412ecd6740803ea9452f1d17fd872e263a0df7 3.0.2-start  42784bf50fa01974bada2a1af3892ee09c93fcda 3.0.2-beta1  42784bf50fa01974bada2a1af3892ee09c93fcda DRTVWR-83_3.0.2-beta1 -1778f26b6d0ae762dec3ca37140f66620f2485d9 3.0.0-release -1778f26b6d0ae762dec3ca37140f66620f2485d9 DRTVWR-77_3.0.0-release  e5c9af2d7980a99a71650be3a0cf7b2b3c3b897e 3.0.2-beta2  e5c9af2d7980a99a71650be3a0cf7b2b3c3b897e DRTVWR-86_3.0.2-beta2  b95ddac176ac944efdc85cbee94ac2e1eab44c79 3.0.3-start @@ -170,9 +170,9 @@ b95ddac176ac944efdc85cbee94ac2e1eab44c79 3.0.3-start  6694f3f062aa45f64ab391d25a3eb3d5eb1b0871 DRTVWR-85_3.0.3-beta1  61aa7974df089e8621fe9a4c69bcdefdb3cc208a 3.0.3-beta2  61aa7974df089e8621fe9a4c69bcdefdb3cc208a DRTVWR-89_3.0.3-beta2 -586907287be581817b2422b5137971b22d54ea48 3.0.4-start  0496d2f74043cf4e6058e76ac3db03d44cff42ce 3.0.3-release  0496d2f74043cf4e6058e76ac3db03d44cff42ce DRTVWR-84_3.0.3-release +586907287be581817b2422b5137971b22d54ea48 3.0.4-start  92a3aa04775438226399b19deee12ac3b5a62838 3.0.5-start  c7282e59f374ee904bd793c3c444455e3399b0c5 3.1.0-start  2657fa785bbfac115852c41bd0adaff74c2ad5da 3.1.0-beta1 @@ -193,11 +193,11 @@ e440cd1dfbd128d7d5467019e497f7f803640ad6 DRTVWR-95_3.2.0-beta1  c4911ec8cd81e676dfd2af438b3e065407a94a7a 3.2.1-start  9e390d76807fa70d356b8716fb83b8ce42a629ef 3.2.1-beta1  9e390d76807fa70d356b8716fb83b8ce42a629ef DRTVWR-100_3.2.1-beta1 +a8c7030d6845186fac7c188be4323a0e887b4184 3.2.1-release +a8c7030d6845186fac7c188be4323a0e887b4184 DRTVWR-99_3.2.1-release  40b46edba007d15d0059c80864b708b99c1da368 3.2.2-start  523df3e67378541498d516d52af4402176a26bac 3.2.2-beta1  523df3e67378541498d516d52af4402176a26bac DRTVWR-102_3.2.2-beta1 -a8c7030d6845186fac7c188be4323a0e887b4184 3.2.1-release -a8c7030d6845186fac7c188be4323a0e887b4184 DRTVWR-99_3.2.1-release  80f3e30d8aa4d8f674a48bd742aaa6d8e9eae0b5 3.2.3-start  3fe994349fae64fc40874bb59db387131eb35a41 3.2.4-beta1  3fe994349fae64fc40874bb59db387131eb35a41 3.2.4-start @@ -248,57 +248,67 @@ bb9932a7a5fd00edf52d95f354e3b37ae6a942db DRTVWR-156  6414ecdabc5d89515b08d1f872cf923ed3a5523a DRTVWR-148  2a3965b3ad202df7ea25d2be689291bb14a1280e DRTVWR-155  24a7281bef42bd4430ceb25db8b195449c2c7de3 DRTVWR-153 +a716684aa7c07c440b1de5815b8a1f3dd3fd8bfb DRTVWR-159 +9a78ac13f047056f788c4734dd91aebfe30970e3 DRTVWR-157  5910f8063a7e1ddddf504c2f35ca831cc5e8f469 DRTVWR-160  f0a174c2adb4bc39b16722a61d7eeb4f2a1d4843 3.3.3-beta1  f0a174c2adb4bc39b16722a61d7eeb4f2a1d4843 DRTVWR-144 -2d6c0634b11e6f3df11002b8510a72a0433da00a DRTVWR-164 +089e5c84b2dece68f2b016c842ef9b5de4786842 DRTVWR-161  600f3b3920d94de805ac6dc8bb6def9c069dd360 DRTVWR-162 +c08e2ac17a99973b2a94477659220b99b8847ae2 DRTVWR-163 +2d6c0634b11e6f3df11002b8510a72a0433da00a DRTVWR-164  80b5e5e9775966d3839331ffa7a16a60f9d7c930 DRTVWR-165  fdcc08a4f20ae9bb060f4693c8980d216534efdf 3.3.3-beta2  af5f3e43e6e4424b1da19d9e16f6b853a7b822ed DRTVWR-169  4b3c68199a86cabaa5d9466d7b0f7e141e901d7a 3.3.3-beta3  6428242e124b523813bfaf4c45b3d422f0298c81 3.3.3-release -a716684aa7c07c440b1de5815b8a1f3dd3fd8bfb DRTVWR-159 -9a78ac13f047056f788c4734dd91aebfe30970e3 DRTVWR-157 -089e5c84b2dece68f2b016c842ef9b5de4786842 DRTVWR-161 -c08e2ac17a99973b2a94477659220b99b8847ae2 DRTVWR-163  b9d0170b62eb1c7c3adaa37a0b13a833e5e659f9 DRTVWR-171  050e48759337249130f684b4a21080b683f61732 DRTVWR-168  09ef7fd1b0781f33b8a3a9af6236b7bcb4831910 DRTVWR-170  f87bfbe0b62d26f451d02a47c80ebef6b9168fc2 DRTVWR-158  f91d003091a61937a044652c4c674447f7dcbb7a 3.3.4-beta1 +005dfe5c4c377207d065fb27858d2eb0b53b143a DRTVWR-167  bce218b2b45b730b22cc51e4807aa8b571cadef3 DRTVWR-173  cbea6356ce9cb0c313b6777f10c5c14783264fcc DRTVWR-174  82b5330bc8b17d0d4b598832e9c5a92e90075682 3.3.4-beta2  57d221de3df94f90b55204313c2cef044a3c0ae2 DRTVWR-176  eb539c65e6ee26eea2bf373af2d0f4b52dc91289 DRTVWR-177  a8057e1b9a1246b434a27405be35e030f7d28b0c 3.3.4-beta3 +888768f162d2c0a8de1dcc5fb9a08bd8bd120a6b DRTVWR-175  4281aa899fb2cedb7a9ca7ce91c5c29d4aa69594 DRTVWR-180  5c08e1d8edd871807153603b690e3ee9dbb548aa DRTVWR-183  6c75f220b103db1420919c8b635fe53e2177f318 3.3.4-beta4  9cd174d3a54d93d409a7c346a15b8bfb40fc58f4 DRTVWR-184  ab2ffc547c8a8950ff187c4f6c95e5334fab597b 3.3.4-beta5  28e100d0379a2b0710c57647a28fc5239d3d7b99 3.3.4-release -005dfe5c4c377207d065fb27858d2eb0b53b143a DRTVWR-167 -888768f162d2c0a8de1dcc5fb9a08bd8bd120a6b DRTVWR-175  a8b3eca451a9eaab59987efb0ab1c4217e3f2dcc DRTVWR-182  1f27cdfdc54246484f8afbbe42ce48e954175cbd 3.4.0-beta1 -9ee9387789701d597130f879d9011a4958753862 DRTVWR-189 +81f6b745ef27f5915fd07f988fdec9944f2bb73e DRTVWR-186  47f0d08ba7ade0a3905074009067c6d3df7e16ae DRTVWR-190 +cc953f00956be52cc64c30637bbeec310eea603f DRTVWR-181 +c04e68e1b0034fd0a20815ae24c77e5f8428e822 DRTVWR-188 +9ee9387789701d597130f879d9011a4958753862 DRTVWR-189  421126293dcbde918e0da027ca0ab9deb5b4fbf2 DRTVWR-192 +4b2c52aecb7a75de31dbb12d9f5b9a251d8707be DRTVWR-191  33a2fc7a910ae29ff8b4850316ed7fbff9f64d33 DRTVWR-195  e9732c739c8a72a590216951505ea9c76a526a84 DRTVWR-193 +78ca0bbf43a92e8914d4cfa87d69a6717ef7d4cf DRTVWR-194  7602f61c804a512764e349c034c02ddabeefebc4 DRTVWR-196  ae5c83dd61d2d37c45f1d5b8bf2b036d87599f1b DRTVWR-198  507bdfbd6bf844a511c1ffeda4baa80016ed1346 DRTVWR-197  b1dbb1a83f48f93f6f878cff9e52d2cb635e145c 3.4.0-beta2  37402e2b19af970d51b0a814d79892cc5647532b DRTVWR-200  182a9bf30e81070361bb020a78003b1cf398e79c 3.4.0-beta3 +248f4acd92a706c79e842bc83d80baa7369c0c2e DRTVWR-203  6dfb0fba782c9233dd95f24ec48146db0d3f210b DRTVWR-199  7c9102fb998885621919f2474a002c35b583539b 3.3.4-release2  7649a3dff5ec22d3727377e5f02efd0f421e4cb5 DRTVWR-201  84fb70dfe3444e75a44fb4bee43e2fc8221cebdd 3.4.0-beta4 +de3be913f68813a9bac7d1c671fef96d1159bcd6 DRTVWR-202  573e863be2f26d3687161def4b9fea9b7038dda8 3.4.0-beta5 +34dbbe2b00afe90352d3acf8290eb10ab90d1c8b oz-build-test-tag +6ee71714935ffcd159db3d4f5800c1929aac54e1 DRTVWR-205 +7b22c612fc756e0ea63b10b163e81d107f85dbf8 DRTVWR-206  8c9085066c78ed5f6c9379dc054c82a6fcdb1851 DRTVWR-207  351eea5f9dc192fc5ddea3b02958de97677a0a12 3.3.4-release3  af7b28e75bd5a629cd9e0dc46fb3f1757626f493 DRTVWR-212 @@ -309,6 +319,7 @@ ceed0b65a69f1eac20d523e0203320a32f9a3f3c DRTVWR-215  97977c67245f52db20eb15f1918cc0f24778cabc 3.4.0-release  5adb2b8f96c3cac88ad7c7d996d707f1b29df336 3.4.1-beta1  b3f74858a1c8720c82d0978f3877a3fc8ba459ec 3.4.1-beta1a +b61afe175b829c149d369524a4e974dfda99facf DRTVWR-219  2b779f233ee6f38c89cb921650c773a96e63da92 DRTVWR-220  0b9d95f4bfb6867cbf56eaec51633b0da2f1262d DRTVWR-221  e6e553761829dc0270eaaa712b7cb0622535b076 3.4.1-beta3 @@ -333,17 +344,6 @@ baf97f06ae17223614c5e31aa42e71d87cff07fe DRTVWR-236  b2f21e3442542283a80e7eaebae9f833e5a927b6 DRTVWR-237  3f9be82de642d468c5fc272cb9d96b46b5498402 3.4.1-beta12  e59ffd3fe0838ae6b09b242a6e9df71761b88f41 3.4.1-release -81f6b745ef27f5915fd07f988fdec9944f2bb73e DRTVWR-186 -cc953f00956be52cc64c30637bbeec310eea603f DRTVWR-181 -c04e68e1b0034fd0a20815ae24c77e5f8428e822 DRTVWR-188 -4b2c52aecb7a75de31dbb12d9f5b9a251d8707be DRTVWR-191 -78ca0bbf43a92e8914d4cfa87d69a6717ef7d4cf DRTVWR-194 -248f4acd92a706c79e842bc83d80baa7369c0c2e DRTVWR-203 -de3be913f68813a9bac7d1c671fef96d1159bcd6 DRTVWR-202 -34dbbe2b00afe90352d3acf8290eb10ab90d1c8b oz-build-test-tag -6ee71714935ffcd159db3d4f5800c1929aac54e1 DRTVWR-205 -7b22c612fc756e0ea63b10b163e81d107f85dbf8 DRTVWR-206 -b61afe175b829c149d369524a4e974dfda99facf DRTVWR-219  32896d5e920ca9a29256ff3b747c2e99752aa5ae DRTVWR-217  704bbae7b182a1f2811a47a054e680522966f54a 3.4.2-beta1  288539fc0408ed4b69a99665de33bbbc2c3c08fe DRTVWR-216 @@ -417,3 +417,4 @@ b23419a2748483c98f3b84b630468a21c88feba5 DRTVWR-292  0a5d409161ef2a89b28c9a741051dd2dedc707d6 DRTVWR-297  852b69ef0b5fe6b13b69cc2217282cc64de6afab 3.4.5-beta5  a49c715243a36a8a380504d14cb7416b3039c956 3.4.5-release +e6b8a92acffd693cd1459e4212e3dff1050acf67 DRTVWR-278 diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt index 4771923871..ae69d0b843 100644 --- a/indra/CMakeLists.txt +++ b/indra/CMakeLists.txt @@ -73,8 +73,7 @@ if (VIEWER)      add_dependencies(viewer linux-crash-logger-strip-target)    elseif (DARWIN)      add_subdirectory(${VIEWER_PREFIX}mac_crash_logger) -    add_subdirectory(${VIEWER_PREFIX}mac_updater) -    add_dependencies(viewer mac-updater mac-crash-logger) +    add_dependencies(viewer mac-crash-logger)    elseif (WINDOWS)      add_subdirectory(${VIEWER_PREFIX}win_crash_logger)      # cmake EXISTS requires an absolute path, see indra/cmake/Variables.cmake diff --git a/indra/mac_updater/AutoUpdater.nib/classes.nib b/indra/mac_updater/AutoUpdater.nib/classes.nib deleted file mode 100644 index ea58db1189..0000000000 --- a/indra/mac_updater/AutoUpdater.nib/classes.nib +++ /dev/null @@ -1,4 +0,0 @@ -{ -IBClasses = (); -IBVersion = 1; -} diff --git a/indra/mac_updater/AutoUpdater.nib/info.nib b/indra/mac_updater/AutoUpdater.nib/info.nib deleted file mode 100644 index a49a92385b..0000000000 --- a/indra/mac_updater/AutoUpdater.nib/info.nib +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> -<plist version="1.0"> -<dict> -	<key>IBDocumentLocation</key> -	<string>103 138 356 240 0 0 1280 1002 </string> -	<key>IBFramework Version</key> -	<string>362.0</string> -	<key>IBSystem Version</key> -	<string>7D24</string> -	<key>targetFramework</key> -	<string>IBCarbonFramework</string> -</dict> -</plist> diff --git a/indra/mac_updater/AutoUpdater.nib/objects.xib b/indra/mac_updater/AutoUpdater.nib/objects.xib deleted file mode 100644 index 310411b711..0000000000 --- a/indra/mac_updater/AutoUpdater.nib/objects.xib +++ /dev/null @@ -1,56 +0,0 @@ -<?xml version="1.0" standalone="yes"?> -<object class="NSIBObjectData"> -  <string name="targetFramework">IBCarbonFramework</string> -  <object name="rootObject" class="NSCustomObject" id="1"> -    <string name="customClass">NSApplication</string> -  </object> -  <array count="5" name="allObjects"> -    <object class="IBCarbonWindow" id="166"> -      <string name="windowRect">405 222 533 663 </string> -      <string name="title">Second Life Updater</string> -      <object name="rootControl" class="IBCarbonRootControl" id="167"> -        <string name="bounds">0 0 128 441 </string> -        <array count="3" name="subviews"> -          <object class="IBCarbonStaticText" id="181"> -            <string name="bounds">20 20 44 421 </string> -            <ostype name="controlSignature">what</ostype> -            <string name="title">Initializing…</string> -          </object> -          <object class="IBCarbonButton" id="183"> -            <string name="bounds">88 351 108 421 </string> -            <string name="title">Cancel</string> -            <ostype name="command">not!</ostype> -            <int name="buttonType">2</int> -          </object> -          <object class="IBCarbonProgressBar" id="193"> -            <string name="bounds">51 19 70 422 </string> -            <ostype name="controlSignature">prog</ostype> -            <int name="initialValue">50</int> -          </object> -        </array> -      </object> -      <boolean name="isResizable">FALSE</boolean> -      <int name="carbonWindowClass">2</int> -      <int name="themeBrush">3</int> -      <int name="windowPosition">7</int> -    </object> -    <reference idRef="167"/> -    <reference idRef="181"/> -    <reference idRef="183"/> -    <reference idRef="193"/> -  </array> -  <array count="5" name="allParents"> -    <reference idRef="1"/> -    <reference idRef="166"/> -    <reference idRef="167"/> -    <reference idRef="167"/> -    <reference idRef="167"/> -  </array> -  <dictionary count="2" name="nameTable"> -    <string>File's Owner</string> -    <reference idRef="1"/> -    <string>Updater</string> -    <reference idRef="166"/> -  </dictionary> -  <unsigned_int name="nextObjectID">194</unsigned_int> -</object> diff --git a/indra/mac_updater/CMakeLists.txt b/indra/mac_updater/CMakeLists.txt deleted file mode 100644 index 00dcedecaa..0000000000 --- a/indra/mac_updater/CMakeLists.txt +++ /dev/null @@ -1,73 +0,0 @@ -# -*- cmake -*- - -project(mac_updater) - -include(00-Common) -include(OpenSSL) -include(CURL) -include(CARes) -include(LLCommon) -include(LLVFS) -include(Linking) - -include_directories( -    ${LLCOMMON_INCLUDE_DIRS} -    ${LLVFS_INCLUDE_DIRS} -    ${CURL_INCLUDE_DIRS} -    ${CARES_INCLUDE_DIRS} -    ) - -set(mac_updater_SOURCE_FILES -    mac_updater.cpp -    ) - -set(mac_updater_HEADER_FILES -    CMakeLists.txt -    ) - -set_source_files_properties(${mac_updater_HEADER_FILES} -                            PROPERTIES HEADER_FILE_ONLY TRUE) - -list(APPEND mac_updater_SOURCE_FILES ${mac_updater_HEADER_FILES}) - - -set(mac_updater_RESOURCE_FILES -  AutoUpdater.nib/ -  ) -set_source_files_properties( -  ${mac_updater_RESOURCE_FILES} -  PROPERTIES -  HEADER_FILE_ONLY TRUE -  ) -SOURCE_GROUP("Resources" FILES ${mac_updater_RESOURCE_FILES}) -list(APPEND mac_updater_SOURCE_FILES ${mac_updater_RESOURCE_FILES}) - -add_executable(mac-updater -  MACOSX_BUNDLE -  ${mac_updater_SOURCE_FILES}) - -set_target_properties(mac-updater -  PROPERTIES -  MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist -  ) - -target_link_libraries(mac-updater -    ${LLVFS_LIBRARIES} -    ${OPENSSL_LIBRARIES} -    ${CRYPTO_LIBRARIES} -    ${CURL_LIBRARIES} -    ${CARES_LIBRARIES} -    ${LLCOMMON_LIBRARIES} -    ) - -add_custom_command( -  TARGET mac-updater POST_BUILD -  COMMAND ${CMAKE_COMMAND} -  ARGS -    -E -    copy_directory -    ${CMAKE_CURRENT_SOURCE_DIR}/AutoUpdater.nib -    ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/mac-updater.app/Contents/Resources/AutoUpdater.nib -  ) - -ll_deploy_sharedlibs_command(mac-updater)  diff --git a/indra/mac_updater/Info.plist b/indra/mac_updater/Info.plist deleted file mode 100644 index bb27fddb03..0000000000 --- a/indra/mac_updater/Info.plist +++ /dev/null @@ -1,26 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> -<plist version="1.0"> -<dict> -	<key>CFBundleDevelopmentRegion</key> -	<string>English</string> -	<key>CFBundleExecutable</key> -	<string>mac-updater</string> -	<key>CFBundleGetInfoString</key> -	<string></string> -	<key>CFBundleIconFile</key> -	<string></string> -	<key>CFBundleIdentifier</key> -	<string>com.secondlife.indra.autoupdater</string> -	<key>CFBundleInfoDictionaryVersion</key> -	<string>6.0</string> -	<key>CFBundlePackageType</key> -	<string>APPL</string> -	<key>CFBundleShortVersionString</key> -	<string></string> -	<key>CFBundleSignature</key> -	<string>????</string> -	<key>CFBundleVersion</key> -	<string>1.0.0</string> -</dict> -</plist> diff --git a/indra/mac_updater/mac_updater.cpp b/indra/mac_updater/mac_updater.cpp deleted file mode 100644 index aa45c5d23f..0000000000 --- a/indra/mac_updater/mac_updater.cpp +++ /dev/null @@ -1,1257 +0,0 @@ -/**  - * @file mac_updater.cpp - * @brief  - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 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$ - */ - -#include "linden_common.h" - -#include <boost/format.hpp> - -#include <libgen.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> - -#include <curl/curl.h> -#include <pthread.h> - -#include "llerror.h" -#include "lltimer.h" -#include "lldir.h" -#include "llfile.h" - -#include "llstring.h" - -#include <Carbon/Carbon.h> - -#include "llerrorcontrol.h" - -enum -{ -	kEventClassCustom = 'Cust', -	kEventCustomProgress = 'Prog', -	kEventParamCustomCurValue = 'Cur ', -	kEventParamCustomMaxValue = 'Max ', -	kEventParamCustomText = 'Text', -	kEventCustomDone = 'Done', -}; - -WindowRef gWindow = NULL; -EventHandlerRef gEventHandler = NULL; -OSStatus gFailure = noErr; -Boolean gCancelled = false; - -const char *gUpdateURL; -const char *gProductName; -const char *gBundleID; -const char *gDmgFile; -const char *gMarkerPath; - -void *updatethreadproc(void*); - -pthread_t updatethread; - -OSStatus setProgress(int cur, int max) -{ -	OSStatus err; -	ControlRef progressBar = NULL; -	ControlID id; - -	id.signature = 'prog'; -	id.id = 0; - -	err = GetControlByID(gWindow, &id, &progressBar); -	if(err == noErr) -	{ -		Boolean indeterminate; -		 -		if(max == 0) -		{ -			indeterminate = true; -			err = SetControlData(progressBar, kControlEntireControl, kControlProgressBarIndeterminateTag, sizeof(Boolean), (Ptr)&indeterminate); -		} -		else -		{ -			double percentage = (double)cur / (double)max; -			SetControlMinimum(progressBar, 0); -			SetControlMaximum(progressBar, 100); -			SetControlValue(progressBar, (SInt16)(percentage * 100)); - -			indeterminate = false; -			err = SetControlData(progressBar, kControlEntireControl, kControlProgressBarIndeterminateTag, sizeof(Boolean), (Ptr)&indeterminate); - -			Draw1Control(progressBar); -		} -	} - -	return(err); -} - -OSStatus setProgressText(CFStringRef text) -{ -	OSStatus err; -	ControlRef progressText = NULL; -	ControlID id; - -	id.signature = 'what'; -	id.id = 0; - -	err = GetControlByID(gWindow, &id, &progressText); -	if(err == noErr) -	{ -		err = SetControlData(progressText, kControlEntireControl, kControlStaticTextCFStringTag, sizeof(CFStringRef), (Ptr)&text); -		Draw1Control(progressText); -	} - -	return(err); -} - -OSStatus sendProgress(long cur, long max, CFStringRef text = NULL) -{ -	OSStatus result; -	EventRef evt; -	 -	result = CreateEvent(  -			NULL, -			kEventClassCustom,  -			kEventCustomProgress, -			0,  -			kEventAttributeNone,  -			&evt); -	 -	// This event needs to be targeted at the window so it goes to the window's handler. -	if(result == noErr) -	{ -		EventTargetRef target = GetWindowEventTarget(gWindow); -		result = SetEventParameter ( -			evt, -			kEventParamPostTarget, -			typeEventTargetRef, -			sizeof(target), -			&target); -	} - -	if(result == noErr) -	{ -		result = SetEventParameter ( -			evt, -			kEventParamCustomCurValue, -			typeLongInteger, -			sizeof(cur), -			&cur); -	} - -	if(result == noErr) -	{ -		result = SetEventParameter ( -			evt, -			kEventParamCustomMaxValue, -			typeLongInteger, -			sizeof(max), -			&max); -	} -	 -	if(result == noErr) -	{ -		if(text != NULL) -		{ -			result = SetEventParameter ( -				evt, -				kEventParamCustomText, -				typeCFStringRef, -				sizeof(text), -				&text); -		} -	} -	 -	if(result == noErr) -	{ -		// Send the event -		PostEventToQueue( -			GetMainEventQueue(), -			evt, -			kEventPriorityStandard); - -	} -	 -	return(result); -} - -OSStatus sendDone(void) -{ -	OSStatus result; -	EventRef evt; -	 -	result = CreateEvent(  -			NULL, -			kEventClassCustom,  -			kEventCustomDone, -			0,  -			kEventAttributeNone,  -			&evt); -	 -	// This event needs to be targeted at the window so it goes to the window's handler. -	if(result == noErr) -	{ -		EventTargetRef target = GetWindowEventTarget(gWindow); -		result = SetEventParameter ( -			evt, -			kEventParamPostTarget, -			typeEventTargetRef, -			sizeof(target), -			&target); -	} - -	if(result == noErr) -	{ -		// Send the event -		PostEventToQueue( -			GetMainEventQueue(), -			evt, -			kEventPriorityStandard); - -	} -	 -	return(result); -} - -OSStatus dialogHandler(EventHandlerCallRef handler, EventRef event, void *userdata) -{ -	OSStatus result = eventNotHandledErr; -	OSStatus err; -	UInt32 evtClass = GetEventClass(event); -	UInt32 evtKind = GetEventKind(event); -	 -	if((evtClass == kEventClassCommand) && (evtKind == kEventCommandProcess)) -	{ -		HICommand cmd; -		err = GetEventParameter(event, kEventParamDirectObject, typeHICommand, NULL, sizeof(cmd), NULL, &cmd); -		 -		if(err == noErr) -		{ -			switch(cmd.commandID) -			{				 -				case kHICommandCancel: -					gCancelled = true; -//					QuitAppModalLoopForWindow(gWindow); -					result = noErr; -				break; -			} -		} -	} -	else if((evtClass == kEventClassCustom) && (evtKind == kEventCustomProgress)) -	{ -		// Request to update the progress dialog -		long cur = 0; -		long max = 0; -		CFStringRef text = NULL; -		(void) GetEventParameter(event, kEventParamCustomCurValue, typeLongInteger, NULL, sizeof(cur), NULL, &cur); -		(void) GetEventParameter(event, kEventParamCustomMaxValue, typeLongInteger, NULL, sizeof(max), NULL, &max); -		(void) GetEventParameter(event, kEventParamCustomText, typeCFStringRef, NULL, sizeof(text), NULL, &text); -		 -		err = setProgress(cur, max); -		if(err == noErr) -		{ -			if(text != NULL) -			{ -				setProgressText(text); -			} -		} -		 -		result = noErr; -	} -	else if((evtClass == kEventClassCustom) && (evtKind == kEventCustomDone)) -	{ -		// We're done.  Exit the modal loop. -		QuitAppModalLoopForWindow(gWindow); -		result = noErr; -	} -	 -	return(result); -} - -#if 0 -size_t curl_download_callback(void *data, size_t size, size_t nmemb, -										  void *user_data) -{ -	S32 bytes = size * nmemb; -	char *cdata = (char *) data; -	for (int i =0; i < bytes; i += 1) -	{ -		gServerResponse.append(cdata[i]); -	} -	return bytes; -} -#endif - -int curl_progress_callback_func(void *clientp, -							  double dltotal, -							  double dlnow, -							  double ultotal, -							  double ulnow) -{ -	int max = (int)(dltotal / 1024.0); -	int cur = (int)(dlnow / 1024.0); -	sendProgress(cur, max); -	 -	if(gCancelled) -		return(1); - -	return(0); -} - -int parse_args(int argc, char **argv) -{ -	int j; - -	for (j = 1; j < argc; j++)  -	{ -		if ((!strcmp(argv[j], "-url")) && (++j < argc))  -		{ -			gUpdateURL = argv[j]; -		} -		else if ((!strcmp(argv[j], "-name")) && (++j < argc))  -		{ -			gProductName = argv[j]; -		} -		else if ((!strcmp(argv[j], "-bundleid")) && (++j < argc))  -		{ -			gBundleID = argv[j]; -		} -		else if ((!strcmp(argv[j], "-dmg")) && (++j < argc))  -		{ -			gDmgFile = argv[j]; -		} -		else if ((!strcmp(argv[j], "-marker")) && (++j < argc))  -		{ -			gMarkerPath = argv[j];; -		} -	} - -	return 0; -} - -int main(int argc, char **argv) -{ -	// We assume that all the logs we're looking for reside on the current drive -	gDirUtilp->initAppDirs("SecondLife"); - -	LLError::initForApplication( gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); - -	// Rename current log file to ".old" -	std::string old_log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "updater.log.old"); -	std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "updater.log"); -	LLFile::rename(log_file.c_str(), old_log_file.c_str()); - -	// Set the log file to updater.log -	LLError::logToFile(log_file); - -	///////////////////////////////////////// -	// -	// Process command line arguments -	// -	gUpdateURL  = NULL; -	gProductName = NULL; -	gBundleID = NULL; -	gDmgFile = NULL; -	gMarkerPath = NULL; -	parse_args(argc, argv); -	if ((gUpdateURL == NULL) && (gDmgFile == NULL)) -	{ -		llinfos << "Usage: mac_updater -url <url> | -dmg <dmg file> [-name <product_name>] [-program <program_name>]" << llendl; -		exit(1); -	} -	else -	{ -		llinfos << "Update url is: " << gUpdateURL << llendl; -		if (gProductName) -		{ -			llinfos << "Product name is: " << gProductName << llendl; -		} -		else -		{ -			gProductName = "Second Life"; -		} -		if (gBundleID) -		{ -			llinfos << "Bundle ID is: " << gBundleID << llendl; -		} -		else -		{ -			gBundleID = "com.secondlife.indra.viewer"; -		} -	} -	 -	llinfos << "Starting " << gProductName << " Updater" << llendl; - -	// Real UI... -	OSStatus err; -	IBNibRef nib = NULL; -	 -	err = CreateNibReference(CFSTR("AutoUpdater"), &nib); - -	char windowTitle[MAX_PATH];		/* Flawfinder: ignore */ -	snprintf(windowTitle, sizeof(windowTitle), "%s Updater", gProductName);		 -	CFStringRef windowTitleRef = NULL; -	windowTitleRef = CFStringCreateWithCString(NULL, windowTitle, kCFStringEncodingUTF8); -	 -	if(err == noErr) -	{ -		err = CreateWindowFromNib(nib, CFSTR("Updater"), &gWindow); -	} - -	if (err == noErr) -	{ -		err = SetWindowTitleWithCFString(gWindow, windowTitleRef);	 -	} -	CFRelease(windowTitleRef); - -	if(err == noErr) -	{ -		// Set up an event handler for the window. -		EventTypeSpec handlerEvents[] =  -		{ -			{ kEventClassCommand, kEventCommandProcess }, -			{ kEventClassCustom, kEventCustomProgress }, -			{ kEventClassCustom, kEventCustomDone } -		}; -		InstallStandardEventHandler(GetWindowEventTarget(gWindow)); -		InstallWindowEventHandler( -				gWindow,  -				NewEventHandlerUPP(dialogHandler),  -				GetEventTypeCount (handlerEvents),  -				handlerEvents,  -				0,  -				&gEventHandler); -	} -	 -	if(err == noErr) -	{ -		ShowWindow(gWindow); -		SelectWindow(gWindow); -	} -		 -	if(err == noErr) -	{ -		pthread_create(&updatethread,  -                         NULL, -                         &updatethreadproc,  -                         NULL); -						  -	} -	 -	if(err == noErr) -	{ -		RunAppModalLoopForWindow(gWindow); -	} - -	void *threadresult; - -	pthread_join(updatethread, &threadresult); - -	if(!gCancelled && (gFailure != noErr)) -	{ -		// Something went wrong.  Since we always just tell the user to download a new version, we don't really care what. -		AlertStdCFStringAlertParamRec params; -		SInt16 retval_mac = 1; -		DialogRef alert = NULL; -		OSStatus err; - -		params.version = kStdCFStringAlertVersionOne; -		params.movable = false; -		params.helpButton = false; -		params.defaultText = (CFStringRef)kAlertDefaultOKText; -		params.cancelText = 0; -		params.otherText = 0; -		params.defaultButton = 1; -		params.cancelButton = 0; -		params.position = kWindowDefaultPosition; -		params.flags = 0; - -		err = CreateStandardAlert( -				kAlertStopAlert, -				CFSTR("Error"), -				CFSTR("An error occurred while updating Second Life.  Please download the latest version from www.secondlife.com."), -				¶ms, -				&alert); -		 -		if(err == noErr) -		{ -			err = RunStandardAlert( -					alert, -					NULL, -					&retval_mac); -		} -		 -		if(gMarkerPath != 0) -		{ -			// Create a install fail marker that can be used by the viewer to -			// detect install problems. -			std::ofstream stream(gMarkerPath); -			if(stream) stream << -1; -		} -		exit(-1); -	} else { -		exit(0); -	} - -	if(gWindow != NULL) -	{ -		DisposeWindow(gWindow); -	} -	 -	if(nib != NULL) -	{ -		DisposeNibReference(nib); -	} -	 -	return 0; -} - -bool isDirWritable(FSRef &dir) -{ -	bool result = false; -	 -	// Test for a writable directory by creating a directory, then deleting it again. -	// This is kinda lame, but will pretty much always give the right answer. -	 -	OSStatus err = noErr; -	char temp[PATH_MAX] = "";		/* Flawfinder: ignore */ - -	err = FSRefMakePath(&dir, (UInt8*)temp, sizeof(temp)); - -	if(err == noErr) -	{ -		strncat(temp, "/.test_XXXXXX", (sizeof(temp) - strlen(temp)) - 1); -		 -		if(mkdtemp(temp) != NULL) -		{ -			// We were able to make the directory.  This means the directory is writable. -			result = true; -			 -			// Clean up. -			rmdir(temp); -		} -	} - -#if 0 -	// This seemed like a good idea, but won't tell us if we're on a volume mounted read-only. -	UInt8 perm; -	err = FSGetUserPrivilegesPermissions(&targetParentRef, &perm, NULL); -	if(err == noErr) -	{ -		if(perm & kioACUserNoMakeChangesMask) -		{ -			// Parent directory isn't writable. -			llinfos << "Target parent directory not writable." << llendl; -			err = -1; -			replacingTarget = false; -		} -	} -#endif - -	return result; -} - -static std::string HFSUniStr255_to_utf8str(const HFSUniStr255* src) -{ -	llutf16string string16((U16*)&(src->unicode), src->length); -	std::string result = utf16str_to_utf8str(string16); -	return result; -} - -int restoreObject(const char* aside, const char* target, const char* path, const char* object) -{ -	char source[PATH_MAX] = "";		/* Flawfinder: ignore */ -	char dest[PATH_MAX] = "";		/* Flawfinder: ignore */ -	snprintf(source, sizeof(source), "%s/%s/%s", aside, path, object);		 -	snprintf(dest, sizeof(dest), "%s/%s", target, path);		 -	FSRef sourceRef; -	FSRef destRef; -	OSStatus err; -	err = FSPathMakeRef((UInt8 *)source, &sourceRef, NULL); -	if(err != noErr) return false; -	err = FSPathMakeRef((UInt8 *)dest, &destRef, NULL); -	if(err != noErr) return false; - -	llinfos << "Copying " << source << " to " << dest << llendl; - -	err = FSCopyObjectSync( -			&sourceRef, -			&destRef, -			NULL, -			NULL, -			kFSFileOperationOverwrite); - -	if(err != noErr) return false; -	return true; -} - -// Replace any mention of "Second Life" with the product name. -void filterFile(const char* filename) -{ -	char temp[PATH_MAX] = "";		/* Flawfinder: ignore */ -	// First copy the target's version, so we can run it through sed. -	snprintf(temp, sizeof(temp), "cp '%s' '%s.tmp'", filename, filename);		 -	system(temp);		/* Flawfinder: ignore */ - -	// Now run it through sed. -	snprintf(temp, sizeof(temp), 		 -			"sed 's/Second Life/%s/g' '%s.tmp' > '%s'", gProductName, filename, filename); -	system(temp);		/* Flawfinder: ignore */ -} - -static bool isFSRefViewerBundle(FSRef *targetRef) -{ -	bool result = false; -	CFURLRef targetURL = NULL; -	CFBundleRef targetBundle = NULL; -	CFStringRef targetBundleID = NULL; -	CFStringRef sourceBundleID = NULL; - -	targetURL = CFURLCreateFromFSRef(NULL, targetRef); - -	if(targetURL == NULL) -	{ -		llinfos << "Error creating target URL." << llendl; -	} -	else -	{ -		targetBundle = CFBundleCreate(NULL, targetURL); -	} -	 -	if(targetBundle == NULL) -	{ -		llinfos << "Failed to create target bundle." << llendl; -	} -	else -	{ -		targetBundleID = CFBundleGetIdentifier(targetBundle); -	} -	 -	if(targetBundleID == NULL) -	{ -		llinfos << "Couldn't retrieve target bundle ID." << llendl; -	} -	else -	{ -		sourceBundleID = CFStringCreateWithCString(NULL, gBundleID, kCFStringEncodingUTF8); -		if(CFStringCompare(sourceBundleID, targetBundleID, 0) == kCFCompareEqualTo) -		{ -			// This is the bundle we're looking for. -			result = true; -		} -		else -		{ -			llinfos << "Target bundle ID mismatch." << llendl; -		} -	} -	 -	// Don't release targetBundleID -- since we don't retain it, it's released when targetBundle is released. -	if(targetURL != NULL) -		CFRelease(targetURL); -	if(targetBundle != NULL) -		CFRelease(targetBundle); -	 -	return result; -} - -// Search through the directory specified by 'parent' for an item that appears to be a Second Life viewer. -static OSErr findAppBundleOnDiskImage(FSRef *parent, FSRef *app) -{ -	FSIterator		iterator; -	bool			found = false; - -	OSErr err = FSOpenIterator( parent, kFSIterateFlat, &iterator ); -	if(!err) -	{ -		do -		{ -			ItemCount actualObjects = 0; -			Boolean containerChanged = false; -			FSCatalogInfo info; -			FSRef ref; -			HFSUniStr255 unicodeName; -			err = FSGetCatalogInfoBulk(  -					iterator,  -					1,  -					&actualObjects,  -					&containerChanged, -					kFSCatInfoNodeFlags,  -					&info,  -					&ref, -					NULL,  -					&unicodeName ); -			 -			if(actualObjects == 0) -				break; -				 -			if(!err) -			{ -				// Call succeeded and not done with the iteration. -				std::string name = HFSUniStr255_to_utf8str(&unicodeName); - -				llinfos << "Considering \"" << name << "\"" << llendl; - -				if(info.nodeFlags & kFSNodeIsDirectoryMask) -				{ -					// This is a directory.  See if it's a .app -					if(name.find(".app") != std::string::npos) -					{ -						// Looks promising.  Check to see if it has the right bundle identifier. -						if(isFSRefViewerBundle(&ref)) -						{ -							llinfos << name << " is the one" << llendl; -							// This is the one.  Return it. -							*app = ref; -							found = true; -							break; -						} else { -							llinfos << name << " is not the bundle we are looking for; move along" << llendl; -						} - -					} -				} -			} -		} -		while(!err); -		 -		llinfos << "closing the iterator" << llendl; -		 -		FSCloseIterator(iterator); -		 -		llinfos << "closed" << llendl; -	} -	 -	if(!err && !found) -		err = fnfErr; -		 -	return err; -} - -void *updatethreadproc(void*) -{ -	char tempDir[PATH_MAX] = "";		/* Flawfinder: ignore */ -	FSRef tempDirRef; -	char temp[PATH_MAX] = "";	/* Flawfinder: ignore */ -	// *NOTE: This buffer length is used in a scanf() below. -	char deviceNode[1024] = "";	/* Flawfinder: ignore */ -	LLFILE *downloadFile = NULL; -	OSStatus err; -	ProcessSerialNumber psn; -	char target[PATH_MAX] = "";		/* Flawfinder: ignore */ -	FSRef targetRef; -	FSRef targetParentRef; -	FSVolumeRefNum targetVol; -	FSRef trashFolderRef; -	Boolean replacingTarget = false; - -	memset(&tempDirRef, 0, sizeof(tempDirRef)); -	memset(&targetRef, 0, sizeof(targetRef)); -	memset(&targetParentRef, 0, sizeof(targetParentRef)); -	 -	try -	{ -		// Attempt to get a reference to the Second Life application bundle containing this updater. -		// Any failures during this process will cause us to default to updating /Applications/Second Life.app -		{ -			FSRef myBundle; - -			err = GetCurrentProcess(&psn); -			if(err == noErr) -			{ -				err = GetProcessBundleLocation(&psn, &myBundle); -			} - -			if(err == noErr) -			{ -				// Sanity check:  Make sure the name of the item referenced by targetRef is "Second Life.app". -				FSRefMakePath(&myBundle, (UInt8*)target, sizeof(target)); -				 -				llinfos << "Updater bundle location: " << target << llendl; -			} -			 -			// Our bundle should be in Second Life.app/Contents/Resources/AutoUpdater.app -			// so we need to go up 3 levels to get the path to the main application bundle. -			if(err == noErr) -			{ -				err = FSGetCatalogInfo(&myBundle, kFSCatInfoNone, NULL, NULL, NULL, &targetRef); -			} -			if(err == noErr) -			{ -				err = FSGetCatalogInfo(&targetRef, kFSCatInfoNone, NULL, NULL, NULL, &targetRef); -			} -			if(err == noErr) -			{ -				err = FSGetCatalogInfo(&targetRef, kFSCatInfoNone, NULL, NULL, NULL, &targetRef); -			} -			 -			// And once more to get the parent of the target -			if(err == noErr) -			{ -				err = FSGetCatalogInfo(&targetRef, kFSCatInfoNone, NULL, NULL, NULL, &targetParentRef); -			} -			 -			if(err == noErr) -			{ -				FSRefMakePath(&targetRef, (UInt8*)target, sizeof(target)); -				llinfos << "Path to target: " << target << llendl; -			} -			 -			// Sanity check: make sure the target is a bundle with the right identifier -			if(err == noErr) -			{ -				// Assume the worst... -				err = -1; - -				if(isFSRefViewerBundle(&targetRef)) -				{ -					// This is the bundle we're looking for. -					err = noErr; -					replacingTarget = true; -				} -			} -			 -			// Make sure the target's parent directory is writable. -			if(err == noErr) -			{ -				if(!isDirWritable(targetParentRef)) -				{ -					// Parent directory isn't writable. -					llinfos << "Target parent directory not writable." << llendl; -					err = -1; -					replacingTarget = false; -				} -			} - -			if(err != noErr) -			{ -				Boolean isDirectory; -				llinfos << "Target search failed, defaulting to /Applications/" << gProductName << ".app." << llendl; -				 -				// Set up the parent directory -				err = FSPathMakeRef((UInt8*)"/Applications", &targetParentRef, &isDirectory); -				if((err != noErr) || (!isDirectory)) -				{ -					// We're so hosed. -					llinfos << "Applications directory not found, giving up." << llendl; -					throw 0; -				} -				 -				snprintf(target, sizeof(target), "/Applications/%s.app", gProductName);		 - -				memset(&targetRef, 0, sizeof(targetRef)); -				err = FSPathMakeRef((UInt8*)target, &targetRef, NULL); -				if(err == fnfErr) -				{ -					// This is fine, just means we're not replacing anything. -					err = noErr; -					replacingTarget = false; -				} -				else -				{ -					replacingTarget = true; -				} - -				// Make sure the target's parent directory is writable. -				if(err == noErr) -				{ -					if(!isDirWritable(targetParentRef)) -					{ -						// Parent directory isn't writable. -						llinfos << "Target parent directory not writable." << llendl; -						err = -1; -						replacingTarget = false; -					} -				} - -			} -			 -			// If we haven't fixed all problems by this point, just bail. -			if(err != noErr) -			{ -				llinfos << "Unable to pick a target, giving up." << llendl; -				throw 0; -			} -		} -		 -		// Find the volID of the volume the target resides on -		{ -			FSCatalogInfo info; -			err = FSGetCatalogInfo( -				&targetParentRef, -				kFSCatInfoVolume, -				&info, -				NULL,  -				NULL,   -				NULL); -				 -			if(err != noErr) -				throw 0; -			 -			targetVol = info.volume; -		} - -		// Find the temporary items and trash folders on that volume. -		err = FSFindFolder( -			targetVol, -			kTrashFolderType, -			true, -			&trashFolderRef); - -		if(err != noErr) -			throw 0; - -#if 0 // *HACK for DEV-11935 see below for details. - -		FSRef tempFolderRef; - -		err = FSFindFolder( -			targetVol, -			kTemporaryFolderType, -			true, -			&tempFolderRef); -		 -		if(err != noErr) -			throw 0; -		 -		err = FSRefMakePath(&tempFolderRef, (UInt8*)temp, sizeof(temp)); - -		if(err != noErr) -			throw 0; - -#else		 - -		// *HACK for DEV-11935  the above kTemporaryFolderType query was giving -		// back results with path names that seem to be too long to be used as -		// mount points.  I suspect this incompatibility was introduced in the -		// Leopard 10.5.2 update, but I have not verified this.  -		char const HARDCODED_TMP[] = "/tmp"; -		strncpy(temp, HARDCODED_TMP, sizeof(HARDCODED_TMP)); - -#endif // 0 *HACK for DEV-11935 -		 -		// Skip downloading the file if the dmg was passed on the command line. -		std::string dmgName; -		if(gDmgFile != NULL) { -			dmgName = basename((char *)gDmgFile); -			char * dmgDir = dirname((char *)gDmgFile); -			strncpy(tempDir, dmgDir, sizeof(tempDir)); -			err = FSPathMakeRef((UInt8*)tempDir, &tempDirRef, NULL); -			if(err != noErr) throw 0; -			chdir(tempDir); -			goto begin_install; -		} else { -			// Continue on to download file. -			dmgName = "SecondLife.dmg"; -		} - -		 -		strncat(temp, "/SecondLifeUpdate_XXXXXX", (sizeof(temp) - strlen(temp)) - 1); -		if(mkdtemp(temp) == NULL) -		{ -			throw 0; -		} -		 -		strncpy(tempDir, temp, sizeof(tempDir)); -		temp[sizeof(tempDir) - 1] = '\0'; -		 -		llinfos << "tempDir is " << tempDir << llendl; - -		err = FSPathMakeRef((UInt8*)tempDir, &tempDirRef, NULL); - -		if(err != noErr) -			throw 0; -				 -		chdir(tempDir); -		 -		snprintf(temp, sizeof(temp), "SecondLife.dmg");		 -		 -		downloadFile = LLFile::fopen(temp, "wb");		/* Flawfinder: ignore */ -		if(downloadFile == NULL) -		{ -			throw 0; -		} - -		{ -			CURL *curl = curl_easy_init(); - -			curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); -	//		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &curl_download_callback); -			curl_easy_setopt(curl, CURLOPT_FILE, downloadFile); -			curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0); -			curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, &curl_progress_callback_func); -			curl_easy_setopt(curl, CURLOPT_URL,	gUpdateURL); -			curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); -			 -			sendProgress(0, 1, CFSTR("Downloading...")); -			 -			CURLcode result = curl_easy_perform(curl); -			 -			curl_easy_cleanup(curl); -			 -			if(gCancelled) -			{ -				llinfos << "User cancel, bailing out."<< llendl; -				throw 0; -			} -			 -			if(result != CURLE_OK) -			{ -				llinfos << "Error " << result << " while downloading disk image."<< llendl; -				throw 0; -			} -			 -			fclose(downloadFile); -			downloadFile = NULL; -		} - -	begin_install: -		sendProgress(0, 0, CFSTR("Mounting image...")); -		LLFile::mkdir("mnt", 0700); -		 -		// NOTE: we could add -private at the end of this command line to keep the image from showing up in the Finder, -		//		but if our cleanup fails, this makes it much harder for the user to unmount the image. -		std::string mountOutput; -		boost::format cmdFormat("hdiutil attach %s -mountpoint mnt"); -		cmdFormat % dmgName; -		FILE* mounter = popen(cmdFormat.str().c_str(), "r");		/* Flawfinder: ignore */ -		 -		if(mounter == NULL) -		{ -			llinfos << "Failed to mount disk image, exiting."<< llendl; -			throw 0; -		} -		 -		// We need to scan the output from hdiutil to find the device node it uses to attach the disk image. -		// If we don't have this information, we can't detach it later. -		while(mounter != NULL) -		{ -			size_t len = fread(temp, 1, sizeof(temp)-1, mounter); -			temp[len] = 0; -			mountOutput.append(temp); -			if(len < sizeof(temp)-1) -			{ -				// End of file or error. -				int result = pclose(mounter); -				if(result != 0) -				{ -					// NOTE: We used to abort here, but pclose() started returning  -					// -1, possibly when the size of the DMG passed a certain point  -					llinfos << "Unexpected result closing pipe: " << result << llendl;  -				} -				mounter = NULL; -			} -		} -		 -		if(!mountOutput.empty()) -		{ -			const char *s = mountOutput.c_str(); -			const char *prefix = "/dev/"; -			char *sub = strstr(s, prefix); -			 -			if(sub != NULL) -			{ -				sub += strlen(prefix);	/* Flawfinder: ignore */ -				sscanf(sub, "%1023s", deviceNode);	/* Flawfinder: ignore */ -			} -		} -		 -		if(deviceNode[0] != 0) -		{ -			llinfos << "Disk image attached on /dev/" << deviceNode << llendl; -		} -		else -		{ -			llinfos << "Disk image device node not found!" << llendl; -			throw 0;  -		} -		 -		// Get an FSRef to the new application on the disk image -		FSRef sourceRef; -		FSRef mountRef; -		snprintf(temp, sizeof(temp), "%s/mnt", tempDir);		 - -		llinfos << "Disk image mount point is: " << temp << llendl; - -		err = FSPathMakeRef((UInt8 *)temp, &mountRef, NULL); -		if(err != noErr) -		{ -			llinfos << "Couldn't make FSRef to disk image mount point." << llendl; -			throw 0; -		} - -		sendProgress(0, 0, CFSTR("Searching for the app bundle...")); -		err = findAppBundleOnDiskImage(&mountRef, &sourceRef); -		if(err != noErr) -		{ -			llinfos << "Couldn't find application bundle on mounted disk image." << llendl; -			throw 0; -		} -		else -		{ -			llinfos << "found the bundle." << llendl; -		} - -		sendProgress(0, 0, CFSTR("Preparing to copy files...")); -		 -		FSRef asideRef; -		char aside[MAX_PATH];		/* Flawfinder: ignore */ -		 -		// this will hold the name of the destination target -		CFStringRef appNameRef; - -		if(replacingTarget) -		{ -			// Get the name of the target we're replacing -			HFSUniStr255 appNameUniStr; -			err = FSGetCatalogInfo(&targetRef, 0, NULL, &appNameUniStr, NULL, NULL); -			if(err != noErr) -				throw 0; -			appNameRef = FSCreateStringFromHFSUniStr(NULL, &appNameUniStr); -			 -			// Move aside old version (into work directory) -			err = FSMoveObject(&targetRef, &tempDirRef, &asideRef); -			if(err != noErr) -			{ -				llwarns << "failed to move aside old version (error code " <<  -					err << ")" << llendl; -				throw 0; -			} - -			// Grab the path for later use. -			err = FSRefMakePath(&asideRef, (UInt8*)aside, sizeof(aside)); -		} -		else -		{ -			// Construct the name of the target based on the product name -			char appName[MAX_PATH];		/* Flawfinder: ignore */ -			snprintf(appName, sizeof(appName), "%s.app", gProductName);		 -			appNameRef = CFStringCreateWithCString(NULL, appName, kCFStringEncodingUTF8); -		} -		 -		sendProgress(0, 0, CFSTR("Copying files...")); -		 -		llinfos << "Starting copy..." << llendl; - -		// Copy the new version from the disk image to the target location. -		err = FSCopyObjectSync( -				&sourceRef, -				&targetParentRef, -				appNameRef, -				&targetRef, -				kFSFileOperationDefaultOptions); -		 -		// Grab the path for later use. -		err = FSRefMakePath(&targetRef, (UInt8*)target, sizeof(target)); -		if(err != noErr) -			throw 0; - -		llinfos << "Copy complete. Target = " << target << llendl; - -		if(err != noErr) -		{ -			// Something went wrong during the copy.  Attempt to put the old version back and bail. -			(void)FSDeleteObject(&targetRef); -			if(replacingTarget) -			{ -				(void)FSMoveObject(&asideRef, &targetParentRef, NULL); -			} -			throw 0; -		} -		else -		{ -			// The update has succeeded.  Clear the cache directory. - -			sendProgress(0, 0, CFSTR("Clearing cache...")); -	 -			llinfos << "Clearing cache..." << llendl; -			 -			gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""), "*.*"); -			 -			llinfos << "Clear complete." << llendl; - -		} -	} -	catch(...) -	{ -		if(!gCancelled) -			if(gFailure == noErr) -				gFailure = -1; -	} - -	// Failures from here on out are all non-fatal and not reported. -	sendProgress(0, 3, CFSTR("Cleaning up...")); - -	// Close disk image file if necessary -	if(downloadFile != NULL) -	{ -		llinfos << "Closing download file." << llendl; - -		fclose(downloadFile); -		downloadFile = NULL; -	} - -	sendProgress(1, 3); -	// Unmount image -	if(deviceNode[0] != 0) -	{ -		llinfos << "Detaching disk image." << llendl; - -		snprintf(temp, sizeof(temp), "hdiutil detach '%s'", deviceNode);		 -		system(temp);		/* Flawfinder: ignore */ -	} - -	sendProgress(2, 3); - -	// Move work directory to the trash -	if(tempDir[0] != 0) -	{ -		llinfos << "Moving work directory to the trash." << llendl; - -		FSRef trashRef; -		OSStatus err = FSMoveObjectToTrashSync(&tempDirRef, &trashRef, 0);  -		if(err != noErr) { -			llwarns << "failed to move files to trash, (error code " << -				err << ")" << llendl; -		} -	} -	 -	if(!gCancelled  && !gFailure && (target[0] != 0)) -	{ -		llinfos << "Touching application bundle." << llendl; - -		snprintf(temp, sizeof(temp), "touch '%s'", target);		 -		system(temp);		/* Flawfinder: ignore */ - -		llinfos << "Launching updated application." << llendl; - -		snprintf(temp, sizeof(temp), "open '%s'", target);		 -		system(temp);		/* Flawfinder: ignore */ -	} - -	sendDone(); -	 -	return(NULL); -} diff --git a/indra/mac_updater/mac_updater.h b/indra/mac_updater/mac_updater.h deleted file mode 100644 index f65b481cb6..0000000000 --- a/indra/mac_updater/mac_updater.h +++ /dev/null @@ -1,91 +0,0 @@ -/**  - * @file mac_updater.h - * @brief  - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 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$ - */ - -#include <iostream> -#include <pthread.h> -#include <boost/filesystem.hpp> - -#ifndef LL_MAC_UPDATER_H -#define LL_MAC_UPDATER_H -extern bool gCancelled; -extern bool gFailure; - -void *updatethreadproc(void*); -std::string* walkParents( signed int depth, std::string* childpath ); -std::string* getUserTrashFolder(); - -void setProgress(int cur, int max); -void setProgressText(const std::string& str); -void sendProgress(int cur, int max, std::string str); -void sendDone(); -void sendStopAlert(); - -bool isFSRefViewerBundle(const std::string& targetURL); -bool isDirWritable(const std::string& dir_name); -bool mkTempDir(boost::filesystem::path& temp_dir); -bool copyDir(const std::string& src_dir, const std::string& dest_dir); - -int oldmain(); - -class LLMacUpdater -{ -public: -    LLMacUpdater(); -    void doUpdate(); -    const std::string walkParents( signed int depth, const std::string& childpath ); -    bool isApplication(const std::string& app_str); -    void filterFile(const char* filename); - -    bool findAppBundleOnDiskImage(const boost::filesystem::path& dir_path, -                                  boost::filesystem::path& path_found); - -    bool verifyDirectory(const boost::filesystem::path* directory, bool isParent=false); -    bool getViewerDir(boost::filesystem::path &app_dir); -    bool downloadDMG(const std::string& dmgName, boost::filesystem::path* temp_dir); -    bool doMount(const std::string& dmgName, char* deviceNode, const boost::filesystem::path& temp_dir); -    bool moveApplication (const boost::filesystem::path& app_dir,  -                          const boost::filesystem::path& temp_dir,  -                          boost::filesystem::path& aside_dir); -    bool doInstall(const boost::filesystem::path& app_dir,  -                   const boost::filesystem::path& temp_dir, -                   boost::filesystem::path& mount_dir, -                   bool replacingTarget); -    void* updatethreadproc(void*); -    static void* sUpdatethreadproc(void*); - -public: -    std::string *mUpdateURL; -    std::string *mProductName; -    std::string *mBundleID; -    std::string *mDmgFile; -    std::string *mMarkerPath; -    std::string *mApplicationPath; -    static LLMacUpdater *sInstance; - -}; -#endif - - diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 002c826a30..0b21d6c8fb 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -2000,7 +2000,7 @@ if (DARWIN)        generate_viewer_version      ) -  add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_quicktime media_plugin_webkit mac-updater mac-crash-logger) +  add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_quicktime media_plugin_webkit mac-crash-logger)    if (ENABLE_SIGNING)        set(SIGNING_SETTING "--signature=${SIGNING_IDENTITY}") @@ -2056,12 +2056,11 @@ if (PACKAGE)      # *TODO: Generate these search dirs in the cmake files related to each binary.      list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/llplugin/slplugin/${CMAKE_CFG_INTDIR}")      list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/mac_crash_logger/${CMAKE_CFG_INTDIR}") -    list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/mac_updater/${CMAKE_CFG_INTDIR}")      list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/media_plugins/gstreamer010/${CMAKE_CFG_INTDIR}")      list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/media_plugins/quicktime/${CMAKE_CFG_INTDIR}")      list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/media_plugins/webkit/${CMAKE_CFG_INTDIR}")      set(VIEWER_SYMBOL_FILE "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/secondlife-symbols-darwin.tar.bz2") -    set(VIEWER_EXE_GLOBS "'Second Life' SLPlugin mac-updater mac-crash-logger") +    set(VIEWER_EXE_GLOBS "'Second Life' SLPlugin mac-crash-logger")      set(VIEWER_LIB_GLOB "*.dylib")    endif (DARWIN)    if (LINUX) diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index b3c0e650ec..9f06dca17a 100644 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -635,7 +635,9 @@ class DarwinManifest(ViewerManifest):              self.path("../packages/lib/release/libndofdev.dylib", dst="Resources/libndofdev.dylib")              self.path("../packages/lib/release/libhunspell-1.3.0.dylib", dst="Resources/libhunspell-1.3.0.dylib") -            self.path("../viewer_components/updater/scripts/darwin/update_install", "MacOS/update_install") +            if self.prefix(dst="MacOS"): +                self.path2basename("../viewer_components/updater/scripts/darwin", "*.py") +                self.end_prefix()              # most everything goes in the Resources directory              if self.prefix(src="", dst="Resources"): @@ -731,7 +733,6 @@ class DarwinManifest(ViewerManifest):                  # our apps                  for app_bld_dir, app in (("mac_crash_logger", "mac-crash-logger.app"), -                                         ("mac_updater", "mac-updater.app"),                                           # plugin launcher                                           (os.path.join("llplugin", "slplugin"), "SLPlugin.app"),                                           ): @@ -777,7 +778,7 @@ class DarwinManifest(ViewerManifest):      def copy_finish(self):          # Force executable permissions to be set for scripts          # see CHOP-223 and http://mercurial.selenic.com/bts/issue1802 -        for script in 'Contents/MacOS/update_install',: +        for script in 'Contents/MacOS/update_install.py',:              self.run_command("chmod +x %r" % os.path.join(self.get_dst_prefix(), script))      def package_finish(self): diff --git a/indra/viewer_components/updater/llupdaterservice.cpp b/indra/viewer_components/updater/llupdaterservice.cpp index 324b051b21..c1e57122ee 100644 --- a/indra/viewer_components/updater/llupdaterservice.cpp +++ b/indra/viewer_components/updater/llupdaterservice.cpp @@ -65,6 +65,8 @@ namespace  	{  #ifdef LL_WINDOWS  		std::string scriptFile = "update_install.bat"; +#elif LL_DARWIN +		std::string scriptFile = "update_install.py";  #else  		std::string scriptFile = "update_install";  #endif @@ -76,6 +78,8 @@ namespace  #ifdef LL_WINDOWS  		return LL_COPY_INSTALL_SCRIPT_TO_TEMP;  #else +		// This is important on Mac because update_install.py looks at its own +		// script pathname to discover the viewer app bundle to update.  		return LL_RUN_INSTALL_SCRIPT_IN_PLACE;  #endif  	}; diff --git a/indra/viewer_components/updater/scripts/darwin/janitor.py b/indra/viewer_components/updater/scripts/darwin/janitor.py new file mode 100644 index 0000000000..cdf33df731 --- /dev/null +++ b/indra/viewer_components/updater/scripts/darwin/janitor.py @@ -0,0 +1,133 @@ +#!/usr/bin/python +"""\ +@file   janitor.py +@author Nat Goodspeed +@date   2011-09-14 +@brief  Janitor class to clean up arbitrary resources + +2013-01-04 cloned from vita because it's exactly what update_install.py needs. + +$LicenseInfo:firstyear=2011&license=viewerlgpl$ +Copyright (c) 2011, Linden Research, Inc. +$/LicenseInfo$ +""" + +import sys +import functools +import itertools + +class Janitor(object): +    """ +    Usage: + +    Basic: +    self.janitor = Janitor(sys.stdout) # report cleanup actions on stdout +    ... +    self.janitor.later(os.remove, some_temp_file) +    self.janitor.later(os.remove, some_other_file) +    ... +    self.janitor.cleanup()          # perform cleanup actions + +    Context Manager: +    with Janitor() as janitor:      # clean up quietly +        ... +        janitor.later(shutil.rmtree, some_temp_directory) +        ... +    # exiting 'with' block performs cleanup + +    Test Class: +    class TestMySoftware(unittest.TestCase, Janitor): +        def __init__(self): +            Janitor.__init__(self)  # quiet cleanup +            ... + +        def setUp(self): +            ... +            self.later(os.rename, saved_file, original_location) +            ... + +        def tearDown(self): +            Janitor.tearDown(self)  # calls cleanup() +            ... +            # Or, if you have no other tearDown() logic for +            # TestMySoftware, you can omit the TestMySoftware.tearDown() +            # def entirely and let it inherit Janitor.tearDown(). +    """ +    def __init__(self, stream=None): +        """ +        If you pass stream= (e.g.) sys.stdout or sys.stderr, Janitor will +        report its cleanup operations as it performs them. If you don't, it +        will perform them quietly -- unless one or more of the actions throws +        an exception, in which case you'll get output on stderr. +        """ +        self.stream   = stream +        self.cleanups = [] + +    def later(self, func, *args, **kwds): +        """ +        Pass the callable you want to call at cleanup() time, plus any +        positional or keyword args you want to pass it. +        """ +        # Get a name string for 'func' +        try: +            # A free function has a __name__ +            name = func.__name__ +        except AttributeError: +            try: +                # A class object (even builtin objects like ints!) support +                # __class__.__name__ +                name = func.__class__.__name__ +            except AttributeError: +                # Shrug! Just use repr() to get a string describing this func. +                name = repr(func) +        # Construct a description of this operation in Python syntax from +        # args, kwds. +        desc = "%s(%s)" % \ +               (name, ", ".join(itertools.chain((repr(a) for a in args), +                                                ("%s=%r" % (k, v) for (k, v) in kwds.iteritems())))) +        # Use functools.partial() to bind passed args and keywords to the +        # passed func so we get a nullary callable that does what caller +        # wants. +        bound = functools.partial(func, *args, **kwds) +        self.cleanups.append((desc, bound)) + +    def cleanup(self): +        """ +        Perform all the actions saved with later() calls. +        """ +        # Typically one allocates resource A, then allocates resource B that +        # depends on it. In such a scenario it's appropriate to delete B +        # before A -- so perform cleanup actions in reverse order. (This is +        # the same strategy used by atexit().) +        while self.cleanups: +            # Until our list is empty, pop the last pair. +            desc, bound = self.cleanups.pop(-1) + +            # If requested, report the action. +            if self.stream is not None: +                print >>self.stream, desc + +            try: +                # Call the bound callable +                bound() +            except Exception, err: +                # This is cleanup. Report the problem but continue. +                print >>(self.stream or sys.stderr), "Calling %s\nraised  %s: %s" % \ +                      (desc, err.__class__.__name__, err) + +    def tearDown(self): +        """ +        If a unittest.TestCase subclass (or a nose test class) adds Janitor as +        one of its base classes, and has no other tearDown() logic, let it +        inherit Janitor.tearDown(). +        """ +        self.cleanup() + +    def __enter__(self): +        return self + +    def __exit__(self, type, value, tb): +        # Perform cleanup no matter how we exit this 'with' statement +        self.cleanup() +        # Propagate any exception from the 'with' statement, don't swallow it +        return False diff --git a/indra/viewer_components/updater/scripts/darwin/messageframe.py b/indra/viewer_components/updater/scripts/darwin/messageframe.py new file mode 100644 index 0000000000..8f58848882 --- /dev/null +++ b/indra/viewer_components/updater/scripts/darwin/messageframe.py @@ -0,0 +1,66 @@ +#!/usr/bin/python +"""\ +@file   messageframe.py +@author Nat Goodspeed +@date   2013-01-03 +@brief  Define MessageFrame class for popping up messages from a command-line +        script. + +$LicenseInfo:firstyear=2013&license=viewerlgpl$ +Copyright (c) 2013, Linden Research, Inc. +$/LicenseInfo$ +""" + +import Tkinter as tk +import os + +# Tricky way to obtain the filename of the main script (default title string) +import __main__ + +# This class is intended for displaying messages from a command-line script. +# Getting the base class right took a bit of trial and error. +# If you derive from tk.Frame, the destroy() method doesn't actually close it. +# If you derive from tk.Toplevel, it pops up a separate Tk frame too. destroy() +# closes this frame, but not that one. +# Deriving from tk.Tk appears to do the right thing. +class MessageFrame(tk.Tk): +    def __init__(self, text="", title=os.path.splitext(os.path.basename(__main__.__file__))[0], +                 width=320, height=120): +        tk.Tk.__init__(self) +        self.grid() +        self.title(title) +        self.var = tk.StringVar() +        self.var.set(text) +        self.msg = tk.Label(self, textvariable=self.var) +        self.msg.grid() +        # from http://stackoverflow.com/questions/3352918/how-to-center-a-window-on-the-screen-in-tkinter : +        self.update_idletasks() + +        # The constants below are to adjust for typical overhead from the +        # frame borders. +        xp = (self.winfo_screenwidth()  / 2) - (width  / 2) - 8 +        yp = (self.winfo_screenheight() / 2) - (height / 2) - 20 +        self.geometry('{0}x{1}+{2}+{3}'.format(width, height, xp, yp)) +        self.update() + +    def set(self, text): +        self.var.set(text) +        self.update() + +if __name__ == "__main__": +    # When run as a script, just test the MessageFrame. +    import sys +    import time + +    frame = MessageFrame("something in the way she moves....") +    time.sleep(3) +    frame.set("smaller") +    time.sleep(3) +    frame.set("""this has +several +lines""") +    time.sleep(3) +    frame.destroy() +    print "Destroyed!" +    sys.stdout.flush() +    time.sleep(3) diff --git a/indra/viewer_components/updater/scripts/darwin/update_install b/indra/viewer_components/updater/scripts/darwin/update_install deleted file mode 100644 index e7f36dc5a3..0000000000 --- a/indra/viewer_components/updater/scripts/darwin/update_install +++ /dev/null @@ -1,10 +0,0 @@ -#! /bin/bash - -# -# The first argument contains the path to the installer app.  The second a path -# to a marker file which should be created if the installer fails.q -# - -cd "$(dirname "$0")" -(../Resources/mac-updater.app/Contents/MacOS/mac-updater -dmg "$1" -name "Second Life Viewer"; if [ $? -ne 0 ]; then echo $3 >> "$2"; fi;) & -exit 0 diff --git a/indra/viewer_components/updater/scripts/darwin/update_install.py b/indra/viewer_components/updater/scripts/darwin/update_install.py new file mode 100755 index 0000000000..2fc6fcdb29 --- /dev/null +++ b/indra/viewer_components/updater/scripts/darwin/update_install.py @@ -0,0 +1,373 @@ +#!/usr/bin/python +"""\ +@file   update_install.py +@author Nat Goodspeed +@date   2012-12-20 +@brief  Update the containing Second Life application bundle to the version in +        the specified disk image file. + +        This Python implementation is derived from the previous mac-updater +        application, a funky mix of C++, classic C and Objective-C. + +$LicenseInfo:firstyear=2012&license=viewerlgpl$ +Copyright (c) 2012, Linden Research, Inc. +$/LicenseInfo$ +""" + +import os +import sys +import cgitb +import errno +import glob +import plistlib +import re +import shutil +import subprocess +import tempfile +import time +from janitor import Janitor +from messageframe import MessageFrame +import Tkinter, tkMessageBox + +TITLE = "Second Life Viewer Updater" +# Magic bundle identifier used by all Second Life viewer bundles +BUNDLE_IDENTIFIER = "com.secondlife.indra.viewer" + +# Global handle to the MessageFrame so we can update message +FRAME = None +# Global handle to logfile, once it's open +LOGF  = None + +# **************************************************************************** +#   Logging and messaging +# +#   This script is normally run implicitly by the old viewer to update to the +#   new viewer. Its UI consists of a MessageFrame and possibly a Tk error box. +#   Log details to updater.log -- especially uncaught exceptions! +# **************************************************************************** +def log(message): +    """write message only to LOGF (also called by status() and fail())""" +    # If we don't even have LOGF open yet, at least write to Console log +    logf = LOGF or sys.stderr +    logf.writelines((time.strftime("%Y-%m-%dT%H:%M:%SZ ", time.gmtime()), message, '\n')) +    logf.flush() + +def status(message): +    """display and log normal progress message""" +    log(message) + +    global FRAME +    if not FRAME: +        FRAME = MessageFrame(message, TITLE) +    else: +        FRAME.set(message) + +def fail(message): +    """log message, produce error box, then terminate with nonzero rc""" +    log(message) + +    # If we haven't yet called status() (we don't yet have a FRAME), perform a +    # bit of trickery to bypass the spurious "main window" that Tkinter would +    # otherwise pop up if the first call is showerror(). +    if not FRAME: +        root = Tkinter.Tk() +        root.withdraw() + +    # If we do have a LOGF available, mention it in the error box. +    if LOGF: +        message = "%s\n(Updater log in %s)" % (message, LOGF.name) + +    # We explicitly specify the WARNING icon because, at least on the Tkinter +    # bundled with the system-default Python 2.7 on Mac OS X 10.7.4, the +    # ERROR, QUESTION and INFO icons are all the silly Tk rocket ship. At +    # least WARNING has an exclamation in a yellow triangle, even though +    # overlaid by a smaller image of the rocket ship. +    tkMessageBox.showerror(TITLE, +"""An error occurred while updating Second Life: +%s +Please download the latest viewer from www.secondlife.com.""" % message, +                           icon=tkMessageBox.WARNING) +    sys.exit(1) + +def exception(err): +    """call fail() with an exception instance""" +    fail("%s exception: %s" % (err.__class__.__name__, str(err))) + +def excepthook(type, value, traceback): +    """ +    Store this hook function into sys.excepthook until we have a logfile. +    """ +    # At least in older Python versions, it could be tricky to produce a +    # string from 'type' and 'value'. For instance, an OSError exception would +    # pass type=OSError and value=some_tuple. Empirically, this funky +    # expression seems to work. +    exception(type(*value)) +sys.excepthook = excepthook + +class ExceptHook(object): +    """ +    Store an instance of this class into sys.excepthook once we have a logfile +    open. +    """ +    def __init__(self, logfile): +        # There's no magic to the cgitb.enable() function -- it merely stores +        # an instance of cgitb.Hook into sys.excepthook, passing enable()'s +        # params into Hook.__init__(). Sadly, enable() doesn't forward all its +        # params using (*args, **kwds) syntax -- another story. But the point +        # is that all the goodness is in the cgitb.Hook class. Capture an +        # instance. +        self.hook = cgitb.Hook(file=logfile, format="text") + +    def __call__(self, type, value, traceback): +        # produce nice text traceback to logfile +        self.hook(type, value, traceback) +        # Now display an error box. +        excepthook(type, value, traceback) + +def write_marker(markerfile, markertext): +    log("writing %r to %s" % (markertext, markerfile)) +    try: +        with open(markerfile, "w") as markerf: +            markerf.write(markertext) +    except IOError, err: +        # write_marker() is invoked by fail(), and fail() is invoked by other +        # error-handling functions. If we try to invoke any of those, we'll +        # get infinite recursion. If for any reason we can't write markerfile, +        # try to log it -- otherwise shrug. +        log("%s exception: %s" % (err.__class__.__name__, err)) + +# **************************************************************************** +#   Main script logic +# **************************************************************************** +def main(dmgfile, markerfile, markertext): +    # Should we fail, we're supposed to write 'markertext' to 'markerfile'. +    # Wrap the fail() function so we do that. +    global fail +    oldfail = fail +    def fail(message): +        write_marker(markerfile, markertext) +        oldfail(message) + +    try: +        # Starting with the Cocoafied viewer, we'll find viewer logs in +        # ~/Library/Application Support/$CFBundleIdentifier/logs rather than in +        # ~/Library/Application Support/SecondLife/logs as before. This could be +        # obnoxious -- but we Happen To Know that markerfile is a path specified +        # within the viewer's logs directory. Use that. +        logsdir = os.path.dirname(markerfile) + +        # Move the old updater.log file out of the way +        logname = os.path.join(logsdir, "updater.log") +        try: +            os.rename(logname, logname + ".old") +        except OSError, err: +            # Nonexistence is okay. Anything else, not so much. +            if err.errno != errno.ENOENT: +                raise + +        # Open new updater.log. +        global LOGF +        LOGF = open(logname, "w") + +        # Now that LOGF is in fact open for business, use it to log any further +        # uncaught exceptions. +        sys.excepthook = ExceptHook(LOGF) + +        # log how this script was invoked +        log(' '.join(repr(arg) for arg in sys.argv)) + +        # prepare for other cleanup +        with Janitor(LOGF) as janitor: + +            # Try to derive the name of the running viewer app bundle from our +            # own pathname. (Hopefully the old viewer won't copy this script +            # to a temp dir before running!) +            # Somewhat peculiarly, this script is currently packaged in +            # Appname.app/Contents/MacOS with the viewer executable. But even +            # if we decide to move it to Appname.app/Contents/Resources, we'll +            # still find Appname.app two levels up from dirname(__file__). +            appdir = os.path.abspath(os.path.join(os.path.dirname(__file__), +                                                  os.pardir, os.pardir)) +            if not appdir.endswith(".app"): +                # This can happen if either this script has been copied before +                # being executed, or if it's in an unexpected place in the app +                # bundle. +                fail(appdir + " is not an application directory") + +            # We need to install into appdir's parent directory -- can we? +            installdir = os.path.abspath(os.path.join(appdir, os.pardir)) +            if not os.access(installdir, os.W_OK): +                fail("Can't modify " + installdir) + +            # invent a temporary directory +            tempdir = tempfile.mkdtemp() +            log("created " + tempdir) +            # clean it up when we leave +            janitor.later(shutil.rmtree, tempdir) + +            status("Mounting image...") + +            mntdir = os.path.join(tempdir, "mnt") +            log("mkdir " + mntdir) +            os.mkdir(mntdir) +            command = ["hdiutil", "attach", dmgfile, "-mountpoint", mntdir] +            log(' '.join(command)) +            # Instantiating subprocess.Popen launches a child process with the +            # specified command line. stdout=PIPE passes a pipe to its stdout. +            hdiutil = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=LOGF) +            # Popen.communicate() reads that pipe until the child process +            # terminates, returning (stdout, stderr) output. Select just stdout. +            hdiutil_out = hdiutil.communicate()[0] +            if hdiutil.returncode != 0: +                fail("Couldn't mount " + dmgfile) +            # hdiutil should report the devnode. Find that. +            found = re.search(r"/dev/[^ ]*\b", hdiutil_out) +            if not found: +                # If we don't spot the devnode, log it and continue -- we only +                # use it to detach it. Don't fail the whole update if we can't +                # clean up properly. +                log("Couldn't spot devnode in hdiutil output:\n" + hdiutil_out) +            else: +                # If we do spot the devnode, detach it when done. +                janitor.later(subprocess.call, ["hdiutil", "detach", found.group(0)], +                              stdout=LOGF, stderr=subprocess.STDOUT) + +            status("Searching for app bundle...") + +            for candidate in glob.glob(os.path.join(mntdir, "*.app")): +                log("Considering " + candidate) +                try: +                    # By convention, a valid Mac app bundle has a +                    # Contents/Info.plist file containing at least +                    # CFBundleIdentifier. +                    CFBundleIdentifier = \ +                        plistlib.readPlist(os.path.join(candidate, "Contents", +                                                        "Info.plist"))["CFBundleIdentifier"] +                except Exception, err: +                    # might be IOError, xml.parsers.expat.ExpatError, KeyError +                    # Any of these means it's not a valid app bundle. Instead +                    # of aborting, just skip this candidate and continue. +                    log("%s not a valid app bundle: %s: %s" % +                        (candidate, err.__class__.__name__, err)) +                    continue + +                if CFBundleIdentifier == BUNDLE_IDENTIFIER: +                    break + +                log("unrecognized CFBundleIdentifier: " + CFBundleIdentifier) + +            else: +                fail("Could not find Second Life viewer in " + dmgfile) + +            # Here 'candidate' is the new viewer to install +            log("Found " + candidate) + +            # This logic was changed to make Mac updates behave more like +            # Windows. Most of the time, the user doesn't change the name of +            # the app bundle on our .dmg installer (e.g. "Second Life Beta +            # Viewer.app"). Most of the time, the version manager directs a +            # given viewer to update to another .dmg containing an app bundle +            # with THE SAME name. In that case, everything behaves as usual. + +            # The case that was changed is when the version manager offers (or +            # mandates) an update to a .dmg containing a different app bundle +            # name. This can happen, for instance, to a user who's downloaded +            # a "project beta" viewer, and the project subsequently publishes +            # a Release Candidate viewer. Say the project beta's app bundle +            # name is something like "Second Life Beta Neato.app". Anyone +            # launching that viewer will be offered an update to the +            # corresponding Release Candidate viewer -- which will be built as +            # a release viewer, with app bundle name "Second Life Viewer.app". + +            # On Windows, we run the NSIS installer, which will update/replace +            # the embedded install directory name, e.g. Second Life Viewer. +            # But the Mac installer used to locate the app bundle name in the +            # mounted .dmg file, then ignore that name, copying its contents +            # into the app bundle directory of the running viewer. That is, +            # we'd install the Release Candidate from the .dmg's "Second +            # Life.app" into "/Applications/Second Life Beta Neato.app". This +            # is undesired behavior. + +            # Instead, having found the app bundle name on the mounted .dmg, +            # we try to install that app bundle name into the parent directory +            # of the running app bundle. + +            # Are we installing a different app bundle name? If so, call it +            # out, both in the log and for the user -- this is an odd case. +            # (Presumably they've already agreed to a similar notification in +            # the viewer before the viewer launched this script, but still.) +            bundlename = os.path.basename(candidate) +            if os.path.basename(appdir) == bundlename: +                # updating the running app bundle, which we KNOW exists +                appexists = True +            else: +                # installing some other app bundle +                newapp = os.path.join(installdir, bundlename) +                appexists = os.path.exists(newapp) +                message = "Note: %s %s %s" % \ +                          (appdir, "updating" if appexists else "installing new", newapp) +                status(message) +                # okay, we have no further need of the name of the running app +                # bundle. +                appdir = newapp + +            status("Preparing to copy files...") + +            if appexists: +                # move old viewer to temp location in case copy from .dmg fails +                aside = os.path.join(tempdir, os.path.basename(appdir)) +                log("mv %r %r" % (appdir, aside)) +                # Use shutil.move() instead of os.rename(). move() first tries +                # os.rename(), but falls back to shutil.copytree() if the dest is +                # on a different filesystem. +                shutil.move(appdir, aside) + +            status("Copying files...") + +            # shutil.copytree()'s target must not already exist. But we just +            # moved appdir out of the way. +            log("cp -p %r %r" % (candidate, appdir)) +            try: +                # The viewer app bundle does include internal symlinks. Keep them +                # as symlinks. +                shutil.copytree(candidate, appdir, symlinks=True) +            except Exception, err: +                # copy failed -- try to restore previous viewer before crumping +                type, value, traceback = sys.exc_info() +                if appexists: +                    log("exception response: mv %r %r" % (aside, appdir)) +                    shutil.move(aside, appdir) +                # let our previously-set sys.excepthook handle this +                raise type, value, traceback + +            status("Cleaning up...") + +            log("touch " + appdir) +            os.utime(appdir, None)      # set to current time + +            command = ["open", appdir] +            log(' '.join(command)) +            subprocess.check_call(command, stdout=LOGF, stderr=subprocess.STDOUT) + +    except Exception, err: +        # Because we carefully set sys.excepthook -- and even modify it to log +        # the problem once we have our log file open -- you might think we +        # could just let exceptions propagate. But when we do that, on +        # exception in this block, we FIRST restore the no-side-effects fail() +        # and THEN implicitly call sys.excepthook(), which calls the (no-side- +        # effects) fail(). Explicitly call sys.excepthook() BEFORE restoring +        # fail(). Only then do we get the enriched fail() behavior. +        sys.excepthook(*sys.exc_info()) + +    finally: +        # When we leave main() -- for whatever reason -- reset fail() the way +        # it was before, because the bound markerfile, markertext params +        # passed to this main() call are no longer applicable. +        fail = oldfail + +if __name__ == "__main__": +    # We expect this script to be invoked with: +    # - the pathname to the .dmg we intend to install; +    # - the pathname to an update-error marker file to create on failure; +    # - the content to write into the marker file. +    main(*sys.argv[1:]) | 
