diff options
| author | Nat Goodspeed <nat@lindenlab.com> | 2013-01-05 09:17:51 -0500 | 
|---|---|---|
| committer | Nat Goodspeed <nat@lindenlab.com> | 2013-01-05 09:17:51 -0500 | 
| commit | 840cb864a3b41ccff310077eff487c3fa1d6b805 (patch) | |
| tree | abed8e38943228061790779c9b7568b9a4f49f83 | |
| parent | ab23506eb1d6a8435177a8e0b10331a5f03cff15 (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.txt | 3 | ||||
| -rwxr-xr-x | indra/mac_updater/AutoUpdater.nib | bin | 5251 -> 0 bytes | |||
| -rw-r--r-- | indra/mac_updater/AutoUpdater.xib | 520 | ||||
| -rw-r--r-- | indra/mac_updater/CMakeLists.txt | 89 | ||||
| -rw-r--r-- | indra/mac_updater/Info.plist | 26 | ||||
| -rw-r--r-- | indra/mac_updater/MacUpdater-Info.plist | 30 | ||||
| -rw-r--r-- | indra/mac_updater/MacUpdaterAppDelegate.h | 60 | ||||
| -rw-r--r-- | indra/mac_updater/MacUpdaterAppDelegate.mm | 288 | ||||
| -rw-r--r-- | indra/mac_updater/mac_updater.cpp | 659 | ||||
| -rw-r--r-- | indra/mac_updater/mac_updater.h | 91 | ||||
| -rw-r--r-- | indra/mac_updater/main.m | 34 | ||||
| -rwxr-xr-x | indra/newview/CMakeLists.txt | 5 | ||||
| -rw-r--r-- | indra/newview/viewer_manifest.py | 7 | ||||
| -rw-r--r-- | indra/viewer_components/updater/llupdaterservice.cpp | 4 | ||||
| -rw-r--r-- | indra/viewer_components/updater/scripts/darwin/janitor.py | 133 | ||||
| -rw-r--r-- | indra/viewer_components/updater/scripts/darwin/messageframe.py | 66 | ||||
| -rw-r--r-- | indra/viewer_components/updater/scripts/darwin/update_install | 10 | ||||
| -rwxr-xr-x | indra/viewer_components/updater/scripts/darwin/update_install.py | 336 | 
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.nibBinary files differ deleted file mode 100755 index 03883e2b86..0000000000 --- a/indra/mac_updater/AutoUpdater.nib +++ /dev/null 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:]) | 
