summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOz Linden <oz@lindenlab.com>2013-03-06 16:39:48 -0500
committerOz Linden <oz@lindenlab.com>2013-03-06 16:39:48 -0500
commitc70b0a9de66e6b8d93f1027932ba7e801de3473b (patch)
treed1157e2897ac8bf1e79ce6f55200406d1bb7fca2
parentce73cc392c3f6e2a80c03e30a7dd975408e69f1c (diff)
parent1eabdf70fc61f7f1cff5fe2522e3e769d0e35db5 (diff)
merge changes for DRTVWR-278
-rw-r--r--.hgtags89
-rw-r--r--indra/CMakeLists.txt3
-rw-r--r--indra/mac_updater/AutoUpdater.nib/classes.nib4
-rw-r--r--indra/mac_updater/AutoUpdater.nib/info.nib14
-rw-r--r--indra/mac_updater/AutoUpdater.nib/objects.xib56
-rw-r--r--indra/mac_updater/CMakeLists.txt73
-rw-r--r--indra/mac_updater/Info.plist26
-rw-r--r--indra/mac_updater/mac_updater.cpp1257
-rw-r--r--indra/mac_updater/mac_updater.h91
-rw-r--r--indra/newview/CMakeLists.txt5
-rw-r--r--indra/newview/viewer_manifest.py7
-rw-r--r--indra/viewer_components/updater/llupdaterservice.cpp4
-rw-r--r--indra/viewer_components/updater/scripts/darwin/janitor.py133
-rw-r--r--indra/viewer_components/updater/scripts/darwin/messageframe.py66
-rw-r--r--indra/viewer_components/updater/scripts/darwin/update_install10
-rwxr-xr-xindra/viewer_components/updater/scripts/darwin/update_install.py373
16 files changed, 628 insertions, 1583 deletions
diff --git a/.hgtags b/.hgtags
index 92ddad7884..23ac1b88ca 100644
--- a/.hgtags
+++ b/.hgtags
@@ -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&apos;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."),
- &params,
- &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:])