1 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
5 """Chromoting helper to install/uninstall host and replace pref pane."""
14 class ChromotingHelper(object):
15 """Chromoting helper base class."""
16 __metaclass__
= abc
.ABCMeta
19 def InstallHost(self
, bin_dir
):
20 """Installs the chromoting host"""
24 def UninstallHost(self
, bin_dir
):
25 """Uninstalls the chromoting host"""
29 class ChromotingHelperMac(ChromotingHelper
):
30 """Chromoting Helper class for Mac.
32 Installs/uninstalls host and replace the pref pane for testing purpose.
35 def InstallHost(self
, bin_dir
):
36 """Installs host on Mac."""
37 assert os
.geteuid() == 0, 'Need superuser privileges'
39 # Run most of the steps here with login user
40 login_uid
= os
.getuid()
43 # Change the working dir to the dir that has the host zip file
44 current_dir
= os
.getcwd()
45 pyautolib_dir
= os
.path
.dirname(os
.path
.abspath(__file__
))
47 host_dir
= 'remoting-me2me-host-mac'
48 output_dir
= os
.path
.join(host_dir
, 'output')
50 # Remove remoting-me2me-host-mac dir just in case
51 shutil
.rmtree(host_dir
, True)
53 # Unzip the host archive and prepare the files/dirs
54 subprocess
.call('unzip remoting-me2me-host-mac.zip', shell
=True)
55 subprocess
.call('mkdir ' + output_dir
, shell
=True)
57 # Prepare security identity for code signing purpose
59 key_chain
= '/Library/Keychains/ChromotingTest'
61 key
= os
.path
.join(pyautolib_dir
, 'chromoting_key.p12')
62 cert
= os
.path
.join(pyautolib_dir
, 'chromoting_cert.p12')
63 subprocess
.call(['security', 'delete-keychain', key_chain
])
64 subprocess
.call(['security', 'create-keychain', '-p',
66 subprocess
.call(['security', 'import', key
,
67 '-k', key_chain
, '-P', password
, '-A'])
68 subprocess
.call(['security', 'import', cert
,
69 '-k', key_chain
, '-P', password
])
73 do_signing
= os
.path
.join(host_dir
, 'do_signing.sh')
74 subprocess
.call(do_signing
+ ' ' + output_dir
+ ' ' + host_dir
+ ' ' +
75 key_chain
+ ' "Chromoting Test"', shell
=True)
77 # Remove security identify
79 subprocess
.call(['security', 'delete-keychain', key_chain
])
82 # Figure out the dmg name
84 for output_file
in os
.listdir(output_dir
):
85 if output_file
.endswith('.dmg'):
86 version
= os
.path
.basename(output_file
)[len('ChromotingHost-'):-4]
88 # Mount before installation
89 dmg
= os
.path
.join(output_dir
, 'ChromotingHost-' + version
+ '.dmg')
90 subprocess
.call('hdiutil' + ' mount ' + dmg
, shell
=True)
94 mpkg
= os
.path
.join('/Volumes', 'Chromoting Host ' + version
,
95 'Chromoting Host.pkg')
96 subprocess
.call(['/usr/sbin/installer', '-pkg',
97 mpkg
, '-target', '/'])
100 # Unmount after installation
101 mounted
= os
.path
.join('/Volumes', 'Chromoting Host ' + version
)
102 subprocess
.call('hdiutil detach "' + mounted
+ '"', shell
=True)
104 # Clean up remoting-me2me-host-mac dir
105 shutil
.rmtree(host_dir
, True)
107 # Resume the original working dir
108 os
.chdir(current_dir
)
110 def UninstallHost(self
, bin_dir
):
111 """Uninstalls host on Mac."""
112 assert os
.geteuid() == 0, 'Need superuser privileges'
113 uninstall_app
= os
.path
.join('/', 'Applications',
114 'Chromoting Host Uninstaller.app',
116 'remoting_host_uninstaller')
117 subprocess
.call([uninstall_app
, '--no-ui'])
119 def ReplacePrefPaneMac(self
, operation
):
120 """Constructs mock pref pane to replace the actual pref pane on Mac."""
121 assert os
.geteuid() == 0, 'Need superuser privileges'
123 pref_pane_dir
= os
.path
.join('/Library', 'PreferencePanes')
125 mock_pref_pane
= os
.path
.join(pref_pane_dir
, 'mock_pref_pane')
126 pref_pane
= os
.path
.join(pref_pane_dir
,
127 'org.chromium.chromoting.prefPane')
128 mock_pref_pane_python
= os
.path
.join(
129 os
.path
.dirname(os
.path
.abspath(__file__
)),
132 # When the symlink from real pref pane to mock pref pane exists,
133 # mock pref pane will be modified to be a dir when the host is installed.
134 # After the host is installed and mock pref pane is modified to be a file,
135 # it will be a file until next host installation.
136 if os
.path
.isdir(mock_pref_pane
):
137 shutil
.rmtree(mock_pref_pane
, True)
138 elif os
.path
.isfile(mock_pref_pane
):
139 os
.remove(mock_pref_pane
)
141 mock_pref_pane_file
= open(mock_pref_pane
, 'w')
142 mock_pref_pane_file
.write('#!/bin/bash\n')
143 mock_pref_pane_file
.write('\n')
144 mock_pref_pane_file
.write('suid-python' +
145 ' ' + mock_pref_pane_python
+ ' ' + operation
)
146 mock_pref_pane_file
.close()
148 subprocess
.call(['chmod', 'a+x', mock_pref_pane
])
150 # The real pref pane is a dir if the host is installed on a clean machine.
151 # Once the test is run on the machine, real pref pane will be replaced to
153 if os
.path
.isdir(pref_pane
):
154 shutil
.rmtree(pref_pane
, True)
155 elif os
.path
.isfile(pref_pane
):
158 subprocess
.call(['ln', '-s', mock_pref_pane
, pref_pane
])
161 class ChromotingHelperWindows(ChromotingHelper
):
162 """Chromoting Helper class for Windows for installing/uninstalling host."""
164 def InstallHost(self
, bin_dir
):
165 """Installs host on Windows."""
166 host_msi
= os
.path
.join(bin_dir
, 'chromoting.msi')
167 subprocess
.Popen(['msiexec', '/i', host_msi
, '/passive']).wait()
169 def UninstallHost(self
, bin_dir
):
170 """Uninstalls host on Windows."""
171 host_msi
= os
.path
.join(bin_dir
, 'chromoting.msi')
172 subprocess
.Popen(['msiexec', '/x', host_msi
, '/passive']).wait()
176 """Main function to dispatch operations."""
177 assert sys
.platform
.startswith('win') or \
178 sys
.platform
.startswith('darwin'), \
179 'Only support Windows and Mac'
181 if sys
.platform
.startswith('win'):
182 helper
= ChromotingHelperWindows()
183 elif sys
.platform
.startswith('darwin'):
184 helper
= ChromotingHelperMac()
186 if sys
.argv
[1] == 'install':
187 helper
.InstallHost(sys
.argv
[2])
188 elif sys
.argv
[1] == 'uninstall':
189 helper
.UninstallHost(sys
.argv
[2])
190 elif sys
.argv
[1] in ['enable', 'disable', 'changepin']:
191 assert sys
.platform
.startswith('darwin'), \
192 'Replacing pref pane is Mac specific'
193 helper
.ReplacePrefPaneMac(sys
.argv
[1])
195 print >>sys
.stderr
, 'Invalid syntax'
199 if __name__
== '__main__':