summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNat Goodspeed <nat@lindenlab.com>2013-01-05 09:17:51 -0500
committerNat Goodspeed <nat@lindenlab.com>2013-01-05 09:17:51 -0500
commit840cb864a3b41ccff310077eff487c3fa1d6b805 (patch)
treeabed8e38943228061790779c9b7568b9a4f49f83
parentab23506eb1d6a8435177a8e0b10331a5f03cff15 (diff)
MAINT-2155: replace embedded mac-updater.app with a Python script.
Remove mac-updater subtree from viewer source, along with the update_install bash script that invoked it. Remove all mention of mac-updater in CMakeLists.txt files and in viewer_manifest.py. Change Mac update_install bash script references in viewer_manifest.py and in llupdaterservice.cpp (which invokes it) to new Python update_install.py. Add update_install.py, messageframe.py (which puts up some Tkinter UI) and janitor.py (cloned from vita, it's exactly what we need here).
-rw-r--r--indra/CMakeLists.txt3
-rwxr-xr-xindra/mac_updater/AutoUpdater.nibbin5251 -> 0 bytes
-rw-r--r--indra/mac_updater/AutoUpdater.xib520
-rw-r--r--indra/mac_updater/CMakeLists.txt89
-rw-r--r--indra/mac_updater/Info.plist26
-rw-r--r--indra/mac_updater/MacUpdater-Info.plist30
-rw-r--r--indra/mac_updater/MacUpdaterAppDelegate.h60
-rw-r--r--indra/mac_updater/MacUpdaterAppDelegate.mm288
-rw-r--r--indra/mac_updater/mac_updater.cpp659
-rw-r--r--indra/mac_updater/mac_updater.h91
-rw-r--r--indra/mac_updater/main.m34
-rwxr-xr-xindra/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.py336
18 files changed, 546 insertions, 1815 deletions
diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt
index 24c98bfada..45608de674 100644
--- a/indra/CMakeLists.txt
+++ b/indra/CMakeLists.txt
@@ -86,8 +86,7 @@ if (VIEWER)
add_dependencies(viewer linux-crash-logger-strip-target linux-updater)
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 b/indra/mac_updater/AutoUpdater.nib
deleted file mode 100755
index 03883e2b86..0000000000
--- a/indra/mac_updater/AutoUpdater.nib
+++ /dev/null
Binary files differ
diff --git a/indra/mac_updater/AutoUpdater.xib b/indra/mac_updater/AutoUpdater.xib
deleted file mode 100644
index b29fffba3a..0000000000
--- a/indra/mac_updater/AutoUpdater.xib
+++ /dev/null
@@ -1,520 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="8.00">
- <data>
- <int key="IBDocument.SystemTarget">1070</int>
- <string key="IBDocument.SystemVersion">11G63</string>
- <string key="IBDocument.InterfaceBuilderVersion">2182</string>
- <string key="IBDocument.AppKitVersion">1138.51</string>
- <string key="IBDocument.HIToolboxVersion">569.00</string>
- <object class="NSMutableDictionary" key="IBDocument.PluginVersions">
- <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string key="NS.object.0">2182</string>
- </object>
- <array key="IBDocument.IntegratedClassDependencies">
- <string>NSTextField</string>
- <string>NSView</string>
- <string>NSWindowTemplate</string>
- <string>NSProgressIndicator</string>
- <string>NSCustomObject</string>
- <string>IBNSLayoutConstraint</string>
- <string>NSButtonCell</string>
- <string>NSButton</string>
- <string>NSUserDefaultsController</string>
- <string>NSTextFieldCell</string>
- </array>
- <array key="IBDocument.PluginDependencies">
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- </array>
- <object class="NSMutableDictionary" key="IBDocument.Metadata">
- <string key="NS.key.0">PluginDependencyRecalculationVersion</string>
- <integer value="1" key="NS.object.0"/>
- </object>
- <array class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
- <object class="NSCustomObject" id="1001">
- <string key="NSClassName">NSObject</string>
- </object>
- <object class="NSCustomObject" id="1003">
- <string key="NSClassName">FirstResponder</string>
- </object>
- <object class="NSCustomObject" id="1004">
- <string key="NSClassName">NSApplication</string>
- </object>
- <object class="NSWindowTemplate" id="1005">
- <int key="NSWindowStyleMask">15</int>
- <int key="NSWindowBacking">2</int>
- <string key="NSWindowRect">{{196, 240}, {402, 120}}</string>
- <int key="NSWTFlags">544735232</int>
- <string key="NSWindowTitle">Window</string>
- <string key="NSWindowClass">NSWindow</string>
- <nil key="NSViewClass"/>
- <nil key="NSUserInterfaceItemIdentifier"/>
- <object class="NSView" key="NSWindowView" id="1006">
- <reference key="NSNextResponder"/>
- <int key="NSvFlags">256</int>
- <array class="NSMutableArray" key="NSSubviews">
- <object class="NSTextField" id="269124353">
- <reference key="NSNextResponder" ref="1006"/>
- <int key="NSvFlags">268</int>
- <string key="NSFrame">{{17, 83}, {79, 17}}</string>
- <reference key="NSSuperview" ref="1006"/>
- <reference key="NSWindow"/>
- <reference key="NSNextKeyView" ref="730867742"/>
- <string key="NSReuseIdentifierKey">_NS:1505</string>
- <bool key="NSEnabled">YES</bool>
- <object class="NSTextFieldCell" key="NSCell" id="702170046">
- <int key="NSCellFlags">68288064</int>
- <int key="NSCellFlags2">272630784</int>
- <string key="NSContents">Initalizing...</string>
- <object class="NSFont" key="NSSupport">
- <string key="NSName">LucidaGrande</string>
- <double key="NSSize">13</double>
- <int key="NSfFlags">1044</int>
- </object>
- <string key="NSCellIdentifier">_NS:1505</string>
- <reference key="NSControlView" ref="269124353"/>
- <object class="NSColor" key="NSBackgroundColor">
- <int key="NSColorSpace">6</int>
- <string key="NSCatalogName">System</string>
- <string key="NSColorName">controlColor</string>
- <object class="NSColor" key="NSColor">
- <int key="NSColorSpace">3</int>
- <bytes key="NSWhite">MC42NjY2NjY2NjY3AA</bytes>
- </object>
- </object>
- <object class="NSColor" key="NSTextColor">
- <int key="NSColorSpace">6</int>
- <string key="NSCatalogName">System</string>
- <string key="NSColorName">controlTextColor</string>
- <object class="NSColor" key="NSColor">
- <int key="NSColorSpace">3</int>
- <bytes key="NSWhite">MAA</bytes>
- </object>
- </object>
- </object>
- </object>
- <object class="NSProgressIndicator" id="730867742">
- <reference key="NSNextResponder" ref="1006"/>
- <int key="NSvFlags">268</int>
- <string key="NSFrame">{{18, 55}, {366, 20}}</string>
- <reference key="NSSuperview" ref="1006"/>
- <reference key="NSWindow"/>
- <reference key="NSNextKeyView" ref="302149677"/>
- <string key="NSReuseIdentifierKey">_NS:9</string>
- <string key="NSHuggingPriority">{250, 250}</string>
- <int key="NSpiFlags">16399</int>
- <double key="NSMaxValue">100</double>
- </object>
- <object class="NSButton" id="302149677">
- <reference key="NSNextResponder" ref="1006"/>
- <int key="NSvFlags">268</int>
- <string key="NSFrame">{{308, 19}, {74, 19}}</string>
- <reference key="NSSuperview" ref="1006"/>
- <reference key="NSWindow"/>
- <reference key="NSNextKeyView"/>
- <string key="NSReuseIdentifierKey">_NS:9</string>
- <bool key="NSEnabled">YES</bool>
- <object class="NSButtonCell" key="NSCell" id="677565961">
- <int key="NSCellFlags">-2080244224</int>
- <int key="NSCellFlags2">134217728</int>
- <string key="NSContents">Cancel</string>
- <object class="NSFont" key="NSSupport">
- <string key="NSName">LucidaGrande</string>
- <double key="NSSize">12</double>
- <int key="NSfFlags">16</int>
- </object>
- <string key="NSCellIdentifier">_NS:9</string>
- <reference key="NSControlView" ref="302149677"/>
- <int key="NSButtonFlags">-2038152961</int>
- <int key="NSButtonFlags2">164</int>
- <string key="NSAlternateContents"/>
- <string key="NSKeyEquivalent"/>
- <int key="NSPeriodicDelay">400</int>
- <int key="NSPeriodicInterval">75</int>
- </object>
- </object>
- </array>
- <string key="NSFrameSize">{402, 120}</string>
- <reference key="NSSuperview"/>
- <reference key="NSWindow"/>
- <reference key="NSNextKeyView" ref="269124353"/>
- </object>
- <string key="NSScreenRect">{{0, 0}, {1680, 1028}}</string>
- <string key="NSMaxSize">{10000000000000, 10000000000000}</string>
- <bool key="NSWindowIsRestorable">YES</bool>
- </object>
- <object class="NSCustomObject" id="492080840">
- <string key="NSClassName">MacUpdaterAppDelegate</string>
- </object>
- <object class="NSUserDefaultsController" id="21008314">
- <bool key="NSSharedInstance">YES</bool>
- </object>
- </array>
- <object class="IBObjectContainer" key="IBDocument.Objects">
- <array class="NSMutableArray" key="connectionRecords">
- <object class="IBConnectionRecord">
- <object class="IBBindingConnection" key="connection">
- <string key="label">title: values</string>
- <reference key="source" ref="1005"/>
- <reference key="destination" ref="21008314"/>
- <object class="NSNibBindingConnector" key="connector">
- <reference key="NSSource" ref="1005"/>
- <reference key="NSDestination" ref="21008314"/>
- <string key="NSLabel">title: values</string>
- <string key="NSBinding">title</string>
- <string key="NSKeyPath">values</string>
- <int key="NSNibBindingConnectorVersion">2</int>
- </object>
- </object>
- <int key="connectionID">41</int>
- </object>
- </array>
- <object class="IBMutableOrderedSet" key="objectRecords">
- <array key="orderedObjects">
- <object class="IBObjectRecord">
- <int key="objectID">0</int>
- <array key="object" id="0"/>
- <reference key="children" ref="1000"/>
- <nil key="parent"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">-2</int>
- <reference key="object" ref="1001"/>
- <reference key="parent" ref="0"/>
- <string key="objectName">File's Owner</string>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">-1</int>
- <reference key="object" ref="1003"/>
- <reference key="parent" ref="0"/>
- <string key="objectName">First Responder</string>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">-3</int>
- <reference key="object" ref="1004"/>
- <reference key="parent" ref="0"/>
- <string key="objectName">Application</string>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">1</int>
- <reference key="object" ref="1005"/>
- <array class="NSMutableArray" key="children">
- <reference ref="1006"/>
- </array>
- <reference key="parent" ref="0"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">2</int>
- <reference key="object" ref="1006"/>
- <array class="NSMutableArray" key="children">
- <reference ref="269124353"/>
- <reference ref="730867742"/>
- <object class="IBNSLayoutConstraint" id="463541650">
- <reference key="firstItem" ref="269124353"/>
- <int key="firstAttribute">5</int>
- <int key="relation">0</int>
- <reference key="secondItem" ref="1006"/>
- <int key="secondAttribute">5</int>
- <float key="multiplier">1</float>
- <object class="IBNSLayoutSymbolicConstant" key="constant">
- <double key="value">20</double>
- </object>
- <float key="priority">1000</float>
- <int key="scoringType">8</int>
- <float key="scoringTypeFloat">29</float>
- <int key="contentType">3</int>
- <reference key="containingView" ref="1006"/>
- </object>
- <object class="IBNSLayoutConstraint" id="772497817">
- <reference key="firstItem" ref="730867742"/>
- <int key="firstAttribute">5</int>
- <int key="relation">0</int>
- <reference key="secondItem" ref="1006"/>
- <int key="secondAttribute">5</int>
- <float key="multiplier">1</float>
- <object class="IBNSLayoutSymbolicConstant" key="constant">
- <double key="value">20</double>
- </object>
- <float key="priority">1000</float>
- <int key="scoringType">8</int>
- <float key="scoringTypeFloat">29</float>
- <int key="contentType">3</int>
- <reference key="containingView" ref="1006"/>
- </object>
- <object class="IBNSLayoutConstraint" id="929212820">
- <reference key="firstItem" ref="1006"/>
- <int key="firstAttribute">6</int>
- <int key="relation">0</int>
- <reference key="secondItem" ref="730867742"/>
- <int key="secondAttribute">6</int>
- <float key="multiplier">1</float>
- <object class="IBNSLayoutSymbolicConstant" key="constant">
- <double key="value">20</double>
- </object>
- <float key="priority">1000</float>
- <int key="scoringType">8</int>
- <float key="scoringTypeFloat">29</float>
- <int key="contentType">3</int>
- <reference key="containingView" ref="1006"/>
- </object>
- <reference ref="302149677"/>
- <object class="IBNSLayoutConstraint" id="813415053">
- <reference key="firstItem" ref="1006"/>
- <int key="firstAttribute">6</int>
- <int key="relation">0</int>
- <reference key="secondItem" ref="302149677"/>
- <int key="secondAttribute">6</int>
- <float key="multiplier">1</float>
- <object class="IBNSLayoutSymbolicConstant" key="constant">
- <double key="value">20</double>
- </object>
- <float key="priority">1000</float>
- <int key="scoringType">8</int>
- <float key="scoringTypeFloat">29</float>
- <int key="contentType">3</int>
- <reference key="containingView" ref="1006"/>
- </object>
- <object class="IBNSLayoutConstraint" id="178579609">
- <reference key="firstItem" ref="269124353"/>
- <int key="firstAttribute">3</int>
- <int key="relation">0</int>
- <reference key="secondItem" ref="1006"/>
- <int key="secondAttribute">3</int>
- <float key="multiplier">1</float>
- <object class="IBNSLayoutSymbolicConstant" key="constant">
- <double key="value">20</double>
- </object>
- <float key="priority">1000</float>
- <int key="scoringType">8</int>
- <float key="scoringTypeFloat">29</float>
- <int key="contentType">3</int>
- <reference key="containingView" ref="1006"/>
- </object>
- <object class="IBNSLayoutConstraint" id="594621082">
- <reference key="firstItem" ref="730867742"/>
- <int key="firstAttribute">3</int>
- <int key="relation">0</int>
- <reference key="secondItem" ref="269124353"/>
- <int key="secondAttribute">4</int>
- <float key="multiplier">1</float>
- <object class="IBNSLayoutSymbolicConstant" key="constant">
- <double key="value">8</double>
- </object>
- <float key="priority">1000</float>
- <int key="scoringType">6</int>
- <float key="scoringTypeFloat">24</float>
- <int key="contentType">3</int>
- <reference key="containingView" ref="1006"/>
- </object>
- <object class="IBNSLayoutConstraint" id="658067790">
- <reference key="firstItem" ref="1006"/>
- <int key="firstAttribute">4</int>
- <int key="relation">0</int>
- <reference key="secondItem" ref="302149677"/>
- <int key="secondAttribute">4</int>
- <float key="multiplier">1</float>
- <object class="IBNSLayoutSymbolicConstant" key="constant">
- <double key="value">20</double>
- </object>
- <float key="priority">1000</float>
- <int key="scoringType">8</int>
- <float key="scoringTypeFloat">29</float>
- <int key="contentType">3</int>
- <reference key="containingView" ref="1006"/>
- </object>
- </array>
- <reference key="parent" ref="1005"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">3</int>
- <reference key="object" ref="269124353"/>
- <array class="NSMutableArray" key="children">
- <reference ref="702170046"/>
- </array>
- <reference key="parent" ref="1006"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">4</int>
- <reference key="object" ref="702170046"/>
- <reference key="parent" ref="269124353"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">8</int>
- <reference key="object" ref="730867742"/>
- <array class="NSMutableArray" key="children"/>
- <reference key="parent" ref="1006"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">20</int>
- <reference key="object" ref="463541650"/>
- <reference key="parent" ref="1006"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">22</int>
- <reference key="object" ref="302149677"/>
- <array class="NSMutableArray" key="children">
- <reference ref="677565961"/>
- <object class="IBNSLayoutConstraint" id="981064020">
- <reference key="firstItem" ref="302149677"/>
- <int key="firstAttribute">7</int>
- <int key="relation">0</int>
- <nil key="secondItem"/>
- <int key="secondAttribute">0</int>
- <float key="multiplier">1</float>
- <object class="IBLayoutConstant" key="constant">
- <double key="value">74</double>
- </object>
- <float key="priority">1000</float>
- <int key="scoringType">3</int>
- <float key="scoringTypeFloat">9</float>
- <int key="contentType">1</int>
- <reference key="containingView" ref="302149677"/>
- </object>
- </array>
- <reference key="parent" ref="1006"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">23</int>
- <reference key="object" ref="677565961"/>
- <reference key="parent" ref="302149677"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">31</int>
- <reference key="object" ref="772497817"/>
- <reference key="parent" ref="1006"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">32</int>
- <reference key="object" ref="929212820"/>
- <reference key="parent" ref="1006"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">35</int>
- <reference key="object" ref="813415053"/>
- <reference key="parent" ref="1006"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">36</int>
- <reference key="object" ref="981064020"/>
- <reference key="parent" ref="302149677"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">37</int>
- <reference key="object" ref="178579609"/>
- <reference key="parent" ref="1006"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">38</int>
- <reference key="object" ref="594621082"/>
- <reference key="parent" ref="1006"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">39</int>
- <reference key="object" ref="658067790"/>
- <reference key="parent" ref="1006"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">40</int>
- <reference key="object" ref="21008314"/>
- <reference key="parent" ref="0"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">42</int>
- <reference key="object" ref="492080840"/>
- <reference key="parent" ref="0"/>
- </object>
- </array>
- </object>
- <dictionary class="NSMutableDictionary" key="flattenedProperties">
- <string key="-1.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string key="-2.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string key="-3.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string key="1.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string key="1.IBWindowTemplateEditedContentRect">{{357, 418}, {480, 270}}</string>
- <integer value="1" key="1.NSWindowTemplate.visibleAtLaunch"/>
- <array class="NSMutableArray" key="2.IBNSViewMetadataConstraints">
- <reference ref="463541650"/>
- <reference ref="772497817"/>
- <reference ref="929212820"/>
- <reference ref="813415053"/>
- <reference ref="178579609"/>
- <reference ref="594621082"/>
- <reference ref="658067790"/>
- </array>
- <string key="2.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string key="20.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
- <array class="NSMutableArray" key="22.IBNSViewMetadataConstraints">
- <reference ref="981064020"/>
- </array>
- <boolean value="NO" key="22.IBNSViewMetadataTranslatesAutoresizingMaskIntoConstraints"/>
- <string key="22.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string key="23.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
- <boolean value="NO" key="3.IBNSViewMetadataTranslatesAutoresizingMaskIntoConstraints"/>
- <string key="3.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string key="31.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string key="32.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string key="35.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string key="36.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string key="37.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string key="38.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string key="39.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string key="4.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string key="40.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string key="42.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
- <boolean value="NO" key="8.IBNSViewMetadataTranslatesAutoresizingMaskIntoConstraints"/>
- <string key="8.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
- </dictionary>
- <dictionary class="NSMutableDictionary" key="unlocalizedProperties"/>
- <nil key="activeLocalization"/>
- <dictionary class="NSMutableDictionary" key="localizations"/>
- <nil key="sourceID"/>
- <int key="maxID">42</int>
- </object>
- <object class="IBClassDescriber" key="IBDocument.Classes">
- <array class="NSMutableArray" key="referencedPartialClassDescriptions">
- <object class="IBPartialClassDescription">
- <string key="className">MacUpdaterAppDelegate</string>
- <string key="superclassName">NSObject</string>
- <object class="NSMutableDictionary" key="actions">
- <string key="NS.key.0">cancel:</string>
- <string key="NS.object.0">id</string>
- </object>
- <object class="NSMutableDictionary" key="actionInfosByName">
- <string key="NS.key.0">cancel:</string>
- <object class="IBActionInfo" key="NS.object.0">
- <string key="name">cancel:</string>
- <string key="candidateClassName">id</string>
- </object>
- </object>
- <dictionary class="NSMutableDictionary" key="outlets">
- <string key="mProgressBar">NSProgressIndicator</string>
- <string key="mProgressText">NSTextField</string>
- <string key="window">NSWindow</string>
- </dictionary>
- <dictionary class="NSMutableDictionary" key="toOneOutletInfosByName">
- <object class="IBToOneOutletInfo" key="mProgressBar">
- <string key="name">mProgressBar</string>
- <string key="candidateClassName">NSProgressIndicator</string>
- </object>
- <object class="IBToOneOutletInfo" key="mProgressText">
- <string key="name">mProgressText</string>
- <string key="candidateClassName">NSTextField</string>
- </object>
- <object class="IBToOneOutletInfo" key="window">
- <string key="name">window</string>
- <string key="candidateClassName">NSWindow</string>
- </object>
- </dictionary>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">./Classes/MacUpdaterAppDelegate.h</string>
- </object>
- </object>
- </array>
- </object>
- <int key="IBDocument.localizationMode">0</int>
- <string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
- <bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
- <int key="IBDocument.defaultPropertyAccessControl">3</int>
- <bool key="IBDocument.UseAutolayout">YES</bool>
- </data>
-</archive>
diff --git a/indra/mac_updater/CMakeLists.txt b/indra/mac_updater/CMakeLists.txt
deleted file mode 100644
index 7382e912bf..0000000000
--- a/indra/mac_updater/CMakeLists.txt
+++ /dev/null
@@ -1,89 +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
- main.m
- MacUpdaterAppDelegate.mm
- mac_updater.cpp
- )
-
-set(mac_updater_HEADER_FILES
- MacUpdaterAppDelegate.h
- mac_updater.h
- 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}/MacUpdater-Info.plist
- )
-
-find_library(COCOA_LIBRARY Cocoa)
-find_library(IOKIT_LIBRARY IOKit)
-
-target_link_libraries(mac-updater
- ${LLVFS_LIBRARIES}
- ${OPENSSL_LIBRARIES}
- ${CRYPTO_LIBRARIES}
- ${COCOA_LIBRARIES}
- ${BOOST_FILESYSTEM_LIBRARY}
- ${IOKIT_LIBRARY}
- ${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
- COMMAND ${CMAKE_COMMAND}
- ARGS
- -E
- copy
- ${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/MacUpdater-Info.plist b/indra/mac_updater/MacUpdater-Info.plist
deleted file mode 100644
index 92137095ff..0000000000
--- a/indra/mac_updater/MacUpdater-Info.plist
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>CFBundleDevelopmentRegion</key>
- <string>en</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>
- <key>NSMainNibFile</key>
- <string>AutoUpdater</string>
- <key>NSPrincipalClass</key>
- <string>NSApplication</string>
-</dict>
-</plist>
diff --git a/indra/mac_updater/MacUpdaterAppDelegate.h b/indra/mac_updater/MacUpdaterAppDelegate.h
deleted file mode 100644
index c051214bb8..0000000000
--- a/indra/mac_updater/MacUpdaterAppDelegate.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/**
- * @file MacUpdaterAppDelegate.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$
- */
-
-
-#import <Cocoa/Cocoa.h>
-#include <iostream>
-#include "mac_updater.h"
-
-#ifndef LL_MAC_UPDATE_DELEGATE_H
-#define LL_MAC_UPDATE_DELEGATE_H
-
-@interface MacUpdaterAppDelegate : NSObject <NSApplicationDelegate>
-{
- IBOutlet NSProgressIndicator *mProgressBar;
- IBOutlet NSTextField *mProgressText;
-}
-- (void)setWindow:(NSWindow *)newWindow;
-- (NSWindow *)window;
-- (IBAction)cancel:(id)sender;
-- (void) setProgress:(int)cur max:(int) max;
-- (void) setProgressText:(const std::string&)str;
-- (int) parse_args:(NSArray *) args;
-- (void)stopAlert;
-- (void)stopAlertDidEnd:(NSAlert *)alert returnCode:(int)returnCode contextInfo:(void *)contextInfo;
-
-
-NSWindow *_window;
-bool mAnimated;
-double mProgressPercentage;
-@property (assign) IBOutlet NSWindow *window;
-LLMacUpdater mUpdater;
-
-@end
-
-#endif //LL_MAC_UPDATE_DELEGATE_H
-
-
diff --git a/indra/mac_updater/MacUpdaterAppDelegate.mm b/indra/mac_updater/MacUpdaterAppDelegate.mm
deleted file mode 100644
index 4457419a94..0000000000
--- a/indra/mac_updater/MacUpdaterAppDelegate.mm
+++ /dev/null
@@ -1,288 +0,0 @@
-/**
- * @file MacUpdaterAppDelegate.mm
- * @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$
- */
-
-#import "MacUpdaterAppDelegate.h"
-#include "llvfs_objc.h"
-#include <string.h>
-#include <boost/filesystem.hpp>
-
-@implementation MacUpdaterAppDelegate
-
-MacUpdaterAppDelegate *gWindow;
-bool gCancelled = false;
-bool gFailure =false;
-
-
-//@synthesize window = _window;
-- (void)setWindow:(NSWindow *)window
-{
- _window = window;
-}
-
-- (NSWindow *)window
-{
- return _window;
-}
-
-- (id)init
-{
- self = [super init];
- if (self) {
-
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- mAnimated = false;
- mProgressPercentage = 0.0;
- NSArray *arguments = [[NSProcessInfo processInfo] arguments];
-
- [self parse_args:arguments];
- gWindow = self;
-
- mUpdater.doUpdate();
- [pool drain];
- [pool release];
- }
- return self;
-}
-
-- (void)dealloc
-{
- [super dealloc];
-}
-
-std::string* NSToString( NSString *ns_str )
-{
- return ( new std::string([ns_str UTF8String]) );
-}
-
-
-- (void) setProgress:(int)cur max:(int) max
-{
- bool indeterminate = false;
- if (max==0)
- {
- indeterminate = true;
- }
- else
- {
- double percentage = ((double)cur / (double)max) * 100.0;
- [mProgressBar setDoubleValue:percentage];
- }
- [mProgressBar setIndeterminate:indeterminate];
-}
-
-- (void) setProgressText:(const std::string& )str
-{
- [mProgressText setStringValue:[NSString stringWithUTF8String:str.c_str()]];
-}
-
-void sendDone()
-{
- [ [ (id) gWindow window ] close];
-}
-
-void sendStopAlert()
-{
- [ gWindow stopAlert ];
-}
-
-void setProgress(int cur, int max)
-{
- [ (id) gWindow setProgress:cur max:max];
-}
-
-void setProgressText(const std::string& str)
-{
- [ (id) gWindow setProgressText:str];
-}
-
-void sendProgress(int cur, int max, const std::string str)
-{
- setProgress(cur,max);
- setProgressText(str);
-}
-
-bool mkTempDir(boost::filesystem::path& temp_dir)
-{
- NSString * tempDir = NSTemporaryDirectory();
- if (tempDir == nil)
- tempDir = @"/tmp/";
-
- std::string* temp_str = NSToString(tempDir);
- *temp_str += std::string("SecondLifeUpdate_XXXXXX");
-
- std::cout << "tempDir is " << temp_str << std::endl;
-
- char temp[PATH_MAX] = ""; /* Flawfinder: ignore */
- strncpy(temp, temp_str->c_str(), temp_str->length());
-
- if(mkdtemp(temp) == NULL)
- {
- return false;
- }
-
- temp_dir = boost::filesystem::path(temp);
-
- return true;
-}
-bool copyDir(const std::string& src_dir, const std::string& dest_dir)
-{
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-
- NSString* file = [NSString stringWithCString:src_dir.c_str()
- encoding:[NSString defaultCStringEncoding]];
- NSString* toParent = [NSString stringWithCString:dest_dir.c_str()
- encoding:[NSString defaultCStringEncoding]];
- NSError* error = nil;
-
- bool result = [[NSFileManager defaultManager] copyItemAtPath: file toPath: toParent error:&error];
-
- if (!result) {
- NSLog(@"Error during copy: %@", [error localizedDescription]);
- }
- [pool release];
-
- return result;
-}
-
-- (int) parse_args:(NSArray *) args
-{
- int i;
- int argc = [args count];
-
- mUpdater.mApplicationPath = NSToString( [args objectAtIndex:0] );
-
- for( i = 1; i < argc; i++ )
- {
- NSString* ns_arg = [args objectAtIndex:i];
- const char *arg = [ns_arg UTF8String];
-
- if ((!strcmp(arg, "-url")) && (i < argc))
- {
- mUpdater.mUpdateURL = NSToString( [args objectAtIndex:(++i)] );
- }
- else if ((!strcmp(arg, "-name")) && (i < argc))
- {
- mUpdater.mProductName = NSToString( [args objectAtIndex:(++i)] );
- }
- else if ((!strcmp(arg, "-bundleid")) && (i < argc))
- {
- mUpdater.mBundleID = NSToString( [args objectAtIndex:(++i)] );
- }
- else if ((!strcmp(arg, "-dmg")) && (i < argc))
- {
- mUpdater.mDmgFile = NSToString( [args objectAtIndex:(++i)] );
- }
- else if ((!strcmp(arg, "-marker")) && (i < argc))
- {
- mUpdater.mMarkerPath = NSToString( [args objectAtIndex:(++i)] );
- }
- }
- return 0;
-}
-
-bool isDirWritable(const std::string& dir_name)
-{
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-
- NSString *fullPath = [NSString stringWithCString:dir_name.c_str()
- encoding:[NSString defaultCStringEncoding]];
-
- NSFileManager *fm = [NSFileManager defaultManager];
- bool result = [fm isWritableFileAtPath:fullPath];
- [pool release];
-
- return result;
-}
-
-std::string* getUserTrashFolder()
-{
- std::string *result;
-
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-
- NSString *trash_str=[NSHomeDirectory() stringByAppendingPathComponent:@".Trash"];
-
- result = NSToString( trash_str );
-
- [pool release];
- return result;
-
-}
-
-bool isFSRefViewerBundle(const std::string& targetURL)
-{
- bool result = false;
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-
- NSString *fullPath = [NSString stringWithCString:targetURL.c_str()
- encoding:[NSString defaultCStringEncoding]];
- NSBundle *targetBundle = [NSBundle bundleWithPath:fullPath];
- NSString *targetBundleStr = [targetBundle bundleIdentifier];
- NSString *sourceBundleStr = [NSString stringWithCString:mUpdater.mBundleID->c_str()
- encoding:[NSString defaultCStringEncoding]];
-
- result = [targetBundleStr isEqualToString:sourceBundleStr];
-
- if(!result)
- {
- std::cout << "Target bundle ID mismatch." << std::endl;
- }
-
- [pool release];
-
- return result;
-}
-
-
-- (IBAction)cancel:(id)sender
-{
- gCancelled = true;
- sendDone();
-}
-
-- (void)stopAlert
-{
- NSAlert *alert = [[NSAlert alloc] init];
- [alert setAlertStyle:NSInformationalAlertStyle];
- [alert setMessageText:@"Error"];
- [alert setInformativeText:@"An error occurred while updating Second Life. Please download the latest version from www.secondlife.com."];
-
- [alert beginSheetModalForWindow:_window
- modalDelegate:self
-
- didEndSelector:@selector(stopAlertDidEnd:returnCode:
- contextInfo:)
- contextInfo:nil];
- }
-
- - (void)stopAlertDidEnd:(NSAlert *)alert
- returnCode:(int)returnCode contextInfo:(void *)contextInfo
-{
- [alert release];
-}
-
-
-@end
diff --git a/indra/mac_updater/mac_updater.cpp b/indra/mac_updater/mac_updater.cpp
deleted file mode 100644
index bc9fec3558..0000000000
--- a/indra/mac_updater/mac_updater.cpp
+++ /dev/null
@@ -1,659 +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 <boost/filesystem/operations.hpp>
-#include <boost/filesystem.hpp>
-
-#include <libgen.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include <curl/curl.h>
-
-#include "llerror.h"
-#include "lltimer.h"
-#include "lldir.h"
-#include "llfile.h"
-
-#include "llstring.h"
-
-#include "llerrorcontrol.h"
-#include "mac_updater.h"
-#include <sstream>
-
-pthread_t updatethread;
-
-LLMacUpdater* LLMacUpdater::sInstance = NULL;
-
-LLMacUpdater::LLMacUpdater():
- mUpdateURL (NULL),
- mProductName (NULL),
- mBundleID (NULL),
- mDmgFile (NULL),
- mMarkerPath (NULL)
-{
- sInstance = this;
-}
-
-void LLMacUpdater::doUpdate()
-{
- // 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);
-
- if ((mUpdateURL == NULL) && (mDmgFile == NULL))
- {
- llinfos << "Usage: mac_updater -url <url> | -dmg <dmg file> [-name <product_name>] [-program <program_name>]" << llendl;
- exit(1);
- }
- else
- {
- llinfos << "Update url is: " << mUpdateURL << llendl;
- if (mProductName)
- {
- llinfos << "Product name is: " << *mProductName << llendl;
- }
- else
- {
- mProductName = new std::string("Second Life");
- }
- if (mBundleID)
- {
- llinfos << "Bundle ID is: " << *mBundleID << llendl;
- }
- else
- {
- mBundleID = new std::string("com.secondlife.indra.viewer");
- }
- }
-
- llinfos << "Starting " << *mProductName << " Updater" << llendl;
-
- pthread_create(&updatethread,
- NULL,
- &sUpdatethreadproc,
- NULL);
-
-
- void *threadresult;
-
- pthread_join(updatethread, &threadresult);
-
- if(gCancelled || gFailure)
- {
- sendStopAlert();
-
- if(mMarkerPath != 0)
- {
- // Create a install fail marker that can be used by the viewer to
- // detect install problems.
- std::ofstream stream(mMarkerPath->c_str());
- if(stream) stream << -1;
- }
- exit(-1);
- } else {
- exit(0);
- }
-
- return;
-}
-
-//SPATTERS TODO this should be moved to lldir_mac.cpp
-const std::string LLMacUpdater::walkParents( signed int depth, const std::string& childpath )
-{
- boost::filesystem::path fullpath(childpath.c_str());
-
- while (depth > 0 && fullpath.has_parent_path())
- {
- fullpath = boost::filesystem::path(fullpath.parent_path());
- --depth;
- }
-
- return fullpath.string();
-}
-
-//#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);
- setProgress(cur, max);
-
- if(gCancelled)
- return(1);
-
- return(0);
-}
-
-bool LLMacUpdater::isApplication(const std::string& app_str)
-{
- return !(bool) app_str.compare( app_str.length()-4, 4, ".app");
-}
-
-// Search through the directory specified by 'parent' for an item that appears to be a Second Life viewer.
-bool LLMacUpdater::findAppBundleOnDiskImage(const boost::filesystem::path& dir_path,
- boost::filesystem::path& path_found)
-{
- if ( !boost::filesystem::exists( dir_path ) ) return false;
-
- boost::filesystem::directory_iterator end_itr;
-
- for ( boost::filesystem::directory_iterator itr( dir_path );
- itr != end_itr;
- ++itr )
- {
- if ( boost::filesystem::is_directory(itr->status()) )
- {
- std::string dir_name = itr->path().string();
- if ( isApplication(dir_name) )
- {
- if(isFSRefViewerBundle(dir_name))
- {
- llinfos << dir_name << " is the one" << llendl;
-
- path_found = itr->path();
- return true;
- }
- }
- }
- }
- return false;
-}
-
-bool LLMacUpdater::verifyDirectory(const boost::filesystem::path* directory, bool isParent)
-{
- bool replacingTarget;
- std::string app_str = directory->string();
-
- if (boost::filesystem::is_directory(*directory))
- {
- // This is fine, just means we're not replacing anything.
- replacingTarget = true;
- }
- else
- {
- replacingTarget = isParent;
- }
-
- //Check that the directory is writeable.
- if(!isDirWritable(app_str))
- {
- // Parent directory isn't writable.
- llinfos << "Target directory not writable." << llendl;
- replacingTarget = false;
- }
- return replacingTarget;
-}
-
-bool LLMacUpdater::getViewerDir(boost::filesystem::path &app_dir)
-{
- std::string app_dir_str;
-
- //Walk up 6 levels from the App Updater's installation point.
- app_dir_str = walkParents( 6, *mApplicationPath );
-
- app_dir = boost::filesystem::path(app_dir_str);
-
- //Check to see that the directory's name ends in .app Lame but it's the best thing we have to go on.
- //If it's not there, we're going to default to /Applications/VIEWERNAME
- if (!isApplication(app_dir_str))
- {
- llinfos << "Target search failed, defaulting to /Applications/" << *mProductName << ".app." << llendl;
- std::string newpath = std::string("/Applications/") + mProductName->c_str();
- app_dir = boost::filesystem::path(newpath);
- }
- return verifyDirectory(&app_dir);
-}
-
-bool LLMacUpdater::downloadDMG(const std::string& dmgName, boost::filesystem::path* temp_dir)
-{
- LLFILE *downloadFile = NULL;
- char temp[PATH_MAX] = ""; /* Flawfinder: ignore */
-
- chdir(temp_dir->string().c_str());
-
- snprintf(temp, sizeof(temp), "SecondLife.dmg");
-
- downloadFile = LLFile::fopen(temp, "wb"); /* Flawfinder: ignore */
- if(downloadFile == NULL)
- {
- return false;
- }
-
- bool success = false;
-
- 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, mUpdateURL);
- curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
-
- sendProgress(0, 1, std::string("Downloading..."));
-
- CURLcode result = curl_easy_perform(curl);
-
- curl_easy_cleanup(curl);
-
- if(gCancelled)
- {
- llinfos << "User cancel, bailing out."<< llendl;
- goto close_file;
- }
-
- if(result != CURLE_OK)
- {
- llinfos << "Error " << result << " while downloading disk image."<< llendl;
- goto close_file;
- }
-
- fclose(downloadFile);
- downloadFile = NULL;
-
- success = true;
-
-close_file:
- // Close disk image file if necessary
- if(downloadFile != NULL)
- {
- llinfos << "Closing download file." << llendl;
-
- fclose(downloadFile);
- downloadFile = NULL;
- }
-
- return success;
-}
-
-bool LLMacUpdater::doMount(const std::string& dmgName, char* deviceNode, const boost::filesystem::path& temp_dir)
-{
- char temp[PATH_MAX] = ""; /* Flawfinder: ignore */
-
- sendProgress(0, 0, std::string("Mounting image..."));
- chdir(temp_dir.string().c_str());
- std::string mnt_dir = temp_dir.string() + std::string("/mnt");
- LLFile::mkdir(mnt_dir.c_str(), 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;
- return false;
- }
-
- // 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;
- return false;
- }
-
- return true;
-}
-
-bool LLMacUpdater::moveApplication (const boost::filesystem::path& app_dir,
- const boost::filesystem::path& temp_dir,
- boost::filesystem::path& aside_dir)
-{
- try
- {
- //Grab filename from installdir append to tempdir move set aside_dir to moved path.
- std::string install_str = app_dir.parent_path().string();
- std::string temp_str = temp_dir.string();
- std::string app_str = app_dir.filename().string();
- aside_dir = boost::filesystem::path( boost::filesystem::operator/(temp_dir,app_str) );
- std::cout << "Attempting to move " << app_dir.string() << " to " << aside_dir.string() << std::endl;
-
- boost::filesystem::rename(app_dir, aside_dir);
- }
- catch(boost::filesystem::filesystem_error e)
- {
- llinfos << "Application move failed." << llendl;
- return false;
- }
- return true;
-}
-
-bool LLMacUpdater::doInstall(const boost::filesystem::path& app_dir,
- const boost::filesystem::path& temp_dir,
- boost::filesystem::path& mount_dir,
- bool replacingTarget)
-{
- std::string temp_name = temp_dir.string() + std::string("/mnt");
-
- llinfos << "Disk image mount point is: " << temp_name << llendl;
-
- mount_dir = boost::filesystem::path(temp_name.c_str());
-
- if (! boost::filesystem::exists ( mount_dir ) )
- {
- llinfos << "Couldn't make FSRef to disk image mount point." << llendl;
- return false;
- }
-
- sendProgress(0, 0, std::string("Searching for the app bundle..."));
-
- boost::filesystem::path source_dir;
-
- if ( !findAppBundleOnDiskImage(mount_dir, source_dir) )
- {
- llinfos << "Couldn't find application bundle on mounted disk image." << llendl;
- return false;
- }
- else
- {
- llinfos << "found the bundle." << llendl;
- }
-
- sendProgress(0, 0, std::string("Preparing to copy files..."));
-
- // this will hold the name of the destination target
- boost::filesystem::path aside_dir;
-
- if(replacingTarget)
- {
-
- if (! moveApplication (app_dir, temp_dir, aside_dir) )
- {
- llwarns << "failed to move aside old version." << llendl;
- return false;
- }
- }
-
- sendProgress(0, 0, std::string("Copying files..."));
-
- llinfos << "Starting copy..." << llendl;
- // If we were replacingTarget, we've moved the app to a temp directory.
- // Otherwise the destination should be empty.
- // We have mounted the DMG as a volume so we should be able to just
- // move the app from the volume to the destination and everything will just work.
-
-
- // Copy the new version from the disk image to the target location.
-
- //The installer volume is mounted read-only so we can't move. Instead copy and then unmount.
- if (! copyDir(source_dir.string(), app_dir.string()) )
- {
- llwarns << "Failed to copy " << source_dir.string() << " to " << app_dir.string() << llendl;
-
- // Something went wrong during the copy. Attempt to put the old version back and bail.
- boost::filesystem::rename(app_dir, aside_dir);
- return false;
-
- }
-
- // The update has succeeded. Clear the cache directory.
-
- sendProgress(0, 0, std::string("Clearing cache..."));
-
- llinfos << "Clearing cache..." << llendl;
-
- gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""), "*.*");
-
- llinfos << "Clear complete." << llendl;
-
- return true;
-}
-
-void* LLMacUpdater::updatethreadproc(void*)
-{
- char tempDir[PATH_MAX] = ""; /* Flawfinder: ignore */
- char temp[PATH_MAX] = ""; /* Flawfinder: ignore */
- // *NOTE: This buffer length is used in a scanf() below.
- char deviceNode[1024] = ""; /* Flawfinder: ignore */
-
- bool replacingTarget = false;
-
- boost::filesystem::path app_dir;
- boost::filesystem::path temp_dir;
- boost::filesystem::path mount_dir;
-
- // 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
-
- try
- {
- replacingTarget = getViewerDir( app_dir );
-
- if (!mkTempDir(temp_dir))
- {
- throw 0;
- }
-
- //In case the dir doesn't exist, try to create it. If create fails, verify it exists.
- if (! boost::filesystem::create_directory(app_dir))
- {
-
-
- if(isFSRefViewerBundle(app_dir.string()))
- {
- // This is the bundle we're looking for.
- replacingTarget = true;
- }
- else
- {
- throw 0;
- }
- }
-
- if ( !verifyDirectory(&app_dir, true) )
- {
- // We're so hosed.
- llinfos << "Applications directory not found, giving up." << llendl;
- throw 0;
- }
-
- // Skip downloading the file if the dmg was passed on the command line.
- std::string dmgName;
- if(mDmgFile != NULL) {
- //Create a string from the mDmgFile then a dir reference to that.
- //change to that directory and begin install.
-
- boost::filesystem::path dmg_path(*mDmgFile);
-
- dmgName = dmg_path.string();
- std::string* dmgPath = new std::string(dmg_path.parent_path().string());
- if ( !boost::filesystem::exists( dmg_path.parent_path() ) ) {
- llinfos << "Path " << *dmgPath << " is not writeable. Aborting." << llendl;
- throw 0;
- }
-
- chdir(dmgPath->c_str());
- } else {
- // Continue on to download file.
- dmgName = "SecondLife.dmg";
-
-
- if (!downloadDMG(dmgName, &temp_dir))
- {
- throw 0;
- }
- }
-
- if (!doMount(dmgName, deviceNode, temp_dir))
- {
- throw 0;
- }
-
- if (!doInstall( app_dir, temp_dir, mount_dir, replacingTarget ))
- {
- throw 0;
- }
-
- }
- catch(...)
- {
- if(!gCancelled)
- gFailure = true;
- }
-
- // Failures from here on out are all non-fatal and not reported.
- sendProgress(0, 3, std::string("Cleaning up..."));
-
- setProgress(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 */
- }
-
- setProgress(2, 3);
- std::string *trash_str=getUserTrashFolder();
-
- // Move work directory to the trash
- if(tempDir[0] != 0)
- {
- llinfos << "Moving work directory to the trash." << llendl;
-
- try
- {
- boost::filesystem::path trash_dir(*trash_str);
- boost::filesystem::rename(mount_dir, trash_dir);
- }
- catch(boost::filesystem::filesystem_error e)
- {
- llwarns << "Failed to move " << mount_dir.string() << " to " << *trash_str << llendl;
- return (NULL);
- }
- }
-
- std::string app_name_str = app_dir.string();
-
- if(!gCancelled && !gFailure && !app_name_str.empty())
- {
- //SPATTERS todo is there no better way to do this than system calls?
- llinfos << "Touching application bundle." << llendl;
-
- std::stringstream touch_str;
-
- touch_str << "touch '" << app_name_str << "'";
-
- system(touch_str.str().c_str()); /* Flawfinder: ignore */
-
- llinfos << "Launching updated application." << llendl;
-
- std::stringstream open_str;
-
- open_str << "open '" << app_name_str << "'";
-
- system(open_str.str().c_str()); /* Flawfinder: ignore */
- }
-
- sendDone();
-
- return (NULL);
-}
-
-//static
-void* LLMacUpdater::sUpdatethreadproc(void* vptr)
-{
- if (!sInstance)
- {
- llerrs << "LLMacUpdater not instantiated before use. Aborting." << llendl;
- return (NULL);
- }
- return sInstance->updatethreadproc(vptr);
-}
-
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/mac_updater/main.m b/indra/mac_updater/main.m
deleted file mode 100644
index aa3776a87d..0000000000
--- a/indra/mac_updater/main.m
+++ /dev/null
@@ -1,34 +0,0 @@
-/**
- * @file main.m
- * @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$
- */
-
-#import <Cocoa/Cocoa.h>
-
-int main(int argc, char *argv[])
-{
- int retVal = NSApplicationMain(argc, (const char **)argv);
-
- return retVal;
-}
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index dff2c04fbc..5da282cbd3 100755
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -1960,7 +1960,7 @@ if (DARWIN)
DEPENDS ${VIEWER_BINARY_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
)
- 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}")
@@ -2013,12 +2013,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 ea75d4f4f6..c09043b879 100644
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -672,7 +672,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"):
@@ -764,7 +766,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"),
):
@@ -810,7 +811,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 bc73c72ddc..3fa96dd223 100644
--- a/indra/viewer_components/updater/llupdaterservice.cpp
+++ b/indra/viewer_components/updater/llupdaterservice.cpp
@@ -60,6 +60,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
@@ -71,6 +73,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..e8b96e6123
--- /dev/null
+++ b/indra/viewer_components/updater/scripts/darwin/update_install.py
@@ -0,0 +1,336 @@
+#!/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 = "SecondLife 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, appdir=None):
+ # 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.EEXIST:
+ 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:
+
+ # Hopefully caller explicitly stated the viewer bundle to update.
+ # But if not, try to derive it from our own pathname. (The only
+ # trouble with that is that the old viewer might copy this script
+ # to a temp dir before running.)
+ if not appdir:
+ # 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"):
+ 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)
+ status("Preparing to copy files...")
+
+ # 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()
+ 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("Clearing cache...")
+
+ # We don't know whether the previous viewer was old-style or
+ # new-style (Cocoa). Clear both kinds of caches.
+ for cachesubdir in "SecondLife", BUNDLE_IDENTIFIER:
+ wildcard = "~/Library/Caches/%s/*" % cachesubdir
+ log("rm " + wildcard)
+ for f in glob.glob(os.path.expanduser(wildcard)):
+ # Don't try to remove subdirs this way
+ if os.path.isfile(f):
+ try:
+ os.remove(f)
+ except Exception, err:
+ log("%s removing %s: %s" % (err.__class__.__name__, f, err))
+
+ 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;
+ # - optionally, the pathname of the Second Life viewer to update.
+ main(*sys.argv[1:])